From 0916914643e0eb5d78f26d2be94588bcb9136396 Mon Sep 17 00:00:00 2001 From: Garrett Wollman Date: Tue, 21 Dec 1993 18:36:48 +0000 Subject: [PATCH] xntpd 3.3b from UDel --- contrib/xntpd/COPYRIGHT | 56 + contrib/xntpd/Config | 200 + contrib/xntpd/Config.local | 190 + contrib/xntpd/Config.local.dist | 190 + contrib/xntpd/Config.sed | 14 + contrib/xntpd/Makefile | 359 ++ contrib/xntpd/PORTING | 37 + contrib/xntpd/README | 163 + contrib/xntpd/RELNOTES | 195 + contrib/xntpd/TODO | 37 + contrib/xntpd/VERSION | 1 + contrib/xntpd/adjtime/Makefile.tmpl | 53 + contrib/xntpd/adjtime/README | 23 + contrib/xntpd/adjtime/adjtime.c | 101 + contrib/xntpd/adjtime/adjtime.h | 63 + contrib/xntpd/adjtime/adjtimed.c | 485 +++ contrib/xntpd/authstuff/Makefile.tmpl | 92 + contrib/xntpd/authstuff/README | 13 + contrib/xntpd/authstuff/auth.samplekeys | 45 + contrib/xntpd/authstuff/auth.speed | 20 + contrib/xntpd/authstuff/authcert.c | 96 + contrib/xntpd/authstuff/authspeed.c | 315 ++ contrib/xntpd/authstuff/certdata | 34 + contrib/xntpd/authstuff/keyparity.c | 279 ++ contrib/xntpd/authstuff/makeIPFP.c | 345 ++ contrib/xntpd/authstuff/makePC1.c | 286 ++ contrib/xntpd/authstuff/makePC2.c | 238 ++ contrib/xntpd/authstuff/makeSP.c | 183 + contrib/xntpd/authstuff/md5_sample_output | 8 + contrib/xntpd/authstuff/md5driver.c | 209 + contrib/xntpd/authstuff/mkrandkeys.c | 167 + contrib/xntpd/authstuff/omakeIPFP.c | 361 ++ contrib/xntpd/authstuff/results | 2 + contrib/xntpd/authstuff/unixcert.c | 156 + contrib/xntpd/clockstuff/Makefile.tmpl | 60 + contrib/xntpd/clockstuff/README | 31 + contrib/xntpd/clockstuff/chutest.c | 798 ++++ contrib/xntpd/clockstuff/clktest.c | 511 +++ contrib/xntpd/clockstuff/propdelay.c | 536 +++ contrib/xntpd/compilers/README | 5 + contrib/xntpd/compilers/aux2.gcc | 1 + contrib/xntpd/compilers/aux3.gcc | 1 + contrib/xntpd/compilers/decosf1.gcc | 1 + contrib/xntpd/compilers/hpux.cc | 2 + contrib/xntpd/compilers/hpux.gcc | 2 + contrib/xntpd/compilers/hpux10+.cc | 1 + contrib/xntpd/compilers/linux.gcc | 2 + contrib/xntpd/compilers/mips.cc | 1 + contrib/xntpd/compilers/sinix-m.cc | 1 + contrib/xntpd/compilers/sinix-m.gcc | 2 + contrib/xntpd/compilers/sunos4.bsd.cc | 1 + contrib/xntpd/compilers/sunos4.bsd.gcc | 1 + contrib/xntpd/compilers/sunos4.posix.gcc | 1 + contrib/xntpd/compilers/sunos5.1.gcc | 2 + contrib/xntpd/compilers/sunos5.2.gcc | 2 + contrib/xntpd/compilers/ultrix.bsd.cc | 2 + contrib/xntpd/compilers/ultrix.bsd.gcc | 1 + contrib/xntpd/compilers/ultrix.posix.cc | 2 + contrib/xntpd/compilers/ultrix.posix.gcc | 1 + contrib/xntpd/conf/Config.CHATHAM | 214 + contrib/xntpd/conf/Config.MONOMOY | 189 + contrib/xntpd/conf/Config.TIGER | 185 + contrib/xntpd/conf/Config.TRURO | 205 + contrib/xntpd/conf/Config.dartnet | 187 + contrib/xntpd/conf/Config.local | 190 + contrib/xntpd/conf/Config.svr4 | 167 + contrib/xntpd/conf/README | 8 + contrib/xntpd/conf/dewey.conf | 38 + contrib/xntpd/conf/grundoon.conf | 58 + contrib/xntpd/conf/malarky.conf | 40 + contrib/xntpd/conf/ntp.conf.gw | 34 + contrib/xntpd/conf/ntp.conf.ipl | 32 + contrib/xntpd/conf/ntp.conf.nsf | 156 + contrib/xntpd/conf/ntp.conf.shiningtree | 32 + contrib/xntpd/conf/ntp.conf.suzuki | 43 + contrib/xntpd/conf/pogo.conf | 50 + contrib/xntpd/conf/rackety.conf | 75 + contrib/xntpd/conf/snow-white.conf | 33 + contrib/xntpd/doc/README.irig | 306 ++ contrib/xntpd/doc/README.kern | 775 ++++ contrib/xntpd/doc/README.magic | 346 ++ contrib/xntpd/doc/UofT | 146 + contrib/xntpd/doc/notes.txt | 1258 ++++++ contrib/xntpd/doc/ntpdate.8 | 185 + contrib/xntpd/doc/ntpq.8 | 566 +++ contrib/xntpd/doc/ntptrace.8 | 104 + contrib/xntpd/doc/tickadj.8 | 143 + contrib/xntpd/doc/xntpd.8 | 1352 +++++++ contrib/xntpd/doc/xntpdc.8 | 659 ++++ contrib/xntpd/gadget/README | 84 + contrib/xntpd/gadget/adt0127.lpr | 1427 +++++++ contrib/xntpd/gadget/art01.lpr | 890 +++++ contrib/xntpd/gadget/art02.lpr | 893 +++++ contrib/xntpd/gadget/dd0124.lpr | 813 ++++ contrib/xntpd/gadget/gadget.lst | 332 ++ contrib/xntpd/gadget/gadget.s01 | 2277 +++++++++++ contrib/xntpd/gadget/gadget.s02 | 288 ++ contrib/xntpd/gadget/gen0102.lpr | 1973 ++++++++++ contrib/xntpd/gadget/sm0228.lpr | 744 ++++ contrib/xntpd/gadget/sst0126.lpr | 1118 ++++++ contrib/xntpd/hints/README | 12 + contrib/xntpd/hints/aux | 159 + contrib/xntpd/hints/bsdi | 61 + contrib/xntpd/hints/decosf1 | 40 + contrib/xntpd/hints/hpux | 76 + contrib/xntpd/hints/notes-xntp-v3 | 119 + contrib/xntpd/hints/parse | 105 + contrib/xntpd/hints/refclocks | 32 + contrib/xntpd/hints/rs6000 | 56 + contrib/xntpd/hints/sgi | 74 + contrib/xntpd/hints/solaris | 88 + contrib/xntpd/hints/svr4-dell | 6 + contrib/xntpd/include/README | 6 + contrib/xntpd/include/l_stdlib.h | 228 ++ contrib/xntpd/include/md5.h | 56 + contrib/xntpd/include/mx4200.h | 42 + contrib/xntpd/include/ntp.h | 681 ++++ contrib/xntpd/include/ntp_calendar.h | 80 + contrib/xntpd/include/ntp_control.h | 249 ++ contrib/xntpd/include/ntp_filegen.h | 51 + contrib/xntpd/include/ntp_fp.h | 315 ++ contrib/xntpd/include/ntp_if.h | 43 + contrib/xntpd/include/ntp_io.h | 24 + contrib/xntpd/include/ntp_machine.h | 457 +++ contrib/xntpd/include/ntp_malloc.h | 15 + contrib/xntpd/include/ntp_refclock.h | 142 + contrib/xntpd/include/ntp_request.h | 713 ++++ contrib/xntpd/include/ntp_select.h | 20 + contrib/xntpd/include/ntp_stdlib.h | 92 + contrib/xntpd/include/ntp_string.h | 29 + contrib/xntpd/include/ntp_syslog.h | 15 + contrib/xntpd/include/ntp_timex.h | 158 + contrib/xntpd/include/ntp_types.h | 60 + contrib/xntpd/include/ntp_unixtime.h | 119 + contrib/xntpd/include/ntpd.h | 142 + contrib/xntpd/include/parse.h | 401 ++ contrib/xntpd/include/parse_conf.h | 54 + contrib/xntpd/include/sys/bsd_audioirig.h | 101 + contrib/xntpd/include/sys/chudefs.h | 22 + contrib/xntpd/include/sys/clkdefs.h | 31 + contrib/xntpd/include/sys/parsestreams.h | 66 + contrib/xntpd/include/sys/ppsclock.h | 59 + contrib/xntpd/include/sys/tpro.h | 34 + contrib/xntpd/kernel/Makefile.tmpl | 39 + contrib/xntpd/kernel/README | 90 + contrib/xntpd/kernel/README.kern | 596 +++ contrib/xntpd/kernel/README.streams | 86 + contrib/xntpd/kernel/tty_chu.c | 276 ++ contrib/xntpd/kernel/tty_chu_STREAMS.c | 444 +++ contrib/xntpd/kernel/tty_clk.c | 303 ++ contrib/xntpd/kernel/tty_clk_STREAMS.c | 265 ++ contrib/xntpd/lib/Makefile.tmpl | 75 + contrib/xntpd/lib/README | 5 + contrib/xntpd/lib/a_md512crypt.c | 86 + contrib/xntpd/lib/a_md5decrypt.c | 58 + contrib/xntpd/lib/a_md5encrypt.c | 68 + contrib/xntpd/lib/adjtimex.c | 15 + contrib/xntpd/lib/atoint.c | 48 + contrib/xntpd/lib/atolfp.c | 117 + contrib/xntpd/lib/atouint.c | 33 + contrib/xntpd/lib/auth12crypt.c | 125 + contrib/xntpd/lib/authdecrypt.c | 85 + contrib/xntpd/lib/authdes.c | 891 +++++ contrib/xntpd/lib/authdes.c.des | Bin 0 -> 35168 bytes contrib/xntpd/lib/authdes.c.export | 40 + contrib/xntpd/lib/authencrypt.c | 88 + contrib/xntpd/lib/authkeys.c | 602 +++ contrib/xntpd/lib/authparity.c | 58 + contrib/xntpd/lib/authreadkeys.c | 191 + contrib/xntpd/lib/authusekey.c | 132 + contrib/xntpd/lib/buftvtots.c | 61 + contrib/xntpd/lib/caljulian.c | 105 + contrib/xntpd/lib/calleapwhen.c | 61 + contrib/xntpd/lib/caltontp.c | 90 + contrib/xntpd/lib/calyearstart.c | 62 + contrib/xntpd/lib/clocktime.c | 131 + contrib/xntpd/lib/clocktypes.c | 45 + contrib/xntpd/lib/decodenetnum.c | 58 + contrib/xntpd/lib/dofptoa.c | 117 + contrib/xntpd/lib/dolfptoa.c | 162 + contrib/xntpd/lib/emalloc.c | 20 + contrib/xntpd/lib/findconfig.c | 62 + contrib/xntpd/lib/fptoa.c | 24 + contrib/xntpd/lib/fptoms.c | 23 + contrib/xntpd/lib/getopt.c | 106 + contrib/xntpd/lib/gettstamp.c | 29 + contrib/xntpd/lib/hextoint.c | 38 + contrib/xntpd/lib/hextolfp.c | 66 + contrib/xntpd/lib/humandate.c | 61 + contrib/xntpd/lib/inttoa.c | 19 + contrib/xntpd/lib/lib_strbuf.c | 21 + contrib/xntpd/lib/lib_strbuf.h | 22 + contrib/xntpd/lib/machines.c | 118 + contrib/xntpd/lib/md5.c | 322 ++ contrib/xntpd/lib/mfptoa.c | 22 + contrib/xntpd/lib/mfptoms.c | 22 + contrib/xntpd/lib/modetoa.c | 33 + contrib/xntpd/lib/mstolfp.c | 99 + contrib/xntpd/lib/msutotsf.c | 35 + contrib/xntpd/lib/msyslog.c | 107 + contrib/xntpd/lib/numtoa.c | 24 + contrib/xntpd/lib/numtohost.c | 39 + contrib/xntpd/lib/octtoint.c | 34 + contrib/xntpd/lib/prettydate.c | 44 + contrib/xntpd/lib/ranny.c | 97 + contrib/xntpd/lib/refnumtoa.c | 34 + contrib/xntpd/lib/syssignal.c | 45 + contrib/xntpd/lib/systime.c | 371 ++ contrib/xntpd/lib/tsftomsu.c | 37 + contrib/xntpd/lib/tstotod.c | 21 + contrib/xntpd/lib/tstotv.c | 135 + contrib/xntpd/lib/tvtoa.c | 33 + contrib/xntpd/lib/tvtots.c | 159 + contrib/xntpd/lib/uglydate.c | 53 + contrib/xntpd/lib/uinttoa.c | 19 + contrib/xntpd/lib/utvtoa.c | 21 + contrib/xntpd/machines/README | 5 + contrib/xntpd/machines/aix3.2 | 10 + contrib/xntpd/machines/aux2 | 9 + contrib/xntpd/machines/aux3 | 9 + contrib/xntpd/machines/bsdi | 9 + contrib/xntpd/machines/convexos10 | 10 + contrib/xntpd/machines/convexos9 | 9 + contrib/xntpd/machines/decosf1 | 9 + contrib/xntpd/machines/freebsd | 8 + contrib/xntpd/machines/hpux | 8 + contrib/xntpd/machines/hpux10+ | 8 + contrib/xntpd/machines/i386 | 7 + contrib/xntpd/machines/i386svr4 | 9 + contrib/xntpd/machines/irix4 | 9 + contrib/xntpd/machines/irix5 | 9 + contrib/xntpd/machines/linux | 8 + contrib/xntpd/machines/mips | 9 + contrib/xntpd/machines/netbsd | 8 + contrib/xntpd/machines/next | 9 + contrib/xntpd/machines/ptx | 8 + contrib/xntpd/machines/sequent | 8 + contrib/xntpd/machines/sinix-m | 11 + contrib/xntpd/machines/sony | 6 + contrib/xntpd/machines/sunos4.bsd | 11 + contrib/xntpd/machines/sunos4.posix | 11 + contrib/xntpd/machines/sunos5.1 | 11 + contrib/xntpd/machines/sunos5.2 | 11 + contrib/xntpd/machines/svr4 | 10 + contrib/xntpd/machines/ultrix.bsd | 7 + contrib/xntpd/machines/ultrix.posix | 7 + contrib/xntpd/machines/vax | 6 + contrib/xntpd/ntpdate/Makefile.tmpl | 70 + contrib/xntpd/ntpdate/README | 7 + contrib/xntpd/ntpdate/ntpdate.c | 1598 ++++++++ contrib/xntpd/ntpdate/ntpdate.h | 86 + contrib/xntpd/ntpq/Makefile.tmpl | 68 + contrib/xntpd/ntpq/README | 6 + contrib/xntpd/ntpq/ntpq.c | 3059 +++++++++++++++ contrib/xntpd/ntpq/ntpq.h | 97 + contrib/xntpd/ntpq/ntpq_ops.c | 1600 ++++++++ contrib/xntpd/ntptrace/Makefile.tmpl | 70 + contrib/xntpd/ntptrace/README | 7 + contrib/xntpd/ntptrace/ntptrace.c | 777 ++++ contrib/xntpd/ntptrace/ntptrace.h | 36 + contrib/xntpd/parse/Makefile.kernel | 71 + contrib/xntpd/parse/Makefile.tmpl | 111 + contrib/xntpd/parse/README | 100 + contrib/xntpd/parse/README.parse | 142 + contrib/xntpd/parse/clk_dcf7000.c | 142 + contrib/xntpd/parse/clk_meinberg.c | 444 +++ contrib/xntpd/parse/clk_rawdcf.c | 553 +++ contrib/xntpd/parse/clk_schmid.c | 195 + contrib/xntpd/parse/clk_trimble.c | 131 + contrib/xntpd/parse/empty.c | 7 + contrib/xntpd/parse/parse.c | 1193 ++++++ contrib/xntpd/parse/parse_conf.c | 117 + contrib/xntpd/parse/parsesolaris.c | 1170 ++++++ contrib/xntpd/parse/parsestreams.c | 1277 ++++++ contrib/xntpd/parse/util/Makefile | 49 + contrib/xntpd/parse/util/Makefile.tmpl | 49 + contrib/xntpd/parse/util/README | 12 + contrib/xntpd/parse/util/dcfd.c | 1206 ++++++ contrib/xntpd/parse/util/parsetest.c | 268 ++ contrib/xntpd/parse/util/testdcf.c | 485 +++ contrib/xntpd/ppsclock/CHANGES | 18 + contrib/xntpd/ppsclock/Makefile | 7 + contrib/xntpd/ppsclock/README | 229 ++ contrib/xntpd/ppsclock/RELEASE | 1 + contrib/xntpd/ppsclock/b-and-b.ps | 2030 ++++++++++ contrib/xntpd/ppsclock/magnavox.ps | 2041 ++++++++++ contrib/xntpd/ppsclock/ppstest/Makefile | 10 + contrib/xntpd/ppsclock/ppstest/ppstest.c | 132 + .../xntpd/ppsclock/sys/genassym/genassym.c | 84 + .../xntpd/ppsclock/sys/os/kern_clock.c.patch | 19 + .../xntpd/ppsclock/sys/sun/str_conf.c.patch | 38 + .../sys/sun4c/conf/Makefile.src.patch | 17 + .../sys/sun4c/conf/files.microtime.patch | 12 + .../xntpd/ppsclock/sys/sun4c/conf/files.patch | 12 + contrib/xntpd/ppsclock/sys/sun4c/microtime.s | 98 + .../sys/sun4m/conf/Makefile.src.patch | 17 + .../sys/sun4m/conf/files.microtime.patch | 12 + .../xntpd/ppsclock/sys/sun4m/conf/files.patch | 12 + contrib/xntpd/ppsclock/sys/sun4m/microtime.s | 98 + contrib/xntpd/ppsclock/sys/sundev/ppsclock.c | 249 ++ contrib/xntpd/ppsclock/sys/sys/ppsclock.h | 49 + contrib/xntpd/refclocks/Dependencies | 28 + contrib/xntpd/refclocks/README | 4 + contrib/xntpd/refclocks/check | 2 + contrib/xntpd/refclocks/echon | 2 + contrib/xntpd/refclocks/query | 11 + contrib/xntpd/refclocks/rclk.AS2201 | 29 + contrib/xntpd/refclocks/rclk.CHU | 24 + contrib/xntpd/refclocks/rclk.GOES | 32 + contrib/xntpd/refclocks/rclk.IRIG | 24 + contrib/xntpd/refclocks/rclk.LEITCH | 29 + contrib/xntpd/refclocks/rclk.LOCAL_CLOCK | 22 + contrib/xntpd/refclocks/rclk.MSFEES | 26 + contrib/xntpd/refclocks/rclk.MX4200 | 27 + contrib/xntpd/refclocks/rclk.OMEGA | 29 + contrib/xntpd/refclocks/rclk.PARSE | 51 + contrib/xntpd/refclocks/rclk.PST | 37 + contrib/xntpd/refclocks/rclk.TPRO | 24 + contrib/xntpd/refclocks/rclk.WWVB | 38 + contrib/xntpd/refclocks/rconfig | 119 + contrib/xntpd/refclocks/setup | 16 + contrib/xntpd/refclocks/setupfn | 27 + contrib/xntpd/scripts/Guess.sh | 116 + contrib/xntpd/scripts/README | 41 + contrib/xntpd/scripts/autoconf | 885 +++++ contrib/xntpd/scripts/install.sh | 100 + contrib/xntpd/scripts/makeconfig.sh | 85 + contrib/xntpd/scripts/mklinks | 9 + contrib/xntpd/scripts/mkversion | 33 + contrib/xntpd/scripts/monitoring/README | 154 + .../monitoring/loopwatch.config.SAMPLE | 89 + contrib/xntpd/scripts/monitoring/lr.pl | 145 + contrib/xntpd/scripts/monitoring/ntp.pl | 477 +++ contrib/xntpd/scripts/monitoring/ntploopstat | 457 +++ contrib/xntpd/scripts/monitoring/ntploopwatch | 1631 ++++++++ contrib/xntpd/scripts/monitoring/ntptrap | 453 +++ contrib/xntpd/scripts/monitoring/timelocal.pl | 77 + contrib/xntpd/scripts/ntp-groper | 95 + contrib/xntpd/scripts/ntp-restart | 9 + contrib/xntpd/scripts/stats/README | 32 + contrib/xntpd/scripts/stats/README.stats | 246 ++ contrib/xntpd/scripts/stats/README.timecodes | 149 + contrib/xntpd/scripts/stats/clock.awk | 341 ++ contrib/xntpd/scripts/stats/clock.sh | 17 + contrib/xntpd/scripts/stats/dupe.awk | 7 + contrib/xntpd/scripts/stats/ensemble.awk | 17 + contrib/xntpd/scripts/stats/etf.awk | 19 + contrib/xntpd/scripts/stats/itf.awk | 19 + contrib/xntpd/scripts/stats/loop.awk | 49 + contrib/xntpd/scripts/stats/loop.sh | 13 + contrib/xntpd/scripts/stats/peer.awk | 57 + contrib/xntpd/scripts/stats/peer.sh | 13 + contrib/xntpd/scripts/stats/psummary.awk | 41 + contrib/xntpd/scripts/stats/summary.sh | 12 + contrib/xntpd/scripts/stats/tdata.awk | 45 + contrib/xntpd/scripts/support/README | 73 + contrib/xntpd/scripts/support/bin/monl | 212 + contrib/xntpd/scripts/support/bin/mvstats | 23 + .../xntpd/scripts/support/conf/hp300.hp300 | 70 + .../xntpd/scripts/support/conf/hp700.hp700 | 67 + .../scripts/support/conf/hp700.hp700.faui47 | 71 + .../xntpd/scripts/support/conf/hp800.hp800 | 70 + contrib/xntpd/scripts/support/conf/ntp.conf | 36 + contrib/xntpd/scripts/support/conf/ntp.keys | 0 .../xntpd/scripts/support/conf/ntp.keys.dumb | 0 contrib/xntpd/scripts/support/conf/sun3.sun3 | 36 + .../scripts/support/conf/sun4.sun4.faui01 | 83 + .../scripts/support/conf/sun4.sun4.faui10 | 176 + .../scripts/support/conf/sun4.sun4.faui45 | 228 ++ contrib/xntpd/scripts/support/conf/sun4.sun4c | 63 + .../scripts/support/conf/sun4.sun4c.Lucifer | 174 + contrib/xntpd/scripts/support/conf/sun4.sun4m | 69 + .../scripts/support/conf/sun4.sun4m.faui42 | 152 + .../scripts/support/conf/sun4.sun4m.faui45m | 165 + contrib/xntpd/scripts/support/conf/tickconf | 19 + contrib/xntpd/scripts/support/etc/cron | 18 + contrib/xntpd/scripts/support/etc/crontab | 8 + contrib/xntpd/scripts/support/etc/install | 67 + contrib/xntpd/scripts/support/etc/rc | 198 + contrib/xntpd/scripts/support/etc/setup | 72 + contrib/xntpd/util/Makefile.tmpl | 62 + contrib/xntpd/util/README | 67 + contrib/xntpd/util/byteorder.c | 52 + contrib/xntpd/util/jitter.c | 73 + contrib/xntpd/util/kern.c | 210 + contrib/xntpd/util/longsize.c | 11 + contrib/xntpd/util/ntptime.c | 220 ++ contrib/xntpd/util/precision.c | 81 + contrib/xntpd/util/testrs6000.c | 44 + contrib/xntpd/util/tickadj.c | 518 +++ contrib/xntpd/util/timetrim.c | 85 + contrib/xntpd/xntpd/Makefile.tmpl | 138 + contrib/xntpd/xntpd/README | 6 + contrib/xntpd/xntpd/ntp_config.c | 1849 +++++++++ contrib/xntpd/xntpd/ntp_control.c | 2305 +++++++++++ contrib/xntpd/xntpd/ntp_filegen.c | 536 +++ contrib/xntpd/xntpd/ntp_intres.c | 792 ++++ contrib/xntpd/xntpd/ntp_io.c | 1621 ++++++++ contrib/xntpd/xntpd/ntp_leap.c | 315 ++ contrib/xntpd/xntpd/ntp_loopfilter.c | 944 +++++ contrib/xntpd/xntpd/ntp_monitor.c | 305 ++ contrib/xntpd/xntpd/ntp_peer.c | 639 +++ contrib/xntpd/xntpd/ntp_proto.c | 2168 ++++++++++ contrib/xntpd/xntpd/ntp_refclock.c | 439 +++ contrib/xntpd/xntpd/ntp_request.c | 2336 +++++++++++ contrib/xntpd/xntpd/ntp_restrict.c | 297 ++ contrib/xntpd/xntpd/ntp_timer.c | 187 + contrib/xntpd/xntpd/ntp_unixclock.c | 564 +++ contrib/xntpd/xntpd/ntp_util.c | 466 +++ contrib/xntpd/xntpd/ntpd.c | 438 +++ contrib/xntpd/xntpd/refclock_as2201.c | 991 +++++ contrib/xntpd/xntpd/refclock_chu.c | 1135 ++++++ contrib/xntpd/xntpd/refclock_conf.c | 121 + contrib/xntpd/xntpd/refclock_goes.c | 1009 +++++ contrib/xntpd/xntpd/refclock_irig.c | 566 +++ contrib/xntpd/xntpd/refclock_leitch.c | 700 ++++ contrib/xntpd/xntpd/refclock_local.c | 307 ++ contrib/xntpd/xntpd/refclock_msfees.c | 1570 ++++++++ contrib/xntpd/xntpd/refclock_mx4200.c | 1357 +++++++ contrib/xntpd/xntpd/refclock_omega.c | 1015 +++++ contrib/xntpd/xntpd/refclock_parse.c | 3471 +++++++++++++++++ contrib/xntpd/xntpd/refclock_pst.c | 1800 +++++++++ contrib/xntpd/xntpd/refclock_tpro.c | 498 +++ contrib/xntpd/xntpd/refclock_wwvb.c | 1041 +++++ contrib/xntpd/xntpdc/Makefile.tmpl | 68 + contrib/xntpd/xntpdc/README | 6 + contrib/xntpd/xntpdc/ntpdc.c | 1536 ++++++++ contrib/xntpd/xntpdc/ntpdc.h | 59 + contrib/xntpd/xntpdc/ntpdc_ops.c | 2421 ++++++++++++ contrib/xntpd/xntpres/Makefile.tmpl | 68 + contrib/xntpd/xntpres/README | 6 + contrib/xntpd/xntpres/xntpres.c | 845 ++++ 432 files changed, 106754 insertions(+) create mode 100644 contrib/xntpd/COPYRIGHT create mode 100644 contrib/xntpd/Config create mode 100644 contrib/xntpd/Config.local create mode 100644 contrib/xntpd/Config.local.dist create mode 100644 contrib/xntpd/Config.sed create mode 100644 contrib/xntpd/Makefile create mode 100644 contrib/xntpd/PORTING create mode 100644 contrib/xntpd/README create mode 100644 contrib/xntpd/RELNOTES create mode 100644 contrib/xntpd/TODO create mode 100644 contrib/xntpd/VERSION create mode 100644 contrib/xntpd/adjtime/Makefile.tmpl create mode 100644 contrib/xntpd/adjtime/README create mode 100644 contrib/xntpd/adjtime/adjtime.c create mode 100644 contrib/xntpd/adjtime/adjtime.h create mode 100644 contrib/xntpd/adjtime/adjtimed.c create mode 100644 contrib/xntpd/authstuff/Makefile.tmpl create mode 100644 contrib/xntpd/authstuff/README create mode 100644 contrib/xntpd/authstuff/auth.samplekeys create mode 100644 contrib/xntpd/authstuff/auth.speed create mode 100644 contrib/xntpd/authstuff/authcert.c create mode 100644 contrib/xntpd/authstuff/authspeed.c create mode 100644 contrib/xntpd/authstuff/certdata create mode 100644 contrib/xntpd/authstuff/keyparity.c create mode 100644 contrib/xntpd/authstuff/makeIPFP.c create mode 100644 contrib/xntpd/authstuff/makePC1.c create mode 100644 contrib/xntpd/authstuff/makePC2.c create mode 100644 contrib/xntpd/authstuff/makeSP.c create mode 100644 contrib/xntpd/authstuff/md5_sample_output create mode 100644 contrib/xntpd/authstuff/md5driver.c create mode 100644 contrib/xntpd/authstuff/mkrandkeys.c create mode 100644 contrib/xntpd/authstuff/omakeIPFP.c create mode 100644 contrib/xntpd/authstuff/results create mode 100644 contrib/xntpd/authstuff/unixcert.c create mode 100644 contrib/xntpd/clockstuff/Makefile.tmpl create mode 100644 contrib/xntpd/clockstuff/README create mode 100644 contrib/xntpd/clockstuff/chutest.c create mode 100644 contrib/xntpd/clockstuff/clktest.c create mode 100644 contrib/xntpd/clockstuff/propdelay.c create mode 100644 contrib/xntpd/compilers/README create mode 100644 contrib/xntpd/compilers/aux2.gcc create mode 100644 contrib/xntpd/compilers/aux3.gcc create mode 100644 contrib/xntpd/compilers/decosf1.gcc create mode 100644 contrib/xntpd/compilers/hpux.cc create mode 100644 contrib/xntpd/compilers/hpux.gcc create mode 100644 contrib/xntpd/compilers/hpux10+.cc create mode 100644 contrib/xntpd/compilers/linux.gcc create mode 100644 contrib/xntpd/compilers/mips.cc create mode 100644 contrib/xntpd/compilers/sinix-m.cc create mode 100644 contrib/xntpd/compilers/sinix-m.gcc create mode 100644 contrib/xntpd/compilers/sunos4.bsd.cc create mode 100644 contrib/xntpd/compilers/sunos4.bsd.gcc create mode 100644 contrib/xntpd/compilers/sunos4.posix.gcc create mode 100644 contrib/xntpd/compilers/sunos5.1.gcc create mode 100644 contrib/xntpd/compilers/sunos5.2.gcc create mode 100644 contrib/xntpd/compilers/ultrix.bsd.cc create mode 100644 contrib/xntpd/compilers/ultrix.bsd.gcc create mode 100644 contrib/xntpd/compilers/ultrix.posix.cc create mode 100644 contrib/xntpd/compilers/ultrix.posix.gcc create mode 100644 contrib/xntpd/conf/Config.CHATHAM create mode 100644 contrib/xntpd/conf/Config.MONOMOY create mode 100644 contrib/xntpd/conf/Config.TIGER create mode 100644 contrib/xntpd/conf/Config.TRURO create mode 100644 contrib/xntpd/conf/Config.dartnet create mode 100644 contrib/xntpd/conf/Config.local create mode 100644 contrib/xntpd/conf/Config.svr4 create mode 100644 contrib/xntpd/conf/README create mode 100644 contrib/xntpd/conf/dewey.conf create mode 100644 contrib/xntpd/conf/grundoon.conf create mode 100644 contrib/xntpd/conf/malarky.conf create mode 100644 contrib/xntpd/conf/ntp.conf.gw create mode 100644 contrib/xntpd/conf/ntp.conf.ipl create mode 100644 contrib/xntpd/conf/ntp.conf.nsf create mode 100644 contrib/xntpd/conf/ntp.conf.shiningtree create mode 100644 contrib/xntpd/conf/ntp.conf.suzuki create mode 100644 contrib/xntpd/conf/pogo.conf create mode 100644 contrib/xntpd/conf/rackety.conf create mode 100644 contrib/xntpd/conf/snow-white.conf create mode 100644 contrib/xntpd/doc/README.irig create mode 100644 contrib/xntpd/doc/README.kern create mode 100644 contrib/xntpd/doc/README.magic create mode 100644 contrib/xntpd/doc/UofT create mode 100644 contrib/xntpd/doc/notes.txt create mode 100644 contrib/xntpd/doc/ntpdate.8 create mode 100644 contrib/xntpd/doc/ntpq.8 create mode 100644 contrib/xntpd/doc/ntptrace.8 create mode 100644 contrib/xntpd/doc/tickadj.8 create mode 100644 contrib/xntpd/doc/xntpd.8 create mode 100644 contrib/xntpd/doc/xntpdc.8 create mode 100644 contrib/xntpd/gadget/README create mode 100644 contrib/xntpd/gadget/adt0127.lpr create mode 100644 contrib/xntpd/gadget/art01.lpr create mode 100644 contrib/xntpd/gadget/art02.lpr create mode 100644 contrib/xntpd/gadget/dd0124.lpr create mode 100644 contrib/xntpd/gadget/gadget.lst create mode 100644 contrib/xntpd/gadget/gadget.s01 create mode 100644 contrib/xntpd/gadget/gadget.s02 create mode 100644 contrib/xntpd/gadget/gen0102.lpr create mode 100644 contrib/xntpd/gadget/sm0228.lpr create mode 100644 contrib/xntpd/gadget/sst0126.lpr create mode 100644 contrib/xntpd/hints/README create mode 100644 contrib/xntpd/hints/aux create mode 100644 contrib/xntpd/hints/bsdi create mode 100644 contrib/xntpd/hints/decosf1 create mode 100644 contrib/xntpd/hints/hpux create mode 100644 contrib/xntpd/hints/notes-xntp-v3 create mode 100644 contrib/xntpd/hints/parse create mode 100644 contrib/xntpd/hints/refclocks create mode 100644 contrib/xntpd/hints/rs6000 create mode 100644 contrib/xntpd/hints/sgi create mode 100644 contrib/xntpd/hints/solaris create mode 100644 contrib/xntpd/hints/svr4-dell create mode 100644 contrib/xntpd/include/README create mode 100644 contrib/xntpd/include/l_stdlib.h create mode 100644 contrib/xntpd/include/md5.h create mode 100644 contrib/xntpd/include/mx4200.h create mode 100644 contrib/xntpd/include/ntp.h create mode 100644 contrib/xntpd/include/ntp_calendar.h create mode 100644 contrib/xntpd/include/ntp_control.h create mode 100644 contrib/xntpd/include/ntp_filegen.h create mode 100644 contrib/xntpd/include/ntp_fp.h create mode 100644 contrib/xntpd/include/ntp_if.h create mode 100644 contrib/xntpd/include/ntp_io.h create mode 100644 contrib/xntpd/include/ntp_machine.h create mode 100644 contrib/xntpd/include/ntp_malloc.h create mode 100644 contrib/xntpd/include/ntp_refclock.h create mode 100644 contrib/xntpd/include/ntp_request.h create mode 100644 contrib/xntpd/include/ntp_select.h create mode 100644 contrib/xntpd/include/ntp_stdlib.h create mode 100644 contrib/xntpd/include/ntp_string.h create mode 100644 contrib/xntpd/include/ntp_syslog.h create mode 100644 contrib/xntpd/include/ntp_timex.h create mode 100644 contrib/xntpd/include/ntp_types.h create mode 100644 contrib/xntpd/include/ntp_unixtime.h create mode 100644 contrib/xntpd/include/ntpd.h create mode 100644 contrib/xntpd/include/parse.h create mode 100644 contrib/xntpd/include/parse_conf.h create mode 100644 contrib/xntpd/include/sys/bsd_audioirig.h create mode 100644 contrib/xntpd/include/sys/chudefs.h create mode 100644 contrib/xntpd/include/sys/clkdefs.h create mode 100644 contrib/xntpd/include/sys/parsestreams.h create mode 100644 contrib/xntpd/include/sys/ppsclock.h create mode 100644 contrib/xntpd/include/sys/tpro.h create mode 100644 contrib/xntpd/kernel/Makefile.tmpl create mode 100644 contrib/xntpd/kernel/README create mode 100644 contrib/xntpd/kernel/README.kern create mode 100644 contrib/xntpd/kernel/README.streams create mode 100644 contrib/xntpd/kernel/tty_chu.c create mode 100644 contrib/xntpd/kernel/tty_chu_STREAMS.c create mode 100644 contrib/xntpd/kernel/tty_clk.c create mode 100644 contrib/xntpd/kernel/tty_clk_STREAMS.c create mode 100644 contrib/xntpd/lib/Makefile.tmpl create mode 100644 contrib/xntpd/lib/README create mode 100644 contrib/xntpd/lib/a_md512crypt.c create mode 100644 contrib/xntpd/lib/a_md5decrypt.c create mode 100644 contrib/xntpd/lib/a_md5encrypt.c create mode 100644 contrib/xntpd/lib/adjtimex.c create mode 100644 contrib/xntpd/lib/atoint.c create mode 100644 contrib/xntpd/lib/atolfp.c create mode 100644 contrib/xntpd/lib/atouint.c create mode 100644 contrib/xntpd/lib/auth12crypt.c create mode 100644 contrib/xntpd/lib/authdecrypt.c create mode 100644 contrib/xntpd/lib/authdes.c create mode 100644 contrib/xntpd/lib/authdes.c.des create mode 100644 contrib/xntpd/lib/authdes.c.export create mode 100644 contrib/xntpd/lib/authencrypt.c create mode 100644 contrib/xntpd/lib/authkeys.c create mode 100644 contrib/xntpd/lib/authparity.c create mode 100644 contrib/xntpd/lib/authreadkeys.c create mode 100644 contrib/xntpd/lib/authusekey.c create mode 100644 contrib/xntpd/lib/buftvtots.c create mode 100644 contrib/xntpd/lib/caljulian.c create mode 100644 contrib/xntpd/lib/calleapwhen.c create mode 100644 contrib/xntpd/lib/caltontp.c create mode 100644 contrib/xntpd/lib/calyearstart.c create mode 100644 contrib/xntpd/lib/clocktime.c create mode 100644 contrib/xntpd/lib/clocktypes.c create mode 100644 contrib/xntpd/lib/decodenetnum.c create mode 100644 contrib/xntpd/lib/dofptoa.c create mode 100644 contrib/xntpd/lib/dolfptoa.c create mode 100644 contrib/xntpd/lib/emalloc.c create mode 100644 contrib/xntpd/lib/findconfig.c create mode 100644 contrib/xntpd/lib/fptoa.c create mode 100644 contrib/xntpd/lib/fptoms.c create mode 100644 contrib/xntpd/lib/getopt.c create mode 100644 contrib/xntpd/lib/gettstamp.c create mode 100644 contrib/xntpd/lib/hextoint.c create mode 100644 contrib/xntpd/lib/hextolfp.c create mode 100644 contrib/xntpd/lib/humandate.c create mode 100644 contrib/xntpd/lib/inttoa.c create mode 100644 contrib/xntpd/lib/lib_strbuf.c create mode 100644 contrib/xntpd/lib/lib_strbuf.h create mode 100644 contrib/xntpd/lib/machines.c create mode 100644 contrib/xntpd/lib/md5.c create mode 100644 contrib/xntpd/lib/mfptoa.c create mode 100644 contrib/xntpd/lib/mfptoms.c create mode 100644 contrib/xntpd/lib/modetoa.c create mode 100644 contrib/xntpd/lib/mstolfp.c create mode 100644 contrib/xntpd/lib/msutotsf.c create mode 100644 contrib/xntpd/lib/msyslog.c create mode 100644 contrib/xntpd/lib/numtoa.c create mode 100644 contrib/xntpd/lib/numtohost.c create mode 100644 contrib/xntpd/lib/octtoint.c create mode 100644 contrib/xntpd/lib/prettydate.c create mode 100644 contrib/xntpd/lib/ranny.c create mode 100644 contrib/xntpd/lib/refnumtoa.c create mode 100644 contrib/xntpd/lib/syssignal.c create mode 100644 contrib/xntpd/lib/systime.c create mode 100644 contrib/xntpd/lib/tsftomsu.c create mode 100644 contrib/xntpd/lib/tstotod.c create mode 100644 contrib/xntpd/lib/tstotv.c create mode 100644 contrib/xntpd/lib/tvtoa.c create mode 100644 contrib/xntpd/lib/tvtots.c create mode 100644 contrib/xntpd/lib/uglydate.c create mode 100644 contrib/xntpd/lib/uinttoa.c create mode 100644 contrib/xntpd/lib/utvtoa.c create mode 100644 contrib/xntpd/machines/README create mode 100644 contrib/xntpd/machines/aix3.2 create mode 100644 contrib/xntpd/machines/aux2 create mode 100644 contrib/xntpd/machines/aux3 create mode 100644 contrib/xntpd/machines/bsdi create mode 100644 contrib/xntpd/machines/convexos10 create mode 100644 contrib/xntpd/machines/convexos9 create mode 100644 contrib/xntpd/machines/decosf1 create mode 100644 contrib/xntpd/machines/freebsd create mode 100644 contrib/xntpd/machines/hpux create mode 100644 contrib/xntpd/machines/hpux10+ create mode 100644 contrib/xntpd/machines/i386 create mode 100644 contrib/xntpd/machines/i386svr4 create mode 100644 contrib/xntpd/machines/irix4 create mode 100644 contrib/xntpd/machines/irix5 create mode 100644 contrib/xntpd/machines/linux create mode 100644 contrib/xntpd/machines/mips create mode 100644 contrib/xntpd/machines/netbsd create mode 100644 contrib/xntpd/machines/next create mode 100644 contrib/xntpd/machines/ptx create mode 100644 contrib/xntpd/machines/sequent create mode 100644 contrib/xntpd/machines/sinix-m create mode 100644 contrib/xntpd/machines/sony create mode 100644 contrib/xntpd/machines/sunos4.bsd create mode 100644 contrib/xntpd/machines/sunos4.posix create mode 100644 contrib/xntpd/machines/sunos5.1 create mode 100644 contrib/xntpd/machines/sunos5.2 create mode 100644 contrib/xntpd/machines/svr4 create mode 100644 contrib/xntpd/machines/ultrix.bsd create mode 100644 contrib/xntpd/machines/ultrix.posix create mode 100644 contrib/xntpd/machines/vax create mode 100644 contrib/xntpd/ntpdate/Makefile.tmpl create mode 100644 contrib/xntpd/ntpdate/README create mode 100644 contrib/xntpd/ntpdate/ntpdate.c create mode 100644 contrib/xntpd/ntpdate/ntpdate.h create mode 100644 contrib/xntpd/ntpq/Makefile.tmpl create mode 100644 contrib/xntpd/ntpq/README create mode 100644 contrib/xntpd/ntpq/ntpq.c create mode 100644 contrib/xntpd/ntpq/ntpq.h create mode 100644 contrib/xntpd/ntpq/ntpq_ops.c create mode 100644 contrib/xntpd/ntptrace/Makefile.tmpl create mode 100644 contrib/xntpd/ntptrace/README create mode 100644 contrib/xntpd/ntptrace/ntptrace.c create mode 100644 contrib/xntpd/ntptrace/ntptrace.h create mode 100644 contrib/xntpd/parse/Makefile.kernel create mode 100644 contrib/xntpd/parse/Makefile.tmpl create mode 100644 contrib/xntpd/parse/README create mode 100644 contrib/xntpd/parse/README.parse create mode 100644 contrib/xntpd/parse/clk_dcf7000.c create mode 100644 contrib/xntpd/parse/clk_meinberg.c create mode 100644 contrib/xntpd/parse/clk_rawdcf.c create mode 100644 contrib/xntpd/parse/clk_schmid.c create mode 100644 contrib/xntpd/parse/clk_trimble.c create mode 100644 contrib/xntpd/parse/empty.c create mode 100644 contrib/xntpd/parse/parse.c create mode 100644 contrib/xntpd/parse/parse_conf.c create mode 100644 contrib/xntpd/parse/parsesolaris.c create mode 100644 contrib/xntpd/parse/parsestreams.c create mode 100644 contrib/xntpd/parse/util/Makefile create mode 100644 contrib/xntpd/parse/util/Makefile.tmpl create mode 100644 contrib/xntpd/parse/util/README create mode 100644 contrib/xntpd/parse/util/dcfd.c create mode 100644 contrib/xntpd/parse/util/parsetest.c create mode 100644 contrib/xntpd/parse/util/testdcf.c create mode 100644 contrib/xntpd/ppsclock/CHANGES create mode 100644 contrib/xntpd/ppsclock/Makefile create mode 100644 contrib/xntpd/ppsclock/README create mode 100644 contrib/xntpd/ppsclock/RELEASE create mode 100644 contrib/xntpd/ppsclock/b-and-b.ps create mode 100644 contrib/xntpd/ppsclock/magnavox.ps create mode 100644 contrib/xntpd/ppsclock/ppstest/Makefile create mode 100644 contrib/xntpd/ppsclock/ppstest/ppstest.c create mode 100644 contrib/xntpd/ppsclock/sys/genassym/genassym.c create mode 100644 contrib/xntpd/ppsclock/sys/os/kern_clock.c.patch create mode 100644 contrib/xntpd/ppsclock/sys/sun/str_conf.c.patch create mode 100644 contrib/xntpd/ppsclock/sys/sun4c/conf/Makefile.src.patch create mode 100644 contrib/xntpd/ppsclock/sys/sun4c/conf/files.microtime.patch create mode 100644 contrib/xntpd/ppsclock/sys/sun4c/conf/files.patch create mode 100644 contrib/xntpd/ppsclock/sys/sun4c/microtime.s create mode 100644 contrib/xntpd/ppsclock/sys/sun4m/conf/Makefile.src.patch create mode 100644 contrib/xntpd/ppsclock/sys/sun4m/conf/files.microtime.patch create mode 100644 contrib/xntpd/ppsclock/sys/sun4m/conf/files.patch create mode 100644 contrib/xntpd/ppsclock/sys/sun4m/microtime.s create mode 100644 contrib/xntpd/ppsclock/sys/sundev/ppsclock.c create mode 100644 contrib/xntpd/ppsclock/sys/sys/ppsclock.h create mode 100644 contrib/xntpd/refclocks/Dependencies create mode 100644 contrib/xntpd/refclocks/README create mode 100644 contrib/xntpd/refclocks/check create mode 100644 contrib/xntpd/refclocks/echon create mode 100644 contrib/xntpd/refclocks/query create mode 100644 contrib/xntpd/refclocks/rclk.AS2201 create mode 100644 contrib/xntpd/refclocks/rclk.CHU create mode 100644 contrib/xntpd/refclocks/rclk.GOES create mode 100644 contrib/xntpd/refclocks/rclk.IRIG create mode 100644 contrib/xntpd/refclocks/rclk.LEITCH create mode 100644 contrib/xntpd/refclocks/rclk.LOCAL_CLOCK create mode 100644 contrib/xntpd/refclocks/rclk.MSFEES create mode 100644 contrib/xntpd/refclocks/rclk.MX4200 create mode 100644 contrib/xntpd/refclocks/rclk.OMEGA create mode 100644 contrib/xntpd/refclocks/rclk.PARSE create mode 100644 contrib/xntpd/refclocks/rclk.PST create mode 100644 contrib/xntpd/refclocks/rclk.TPRO create mode 100644 contrib/xntpd/refclocks/rclk.WWVB create mode 100644 contrib/xntpd/refclocks/rconfig create mode 100644 contrib/xntpd/refclocks/setup create mode 100644 contrib/xntpd/refclocks/setupfn create mode 100644 contrib/xntpd/scripts/Guess.sh create mode 100644 contrib/xntpd/scripts/README create mode 100644 contrib/xntpd/scripts/autoconf create mode 100644 contrib/xntpd/scripts/install.sh create mode 100644 contrib/xntpd/scripts/makeconfig.sh create mode 100644 contrib/xntpd/scripts/mklinks create mode 100644 contrib/xntpd/scripts/mkversion create mode 100644 contrib/xntpd/scripts/monitoring/README create mode 100644 contrib/xntpd/scripts/monitoring/loopwatch.config.SAMPLE create mode 100644 contrib/xntpd/scripts/monitoring/lr.pl create mode 100644 contrib/xntpd/scripts/monitoring/ntp.pl create mode 100644 contrib/xntpd/scripts/monitoring/ntploopstat create mode 100644 contrib/xntpd/scripts/monitoring/ntploopwatch create mode 100644 contrib/xntpd/scripts/monitoring/ntptrap create mode 100644 contrib/xntpd/scripts/monitoring/timelocal.pl create mode 100644 contrib/xntpd/scripts/ntp-groper create mode 100644 contrib/xntpd/scripts/ntp-restart create mode 100644 contrib/xntpd/scripts/stats/README create mode 100644 contrib/xntpd/scripts/stats/README.stats create mode 100644 contrib/xntpd/scripts/stats/README.timecodes create mode 100644 contrib/xntpd/scripts/stats/clock.awk create mode 100644 contrib/xntpd/scripts/stats/clock.sh create mode 100644 contrib/xntpd/scripts/stats/dupe.awk create mode 100644 contrib/xntpd/scripts/stats/ensemble.awk create mode 100644 contrib/xntpd/scripts/stats/etf.awk create mode 100644 contrib/xntpd/scripts/stats/itf.awk create mode 100644 contrib/xntpd/scripts/stats/loop.awk create mode 100644 contrib/xntpd/scripts/stats/loop.sh create mode 100644 contrib/xntpd/scripts/stats/peer.awk create mode 100644 contrib/xntpd/scripts/stats/peer.sh create mode 100644 contrib/xntpd/scripts/stats/psummary.awk create mode 100644 contrib/xntpd/scripts/stats/summary.sh create mode 100644 contrib/xntpd/scripts/stats/tdata.awk create mode 100644 contrib/xntpd/scripts/support/README create mode 100644 contrib/xntpd/scripts/support/bin/monl create mode 100644 contrib/xntpd/scripts/support/bin/mvstats create mode 100644 contrib/xntpd/scripts/support/conf/hp300.hp300 create mode 100644 contrib/xntpd/scripts/support/conf/hp700.hp700 create mode 100644 contrib/xntpd/scripts/support/conf/hp700.hp700.faui47 create mode 100644 contrib/xntpd/scripts/support/conf/hp800.hp800 create mode 100644 contrib/xntpd/scripts/support/conf/ntp.conf create mode 100644 contrib/xntpd/scripts/support/conf/ntp.keys create mode 100644 contrib/xntpd/scripts/support/conf/ntp.keys.dumb create mode 100644 contrib/xntpd/scripts/support/conf/sun3.sun3 create mode 100644 contrib/xntpd/scripts/support/conf/sun4.sun4.faui01 create mode 100644 contrib/xntpd/scripts/support/conf/sun4.sun4.faui10 create mode 100644 contrib/xntpd/scripts/support/conf/sun4.sun4.faui45 create mode 100644 contrib/xntpd/scripts/support/conf/sun4.sun4c create mode 100644 contrib/xntpd/scripts/support/conf/sun4.sun4c.Lucifer create mode 100644 contrib/xntpd/scripts/support/conf/sun4.sun4m create mode 100644 contrib/xntpd/scripts/support/conf/sun4.sun4m.faui42 create mode 100644 contrib/xntpd/scripts/support/conf/sun4.sun4m.faui45m create mode 100644 contrib/xntpd/scripts/support/conf/tickconf create mode 100644 contrib/xntpd/scripts/support/etc/cron create mode 100644 contrib/xntpd/scripts/support/etc/crontab create mode 100644 contrib/xntpd/scripts/support/etc/install create mode 100644 contrib/xntpd/scripts/support/etc/rc create mode 100644 contrib/xntpd/scripts/support/etc/setup create mode 100644 contrib/xntpd/util/Makefile.tmpl create mode 100644 contrib/xntpd/util/README create mode 100644 contrib/xntpd/util/byteorder.c create mode 100644 contrib/xntpd/util/jitter.c create mode 100644 contrib/xntpd/util/kern.c create mode 100644 contrib/xntpd/util/longsize.c create mode 100644 contrib/xntpd/util/ntptime.c create mode 100644 contrib/xntpd/util/precision.c create mode 100644 contrib/xntpd/util/testrs6000.c create mode 100644 contrib/xntpd/util/tickadj.c create mode 100644 contrib/xntpd/util/timetrim.c create mode 100644 contrib/xntpd/xntpd/Makefile.tmpl create mode 100644 contrib/xntpd/xntpd/README create mode 100644 contrib/xntpd/xntpd/ntp_config.c create mode 100644 contrib/xntpd/xntpd/ntp_control.c create mode 100644 contrib/xntpd/xntpd/ntp_filegen.c create mode 100644 contrib/xntpd/xntpd/ntp_intres.c create mode 100644 contrib/xntpd/xntpd/ntp_io.c create mode 100644 contrib/xntpd/xntpd/ntp_leap.c create mode 100644 contrib/xntpd/xntpd/ntp_loopfilter.c create mode 100644 contrib/xntpd/xntpd/ntp_monitor.c create mode 100644 contrib/xntpd/xntpd/ntp_peer.c create mode 100644 contrib/xntpd/xntpd/ntp_proto.c create mode 100644 contrib/xntpd/xntpd/ntp_refclock.c create mode 100644 contrib/xntpd/xntpd/ntp_request.c create mode 100644 contrib/xntpd/xntpd/ntp_restrict.c create mode 100644 contrib/xntpd/xntpd/ntp_timer.c create mode 100644 contrib/xntpd/xntpd/ntp_unixclock.c create mode 100644 contrib/xntpd/xntpd/ntp_util.c create mode 100644 contrib/xntpd/xntpd/ntpd.c create mode 100644 contrib/xntpd/xntpd/refclock_as2201.c create mode 100644 contrib/xntpd/xntpd/refclock_chu.c create mode 100644 contrib/xntpd/xntpd/refclock_conf.c create mode 100644 contrib/xntpd/xntpd/refclock_goes.c create mode 100644 contrib/xntpd/xntpd/refclock_irig.c create mode 100644 contrib/xntpd/xntpd/refclock_leitch.c create mode 100644 contrib/xntpd/xntpd/refclock_local.c create mode 100644 contrib/xntpd/xntpd/refclock_msfees.c create mode 100644 contrib/xntpd/xntpd/refclock_mx4200.c create mode 100644 contrib/xntpd/xntpd/refclock_omega.c create mode 100644 contrib/xntpd/xntpd/refclock_parse.c create mode 100644 contrib/xntpd/xntpd/refclock_pst.c create mode 100644 contrib/xntpd/xntpd/refclock_tpro.c create mode 100644 contrib/xntpd/xntpd/refclock_wwvb.c create mode 100644 contrib/xntpd/xntpdc/Makefile.tmpl create mode 100644 contrib/xntpd/xntpdc/README create mode 100644 contrib/xntpd/xntpdc/ntpdc.c create mode 100644 contrib/xntpd/xntpdc/ntpdc.h create mode 100644 contrib/xntpd/xntpdc/ntpdc_ops.c create mode 100644 contrib/xntpd/xntpres/Makefile.tmpl create mode 100644 contrib/xntpd/xntpres/README create mode 100644 contrib/xntpd/xntpres/xntpres.c diff --git a/contrib/xntpd/COPYRIGHT b/contrib/xntpd/COPYRIGHT new file mode 100644 index 0000000000..be272fe180 --- /dev/null +++ b/contrib/xntpd/COPYRIGHT @@ -0,0 +1,56 @@ +/****************************************************************************** + * * + * Copyright (c) David L. Mills 1992, 1993 * + * * + * 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. * + * * + ******************************************************************************/ + +/* + * For all files included in this distribution and not specifically marked + * otherwise, the above copyright information applies. + * + * Authors + * + * Dennis Ferguson (foundation code for NTP + * Version 2 as specified in RFC-1119) + * Lars H. Mathiesen (adaptation of foundation code for + * Version 3 as specified in RFC-1305) + * Louis A. Mamakos (support for md5-based + * authentication) + * Craig Leres (port to 4.4BSD operating system, + * ppsclock, Maganavox GPS clock driver) + * Nick Sayer (SunOS streams modules) + * Frank Kardel + * (PARSE (GENERIC) driver, STREAMS module for PARSE, support scripts, + * reference clock configuration scripts, Makefile cleanup) + * Rainer Pruy (monitoring/trap + * scripts, statistics file handling) + * Glenn Hollinger (GOES clock driver) + * Kenneth Stone (port to HPUX operating system) + * Dave Katz (port to RS/6000 AIX operating system) + * William L. Jones (RS/6000 AIX + * modifications, HPUX modifications) + * John A. Dundas III (Apple A/UX port) + * David L. Mills (Spectractom WWVB, Austron GPS, + * and KSI/Odetics IRIG-B clock drivers; pps support) + * Jeffrey Mogul (ntptrace utility) + * Steve Clift (clift@ml.csiro.au) OMEGA clock driver) + * Mike Iglesias (iglesias@uci.edu) (DEC Alpha changes) + * Mark Andrews (Leitch atomic clock controller) + * George Lindholm (port to SunOS 5.1 operating system) + * Jeff Johnson (massive prototyping overhaul) + * Tom Moore (port to i386 svr4) + * Piete Brooks (MSF clock driver, Trimble PARSE + * support) + * Karl Berry (syslog to file option) + * Torsten Duwe (Linux Port) + */ diff --git a/contrib/xntpd/Config b/contrib/xntpd/Config new file mode 100644 index 0000000000..c15ec053a5 --- /dev/null +++ b/contrib/xntpd/Config @@ -0,0 +1,200 @@ +RANLIB= ranlib +DEFS_LOCAL=-DREFCLOCK +DEFS= -DSYS_FREEBSD -DSYS_386BSD +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lcrypt +RESLIB= +COPTS= -O2 +COMPILER= gcc +LIBDEFS= -DXNTP_LITTLE_ENDIAN +# This is the local configure file (distribution version). +# You must modify it to fit your particular configuration +# and name it Config.local +# The following configuratiions can be auto-generated: +# +# make Config.local.green +# make a Config.local that supports a local clock +# (i.e. allow fallback to use of the CPU's own clock) +# make Config.local.NO.clock +# make a Config.local that supports no clocks +# +# +# NOTE TO GREENHORNS +# +# For plug-'n-play and no radios or other complicated gadgetry, +# use "make Config.local.green" as above. +# +# Following defines can be set in the DEFS_OPT= define: +# +# The flag -DDEBUG includes some debugging code. To use this, include +# the define and start the daemon with one or more -d flags, depending +# on your calibration of pearannoya. The daemon will not detach your +# terminal in this case. Judicious use of grep will reduce the speaker +# volume to bearable levels. +# +# To change the location of the configuration file, use a +# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar. +# +# The -DSYSLOG_FILE defines allows logging messages that are normally +# reported via syslof() in a file. The file name can be configured using +# the configuration line "logfile " in CONFIG_FILE. +# +# There are three serial port system software interfaces, each of +# which is peculiar to one or more Unix versions. Define +# -DHAVE_SYSV_TTYS for basic System V compatibility; define -DSTREAM +# for POSIX compatibility including System V Streams, and +# HAVE_BSD_TTYS for 4.3bsd compatibility. Only one of these three +# should be defined. If none are defined, HAVE_BSD_TTYS is assumed. +# Usually these defines are already set correctly. +# +DEFS_OPT=-DDEBUG + +# +# The DEFS_LOCAL define picks up all flags from DEFS_OPT (do not delete that) +# and one of the following: +# +# The flag -DREFCLOCK causes the basic reference clock support to be +# compiled into the daemon. If you set this you may also want to +# configure the particular clock drivers you want in the CLOCKDEFS= line +# below. This flag affects xntpd only. This define is included by +# default when using the "make makeconfig" script. +# +# The next two sets of defines are meaningful only when radio clock +# drivers or special 1-pps signals are to be used. For systems without +# these features, these delicious complexities can be avoided. Ordinarily, +# the "make makeconfig" script figures out which ones to use, but your +# mileage may vary. +# +# There are three ways to utilize external 1-pps signals. Define +# -DPPS to include just the pps routine, such as used by the DCF77(PARSE) +# clock driver. Define -DPPSCLK to include a serial device driver +# which avoids much of the jitter due to upper level port +# processing. This requires a dedicated serial port and either the +# tty_clock line discipline or tty_clk_streams module, both of +# which are in the ./kernel directory. Define -DPPSCD to include a +# special driver which intercepts carrier-detect transitions +# generated by the pps signal. This requires a nondedicated serial +# port and the ppsclock streams module in the ./kernel directory. +# Only one of these three flags should be defined. +# +# The flag KERNEL_PLL causes code to be compiled for a special feature of +# the kernel that (a) implements the phase-lock loop and (b) provides +# a user interface to learn time, maximum error and estimated error. +# See the file README.kern in the doc directory for further info. +# This code is activated only if the relevant kernel features have +# been configured; it does not affect operation of unmodified kernels. +# To compile it, however, requires a few header files from the +# special distribution. +# +# Note: following line must always start with DEFS_LOCAL= $(DEFS_OPT) +DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DPPSPPS -DKERNEL_PLL + +# +# Radio clock support definitions (these only make sense if -DREFCLOCK +# used), which is normally the case. Note that a configuration can include +# no clocks, more than one type of clock and even multiple clocks of the +# same type. +# +# For most radio clocks operating with serial ports, accuracy can +# be considerably improved through use of the tty_clk line +# discipline or tty_clk_STREAMS streams module found in the +# ./kernel directory. These gizmos capture a timestamp upon +# occurrence of an intercept character and stuff it in the data +# stream for the clock driver to munch. To select this mode, +# postfix the driver name with the string CLK; that is, WWVB +# becomes WWVBCLK. If more than one clock is in use, the CLK +# postfix can be used with any or all of them. +# +# Alternatively, for the best accuracy, use the ppsclock streams +# module in the ./ppsclock directory to steal the carrier-detect +# transition and capture a precision timestamp. At present this +# works only with SunOS 4.1.1 or later. To select this mode, +# postfix the driver name with the string PPS; that is, AS2201 +# becomes AS2201PPS. If more than one clock is in use, the PPS +# postfix should be used with only one of them. If any PPS +# postfix is defined, the -DPPSPPS define should be used on the +# DEFS above. +# +# Define -DLOCAL_CLOCK for a local pseudo-clock to masquerade as a +# reference clock for those subnets without access to the real thing. +# Works in all systems and requires no hardware support. This is defined +# by default when using the "make makeconfig" script and greenhorn +# configuraiton. +# +# Define -DPST for a PST/Traconex 1020 WWV/H receiver. The driver +# supports both the CLK and PPS modes. It should work in all systems +# with a serial port. +# +# Define -DWWVB for a Spectracom 8170 or Netclock/2 WWVB receiver. It +# should work in all systems with a serial port. The driver supports +# both the CLK and PPS modes if the requisite kernel support is installed. +# +# Define -DCHU for a special CHU receiver using an ordinary shortwave +# radio. This requires the chu_clk line discipline or chu_clk_STREAMS +# module in the ./kernel directory. At present, this driver works only +# on SunOS4.1.x; operation in other systems has not been confirmed. +# Construction details for a suitable modem can be found in the ./gadget +# directory. The driver supports # neither the CLK nor PPS modes. +# +# Define -DPARSE for a DCF77/GPS(GENERIC) receiver. For best performance +# this requires a special parsestreams STREAMS (SunOS 4.x) module in the +# ./parse directory. Define -DPARSEPPS for PPS support via the +# DCF77/GPS (GENERIC) receiver; also, define -DPPS in the DEFS above. +# Define: -DCLOCK_MEINBERG for Meinberg clocks +# -DCLOCK_SCHMID for Schmid receivers +# -DCLOCK_DCF7000 for ELV DCF7000 +# -DCLOCK_RAWDCF for simple receivers (100/200ms pulses on Rx) +# -DCLOCK_TRIMSV6 for Trimble SV6 GPS receiver +# +# Define -DMX4200PPS for a Magnavox 4200 GPS receiver. At present, this +# driver works only on SunOS4.1.x with CPU serial ports only. The PPS +# mode is required. +# +# Define -DAS2201 for an Austron 2200A or 2201A GPS receiver. It should +# work in all systems with a serial port. The driver does not support the +# CLK mode, but does support the PPS mode. If the radio is connected to +# more than one machine, the PPS mode is required. +# +# Define -DGOES for a Kinemetrics/TrueTime 468-DC GOES receiver. This +# driver is known to work with some other TrueTime products as well, +# including the GPS-DC GPS receiver. It should work in all systems with +# a serial port. The driver does not support the CLK mode, but does +# support the PPS mode. +# +# Define -DOMEGA for a Kinemetrics/TrueTime OM-DC OMEGA receiver. It +# should work in all systems with a serial port. The driver does not +# support the CLK mode, but does support the PPS mode. +# +# Define -DTPRO for a KSI/Odetics TPRO-S IRIG-B timecode reader. This +# requires the SunOS interface driver available from KSI. The driver +# supports neither the CLK nor PPS modes. +# +# Define -DLEITCH for a Leitch CSD 5300 Master Clock System Driver for +# the HP 5061B Cesium Clock. It should work in all systems with a serial +# port. The driver does not support the CLK mode, but does support the +# PPS mode. +# +# Define -DMSFEESPPS for an EES M201 MSF receiver. It currently only works +# under SunOS 4.x with the PPSCD (ppsclock) STREAMS module, but the RCS +# files on cl.cam.ac.uk still has support for CLK and CBREAK modes. +# +# Define -DIRIG for a IRIG-B timecode timecode using the audio codec of +# the Sun SPARCstations. This requires a modified BSD audio driver and +# exclusive access to the audio port. A memo describing how it works and +# how to install the driver is in the README.irig file in the ./doc +# directory. +# +# Note: The following defines result in compilation of all the above radio +# clocks. This works on a Sun 4.1.x system which has tty_clk, chu_clk and +# ppsclock STREAMS modules installed. If the trailing CLK and PPS suffixes +# are removed and the IRIG, PARSE* and CLOCK* deleted, all of the rest compile +# under Ultrix 4.2a/3. If the MX4200 is removed, all the rest compile on a DEC +# OSF/1 Alpha. +# +CLOCKDEFS= -DLOCAL_CLOCK -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH + +# +# Directory into which binaries should be installed (default /usr/local) +# +BINDIR= /usr/local/bin diff --git a/contrib/xntpd/Config.local b/contrib/xntpd/Config.local new file mode 100644 index 0000000000..4c5095c164 --- /dev/null +++ b/contrib/xntpd/Config.local @@ -0,0 +1,190 @@ +# This is the local configure file (distribution version). +# You must modify it to fit your particular configuration +# and name it Config.local +# The following configuratiions can be auto-generated: +# +# make Config.local.green +# make a Config.local that supports a local clock +# (i.e. allow fallback to use of the CPU's own clock) +# make Config.local.NO.clock +# make a Config.local that supports no clocks +# +# +# NOTE TO GREENHORNS +# +# For plug-'n-play and no radios or other complicated gadgetry, +# use "make Config.local.green" as above. +# +# Following defines can be set in the DEFS_OPT= define: +# +# The flag -DDEBUG includes some debugging code. To use this, include +# the define and start the daemon with one or more -d flags, depending +# on your calibration of pearannoya. The daemon will not detach your +# terminal in this case. Judicious use of grep will reduce the speaker +# volume to bearable levels. +# +# To change the location of the configuration file, use a +# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar. +# +# The -DSYSLOG_FILE defines allows logging messages that are normally +# reported via syslof() in a file. The file name can be configured using +# the configuration line "logfile " in CONFIG_FILE. +# +# There are three serial port system software interfaces, each of +# which is peculiar to one or more Unix versions. Define +# -DHAVE_SYSV_TTYS for basic System V compatibility; define -DSTREAM +# for POSIX compatibility including System V Streams, and +# HAVE_BSD_TTYS for 4.3bsd compatibility. Only one of these three +# should be defined. If none are defined, HAVE_BSD_TTYS is assumed. +# Usually these defines are already set correctly. +# +DEFS_OPT=-DDEBUG + +# +# The DEFS_LOCAL define picks up all flags from DEFS_OPT (do not delete that) +# and one of the following: +# +# The flag -DREFCLOCK causes the basic reference clock support to be +# compiled into the daemon. If you set this you may also want to +# configure the particular clock drivers you want in the CLOCKDEFS= line +# below. This flag affects xntpd only. This define is included by +# default when using the "make makeconfig" script. +# +# The next two sets of defines are meaningful only when radio clock +# drivers or special 1-pps signals are to be used. For systems without +# these features, these delicious complexities can be avoided. Ordinarily, +# the "make makeconfig" script figures out which ones to use, but your +# mileage may vary. +# +# There are three ways to utilize external 1-pps signals. Define +# -DPPS to include just the pps routine, such as used by the DCF77(PARSE) +# clock driver. Define -DPPSCLK to include a serial device driver +# which avoids much of the jitter due to upper level port +# processing. This requires a dedicated serial port and either the +# tty_clock line discipline or tty_clk_streams module, both of +# which are in the ./kernel directory. Define -DPPSCD to include a +# special driver which intercepts carrier-detect transitions +# generated by the pps signal. This requires a nondedicated serial +# port and the ppsclock streams module in the ./kernel directory. +# Only one of these three flags should be defined. +# +# The flag KERNEL_PLL causes code to be compiled for a special feature of +# the kernel that (a) implements the phase-lock loop and (b) provides +# a user interface to learn time, maximum error and estimated error. +# See the file README.kern in the doc directory for further info. +# This code is activated only if the relevant kernel features have +# been configured; it does not affect operation of unmodified kernels. +# To compile it, however, requires a few header files from the +# special distribution. +# +# Note: following line must always start with DEFS_LOCAL= $(DEFS_OPT) +DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DPPSPPS -DKERNEL_PLL + +# +# Radio clock support definitions (these only make sense if -DREFCLOCK +# used), which is normally the case. Note that a configuration can include +# no clocks, more than one type of clock and even multiple clocks of the +# same type. +# +# For most radio clocks operating with serial ports, accuracy can +# be considerably improved through use of the tty_clk line +# discipline or tty_clk_STREAMS streams module found in the +# ./kernel directory. These gizmos capture a timestamp upon +# occurrence of an intercept character and stuff it in the data +# stream for the clock driver to munch. To select this mode, +# postfix the driver name with the string CLK; that is, WWVB +# becomes WWVBCLK. If more than one clock is in use, the CLK +# postfix can be used with any or all of them. +# +# Alternatively, for the best accuracy, use the ppsclock streams +# module in the ./ppsclock directory to steal the carrier-detect +# transition and capture a precision timestamp. At present this +# works only with SunOS 4.1.1 or later. To select this mode, +# postfix the driver name with the string PPS; that is, AS2201 +# becomes AS2201PPS. If more than one clock is in use, the PPS +# postfix should be used with only one of them. If any PPS +# postfix is defined, the -DPPSPPS define should be used on the +# DEFS above. +# +# Define -DLOCAL_CLOCK for a local pseudo-clock to masquerade as a +# reference clock for those subnets without access to the real thing. +# Works in all systems and requires no hardware support. This is defined +# by default when using the "make makeconfig" script and greenhorn +# configuraiton. +# +# Define -DPST for a PST/Traconex 1020 WWV/H receiver. The driver +# supports both the CLK and PPS modes. It should work in all systems +# with a serial port. +# +# Define -DWWVB for a Spectracom 8170 or Netclock/2 WWVB receiver. It +# should work in all systems with a serial port. The driver supports +# both the CLK and PPS modes if the requisite kernel support is installed. +# +# Define -DCHU for a special CHU receiver using an ordinary shortwave +# radio. This requires the chu_clk line discipline or chu_clk_STREAMS +# module in the ./kernel directory. At present, this driver works only +# on SunOS4.1.x; operation in other systems has not been confirmed. +# Construction details for a suitable modem can be found in the ./gadget +# directory. The driver supports # neither the CLK nor PPS modes. +# +# Define -DPARSE for a DCF77/GPS(GENERIC) receiver. For best performance +# this requires a special parsestreams STREAMS (SunOS 4.x) module in the +# ./parse directory. Define -DPARSEPPS for PPS support via the +# DCF77/GPS (GENERIC) receiver; also, define -DPPS in the DEFS above. +# Define: -DCLOCK_MEINBERG for Meinberg clocks +# -DCLOCK_SCHMID for Schmid receivers +# -DCLOCK_DCF7000 for ELV DCF7000 +# -DCLOCK_RAWDCF for simple receivers (100/200ms pulses on Rx) +# -DCLOCK_TRIMSV6 for Trimble SV6 GPS receiver +# +# Define -DMX4200PPS for a Magnavox 4200 GPS receiver. At present, this +# driver works only on SunOS4.1.x with CPU serial ports only. The PPS +# mode is required. +# +# Define -DAS2201 for an Austron 2200A or 2201A GPS receiver. It should +# work in all systems with a serial port. The driver does not support the +# CLK mode, but does support the PPS mode. If the radio is connected to +# more than one machine, the PPS mode is required. +# +# Define -DGOES for a Kinemetrics/TrueTime 468-DC GOES receiver. This +# driver is known to work with some other TrueTime products as well, +# including the GPS-DC GPS receiver. It should work in all systems with +# a serial port. The driver does not support the CLK mode, but does +# support the PPS mode. +# +# Define -DOMEGA for a Kinemetrics/TrueTime OM-DC OMEGA receiver. It +# should work in all systems with a serial port. The driver does not +# support the CLK mode, but does support the PPS mode. +# +# Define -DTPRO for a KSI/Odetics TPRO-S IRIG-B timecode reader. This +# requires the SunOS interface driver available from KSI. The driver +# supports neither the CLK nor PPS modes. +# +# Define -DLEITCH for a Leitch CSD 5300 Master Clock System Driver for +# the HP 5061B Cesium Clock. It should work in all systems with a serial +# port. The driver does not support the CLK mode, but does support the +# PPS mode. +# +# Define -DMSFEESPPS for an EES M201 MSF receiver. It currently only works +# under SunOS 4.x with the PPSCD (ppsclock) STREAMS module, but the RCS +# files on cl.cam.ac.uk still has support for CLK and CBREAK modes. +# +# Define -DIRIG for a IRIG-B timecode timecode using the audio codec of +# the Sun SPARCstations. This requires a modified BSD audio driver and +# exclusive access to the audio port. A memo describing how it works and +# how to install the driver is in the README.irig file in the ./doc +# directory. +# +# Note: The following defines result in compilation of all the above radio +# clocks. This works on a Sun 4.1.x system which has tty_clk, chu_clk and +# ppsclock STREAMS modules installed. If the trailing CLK and PPS suffixes +# are removed and the IRIG, PARSE* and CLOCK* deleted, all of the rest compile +# under Ultrix 4.2a/3. If the MX4200 is removed, all the rest compile on a DEC +# OSF/1 Alpha. +# +CLOCKDEFS= -DLOCAL_CLOCK -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH + +# +# Directory into which binaries should be installed (default /usr/local) +# +BINDIR= /usr/local/bin diff --git a/contrib/xntpd/Config.local.dist b/contrib/xntpd/Config.local.dist new file mode 100644 index 0000000000..4c5c246727 --- /dev/null +++ b/contrib/xntpd/Config.local.dist @@ -0,0 +1,190 @@ +# This is the local configure file (distribution version). +# You must modify it to fit your particular configuration +# and name it Config.local +# The following configuratiions can be auto-generated: +# +# make Config.local.green +# make a Config.local that supports a local clock +# (i.e. allow fallback to use of the CPU's own clock) +# make Config.local.NO.clock +# make a Config.local that supports no clocks +# +# +# NOTE TO GREENHORNS +# +# For plug-'n-play and no radios or other complicated gadgetry, +# use "make Config.local.green" as above. +# +# Following defines can be set in the DEFS_OPT= define: +# +# The flag -DDEBUG includes some debugging code. To use this, include +# the define and start the daemon with one or more -d flags, depending +# on your calibration of pearannoya. The daemon will not detach your +# terminal in this case. Judicious use of grep will reduce the speaker +# volume to bearable levels. +# +# To change the location of the configuration file, use a +# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar. +# +# The -DSYSLOG_FILE defines allows logging messages that are normally +# reported via syslof() in a file. The file name can be configured using +# the configuration line "logfile " in CONFIG_FILE. +# +# There are three serial port system software interfaces, each of +# which is peculiar to one or more Unix versions. Define +# -DHAVE_SYSV_TTYS for basic System V compatibility; define -DSTREAM +# for POSIX compatibility including System V Streams, and +# HAVE_BSD_TTYS for 4.3bsd compatibility. Only one of these three +# should be defined. If none are defined, HAVE_BSD_TTYS is assumed. +# Usually these defines are already set correctly. +# +DEFS_OPT=-DDEBUG + +# +# The DEFS_LOCAL define picks up all flags from DEFS_OPT (do not delete that) +# and one of the following: +# +# The flag -DREFCLOCK causes the basic reference clock support to be +# compiled into the daemon. If you set this you may also want to +# configure the particular clock drivers you want in the CLOCKDEFS= line +# below. This flag affects xntpd only. This define is included by +# default when using the "make makeconfig" script. +# +# The next two sets of defines are meaningful only when radio clock +# drivers or special 1-pps signals are to be used. For systems without +# these features, these delicious complexities can be avoided. Ordinarily, +# the "make makeconfig" script figures out which ones to use, but your +# mileage may vary. +# +# There are three ways to utilize external 1-pps signals. Define +# -DPPS to include just the pps routine, such as used by the DCF77(PARSE) +# clock driver. Define -DPPSCLK to include a serial device driver +# which avoids much of the jitter due to upper level port +# processing. This requires a dedicated serial port and either the +# tty_clock line discipline or tty_clk_streams module, both of +# which are in the ./kernel directory. Define -DPPSCD to include a +# special driver which intercepts carrier-detect transitions +# generated by the pps signal. This requires a nondedicated serial +# port and the ppsclock streams module in the ./kernel directory. +# Only one of these three flags should be defined. +# +# The flag KERNEL_PLL causes code to be compiled for a special feature of +# the kernel that (a) implements the phase-lock loop and (b) provides +# a user interface to learn time, maximum error and estimated error. +# See the file README.kern in the doc directory for further info. +# This code is activated only if the relevant kernel features have +# been configured; it does not affect operation of unmodified kernels. +# To compile it, however, requires a few header files from the +# special distribution. +# +# Note: following line must always start with DEFS_LOCAL= $(DEFS_OPT) +DEFS_LOCAL= $(DEFS_OPT) #GREEN -DREFCLOCK #TEST -DPPSPPS -DKERNEL_PLL + +# +# Radio clock support definitions (these only make sense if -DREFCLOCK +# used), which is normally the case. Note that a configuration can include +# no clocks, more than one type of clock and even multiple clocks of the +# same type. +# +# For most radio clocks operating with serial ports, accuracy can +# be considerably improved through use of the tty_clk line +# discipline or tty_clk_STREAMS streams module found in the +# ./kernel directory. These gizmos capture a timestamp upon +# occurrence of an intercept character and stuff it in the data +# stream for the clock driver to munch. To select this mode, +# postfix the driver name with the string CLK; that is, WWVB +# becomes WWVBCLK. If more than one clock is in use, the CLK +# postfix can be used with any or all of them. +# +# Alternatively, for the best accuracy, use the ppsclock streams +# module in the ./ppsclock directory to steal the carrier-detect +# transition and capture a precision timestamp. At present this +# works only with SunOS 4.1.1 or later. To select this mode, +# postfix the driver name with the string PPS; that is, AS2201 +# becomes AS2201PPS. If more than one clock is in use, the PPS +# postfix should be used with only one of them. If any PPS +# postfix is defined, the -DPPSPPS define should be used on the +# DEFS above. +# +# Define -DLOCAL_CLOCK for a local pseudo-clock to masquerade as a +# reference clock for those subnets without access to the real thing. +# Works in all systems and requires no hardware support. This is defined +# by default when using the "make makeconfig" script and greenhorn +# configuraiton. +# +# Define -DPST for a PST/Traconex 1020 WWV/H receiver. The driver +# supports both the CLK and PPS modes. It should work in all systems +# with a serial port. +# +# Define -DWWVB for a Spectracom 8170 or Netclock/2 WWVB receiver. It +# should work in all systems with a serial port. The driver supports +# both the CLK and PPS modes if the requisite kernel support is installed. +# +# Define -DCHU for a special CHU receiver using an ordinary shortwave +# radio. This requires the chu_clk line discipline or chu_clk_STREAMS +# module in the ./kernel directory. At present, this driver works only +# on SunOS4.1.x; operation in other systems has not been confirmed. +# Construction details for a suitable modem can be found in the ./gadget +# directory. The driver supports # neither the CLK nor PPS modes. +# +# Define -DPARSE for a DCF77/GPS(GENERIC) receiver. For best performance +# this requires a special parsestreams STREAMS (SunOS 4.x) module in the +# ./parse directory. Define -DPARSEPPS for PPS support via the +# DCF77/GPS (GENERIC) receiver; also, define -DPPS in the DEFS above. +# Define: -DCLOCK_MEINBERG for Meinberg clocks +# -DCLOCK_SCHMID for Schmid receivers +# -DCLOCK_DCF7000 for ELV DCF7000 +# -DCLOCK_RAWDCF for simple receivers (100/200ms pulses on Rx) +# -DCLOCK_TRIMSV6 for Trimble SV6 GPS receiver +# +# Define -DMX4200PPS for a Magnavox 4200 GPS receiver. At present, this +# driver works only on SunOS4.1.x with CPU serial ports only. The PPS +# mode is required. +# +# Define -DAS2201 for an Austron 2200A or 2201A GPS receiver. It should +# work in all systems with a serial port. The driver does not support the +# CLK mode, but does support the PPS mode. If the radio is connected to +# more than one machine, the PPS mode is required. +# +# Define -DGOES for a Kinemetrics/TrueTime 468-DC GOES receiver. This +# driver is known to work with some other TrueTime products as well, +# including the GPS-DC GPS receiver. It should work in all systems with +# a serial port. The driver does not support the CLK mode, but does +# support the PPS mode. +# +# Define -DOMEGA for a Kinemetrics/TrueTime OM-DC OMEGA receiver. It +# should work in all systems with a serial port. The driver does not +# support the CLK mode, but does support the PPS mode. +# +# Define -DTPRO for a KSI/Odetics TPRO-S IRIG-B timecode reader. This +# requires the SunOS interface driver available from KSI. The driver +# supports neither the CLK nor PPS modes. +# +# Define -DLEITCH for a Leitch CSD 5300 Master Clock System Driver for +# the HP 5061B Cesium Clock. It should work in all systems with a serial +# port. The driver does not support the CLK mode, but does support the +# PPS mode. +# +# Define -DMSFEESPPS for an EES M201 MSF receiver. It currently only works +# under SunOS 4.x with the PPSCD (ppsclock) STREAMS module, but the RCS +# files on cl.cam.ac.uk still has support for CLK and CBREAK modes. +# +# Define -DIRIG for a IRIG-B timecode timecode using the audio codec of +# the Sun SPARCstations. This requires a modified BSD audio driver and +# exclusive access to the audio port. A memo describing how it works and +# how to install the driver is in the README.irig file in the ./doc +# directory. +# +# Note: The following defines result in compilation of all the above radio +# clocks. This works on a Sun 4.1.x system which has tty_clk, chu_clk and +# ppsclock STREAMS modules installed. If the trailing CLK and PPS suffixes +# are removed and the IRIG, PARSE* and CLOCK* deleted, all of the rest compile +# under Ultrix 4.2a/3. If the MX4200 is removed, all the rest compile on a DEC +# OSF/1 Alpha. +# +CLOCKDEFS= #GREEN -DLOCAL_CLOCK #TEST -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPST -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH -DPARSE -DPARSEPPS -DCLOCK_MEINBERG -DCLOCK_RAWDCF -DCLOCK_SCHMID -DCLOCK_DCF7000 -DCLOCK_TRIMSV6 + +# +# Directory into which binaries should be installed (default /usr/local) +# +BINDIR= /usr/local/bin diff --git a/contrib/xntpd/Config.sed b/contrib/xntpd/Config.sed new file mode 100644 index 0000000000..fe5a9b7927 --- /dev/null +++ b/contrib/xntpd/Config.sed @@ -0,0 +1,14 @@ +s~^RANLIB=.*~RANLIB= ranlib~ +s~^DEFS_LOCAL=.*~DEFS_LOCAL=-DREFCLOCK~ +s~^DEFS=.*~DEFS= -DSYS_FREEBSD -DSYS_386BSD~ +s~^AUTHDEFS=.*~AUTHDEFS= -DDES -DMD5~ +s~^CLOCKDEFS=.*~CLOCKDEFS= -DLOCAL_CLOCK~ +s~^DAEMONLIBS=.*~DAEMONLIBS= -lcrypt~ +s~^RESLIB=.*~RESLIB=~ +s~^COPTS=.*~COPTS= -O2~ +s~^COMPILER=.*~COMPILER= gcc~ +s~^LIBDEFS=.*~LIBDEFS= -DXNTP_LITTLE_ENDIAN~ +s~^DEFS_OPT=.*~DEFS_OPT=-DDEBUG~ +s~^DEFS_LOCAL=.*~DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DPPSPPS -DKERNEL_PLL~ +s~^CLOCKDEFS=.*~CLOCKDEFS= -DLOCAL_CLOCK -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH~ +s~^BINDIR=.*~BINDIR= /usr/local/bin~ diff --git a/contrib/xntpd/Makefile b/contrib/xntpd/Makefile new file mode 100644 index 0000000000..30e59bbb5c --- /dev/null +++ b/contrib/xntpd/Makefile @@ -0,0 +1,359 @@ +# WARNING: +# CONTENTS UNDER PRESSURE. +# HIGHLY FLAMMABLE. +# RISK OF SHOCK. +# DO NOT ATTEMPT TO OPEN COVER. +# NO USER SERVICEABLE PARTS INSIDE. +# REFER SERVICING TO QUALIFIED PERSONNEL. +# +# The vendor hits you... +# You try to hit the vendor... +# You die. +# +# Unfortunately the above is no fun... +# +# During testing/porting we have found a long list +# of "make" and "sh" and "awk" features in different implementations. +# Some goodies (make good horror stories for your kids 8-(): +# gmake 3.62 +# non standard target construction +# +# pmake (e. g. NetBSD on MAC, possible other BNR2+pmake systems) +# skips '' (empty string positional) args to sh +# (this leads to following stupid constructions +# sh -c "./scripts/makeconfig.sh '$(OS)' '$(COMP)'") +# +# Following Makefile construction fails for no +# apparent reason (at least to me) +# doit: +# $(MAKE) MAKE=\"$(MAKE)\" all +# +# all: +# @echo all done. +# +# for the "make MAKE=make" call not for "make" or +# "make -e MAKE=make". Use the last form if you suffer +# from that kind of make problems. (Easily detected +# by failure to build with the message: +# "don't know how to make make". +# +# sh (Ultrix 4.2 MIPS) +# shell broken (reversed pipe construction "false | true" +# returns false - major bummer) +# +# awk (EP/IX 2.?) +# unable to do regexp matches +# (aka awk '/..*/ { print; }' fails on match) +# +# Usually the vendor should fix these bugs in vital utilities. +# We try to circumvent these bugs in a hopefully portable way. +# If you can reproduce these bugs on your system please bug your +# vendor to fix them. We are not trying anything fancy in here and +# we are shocked that even the most common tools fail so miserably. +# By the time you get this code the above utilities may already +# have been fixed. Hopefully one day we do not have to cope with +# this kind of broken utilities. +# +# Sorry about the situation, +# Frank Kardel +# +SHELL=/bin/sh +CONF = Config +CONFL = $(CONF).local +CONFLD= $(CONFL).dist +TARGETS = xntpd/xntpd xntpdc/xntpdc ntpq/ntpq ntpdate/ntpdate \ + ntptrace/ntptrace xntpres/xntpres authstuff/authspeed util/tickadj +OPTTARG = adjtime/adjtimed util/ntptime util/precision +REFCONF= +COMPRESSOR=compress +# Base distribution name (will be extended by .tar.) +DISTNAME=xntp- +MAKE= make + +all: version $(TARGETS) kernel_modules + +$(TARGETS): VERSION $(CONF) + +version: + @echo '### Building XNTP:' "`egrep '^.*=.*$$' VERSION | tr '\012' ';'`" + +makeconfig: + sh -c "./scripts/makeconfig.sh '$(OS)' '$(COMP)'" + +$(CONFL).NO.clock: + @echo '###' creating $(CONFL) for absolutely '*NO*' clocks '*AT ALL*' + rm -f $(CONFL)-t $(CONFL) + cat < $(CONFLD) > $(CONFL)-t && mv $(CONFL)-t $(CONFL) + +$(CONFL).green: + @echo '###' creating $(CONFL) for greenhorns '(local refclock only)' + rm -f $(CONFL)-t $(CONFL) + sed 's/#GREEN//' < $(CONFLD) > $(CONFL)-t && mv $(CONFL)-t $(CONFL) + +$(CONFL): + @echo '' + @echo '### creating a $(CONFL) file as none existed.' + @echo '### Use "make refconf" if you have a radio clock' + @echo '' + @$(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" $(CONFL).green + +$(CONF): $(CONFL) + @echo + @echo '###' creating new configuration + @sh -c "./scripts/makeconfig.sh '$(OS)' '$(COMP)'" + +refconf: $(CONF) + -@sh refclocks/rconfig '$(REFCONF)' + @sh -c "./scripts/makeconfig.sh '$(OS)' '$(COMP)'" + +kernel_modules: kernel/Makefile + @cd kernel && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +xntpd/xntpd: lib/libntp.a parse/libparse.a xntpd/Makefile FRC + @echo + @echo '###' creating NTP daemon + @cd xntpd && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +xntpdc/xntpdc: lib/libntp.a xntpdc/Makefile FRC + @echo + @echo '###' creating XNTPDC utility + @cd xntpdc && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +ntpq/ntpq: lib/libntp.a ntpq/Makefile FRC + @echo + @echo '###' creating NTPQ utility + @cd ntpq && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +ntptrace/ntptrace: lib/libntp.a ntptrace/Makefile FRC + @echo + @echo '###' creating NTPTRACE utility + @cd ntptrace && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +ntpdate/ntpdate: lib/libntp.a ntpdate/Makefile FRC + @echo + @echo '###' creating NTPDATE utility + @cd ntpdate && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +authstuff/authspeed: lib/libntp.a authstuff/Makefile FRC + @echo + @echo '###' creating AUTH utilities + @cd authstuff && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +xntpres/xntpres: lib/libntp.a xntpres/Makefile FRC + @echo + @echo '###' creating XNTPRES utility + @cd xntpres && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +util/tickadj: util/Makefile FRC + @echo + @echo '###' creating TICKADJ utility + @cd util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +lib/libntp.a: lib/*.c lib/Makefile adjtime/Makefile + @echo + @echo '###' creating NTP library + @cd lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +parse/libparse.a: parse/*.c parse/Makefile parse/util/Makefile lib/libntp.a + @echo + @echo '### creating PARSE subsystem (if configured)' + @cd parse && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +FRC: + +savebin: + @test -d bin || mkdir bin + @echo + @echo '### saving $(TARGETS) $(OPTTARG) in bin' + -@for f in $(TARGETS) $(OPTTARG); \ + do test -f $$f && mv $$f bin/. && echo "### saved $$f in bin/"; \ + done; \ + true + +neatneat: + @echo '###' cleaning derived config files + -@rm -f $(CONF).sed $(CONF) + +neat: + @echo '###' cleaning top level left overs + -@rm -f eddep makedep Makefile.bak make.log make.out + +distclean: neatneat clean + @echo '###' cleaning configuration dependent Makefiles + -@find . -name Makefile -print | \ + while read X; do \ + if [ -f "$$X.tmpl" ]; then \ + rm -f "$$X"; \ + else \ + :; \ + fi \ + done + @echo '###' cleaning old scratch files + -@find . \( -name '*.rej' -o -name '*.orig' -o -name '*~' -o \ + -name '.version' -o -name '#*' -o -name '.#*' -o \ + -name core -o -name version.c \) -print | xargs rm -f + @echo '###' cleaning saved binaries + -@rm -fr bin + +clean: neat + @echo '###' cleaning adjtime + @cd adjtime && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" -f Makefile.tmpl $@ + @echo '###' cleaning authstuff + @cd authstuff && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + @echo '###' cleaning clockstuff + @cd clockstuff && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + @echo '###' cleaning lib + @cd lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + @echo '###' cleaning ntpdate + @cd ntpdate && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + @echo '###' cleaning ntpq + @cd ntpq && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + @echo '###' cleaning ntptrace + @cd ntptrace && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + @echo '###' cleaning util + @cd util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + @echo '###' cleaning xntpd + @cd xntpd && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + @echo '###' cleaning xntpdc + @cd xntpdc && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + @echo '###' cleaning xntpres + @cd xntpres && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + @echo '###' cleaning parse + @cd parse && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@ + +install: all + @echo installing from xntpd + @cd xntpd && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install + @echo installing from xntpdc + @cd xntpdc && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install + @echo installing from ntpq + @cd ntpq && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install + @echo installing from ntptrace + @cd ntptrace && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install + @echo installing from ntpdate + @cd ntpdate && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install + @echo installing from xntpres + @cd xntpres && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install + @echo installing from util + @cd util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install + @echo installing from parse + @cd parse && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install + +dist: + @echo '### building distribution ...' + @$(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" distclean + @DISTVERSION="`sed -e 's/^[ ]*[Vv][Ee][Rr][Ss][Ii][Oo][Nn][ ]*=\(.*\)$$/\1/' VERSION | \ + sed -e 's/[^0-9a-zA-Z\.]/_/g; s/__*/_/g; s/_*$$//'`" && \ + echo "### creating distribution file $(DISTNAME)$${DISTVERSION}.tar" && \ + rm -f $(DISTNAME)$${DISTVERSION}.tar $(DISTNAME)$${DISTVERSION}.tar.* && \ + tar cfv $(DISTNAME)$${DISTVERSION}.tar `ls | egrep -v "^$(CONFL)$$|^$(DISTNAME)$${DISTVERSION}.tar$$"` && \ + $(COMPRESSOR) -v $(DISTNAME)$${DISTVERSION}.tar + +$(CONF).sed: $(CONF) Makefile + @sed -n -e 's:^\([^ ]*\)=[ ]*\(.*\):s~^\1=.*~&~:p' < $(CONF) > $@ + +depend: + find . -name Makefile.tmpl -print > eddep + echo >> makedep + sed -e 's:^\./::' -e '/^Makefile/d' \ + -e h \ + -e 's/^\(.*\)\.tmpl$$/\1: \1.tmpl $${CONF}.sed/' -e p -e g \ + -e 's/.*/ @echo/' -e p -e g \ + -e 's:^\(.*\)/Makefile\.tmpl$$: @echo '"'###'"' updating Makefile in \1:' -e p -e g \ + -e 's/.*/ @sed -f $${CONF}.sed < $$@.tmpl > $$@/' -e p -e g \ + -e 's:^\(.*\)/Makefile\.tmpl$$: @echo '"'###'"' cleaning in \1:' -e p -e g \ + -e 's:^\(.*\)/Makefile\.tmpl$$: @cd \1 \&\& $$(MAKE) $$(MFLAGS) MFLAGS="$$(MFLAGS)" -f Makefile.tmpl MAKE="$$(MAKE)" clean:p' \ + < eddep >> makedep + echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + cp Makefile Makefile.bak + /bin/ed - Makefile < eddep + rm eddep makedep + +# DO NOT DELETE THIS LINE -- It is used by 'make depend' to update this file + +adjtime/Makefile: adjtime/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in adjtime + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in adjtime + @cd adjtime && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +authstuff/Makefile: authstuff/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in authstuff + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in authstuff + @cd authstuff && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +clockstuff/Makefile: clockstuff/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in clockstuff + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in clockstuff + @cd clockstuff && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +kernel/Makefile: kernel/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in kernel + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in kernel + @cd kernel && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +lib/Makefile: lib/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in lib + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in lib + @cd lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +ntpdate/Makefile: ntpdate/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in ntpdate + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in ntpdate + @cd ntpdate && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +ntpq/Makefile: ntpq/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in ntpq + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in ntpq + @cd ntpq && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +ntptrace/Makefile: ntptrace/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in ntptrace + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in ntptrace + @cd ntptrace && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +util/Makefile: util/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in util + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in util + @cd util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +xntpd/Makefile: xntpd/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in xntpd + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in xntpd + @cd xntpd && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +xntpdc/Makefile: xntpdc/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in xntpdc + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in xntpdc + @cd xntpdc && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +xntpres/Makefile: xntpres/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in xntpres + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in xntpres + @cd xntpres && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +parse/util/Makefile: parse/util/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in parse/util + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in parse/util + @cd parse/util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean +parse/Makefile: parse/Makefile.tmpl ${CONF}.sed + @echo + @echo '###' updating Makefile in parse + @sed -f ${CONF}.sed < $@.tmpl > $@ + @echo '###' cleaning in parse + @cd parse && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean diff --git a/contrib/xntpd/PORTING b/contrib/xntpd/PORTING new file mode 100644 index 0000000000..7f236424ec --- /dev/null +++ b/contrib/xntpd/PORTING @@ -0,0 +1,37 @@ +These are the rules so that older bsd systems and the POSIX standard +system can coexist togather. + + 1) If you use select then include "ntp_select.h" + select is not standard, since it is very system depenedent as to where + select is defined. The logic to include the right system dependent + include file is in "ntp_select.h". + 2) Always use POSIX defintion of strings. Inlcude "ntp_string.h" instaed + of . + 3) Always include "ntp_malloc.h" if you use malloc. + 4) Always include "ntp_io.h" instead of or to + get O_* flags. + 5) Always include "ntp_if.h" instead of . + 6) Always include "ntp_stdlib.h" instead of . + 7) Always define a system identifier for any new system added to the + machines directory. The identifier should always start with SYS_! + 8) Define any special defines needed for a system in + ./include/ntp_machine.h based on system identifier. This file is + included by the "ntp_types.h" file and should always be placed + first after the <> defines. + 9) Define any special library prototypes left over from the system + library and include files in the "l_stdlib.h" file. This file is + included by the "ntp_stdlib.h" file and should ordinarily be + placed last in the includes list. + 10) Don't define a include file by the same name as a system include file. + + +"l_stdlib.h" can contain any extra definitions that are needed so that +gcc will shut up. They should be controlled by a system identifier and +there should be a seperate section for each system. Really this will +make it easier to maintain. + +See include/ntp_machines.h for the verious compile time options. + +Good luck. + +Bill Jones, with amendments by Dave Mills diff --git a/contrib/xntpd/README b/contrib/xntpd/README new file mode 100644 index 0000000000..76414a2a52 --- /dev/null +++ b/contrib/xntpd/README @@ -0,0 +1,163 @@ +The xntp3 Distribution + +This directory and its subdirectories contain the Network Time Protocol +Version 3 (NTP) distribution for Unix systems. It contains source code +for the daemon, together with related auxiliary programs, documentation +and strange stuff. You are welcome to the lot, with due consideration of +the COPYRIGHT files stashed in the distributions. You are also invited +to contribute bugfixes and drivers for new and exotic radios, telephones +and sundials. This distribution is normally available by anonymous ftp +as the compressed tar archive xntp-.tar.Z in the pub/ntp directory +on louie.udel.edu. + +The base directory contains the distributions and related stuff. The files +marked with a "*" are not distributed, but generated. Most of +the subdirectories contain README files describing their contents. The +base directory ./ includes: + +COPYRIGHT file specifying copyright conditions, together with a + list of major authors and electric addresses + +Config * configuration file built by the configuration script + "make makeconfig" and used to buile the makefiles in the + various subdirectories. Do not edit. + +Config.local * Unless you have a reference clock (besides the local + computer clock) or want to change the default installlation + directory (/usr/local/bin) not action is needed. For + configuring a reference clock a "make refconf" should + suffice. Diehards can still use an editor on this file. + +Config.local.dist file used to generate a plausible Config.local by commands + such as "make Config.local.green" + +Config.sed * sed script used to build makefiles from the + configuration file. Do not edit. + +Makefile this is the root of the makefile tree. Do not edit. + (Contents under pressure - qualified personel only 8-) + +PORTING contains useful information for porting to unexplored + new systems + +RELNOTES instructions for compiling and installing the daemon and + supporting programs + +README this file + +TODO our current problems where we could need help. + +adjtime directory containing the sources for the adjtime daemon + for HP/UX systems + +authstuff directory containing sources for miscellaneous programs + to test, calibrate and certify the cryptographic + mechanisms for DES and MD5 based authentication. These + programs do not include the cryptographic routines + themselves, so are free of U.S. export restrictions. + +clockstuff directory containing sources for miscellaneous programs + to test certain auxilliary programs used with some + kernel configurations, together with a program to + calculate propagation delays for use with radio clocks + and national time dissemination services such as + WWV/WWVH, WWVB and CHU + +compilers directory containing configuration scripts for various + compilers and operating systems + +conf directory containing a motley collection of + configuration files for various systems. For example + only. + +doc directory containing miscellaneous man pages and memos + useful for installation and subnet management + +gadget directory containing instructions and construction data + for a mysterious little box used as a CHU radio + demodulator and/or a level converter-pulse generator for + a precision 1-pps signal + +include directory containing include header files used by most + programs in the distribution + +hints directory containing files with hints on particular + topics like installation on specific OS variants or + general information + +historical.tar.Z + tar file with stuff believed to be old. If you find things + in there that are helpful for the current release, please + send email to mills@udel.edu. + +kernel directory containing sources for kernel programs such as + line disciplines and STREAMS modules used with the CHU + decoder and precision 1-pps signals + +lib directory containing sources for the library programs + used by most programs in the distribution + +machines directory containing configuration scripts for various + operating systems + +ntpdate directory containing sources for a program to set the + local machine time from one or more remote machines + running NTP. Operates like rdate, but much more + accurate. + +ntpq directory containing sources for a utility program to + query local and remote NTP peers for state variables and + related timekeeping information. This program conforms + to Appendix A of the NTP Version 3 Specification RFC + 1305. + +ntptrace directory containing sources for a utility program that + can be used to reveal the chain of NTP peers from a + designated peer to the primary server at the root of the + timekeeping subnet + +parse directory containing file belonging to the generic parse + reference clock driver. for reasonable simple clocks it + is possible to get away with about 3-4Kb of code. + additionally the SunOS 4.x streams module for parse is + residing here. + +parse/util some goodies for testing parse processing of DCF77 information. + (primarily for use on Suns / although others may work + also - possibly with a little porting) + one little gem is dcfd.c - DCF77 decoder with ntp loopfilter + code for standalone DCF77 synchronisation without the full + works of NTP. + +ppsclock directory containing sources for modifications to the + kernel asynchronous serial driver plus a STREAMS module + to capture a precision 1-pps signal. Useful on SunOS + 4.1.X systems only. + +refclocks directory containing reference clock configuration support + the file in here are still experimental. Do not expect them + to work flawlessly on all architectures. the coded dependencies + might not even be correct. + +scripts directory containing scripts to build the configuration + file "config" in this directory and then the makefiles + used in various dependent directories. + the subdirectories monitoring and support hold various + perl and shell scripts for visualising synchronisation + and daemon startup. + +util directory containing sources for various utility and + testing programs + +xntpd directory containing sources for the NTP Version 3 + daemon + +xntpdc directory containing sources for a utility program to + query local and remote NTP peers for state variables and + related timekeeping information. This program is + specific to this implmentation of NTP Version 3 and does + not conform to Appendix A of the NTP Version 3 + Specification RFC 1305. + +xntpres directory containing sources for a name-resolution + program used in some configurations of NTP Version 3 diff --git a/contrib/xntpd/RELNOTES b/contrib/xntpd/RELNOTES new file mode 100644 index 0000000000..277b8921de --- /dev/null +++ b/contrib/xntpd/RELNOTES @@ -0,0 +1,195 @@ +For special hints on setup/compilation/installation and other general +topics you may persue the files in the hints directory. + +This file contains the usual instructions to compile and install the programs in +this distribution. To make these programs: + +(0) Make sure that you have all necessary tools for building executables. + These tools include cc/gcc, make, awk, sed, tr, sh, grep, egrep and + a few others. Not all of these tools exist in the standard distribution + of todays Unix versions (Compilers are likely to be an extra product). + For a successful build all of these tools should be accessible via the + current path. + +(1) By default, if there is no Config.local, the system will generate one + to support a local ref clock (i.e. run off the system clock). + Greenhorns can skip on to (2). + + HACKers can create a Config.local and choose the compilation options, + install destination directory and clock drivers. + A template for Config.local can be found in Config.local.dist. + There are two Configurations that can be auto-generated: + make Config.local.local # network configuration plus local + # reference clock (the default) + make Config.local.NO.clock # network only configuration + + To set up for a radio clock, type "make refconf" and answer the questions + about PLL, PPS and radio clock type. + If this is the first use of the ref clock, don't forget to make suitable + files in /dev/ + + For custom tailored configuration copying Config.local.dist to Config.local + and editing Config.local to suit the local needs is neccessary (at most + 3 lines to change), or use one of the make's above and then tweak it. + +(2) Type "make" to compile everything of general interest. Expect few or + no warnings using cc and a moderate level of warnings using gcc. + Note: On some Unix platforms the use of gcc can result in quite a few + complaints about system header files and type problems within xntp + code. This is usually the case when the OS header files are not up + up to ANSI standards or GCCISMs. (There may, however, be still some + inconsistencies in the code) + + Other known problems stem from bugs/features/... in utility programs + of some vendors. + + See section "build problems" for known problems and possible work- + arounds. + + Each time you change the configuration a script that pokes your hard- and + software will be run to build the actual configuration files. + If the script fails, it will give you a list of machines it knows about. + You can override the automatic choice by cd to the ../machines directory + and typing "make makeconfig OS=", where is one of the + file names in the ../machine directory. + + The shell script will attempt to find the gcc compiler and, if + found, will use it instead of the cc compiler. You can override + this automatic choice by cd to the ../machines directory and typing + "make makeconfig COMP=", where is one of the file + names in the ../compilers directory. This can be combined with + the OS argument above. + + The configuration step can be separatly invoked by "make makeconfig". + + Note that any reconfiguration will result in cleaning the old + program and object files. + +(3) Assuming you have write permission on the install destination directory, + type "make install" to install the binaries in the destination directory. + At the time of writing this includes + the programs xntpd (the daemon), xntpdc (an xntpd-dependent query + program), ntpq (a standard query program), ntpdate (an rdate + replacement for boot time date setting and sloppy time keeping) + and xntpres (a program which provides name resolver support for + some xntpd configurations). + +(4) You are now ready to configure the daemon and start it. At this + point it might be useful to format and print the file doc/notes.me + and read a little bit. The sections on configuration and on the + tickadj program will be immediately useful. + +Additional "make" target you might find useful are: + +clean cleans out object files, programs and temporary files + +dist makes a new distribution file (also cleans current binaries) + All usual scratch and backup files (*.rej, *.orig, *.o, *~ + core, lint*.errs, executables, tags, Makefile.bak, make.log) + will be removed. The distribution is created in a tar file + (file name: .tar. - with + the prefix usually being ../xntp- and a compression suffix + of .Z (compress)) + Note: the file Config.local will never be included in the + distribution tar file. For configuration hints to propagate + in in distribution changes must be made to Config.local.dist. + +depend possible maker of hazardous waste + +refconf a target to interactively configure reference clock support. + This should work for you, but has not yet been tested on + the more exotic Unix ports (mostly the supercomputer ones). + +Bug reports of a general nature can be sent to David Mills (mills@udel.edu). +Reports concerning specific hardware or software systems mentioned in the +COPYRIGHT file should be sent to the author, with copy to David Mills for +archive. + +The distribution has been compiled and run on at least the following +machines, operating systems and compilers. In all known cases, if +the gcc compiler eats it with some success, the cc compiler also enjoys +the meal. The converse is not always true. + + VAX-11/785 4.3 tahoe cc no REFCLOCK (dm 93/11/20) + Sun3 SunOS 4.1.1 gcc no REFCLOCK (pb 93/10/25) + Sun4 SunOS 4.1.1 gcc all REFCLOCK drivers (dm 93/10/25) + Sun4 SunOS 4.1.3 gcc all REFLCOCK drivers + Sun4 SunOS 5.1 gcc no REFCLOCK (pb 93/10/25) + Sun4 SunOS 5.2 gcc no REFCLOCK (dm 93/11/20) + Sun4 SunOS 5.2 gcc PARSE REFCLOCK (kd 93/11/10) + Sun4 SunOS 5.3 gcc local (pb 93/11/10) + HP700 HPUX 9.0 cc no REFCLOCK + hp7xx HPUX 9.01 cc local + PARSE (kd 93/10/26) + HP3xx HPUX 9.01 cc no REFCLOCK (pb 93/10/25) + HP3xx HPUX 8.0 cc no REFCLOCK (pb 93/10/25) + MIPS Ultrix 4.3a gcc WWVB clock (dm 93/11/20) + MIPS Ultrix 3a gcc green (pb 93/10/26) + ALPHA OSF 1.2a gcc no REFCLOCK (dm 93/11/20) + ALPHA OSF 1.3 gcc no REFCLOCK (pb 93/10/25) + ALPHA OSF1 1.3 gcc green (pb 93/10/26) + Convex Convex OS 10.1 ? ? + SGI IRIX 4.0.5F gcc no REFCLOCK (pb 93/11/10) + AIX 3.2 ? ? + A/UX 2.0.1, 3.0.x ? ? + RS6000 AIX 3.2 gcc no REFCLOCK + MX500 Sinix-m V5.40 cc PARSE REFCLOCK + S2000 Sequent PTX 1.4 cc LOCAL_CLOCK (kd 93/11/10) + S2000 Sequent PTX 1.4 gcc LOCAL_CLOCK (kd 93/11/10) + PC FreeBSD gcc LOCAL_CLOCK see "build problems" + PC NetBSD? gcc LOCAL_CLOCK possibly see "build problems" + PC BSDI? gcc LOCAL_CLOCK possibly see "build problems" + PC Linux (pl14) gcc LOCAL_CLOCK (dw 93/10/30) + + pb: Piete Brooks + kd: Frank Kardel + dw: Torsten Duwe (duwe@informatik.uni-erlangen.de) + dm: David Mills (mills@udel.edu) + +Build Problems (and workaround): + +During testing/porting we have found some +of "make" and "sh" and "awk" features in different implementations. +If you have problems other tha the one listed below please check for +usualy things like the latest sh compatible pd shell in your own +environment. Things like this are known to hinder compilation if +they ate not fully compatible with sh or are buggy. + +Current build problem on (Mac) NetBSD, possibly BSDI and 386BSD: + pmake (e. g. NetBSD on MAC, possible other BNR2+pmake systems) + Following Makefile construction fails for no + apparent reason (at least to me) + doit: + $(MAKE) MAKE=\"$(MAKE)\" all + + all: + @echo all done. + + for the "make MAKE=make" call but not for "make" or + "make -e MAKE=make". Use the last form if you suffer + from that kind of make problems. (Easily detected + by failure to build with the message: + "don't know how to make make". + +The known sh and some make pecularities have already been taken care of. +The pmake (in the BNR2 branches) problem seems to be real at the time of this +writing. If you know a portable(!) fix we'd like to hear from you. + +Usually the vendor should fix these bugs in vital utilities. +We try to circumvent these bugs in a hopefully portable way. +If you can reproduce these bugs on your system please bug your +vendor/developer group to fix them. We are not trying anything fancy +in here (except for starting sub-makes) and we are shocked that even +the most common tools fail so miserably. By the time you get this +code the above utilities may already have been fixed. Hopefully one +day we do not have to cope with this kind of broken utilities. + Frank Kardel + +William L. Jones +Dennis Ferguson (Advanced Network Systems) +Lars Mathiesen (University of Copenhagen) +David Mills +Frank Kardel +Piete Brooks + +-- and a cast of thousands -- see the COPYRIGHT file +16 November 1993 diff --git a/contrib/xntpd/TODO b/contrib/xntpd/TODO new file mode 100644 index 0000000000..9b803722ef --- /dev/null +++ b/contrib/xntpd/TODO @@ -0,0 +1,37 @@ +# +# TODO,v 3.3 1993/11/09 23:20:16 kardel Exp +# +This file contains problems known to the authors that still need to be done. +We would appreciate if you could spare some of your time to look through +these topics and help us with some open questions. Most of the topics +pertain to specific architectures where we have no direct access or not +the time or expertise to currently track down the problem further. +If you don't know what we are talking about in the topics don't bother +with finding out - somebody else will probably solve that problem. + +Before you try to send a solution to mills@udel.edu please check whether +this problem still exists in the distribution on louie.udel.edu. + +Thank you for your help ! + Dave Mills + Frank Kardel + Piete Brooks + +Open issues: + +HPUX: + - Time warp + During the last few month disturbing reports about xntp setting + preposterous times during periods of high load have been reported + on HPUX 8 and 9. The theory is that the adjtimed message queue + gets deleted. Symptoms are that xntp() complains about interrupted + system calls in adjtime()-emulation and the time is set to some + invalid date. Also the adjtimed seems to have problems. We could + need some help here by an experienced HPUX guru. + Files affected: adjtime/* + +Apollo: + - terminal affiliation + Check whether thing are still correct in respect to breaking + terminal affiliation - horrible stories are told in the code. + File affected: xntpd/ntpd.c diff --git a/contrib/xntpd/VERSION b/contrib/xntpd/VERSION new file mode 100644 index 0000000000..80868e3ba5 --- /dev/null +++ b/contrib/xntpd/VERSION @@ -0,0 +1 @@ +version=3.3b (beta) diff --git a/contrib/xntpd/adjtime/Makefile.tmpl b/contrib/xntpd/adjtime/Makefile.tmpl new file mode 100644 index 0000000000..c2e8381165 --- /dev/null +++ b/contrib/xntpd/adjtime/Makefile.tmpl @@ -0,0 +1,53 @@ +######################################################################### +## (c) Copyright 1988, Hewlett-Packard Co. All Rights Reserved. ## +## ## +## Author: Tai Jin, Hewlett-Packard Laboratories. ## +######################################################################### + +## Makefile.tmpl,v 3.1 1993/07/06 01:04:40 jbj Exp + +# +PROGRAM = adjtimed +COMPILER= cc +CC= $(COMPILER) +BINDIR= /usr/local/etc +COPTS= -O +DEFS= +DEFS_OPT= +DEFS_LOCAL= +INCL= -I../include +LLIBS= +INSTALL= install + + +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +LDFLAGS= +LIBS= $(LLIBS) -lc +OBJ= adjtime.o adjtimed.o +ALL= libadjtime.a adjtimed + +all: $(ALL) + +libadjtime.a: adjtime.o + ar vr libadjtime.a $? + +adjtimed: adjtimed.o ../lib/libntp.a + $(CC) $(LDFLAGS) -o adjtimed adjtimed.o ../lib/libntp.a $(LIBS) + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" + +install: $(BINDIR)/$(PROGRAM) + +$(BINDIR)/$(PROGRAM): $(PROGRAM) + $(INSTALL) -c -m 0755 $(PROGRAM) $(BINDIR) + +clean: + -@rm -f *.a *.o adjtimed + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +install: $(PROGRAM) + cp $(PROGRAM) $(BINDIR) diff --git a/contrib/xntpd/adjtime/README b/contrib/xntpd/adjtime/README new file mode 100644 index 0000000000..fe8b7e51e7 --- /dev/null +++ b/contrib/xntpd/adjtime/README @@ -0,0 +1,23 @@ +------------------------------------------------------------------------------ +The adjtimed daemon emulates the BSD adjtime(2) system call. The +adjtime() routine communicates with this daemon via SYSV messages. + +The emulation uses an undocumented kernel variable (as of 6.0/2.0 +and later releases) and as such it cannot be guaranteed to work in +future HP-UX releases. Perhaps HP-UX will have a real adjtime(2) +system call in the future. + +Author: Tai Jin (tai@sde.hp.com) +------------------------------------------------------------------------------ + +IMPORTANT NOTE: This stuff must be compiled with no optimization !! + +NOTE: This code is known to work as of 8.0 on s300's, s700's and s800's. + PLEASE do not modify it unless you have access to kernel sources + and fully understand the implications of any changes you are making. + One person already has trashed adjtimed by making it do "the right + thing". This is not an exact replacement for BSD adjtime(2), don't + try to make it into one. + + -- Ken + diff --git a/contrib/xntpd/adjtime/adjtime.c b/contrib/xntpd/adjtime/adjtime.c new file mode 100644 index 0000000000..5b0475e1d3 --- /dev/null +++ b/contrib/xntpd/adjtime/adjtime.c @@ -0,0 +1,101 @@ +/*************************************************************************/ +/* (c) Copyright Tai Jin, 1988. All Rights Reserved. */ +/* Hewlett-Packard Laboratories. */ +/* */ +/* Permission is hereby granted for unlimited modification, use, and */ +/* distribution. This software is made available with no warranty of */ +/* any kind, express or implied. This copyright notice must remain */ +/* intact in all versions of this software. */ +/* */ +/* The author would appreciate it if any bug fixes and enhancements were */ +/* to be sent back to him for incorporation into future versions of this */ +/* software. Please send changes to tai@iag.hp.com or ken@sdd.hp.com. */ +/*************************************************************************/ + +#ifndef lint +static char RCSid[] = "adjtime.c,v 3.1 1993/07/06 01:04:42 jbj Exp"; +#endif + +#include +#include +#include +#include +#include +#include "adjtime.h" + +#define abs(x) ((x) < 0 ? -(x) : (x)) +static LONG adjthresh = 400L; +static LONG saveup; + + +_clear_adjtime() +{ + saveup = 0L; +} + + +adjtime(delta, olddelta) + register struct timeval *delta; + register struct timeval *olddelta; +{ + struct timeval newdelta; + + /* If they are giving us seconds, ignore up to current threshold saved */ + if (delta->tv_sec) { + saveup = 0L; + return(_adjtime(delta, olddelta)); + } + + /* add in, needs check for overflow ? */ + saveup += delta->tv_usec; + + /* Broke the threshold, call adjtime() */ + if (abs(saveup) > adjthresh) { + newdelta.tv_sec = 0L; + newdelta.tv_usec = saveup; + saveup = 0L; + return(_adjtime(&newdelta, olddelta)); + } + + if (olddelta) + olddelta->tv_sec = olddelta->tv_usec = 0L; + return(0); +} + + +_adjtime(delta, olddelta) + register struct timeval *delta; + register struct timeval *olddelta; +{ + register int mqid; + MsgBuf msg; + register MsgBuf *msgp = &msg; + + /* + * get the key to the adjtime message queue + * (note that we must get it every time because the queue might have been + * removed and recreated) + */ + if ((mqid = msgget(KEY, 0)) == -1) + return (-1); + + msgp->msgb.mtype = CLIENT; + msgp->msgb.tv = *delta; + + if (olddelta) + msgp->msgb.code = DELTA2; + else + msgp->msgb.code = DELTA1; + + if (msgsnd(mqid, &msgp->msgp, MSGSIZE, 0) == -1) + return (-1); + + if (olddelta) { + if (msgrcv(mqid, &msgp->msgp, MSGSIZE, SERVER, 0) == -1) + return (-1); + + *olddelta = msgp->msgb.tv; + } + + return (0); +} diff --git a/contrib/xntpd/adjtime/adjtime.h b/contrib/xntpd/adjtime/adjtime.h new file mode 100644 index 0000000000..f063a4777b --- /dev/null +++ b/contrib/xntpd/adjtime/adjtime.h @@ -0,0 +1,63 @@ +/*************************************************************************/ +/* (c) Copyright Tai Jin, 1988. All Rights Reserved. */ +/* Hewlett-Packard Laboratories. */ +/* */ +/* Permission is hereby granted for unlimited modification, use, and */ +/* distribution. This software is made available with no warranty of */ +/* any kind, express or implied. This copyright notice must remain */ +/* intact in all versions of this software. */ +/* */ +/* The author would appreciate it if any bug fixes and enhancements were */ +/* to be sent back to him for incorporation into future versions of this */ +/* software. Please send changes to tai@iag.hp.com or ken@sdd.hp.com. */ +/*************************************************************************/ + +/* "adjtime.h,v 3.1 1993/07/06 01:04:43 jbj Exp" */ +/* adjtime.h,v + * Revision 3.1 1993/07/06 01:04:43 jbj + * XNTP release 3.1 + * + * + * Revision 1.5 90/02/07 15:34:18 15:34:18 src (Source Hacker) + * CHANGED KEY !!! + * + * Revision 1.4 89/02/09 12:26:35 12:26:35 tai (Tai Jin (Guest)) + * *** empty log message *** + * + * Revision 1.4 89/02/09 12:26:35 12:26:35 tai (Tai Jin) + * added comment + * + * Revision 1.3 88/08/30 01:08:29 01:08:29 tai (Tai Jin) + * fix copyright notice again + * + * Revision 1.2 88/08/30 00:51:55 00:51:55 tai (Tai Jin) + * fix copyright notice + * + * Revision 1.1 88/04/02 14:56:54 14:56:54 tai (Tai Jin) + * Initial revision + * */ + +#include "ntp_types.h" + +#define KEY 659847L + +typedef union { + struct msgbuf msgp; + struct { + LONG mtype; + int code; + struct timeval tv; + } msgb; +} MsgBuf; + +#define MSGSIZE (sizeof(int) + sizeof(struct timeval)) +/* + * mtype values + */ +#define CLIENT 1L +#define SERVER 2L +/* + * code values + */ +#define DELTA1 0 +#define DELTA2 1 diff --git a/contrib/xntpd/adjtime/adjtimed.c b/contrib/xntpd/adjtime/adjtimed.c new file mode 100644 index 0000000000..f2de6921cf --- /dev/null +++ b/contrib/xntpd/adjtime/adjtimed.c @@ -0,0 +1,485 @@ +/*************************************************************************/ +/* (c) Copyright Tai Jin, 1988. All Rights Reserved. */ +/* Hewlett-Packard Laboratories. */ +/* */ +/* Permission is hereby granted for unlimited modification, use, and */ +/* distribution. This software is made available with no warranty of */ +/* any kind, express or implied. This copyright notice must remain */ +/* intact in all versions of this software. */ +/* */ +/* The author would appreciate it if any bug fixes and enhancements were */ +/* to be sent back to him for incorporation into future versions of this */ +/* software. Please send changes to tai@iag.hp.com or ken@sdd.hp.com. */ +/*************************************************************************/ + +#ifndef lint +static char RCSid[] = "adjtimed.c,v 3.1 1993/07/06 01:04:45 jbj Exp"; +#endif + +/* + * Adjust time daemon. + * This deamon adjusts the rate of the system clock a la BSD's adjtime(). + * The adjtime() routine uses SYSV messages to communicate with this daemon. + * + * Caveat: This emulation uses an undocumented kernel variable. As such, it + * cannot be guaranteed to work in future HP-UX releases. Perhaps a real + * adjtime(2) will be supported in the future. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ntp_syslog.h" +#include "adjtime.h" + +double atof(); +extern int optind; +extern char *optarg; + +int InitClockRate(); +int AdjustClockRate(); +#ifdef notdef +LONG GetClockRate(); +#endif +int SetClockRate(); +void ResetClockRate(); +void Cleanup(); +void Exit(); + +#define MILLION 1000000L + +#define tvtod(tv) ((double)(LONG)tv.tv_sec + \ + ((double)tv.tv_usec / (double)MILLION)) + +char *progname = NULL; +int verbose = 0; +int sysdebug = 0; +static int mqid; +static double oldrate = 0.0; +static double RATE = 0.25; +static double PERIOD = 6.666667; + + +main(argc, argv) + int argc; + char **argv; +{ + struct timeval remains; + struct sigvec vec; + MsgBuf msg; + char ch; + int nofork = 0; + int fd; + + progname = argv[0]; + + openlog("adjtimed", LOG_PID, LOG_LOCAL6); + + while ((ch = getopt(argc, argv, "hkrvdfp:")) != EOF) { + switch (ch) { + case 'k': + case 'r': + if ((mqid = msgget(KEY, 0)) != -1) { + if (msgctl(mqid, IPC_RMID, (struct msqid_ds *)0) == -1) { + syslog(LOG_ERR, "remove old message queue: %m"); + perror("adjtimed: remove old message queue"); + exit(1); + } + } + + if (ch == 'k') + exit(0); + + break; + + case 'v': + ++verbose, nofork = 1; + break; + + case 'd': + ++sysdebug; + break; + + case 'f': + nofork = 1; + break; + + case 'p': + if ((RATE = atof(optarg)) <= 0.0 || RATE >= 100.0) { + fputs("adjtimed: percentage must be between 0.0 and 100.0\n", stderr); + exit(1); + } + + RATE /= 100.0; + PERIOD = 1.0 / RATE; + break; + + default: + puts("usage: adjtimed -hkrvdf -p rate"); + puts("-h\thelp"); + puts("-k\tkill existing adjtimed, if any"); + puts("-r\trestart (kills existing adjtimed, if any)"); + puts("-v\tdebug output (repeat for more output)"); + puts("-d\tsyslog output (repeat for more output)"); + puts("-f\tno fork"); + puts("-p rate\tpercent rate of change"); + syslog(LOG_ERR, "usage error"); + exit(1); + } /* switch */ + } /* while */ + + if (!nofork) { + switch (fork()) { + case 0: + close(fileno(stdin)); + close(fileno(stdout)); + close(fileno(stderr)); + +#ifdef TIOCNOTTY + if ((fd = open("/dev/tty")) != -1) { + ioctl(fd, TIOCNOTTY, 0); + close(fd); + } +#else + setpgrp(); +#endif + break; + + case -1: + syslog(LOG_ERR, "fork: %m"); + perror("adjtimed: fork"); + exit(1); + + default: + exit(0); + } /* switch */ + } /* if */ + + if (nofork) { + setvbuf(stdout, NULL, _IONBF, BUFSIZ); + setvbuf(stderr, NULL, _IONBF, BUFSIZ); + } + + syslog(LOG_INFO, "started (rate %.2f%%)", RATE * 100.0); + if (verbose) printf("adjtimed: started (rate %.2f%%)\n", RATE * 100.0); + + if (InitClockRate() == -1) + Exit(2); + + (void)signal(SIGHUP, SIG_IGN); + (void)signal(SIGINT, SIG_IGN); + (void)signal(SIGQUIT, SIG_IGN); + (void)signal(SIGTERM, Cleanup); + + vec.sv_handler = ResetClockRate; + vec.sv_flags = 0; + vec.sv_mask = ~0; + sigvector(SIGALRM, &vec, (struct sigvec *)0); + + if (msgget(KEY, IPC_CREAT|IPC_EXCL) == -1) { + if (errno == EEXIST) { + syslog(LOG_ERR, "message queue already exists, use -r to remove it"); + fputs("adjtimed: message queue already exists, use -r to remove it\n", + stderr); + Exit(1); + } + + syslog(LOG_ERR, "create message queue: %m"); + perror("adjtimed: create message queue"); + Exit(1); + } + + if ((mqid = msgget(KEY, 0)) == -1) { + syslog(LOG_ERR, "get message queue id: %m"); + perror("adjtimed: get message queue id"); + Exit(1); + } + + for (;;) { + if (msgrcv(mqid, &msg.msgp, MSGSIZE, CLIENT, 0) == -1) { + if (errno == EINTR) continue; + syslog(LOG_ERR, "read message: %m"); + perror("adjtimed: read message"); + Cleanup(); + } + + switch (msg.msgb.code) { + case DELTA1: + case DELTA2: + AdjustClockRate(&msg.msgb.tv, &remains); + + if (msg.msgb.code == DELTA2) { + msg.msgb.tv = remains; + msg.msgb.mtype = SERVER; + + while (msgsnd(mqid, &msg.msgp, MSGSIZE, 0) == -1) { + if (errno == EINTR) continue; + syslog(LOG_ERR, "send message: %m"); + perror("adjtimed: send message"); + Cleanup(); + } + } + + if (remains.tv_sec + remains.tv_usec != 0L) { + if (verbose) { + printf("adjtimed: previous correction remaining %.6fs\n", + tvtod(remains)); + } + if (sysdebug) { + syslog(LOG_INFO, "previous correction remaining %.6fs", + tvtod(remains)); + } + } + break; + + default: + fprintf(stderr, "adjtimed: unknown message code %d\n", msg.msgb.code); + syslog(LOG_ERR, "unknown message code %d", msg.msgb.code); + } /* switch */ + } /* loop */ +} /* main */ + +/* + * Default clock rate (old_tick). + */ +#define DEFAULT_RATE (MILLION / HZ) +#define UNKNOWN_RATE 0L +#define SLEW_RATE (MILLION / DEFAULT_RATE) +#define MIN_DELTA SLEW_RATE +/* +#define RATE 0.005 +#define PERIOD (1.0 / RATE) +*/ +static LONG default_rate = DEFAULT_RATE; +static LONG slew_rate = SLEW_RATE; + +AdjustClockRate(delta, olddelta) + register struct timeval *delta, *olddelta; +{ + register LONG rate, dt; + struct itimerval period, remains; + static LONG leftover = 0; +/* + * rate of change + */ + dt = (delta->tv_sec * MILLION) + delta->tv_usec + leftover; + + if (dt < MIN_DELTA && dt > -MIN_DELTA) { + leftover += delta->tv_usec; + + if (olddelta) { + getitimer(ITIMER_REAL, &remains); + dt = ((remains.it_value.tv_sec * MILLION) + remains.it_value.tv_usec) * + oldrate; + olddelta->tv_sec = dt / MILLION; + olddelta->tv_usec = dt - (olddelta->tv_sec * MILLION); + } + + if (verbose > 2) printf("adjtimed: delta is too small: %dus\n", dt); + if (sysdebug > 2) syslog(LOG_INFO, "delta is too small: %dus", dt); + return (1); + } + + leftover = dt % MIN_DELTA; + dt -= leftover; + + if (verbose) + printf("adjtimed: new correction %.6fs\n", (double)dt / (double)MILLION); + if (sysdebug) + syslog(LOG_INFO, "new correction %.6fs", (double)dt / (double)MILLION); + if (verbose > 2) printf("adjtimed: leftover %dus\n", leftover); + if (sysdebug > 2) syslog(LOG_INFO, "leftover %dus", leftover); + rate = dt * RATE; + + if (rate < slew_rate && rate > -slew_rate) { + rate = (rate < 0L ? -slew_rate : slew_rate); + dt = abs(dt * (MILLION / slew_rate)); + period.it_value.tv_sec = dt / MILLION; + } else { + period.it_value.tv_sec = (LONG)PERIOD; + } +/* + * The adjustment will always be a multiple of the minimum adjustment. + * So the period will always be a whole second value. + */ + period.it_value.tv_usec = 0; + + if (verbose > 1) + printf("adjtimed: will be complete in %ds\n", period.it_value.tv_sec); + if (sysdebug > 1) + syslog(LOG_INFO, "will be complete in %ds", period.it_value.tv_sec); +/* + * adjust the clock rate + */ + if (SetClockRate((rate / slew_rate) + default_rate) == -1) { + syslog(LOG_ERR, "set clock rate: %m"); + perror("adjtimed: set clock rate"); + } +/* + * start the timer + * (do this after changing the rate because the period has been rounded down) + */ + period.it_interval.tv_sec = period.it_interval.tv_usec = 0L; + setitimer(ITIMER_REAL, &period, &remains); +/* + * return old delta + */ + if (olddelta) { + dt = ((remains.it_value.tv_sec * MILLION) + remains.it_value.tv_usec) * + oldrate; + olddelta->tv_sec = dt / MILLION; + olddelta->tv_usec = dt - (olddelta->tv_sec * MILLION); + } + + oldrate = (double)rate / (double)MILLION; +} /* AdjustClockRate */ + +static struct nlist nl[] = { +#ifdef hp9000s800 +#ifdef PRE7_0 + { "tick" }, +#else + { "old_tick" }, +#endif +#else + { "_old_tick" }, +#endif + { "" } +}; + +static int kmem; + +/* + * The return value is the clock rate in old_tick units or -1 if error. + */ +LONG +GetClockRate() +{ + LONG rate, mask; + + if (lseek(kmem, (LONG)nl[0].n_value, 0) == -1L) + return (-1L); + + mask = sigblock(sigmask(SIGALRM)); + + if (read(kmem, (caddr_t)&rate, sizeof(rate)) != sizeof(rate)) + rate = UNKNOWN_RATE; + + sigsetmask(mask); + return (rate); +} /* GetClockRate */ + +/* + * The argument is the new rate in old_tick units. + */ +SetClockRate(rate) + LONG rate; +{ + LONG mask; + + if (lseek(kmem, (LONG)nl[0].n_value, 0) == -1L) + return (-1); + + mask = sigblock(sigmask(SIGALRM)); + + if (write(kmem, (caddr_t)&rate, sizeof(rate)) != sizeof(rate)) { + sigsetmask(mask); + return (-1); + } + + sigsetmask(mask); + + if (rate != default_rate) { + if (verbose > 3) { + printf("adjtimed: clock rate (%lu) %ldus/s\n", rate, + (rate - default_rate) * slew_rate); + } + if (sysdebug > 3) { + syslog(LOG_INFO, "clock rate (%lu) %ldus/s", rate, + (rate - default_rate) * slew_rate); + } + } + + return (0); +} /* SetClockRate */ + +InitClockRate() +{ + if ((kmem = open("/dev/kmem", O_RDWR)) == -1) { + syslog(LOG_ERR, "open(/dev/kmem): %m"); + perror("adjtimed: open(/dev/kmem)"); + return (-1); + } + + nlist("/hp-ux", nl); + + if (nl[0].n_type == 0) { + fputs("adjtimed: /hp-ux has no symbol table\n", stderr); + syslog(LOG_ERR, "/hp-ux has no symbol table"); + return (-1); + } +/* + * Set the default to the system's original value + */ + default_rate = GetClockRate(); + if (default_rate == UNKNOWN_RATE) default_rate = DEFAULT_RATE; + slew_rate = (MILLION / default_rate); + + return (0); +} /* InitClockRate */ + +/* + * Reset the clock rate to the default value. + */ +void +ResetClockRate() +{ + struct itimerval it; + + it.it_value.tv_sec = it.it_value.tv_usec = 0L; + setitimer(ITIMER_REAL, &it, (struct itimerval *)0); + + if (verbose > 2) puts("adjtimed: resetting the clock"); + if (sysdebug > 2) syslog(LOG_INFO, "resetting the clock"); + + if (GetClockRate() != default_rate) { + if (SetClockRate(default_rate) == -1) { + syslog(LOG_ERR, "set clock rate: %m"); + perror("adjtimed: set clock rate"); + } + } + + oldrate = 0.0; +} /* ResetClockRate */ + +void +Cleanup() +{ + ResetClockRate(); + + if (msgctl(mqid, IPC_RMID, (struct msqid_ds *)0) == -1) { + if (errno != EINVAL) { + syslog(LOG_ERR, "remove message queue: %m"); + perror("adjtimed: remove message queue"); + } + } + + Exit(2); +} /* Cleanup */ + +void +Exit(status) + int status; +{ + syslog(LOG_ERR, "terminated"); + closelog(); + if (kmem != -1) close(kmem); + exit(status); +} /* Exit */ diff --git a/contrib/xntpd/authstuff/Makefile.tmpl b/contrib/xntpd/authstuff/Makefile.tmpl new file mode 100644 index 0000000000..e5f0310eb3 --- /dev/null +++ b/contrib/xntpd/authstuff/Makefile.tmpl @@ -0,0 +1,92 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:04:48 jbj Exp +# +PROGRAM= authcert authspeed md5 +# +# authcert, authspeed - authentication utilities +# +COMPILER= cc +COPTS= -O +BINDIR= /usr/local +DEFS= +DEFS_OPT= +DEFS_LOCAL= +COMPAT= +RESLIB= +# +INCL= -I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +LIB= ../lib/libntp.a +MAKE= make +# +CRTOBJS= authcert.o +SPDOBJS= authspeed.o +PAROBJS= keyparity.o +IFPOBJS= makeIPFP.o +PC1OBJS= makePC1.o +PC2OBJS= makePC2.o +SPOBJS= makeSP.o +RNDOBJS= mkrandkeys.o +OIFOBJS= omakeIPFP.o +UNXOBJS= unixcert.o +MD5OBJS= md5driver.o + +SOURCE= authcert.c authspeed.c keyparity.c makeIPFP.c makePC1.c \ + makePC2.c makeSP.c mkrandkeys.c omakeIPFP.c unixcert.c md5driver.c + +all: $(PROGRAM) + +authcert: $(CRTOBJS) $(LIB) + $(CC) $(COPTS) -o $@ $(CRTOBJS) $(LIB) + +authspeed: $(SPDOBJS) $(LIB) + $(CC) $(COPTS) -o $@ $(SPDOBJS) $(LIB) $(COMPAT) $(RESLIB) + +keyparity: $(PAROBJS) $(LIB) + $(CC) $(COPTS) -o $@ $(PAROBJS) $(LIB) + +makeIPFP: $(IFPOBJS) + $(CC) $(COPTS) -o $@ $(IFPOBJS) + +makePC1: $(PC1OBJS) + $(CC) $(COPTS) -o $@ $(PC1OBJS) + +makePC2: $(PC2OBJS) + $(CC) $(COPTS) -o $@ $(PC2OBJS) + +makeSP: $(SPOBJS) + $(CC) $(COPTS) -o $@ $(SPOBJS) + +mkrandkeys: $(RNDOBJS) $(LIB) + $(CC) $(COPTS) -o $@ $(RNDOBJS) $(LIB) + +omakeIPFP: $(OIFBJS) + $(CC) $(COPTS) -o $@ $(OIFBJS) + +unixcert: $(UNXBJS) + $(CC) $(COPTS) -o $@ $(UNXBJS) + +md5: $(MD5OBJS) + $(CC) $(COPTS) -o $@ $(MD5OBJS) $(LIB) + +tags: + ctags *.c *.h + +install: + # Don't install any of this shit + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(PROGRAM) *.o *.out tags make.log Makefile.bak keyparity \ + makeIPFP makePC1 makePC2 makeSP mkrandkeys omakeIPFP unixcert \ + lint.errs md5cert + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" + diff --git a/contrib/xntpd/authstuff/README b/contrib/xntpd/authstuff/README new file mode 100644 index 0000000000..2985751cc0 --- /dev/null +++ b/contrib/xntpd/authstuff/README @@ -0,0 +1,13 @@ +README file for directory ./authstuff of the NTP Version 3 distribution + +This directory contains the sources for miscellaneous programs to test, +validate and calibreate cryptographic routines used by NTP. These include + +authcert.c used to certify the DES and MD5 message digest algorithms + work properly. See the source for directions for use. + +authspeed.c used to determing the running time for DES and MD5 + messge digest algorithms. See the source for directions + for use. + +For other programs, see the source files. diff --git a/contrib/xntpd/authstuff/auth.samplekeys b/contrib/xntpd/authstuff/auth.samplekeys new file mode 100644 index 0000000000..c46d283405 --- /dev/null +++ b/contrib/xntpd/authstuff/auth.samplekeys @@ -0,0 +1,45 @@ +# auth.samplekeys,v 3.1 1993/07/06 01:04:49 jbj Exp +# +# Sample key file, also used for testing. +# +# Note that there are three formats for keys. Standard format is a +# hex format with the low order bit of each byte being a parity +# bit, a la the NBS standard. NTP format is also hex, but uses the +# high order bit of each byte for parity. Ascii format simply encodes +# a 1-8 character ascii string as a key. Note that because of the +# simple tokenizing routine, the characters ' ', '#', '\t', '\n' and +# '\0' can't be used in an ascii key. Everything else is fair game, though. +# + +1 S 0101010101010101 # odd parity 0 key +2 N 8080808080808080 # and again +3 A ugosnod +4 A BigbOObs +5 S f1f1f1f1f1f1f1f1 +6 N f8f8f8f8f8f8f8f8 # same as key 5 +7 S f8f8f8f8f8f8f8f8 # not same as key 6 +8 A a # short ascii keys are zero padded +9 A &^%$@!*( +10 S 01020407080bf1f1 +11 N 4040404040404040 +12 A more +13 A random +14 A keys +15 A password # 15 used as password by runtime configuration +# +16 M password # MD5 key +17 M secret +18 M key1 +19 M key2 +20 M foobar +21 M tick +22 M tock +23 M key23 +24 M key24 +25 M key25 +26 M a +27 M few +28 M more +29 M random +30 M md5 +31 M keys! diff --git a/contrib/xntpd/authstuff/auth.speed b/contrib/xntpd/authstuff/auth.speed new file mode 100644 index 0000000000..b55f20cbd8 --- /dev/null +++ b/contrib/xntpd/authstuff/auth.speed @@ -0,0 +1,20 @@ +Authentication delays (us) DES MD5 +DEC 3000/400 OSF/1 bunnylou 14 35 +HP9000/735 hpux9.0 na 30 +HP9000/730 hpux8.07(+OV) 16 55 +SGI Indigo R4000 19 48 +HP9000/720 hpux8.07 21 66 +SGI 4/35 38 110 +DECstation 5000/240 cowbird 39 81 +Sun4c/75 SS2 43 96 +Sun4c/50 IPX malarky 47 94 +DECstation 5000/33 sundeck 49 106 +SGI Indigo 54 115 +DECstation 5000/125 herald 63 136 +Sun4c/65 SS1+ pogo 72 159 +Sun4c/40 IPC grundoon 73 163 +Sun4c/60 SS1 albert 95 199 +Sun4c/20 SLC 95 203 +DECstation 3100 sheol 98 214 +DECstation 2100 circus 126 278 +VAX 780 985 ? diff --git a/contrib/xntpd/authstuff/authcert.c b/contrib/xntpd/authstuff/authcert.c new file mode 100644 index 0000000000..6f6e42c220 --- /dev/null +++ b/contrib/xntpd/authstuff/authcert.c @@ -0,0 +1,96 @@ +/* authcert.c,v 3.1 1993/07/06 01:04:52 jbj Exp + * This file, and the certdata file, shamelessly stolen + * from Phil Karn's DES implementation. + */ + +#include +#include +#include +#include + +#define DES +#include "ntp_stdlib.h" + +u_char ekeys[128]; +u_char dkeys[128]; + +static void get8 P((U_LONG *)); +static void put8 P((U_LONG *)); + +void +main() +{ + U_LONG key[2], plain[2], cipher[2], answer[2]; + int i; + int test; + int fail; + + for(test=0;!feof(stdin);test++){ + get8(key); + DESauth_subkeys(key, ekeys, dkeys); + printf(" K: "); put8(key); + + get8(plain); + printf(" P: "); put8(plain); + + get8(answer); + printf(" C: "); put8(answer); + + + for(i=0;i<2;i++) + cipher[i] = htonl(plain[i]); + DESauth_des(cipher, ekeys); + + for(i=0;i<2;i++) + if(ntohl(cipher[i]) != answer[i]) + break; + fail = 0; + if(i != 2){ + printf(" Encrypt FAIL"); + fail++; + } + DESauth_des(cipher, dkeys); + for(i=0;i<2;i++) + if(ntohl(cipher[i]) != plain[i]) + break; + if(i != 2){ + printf(" Decrypt FAIL"); + fail++; + } + if(fail == 0) + printf(" OK"); + printf("\n"); + } +} + +static void +get8(lp) +U_LONG *lp; +{ + int t; + U_LONG l[2]; + int i; + + l[0] = l[1] = 0L; + for(i=0;i<8;i++){ + scanf("%2x",&t); + if(feof(stdin)) + exit(0); + l[i/4] <<= 8; + l[i/4] |= (U_LONG)(t & 0xff); + } + *lp = l[0]; + *(lp+1) = l[1]; +} + +static void +put8(lp) +U_LONG *lp; +{ + int i; + + + for(i=0;i<2;i++){ + printf("%08x",*lp++); + } +} diff --git a/contrib/xntpd/authstuff/authspeed.c b/contrib/xntpd/authstuff/authspeed.c new file mode 100644 index 0000000000..05af1326d8 --- /dev/null +++ b/contrib/xntpd/authstuff/authspeed.c @@ -0,0 +1,315 @@ +/* authspeed.c,v 3.1 1993/07/06 01:04:54 jbj Exp + * authspeed - figure out how LONG it takes to do an NTP encryption + */ + +#if defined(SYS_HPUX) || defined(SYS_AUX3) || defined(SYS_AUX2) || defined(SOLARIS) || defined(SYS_SVR4) || defined(SYS_PTX) +#define FAKE_RUSAGE +#endif + +#include +#include +#include +#include +#ifdef FAKE_RUSAGE +#include +#include +#endif + +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +#define DEFLOOPS -1 + +#define DEFDELAYLOOPS 20000 +#define DEFCOSTLOOPS 2000 + +char *progname; +int debug; + +struct timeval tstart, tend; +#ifdef FAKE_RUSAGE +struct tms rstart, rend; +#define getrusage(foo, t) times(t) +#define RUSAGE_SELF 0 +#else +struct rusage rstart, rend; +#endif + +l_fp dummy1, dummy2; +U_LONG dummy3; + +U_LONG pkt[15]; + +int totalcost = 0; +double rtime; +double vtime; + +int domd5 = 0; + +static void dodelay P((int)); +static void docheap P((int)); +static void docost P((int)); +static void subtime P((struct timeval *, struct timeval *, double *)); + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int loops; + int i; + int errflg = 0; + extern int optind; + extern char *optarg; + + progname = argv[0]; + loops = DEFLOOPS; + while ((c = getopt_l(argc, argv, "cdmn:")) != EOF) + switch (c) { + case 'c': + totalcost++; + break; + case 'd': + ++debug; + break; + case 'm': + domd5 = 16; /* offset into list of keys */ + break; + case 'n': + loops = atoi(optarg); + if (loops <= 0) { + (void) fprintf(stderr, + "%s: %s is unlikely to be a useful number of loops\n", + progname, optarg); + errflg++; + } + break; + default: + errflg++; + break; + } + if (errflg || optind == argc) { + (void) fprintf(stderr, + "usage: %s [-d] [-n loops] [ -c ] auth.samplekeys\n", + progname); + exit(2); + } + printf("Compute timing for "); + if (domd5) + printf("MD5"); + else + printf("DES"); + printf(" based authentication.\n"); + + init_auth(); + authreadkeys(argv[optind]); + for (i = 0; i < 16; i++) { + if (!auth_havekey(i + domd5)) { + errflg++; + (void) fprintf(stderr, "%s: key %d missing\n", + progname, i + domd5); + } + } + + if (errflg) { + (void) fprintf(stderr, + "%s: check syslog for errors, or use file with complete set of keys\n", + progname); + exit(1); + } + + if (loops == DEFLOOPS) { + if (totalcost) + loops = DEFCOSTLOOPS; + else + loops = DEFDELAYLOOPS; + } + + dummy1.l_ui = 0x80808080; + dummy1.l_uf = 0xffffff00; + dummy3 = 0x0aaaaaaa; + + for (i = 0; i < 12; i++) + pkt[i] = i * 0x22222; + + if (totalcost) { + if (totalcost > 1) + docheap(loops); + else + docost(loops); + } else { + dodelay(loops); + } + + printf("total real time: %.3f\n", rtime); + printf("total CPU time: %.3f\n", vtime); + if (totalcost) { + printf("real cost (in seconds): %.6f\n", + rtime/(double)loops); + printf("CPU cost (in seconds): %.6f\n", + vtime/(double)loops); + printf("\nThis includes the cost of a decryption plus the\n"); + printf("the cost of an encryption, i.e. the cost to process\n"); + printf("a single authenticated packet.\n"); + } else { + printf("authdelay in the configuration file\n"); + printf("real authentication delay: %.6f\n", + rtime/(double)loops); + printf("authentication delay in CPU time: %.6f\n", + vtime/(double)loops); + printf("\nThe CPU delay is probably the best bet for\n"); + printf("authdelay in the configuration file\n"); + } + exit(0); +} + + +/* + * dodelay - do the delay measurement + */ +static void +dodelay(loops) + int loops; +{ + double vtime1, rtime1, vtime2, rtime2; + register int loopcount; + /* + * If we're attempting to compute the cost of an auth2crypt() + * for first compute the total cost, then compute the + * cost of only doing the first step, auth1crypt(). What + * remains is the cost of auth2crypt. + */ + loopcount = loops; + (void) gettimeofday(&tstart, (struct timezone *)0); + (void) getrusage(RUSAGE_SELF, &rstart); + + while (loopcount-- > 0) { + auth1crypt((loops & 0xf) + domd5, pkt, 48); + L_ADDUF(&dummy1, dummy3); + auth2crypt((loops & 0xf) + domd5, pkt, 48); + } + + (void) getrusage(RUSAGE_SELF, &rend); + (void) gettimeofday(&tend, (struct timezone *)0); + + subtime(&tstart, &tend, &rtime1); +#ifdef FAKE_RUSAGE + vtime1 = (rend.tms_utime - rstart.tms_utime) * 1.0 / HZ; +#else + subtime(&rstart.ru_utime, &rend.ru_utime, &vtime1); +#endif +printf("Time for full encryptions is %f rusage %f real\n", vtime1, rtime1); + loopcount = loops; + (void) gettimeofday(&tstart, (struct timezone *)0); + (void) getrusage(RUSAGE_SELF, &rstart); + + while (loopcount-- > 0) { + auth1crypt((loops & 0xf) + domd5, pkt, 48); + } + + (void) getrusage(RUSAGE_SELF, &rend); + (void) gettimeofday(&tend, (struct timezone *)0); + + subtime(&tstart, &tend, &rtime2); +#ifdef FAKE_RUSAGE + vtime2 = (rend.tms_utime - rstart.tms_utime) * 1.0 / HZ; +#else + subtime(&rstart.ru_utime, &rend.ru_utime, &vtime2); +#endif + +printf("Time for auth1crypt is %f rusage %f real\n", vtime2, rtime2); + vtime = vtime1 - vtime2; + rtime = rtime1 - rtime2; +} + + +/* + * docheap - do the cost measurement the cheap way + */ +static void +docheap(loops) + register int loops; +{ + + (void) authhavekey(3 + domd5); + + (void) gettimeofday(&tstart, (struct timezone *)0); + (void) getrusage(RUSAGE_SELF, &rstart); + + while (loops-- > 0) { + auth1crypt(3 + domd5, pkt, 48); + L_ADDUF(&dummy1, dummy3); + auth2crypt(3 + domd5, pkt, 48); + (void) authdecrypt(3 + domd5, pkt, 48); + } + + (void) getrusage(RUSAGE_SELF, &rend); + (void) gettimeofday(&tend, (struct timezone *)0); + + subtime(&tstart, &tend, &rtime); +#ifdef FAKE_RUSAGE + vtime = (rend.tms_utime - rstart.tms_utime) * 1.0 / HZ; +#else + subtime(&rstart.ru_utime, &rend.ru_utime, &vtime); +#endif +} + + +/* + * docost - do the cost measurement + */ +static void +docost(loops) + register int loops; +{ + + (void) gettimeofday(&tstart, (struct timezone *)0); + (void) getrusage(RUSAGE_SELF, &rstart); + + while (loops-- > 0) { + auth1crypt((loops & 0xf) + domd5, pkt, 48); + L_ADDUF(&dummy1, dummy3); + auth2crypt((loops & 0xf) + domd5, pkt, 48); + (void) authdecrypt(((loops+1) & 0xf) + domd5, pkt, 48); + } + + (void) getrusage(RUSAGE_SELF, &rend); + (void) gettimeofday(&tend, (struct timezone *)0); + + subtime(&tstart, &tend, &rtime); +#ifdef FAKE_RUSAGE + vtime = (rend.tms_utime - rstart.tms_utime) * 1.0 / HZ; +#else + subtime(&rstart.ru_utime, &rend.ru_utime, &vtime); +#endif +} + + +/* + * subtime - subtract two struct timevals, return double result + */ +static void +subtime(tvs, tve, res) + struct timeval *tvs, *tve; + double *res; +{ + LONG sec; + LONG usec; + + sec = tve->tv_sec - tvs->tv_sec; + usec = tve->tv_usec - tvs->tv_usec; + + if (usec < 0) { + usec += 1000000; + sec--; + } + + *res = (double)sec + (double)usec/1000000.; + return; +} diff --git a/contrib/xntpd/authstuff/certdata b/contrib/xntpd/authstuff/certdata new file mode 100644 index 0000000000..f9a818efec --- /dev/null +++ b/contrib/xntpd/authstuff/certdata @@ -0,0 +1,34 @@ +0000000000000000 0000000000000000 8CA64DE9C1B123A7 +FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7359B2163E4EDC58 +3000000000000000 1000000000000001 958E6E627A05557B +1111111111111111 1111111111111111 F40379AB9E0EC533 +0123456789ABCDEF 1111111111111111 17668DFC7292532D +1111111111111111 0123456789ABCDEF 8A5AE1F81AB8F2DD +0000000000000000 0000000000000000 8CA64DE9C1B123A7 +FEDCBA9876543210 0123456789ABCDEF ED39D950FA74BCC4 +7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B +0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271 +07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A +3849674C2602319E 51454B582DDF440A 7178876E01F19B2A +04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095 +0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B +0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09 +43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A +07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F +04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088 +37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77 +1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A +584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56 +025816164629B007 480D39006EE762F2 A1F9915541020B56 +49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556 +4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC +49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A +018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41 +1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793 +0101010101010101 0123456789ABCDEF 617B3A0CE8F07100 +1F1F1F1F0E0E0E0E 0123456789ABCDEF DB958605F8C8C606 +E0FEE0FEF1FEF1FE 0123456789ABCDEF EDBFD1C66C29CCC7 +0000000000000000 FFFFFFFFFFFFFFFF 355550B2150E2451 +FFFFFFFFFFFFFFFF 0000000000000000 CAAAAF4DEAF1DBAE +0123456789ABCDEF 0000000000000000 D5D44FF720683D0D +FEDCBA9876543210 FFFFFFFFFFFFFFFF 2A2BB008DF97C2F2 diff --git a/contrib/xntpd/authstuff/keyparity.c b/contrib/xntpd/authstuff/keyparity.c new file mode 100644 index 0000000000..45a706173b --- /dev/null +++ b/contrib/xntpd/authstuff/keyparity.c @@ -0,0 +1,279 @@ +/* keyparity.c,v 3.1 1993/07/06 01:04:57 jbj Exp + * keyparity - add parity bits to key and/or change an ascii key to binary + */ + +#include +#include +#include + +#include "ntp_string.h" +#include "ntp_stdlib.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +/* + * Types of ascii representations for keys. "Standard" means a 64 bit + * hex number in NBS format, i.e. with the low order bit of each byte + * a parity bit. "NTP" means a 64 bit key in NTP format, with the + * high order bit of each byte a parity bit. "Ascii" means a 1-to-8 + * character string whose ascii representation is used as the key. + */ +#define KEY_TYPE_STD 1 +#define KEY_TYPE_NTP 2 +#define KEY_TYPE_ASCII 3 + +#define STD_PARITY_BITS 0x01010101 + +char *progname; +int debug; + +int ntpflag = 0; +int stdflag = 0; +int asciiflag = 0; +int ntpoutflag = 0; +int gotoopt = 0; + +static int parity P((U_LONG *)); +static int decodekey P((int, char *, U_LONG *)); +static void output P((U_LONG *, int)); + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + int keytype; + U_LONG key[2]; + extern int optind; + extern char *optarg; + + progname = argv[0]; + while ((c = getopt_l(argc, argv, "adno:s")) != EOF) + switch (c) { + case 'a': + asciiflag = 1; + break; + case 'd': + ++debug; + break; + case 'n': + ntpflag = 1; + break; + case 's': + stdflag = 1; + break; + case 'o': + if (*optarg == 'n') { + ntpoutflag = 1; + gotoopt = 1; + } else if (*optarg == 's') { + ntpoutflag = 0; + gotoopt = 1; + } else { + (void) fprintf(stderr, + "%s: output format must be `n' or `s'\n", + progname); + errflg++; + } + break; + default: + errflg++; + break; + } + if (errflg || optind == argc) { + (void) fprintf(stderr, + "usage: %s -n|-s [-a] [-o n|s] key [...]\n", + progname); + exit(2); + } + + if (!ntpflag && !stdflag) { + (void) fprintf(stderr, + "%s: one of either the -n or -s flags must be specified\n", + progname); + exit(2); + } + + if (ntpflag && stdflag) { + (void) fprintf(stderr, + "%s: only one of the -n and -s flags may be specified\n", + progname); + exit(2); + } + + if (!gotoopt) { + if (ntpflag) + ntpoutflag = 1; + } + + if (asciiflag) + keytype = KEY_TYPE_ASCII; + else if (ntpflag) + keytype = KEY_TYPE_NTP; + else + keytype = KEY_TYPE_STD; + + for (; optind < argc; optind++) { + if (!decodekey(keytype, argv[optind], key)) { + (void) fprintf(stderr, + "%s: format of key %s invalid\n", + progname, argv[optind]); + exit(1); + } + (void) parity(key); + output(key, ntpoutflag); + } + exit(0); +} + + + +/* + * parity - set parity on a key/check for odd parity + */ +static int +parity(key) + U_LONG *key; +{ + U_LONG mask; + int parity_err; + int bitcount; + int half; + int byte; + int i; + + /* + * Go through counting bits in each byte. Check to see if + * each parity bit was set correctly. If not, note the error + * and set it right. + */ + parity_err = 0; + for (half = 0; half < 2; half++) { /* two halves of key */ + mask = 0x80000000; + for (byte = 0; byte < 4; byte++) { /* 4 bytes per half */ + bitcount = 0; + for (i = 0; i < 7; i++) { /* 7 data bits / byte */ + if (key[half] & mask) + bitcount++; + mask >>= 1; + } + + /* + * If bitcount is even, parity must be set. If + * bitcount is odd, parity must be clear. + */ + if ((bitcount & 0x1) == 0) { + if (!(key[half] & mask)) { + parity_err++; + key[half] |= mask; + } + } else { + if (key[half] & mask) { + parity_err++; + key[half] &= ~mask; + } + } + mask >>= 1; + } + } + + /* + * Return the result of the parity check. + */ + return (parity_err == 0); +} + + +static int +decodekey(keytype, str, key) + int keytype; + char *str; + U_LONG *key; +{ + u_char keybytes[8]; + char *cp; + char *xdigit; + int len; + int i; + static char *hex = "0123456789abcdef"; + + cp = str; + len = strlen(cp); + if (len == 0) + return 0; + + switch(keytype) { + case KEY_TYPE_STD: + case KEY_TYPE_NTP: + if (len != 16) /* Lazy. Should define constant */ + return 0; + /* + * Decode hex key. + */ + key[0] = 0; + key[1] = 0; + for (i = 0; i < 16; i++) { + if (!isascii(*cp)) + return 0; + xdigit = strchr(hex, isupper(*cp) ? tolower(*cp) : *cp); + cp++; + if (xdigit == 0) + return 0; + key[i>>3] <<= 4; + key[i>>3] |= (U_LONG)(xdigit - hex) & 0xf; + } + + /* + * If this is an NTP format key, put it into NBS format + */ + if (keytype == KEY_TYPE_NTP) { + for (i = 0; i < 2; i++) + key[i] = ((key[i] << 1) & ~STD_PARITY_BITS) + | ((key[i] >> 7) & STD_PARITY_BITS); + } + break; + + case KEY_TYPE_ASCII: + /* + * Make up key from ascii representation + */ + bzero(keybytes, sizeof(keybytes)); + for (i = 0; i < 8 && i < len; i++) + keybytes[i] = *cp++ << 1; + key[0] = keybytes[0] << 24 | keybytes[1] << 16 + | keybytes[2] << 8 | keybytes[3]; + key[1] = keybytes[4] << 24 | keybytes[5] << 16 + | keybytes[6] << 8 | keybytes[7]; + break; + + default: + /* Oh, well */ + return 0; + } + + return 1; +} + + +/* + * output - print a hex key on the standard output + */ +static void +output(key, ntpformat) + U_LONG *key; + int ntpformat; +{ + int i; + + if (ntpformat) { + for (i = 0; i < 2; i++) + key[i] = ((key[i] & ~STD_PARITY_BITS) >> 1) + | ((key[i] & STD_PARITY_BITS) << 7); + } + (void) printf("%08x%08x\n", key[0], key[1]); +} diff --git a/contrib/xntpd/authstuff/makeIPFP.c b/contrib/xntpd/authstuff/makeIPFP.c new file mode 100644 index 0000000000..51f8a55e72 --- /dev/null +++ b/contrib/xntpd/authstuff/makeIPFP.c @@ -0,0 +1,345 @@ +/* makeIPFP.c,v 3.1 1993/07/06 01:04:58 jbj Exp + * makeIPFP - make fast DES IP and FP tables + */ + +#include +#include + +#include "ntp_stdlib.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +U_LONG IPL[256]; +U_LONG FPL[256]; + +char *progname; +int debug; + +static void perm P((u_char *, u_char *, U_LONG *, U_LONG *)); +static void doit P((void)); + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + + progname = argv[0]; + while ((c = getopt_l(argc, argv, "d")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + default: + errflg++; + break; + } + if (errflg) { + (void) fprintf(stderr, "usage: %s [-d]\n", progname); + exit(2); + } + doit(); + exit(0); +} + + +/* + * Initial permutation table + */ +u_char IP[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7 +}; + +/* + * Inverse initial permutation table + */ +u_char FP[64] = { + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25 +}; + + +/* + * Bit order after the operation + * + * ((left & 0x55555555) << 1) | (right & 0x55555555) + */ +u_char IPLbits[32] = { + 2, 34, 4, 36, 6, 38, 8, 40, + 10, 42, 12, 44, 14, 46, 16, 48, + 18, 50, 20, 52, 22, 54, 24, 56, + 26, 58, 28, 60, 30, 62, 32, 64 +}; + + +/* + * Bit order after the operation + * + * (left & 0xaaaaaaaa) | ((right & 0xaaaaaaaa) >> 1) + */ +u_char IPRbits[32] = { + 1, 33, 3, 35, 5, 37, 7, 39, + 9, 41, 11, 43, 13, 45, 15, 47, + 17, 49, 19, 51, 21, 53, 23, 55, + 25, 57, 27, 59, 29, 61, 31, 63 +}; + + +/* + * Bit order after the operation + * + * ((left & 0x0f0f0f0f) << 4) | (right & 0x0f0f0f0f) + */ +u_char FPLbits[32] = { + 5, 6, 7, 8, 37, 38, 39, 40, + 13, 14, 15, 16, 45, 46, 47, 48, + 21, 22, 23, 24, 53, 54, 55, 56, + 29, 30, 31, 32, 61, 62, 63, 64 +}; + + +/* + * Bit order after the operation + * + * (left & 0xf0f0f0f0) | ((right & 0xf0f0f0f0) >> 4) + */ +u_char FPRbits[32] = { + 1, 2, 3, 4, 33, 34, 35, 36, + 9, 10, 11, 12, 41, 42, 43, 44, + 17, 18, 19, 20, 49, 50, 51, 52, + 25, 26, 27, 28, 57, 58, 59, 60 +}; + + +/* + * perm - do a permutation with the given table + */ +static void +perm(databits, permtab, leftp, rightp) + u_char *databits; + u_char *permtab; + U_LONG *leftp; + U_LONG *rightp; +{ + register U_LONG left; + register U_LONG right; + register u_char *PT; + register u_char *bits; + register int i; + + left = right = 0; + PT = permtab; + bits = databits; + + for (i = 0; i < 32; i++) { + left <<= 1; + if (bits[PT[i]-1]) + left |= 1; + } + + for (i = 32; i < 64; i++) { + right <<= 1; + if (bits[PT[i]-1]) + right |= 1; + } + + *leftp = left; + *rightp = right; +} + + +/* + * doit - make up the tables + */ +static void +doit() +{ + u_char bits[64]; + U_LONG left; + U_LONG right; + int tabno; + int i; + int ind0, ind1, ind2, ind3; + int ind4, ind5, ind6, ind7; + int octbits; + + bzero((char *)bits, sizeof bits); + + /* + * Do the rounds for the IP table. We save the results of + * this as well as printing them. Note that this is the + * left-half table, the right half table will be identical. + */ + printf("static U_LONG IP[256] = {"); + for (tabno = 0; tabno < 4; tabno++) { + i = tabno * 8; + ind7 = IPLbits[i] - 1; + ind6 = IPLbits[i+1] - 1; + ind5 = IPLbits[i+2] - 1; + ind4 = IPLbits[i+3] - 1; + ind3 = IPLbits[i+4] - 1; + ind2 = IPLbits[i+5] - 1; + ind1 = IPLbits[i+6] - 1; + ind0 = IPLbits[i+7] - 1; + for (octbits = 0; octbits < 256; octbits++) { + if (octbits & (1 << 7)) + bits[ind7] = 1; + if (octbits & (1 << 6)) + bits[ind6] = 1; + if (octbits & (1 << 5)) + bits[ind5] = 1; + if (octbits & (1 << 4)) + bits[ind4] = 1; + if (octbits & (1 << 3)) + bits[ind3] = 1; + if (octbits & (1 << 2)) + bits[ind2] = 1; + if (octbits & (1 << 1)) + bits[ind1] = 1; + if (octbits & 1) + bits[ind0] = 1; + perm(bits, IP, &left, &right); + bits[ind7] = 0; + bits[ind6] = 0; + bits[ind5] = 0; + bits[ind4] = 0; + bits[ind3] = 0; + bits[ind2] = 0; + bits[ind1] = 0; + bits[ind0] = 0; + if (right != 0) { + fprintf(stderr, + "IP tabno %d oct %d right not zero\n", + tabno, octbits); + exit(1); + } + if (tabno > 0) { + if ((IPL[octbits] << tabno) != left) { + fprintf(stderr, + "IP tabno %d oct %d IP %d left %d, IP != left\n", + tabno, octbits, IPL[octbits], left); + exit (1); + } + } else { + IPL[octbits] = left; + if (octbits == 255) { + printf(" 0x%08x", left); + } else if (octbits & 0x3) { + printf(" 0x%08x,", left); + } else { + printf("\n\t0x%08x,", left); + } + } + } + if (tabno == 0) + printf("\n};\n\n"); + } + + /* + * Next is the FP table, in big endian order + */ + printf("#if BYTE_ORDER == LITTLE_ENDIAN\nstatic U_LONG FP[256] = {"); + for (tabno = 3; tabno >= 0; tabno--) { + i = tabno * 8; + ind7 = FPLbits[i] - 1; + ind6 = FPLbits[i+1] - 1; + ind5 = FPLbits[i+2] - 1; + ind4 = FPLbits[i+3] - 1; + ind3 = FPLbits[i+4] - 1; + ind2 = FPLbits[i+5] - 1; + ind1 = FPLbits[i+6] - 1; + ind0 = FPLbits[i+7] - 1; + for (octbits = 0; octbits < 256; octbits++) { + if (octbits & (1 << 7)) + bits[ind7] = 1; + if (octbits & (1 << 6)) + bits[ind6] = 1; + if (octbits & (1 << 5)) + bits[ind5] = 1; + if (octbits & (1 << 4)) + bits[ind4] = 1; + if (octbits & (1 << 3)) + bits[ind3] = 1; + if (octbits & (1 << 2)) + bits[ind2] = 1; + if (octbits & (1 << 1)) + bits[ind1] = 1; + if (octbits & 1) + bits[ind0] = 1; + perm(bits, FP, &left, &right); + bits[ind7] = 0; + bits[ind6] = 0; + bits[ind5] = 0; + bits[ind4] = 0; + bits[ind3] = 0; + bits[ind2] = 0; + bits[ind1] = 0; + bits[ind0] = 0; + if (right != 0) { + fprintf(stderr, + "FP tabno %d oct %d right not zero\n", + tabno, octbits); + exit(1); + } + if (tabno != 3) { + if ((FPL[octbits] << ((3-tabno)<<1)) != left) { + fprintf(stderr, + "FP tabno %d oct %d FP %x left %x, FP != left\n", + tabno, octbits, FPL[octbits], left); + exit (1); + } + } else { + FPL[octbits] = left; + if (octbits == 255) { + printf(" 0x%08x", left); + } else if (octbits & 0x3) { + printf(" 0x%08x,", left); + } else { + printf("\n\t0x%08x,", left); + } + } + } + if (tabno == 3) + printf("\n};\n"); + } + + /* + * Now reouput the FP table in order appropriate for little + * endian machines + */ + printf("#else\nstatic U_LONG FP[256] = {"); + for (octbits = 0; octbits < 256; octbits++) { + left = ((FPL[octbits] >> 24) & 0x000000ff) + | ((FPL[octbits] >> 8) & 0x0000ff00) + | ((FPL[octbits] << 8) & 0x00ff0000) + | ((FPL[octbits] << 24) & 0xff000000); + if (octbits == 255) { + printf(" 0x%08x", left); + } else if (octbits & 0x3) { + printf(" 0x%08x,", left); + } else { + printf("\n\t0x%08x,", left); + } + } + printf("\n};\n#endif\n"); +} diff --git a/contrib/xntpd/authstuff/makePC1.c b/contrib/xntpd/authstuff/makePC1.c new file mode 100644 index 0000000000..c0109892fa --- /dev/null +++ b/contrib/xntpd/authstuff/makePC1.c @@ -0,0 +1,286 @@ +/* makePC1.c,v 3.1 1993/07/06 01:04:59 jbj Exp + * makePC1 - build custom permutted choice 1 tables + */ + +#include +#include + +#include "ntp_stdlib.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +char *progname; +int debug; + +static void permute P((u_char *, U_LONG *, U_LONG *)); +static void doit P((void)); + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + + progname = argv[0]; + while ((c = getopt_l(argc, argv, "d")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + default: + errflg++; + break; + } + if (errflg) { + (void) fprintf(stderr, "usage: %s [-d]\n", progname); + exit(2); + } + doit(); + exit(0); +} + +/* + * Permuted choice 1 table, to produce the initial C. This table + * has had 1 subtracted from it to give it a zero base. + */ +static u_char PC1_C[28] = { + 56, 48, 40, 32, 24, 16, 8, + 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, + 18, 10, 2, 59, 51, 43, 35 +}; + +/* + * Permuted choice 1 table, to produce the initial D. Again, 1 has + * been subtracted to match C language zero base arrays. + */ +static u_char PC1_D[28] = { + 62, 54, 46, 38, 30, 22, 14, + 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, + 20, 12, 4, 27, 19, 11, 3 +}; + +/* + * permute - produce c and d for the given bits + */ +static void +permute(bits, cp, dp) + u_char *bits; + U_LONG *cp; + U_LONG *dp; +{ + register int i; + register U_LONG mask; + u_char c[28]; + u_char d[28]; + + bzero((char *)c, sizeof c); + bzero((char *)d, sizeof d); + + for (i = 0; i < 28; i++) { + c[i] = bits[PC1_C[i]]; + d[i] = bits[PC1_D[i]]; + } + + mask = 0x10000000; + *cp = *dp = 0; + for (i = 0; i < 28; i++) { + mask >>= 1; + if (c[i]) + *cp |= mask; + if (d[i]) + *dp |= mask; + } +} + + +/* + * bits from the left part of the key used to form the C subkey + */ +static int lc3[4] = { 0, 8, 16, 24 }; + +/* + * bits from the left part of the key used to form the D subkey + */ +static int ld4[4] = { 3, 11, 19, 27 }; + +/* + * bits from the right part of the key used to form the C subkey + */ +static int rc4[4] = { 32, 40, 48, 56 }; + +/* + * bits from the right part of the key used to form the D subkey + */ +static int rd3[4] = { 36, 44, 52, 60 }; + +static U_LONG PC_CL[8]; +static U_LONG PC_DL[16]; +static U_LONG PC_CR[16]; +static U_LONG PC_DR[8]; + + +/* + * doit - compute and print the four PC1 tables + */ +static void +doit() +{ + int i; + int comb; + U_LONG c; + U_LONG d; + u_char bits[64]; + + bzero((char *)bits, sizeof bits); + + printf("static U_LONG PC1_CL[8] = {"); + for (i = 0; i < 4; i++) { + for (comb = 0; comb < 8; comb++) { + if (comb & 0x4) + bits[lc3[i]] = 1; + if (comb & 0x2) + bits[lc3[i]+1] = 1; + if (comb & 0x1) + bits[lc3[i]+2] = 1; + permute(bits, &c, &d); + bits[lc3[i]] = 0; + bits[lc3[i]+1] = 0; + bits[lc3[i]+2] = 0; + if (d != 0) { + (void) fprintf(stderr, + "Error PC_CL i %d comb %d\n", i, comb); + } + if (i == 0) { + PC_CL[comb] = c; + if ((comb & 0x3) == 0) + printf("\n\t0x%08x,", c); + else if (comb == 7) + printf(" 0x%08x\n};\n\n", c); + else + printf(" 0x%08x,", c); + } else { + if (c != PC_CL[comb] << i) + (void) fprintf(stderr, + "Error PC_CL 0x%08x c 0x%08x\n", + PC_CL[comb], c); + } + } + } + + printf("static U_LONG PC1_DL[16] = {"); + for (i = 0; i < 4; i++) { + for (comb = 0; comb < 16; comb++) { + if (comb & 0x8) + bits[ld4[i]] = 1; + if (comb & 0x4) + bits[ld4[i]+1] = 1; + if (comb & 0x2) + bits[ld4[i]+2] = 1; + if (comb & 0x1) + bits[ld4[i]+3] = 1; + permute(bits, &c, &d); + bits[ld4[i]] = 0; + bits[ld4[i]+1] = 0; + bits[ld4[i]+2] = 0; + bits[ld4[i]+3] = 0; + if (c != 0) { + (void) fprintf(stderr, + "Error PC_DL i %d comb %d\n", i, comb); + } + if (i == 0) { + PC_DL[comb] = d; + if ((comb & 0x3) == 0) + printf("\n\t0x%08x,", d); + else if (comb == 15) + printf(" 0x%08x\n};\n\n", d); + else + printf(" 0x%08x,", d); + } else { + if (d != PC_DL[comb] << i) + (void) fprintf(stderr, + "Error PC_DL 0x%08x c 0x%08x\n", + PC_DL[comb], d); + } + } + } + + printf("static U_LONG PC1_CR[16] = {"); + for (i = 0; i < 4; i++) { + for (comb = 0; comb < 16; comb++) { + if (comb & 0x8) + bits[rc4[i]] = 1; + if (comb & 0x4) + bits[rc4[i]+1] = 1; + if (comb & 0x2) + bits[rc4[i]+2] = 1; + if (comb & 0x1) + bits[rc4[i]+3] = 1; + permute(bits, &c, &d); + bits[rc4[i]] = 0; + bits[rc4[i]+1] = 0; + bits[rc4[i]+2] = 0; + bits[rc4[i]+3] = 0; + if (d != 0) { + (void) fprintf(stderr, + "Error PC_CR i %d comb %d\n", i, comb); + } + if (i == 0) { + PC_CR[comb] = c; + if ((comb & 0x3) == 0) + printf("\n\t0x%08x,", c); + else if (comb == 15) + printf(" 0x%08x\n};\n\n", c); + else + printf(" 0x%08x,", c); + } else { + if (c != PC_CR[comb] << i) + (void) fprintf(stderr, + "Error PC_CR 0x%08x c 0x%08x\n", + PC_CR[comb], c); + } + } + } + + printf("static U_LONG PC1_DR[8] = {"); + for (i = 0; i < 4; i++) { + for (comb = 0; comb < 8; comb++) { + if (comb & 0x4) + bits[rd3[i]] = 1; + if (comb & 0x2) + bits[rd3[i]+1] = 1; + if (comb & 0x1) + bits[rd3[i]+2] = 1; + permute(bits, &c, &d); + bits[rd3[i]] = 0; + bits[rd3[i]+1] = 0; + bits[rd3[i]+2] = 0; + if (c != 0) { + (void) fprintf(stderr, + "Error PC_DR i %d comb %d\n", i, comb); + } + if (i == 0) { + PC_DR[comb] = d; + if ((comb & 0x3) == 0) + printf("\n\t0x%08x,", d); + else if (comb == 7) + printf(" 0x%08x\n};\n\n", d); + else + printf(" 0x%08x,", d); + } else { + if (d != PC_DR[comb] << i) + (void) fprintf(stderr, + "Error PC_DR 0x%08x c 0x%08x\n", + PC_DR[comb], d); + } + } + } +} diff --git a/contrib/xntpd/authstuff/makePC2.c b/contrib/xntpd/authstuff/makePC2.c new file mode 100644 index 0000000000..d92d2b2a9e --- /dev/null +++ b/contrib/xntpd/authstuff/makePC2.c @@ -0,0 +1,238 @@ +/* makePC2.c,v 3.1 1993/07/06 01:05:01 jbj Exp + * makePC2 - build custom permutted choice 2 tables + */ + +#include +#include + +#include "ntp_stdlib.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +char *progname; +int debug; + +static void permc P((u_char *, U_LONG *)); +static void permd P((u_char *, U_LONG *)); +static void doit P((void)); + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + + progname = argv[0]; + while ((c = getopt_l(argc, argv, "d")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + default: + errflg++; + break; + } + if (errflg) { + (void) fprintf(stderr, "usage: %s [-d]\n", progname); + exit(2); + } + doit(); + exit(0); +} + +/* + * Permuted choice 2 table. This actually produces the low order 24 + * bits of the subkey Ki from the 28 bit value of Ci. This has had + * 1 subtracted from it to give a zero base. + */ +static u_char PC2_C[24] = { + 13, 16, 10, 23, 0, 4, + 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, + 15, 6, 26, 19, 12, 1 +}; + +/* + * Permuted choice 2 table, operating on the 28 Di bits to produce the + * high order 24 bits of subkey Ki. This has had 29 subtracted from + * it to give it a zero base into our D bit array. + */ +static u_char PC2_D[24] = { + 12, 23, 2, 8, 18, 26, + 1, 11, 22, 16, 4, 19, + 15, 20, 10, 27, 5, 24, + 17, 13, 21, 7, 0, 3 +}; + +U_LONG masks[4] = { 0x40000000, 0x400000, 0x4000, 0x40 }; + + +/* + * permc - permute C, producing a four byte result + */ +static void +permc(bits, resp) + u_char *bits; + U_LONG *resp; +{ + register int part; + register int i; + register U_LONG mask; + u_char res[24]; + + bzero((char *)res, sizeof res); + + for (i = 0; i < 24; i++) { + res[i] = bits[PC2_C[i]]; + } + + *resp = 0; + for (part = 0; part < 4; part++) { + mask = masks[part]; + for (i = part*6; i < (part+1)*6; i++) { + mask >>= 1; + if (res[i]) + *resp |= mask; + } + } +} + +/* + * permd - permute D, producing a four byte result + */ +static void +permd(bits, resp) + u_char *bits; + U_LONG *resp; +{ + register int part; + register int i; + register U_LONG mask; + u_char res[24]; + + bzero((char *)res, sizeof res); + + for (i = 0; i < 24; i++) { + res[i] = bits[PC2_D[i]]; + } + + *resp = 0; + for (part = 0; part < 4; part++) { + mask = masks[part]; + for (i = part*6; i < (part+1)*6; i++) { + mask >>= 1; + if (res[i]) + *resp |= mask; + } + } +} + + +/* + * bits used for each round in C + */ +static int cbits[4][6] = { + 0, 1, 2, 3, 4, 5, + 6, 7, 9, 10, 11, 12, + 13, 14, 15, 16, 22, 23, + 18, 19, 20, 25, 26, 27 +}; + + +/* + * bits used for each round in D + */ +static int dbits[4][6] = { + 0, 1, 2, 3, 4, 5, + 7, 8, 10, 11, 12, 13, + 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 26, 27 +}; + + +/* + * doit - compute and print the four PC1 tables + */ +static void +doit() +{ + int i; + int comb; + U_LONG res; + u_char bits[28]; + + bzero((char *)bits, sizeof bits); + + printf("static U_LONG PC2_C[4][64] = {"); + for (i = 0; i < 4; i++) { + for (comb = 0; comb < 64; comb++) { + if (comb & 0x20) + bits[cbits[i][0]] = 1; + if (comb & 0x10) + bits[cbits[i][1]] = 1; + if (comb & 0x8) + bits[cbits[i][2]] = 1; + if (comb & 0x4) + bits[cbits[i][3]] = 1; + if (comb & 0x2) + bits[cbits[i][4]] = 1; + if (comb & 0x1) + bits[cbits[i][5]] = 1; + permc(bits, &res); + bits[cbits[i][0]] = 0; + bits[cbits[i][1]] = 0; + bits[cbits[i][2]] = 0; + bits[cbits[i][3]] = 0; + bits[cbits[i][4]] = 0; + bits[cbits[i][5]] = 0; + if ((comb & 0x3) == 0) + printf("\n\t0x%08x,", res); + else if (comb == 63 && i == 3) + printf(" 0x%08x\n};\n\n", res); + else if (comb == 63) + printf(" 0x%08x,\n", res); + else + printf(" 0x%08x,", res); + } + } + + printf("static U_LONG PC2_D[4][64] = {"); + for (i = 0; i < 4; i++) { + for (comb = 0; comb < 64; comb++) { + if (comb & 0x20) + bits[dbits[i][0]] = 1; + if (comb & 0x10) + bits[dbits[i][1]] = 1; + if (comb & 0x8) + bits[dbits[i][2]] = 1; + if (comb & 0x4) + bits[dbits[i][3]] = 1; + if (comb & 0x2) + bits[dbits[i][4]] = 1; + if (comb & 0x1) + bits[dbits[i][5]] = 1; + permd(bits, &res); + bits[dbits[i][0]] = 0; + bits[dbits[i][1]] = 0; + bits[dbits[i][2]] = 0; + bits[dbits[i][3]] = 0; + bits[dbits[i][4]] = 0; + bits[dbits[i][5]] = 0; + if ((comb & 0x3) == 0) + printf("\n\t0x%08x,", res); + else if (comb == 63 && i == 3) + printf(" 0x%08x\n};\n\n", res); + else if (comb == 63) + printf(" 0x%08x,\n", res); + else + printf(" 0x%08x,", res); + } + } +} diff --git a/contrib/xntpd/authstuff/makeSP.c b/contrib/xntpd/authstuff/makeSP.c new file mode 100644 index 0000000000..bfeb82c130 --- /dev/null +++ b/contrib/xntpd/authstuff/makeSP.c @@ -0,0 +1,183 @@ +/* makeSP.c,v 3.1 1993/07/06 01:05:02 jbj Exp + * makeSP - build combination S and P tables for quick DES computation + */ + +#include +#include + +#include "ntp_stdlib.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +char *progname; +int debug; + +static void selperm P((int, int, U_LONG *)); +static void doit P((void)); + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + + progname = argv[0]; + while ((c = getopt_l(argc, argv, "d")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + default: + errflg++; + break; + } + if (errflg) { + (void) fprintf(stderr, "usage: %s [-d]\n", progname); + exit(2); + } + doit(); + exit(0); +} + + +/* + * The cipher selection function tables. These turn 6 bit data back + * into 4 bit data. + */ +u_char S[8][64] = { + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, + + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, + + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, + + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, + + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, + + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, + + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, + + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 +}; + +/* + * Cipher function permutation table + */ +u_char PT[32] = { + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25 +}; + + +/* + * Bits array. We keep this zeroed. + */ +u_char bits[32]; + + +/* + * selperm - run six bit data through the given selection table, then + * through the PT table to produce a LONG output. + */ +static void +selperm(selnumber, sixbits, resp) + int selnumber; + int sixbits; + U_LONG *resp; +{ + register U_LONG res; + register int selno; + register int i; + register int ind; + + selno = selnumber; + i = sixbits; + ind = (i & 0x20) | ((i >> 1) & 0xf) | ((i & 0x1) << 4); + i = S[selno][ind]; + + for (ind = 0; ind < 4; ind++) { + if (i & 0x8) + bits[4*selno + ind] = 1; + i <<= 1; + } + + res = 0; + for (i = 0; i < 32; i++) { + res <<= 1; + if (bits[PT[i]-1]) + res |= 1; + } + + *resp = res; + bits[4*selno] = 0; + bits[4*selno + 1] = 0; + bits[4*selno + 2] = 0; + bits[4*selno + 3] = 0; +} + + +/* + * doit - compute and print the 8 SP tables + */ +static void +doit() +{ + int selno; + U_LONG result; + int sixbits; + + bzero((char *)bits, sizeof bits); + printf("static U_LONG SP[8][64] = {"); + for (selno = 0; selno < 8; selno++) { + for (sixbits = 0; sixbits < 64; sixbits++) { + selperm(selno, sixbits, &result); + if ((sixbits & 0x3) == 0) + printf("\n\t0x%08x,", result); + else if (sixbits == 63 && selno == 7) + printf(" 0x%08x\n};\n", result); + else if (sixbits == 63) + printf(" 0x%08x,\n", result); + else + printf(" 0x%08x,", result); + } + } +} diff --git a/contrib/xntpd/authstuff/md5_sample_output b/contrib/xntpd/authstuff/md5_sample_output new file mode 100644 index 0000000000..a7d4282d2e --- /dev/null +++ b/contrib/xntpd/authstuff/md5_sample_output @@ -0,0 +1,8 @@ +MD5 test suite results: +d41d8cd98f00b204e9800998ecf8427e "" +0cc175b9c0f1b6a831c399e269772661 "a" +900150983cd24fb0d6963f7d28e17f72 "abc" +f96b697d7cb7938d525a2f31aaf161d0 "message digest" +c3fcd3d76192e4007dfb496cca67e13b "abcdefghijklmnopqrstuvwxyz" +d174ab98d277d9f5a5611c2c9f419d9f "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" +57edf4a22be3c955ac49da2e2107b67a "12345678901234567890123456789012345678901234567890123456789012345678901234567890" diff --git a/contrib/xntpd/authstuff/md5driver.c b/contrib/xntpd/authstuff/md5driver.c new file mode 100644 index 0000000000..73db940598 --- /dev/null +++ b/contrib/xntpd/authstuff/md5driver.c @@ -0,0 +1,209 @@ +/* md5driver.c,v 3.1 1993/07/06 01:05:07 jbj Exp + *********************************************************************** + ** md5driver.c -- sample test routines ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/16/90 RLR ** + ** Updated: 1/91 SRD ** + ** Updated: 7/91 SRD Removed file "foo" from test suite ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#include +#include +#include +#ifdef __bsdi__ +#include +#endif /* __bsdi__ */ +#include "md5.h" + +#define MD5 +#include "ntp_string.h" +#include "ntp_stdlib.h" + +/* Prints message digest buffer in mdContext as 32 hexadecimal digits. + Order is from low-order byte to high-order byte of digest. + Each byte is printed with high-order hexadecimal digit first. + */ +static void +MDPrint (mdContext) +MD5_CTX *mdContext; +{ + int i; + + for (i = 0; i < 16; i++) + printf ("%02x", mdContext->digest[i]); +} + +/* size of test block */ +#define TEST_BLOCK_SIZE 1000 + +/* number of blocks to process */ +#define TEST_BLOCKS 10000 + +/* number of test bytes = TEST_BLOCK_SIZE * TEST_BLOCKS */ +static LONG TEST_BYTES = (LONG)TEST_BLOCK_SIZE * (LONG)TEST_BLOCKS; + +/* A time trial routine, to measure the speed of MD5. + Measures wall time required to digest TEST_BLOCKS * TEST_BLOCK_SIZE + characters. + */ +static void +MDTimeTrial () +{ + MD5_CTX mdContext; + time_t endTime, startTime; + unsigned char data[TEST_BLOCK_SIZE]; + unsigned int i; + + /* initialize test data */ + for (i = 0; i < TEST_BLOCK_SIZE; i++) + data[i] = (unsigned char)(i & 0xFF); + + /* start timer */ + printf ("MD5 time trial. Processing %ld characters...\n", TEST_BYTES); + time (&startTime); + + /* digest data in TEST_BLOCK_SIZE byte blocks */ + MD5Init (&mdContext); + for (i = TEST_BLOCKS; i > 0; i--) + MD5Update (&mdContext, data, TEST_BLOCK_SIZE); + MD5Final (&mdContext); + + /* stop timer, get time difference */ + time (&endTime); + MDPrint (&mdContext); + printf (" is digest of test input.\n"); + printf + ("Seconds to process test input: %ld\n", (LONG)(endTime-startTime)); + printf + ("Characters processed per second: %ld\n", + TEST_BYTES/(endTime-startTime)); +} + +/* Computes the message digest for string inString. + Prints out message digest, a space, the string (in quotes) and a + carriage return. + */ +static void +MDString (inString) +char *inString; +{ + MD5_CTX mdContext; + unsigned int len = strlen (inString); + + MD5Init (&mdContext); + MD5Update (&mdContext, inString, len); + MD5Final (&mdContext); + MDPrint (&mdContext); + printf (" \"%s\"\n", inString); +} + +/* Computes the message digest for a specified file. + Prints out message digest, a space, the file name, and a carriage + return. + */ +static void +MDFile (filename) +char *filename; +{ + FILE *inFile = fopen (filename, "rb"); + MD5_CTX mdContext; + int bytes; + unsigned char data[1024]; + + if (inFile == NULL) { + printf ("%s can't be opened.\n", filename); + return; + } + + MD5Init (&mdContext); + while ((bytes = fread (data, 1, 1024, inFile)) != 0) + MD5Update (&mdContext, data, bytes); + MD5Final (&mdContext); + MDPrint (&mdContext); + printf (" %s\n", filename); + fclose (inFile); +} + +/* Writes the message digest of the data from stdin onto stdout, + followed by a carriage return. + */ +static void +MDFilter () +{ + MD5_CTX mdContext; + int bytes; + unsigned char data[16]; + + MD5Init (&mdContext); + while ((bytes = fread (data, 1, 16, stdin)) != 0) + MD5Update (&mdContext, data, bytes); + MD5Final (&mdContext); + MDPrint (&mdContext); + printf ("\n"); +} + +/* Runs a standard suite of test data. + */ +static void +MDTestSuite () +{ + printf ("MD5 test suite results:\n"); + MDString (""); + MDString ("a"); + MDString ("abc"); + MDString ("message digest"); + MDString ("abcdefghijklmnopqrstuvwxyz"); + MDString + ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + MDString + ("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); +} + +void +main (argc, argv) +int argc; +char *argv[]; +{ + int i; + + /* For each command line argument in turn: + ** filename -- prints message digest and name of file + ** -sstring -- prints message digest and contents of string + ** -t -- prints time trial statistics for 10M + characters + ** -x -- execute a standard suite of test data + ** (no args) -- writes messages digest of stdin onto stdout + */ + if (argc == 1) + MDFilter (); + else + for (i = 1; i < argc; i++) + if (argv[i][0] == '-' && argv[i][1] == 's') + MDString (argv[i] + 2); + else if (strcmp (argv[i], "-t") == 0) + MDTimeTrial (); + else if (strcmp (argv[i], "-x") == 0) + MDTestSuite (); + else MDFile (argv[i]); +} + +/* + *********************************************************************** + ** End of md5driver.c ** + ******************************** (cut) ******************************** + */ diff --git a/contrib/xntpd/authstuff/mkrandkeys.c b/contrib/xntpd/authstuff/mkrandkeys.c new file mode 100644 index 0000000000..3bb987af8f --- /dev/null +++ b/contrib/xntpd/authstuff/mkrandkeys.c @@ -0,0 +1,167 @@ +/* mkrandkeys.c,v 3.1 1993/07/06 01:05:08 jbj Exp + * mkrandkeys - make a key file for xntpd with some quite random keys + */ +#include +#include +#include + +#include "ntp_stdlib.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +char *progname; +int debug; + +U_LONG keydata[2]; + +int std = 1; /* DES standard key format */ +u_char dokey[16] = { 0 }; + +static void rand_data P((U_LONG *)); + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int i; + int j; + int errflg = 0; + int numkeys; + U_LONG tmp; + char *passwd; + extern int optind; + extern char *optarg; + extern char *getpass(); + + numkeys = 0; + progname = argv[0]; + passwd = NULL; + while ((c = getopt_l(argc, argv, "dnp:s")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + case 'n': + std = 0; + break; + case 'p': + passwd = optarg; + break; + case 's': + std = 1; + break; + default: + errflg++; + break; + } + + numkeys = 0; + for (; !errflg && optind < argc; optind++) { + c = atoi(argv[optind]); + if (c <= 0 || c > 15) { + (void) fprintf("%s: invalid key number `%s'\n", + progname, argv[optind]); + exit(2); + } + dokey[c] = 1; + numkeys++; + } + + if (errflg || numkeys == 0) { + (void) fprintf(stderr, + "usage: %s [-ns] [-p seed] key# [key# ...]\n", + progname); + exit(2); + } + + while (passwd == 0 || *passwd == '\0') { + passwd = getpass("Seed: "); + if (*passwd == '\0') { + (void) fprintf(stderr, + "better use a better seed than that\n"); + } + } + + keydata[0] = keydata[1] = 0; + for (i = 0; i < 8 && *passwd != '\0'; i++) { + keydata[i/4] |= ((((U_LONG)(*passwd))&0xff)<<(1+((3-(i%4))*8))); + passwd++; + } + + for (i = 1; i <= 15; i++) { + if (dokey[i]) { + for (c = 0, tmp = 0; c < 32; c += 4) + tmp |= (i << c); + keydata[0] ^= tmp; + keydata[1] ^= tmp; + rand_data(keydata); + DESauth_parity(keydata); + + if (std) { + (void)printf("%-2d S\t%08x%08x\n", + i, keydata[0], keydata[1]); + } else { + for (j = 0; j < 2; j++) { + keydata[j] + = ((keydata[j] & 0xfefefefe) >> 1) + | ((keydata[j] & 0x01010101) << 7); + } + (void)printf("%-2d N\t%08x%08x\n", + i, keydata[0], keydata[1]); + } + } + } + exit(0); +} + +char *volatile_file[] = { + "/bin/echo", + "/bin/sh", + "/bin/cat", + "/bin/ls", + "/bin/stty", + "/bin/date", + "/bin/cat", + "/bin/cc", + "/etc/motd", + "/etc/utmp", + "/dev/kmem", + "/dev/null", + "", +}; + +#define NEXT(X) (0x1e1f2f2d*(X) + 0x361962e9) + +static void +rand_data(data) + U_LONG *data; +{ + register i; + struct stat buf; + extern LONG time(); + char ekeys[128], dkeys[128]; + + *data ^= 0x9662f394; + *(data+1) ^= 0x9f17c55f; + DESauth_subkeys(data, ekeys, dkeys); + *data ^= NEXT(getpid() + (getuid() << 16)); + *(data+1) ^= NEXT(time((LONG *)0)); + DESauth_des(data, ekeys); + for (i = 0; strlen(volatile_file[i]); i++) { + if (stat(volatile_file[i], &buf) == -1) + continue; + if (i & 1) { + *data ^= NEXT(buf.st_atime); + *(data+1) ^= NEXT(buf.st_mtime); + } else { + *data ^= NEXT(buf.st_mtime); + *(data+1) ^= NEXT(buf.st_atime); + } + DESauth_des(data, ekeys); + } +} diff --git a/contrib/xntpd/authstuff/omakeIPFP.c b/contrib/xntpd/authstuff/omakeIPFP.c new file mode 100644 index 0000000000..887cc58c28 --- /dev/null +++ b/contrib/xntpd/authstuff/omakeIPFP.c @@ -0,0 +1,361 @@ +/* omakeIPFP.c,v 3.1 1993/07/06 01:05:10 jbj Exp + * makeIPFP - make fast DES IP and FP tables + * + * This is an older version which generated tables half the size of + * the current version, but which took about double the CPU time to + * compute permutations from these tables. Since the CPU spent on the + * permutations is small compared to the CPU spent in the cipher code, + * I may go back to the smaller tables to save the space some day. + */ + +#include +#include + +#include "ntp_stdlib.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +U_LONG IPL[8][16]; +U_LONG FPL[8][16]; + +char *progname; +int debug; + +static void perm P((u_char *, u_char *, U_LONG *, U_LONG *)); +static void doit P((void)); + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + + progname = argv[0]; + while ((c = getopt_l(argc, argv, "d")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + default: + errflg++; + break; + } + if (errflg) { + (void) fprintf(stderr, "usage: %s [-d]\n", progname); + exit(2); + } + doit(); + exit(0); +} + + +/* + * Initial permutation table + */ +u_char IP[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7 +}; + +/* + * Inverse initial permutation table + */ +u_char FP[64] = { + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25 +}; + + +/* + * Bit order after the operation + * + * ((left & 0x55555555) << 1) | (right & 0x55555555) + */ +u_char IPLbits[32] = { + 2, 34, 4, 36, 6, 38, 8, 40, + 10, 42, 12, 44, 14, 46, 16, 48, + 18, 50, 20, 52, 22, 54, 24, 56, + 26, 58, 28, 60, 30, 62, 32, 64 +}; + + +/* + * Bit order after the operation + * + * (left & 0xaaaaaaaa) | ((right & 0xaaaaaaaa) >> 1) + */ +u_char IPRbits[32] = { + 1, 33, 3, 35, 5, 37, 7, 39, + 9, 41, 11, 43, 13, 45, 15, 47, + 17, 49, 19, 51, 21, 53, 23, 55, + 25, 57, 27, 59, 29, 61, 31, 63 +}; + + +/* + * Bit order after the operation + * + * ((left & 0x0f0f0f0f) << 4) | (right & 0x0f0f0f0f) + */ +u_char FPLbits[32] = { + 5, 6, 7, 8, 37, 38, 39, 40, + 13, 14, 15, 16, 45, 46, 47, 48, + 21, 22, 23, 24, 53, 54, 55, 56, + 29, 30, 31, 32, 61, 62, 63, 64 +}; + + +/* + * Bit order after the operation + * + * (left & 0xf0f0f0f0) | ((right & 0xf0f0f0f0) >> 4) + */ +u_char FPRbits[32] = { + 1, 2, 3, 4, 33, 34, 35, 36, + 9, 10, 11, 12, 41, 42, 43, 44, + 17, 18, 19, 20, 49, 50, 51, 52, + 25, 26, 27, 28, 57, 58, 59, 60 +}; + + +/* + * perm - do a permutation with the given table + */ +static void +perm(databits, permtab, leftp, rightp) + u_char *databits; + u_char *permtab; + U_LONG *leftp; + U_LONG *rightp; +{ + register U_LONG left; + register U_LONG right; + register u_char *PT; + register u_char *bits; + register int i; + + left = right = 0; + PT = permtab; + bits = databits; + + for (i = 0; i < 32; i++) { + left <<= 1; + if (bits[PT[i]-1]) + left |= 1; + } + + for (i = 32; i < 64; i++) { + right <<= 1; + if (bits[PT[i]-1]) + right |= 1; + } + + *leftp = left; + *rightp = right; +} + + +/* + * doit - make up the tables + */ +static void +doit() +{ + u_char bits[64]; + U_LONG left; + U_LONG right; + int tabno; + int i; + int ind0, ind1, ind2, ind3; + int quadbits; + + bzero((char *)bits, sizeof bits); + + /* + * Do the rounds for the IPL table. We save the results of + * this as well as printing them. Note that this is the + * left-half table. + */ + printf("static U_LONG IP[8][16] = {"); + for (tabno = 0; tabno < 8; tabno++) { + i = tabno * 4; + ind3 = IPLbits[i] - 1; + ind2 = IPLbits[i+1] - 1; + ind1 = IPLbits[i+2] - 1; + ind0 = IPLbits[i+3] - 1; + for (quadbits = 0; quadbits < 16; quadbits++) { + if (quadbits & (1 << 3)) + bits[ind3] = 1; + if (quadbits & (1 << 2)) + bits[ind2] = 1; + if (quadbits & (1 << 1)) + bits[ind1] = 1; + if (quadbits & 1) + bits[ind0] = 1; + perm(bits, IP, &left, &right); + bits[ind3] = 0; + bits[ind2] = 0; + bits[ind1] = 0; + bits[ind0] = 0; + if (right != 0) { + fprintf(stderr, + "IPL tabno %d quad %d right not zero\n", + tabno, quadbits); + exit(1); + } + IPL[tabno][quadbits] = left; + if (quadbits == 15 && tabno == 7) { + printf(" 0x%08x", left); + } else if (quadbits & 0x3) { + printf(" 0x%08x,", left); + } else { + printf("\n\t0x%08x,", left); + } + } + if (tabno == 7) + printf("\n};\n"); + printf("\n"); + } + + /* + * Compute the right half of the same table. I noticed this table + * was the same as the previous one, just by luck, so we don't + * actually have to do this. Do it anyway just for a check. + */ + for (tabno = 0; tabno < 8; tabno++) { + i = tabno * 4; + ind3 = IPRbits[i] - 1; + ind2 = IPRbits[i+1] - 1; + ind1 = IPRbits[i+2] - 1; + ind0 = IPRbits[i+3] - 1; + for (quadbits = 0; quadbits < 16; quadbits++) { + if (quadbits & (1 << 3)) + bits[ind3] = 1; + if (quadbits & (1 << 2)) + bits[ind2] = 1; + if (quadbits & (1 << 1)) + bits[ind1] = 1; + if (quadbits & 1) + bits[ind0] = 1; + perm(bits, IP, &left, &right); + bits[ind3] = 0; + bits[ind2] = 0; + bits[ind1] = 0; + bits[ind0] = 0; + if (left != 0) { + fprintf(stderr, + "IPR tabno %d quad %d left not zero\n", + tabno, quadbits); + exit(1); + } + if (right != IPL[tabno][quadbits]) { + fprintf(stderr, + "IPR tabno %d quad %d: 0x%08x not same as 0x%08x\n", + tabno, quadbits, right,IPL[tabno][quadbits]); + exit(1); + } + } + } + + /* + * Next are the FP tables + */ + printf("static U_LONG FP[8][16] = {"); + for (tabno = 0; tabno < 8; tabno++) { + i = tabno * 4; + ind3 = FPLbits[i] - 1; + ind2 = FPLbits[i+1] - 1; + ind1 = FPLbits[i+2] - 1; + ind0 = FPLbits[i+3] - 1; + for (quadbits = 0; quadbits < 16; quadbits++) { + if (quadbits & (1 << 3)) + bits[ind3] = 1; + if (quadbits & (1 << 2)) + bits[ind2] = 1; + if (quadbits & (1 << 1)) + bits[ind1] = 1; + if (quadbits & 1) + bits[ind0] = 1; + perm(bits, FP, &left, &right); + bits[ind3] = 0; + bits[ind2] = 0; + bits[ind1] = 0; + bits[ind0] = 0; + if (right != 0) { + fprintf(stderr, + "FPL tabno %d quad %d right not zero\n", + tabno, quadbits); + exit(1); + } + FPL[tabno][quadbits] = left; + if (quadbits == 15 && tabno == 7) { + printf(" 0x%08x", left); + } else if (quadbits & 0x3) { + printf(" 0x%08x,", left); + } else { + printf("\n\t0x%08x,", left); + } + } + if (tabno == 7) + printf("\n};"); + printf("\n"); + } + + /* + * Right half of same set of tables. This was symmetric too. + * Amazing! + */ + for (tabno = 0; tabno < 8; tabno++) { + i = tabno * 4; + ind3 = FPRbits[i] - 1; + ind2 = FPRbits[i+1] - 1; + ind1 = FPRbits[i+2] - 1; + ind0 = FPRbits[i+3] - 1; + for (quadbits = 0; quadbits < 16; quadbits++) { + if (quadbits & (1 << 3)) + bits[ind3] = 1; + if (quadbits & (1 << 2)) + bits[ind2] = 1; + if (quadbits & (1 << 1)) + bits[ind1] = 1; + if (quadbits & 1) + bits[ind0] = 1; + perm(bits, FP, &left, &right); + bits[ind3] = 0; + bits[ind2] = 0; + bits[ind1] = 0; + bits[ind0] = 0; + if (left != 0) { + fprintf(stderr, + "FPR tabno %d quad %d left not zero\n", + tabno, quadbits); + exit(1); + } + if (right != FPL[tabno][quadbits]) { + fprintf(stderr, + "FPR tabno %d quad %d: 0x%08x not same as 0x%08x\n", + tabno, quadbits, right,FPL[tabno][quadbits]); + exit(1); + } + } + } +} diff --git a/contrib/xntpd/authstuff/results b/contrib/xntpd/authstuff/results new file mode 100644 index 0000000000..305a179d0a --- /dev/null +++ b/contrib/xntpd/authstuff/results @@ -0,0 +1,2 @@ +odin/1000000: 0.000145 +idavolde/1000000: 0.000451 diff --git a/contrib/xntpd/authstuff/unixcert.c b/contrib/xntpd/authstuff/unixcert.c new file mode 100644 index 0000000000..36234b13f5 --- /dev/null +++ b/contrib/xntpd/authstuff/unixcert.c @@ -0,0 +1,156 @@ +/* unixcert.c,v 3.1 1993/07/06 01:05:14 jbj Exp + * This file, and the certdata file, shamelessly stolen + * from Phil Karn's DES implementation. + * + * This version uses the standard Unix setkey() and encrypt() + * routines to do the encryption. + */ + +#include +#include + +#include "ntp_stdlib.h" + +static void get8 P((U_LONG *)); +static void put8 P((U_LONG *)); +static void do_setkey P((U_LONG *)); +static void do_crypt P((U_LONG *, int)); + +void +main() +{ + U_LONG key[2], plain[2], cipher[2], answer[2]; + int i; + int test; + int fail; + + for(test=0;!feof(stdin);test++){ + get8(key); + do_setkey(key); + printf(" K: "); put8(key); + + get8(plain); + printf(" P: "); put8(plain); + + get8(answer); + printf(" C: "); put8(answer); + + + for(i=0;i<2;i++) + cipher[i] = plain[i]; + do_crypt(cipher, 0); + + for(i=0;i<2;i++) + if(cipher[i] != answer[i]) + break; + fail = 0; + if(i != 2){ + printf(" Encrypt FAIL"); + fail++; + } + do_crypt(cipher, 1); + for(i=0;i<2;i++) + if(cipher[i] != plain[i]) + break; + if(i != 2){ + printf(" Decrypt FAIL"); + fail++; + } + if(fail == 0) + printf(" OK"); + printf("\n"); + } +} + +static void +get8(lp) +U_LONG *lp; +{ + int t; + U_LONG l[2]; + int i; + + l[0] = l[1] = 0L; + for(i=0;i<8;i++){ + scanf("%2x",&t); + if(feof(stdin)) + exit(0); + l[i/4] <<= 8; + l[i/4] |= (U_LONG)(t & 0xff); + } + *lp = l[0]; + *(lp+1) = l[1]; +} + +static void +put8(lp) +U_LONG *lp; +{ + int i; + + + for(i=0;i<2;i++){ + printf("%08x",*lp++); + } +} + +static void +do_setkey(key) + U_LONG *key; +{ + int j; + register int i; + register char *kb; + register U_LONG *kp; + char keybits[64]; + + kb = keybits; + kp = key; + for (j = 0; j < 2; j++) { + for (i = 0; i < 32; i++) { + if (*kp & (1<<(31-i))) + *kb++ = 1; + else + *kb++ = 0; + } + kp++; + } + setkey(keybits); +} + +static void +do_crypt(data, edflag) + U_LONG *data; + int edflag; +{ + int j; + register int i; + register char *bp; + register U_LONG *dp; + char block[64]; + + bp = block; + dp = data; + for (j = 0; j < 2; j++) { + for (i = 0; i < 32; i++) { + if (*dp & (1<<(31-i))) + *bp++ = 1; + else + *bp++ = 0; + } + dp++; + } + + encrypt(block, edflag); + + bp = block; + dp = data; + for (j = 0; j < 2; j++) { + *dp = 0; + for (i = 0; i < 32; i++) { + if (*bp++) + *dp |= 1<<(31-i); + } + dp++; + } +} diff --git a/contrib/xntpd/clockstuff/Makefile.tmpl b/contrib/xntpd/clockstuff/Makefile.tmpl new file mode 100644 index 0000000000..9a0f9c184b --- /dev/null +++ b/contrib/xntpd/clockstuff/Makefile.tmpl @@ -0,0 +1,60 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:05:19 jbj Exp +# +PROGRAM= propdelay +# +# Makefile for clock miscellany +# +COMPILER= cc +COPTS= -O +BINDIR= /usr/local +DEFS= +DEFS_OPT= +DEFS_LOCAL= +COMPAT= +# +INCL= -I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +LIB= ../lib/libntp.a +LINTLIB= ../lib/llib-llibntp.ln +MAKE= make +INSTALL= install +# +SOURCE= chutest.c propdelay.c +OBJS= propdelay.o +CHUOBJS= chutest.o +CLKOBJS= clktest.o + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) + $(CC) $(COPTS) -o $@ $(OBJS) -lm $(COMPAT) + +chutest: $(CHUOBJS) $(LIB) + $(CC) $(COPTS) -o $@ $(CHUOBJS) $(LIB) + +clktest: $(CLKOBJS) $(LIB) + $(CC) $(COPTS) -o $@ $(CLKOBJS) $(LIB) + +install: $(BINDIR)/$(PROGRAM) + +$(BINDIR)/$(PROGRAM): $(PROGRAM) +# $(INSTALL) -c -m 0755 $(PROGRAM) $(BINDIR) + +tags: + ctags *.c *.h + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(PROGRAM) *.o *.out tags make.log Makefile.bak chutest clktest \ + lint.errs + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" + diff --git a/contrib/xntpd/clockstuff/README b/contrib/xntpd/clockstuff/README new file mode 100644 index 0000000000..3714ab3b47 --- /dev/null +++ b/contrib/xntpd/clockstuff/README @@ -0,0 +1,31 @@ +README file for directory ./clockstuff of the NTP Version 3 distribution + +This directory contains the sources for utility programs designed to +support radio clocks. The chutest.c and clktest.c are desgined to +test the chu_clk and tty_clk line disciplines and STREAMS modules in +the ../kernel directory. + +These files have been modified to work with either the line disciplines +or the STREAMS modules. Be sure to define -DSTREAM if appropriate. + +These are random bits of things written to help with clocks. You can +make things in here by typing one or more of: + + make propdelay (or `make') + make chutest + make clktest + +Propdelay computes high frequency propagation delays, given the +longitude and latitude of the transmitter and receiver. Use +this for WWV/H and CHU. Don't use it for WWVB (the computation +is easier for that). + +Chutest can be used to input and process data from a CHU modem +attached to a serial port. It will use the CHU line discipline +(if installed), or raw mode otherwise. This was used to test +out the initial reduction algorithms, and may not be up to date. + +Clktest can be used to test the clock line discipline (CLKLDISC, +it must be available), and to take a look at radio clocks attached to a +serial port. + diff --git a/contrib/xntpd/clockstuff/chutest.c b/contrib/xntpd/clockstuff/chutest.c new file mode 100644 index 0000000000..f65686c3b3 --- /dev/null +++ b/contrib/xntpd/clockstuff/chutest.c @@ -0,0 +1,798 @@ +/* chutest.c,v 3.1 1993/07/06 01:05:21 jbj Exp + * chutest - test the CHU clock + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/ntp_fp.h" +#include "../include/ntp.h" +#include "../include/ntp_unixtime.h" + +#ifdef STREAM +#include +#include +#endif + +#ifdef CHULDISC +#include +#endif + +#ifndef CHULDISC +#ifndef STREAM +#define NCHUCHARS (10) + +struct chucode { + u_char codechars[NCHUCHARS]; /* code characters */ + u_char ncodechars; /* number of code characters */ + u_char chustatus; /* not used currently */ + struct timeval codetimes[NCHUCHARS]; /* arrival times */ +}; +#endif +#endif + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +char *progname; +int debug; + +int dofilter = 0; /* set to 1 when we should run filter algorithm */ +int showtimes = 0; /* set to 1 when we should show char arrival times */ +int doprocess = 0; /* set to 1 when we do processing analogous to driver */ +#ifdef CHULDISC +int usechuldisc = 0; /* set to 1 when CHU line discipline should be used */ +#endif +#ifdef STREAM +int usechuldisc = 0; /* set to 1 when CHU line discipline should be used */ +#endif + +struct timeval lasttv; +struct chucode chudata; + +extern u_long ustotslo[]; +extern u_long ustotsmid[]; +extern u_long ustotshi[]; + +/* + * main - parse arguments and handle options + */ +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + void init_chu(); + + progname = argv[0]; + while ((c = getopt_l(argc, argv, "cdfpt")) != EOF) + switch (c) { + case 'c': +#ifdef STREAM + usechuldisc = 1; + break; +#endif +#ifdef CHULDISC + usechuldisc = 1; + break; +#endif +#ifndef STREAM +#ifndef CHULDISC + (void) fprintf(stderr, + "%s: CHU line discipline not available on this machine\n", + progname); + exit(2); +#endif +#endif + case 'd': + ++debug; + break; + case 'f': + dofilter = 1; + break; + case 'p': + doprocess = 1; + case 't': + showtimes = 1; + break; + default: + errflg++; + break; + } + if (errflg || optind+1 != argc) { +#ifdef STREAM + (void) fprintf(stderr, "usage: %s [-dft] tty_device\n", + progname); +#endif +#ifdef CHULDISC + (void) fprintf(stderr, "usage: %s [-dft] tty_device\n", + progname); +#endif +#ifndef STREAM +#ifndef CHULDISC + (void) fprintf(stderr, "usage: %s [-cdft] tty_device\n", + progname); +#endif +#endif + exit(2); + } + + (void) gettimeofday(&lasttv, (struct timezone *)0); + c = openterm(argv[optind]); + init_chu(); +#ifdef STREAM + if (usechuldisc) + process_ldisc(c); + else +#endif +#ifdef CHULDISC + if (usechuldisc) + process_ldisc(c); + else +#endif + process_raw(c); + /*NOTREACHED*/ +} + + +/* + * openterm - open a port to the CHU clock + */ +int +openterm(dev) + char *dev; +{ + int s; + struct sgttyb ttyb; + + if (debug) + (void) fprintf(stderr, "Doing open..."); + if ((s = open(dev, O_RDONLY, 0777)) < 0) + error("open(%s)", dev, ""); + if (debug) + (void) fprintf(stderr, "open okay\n"); + + if (debug) + (void) fprintf(stderr, "Setting exclusive use..."); + if (ioctl(s, TIOCEXCL, (char *)0) < 0) + error("ioctl(TIOCEXCL)", "", ""); + if (debug) + (void) fprintf(stderr, "done\n"); + + ttyb.sg_ispeed = ttyb.sg_ospeed = B300; + ttyb.sg_erase = ttyb.sg_kill = 0; + ttyb.sg_flags = EVENP|ODDP|RAW; + if (debug) + (void) fprintf(stderr, "Setting baud rate et al..."); + if (ioctl(s, TIOCSETP, (char *)&ttyb) < 0) + error("ioctl(TIOCSETP, raw)", "", ""); + if (debug) + (void) fprintf(stderr, "done\n"); + +#ifdef CHULDISC + if (usechuldisc) { + int ldisc; + + if (debug) + (void) fprintf(stderr, "Switching to CHU ldisc..."); + ldisc = CHULDISC; + if (ioctl(s, TIOCSETD, (char *)&ldisc) < 0) + error("ioctl(TIOCSETD, CHULDISC)", "", ""); + if (debug) + (void) fprintf(stderr, "okay\n"); + } +#endif +#ifdef STREAM + if (usechuldisc) { + + if (debug) + (void) fprintf(stderr, "Poping off streams..."); + while (ioctl(s, I_POP, 0) >=0) ; + if (debug) + (void) fprintf(stderr, "okay\n"); + if (debug) + (void) fprintf(stderr, "Pushing CHU stream..."); + if (ioctl(s, I_PUSH, "chu") < 0) + error("ioctl(I_PUSH, \"chu\")", "", ""); + if (debug) + (void) fprintf(stderr, "okay\n"); + } +#endif + return s; +} + + +/* + * process_raw - process characters in raw mode + */ +process_raw(s) + int s; +{ + u_char c; + int n; + struct timeval tv; + struct timeval difftv; + + while ((n = read(s, &c, sizeof(char))) > 0) { + (void) gettimeofday(&tv, (struct timezone *)0); + if (dofilter) + raw_filter((unsigned int)c, &tv); + else { + difftv.tv_sec = tv.tv_sec - lasttv.tv_sec; + difftv.tv_usec = tv.tv_usec - lasttv.tv_usec; + if (difftv.tv_usec < 0) { + difftv.tv_sec--; + difftv.tv_usec += 1000000; + } + (void) printf("%02x\t%lu.%06lu\t%lu.%06lu\n", + c, tv.tv_sec, tv.tv_usec, difftv.tv_sec, + difftv.tv_usec); + lasttv = tv; + } + } + + if (n == 0) { + (void) fprintf(stderr, "%s: zero returned on read\n", progname); + exit(1); + } else + error("read()", "", ""); +} + + +/* + * raw_filter - run the line discipline filter over raw data + */ +raw_filter(c, tv) + unsigned int c; + struct timeval *tv; +{ + static struct timeval diffs[10] = { 0 }; + struct timeval diff; + l_fp ts; + void chufilter(); + + if ((c & 0xf) > 9 || ((c>>4)&0xf) > 9) { + if (debug) + (void) fprintf(stderr, + "character %02x failed BCD test\n"); + chudata.ncodechars = 0; + return; + } + + if (chudata.ncodechars > 0) { + diff.tv_sec = tv->tv_sec + - chudata.codetimes[chudata.ncodechars].tv_sec; + diff.tv_usec = tv->tv_usec + - chudata.codetimes[chudata.ncodechars].tv_usec; + if (diff.tv_usec < 0) { + diff.tv_sec--; + diff.tv_usec += 1000000; + } /* + if (diff.tv_sec != 0 || diff.tv_usec > 900000) { + if (debug) + (void) fprintf(stderr, + "character %02x failed time test\n"); + chudata.ncodechars = 0; + return; + } */ + } + + chudata.codechars[chudata.ncodechars] = c; + chudata.codetimes[chudata.ncodechars] = *tv; + if (chudata.ncodechars > 0) + diffs[chudata.ncodechars] = diff; + if (++chudata.ncodechars == 10) { + if (doprocess) { + TVTOTS(&chudata.codetimes[NCHUCHARS-1], &ts); + ts.l_ui += JAN_1970; + chufilter(&chudata, &chudata.codetimes[NCHUCHARS-1]); + } else { + register int i; + + for (i = 0; i < chudata.ncodechars; i++) { + (void) printf("%x%x\t%lu.%06lu\t%lu.%06lu\n", + chudata.codechars[i] & 0xf, + (chudata.codechars[i] >>4 ) & 0xf, + chudata.codetimes[i].tv_sec, + chudata.codetimes[i].tv_usec, + diffs[i].tv_sec, diffs[i].tv_usec); + } + } + chudata.ncodechars = 0; + } +} + + +/* #ifdef CHULDISC*/ +/* + * process_ldisc - process line discipline + */ +process_ldisc(s) + int s; +{ + struct chucode chu; + int n; + register int i; + struct timeval diff; + l_fp ts; + void chufilter(); + + while ((n = read(s, (char *)&chu, sizeof chu)) > 0) { + if (n != sizeof chu) { + (void) fprintf(stderr, "Expected %d, got %d\n", + sizeof chu, n); + continue; + } + + if (doprocess) { + TVTOTS(&chu.codetimes[NCHUCHARS-1], &ts); + ts.l_ui += JAN_1970; + chufilter(&chu, &ts); + } else { + for (i = 0; i < NCHUCHARS; i++) { + if (i == 0) + diff.tv_sec = diff.tv_usec = 0; + else { + diff.tv_sec = chu.codetimes[i].tv_sec + - chu.codetimes[i-1].tv_sec; + diff.tv_usec = chu.codetimes[i].tv_usec + - chu.codetimes[i-1].tv_usec; + if (diff.tv_usec < 0) { + diff.tv_sec--; + diff.tv_usec += 1000000; + } + } + (void) printf("%x%x\t%lu.%06lu\t%lu.%06lu\n", + chu.codechars[i] & 0xf, (chu.codechars[i]>>4)&0xf, + chu.codetimes[i].tv_sec, chu.codetimes[i].tv_usec, + diff.tv_sec, diff.tv_usec); + } + } + } + if (n == 0) { + (void) fprintf(stderr, "%s: zero returned on read\n", progname); + exit(1); + } else + error("read()", "", ""); +} +/*#endif*/ + + +/* + * error - print an error message + */ +error(fmt, s1, s2) + char *fmt; + char *s1; + char *s2; +{ + (void) fprintf(stderr, "%s: ", progname); + (void) fprintf(stderr, fmt, s1, s2); + (void) fprintf(stderr, ": "); + perror(""); + exit(1); +} + +/* + * Definitions + */ +#define MAXUNITS 4 /* maximum number of CHU units permitted */ +#define CHUDEV "/dev/chu%d" /* device we open. %d is unit number */ +#define NCHUCODES 9 /* expect 9 CHU codes per minute */ + +/* + * When CHU is operating optimally we want the primary clock distance + * to come out at 300 ms. Thus, peer.distance in the CHU 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 CHUDISTANCE 0x00004a3d +#define CHUBASEDELAY 0x0000028f + +/* + * To compute a quality for the estimate (a pseudo delay) we add a + * fixed 10 ms for each missing code in the minute and add to this + * the sum of the differences between the remaining offsets and the + * estimated sample offset. + */ +#define CHUDELAYPENALTY 0x0000028f + +/* + * Other constant stuff + */ +#define CHUPRECISION (-9) /* what the heck */ +#define CHUREFID "CHU\0" + +/* + * Default fudge factors + */ +#define DEFPROPDELAY 0x00624dd3 /* 0.0015 seconds, 1.5 ms */ +#define DEFFILTFUDGE 0x000d1b71 /* 0.0002 seconds, 200 us */ + +/* + * Hacks to avoid excercising the multiplier. I have no pride. + */ +#define MULBY10(x) (((x)<<3) + ((x)<<1)) +#define MULBY60(x) (((x)<<6) - ((x)<<2)) /* watch overflow */ +#define MULBY24(x) (((x)<<4) + ((x)<<3)) + +/* + * Constants for use when multiplying by 0.1. ZEROPTONE is 0.1 + * as an l_fp fraction, NZPOBITS is the number of significant bits + * in ZEROPTONE. + */ +#define ZEROPTONE 0x1999999a +#define NZPOBITS 29 + +/* + * The CHU table. This gives the expected time of arrival of each + * character after the on-time second and is computed as follows: + * The CHU time code is sent at 300 bps. Your average UART will + * synchronize at the edge of the start bit and will consider the + * character complete at the center of the first stop bit, i.e. + * 0.031667 ms later. Thus the expected time of each interrupt + * is the start bit time plus 0.031667 seconds. These times are + * in chutable[]. To this we add such things as propagation delay + * and delay fudge factor. + */ +#define CHARDELAY 0x081b4e80 + +static u_long chutable[NCHUCHARS] = { + 0x2147ae14 + CHARDELAY, /* 0.130 (exactly) */ + 0x2ac08312 + CHARDELAY, /* 0.167 (exactly) */ + 0x34395810 + CHARDELAY, /* 0.204 (exactly) */ + 0x3db22d0e + CHARDELAY, /* 0.241 (exactly) */ + 0x472b020c + CHARDELAY, /* 0.278 (exactly) */ + 0x50a3d70a + CHARDELAY, /* 0.315 (exactly) */ + 0x5a1cac08 + CHARDELAY, /* 0.352 (exactly) */ + 0x63958106 + CHARDELAY, /* 0.389 (exactly) */ + 0x6d0e5604 + CHARDELAY, /* 0.426 (exactly) */ + 0x76872b02 + CHARDELAY, /* 0.463 (exactly) */ +}; + +/* + * Keep the fudge factors separately so they can be set even + * when no clock is configured. + */ +static l_fp propagation_delay; +static l_fp fudgefactor; +static l_fp offset_fudge; + +/* + * We keep track of the start of the year, watching for changes. + * We also keep track of whether the year is a leap year or not. + * All because stupid CHU doesn't include the year in the time code. + */ +static u_long yearstart; + +/* + * Imported from the timer module + */ +extern u_long current_time; +extern struct event timerqueue[]; + +/* + * Time conversion tables imported from the library + */ +extern u_long ustotslo[]; +extern u_long ustotsmid[]; +extern u_long ustotshi[]; + + +/* + * init_chu - initialize internal chu driver data + */ +void +init_chu() +{ + + /* + * Initialize fudge factors to default. + */ + propagation_delay.l_ui = 0; + propagation_delay.l_uf = DEFPROPDELAY; + fudgefactor.l_ui = 0; + fudgefactor.l_uf = DEFFILTFUDGE; + offset_fudge = propagation_delay; + L_ADD(&offset_fudge, &fudgefactor); + + yearstart = 0; +} + + +void +chufilter(chuc, rtime) + struct chucode *chuc; + l_fp *rtime; +{ + register int i; + register u_long date_ui; + register u_long tmp; + register u_char *code; + int isneg; + int imin; + int imax; + u_long reftime; + l_fp off[NCHUCHARS]; + l_fp ts; + int day, hour, minute, second; + static u_char lastcode[NCHUCHARS]; + extern u_long calyearstart(); + extern char *mfptoa(); + void chu_process(); + extern char *prettydate(); + + /* + * We'll skip the checks made in the kernel, but assume they've + * been done. This means that all characters are BCD and + * the intercharacter spacing isn't unreasonable. + */ + + /* + * print the code + */ + for (i = 0; i < NCHUCHARS; i++) + printf("%c%c", (chuc->codechars[i] & 0xf) + '0', + ((chuc->codechars[i]>>4) & 0xf) + '0'); + printf("\n"); + + /* + * Format check. Make sure the two halves match. + */ + for (i = 0; i < NCHUCHARS/2; i++) + if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) { + (void) printf("Bad format, halves don't match\n"); + return; + } + + /* + * Break out the code into the BCD nibbles. Only need to fiddle + * with the first half since both are identical. Note the first + * BCD character is the low order nibble, the second the high order. + */ + code = lastcode; + for (i = 0; i < NCHUCHARS/2; i++) { + *code++ = chuc->codechars[i] & 0xf; + *code++ = (chuc->codechars[i] >> 4) & 0xf; + } + + /* + * If the first nibble isn't a 6, we're up the creek + */ + code = lastcode; + if (*code++ != 6) { + (void) printf("Bad format, no 6 at start\n"); + return; + } + + /* + * Collect the day, the hour, the minute and the second. + */ + day = *code++; + day = MULBY10(day) + *code++; + day = MULBY10(day) + *code++; + hour = *code++; + hour = MULBY10(hour) + *code++; + minute = *code++; + minute = MULBY10(minute) + *code++; + second = *code++; + second = MULBY10(second) + *code++; + + /* + * Sanity check the day and time. Note that this + * only occurs on the 31st through the 39th second + * of the minute. + */ + if (day < 1 || day > 366 + || hour > 23 || minute > 59 + || second < 31 || second > 39) { + (void) printf("Failed date sanity check: %d %d %d %d\n", + day, hour, minute, second); + return; + } + + /* + * Compute seconds into the year. + */ + tmp = (u_long)(MULBY24((day-1)) + hour); /* hours */ + tmp = MULBY60(tmp) + (u_long)minute; /* minutes */ + tmp = MULBY60(tmp) + (u_long)second; /* seconds */ + + /* + * Now the fun begins. We demand that the received time code + * be within CLOCK_WAYTOOBIG of the receive timestamp, but + * there is uncertainty about the year the timestamp is in. + * Use the current year start for the first check, this should + * work most of the time. + */ + date_ui = tmp + yearstart; + if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG) + && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG)) + goto codeokay; /* looks good */ + + /* + * Trouble. Next check is to see if the year rolled over and, if + * so, try again with the new year's start. + */ + date_ui = calyearstart(rtime->l_ui); + if (date_ui != yearstart) { + yearstart = date_ui; + date_ui += tmp; + (void) printf("time %u, code %u, difference %d\n", + date_ui, rtime->l_ui, (long)date_ui-(long)rtime->l_ui); + if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG) + && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG)) + goto codeokay; /* okay this time */ + } + + ts.l_uf = 0; + ts.l_ui = yearstart; + printf("yearstart %s\n", prettydate(&ts)); + printf("received %s\n", prettydate(rtime)); + ts.l_ui = date_ui; + printf("date_ui %s\n", prettydate(&ts)); + + /* + * Here we know the year start matches the current system + * time. One remaining possibility is that the time code + * is in the year previous to that of the system time. This + * is only worth checking if the receive timestamp is less + * than CLOCK_WAYTOOBIG seconds into the new year. + */ + if ((rtime->l_ui - yearstart) < CLOCK_WAYTOOBIG) { + date_ui = tmp + calyearstart(yearstart - CLOCK_WAYTOOBIG); + if ((rtime->l_ui - date_ui) < CLOCK_WAYTOOBIG) + goto codeokay; + } + + /* + * One last possibility is that the time stamp is in the year + * following the year the system is in. Try this one before + * giving up. + */ + date_ui = tmp + calyearstart(yearstart + (400*24*60*60)); /* 400 days */ + if ((date_ui - rtime->l_ui) >= CLOCK_WAYTOOBIG) { + printf("Date hopelessly off\n"); + return; /* hopeless, let it sync to other peers */ + } + +codeokay: + reftime = date_ui; + /* + * We've now got the integral seconds part of the time code (we hope). + * The fractional part comes from the table. We next compute + * the offsets for each character. + */ + for (i = 0; i < NCHUCHARS; i++) { + register u_long tmp2; + + off[i].l_ui = date_ui; + off[i].l_uf = chutable[i]; + tmp = chuc->codetimes[i].tv_sec + JAN_1970; + TVUTOTSF(chuc->codetimes[i].tv_usec, tmp2); + M_SUB(off[i].l_ui, off[i].l_uf, tmp, tmp2); + } + + /* + * Here is a *big* problem. What one would normally + * do here on a machine with lots of clock bits (say + * a Vax or the gizmo board) is pick the most positive + * offset and the estimate, since this is the one that + * is most likely suffered the smallest interrupt delay. + * The trouble is that the low order clock bit on an IBM + * RT, which is the machine I had in mind when doing this, + * ticks at just under the millisecond mark. This isn't + * precise enough. What we can do to improve this is to + * average all 10 samples and rely on the second level + * filtering to pick the least delayed estimate. Trouble + * is, this means we have to divide a 64 bit fixed point + * number by 10, a procedure which really sucks. Oh, well. + * First compute the sum. + */ + date_ui = 0; + tmp = 0; + for (i = 0; i < NCHUCHARS; i++) + M_ADD(date_ui, tmp, off[i].l_ui, off[i].l_uf); + if (M_ISNEG(date_ui, tmp)) + isneg = 1; + else + isneg = 0; + + /* + * Here is a multiply-by-0.1 optimization that should apply + * just about everywhere. If the magnitude of the sum + * is less than 9 we don't have to worry about overflow + * out of a 64 bit product, even after rounding. + */ + if (date_ui < 9 || date_ui > 0xfffffff7) { + register u_long prod_ui; + register u_long prod_uf; + + prod_ui = prod_uf = 0; + /* + * This code knows the low order bit in 0.1 is zero + */ + for (i = 1; i < NZPOBITS; i++) { + M_LSHIFT(date_ui, tmp); + if (ZEROPTONE & (1< +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/ntp_fp.h" +#include "../include/ntp.h" +#include "../include/ntp_unixtime.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +#if defined(ULT_2_0_SUCKS) +#ifndef sigmask +#define sigmask(m) (1<<(m)) +#endif +#endif + +#ifndef STREAM +#ifndef CLKLDISC + CLOCK_LINE_DISCIPLINE_NEEDED_BY_THIS_PROGRAM; +#endif +#endif + +/* + * Mask for blocking SIGIO and SIGALRM + */ +#define BLOCKSIGMASK (sigmask(SIGIO)|sigmask(SIGALRM)) + +/* + * speed table + */ +struct speeds { + int bps; + int rate; +} speedtab[] = { + { 300, B300 }, + { 1200, B1200 }, + { 2400, B2400 }, + { 4800, B4800 }, + { 9600, B9600 }, + { 19200, EXTA }, + { 38400, EXTB }, + { 0, 0 } +}; + +char *progname; +int debug; + +#ifdef CLKLDISC +#define DEFMAGIC '\r' +#endif + +#ifdef STREAM +#include +#include +#define DEFMAGIC "\r" +#endif + +struct timeval timeout = { 0 }; +char *cmd = NULL; +int cmdlen; +int docmd = 0; +#ifdef CLKLDISC +u_long magic1 = DEFMAGIC; +u_long magic2 = DEFMAGIC; +#endif +#ifdef STREAM +char magic[32]; +#endif +int speed = B9600; +int ttflags = RAW|EVENP|ODDP; + +int wasalarmed; +int iosig; + +struct timeval lasttv; + +extern u_long ustotslo[]; +extern u_long ustotsmid[]; +extern u_long ustotshi[]; + +/* + * main - parse arguments and handle options + */ +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + struct speeds *spd; + u_long tmp; + int fd; + struct sgttyb ttyb; + struct itimerval itimer; + extern int optind; + extern char *optarg; + int alarming(); + int ioready(); + + progname = argv[0]; +#ifdef STREAM + magic[0] = 0; +#endif + while ((c = getopt_l(argc, argv, "a:b:c:dfs:t:")) != EOF) + switch (c) { +#ifdef CLKLDISC + case 'a': +#endif + case 'c': + if (!atouint(optarg, &tmp)) { + (void) fprintf(stderr, + "%s: argument for -%c must be integer\n", + progname, c); + errflg++; + break; + } +#ifdef CLKLDISC + if (c == 'c') + magic1 = tmp; + else + magic2 = tmp; +#endif +#ifdef STREAM + magic[strlen(magic)+1] = '\0'; + magic[strlen(magic)] = tmp; +#endif + break; + case 'b': + if (!atouint(optarg, &tmp)) { + errflg++; + break; + } + spd = speedtab; + while (spd->bps != 0) + if ((int)tmp == spd->bps) + break; + if (spd->bps == 0) { + (void) fprintf(stderr, + "%s: speed %lu is unsupported\n", + progname, tmp); + errflg++; + } else { + speed = spd->rate; + } + break; + case 'd': + ++debug; + break; + case 'f': + ttflags |= CRMOD; + break; + case 's': + cmdlen = strlen(optarg); + if (cmdlen == 0) + errflg++; + else + cmd = optarg; + break; + case 't': + if (!atouint(optarg, &tmp)) + errflg++; + else { + timeout.tv_sec = (long)tmp; + docmd = 1; + } + break; + default: + errflg++; + break; + } + if (errflg || optind+1 != argc) { + (void) fprintf(stderr, +#ifdef CLKLDISC +"usage: %s [-b bps] [-c magic1] [-a magic2] [-f] [-s cmd] [-t timeo] tty_device\n", +#endif +#ifdef STREAM +"usage: %s [-b bps] [-c magic1] [-c magic2]... [-f] [-s cmd] [-t timeo] tty_device\n", +#endif + progname); + exit(2); + } + +#ifdef STREAM + if (!strlen(magic)) + strcpy(magic,DEFMAGIC); +#endif + + if (docmd) + fd = open(argv[optind], O_RDWR, 0777); + else + fd = open(argv[optind], O_RDONLY, 0777); + if (fd == -1) { + (void) fprintf(stderr, "%s: open(%s): ", progname, + argv[optind]); + perror(""); + exit(1); + } + + if (ioctl(fd, TIOCEXCL, (char *)0) < 0) { + (void) fprintf(stderr, "%s: ioctl(TIOCEXCL): ", progname); + perror(""); + exit(1); + } + + /* + * If we have the clock discipline, set the port to raw. Otherwise + * we run cooked. + */ + ttyb.sg_ispeed = ttyb.sg_ospeed = speed; +#ifdef CLKLDISC + ttyb.sg_erase = (char)magic1; + ttyb.sg_kill = (char)magic2; +#endif + ttyb.sg_flags = (short)ttflags; + if (ioctl(fd, TIOCSETP, (char *)&ttyb) < 0) { + (void) fprintf(stderr, "%s: ioctl(TIOCSETP): ", progname); + perror(""); + exit(1); + } + + if (fcntl(fd, F_SETOWN, getpid()) == -1) { + (void) fprintf(stderr, "%s: fcntl(F_SETOWN): ", progname); + perror(""); + exit(1); + } + +#ifdef CLKLDISC + { + int ldisc; + ldisc = CLKLDISC; + if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) { + (void) fprintf(stderr, "%s: ioctl(TIOCSETD): ", progname); + perror(""); + exit(1); + } + } +#endif +#ifdef STREAM + if (ioctl(fd, I_POP, 0) >=0 ) ; + if (ioctl(fd, I_PUSH, "clk") < 0) { + (void) fprintf(stderr, "%s: ioctl(I_PUSH): ", progname); + perror(""); + exit(1); + } + if (ioctl(fd, CLK_SETSTR, magic) < 0) { + (void) fprintf(stderr, "%s: ioctl(CLK_SETSTR): ", progname); + perror(""); + exit(1); + } +#endif + + + (void) gettimeofday(&lasttv, (struct timezone *)0); + if (docmd) { + /* + * set non-blocking, async I/O on the descriptor + */ + iosig = 0; + (void) signal(SIGIO, ioready); + if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) { + (void) fprintf(stderr, "%s: fcntl(F_SETFL): ", + progname); + perror(""); + exit(1); + } + + /* + * Set up the alarm interrupt. + */ + wasalarmed = 0; + (void) signal(SIGALRM, alarming); + itimer.it_interval = itimer.it_value = timeout; + setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); + doboth(fd); + } + doioonly(fd); +} + + +/* + * doboth - handle both I/O and alarms via SIGIO + */ +doboth(fd) + int fd; +{ + int n; + int sawalarm; + int sawiosig; + int omask; + fd_set fds; + struct timeval tvzero; + + sawalarm = 0; + sawiosig = 0; + FD_ZERO(&fds); + for (;;) { + omask = sigblock(BLOCKSIGMASK); + if (wasalarmed) { /* alarmed? */ + sawalarm = 1; + wasalarmed = 0; + } + if (iosig) { + sawiosig = 1; + iosig = 0; + } + + if (!sawalarm && !sawiosig) { + /* + * Nothing to do. Wait for something. + */ + sigpause(omask); + if (wasalarmed) { /* alarmed? */ + sawalarm = 1; + wasalarmed = 0; + } + if (iosig) { + sawiosig = 1; + iosig = 0; + } + } + (void)sigsetmask(omask); + + if (sawiosig) { + + do { + tvzero.tv_sec = tvzero.tv_usec = 0; + FD_SET(fd, &fds); + n = select(fd+1, &fds, (fd_set *)0, + (fd_set *)0, &tvzero); + if (n > 0) + doio(fd); + } while (n > 0); + + if (n == -1) { + (void) fprintf(stderr, "%s: select: ", + progname); + perror(""); + exit(1); + } + sawiosig = 0; + } + if (sawalarm) { + doalarm(fd); + sawalarm = 0; + } + } +} + + +/* + * doioonly - do I/O. This avoids the use of signals + */ +doioonly(fd) + int fd; +{ + int n; + fd_set fds; + + FD_ZERO(&fds); + for (;;) { + FD_SET(fd, &fds); + n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, + (struct timeval *)0); + if (n > 0) + doio(fd); + } +} + + +/* + * doio - read a buffer full of stuff and print it out + */ +doio(fd) + int fd; +{ + register char *rp, *rpend; + register char *cp; + register int i; + char raw[512]; + struct timeval tv, tvd; + int rlen; + int ind; + char cooked[2049]; + static char *digits = "0123456789abcdef"; + + rlen = read(fd, raw, sizeof(raw)); + if (rlen < 0) { + (void) fprintf(stderr, "%s: read(): ", progname); + perror(""); + return; + } + if (rlen == 0) { + (void) printf("Zero length read\n"); + return; + } + + cp = cooked; + rp = raw; + rpend = &raw[rlen]; + ind = 0; + + while (rp < rpend) { + ind = 1; + if (isprint(*rp)) + *cp++ = *rp; + else { + *cp++ = '<'; + *cp++ = digits[((*rp)>>4) & 0xf]; + *cp++ = digits[*rp & 0xf]; + *cp++ = '>'; + } +#ifdef CLKLDISC + if (*rp == (char)magic1 || *rp == (char)magic2) { +#else + if ( strchr( magic, *rp) != NULL ) { +#endif + rp++; + ind = 0; + *cp = '\0'; + if ((rpend - rp) < sizeof(struct timeval)) { + (void)printf( + "Too little data (%d): %s\n", + rpend-rp, cooked); + return; + } + + tv.tv_sec = 0; + for (i = 0; i < 4; i++) { + tv.tv_sec <<= 8; + tv.tv_sec |= ((long)*rp++) & 0xff; + } + tv.tv_usec = 0; + for (i = 0; i < 4; i++) { + tv.tv_usec <<= 8; + tv.tv_usec |= ((long)*rp++) & 0xff; + } + + tvd.tv_sec = tv.tv_sec - lasttv.tv_sec; + tvd.tv_usec = tv.tv_usec - lasttv.tv_usec; + if (tvd.tv_usec < 0) { + tvd.tv_usec += 1000000; + tvd.tv_sec--; + } + + (void)printf("%lu.%06lu %lu.%06lu %s\n", + tv.tv_sec, tv.tv_usec, tvd.tv_sec, tvd.tv_usec, + cooked); + lasttv = tv; + } else { + rp++; + } + } + + if (ind) { + *cp = '\0'; + (void)printf("Incomplete data: %s\n", cooked); + } +} + + +/* + * doalarm - send a string out the port, if we have one. + */ +doalarm(fd) + int fd; +{ + int n; + + if (cmd == NULL || cmdlen <= 0) + return; + + n = write(fd, cmd, cmdlen); + + if (n < 0) { + (void) fprintf(stderr, "%s: write(): ", progname); + perror(""); + } else if (n < cmdlen) { + (void) printf("Short write (%d bytes, should be %d)\n", + n, cmdlen); + } +} + + +/* + * alarming - receive alarm interupt + */ +alarming() +{ + wasalarmed = 1; +} + +/* + * ioready - handle SIGIO interrupt + */ +ioready() +{ + iosig = 1; +} diff --git a/contrib/xntpd/clockstuff/propdelay.c b/contrib/xntpd/clockstuff/propdelay.c new file mode 100644 index 0000000000..5ba1789eee --- /dev/null +++ b/contrib/xntpd/clockstuff/propdelay.c @@ -0,0 +1,536 @@ +/* propdelay.c,v 3.1 1993/07/06 01:05:24 jbj Exp + * propdelay - compute propagation delays + * + * cc -o propdelay propdelay.c -lm + * + * "Time and Frequency Users' Manual", NBS Technical Note 695 (1977). + */ + +/* + * This can be used to get a rough idea of the HF propagation delay + * between two points (usually between you and the radio station). + * The usage is + * + * propdelay latitudeA longitudeA latitudeB longitudeB + * + * where points A and B are the locations in question. You obviously + * need to know the latitude and longitude of each of the places. + * The program expects the latitude to be preceded by an 'n' or 's' + * and the longitude to be preceded by an 'e' or 'w'. It understands + * either decimal degrees or degrees:minutes:seconds. Thus to compute + * the delay between the WWVH (21:59:26N, 159:46:00W) and WWV (40:40:49N, + * 105:02:27W) you could use: + * + * propdelay n21:59:26 w159:46 n40:40:49 w105:02:27 + * + * By default it prints out a summer (F2 average virtual height 350 km) and + * winter (F2 average virtual height 250 km) number. The results will be + * quite approximate but are about as good as you can do with HF time anyway. + * You might pick a number between the values to use, or use the summer + * value in the summer and switch to the winter value when the static + * above 10 MHz starts to drop off in the fall. You can also use the + * -h switch if you want to specify your own virtual height. + * + * You can also do a + * + * propdelay -W n45:17:47 w75:45:22 + * + * to find the propagation delays to WWV and WWVH (from CHU in this + * case), a + * + * propdelay -C n40:40:49 w105:02:27 + * + * to find the delays to CHU, and a + * + * propdelay -G n52:03:17 w98:34:18 + * + * to find delays to GOES via each of the three satellites. + */ + +#include +#include + +#include "ntp_stdlib.h" + +extern double sin P((double)); +extern double cos P((double)); +extern double acos P((double)); +extern double tan P((double)); +extern double atan P((double)); +extern double sqrt P((double)); + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +/* + * Program constants + */ +#define EARTHRADIUS (6370.0) /* raduis of earth (km) */ +#define LIGHTSPEED (299800.0) /* speed of light, km/s */ +#define PI (3.1415926536) +#define RADPERDEG (PI/180.0) /* radians per degree */ +#define MILE (1.609344) /* km in a mile */ + +#define SUMMERHEIGHT (350.0) /* summer height in km */ +#define WINTERHEIGHT (250.0) /* winter height in km */ + +#define SATHEIGHT (6.6110 * 6378.0) /* geosync satellite height in km + from centre of earth */ + +#define WWVLAT "n40:40:49" +#define WWVLONG "w105:02:27" + +#define WWVHLAT "n21:59:26" +#define WWVHLONG "w159:46:00" + +#define CHULAT "n45:17:47" +#define CHULONG "w75:45:22" + +#define GOES_UP_LAT "n37:52:00" +#define GOES_UP_LONG "w75:27:00" +#define GOES_EAST_LONG "w75:00:00" +#define GOES_STBY_LONG "w105:00:00" +#define GOES_WEST_LONG "w135:00:00" +#define GOES_SAT_LAT "n00:00:00" + +char *wwvlat = WWVLAT; +char *wwvlong = WWVLONG; + +char *wwvhlat = WWVHLAT; +char *wwvhlong = WWVHLONG; + +char *chulat = CHULAT; +char *chulong = CHULONG; + +char *goes_up_lat = GOES_UP_LAT; +char *goes_up_long = GOES_UP_LONG; +char *goes_east_long = GOES_EAST_LONG; +char *goes_stby_long = GOES_STBY_LONG; +char *goes_west_long = GOES_WEST_LONG; +char *goes_sat_lat = GOES_SAT_LAT; + +int hflag = 0; +int Wflag = 0; +int Cflag = 0; +int Gflag = 0; +int height; + +char *progname; +int debug; + +static void doit P((double, double, double, double, double, char *)); +static double latlong P((char *, int)); +static double greatcircle P((double, double, double, double)); +static double waveangle P((double, double, int)); +static double propdelay P((double, double, int)); +static int finddelay P((double, double, double, double, double, double *)); +static void satdoit P((double, double, double, double, double, double, char *)); +static void satfinddelay P((double, double, double, double, double *)); +static double satpropdelay P((double)); + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + double lat1, long1; + double lat2, long2; + double lat3, long3; + extern int optind; + extern char *optarg; + + progname = argv[0]; + while ((c = getopt_l(argc, argv, "dh:CWG")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + case 'h': + hflag++; + height = atof(optarg); + if (height <= 0.0) { + (void) fprintf(stderr, "height %s unlikely\n", + optarg); + errflg++; + } + break; + case 'C': + Cflag++; + break; + case 'W': + Wflag++; + break; + case 'G': + Gflag++; + break; + default: + errflg++; + break; + } + if (errflg || (!(Cflag || Wflag || Gflag) && optind+4 != argc) || + ((Cflag || Wflag || Gflag) && optind+2 != argc)) { + (void) fprintf(stderr, + "usage: %s [-d] [-h height] lat1 long1 lat2 long2\n", + progname); + (void) fprintf(stderr," - or -\n"); + (void) fprintf(stderr, + "usage: %s -CWG [-d] lat long\n", + progname); + exit(2); + } + + + if (!(Cflag || Wflag || Gflag)) { + lat1 = latlong(argv[optind], 1); + long1 = latlong(argv[optind + 1], 0); + lat2 = latlong(argv[optind + 2], 1); + long2 = latlong(argv[optind + 3], 0); + if (hflag) { + doit(lat1, long1, lat2, long2, height, ""); + } else { + doit(lat1, long1, lat2, long2, (double)SUMMERHEIGHT, + "summer propagation, "); + doit(lat1, long1, lat2, long2, (double)WINTERHEIGHT, + "winter propagation, "); + } + } else if (Wflag) { + /* + * Compute delay from WWV + */ + lat1 = latlong(argv[optind], 1); + long1 = latlong(argv[optind + 1], 0); + lat2 = latlong(wwvlat, 1); + long2 = latlong(wwvlong, 0); + if (hflag) { + doit(lat1, long1, lat2, long2, height, "WWV "); + } else { + doit(lat1, long1, lat2, long2, (double)SUMMERHEIGHT, + "WWV summer propagation, "); + doit(lat1, long1, lat2, long2, (double)WINTERHEIGHT, + "WWV winter propagation, "); + } + + /* + * Compute delay from WWVH + */ + lat2 = latlong(wwvhlat, 1); + long2 = latlong(wwvhlong, 0); + if (hflag) { + doit(lat1, long1, lat2, long2, height, "WWVH "); + } else { + doit(lat1, long1, lat2, long2, (double)SUMMERHEIGHT, + "WWVH summer propagation, "); + doit(lat1, long1, lat2, long2, (double)WINTERHEIGHT, + "WWVH winter propagation, "); + } + } else if (Cflag) { + lat1 = latlong(argv[optind], 1); + long1 = latlong(argv[optind + 1], 0); + lat2 = latlong(chulat, 1); + long2 = latlong(chulong, 0); + if (hflag) { + doit(lat1, long1, lat2, long2, height, "CHU "); + } else { + doit(lat1, long1, lat2, long2, (double)SUMMERHEIGHT, + "CHU summer propagation, "); + doit(lat1, long1, lat2, long2, (double)WINTERHEIGHT, + "CHU winter propagation, "); + } + } else if (Gflag) { + lat1 = latlong(goes_up_lat, 1); + long1 = latlong(goes_up_long, 0); + lat3 = latlong(argv[optind], 1); + long3 = latlong(argv[optind + 1], 0); + + lat2 = latlong(goes_sat_lat, 1); + + long2 = latlong(goes_west_long, 0); + satdoit(lat1, long1, lat2, long2, lat3, long3, + "GOES Delay via WEST"); + + long2 = latlong(goes_stby_long, 0); + satdoit(lat1, long1, lat2, long2, lat3, long3, + "GOES Delay via STBY"); + + long2 = latlong(goes_east_long, 0); + satdoit(lat1, long1, lat2, long2, lat3, long3, + "GOES Delay via EAST"); + + } + exit(0); +} + + +/* + * doit - compute a delay and print it + */ +static void +doit(lat1, long1, lat2, long2, h, str) + double lat1; + double long1; + double lat2; + double long2; + double h; + char *str; +{ + int hops; + double delay; + + hops = finddelay(lat1, long1, lat2, long2, h, &delay); + printf("%sheight %g km, hops %d, delay %g seconds\n", + str, h, hops, delay); +} + + +/* + * latlong - decode a latitude/longitude value + */ +static double +latlong(str, islat) + char *str; + int islat; +{ + register char *cp; + register char *bp; + double arg; + double div; + int isneg; + char buf[32]; + char *colon; + + if (islat) { + /* + * Must be north or south + */ + if (*str == 'N' || *str == 'n') + isneg = 0; + else if (*str == 'S' || *str == 's') + isneg = 1; + else + isneg = -1; + } else { + /* + * East is positive, west is negative + */ + if (*str == 'E' || *str == 'e') + isneg = 0; + else if (*str == 'W' || *str == 'w') + isneg = 1; + else + isneg = -1; + } + + if (isneg >= 0) + str++; + + colon = strchr(str, ':'); + if (colon != NULL) { + /* + * in hhh:mm:ss form + */ + cp = str; + bp = buf; + while (cp < colon) + *bp++ = *cp++; + *bp = '\0'; + cp++; + arg = atof(buf); + div = 60.0; + colon = strchr(cp, ':'); + if (colon != NULL) { + bp = buf; + while (cp < colon) + *bp++ = *cp++; + *bp = '\0'; + cp++; + arg += atof(buf) / div; + div = 3600.0; + } + if (*cp != '\0') + arg += atof(cp) / div; + } else { + arg = atof(str); + } + + if (isneg == 1) + arg = -arg; + + if (debug > 2) + (void) printf("latitude/longitude %s = %g\n", str, arg); + + return arg; +} + + +/* + * greatcircle - compute the great circle distance in kilometers + */ +static double +greatcircle(lat1, long1, lat2, long2) + double lat1; + double long1; + double lat2; + double long2; +{ + double dg; + double l1r, l2r; + + l1r = lat1 * RADPERDEG; + l2r = lat2 * RADPERDEG; + dg = EARTHRADIUS * acos( + (cos(l1r) * cos(l2r) * cos((long2-long1)*RADPERDEG)) + + (sin(l1r) * sin(l2r))); + if (debug >= 2) + printf( + "greatcircle lat1 %g long1 %g lat2 %g long2 %g dist %g\n", + lat1, long1, lat2, long2, dg); + return dg; +} + + +/* + * waveangle - compute the wave angle for the given distance, virtual + * height and number of hops. + */ +static double +waveangle(dg, h, n) + double dg; + double h; + int n; +{ + double theta; + double delta; + + theta = dg / (EARTHRADIUS * (double)(2 * n)); + delta = atan((h / (EARTHRADIUS * sin(theta))) + tan(theta/2)) - theta; + if (debug >= 2) + printf("waveangle dist %g height %g hops %d angle %g\n", + dg, h, n, delta / RADPERDEG); + return delta; +} + + +/* + * propdelay - compute the propagation delay + */ +static double +propdelay(dg, h, n) + double dg; + double h; + int n; +{ + double phi; + double theta; + double td; + + theta = dg / (EARTHRADIUS * (double)(2 * n)); + phi = (PI/2.0) - atan((h / (EARTHRADIUS * sin(theta))) + tan(theta/2)); + td = dg / (LIGHTSPEED * sin(phi)); + if (debug >= 2) + printf("propdelay dist %g height %g hops %d time %g\n", + dg, h, n, td); + return td; +} + + +/* + * finddelay - find the propagation delay + */ +static int +finddelay(lat1, long1, lat2, long2, h, delay) + double lat1; + double long1; + double lat2; + double long2; + double h; + double *delay; +{ + double dg; /* great circle distance */ + double delta; /* wave angle */ + int n; /* number of hops */ + + dg = greatcircle(lat1, long1, lat2, long2); + if (debug) + printf("great circle distance %g km %g miles\n", dg, dg/MILE); + + n = 1; + while ((delta = waveangle(dg, h, n)) < 0.0) { + if (debug) + printf("tried %d hop%s, no good\n", n, n>1?"s":""); + n++; + } + if (debug) + printf("%d hop%s okay, wave angle is %g\n", n, n>1?"s":"", + delta / RADPERDEG); + + *delay = propdelay(dg, h, n); + return n; +} + +/* + * satdoit - compute a delay and print it + */ +static void +satdoit(lat1, long1, lat2, long2, lat3, long3, str) + double lat1; + double long1; + double lat2; + double long2; + double lat3; + double long3; + char *str; +{ + double up_delay,down_delay; + + satfinddelay(lat1, long1, lat2, long2, &up_delay); + satfinddelay(lat3, long3, lat2, long2, &down_delay); + + printf("%s, delay %g seconds\n", str, up_delay + down_delay); +} + +/* + * satfinddelay - calculate the one-way delay time between a ground station + * and a satellite + */ +static void +satfinddelay(lat1, long1, lat2, long2, delay) + double lat1; + double long1; + double lat2; + double long2; + double *delay; +{ + double dg; /* great circle distance */ + + dg = greatcircle(lat1, long1, lat2, long2); + + *delay = satpropdelay(dg); +} + +/* + * satpropdelay - calculate the one-way delay time between a ground station + * and a satellite + */ +static double +satpropdelay(dg) + double dg; +{ + double k1, k2, dist; + double theta; + double td; + + theta = dg / (EARTHRADIUS); + k1 = EARTHRADIUS * sin(theta); + k2 = SATHEIGHT - (EARTHRADIUS * cos(theta)); + if (debug >= 2) + printf("Theta %g k1 %g k2 %g\n", theta, k1, k2); + dist = sqrt(k1*k1 + k2*k2); + td = dist / LIGHTSPEED; + if (debug >= 2) + printf("propdelay dist %g height %g time %g\n", dg, dist, td); + return td; +} diff --git a/contrib/xntpd/compilers/README b/contrib/xntpd/compilers/README new file mode 100644 index 0000000000..46794dc539 --- /dev/null +++ b/contrib/xntpd/compilers/README @@ -0,0 +1,5 @@ +README file for directory ./compilers of the NTP Version 3 distribution + +This directory contains configuration files for the various machines +and compilers supported by the distribution. README and RELNOTES files in the +parent directory for directions on how to use these files. diff --git a/contrib/xntpd/compilers/aux2.gcc b/contrib/xntpd/compilers/aux2.gcc new file mode 100644 index 0000000000..53672c4536 --- /dev/null +++ b/contrib/xntpd/compilers/aux2.gcc @@ -0,0 +1 @@ +COMPILER=gcc -O -pipe -finline-functions -fomit-frame-pointer -D_POSIX_SOURCE diff --git a/contrib/xntpd/compilers/aux3.gcc b/contrib/xntpd/compilers/aux3.gcc new file mode 100644 index 0000000000..53672c4536 --- /dev/null +++ b/contrib/xntpd/compilers/aux3.gcc @@ -0,0 +1 @@ +COMPILER=gcc -O -pipe -finline-functions -fomit-frame-pointer -D_POSIX_SOURCE diff --git a/contrib/xntpd/compilers/decosf1.gcc b/contrib/xntpd/compilers/decosf1.gcc new file mode 100644 index 0000000000..d071385d7a --- /dev/null +++ b/contrib/xntpd/compilers/decosf1.gcc @@ -0,0 +1 @@ +COMPILER= gcc -Wall -O2 -finline-functions diff --git a/contrib/xntpd/compilers/hpux.cc b/contrib/xntpd/compilers/hpux.cc new file mode 100644 index 0000000000..e3c27af87b --- /dev/null +++ b/contrib/xntpd/compilers/hpux.cc @@ -0,0 +1,2 @@ +COMPILER=cc +COPTS=+O1 diff --git a/contrib/xntpd/compilers/hpux.gcc b/contrib/xntpd/compilers/hpux.gcc new file mode 100644 index 0000000000..ecd037212e --- /dev/null +++ b/contrib/xntpd/compilers/hpux.gcc @@ -0,0 +1,2 @@ +COMPILER=gcc +COPTS=-O2 diff --git a/contrib/xntpd/compilers/hpux10+.cc b/contrib/xntpd/compilers/hpux10+.cc new file mode 100644 index 0000000000..cf058ef46b --- /dev/null +++ b/contrib/xntpd/compilers/hpux10+.cc @@ -0,0 +1 @@ +COMPILER=cc +O1 diff --git a/contrib/xntpd/compilers/linux.gcc b/contrib/xntpd/compilers/linux.gcc new file mode 100644 index 0000000000..501568c714 --- /dev/null +++ b/contrib/xntpd/compilers/linux.gcc @@ -0,0 +1,2 @@ +COMPILER= gcc -DUSE_PROTOTYPES -Wall +COPTS= -O6 -finline-functions -fomit-frame-pointer diff --git a/contrib/xntpd/compilers/mips.cc b/contrib/xntpd/compilers/mips.cc new file mode 100644 index 0000000000..dcd8697077 --- /dev/null +++ b/contrib/xntpd/compilers/mips.cc @@ -0,0 +1 @@ +COMPILER= cc -systype bsd43 diff --git a/contrib/xntpd/compilers/sinix-m.cc b/contrib/xntpd/compilers/sinix-m.cc new file mode 100644 index 0000000000..e4712dc89e --- /dev/null +++ b/contrib/xntpd/compilers/sinix-m.cc @@ -0,0 +1 @@ +COMPILER= /usr/ucb/cc diff --git a/contrib/xntpd/compilers/sinix-m.gcc b/contrib/xntpd/compilers/sinix-m.gcc new file mode 100644 index 0000000000..fe6af589c4 --- /dev/null +++ b/contrib/xntpd/compilers/sinix-m.gcc @@ -0,0 +1,2 @@ +COMPILER= gcc -traditional + diff --git a/contrib/xntpd/compilers/sunos4.bsd.cc b/contrib/xntpd/compilers/sunos4.bsd.cc new file mode 100644 index 0000000000..eb4dd62986 --- /dev/null +++ b/contrib/xntpd/compilers/sunos4.bsd.cc @@ -0,0 +1 @@ +COMPILER= cc diff --git a/contrib/xntpd/compilers/sunos4.bsd.gcc b/contrib/xntpd/compilers/sunos4.bsd.gcc new file mode 100644 index 0000000000..09e841a2b4 --- /dev/null +++ b/contrib/xntpd/compilers/sunos4.bsd.gcc @@ -0,0 +1 @@ +COMPILER= gcc -DUSE_PROTOTYPES -Wall -O2 -finline-functions -fdelayed-branch -fomit-frame-pointer diff --git a/contrib/xntpd/compilers/sunos4.posix.gcc b/contrib/xntpd/compilers/sunos4.posix.gcc new file mode 100644 index 0000000000..09e841a2b4 --- /dev/null +++ b/contrib/xntpd/compilers/sunos4.posix.gcc @@ -0,0 +1 @@ +COMPILER= gcc -DUSE_PROTOTYPES -Wall -O2 -finline-functions -fdelayed-branch -fomit-frame-pointer diff --git a/contrib/xntpd/compilers/sunos5.1.gcc b/contrib/xntpd/compilers/sunos5.1.gcc new file mode 100644 index 0000000000..fe6af589c4 --- /dev/null +++ b/contrib/xntpd/compilers/sunos5.1.gcc @@ -0,0 +1,2 @@ +COMPILER= gcc -traditional + diff --git a/contrib/xntpd/compilers/sunos5.2.gcc b/contrib/xntpd/compilers/sunos5.2.gcc new file mode 100644 index 0000000000..fe6af589c4 --- /dev/null +++ b/contrib/xntpd/compilers/sunos5.2.gcc @@ -0,0 +1,2 @@ +COMPILER= gcc -traditional + diff --git a/contrib/xntpd/compilers/ultrix.bsd.cc b/contrib/xntpd/compilers/ultrix.bsd.cc new file mode 100644 index 0000000000..06f68830e5 --- /dev/null +++ b/contrib/xntpd/compilers/ultrix.bsd.cc @@ -0,0 +1,2 @@ +COMPILER= cc -Olimit 800 + diff --git a/contrib/xntpd/compilers/ultrix.bsd.gcc b/contrib/xntpd/compilers/ultrix.bsd.gcc new file mode 100644 index 0000000000..5ed9d554ab --- /dev/null +++ b/contrib/xntpd/compilers/ultrix.bsd.gcc @@ -0,0 +1 @@ +COMPILER= gcc -Wall -O2 -finline-functions -fdelayed-branch diff --git a/contrib/xntpd/compilers/ultrix.posix.cc b/contrib/xntpd/compilers/ultrix.posix.cc new file mode 100644 index 0000000000..06f68830e5 --- /dev/null +++ b/contrib/xntpd/compilers/ultrix.posix.cc @@ -0,0 +1,2 @@ +COMPILER= cc -Olimit 800 + diff --git a/contrib/xntpd/compilers/ultrix.posix.gcc b/contrib/xntpd/compilers/ultrix.posix.gcc new file mode 100644 index 0000000000..5ed9d554ab --- /dev/null +++ b/contrib/xntpd/compilers/ultrix.posix.gcc @@ -0,0 +1 @@ +COMPILER= gcc -Wall -O2 -finline-functions -fdelayed-branch diff --git a/contrib/xntpd/conf/Config.CHATHAM b/contrib/xntpd/conf/Config.CHATHAM new file mode 100644 index 0000000000..41e6fc2aa3 --- /dev/null +++ b/contrib/xntpd/conf/Config.CHATHAM @@ -0,0 +1,214 @@ +# Edit this file to reflect information specific to your installation. +# Then run 'make makeconfig' to propagate the information to all the makefiles, +# Config.CHATHAM,v 3.1 1993/07/06 01:03:42 jbj Exp + +# +# Definitions for the library: +# +# You must define one of -DXNTP_BIG_ENDIAN, -DXNTP_LITTLE_ENDIAN +# or -DXNTP_AUTO_ENDIAN depending on which way your machine's +# bytes go for the benefit of the DES routine. Most things +# sold by DEC, the NS32x32 and the 80386 deserve a +# -DXNTP_LITTLE_ENDIAN. Most of the rest of the world does +# it the other way. If in doubt, pick one, compile +# everything and run authstuff/authcert < authstuff/certdata. +# If everything fails, do it the other way. +# +# Under BSD, you may define -DXNTP_NETINET_ENDIAN to use +# netinet/in.h to determine which of -DXNTP_BIG_ENDIAN and +# XNTP_LITTLE_ENDIAN should be used. +# +LIBDEFS= -DWORDS_BIGENDIAN + +# +# Library loading: +# +# If you don't want your library ranlib'ed, chose the second line +# +RANLIB= ranlib +#RANLIB= : # ar does the work of ranlib under System V + +# +# Definitions for programs: +# +# If your compiler doesn't understand the declaration `signed char', +# add -DNO_SIGNED_CHAR_DECL. Your `char' data type had better be +# signed. If you don't know what the compiler knows, try it +# without the flag. If you get a syntax error on line 13 of +# ntp.h, add it. Note that `signed char' is an ANSIism. Most +# older, pcc-derived compilers will need this flag. +# +# If your library already has 's_char' defined, add -DS_CHAR_DEFINED. +# +# For SunOS 3.x, add -DSUN_3_3_STINKS (otherwise it will complain +# about broadaddr and will hang if you run without a -d flag +# on the command line. I actually can't believe the latter +# bug. If it hangs on your system with the flag defined, peruse +# xntpd/ntp_io.c for some rude comments about SunOS 3.5 and try it +# the other way). This flag affects xntpd only. +# +# For Ultrix 2.0, add -DULT_2_0_SUCKS. This OS has the same hanging +# bug as SunOS 3.5 (is this an original 4.2 bug?) and in addition +# has some strangeness concerning signal masks. Ultrix 2.3 doesn't +# have these problems. If you're running something in between +# you're on your own. This flag affects xntpd only. +# +# For SunOS 4.x, add -DDOSYNCTODR_SUCKS to include the code in ntp_util.c +# that sets the battery clock at the same time that it updates +# the driftfile. It does this by revving up the niceness, then +# sets the time of day to the current time of day. Ordinarily, +# you would need this only on non-networked machines. +# +# For some machines, settimeofday does not set the sub-second component +# of the time correctly. For these machines add -DSETTIMEOFDAY_BROKEN. +# If xntpd keeps STEPPING the clock by small amounts, then it is +# possible that you are suffering from this problem. +# +# There are three ways to pry loose the kernel variables tick and tickadj +# needed by ntp_unixclock.c. One reads kmem and and is enabled +# with -DREADKMEM. One uses Sun's libkvm and is enabled with +# -DUSELIBKVM. The last one uses builtin defaults and is enabled +# with -DNOKMEM. Therefore, one of -DUSELIBKVM, -DREADKMEM or +# -DNOKMEM must be defined. Suns and recent BSD should use +# -DUSELIBKVM; others should use -DREADKMEM. If -DUSELIBKVM, use +# the DAEMONLIBS below to get the kernel routines. +# +# If your gethostbyname() routine isn't based on the DNS resolver (and, +# in particular, h_errno doesn't exist) add a -DNODNS. There +# doesn't seem to be a good way to detect this automatically which +# works in all cases. This flag affects xntpres only. +# +# Adding -DLOCK_PROCESS to the compilation flags will prevent +# xntpd from being swapped out on systems where the plock(3) call +# is available. +# +# The flag -DDEBUG includes some debugging code. +# +# The flag -DREFCLOCK causes the basic reference clock support to be +# compiled into the daemon. If you set this you will also want +# to configure the particular clock drivers you want in the +# CLOCKDEFS= line below. This flag affects xntpd only. +# +# There is an occurance of a call to rindex() in the daemon. You may +# have to include a -Drindex=strrchr to get this to load right. +# +# To change the location of the configuration file, use a +# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar. +# +# Under HP-UX, you must use either -Dhpux70 or -Dhpux80 as, +# well as -DNOKMEM +# +# If your library doesn't include the vsprintf() routine, define +# NEED_VSPRINTF. +# +# There are three ways to utilize external 1-pps signals. Define -DPPS to +# include just the pps routine, such as used by the DCF77 reference clock +# driver. Define -DPPSDEV ito include a serial device driver. This +# requires a serial port and either a line discipline or STREAMS module. +# Define -DPPSCD to include the driver and a special kernal hack +# (for SunOS 4.1.1) that intercepts carrier-detect transitions +# generated by the pps signal. Only one of these flags should be defined. +# +DEFS= -DUSELIBKVM -DDEBUG -DSTREAM -DREFCLOCK -DNO_SIGNED_CHAR_DECL -DPPS -DPPSDEV -DXNTP_RETROFIT_STDLIB -DHAVE_UNISTD_H + +# +# Authentication types supported. Choose from DES and MD5. If you +# have a 680x0 type CPU and GNU-C, also choose -DFASTMD5 +# +AUTHDEFS=-DDES -DMD5 + +# +# Clock support definitions (these only make sense if -DREFCLOCK used): +# +# Define -DLOCAL_CLOCK to include local pseudo-clock support +# +# Define -DPST to include support for the PST 1020 WWV/H receiver. +# +# Define -DWWVB to include support for the Spectracom 8170 WWVB receiver. +# Define -DWWVBPPS for PPS support via the WWVB receiver; also, +# define -DPPSCD in the DEFS above. This requires the ppsclock +# streams module under SunOS 4.2. +# +# Define -DCHU to include support for a driver to receive the CHU +# timecode. Note that to compile in CHU support you must +# previously have installed the CHU serial line discipline in +# the kernel of the machine you are doing the compile on. +# +# Define -DDCF to include support for the DCF77 receiver. This code +# requires a special STREAMS module found in the kernel directory. +# Define -DDCFPPS for PPS support via the DCF77 receiver; also, +# devine -DPPS in the DEFS above. +# +# Define -DMX4200 to support a Magnavox 4200 GPS receiver. Define -DPPSCD +# in the DEFS above for PPS support via this receiver. This requires +# the ppsclock streams module under SunOS 4.2. +# +# Define -DAS2201 to include support for the Austron 2201 GPS Timing +# Receiver. Define -DPPSCD in the DEFS above for PPS support via this +# receiver. This requires the ppsclock streams module under SunOS 4.2. +# +# Define -DGOES to support a Kinemetrics TrueTime 468-DC GOES receiver. This +# driver may work with other True-Time products as well. +# +# Define -DOMEGA to support a Kinemetrics TrueTime OM-DC OMEGA receiver. +# +# Define -DTPRO to support a KSI/Odetics TPRO-S IRIG-B timecode reader. This +# requires the Sun interface driver available from KSI. +# +# Define -DLEITCH to support a Leitch CSD 5300 Master Clock System Driver +# for the HP 5061B Cesium Clock. +# +CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DWWVBPPS -DCHU -DDCF -DMX4200 -DAS2201 -DGOES -DOMEGA -DTPRO -DLEITCH -DIRIG + +# +# For MIPS 4.3BSD or RISCos 4.0, include a -lmld to get the nlist() routine. +# If USELIBKVM is defined above, include a -lkvm to get the kernel +# routines. +# +#DAEMONLIBS= -lmld +DAEMONLIBS= -lkvm +#DAEMONLIBS= + +# +# Name resolver library. Included when loading xntpres, which calls +# gethostbyname(). Define this if you would rather use a different +# version of the routine than the one in libc.a +# +#RESLIB= -lresolv +RESLIB= + +# +# Option flags for the C compiler. A -g if you are uncomfortable +# +COPTS= -O + +# +# C compiler to use. gcc will work, but avoid the -fstrength-reduce option +# if the version is 1.35 or earlier (using this option caused incorrect +# code to be generated in the DES key permutation code, and perhaps +# elsewhere). +# +COMPILER= gcc -pipe -Wall -g -O2 -finline-functions -fdelayed-branch -fomit-frame-pointer +#COMPILER= cc -pipe + +# +# Directory into which binaries should be installed +# +BINDIR= /usr/local/bin + +# +# Special library for adjtime emulation. Used under HP-UX +# (remember to run make in the adjtime directory) +# +#ADJLIB= ../adjtime/libadjtime.a +ADJLIB= + +# +# BSD emulation library. In theory, this fixes signal semantics under +# HP-UX, but it doesn't work with 8.0 on a 9000s340, so there is now +# a work-around in the code (compiled when hpux80 is defined). In other +# words, use this for HP-UX prior to 8.0. +# +#COMPAT= -lBSD +COMPAT= + diff --git a/contrib/xntpd/conf/Config.MONOMOY b/contrib/xntpd/conf/Config.MONOMOY new file mode 100644 index 0000000000..b9e075fbfc --- /dev/null +++ b/contrib/xntpd/conf/Config.MONOMOY @@ -0,0 +1,189 @@ +# Edit this file to reflect information specific to your installation. +# Then run 'make makeconfig' to propagate the information to all the makefiles, +# Config.MONOMOY,v 3.1 1993/07/06 01:03:43 jbj Exp + +# Config.bsdi by Bdale Garbee, N3EUA, bdale@gag.com +# +# Tested with the BSDI BSD/386 0.9.3 "gamma 4" revision. It should +# work fine with this or later revs of BSD/386. +# +# Definitions for the library: +# +# You must define one of -DXNTP_BIG_ENDIAN, -DXNTP_LITTLE_ENDIAN +# or -DXNTP_AUTO_ENDIAN depending on which way your machine's +# bytes go for the benefit of the DES routine. Most things +# sold by DEC, the NS32x32 and the 80386 deserve a +# -DXNTP_LITTLE_ENDIAN. Most of the rest of the world does +# it the other way. If in doubt, pick one, compile +# everything and run authstuff/authcert < authstuff/certdata. +# If everything fails, do it the other way. +# +# Under BSD, you may define -DXNTP_NETINET_ENDIAN to use +# netinet/in.h to determine which of -DXNTP_BIG_ENDIAN and +# XNTP_LITTLE_ENDIAN should be used. +# +LIBDEFS= -DXNTP_LITTLE_ENDIAN + +# +# Library loading: +# +# If you don't want your library ranlib'ed, chose the second line +# +RANLIB= ranlib +#RANLIB= : # ar does the work of ranlib under System V + +# +# Definitions for programs: +# +# If your compiler doesn't understand the declaration `signed char', +# add -DNO_SIGNED_CHAR_DECL. Your `char' data type had better be +# signed. If you don't know what the compiler knows, try it +# without the flag. If you get a syntax error on line 13 of +# ntp.h, add it. Note that `signed char' is an ANSIism. Most +# older, pcc-derived compilers will need this flag. +# +# If your library already has 's_char' defined, add -DS_CHAR_DEFINED. +# +# For SunOS 3.x, add -DSUN_3_3_STINKS (otherwise it will complain +# about broadaddr and will hang if you run without a -d flag +# on the command line. I actually can't believe the latter +# bug. If it hangs on your system with the flag defined, peruse +# xntpd/ntp_io.c for some rude comments about SunOS 3.5 and try it +# the other way). This flag affects xntpd only. +# +# For Ultrix 2.0, add -DULT_2_0_SUCKS. This OS has the same hanging +# bug as SunOS 3.5 (is this an original 4.2 bug?) and in addition +# has some strangeness concerning signal masks. Ultrix 2.3 doesn't +# have these problems. If you're running something in between +# you're on your own. This flag affects xntpd only. +# +# For SunOS 4.x, add -DDOSYNCTODR_SUCKS to include the code in ntp_util.c +# that sets the battery clock at the same time that it updates +# the driftfile. It does this by revving up the niceness, then +# sets the time of day to the current time of day. Ordinarily, +# you would need this only on non-networked machines. +# +# There are three ways to pry loose the kernel variables tick and tickadj +# needed by ntp_unixclock.c. One reads kmem and and is enabled +# with -DREADKMEM. One uses Sun's libkvm and is enabled with +# -DUSELIBKVM. The last one uses builtin defaults and is enabled +# with -DNOKMEM. Therefore, one of -DUSELIBKVM, -DREADKMEM or +# -DNOKMEM must be defined. Suns and recent BSD should use +# -DUSELIBKVM; others should use -DREADKMEM. If -DUSELIBKVM, use +# the DAEMONLIBS below to get the kernel routines. +# +# If your gethostbyname() routine isn't based on the DNS resolver (and, +# in particular, h_errno doesn't exist) add a -DNODNS. There +# doesn't seem to be a good way to detect this automatically which +# works in all cases. This flag affects xntpres only. +# +# The flag -DDEBUG includes some debugging code. +# +# The flag -DREFCLOCK causes the basic reference clock support to be +# compiled into the daemon. If you set this you will also want +# to configure the particular clock drivers you want in the +# CLOCKDEFS= line below. This flag affects xntpd only. +# +# There is an occurance of a call to rindex() in the daemon. You may +# have to include a -Drindex=strrchr to get this to load right. +# +# To change the location of the configuration file, use a +# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar. +# +# Under HP-UX, you must use either -Dhpux70 or -Dhpux80 as, +# well as -DNOKMEM +# +# If your library doesn't include the vsprintf() routine, define +# NEED_VSPRINTF. +# +# Define -DPPS to include support for a 1-pps signal. Define -DPPSDEV +# to include a device driver for it. The latter requires a +# serial port and either a line discipline or STREAMS module. +# The PPS signal may also be generated via a reference clock +# module like DCF77. In that case a special define is required for +# the reference clock module (only one source of PPS signal should +# be used) +# +DEFS= -DBSDI -DUSELIBKVM -DDEBUG -DREFCLOCK -DPPS -DCONFIG_FILE=\\"/usr/local/etc/xntp.conf\\" -DHAVE_UNISTD_H + +# +# Authentication types supported. Choose from DES and MD5. If you +# have a 680x0 type CPU and GNU-C, also choose -DFASTMD5 +# +AUTHDEFS=-DDES -DMD5 + +# +# Clock support definitions (these only make sense if -DREFCLOCK used): +# +# Define -DLOCAL_CLOCK to include local pseudo-clock support +# +# Define -DPST to include support for the PST 1020 WWV/H receiver. +# +# Define -DWWVB to include support for the Spectracom 8170 WWVB receiver. +# +# Define -DCHU to include support for a driver to receive the CHU +# timecode. Note that to compile in CHU support you must +# previously have installed the CHU serial line discipline in +# the kernel of the machine you are doing the compile on. +# +# Define -DDCF to include support for the DCF77 receiver. This code +# requires a special STREAMS module found in the kernel directory. +# Define -DDCFPPS for PPS support via the DCF77 receiver +# (see also: -DPPS) +# +# Define -DGOES to support a Kinemetrics TrueTime 468-DC GOES receiver. +# +CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DCHU -DGOES # -DMX4200 -DAS2201 + +# +# For MIPS 4.3BSD or RISCos 4.0, include a -lmld to get the nlist() routine. +# If USELIBKVM is defined above, include a -lkvm to get the kernel +# routines. +# +#DAEMONLIBS= -lmld +DAEMONLIBS= -lkvm +#DAEMONLIBS= + +# +# Name resolver library. Included when loading xntpres, which calls +# gethostbyname(). Define this if you would rather use a different +# version of the routine than the one in libc.a +# +#RESLIB= -lresolv +RESLIB= + +# +# Option flags for the C compiler. A -g if you are uncomfortable +# +COPTS= -O + +# +# C compiler to use. gcc will work, but avoid the -fstrength-reduce option +# if the version is 1.35 or earlier (using this option caused incorrect +# code to be generated in the DES key permutation code, and perhaps +# elsewhere). +# +COMPILER= gcc -pipe -Wall -g -O -finline-functions -fdelayed-branch -fomit-frame-pointer +#COMPILER= cc -pipe -g + +# +# Directory into which binaries should be installed +# +BINDIR= /usr/local/bin + +# +# Special library for adjtime emulation. Used under HP-UX +# (remember to run make in the adjtime directory) +# +#ADJLIB= ../adjtime/libadjtime.a +ADJLIB= + +# +# BSD emulation library. In theory, this fixes signal semantics under +# HP-UX, but it doesn't work with 8.0 on a 9000s340, so there is now +# a work-around in the code (compiled when hpux80 is defined). In other +# words, use this for HP-UX prior to 8.0. +# +#COMPAT= -lBSD +COMPAT= + diff --git a/contrib/xntpd/conf/Config.TIGER b/contrib/xntpd/conf/Config.TIGER new file mode 100644 index 0000000000..c757ad90e1 --- /dev/null +++ b/contrib/xntpd/conf/Config.TIGER @@ -0,0 +1,185 @@ +# Edit this file to reflect information specific to your installation. +# Then run 'make makeconfig' to propagate the information to all the makefiles, +# Config.TIGER,v 3.1 1993/07/06 01:03:45 jbj Exp + +# +# Definitions for the library: +# +# You must define one of -DXNTP_BIG_ENDIAN, -DXNTP_LITTLE_ENDIAN +# or -DXNTP_AUTO_ENDIAN depending on which way your machine's +# bytes go for the benefit of the DES routine. Most things +# sold by DEC, the NS32x32 and the 80386 deserve a +# -DXNTP_LITTLE_ENDIAN. Most of the rest of the world does +# it the other way. If in doubt, pick one, compile +# everything and run authstuff/authcert < authstuff/certdata. +# If everything fails, do it the other way. +# +# Under BSD, you may define -DXNTP_NETINET_ENDIAN to use +# netinet/in.h to determine which of -DXNTP_BIG_ENDIAN and +# XNTP_LITTLE_ENDIAN should be used. +# +LIBDEFS= -DXNTP_LITTLE_ENDIAN + +# +# Library loading: +# +# If you don't want your library ranlib'ed, chose the second line +# +RANLIB= ranlib +#RANLIB= : # ar does the work of ranlib under System V + +# +# Definitions for programs: +# +# If your compiler doesn't understand the declaration `signed char', +# add -DNO_SIGNED_CHAR_DECL. Your `char' data type had better be +# signed. If you don't know what the compiler knows, try it +# without the flag. If you get a syntax error on line 13 of +# ntp.h, add it. Note that `signed char' is an ANSIism. Most +# older, pcc-derived compilers will need this flag. +# +# If your library already has 's_char' defined, add -DS_CHAR_DEFINED. +# +# For SunOS 3.x, add -DSUN_3_3_STINKS (otherwise it will complain +# about broadaddr and will hang if you run without a -d flag +# on the command line. I actually can't believe the latter +# bug. If it hangs on your system with the flag defined, peruse +# xntpd/ntp_io.c for some rude comments about SunOS 3.5 and try it +# the other way). This flag affects xntpd only. +# +# For Ultrix 2.0, add -DULT_2_0_SUCKS. This OS has the same hanging +# bug as SunOS 3.5 (is this an original 4.2 bug?) and in addition +# has some strangeness concerning signal masks. Ultrix 2.3 doesn't +# have these problems. If you're running something in between +# you're on your own. This flag affects xntpd only. +# +# For SunOS 4.x, add -DDOSYNCTODR_SUCKS to include the code in ntp_util.c +# that sets the battery clock at the same time that it updates +# the driftfile. It does this by revving up the niceness, then +# sets the time of day to the current time of day. Ordinarily, +# you would need this only on non-networked machines. +# +# There are three ways to pry loose the kernel variables tick and tickadj +# needed by ntp_unixclock.c. One reads kmem and and is enabled +# with -DREADKMEM. One uses Sun's libkvm and is enabled with +# -DUSELIBKVM. The last one uses builtin defaults and is enabled +# with -DNOKMEM. Therefore, one of -DUSELIBKVM, -DREADKMEM or +# -DNOKMEM must be defined. Suns and recent BSD should use +# -DUSELIBKVM; others should use -DREADKMEM. If -DUSELIBKVM, use +# the DAEMONLIBS below to get the kernel routines. +# +# If your gethostbyname() routine isn't based on the DNS resolver (and, +# in particular, h_errno doesn't exist) add a -DNODNS. There +# doesn't seem to be a good way to detect this automatically which +# works in all cases. This flag affects xntpres only. +# +# The flag -DDEBUG includes some debugging code. +# +# The flag -DREFCLOCK causes the basic reference clock support to be +# compiled into the daemon. If you set this you will also want +# to configure the particular clock drivers you want in the +# CLOCKDEFS= line below. This flag affects xntpd only. +# +# There is an occurance of a call to rindex() in the daemon. You may +# have to include a -Drindex=strrchr to get this to load right. +# +# To change the location of the configuration file, use a +# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar. +# +# Under HP-UX, you must use either -Dhpux70 or -Dhpux80 as, +# well as -DNOKMEM +# +# If your library doesn't include the vsprintf() routine, define +# NEED_VSPRINTF. +# +# Define -DPPS to include support for a 1-pps signal. Define -DPPSDEV +# to include a device driver for it. The latter requires a +# serial port and either a line discipline or STREAMS module. +# The PPS signal may also be generated via a reference clock +# module like DCF77. In that case a special define is required for +# the reference clock module (only one source of PPS signal should +# be used) +# +DEFS= -DREFCLOCK -DS_CHAR_DEFINED -DREADKMEM -DDEBUG -DPLL -DXNTP_RETROFIT_STDLIB -DHAVE_UNISTD_H + +# +# Authentication types supported. Choose from DES and MD5. If you +# have a 680x0 type CPU and GNU-C, also choose -DFASTMD5 +# +AUTHDEFS=-DDES -DMD5 + +# +# Clock support definitions (these only make sense if -DREFCLOCK used): +# +# Define -DLOCAL_CLOCK to include local pseudo-clock support +# +# Define -DPST to include support for the PST 1020 WWV/H receiver. +# +# Define -DWWVB to include support for the Spectracom 8170 WWVB receiver. +# +# Define -DCHU to include support for a driver to receive the CHU +# timecode. Note that to compile in CHU support you must +# previously have installed the CHU serial line discipline in +# the kernel of the machine you are doing the compile on. +# +# Define -DDCF to include support for the DCF77 receiver. This code +# requires a special STREAMS module found in the kernel directory. +# Define -DDCFPPS for PPS support via the DCF77 receiver +# (see also: -DPPS) +# +# Define -DGOES to support a Kinemetrics TrueTime 468-DC GOES receiver. +# +CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DGOES -DCHU + +# +# For MIPS 4.3BSD or RISCos 4.0, include a -lmld to get the nlist() routine. +# If USELIBKVM is defined above, include a -lkvm to get the kernel +# routines. +# +#DAEMONLIBS= -lmld +#DAEMONLIBS= -lkvm +DAEMONLIBS= + +# +# Name resolver library. Included when loading xntpres, which calls +# gethostbyname(). Define this if you would rather use a different +# version of the routine than the one in libc.a +# +#RESLIB= -lresolv +RESLIB= + +# +# Option flags for the C compiler. A -g if you are uncomfortable +# +COPTS= -O + +# +# C compiler to use. gcc will work, but avoid the -fstrength-reduce option +# if the version is 1.35 or earlier (using this option caused incorrect +# code to be generated in the DES key permutation code, and perhaps +# elsewhere). +# +COMPILER= gcc -Wall -g -O2 -finline-functions -fdelayed-branch -fomit-frame-pointer +#COMPILER= cc + +# +# Directory into which binaries should be installed +# +BINDIR= /usr/local/bin + +# +# Special library for adjtime emulation. Used under HP-UX +# (remember to run make in the adjtime directory) +# +#ADJLIB= ../adjtime/libadjtime.a +ADJLIB= + +# +# BSD emulation library. In theory, this fixes signal semantics under +# HP-UX, but it doesn't work with 8.0 on a 9000s340, so there is now +# a work-around in the code (compiled when hpux80 is defined). In other +# words, use this for HP-UX prior to 8.0. +# +#COMPAT= -lBSD +COMPAT= + diff --git a/contrib/xntpd/conf/Config.TRURO b/contrib/xntpd/conf/Config.TRURO new file mode 100644 index 0000000000..6caa2b82d6 --- /dev/null +++ b/contrib/xntpd/conf/Config.TRURO @@ -0,0 +1,205 @@ +# Edit this file to reflect information specific to your installation. +# Then run 'make makeconfig' to propagate the information to all the makefiles, +# Config.TRURO,v 3.1 1993/07/06 01:03:46 jbj Exp + +# +# Definitions for the library: +# +# You must define one of -DXNTP_BIG_ENDIAN, -DXNTP_LITTLE_ENDIAN +# or -DXNTP_AUTO_ENDIAN depending on which way your machine's +# bytes go for the benefit of the DES routine. Most things +# sold by DEC, the NS32x32 and the 80386 deserve a +# -DXNTP_LITTLE_ENDIAN. Most of the rest of the world does +# it the other way. If in doubt, pick one, compile +# everything and run authstuff/authcert < authstuff/certdata. +# If everything fails, do it the other way. +# +# Under BSD, you may define -DXNTP_NETINET_ENDIAN to use +# netinet/in.h to determine which of -DXNTP_BIG_ENDIAN and +# XNTP_LITTLE_ENDIAN should be used. +# +LIBDEFS= -DWORDS_BIGENDIAN + +# +# Library loading: +# +# If you don't want your library ranlib'ed, chose the second line +# +RANLIB= : # ar does the work of ranlib under System V + +# +# Definitions for programs: +# +# If your compiler doesn't understand the declaration `signed char', +# add -DNO_SIGNED_CHAR_DECL. Your `char' data type had better be +# signed. If you don't know what the compiler knows, try it +# without the flag. If you get a syntax error on line 13 of +# ntp.h, add it. Note that `signed char' is an ANSIism. Most +# older, pcc-derived compilers will need this flag. +# +# If your library already has 's_char' defined, add -DS_CHAR_DEFINED. +# +# For SunOS 3.x, add -DSUN_3_3_STINKS (otherwise it will complain +# about broadaddr and will hang if you run without a -d flag +# on the command line. I actually can't believe the latter +# bug. If it hangs on your system with the flag defined, peruse +# xntpd/ntp_io.c for some rude comments about SunOS 3.5 and try it +# the other way). This flag affects xntpd only. +# +# For Ultrix 2.0, add -DULT_2_0_SUCKS. This OS has the same hanging +# bug as SunOS 3.5 (is this an original 4.2 bug?) and in addition +# has some strangeness concerning signal masks. Ultrix 2.3 doesn't +# have these problems. If you're running something in between +# you're on your own. This flag affects xntpd only. +# +# For SunOS 4.x, add -DDOSYNCTODR_SUCKS to include the code in ntp_util.c +# that sets the battery clock at the same time that it updates +# the driftfile. It does this by revving up the niceness, then +# sets the time of day to the current time of day. Ordinarily, +# you would need this only on non-networked machines. +# +# For some machines, settimeofday does not set the sub-second component +# of the time correctly. For these machines add -DSETTIMEOFDAY_BROKEN. +# If xntpd keeps STEPPING the clock by small amounts, then it is +# possible that you are suffering from this problem. +# +# There are four ways to pry loose the kernel variables tick and tickadj +# needed by ntp_unixclock.c. One reads kmem and and is enabled +# with -DREADKMEM. One uses Sun's libkvm and is enabled with +# -DUSELIBKVM. The last one uses builtin defaults and is enabled +# with -DNOKMEM. Therefore, one of -DUSELIBKVM, -DREADKMEM or +# -DNOKMEM must be defined. Suns, if they are not running Solaris, +# and recent BSD should use -DUSELIBKVM; others should use +# -DREADKMEM. Soalris 2.1 should use -DSOLARIS. +# If -DUSELIBKVM, use the DAEMONLIBS below to get the +# kernel routines. +# +# If your gethostbyname() routine isn't based on the DNS resolver (and, +# in particular, h_errno doesn't exist) add a -DNODNS. There +# doesn't seem to be a good way to detect this automatically which +# works in all cases. This flag affects xntpres only. +# +# The flag -DDEBUG includes some debugging code. +# +# The flag -DREFCLOCK causes the basic reference clock support to be +# compiled into the daemon. If you set this you will also want +# to configure the particular clock drivers you want in the +# CLOCKDEFS= line below. This flag affects xntpd only. +# +# There is an occurance of a call to rindex() in the daemon. You may +# have to include a -Drindex=strrchr to get this to load right. +# +# To change the location of the configuration file, use a +# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar. +# +# Under HP-UX, you must use either -Dhpux70 or -Dhpux80 as, +# well as -DNOKMEM +# +# Under Solaris 2.1, you must use -DSOLARIS and -DSLEWALWAYS. +# Don't define USELIBKVM, NOKMEM or READKMEM. +# +# If your library doesn't include the vsprintf() routine, define +# NEED_VSPRINTF. +# +# There are three ways to utilize external 1-pps signals. Define -DPPS to +# include just the pps routine, such as used by the DCF77 reference clock +# driver. Define -DPPSDEV ito include a serial device driver. This +# requires a serial port and either a line discipline or STREAMS module. +# Define -DPPSCD to include the driver and a special kernal hack +# (for SunOS 4.1.1) that intercepts carrier-detect transitions +# generated by the pps signal. Only one of these flags should be defined. +# +DEFS= -DDEBUG -DSTREAM -DREFCLOCK -DNO_SIGNED_CHAR_DECL -DSLEWALWAYS -DSOLARIS -DPPS -DSTUPID_SIGNAL -DXNTP_RETROFIT_STDLIB -DHAVE_UNISTD_H + +# +# Authentication types supported. Choose from DES and MD5. If you +# have a 680x0 type CPU and GNU-C, also choose -DFASTMD5 +# +AUTHDEFS=-DDES -DMD5 + +# +# Clock support definitions (these only make sense if -DREFCLOCK used): +# +# Define -DLOCAL_CLOCK to include local pseudo-clock support +# +# Define -DPST to include support for the PST 1020 WWV/H receiver. +# +# Define -DWWVB to include support for the Spectracom 8170 WWVB receiver. +# Define -DWWVBPPS for PPS support via the WWVB receiver; also, +# define -DPPSCD in the DEFS above. This requires the ppsclock +# streams module under SunOS 4.2. +# +# Define -DCHU to include support for a driver to receive the CHU +# timecode. Note that to compile in CHU support you must +# previously have installed the CHU serial line discipline in +# the kernel of the machine you are doing the compile on. +# +# Define -DDCF to include support for the DCF77 receiver. This code +# requires a special STREAMS module found in the kernel directory. +# Define -DDCFPPS for PPS support via the DCF77 receiver; also, +# devine -DPPS in the DEFS above. +# +# Define -DMX4200 to support a Magnavox 4200 GPS receiver. Define -DPPSCD +# in the DEFS above for PPS support via this receiver. This requires +# the ppsclock streams module under SunOS 4.2. +# +# Define -DAS2201 to include support for the Austron 2201 GPS Timing +# Receiver. Define -DPPSCD in the DEFS above for PPS support via this +# receiver. This requires the ppsclock streams module under SunOS 4.2. +# +# Define -DGOES to support a Kinemetrics TrueTime 468-DC GOES receiver. This +# driver may work with other True-Time products as well. +# +CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DWWVBPPS -DGOES -DCHU -DMX4200 -DAS2201 -DOMEGA -DTPRO -DLEITCH -DIRIG + +# +# For MIPS 4.3BSD or RISCos 4.0, include a -lmld to get the nlist() routine. +# If USELIBKVM is defined above, include a -lkvm to get the kernel +# routines. +# +#DAEMONLIBS= -lmld +DAEMONLIBS= + +# +# Name resolver library. Included when loading xntpres, which calls +# gethostbyname(). Define this if you would rather use a different +# version of the routine than the one in libc.a +# +#RESLIB= -lresolv +RESLIB= -lsocket -lnsl -lelf + +# +# Option flags for the C compiler. A -g if you are uncomfortable +# +COPTS= -O + +# +# C compiler to use. gcc will work, but avoid the -fstrength-reduce option +# if the version is 1.35 or earlier (using this option caused incorrect +# code to be generated in the DES key permutation code, and perhaps +# elsewhere). +# +#COMPILER= gcc -traditional +COMPILER= gcc -pipe -Wall -g -O2 -finline-functions -fdelayed-branch -fomit-frame-pointer + +# +# Directory into which binaries should be installed +# +BINDIR= /usr/local/bin + +# +# Special library for adjtime emulation. Used under HP-UX +# (remember to run make in the adjtime directory) +# +#ADJLIB= ../adjtime/libadjtime.a +ADJLIB= + +# +# BSD emulation library. In theory, this fixes signal semantics under +# HP-UX, but it doesn't work with 8.0 on a 9000s340, so there is now +# a work-around in the code (compiled when hpux80 is defined). In other +# words, use this for HP-UX prior to 8.0. +# +#COMPAT= -lBSD +COMPAT= + diff --git a/contrib/xntpd/conf/Config.dartnet b/contrib/xntpd/conf/Config.dartnet new file mode 100644 index 0000000000..b591db3416 --- /dev/null +++ b/contrib/xntpd/conf/Config.dartnet @@ -0,0 +1,187 @@ +# This is the local configure file (distribution version). +# You must modify it to fit your particular configuration +# and name it Config.local +# The following configuratiions can be auto-generated: +# +# make Config.local.green +# make a Config.local that supports a local clock +# (i.e. allow fallback to use of the CPU's own clock) +# make Config.local.NO.clock +# make a Config.local that supports no clocks +# +# +# NOTE TO GREENHORNS +# +# For plug-'n-play and no radios or other complicated gadgetry, +# use "make Config.local.green" or "make Config.local.local" as above. +# +# Following defines can be set in the DEFS_OPT= define: +# +# The flag -DDEBUG includes some debugging code. To use this, include +# the define and start the daemon with one or more -d flags, depending +# on your calibration of pearannoya. The daemon will not detach your +# terminal in this case. Judicious use of grep will reduce the speaker +# volume to bearable levels. +# +# To change the location of the configuration file, use a +# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar. +# +# The -DSYSLOG_FILE defines allows logging messages that are normally +# reported via syslof() in a file. The file name can be configured using +# the configuration line "logfile " in CONFIG_FILE. +# +# There are three serial port system software interfaces, each of +# which is peculiar to one or more Unix versions. Define +# -DHAVE_SYSV_TTYS for basic System V compatibility; define -DSTREAM +# for POSIX compatibility including System V Streams, and +# HAVE_BSD_TTYS for 4.3bsd compatibility. Only one of these three +# should be defined. If none are defined, HAVE_BSD_TTYS is assumed. +# Usually these defines are already set correctly. +# +DEFS_OPT=-DDEBUG +# +# The DEFS_LOCAL define picks up all flags from DEFS_OPT (do not delete that) +# and one of the following: +# +# The flag -DREFCLOCK causes the basic reference clock support to be +# compiled into the daemon. If you set this you may also want to +# configure the particular clock drivers you want in the CLOCKDEFS= line +# below. This flag affects xntpd only. This define is included by +# default when using the "make makeconfig" script. +# +# The next two sets of defines are meaningful only when radio clock +# drivers or special 1-pps signals are to be used. For systems without +# these features, these delicious complexities can be avoided. Ordinarily, +# the "make makeconfig" script figures out which ones to use, but your +# mileage may vary. +# +# There are three ways to utilize external 1-pps signals. Define +# -DPPS to include just the pps routine, such as used by the DCF77(PARSE) +# clock driver. Define -DPPSCLK to include a serial device driver +# which avoids much of the jitter due to upper level port +# processing. This requires a dedicated serial port and either the +# tty_clock line discipline or tty_clk_streams module, both of +# which are in the ./kernel directory. Define -DPPSCD to include a +# special driver which intercepts carrier-detect transitions +# generated by the pps signal. This requires a nondedicated serial +# port and the ppsclock streams module in the ./kernel directory. +# Only one of these three flags should be defined. +# +# The flag KERNEL_PLL causes code to be compiled for a special feature of +# the kernel that (a) implements the phase-lock loop and (b) provides +# a user interface to learn time, maximum error and estimated error. +# See the file README.kern in the doc directory for further info. +# This code is activated only if the relevant kernel features have +# been configured; it does not affect operation of unmodified kernels. +# To compile it, however, requires a few header files from the +# special distribution. +# +# Note: following line must always start with DEFS_LOCAL= $(DEFS_OPT) +DEFS_LOCAL= $(DEFS_OPT) -DPPSPPS -DREFCLOCK -DKERNEL_PLL +# +# Radio clock support definitions (these only make sense if -DREFCLOCK +# used), which is normally the case. Note that a configuration can include +# no clocks, more than one type of clock and even multiple clocks of the +# same type. +# +# For most radio clocks operating with serial ports, accuracy can +# be considerably improved through use of the tty_clk line +# discipline or tty_clk_STREAMS streams module found in the +# ./kernel directory. These gizmos capture a timestamp upon +# occurrence of an intercept character and stuff it in the data +# stream for the clock driver to munch. To select this mode, +# postfix the driver name with the string CLK; that is, WWVB +# becomes WWVBCLK. If more than one clock is in use, the CLK +# postfix can be used with any or all of them. +# +# Alternatively, for the best accuracy, use the ppsclock streams +# module in the ./ppsclock directory to steal the carrier-detect +# transition and capture a precision timestamp. At present this +# works only with SunOS 4.1.1 or later. To select this mode, +# postfix the driver name with the string PPS; that is, AS2201 +# becomes AS2201PPS. If more than one clock is in use, the PPS +# postfix should be used with only one of them. If any PPS +# postfix is defined, the -DPPSPPS define should be used on the +# DEFS above. +# +# Define -DLOCAL_CLOCK for a local pseudo-clock to masquerade as a +# reference clock for those subnets without access to the real thing. +# Works in all systems and requires no hardware support. This is defined +# by default when using the "make makeconfig" script and greenhorn +# configuraiton. +# +# Define -DPST for a PST/Traconex 1020 WWV/H receiver. The driver +# supports both the CLK and PPS modes. It should work in all systems +# with a serial port. +# +# Define -DWWVB for a Spectracom 8170 or Netclock/2 WWVB receiver. It +# should work in all systems with a serial port. The driver supports +# both the CLK and PPS modes if the requisite kernel support is installed. +# +# Define -DCHU for a special CHU receiver using an ordinary shortwave +# radio. This requires the chu_clk line discipline or chu_clk_STREAMS +# module in the ./kernel directory. At present, this driver works only +# on SunOS4.1.x; operation in other systems has not been confirmed. +# Construction details for a suitable modem can be found in the ./gadget +# directory. The driver supports # neither the CLK nor PPS modes. +# +# Define -DPARSE for a DCF77/GPS(GENERIC) receiver. For best performance +# this requires a special parsestreams STREAMS (SunOS 4.x) module in the +# ./parse directory. Define -DPARSEPPS for PPS support via the +# DCF77/GPS (GENERIC) receiver; also, define -DPPS in the DEFS above. +# Define: -DCLOCK_MEINBERG for Meinberg clocks +# -DCLOCK_SCHMID for Schmid receivers +# -DCLOCK_DCF7000 for ELV DCF7000 +# -DCLOCK_RAWDCF for simple receivers (100/200ms pulses on Rx) +# -DCLOCK_TRIMSV6 for Trimble SV6 GPS receiver +# +# Define -DMX4200PPS for a Magnavox 4200 GPS receiver. At present, this +# driver works only on SunOS4.1.x with CPU serial ports only. The PPS +# mode is required. +# +# Define -DAS2201 for an Austron 2200A or 2201A GPS receiver. It should +# work in all systems with a serial port. The driver does not support the +# CLK mode, but does support the PPS mode. If the radio is connected to +# more than one machine, the PPS mode is required. +# +# Define -DGOES for a Kinemetrics/TrueTime 468-DC GOES receiver. This +# driver is known to work with some other TrueTime products as well, +# including the GPS-DC GPS receiver. It should work in all systems with +# a serial port. The driver does not support the CLK mode, but does +# support the PPS mode. +# +# Define -DOMEGA for a Kinemetrics/TrueTime OM-DC OMEGA receiver. It +# should work in all systems with a serial port. The driver does not +# support the CLK mode, but does support the PPS mode. +# +# Define -DTPRO for a KSI/Odetics TPRO-S IRIG-B timecode reader. This +# requires the SunOS interface driver available from KSI. The driver +# supports neither the CLK nor PPS modes. +# +# Define -DLEITCH for a Leitch CSD 5300 Master Clock System Driver for +# the HP 5061B Cesium Clock. It should work in all systems with a serial +# port. The driver does not support the CLK mode, but does support the +# PPS mode. +# +# Define -DMSFEESPPS for an EES M201 MSF receiver. It currently only works +# under SunOS 4.x with the PPSCD (ppsclock) STREAMS module, but the RCS +# files on cl.cam.ac.uk still has support for CLK and CBREAK modes. +# +# Define -DIRIG for a IRIG-B timecode timecode using the audio codec of +# the Sun SPARCstations. This requires a modified BSD audio driver and +# exclusive access to the audio port. A memo describing how it works and +# how to install the driver is in the README.irig file in the ./doc +# directory. +# +# Note: The following defines result in compilation of all the above radio +# clocks. This works on a Sun 4.1.x system which has tty_clk, chu_clk and +# ppsclock STREAMS modules installed. If the trailing CLK and PPS suffixes +# are removed and the IRIG, PARSE* and CLOCK* deleted, all of the rest compile +# under Ultrix 4.2a/3. If the MX4200 is removed, all the rest compile on a DEC +# OSF/1 Alpha. +# +CLOCKDEFS=-DAS2201PPS -DCHU -DGOES -DIRIG -DLEITCH -DLOCAL_CLOCK -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK +# +# Directory into which binaries should be installed (default /usr/local) +# +BINDIR= /usr/local/bin diff --git a/contrib/xntpd/conf/Config.local b/contrib/xntpd/conf/Config.local new file mode 100644 index 0000000000..4c5095c164 --- /dev/null +++ b/contrib/xntpd/conf/Config.local @@ -0,0 +1,190 @@ +# This is the local configure file (distribution version). +# You must modify it to fit your particular configuration +# and name it Config.local +# The following configuratiions can be auto-generated: +# +# make Config.local.green +# make a Config.local that supports a local clock +# (i.e. allow fallback to use of the CPU's own clock) +# make Config.local.NO.clock +# make a Config.local that supports no clocks +# +# +# NOTE TO GREENHORNS +# +# For plug-'n-play and no radios or other complicated gadgetry, +# use "make Config.local.green" as above. +# +# Following defines can be set in the DEFS_OPT= define: +# +# The flag -DDEBUG includes some debugging code. To use this, include +# the define and start the daemon with one or more -d flags, depending +# on your calibration of pearannoya. The daemon will not detach your +# terminal in this case. Judicious use of grep will reduce the speaker +# volume to bearable levels. +# +# To change the location of the configuration file, use a +# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar. +# +# The -DSYSLOG_FILE defines allows logging messages that are normally +# reported via syslof() in a file. The file name can be configured using +# the configuration line "logfile " in CONFIG_FILE. +# +# There are three serial port system software interfaces, each of +# which is peculiar to one or more Unix versions. Define +# -DHAVE_SYSV_TTYS for basic System V compatibility; define -DSTREAM +# for POSIX compatibility including System V Streams, and +# HAVE_BSD_TTYS for 4.3bsd compatibility. Only one of these three +# should be defined. If none are defined, HAVE_BSD_TTYS is assumed. +# Usually these defines are already set correctly. +# +DEFS_OPT=-DDEBUG + +# +# The DEFS_LOCAL define picks up all flags from DEFS_OPT (do not delete that) +# and one of the following: +# +# The flag -DREFCLOCK causes the basic reference clock support to be +# compiled into the daemon. If you set this you may also want to +# configure the particular clock drivers you want in the CLOCKDEFS= line +# below. This flag affects xntpd only. This define is included by +# default when using the "make makeconfig" script. +# +# The next two sets of defines are meaningful only when radio clock +# drivers or special 1-pps signals are to be used. For systems without +# these features, these delicious complexities can be avoided. Ordinarily, +# the "make makeconfig" script figures out which ones to use, but your +# mileage may vary. +# +# There are three ways to utilize external 1-pps signals. Define +# -DPPS to include just the pps routine, such as used by the DCF77(PARSE) +# clock driver. Define -DPPSCLK to include a serial device driver +# which avoids much of the jitter due to upper level port +# processing. This requires a dedicated serial port and either the +# tty_clock line discipline or tty_clk_streams module, both of +# which are in the ./kernel directory. Define -DPPSCD to include a +# special driver which intercepts carrier-detect transitions +# generated by the pps signal. This requires a nondedicated serial +# port and the ppsclock streams module in the ./kernel directory. +# Only one of these three flags should be defined. +# +# The flag KERNEL_PLL causes code to be compiled for a special feature of +# the kernel that (a) implements the phase-lock loop and (b) provides +# a user interface to learn time, maximum error and estimated error. +# See the file README.kern in the doc directory for further info. +# This code is activated only if the relevant kernel features have +# been configured; it does not affect operation of unmodified kernels. +# To compile it, however, requires a few header files from the +# special distribution. +# +# Note: following line must always start with DEFS_LOCAL= $(DEFS_OPT) +DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DPPSPPS -DKERNEL_PLL + +# +# Radio clock support definitions (these only make sense if -DREFCLOCK +# used), which is normally the case. Note that a configuration can include +# no clocks, more than one type of clock and even multiple clocks of the +# same type. +# +# For most radio clocks operating with serial ports, accuracy can +# be considerably improved through use of the tty_clk line +# discipline or tty_clk_STREAMS streams module found in the +# ./kernel directory. These gizmos capture a timestamp upon +# occurrence of an intercept character and stuff it in the data +# stream for the clock driver to munch. To select this mode, +# postfix the driver name with the string CLK; that is, WWVB +# becomes WWVBCLK. If more than one clock is in use, the CLK +# postfix can be used with any or all of them. +# +# Alternatively, for the best accuracy, use the ppsclock streams +# module in the ./ppsclock directory to steal the carrier-detect +# transition and capture a precision timestamp. At present this +# works only with SunOS 4.1.1 or later. To select this mode, +# postfix the driver name with the string PPS; that is, AS2201 +# becomes AS2201PPS. If more than one clock is in use, the PPS +# postfix should be used with only one of them. If any PPS +# postfix is defined, the -DPPSPPS define should be used on the +# DEFS above. +# +# Define -DLOCAL_CLOCK for a local pseudo-clock to masquerade as a +# reference clock for those subnets without access to the real thing. +# Works in all systems and requires no hardware support. This is defined +# by default when using the "make makeconfig" script and greenhorn +# configuraiton. +# +# Define -DPST for a PST/Traconex 1020 WWV/H receiver. The driver +# supports both the CLK and PPS modes. It should work in all systems +# with a serial port. +# +# Define -DWWVB for a Spectracom 8170 or Netclock/2 WWVB receiver. It +# should work in all systems with a serial port. The driver supports +# both the CLK and PPS modes if the requisite kernel support is installed. +# +# Define -DCHU for a special CHU receiver using an ordinary shortwave +# radio. This requires the chu_clk line discipline or chu_clk_STREAMS +# module in the ./kernel directory. At present, this driver works only +# on SunOS4.1.x; operation in other systems has not been confirmed. +# Construction details for a suitable modem can be found in the ./gadget +# directory. The driver supports # neither the CLK nor PPS modes. +# +# Define -DPARSE for a DCF77/GPS(GENERIC) receiver. For best performance +# this requires a special parsestreams STREAMS (SunOS 4.x) module in the +# ./parse directory. Define -DPARSEPPS for PPS support via the +# DCF77/GPS (GENERIC) receiver; also, define -DPPS in the DEFS above. +# Define: -DCLOCK_MEINBERG for Meinberg clocks +# -DCLOCK_SCHMID for Schmid receivers +# -DCLOCK_DCF7000 for ELV DCF7000 +# -DCLOCK_RAWDCF for simple receivers (100/200ms pulses on Rx) +# -DCLOCK_TRIMSV6 for Trimble SV6 GPS receiver +# +# Define -DMX4200PPS for a Magnavox 4200 GPS receiver. At present, this +# driver works only on SunOS4.1.x with CPU serial ports only. The PPS +# mode is required. +# +# Define -DAS2201 for an Austron 2200A or 2201A GPS receiver. It should +# work in all systems with a serial port. The driver does not support the +# CLK mode, but does support the PPS mode. If the radio is connected to +# more than one machine, the PPS mode is required. +# +# Define -DGOES for a Kinemetrics/TrueTime 468-DC GOES receiver. This +# driver is known to work with some other TrueTime products as well, +# including the GPS-DC GPS receiver. It should work in all systems with +# a serial port. The driver does not support the CLK mode, but does +# support the PPS mode. +# +# Define -DOMEGA for a Kinemetrics/TrueTime OM-DC OMEGA receiver. It +# should work in all systems with a serial port. The driver does not +# support the CLK mode, but does support the PPS mode. +# +# Define -DTPRO for a KSI/Odetics TPRO-S IRIG-B timecode reader. This +# requires the SunOS interface driver available from KSI. The driver +# supports neither the CLK nor PPS modes. +# +# Define -DLEITCH for a Leitch CSD 5300 Master Clock System Driver for +# the HP 5061B Cesium Clock. It should work in all systems with a serial +# port. The driver does not support the CLK mode, but does support the +# PPS mode. +# +# Define -DMSFEESPPS for an EES M201 MSF receiver. It currently only works +# under SunOS 4.x with the PPSCD (ppsclock) STREAMS module, but the RCS +# files on cl.cam.ac.uk still has support for CLK and CBREAK modes. +# +# Define -DIRIG for a IRIG-B timecode timecode using the audio codec of +# the Sun SPARCstations. This requires a modified BSD audio driver and +# exclusive access to the audio port. A memo describing how it works and +# how to install the driver is in the README.irig file in the ./doc +# directory. +# +# Note: The following defines result in compilation of all the above radio +# clocks. This works on a Sun 4.1.x system which has tty_clk, chu_clk and +# ppsclock STREAMS modules installed. If the trailing CLK and PPS suffixes +# are removed and the IRIG, PARSE* and CLOCK* deleted, all of the rest compile +# under Ultrix 4.2a/3. If the MX4200 is removed, all the rest compile on a DEC +# OSF/1 Alpha. +# +CLOCKDEFS= -DLOCAL_CLOCK -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH + +# +# Directory into which binaries should be installed (default /usr/local) +# +BINDIR= /usr/local/bin diff --git a/contrib/xntpd/conf/Config.svr4 b/contrib/xntpd/conf/Config.svr4 new file mode 100644 index 0000000000..d6d0661539 --- /dev/null +++ b/contrib/xntpd/conf/Config.svr4 @@ -0,0 +1,167 @@ +# +# This is the local configure file. Modify it to fit your particular +# configuration. +# +# NOTE TO GREENHORNS +# +# For plug-'n-play and no radios or other complicated gadgetry, set the +# alternate defines as shown. +# +# The flag -DDEBUG includes some debugging code. To use this, include +# the define and start the daemon with one or more -d flags, depending +# on your calibration of pearannoya. The daemon will not detach your +# terminal in this case. Judicious use of grep will reduce the speaker +# volume to bearable levels. +# +# To change the location of the configuration file, use a +# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar. +# +# The flag -DREFCLOCK causes the basic reference clock support to be +# compiled into the daemon. If you set this you may also want to +# configure the particular clock drivers you want in the CLOCKDEFS= line +# below. This flag affects xntpd only. This define is included by +# default when using the "make makeconfig" script. +# +# The next two sets of defines are meaningful only when radio clock +# drivers or special 1-pps signals are to be used. For systems without +# these features, these delicious complexities can be avoided. Ordinarily, +# the "make makeconfig" script figures out which ones to use, but your +# mileage may vary. +# +# There are three ways to utilize external 1-pps signals. Define +# -DPPS to include just the pps routine, such as used by the DCF77 +# clock driver. Define -DPPSCLK to include a serial device driver +# which avoids much of the jitter due to upper level port +# processing. This requires a dedicated serial port and either the +# tty_clock line discipline or tty_clk_streams module, both of +# which are in the ./kernel directory. Define -DPPSCD to include a +# special driver which intercepts carrier-detect transitions +# generated by the pps signal. This requires a nondedicated serial +# port and the ppsclock streams module in the ./kernel directory. +# Only one of these three flags should be defined. +# +# There are three serial port system software interfaces, each of +# which is peculiar to one or more Unix versions. Define +# -DHAVE_SYSV_TTYS for basic System V compatibility; define -DSTREAM +# for POSIX compatibility including System V Streams, and +# HAVE_BSD_TTYS for 4.3bsd compatibility. Only one of these three +# should be defined. If none are defined, HAVE_BSD_TTYS is assumed. +# Ordinarily, the correct define is sniffed by the "make makeconfig" +# script and automatically included. +# +# The flag KERNEL_PLL is a temporary hack to use when the phase-lock loop +# is implmented in the kernel. Do not use unless you have modified +# kernel routines (see doc/README.kern). +# +#DEFS_LOCAL= -DDEBUG -DPPSPPS -DKERNEL_PLL +DEFS_LOCAL= -DDEBUG +#DEFS_LOCAL= # for greenhorns +# +# Radio clock support definitions (these only make sense if -DREFCLOCK +# used), which is normally the case. Note that a configuration can include +# no clocks, more than one type of clock and even multiple clocks of the +# same type. +# +# For most radio clocks operating with serial ports, accuracy can +# be considerably improved through use of the tty_clk line +# discipline or tty_clk_STREAMS streams module found in the +# ./kernel directory. These gizmos capture a timestamp upon +# occurrence of an intercept character and stuff it in the data +# stream for the clock driver to munch. To select this mode, +# postfix the driver name with the string CLK; that is, WWVB +# becomes WWVBCLK. If more than one clock is in use, the CLK +# postfix can be used with any or all of them. +# +# Alternatively, for the best accuracy, use the ppsclock streams +# module in the ./ppsclock directory to steal the carrier-detect +# transition and capture a precision timestamp. At present this +# works only with SunOS 4.1.1 or later. To select this mode, +# postfix the driver name with the string PPS; that is, AS2201 +# becomes AS2201PPS. If more than one clock is in use, the PPS +# postfix should be used with only one of them. If any PPS +# postfix is defined, the -DPPSPPS define should be used on the +# DEFS above. +# +# Define -DLOCAL_CLOCK for a local pseudo-clock to masquerade as a +# reference clock for those subnets without access to the real thing. +# Works in all systems and requires no hardware support. This is defined +# by default when using the "make makeconfig" script. +# +# Define -DPST for a PST/Traconex 1020 WWV/H receiver. The driver +# supports both the CLK and PPS modes. It should work in all systems +# with a serial port. +# +# Define -DWWVB for a Spectracom 8170 or Netclock/2 WWVB receiver. It +# should work in all systems with a serial port. The driver supports +# both the CLK and PPS modes if the requisite kernel support is installed. +# +# Define -DCHU for a special CHU receiver using an ordinary shortwave +# radio. This requires the chu_clk line discipline or chu_clk_STREAMS +# module in the ./kernel directory. At present, this driver works only +# on SunOS4.1.x; operation in other systems has not been confirmed. +# Construction details for a suitable modem can be found in the ./gadget +# directory. The driver supports # neither the CLK nor PPS modes. +# +# Define -DPARSE for a DCF77/GPS(GENERIC) receiver. For best performance +# this requires a special parsestreams STREAMS (SunOS 4.x) module in the +# ./kernel directory. Define -DPARSEPPS for PPS support via the +# DCF77/GPS (GENERIC) receiver; also, define -DPPS in the DEFS above. +# Define PARSESTREAM for utilising the STREAMS module for improved +# precision (currently only SunOS4.x) +# +# Define: -DCLOCK_MEINBERG for Meinberg clocks +# -DCLOCK_SCHMID for Schmid receivers +# -DCLOCK_DCF7000 for ELV DCF7000 +# -DCLOCK_RAWDCF for simple receivers (100/200ms pulses on Rx) +# +# Define -DMX4200PPS for a Magnavox 4200 GPS receiver. At present, this +# driver works only on SunOS4.1.x with CPU serial ports only. The PPS +# mode is required. +# +# Define -DAS2201 for an Austron 2200A or 2201A GPS receiver. It should +# work in all systems with a serial port. The driver does not support the +# CLK mode, but does support the PPS mode. If the radio is connected to +# more than one machine, the PPS mode is required. +# +# Define -DGOES for a Kinemetrics/TrueTime 468-DC GOES receiver. This +# driver is known to work with some other TrueTime products as well, +# including the GPS-DC GPS receiver. It should work in all systems with +# a serial port. The driver does not support the CLK mode, but does +# support the PPS mode. +# +# Define -DOMEGA for a Kinemetrics/TrueTime OM-DC OMEGA receiver. It +# should work in all systems with a serial port. The driver does not +# support the CLK mode, but does support the PPS mode. +# +# Define -DTPRO for a KSI/Odetics TPRO-S IRIG-B timecode reader. This +# requires the SunOS interface driver available from KSI. The driver +# supports neither the CLK nor PPS modes. +# +# Define -DLEITCH for a Leitch CSD 5300 Master Clock System Driver for +# the HP 5061B Cesium Clock. It should work in all systems with a serial +# port. The driver does not support the CLK mode, but does support the +# PPS mode. +# +# Define -DMSF for a EES M201 MSF receiver. It should work in all systems +# with a serial port. The driver does not support the CLK mode, but does +# support the # PPS mode. +# +# Define -DIRIG for a IRIG-B timecode timecode using the audio codec of +# the Sun SPARCstations. This requires a modified BSD audio driver and +# exclusive access to the audio port. A memo describing how it works and +# how to install the driver is in the README.irig file in the ./doc +# directory. +# +# Note: The following defines result in compilation of all the above radio +# clocks. This works on a Sun 4.1.x system which has tty_clk, chu_clk and +# ppsclock STREAMS modules installed. If the trailing CLK and PPS suffixes +# are removed and the IRIG deleted, all of the rest compile under +# Ultrix 4.2a/3. If the MX4200 is removed, all the rest compile on a DEC +# OSF/1 Alpha. +# +#CLOCKDEFS= -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPST -DPSTCLK -DTPRO -DWWVBCLK +CLOCKDEFS= # for greenhorns +# +# Directory into which binaries should be installed +# +BINDIR= /usr/etc diff --git a/contrib/xntpd/conf/README b/contrib/xntpd/conf/README new file mode 100644 index 0000000000..19dcb795f8 --- /dev/null +++ b/contrib/xntpd/conf/README @@ -0,0 +1,8 @@ +README file for directory ./conf of the NTP Version 3 distribution + +This directory contains example run-time configuration files for the +NTP Version 3 daemon xntpd. These files illustrate some of the more +obtuse configurations you may run into. They are not likely to do +anything good if run on machines other than their native spot, so don't +just blindly copy something and put it up. Additional information can +be found in the ./doc directory of the base directory. diff --git a/contrib/xntpd/conf/dewey.conf b/contrib/xntpd/conf/dewey.conf new file mode 100644 index 0000000000..523008fcdc --- /dev/null +++ b/contrib/xntpd/conf/dewey.conf @@ -0,0 +1,38 @@ +# +# NTP configuration file (ntp.conf) +# dewey.udel.edu (128.175.1.2) +# +# Stratum-1 peers +# +#peer 128.4.1.5 # dcn5.udel.edu +#peer 128.8.10.1 # umd1.umd.edu +#peer 18.72.0.3 version 2 # bitsy.mit.edu +peer 192.43.244.9 # ncar-fuzz.nsf.net +peer 132.249.16.1 # sdsc-fuzz.nsf.net +peer 128.118.46.3 version 2 # otc1.psu.edu +#peer 130.126.174.40 # truechimer.cso.uiuc.edu +#peer 128.9.2.129 # wwvb.isi.edu +#peer 130.43.2.2 version 2 # apple.com +# +# Stratum-2 peers +# +peer 128.175.1.1 # huey.udel.edu +#peer 128.175.1.2 # dewey.udel.edu +peer 128.175.1.3 # louie.udel.edu +#peer 128.175.2.33 # louie.udel.edu +#peer 128.175.7.39 # louie.udel.edu +# +# Miscellaneous stuff +# +monitor yes # enable monitoring +precision -7 # clock reading precision (10 msec) +driftfile /etc/ntp.drift # path for drift file +# +# Authentication stuff +# +authenticate yes # enable authentication +keys /etc/ntp.keys # path for key file +trustedkey 1 2 15 # define trusted keys +requestkey 15 # key (7) for accessing server variables +controlkey 15 # key (6) for accessing server variables +authdelay 0.001501 # authentication delay (VAX 11/780) diff --git a/contrib/xntpd/conf/grundoon.conf b/contrib/xntpd/conf/grundoon.conf new file mode 100644 index 0000000000..c5aef6eb88 --- /dev/null +++ b/contrib/xntpd/conf/grundoon.conf @@ -0,0 +1,58 @@ +# +# NTP configuration file (ntp.conf) +# grundoon.udel.edu (128.4.2.7) +# +server 127.127.6.0 prefer # irig audio decoder +fudge 127.127.6.0 time1 0.0005 +#pps delay -0.0004 # pps correction for CLK streams module +server 127.127.4.1 # spectracom 8170/netclock-2 wwvb receiver +# propagation delay: wwvb 0.0088; receiver delay 0.0173 os delay .0035 +fudge 127.127.4.1 time1 0.0035 flag4 1 +server 127.127.3.1 # pst/traconex 1020 wwv/h receiver +# propagation delay: wwv 0.0088 wwvh 0.0281; receiver+os delay 0.0035 +fudge 127.127.3.1 time1 0.0123 time2 0.0316 +server 127.127.7.1 # scratchbuilt chu receiver/demodulator +# propagtion delay: chu 0.0030; receiver+os delay 0.0060 +fudge 127.127.7.1 time1 0.0030 time2 0.0060 +#server 127.127.10.1 # austron 2201 gps receiver + +server 127.127.1.2 # local clock +#server 127.127.12.2 # ksi/odetics tpr0-s irig-b reader + +#broadcast 128.4.2.255 + +peer 128.4.1.1 key 3 # rackety.udel.edu (Sun4c/40 IPC) +peer 128.4.1.4 # barnstable.udel.edu (Sun4c/65 SS1+) +#peer 128.4.1.5 # churchy.udel.edu (Bancomm bc700LAN) +#peer 128.4.2.7 key 3 # grundoon.udel.edu (Sun4c/40 IPC) +peer 128.4.1.8 # bridgeport.udel.edu (Sun4c/40 IPC) +peer 128.4.1.20 key 3 # pogo.udel.edu (Sun4c/65 SS1+) +peer 128.4.1.22 # malarky.udel.edu (Sun4c/50 IPX) +peer 128.4.1.23 # beauregard.udel.edu (Sun4/40 IPC) +peer 128.4.1.24 # baldwin.udel.edu (Sun4/40 IPC) +peer 128.4.1.25 # albert.udel.edu (Sun4c/60 SS1) +peer 128.4.1.27 # bunnylou.udel.edu (Sun4c/40 IPC) +peer 128.4.1.28 # cowbird.udel.edu (DEC 5000/240) +peer 128.4.1.29 # porkypine.udel.edu (DEC 5000/240) +# +# Miscellaneous stuff +# +monitor yes # enable monitoring +precision -18 # clock reading precision (usec) +driftfile /etc/ntp.drift # path for drift file +statsdir /grundoon/ntpstats/ # directory for statistics files +filegen peerstats file peerstats type day enable +filegen loopstats file loopstats type day enable +filegen clockstats file clockstats type day enable + +# +# Authentication stuff +# +authenticate yes # enable authentication +keys /usr/local/ntp.keys # path for keys file +trustedkey 1 2 3 4 14 15 # define trusted keys +requestkey 15 # key (7) for accessing server variables +controlkey 15 # key (6) for accessing server variables +#authdelay 0.000073 # authentication delay (SPARC4c/40 IPC DES) +authdelay 0.000163 # authentication delay (SPARC4c/40 IPC MD5) + diff --git a/contrib/xntpd/conf/malarky.conf b/contrib/xntpd/conf/malarky.conf new file mode 100644 index 0000000000..f887f839d1 --- /dev/null +++ b/contrib/xntpd/conf/malarky.conf @@ -0,0 +1,40 @@ +# +# NTP configuration file (ntp.conf) +# malarky.udel.edu (128.4.1.22) +# +peer 128.4.1.1 # rackety.udel.edu +peer 128.4.1.4 # barnstable.udel.edu +#peer 128.4.1.5 #churchy.udel.edu +peer 128.4.2.7 # grundoon.udel.edu +peer 128.4.1.8 # bridgeport.udel.edu +peer 128.4.1.20 prefer # pogo.udel.edu +#peer 128.4.1.22 # malarky.udel.edu +peer 128.4.1.23 # beauregard.udel.edu +peer 128.4.1.24 # baldwin.udel.edu +peer 128.4.1.25 # albert.udel.edu +peer 128.4.1.27 # bunnylou.udel.edu +peer 128.4.1.28 # cowbird.udel.edu +peer 128.4.1.29 # porkypine.udel.edu + +# +# Miscellaneous stuff +# +monitor yes # enable monitoring +precision -18 # clock reading precision (usec) +driftfile /etc/ntp.drift # path for drift file +statsdir /malarky/ntpstats/ # directory for statistics files +filegen peerstats file peerstats type day enable +filegen loopstats file loopstats type day enable +filegen clockstats file clockstats type day enable + +# +# Authentication stuff +# +authenticate yes # enable authentication +keys /usr/local/bin/ntp.keys # path for key file +trustedkey 1 2 3 4 14 15 # define trusted keys +requestkey 15 # key (7) for accessing server variables +controlkey 15 # key (6) for accessing server variables +#authdelay 0.000047 # authentication delay (Sun4c/50 IPX DES) +authdelay 0.000094 # authentication delay (Sun4c/50 IPX MD5) + diff --git a/contrib/xntpd/conf/ntp.conf.gw b/contrib/xntpd/conf/ntp.conf.gw new file mode 100644 index 0000000000..bd5687874f --- /dev/null +++ b/contrib/xntpd/conf/ntp.conf.gw @@ -0,0 +1,34 @@ +# +# peers for gw.ccie.utoronto.ca (128.100.63.2, 128.100.49.104, 128.100.224.224) +# +peer 128.4.0.1 key 1 # dcn1.udel.edu +peer 128.8.10.1 key 2 # umd1.umd.edu +peer 128.116.64.3 key 3 # ncarfuzz.ucar.edu +peer 128.9.2.129 key 4 # wwvb.isi.edu +#peer 128.4.0.6 key 1 # dcn6.udel.edu +# +# Don't configure associations with the other secondaries. This is +# the only one in a machine room and will hold itself pretty stable +# when all else fails +# +monitor yes # keep track of traffic + +# +# drift file +# +driftfile /etc/ntp.drift + +# +# authentication stuff. We're running authenticated, tell it +# where the keys are and which to trust. +# +authenticate yes +authdelay 0.000323 # seconds, about right for an RT model 125 +trustedkey 1 2 3 4 21 22 23 24 +keys /etc/ntp.keys + +# +# allow run time reconfiguration using key 65535 +# +requestkey 65535 +controlkey 65535 diff --git a/contrib/xntpd/conf/ntp.conf.ipl b/contrib/xntpd/conf/ntp.conf.ipl new file mode 100644 index 0000000000..1fd5b7d621 --- /dev/null +++ b/contrib/xntpd/conf/ntp.conf.ipl @@ -0,0 +1,32 @@ +# +# peers for ipl.utcs.utoronto.ca (128.100.102.7) +# +peer 128.4.0.5 key 1 # dcn5.udel.edu +peer 128.8.10.1 key 2 # umd1.umd.edu +peer 192.12.207.1 key 3 # fuzz.sdsc.edu +peer 128.9.2.129 key 4 # wwvb.isi.edu +peer 128.100.63.2 key 21 # gw.ccie +peer 128.100.49.105 key 22 # suzuki.ccie +peer 128.100.102.4 key 23 # shiningtree.utcs +# +monitor yes # keep track of traffic + +# +# drift file +# +driftfile /etc/ntp.drift + +# +# authentication stuff. We're running authenticated, tell it +# where the keys are and which to trust. +# +authenticate yes +authdelay 0.000323 # seconds, about right for an RT model 125 +trustedkey 1 2 3 4 21 22 23 +keys /etc/ntp.keys + +# +# allow run time reconfiguration using key 65535 +# +requestkey 65535 +controlkey 65535 diff --git a/contrib/xntpd/conf/ntp.conf.nsf b/contrib/xntpd/conf/ntp.conf.nsf new file mode 100644 index 0000000000..298bb7a690 --- /dev/null +++ b/contrib/xntpd/conf/ntp.conf.nsf @@ -0,0 +1,156 @@ +# +# Maybe an alternate xntpd configuration for NSS#17 +# + +# +# precision is supported, but you don't really need it. The code +# will determine a precision from the kernel's value of _hz which +# is fine. Note you shouldn't claim too good a precision on a +# Unix machine even if the clock carries a lot of bits, since +# precision also depends on things like I/O delays and scheduling +# latencies, which Unix machines control poorly. If you claim better +# than -6 or -7 it will make the anti-hop aperture tighter than is +# reasonable for a Unix machine. +# +#precision -7 + +# +# peers are ncarfuzz.ucar.edu umd1.umd.edu dcn5.udel.edu fuzz.sdsc.edu +# syntax is peer addr [ key 1-15 ] [ version 1_or_2 ] +# + +peer 128.116.64.3 # ncarfuzz.ucar.edu +peer 128.8.10.1 # umd1.umd.edu +peer 128.4.0.5 # dcn5.udel.edu +peer 192.12.207.1 # fuzz.sdsc.edu + +# +# Drift file. Put this in a directory which the daemon can write to. +# No symbolic links allowed, either, since the daemon updates the file +# by creating a temporary in the same directory and then rename()'ing +# it to the file. +# +# This is a nice feature. Once you've got the drift computed it hardly +# ever takes more than an hour or so to resync after a restart. +# +driftfile /etc/ntp.drift + +# +# The server statement causes polling to be done in client mode rather +# than symmetric active. It is an alternative to the peer command +# above. Which you use depends on what you want to achieve. Usually +# it doesn't matter. Syntax is: +# +#server 128.100.49.1 key 4 version 1 + +# +# The broadcast statement tells it to start broadcasting time out one +# of its interfaces. Syntax is +# +#broadcast 128.100.49.255 # [ key n ] [ version n ] + +# +# broadcastclient tells the daemon whether it should attempt to sync +# to broadcasts or not. Defaults to `no'. +# +#broadcastclient yes # or no + +# +# broadcastdelay configures in a default round-trip delay to use for +# broadcast time. It may poll to improve this estimate. +# +#broadcastdelay 0.0095 # in seconds + +# +# authenticate configures us into strict authentication mode (or not). +# +#authenticate yes # or no. Default is no + +# +# authdelay is the time it takes to do an NTP encryption on this host. +# The current routine is pretty fast. +# +#authdelay 0.000340 # in seconds + +# +# trustedkey are used when authenticate is on. We only trust (and sync to) +# peers who know these keys. +# +#trustedkey 1 3 4 8 + +# +# monitor turns on the monitoring facility. See xntpdc's monlist command. +# This shows a lot of neat stuff, but I'm not fussy about the implementation. +# Uses up to 20Kb of memory at run time. You could try this. +# +#monitor yes # or no. Default is no + +# +# keys points at the file which holds the authentication keys. +# +#keys /etc/ntp.keys + +# +# requestkey indicates which key is to be used for validating +# runtime reconfiguration requests. If this isn't defined, or the +# key isn't in the keys file, you can't do runtime reconfiguration. +# controlkey indicates which key is to be used for validating +# mode 6 write variables commands. If this isn't defined you can't +# do it. The only thing the latter is used for is to set leap second +# warnings on machines with radio clocks. +# +#requestkey 65535 +#controlkey 65534 + +# +# restrict places restrictions on the punters. This is implemented as +# a sorted address-and-mask list, with each entry including a set of +# flags which define what a host matching the entry *can't* do (the sort +# also saves CPU time searching the table since it needn't be searched +# to the end). The last match in the table defines what the host does. +# The default entry, which everyone matches, is first, most specific +# matches are later in the table. The flags are: +# +# ignore - ignore all traffic from host +# noserve - don't give host any time (but let him make queries?) +# notrust - give host time, let him make queries, but don't sync to him +# noquery - host can have time, but not make queries +# nomodify - allow the host to make queries except those which are +# actually run-time configuration commands. +# notrap - don't allow matching hosts to set traps. If noquery is +# set this isn't needed +# lowpriotrap - if this guy sets a trap make it easy to delete +# ntpport - a different kind of flag. Makes matches for this entry +# possible only if the source port is 123. +# +# To understand this better, take a look at xntpdc's reslist command when the +# server is running. This usually prints in the sorted order. +# +# This should match the NSS 17 stuff. Default mask is all ones. + +restrict default ignore # ignore almost everyone + +# +# These guys can be served time and make non-modifying queries +# +restrict 129.140.0.0 mask 255.255.0.0 notrust nomodify +restrict 35.1.1.42 notrust nomodify + +# +# Rest of 35.1.1 gets to look but not touch +# +restrict 35.1.1.0 mask 255.255.255.0 noserve nomodify + +# +# modifications can be made from local NSS only +# +restrict 129.140.17.0 mask 255.255.255.0 notrust +restrict 127.0.0.1 notrust + +# +# take time from the following peers, but don't let them peek or modify +# +restrict 128.116.64.3 noquery +restrict 128.8.10.1 noquery +restrict 128.4.0.5 noquery +restrict 192.12.207.1 noquery diff --git a/contrib/xntpd/conf/ntp.conf.shiningtree b/contrib/xntpd/conf/ntp.conf.shiningtree new file mode 100644 index 0000000000..1576ebbd07 --- /dev/null +++ b/contrib/xntpd/conf/ntp.conf.shiningtree @@ -0,0 +1,32 @@ +# +# peers for shiningtree.utcs.utoronto.ca (128.100.102.4) +# +peer 128.4.0.1 key 1 # dcn1.udel.edu +peer 130.126.174.40 key 2 # truechimer.cso.uiuc.edu +peer 192.12.207.1 key 3 # fuzz.sdsc.edu +peer 128.116.64.3 key 4 # ncarfuzz.ucar.edu +peer 128.100.63.2 key 21 # gw.ccie +peer 128.100.49.105 key 22 # suzuki.ccie +peer 128.100.102.7 key 23 # ipl.utcs +# +monitor yes # keep track of traffic + +# +# drift file +# +driftfile /etc/ntp.drift + +# +# authentication stuff. We're running authenticated, tell it +# where the keys are and which to trust. +# +authenticate yes +authdelay 0.000323 # seconds, about right for an RT model 125 +trustedkey 1 2 3 4 21 22 23 +keys /etc/ntp.keys + +# +# allow run time reconfiguration using key 65535 +# +requestkey 65535 +controlkey 65535 diff --git a/contrib/xntpd/conf/ntp.conf.suzuki b/contrib/xntpd/conf/ntp.conf.suzuki new file mode 100644 index 0000000000..ee32e7ad87 --- /dev/null +++ b/contrib/xntpd/conf/ntp.conf.suzuki @@ -0,0 +1,43 @@ +# +# peers for suzuki.ccie.utoronto.ca (128.100.49.105, 128.100.224.225) +# + +# +# the reference clock, /dev/chu1 +# +server 127.127.7.1 key 4 +# Propagation delay 2.5 ms, sloppy clock flag on +fudge 127.127.7.1 time1 0.0025 flag1 1 + +peer 128.4.0.5 key 1 # dcn5.udel.edu +peer 128.8.10.1 key 2 # umd1.umd.edu +peer 128.116.64.34 key 3 # ncarfuzz.ucar.edu +peer 130.126.174.40 key 4 # truechimer.cso.uiuc.edu +peer 128.100.49.104 key 24 # gw.ccie +peer 128.100.102.4 key 22 # shiningtree.utcs +peer 128.100.102.7 key 22 # ipl.utcs + +peer 128.4.0.6 key 1 # dcn6.udel.edu + +# +monitor yes # keep track of traffic + +# +# drift file +# +driftfile /etc/ntp.drift + +# +# authentication stuff. We're running authenticated, tell it +# where the keys are and which to trust. +# +authenticate yes +authdelay 0.000323 # seconds, about right for an RT model 125 +trustedkey 1 2 3 4 21 22 23 24 +keys /etc/ntp.keys + +# +# allow run time reconfiguration using key 65535 +# +requestkey 65535 +controlkey 65535 diff --git a/contrib/xntpd/conf/pogo.conf b/contrib/xntpd/conf/pogo.conf new file mode 100644 index 0000000000..94ac6c84ea --- /dev/null +++ b/contrib/xntpd/conf/pogo.conf @@ -0,0 +1,50 @@ +# +# NTP configuration file (ntp.conf) +# pogo.udel.edu (128.4.1.20) +# +server 127.127.10.1 prefer # austron 2201 gps receiver +#server 127.127.4.1 # spectracom 8170/netclock-2 wwvb receiver +# propagation delay: wwvb 0.0088; receiver delay 0.0017 +#fudge 127.127.4.1 time1 0.0017 + +peer 128.4.1.1 key 3 # rackety.udel.edu (Sun4c/40 IPC) +peer 128.4.1.2 # mizbeaver.udel.edu +peer 128.4.1.4 # barnstable.udel.edu (Sun4c/65 SS1+) +#peer 128.4.1.5 # churchy.udel.edu (Bancomm bc700LAN) +peer 128.4.2.7 key 3 # grundoon.udel.edu (Sun4c/40 IPC) +peer 128.4.1.5 maxpoll 8 # churchy.udel.edu (cisco IGS router) +#peer 128.4.1.8 # bridgeport.udel.edu (Sun4c/40 IPC) +#peer 128.4.1.20 key 3 # pogo.udel.edu (Sun4c/65 SS1+) +#peer 128.4.1.22 # malarky.udel.edu (Sun4c/50 IPX) +#peer 128.4.1.23 # beauregard.udel.edu (Sun4/40 IPC) +peer 128.4.1.24 # baldwin.udel.edu (Sun4/40 IPC) +#peer 128.4.1.25 # albert.udel.edu (Sun4c/60 SS1) +#peer 128.4.1.27 # maccarony.udel.edu (Sun4c/40 IPC) +peer 128.4.1.29 # porkypine.udel.edu +peer 132.163.135.130 maxpoll 8 # time_A.timefreq.bldrdoc.gov (ACTS) +peer 131.188.1.40 maxpoll 8 # ntps1-0.uni-erlangen.de (DCF77) +peer 129.132.2.21 maxpoll 8 # swisstime.ethz.ch (DCF77) +peer 130.155.98.13 maxpoll 8 # terss.ml.csiro.au (OMEGA) + +# +# Miscellaneous stuff +# +monitor yes # enable monitoring +precision -18 # clock reading precision (usec) +driftfile /etc/ntp.drift # path for drift file +statsdir /pogo/ntpstats/ # directory for statistics files +filegen peerstats file peerstats type day enable +filegen loopstats file loopstats type day enable +filegen clockstats file clockstats type day enable + +# +# Authentication stuff +# +authenticate yes # enable authentication +keys /usr/local/bin/ntp.keys # path for keys file +trustedkey 1 2 3 4 14 15 # define trusted keys +requestkey 15 # key (7) for accessing server variables +controlkey 15 # key (6) for accessing server variables +#authdelay 0.000072 # authentication delay (SPARC4c/65 SS1+ DES) +authdelay 0.000159 # authentication delay (SPARC4c/65 SS1+ MD5) + diff --git a/contrib/xntpd/conf/rackety.conf b/contrib/xntpd/conf/rackety.conf new file mode 100644 index 0000000000..1a5181cd4b --- /dev/null +++ b/contrib/xntpd/conf/rackety.conf @@ -0,0 +1,75 @@ +# +# NTP configuration file (ntp.conf) +# rackety (128.4.1.1) +# +server 127.127.10.1 prefer # austron 2201 gps receiver +fudge 127.127.10.1 flag4 1 # enable statistics +server 127.127.4.1 # spectracom 8170/netclock-2 wwvb receiver +#propagation delay: wwvb 0.0088; receiver delay 0.0017 +fudge 127.127.4.1 time1 0.0017 value1 2 + +# +# ee vaxen +# +peer 128.175.1.1 # huey.udel.edu +peer 128.175.1.2 # louie.udel.edu +peer 128.175.1.3 # dewey.udel.edu + +# +# munchkins (stratum-1 only) +# +peer 128.4.1.2 # mizbeaver.udel.edu +#peer 128.4.1.5 # churchy.udel.edu +peer 128.4.2.7 key 3 # grundoon.udel.edu +peer 128.4.1.20 key 3 # pogo.udel.edu + +# +# dartnet +# +peer 140.173.112.2 # ames.dart.net +peer 140.173.128.1 # la.dart.net +peer 140.173.64.1 # dc.dart.net +peer 140.173.144.2 # parc.dart.net +peer 140.173.80.1 # sri.dart.net +peer 140.173.96.1 # lbl.dart.net +peer 140.173.128.2 # isi.dart.net +peer 140.173.16.1 # udel.dart.net +peer 140.173.32.1 # bbn.dart.net +peer 140.173.48.2 # mit.dart.net + +# +# nsfnet t3 backbone +# +server 140.222.134.1 version 2 # enss134 (cambridge - mit) +server 140.222.135.1 version 2 # enss135 (san diego - sdsc) +peer 140.222.136.1 version 2 # enss136 (college park - sura) +server 140.222.141.1 version 2 # enss141 (boulder - ncar) +server 140.222.144.1 version 2 # enss144 (sunnyvale - nasa ames) + +# +# famous players +# +#peer 132.163.135.130 # time_A.timefreq.bldrdoc.gov + +# +# Miscellaneous stuff +# +monitor yes # enable monitoring +precision -18 # clock reading precision (usec) +driftfile /etc/ntp.drift # path for drift file +statsdir /rackety/ntpstats/ # directory for statistics files +filegen peerstats file peerstats type day enable +filegen loopstats file loopstats type day enable +filegen clockstats file clockstats type day enable + +# +# Authentication stuff +# +authenticate yes # enable authentication +keys /usr/local/bin/ntp.keys # path for keys file +trustedkey 1 2 3 4 14 15 # define trusted keys +requestkey 15 # key (7) for accessing server variables +controlkey 15 # key (6) for accessing server variables +#authdelay 0.000073 # authentication delay (SPARC4c/40 IPC DES) +authdelay 0.000163 # authentication delay (SPARC4c/40 IPC MD5) + diff --git a/contrib/xntpd/conf/snow-white.conf b/contrib/xntpd/conf/snow-white.conf new file mode 100644 index 0000000000..a86cb4bc5b --- /dev/null +++ b/contrib/xntpd/conf/snow-white.conf @@ -0,0 +1,33 @@ +# +# NTP configuration file (ntp.conf) +# snow-white.udel.edu (128.175.2.15) +# +# Stratum-2 peers +# +peer 128.175.1.1 # huey.udel.edu +peer 128.175.1.2 # dewey.udel.edu +#peer 128.175.1.3 # louie.udel.edu +peer 128.175.2.33 # louie.udel.edu +#peer 128.175.7.39 # louie.udel.edu +# +# Stratum-3 peers +# +peer 128.175.7.4 # sol.cis.udel.edu +peer 128.175.7.18 # ra.cis.udel.edu +#peer 128.175.2.15 # snow-white.ee.udel.edu +peer 128.175.2.21 # opus.ee.udel.edu +# +# Miscellaneous stuff +# +monitor yes # enable monitoring +precision -18 # clock reading precision (1 usec) +driftfile /etc/ntp.drift # path for drift file +# +# Authentication stuff +# +authenticate yes # enable authentication +keys /etc/ntp.keys # path for key file +trustedkey 1 2 15 # define trusted keys +requestkey 15 # key (7) for accessing server variables +controlkey 15 # key (6) for accessing server variables +authdelay 0.000077 # authentication delay (SPARC IPC) diff --git a/contrib/xntpd/doc/README.irig b/contrib/xntpd/doc/README.irig new file mode 100644 index 0000000000..f293f4cde1 --- /dev/null +++ b/contrib/xntpd/doc/README.irig @@ -0,0 +1,306 @@ + Audio IRIG Receiver for Precision Timekeeping + + Revised 20 September 1993 + +Note: This information file is included in both the BSD audio driver +distribution (bsd_audio.tar.Z) and NTP Version 3 distribution +(xntp3.tar.Z) as the file README.irig. Both distributions can be +obtained via anonymous ftp from louie.udel.edu in the directory pub/ntp. + +1. Introduction + +This software distribution includes modifications to the BSD audio +driver for the Sun SPARCstation written by Van Jacobson and +collaborators at Lawrence Berkeley National Laboratory. The +modifications provide for the connection of a standard Inter-Range +Instrumentation Group (IRIG) timecode signal generator and the decoding +of the signal to produce data sufficient to synchronize a host clock to +the IRIG signal. There are several timing receivers now on the market +that can produce IRIG signals, including those made by Austron, +TrueTime, Odetics and Spectracom, among others. These data can be used +to precisely synchronize the host computer clock to within a few +microseconds without requiring level converters or pulse generators +necessary with the one-pulse-per-second signals also produced by these +receivers. The current implementation of the Network Time Protocol +Version 3 supports the modified BSD driver when installed in the SunOS +4.1.x kernel. + +The specific IRIG signal format supported by the driver is designated +IRIG-B. It consists of an amplitude-modulated 1000-Hz sinewave, where +each symbol is encoded as ten full carrier cycles, or 10 ms in duration. +The symbols are distinguished using a pulse-width code, where 2 ms +corresponds to logic zero, 5 ms to logic one and 8 ms to a position +identifier used for symbol synchronization. The complete IRIG-B message +consists of a frame of ten fields, each field consisting of a nine +information symbols followed by a position identifier for a total frame +duration of one second. The first symbol in the frame is also a position +identifier to facilitate frame synchronization. + +The IRIG-B signal encodes the day of year and time of day in binary- +coded decimal (BCD) format, together with a set of control functions, +which are not used by the driver, but included in the raw binary +timecode. Either the BCD timecode or the combined raw timecode and BCD +timecode can be returned in response to a read() system call. The BCD +timecode is in handy ASCII format: "ddd hh:mm:ss*" for convenience in +client programs. In this format the "*" status character is " " when the +driver is operating normally and "?" when errors may be present (see +below). In order to reduce residual errors to the greatest extent +possible, the driver computes a timestamp based on the value of the +kernel clock at the on-time epoch of the IRIG-B signal. In addition, the +driver automatically adjusts for slowly varying amplitude levels of the +IRIG-B signal and suppresses noise transients. + +In operation the IRIG driver interprets the IRIG-B signal in real time, +synchronizes to the signal, demodulates the data bits and prepares the +data to be read later. At the on-time epoch a timestamp is captured from +the kernel clock and adjusted for the phase of the IRIG carrier signal +relative to the 8-kHz codec sample clock. When a client program issues a +read() request, the most recent timecode data, including a status byte +and the corrected timestamp, are stored in a structure and returned to +the caller. Depending on the frequency with which the driver is called, +this may result in old data or duplicate data or even invalid data, +should the driver be called before it has computed its first timestamp. + +In practice, the resulting ambiguity causes few problems. The caller +converts the ASCII timecode returned by a read() system call to Unix +timeval format and subtracts it from the kernel timestamp provided by +the driver. The result is an adjustment that can be subtracted from the +kernel time, as returned in a gettimeofday() call, for example, to +correct for the deviation between IRIG time and kernel time. The result +can always be relied on to within plus/minus 128 microseconds, the audio +codec sampling interval, and ordinarily to within a few microseconds, as +determined by the interpolation algorithm. + +2. Programming Interface + +The IRIG driver modifications are integrated in the BSD audio driver +bsd_audio.c without affecting its usual functions in transmitting and +receiving ordinary speech, except when enabled by specific ioctl() +system calls. However, the driver cannot be used for both speech and +IRIG signals at the same time. Once activated by a designated ioctl() +call, the driver remains active until it is explicitly deactivated by +another ioctl() call. This allows applications to configure the audio +device and pass the pre-configured driver to other applications. Since +the driver is currently only a receiver, it does not affect the +operation of the BSD audio output driver. + +Data are read using the standard read() system call. Since the output +formats have constant lengths, the application receives the data into a +fixed-length buffer or structure. The read() call never blocks; it +simply returns the most recent IRIG data received during the last +second. It may happen that, due to unavoidable race conditions in the +kernel, data for other than the most recent second are returned. The +driver's internal data structure is updated as an atomic unit; thus, the +entire structure is valid, even if it contains old data. This should +cause no problems, since in the intended application the driver is +called at regular intervals by a time-synchronization daemon such as +NTP. The daemon can determine the validity of the time indication by +checking the timecode or status byte returned with the data. + +The header file bsd_audioirig.h defines the irig_time structure and +ioctl() codes used by the driver. Following are those codes specific to +the IRIG function of the driver. Unless indicated otherwise, the (third) +argument of the ioctl() system call points to an integer or string. + +AUDIO_IRIG_OPEN + + This command activates the IRIG receiver. The audio driver must be + opened with this command before other commands can be issued. The + argument is ignored. When the IRIG receiver is initialized, all + internal data are purged and any buffered data are lost. + +AUDIO_IRIG_CLOSE + + This command deactivates the IRIG receiver. The argument is + ignored. The buffers are purged and any buffered time data are + lost. The original BSD audio driver functions are enabled and it + resumes operating normally. + +AUDIO_IRIG_SETFORMAT + + The argument is a pointer to an integer designating the output + format for the IRIG data. There are currently two formats defined, + 0 (default) and 1. If an invalid format is selected, the default + format is used. + +The data returned by a read() system call in format 0 is a character +string in the format "ddd hh:mm:ss*\n", which consists of 13 ASCII +characters followed by a newline terminator for a total of 14 +characters. The "*" status character is an ASCII space " " if the status +byte determined by the driver is zero and "?" if not. This format is +intended to be used with simple user programs that care only about the +time to the nearest second. +The data returned by a read() system call in format 1 is a structure +defined in the bsd_audioirig.h header file: + + struct irig_time { + struct timeval stamp; /* timestamp */ + u_char bits[13]; /* 100 irig data bits */ + u_char status; /* status byte */ + char time[14]; /* time string */ + }; + +The irig-time.stamp is a pair of 32-bit longwords in Unix timeval +format, as defined in the sys/time.h header file. The first word is the +number of seconds since 1 January 1970, while the second is the number +of microseconds in the current second. The timestamp is captured at the +most recent on-time instant of the IRIG timecode and applies to all +other values returned in the irig_time structure. + +The irig_time.bits[13] is a vector of 13 bytes to hold the 100-bit, +zero-padded raw binary timecode, packed 8 symbols per byte. The symbol +encoding maps IRIG one to 1 and both IRIG zero and IRIG position +identifier to 0. The order of encoding is illustrated by the following +diagram (the padding bits are represented by xxxx, which are set to +zero): + +IRIG symbol number 00000000001111111111 . . . 8888889999999999xxxx + 01234567890123456789 . . . 4567890123456789xxxx + ----------------------------------------------- +bits byte number <--00--><--01--><---- ----><--11--><--12--> +bits bit in byte 01234567012345670123 . . . 45670123456701234567 + +The irig_time.status is a single byte with bits defined in the +bsd_audioirig.h header file. In ordinary operation all bits of the +status byte are zero and the " " status character is set in the ASCII +timecode. If any of these bits are nonzero, the "?" status character is +set in the ASCII timecode. + +AUDIO_IRIG_BADSIGNAL + + The signal amplitude is outside tolerance limits, either in + amplitude or modulation depth. The indicated time may or may not be + in error. If the signal is too high, it may be clipped by the + codec, so that the pulse width cannot be reliably determined. If + too low, it may be obscured by noise. The nominal expectation is + that the peak amplitude of the signal be maintained by the codec + AGC at about 10 dB below the clipping level and that the modulation + index be at least 0.5 (6 dB). + +AUDIO_IRIG_BADDATA + + An invalid hex code (A through F) has been found where BCD data is + expected. The ASCII representation of the invalid code is set to + "?". Errors of this type are most likely due to noise on the IRIG + signal due to ground loops, coupling to other noise sources, etc. + +AUDIO_IRIG_BADSYNC + + A code element has been found where a position identifier should be + or a position identifier has been found where a code element should + be. The time is meaningless and should be disregarded. Errors of + this type can be due to severe noise on the IRIG signal due to + ground loops, coupling to other noise sources, etc., or during + initial acquisition of the signal. + +AUDIO_IRIG_BADCLOCK + + Some IRIG timecode generators can indicate whether or not the + generator is operating correctly or synchronized to its source of + standard time using a designated field in the raw binary timecode. + Where such information is available and the IRIG decoder can detect + it, this bit is set when the generator reports anything except + normal operating conditions. + +AUDIO_IRIG_OLDDATA + + The IRIG time has not changed since the last time it was returned + in a read() call. This is not normally considered an error, unless + it persists for longer than a few seconds, in which case it + probably indicates a hardware problem. + +The irig_time.time[14] vector is a character string in the format "ddd +hh:mm:ss*\0", which consists of 13 ASCII characters followed by a zero +terminator. The "*" status character is an ASCII space " " if the status +byte is zero and "?" if not. This format is identical to format 0, +except that in format 1 the time string is null-terminated. + +2.1. Programming Example + +The following pseudo-code demonstrates how the IRIG receiver may be used +by a simple user program. Of course, real code should include error +checking after each call to ensure the driver is communicating properly. +It should also verify that the correct fields in the structure are being +filled by the read() call. + + include "bsd_audioirig.h" + + int format = 1; + struct irig_time it; + + Audio_fd = open("/dev/audio", O_RDONLY); + ioctl(Audio_fd, AUDIO_IRIG_OPEN, NULL); + ioctl(Audio_fd, AUDIO_IRIG_SETFORMAT,&format); + while (condition) + read(Audio_fd, &it, sizeof(it); + printf("%s\n", it.time); + ioctl(Audio_fd, AUDIO_IRIG_CLOSE, NULL); + close(Audio_fd); + +3. Implementation and Configuration Notes + +The signal level produced by most IRIG-equipped radios is on the order +of a few volts peak-peak, which is far larger than the audio codec can +accept; therefore, an attenuator in the form of a voltage divider is +needed. The codec can handle IRIG signals at the microphone input from +4.2mV to 230mV peak-peak. A suitable attenuator conists of a series- +connected 100K-Ohm resistor at the input and a parallel-connected 1K-Ohm +resistor at the output, both contained along with suitable connectors in +a small aluminum box. The exact values of these resistors are not +critical, since the IRIG driver includes an automatic level-adjustment +capability. + +For the most accurate time using the IRIG signal and a particular radio, +it may be necessary to adjust the time1 parameter of the fudge command +to compensate for the codec delay and any additional delay due to IRIG +processing in the radio itself. Since the codec samples at an 8-kHz +rate, the average delay is about 62 usec; however, the delays due to the +radios and IRIG signals themselves can vary. For instance, in the +Austron recievers the IRIG delay is essentially zero, while in the +Spectracom receivers the delay is about 240 usec relative to the 1-pps +signal. In addition, the poll interval can be reduced from the usual 64 +seconds to 16 seconds to reduce wander of the local hardware clock. +Finally, the prefer parameter can be used to bias the clock-selection +algorithm to favor the IRIG time, which is ordinarily the best time +available. For example, the following two lines in the NTP configuration +file ntp.conf are appropriate for the Spectracom Netclock/1 WWVB +Synchronized Clock with IRIG Option: + +server 127.127.6.0 prefer minpoll 4 maxpoll 4 # irig audio decoder +fudge 127.127.6.0 time1 0.0005 + +The time1 value of .0005 s (500 usec) was determined by actual +measurement. Since the IRIG delay in Austron receivers is essentially +zero, the fudge command is not necessary with these receivers. The +correct value in case of other radios may have to be determined by +actual measurement. A convenient way of doing this is to configure the +PPSPPS feature in the NTP Version 3 distribution and adjust time1 until +the 1-pps signal and IRIG signal both show the same offset. + +The modified BSD driver includes both the modified driver itself +bsd_audio.c and the IRIG header file bsd_audioirig.h, as well as +modified header files bsd_audiovar.h and bsd_audioio.h. The driver is +installed in the same way as described in the BSD driver documentation, +with the addition of the following define in the kernel configuration +file: + +options AUDIO_IRIG # IRIG driver + +This causes the IRIG code to be included in the BSD driver, as well as a +C-coded codec interrupt routine which replaces the assembly-coded +routine and provides the IRIG functionality. While the C-coded routine +is somewhat slower than the assembly-coded routine, the extra overhead +is not expected to be significant. Note that the IRIG driver calls the +kernel routine microtime() as included in the ppsclock directory of the +NTP Version 3 distribution xntp3. It is highly recommended that this +routine be installed in the kernel configuration as well. The +instructions for doing this are contained in the ppsclock directory of +the xntp3 distribution. + +Roy LeCates and David Mills +Electrical Engineering Department +University of Delaware +Newark, DE 19716 +302 831 8247 fax 302 831 4316 + +24 August 1993 diff --git a/contrib/xntpd/doc/README.kern b/contrib/xntpd/doc/README.kern new file mode 100644 index 0000000000..1b791c325c --- /dev/null +++ b/contrib/xntpd/doc/README.kern @@ -0,0 +1,775 @@ + Unix Kernel Modifications for Precision Timekeeping + + Revised 3 December 1993 + +Note: This information file is included in the distributions for the +SunOS, Ultrix and OSF/1 kernels and in the NTP Version 3 distribution +(xntp3.tar.Z) as the file README.kern. Availability of the kernel +distributions, which involve licensed code, will be announced +separately. The NTP Version 3 distribution can be obtained via anonymous +ftp from louie.udel.edu in the directory pub/ntp. In order to utilize +all features of this distribution, the NTP version number should be 3.3 +or later. + +1. Introduction + +This memo describes modifications to certain SunOS, Ultrix and OSF/1 +kernel software that manage the system clock and timer functions. They +provide improved accuracy and stability through the use of a disciplined +clock interface for use with the Network Time Protocol (NTP) or similar +time-synchronization protocol. In addition, for the DEC 3000 AXP (Alpha) +and DECstation 5000/240 machines, the modifications provide improved +precision within one microsecond (us) (SunOS 4.1.x already does provide +precision to this order). The NTP Version 3 daemon xntpd operates with +these kernel modifications to provide synchronization in principle to +within this order, but in practice this is limited by the short-term +stability of the timer oscillator to within the order of 100 usec. + +This memo describes the principles behind the design and operation of +the new software. There are three versions: one that operates with the +SunOS 4.1.x kernels, a second that operates with the Ultrix 4.x kernels +and a third that operates with the OSF/1 V1.x kernels. A detailed +description of the variables and algorithms is given in the hope that +similar functionality can be incorporated in Unix kernels for other +machines. The algorithms involve only minor changes to the system clock +and interval timer routines and include interfaces for application +programs to learn the system clock status and certain statistics of the +time-synchronization process. Detailed installation instructions are +given in a companion README.install file included in the kernel +distributions. The kernel software itself is not provided for public +distribution, since it involves licensed code. Detailed instructions on +how to obtain it for either SunOS, Ultrix or OSF/1 will be given +separately. + +The principal feature added to the Unix kernels is to change the way the +system clock is controlled, in order to provide precision time and +frequency adjustments. Another feature utilizes an undocumented bus- +cycle counter in the DEC 3000 AXP and DECstation 5000/240 to provide +precise time to the microsecond. This feature can in principle be used +with any DEC machine that has this counter, although this has not been +verified. The addition of these features does not affect the operation +of existing Unix system calls such as gettimeofday(), settimeofday() and +adjtime(); however, if the new features are in use, the operations of +adjtime() are controlled instead by a new system call ntp_adjtime(). + +Most Unix programs read the system clock using the gettimeofday() system +call, which returns only the system time and timezone data. For some +applications it is useful to know the maximum error of the reported time +due to all causes, including clock reading errors, oscillator frequency +errors and accumulated latencies on the path to a primary reference +source. However, the new software can adjust the system clock to +compensate for its intrinsic frequency error, so that the timing errors +expected in normal operation will usually be much less than the maximum +error. The user application interface includes a new system call +ntp_gettime(), which returns the system time, as well as the maximum +error and estimated error. This interface is intended to support +applications that need such things, including distributed file systems, +multimedia teleconferencing and other real-time applications. The +protocol daemon application interface includes a new system call +ntp_adjtime(), which can be used to read and write kernel variables used +for precision timekeeping, including time and frequency adjustments, +controlling time constant, leap-second warning and related data. + +In this memo, NTP Version 3 and the Unix implementation xntpd are used +as an example application of the new system calls for use by a protocol +daemon. In principle, the new system calls can be used by other +protocols and daemon implementations as well. Even in cases where the +local time is maintained by periodic exchanges of messages at relatively +long intervals, such as using the NIST Automated Computer Time Service, +the ability to precisely adjust the local clock frequency simplifies the +synchronization procedures and allows the call frequency to be +considerably reduced. + +2. Design Principles + +In order to understand how the new software works, it is useful to +consider how most Unix systems maintain the system time. In the original +design a hardware timer interrupts the kernel at a fixed rate: 100 Hz in +the SunOS kernel, 256 Hz in the Ultrix kernel and 1024 Hz in the OSF/1 +kernel. Since the Ultrix kernel rate does not evenly divide one second +in microseconds, the kernel adds 64 microseconds once each second, so +the timescale consists of 255 advances of 3906 usec plus one of 3970 +usec. Similarly, the OSF/1 kernel adds 576 usec once each second, so its +timescale consists of 1023 advances of 976 usec plus one of 1552 usec. + +In all Unix kernels considered in this memo, it is possible to slew the +system clock to a new offset using the standard Unix adjtime() system +call. To do this the clock frequency is changed by adding or subtracting +a fixed amount (tickadj) at each timer interrupt (tick) for a calculated +number of ticks. Since this calculation involves dividing the requested +offset by tickadj, it is possible to slew to a new offset with a +precision only of tickadj, which is usually in the neighborhood of 5 us, +but sometimes much higher. This results in an amortization error which +can accumulate to unacceptable levels, so that special provisions must +be made in the clock adjustment procedures of the protocol daemon. + +In order to maintain the system clock within specified bounds with this +scheme, it is necessary to call adjtime() on a regular basis. For +instance, let the bound be set at 100 usec, which is a reasonable value +for NTP-synchronized hosts on a local network, and let the onboard +oscillator tolerance be 100 parts-per-million (ppm), which is a +reasonably conservative assumption. This requires that adjtime() be +called at intervals not exceeding 1 second (s), which is in fact what +the unmodified NTP software daemon does. + +In the new software this scheme is replaced by another that extends the +low-order bits of the system clock to provide very precise clock +adjustments. At each timer interrupt a precisely calibrated quantity is +added to the composite time value and overflows handled as required. The +quantity is computed from the measured clock offset and in addition a +frequency adjustment, which is automatically calculated from previous +time adjustments. This implementation operates as an adaptive-parameter +first-order, type-II, phase-lock loop (PLL), which in principle provides +precision control of the system clock phase to within +-1 us and +frequency to within +-5 nanoseconds (ns) per day. + +This PLL model is identical to the one implemented in NTP, except that +in NTP the software daemon has to simulate the PLL using only the +original adjtime() system call. The daemon is considerably complicated +by the need to parcel time adjustments at frequent intervals in order to +maintain the accuracy to specified bounds. The modified kernel routines +do this directly, allowing vast gobs of ugly daemon code to be avoided +at the expense of only a small amount of new code in the kernel. In +fact, the amount of code added to the kernel for the new scheme is about +the amount needed to implement the old scheme. A new system call +ntp_adjtime(), which operates in a way similar to the original +adjtime(), is called only as each new time update is determined, which +in NTP occurs at intervals of from 16 s to 1024 s. In addition, doing +the frequency correction in the kernel means that the system time runs +true even if the daemon were to cease operation or the network paths to +the primary reference source fail. The addition of the new ntp_adjtime() +system call does not affect the original adjtime() system call, which +continues to operate in its traditional fashion. However, the two system +calls canot be used at the same time; only one of the two should be used +on any given system. + +It is the intent in the design that settimeofday() be used for changes +in system time greater than +-128 ms. It has been the Internet +experience that the need to change the system time in increments greater +than +-128 milliseconds is extremely rare and is usually associated with +a hardware or software malfunction or system reboot. Once the system +clock has been set in this way, the ntp_adjtime() system call is used to +provide periodic updates including the time offset, maximum error, +estimated error and PLL time constant. With NTP the update interval +depends on the measured error and time constant; however, the scheme is +quite forgiving and neither moderate loss of updates nor variations in +the length of the polling interval are serious. + +In addition, the kernel adjusts the maximum error to grow by an amount +equal to the oscillator frequency tolerance times the elapsed time since +the last update. The default engineering parameters have been optimized +for intervals not greater than about 16 s. For longer intervals the PLL +time constant can be adjusted to optimize the dynamic response up to +intervals of 1024 s. Normally, this is automatically done by NTP. In any +case, if updates are suspended, the PLL coasts at the frequency last +determined, which usually results in errors increasing only to a few +tens of milliseconds over a day. + +The new code needs to know the initial frequency offset and time +constant for the PLL, and the daemon needs to know the current frequency +offset computed by the kernel for monitoring purposes. These data are +exchanged between the kernel and protocol daemon using ntp_adjtime() as +documented later in this memo. Provisions are made to exchange related +timing information, such as the maximum error and estimated error, +between the kernel and daemon and between the kernel and application +programs. + +In the DEC 3000 AXP, DECstation 5000/240 and possibly other DEC +machines there is an undocumented hardware register that counts system +bus cycles at a rate of 25 MHz. The new kernel microtime() routine tests +for the CPU type and, in the case of these machines, use this register +to interpolate system time between hardware timer interrupts. This +results in a precision of +-1 us for all time values obtained via the +gettimeofday() and ntp_gettime() system calls. These routines call the +microtime() routine, which returns the actual interpolated value but +does not change the kernel time variable. Therefore, other kernel +routines that access the kernel time variable directly and do not call +either gettimeofday(), ntp_gettime() or microtime() will continue their +present behavior. The microtime() feature is independent of other +features described here and is operative even if the kernel PLL or new +system calls have not been implemented. + +While any protocol daemon can in principle be modified to use the new +system calls, the most likely will be users of the NTP Version 3 daemon +xntpd. The xntpd code determines whether the new system calls are +implemented and automatically reconfigures as required. When +implemented, the daemon reads the frequency offset from a file and +provides it and the initial time constant via ntp_adjtime(). In +subsequent calls to ntp_adjtime(), only the time adjustment and time +constant are affected. The daemon reads the frequency from the kernel +using ntp_adjtime() at intervals of about one hour and writes it to the +system log file. This information is recovered when the daemon is +restarted after reboot, for example, so the sometimes extensive training +period to learn the frequency separately for each system can be avoided. + +3. Kernel Interfaces + +This section describes the kernel interfaces to the protocol daemon and +user applications. The ideas are based on suggestions from Jeff Mogul +and Philip Gladstone and a similar interface designed by the latter. It +is important to point out that the functionality of the original Unix +adjtime() system call is preserved, so that the modified kernel will +work as the unmodified one should the kernel PLL not be in use. In this +case the ntp_adjtime() system call can still be used to read and write +kernel variables that might be used by a protocol daemon other than NTP, +for example. + +3.1. The ntp_gettime() System Call + +The syntax and semantics of the ntp_gettime() call are given in the +following fragment of the timex.h header file. This file is identical in +the SunOS, Ultrix and OSF/1 kernel distributions. Note that the timex.h +file calls the syscall.h system header file, which must be modified to +define the SYS_ntp_gettime system call specific to each system type. The +kernel distributions include directions on how to do this. + +/* + * This header file defines the Network Time Protocol (NTP) interfaces + * for user and daemon application programs. These are implemented using + * private system calls and data structures and require specific kernel + * support. + * + * NAME + * ntp_gettime - NTP user application interface + * + * SYNOPSIS + * #include + * + * int system call(SYS_ntp_gettime, tptr) + * + * int SYS_ntp_gettime defined in syscall.h header file + * struct ntptimeval *tptr pointer to ntptimeval structure + * + * NTP user interface - used to read kernel clock values + * Note: maximum error = NTP synch distance = dispersion + delay / 2; + * estimated error = NTP dispersion. + */ +struct ntptimeval { + struct timeval time; /* current time */ + long maxerror; /* maximum error (usec) */ + long esterror; /* estimated error (usec) */ +}; + +The ntp_gettime() system call returns three values in the ntptimeval +structure: the current time in unix timeval format plus the maximum and +estimated errors in microseconds. While the 32-bit long data type limits +the error quantities to something more than an hour, in practice this is +not significant, since the protocol itself will declare an +unsynchronized condition well below that limit. If the protocol computes +either of these values in excess of 16 seconds, they are clamped to that +value and the local clock declared unsynchronized. + +Following is a detailed description of the ntptimeval structure members. + +struct timeval time; + + This member is set to the current system time, expressed as a Unix + timeval structure. The timeval structure consists of two 32-bit + words, one for the number of seconds past 1 January 1970 and the + other the number of microseconds past the most recent second's + epoch. + +long maxerror; + + This member is set to the value of the time_maxerror kernel + variable, which establishes the maximum error of the indicated time + relative to the primary reference source, in microseconds. This + variable can also be set and read by the ntp_adjtime() system call. + For NTP, the value is determined as the synchronization distance, + which is equal to the root dispersion plus one-half the root delay. + It is increased by a small amount (time_tolerance) each second to + reflect the clock frequency tolerance. This variable is computed by + the time-synchronization daemon and the kernel and returned in a + ntp_gettime() system call, but is otherwise not used by the kernel. + +long esterror; + + This member is set to the value of the time_esterror kernel + variable, which establishes the expected error of the indicated + time relative to the primary reference source, in microseconds. + This variable can also be set and read by the ntp_adjtime() system + call. For NTP, the value is determined as the root dispersion, + which represents the best estimate of the actual error of the + system clock based on its past behavior, together with observations + of multiple clocks within the peer group. This variable is computed + by the time-synchronization daemon and returned in a ntp_gettime() + system call, but is otherwise not used by the kernel. + +3.2. The ntp_adjtime() System Call + +The syntax and semantics of the ntp_adjtime() call is given in the +following fragment of the timex.h header file. Note that, as in the +ntp_gettime() system call, the the syscall.h system header file must be +modified to define the SYS_ntp_adjtime system call specific to each +system type. + +/* + * NAME + * ntp_adjtime - NTP daemon application interface + * + * SYNOPSIS + * #include + * + * int system call(SYS_ntp_adjtime, mode, tptr) + * + * int SYS_ntp_adjtime defined in syscall.h header file + * struct timex *tptr pointer to timex structure + * + * NTP daemon interface - used to discipline kernel clock oscillator + */ +struct timex { + int mode; /* mode selector */ + long offset; /* time offset (usec) */ + long frequency; /* frequency offset (scaled ppm) */ + long maxerror; /* maximum error (usec) */ + long esterror; /* estimated error (usec) */ + int status; /* clock command/status */ + long time_constant; /* pll time constant */ + long precision; /* clock precision (usec) (read only) */ + long tolerance; /* clock frequency tolerance (ppm) + * (read only) + */ +}; + +The ntp_adjtime() system call is used to read and write certain time- +related kernel variables summarized in this and subsequent sections. +Writing these variables can only be done in superuser mode. To write a +variable, the mode structure member is set with one or more bits, one of +which is assigned each of the following variables in turn. The current +values for all variables are returned in any case; therefore, a mode +argument of zero means to return these values without changing anything. + +Following is a description of the timex structure members. + +int mode; + + This is a bit-coded variable selecting one or more structure + members, with one bit assigned each member. If a bit is set, the + value of the associated member variable is copied to the + corresponding kernel variable; if not, the member is ignored. The + bits are assigned as given in the following fragment of the timex.h + header file. Note that the precision and tolerance are intrinsic + properties of the kernel configuration and cannot be changed. + + /* + * Mode codes (timex.mode) + */ + #define ADJ_OFFSET 0x0001 /* time offset */ + #define ADJ_FREQUENCY 0x0002 /* frequency offset */ + #define ADJ_MAXERROR 0x0004 /* maximum time error */ + #define ADJ_ESTERROR 0x0008 /* estimated time error */ + #define ADJ_STATUS 0x0010 /* clock status */ + #define ADJ_TIMECONST 0x0020 /* pll time constant */ + +long offset; + + If selected, this member (scaled) replaces the value of the + time_offset kernel variable, which defines the current time offset + of the phase-lock loop. The value must be in the range +-512 ms in + the present implementation. If so, the clock status is + automatically set to TIME_OK. + +long time_constant; + + If selected, this member replaces the value of the time_constant + kernel variable, which establishes the bandwidth of "stiffness" of + the kernel PLL. The value is used as a shift, with the effective + PLL time constant equal to a multiple of (1 << time_constant), in + seconds. The optimum value for the time_constant variable is + log2(update_interval) - 4, where update_interval is the nominal + interval between clock updates, in seconds. With an ordinary crystal + oscillator the optimum value for time_constant is about 2, giving + an update_interval of 4 (64 s). Values of time_constant between zero + and 2 can be used if quick convergence is necessary; values between + 2 and 6 can be used to reduce network load, but at a modest cost in + accuracy. Values above 6 are appropriate only if a precision + oscillator is available. + +long frequency; + + If selected, this member (scaled) replaces the value of the + time_frequency kernel variable, which establishes the intrinsic + frequency of the local clock oscillator. This variable is scaled by + (1 << SHIFT_USEC) in parts-per-million (ppm), giving it a maximum + value of about +-31 ms/s and a minimum value (frequency resolution) + of about 2e-11, which is appropriate for even the best quartz + oscillator. + +long maxerror; + + If selected, this member replaces the value of the time_maxerror + kernel variable, which establishes the maximum error of the + indicated time relative to the primary reference source, in + microseconds. This variable can also be read by the ntp_gettime() + system call. For NTP, the value is determined as the + synchronization distance, which is equal to the root dispersion + plus one-half the root delay. It is increased by a small amount + (time_tolerance) each second to reflect the clock frequency + tolerance. This variable is computed by the time-synchronization + daemon and the kernel and returned in a ntp_gettime() system call, + but is otherwise not used by the kernel. + +long esterror; + + If selected, this member replaces the value of the time_esterror + kernel variable, which establishes the expected error of the + indicated time relative to the primary reference source, in + microseconds. This variable can also be read by the ntp_gettime() + system call. For NTP, the value is determined as the root + dispersion, which represents the best estimate of the actual error + of the system clock based on its past behavior, together with + observations of multiple clocks within the peer group. This + variable is computed by the time-synchronization daemon and + returned in a ntp_gettime() system call, but is otherwise not used + by the kernel. + +int status; + + If selected, this member replaces the value of the time_status + kernel variable, which records whether the clock is synchronized, + waiting for a leap second, etc. In order to set this variable + explicitly, either (a) the current clock status is TIME_OK or (b) + the member value is TIME_BAD; that is, the ntp_adjtime() call can + always set the clock to the unsynchronized state or, if the clock + is running correctly, can set it to any state. In any case, the + ntp_adjtime() call always returns the current state in this member, + so the caller can determine whether or not the request succeeded. + +long precision; + + This member is set equal to the time_precision kernel in + microseconds variable upon return from the system call. The + time_precision variable cannot be written. This variable represents + the maximum error in reading the system clock, which is ordinarily + equal to the kernel variable tick, 10000 usec in the SunOS kernel, + 3906 usec in Ultrix kernel and 976 usec in the OSF/1 kernel. + However, in cases where the time can be interpolated with + microsecond resolution, such as in the SunOS kernel and modified + Ultrix and OSF/1 kernels, the precision is specified as 1 usec. + This variable is computed by the kernel for use by the time- + synchronization daemon, but is otherwise not used by the kernel. + +long tolerance; + + This member is set equal to the time_tolerance kernel variable in + parts-per-million (ppm) upon return from the system call. The + time_tolerance variable cannot be written. This variable represents + the maximum frequency error or tolerance of the particular platform + and is a property of the architecture and manufacturing process. + +3.3. Command/Status Codes + +The kernel routines use the system clock status variable time_status, +which records whether the clock is synchronized, waiting for a leap +second, etc. The value of this variable is returned as the result code +by both the ntp_gettime() and ntp_adjtime() system calls. In addition, +it can be explicitly read and written using the ntp_adjtime() system +call, but can be written only in superuser mode. Values presently +defined in the timex.h header file are as follows: + +/* + * Clock command/status codes (timex.status) + */ +#define TIME_OK 0 /* clock synchronized */ +#define TIME_INS 1 /* insert leap second */ +#define TIME_DEL 2 /* delete leap second */ +#define TIME_OOP 3 /* leap second in progress */ +#define TIME_BAD 4 /* clock not synchronized */ + +A detailed description of these codes as used by the leap-second state +machine is given later in this memo. In case of a negative result code, +the kernel has intercepted an invalid address or (in case of the +ntp_adjtime() system call), a superuser violation. + +4. Technical Summary + +In order to more fully understand the workings of the PLL, a stand-alone +simulator kern.c is included in the kernel distributions. This is an +implementation of an adaptive-parameter, first-order, type-II phase-lock +loop. The system clock is implemented using a set of variables and +algorithms defined in the simulator and driven by explicit offsets +generated by the simulator. The algorithms include code fragments +identical to those in the modified kernel routines and operate in the +same way, but the operations can be understood separately from any +licensed source code into which these fragments may be integrated. The +code segments themselves are not derived from any licensed code. + +4.1. PLL Simulation + +In the simulator the hardupdate() fragment is called by ntp_adjtime() as +each update is computed to adjust the system clock phase and frequency. +Note that the time constant is in units of powers of two, so that +multiplies can be done by simple shifts. The phase variable is computed +as the offset multiplied by the time constant. Then, the time since the +last update is computed and clamped to a maximum (for robustness) and to +zero if initializing. The offset is multiplied (sorry about the ugly +multiply) by the result and by the square of the time constant and then +added to the frequency variable. Finally, the frequency variable is +clamped not to exceed the tolerance. Note that all shifts are assumed to +be positive and that a shift of a signed quantity to the right requires +a little dance. + +With the defines given, the maximum time offset is determined by the +size in bits of the long type (32) less the SHIFT_UPDATE scale factor or +18 bits (signed). The scale factor is chosen so that there is no loss of +significance in later steps, which may involve a right shift up to 14 +bits. This results in a maximum offset of about +-130 ms. Since +time_constant must be greater than or equal to zero, the maximum +frequency offset is determined by the SHIFT_KF (20) scale factor, or +about +-130 ppm. In the addition step, the value of offset * mtemp is +represented in 18 + 10 = 28 bits, which will not overflow a long add. +There could be a loss of precision due to the right shift of up to eight +bits, since time_constant is bounded at 6. This results in a net worst- +case frequency error of about 2^-16 us or well down into the oscillator +phase noise. While the time_offset value is assumed checked before +entry, the time_phase variable is an accumulator, so is clamped to the +tolerance on every call. This helps to damp transients before the +oscillator frequency has been determined, as well as to satisfy the +correctness assertions if the time-synchronization protocol comes +unstuck. + +The hardclock() fragment is inserted in the hardware timer interrupt +routine at the point the system clock is to be incremented. Previous to +this fragment the time_update variable has been initialized to the value +computed by the adjtime() system call in the stock Unix kernel, normally +the value of tick plus/minus the tickadj value, which is usually in the +order of 5 microseconds. When the kernel PLL is in use, adjtime() is +not, so the time_update value at this point is the value of tick. This +value, the phase adjustment (time_adj) and the clock phase (time_phase) +are summed and the total tested for overflow of the microsecond. If an +overflow occurs, the microsecond (tick) is incremented or decremented, +depending on the sign of the overflow. + +The second_overflow() fragment is inserted at the point where the +microseconds field of the system time variable is being checked for +overflow. On rollover of the second the maximum error is increased by +the tolerance and the time offset is divided by the phase weight +(SHIFT_KG) and time constant. The time offset is then reduced by the +result and the result is scaled and becomes the value of the phase +adjustment. The phase adjustment is then corrected for the calculated +frequency offset and a fixed offset determined from the fixtick variable +in some kernel implementations. On rollover of the day, the leap-warning +indicator is checked and the apparent time adjusted +-1 s accordingly. +The microtime() routine insures that the reported time is always +monotonically increasing. + +The simulator has been used to check the PLL operation over the design +envelope of +-128 ms in time error and +-100 ppm in frequency error. +This confirms that no overflows occur and that the loop initially +converges in about 15 minutes for timer interrupt rates from 50 Hz to +1024 Hz. The loop has a normal overshoot of about seven percent and a +final convergence time of several hours, depending on the initial time +and frequency error. + +4.2. Leap Seconds + +It does not seem generally useful in the user application interface to +provide additional details private to the kernel and synchronization +protocol, such as stratum, reference identifier, reference timestamp and +so forth. It would in principle be possible for the application to +independently evaluate the quality of time and project into the future +how long this time might be "valid." However, to do that properly would +duplicate the functionality of the synchronization protocol and require +knowledge of many mundane details of the platform architecture, such as +the subnet configuration, reachability status and related variables. +However, for the curious, the ntp_adjtime() system call can be used to +reveal some of these mysteries. + +However, the user application may need to know whether a leap second is +scheduled, since this might affect interval calculations spanning the +event. A leap-warning condition is determined by the synchronization +protocol (if remotely synchronized), by the timecode receiver (if +available), or by the operator (if awake). This condition is set by the +protocol daemon on the day the leap second is to occur (30 June or 31 +December, as announced) by specifying in a ntp_adjtime() system call a +clock status of either TIME_DEL, if a second is to be deleted, or +TIME_INS, if a second is to be inserted. Note that, on all occasions +since the inception of the leap-second scheme, there has never been a +deletion occasion. If the value is TIME_DEL, the kernel adds one second +to the system time immediately following second 23:59:58 and resets the +clock status to TIME_OK. If the value is TIME_INS, the kernel subtracts +one second from the system time immediately following second 23:59:59 +and resets the clock status to TIME_OOP, in effect causing system time +to repeat second 59. Immediately following the repeated second, the +kernel resets the clock status to TIME_OK. + +Depending upon the system call implementation, the reported time during +a leap second may repeat (with the TIME_OOP return code set to advertise +that fact) or be monotonically adjusted until system time "catches up" +to reported time. With the latter scheme the reported time will be +correct before and shortly after the leap second (depending on the +number of microtime() calls during the leap second itself), but freeze +or slowly advance during the leap second itself. However, Most programs +will probably use the ctime() library routine to convert from timeval +(seconds, microseconds) format to tm format (seconds, minutes,...). If +this routine is modified to use the ntp_gettime() system call and +inspect the return code, it could simply report the leap second as +second 60. + +To determine local midnight without fuss, the kernel simply finds the +residue of the time.tv_sec value mod 86,400, but this requires a messy +divide. Probably a better way to do this is to initialize an auxiliary +counter in the settimeofday() routine using an ugly divide and increment +the counter at the same time the time.tv_sec is incremented in the timer +interrupt routine. For future embellishment. + +4.2. Kernel Variables + +The following kernel variables are defined by the new code: + +long time_offset = 0; /* time adjustment (us) */ + + This variable is used by the PLL to adjust the system time in small + increments. It is scaled by (1 << SHIFT_UPDATE) in binary + microseconds. The maximum value that can be represented is about +- + 512 ms and the minimum value or precision is one microsecond. + +long time_constant = 0; /* pll time constant */ + + This variable determines the bandwidth or "stiffness" of the PLL. + It is used as a shift, with the effective value in positive powers + of two. The default value (0) corresponds to a PLL time constant of + about 4 minutes. + +long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */ + + This variable represents the maximum frequency error or tolerance + of the particular platform and is a property of the architecture. + It is expressed as a positive number greater than zero in parts- + per-million (ppm). The default MAXFREQ (100) is appropriate for + conventional workstations. + +long time_precision = 1000000 / HZ; /* clock precision (us) */ + + This variable represents the maximum error in reading the system + clock. It is expressed as a positive number greater than zero in + microseconds and is usually based on the number of microseconds + between timer interrupts, 3906 usec for the Ultrix kernel, 976 usec + for the OSF/1 kernel. However, in cases where the time can be + interpolated between timer interrupts with microsecond resolution, + such as in the unmodified SunOS kernel and modified Ultrix and + OSF/1 kernels, the precision is specified as 1 usec. This variable + is computed by the kernel for use by the time-synchronization + daemon, but is otherwise not used by the kernel. + +long time_maxerror; /* maximum error */ + + This variable establishes the maximum error of the indicated time + relative to the primary reference source, in microseconds. For NTP, + the value is determined as the synchronization distance, which is + equal to the root dispersion plus one-half the root delay. It is + increased by a small amount (time_tolerance) each second to reflect + the clock frequency tolerance. This variable is computed by the + time-synchronization daemon and the kernel, but is otherwise not + used by the kernel. + +long time_esterror; /* estimated error */ + + This variable establishes the expected error of the indicated time + relative to the primary reference source, in microseconds. For NTP, + the value is determined as the root dispersion, which represents + the best estimate of the actual error of the system clock based on + its past behavior, together with observations of multiple clocks + within the peer group. This variable is computed by the time- + synchronization daemon and returned in system calls, but is + otherwise not used by the kernel. + +long time_phase = 0; /* phase offset (scaled us) */ +long time_freq = 0; /* frequency offset (scaled ppm) */ +time_adj = 0; /* tick adjust (scaled 1 / HZ) */ + + These variables control the phase increment and the frequency + increment of the system clock at each tick. The time_phase variable + is scaled by (1 << SHIFT_SCALE) (24) in microseconds, giving a + maximum adjustment of about +-128 us/tick and a resolution of about + 60 femtoseconds/tick. The time_freq variable is scaled by (1 << + SHIFT_KF) in parts-per-million (ppm), giving it a maximum value of + over +-2000 ppm and a minimum value (frequency resolution) of about + 1e-5 ppm. The time_adj variable is the actual phase increment in + scaled microseconds to add to time_phase once each tick. It is + computed from time_phase and time_freq once per second. + +long time_reftime = 0; /* time at last adjustment (s) */ + + This variable is the second's portion of the system time on the + last call to adjtime(). It is used to adjust the time_freq variable + as the time since the last update increases. + +int fixtick = 1000000 % HZ; /* amortization factor */ + + In some systems such as the Ultrix and OSF/1 kernels, the local + clock runs at some frequency that does not divide the number of + microseconds in the second. In order that the clock runs at a + precise rate, it is necessary to introduce an amortization factor + into the local timescale, in effect a leap-multimicrosecond. This + is not a new kernel variable, but a new use of an existing kernel + variable. + +4.3. Architecture Constants + +Following is a list of the important architecture constants that +establish the response and stability of the PLL and provide maximum +bounds on behavior in order to satisfy correctness assertions made in +the protocol specification. + +#define HZ 256 /* timer interrupt frequency (Hz) */ +#define SHIFT_HZ 8 /* log2(HZ) */ + + The HZ define (a variable in some kernels) establishes the timer + interrupt frequency, 100 Hz for the SunOS kernel, 256 Hz for the + Ultrix kernel and 1024 Hz for the OSF/1 kernel. The SHIFT_HZ define + expresses the same value as the nearest power of two in order to + avoid hardware multiply operations. These are the only parameters + that need to be changed for different kernel timer interrupt + frequencies. + +#define SHIFT_KG 6 /* shift for phase increment */ +#define SHIFT_KF 16 /* shift for frequency increment */ +#define MAXTC 6 /* maximum time constant (shift) */ + + These defines establish the response and stability characteristics + of the PLL model. The SHIFT_KG and SHIFT_KF defines establish the + damping of the PLL and are chosen by analysis for a slightly + underdamped convergence characteristic. The MAXTC define + establishes the maximum time constant of the PLL. + +#define SHIFT_SCALE (SHIFT_KF + SHIFT_HZ) /* shift for scale factor */ +#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* shift for offset scale + * factor */ +#define SHIFT_USEC 16 /* shift for 1 us in external units */ +#define FINEUSEC (1 << SHIFT_SCALE) /* 1 us in scaled units */ + + The SHIFT_SCALE define establishes the decimal point on the + time_phase variable which serves as a an extension to the low-order + bits of the system clock variable. The SHIFT_UPDATE define + establishes the decimal point of the phase portion of the + ntp_adjtime() update. The SHIFT_USEC define represents 1 us in + external units (shift), while the FINEUSEC define represents 1 us + in internal units. + +#define MAXPHASE 128000 /* max phase error (usec) */ +#define MAXFREQ 100 /* max frequency error (ppm) */ +#define MINSEC 16 /* min interval between updates (s) */ +#define MAXSEC 1200 /* max interval between updates (s) */ + + These defines establish the performance envelope of the PLL, one to + bound the maximum phase error, another to bound the maximum + frequency error and two others to bound the minimum and maximum + time between updates. The intent of these bounds is to force the + PLL to operate within predefined limits in order to conform to the + correctness models assumed by time-synchronization protocols like + NTP and DTSS. An excursion which exceeds these bounds is clamped to + the bound and operation proceeds accordingly. In practice, this can + occur only if something has failed or is operating out of + tolerance, but otherwise the PLL continues to operate in a stable + mode. Note that the MAXPHASE define conforms to the maximum offset + allowed in NTP before the system time is reset (by settimeofday(), + rather than incrementally adjusted (by ntp_adjtime(). + +David L. Mills +Electrical Engineering Department +University of Delaware +Newark, DE 19716 +302 831 8247 fax 302 831 4316 + +1 April 1992 diff --git a/contrib/xntpd/doc/README.magic b/contrib/xntpd/doc/README.magic new file mode 100644 index 0000000000..f473a9220c --- /dev/null +++ b/contrib/xntpd/doc/README.magic @@ -0,0 +1,346 @@ + Magic Tricks for Precision Timekeeping + + Revised 19 September 1993 + +Note: This information file is included in the NTP Version 3 +distribution (xntp3.tar.Z) as the file README.magic. This distribution +can be obtained via anonymous ftp from louie.udel.edu in the directory +pub/ntp. + +1. Introduction + +It most cases it is possible using NTP to synchronize a number of hosts +on an Ethernet or moderately loaded T1 network to a radio clock within a +few tens of milliseconds with no particular care in selecting the radio +clock or configuring the servers on the network. This may be adequate +for the majority of applications; however, modern workstations and high +speed networks can do much better than that, generally to within some +fraction of a millisecond, by using special care in the design of the +hardware and software interfaces. + +The timekeeping accuracy of a NTP-synchronized host depends on two +quantities: the delay due to hardware and software processing and the +accumulated jitter due to such things as clock reading precision and +varying latencies in hardware and software queuing. Processing delays +directly affect the timekeeping accuracy, unless minimized by systematic +analysis and adjustment. Jitter, on the other hand, can be essentially +removed, as long as the statistical properties are unbiased, by the low- +pass filtering of the phase-lock loop incorporated in the NTP local +clock model. + +This note discusses issues in the connection of external time sources +such as radio clocks and related timing signals to a primary (stratum-1) +NTP time server. Of principal concern are various techniques that can be +utilized to improve the accuracy and precision of the time accuracy and +frequency stability. Radio clocks are most often connected to a time +server using a serial asynchronous port. Much of the discussion in this +memorandum has to do with ways in which the delay incurred in this type +of connection can be controlled and ways in which the jitter due to +various causes can be minimized. + +However, there are ways other than serial ports to connect a radio +clock, including special purpose hardware devices for some +architectures, and even unusual applications of existing interface +devices, such as the audio codec provided in some systems. Many of these +methods can yield accuracies as good as any attainable with a serial +port. For those radio clocks equipped with an IRIG-B signal output, for +example, a hardware device is available for the Sun SPARCstation; see +the xntpd.8 manual page in the doc directory of the NTP Version 3 +distribution for further information. In addition, it is possible to +decode the IRIG-B signal using the audio codec included in the Sun +SPARCstation and a special kernel driver described in the irig.txt file +in the doc directory of the NTP Version 3 distribution. These devices +will not be discussed further in this memorandum. + +2. Connection via Serial Port + +Most radio clocks produce an ASCII timecode with a precision only to the +millisecond. This results in a maximum peak-to-peak (p-p) jitter in the +clock readings of one millisecond. However, assuming the read requests +are statistically independent of the clock update times, the reading +error is uniformly distributed over the millisecond, so that the average +over a large number of readings will make the clock appear 0.5 ms late. +To compensate for this, it is only necessary to add 0.5 ms to its +reading before further processing by the NTP algorithms. + +Radio clocks are usually connected to the host computer using a serial +port operating at a typical speed of 9600 baud. The on-time reference +epoch for the timecode is usually the start bit of a designated +character, usually , which is part of the timecode. The UART chip +implementing the serial port most often has a sample clock of eight to +16 times the basic baud rate. Assuming the sample clock starts midway in +the start bit and continues to midway in the first stop bit, this +creates a processing delay of 10.5 baud times, or about 1.1 ms, relative +to the start bit of the character. The jitter contribution is usually no +more than a couple of sample-clock periods, or about 26 usec p-p. This +is small compared to the clock reading jitter and can be ignored. Thus, +the UART delay can be considered constant, so the hardware contribution +to the total mean delay budget is 0.5 + 1.1 = 1.6 ms. + +In some kernel serial port drivers, in particular, the Sun zs driver, +an intentional delay is introduce in input character processing when the +first character is received after an idle period. A batch of characters +is passed to the calling program when either (a) a timeout in the +neighborhood of 10 ms expires or (b) an input buffer fills up. The +intent in this design is to reduce the interrupt load on the processor +by batching the characters where possible. Obviously, this can cause +severe problems for precision timekeeping. It is possible to patch the +zs driver to eliminate the jitter due to this cause; contact the author +for further details. However, there is a better solution which will be +described later in this note. The problem does not appear to be present +in the Serial/Parallel Controller (SPC) for the SBus, which contains +eight serial asynchronous ports along with a parallel port. The +measurements referred to below were made using this controller. + +Good timekeeping depends strongly on the means available to capture an +accurate sample of the local clock or timestamp at the instant the stop +bit of the on-time character is found; therefore, the code path delay +between the character interrupt routine and the first place a timestamp +can be captured is very important, since on some systems such as Sun +SPARCstations, this path can be astonishingly long. The Sun scheduling +mechanisms involve both a hardware interrupt queue and a software +interrupt queue. Entries are made on the hardware queue as the interrupt +is signalled and generally with the lowest latency, estimated at 20-30 +microseconds (usec) for a SPARC 4/65 IPC. Then, after minimal +processing, an entry is made on the software queue for later processing +in order of software interrupt priority. Finally, the software interrupt +unblocks the NTP daemon which calculates the current local clock offset +and introduces corrections as required. + +Opportunities exist to capture timestamps at the hardware interrupt +time, software interrupt time and at the time the NTP daemon is +activated, but these involve various degrees of kernel trespass and +hardware gimmicks. To gain some idea of the severity of the errors +introduced at each of these stages, measurements were made using a Sun +4/65 IPC and a test setup that results in an error between the host +clock and a precision time source (calibrated cesium clock) no greater +than 0.1 ms. The total delay from the on-time epoch to when the NTP +daemon is activated was measured at 8.3 ms in an otherwise idle system, +but increased on rare occasion to over 25 ms under load, even when the +NTP daemon was operated at the highest available software priority +level. Since 1.6 ms of the total delay is due to the hardware, the +remaining 6.7 ms represents the total code path delay accounting for all +software processing from the hardware interrupt to the NTP daemon. + +It is commonly observed that the latency variations (jitter) in typical +real-time applications scale as the processing delay. In the case above, +the ratio of the maximum observed delay (25 ms) to the baseline code +path delay (8.3 ms) is about three. It is natural to expect that this +ratio remain the same or less as the code path between the hardware +interrupt and where the timestamp is captured is reduced. However, in +general this requires trespass on kernel facilities and/or making use of +features not common to all or even most Unix implementations. In order +to assess the cost and benefits of increasingly more aggressive insult +to the hardware and software of the system, it is useful to construct a +budget of the code path delay at each of the timestamp opportunity +times. For instance, on Unix systems which include support for the SIGIO +facility, it is possible to intervene at the time the software interrupt +is serviced. The NTP daemon code uses this facility, when available, to +capture a timestamp and save it along with the data in a buffer for +later processing. This reduces the total code path delay from 6.7 ms to +3.5 ms on an otherwise idle system. This reduction applies to all input +processing, including network interfaces and serial ports. + +3. The CLK Mode + +By far the best place to capture the timestamp is right in the kernel +interrupt routine, but this gerally requires intruding in the code +itself, which can be intricate and architecture dependent. The next best +place is in some routine close to the interrupt routine on the code +path. There are two ways to do this, depending on the ancestry of the +Unix operating system variant. Older systems based primarily on the +original Unix 4.3bsd support what is called a line discipline module, +which is a hunk of code with more-or-less well defined interface +specifications that can get in the way, so to speak, of the code path +between the interrupt routine and the remainder of the serial port +processing. Newer systems based on System V STREAMS can do the same +thing using what is called a streams module. Both approaches are +supported in the NTP Version 3 distribution, as described in the README +files in the kernel directory of the distribution. In either case, +header and source files have to be copied to the kernel build tree and +certain tables in the kernel have to be modified. In neither case, +however, are kernel sources required. In order to take advantage of +this, the clock driver must include code to activate the feature and +extract the timestamp. At present, this support is included in the clock +drivers for the Spectracom WWVB clock (WWVB define), the PSTI/Traconex +WWV/WWVH clock (PST define) and a special one-pulse-per-second (pps) +signal (PPSCLK define) described later. If justified, support can be +easily added to most other clock drivers as well. For future reference, +these modules operating with supported drivers will be called the CLK +support. + +The CLK line discipline and STREAMS modules operate in the same way. +They look for a designated character, usually , and stuff a Unix +timestamp in the data stream following that character whenever it is +found. Eventually, the data arrive at the particular clock driver +configured in the NTP Version 3 distribution. The driver then uses the +timestamp as a precise reference epoch, subject to the earlier +processing delays and jitter budget, for future reference. In order to +gain some insight as to the effectiveness of this approach, measurements +were made using the same test setup described above. The total delay +from the on-time epoch to the instant when the timestamp is captured was +measured at 3.5 ms. Thus, the code path delay is this value less the +hardware delay 3.5 - 1.6 = 1.9 ms. + +While the improvement in accuracy in the baseline case is significant, +there is another factor, at least in Sun systems, that makes it even +more worthwhile. When processing the code path up to the CLK module, the +priority is apparently higher than for processing beyond it. In case of +heavy CPU activity, this can lead to relatively long tails in the +processing delays for the driver, which of course are avoided by +capturing the timestamp early in the code path. + +4. The PPSCLK Mode + +Many timing receivers can produce a 1-pps signal of considerably better +precision than the ASCII timecode. Using this signal, it is possible to +avoid the 1-ms p-p jitter and 1.6 ms hardware timecode adjustment +entirely. However, a device is required to interface this signal to the +hardware and operating system. In general, this requires some sort of +level converter and pulse generator that can turn the 1-pps signal on- +time transition into a valid character. An example of such a device is +described in the gadget directory of the NTP Version 3 distribution. +Although many different circuit designs could be used as well, this +particular device generates a single 26-usec start bit for each 1-pps +signal on-time transition. This appears to the UART operating at 38.4K +baud as an ASCII DEL (hex FF). + +Now, assuming a serial port can be dedicated to this purpose, a source +of 1-pps character interrupts is available and can be used to provide a +precision reference. The NTP Version 3 daemon can be configured to +utilize this feature by specifying the PPSCLK define, which requires the +CLK module and gadget box described above. The character resulting from +each 1-pps signal on-time transition is intercepted by the CLK module +and a timestamp is inserted in the data stream. An interrupt is created +for the device driver, which reads the timestamp and discards the DEL +character. Since the timestamp is captured at the on-time transition, +the seconds-fraction portion is the offset between the local clock and +the on-time epoch less the UART delay of 273 usec at 38.4K baud. If the +local clock is within +-0.5 second of this epoch, as determined by other +means, the local clock correction is taken as the offset itself, if +between zero and 0.5 s, and the offset minus one second, if between 0.5 +and 1.0 s. In the NTP daemon the resulting correction is first processed +by a multi-stage median/trimmed mean filter to remove residual jitter +and then processed by the usual NTP algorithms. + +The baseline delay between the on-time transition and the timestamp +capture was measured at 400+-10 usec on an otherwise idle test system. +As the UART delay at 38.4K baud is about 270 usec, the difference, 130 +usec, must be due to the hardware interrupt latency plus the time to +call the microtime() routine which actually reads the system clock and +microsecond counter. For these measurements the assembly-coded version +of this routine described in the ppsclock directory of the NTP Version 3 +distribution was used. This routine reduces the time to read the system +clock from 42-85 usec with the native Sun C-coded routine to about 3 +usec using the microtime() assembly-coded routine and can be ignored. +Thus, the 130 usec must be accounted for in interrupt service, register +window, context switching, streams operations and measurement +uncertainty, which is probably not unreasonable. The reason for the +difference between the this figure and the previously calculated value +of 1.9 ms for the CLK module and serial ASCII timecode is probably due +to the fact that all STREAMS modules other than the CLK module were +removed, since the serial port is not used for ordinary ASCII data. + +An interesting feature of this approach is that the 1-pps signal is not +necessarily associated with any particular radio clock and, indeed, +there may be no such clock at all. Some precision timekeeping equipment, +such as cesium clocks, VLF receivers and LORAN-C timing receivers +produce only a precision 1-pps signal and rely on other mechanisms to +resolve the second of the day and day of the year. It is possible for an +NTP-synchronized host to derive the latter information using other NTP +peers, presumably properly synchronized within +-0.5 second, and to +remove residual jitter using the 1-pps signal. This makes it quite +practical to deliver precision time to local clients when the subnet +paths to remote primary servers are heavily congested. In extreme cases +like this, it has been found useful to increase the tracking aperture +from +-128 ms to as high as +-512 ms. + +In the current implementation the radio timecode and 1-pps signal are +separately processed. The timecode capture and CLK support, if provided +by the radio driver, operate the same way whether or not the PPSCLK +support is enabled. If the local clock is reliably synchronized within ++-0.5 s and the 1-pps signal has been valid for some number of seconds, +its offset rather than whatever synchronization source has been selected +is used instead. However, while a this procedure delivers a new offset +estimate every second, the local clock is updated only as each valid +update is computed for the peer selected as the source of +synchronization. + +However, there is a hazard to the use of the 1-pps signal in this way if +the radio generating the 1-pps signal misbehaves or loses +synchronization with its transmitter. In such a case the radio might +indicate the error, but the system has no way to associate the error +with the 1-pps signal. To deal with this problem the prefer parameter +described in the xntpd.8 man page in the doc directory of the NTP +Version 3 distribution can be used both to cause the clock selection +algorithm to choose a preferred peer, all other things being equal, as +well as associate the error indications in such a way that the 1-pps +signal will be disregarded if the peer stops providing valid updates, +such as would occur in an error condition. The prefer parameter can be +used in other situations as well when preference is to be given a +particular source of synchronization. + +5. The PPS Mode + +For the ultimate accuracy and lowest jitter, it would be best to +eliminate the UART and capture the 1-pps on-time transition directly +using an appropriate interface. This is in fact possible using a +modified serial port driver and data lead in the serial port interface +cable. In this scheme, described in detail in the ppsclock directory of +the NTP Version 3 distribution, the 1-pps source is connected via the +previously described gadget box to the carrier-detect lead of a serial +port. Happily, this can be the same port used for a radio clock, for +example, or another unrelated serial device. The scheme, referred to +subsequently as the PPS mode, is specific to the SunOS 4.1.x kernel and +requires a special STREAMS module. Instructions on how to build the +kernel are also included in that directory. + +Except for special-purpose interface modules, such as the KSI/Odetics +TPRO IRIG-B decoder and the modified audio driver for the IRIG-B signal +mentioned previously, the PPS mode provides the most accurate and +precise timestamp available. There is essentially no latency and the +timestamp is captured within 20-30 usec of the on-time epoch. + +The PPS mode requires the PPSPPS define and one of the radio clock +serial ports to be selected as the PPS interface. This is the port which +handles the 1-pps signal; however, the signal path has nothing to do +with the ordinary serial data path; the two signals are not related, +other than by the need to activate the PPS mode and pass the file +descriptor to a common processing routine. Thus, for the port to be +selected for the PPS function, the define for the associated radio clock +needs to have a PPS suffix. In case of multiple radio clocks on a single +time server, the PPS suffix is necessary on only one of them; more than +one PPS suffix would be an error. + +The PPS mode works just like the CLK mode in the treatment of the prefer +parameter and indicated peer errors. As in the CLK mode, only the offset +within the second is used and only when the offset is less than +-0.5 s. +However, the precision of the clock adjustments is usually so fine that +the error budget is dominated by the inherent short-term stability of +typical computer local clock oscillators. Therefore, it is advisable to +reduce the poll interval for the preferred peer from the default 64 s to +something less, like 16 s. This is done using the minpoll and maxpoll +parameters of the peer or server command associated with the clock. +These parameters take as arguments a power of 2, in seconds, which +becomes the poll interval and, indirectly, affects the bandwidth of the +tracking loop. + +6. Results and Conclusions + +It is clear from the above that substantial improvements in timekeeping +accuracy are possible with varying degrees of hardware and software +intrusion. While the ultimate accuracy depends on the jitter and wander +characteristics of the computer local oscillator, it is possible to +reduce jitter to a negligible degree simply by processing with the NTP +phase-lock loop and local clock algorithms. The residual jitter using +the PPS mode on a Sun4 IPC is typically in the 40-100 usec range, while +the wander is rarely more than twice that under typical environmental +room conditions. + +David L. Mills +Electrical Engineering Department +University of Delaware +Newark, DE 19716 +302 831 8247 fax 302 831 4316 + +25 August 1993 diff --git a/contrib/xntpd/doc/UofT b/contrib/xntpd/doc/UofT new file mode 100644 index 0000000000..54420d5f52 --- /dev/null +++ b/contrib/xntpd/doc/UofT @@ -0,0 +1,146 @@ +This file is the original README, and is a little out of date. It +is also very specific to UofT, since there was a time when the daemon +was only run here. + +To run this: + +(1) Fix your kernel's value of tickadj. Tickadj sets both the + precision with which time slews can be performed and the amount + of slew you can do in a given interval. Xntpd operates by making + a bunch of little adjustments. Make tickadj too large (the default + value almost always is) and xntpd will perform poorly since the + slews will disappear in the roundoff. Make tickadj too small + and large slews won't complete before the next adjustment is + ready. + + To determine a good value of tickadj to use, first determine your + kernel's value of hz (50 on a Sun 3, 100 on Sun 4's and vaxes). + Divide that number into 500 (i.e. compute 500/hz) and use an + integer near there as tickadj (say, 10 on Sun 3's, 5 on Sun 4's + and vaxes). Then adb your kernel and write the new value. You + should probably do both the running kernel and the disk image. + + If your machine doesn't come with adb, or if the kernel is of a + non-Berkeley flavour, take a look at the util directory, particularly + util/tickadj. + +(2) Edit the Config file in this directory. You *must* tell it whether + your machine uses big endian or little endian byte order. Also, + Suns running SunOS 3.x require special consideration, as well as Vaxes + running Ultrix 2.0 and compilers which don't understand `signed char' + declarations. When you've got all this worked out, type `make makefiles' + to distribute configuration information to Makefiles for individual + programs, followed by `make' to compile everything. + +(2a) Note that, among other things, two programs were made in the authstuff + directory, authcert and authspeed. The last two are utilities for + checking the authentication code. Type `authcert < certdata'. If + this provokes a massive failure you probably got the byte order wrong + in the Config file. Type `authspeed -n 10000 auth.samplekeys', or + something, a couple of times to get a value of authdelay to stick in + the configuration file. The numbers for machines I've tried look like: + + uVax II 0.001450 + Sun 3/180 0.000620 + uVax III 0.000515 + Sun 3/60 0.000455 + IBM RT Mdl 125 0.000323 + Sun 3/280 0.000302 + Sun 4/280 0.000110 + MIPS M/1000 0.000100 + +(3) Typing `make install' will nstall xntpd, xntpdc, ntpdate and ntpq. Watch + the install location in the Config file. + +(4) If you will be running xntpd (see 4a below for the alternative), + configure it (configuration is necessary for all machines now, though + this restriction will go away when I get broadcast time fully tested). + xntpd reads its configuration from /etc/ntp.conf (by default) and + you must tell it which machines it is to get its time from in + here. + + Note that NTP operates in a hierarchy. Machines with radio clocks + (which are stratum 1 servers) are at the top of the heap, in that + all time originates with them. The situation with servers locally + is in a state of flux. We currently have one semi-reliable stratum 1 + server on campus (suzuki.ccie), and maintain three other stratum 2 + servers which (gently) access other people's off-campus stratum 1 + servers. All of these machines are lightly loaded and have good + quality clocks, and so will probably do until we get some more stratum 1 + weight. + + Thus you are probably faced with choosing whether your hosts should + be stratum 2 or stratum 3 (or stratum 3 or 4 when suzuki's clock is down). + The rule of thumb is to make your best clocks and/or your file servers + stratum 2 (or 3) by peering them with the four campus servers, and make + lesser clocks and clients stratum 3 (or 4) by peering them with near + by servers which are synchonized to the campus servers. The second rule + of thumb is that more servers are better. It is quite possible to + synchronize with just a single server, but if you do your xtnpd daemon + won't have any cross checks to tell it when the server has gone + wonky. 3 or 4 lower stratum peers is about right. Note that while + you can also peer with same-stratum peers, you shouldn't do this + unless the same-stratum peer is exchanging time with a lower stratum + peer you don't talk to directly. + + Anyway, for your stratum 2 servers you can probably use ntp.conf + from the conf directory directly. You will have to handcraft the + peer assocations for your stratum 3 servers. + + Oh, and a note about the drift file (see ntp.conf). One of the + things xntpd does is accumulate a correction for the frequency of + the crystal in your computer. It usually takes a day or so of + running to figure this out, after which the value will usually remain + pretty stable, especially if the computer is in a machine room. The + value is printed in your syslog file (once a minute, currently, though + this will change), and can be obtained from the daemon using xntpdc. + + To avoid having to wait a day after restarts before the computer + synchronizes really well, xntpd will optionally write its current + value of the frequency correction into a file, once an hour. When + it is killed and restarted, xntpd reinitializes itself to this + value on start up. This is an advantageous feature, so a driftfile + line should always be included in the configuration file. + +(4a) Xntpd is a daemon. It will keep your time exquisitely precise under + normal conditions (it is quite capable of keeping a good clock within + a millisecond of a good server. Our servers aren't normally this + good, yet, but may become so when we get a few more stable local + stratum 1 peers). Even when cut off entirely from its servers xntpd + will prevent your clock from drifting seriously by continuing to apply + its accumulated frequency correction. The cost of this is that xntpd + will permanently consume memory while it is running, and real memory + at that since xntpd is unlikely to ever swap out. This cost is + currently over 100 kb. + + If you aren't too worried about millisecond timing and feel religious + about keeping memory consumption at a minimum (perhaps on memory-poor + workstations), a passable alternative might be to run ntpdate instead. + Ntpdate is the NTP equivalent of rdate, a one shot date setting + program, and implements the same multiple sample/multiple server + filter algorithms as xntpd. Ntpdate was explicitly designed to be + run repeatly from cron, though it also makes a good boot time date + setter. Running ntpdate from cron on an hourly basis will keep all + but seriously broken clocks within 100 ms of on-time, and for most + clocks will probably do better than 50 ms. If this is an attractive + alternative see the manual page. You should choose ntpdate's servers + as you would the peer associations for a stratum 3 xntpd server. + +(5) Once everything is configured, start the daemon(s). ntpq can be + used to see what xntpd is doing. It runs both interactive and from + the command line, type ? to see the interactive commands and ? command + to see what a command does. The `peers' command is a good one. ntpq + can also be used to see what other peoples' servers are doing, in + particular the fuzzball primary servers. + +(6) If you want to use the authentication facility (this might be useful + if, for example, you were running Kerberos since this prevents people + from setting your time back and doing replay attacks on the server), + you might find a couple of useful programs in the auth_stuff directory. + mkrandkeys will generate some very random keys to use. keyparity + generates odd parity bits for keys (needed for the key file) and will + convert between key formats. + +All bug reports gratefully received. + +Dennis diff --git a/contrib/xntpd/doc/notes.txt b/contrib/xntpd/doc/notes.txt new file mode 100644 index 0000000000..5ea2b3318b --- /dev/null +++ b/contrib/xntpd/doc/notes.txt @@ -0,0 +1,1258 @@ + Notes on Xntpd Configuration + + David L. Mills (mills@udel.edu) + University of Delaware + 14 January 1993 + +Introduction + +This document is a collection of notes concerning the use of xntpd and +related programs, and on coping with the Network Time Protocol (NTP) in +general. It is a major rewrite and update of an earlier document written +by Dennis Ferguson of the University of Toronto dated 5 November 1989. +It includes many changes and additions resulting from the NTP Version 3 +specification and new implementation features. It supersedes the earlier +document, which should no longer be used for new configurations. + +Xntpd is a complete implementation of the NTP Version 3 specification as +defined in RFC 1305. It also retains compatibility with both NTP Version +2, as defined in RFC 1119, and NTP Version 1, as defined in RFC 1059, +although this compatibility is sometimes strained and only +semiautomatic. In order to support in principle the ultimate precision +of about 232 picoseconds in the NTP specification, xntpd does no +floating-point arithmetic and instead manipulates the 64-bit NTP +timestamps as unsigned 64-bit integers. Xntpd fully implements NTP +Versions 2 and 3 authentication and a mode-6 control-message facility. +As extensions to the specification, a flexible address-and-mask +restriction facility has been included, along with a private mode-7 +control-message facility used to remotely reconfigure the system and +monitor a considerable amount of internal detail. + +The code is biased towards the needs of a busy time server with +numerous, possibly hundreds, of clients and other servers. Tables are +hashed to allow efficient handling of many associations, though at the +expense of additional overhead when the number of associations is small. +Many fancy features have been included to permit efficient management +and monitoring of a busy primary server, features which are simply +excess baggage for a server on a high stratum client. The code was +written with near demonic attention to details which can affect +precision and as a consequence should be able to make good use of high +performance, special purpose hardware such as precision oscillators and +radio clocks. The present code supports a number of radio clocks, +including those for the WWV, CHU, WWVB, DCF77, GOES and GPS radio and +satellite services. The server methodically avoids the use of Unix- +specific library routines where possible by implementing local versions, +in order to aid in porting the code to perverse Unix and non-Unix +platforms. + +While this implementation slavishly obeys the NTP specification RFC +1305, it has been specifically tuned to achieve the highest accuracy +possible on whatever hardware and operating-system platform is +available. In general, its precision is limited only by that of the +onboard time-of-day clock maintained by the hardware and operating +system, while its stability is limited only by that of the onboard +frequency source, usually an uncompensated crystal oscillator. On modern +RISC-based processors connected directly to radio clocks via serial- +asynchronous interfaces, the accuracy is usually limited by that of the +radio clock and interface to the order of a few milliseconds. The code +includes special features to support a one-pulse-per-second (1-pps) +signal generated by some radio clocks. When used in conjunction with a +suitable hardware level converter, the accuracy can be improved to the +order of 100 microseconds. Further improvement is possible using an +outboard, stabilized frequency source, in which the accuracy and +stability are limited only by the characteristics of that source. + +The xntp3 distribution includes, in addition to the daemon itself +(xntpd), several utility programs, including two remote-monitoring +programs (ntpq, xntpdc), a remote clock-setting program similar to the +Unix rdate program (ntpdate), a traceback utility useful to discover +suitable synchronization sources (ntptrace), and various programs used +to configure the local platform and calibrate the intrinsic errors. NTP +has been ported to a large number of platforms, including most RISC and +CISC workstations and mainframes manufactured today. Example +configuration files for many models of these machines are included in +the xntp3 distribution. While in most cases the standard version of the +implementation runs with no hardware or operating-system modifications, +not all features of the distribution are available on all platforms. For +instance, a special feature allowing Sun 4s to achieve accuracies in the +order of 100 microseconds requires some minor changes and additions to +the kernel and input/output support. + +There are, however, several drawbacks to all of this. Xntpd is very, +very fat. This is rotten if your intended platform for the daemon is +memory-limited. Xntpd uses SIGIO for all input, a facility which appears +to not enjoy universal support and whose use seems to exercise the parts +of your vendors' kernels which are most likely to have been done poorly. +The code is unforgiving in the face of kernel problems which affect +performance, and generally requires that you repair the problems in +order to achieve acceptable performance. The code has a distinctly +experimental flavour and contains features which could charitably be +termed failed experiments, but which have not been hacked out yet. There +is code which has not been thoroughly tested (e.g. leap-second support) +due to the inconvenience of setting up tests. Much was learned from the +addition of support for a variety of radio clocks, with the result that +this support could use some rewriting. + +How NTP Works + +The approach used by NTP to achieve reliable time synchronization from a +set of possibly unreliable remote time servers is somewhat different +than other such protocols. In particular, NTP does not attempt to +synchronize clocks to each other. Rather, each server attempts to +synchronize to UTC (i.e., Universal Coordinated Time) using the best +available source and available transmission paths to that source. This +is a fine point which is worth understanding. A group of NTP- +synchronized clocks may be close to each other in time, but this is not +a consequence of the clocks in the group having synchronized to each +other, but rather because each clock has synchronized closely to UTC via +the best source it has access to. As such, trying to synchronize a set +of clocks to a set of servers whose time is not in mutual agreement may +not result in any sort of useful synchronization of the clocks, even if +you don't care about UTC. NTP operates on the premise that there is one +true standard time, and that if several servers which claim +synchronization to standard time disagree about what that time is, then +one or more of them must be broken. There is no attempt to resolve +differences more gracefully since the premise is that substantial +differences cannot exist. In essence, NTP expects that the time being +distributed from the root of the synchronization subnet will be derived +from some external source of UTC (e.g. a radio clock). This makes it +somewhat inconvenient (though not impossible) to synchronize hosts +together without a reliable source of UTC to synchronize them to. If +your network is isolated and you cannot access other people's servers +across the Internet, a radio clock may make a good investment. + +Time is distributed through a hierarchy of NTP servers, with each server +adopting a "stratum" which indicates how far away from an external +source of UTC it is operating at. Stratum-1 servers, which are at the +top of the pile (or bottom, depending on your point of view), have +access to some external time source, usually a radio clock synchronized +to time signal broadcasts from radio stations which explicitly provide a +standard time service. A stratum-2 server is one which is currently +obtaining time from a stratum-1 server, a stratum-3 server gets its time +from a stratum-2 server, and so on. To avoid long lived synchronization +loops the number of strata is limited to 15. + +Each client in the synchronization subnet (which may also be a server +for other, higher stratum clients) chooses exactly one of the available +servers to synchronize to, usually from among the lowest stratum servers +it has access to. It is thus possible to construct a synchronization +subnet where each server has exactly one source of lower stratum time to +synchronize to. This is, however, not an optimal configuration, for +indeed NTP operates under another premise as well, that each server's +time should be viewed with a certain amount of distrust. NTP really +prefers to have access to several sources of lower stratum time (at +least three) since it can then apply an agreement algorithm to detect +insanity on the part of any one of these. Normally, when all servers are +in agreement, NTP will choose the best of these, where "best" is defined +in terms of lowest stratum, closest (in terms of network delay) and +claimed precision, along with several other considerations. The +implication is that, while one should aim to provide each client with +three or more sources of lower stratum time, several of these will only +be providing backup service and may be of lesser quality in terms of +network delay and stratum (i.e. a same-stratum peer which receives time +from lower stratum sources the local server doesn't access directly can +also provide good backup service). + +Finally, there is the issue of association modes. There are a number of +modes in which NTP servers can associate with each other, with the mode +of each server in the pair indicating the behaviour the other server can +expect from it. In particular, when configuring a server to obtain time +from other servers, there is a choice of two modes which may be +alternatively used. Configuring an association in symmetric-active mode +(usually indicated by a "peer" declaration in configuration files) +indicates to the remote server that one wishes to obtain time from the +remote server and that one is also willing to supply time to the remote +server if need be. This mode is appropriate in configurations involving +a number of redundant time servers interconnected via diverse network +paths, which is presently the case for most stratum-1 and stratum-2 +servers on the Internet today. Configuring an association in client mode +(usually indicated by a "server" declaration in configuration files) +indicates that one wishes to obtain time from the remote server, but that +one is not willing to provide time to the remote server. This mode is +appropriate for file-server and workstation clients that do not provide +synchronization to other local clients. Client mode is also useful for +boot-date-setting programs and the like, which really have no time to +provide and which don't retain state about associations over the longer +term. + +Configuring Your Subnet + +At startup time the xntpd daemon running on a host reads the initial +configuration information from a file, usually /etc/ntp.conf, unless a +different name has been specified at compile time. Putting something in +this file which will enable the host to obtain time from somewhere else +is usually the first big hurdle after installation of the software +itself, which is described in other documents included in the xntp3 +distribution. At its simplest, what you need to do in the configuration +file is declare the servers that the daemon should poll for time +synchronization. In principle, no such list is needed if some other time +server explicitly mentions the host and is willing to provide +synchronization; however, this is considered dangerous, unless the +access control or authentication features (described later) are in use. + +In the case of a workstation operating in an enterprise network for a +public or private organization, there is often an administrative +department that coordinates network services, including NTP. Where +available, the addresses of appropriate servers can be provided by that +department. However, if this infrastructure is not available, it is +necessary to explore some portion of the existing NTP subnet now running +in the Internet. There are at present many thousands of time servers +running NTP in the Internet, a significant number of which are willing +to provide a public time-synchronization service. Some of these are +listed in a file maintained on the Internet host louie.udel.edu +(128.175.1.3) on the path pub/ntp/doc/clock.txt. This file is updated on +a regular basis using information provided voluntarily by various site +administrators. There are other ways to explore the nearby subnet using +the ntptrace and ntpq programs. See the man pages for further +information on these programs. + +It is vital to carefully consider the issues of robustness and +reliability when selecting the sources of synchronization. Normally, not +less than three sources should be available, preferably selected to +avoid common points of failure. It is usually better to choose sources +which are likely to be "close" to you in terms of network topology, +though you shouldn't worry overly about this if you are unable to +determine who is close and who isn't. Normally, it is much more serious +when a server becomes faulty and delivers incorrect time than when it +simply stops operating, since an NTP-synchronized host normally can +coast for hours or even days without its clock accumulating serious +error over one second, for instance. Selecting at least three sources +from different operating administrations, where possible, is the minimum +recommended, although a lesser number could provide acceptable service +with a degraded degree of robustness. + +Normally, it is not considered good practice for a single workstation to +request synchronization from a primary (stratum-1) time server. At +present, these servers provide synchronization for hundreds of clients +in many cases and could, along with the network access paths, become +seriously overloaded if large numbers of workstation clients requested +synchronization directly. Therefore, workstations located in sparsely +populated administrative domains with no local synchronization +infrastructure should request synchronization from nearby stratum-2 +servers instead. In most cases the keepers of those servers listed in +the clock.txt file provide unrestricted access without prior permission; +however, in all cases it is considered polite to notify the +administrator listed in the file upon commencement of regular service. +In all cases the access mode and notification requirements listed in the +file must be respected. + +In the case of a gateway or file server providing service to a +significant number of workstations or file servers in an enterprise +network it is even more important to provide multiple, redundant sources +of synchronization and multiple, diversity-routed, network access paths. +The preferred configuration is at least three administratively +coordinated time servers providing service throughout the administrative +domain including campus networks and subnetworks. Each of these should +obtain service from at least two different outside sources of +synchronization, preferably via different gateways and access paths. +These sources should all operate at the same stratum level, which is one +less than the stratum level to be used by the local time servers +themselves. In addition, each of these time servers should peer with all +of the other time servers in the local administrative domain at the +stratum level used by the local time servers, as well as at least one +(different) outside source at this level. This configuration results in +the use of six outside sources at a lower stratum level (toward the +primary source of synchronization, usually a radio clock), plus three +outside sources at the same stratum level, for a total of nine outside +sources of synchronization. While this may seem excessive, the actual +load on network resources is minimal, since the interval between polling +messages exchanged between peers usually ratchets back to no more than +one message every 17 minutes. + +The stratum level to be used by the local time servers is an engineering +choice. As a matter of policy, and in order to reduce the load on the +primary servers, it is desirable to use the highest stratum consistent +with reliable, accurate time synchronization throughout the +administrative domain. In the case of enterprise networks serving +hundreds or thousands of client file servers and workstations, +conventional practice is to obtain service from stratum-1 primary +servers such as listed in the clock.txt file. When choosing sources away +from the primary sources, the particular synchronization path in use at +any time can be verified using the ntptrace program included in the +xntp3 distribution. It is important to avoid loops and possible common +points of failure when selecting these sources. Note that, while NTP +detects and rejects loops involving neighboring servers, it does not +detect loops involving intervening servers. In the unlikely case that +all primary sources of synchronization are lost throughout the subnet, +the remaining servers on that subnet can form temporary loops and, if +the loss continues for an interval of many hours, the servers will drop +off the subnet and free-run with respect to their internal (disciplined) +timing sources. + +In many cases the purchase of one or more radio clocks is justified, in +which cases good engineering practice is to use the configurations +described above and connect the radio clock to one of the local servers. +This server is then encouraged to participate in a special primary- +server subnetwork in which each radio-equipped server peers with several +other similarly equipped servers. In this way the radio-equipped server +may provide synchronization, as well as receive synchronization, should +the local or remote radio clock(s) fail or become faulty. Xntpd treats +attached radio clock(s) in the same way as other servers and applies the +same criteria and algorithms to the time indications, so can detect when +the radio fails or becomes faulty and switch to alternate sources of +synchronization. It is strongly advised, and in practice for most +primary servers today, to employ the authentication or access-control +features of the xntp3 distribution in order to protect against hostile +penetration and possible destabilization of the time service. + +Using this or similar strategies, the remaining hosts in the same +administrative domain can be synchronized to the three (or more) +selected time servers. Assuming these servers are synchronized directly +to stratum-1 sources and operate normally as stratum-2, the next level +away from the primary source of synchronization, for instance various +campus file servers, will operate at stratum 3 and dependent +workstations at stratum 4. Engineered correctly, such a subnet will +survive all but the most exotic failures or even hostile penetrations of +the various, distributed timekeeping resources. + +The above arrangement should provide very good, robust time service with +a minimum of traffic to distant servers and with manageable loads on the +local servers. While it is theoretically possible to extend the +synchronization subnet to even higher strata, this is seldom justified +and can make the maintenance of configuration files unmanageable. +Serving time to a higher stratum peer is very inexpensive in terms of +the load on the lower stratum server if the latter is located on the +same concatenated LAN. When justified by the accuracy expectations, NTP +can be operated in broadcast mode, so that clients need only listen for +periodic broadcasts and do not need to send anything. + +When planning your network you might, beyond this, keep in mind a few +generic don'ts, in particular: + +1. Don't synchronize a local time server to another peer at the same + stratum, unless the latter is receiving time from lower stratum + sources the former doesn't talk to directly. This minimizes the + occurance of common points of failure, but does not eliminate them + in cases where the usual chain of associations to the primary + sources of synchronization are disrupted due to failures. +2. Don't configure peer associations with higher stratum servers. Let + the higher strata configure lower stratum servers, but not the + reverse. This greatly simplifies configuration file maintenance, + since there is usually much greater configuration churn in the high + stratum clients such as personal workstations. + +3. Don't synchronize more than one time server in a particular + administrative domain to the same time server outside that domain. + Such a practice invites common points of failure, as well as raises + the possibility of massive abuse, should the configuration file be + automatically distributed do a large number of clients. + +There are many useful exceptions to these rules. When in doubt, however, +follow them. + +Dennis Ferguson writes: Note that mention was made of machines with +"good" clocks versus machines with "bad" ones. There are two things that +make a clock good, the precision of the clock (e.g. how many low order +bits in a time value are actually significant) and the frequency of +occurance (or lack thereof) of such things as lost clock interrupts. +Among the most common computers I have observed there to be a fairly +simple algorithm for determining the goodness of its clock. If the +machine is a Vax, it probably has a good clock (the low order bit in the +time is in the microseconds and most of these seem to manage to get +along without losing clock interrupts). If the machine is a Sun 3 it +probably doesn't (the low order clock bit is at the 10 or 20 millisecond +mark and Sun 3s like to lose clock interrupts, particularly if they have +a screen and particularly if they run SunOS 4.0.x). If you have IBM RTs +running AOS 4.3, they have fair clocks (low order clock bit at about a +millisecond and they don't lose clock interrupts, though they do have +trouble with clock rollovers while reading the low order clock bits) but +I recommend them as low stratum NTP servers anyway since they aren't +much use as anything else. Sun 4s running SunOS 4.1.1 make very good +time servers, once some native foolishness mentioned below is +surmounted. [However, it is very important to avoid using the keyboard +firmware, which can cause severe interrupt latencies, in favor of the +software drivers ordinarily used in conjunction with a windowing system. +- DLM] For other machines you are on your own since I don't have enough +data points to venture an opinion. In any event, if at all possible you +should try to use machines with good clocks for the lower strata. + +Configuring Your Server or Client + +As mentioned previously, the configuration file is usually called +/etc/ntp.conf. This is an ASCII file conforming to the usual comment and +whitespace conventions. A working configuration file might look like (In +this and other examples, do not copy this directly.): + + # peer configuration for 128.100.100.7 + # (expected to operate at stratum 2) + + server 128.4.1.1 # rackety.udel.edu + server 128.8.10.1 # umd1.umd.edu + server 192.35.82.50 # lilben.tn.cornell.edu + driftfile /etc/ntp.drift + +This particular host is expected to operate as a client at stratum 2 by +virtue of the "server" keyward and the fact that two of the three +servers declared (the first two, actually) have radio clocks and usually +run at stratum 1. The third server in the list has no radio clock, but +is known to maintain associations with a number of stratum 1 peers and +usually operates at stratum 2. Of particular importance with the last +host is that it maintains associations with peers besides the two +stratum 1 peers mentioned. This can be verified using the ntpq program +included in the xntp3 distribution. When configured using the "server" +keyword, this host can receive synchronization from any of the listed +servers, but can never provide synchronization to them. + +Unless restricted using facilities described later, this host can +provide synchronization to dependent clients, which do not have to be +listed in the configuration file. Associations maintained for these +clients are transitory and result in no persistent state in the host. +These clients are normally not visible using the ntpq program included +in the xntp3 distribution; however, xntpd includes a monitoring feature +(described later) which caches a minimal amount of client information +useful for debugging administrative purposes. + +A time server expected to both receive synchronization from another +server, as well as to provide synchronization to it, is delared using +the "peer" keyword instead of the "server" keyword. In all other aspects +the server operates the same in either mode and can provide +synchronization to dependent clients or other peers. It is considered +good engineering practice to declare time servers outside the +administrative domain as "peer" and those inside as "server" in order to +provide redundancy in the global Internet, while minimizing the +possibility of instability within the domain itself. A time server in +one domain can in principle heal another domain temporarily isolated +from all other sources of synchronization. However, it is probably +unwise for a casual workstation to bridge fragments of the local domain +which have become temporarily isolated. + +Note the inclusion of a "driftfile" declaration. One of the things the +NTP daemon does when it is first started is to compute the error in the +intrinsic frequency of the clock on the computer it is running on. It +usually takes about a day or so after the daemon is started to compute a +good estimate of this (and it needs a good estimate to synchronize +closely to its server). Once the initial value is computed, it will +change only by relatively small amounts during the course of continued +operation. The "driftfile" declaration indicates to the daemon the name +of a file where it may store the current value of the frequency error so +that, if the daemon is stopped and restarted, it can reinitialize itself +to the previous estimate and avoid the day's worth of time it will take +to recompute the frequency estimate. Since this is a desireable feature, +a "driftfile" declaration should always be included in the configuration +file. + +An implication in the above is that, should xntpd be stopped for some +reason, the local platform time will diverge from UTC by an amount that +depends on the intrinsic error of the clock oscillator and the time +since last synchronized. In view of the length of time necessary to +refine the frequency estimate, every effort should be made to operate +the daemon on a continuous basis and minimize the intervals when for +some reason it is not running. + +Xntpd3 Versus Previous Versions + +There are several items of note when dealing with a mixture of xntp3 and +and previous distributions of xntp (NTP Version 2 xntpd) and ntp3.4 (NTP +Version 1 ntpd). The xntp3 implementation of xntpd is an NTP Version 3 +implementation. As such, by default when no additional information is +available concerning the preferences of the peer, xntpd claims to be +version 3 in the packets that it sends. + +An NTP implementation conforming to a previous version specification +ordinarily discards packets from a later version. However, in most +respects documented in RFC 1305, the previous version is compatible with +the version-3 algorithms and protocol. Ntpd, while implementing most of +the version-2 algorithms, still believes itself to be a version-1 +implementation. The sticky part here is that, when either xntpd version +2 or ntpd version 1 receives a packet claiming to be from a version-3 +server, it discards it without further processing. Hence there is a +danger that in some situations synchronization with previous versions +will fail. + +Xntpd is aware of this problem. In particular, when xntpd is polled +first by a host claiming to be a previous version 1 or version 2 +implementation, xntpd claims to be a version 1 or 2 implementation, +respectively, in packets returned to the poller. This allows xntpd to +serve previous version clients transparently. The trouble occurs when an +previous version is to be included in an xntpd configuration file. With +no further indication, xntpd will send packets claiming to be version 3 +when it polls. To get around this, xntpd allows a qualifier to be added +to configuration entries to indicate which version to use when polling. +Hence the entry + + # specify NTP version 1 + + peer 130.43.2.2 version 1 # apple.com (running ntpd version 1) + peer 130.43.2.2 version 2 # apple.com (running xntpd version 2) + +will cause version 1 packets to be sent to the host address 130.43.2.2. +If you are testing xntpd against previous version servers you will need +to be careful about this. Note that, as indicated in the RFC 1305 +specification, there is no longer support for the original NTP +specification, popularly called NTP Version 0. + +There are a few other items to watch when converting an ntpd +configuration file for use with xntpd. The first is to reconsider the +precision entry from the configuration file, if there is one. There was +a time when the precision claimed by a server was mostly commentary, +with no particularly useful purpose. This is no longer the case, +however, and so changing the precision a server claims should only be +done with some consideration as to how this alters the performance of +the server. The default precision claimed by xntpd will be right for +most situations. A section later on will deal with when and how it is +appropriate to change a server's precision without doing things you +don't intend. + +Second, note that in the example configuration file above numeric +addresses are used in the peer and server declarations. It is also +possible to use names requiring resolution instead, but only if some +additional configuration is done (xntpd doesn't include the resolver +routines itself, and requires that a second program be used to do name +resolution). If you find numeric addresses offensive, see below. + +Finally, "passive" and "client" entries in an ntpd configuration file +have no useful equivalent semantics for xntpd and should be deleted. +Xntpd won't reset the kernel variable tickadj when it starts, so you can +remove anything dealing with this in the configuration file. The +configuration of radio clock peers is done using different language in +xntpd configuration files, so you will need to delete these entries from +your ntpd configuration file and see below for the equivalent language. + +Traffic Monitoring + +Xntpd handles peers whose stratum is higher than the stratum of the +local server and pollers using client mode by a fast path which +minimizes the work done in responding to their polls, and normally +retains no memory of these pollers. Sometimes, however, it is +interesting to be able to determine who is polling the server, and how +often, as well as who has been sending other types of queries to the +server. + +To allow this, xntpd implements a traffic monitoring facility which +records the source address and a minimal amount of other information +from each packet which is received by the server. This can be enabled by +adding the following line to the server's configuration file: + + # enable monitoring feature + + monitor yes + +The recorded information can be displayed using the xntpdc query +program, described briefly below. + +Address-and-Mask Restrictions + +The address-and-mask configuration facility supported by xntpd is quite +flexible and general, but is not an integral part of the NTP Version 3 +specification. The major drawback is that, while the internal +implementation is very nice, the user interface sucks. For this reason +it is probably worth doing an example here. Briefly, the facility works +as follows. There is an internal list, each entry of which holds an +address, a mask and a set of flags. On receipt of a packet, the source +address of the packet is compared to each entry in the list, with a +match being posted when the following is true: + + (source_addr & mask) == (address & mask) + +A particular source address may match several list entries. In this case +the entry with the most one bits in the mask is chosen. The flags +associated with this entry are used to control the access. + +In the current implementation the flags always add restrictions. In +effect, an entry with no flags set leaves matching hosts unrestricted. +An entry can be added to the internal list using a "restrict" +declaration. The flags associated with the entry are specified +textually. For example, the "notrust" flag indicates that hosts matching +this entry, while treated normally in other respects, shouldn't be +trusted to provide synchronization even if otherwise so enabled. The +"nomodify" flag indicates that hosts matching this entry should not be +allowed to do run time configuration. There are many more flags, see the +xntpd.8 man page. + +Now the example. Suppose you are running the server on a host whose +address is 128.100.100.7. You would like to ensure that run time +reconfiguration requests can only be made from the local host and that +the server only ever synchronizes to one of a pair of off-campus servers +or, failing that, a time source on net 128.100. The following entries in +the configuration file would implement this policy: + + # by default, don't trust and don't allow modifications + + restrict default notrust nomodify + + # these guys are trusted for time, but no modifications allowed + + restrict 128.100.0.0 mask 255.255.0.0 nomodify + restrict 128.8.10.1 nomodify + restrict 192.35.82.50 nomodify + + # the local addresses are unrestricted + + restrict 128.100.100.7 + restrict 127.0.0.1 + +The first entry is the default entry, which all hosts match and hence +which provides the default set of flags. The next three entries indicate +that matching hosts will only have the nomodify flag set and hence will +be trusted for time. If the mask isn't specified in the restrict +keyward, it defaults to 255.255.255.255. Note that the address +128.100.100.7 matches three entries in the table, the default entry +(mask 0.0.0.0), the entry for net 128.100 (mask 255.255.0.0) and the +entry for the host itself (mask 255.255.255.255). As expected, the flags +for the host are derived from the last entry since the mask has the most +bits set. + +The only other thing worth mentioning is that the restrict declarations +apply to packets from all hosts, including those that are configured +elsewhere in the configuration file and even including your clock +pseudopeer(s), in any. Hence, if you specify a default set of +restrictions which you don't wish to be applied to your configured +peers, you must remove those restrictions for the configured peers with +additional restrict declarations mentioning each peer separately. + +Authentication + +Xntpd supports the optional authentication procedure specified in the +NTP Version 2 and 3 specifications. Briefly, when an association runs in +authenticated mode, each packet transmitted has appended to it a 32-bit +key ID and a 64-bit crypto checksum of the contents of the packet +computed using either the Data Encryption Standard (DES) or Message +Digest (MD5) algorithms. Note that while either of these algorithms +provide sufficient protection from message-modification attacks, +distribution of the former algorithm implementation is restricted to the +U.S. and Canada, while the latter presently is free from such +restrictions. With either algorithm the receiving peer recomputes the +checksum and compares it with the one included in the packet. For this +to work, the peers must share at least one encryption key and, +furthermore, must associate the shared key with the same key ID. + +This facility requires some minor modifications to the basic packet +processing procedures, as required by the specification. These +modifications are enabled by the "authenticate" configuration +declaration. In particular, in authenticated mode, peers which send +unauthenticated packets, peers which send authenticated packets which +the local server is unable to decrypt and peers which send authenticated +packets encrypted using a key we don't trust are all marked +untrustworthy and unsuitable for synchronization. Note that, while the +server may know many keys (identified by many key IDs), it is possible +to declare only a subset of these as trusted. This allows the server to +share keys with a client which requires authenticated time and which +trusts the server but which is not trusted by the server. Also, some +additional configuration language is required to specify the key ID to +be used to authenticate each configured peer association. Hence, for a +server running in authenticated mode, the configuration file might look +similar to the following: + + # peer configuration for 128.100.100.7 + # (expected to operate at stratum 2) + # fully authenticated this time + + peer 128.100.49.105 key 22 # suzuki.ccie.utoronto.ca + peer 128.8.10.1 key 4 # umd1.umd.edu + peer 192.35.82.50 key 6 # lilben.tn.cornell.edu + authenticate yes # enable authentication + keys /usr/local/bin/ntp.keys # path for key file + trustedkey 1 2 14 15 # define trusted keys + requestkey 15 # key (7) for accessing server variables + controlkey 15 # key (6) for accessing server variables + + #authdelay 0.000047 # authentication delay (Sun4c/50 IPX DES) + authdelay 0.000094 # authentication delay (Sun4c/50 IPX MD5) + +There are a couple of previously unmentioned things in here. The +"authenticate yes" line enables authentication processing, while the +"keys /usr/local/bin/ntp.keys" specifies the path to the keys file (see +below and the xntpd.8 man page for detaiils of the file format). The +"trustedkey" declaration identifies those keys that are known to be +uncompromised; the remainder presumably represent the expired or +possibly compromised keys. Both sets of keys must be declared by key +identifier in the ntp.keys file described below. This provides a way to +retire old keys while minimrequestkey 15izing the frequency of delicate +key-distribution procedures. The "requestkey 15" line establishes the +key to be used for mode-6 control messages as specified in RFC 1305 and +used by the ntpq utility program, while the "controlkey 15" establishes +the key to be used for mode-7 private control messages used by the +xntpdc utility program these keys are used to prevent unauthorized +modification of daemon variables. + +The "authdelay" declaration is an estimate of the amount of processing +time taken between the freezing of a transmit timestamp and the actual +transmission of the packet when authentication is enabled (i.e. more or +less the time it takes for the DES or MD5 routine to encrypt a single +block), and is used as a correction for the transmit timestamp. This can +be computed for your CPU by the authspeed program included in the +authstuff directory in the xntp3 distribution. The usage is illustrated +to the following: + + # for DES keys + + authspeed -n 30000 auth.samplekeys + + # for MD5 keys + + authspeed -nd 30000 auth.samplekeys + +Additional utility programs included in the authstuff directory can be +used to generate random keys, certify implementation correctness and +display sample keys. As a general rule, keys should be chosen randomly, +except possibly the request and control keys, which must be entered by +the user as a password. + +The ntp.keys file contains the list of keys and associated key IDs the +server knows about (for obvious reasons this file is better left +unreadable by anyone except the server). The contents of this file might +look like: + + # ntp keys file (ntp.keys) + + 1 N 29233E0461ECD6AE # des key in NTP format + 2 M RIrop8KPPvQvYotM # md5 key as an ASCII random string + 14 M sundial # md5 key as an ASCII string + 15 A sundial # des key as an ASCII string + + # the following 3 keys are identical + + 10 A SeCReT + 10 N d3e54352e5548080 + 10 S a7cb86a4cba80101 + +In the keys file the first token on each line indicates the key ID, the +second token the format of the key and the third the key itself. There +are four key formats. An "A" indicates a DES key written as a 1-to-8 +character string in 7-bit ASCII representation, with each character +standing for a key octet (like a Unix password). An "S" indicates a DES +key written as a hex number in the DES standard format, with the low +order bit (LSB) of each octet being the (odd) parity bit. An "N" +indicates a DES key again written as a hex number, but in NTP standard +format with the high order bit of each octet being the (odd) parity bit +(confusing enough?). An "M" indicates an MD5 key written as a 1-to-31 +character ASCII string in the "A" format. Note that, because of the +simple tokenizing routine, the characters ' ', '#', '\t', '\n' and '\0' +can't be used in either a DES or MD5 ASCII key. Everything else is fair +game, though. Key 0 (zero) is used for special purposes and should not +appear in this file. + +The big trouble with the authentication facility is the keys file. It is +a maintenance headache and a security problem. This should be fixed some +day. Presumably, this whole bag of worms goes away if/when a generic +security regime for the Internet is established. + +Query Programs + +Three utility query programs are included with the xntp3 distribution, +ntpq, ntptrace and xntpdc. Ntpq is a rather handy program which sends +queries and receives responses using NTP standard mode-6 control +messages. Since it uses the standard control protocol specified in RFC +1305, it may be used with NTP Version 2 and Version 3 implementations +for both Unix and Fuzzball, but not Version 1 implementations. It is +most useful to query remote NTP implementations to assess timekeeping +accuracy and expose bugs in configuration or operation. + +Ntptrace can be used to display the current synchronization path from a +selected host through possibly intervening servers to the primary source +of synchronization, usually a radio clock. It works with both version 2 +and version 3 servers, but not version 1. + +Xnptdc is a horrid program which uses NTP private mode-7 control +messages to query local or remote servers. The format and and contents +of these messages are specific to xntpd. The program does allow +inspection of a wide variety of internal counters and other state data, +and hence does make a pretty good debugging tool, even if it is +frustrating to use. The other thing of note about xntpdc is that it +provides a user interface to the run time reconfiguration facility. + +See the respective man pages for details on the use of these programs. +The primary reason for mentioning them here is to point out an +inconsistancy which can be awfully annoying if it catches you, and which +is worth keeping firmly in mind. Both xntpdc and xntpd demand that +anything which has dimensions of time be specified in units of seconds, +both in the configuration file and when doing run time reconfiguration. +Both programs also print the values in seconds. Ntpq on the other hand, +obeys the standard by printing all time values in milliseconds. This +makes the process of looking at values with ntpq and then changing them +in the configuration file or with xntpdc very prone to errors (by three +orders of magnitude). I wish this problem didn't exist, but xntpd and +its love of seconds predate the mode-6 protocol and the latter's +(Fuzzball-inspired) millisecond orientation, making the inconsistancy +irresolvable without considerable work. + +Run Time Reconfiguration + +Xntpd was written specifically to allow its configuration to be fully +modifiable at run time. Indeed, the only way to configure the server is +at run time. The configuration file is read only after the rest of the +server has been initialized into a running, but default unconfigured, +state. This facility was included not so much for the benefit of Unix, +where it is handy but not strictly essential, but rather for dedicated +platforms where the feature is more important for maintenance. +Nevertheless, run time configuration works very nicely for Unix servers +as well. + +Nearly all of the things it is possible to configure in the +configuration file may be altered via NTP mode-7 messages using the +xntpdc program. Mode-6 messages may also provide some limited +configuration functionality (though the only thing you can currently do +with mode-6 messages is set the leap-second warning bits) and the ntpq +program provides generic support for the latter. The leap bits that can be +set in the leap_warning variable (up to one month ahead) and in the +leap_indication variable have a slighly different encoding than the +usual interpretation: + + Value Action + 00 The daemon passes the leap bits of its + synchronisation source (usual mode of operation) + 01/10 A leap second is added/deleted + 11 Leap information from the sychronisation source + is ignored (thus LEAP_NOWARNING is passed on) + +Mode-6 and mode-7 messages which would modify the configuration of the +server are required to be authenticated using standard NTP +authentication. To enable the facilities one must, in addition to +specifying the location of a keys file, indicate in the configuration +file the key IDs to be used for authenticating reconfiguration commands. +Hence the following fragment might be added to a configuration file to +enable the mode-6 (ntpq) and mode-7 (xntpdc) facilities in the daemon: + + # specify mode-6 and mode-7 trusted keys + + requestkey 65535 # for mode-7 requests + controlkey 65534 # for mode-6 requests + +If the "requestkey" and/or the "controlkey" configuration declarations +are omitted from the configuration file, the corresponding run time +reconfiguration facility is disabled. + +The query programs require the user to specify a key ID and a key to use +for authenticating requests to be sent. The key ID provided should be +the same as the one mentioned in the configuration file, while the key +should match that corresponding to the key ID in the keys file. As the +query programs prompt for the key as a password, it is useful to make +the request and control authentication keys typable (in ASCII format) +from the keyboard. + +Name Resolution + +Xntpd includes the cability to specify host names requiring resolution +in "peer" and "server" declarations in the configuration file. There are +several reasons why this was not permitted in the past. Chief among +these is the fact that name service is unreliable and the interface to +the Unix resolver routines is synchronous. The hangups and delays +resulting from name-resolver clanking can be unacceptable once the NTP +server is running (and remember it is up and running before the +configuration file is read). However, it is advantageous to resolve time +server names, since their addresses are occasionally changed. + +Instead of running the resolver itself the daemon can defer this task to +a separate program, xntpres. When the daemon comes across a "peer" or +"server" entry with a non-numeric host address it records the relevant +information in a temporary file and continues on. When the end of the +configuration file has been reached and one or more entries requiring +name resolution have been found, the server runs an instance of xntpres +with the temporary file as an argument. The server then continues on +normally but with the offending peers/servers omitted from its +configuration. + +When xntpres successfully resolves a name from this file, it configures +the associated entry into the server using the same mode-7 run time +reconfiguration facility that xntpdc uses. If temporary resolver +failures occur, xntpres will periodically retry the offending requests +until a definite response is received. The program will continue to run +until all entries have been resolved. +There are several configuration requirements if xntpres is to be used. +The path to the xntpres program must be made known to the daemon via a +"resolver" configuration entry, and mode-7 run time reconfiguration must +be enabled. The following fragment might be used to accomplish this: + + # specify host name resolver data + + resolver /local/etc/xntpres + keys /etc/ntp.keys + requestkey 65535 + +Note that xntpres sends packets to the server with a source address of +127.0.0.1. You should obviously avoid "restrict" modification requests +from this address or xntpres will fail. + +Dealing with Frequency Tolerance Violations (Tickadj and Friends) + +The NTP Version 3 specification RFC 1305 calls for a maximum oscillator +frequency tolerance of +-100 parts-per-million (ppm), which is +representative of those components suitable for use in relatively +inexpensive workstation platforms. For those platforms meeting this +tolerance, NTP will automatically compensate for the frequency errors of +the individual oscillator and no further adjustments are required, +either to the configuration file or to various kernel variables. + +However, in the case of certain notorious platforms, in particular Sun +4s, the 100-ppm tolerance is routinely violated. In such cases it may be +necessary to adjust the values of certain kernel variables; in +particular, "tick" and "tickadj". The variable tick is the increment in +microseconds added to the system time on each interval-timer interrupt, +while the variable tickadj is used by the time adjustment code as a slew +rate. When the time is being adjusted via a call to the system routine +adjtime(), the kernel increases or reduces tick by tickadj microseconds +until the specified adjustment has been completed. Unfortunately, in +most Unix implementations the tick increment must be either zero or +plus/minus exactly tickadj microseconds, meaning that adjustments are +truncated to be an integral multiple of tickadj (this latter behaviour +is a misfeature, and is the only reason the xntpd code needs to concern +itself with the internal implementation of adjtime() at all). In +addition, the stock Unix implementation considers it an error to request +another adjustment before a prior one has completed. + +Thus, to make very sure it avoids problems related to the roundoff, the +xntpd daemon reads the values of tick and tickadj from /dev/kmem when it +starts. It then ensures that all adjustments given to adjtime() are an +even multiple of tickadj microseconds and computes the largest +adjustment that can be completed in the adjustment interval (using both +the value of tickadj and the value of tick) so it can avoid exceeding +this limit. + +Unfortunately, the value of tickadj set by default is almost always too +large for xntpd. NTP operates by continuously making small adjustments +to the clock, usually at one-second intervals. If tickadj is set too +large, the adjustments will disappear in the roundoff; while, if tickadj +is too small, NTP will have difficulty if it needs to make an occasional +large adjustment. While the daemon itself will read the kernel's values +of tick and tickadj, it will not change the values, even if they are +unsuitable. You must do this yourself before the daemon is started, +either with adb or, in the running kernel only, with the tickadj program +included in the util directory of the xntp3 distribution. Note that the +latter program will also computes an optimal value of tickadj for NTP +use based on the kernel's value of tick. + +The tickadj program can reset several other kernel variables if asked. +It can also change the value of tick if asked, this being necessary on a +few machines with very broken clocks, like Sun 4s. With these machines +it should also set the value of the kernel dosynctodr variable to zero. +This variable controls whether to synchronize the system clock to the +time-of-day clock, something you really don't want to be happen when +xntpd is trying to keep it under control. + +In order to maintain reasonable correctness bounds, as well as +reasonably good accuracy with acceptable polling intervals, xntpd will +complain if the frequency error is greater than 100 ppm. For machines +with a value of tick in the 10-ms range, a change of one in the value of +tick will change the frequency by about 100 ppm. In order to determine +the value of tick for a particular CPU, disconnect the machine from all +sources of time (dosynctodr = 0) and record its actual time compared to +an outside source (eyeball-and-wristwatch will do) over a day or more. +Multiply the time change over the day by 0.116 and add or subtract the +result to tick, depending on whether the CPU is fast or slow. An example +call to tickadj useful on Sun 4s is: + + tickadj -t 9999 -a 5 -s + +which sets tick 100 ppm fast, tickadj to 5 microseconds and turns off +the clock/calendar chip fiddle. This line can be added to the rc.local +configuration file to automatically set the kernel variables at boot +time. + +All this stuff about diddling kernel variables so the NTP daemon will +work is really silly. If vendors would ship machines with clocks that +kept reasonable time and would make their adjtime() system call apply +the slew it is given exactly, independent of the value of tickadj, all +this could go away. + +Tuning Your Subnet + +There are several parameters available for tuning the NTP subnet for +maximum accuracy and minimum jitter. Two important parameters are the +the "precision" and "prefer" configuration declarations. The precision +declaration specifies the number of significant bits of the system clock +representation relative to one second. For instance, the default value +of -6 corresponds to 1/64 second or about 16 milliseconds. + +The NTP protocol makes use of the precision parameter in several places. +It is included in packets sent to peers and is used by them to calculate +the maximum absolute error and maximum statistical error. When faced +with selecting one of several servers of the same stratum and about the +same network path delay for synchronization purposes, clients will +usually prefer to synchronize to those servers claiming the smallest +(most negative) precision, since this maximizes the accuracy and +minimizes the jitter apparent to application programs running on the +client platform. Therefore, when the maximum attainable accuracy is +required, it is important that every platform configure an accurate +value for the precision variable. This can be done using the optional +"precision" declaration in the configuration file: + + # precision declaration + + precision -18 # for microsecond clocks (Sun 4s, DEC 5000/240) + +When more than one eligible server exists, the NTP clock-selection and +combining algorithms act to winnow out all except the "best" set of +servers using several criteria based on differences between the readings +of different servers and between successive readings of the same server. +The result is usually a set of surviving servers that are apparently +statistically equivalent in accuracy, jitter and stability. The +population of survivors remaining in this set depends on the individual +server characteristics measured during the selection process and may +vary from time to time as the result of normal statistical variations. +In LANs with high speed RISC-based time servers, the population can +become somewhat unstable, with individual servers popping in and out of +the surviving population, generally resulting in a regime called +clockhopping. + +When only the smallest residual jitter can be tolerated, it may be +convenient to elect one of the servers at each stratum level as the +preferred one using the keyword "prefer" on the configuration +declaration for the selected server: + + # prefered server declaration + + peer 128.4.1.1 prefer # preferred server + +The preferred server will always be included in the surviving +population, regardless of its characteristics and as long as it survives +preliminary sanity checks and validation procedures. + +The most useful application of the prefer keyword is in high speed LANs +equipped with precision radio clocks, such as a GPS receiver. In order +to insure robustness, the hosts need to include outside peers as well as +the GPS-equipped server; however, as long as that server is running, the +synchronization preference should be that server. The keyword should +normally be used in all cases in order to prefer an attached radio +clock. It is probably inadvisable to use this keyword for peers outside +the LAN, since it interferes with the carefully crafted judgement of the +selection and combining algorithms. + +Provisions for Leap Seconds and Accuracy Metrics + +Xntpd understands leap seconds and will attempt to take appropriate +action when one occurs. In principle, every host running xntpd will +insert a leap second in the local timescale in precise synchronization +with UTC. This requires that the leap-warning bits be manually activated +some time prior to the occurance of a leap second at the primary +(stratum 1) servers. Subsequently, these bits are propagated throughout +the subnet depending on these servers by the NTP protocol itself and +automatically implemented by xntpd and the time-conversion routines of +each host. The implementation is independent of the idiosyncracies of +the particular radio clock, which vary widely among the various devices, +as long as the idiosyncratic behavior does not last for more than about +20 minutes following the leap. Provisions are included to modify the +behavior in cases where this cannot be guaranteed. + +While provisions for leap seconds have been carefully crafted so that +correct timekeeping immediately before, during and after the occurance +of a leap second is scrupulously correct, stock Unix systems are mostly +inept in responding to the available information. This caveat goes also +for the maximum-error and statistical-error bounds carefully calculated +for all clients and servers, which could be very useful for application +programs needing to calibrate the delays and offsets to achieve a near- +simulataneous commit procedure, for example. While this information is +maintained in the xntpd data structures, there is at present no way for +application programs to access it. This may be a topic for further +development. + +Clock Support Overview + +Xntpd was designed to support radio (and other external) clocks and does +some parts of this function with utmost care. Clocks are treated by the +protocol as ordinary NTP peers, even to the point of referring to them +with an (invalid) IP host address. Clock addresses are of the form +127.127.t.u, where t specifies the particular type of clock (i.e. refers +to a particular clock driver) and u is a unit number whose +interpretation is clock-driver dependent. This is analogous to the use +of major and minor device numbers by Unix and permits multiple +instantiations of clocks of the same type on the same server, should +such magnificant redundancy be required. + +Because clocks look much like peers, both configuration file syntax and +run time reconfiguration commands can be be used to control clocks in +the same way as ordinary peers. Clocks are configured via "server" +declarations in the configuration file, can be started and stopped using +xntpdc and are subject to address-and-mask restrictions much like a +normal peer, should this stretch of imagination ever be useful. As a +concession to the need to sometimes transmit additional information to +clock drivers, an additional configuration file is available: the +"fudge" statement. This enables one to specify the values two time +quantities, two integral values and two flags, the use of which is +dependent on the particular clock driver. For example, to configure a +PST radio clock which can be accessed through the serial device +/dev/pst1, with propagation delays to WWV and WWVH of 7.5 and 26.5 +milliseconds, respectively, on a machine with an imprecise system clock +and with the driver set to disbelieve the radio clock once it has gone +30 minutes without an update, one might use the following configuration +file entries: + + # radio clock fudge fiddles + + server 127.127.3.1 + fudge 127.127.3.1 time1 0.0075 time2 0.0265 + fudge 127.127.3.1 value2 30 flag1 1 + +Additional information on the interpretation of these data with respect +to various radio clock drivers is given in the xntpd.8 man page. + +Towards the Ultimate Tick + +This section consideres issues in providing precision time +synchronization in NTP subnets which need the highest quality time +available in the present technology. These issues are important in +subnets supporting real-time services such as distributed multimedia +conferencing and wide-are experiment control and monitoring. + +In the Internet of today synchronization paths often span continents and +oceans with moderate to high variations in delay due to traffic spasms. +NTP is specifically designed to minimize timekeeping jitter due to delay +variations using intricately crafted filtering and selection algorithms; +however, in cases where these variations are as much as a second or +more, the residual jitter following these algorithms may still be +excessive. Sometimes, as in the case of some isolated NTP subnets where +a local source of precision time is available, such as a 1-pps signal +produced by a calibrated cesium clock, it is possible to remove the +jitter and retime the local clock oscillator of the NTP server. This has +turned out to be a useful feature to improve the synchronization quality +of time distributed in remote places where radio clocks are not +available. In these cases special features of the xntp3 distribution are +used together with the 1-pps signal to provide a jitter-free timing +signal, while NTP itself is used to provide the coarse timing and +resolve the seconds numbering. + +Most available radio clocks can provide time to an accuracy in the order +of milliseconds, depending on propagation conditions, local noise levels +and so forth. However, as a practical matter, all clocks can +occasionally display errors significantly exceeding nominal +specifications. Usually, the algorithms used by NTP for ordinary network +peers, as well as radio clock "peers" will detect and discard these +errors as discrepancies between the disciplined local clock oscillator +and the decoded time message produced by the radio clock. Some radio +clocks can produce a special 1-pps signal which can be interfaced to the +server platform in a number of ways and used to substantially improve +the (disciplined) clock oscillator jitter and wander characteristics by +at least an order of magnitude. Using these features it is possible to +achieve accuracies in the order of 100 microseconds with a fast RISC- +based platform. + +There are three ways to implement 1-pps support, depending on the radio +clock model, platform model and serial line interface. Each of these +requires circuitry to convert the TTL signal produced by most clocks to +the the EIA levels used by most serial interfaces. An example of a +device designed to do this is presented in the gadget subdirectory +included in the xntp3 distribtuion. Besides being useful for this +purpose, this device includes an inexpensive modem designed for use with +the Canadian CHU time/frequency radio station. + +In order to select the appropriate implementation, it is important to +understand the underlying 1-pps mechanism used by xntpd. The 1-pps +suport depends on a continuous source of 1-pps pulses used to calculate +an offset within +-500 milliseconds relative to the local clock. The +serial timecode produced by the radio or the time determined by NTP in +absence of the radio is used to adjust the local clock within +-128 +milliseconds of the actual time. As long as the local clock is within +this interval the 1-pps support is used to discipline the local clock +and the timecode used only to verify that the local clock is in fact +within the interval. Outside this interval the 1-pps support is disabled +and the timecode used directly to control the local clock. + +The first method of implementation uses a dedicated serial port and +either the bsd line discipline or System V streams module, which can be +found in the kernel directory of the xntp3 distribution. This method can +be used with any radio clock or in the absence of any clock. The line +discipline and streams modules take receive timestamps in the kernel, +specifically the interrupt routine of the serial port hardware driver. +Using this method the port is dedicated to serve the 1-pps signal and +cannot be used for other purposes. Instructions for implementing the +feature, which requires rebuilding the kernel, are included in the +modules themselves. Note that xndpd must be compiled with the -DPPSDEV +compiler switch in this case. There is an inherent error in this method +due to the latency of the interrupt system and remaining serial-line +protocol modules in the order of a millisecond with Sun 4s. While the +jitter in this latency is unavoidable, the systematic component can be +calibrated out using a special configuration declaration: + + # pps delay and baud rate + + pps delay .0017 baud 19200 # pps delay (ms) and baud rate + +Note that the delay defaults to zero and the baud to 38400. + +The second method uses mechanisms embedded in the radio clock driver, +which call the 1-pps support directly and do not require a dedicated +serial port. Currently, only the DCF77 (German radio time service) +driver uses this method. Instructions for implementing this are given in +README files in the xntp3 distribution. + +The third method and the most accurate and intrusive of all uses the +carrier-detect modem-control lead monitored by the serial port driver. +This method can be used with any radio clock and 1-pps interface +mentioned above. It requires in addition to a special streams module, +replacement of the kernel high resolution time-of-day clock routine. +This method is applicable only to Sun 4 platforms running SunOS 4.1.1 +and then only with either of the two onboard serial ports. It does not +work with other platforms, operating systems or external (SBus) serial +multiplexors. + +Swatting Bugs + +Let's say you have compiled and installed the code and put up an +apparently relevant configuration file. In many Unix systems the xntpd +daemon and utility programs (ntpq, ntptrace and xntpdc) are usually +installed in the /usr/local directory along with the key file +(ntp.keys), while the configuration file (ntp.conf) and drift file +(ntp.drift) are installed in the /etc directory. The daemon can is +usually started from the rc.local shell script at system boot time, but +could be started (and stopped) at other times for debugging, etc. How do +you verify that the daemon can form associations with remote peers and +verify correct synchronization? For this you need the ntpq utility +described in the ntpq.8 man page. + +After starting the daemon, run the ntpq program using the -n switch, +which will avoid possible distractions due to name resolutions. Use the +peer command to display a billboard showing the status of configured +peers and possibly other clients poking the daemon. After operating for +a few minutes, the display should be something like: + + remote refid st when poll reach delay offset disp +======================================================================== ++128.4.2.6 132.249.16.1 2 131 256 373 9.89 16.28 23.25 +*128.4.1.20 .WWVB. 1 137 256 377 280.62 21.74 20.23 +-128.8.2.88 128.8.10.1 2 49 128 376 294.14 5.94 17.47 ++128.4.2.17 .WWVB. 1 173 256 377 279.95 20.56 16.40 + +The hosts shown in the "remote" column should agree with the entries in +the configuration file, plus any peers not mentioned in the file at the +same or lower than your stratum that happen to be configured to peer +with you. The "refid" entry shows the current source of synchronization +for that peer, while the "st" reveals its stratum and the "poll" entry +the polling interval, in seconds. The "when" entry shows the time since +the peer was last heard, in seconds, while the "reach" entry shows the +status of the reachability register (see specification), which is in +octal format. The remaining entries show the latest delay, offset and +dispersion computed for the peer, in milliseconds. + +*** This section incomplete. Soon. + +status=0664 leap_none, sync_ntp, 6 events, event_peer/strat_chg +system="UNIX", leap=00, stratum=2, rootdelay=280.62, +rootdispersion=45.26, peer=11673, refid=128.4.1.20, +reftime=af00bb42.56111000 Fri, Jan 15 1993 4:25:38.336, poll=8, +clock=af00bbcd.8a5de000 Fri, Jan 15 1993 4:27:57.540, phase=21.147, +freq=13319.46, compliance=2 + +status=7414 reach, auth, sel_sync, 1 event, event_reach +srcadr=128.4.2.6, srcport=123, dstadr=128.4.2.7, dstport=123, keyid=1, +stratum=2, precision=-10, rootdelay=362.00, rootdispersion=21.99, +refid=132.249.16.1, +reftime=af00bb44.849b0000 Fri, Jan 15 1993 4:25:40.517, +delay= 9.89, offset= 16.28, dispersion=23.25, reach=373, valid=8, +hmode=2, pmode=1, hpoll=8, ppoll=10, leap=00, flash=0x0, +org=af00bb48.31a90000 Fri, Jan 15 1993 4:25:44.193, +rec=af00bb48.305e3000 Fri, Jan 15 1993 4:25:44.188, +xmt=af00bb1e.16689000 Fri, Jan 15 1993 4:25:02.087, +filtdelay= 16.40 9.89 140.08 9.63 9.72 9.22 10.79 122.99, +filtoffset= 13.24 16.28 -49.19 16.04 16.83 16.49 16.95 -39.43, +filterror= 16.27 20.17 27.98 31.89 35.80 39.70 43.61 47.52 + +ind assID status conf reach auth condition last_event cnt +=========================================================== + 1 11670 7414 no yes ok synchr. reachable 1 + 2 11673 7614 no yes ok sys.peer reachable 1 + 3 11833 7314 no yes ok outlyer reachable 1 + 4 11868 7414 no yes ok synchr. reachable 1 + +Parting Shots + +There are several undocumented programs which are useful if you are +trying to set up a clock. They can be found in the clockstuff directory +of the xntp3 distribution. The most useful of these is the propdelay +program, which can compute high frequency radio propagation delays +between any two points whose latitude and longitude are known. The +program understands something about the phenomena which allow high +frequency radio propagation to occur, and will generally provide a +better estimate than a calculation based on the great circle distance. +The other two programs in the directory are clktest, which allows one to +exercise the generic clock line discipline, and chutest, which runs the +basic reduction algorithms used by the daemon on data received from a +serial port. diff --git a/contrib/xntpd/doc/ntpdate.8 b/contrib/xntpd/doc/ntpdate.8 new file mode 100644 index 0000000000..05be737fd8 --- /dev/null +++ b/contrib/xntpd/doc/ntpdate.8 @@ -0,0 +1,185 @@ +''' $Header +''' +.de Sh +.br +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp +.if t .sp .5v +.if n .sp +.. +.de Ip +.br +.ie \\n.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +''' +''' Set up \*(-- to give an unbreakable dash; +''' string Tr holds user defined translation string. +''' Bell System Logo is used as a dummy character. +''' +.tr \(bs-|\(bv\*(Tr +.ie n \{\ +.ds -- \(bs- +.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch +.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch +.ds L" "" +.ds R" "" +.ds L' ' +.ds R' ' +'br\} +.el\{\ +.ds -- \(em\| +.tr \*(Tr +.ds L" `` +.ds R" '' +.ds L' ` +.ds R' ' +'br\} +.TH NTPDATE 8 LOCAL +.SH NAME +ntpdate - set the date and time via NTP +.SH SYNOPSIS +.B ntpdate +[ +.B -bdos +] [ +.B -a +.I key# +] [ +.B -e +.I authdelay +] [ +.B -k +.I keyfile +] [ +.B -p +.I samples +] [ +.B -t +.I timeout +] +server ... +.SH DESCRIPTION +.I Ntpdate +sets the local date and time by polling the Network Time Protocol +server(s) on the host(s) given as arguments to determine +the correct time. It must be run as root on the local host. A number +of samples are obtained from each of the servers specified and the +standard NTP clock filter and selection algorithms are applied to select +the best of these. Typically, +.I ntpdate +can be inserted in the +.I /etc/rc.local +startup up script to set the time of day at boot time and/or can be run +from time\-to\-time via +.IR cron (8). +Note that +.IR ntpdate 's +reliability and precision will improve dramatically with greater numbers +of servers. While a single server may be used, better performance and +greater resistance to insanity on the part of any one server +will be obtained by providing at least three or four servers, if not more. +.PP +Time adjustments are made by +.I ntpdate +in one of two ways. If +.I ntpdate +determines your clock is off by more than 0.5 seconds it will simply +step the time by calling +.IR settimeofday (2). +If the error is less than 0.5 seconds, however, it will by default slew +the clock's time via a call to +.IR adjtime (2) +with the offset. The latter technique is less disruptive and more +accurate when the offset is small, and works quite well when +.I ntpdate +is run by +.I cron (8) +every hour or two. The adjustment made in the latter +case is actually 50% larger than the measured offset since this will +tend to keep a badly drifting clock more accurate (at some expense to +stability, though this tradeoff is usually advantageous). At boot time, +however, it is usually better to always step the time. This can be forced +in all cases by specifying the +.B -b +switch on the command line. The +.B -s +switch tells +.I ntpdate +to log its actions via the +.IR syslog (3) +facility rather than to the standard output, a useful option when +running the program from +.IR cron (8). +.PP +The +.B -d +flag may be used to determine what +.I ntpdate +will do without it actually doing it. Information useful for general +debugging will also be printed. By default +.I ntpdate +claims to be an NTP version 2 implementation in its outgoing packets. As +some older software will decline to respond to version 2 queries, the +.B -o +switch can be used to force the program to poll as a version 1 implementation +instead. +.PP +The number of samples +.I ntpdate +acquires from each server can be set to between 1 and 8 inclusive +using the +.B -p +switch. The default is 4. The time it will spend waiting for a +response can be set using the +.B -t +switch, and will be rounded to a multiple of 0.2 seconds. The default +is 1 second, a value suitable for polling across a LAN. +.PP +.I Ntpdate +will authenticate its transactions if need be. The +.B -a +switch specifies that all packets should be authenticated using the +key number indicated. The +.B -k +switch allows the name of the file from which the keys may be read +to be modified from the default of +.I /etc/ntp.keys. +This file should be in the format described in +.IR xntpd (8). +The +.B -e +option allows the specification of an authentication processing delay, +in seconds (see +.IR xntpd (8) +for details). This number is usually small enough to be negligible for +.IR ntpdate 's +purposes, though specifying a value may improve timekeeping on very slow +CPU's. +.PP +.I Ntpdate +will decline to set the date if an NTP server daemon (e.g. +.IR xntpd (8)) +is running on the same host. When running +.I ntpdate +on a regular basis from +.IR cron (8) +as an alternative to running a daemon, doing so once every hour or two +will result in precise enough timekeeping to avoid stepping the clock. +.SH FILES +.nf +/etc/ntp.keys\0\0contains the encription keys used by \fIntpdate\fP. +.fi +.SH SEE ALSO +xntpd(8) +.SH HISTORY +Written by Dennis Ferguson at the University of Toronto +.SH BUGS +The technique used for improving accuracy by compensating for clock +oscillator errors sucks, but doing better would require the program +to save state from previous runs. diff --git a/contrib/xntpd/doc/ntpq.8 b/contrib/xntpd/doc/ntpq.8 new file mode 100644 index 0000000000..81aca09ac1 --- /dev/null +++ b/contrib/xntpd/doc/ntpq.8 @@ -0,0 +1,566 @@ +''' $Header +''' +.de Sh +.br +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp +.if t .sp .5v +.if n .sp +.. +.de Ip +.br +.ie \\n.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +''' +''' Set up \*(-- to give an unbreakable dash; +''' string Tr holds user defined translation string. +''' Bell System Logo is used as a dummy character. +''' +.tr \(bs-|\(bv\*(Tr +.ie n \{\ +.ds -- \(bs- +.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch +.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch +.ds L" "" +.ds R" "" +.ds L' ' +.ds R' ' +'br\} +.el\{\ +.ds -- \(em\| +.tr \*(Tr +.ds L" `` +.ds R" '' +.ds L' ` +.ds R' ' +'br\} +.TH NTPQ 8 LOCAL +.SH NAME +ntpq - standard Network Time Protocol query program +.SH SYNOPSIS +.B ntpq +[ +.B -inp +] [ +.B -c +.I command +] [ +.I host +] [ +.I ... +] +.SH DESCRIPTION +.I Ntpq +is used to query NTP servers which implement the recommended NTP +mode 6 control message format about current state and to request +changes in that state. The +program may be run either in interactive mode or controlled using +command line arguments. Requests to read and write arbitrary +variables can be assembled, with raw and pretty\-printed output +options being available. +.I Ntpq +can also obtain and print a list of peers in a common format +by sending multiple queries to the server. +.PP +If one or more request options is included on the command line when +.I ntpq +is executed, each of the requests will be sent to the NTP servers running +on each of the hosts given as command line arguments, or on +.I localhost +by default. If no request options are given, +.I ntpq +will attempt to read commands from the standard input and execute these +on the NTP server running on the first host given on the command line, again +defaulting to +.I localhost +when no other host is specified. +.I Ntpq +will prompt for commands if the standard input is a terminal device. +.PP +.I Ntpq +uses NTP mode 6 packets to communicate with the NTP server, and hence +can be used to query any compatable server on the network which permits +it. Note that since NTP is a UDP protocol this communication will be +somewhat unreliable, especially over large distances in terms of network +topology. +.I Ntpq +makes one attempt to retransmit requests, and will time requests out if +the remote host is not heard from within a suitable time out time. +.PP +Command line options are described following. Specifying a command +line option other than +.B -i +or +.B -n +will cause the specified query (queries) to be sent to the indicated +host(s) immediately. Otherwise, +.I ntpq +will attempt to read interactive format commands from the standard input. +.Ip -c 8 +The following argument is interpreted as an interactive format command +and is added to the list of commands to be executed on the specified +host(s). Multiple +.B -c +options may be given. +.Ip -i 8 +Force +.I ntpq +to operate in interactive mode. Prompts will be written to the +standard output and commands read from the standard input. +.Ip -n 8 +Output all host addresses in dotted\-quad numeric format rather than +converting to the canonical host names. +.Ip -p 8 +Print a list of the peers known to the server as well as a summary +of their state. This is equivalent to the \*(L"peers\*(R" interactive +command. +.SH INTERNAL COMMANDS +.PP +Interactive format commands consist of a keyword followed by zero +to four arguments. Only enough characters of the full keyword to +uniquely identify the command need be typed. The output of a command +is normally sent to the standard output, but optionally the output of +individual commands may be sent to a file by appending a \*(L">\*(R", +followed by a file name, to the command line. +.PP +A number of interactive format commands are executed entirely within the +.I ntpq +program itself and do not result in NTP mode 6 requests being sent +to a server. These are described following. +.PP +.B ? +[ +.I command_keyword +} +.PP +A \*(L"?\*(R" by itself will print a list of all the command keywords +known to this incarnation of +.IR ntpq . +A \*(L"?\*(R" followed by a command keyword will print funcation and +usage information about the command. This command is probably a better +source of information about +.I ntpq +than this manual page. +.PP +.B timeout +.I millseconds +.PP +Specify a time out period for responses to server queries. The default +is about 5000 milliseconds. Note that since +.I ntpq +retries each query once after a time out the total waiting time for a +time out will be twice the time out value set. +.PP +.B delay +.I milliseconds +.PP +Specify a time interval to be added to timestamps included in requests +which require authentication. This is used to enable (unreliable) server +reconfiguration over long delay network paths or between machines whose +clocks are unsynchronized. Actually the server does not now require +time stamps in authenticated requests, so this command may be obsolete. +.PP +.B host +.I hostname +.PP +Set the host to which future queries will be sent. +.I Hostname +may be either a host name or a numeric +address. +.PP +.B poll +[ +.I # +] [ +.B verbose +] +.PP +Poll the current server in client mode. The first argument is the +number of times to poll (default is 1) while the second argument may +be given to obtain a more detailed output of the results. This command +is currently just wishful thinking. +.PP +.B keyid +.I # +.PP +This command allows the specification of a key number to be used to +authenticate configuration requests. This must correspond to a +key number the server has been configured to use for this purpose. +.PP +.B passwd +.PP +This command prompts you to type in a password (which will not be +echoed) which will be used to authenticate configuration requests. The +password must correspond to the key configured for use by the NTP +server for this purpose if such requests are to be successful. +.PP +.B "hostnames yes|no" +.PP +If \*(L"yes\*(R" is specified, host names are printed in information +displays. If \*(L"no\*(R" is given, numeric addresses are printed +instead. The default is \*(L"yes\*(R" unless modified using the command +line +.B -n +switch. +.PP +.B raw +.PP +Causes all output from query commands is printed as received from the +remote server. The only formating/intepretation done on the data is +to transform nonascii data into a printable (but barely understandable) +form. +.PP +.B cooked +.PP +Causes output from query commands to be \*(L"cooked\*(R". Variables +which are recognized by the server will have their values reformatted +for human consumption. Variables which +.I ntpq +thinks should have a decodeable value but didn't are marked with a +trailing \*(L"?\*(R". +.PP +.B ntpversion +.B 1|2|3 +.PP +Sets the NTP version number which +.I ntpq +claims in packets. Defaults to 3, Note that mode 6 control messages (and modes, +for that matter) didn't exist in NTP version 1. There appear to be no +servers left which demand version 1. +.PP +.B authenticate +.B yes|no +.PP +Normally +.I ntpq +does not authenticate requests unless they are write requests. The command +.B authenticate yes +causes +.I ntpq +to send authentication with all requests it makes. Authenticated requests +causes some servers to handle requests slightly differently, and can +occasionally melt the CPU in fuzzballs if you turn authentication on before +doing a peer display. +.PP +.B addvars +.IR [=] [,...] +.B rmvars +.IR [,...] +.B clearvars +.PP +The data carried by NTP mode 6 messages consists of a list of items +of the form +.IP "" 8 += +.PP +where the \*(L"=\*(R" is ignored, and can be omitted, in requests +to the server to read variables. +.I Ntpq +maintains an internal list in which data to be included in control messages +can be assembled, and sent using +the +.B readlist +and +.B writelist +commands described below. The +.B addvars +command allows variables and their optional values to be added to the +list. If more than one variable is to be added, the list should be +comma\-separated and not contain white space. The +.B rmvars +command can be used to remove individual variables from the list, while +the +.B clearlist +command removes all variables from the list. +.PP +.B debug +.I more|less|off +.PP +Turns internal query program debugging on and off. +.PP +.B quit +.PP +Exit +.IR ntpq . +.SH CONTROL MESSAGE COMMANDS +.PP +Each peer known to an NTP server has a 16 bit integer +.I association +.I identifier +assigned to it. NTP control messages which carry peer variables +must identify the peer the values correspond to by including +its association ID. An association ID of 0 is special, and indicates +the variables are system variables, whose names are drawn from a +separate name space. +.PP +Control message commands result in one or more NTP mode 6 +messages being sent to the server, and cause the data returned to be +printed in some format. Most commands currently implemented send a single +message and expect a single response. The current exceptions are the +.B peers +command, which will send a preprogrammed series of messages to obtain +the data it needs, and the +.B mreadlist +and +.B mreadvar +commands, which will iterate over a range of associations. +.PP +.B associations +.PP +Obtains and prints a list of association identifiers and +peer statuses for in\-spec +peers of the server being queried. The list is printed in +columns. The first of these is an index numbering the associations +from 1 for internal use, the second the actual association identifier +returned by the server and the third the status word for the peer. This +is followed by a number of columns containing data decoded from the +status word. Note +that the data returned by the \*(L"associations\*(R" command is cached +internally in +.IR ntpq . +The index is then of use when dealing with stupid servers which use +association identifiers which are hard for humans to type, in that +for any subsequent commands which require an association identifier +as an argument, the form +.I &index +may be used as an alternative. +.PP +.B lassocations +.PP +Obtains and prints a list of association identifiers and peer statuses +for all associations for which the server is maintaining state. This +command differs from the +\*(L"associations\*(R" +command only for servers which retain state for out\-of\-spec client +associations (i.e. fuzzballs). Such associations are normally omitted +from the display when the +\*(L"associations\*(R" +command is used, but are included in the output of +\*(L"lassociations\*(R". +.PP +.B passociations +.PP +Prints association data concerning in\-spec peers from the internally cached +list of associations. This command performs +identically to the \*(L"associations\*(R" except that it displays the +internally stored data rather than making a new query. +.PP +.B lpassociations +.PP +Print data for all associations, including out\-of\-spec client +associations, from the internally cached list of associations. This command +differs from \*(L"passociations\*(R" only when dealing with fuzzballs. +.PP +.B pstatus +.I assocID +.PP +Sends a read status request to the server for the given association. +The names and values of the peer variables returned will be printed. Note +that the status word from the header is displayed preceding the variables, +both in hexidecimal and in pidgeon English. +.PP +.B readvar +[ +.I assocID +] [ +.IR [=] [,...] +] +.PP +Requests that the values of the specified variables be returned by the +server by sending a read variables request. If the association ID +is omitted or is given as zero the variables +are system variables, otherwise they +are peer variables and the values returned will be those +of the corresponding peer. Omitting the variable list will send a +request with no data which should induce the server to return a +default display. +.PP +.B rv +[ +.I assocID +] [ +.IR [=] [,...] +] +.PP +An easy\-to\-type short form for the +.B readvar +command. +.PP +.B writevar +.I assocID +.IR = [,...] +.PP +Like the +.B readvar +request, except the specified variables are written instead of read. +.PP +.B readlist +[ +.I assocID +] +.PP +Requests that the values of the variables in the internal variable +list be returned by the server. If the association ID is omitted +or is 0 the variables are assumed to be system variables. Otherwise +they are treated as peer variables. If the internal variable list +is empty a request is sent without data, which should induce the remote +server to return a default display. +.PP +.B rl +[ +.I assocID +] +.PP +An easy\-to\-type short form of the +.B readlist +command. +.PP +.B writelist +[ +.I assocID +] +.PP +Like the +.B readlist +request, except the internal list variables are written instead of +read. +.PP +.B mreadvar +.I assocID +.I assocID +[ +.IR [=] [,...] +] +.PP +Like the +.B readvar +command except the query is done for each of a range of (nonzero) +association IDs. This range is determined from the association list +cached by the most recent +.B associations +command. +.PP +.B mrv +.I assocID +.I assocID +[ +.IR [=] [,...] +] +.PP +An easy\-to\-type short form of the +.B mreadvar +command. +.PP +.B mreadlist +.I assocID +.I assocID +.PP +Like the +.B readlist +command except the query is done for each of a range of (nonzero) +association IDs. This range is determined from the association list +cached by the most recent +.B associations +command. +.PP +.B mrl +.I assocID +.I assocID +.PP +An easy\-to\-type short form of the +.B mreadlist +command. +.PP +.B clockvar +[ +.I assocID +] +[ +.IR [=] [,...] +] +.PP +Requests that a list of the server's clock variables be sent. Servers +which have a radio clock or other external synchronization will respond +positively to this. If the association identifier is omitted or zero +the request is for the variables of the \*(L"system clock\*(R" and will +generally get a positive response from all servers with a clock. If the +server treats clocks as pseudo\-peers, and hence can possibly have more than +one clock connected at once, referencing the appropriate +peer association ID will show the variables of a particular clock. Omitting +the variable list will cause the server to return a default variable display. +.PP +.B cv +[ +.I assocID +] +[ +.IR [=] [,...] +] +.PP +An easy\-to\-type short form of the +.B clockvar +command. +.PP +.B peers +.PP +Obtains a list of in\-spec peers of the server, along +with a summary of each peer's state. Summary information includes the address +of the remote peer, the reference ID (0.0.0.0 if the refID is unknown), +the stratum of the remote peer, the polling interval, +in seconds, the reachability +register, in octal, and the current estimated delay, offset and dispersion +of the peer, all in seconds. +.PP +The character in the left margin indicates the fate of this peer in the +clock selection process. The codes mean: discarded due to high stratum +and/or failed sanity checks; \*(L"x\*(R" designated falsticker by the +intersection algorithm; \*(L".\*(R" culled from the end of the candidate +list; \*(L"-\*(R" discarded by the clustering algorithmi; \*(L"+\*(R" +included in the final selection set; \*(L"#\*(R" selected for synchronizatio;n +but distance exceeds maximum; \*(L"*\*(R" selected for synchronization; and +\*(L"o\*(R" selected for synchronization, pps signal in use. +.PP +Note that since the +.B peers +command depends on the ability to parse the values in the +responses it gets it may fail to work from time to time with servers +which poorly control the data formats. +.PP +The contents of the host field may be one of four forms. It may be a host name, +an IP address, a reference clock implementation name with its parameter or +\*(L"REFCLK(, )\*(R". On \*(L"hostnames no\*(R" +only IP\-addresses will be displayed. +.PP +.B lpeers +.PP +Like +.BR peers , +except a summary of all associations for which the server is maintaining +state is printed. This can produce a much longer list of peers from +fuzzball servers. +.PP +.B opeers +.PP +An old form of the \*(L"peers\*(R" command with the reference ID +replaced by the local interface address. +.SH HISTORY +.PP +Written by Dennis Ferguson at the University of Toronto. +.SH BUGS +.PP +The +.B peers +command is non\-atomic and may occasionally result in spurious error +messages about invalid associations occuring and terminating the +command. +.PP +The timeout time is a fixed constant, which means you wait a long time +for time outs since it assumes sort of a worst case. The program +should improve the time out estimate as it sends queries to a particular +host, but doesn't. diff --git a/contrib/xntpd/doc/ntptrace.8 b/contrib/xntpd/doc/ntptrace.8 new file mode 100644 index 0000000000..fb93ebb4df --- /dev/null +++ b/contrib/xntpd/doc/ntptrace.8 @@ -0,0 +1,104 @@ +''' $Header +''' +.de Sh +.br +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp +.if t .sp .5v +.if n .sp +.. +.de Ip +.br +.ie \\n.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +''' +''' Set up \*(-- to give an unbreakable dash; +''' string Tr holds user defined translation string. +''' Bell System Logo is used as a dummy character. +''' +.tr \(bs-|\(bv\*(Tr +.ie n \{\ +.ds -- \(bs- +.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch +.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch +.ds L" "" +.ds R" "" +.ds L' ' +.ds R' ' +'br\} +.el\{\ +.ds -- \(em\| +.tr \*(Tr +.ds L" `` +.ds R" '' +.ds L' ` +.ds R' ' +'br\} +.TH NTPTRACE 8 LOCAL +.SH NAME +ntptrace - trace a chain of NTP hosts back to their master time source +.SH SYNOPSIS +.B ntptrace +[ +.B -vdn +] [ +.B -r +.I retries +] [ +.B -t +.I timeout +] [ +.I server +] +.SH DESCRIPTION +.I Ntptrace +determines where a given Network Time Protocol (NTP) server gets +its time from, and follows the chain of NTP servers back to their +master time source. +If given no arguments, it starts with ``localhost.'' +.PP +Here is an example of the output from +.IR ntptrace : +.RS 2 +.nf + +% ntptrace +localhost: stratum 4, offset 0.0019529, synch distance 0.144135 +server2.bozo.com: stratum 2, offset 0.0124263, synch distance 0.115784 +usndh.edu: stratum 1, offset 0.0019298, synch distance 0.011993, refid 'WWVB' + +.fi +.RE +On each line, the fields are (left to right): the host name, the +host's stratum, +the time offset between that host and the local host +(as measured by +.IR ntptrace ; +this is why it is not always zero for ``localhost''), +the host's ``synchronization distance,'' +and (only for stratum-1 servers) the reference clock ID. All times +are given in seconds. (Synchronization distance is a measure of the +goodness of the clock's time.) +.SH OPTIONS +.IP "\-d" 5 +Turns on some debugging output. +.IP "\-n" 5 +Turns off the printing of host names; instead, host IP addresses +are given. This may be necessary if a nameserver is down. +.IP "\-r retries" 5 +Sets the number of retransmission attempts for each host; default = 5. +.IP "\-t timeout" 5 +Sets the retransmission timeout (in seconds); default = 2. +.IP "\-v" 5 +Prints verbose information about the NTP servers. +.SH SEE ALSO +xntpd(8), xntpdc(8) +.SH BUGS +This program makes no attempt to improve accuracy by doing multiple +samples. diff --git a/contrib/xntpd/doc/tickadj.8 b/contrib/xntpd/doc/tickadj.8 new file mode 100644 index 0000000000..5fce0884f8 --- /dev/null +++ b/contrib/xntpd/doc/tickadj.8 @@ -0,0 +1,143 @@ +''' $Header +''' +.de Sh +.br +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp +.if t .sp .5v +.if n .sp +.. +.de Ip +.br +.ie \\n.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +''' +''' Set up \*(-- to give an unbreakable dash; +''' string Tr holds user defined translation string. +''' Bell System Logo is used as a dummy character. +''' +.tr \(bs-|\(bv\*(Tr +.ie n \{\ +.ds -- \(bs- +.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch +.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch +.ds L" "" +.ds R" "" +.ds L' ' +.ds R' ' +'br\} +.el\{\ +.ds -- \(em\| +.tr \*(Tr +.ds L" `` +.ds R" '' +.ds L' ` +.ds R' ' +'br\} +.TH TICKADJ 8 LOCAL +.SH NAME +tickadj - fiddle time\-related variables in the kernel +.SH SYNOPSIS +.B tickadj +[ +.B -Aqs +] [ +.B -a +.I new_tickadj +] [ +.B -t +.I new_tick +] +.SH DESCRIPTION +The +.I tickadj +program reads, and optionally modifies, several time\-keeping\-related +variables in the running kernel, via +.IR /dev/kmem . +The particular variables it is concerned with are +.IR tick , +which is the number of microseconds added to the system time during a +clock interrupt, +.IR tickadj , +which sets the slew rate and resolution used by the +.IR adjtime (2) +system call, and +.IR dosynctodr , +which indicates to the kernels on some machines whether they should internally +adjust the system clock to keep it in line with with time\-of\-day clock +or not. +.PP +By default, with no arguments, +.I tickadj +reads the variables of interest in the kernel and prints them. At the +same time it determines an \*(L"optimal\*(R" value for the value of the +.I tickadj +variable if the intent is to run the +.IR xntpd (8) +Network Time Protocol daemon, and prints this as well. Since the operation +of +.I tickadj +when reading the kernel mimics the operation of similar parts of the +.IR xntpd (8) +program fairly closely, this is useful for doing debugging of problems +with +.IR xntpd (8). +.PP +Various flags may be specified to change the variables of interest in +the running kernel. The +.B -a +flag allows one to set the the variable +.I tickadj +to the value specified as an argument. The +.B -A +flag will also cause +.I tickadj +to be modified, but instead will set it to the internally computed +\*(L"optimal\*(R" value. The +.B -t +flag may be used to reset the kernel's value of +.IR tick , +a capability which is useful on machines with very broken clocks. The +.B -s +flag tells the program to set the value of the variable +.I dosynctodr +to zero, a prerequisite for running the +.IR xntpd (8) +daemon under SunOS 4.0. Normally +.I tickadj +is quite verbose about what it is doing. The +.B -q +flag tells it to shut up about everything except errors. +.PP +Note that +.I tickadj +should be run with some caution when being used for the first time on +different types of machines. The operations which +.I tickadj +trys to perform are not guaranteed to work on all Unix machines. +.SH FILES +.nf +/vmunix +/unix +/dev/kmem +.fi +.SH SEE ALSO +xntpd(8) +.SH HISTORY +Written by Dennis Ferguson at the University of Toronto +.SH BUGS +Fiddling with kernel variables at run time as a part of ordinary +operations is a hideous practice which is only necessary to make +up for deficiencies in the implementation of +.IR adjtime (8) +in many kernels and/or brokenness of the system clock in some +vendors' kernels. It would be much better if the kernels were fixed +and the +.I tickadj +program went away. diff --git a/contrib/xntpd/doc/xntpd.8 b/contrib/xntpd/doc/xntpd.8 new file mode 100644 index 0000000000..b02101980d --- /dev/null +++ b/contrib/xntpd/doc/xntpd.8 @@ -0,0 +1,1352 @@ +''' $Header +''' +.de Sh +.br +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp +.if t .sp .5v +.if n .sp +.. +.de Ip +.br +.ie \\n.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +''' +''' Set up \*(-- to give an unbreakable dash; +''' string Tr holds user defined translation string. +''' Bell System Logo is used as a dummy character. +''' +.tr \(bs-|\(bv\*(Tr +.ie n \{\ +.ds -- \(bs- +.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch +.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch +.ds L" "" +.ds R" "" +.ds L' ' +.ds R' ' +'br\} +.el\{\ +.ds -- \(em\| +.tr \*(Tr +.ds L" `` +.ds R" '' +.ds L' ` +.ds R' ' +'br\} +.TH XNTPD 8 LOCAL +.SH NAME +xntpd - Network Time Protocol daemon +.SH SYNOPSIS +.B xntpd +[ +.B -ab +] [ +.B -c +.I conffile +] [ +.B -e +.I authdelay +] [ +.B -f +.I driftfile +] [ +.B -k +.I keyfile +] [ +.B -l +.I loopfile +] [ +.B -p +.I pidfile +] [ +.B -r +.I broaddelay +] [ +.B -s +.I statsdir +] [ +.B -t +.I trustedkey +] +.SH DESCRIPTION +.I Xntpd +is a daemon which maintains a Unix system's time\-of\-day in agreement +with Internet standard time servers. +.I Xntpd +is a complete implementation of the Network Time Protocol (NTP) version +3 standard as defined by RFC 1305 and also retains +compatability with version 1 and 2 servers as defined +by RFC 1059 and RFC 1119, respectively. +.I Xntpd +does all computations in fixed point arithmetic and is entirely free of +floating point code. The computations done in the protocol and clock +adjustment code are carried out with high precision and with attention +to the details which might introduce systematic bias into the integrations, +to try to maintain an accuracy suitable for synchronizing with even the +most precise external time source. +.PP +Ordinarily, +.I xntpd +reads its configuration from a file at startup time. The default configuration +file is +.I /etc/ntp.conf, +though this may be overridden from the command line. It is also possible to +specify a working, though limited, +.I xntpd +configuration entirely on the command line, obviating the need for a +configuration file. This may be particularly appropriate when xntpd is +to be configured as a broadcast client, with all peers being determined +by listening to broadcasts at run time. Various internal +.I xntpd +variables can be displayed, and configuration options altered, while the +daemon is running through use of the +.IR ntpq (8) +and +.IR xntpdc (8) +programs. +.PP +The following command line arguments are understood by +.I xntpd +(see the configuration file description for a more complete functional +description): +.Ip -a 8 +run in \*(L"authenticate\*(R" mode +.Ip -b 8 +listen for broadcast NTP and sync to this if available +.Ip -c 8 +specify an alternate configuration file +.Ip -d 8 +specify debugging options +.Ip -e 8 +specify the time (in seconds) it takes to compute the NTP encryption field +on this computer +.Ip -f 8 +specify the location of the drift file +.Ip -k 8 +specify the location of the file which contains the NTP authentication keys +.Ip -p 8 +specify the name of the file to record the daemon's process id +.Ip -r 8 +specify the default round trip delay (in seconds) +to be used when synchronizing to broadcasts +.Ip -s 8 +specify a directory to be used for creating statistics files +.Ip -t 8 +add a key number to the trusted key list +.SH "CONFIGURATION FILE OPTIONS" +.IR Xntpd 's +configuration file is relatively free format. Comments, which may be +freely inserted, begin with a \*(L"#\*(R" character +and extend to the end of the line. Blank lines are ignored. Configuration +statements include an initial keyword followed by white space separated +arguments, some of which may be optional. Configuration statements +may not be continued over multiple lines. Arguments may be network +numbers (which must be written in numeric, dotted\-quad form), integers, +floating point numbers (when specifying times in seconds) and text +strings. Optional arguments are delimited by \*(L"[]\*(R" in the following +descriptions, while alternatives are separated by \*(L"|\*(R". +.PP +.B peer +.I host_address +[ +.B key +.I # +] [ +.B version +.I # +] [ +.B prefer +] +.br +.B server +.I host_address +[ +.B key +.I # +] [ +.B version +.I # +] [ +.B prefer +] +.br +.B broadcast +.I host_address +[ +.B key +.I # +] [ +.B version +.I # +] [ +.B prefer +] +.PP +These three statements specify various time servers to be used and/or +time services to be provided. The +.B peer +statement specifies that the given host is to be polled in +\*(L"symmetric active\*(R" mode, i.e. that the host is requested to +provide time which you might synchronize to and, in addition, indicates +that you are willing to have to remote host synchronize to your time +if need be. The +.B server +statement specifies that the given host is to be polled in +\*(L"client\*(R" mode, i.e. that the host is requested to provide +time which you might synchronize with but that you are unwilling to have +the remote host synchronize to your own time. The +.B broadcast +statement requests your local daemon to transmit broadcast NTP to +the specified address. The latter is usually the broadcast address +on [one of] your local network[s]. +.PP +The +.B key +option, when included, indicates that all packets sent to the address +are to include authentication fields encrypted using the specified key +number (the range of which is that of an unsigned 32 bit integer). The +default is to not include an encryption field. The +.B version +option allows one to specify the version number to be used for outgoing +NTP packets. Versions 1, 2, and 3 are the choices, version 3 is the default. +The +.B prefer +option marks the host as a preferred host. All other things being equal, this +host will be chosen for synchronization among a set of correctly operating +hosts. +.PP +.B precision +.I # +.PP +Indicates the precision of local timekeeping. The value is an integer +which is approximately the base 2 logarithm of the local timekeeping +precision in seconds. By default this value is set to -6. +.PP +The precision declared by an implementation can affect several aspects +of server operation, and can be used as a tuning parameter for your +synchronization subnet. It should probably not be changed from the +default value, however, unless there is a good reason to do so. +.PP +.B logfile +.I filename +.PP +Gives the file which is to be used instead of syslog output. This +configuration option is also a compile time option (SYSLOG_FILE). +So in order to be able to use this xntpd must be compiled with +-DSYSLOG_FILE. +.PP +.B driftfile +.I filename +.PP +Specifies the name of the file used to record the \*(L"drift\*(R" (or +frequency error) value +.I xntpd +has computed. If the file exists on startup, it is read and the value +used to initialize +.IR xntpd 's +internal value of the frequency error. The file is then updated once +every hour by replacing the old file with a new one containing the +current value of the frequency error. Note that the file is updated +by first writing the current drift value into a temporary file and +then using +.IR rename (3) +to replace the old version. This implies that +.I xntpd +must have write permission for the directory the drift file is located +in, and that file system links, symbolic or otherwise, should probably +be avoided. +.PP +.B "monitor yes|no" +.PP +Indicates whether the +.I xntpd +traffic monitoring function should be enabled or not. When enabled, +this causes the origin address of each packet received by the server +to be recorded along with a limited amount of additional information, such +as the mode of the request and whether it originated from an NTP server port +or not. Traffic monitoring data may be inspected using the +.IR xntpdc (8) +.I monlist +command. The default is \*(L"no\*(R", i.e. traffic monitoring should not +be done. +.PP +Note that the traffic monitoring facility will increase the CPU used +by +.IR xntpd , +as well as increasing the daemon's memory utilization by as much as +8.5 kilobytes. This facility is normally useful for the detection of +peers with malfunctioning software or which are sending bogus data. It +is primarily intended for very popular servers which exchange time with +large numbers of peers, though it may also be useful for access monitoring +of local servers if you are willing to accept the overhead. +.PP +.B "broadcastclient yes|no" +.PP +This indicates whether the local server should listen for, and attempt to +synchonize to, broadcast NTP. The default is \*(L"no\*(R". +.PP +.B broadcastdelay +.I seconds +.PP +Specifies the default round trip delay to the host whose broadcasts +are being synchronized to. The value is specified in seconds and is +typically (for ethernet) a number between 0.007 and 0.015 seconds. This +initial estimate may be improved by polling each server to determine a +more accurate value. Defaults to 0.008 seconds. +.PP +.B "authenticate yes|no" +.PP +Indicates whether the local server should operate in authenticate mode +or not. If \*(L"yes\*(R", only peers which include an authentication field +encrypted with one of our trusted keys (see below) will be considered +as candidates for synchonizing to. The default is \*(L"no\*(R". +.PP +.B authdelay +.I seconds +.PP +Indicates the amount of time it takes to encrypt an NTP authentication +field on the local computer. This value is used to correct transmit +timestamps when the authentication is used on outgoing packets. The +value usually lies somewhere in the range 0.0001 seconds to 0.003 seconds, +though it is very dependent on the CPU speed of the host computer. The +value is usually computed using the +.I authspeed +program included with the distribution. +.PP +.B keys +.I filename +.PP +Specifies the name of a file which contains the encryption keys which +are to be used by +.IR xntpd . +The format of this file is described below. +.PP +.B trustedkey +.I # +[ +.I "# ..." +] +.PP +Allows the specification of the encryption key numbers which are trusted +for the purposes of determining peers suitable for time sychonization, +when authentication is enabled. Only peers using one of these keys for +encryption of the authentication field, and whose authenticity can be +verified by successful decryption, will be considered as synchonization +candidates. The arguments are 32 bit unsigned integers. Note, however, +that NTP key 0 is fixed and globally known. If meaningful authentication +is to be performed the 0 key should not be trusted. +.PP +.B requestkey +.I # +.PP +.I Xntpd +allows run time reconfiguration to be performed using the +.IR xntpdc (8) +program. Such requests must be authenticated. The +.B requestkey +statement allows the specification of a 32 bit unsigned integer +key number to be used for authenticating such requests. Note that +if no +.B requestkey +statement is included in the configuration file the run time reconfiguration +facility will be disabled. +.PP +.B controlkey +.I # +.PP +Certain changes can be made to the +.I xntpd +server via mode 6 control messages, in particular the setting of +leap second indications in a server with a radio clock. The +.B controlkey +statement specifies an encription key number to be used for authenticating +such messages. Omitting this statement will cause control messages +which would change the state of the server to be ignored. +.PP +.B restrict +.I address +[ +.B mask +.I numeric_mask +] [ +.I flag +] [ +.I ... +] +.PP +.I Xntpd +implements a general purpose address\-and\-mask based restriction +list. The list is sorted by address and by mask, and the list is +searched in this order for matches, with the last match found defining +the restriction flags associated with the incoming packets. The source +address of incoming packets is used for the match, with the 32 bit address +being and'ed with the mask associated with the restriction entry and +then compared with the entry's address (which has also been and'ed with +the mask) to look for a match. The \*(L"mask\*(R" argument defaults +to 255.255.255.255, meaning that the \*(L"address\*(R" is treated as the +address of an individual host. A default entry (address 0.0.0.0, mask +0.0.0.0) is always included and, given the sort algorithm, is always the +first entry in the list. Note that, while \*(L"address\*(R" is normally +given as a dotted\-quad address, the text string \*(L"default\*(R", with +no mask option, may be used to indicate the default entry. +.PP +In the current implementation flags always restrict access, i.e. an entry +with no flags indicates that free access to the server is to be given. The +flags are not orthogonal, in that more restrictive flags will often make +less restrictive ones redundant. The flags can generally be classed into +two catagories, those which restrict time service and those which restrict +informational queries and attempts to do run time reconfiguration of the +server. One or more of the following flags may be specified: +.Ip ignore 10 +Ignore all packets from hosts which match this entry. If this flag +is specified neither queries nor time server polls will be responded +to. +.Ip noquery 10 +Ignore all NTP mode 6 and 7 packets (i.e. information queries and configuration +requests) from the source. Time service is not affected. +.Ip nomodify 10 +Ignore all NTP mode 6 and 7 packets which attempt to modify the state of the +server (i.e. run time reconfiguration). Queries which return information +are permitted. +.Ip notrap 10 +Decline to provide mode 6 control message trap service to matching +hosts. The trap service is a subsystem of the mode 6 control message +protocol which is intended for use by remote event logging programs. +.Ip lowpriotrap 10 +Declare traps set by matching hosts to be low priority. The number +of traps a server can maintain is limited (the current limit is 3). +Traps are usually assigned on a first come, first served basis, with +later trap requestors being denied service. This flag modifies the +assignment algorithm by allowing low priority traps to be overridden +by later requests for normal priority traps. +.Ip noserve 10 +Ignore NTP packets whose mode is other than 6 or 7. In effect, time service is +denied, though queries may still be permitted. +.Ip nopeer 10 +Provide stateless time service to polling hosts, but do not allocate peer +memory resources to these hosts even if they otherwise might be considered +useful as future synchronization partners. +.Ip notrust 10 +Treat these hosts normally in other respects, but never use them as +synchronization sources. +.Ip ntpport 10 +This is actually a match algorithm modifier, rather than a restriction +flag. Its presence causes the restriction entry to be matched only if +the source port in the packet is the standard NTP UDP port (123). Both +\*(L"ntpport\*(R" and non\-\*(L"ntpport\*(R" may be specified. The +\*(L"ntpport\*(R" is considered more specific and is sorted later in the +list. +.PP +Default restriction list entries, with the flags \*(L"ignore, ntpport\*(R", +for each of the local host's interface addresses are inserted into the +table at startup to prevent the server from attempting to synchronize to +its own time. A default entry is also always present, though if it is +otherwise unconfigured no flags are associated with the default entry (i.e. +everything besides your own NTP server is unrestricted). +.PP +The restriction facility was added to allow the current access policies +of the time servers running on the NSFnet backbone to be implemented with +.I xntpd +as well. While this facility may be otherwise useful for keeping unwanted or +broken remote time servers from affecting your own, it should not be +considered an alternative to the standard NTP authentication facility. Source +address based restrictions are easily circumvented by a determined cracker. +.PP +.B trap +.I host_address +[ +.B port +.I port_number +] [ +.B interface +.I interface_addess +] +.PP +Configures a trap receiver at the given host address and port number, +sending messages with the specified local interface address. If the +port number is unspecified a value of 18447 is used. If the interface +address is not specified the message is sent with a source address +which is that of the local interface the message is sent through. Note +that on a multihomed host the interface used may vary from time to time +with routing changes. +.PP +The trap receiver will generally log event messages and other information +from the server in a log file. While such monitor programs may also +request their own trap dynamically, configuring a trap receiver will +ensure that no messages are lost when the server is started. +.PP +.B maxskew +.I seconds +.PP +This command is obsolete and not available in this version of +.I xntpd. +.PP +.B select +.I algorithm_number +.PP +This command is obsolete and not available in this version of +.I xntpd. +.PP +.B resolver +.I /path/xntpres +.PP +Normally, names requiring resolution (rather than numeric addresses) +in the configuration file are resolved by code internal to +.I xntpd; +However, in those cases that require it, the code can be installed +in a standalone program called +.I xntpres. +In these cases the full path to the +.I xntpres +program is given as the argument the command. +As +.I xntpres +makes use of mode 7 runtime reconfiguration, this facility must also be +enabled if the procedure is to exceed (see the +.B requestkey +and +.B keys +statements above). +.PP +.B statsdir +.I /directory path/ +.PP +Indicates the full path of a directory where statistics files should +be created (see below). This keyword allows the (otherwise constant) filegen +filename prefix to be modified for file generation sets used for +handling statistics logs (see +.B filegen +statement below). +.PP +.B statistics +.IR name \.\.\. +.PP +Enables writing of statistics records. +Currently, three kinds of statistics are supported. +.Ip loopstats 10 +enables recording of loop filter statistics information. +Each update of the local clock outputs a line of the +following form to the file generation set named \*(L"loopstats\*(R": +.PP +.RS 5 +48773 10847.650 0.0001307 17.3478 2 +.RE + +.RS 10 +The first two fields show the date (Modified Julian Day) and time (seconds +and fraction past UTC midnight). The next three fields show time offset +in seconds, frequency offset in parts-per-million and time constant of +the clock-discipline algorithm at each update of the clock. +.RE +.Ip peerstats 10 +enables recording of peer statistics information. This includes +statistics records of all peers of a NTP server and of the 1-pps signal, +where present and configured. Each +valid update appends a line of the following form to the current +element of a file generation set named \*(L"peerstats\*(R": +.PP +.RS 5 +48773 10847.650 127.127.4.1 9714 -0.001605 0.00000 0.00142 +.RE + +.RS 10 +The first two fields show the date (Modified Julian Day) and time (seconds +and fraction past UTC midnight). The next two fields show the peer +address in dotted-quad notation and status, +respectively. The status field is encoded in hex in the format described +in Appendix A of the NTP specification RFC 1305. The final three fields +show the offset, delay and dispersion, all in seconds. +.RE +.Ip clockstats 10 +enables recording of clock driver statistics information. Each update +received from a clock driver outputs a line of the following form to the +file generation set named \*(L"clockstats\*(R": +.PP +.RS 5 +49213 525.624 127.127.4.1 93 226 00:08:29.606 D +.RE + +.RS 10 +The first two fields show the date (Modified Julian Day) and time (seconds +and fraction past UTC midnight). The next field shows the clock +address in dotted-quad notation, The final field shows the last timecode +received from the clock in decoded ASCII format, where meaningful. In +some clock drivers a good deal of additional information can be gathered +and displayed as well. See information specific to each clock +for further details. +.RE +.PP +Statistic files are managed using file generation sets (see +.B filegen +below). The information obtained by enabling statistics recording +allows analysis of temporal properties of a +.I xntpd +server. It is usually only useful to primary servers or maybe main +campus servers. +.PP +.B filegen +.I name +[ +.B file +.I filename +] [ +.B type +.I typename +] [ +.B flag +.I flagval +] [ +.BR link \| nolink +] [ +.BR enable \| disable +] +.PP +Configures setting of generation file set +.IR name . +Generation file sets provide a means for handling files that are +continously growing during the lifetime of a server. Server statistics +are a typical example for such files. Generation file sets provide +access to a set of files used to store the actual data. At any time at +most one element of the set is being written to. The +.I type +given specifies when and how data will be directed to a new element +of the set. This way, information stored in elements of a file set +that are currently unused are available for administrational +operations +without the risc of desturbing the operation of +.IR xntpd . +(Most important: they can be removed to free space for new data +produced.) +Filenames of set members are built from three elements. +.Ip prefix 10 +This is a constant filename path. It is not subject to modifications +via the +.B filegen +statement. It is defined by the server, usually specified as a compile +time constant. It may, however, be configurable for individual file +generation sets via other commands. For example, the prefix used with +"loopstats" and "peerstats" filegens can be configured using the +.B statsdir +statement explained above. +.Ip filename 10 +This string is directly concatenated to the +.I prefix +mentioned above (no intervening \*(L'/\*(R' (slash)). This can be +modified using the \*(L"file\*(R" argument to the \*(L"filegen\*(R" +statement. No \*(L"..\*(R" elements are allowed in this component to +prevent filenames referring to parts outside the filesystem hierarchy +denoted by \*(L"prefix\*(R". +.Ip suffix 10 +This part is reflects individual elements of a file set. It is generated +according to the +.I type +of a file set as explained below. +.PP +A file generation set is characterized by its type. +The following types are supported: +.Ip none 10 +The file set is actually a single plain file. +.Ip pid 10 +One element of file set is used per incarnation of a +.I xntpd +server. This type does not perform any changes to file set members +during runtime, however it provides an easy way of seperating files +belonging to different +.I xntpd +server incarnations. +The set member filename is built by appending a dot (\*(L'.\*(R') to +concatentated \*(L"prefix\*(R" and \*(L"filename\*(R" strings, and +appending the decimal representation of the process id of the +.I xntpd +server process. +.Ip day 10 +One file generation set element is created per day. The term +.I day +is based on +.IR UTC . +A day is defined as the period between 00:00 and 24:00 UTC. +The file set member suffix consists of a dot \*(L".\*(R" +and a day specification in the form +.RI < YYYYMMDD >. +.I YYYY +is a 4 digit year number (e.g. 1992). +.I MM +is a two digit month number. +.I DD +is a two digit day number. +Thus, all information written at December 10th, 1992 would end up +in a file named +\*(L".19921210\*(R". +.Ip week 10 +Any file set member contains data related to a certain week of a year. +The term +.I week +is definied by computing \*(L"day of year\*(R" modulo 7. Elements of +such a file generation set are distinguished by appending the +following suffix to the file set filename base: +A dot, a four digit year number, the letter \*(L"W\*(R", +and a two digit week number. For example, information from Jamuary, +10th 1992 would end up in a file with suffix \*(L".1992W1\*(R". +.Ip month 10 +One generation file set element is generated per month. The file name +suffix consists of a dot, a four digit year number, and a two digit +month. +.Ip year 10 +One generation file elment is generated per year. The filename suffix +consists of a dot and a 4 digit year number. +.Ip age 10 +This type of file generation sets changes to a new element of the file +set every 24 hours of server operation. The filename suffix consists +of a dot, the letter \*(L"a\*(R", and an eight digit number. This +number is taken to be the number of seconds the server is running at +the start of the corresponding 24 hour period. +.PP +Information is only written to a file generation set when this set is +\*(L"enabled\*(R". Output is prevented by specifying +\*(L"disabled\*(R". +.PP +It is convenient to be able to access the +.I current +element of a file generation set by a fixed name. This feature is +enabled by specifying \*(L"link\*(R" and disabled using +\*(L"nolink\*(R". If \*(L"link\*(R" is specified, a hard link from the +current file set element to a file without suffix is created. When +there is already a file with this name and the number of links of this +file is one, it is renamed appending a dot, the letter \*(L"C\*(R", +and the pid of the +.I xntpd +server process. When the number of links is greater than one, the file +is unlinked. This allows the current file to be accessed by a constant +name. +.SH "AUTHENTICATION KEY FILE FORMAT" +.PP +The NTP standard specifies an extension allowing +verification of the authenticity of received NTP packets, and to provide +an indication of authenticity in outgoing packets. This is implemented +in +.I xntpd +using the DES encryption algorithm. The specification +allows any one of a possible 4 billion keys, numbered with 32 bit unsigned +integers, to be used to +authenticate an association. The servers involved in an association +must agree on the value of the key used to authenticate their data, though +they must each learn the key independently. The keys are standard 56 bit +DES keys. +.PP +Addionally, a new experimental authentication algorithm is available which +uses an MD5 message digest to compute an authenticator. Currently the length +of the key or password is limited to 8 characters, but this will eventually +be changed to accomodate an effectively unlimited password phrase. +.I Xntpd +reads its keys from a file specified using the +.B -k +command line option or the +.B keys +statement in the configuration file. While key number 0 is fixed by the +NTP standard (as 56 zero bits) and may not be changed, one or more of +the keys numbered 1 through 15 may be arbitrarily set in the keys file. +.PP +The key file uses the same comment conventions as the configuration +file. Key entries use a fixed format of the form +.Ip "" 5 +.I "keyno type key" +.PP +where \*(L"keyno\*(R" is a positive integer, +\*(L"type\*(R" is a single character which defines the format the key +is given in, and \*(L"key\*(R" is the key itself. +.PP +The key may be given in one of three different formats, controlled by +the \*(L"type\*(R" character. The three key types, and corresponding +formats, are listed following. +.Ip "S" 5 +The \*(L"key\*(R" is a 64 bit hexadecimal number in the format specified +in the DES document, that is the high order 7 bits of each octet are used +to form the 56 bit key while the low order bit of each octet is given a +value such that odd parity is maintained for the octet. Leading zeroes +must be specified (i.e. the key must be exactly 16 hex digits long) and +odd parity must be maintained. Hence a zero key, in standard format, +would be given as +.I 0101010101010101 . +.Ip "N" 5 +The \*(L"key\*(R" is a 64 bit hexadecimal number in the format specified +in the NTP standard. This is the same as the DES format except the bits +in each octet have been rotated one bit right so that the parity bit is +now the high order bit of the octet. Leading zeroes must be specified +and odd parity must be maintained. A zero key in NTP format would be specified +as +.I 8080808080808080 +.Ip "A" 5 +The \*(L"key\*(R" is a 1\-to\-8 character ASCII string. A key is formed +from this by using the lower order 7 bits of the ASCII representation +of each character in the string, with zeroes being added on the right +when necessary to form a full width 56 bit key, in the same way that +encryption keys are formed from Unix passwords. +.Ip "M" 5 +The \*(L"key\*(R" is a 1\-to\-8 character ASCII string, using the MD5 +authentication scheme. Note that both the keys and the authentication +schemes (DES or MD5) must be identical between a set of peers sharing +the same key number. +.PP +One of the keys may be chosen, +by way of the configuration file +.B requestkey +statement, to authenticate run time configuration +requests made using the +.IR xntpdc (8) +program. The latter program obtains the key from the terminal as +a password, so it is generally appropriate to specify the key chosen +to be used for this purpose in ASCII format. +.SH PRIMARY CLOCK SUPPORT +.PP +.I Xntpd +can be optionally compiled to include support for a number of types +of reference clocks. A reference clock will generally (though +not always) be a radio timecode receiver which is synchronized to a +source of standard time such as the services offered by the NRC in +Canada and NIST in the U.S. The interface between the computer and +the timecode receiver is device dependent and will vary, but is +often a serial port. +.PP +For the purposes of configuration, +.I xntpd +treats reference clocks in a manner analogous to normal NTP peers +as much as possible. Reference clocks are referred to by address, +much as a normal peer is, though an invalid IP address is used to +distinguish them from normal peers. Reference clock addresses are +of the form +.I 127.127.t.u +where +.I t +is an integer denoting the clock type and +.I u +indicates the type\-specific unit number. Reference clocks are normally +enabled by configuring the clock as a server using a +.B server +statement in the configuration file which references the clock's +address (configuring a reference clock with a +.B peer +statement can also be done, though with some clock drivers this may cause +the clock to be treated somewhat differently and by convention is used +for debugging purposes). Clock addresses may generally +be used anywhere else in the configuration file a normal IP address +can be used, for example in +.B restrict +statements. +.PP +There is one additional configuration statement which becomes valid +when reference clock support has been compiled in. Its format is: +.PP +.B fudge +.I 127.127.t.u +[ +.B time1 +.I secs +] [ +.B time2 +.I secs +] [ +.B value1 +.I int +] [ +.B value2 +.I int +] [ +.B flag1 +.I 0|1 +] [ +.B flag2 +.I 0|1 +] +.PP +There are two times (whose values are specified in fixed point seconds), +two integral values and two binary flags available for customizing +the operation of a clock. The interpretation of these values, and +whether they are used at all, is a function of the needs of the particular +clock driver. +.PP +.I Xntpd +on Unix machines currently supports several different types of clock hardware +plus a special pseudo\-clock used for backup or when no other clock +source is available. In the case of most of the clock drivers, support +for a 1-pps precision timing signal is available as described in the +pps.txt file in the doc directory of the xntp3 distribution. +The clock drivers, and the addresses used to configure +them, are described following: +.PP +.B 127.127.1.u +\- Local synchronization clock driver +.PP +This driver doesn't support an actual clock, but rather allows the +server to synchronize to its own clock, in essence to free run without +its stratum increasing to infinity. This can be used to run an +isolated NTP synchronization network where no standard time source is +available, by allowing a free running clock to appear as if it has +external synchronization to other servers. By running the local clock +at an elevated stratum it can also be used to prevent a server's stratum +from rising above a fixed value, this allowing a synchronization subnet +to synchonize to a single local server for periods when connectivity +to the primary servers is lost. +.PP +The unit number of the clock (the least significant octet in the address) +must lie in the range 0 through 15 inclusive and is used as the stratum +the local clock will run at. Note that the server, when synchronized +to the local clock, will advertise a stratum one greater than the clock +peer's stratum. More than one local clock may be configured (indeed all +16 units may be active at once), though this hardly seems useful. +.PP +The local clock driver uses only the fudge time1 parameter. This parameter +provides read and write access to the local clock drift compensation +register. This value, which actually provides a fine resolution speed +adjustment for the local clock, is settable but will remain unchanged +from any set value +when the clock is free running without external synchronization. The +fudge time1 parameter thus provides a way to manually adjust the speed of the +clock to maintain reasonable synchronization with, say, a voice +time announcement. It is actually more useful to manipulate this value +with the +.IR xntpdc (8) +program. +.PP +.B 127.127.3.u +\- Precision Standard Time/Traconex 1010/1020 WWV/H Receiver +.PP +This driver can be used with a PST/Traconex Time Source 1010 or 1020 WWV/WWVH +Synchronized Clock connected via a serial port. Up to +four units, with unit numbers in the range 0 through 3, can be +configured. The driver assumes the serial port device name is +/dev/pst%d (i.e. unit 1, at 127.127.3.1, opens the clock at +/dev/pst1) and that the clock is configured for 9600-baud operation. +.PP +The fudge time1 and time2 parameters are configured directly into the receiver +as nominal propagation delays when synchronized to WWV and WWVH, +respectively; the internal DIPswitches ordinarily used for that purpose +are disabled. The default values are 0.0075 and 0.0265 seconds, +respectively, which are about right for Toronto. Values for other +locations can be calculated using the +.I propdelay +program in the util directory of the xntp3 distribution or equivalent +means described in the user's manual. +.PP +The fudge value1 parameter can be used to set the stratum at which +the peer operates. The default is 0, which is correct if you want the +clock to be considered for synchonization whenever it is operating, though +higher values may be assigned if you only want the clock to provide backup +service when all other primary sources have failed. The value2 parameter +is set to the number of minutes which the daemon will allow the clock to go +without synchronization before it starts disbelieving it. The default +is 20, which is suitable if you have good quality backup NTP peers. If +your network is isolated or your network connections are poor it might +be advantageous to increase this value substantially. +.PP +The fudge flag1 can be used to modifiy the averaging algorithm used +to smooth the clock indications. Ordinarily, the algorithm picks the +median of a set of samples, which is appropriate under conditions +of poor to fair radio propagation conditions. If the clock is located +relatively close to the WWV or WWVH transmitters, setting this flag +will cause the algorithm to average the set of samples, which can +reduce the residual jitter and improve accuracy. +.PP +The fudge flag2 can be used to force the driver to send to +the clock the commands required to reprogram the current WWV and WWVH fudge +delays into it. This is normally done only when the values are to be changed, +such as during inital setup and calibration. Setting +the (otherwise undocumented) fudge flag3 will cause the driver to reset +the clock. The latter two flags are generally useful primarily for debugging. +.PP +127.127.4.u +\- Spectracom 8170 and Netclock/2 WWVB Synchronized Clocks +.PP +This driver can be used with a Spectracom 8170 or Netclock/2 WWVB +Synchronized Clock connected via a serial port. Up to +four units, with unit numbers in the range 0 through 3, can be +configured. The driver assumes the serial port device name is +/dev/wwvb%d (i.e., unit 1 at 127.127.4.1 opens the clock at +/dev/wwvb1) and that the clock is configured for 9600-baud operation. +.PP +The fudge time1 parameter can be used to compensate for inherent +latencies in the serial port hardware and operating system. +The value, which defaults to zero, is in addition to the value +programmed by the propagation switches on the receiver. The +fudge value1 parameter can be used to specify the stratum of the clock +in the same way described above for the WWV/WWVH clock 127.127.3.u. +.PP +.B 127.127.5.u +\- Kinemetrics/TrueTime Timing Receivers +.PP +This driver can be used with at least two models of Kinemetrics/TrueTime +Timing Receivers, the 468-DC MK III GOES Synchronized Clock and GPS-DC +MK III GPS Synchronized Clock and very likely others in the same model +family that use the same timecode formats. The clocks are connected +via a serial port. Up to +four units, with unit numbers in the range 0 through 3, can be +configured. The driver assumes the serial port device name is +/dev/goes%d (i.e., unit 1 at 127.127.5.1 opens the clock at +/dev/goes1) and that the clock is configured for 9600-baud operation. +.PP +The fudge time1 parameter can be used to compensate for inherent +latencies in the serial port hardware and operating system in the same +way as described above for the WWVB clock 127.127.4.u. +The fudge value1 parameter can be used to specify the stratum of the clock +in the same way described above for the WWV/WWVH clock 127.127.3.u. +.PP +.B 127.127.6.0 +\- IRIG-B Audio Decoder +.PP +This driver can be used in conjuction with the Inter-Range Instrumentation +Group standard time-distribution signal IRIG-B. This signal is generated +by several radio clocks, including those made by Austron, TrueTime, Odetics +and Spectracom, among others, although it is generally an add-on option. +The signal is connected via an attenuator box and cable to the audio +codec input on a Sun SPARCstation and requires a specially modified +kernel audio driver. Details are in the irig.txt file in the doc +directory of the xntp3 distribution. As only a single audio codec +is built into a workstation, the driver assumes the device name is /dev/irig. +.PP +Timing jitter using the decoder and a Sun IPC is in the order of a few +microseconds, although the overal timing accuracy is limited by the +wander of the CPU oscillator used for timing purposes to a few hundred +microseconds. These figures are comparable with what can be achieved +using the 1-pps signal described in the pps.txt file in the doc +directory of the xntp3 distribution. +.PP +.B 127.127.7.u +\- CHU Modem Decoder +.PP +This driver can be used with a shortwave receiver and special modem +circuitry described in the gadget directory of the xntp3 distribution. +It requires the chu-clk line discipline or chu_clk STREAMS module +described in the kernel directory of that distribution. It is connected +via a serial port operating at 300 baud. Up to +four units, with unit numbers in the range 0 through 3, can be +configured. The driver assumes the serial port device name is +/dev/chu%d (i.e., unit 1 at 127.127.7.1 opens the clock at +/dev/chu1). +.PP +Unlike the NIST time services, whose timecode requires quite specialized +hardware to interpret, the CHU timecode can be received directly via +a serial port after demodulation. While there are currently no commercial +CHU receivers, the hardware required to receive the CHU timecode is fairly +simple to build. While it is possible to configure several CHU units +simultaneously this is not recommended as the character interrupts from all +units will be occuring at the same time and will interfere with each other. +.PP +The fudge time1 parameter is used to specify the propagation delay between +the CHU transmitter at Ottawa, Ontario, and the receiver. The default +value is 0.0025 seconds, which is about right for Toronto. Values for other +locations can be calculated using the +.I propdelay +program in the util directory of the xntp3 distribution or equivalent +means. +The fudge time2 +parameter is used to compensate for inherent latencies in the modem, +serial port hardware and operating system in the same way as described +above for the WWVB clock 127.127.4.u. The default value is +0.0002 seconds, which is about right for typical telephone modem chips. +The fudge value1 parameter can be used to specify the stratum of the clock +in the same way described above for the WWV/WWVH clock 127.127.3.u. +The fudge flag1 can be used to modify the averaging algorithm in the +same way as described for that clock. +.PP +.B 127.127.8.u +\- Synchronisation to several receivers (DCF77, GPS) +.PP +The timecode of +the receivers will be sampled via a STREAMS module in the kernel (The STREAMS module +has been designed for use with SUN Systems under SunOS 4.1.x. It can be +linked directly into the kernel or loaded via the loadable driver mechanism) +This STREAMS module can be adepted to be able to convert different time code +formats. +If the daemon is compiled without the STREAM definition synchronisation +will work without the Sun streams module, though accuracy is significantly +degraded. +.br +The actual receiver status is mapped into various synchronisation +states generally used by receivers. The STREAMS module is configured to +interpret the time codes of DCF U/A 31, PZF535, GPS166, Trimble SV6 GPS, ELV DCF7000, +Schmid and low cost receivers (see list below). +.br +The reference clock support in xntp contains the necessary configuration tables +for those receivers. In addition to supporting up to 32 different clock types and +4 devices the generation a a PPS signal is also provided as an configuration +option. The PPS configuration option uses the receiver generated time stamps +for feeding the PPS loopfilter control for much finer clock synchronisation. +.br +CAUTION: The PPS configuration option is different from the hardware PPS signal, +which is also supported (see below), as it controls the way xntpd is synchronised +to the reference clock, while the hardware PPS signal controls the way time +offsets are determined. +.br +The use of the PPS option requires receivers with an accuracy of better than 1ms. +.PP +Fudge factors +.PP +Only two fudge factors are utilized. The +.I time1 +fudge factor defines the phase offset of the sychnronisation character to the actual +time. +On the availability of PPS information the +.I time2 +fudge factor show the difference betwteen the PPS time stamp and the reception +time stamp of the serial signal. This parameter is read only attempts to +set this parameter will be ignored. +The +.I flag0 +enables input filtering. This a median filter with continuous sampling. The +.I flag1 +selects averaging of the samples remaining after the filtering. Leap second +handling is controlled with the +.I flag2. +When set a leap second will be deleted on receipt of a leap second indication +from the receiver. Otherwise the leap second will be added (which is the default). +.PP +.I ntpq +timecode variable +.PP +The timecode variable in the ntpq read clock variable command contains several +fields. The first field is the local time in Unix format. The second field is +the offset to UTC (format HHMM). The currently active receiver flags are listed +next. Additional feature flags of the receiver are optionally listed in paranthesis. +The actual time code is enclosed in angle brackets < >. A qualification of the +decoded time code format is following the time code. The last piece of information +is the overall running time and the accumulated times for the clock event states. +.PP +Unit encoding +.PP +The unit field encodes the device, clock type and the PPS generation option. +There are 4 possible devices which are encoded in the lower 2 bits of the +field. The devices are named +.IR /dev/refclock-0 +through +.IR /dev/refclock-3 . +Bits 2 thru 6 encode the clock type. The fudge factors +of the clock type are take from a table +.I clockinfo +in refclock_parse.c. The generation of PPS information for disciplining the +local NTP clock is encoded in bit 7 of . +.PP +Currently nine clock types (devices /dev/refclock-0 - /dev/refclock-3) are supported. +.Ip 127.127.8.0-3 16 +Meinberg PZF535 receiver (FM demodulation/TCXO / 50us) +.Ip 127.127.8.4-7 16 +Meinberg PZF535 receiver (FM demodulation/OCXO / 50us) +.Ip 127.127.8.8-11 16 +Meinberg DCF U/A 31 receiver (AM demodulation / 4ms) +.Ip 127.127.8.12-15 16 +ELV DCF7000 (sloppy AM demodulation / 50ms) +.Ip 127.127.8.16-19 16 +Walter Schmid DCF receiver Kit (AM demodulation / 1ms) +.Ip 127.127.8.20-23 16 +RAW DCF77 100/200ms pulses (Conrad DCF77 receiver module / 5ms) +.Ip 127.127.8.24-27 16 +RAW DCF77 100/200ms pulses (TimeBrick DCF77 receiver module / 5ms) +.Ip 127.127.8.28-31 16 +Meinberg GPS166 receiver (GPS / <<1us) +.Ip 127.127.8.32-35 16 +Trimble SV6 GPS receiver (GPS / <<1us) +.PP +The reference clock support carefully monitors the state transitions of +the receiver. All state changes and exceptional events such as loss of time code +transmission are logged via the +.I syslog +facility. +Every hour a summary of the accumulated times for the clock states is +listed via syslog. +.PP +PPS support is only available when the receiver is completely +synchronised. The receiver is believed to deliver correct time for an additional +period of time after losing sychronisation unless a disruption in time code +transmission is detected (possible power loss). The trust period is dependent +on the receiver oscillator and thus a function of clock type. This is one of +the parameters in the +.I clockinfo +field of the reference clock implementation. This parameter cannot be +configured by xntpdc. +.PP +In addition to the PPS loopfilter control a true PPS hardware signal can be applied +on Sun Sparc stations via the CPU serial ports on the CD pin. This signal is +automatically detected and will be used for offset calculation. The input signal +must be the time mark for the following time code. (The edge sensitivity can be +selected - look into the appropriate kernel/parsestreams.c for details). +Meinberg receivers can be connected by feeding the PPS pulse of the receiver via +a 1488 level converter to Pin 8 (CD) of a Sun serial zs\-port. +.PP +There exists a special firmware release for the PZF535 Meinberg receivers. +This release (PZFUERL 4.6 (or higher - The UERL is important)) is absolutely +recommended for XNTP use, as it provides LEAP warning, time code time zone information +and alternate antenna indication. Please check with Meinberg for this +firmware release. +For the Meinberg GPS166 receiver is also a special firmaware release available +(Uni-Erlangen). This release must be used for proper operation. +.PP +The raw DCF77 pulses can be fed via a level converter directly into Pin 3 (Rx) +of the Sun. The telegrams will be decoded an used for synchronisation. +AM DCF77 receivers are running as low as $25. The accuracy is dependent on +the receiver and is somewhere between 2ms (expensive) to 10ms (cheap). +Upon bad signal reception of DCF77 sychronisation will cease as no backup +oscillator is available as usually found in other reference clock receivers. +So it is important to have a good place for the DCF77 antenna. For transmitter +shutdowns you are out of luck unless you have other NTP servers with alternate +time sources available. +.PP +127.127.9.u +\- Magnavox MX4200 Navigation Receiver used as GPS Synchronized Clocks +.PP +This driver can be used with a Magnavox MX4200 Navigation Receiver +adapted to precision timing applications. This requires an interface +box described in the ppsclock directory of the xntp3 distribution. +It is connected via a serial port and requires the ppsclock STREAMS +module described in the same directory. Up to +four units, with unit numbers in the range 0 through 3, can be +configured. The driver assumes the serial port device name is +/dev/gps%d (i.e., unit 1 at 127.127.9.1 opens the clock at +/dev/gps1) and that the clock is configured for 9600-baud operation. +.PP +The fudge time1 parameter can be used to compensate for inherent +latencies in the serial port hardware and operating system in the +same way described above for the WWVB clock 127.127.4.u. The +fudge value1 parameter can be used to specify the stratum of the clock +in the same way described above for the WWV/WWVH clock 127.127.3.u. +.PP +127.127.10.u +\- Austron 2200A/2201A GPS/LORAN Synchronized Clock and Timing Receiver +.PP +This driver can be used with an Austron 2200A/2201A GPS/LORAN Synchronized +Clock and Timing Receiver connected via a serial port. It supports +several special features of the clock, including the Input Burffer Module, +Output Buffer Module, IRIG-B Interface Module and LORAN Assist Module. It +requires the RS232 Serial Interface module for communication with +the driver. Up to four units (which hardly seems affordable), with unit +numbers in the range 0 through 3, can be +configured. The driver assumes the serial port device name is +/dev/gps%d (i.e., unit 1 at 127.127.10.1 opens the clock at +/dev/gps1) and that the clock is configured for 9600-baud operation. +.PP +The fudge time1 parameter can be used to compensate for inherent +latencies in the serial port hardware and operating system in the +same way described above for the WWVB clock 127.127.4.u. The +fudge value1 parameter can be used to specify the stratum of the clock +in the same way described above for the WWV/WWVH clock 127.127.3.u. +.PP +This receiver is capable of a comprehensive and large volume of +statistics and operational data. The specific data-collection +commands and attributes are embedded in the driver source code; +however, the collection process can be enabled or disabled +using the flag4 flag. If set, collection is enabled; if not, +which is the default, it is disabled. A comprehensive suite of data reduction +and summary scripts is in the ./scripts/stats directory of the xntp +distribution. +.PP +127.127.11.u +\- Kinemetrics/TrueTime OMEGA-DC OMEGA Synchronized Clock +.PP +This driver can be used with a Kinemetrics/TrueTime OMEGA-DC OMEGA +Synchronized Clock connected via a serial port. This clock is +sufficiently different than other Kinemetrics/TrueTime models +to require a separate driver. Up to +four units, with unit numbers in the range 0 through 3, can be +configured. The driver assumes the serial port device name is +/dev/omega%d (i.e., unit 1 at 127.127.11.1 opens the clock at +/dev/omega1) and that the clock is configured for 9600-baud operation. +.PP +The fudge time1 parameter can be used to compensate for inherent +latencies in the serial port hardware and operating system in the +same way described above for the WWVB clock 127.127.4.u. The +fudge value1 parameter can be used to specify the stratum of the clock +in the same way described above for the WWV/WWVH clock 127.127.3.u. +.PP +127.127.12.0 +\- KSI/Odeteics TPRO IRIG-B Decoder +.PP +This driver can be used with a KSI/Odeteics TPRO or TPRO-SAT IRIG-B +Decoder, which is a module connected directly to the SBus of a +Sun workstation. The module works with the IRIG-B signal generated +by several radio clocks, including those made by Austron, TrueTime, Odetics +and Spectracom, among others, although it is generally an add-on option. +In the case of the TPRO-SAT, the module is an integral part of a GPS +receiver, which serves as the primary timing source. +As only a single module of this type can be +used on a single workstation, only the unit number 0 is acceptable. +The driver assumes the device name is /dev/tpro0. +.PP +The fudge time1 parameter can be used to compensate for inherent +latencies in the serial port hardware and operating system in the +same way described above for the WWVB clock 127.127.4.u. The +fudge value1 parameter can be used to specify the stratum of the clock +in the same way described above for the WWV/WWVH clock 127.127.3.u. +.PP +127.127.13.u +\- Leitch CSD 500 Controller with HP 5061A Atomic Clock +.PP +This driver can be used with a Leitch CSD 500 Controller +connected to an HP 5061A Atomic Clock or equivalent primary timing source +and connected via a serial port. Up to +four units, with unit numbers in the range 0 through 3, can be +configured. The driver assumes the serial port device name is +/dev/leitch%d (i.e., unit 1 at 127.127.13.1 opens the clock at +/dev/leitch1) and that the clock is configured for 300-baud operation. +.PP +The fudge time1 parameter can be used to compensate for inherent +latencies in the serial port hardware and operating system in the +same way described above for the WWVB clock 127.127.4.u. The +fudge value1 parameter can be used to specify the stratum of the clock +in the same way described above for the WWV/WWVH clock 127.127.3.u. +.PP +127.127.14.u +\- EES M201 MSF receiver +.PP +This driver can be used with an EES M201 MSF receiver connected +to a Sun running SunOS 4.x with the "ppsclock" STREAMS module. +.PP +The fudge time1 and time2 parameters can be used to compensate for +inherent latencies in the serial port hardware and operating system +respectively in the same way described above for the WWVB clock 127.127.4.u. +The bottom 4 bits of fudge value1 parameter can be used to specify +the stratum of the clock in the same way described above for the +WWV/WWVH clock 127.127.3.u. +The fudge value2 parameter can be used to specify the debug mask. +bit 0x1 causes logging of smoothing processing. +bit 0x4 causes the clock buffer to be dumped. +If flag1 is set, then the system clock is assumed to be sloppy +(e.g. Sun4 with 20ms clock), so samples are averaged. +If flag2 is set, then leaphold is set. +If flag3 is set, then the sample information is dumped. +If flag4 is set, then the input data is smoothed, and all data +points are used. +.SH FILES +.Ip /etc/ntp.conf 20 +the default name of the configuration file +.Ip /etc/ntp.drift 20 +the conventional name of the drift file +.Ip /etc/ntp.keys 20 +the conventional name of the key file +.SH SEE ALSO +.PP +.IR xntpdc (8), +.IR ntpq (8), +.IR ntpdate (8) +.SH HISTORY +.PP +Written by Dennis Ferguson at the University of Toronto. +Text amended by David Mills at the University of Delaware. +.SH BUGS +.PP +.I Xntpd +has gotten rather fat. While not huge, it has gotten larger +than might be desireable for an elevated\-priority daemon running on a +workstation, particularly since many of the fancy features which +consume the space were designed more with a busy primary server, rather +than a high stratum workstation, in mind. This will eventually be corrected +either by adopting the +.I ntpd +daemon as an alternative when it becomes able to match +.IR xntpd 's +performance, or if not than by producing a stripped down version of +.I xntpd +specifically for workstation use. diff --git a/contrib/xntpd/doc/xntpdc.8 b/contrib/xntpd/doc/xntpdc.8 new file mode 100644 index 0000000000..20209b553b --- /dev/null +++ b/contrib/xntpd/doc/xntpdc.8 @@ -0,0 +1,659 @@ +''' $Header +''' +.de Sh +.br +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp +.if t .sp .5v +.if n .sp +.. +.de Ip +.br +.ie \\n.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +''' +''' Set up \*(-- to give an unbreakable dash; +''' string Tr holds user defined translation string. +''' Bell System Logo is used as a dummy character. +''' +.tr \(bs-|\(bv\*(Tr +.ie n \{\ +.ds -- \(bs- +.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch +.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch +.ds L" "" +.ds R" "" +.ds L' ' +.ds R' ' +'br\} +.el\{\ +.ds -- \(em\| +.tr \*(Tr +.ds L" `` +.ds R" '' +.ds L' ` +.ds R' ' +'br\} +.TH XNTPDC 8 LOCAL +.SH NAME +xntpdc - query/control program for the Network Time Protocol daemon +.SH SYNOPSIS +.B xntpdc +[ +.B -ilnps +] [ +.B -c +.I command +] [ +.I host +] [ +.I ... +] +.SH DESCRIPTION +.I Xntpdc +is used to query the +.IR xntpd (8) +daemon about its current state and to request changes in that state. The +program may be run either in interactive mode or controlled using +command line arguments. Extensive state and statistics information is +available through the +.I xntpdc +interface. In addition, nearly all the configuration options which can +be specified at start up using +.IR xntpd 's +configuration file may also be specified at run time using +.IR xntpdc . +.PP +If one or more request options is included on the command line when +.I xntpdc +is executed, each of the requests will be sent to the NTP servers running +on each of the hosts given as command line arguments, or on +.I localhost +by default. If no request options are given, +.I xntpdc +will attempt to read commands from the standard input and execute these +on the NTP server running on the first host given on the command line, again +defaulting to +.I localhost +when no other host is specified. +.I Xntpdc +will prompt for commands if the standard input is a terminal device. +.PP +.I Xntpdc +uses NTP mode 7 packets to communicate with the NTP server, and hence +can be used to query any compatable server on the network which permits +it. Note that since NTP is a UDP protocol this communication will be +somewhat unreliable, especially over large distances in terms of network +topology. +.I Xntpdc +makes no attempt to retransmit requests, and will time requests out if +the remote host is not heard from within a suitable time out time. +.PP +Command line options are described following. Specifying a command +line option other than +.B -i +or +.B -n +will cause the specified query (queries) to be sent to the indicated +host(s) immediately. Otherwise, +.I xntpdc +will attempt to read interactive format commands from the standard input. +.Ip -c 8 +The following argument is interpreted as an interactive format command +and is added to the list of commands to be executed on the specified +host(s). Multiple +.B -c +options may be given. +.Ip -i 8 +Force +.I xntpdc +to operate in interactive mode. Prompts will be written to the +standard output and commands read from the standard input. +.Ip -l 8 +Obtain a list of peers which are known to the server(s). This switch +is equivalent to \*(L"-c listpeers\*(R". +.Ip -n 8 +Output all host addresses in dotted\-quad numeric format rather than +converting to the canonical host names. +.Ip -p 8 +Print a list of the peers known to the server as well as a summary +of their state. This is equivalent to \*(L"-c peers\*(R". +.Ip -s 8 +Print a list of the peers known to the server as well as a summary +of their state, but in a slightly different format than the +.B -p +switch. This is equivalent to \*(L"-c dmpeers\*(R". +.SH INTERNAL COMMANDS +.PP +Interactive format commands consist of a keyword followed by zero +to four arguments. Only enough characters of the full keyword to +uniquely identify the command need be typed. The output of a command +is normally sent to the standard output, but optionally the output of +individual commands may be sent to a file by appending a \*(L">\*(R", +followed by a file name, to the command line. +.PP +A number of interactive format commands are executed entirely within the +.I xntpdc +program itself and do not result in NTP mode 7 requests being sent +to a server. These are described following. +.PP +.B ? +[ +.I command_keyword +} +.PP +A \*(L"?\*(R" by itself will print a list of all the command keywords +known to this incarnation of +.IR xntpdc . +A \*(L"?\*(R" followed by a command keyword will print funcation and +usage information about the command. This command is probably a better +source of information about +.I xntpdc +than this manual page. +.PP +.B help +[ +.I command_keyword +] +.PP +A synonym for the +.B ? +command. +.PP +.B timeout +.I millseconds +.PP +Specify a time out period for responses to server queries. The default +is about 8000 milliseconds. +.PP +.B delay +.I milliseconds +.PP +Specify a time interval to be added to timestamps included in requests +which require authentication. This is used to enable (unreliable) server +reconfiguration over long delay network paths or between machines whose +clocks are unsynchronized. +.PP +.B host +.I hostname +.PP +Set the host to which future queries will be sent. +.I Hostname +may be either a host name or a numeric +address. +.PP +.B poll +[ +.I # +] [ +.B verbose +] +.PP +Poll the current server in client mode. The first argument is the +number of times to poll (default is 1) while the second argument may +be given to obtain a more detailed output of the results. This command +is currently just wishful thinking. +.PP +.B keyid +.I # +.PP +This command allows the specification of a key number to be used to +authenticate configuration requests. This must correspond to the +key number the server has been configured to use for this purpose. +.PP +.B passwd +.PP +This command prompts you to type in a password (which will not be +echoed) which will be used to authenticate configuration requests. The +password must correspond to the key configured for use by the NTP +server for this purpose if such requests are to be successful. +.PP +.B "hostnames yes|no" +.PP +If \*(L"yes\*(R" is specified, host names are printed in information +displays. If \*(L"no\*(R" is given, numeric addresses are printed +instead. The default is \*(L"yes\*(R" unless modified using the command +line +.B -n +switch. +.PP +.B quit +.PP +Exit +.IR xntpdc . +.SH QUERY COMMANDS +.PP +Query commands result in NTP mode 7 packets containing requests for +information being sent to the server. These are \*(L"read\-only\*(R" +commands in that they make no modification of the server configuration +state. +.PP +.B listpeers +.PP +Obtains and prints a brief list of the peers for which the +server is maintaining state. These should include all configured +peer associations as well as those peers whose stratum is such that +they are considered by the server to be possible future synchonization +candidates. +.PP +.B peers +.PP +Obtains a list of peers for which the server is maintaining state, along +with a summary of that state. Summary information includes the address +of the remote peer, the local interface address (0.0.0.0 if a local address +has yet to be determined), the stratum of the remote peer (a stratum of +16 indicates the remote peer is unsynchronized), the polling interval, +in seconds, the reachability +register, in octal, and the current estimated delay, offset and dispersion +of the peer, all in seconds. In addition, the character in the left +margin indicates the mode this peer entry is operating in. A +\*(L"+\*(R" denotes symmetric active, a \*(L"-\*(R" indicates symmetric +passive, a \*(L"=\*(R" means the remote server is being polled in +client mode, a \*(L"^\*(R" indicates that the server is broadcasting +to this address, a \*(L"~\*(R" denotes that the remote peer is sending +broadcasts and a \*(L"*\*(R" marks the peer the server is currently +synchonizing to. +.PP +The contents of the host field may be one of four forms. It may be a host name, +an IP address, a reference clock implementation name with its parameter or +\*(L"REFCLK(, )\*(R". On \*(L"hostnames no\*(R" +only IP\-addresses will be displayed. +.PP +.B dmpeers +.PP +A slightly different peer summary list. Identical to the output of the +.B peers +command except for the character in the leftmost column. Characters +only appear beside peers which were included in the final stage of +the clock selection algorithm. A \*(L".\*(R" indicates that this +peer was cast off in the falseticker detection, while a \*(L"+\*(R" +indicates that the peer made it through. A \*(L"*\*(R" denotes the +peer the server is currently synchronizing with. +.PP +.B showpeer +.I peer_address +[ +.I addr2 +] [ +.I addr3 +] [ +.I addr4 +] +.PP +Shows a detailed display of the current peer variables for one or more +peers. Most of these values are described in the NTP Version 2 +specification. +.PP +.B pstats +.I peer_address +[ +.I addr2 +] [ +.I addr3 +] [ +.I addr4 +] +.PP +Show per\-peer statistic counters associated with the specified peer(s). +.PP +.B loopinfo +[ +.B oneline|multiline +] +.PP +Print the values of selected loop filter variables. The loop filter is +the part of NTP which deals with adjusting the local system clock. The +\*(L"offset\*(R" is the last offset given to the loop filter by the +packet processing code. The \*(L"frequency\*(R" is actually the +frequency error, or drift, of your system's clock in the units NTP +uses for internal computations. Dividing this number by 4096 should +give you the actual drift rate. The \*(L"compliance\*(R" is actually +a long term average offset and is used by NTP to control the gain of +the loop filter. The \*(L"timer\*(R" value is the number of seconds +which have elapsed since a new sample offset was given to the loop +filter. The \*(L"oneline\*(R" and \*(L"multiline\*(R" options specify +the format in which this information is to be printed. \*(L"multiline\*(R" +is the default. +.PP +.B sysinfo +.PP +Print a variety of system state variables, i.e. state related to the +local server. Many of these values are described in the NTP Version 2 +specification, RFC 1119. +.PP +.B sysstats +.PP +Print a number of stat counters maintained in the protocol module. +.PP +.B memstats +.PP +Print a number of counters related to the peer memory allocation +code. +.PP +.B iostats +.PP +Print counters maintained in the input\-output module. +.PP +.B timerstats +.PP +Print counters maintained in the timer/event queue support code. +.PP +.B reslist +.PP +Obtain and print the server's restriction list. This list is (usually) +printed in sorted order and may help to understand how the restrictions +are applied. +.PP +.B monlist +.PP +Obtain and print traffic counts collected and maintained by the +monitor facility. +.PP +.B clockinfo +.I clock_peer_address +[ +.I addr2 +] [ +.I addr3 +] [ +.I addr4 +] +.PP +Obtain and print information concerning a peer clock. The values +obtained provide information on the setting of fudge factors and +other clock performance information. +.PP +.B clkbug +.I clock_peer_address +[ +.I addr2 +] [ +.I addr3 +] [ +.I addr4 +] +.PP +Obtain debugging information for a clock peer. This information is +provided only by some clock drivers and is mostly undecodable without +a copy of the driver source in hand. +.SH RUNTIME CONFIGURATION REQUESTS +.PP +All requests which cause state changes in the server are authenticated +by the server using a configured NTP key (the facility can also be +disabled by +the server by not configuring a key). The key number and the corresponding +key must also be made known to +.IR xtnpdc . +This can be done using the +.B keyid +and +.B passwd +commands, the latter of which will prompt at the +terminal for a password to use +as the encryption key. You will also be prompted automatically for +both the key number and password the +first time a command which would result in an authenticated request +to the server is given. Authentication not only provides verification +that the requester has permission to make such changes, but also gives +an extra degree of protection again transmission errors. +.PP +Authenticated requests always include a timestamp in the packet data, which +is included in the computation of the authentication code. This timestamp +is compared by the server to its receive time stamp. If they differ +by more than a small amount the request is rejected. This is done for +two reasons. First, it makes simple replay attacks on the server, by someone +who might be able to overhear traffic on your LAN, much more difficult. +Second, it makes it more difficult to request configuration changes +to your server from topologically remote hosts. While the reconfiguration +facility will work well with a server on the local host, and may work +adequately between time\-synchronized hosts on the same LAN, it will +work very poorly for more distant hosts. As such, if reasonable passwords +are chosen, care is taken in the distribution and protection of keys and +appropriate source address restrictions are applied, the +run time reconfiguration facility should provide an adequate level of +security. +.PP +The following commands all make authenticated requests. +.PP +.B addpeer +.I peer_address +[ +.I keyid +] [ +.I version# +] [ +.B minpoll|prefer +] +.PP +Add a configured, symmetric active peer association with a peer at the +given address. If the optional \*(L"keyid\*(R" is a nonzero integer +all outgoing packets to the remote server will +have an authentication field attached encrypted with this key. If the +value is 0 (or not given) no authentication will be done. The +\*(L"version#\*(R" can be 1 or 2, and defaults to 2. If \*(L"minpoll\*(R" +is specified the polling interval for the association will remain +clamped at the minimum. The latter option is only useful for testing. +Note that an existing association with the same peer may be deleted +when this command is executed, or may simply be converted to conform to +the new configuration, as appropriate. The prefer keyword indicates +a preferred peer (and thus will be used primarily for clock synchronisation +if possible). The preferred peer also determines the validity of the PPS +signal - if the preferred peer is suitable for synchronisation so is the +PPS signal. +.PP +.B addserver +.I peer_address +[ +.I keyid +] [ +.I version# +] [ +.B minpoll|prefer +] +.PP +Identical to the +.B addpeer +command except that polling is done in client mode rather than +symmetric active mode. +.PP +.B broadcast +.I peer_address +[ +.I keyid +] [ +.I version# +] [ +.B minpoll +] +.PP +Identical to the +.B addpeer +command except that packets are instead sent in broadcast mode. The +\*(L"peer_address\*(R" parameter will generally be a broadcast address +on one of your local networks. +.PP +.B unconfig +.I peer_address +[ +.I addr2 +] [ +.I addr3 +] [ +.I addr4 +] +.PP +This command causes the configured bit to be removed from the specified +peer(s). In many cases this will cause the peer association to be +deleted. When appropriate, however, the association may persist in +an unconfigured mode if the remote peer is willing to continue on in +this fashion. +.PP +.B set bclient|auth +[ +.I ... +] +.PP +Allows the setting of the broadcast client and/or authenticate system +flags. Setting the former causes the server to listen for broadcast +NTP to to synchronize to broadcasts when appropriate. Setting the +latter flag causes the server to only synchronize with peers which +include an authentication field encrypted with one of the local server's +trusted keys. +.PP +.B clear bclient|auth +[ +.I ... +] +.PP +Allows the broadcast client and/or authenticate system flags to be +cleared. Clearing the former causes incoming broadcast NTP packets +to be ignored. Clearing the latter allows peers which have not included +an authentication field, or which have included one but have encrypted +it with an untrusted key, to be considered synchronization candidates. +.PP +.B restrict +.I address +.I mask +.I flag +[ +.I flag +] +.PP +Causes flag(s) to be added to an existing restrict list entry, or adds +a new entry to the list with the specified flag(s). The possible choices +for the flags arguments are given in the following list: +.Ip ignore 10 +Ignore all packets from hosts which match this entry. If this flag +is specified neither queries nor time server polls will be responded +to. +.Ip noquery 10 +Ignore all NTP mode 7 packets (i.e. information queries and configuration +requests) from the source. Time service is not affected. +.Ip nomodify 10 +Ignore all NTP mode 7 packets which attempt to modify the state of the +server (i.e. run time reconfiguration). Queries which return information +are permitted. +.Ip noserve 10 +Ignore NTP packets whose mode is other than 7. In effect, time service is +denied, though queries may still be permitted. +.Ip nopeer 10 +Provide stateless time service to polling hosts, but do not allocate peer +memory resources to these hosts even if they otherwise might be considered +useful as future synchronization partners. +.Ip notrust 10 +Treat these hosts normally in other respects, but never use them as +synchronization sources. +.Ip ntpport 10 +This is actually a match algorithm modifier, rather than a restriction +flag. Its presence causes the restriction entry to be matched only if +the source port in the packet is the standard NTP UDP port (123). Both +\*(L"ntpport\*(R" and non\-\*(L"ntpport\*(R" may be specified. The +\*(L"ntpport\*(R" is considered more specific and is sorted later in the +list. +.PP +.B unrestrict +.I address +.I mask +.I flag +[ +.I flag +] +.PP +Remove the specified flag(s) from the restrict list entry indicated +by the +.I address +and +.I mask +arguments. +.PP +.B delrestrict +.I address +.I mask +[ +.B ntpport +] +.PP +Delete the matching entry from the restrict list. +.PP +.B "monitor yes|no" +.PP +Enable or disable the monitoring facility. Note that a +.B "monitor no" +command followed by a +.B "monitor yes" +command is a good way of resetting the packet counts. +.PP +.B readkeys +.PP +Causes the current set of authentication keys to be purged and a +new set to be obtained by rereading the keys file (which must have +been specified in the +.I xntpd +configuration file). This allows encryption keys to be changed without +restarting the server. +.PP +.B trustkey +.I keyid +[ +.I keyid +] [ +.I keyid +] [ +.I keyid +] +.PP +Adds one or more keys to the trusted key list. When authentication +is enabled, peers whose time is to be trusted must be authenticated using +a trusted key. +.PP +.B untrustkey +.I keyid +[ +.I keyid +] [ +.I keyid +] [ +.I keyid +] +.PP +Removes one or more keys from the trusted key list. +.PP +.B authinfo +.PP +Returns information concerning the authentication module, including +known keys and counts of encryptions and decryptions which have been +done. +.PP +.B setprecision +.I precision_value +.PP +Sets the precision which the server advertises to the specified value. This +should be a negative integer in the range -4 through -20. +.PP +.B setselect +.I algorithm_number +.PP +Sets the selection weight algorithm to that indicated by the specified number. +This should be an integer value between 1 and 5 inclusive. Algorithm 1 +is that specified in RFC 1119, the other 4 algorithms are experimental +and should be used with caution. +.SH SEE ALSO +.PP +.IR xntpd (8) +.SH HISTORY +.PP +Written by Dennis Ferguson at the University of Toronto. +.SH BUGS +.PP +.I Xntpdc +is a crude hack. Much of the information it shows is deadly boring +and could only be loved by its implementer. The program was designed +so that new (and temporary) features were easy to hack in, at great +expense to the program's ease of use. Despite this, the program +is occasionally useful. diff --git a/contrib/xntpd/gadget/README b/contrib/xntpd/gadget/README new file mode 100644 index 0000000000..35bbc18ad2 --- /dev/null +++ b/contrib/xntpd/gadget/README @@ -0,0 +1,84 @@ +Gadget Box + +The gadget box is a 5"x3"x2" aluminum minibox containing level-converter +and modem circuitry and intended for use with host time servers +supporting the Network Time Protocol. It includes two subcircuits. One +of these converts a TTL positive edge into a fixed-width pulse at EIA +levels and is for use with a timecode receiver or oscillator including a +TTL one-pulse-per-second (1-pps) output. The other converts the timecode +modulation broadcast by Canadian time/frequency standard station CHU +into a 300-bps serial character stream at EIA levels and is for use with +the clk_chu.c or clk_chu_STREAMS.c modules in the xntp3 distribution. + +This archive contains complete construction details for the gadget box, +including schematic, parts list and artwork for a two-sided, printed- +circuit board. All files are in PostScript, with the exception of this +file and an information file, which are in ASCII. The artwork is in the +1:1 scale and is suitable for direct printing on photographic resist for +each side of the board. While a plated-through-holes process is most +convenient, it is possible to bridge the two sides using soldered wires +where necessary. + +Following is a brief functional description of the device. See the +schematic diagram gadget.s01 for reference. The audio output of a +shortwave radio tuned to CHU at 3330, 7335 or 14670 kHz is connected to +J2. A level of at least 30 mV peak-peak is required, such as provided by +the recorder output on many receivers. The input level is adjusted by +potentiometer R8 so that the timecode modulation broadcast at 31-39 +seconds past the minute reliably lights green LED1, but the signals +broadcast during other seconds of the minute do not. + +Opamp U4A provides low-impedance drive for the bridged-tee bandpass +filter U4B. The filter has a bandpass of about 600 Hz at the 6-dB points +and a center frequency of about 2150 Hz. It is designed to avoid +aliasing effects with receivers of relatively wide bandpass +characteristics. The modem itself is implemented by U2 and its +associated circuitry. Resistors R4 and R1 are a 40-dB pad which matches +the filter output to the modem input. U2 is a TTL/EIA level converter +with integral power supply for bipolar signals. The modem output is +available at pin 3 (receive data) of DB25 connector J1. + +The TTL 1-pps signal is connected via J3 to a retriggerable one-shot +U3A, which generates a TTL pulse of width determined by potentiometer +R7. The pulse width is determined by the bit rate of the attached serial +port. In the common case the width is one bit-time, such as 26 us for +38.4 kbps, for example. This appears to the port as a single start bit +of zero followed by eight bits of ones and a stop bit of one. The second +one-shot U3B generates a 200-ms pulse suitable for driving the amber +LED3 as a visual monitor. The output of U3A is converted to EIA levels +by U1 and appears at pin 12 (secondary receive data) of J1. + +If only the 1-pps circuit is required, U2 and U4 can be deleted and the +gadget box powered from the EIA modem-control signal at pin 20 (terminal +ready) of J1, assuming this signal is placed in the on (positive +voltage) condition by the computer program. J1 is wired to keep most +finicky UARTs and terminal-driver programs happy. If the CHU circuit is +required, an external 12-volt AC transformer or 9-12-volt DC supply +connected to J4 is required. Red LED2 indicates power is supplied to the +box. + +Following is a list of files included in this archive. All files are in +PostScript, except this one (README) and the information file +(gadget.lst), which are in ASCII. The files gadget.s01, gadget.s02 and +gadget.lst were generated using the Schema schematic-capture program +from Omation. The printed-circuit files *.lpr were generated using +Schema-PCB, also from Omation. + +Files +---------------------------------------- +README this file +gadget.s01 circuit schematic +gadget.s02 minibox assembly drawing +gadget.lst net list, pin list, parts list, etc. +gen0102.lpr pcb x-ray diagram +art01.lpr pcb artword side 1 +art02.lpr pcb artwork side 2 +adt0127.lpr pcb assembly drawing +dd0124.lpr pcb drill drawing +sm0228.lpr pcb solder mask (side 2) +sst0126.lpr pcb silkscreen mask (side 1) + +Dave Mills +University of Delaware +6 July 1992 +Revised 21 August 1992 diff --git a/contrib/xntpd/gadget/adt0127.lpr b/contrib/xntpd/gadget/adt0127.lpr new file mode 100644 index 0000000000..f0359e897d --- /dev/null +++ b/contrib/xntpd/gadget/adt0127.lpr @@ -0,0 +1,1427 @@ +%!PS-Adobe-2.0 +%%Title: PADS Postscript Driver Header +%%Creator: Andy Montalvo, 18 Lupine St., Lowell, MA 01851 +%%CreationDate: 06/08/90 +%%For: CAD Software, Littleton, MA +%%EndComments +%%BeginProcSet: Markers 1.0 0 +% marker attributes +/MAttr_Width 1 def +/MAttr_Size 0 def +/MAttr_Type /M1 def +% procedures +/M1 { %def +% draw marker 1: plus +% Stack: - M1 - + -2 0 rmoveto + 4 0 rlineto + -2 2 rmoveto + 0 -4 rlineto +} bind def +/M2 { %def +% draw marker 2: cross +% Stack: - M2 - + -2 -2 rmoveto + 4 4 rlineto + -4 0 rmoveto + 4 -4 rlineto +} bind def +/M3 { %def +% draw marker 3: square +% Stack: - M3 - + 0 2 rlineto + 2 0 rlineto + 0 -4 rlineto + -4 0 rlineto + 0 4 rlineto + 2 0 rlineto +} bind def +/M4 { %def +% draw marker 4: diamond +% Stack: - M4 - + 0 2 rlineto + 2 -2 rlineto + -2 -2 rlineto + -2 2 rlineto + 2 2 rlineto +} bind def +/M5 { %def +% draw marker 5: hourglass +% Stack: - M5 - + 2 2 rlineto + -4 0 rlineto + 4 -4 rlineto + -4 0 rlineto + 2 2 rlineto +} bind def +/M6 { %def +% draw marker 6: bowtie +% Stack: - M6 - + 2 2 rlineto + 0 -4 rlineto + -4 4 rlineto + 0 -4 rlineto + 2 2 rlineto +} bind def +/M7 { %def +% draw marker 7: small plus (goes with char marker) +% Stack: - M7 - + -1 0 rmoveto + 2 0 rlineto + -1 1 rmoveto + 0 -2 rlineto +} bind def +/Marker { %def +% Command from driver: draw marker +% STACK: x y Marker - + MAttr_Size 0 gt + { + gsave + moveto + MAttr_Size 4 div dup scale + MAttr_Type load exec + 4 MAttr_Size div dup scale + MAttr_Width setlinewidth + stroke + grestore + } if +} def +%%EndProcSet: Markers 1.0 0 +%%BeginProcSet: Lib 1.0 0 +/sg { %def +% Command from driver: set the gray scale 0 - 100 +% STACK: greylevel sg + 100 div dup setgray /glev exch def +} bind def +/Circle { %def +% draw a circle +% STACK: x y radius Circle - + 0 360 arc +} bind def +/RndAper { %def +% select a round aperture +% STACK: - RndAper - + 1 setlinejoin + 1 setlinecap +} bind def +/SqrAper { %def +% select a square aperture +% STACK: - SqrAper - + 0 setlinejoin + 2 setlinecap +} bind def +/Line { %def +% draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] Line - + 3 1 roll + moveto + true + exch + % This pushes the x then the y then does lineto + { exch { false } { lineto true } ifelse } forall + pop +} bind def +/Clipto { %def +% set clipping rectangle from 0,0 to new values +% STACK: x y Clipto - + 0 0 moveto + dup 0 exch lineto + 2 copy lineto + pop + 0 lineto + closepath + clip + newpath +} bind def +/Clip4 { %def +% set clipping rectangle from xmin,ymin to xmax,ymax +% STACK: xmin ymin xmax ymax Clip4 - + 4 copy pop pop moveto + 4 copy pop exch lineto pop + 2 copy lineto + exch pop exch pop lineto + closepath + clip + newpath +} bind def +%%EndProcSet: Lib 1.0 0 +%%BeginProcSet: Lines 1.0 0 +% line attributes % +/LAttr_Width 1 def +% line procedures +/PLine { %def +% Cammand from driver: draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + LAttr_Width setlinewidth + stroke +} bind def % PLine +/Char { %def +% Command from driver: draw a character at the current position +% STACK: type x y stroke_array Char - +% stroke array -- [ stroke1 stroke2 ... stroken ] +% stroke -- connected staight lines +% type = 0 if text 1 if marker + gsave + 4 1 roll + translate + 0 eq { TAttr_Width } { MAttr_Width } ifelse setlinewidth + { + dup length 2 gt + { + dup dup 0 get exch 1 get % get starting point + 3 -1 roll % put x y before array + dup length 2 sub 2 exch getinterval % delete first items from array + Line + stroke + } + { + aload pop currentlinewidth 2 div Circle fill + } ifelse + } forall + grestore +} bind def % Char +/PArc { %def +% Command from driver: draw an arc +% STACK: x y radius startangle deltaangle Arc - + 10 div exch 10 div exch + 2 copy pop add + arc + LAttr_Width setlinewidth + stroke +} bind def +/PCircle { %def +% Command from driver: draw an circle +% STACK: x y radius PCircle - + Circle + LAttr_Width setlinewidth + stroke +} bind def +%%EndProcSet: Lines 1.0 0 +%%BeginProcSet: Polygon 1.0 0 +% polygon attributes % +/PAttr_ExtWidth 1 def +/PAttr_IntWidth 1 def +/PAttr_Grid 1 def +% polygon procedures +/LoopSet { %def +% set up for loop condition +% STACK: start end LoopSet low gridwidth high + 2 copy lt { exch } if + % make grid line up to absolute coordinates + PAttr_Grid div truncate PAttr_Grid mul exch + PAttr_Grid exch +} bind def +/Hatch { %def +% draw cross hatch pattern in current path +% STACK: - Hatch - + pathbbox + /ury exch def + /urx exch def + /lly exch def + /llx exch def + clip + newpath + llx urx LoopSet + { % x loop + dup lly exch ury moveto lineto + } for + lly ury LoopSet + { % y loop + llx exch dup urx exch moveto lineto + } for + PAttr_IntWidth setlinewidth + stroke +} bind def +/PPoly { %def +% Command from driver: draw a plygon +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + closepath + gsave + PAttr_IntWidth PAttr_Grid ge {fill} {Hatch} ifelse + grestore + PAttr_ExtWidth setlinewidth + stroke +} bind def +%%EndProcSet: Polygon 1.0 0 +%%BeginProcSet: Text 1.0 0 +% text attributes % +/TAttr_Mirr 0 def +/TAttr_Orient 0 def +/TAttr_Width 1 def +% text procedures +/Text { %def +% Command from driver: Draw text +% STACK: x y width string Text - + gsave + 4 2 roll + translate + TAttr_Mirr 0 gt + { + -1 1 scale + } if + TAttr_Orient rotate + 0 0 moveto + dup length dup 1 gt + { + exch dup stringwidth pop + 4 -1 roll + exch 2 copy + lt + { + div 1 scale show + } + { + sub + 3 -1 roll 1 sub div + 0 3 -1 roll ashow + } + ifelse + } + { + pop + show + } ifelse + grestore +} bind def +%%EndProcSet: Text 1.0 0 +%%BeginProcSet: FlashSymbols 1.0 0 +% flash symbol attributes % +/FAttr_Type /PRndPad def +/FAttr_Width 0 def +/FAttr_Length 1 def +/FAttr_Orient 0 def +% flash symbol procedures +/PRndPad { %def +% Command from driver: draw an circular pad +% STACK: - PCirclePad - + FAttr_Width dup scale + 0 0 .5 Circle + fill +} bind def +/PSqrPad { %def +% Draw an Square pad +% STACK: - PRectPad - + FAttr_Width dup scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/PRectPad { %def +% Draw an rectangular pad +% STACK: - PRectPad - + FAttr_Length FAttr_Width scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/POvalPad { %def +% Draw an oval pad +% STACK: - POvalPad - + FAttr_Width setlinewidth + FAttr_Length FAttr_Width sub 2 div dup + neg 0 moveto + 0 lineto + RndAper + stroke +} bind def +/Anl { %def + 0 0 .5 Circle + fill + FAttr_Length FAttr_Width lt + { % inner circle + 0 0 + FAttr_Length 0 gt { FAttr_Length FAttr_Width div } { .5 } ifelse + 2 div Circle + 1 setgray + fill + glev setgray + } if +} bind def +/PAnlPad { %def +% Draw an annular pad +% STACK: - PAnlPad - + FAttr_Width dup scale + Anl +} bind def +/PRelPad { %def +% Draw an thermal relief pad +% STACK: - PRelPad - + PAnlPad + 1 setgray + .17 setlinewidth + 0 setlinecap % the x + 45 rotate + .5 0 moveto -.5 0 lineto + 0 .5 moveto 0 -.5 lineto + stroke + glev setgray +} bind def +/Flash { %def +% Command from driver: Flash a symbol +% STACK: x y Flash - + FAttr_Width 0 gt + { + gsave + translate + FAttr_Orient rotate + FAttr_Type load exec + grestore + } if +} def +%%EndProcSet: FlashSymbols 1.0 0 +%%BeginProcSet: SetAttr 1.0 0 +/SetLine { %def +% Set the width of the lines +% STACK: linewidth SetLine - + /LAttr_Width exch def + RndAper +} bind def +/SetPoly { %def +% Set attribute of polygon +% STACK: external_width internal_grid_width grid_spacing SetPoly - + /PAttr_Grid exch def + /PAttr_IntWidth exch def + /PAttr_ExtWidth exch def + RndAper +} bind def +/SetFlash { %def +% Set Attributed of flash pad +% STACK: orientation_angle length width aperture_type SetFlash - + /FAttr_Type exch def + FAttr_Type /PSqrPad eq FAttr_Type /PRectPad eq or + { SqrAper } { RndAper } ifelse + /FAttr_Width exch def + /FAttr_Length exch def + /FAttr_Orient exch 10 div def +} bind def +/SetMkr { %def +% Set attributes of markers +% STACK: linewidth size type SetMkr - + /MAttr_Type exch def + /MAttr_Size exch def + /MAttr_Width exch def + RndAper +} bind def +/SetText1 { %def +% Set attributes of text +% STACK: fontname height orient mirror SetMkr - + /TAttr_Mirr exch def + /TAttr_Orient exch 10 div def + exch findfont exch scalefont setfont + RndAper +} bind def +/SetText2 { %def +% Set attributes of text +% STACK: linewidth height mirror orient SetMkr - + /TAttr_Width exch def + RndAper +} bind def +%%EndProcSet: SetAttr 1.0 0 +%%BeginProcSet: Initialize 1.0 0 +/Init { %def +% Initialize the driver +% STACK: Init - + 72 1000 div dup scale % Scale to 1/1000 inch + 250 250 translate % make origin 1/4 inch from bottom left + 1.5 setmiterlimit 1 RndAper % set line defaults + 0 setgray % set color default + /glev 0 def +} def +%%EndProcSet: Initialize 1.0 0 +%%EndProlog +/Helvetica findfont 12 scalefont setfont +35 760 moveto +(gadget.job - Fri Aug 21 03:35:14 1992) show +gsave +Init +8000 10500 Clipto +4025 2626 translate +0 rotate +1 1 div dup scale +75 sg +50 sg +25 sg +0 sg +10 SetLine +-1350 0 [ -1350 4900 ] PLine +-1350 4900 [ 1350 4900 ] PLine +1350 4900 [ 1350 0 ] PLine +1350 0 [ -1350 0 ] PLine +10 SetLine +-1350 4700 [ -1350 4900 ] PLine +-1350 4900 [ -1150 4900 ] PLine +10 SetLine +1150 4900 [ 1350 4900 ] PLine +1350 4900 [ 1350 4700 ] PLine +10 SetLine +1150 0 [ 1350 0 ] PLine +1350 0 [ 1350 200 ] PLine +10 SetLine +-1350 200 [ -1350 0 ] PLine +-1350 0 [ -1150 0 ] PLine +10 SetLine +400 5100 [ 1350 5100 ] PLine +10 SetLine +1350 5100 [ 1300 5150 ] PLine +10 SetLine +1350 5100 [ 1300 5050 ] PLine +10 SetLine +-1525 4900 [ -1375 4900 ] PLine +10 SetLine +-1350 5100 [ -375 5100 ] PLine +10 SetLine +-1350 5100 [ -1300 5150 ] PLine +10 SetLine +-1350 5100 [ -1300 5050 ] PLine +10 SetLine +-1542 0 [ -1367 0 ] PLine +10 SetLine +-1500 0 [ -1500 1965 ] PLine +10 SetLine +-1500 0 [ -1450 50 ] PLine +10 SetLine +-1500 0 [ -1550 50 ] PLine +10 SetLine +-1500 4900 [ -1450 4850 ] PLine +10 SetLine +-1500 4900 [ -1550 4850 ] PLine +10 SetLine +1350 5150 [ 1350 4925 ] PLine +10 SetLine +-1350 5150 [ -1350 4925 ] PLine +10 SetLine +-1500 4900 [ -1500 2750 ] PLine +10 SetLine +-1050 1400 [ -1050 1200 ] PLine +-1050 1200 [ -1150 1200 ] PLine +-1150 1200 [ -1150 1400 ] PLine +-1150 1400 [ -1050 1400 ] PLine +10 SetLine +-50 3300 [ -100 3300 ] PLine +10 SetLine +250 3235 [ -50 3235 ] PLine +-50 3235 [ -50 3365 ] PLine +-50 3365 [ 250 3365 ] PLine +250 3365 [ 250 3235 ] PLine +10 SetLine +300 3300 [ 250 3300 ] PLine +10 SetLine +250 3100 [ 300 3100 ] PLine +10 SetLine +-50 3165 [ 250 3165 ] PLine +250 3165 [ 250 3035 ] PLine +250 3035 [ -50 3035 ] PLine +-50 3035 [ -50 3165 ] PLine +10 SetLine +-100 3100 [ -50 3100 ] PLine +10 SetLine +-50 3500 [ -100 3500 ] PLine +10 SetLine +250 3435 [ -50 3435 ] PLine +-50 3435 [ -50 3565 ] PLine +-50 3565 [ 250 3565 ] PLine +250 3565 [ 250 3435 ] PLine +10 SetLine +300 3500 [ 250 3500 ] PLine +10 SetLine +-1150 3700 [ -1200 3700 ] PLine +10 SetLine +-450 3575 [ -1150 3575 ] PLine +-1150 3575 [ -1150 3825 ] PLine +-1150 3825 [ -450 3825 ] PLine +-450 3825 [ -450 3575 ] PLine +10 SetLine +-400 3700 [ -450 3700 ] PLine +10 SetLine +-850 1300 [ -900 1300 ] PLine +10 SetLine +-150 1175 [ -850 1175 ] PLine +-850 1175 [ -850 1425 ] PLine +-850 1425 [ -150 1425 ] PLine +-150 1425 [ -150 1175 ] PLine +10 SetLine +-100 1300 [ -150 1300 ] PLine +10 SetLine +550 2800 [ 600 2800 ] PLine +10 SetLine +-150 2925 [ 550 2925 ] PLine +550 2925 [ 550 2675 ] PLine +550 2675 [ -150 2675 ] PLine +-150 2675 [ -150 2925 ] PLine +10 SetLine +-200 2800 [ -150 2800 ] PLine +10 SetLine +-450 2800 [ -400 2800 ] PLine +10 SetLine +-1150 2925 [ -450 2925 ] PLine +-450 2925 [ -450 2675 ] PLine +-450 2675 [ -1150 2675 ] PLine +-1150 2675 [ -1150 2925 ] PLine +10 SetLine +-1200 2800 [ -1150 2800 ] PLine +10 SetLine +0 2150 [ 0 2100 ] PLine +10 SetLine +65 2450 [ 65 2150 ] PLine +65 2150 [ -65 2150 ] PLine +-65 2150 [ -65 2450 ] PLine +-65 2450 [ 65 2450 ] PLine +10 SetLine +0 2500 [ 0 2450 ] PLine +10 SetLine +-1200 3050 [ -1200 3000 ] PLine +10 SetLine +-1135 3350 [ -1135 3050 ] PLine +-1135 3050 [ -1265 3050 ] PLine +-1265 3050 [ -1265 3350 ] PLine +-1265 3350 [ -1135 3350 ] PLine +10 SetLine +-1200 3400 [ -1200 3350 ] PLine +10 SetLine +-950 2250 [ -1150 2250 ] PLine +-1150 2250 [ -1150 2350 ] PLine +-1150 2350 [ -950 2350 ] PLine +-950 2350 [ -950 2250 ] PLine +10 SetLine +-1150 2550 [ -950 2550 ] PLine +-950 2550 [ -950 2450 ] PLine +-950 2450 [ -1150 2450 ] PLine +-1150 2450 [ -1150 2550 ] PLine +10 SetLine +850 2850 [ 1050 2850 ] PLine +1050 2850 [ 1050 2750 ] PLine +1050 2750 [ 850 2750 ] PLine +850 2750 [ 850 2850 ] PLine +10 SetLine +500 1900 [ 450 1900 ] PLine +10 SetLine +1200 1775 [ 500 1775 ] PLine +500 1775 [ 500 2025 ] PLine +500 2025 [ 1200 2025 ] PLine +1200 2025 [ 1200 1775 ] PLine +10 SetLine +1250 1900 [ 1200 1900 ] PLine +10 SetLine +-1150 900 [ -1200 900 ] PLine +10 SetLine +-150 725 [ -1150 725 ] PLine +-1150 725 [ -1150 1075 ] PLine +-1150 1075 [ -150 1075 ] PLine +-150 1075 [ -150 725 ] PLine +10 SetLine +-100 900 [ -150 900 ] PLine +10 SetLine +-1050 4000 [ -1100 4000 ] PLine +10 SetLine +-750 3935 [ -1050 3935 ] PLine +-1050 3935 [ -1050 4065 ] PLine +-1050 4065 [ -750 4065 ] PLine +-750 4065 [ -750 3935 ] PLine +10 SetLine +-700 4000 [ -750 4000 ] PLine +10 SetLine +750 3000 [ 700 3000 ] PLine +10 SetLine +1050 2935 [ 750 2935 ] PLine +750 2935 [ 750 3065 ] PLine +750 3065 [ 1050 3065 ] PLine +1050 3065 [ 1050 2935 ] PLine +10 SetLine +1100 3000 [ 1050 3000 ] PLine +10 SetLine +-250 3750 [ -50 3750 ] PLine +-50 3750 [ -50 3650 ] PLine +-50 3650 [ -250 3650 ] PLine +-250 3650 [ -250 3750 ] PLine +10 SetLine +200 900 [ 150 900 ] PLine +10 SetLine +270 950 [ 270 850 ] PLine +10 SetLine +200 850 [ 200 950 ] PLine +200 950 [ 500 950 ] PLine +500 950 [ 500 850 ] PLine +500 850 [ 200 850 ] PLine +10 SetLine +500 900 [ 550 900 ] PLine +10 SetLine +250 850 [ 250 950 ] PLine +10 SetLine +260 850 [ 260 950 ] PLine +10 SetLine +600 3700 [ 650 3700 ] PLine +10 SetLine +530 3650 [ 530 3750 ] PLine +10 SetLine +600 3750 [ 600 3650 ] PLine +600 3650 [ 300 3650 ] PLine +300 3650 [ 300 3750 ] PLine +300 3750 [ 600 3750 ] PLine +10 SetLine +300 3700 [ 250 3700 ] PLine +10 SetLine +550 3750 [ 550 3650 ] PLine +10 SetLine +540 3750 [ 540 3650 ] PLine +10 SetLine +-750 550 100 PCircle +10 SetLine +0 550 100 PCircle +10 SetLine +750 550 100 PCircle +10 SetLine +768 5000 [ 768 5248 ] PLine +768 5248 [ -768 5248 ] PLine +-768 5248 [ -768 5000 ] PLine +10 SetLine +1058 4900 [ -1058 4900 ] PLine +10 SetLine +1058 5000 [ 1058 4408 ] PLine +1058 4408 [ -1058 4408 ] PLine +-1058 4408 [ -1058 5000 ] PLine +-1058 5000 [ 1058 5000 ] PLine +10 SetLine +1058 5000 [ -1058 5000 ] PLine +10 SetLine +768 4900 [ 768 4408 ] PLine +10 SetLine +-768 4900 [ -768 4408 ] PLine +10 SetLine +900 200 [ 1100 200 ] PLine +1100 200 [ 1100 100 ] PLine +1100 100 [ 900 100 ] PLine +900 100 [ 900 200 ] PLine +10 SetLine +-100 200 [ 100 200 ] PLine +100 200 [ 100 100 ] PLine +100 100 [ -100 100 ] PLine +-100 100 [ -100 200 ] PLine +10 SetLine +-1100 200 [ -900 200 ] PLine +-900 200 [ -900 100 ] PLine +-900 100 [ -1100 100 ] PLine +-1100 100 [ -1100 200 ] PLine +10 SetLine +916 3493 [ 900 3456 ] PLine +900 3456 [ 939 3442 ] PLine +939 3442 [ 953 3477 ] PLine +10 SetLine +988 3612 140 PCircle +10 SetLine +-1000 1529 [ -1039 1490 ] PLine +10 SetLine +-1000 1490 [ -1000 1910 ] PLine +-1000 1910 [ -1300 1910 ] PLine +-1300 1910 [ -1300 1490 ] PLine +-1300 1490 [ -1000 1490 ] PLine +10 SetLine +200 1730 [ 200 1670 ] PLine +200 1670 [ 0 1670 ] PLine +0 1670 [ 0 1730 ] PLine +0 1730 [ 200 1730 ] PLine +10 SetLine +200 1700 [ 260 1700 ] PLine +10 SetLine +0 1700 [ -50 1700 ] PLine +10 SetLine +300 1270 [ 300 1330 ] PLine +300 1330 [ 500 1330 ] PLine +500 1330 [ 500 1270 ] PLine +500 1270 [ 300 1270 ] PLine +10 SetLine +300 1300 [ 240 1300 ] PLine +10 SetLine +500 1300 [ 550 1300 ] PLine +10 SetLine +-600 2270 [ -600 2330 ] PLine +-600 2330 [ -400 2330 ] PLine +-400 2330 [ -400 2270 ] PLine +-400 2270 [ -600 2270 ] PLine +10 SetLine +-600 2300 [ -660 2300 ] PLine +10 SetLine +-400 2300 [ -350 2300 ] PLine +10 SetLine +-800 4230 [ -800 4170 ] PLine +-800 4170 [ -1000 4170 ] PLine +-1000 4170 [ -1000 4230 ] PLine +-1000 4230 [ -800 4230 ] PLine +10 SetLine +-800 4200 [ -740 4200 ] PLine +10 SetLine +-1000 4200 [ -1050 4200 ] PLine +10 SetLine +1000 3230 [ 1000 3170 ] PLine +1000 3170 [ 800 3170 ] PLine +800 3170 [ 800 3230 ] PLine +800 3230 [ 1000 3230 ] PLine +10 SetLine +1000 3200 [ 1060 3200 ] PLine +10 SetLine +800 3200 [ 750 3200 ] PLine +10 SetLine +-600 2470 [ -600 2530 ] PLine +-600 2530 [ -400 2530 ] PLine +-400 2530 [ -400 2470 ] PLine +-400 2470 [ -600 2470 ] PLine +10 SetLine +-600 2500 [ -660 2500 ] PLine +10 SetLine +-400 2500 [ -350 2500 ] PLine +10 SetLine +-600 2070 [ -600 2130 ] PLine +-600 2130 [ -400 2130 ] PLine +-400 2130 [ -400 2070 ] PLine +-400 2070 [ -600 2070 ] PLine +10 SetLine +-600 2100 [ -660 2100 ] PLine +10 SetLine +-400 2100 [ -350 2100 ] PLine +10 SetLine +-900 2130 [ -900 2070 ] PLine +-900 2070 [ -1100 2070 ] PLine +-1100 2070 [ -1100 2130 ] PLine +-1100 2130 [ -900 2130 ] PLine +10 SetLine +-900 2100 [ -840 2100 ] PLine +10 SetLine +-1100 2100 [ -1150 2100 ] PLine +10 SetLine +500 1130 [ 500 1070 ] PLine +500 1070 [ 300 1070 ] PLine +300 1070 [ 300 1130 ] PLine +300 1130 [ 500 1130 ] PLine +10 SetLine +500 1100 [ 560 1100 ] PLine +10 SetLine +300 1100 [ 250 1100 ] PLine +10 SetLine +1000 2521 [ 1039 2560 ] PLine +10 SetLine +1000 2560 [ 1000 2140 ] PLine +1000 2140 [ 1300 2140 ] PLine +1300 2140 [ 1300 2560 ] PLine +1300 2560 [ 1000 2560 ] PLine +10 SetLine +0 1870 [ 0 1930 ] PLine +0 1930 [ 200 1930 ] PLine +200 1930 [ 200 1870 ] PLine +200 1870 [ 0 1870 ] PLine +10 SetLine +0 1900 [ -60 1900 ] PLine +10 SetLine +200 1900 [ 250 1900 ] PLine +10 SetLine +100 1470 [ 100 1530 ] PLine +100 1530 [ 300 1530 ] PLine +300 1530 [ 300 1470 ] PLine +300 1470 [ 100 1470 ] PLine +10 SetLine +100 1500 [ 40 1500 ] PLine +10 SetLine +300 1500 [ 350 1500 ] PLine +10 SetLine +-950 1650 [ -250 1650 ] PLine +-250 1650 [ -250 1850 ] PLine +-250 1850 [ -950 1850 ] PLine +-950 1850 [ -950 1775 ] PLine +-950 1775 [ -900 1775 ] PLine +-900 1775 [ -900 1725 ] PLine +-900 1725 [ -950 1725 ] PLine +-950 1725 [ -950 1650 ] PLine +10 SetLine +150 2250 [ 950 2250 ] PLine +950 2250 [ 950 2450 ] PLine +950 2450 [ 150 2450 ] PLine +150 2450 [ 150 2375 ] PLine +150 2375 [ 200 2375 ] PLine +200 2375 [ 200 2325 ] PLine +200 2325 [ 150 2325 ] PLine +150 2325 [ 150 2250 ] PLine +10 SetLine +150 3950 [ 1150 3950 ] PLine +1150 3950 [ 1150 4150 ] PLine +1150 4150 [ 150 4150 ] PLine +150 4150 [ 150 4075 ] PLine +150 4075 [ 200 4075 ] PLine +200 4075 [ 200 4025 ] PLine +200 4025 [ 150 4025 ] PLine +150 4025 [ 150 3950 ] PLine +10 SetLine +-1050 3150 [ -250 3150 ] PLine +-250 3150 [ -250 3350 ] PLine +-250 3350 [ -1050 3350 ] PLine +-1050 3350 [ -1050 3275 ] PLine +-1050 3275 [ -1000 3275 ] PLine +-1000 3275 [ -1000 3225 ] PLine +-1000 3225 [ -1050 3225 ] PLine +-1050 3225 [ -1050 3150 ] PLine +10 SetLine +800 1075 [ 800 1675 ] PLine +800 1675 [ 1200 1675 ] PLine +1200 1675 [ 1200 1075 ] PLine +1200 1075 [ 800 1075 ] PLine +10 SetLine +875 1075 [ 875 825 ] PLine +875 825 [ 925 825 ] PLine +925 825 [ 925 1075 ] PLine +10 SetLine +1075 1075 [ 1075 825 ] PLine +1075 825 [ 1125 825 ] PLine +1125 825 [ 1125 1075 ] PLine +10 SetLine +975 1075 [ 975 825 ] PLine +975 825 [ 1025 825 ] PLine +1025 825 [ 1025 1075 ] PLine +10 SetLine +996 1549 75 PCircle +10 SetLine +800 1425 [ 1200 1425 ] PLine +10 SetLine +-100 4200 [ -25 4200 ] PLine +10 SetLine +-100 3900 [ -100 4300 ] PLine +-100 4300 [ -500 4300 ] PLine +-500 4300 [ -500 3900 ] PLine +-500 3900 [ -100 3900 ] PLine +10 SetLine +-100 4000 [ -25 4000 ] PLine +10 SetLine +-1100 450 100 PCircle +10 SetLine +1100 450 100 PCircle +10 SetLine +1000 3430 [ 1000 3370 ] PLine +1000 3370 [ 800 3370 ] PLine +800 3370 [ 800 3430 ] PLine +800 3430 [ 1000 3430 ] PLine +10 SetLine +1000 3400 [ 1060 3400 ] PLine +10 SetLine +800 3400 [ 750 3400 ] PLine +10 SetText2 +0 -1175 1225 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -1175 1279 [ [ -53 0 -56 4 -65 11 0 11 ] ] Char +0 -1175 1310 [ [ -65 29 -65 6 -37 4 -40 6 -43 13 -43 20 -40 27 -34 31 -25 34 -18 31 -9 29 -3 25 0 18 0 11 -3 4 -6 2 -12 0 ] ] Char +10 SetText2 +0 75 3375 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 129 3375 [ [ 27 56 25 62 18 65 13 65 6 62 2 53 0 37 0 21 2 9 6 3 13 0 15 0 22 3 27 9 29 18 29 21 27 31 22 37 15 40 13 40 6 37 2 31 0 21 ] ] Char +10 SetText2 +0 75 3175 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 129 3175 [ [ 31 65 9 0 ] [ 0 65 31 65 ] ] Char +10 SetText2 +0 75 3575 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 129 3575 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -825 3850 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -771 3850 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -575 1450 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -521 1450 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -490 1450 [ [ 27 56 25 62 18 65 13 65 6 62 2 53 0 37 0 21 2 9 6 3 13 0 15 0 22 3 27 9 29 18 29 21 27 31 22 37 15 40 13 40 6 37 2 31 0 21 ] ] Char +10 SetText2 +0 125 2950 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 179 2950 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 210 2950 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -825 2950 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -771 2950 [ [ 29 43 27 34 22 28 15 25 13 25 6 28 2 34 0 43 0 46 2 56 6 62 13 65 15 65 22 62 27 56 29 43 29 28 27 12 22 3 15 0 11 0 4 3 2 9 ] ] Char +10 SetText2 +0 -100 2250 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -100 2304 [ [ -53 0 -56 4 -65 11 0 11 ] ] Char +0 -100 2335 [ [ -65 4 -65 29 -40 15 -40 22 -37 27 -34 29 -25 31 -18 31 -9 29 -3 25 0 18 0 11 -3 4 -6 2 -12 0 ] ] Char +10 SetText2 +0 -1275 3200 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -1275 3254 [ [ -50 2 -53 2 -59 4 -62 6 -65 11 -65 20 -62 25 -59 27 -53 29 -46 29 -40 27 -31 22 0 0 0 31 ] ] Char +10 SetText2 +0 -1100 2375 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -1046 2375 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -1015 2375 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1100 2575 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -1046 2575 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -1015 2575 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 900 2875 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 954 2875 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 985 2875 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 800 2050 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 854 2050 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 885 2050 [ [ 31 65 9 0 ] [ 0 65 31 65 ] ] Char +10 SetText2 +0 -675 1100 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -621 1100 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -590 1100 [ [ 11 65 4 62 2 56 2 50 4 43 9 40 18 37 25 34 29 28 31 21 31 12 29 6 27 3 20 0 11 0 4 3 2 6 0 12 0 21 2 28 6 34 13 37 22 40 27 43 29 50 29 56 27 62 20 65 11 65 ] ] Char +10 SetText2 +0 -925 4075 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -871 4075 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 875 3075 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 929 3075 [ [ 11 65 4 62 2 56 2 50 4 43 9 40 18 37 25 34 29 28 31 21 31 12 29 6 27 3 20 0 11 0 4 3 2 6 0 12 0 21 2 28 6 34 13 37 22 40 27 43 29 50 29 56 27 62 20 65 11 65 ] ] Char +10 SetText2 +0 -200 3775 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -146 3775 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 325 975 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 377 975 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 450 3775 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 502 3775 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -775 675 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 -732 675 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -50 675 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 -7 675 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 700 675 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 743 675 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 -1175 4650 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 -1132 4650 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1125 125 [ [ 0 65 0 0 27 0 ] ] Char +0 1172 125 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 1222 125 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 1274 125 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 125 125 [ [ 0 65 0 0 27 0 ] ] Char +0 172 125 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 222 125 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 274 125 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -875 125 [ [ 0 65 0 0 27 0 ] ] Char +0 -828 125 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -778 125 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -726 125 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1075 3425 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] [ 20 12 34 -6 ] ] Char +0 1131 3425 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1075 1475 [ [ 0 -65 0 0 ] [ 0 -65 -20 -65 -27 -62 -29 -59 -31 -53 -31 -46 -29 -40 -27 -37 -20 -34 0 -34 ] [ -15 -34 -31 0 ] ] Char +0 -1127 1475 [ [ -11 -65 -4 -62 -2 -56 -2 -50 -4 -43 -9 -40 -18 -37 -25 -34 -29 -28 -31 -21 -31 -12 -29 -6 -27 -3 -20 0 -11 0 -4 -3 -2 -6 0 -12 0 -21 -2 -28 -6 -34 -13 -37 -22 -40 -27 -43 -29 -50 -29 -56 -27 -62 -20 -65 -11 -65 ] ] Char +10 SetText2 +0 25 1750 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 77 1750 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 108 1750 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 350 1350 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 402 1350 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 433 1350 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -550 2350 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -498 2350 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 -925 4250 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -873 4250 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 850 3250 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 902 3250 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -550 2550 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -498 2550 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -550 2150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -498 2150 [ [ 27 56 25 62 18 65 13 65 6 62 2 53 0 37 0 21 2 9 6 3 13 0 15 0 22 3 27 9 29 18 29 21 27 31 22 37 15 40 13 40 6 37 2 31 0 21 ] ] Char +10 SetText2 +0 -1025 2150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -973 2150 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 350 1150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 402 1150 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 433 1150 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 1200 2125 [ [ 0 -65 0 0 ] [ 0 -65 -20 -65 -27 -62 -29 -59 -31 -53 -31 -46 -29 -40 -27 -37 -20 -34 0 -34 ] [ -15 -34 -31 0 ] ] Char +0 1148 2125 [ [ -31 -65 -9 0 ] [ 0 -65 -31 -65 ] ] Char +10 SetText2 +0 50 1950 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 102 1950 [ [ 29 43 27 34 22 28 15 25 13 25 6 28 2 34 0 43 0 46 2 56 6 62 13 65 15 65 22 62 27 56 29 43 29 28 27 12 22 3 15 0 11 0 4 3 2 9 ] ] Char +10 SetText2 +0 150 1550 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 202 1550 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 233 1550 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -675 1950 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 -623 1950 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 450 2550 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 502 2550 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 500 4275 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 552 4275 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -675 3450 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 -623 3450 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 950 1700 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 1002 1700 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -350 4325 [ [ 0 65 31 0 ] [ 31 65 0 0 ] ] Char +0 -298 4325 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1225 600 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 -1169 600 [ [ 0 65 0 0 ] [ 31 65 31 0 ] [ 0 34 31 34 ] ] Char +0 -1117 600 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1125 600 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 1181 600 [ [ 0 65 0 0 ] [ 31 65 31 0 ] [ 0 34 31 34 ] ] Char +0 1233 600 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 800 3450 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 852 3450 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 883 3450 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 -1075 1225 [ [ -65 0 0 0 ] [ -65 0 -65 15 -62 22 -56 27 -50 29 -40 31 -25 31 -15 29 -9 27 -3 22 0 15 0 0 ] ] Char +0 -1075 1277 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -1075 1331 [ [ -65 18 0 0 ] [ -65 18 0 36 ] [ -21 6 -21 29 ] ] Char +0 -1075 1387 [ [ -65 0 0 0 ] [ -65 0 -65 20 -62 27 -59 29 -53 31 -43 31 -37 29 -34 27 -31 20 -31 0 ] ] Char +10 SetText2 +0 75 3275 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 127 3275 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 181 3275 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 237 3275 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 289 3275 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +10 SetText2 +0 75 3075 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 127 3075 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 181 3075 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 237 3075 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 289 3075 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +10 SetText2 +0 75 3475 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 127 3475 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 181 3475 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 237 3475 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 289 3475 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +10 SetText2 +0 -825 3750 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -771 3750 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -715 3750 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 -663 3750 [ [ 0 78 40 -21 ] ] Char +0 -602 3750 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 -546 3750 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -490 3750 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +0 -436 3750 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 -575 1350 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -521 1350 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -465 1350 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 -413 1350 [ [ 0 78 40 -21 ] ] Char +0 -352 1350 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 -296 1350 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -240 1350 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +0 -186 1350 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 125 2850 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 179 2850 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 235 2850 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 287 2850 [ [ 0 78 40 -21 ] ] Char +0 348 2850 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 404 2850 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 460 2850 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +0 514 2850 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 -825 2850 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -771 2850 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -715 2850 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 -663 2850 [ [ 0 78 40 -21 ] ] Char +0 -602 2850 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 -546 2850 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -490 2850 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +0 -436 2850 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 0 2250 [ [ -65 0 0 0 ] [ -65 0 -65 15 -62 22 -56 27 -50 29 -40 31 -25 31 -15 29 -9 27 -3 22 0 15 0 0 ] ] Char +0 0 2302 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 0 2356 [ [ -65 18 0 0 ] [ -65 18 0 36 ] [ -21 6 -21 29 ] ] Char +0 0 2412 [ [ -65 0 0 0 ] [ -65 0 -65 20 -62 27 -59 29 -53 31 -43 31 -37 29 -34 27 -31 20 -31 0 ] ] Char +0 0 2464 [ [ -65 0 0 0 ] [ -65 0 -65 29 ] [ -34 0 -34 18 ] [ 0 0 0 29 ] ] Char +10 SetText2 +0 -1175 3200 [ [ -65 0 0 0 ] [ -65 0 -65 15 -62 22 -56 27 -50 29 -40 31 -25 31 -15 29 -9 27 -3 22 0 15 0 0 ] ] Char +0 -1175 3252 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -1175 3306 [ [ -65 18 0 0 ] [ -65 18 0 36 ] [ -21 6 -21 29 ] ] Char +0 -1175 3362 [ [ -65 0 0 0 ] [ -65 0 -65 20 -62 27 -59 29 -53 31 -43 31 -37 29 -34 27 -31 20 -31 0 ] ] Char +0 -1175 3414 [ [ -65 0 0 0 ] [ -65 0 -65 29 ] [ -34 0 -34 18 ] [ 0 0 0 29 ] ] Char +10 SetText2 +0 -1100 2275 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -1048 2275 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -994 2275 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -938 2275 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +10 SetText2 +0 -1100 2475 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -1048 2475 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -994 2475 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -938 2475 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +10 SetText2 +0 900 2775 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 952 2775 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 1006 2775 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 1062 2775 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +10 SetText2 +0 800 1950 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 854 1950 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 910 1950 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 962 1950 [ [ 0 78 40 -21 ] ] Char +0 1023 1950 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 1079 1950 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 1135 1950 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +0 1189 1950 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 -675 1000 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -621 1000 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -565 1000 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 -513 1000 [ [ 0 78 40 -21 ] ] Char +0 -452 1000 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 -396 1000 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -340 1000 [ [ 27 56 25 62 18 65 13 65 6 62 2 53 0 37 0 21 2 9 6 3 13 0 15 0 22 3 27 9 29 18 29 21 27 31 22 37 15 40 13 40 6 37 2 31 0 21 ] ] Char +0 -290 1000 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 -925 3975 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -873 3975 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -819 3975 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -763 3975 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 -711 3975 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +10 SetText2 +0 875 2975 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 927 2975 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 981 2975 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 1037 2975 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 1089 2975 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +10 SetText2 +0 -200 3675 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -148 3675 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -94 3675 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -38 3675 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +10 SetText2 +0 325 875 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 377 875 [ [ 0 65 0 0 ] ] Char +0 397 875 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +0 453 875 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 505 875 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +10 SetText2 +0 450 3675 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 502 3675 [ [ 0 65 0 0 ] ] Char +0 522 3675 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +0 578 3675 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 630 3675 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +10 SetText2 +0 -775 575 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -723 575 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 ] [ 0 34 20 34 27 31 29 28 31 21 31 12 29 6 27 3 20 0 0 0 ] ] Char +0 -671 575 [ [ 0 65 0 0 ] [ 0 65 31 0 ] [ 31 65 31 0 ] ] Char +0 -619 575 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +10 SetText2 +0 -50 575 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 2 575 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 ] [ 0 34 20 34 27 31 29 28 31 21 31 12 29 6 27 3 20 0 0 0 ] ] Char +0 54 575 [ [ 0 65 0 0 ] [ 0 65 31 0 ] [ 31 65 31 0 ] ] Char +0 106 575 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +10 SetText2 +0 700 575 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 752 575 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 ] [ 0 34 20 34 27 31 29 28 31 21 31 12 29 6 27 3 20 0 0 0 ] ] Char +0 804 575 [ [ 0 65 0 0 ] [ 0 65 31 0 ] [ 31 65 31 0 ] ] Char +0 856 575 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +10 SetText2 +0 -1175 4550 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -1121 4550 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +0 -1065 4550 [ [ 0 65 0 0 ] [ 0 65 31 0 ] [ 31 65 31 0 ] ] Char +0 -1013 4550 [ [ 0 78 40 -21 ] ] Char +0 -952 4550 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -900 4550 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 ] [ 0 34 20 34 27 31 29 28 31 21 31 12 29 6 27 3 20 0 0 0 ] ] Char +0 -848 4550 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +0 -796 4550 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +0 -742 4550 [ [ 0 65 0 0 ] [ 31 65 31 0 ] [ 0 34 31 34 ] ] Char +0 -690 4550 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] ] Char +10 SetText2 +0 1125 25 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 1177 25 [ [ 0 65 0 0 27 0 ] ] Char +0 1224 25 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 1274 25 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +10 SetText2 +0 125 25 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 177 25 [ [ 0 65 0 0 27 0 ] ] Char +0 224 25 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 274 25 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +10 SetText2 +0 -875 25 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -823 25 [ [ 0 65 0 0 27 0 ] ] Char +0 -776 25 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -726 25 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +10 SetText2 +0 1075 3325 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +0 1127 3325 [ [ 0 65 0 0 ] [ 0 65 31 0 ] [ 31 65 31 0 ] ] Char +0 1179 3325 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +0 1231 3325 [ [ 29 43 27 34 22 28 15 25 13 25 6 28 2 34 0 43 0 46 2 56 6 62 13 65 15 65 22 62 27 56 29 43 29 28 27 12 22 3 15 0 11 0 4 3 2 9 ] ] Char +0 1281 3325 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +0 1333 3325 [ [ 31 65 9 0 ] [ 0 65 31 65 ] ] Char +10 SetText2 +0 -1075 1575 [ [ 0 -65 0 0 ] [ 0 -65 -15 -65 -22 -62 -27 -56 -29 -50 -31 -40 -31 -25 -29 -15 -27 -9 -22 -3 -15 0 0 0 ] ] Char +0 -1127 1575 [ [ 0 -65 0 0 ] [ 0 -65 -20 -65 -27 -62 -29 -59 -31 -53 -31 -43 -29 -37 -27 -34 -20 -31 0 -31 ] ] Char +0 -1179 1575 [ [ -13 -65 -9 -62 -4 -56 -2 -50 0 -40 0 -25 -2 -15 -4 -9 -9 -3 -13 0 -22 0 -27 -3 -31 -9 -34 -15 -36 -25 -36 -40 -34 -50 -31 -56 -27 -62 -22 -65 -13 -65 ] ] Char +0 -1235 1575 [ [ -15 -65 -15 0 ] [ 0 -65 -31 -65 ] ] Char +10 SetText2 +0 25 1650 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 77 1650 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 129 1650 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 179 1650 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 350 1250 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 402 1250 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 454 1250 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 504 1250 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 -550 2250 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -498 2250 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -446 2250 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -396 2250 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 -925 4150 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -873 4150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -821 4150 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -771 4150 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 850 3150 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 902 3150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 954 3150 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 1004 3150 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 -550 2450 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -498 2450 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -446 2450 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -396 2450 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 -550 2050 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -498 2050 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -446 2050 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -396 2050 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 -1025 2050 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -973 2050 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -921 2050 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -871 2050 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 350 1050 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 402 1050 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 454 1050 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 504 1050 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 1200 2225 [ [ 0 -65 0 0 ] [ 0 -65 -15 -65 -22 -62 -27 -56 -29 -50 -31 -40 -31 -25 -29 -15 -27 -9 -22 -3 -15 0 0 0 ] ] Char +0 1148 2225 [ [ 0 -65 0 0 ] [ 0 -65 -20 -65 -27 -62 -29 -59 -31 -53 -31 -43 -29 -37 -27 -34 -20 -31 0 -31 ] ] Char +0 1096 2225 [ [ -13 -65 -9 -62 -4 -56 -2 -50 0 -40 0 -25 -2 -15 -4 -9 -9 -3 -13 0 -22 0 -27 -3 -31 -9 -34 -15 -36 -25 -36 -40 -34 -50 -31 -56 -27 -62 -22 -65 -13 -65 ] ] Char +0 1040 2225 [ [ -15 -65 -15 0 ] [ 0 -65 -31 -65 ] ] Char +10 SetText2 +0 50 1850 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 102 1850 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 154 1850 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 204 1850 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 150 1450 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 202 1450 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 254 1450 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 304 1450 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 -675 1850 [ [ 0 65 0 0 27 0 ] ] Char +0 -628 1850 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 -572 1850 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +0 -520 1850 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +0 -468 1850 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 450 2450 [ [ 31 65 9 0 ] [ 0 65 31 65 ] ] Char +0 502 2450 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +0 556 2450 [ [ 0 65 0 0 27 0 ] ] Char +0 603 2450 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +0 655 2450 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 686 2450 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +0 738 2450 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 500 4175 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 556 4175 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 610 4175 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 641 4175 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +0 695 4175 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +0 749 4175 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +0 803 4175 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +0 857 4175 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -675 3350 [ [ 0 65 0 0 ] ] Char +0 -655 3350 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -601 3350 [ [ 0 65 0 0 27 0 ] ] Char +0 -554 3350 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +0 -502 3350 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +0 -450 3350 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 950 1600 [ [ 0 65 0 0 27 0 ] ] Char +0 997 1600 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 1053 1600 [ [ 31 65 9 0 ] [ 0 65 31 65 ] ] Char +0 1105 1600 [ [ 11 65 4 62 2 56 2 50 4 43 9 40 18 37 25 34 29 28 31 21 31 12 29 6 27 3 20 0 11 0 4 3 2 6 0 12 0 21 2 28 6 34 13 37 22 40 27 43 29 50 29 56 27 62 20 65 11 65 ] ] Char +0 1157 1600 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +0 1209 1600 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -350 4225 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -298 4225 [ [ 0 65 31 0 ] [ 31 65 0 0 ] ] Char +0 -246 4225 [ [ 15 65 15 0 ] [ 0 65 31 65 ] ] Char +0 -194 4225 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -138 4225 [ [ 0 65 0 0 27 0 ] ] Char +10 SetText2 +0 -1225 500 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 -1169 500 [ [ 15 65 15 0 ] [ 0 65 31 65 ] ] Char +0 -1117 500 [ [ 0 65 0 0 ] [ 31 65 31 0 ] [ 0 34 31 34 ] ] Char +0 -1065 500 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +0 -1009 500 [ [ 0 65 0 0 27 0 ] ] Char +0 -962 500 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -912 500 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +0 -860 500 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 1125 500 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 1181 500 [ [ 15 65 15 0 ] [ 0 65 31 65 ] ] Char +0 1233 500 [ [ 0 65 0 0 ] [ 31 65 31 0 ] [ 0 34 31 34 ] ] Char +0 1285 500 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +0 1341 500 [ [ 0 65 0 0 27 0 ] ] Char +0 1388 500 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 1438 500 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +0 1490 500 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 800 3350 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 852 3350 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 904 3350 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 954 3350 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 -300 4725 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +0 -248 4725 [ [ 0 65 0 0 ] ] Char +0 -228 4725 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -176 4725 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -74 4725 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -300 5075 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +0 -248 5075 [ [ 2 6 0 3 2 0 4 3 2 6 ] ] Char +0 -223 5075 [ [ 31 65 9 0 ] [ 0 65 31 65 ] ] Char +0 -171 5075 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +0 -119 5075 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +0 -15 5075 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +0 46 5075 [ [ 40 78 0 -21 ] ] Char +0 107 5075 [ [ 0 28 40 28 ] ] Char +0 220 5075 [ [ 2 6 0 3 2 0 4 3 2 6 ] ] Char +0 245 5075 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +0 297 5075 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +0 349 5075 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1475 2025 [ [ -65 22 -21 0 -21 34 ] [ -65 22 0 22 ] ] Char +0 -1475 2079 [ [ -6 2 -3 0 0 2 -3 4 -6 2 ] ] Char +0 -1475 2104 [ [ -43 29 -34 27 -28 22 -25 15 -25 13 -28 6 -34 2 -43 0 -46 0 -56 2 -62 6 -65 13 -65 15 -62 22 -56 27 -43 29 -28 29 -12 27 -3 22 0 15 0 11 -3 4 -9 2 ] ] Char +0 -1475 2154 [ [ -65 13 -62 6 -53 2 -37 0 -28 0 -12 2 -3 6 0 13 0 18 -3 25 -12 29 -28 31 -37 31 -53 29 -62 25 -65 18 -65 13 ] ] Char +0 -1475 2206 [ [ -65 13 -62 6 -53 2 -37 0 -28 0 -12 2 -3 6 0 13 0 18 -3 25 -12 29 -28 31 -37 31 -53 29 -62 25 -65 18 -65 13 ] ] Char +0 -1475 2310 [ [ -56 20 0 20 ] [ -28 0 -28 40 ] ] Char +0 -1475 2371 [ [ -78 40 21 0 ] ] Char +0 -1475 2432 [ [ -28 0 -28 40 ] ] Char +0 -1475 2545 [ [ -6 2 -3 0 0 2 -3 4 -6 2 ] ] Char +0 -1475 2570 [ [ -65 13 -62 6 -53 2 -37 0 -28 0 -12 2 -3 6 0 13 0 18 -3 25 -12 29 -28 31 -37 31 -53 29 -62 25 -65 18 -65 13 ] ] Char +0 -1475 2622 [ [ -65 13 -62 6 -53 2 -37 0 -28 0 -12 2 -3 6 0 13 0 18 -3 25 -12 29 -28 31 -37 31 -53 29 -62 25 -65 18 -65 13 ] ] Char +0 -1475 2674 [ [ -53 0 -56 4 -65 11 0 11 ] ] Char +grestore +showpage diff --git a/contrib/xntpd/gadget/art01.lpr b/contrib/xntpd/gadget/art01.lpr new file mode 100644 index 0000000000..d770fed357 --- /dev/null +++ b/contrib/xntpd/gadget/art01.lpr @@ -0,0 +1,890 @@ +%!PS-Adobe-2.0 +%%Title: PADS Postscript Driver Header +%%Creator: Andy Montalvo, 18 Lupine St., Lowell, MA 01851 +%%CreationDate: 06/08/90 +%%For: CAD Software, Littleton, MA +%%EndComments +%%BeginProcSet: Markers 1.0 0 +% marker attributes +/MAttr_Width 1 def +/MAttr_Size 0 def +/MAttr_Type /M1 def +% procedures +/M1 { %def +% draw marker 1: plus +% Stack: - M1 - + -2 0 rmoveto + 4 0 rlineto + -2 2 rmoveto + 0 -4 rlineto +} bind def +/M2 { %def +% draw marker 2: cross +% Stack: - M2 - + -2 -2 rmoveto + 4 4 rlineto + -4 0 rmoveto + 4 -4 rlineto +} bind def +/M3 { %def +% draw marker 3: square +% Stack: - M3 - + 0 2 rlineto + 2 0 rlineto + 0 -4 rlineto + -4 0 rlineto + 0 4 rlineto + 2 0 rlineto +} bind def +/M4 { %def +% draw marker 4: diamond +% Stack: - M4 - + 0 2 rlineto + 2 -2 rlineto + -2 -2 rlineto + -2 2 rlineto + 2 2 rlineto +} bind def +/M5 { %def +% draw marker 5: hourglass +% Stack: - M5 - + 2 2 rlineto + -4 0 rlineto + 4 -4 rlineto + -4 0 rlineto + 2 2 rlineto +} bind def +/M6 { %def +% draw marker 6: bowtie +% Stack: - M6 - + 2 2 rlineto + 0 -4 rlineto + -4 4 rlineto + 0 -4 rlineto + 2 2 rlineto +} bind def +/M7 { %def +% draw marker 7: small plus (goes with char marker) +% Stack: - M7 - + -1 0 rmoveto + 2 0 rlineto + -1 1 rmoveto + 0 -2 rlineto +} bind def +/Marker { %def +% Command from driver: draw marker +% STACK: x y Marker - + MAttr_Size 0 gt + { + gsave + moveto + MAttr_Size 4 div dup scale + MAttr_Type load exec + 4 MAttr_Size div dup scale + MAttr_Width setlinewidth + stroke + grestore + } if +} def +%%EndProcSet: Markers 1.0 0 +%%BeginProcSet: Lib 1.0 0 +/sg { %def +% Command from driver: set the gray scale 0 - 100 +% STACK: greylevel sg + 100 div dup setgray /glev exch def +} bind def +/Circle { %def +% draw a circle +% STACK: x y radius Circle - + 0 360 arc +} bind def +/RndAper { %def +% select a round aperture +% STACK: - RndAper - + 1 setlinejoin + 1 setlinecap +} bind def +/SqrAper { %def +% select a square aperture +% STACK: - SqrAper - + 0 setlinejoin + 2 setlinecap +} bind def +/Line { %def +% draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] Line - + 3 1 roll + moveto + true + exch + % This pushes the x then the y then does lineto + { exch { false } { lineto true } ifelse } forall + pop +} bind def +/Clipto { %def +% set clipping rectangle from 0,0 to new values +% STACK: x y Clipto - + 0 0 moveto + dup 0 exch lineto + 2 copy lineto + pop + 0 lineto + closepath + clip + newpath +} bind def +/Clip4 { %def +% set clipping rectangle from xmin,ymin to xmax,ymax +% STACK: xmin ymin xmax ymax Clip4 - + 4 copy pop pop moveto + 4 copy pop exch lineto pop + 2 copy lineto + exch pop exch pop lineto + closepath + clip + newpath +} bind def +%%EndProcSet: Lib 1.0 0 +%%BeginProcSet: Lines 1.0 0 +% line attributes % +/LAttr_Width 1 def +% line procedures +/PLine { %def +% Cammand from driver: draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + LAttr_Width setlinewidth + stroke +} bind def % PLine +/Char { %def +% Command from driver: draw a character at the current position +% STACK: type x y stroke_array Char - +% stroke array -- [ stroke1 stroke2 ... stroken ] +% stroke -- connected staight lines +% type = 0 if text 1 if marker + gsave + 4 1 roll + translate + 0 eq { TAttr_Width } { MAttr_Width } ifelse setlinewidth + { + dup length 2 gt + { + dup dup 0 get exch 1 get % get starting point + 3 -1 roll % put x y before array + dup length 2 sub 2 exch getinterval % delete first items from array + Line + stroke + } + { + aload pop currentlinewidth 2 div Circle fill + } ifelse + } forall + grestore +} bind def % Char +/PArc { %def +% Command from driver: draw an arc +% STACK: x y radius startangle deltaangle Arc - + 10 div exch 10 div exch + 2 copy pop add + arc + LAttr_Width setlinewidth + stroke +} bind def +/PCircle { %def +% Command from driver: draw an circle +% STACK: x y radius PCircle - + Circle + LAttr_Width setlinewidth + stroke +} bind def +%%EndProcSet: Lines 1.0 0 +%%BeginProcSet: Polygon 1.0 0 +% polygon attributes % +/PAttr_ExtWidth 1 def +/PAttr_IntWidth 1 def +/PAttr_Grid 1 def +% polygon procedures +/LoopSet { %def +% set up for loop condition +% STACK: start end LoopSet low gridwidth high + 2 copy lt { exch } if + % make grid line up to absolute coordinates + PAttr_Grid div truncate PAttr_Grid mul exch + PAttr_Grid exch +} bind def +/Hatch { %def +% draw cross hatch pattern in current path +% STACK: - Hatch - + pathbbox + /ury exch def + /urx exch def + /lly exch def + /llx exch def + clip + newpath + llx urx LoopSet + { % x loop + dup lly exch ury moveto lineto + } for + lly ury LoopSet + { % y loop + llx exch dup urx exch moveto lineto + } for + PAttr_IntWidth setlinewidth + stroke +} bind def +/PPoly { %def +% Command from driver: draw a plygon +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + closepath + gsave + PAttr_IntWidth PAttr_Grid ge {fill} {Hatch} ifelse + grestore + PAttr_ExtWidth setlinewidth + stroke +} bind def +%%EndProcSet: Polygon 1.0 0 +%%BeginProcSet: Text 1.0 0 +% text attributes % +/TAttr_Mirr 0 def +/TAttr_Orient 0 def +/TAttr_Width 1 def +% text procedures +/Text { %def +% Command from driver: Draw text +% STACK: x y width string Text - + gsave + 4 2 roll + translate + TAttr_Mirr 0 gt + { + -1 1 scale + } if + TAttr_Orient rotate + 0 0 moveto + dup length dup 1 gt + { + exch dup stringwidth pop + 4 -1 roll + exch 2 copy + lt + { + div 1 scale show + } + { + sub + 3 -1 roll 1 sub div + 0 3 -1 roll ashow + } + ifelse + } + { + pop + show + } ifelse + grestore +} bind def +%%EndProcSet: Text 1.0 0 +%%BeginProcSet: FlashSymbols 1.0 0 +% flash symbol attributes % +/FAttr_Type /PRndPad def +/FAttr_Width 0 def +/FAttr_Length 1 def +/FAttr_Orient 0 def +% flash symbol procedures +/PRndPad { %def +% Command from driver: draw an circular pad +% STACK: - PCirclePad - + FAttr_Width dup scale + 0 0 .5 Circle + fill +} bind def +/PSqrPad { %def +% Draw an Square pad +% STACK: - PRectPad - + FAttr_Width dup scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/PRectPad { %def +% Draw an rectangular pad +% STACK: - PRectPad - + FAttr_Length FAttr_Width scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/POvalPad { %def +% Draw an oval pad +% STACK: - POvalPad - + FAttr_Width setlinewidth + FAttr_Length FAttr_Width sub 2 div dup + neg 0 moveto + 0 lineto + RndAper + stroke +} bind def +/Anl { %def + 0 0 .5 Circle + fill + FAttr_Length FAttr_Width lt + { % inner circle + 0 0 + FAttr_Length 0 gt { FAttr_Length FAttr_Width div } { .5 } ifelse + 2 div Circle + 1 setgray + fill + glev setgray + } if +} bind def +/PAnlPad { %def +% Draw an annular pad +% STACK: - PAnlPad - + FAttr_Width dup scale + Anl +} bind def +/PRelPad { %def +% Draw an thermal relief pad +% STACK: - PRelPad - + PAnlPad + 1 setgray + .17 setlinewidth + 0 setlinecap % the x + 45 rotate + .5 0 moveto -.5 0 lineto + 0 .5 moveto 0 -.5 lineto + stroke + glev setgray +} bind def +/Flash { %def +% Command from driver: Flash a symbol +% STACK: x y Flash - + FAttr_Width 0 gt + { + gsave + translate + FAttr_Orient rotate + FAttr_Type load exec + grestore + } if +} def +%%EndProcSet: FlashSymbols 1.0 0 +%%BeginProcSet: SetAttr 1.0 0 +/SetLine { %def +% Set the width of the lines +% STACK: linewidth SetLine - + /LAttr_Width exch def + RndAper +} bind def +/SetPoly { %def +% Set attribute of polygon +% STACK: external_width internal_grid_width grid_spacing SetPoly - + /PAttr_Grid exch def + /PAttr_IntWidth exch def + /PAttr_ExtWidth exch def + RndAper +} bind def +/SetFlash { %def +% Set Attributed of flash pad +% STACK: orientation_angle length width aperture_type SetFlash - + /FAttr_Type exch def + FAttr_Type /PSqrPad eq FAttr_Type /PRectPad eq or + { SqrAper } { RndAper } ifelse + /FAttr_Width exch def + /FAttr_Length exch def + /FAttr_Orient exch 10 div def +} bind def +/SetMkr { %def +% Set attributes of markers +% STACK: linewidth size type SetMkr - + /MAttr_Type exch def + /MAttr_Size exch def + /MAttr_Width exch def + RndAper +} bind def +/SetText1 { %def +% Set attributes of text +% STACK: fontname height orient mirror SetMkr - + /TAttr_Mirr exch def + /TAttr_Orient exch 10 div def + exch findfont exch scalefont setfont + RndAper +} bind def +/SetText2 { %def +% Set attributes of text +% STACK: linewidth height mirror orient SetMkr - + /TAttr_Width exch def + RndAper +} bind def +%%EndProcSet: SetAttr 1.0 0 +%%BeginProcSet: Initialize 1.0 0 +/Init { %def +% Initialize the driver +% STACK: Init - + 72 1000 div dup scale % Scale to 1/1000 inch + 250 250 translate % make origin 1/4 inch from bottom left + 1.5 setmiterlimit 1 RndAper % set line defaults + 0 setgray % set color default + /glev 0 def +} def +%%EndProcSet: Initialize 1.0 0 +%%EndProlog +/Helvetica findfont 12 scalefont setfont +35 760 moveto +(gadget.job - Fri Aug 21 03:34:56 1992) show +gsave +Init +8000 10500 Clipto +4000 2800 translate +0 rotate +1 1 div dup scale +75 sg +50 sg +25 sg +0 sg +10 SetLine +-1350 4700 [ -1350 4900 ] PLine +-1350 4900 [ -1150 4900 ] PLine +10 SetLine +1150 4900 [ 1350 4900 ] PLine +1350 4900 [ 1350 4700 ] PLine +10 SetLine +1150 0 [ 1350 0 ] PLine +1350 0 [ 1350 200 ] PLine +10 SetLine +-1350 200 [ -1350 0 ] PLine +-1350 0 [ -1150 0 ] PLine +0 0 60 /PRndPad SetFlash +-1100 1450 Flash +-1100 1150 Flash +300 3300 Flash +-100 3300 Flash +-100 3100 Flash +300 3100 Flash +300 3500 Flash +-100 3500 Flash +-400 3700 Flash +-1200 3700 Flash +-100 1300 Flash +-900 1300 Flash +-200 2800 Flash +600 2800 Flash +-1200 2800 Flash +-400 2800 Flash +0 2500 Flash +0 2100 Flash +-1200 3400 Flash +-1200 3000 Flash +-900 2300 Flash +-1200 2300 Flash +-1200 2500 Flash +-900 2500 Flash +800 2800 Flash +1100 2800 Flash +1250 1900 Flash +450 1900 Flash +-100 900 Flash +-1200 900 Flash +-700 4000 Flash +-1100 4000 Flash +1100 3000 Flash +700 3000 Flash +-300 3700 Flash +0 3700 Flash +0 0 60 /PSqrPad SetFlash +100 900 Flash +0 0 60 /PRndPad SetFlash +600 900 Flash +0 0 60 /PSqrPad SetFlash +700 3700 Flash +0 0 60 /PRndPad SetFlash +200 3700 Flash +0 0 70 /PRndPad SetFlash +-750 550 Flash +-750 450 Flash +0 550 Flash +0 450 Flash +750 550 Flash +750 450 Flash +-648 4479 Flash +-540 4479 Flash +-432 4479 Flash +-324 4479 Flash +-216 4479 Flash +-108 4479 Flash +0 4479 Flash +108 4479 Flash +216 4479 Flash +324 4479 Flash +432 4479 Flash +540 4479 Flash +648 4479 Flash +-594 4593 Flash +-486 4593 Flash +-378 4593 Flash +-270 4593 Flash +-162 4593 Flash +-54 4593 Flash +54 4593 Flash +162 4593 Flash +270 4593 Flash +378 4593 Flash +486 4593 Flash +594 4593 Flash +0 0 177 /PRndPad SetFlash +940 4536 Flash +-940 4536 Flash +0 0 60 /PSqrPad SetFlash +950 150 Flash +0 0 60 /PRndPad SetFlash +1050 150 Flash +0 0 60 /PSqrPad SetFlash +-50 150 Flash +0 0 60 /PRndPad SetFlash +50 150 Flash +0 0 60 /PSqrPad SetFlash +-1050 150 Flash +0 0 60 /PRndPad SetFlash +-950 150 Flash +0 0 50 /PRndPad SetFlash +950 3524 Flash +1026 3612 Flash +950 3700 Flash +0 0 60 /PSqrPad SetFlash +-1200 1600 Flash +0 0 60 /PRndPad SetFlash +-1100 1700 Flash +-1200 1800 Flash +300 1700 Flash +-100 1700 Flash +200 1300 Flash +600 1300 Flash +-700 2300 Flash +-300 2300 Flash +-700 4200 Flash +-1100 4200 Flash +1100 3200 Flash +700 3200 Flash +-700 2500 Flash +-300 2500 Flash +-700 2100 Flash +-300 2100 Flash +-800 2100 Flash +-1200 2100 Flash +600 1100 Flash +200 1100 Flash +0 0 60 /PSqrPad SetFlash +1200 2450 Flash +0 0 60 /PRndPad SetFlash +1100 2350 Flash +1200 2250 Flash +-100 1900 Flash +300 1900 Flash +0 1500 Flash +400 1500 Flash +0 0 60 /PSqrPad SetFlash +-900 1600 Flash +0 0 60 /PRndPad SetFlash +-800 1600 Flash +-700 1600 Flash +-600 1600 Flash +-500 1600 Flash +-400 1600 Flash +-300 1600 Flash +-300 1900 Flash +-400 1900 Flash +-500 1900 Flash +-600 1900 Flash +-700 1900 Flash +-800 1900 Flash +-900 1900 Flash +0 0 60 /PSqrPad SetFlash +200 2200 Flash +0 0 60 /PRndPad SetFlash +300 2200 Flash +400 2200 Flash +500 2200 Flash +600 2200 Flash +700 2200 Flash +800 2200 Flash +900 2200 Flash +900 2500 Flash +800 2500 Flash +700 2500 Flash +600 2500 Flash +500 2500 Flash +400 2500 Flash +300 2500 Flash +200 2500 Flash +0 0 60 /PSqrPad SetFlash +200 3900 Flash +0 0 60 /PRndPad SetFlash +300 3900 Flash +400 3900 Flash +500 3900 Flash +600 3900 Flash +700 3900 Flash +800 3900 Flash +900 3900 Flash +1000 3900 Flash +1100 3900 Flash +1100 4200 Flash +1000 4200 Flash +900 4200 Flash +800 4200 Flash +700 4200 Flash +600 4200 Flash +500 4200 Flash +400 4200 Flash +300 4200 Flash +200 4200 Flash +0 0 60 /PSqrPad SetFlash +-1000 3100 Flash +0 0 60 /PRndPad SetFlash +-900 3100 Flash +-800 3100 Flash +-700 3100 Flash +-600 3100 Flash +-500 3100 Flash +-400 3100 Flash +-300 3100 Flash +-300 3400 Flash +-400 3400 Flash +-500 3400 Flash +-600 3400 Flash +-700 3400 Flash +-800 3400 Flash +-900 3400 Flash +-1000 3400 Flash +0 0 70 /PRndPad SetFlash +900 800 Flash +1100 800 Flash +1000 800 Flash +0 0 177 /PRndPad SetFlash +1000 1550 Flash +0 0 60 /PRndPad SetFlash +0 4000 Flash +0 4200 Flash +0 0 250 /PRndPad SetFlash +-1100 450 Flash +1100 450 Flash +0 0 60 /PRndPad SetFlash +1100 3400 Flash +700 3400 Flash +10 SetText2 +0 -300 4725 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +0 -248 4725 [ [ 0 65 0 0 ] ] Char +0 -228 4725 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -176 4725 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -74 4725 [ [ 0 53 4 56 11 65 11 0 ] ] Char +12 SetLine +-100 900 [ -100 800 ] PLine +-100 800 [ 100 800 ] PLine +100 900 [ 100 800 ] PLine +100 800 [ 900 800 ] PLine +300 1100 [ 600 1100 ] PLine +-1100 1150 [ -700 1150 ] PLine +-700 1150 [ -700 1600 ] PLine +175 3300 [ -100 3300 ] PLine +700 3000 [ 300 3000 ] PLine +300 3000 [ 300 3100 ] PLine +300 2500 [ 300 2650 ] PLine +300 2650 [ 800 2650 ] PLine +800 2800 [ 800 2650 ] PLine +800 2650 [ 1000 2650 ] PLine +400 2500 [ 400 2600 ] PLine +400 2600 [ 1100 2600 ] PLine +1100 2600 [ 1100 2800 ] PLine +-900 2300 [ -700 2100 ] PLine +-700 2100 [ -450 2100 ] PLine +500 2500 [ 550 2550 ] PLine +550 2550 [ 750 2550 ] PLine +750 2550 [ 800 2500 ] PLine +-650 2600 [ -100 2600 ] PLine +-100 2250 [ 450 2250 ] PLine +450 2250 [ 500 2200 ] PLine +-1200 2300 [ -1050 2300 ] PLine +-1050 2300 [ -1050 2100 ] PLine +-1050 2100 [ -800 2100 ] PLine +-900 2500 [ -700 2300 ] PLine +-700 2300 [ -700 2200 ] PLine +-700 2200 [ -300 2200 ] PLine +-300 2200 [ -300 2100 ] PLine +1250 1900 [ 1250 1800 ] PLine +1250 1800 [ 800 1800 ] PLine +300 1900 [ 300 1800 ] PLine +300 1800 [ 800 1800 ] PLine +700 1900 [ 450 1900 ] PLine +300 1700 [ 600 1700 ] PLine +500 1600 [ -100 1600 ] PLine +-100 1600 [ -100 1700 ] PLine +1000 3900 [ 1050 3950 ] PLine +1050 3950 [ 1050 4050 ] PLine +1050 4050 [ 50 4050 ] PLine +50 4050 [ 0 4000 ] PLine +0 4100 [ 900 4100 ] PLine +800 3000 [ 1100 3000 ] PLine +0 3700 [ 0 3850 ] PLine +0 3850 [ 450 3850 ] PLine +450 3850 [ 500 3900 ] PLine +-400 3400 [ -400 3600 ] PLine +-400 3600 [ 300 3600 ] PLine +300 3600 [ 300 3700 ] PLine +300 3700 [ 600 3700 ] PLine +450 2700 [ -400 2700 ] PLine +-400 2300 [ -300 2300 ] PLine +-700 4200 [ -650 4250 ] PLine +-650 4250 [ 550 4250 ] PLine +550 4250 [ 600 4200 ] PLine +350 3800 [ 1100 3800 ] PLine +1100 3800 [ 1100 3900 ] PLine +-800 3100 [ -800 2800 ] PLine +-800 2800 [ -400 2800 ] PLine +-850 3700 [ -400 3700 ] PLine +400 1300 [ 600 1300 ] PLine +-1100 4200 [ -1050 4150 ] PLine +-1050 4150 [ 650 4150 ] PLine +650 4150 [ 700 4200 ] PLine +-300 3400 [ -250 3350 ] PLine +-250 3350 [ 1200 3350 ] PLine +1200 3350 [ 1200 4200 ] PLine +1200 4200 [ 1100 4200 ] PLine +-700 3100 [ -700 2875 ] PLine +-700 2875 [ -200 2875 ] PLine +-200 2875 [ -200 2800 ] PLine +-600 3100 [ -600 2950 ] PLine +-600 2950 [ 600 2950 ] PLine +600 2950 [ 600 2800 ] PLine +-750 550 [ -750 1050 ] PLine +-750 1050 [ -1050 1050 ] PLine +950 3200 [ 700 3200 ] PLine +850 1200 [ -600 1200 ] PLine +-550 3900 [ -350 3900 ] PLine +540 4479 [ 540 4300 ] PLine +540 4300 [ -800 4300 ] PLine +432 4479 [ 432 4350 ] PLine +432 4350 [ -750 4350 ] PLine +400 3400 [ 700 3400 ] PLine +50 SetLine +-1000 3400 [ -1000 3250 ] PLine +-1000 3250 [ -200 3250 ] PLine +-200 3250 [ -200 3100 ] PLine +-200 3100 [ -100 3100 ] PLine +0 2500 [ 0 2350 ] PLine +0 2350 [ 200 2350 ] PLine +200 2350 [ 200 2500 ] PLine +0 2350 [ -200 2350 ] PLine +-1000 3400 [ -1200 3400 ] PLine +200 2350 [ 1100 2350 ] PLine +1100 2350 [ 1100 2450 ] PLine +1100 2450 [ 1200 2450 ] PLine +-600 1600 [ -600 1750 ] PLine +-600 1750 [ -200 1750 ] PLine +-1200 3700 [ -1000 3700 ] PLine +-1000 3700 [ -1000 3400 ] PLine +1100 3200 [ 1250 3200 ] PLine +1250 3200 [ 1250 2450 ] PLine +1250 2450 [ 1200 2450 ] PLine +900 4200 [ 900 4300 ] PLine +900 4300 [ 1250 4300 ] PLine +1250 4300 [ 1250 3200 ] PLine +-700 4000 [ -1000 4000 ] PLine +-1000 4000 [ -1000 3700 ] PLine +900 4200 [ 800 4200 ] PLine +200 1400 [ 1100 1400 ] PLine +1100 1400 [ 1100 800 ] PLine +-50 450 [ -50 150 ] PLine +950 150 [ 1100 450 ] PLine +1100 450 [ 1000 800 ] PLine +-250 450 [ -250 1000 ] PLine +-250 1000 [ 200 1000 ] PLine +200 1000 [ 200 1100 ] PLine +0 450 [ -750 450 ] PLine +-750 450 [ -1100 450 ] PLine +0 4475 [ 0 4400 ] PLine +0 4400 [ -648 4400 ] PLine +-648 4400 [ -648 4479 ] PLine +75 4000 [ 300 4000 ] PLine +300 4000 [ 300 3900 ] PLine +1100 450 [ 750 450 ] PLine +750 450 [ 0 450 ] PLine +900 2200 [ 900 2000 ] PLine +900 2000 [ 75 2000 ] PLine +75 2000 [ 75 2200 ] PLine +75 2200 [ 200 2200 ] PLine +300 4000 [ 1000 4000 ] PLine +-1100 450 [ -1050 150 ] PLine +-600 1900 [ -600 2000 ] PLine +-600 2000 [ 75 2000 ] PLine +75 2100 [ 0 2100 ] PLine +0 0 55 /PRndPad SetFlash +-200 2350 Flash +-200 1750 Flash +200 1400 Flash +0 0 55 /PRndPad SetFlash +300 1100 Flash +0 0 55 /PRndPad SetFlash +175 3300 Flash +0 0 55 /PRndPad SetFlash +1000 2650 Flash +0 0 55 /PRndPad SetFlash +-450 2100 Flash +0 0 55 /PRndPad SetFlash +-650 2600 Flash +-100 2600 Flash +-100 2250 Flash +0 0 55 /PRndPad SetFlash +800 1800 Flash +0 0 55 /PRndPad SetFlash +700 1900 Flash +0 0 55 /PRndPad SetFlash +600 1700 Flash +0 0 55 /PRndPad SetFlash +500 1600 Flash +0 0 55 /PRndPad SetFlash +0 4100 Flash +900 4100 Flash +0 0 55 /PRndPad SetFlash +800 3000 Flash +0 0 55 /PRndPad SetFlash +600 3700 Flash +0 0 55 /PRndPad SetFlash +450 2700 Flash +-400 2700 Flash +-400 2300 Flash +0 0 55 /PRndPad SetFlash +350 3800 Flash +0 0 55 /PRndPad SetFlash +-850 3700 Flash +0 0 55 /PRndPad SetFlash +400 1300 Flash +0 0 55 /PRndPad SetFlash +-1050 1050 Flash +0 0 55 /PRndPad SetFlash +0 4475 Flash +75 4000 Flash +1000 4000 Flash +0 0 55 /PRndPad SetFlash +950 3200 Flash +0 0 55 /PRndPad SetFlash +850 1200 Flash +-600 1200 Flash +0 0 55 /PRndPad SetFlash +-550 3900 Flash +-350 3900 Flash +0 0 55 /PRndPad SetFlash +-800 4300 Flash +0 0 55 /PRndPad SetFlash +-750 4350 Flash +0 0 55 /PRndPad SetFlash +400 3400 Flash +grestore +showpage diff --git a/contrib/xntpd/gadget/art02.lpr b/contrib/xntpd/gadget/art02.lpr new file mode 100644 index 0000000000..1b336f3782 --- /dev/null +++ b/contrib/xntpd/gadget/art02.lpr @@ -0,0 +1,893 @@ +%!PS-Adobe-2.0 +%%Title: PADS Postscript Driver Header +%%Creator: Andy Montalvo, 18 Lupine St., Lowell, MA 01851 +%%CreationDate: 06/08/90 +%%For: CAD Software, Littleton, MA +%%EndComments +%%BeginProcSet: Markers 1.0 0 +% marker attributes +/MAttr_Width 1 def +/MAttr_Size 0 def +/MAttr_Type /M1 def +% procedures +/M1 { %def +% draw marker 1: plus +% Stack: - M1 - + -2 0 rmoveto + 4 0 rlineto + -2 2 rmoveto + 0 -4 rlineto +} bind def +/M2 { %def +% draw marker 2: cross +% Stack: - M2 - + -2 -2 rmoveto + 4 4 rlineto + -4 0 rmoveto + 4 -4 rlineto +} bind def +/M3 { %def +% draw marker 3: square +% Stack: - M3 - + 0 2 rlineto + 2 0 rlineto + 0 -4 rlineto + -4 0 rlineto + 0 4 rlineto + 2 0 rlineto +} bind def +/M4 { %def +% draw marker 4: diamond +% Stack: - M4 - + 0 2 rlineto + 2 -2 rlineto + -2 -2 rlineto + -2 2 rlineto + 2 2 rlineto +} bind def +/M5 { %def +% draw marker 5: hourglass +% Stack: - M5 - + 2 2 rlineto + -4 0 rlineto + 4 -4 rlineto + -4 0 rlineto + 2 2 rlineto +} bind def +/M6 { %def +% draw marker 6: bowtie +% Stack: - M6 - + 2 2 rlineto + 0 -4 rlineto + -4 4 rlineto + 0 -4 rlineto + 2 2 rlineto +} bind def +/M7 { %def +% draw marker 7: small plus (goes with char marker) +% Stack: - M7 - + -1 0 rmoveto + 2 0 rlineto + -1 1 rmoveto + 0 -2 rlineto +} bind def +/Marker { %def +% Command from driver: draw marker +% STACK: x y Marker - + MAttr_Size 0 gt + { + gsave + moveto + MAttr_Size 4 div dup scale + MAttr_Type load exec + 4 MAttr_Size div dup scale + MAttr_Width setlinewidth + stroke + grestore + } if +} def +%%EndProcSet: Markers 1.0 0 +%%BeginProcSet: Lib 1.0 0 +/sg { %def +% Command from driver: set the gray scale 0 - 100 +% STACK: greylevel sg + 100 div dup setgray /glev exch def +} bind def +/Circle { %def +% draw a circle +% STACK: x y radius Circle - + 0 360 arc +} bind def +/RndAper { %def +% select a round aperture +% STACK: - RndAper - + 1 setlinejoin + 1 setlinecap +} bind def +/SqrAper { %def +% select a square aperture +% STACK: - SqrAper - + 0 setlinejoin + 2 setlinecap +} bind def +/Line { %def +% draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] Line - + 3 1 roll + moveto + true + exch + % This pushes the x then the y then does lineto + { exch { false } { lineto true } ifelse } forall + pop +} bind def +/Clipto { %def +% set clipping rectangle from 0,0 to new values +% STACK: x y Clipto - + 0 0 moveto + dup 0 exch lineto + 2 copy lineto + pop + 0 lineto + closepath + clip + newpath +} bind def +/Clip4 { %def +% set clipping rectangle from xmin,ymin to xmax,ymax +% STACK: xmin ymin xmax ymax Clip4 - + 4 copy pop pop moveto + 4 copy pop exch lineto pop + 2 copy lineto + exch pop exch pop lineto + closepath + clip + newpath +} bind def +%%EndProcSet: Lib 1.0 0 +%%BeginProcSet: Lines 1.0 0 +% line attributes % +/LAttr_Width 1 def +% line procedures +/PLine { %def +% Cammand from driver: draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + LAttr_Width setlinewidth + stroke +} bind def % PLine +/Char { %def +% Command from driver: draw a character at the current position +% STACK: type x y stroke_array Char - +% stroke array -- [ stroke1 stroke2 ... stroken ] +% stroke -- connected staight lines +% type = 0 if text 1 if marker + gsave + 4 1 roll + translate + 0 eq { TAttr_Width } { MAttr_Width } ifelse setlinewidth + { + dup length 2 gt + { + dup dup 0 get exch 1 get % get starting point + 3 -1 roll % put x y before array + dup length 2 sub 2 exch getinterval % delete first items from array + Line + stroke + } + { + aload pop currentlinewidth 2 div Circle fill + } ifelse + } forall + grestore +} bind def % Char +/PArc { %def +% Command from driver: draw an arc +% STACK: x y radius startangle deltaangle Arc - + 10 div exch 10 div exch + 2 copy pop add + arc + LAttr_Width setlinewidth + stroke +} bind def +/PCircle { %def +% Command from driver: draw an circle +% STACK: x y radius PCircle - + Circle + LAttr_Width setlinewidth + stroke +} bind def +%%EndProcSet: Lines 1.0 0 +%%BeginProcSet: Polygon 1.0 0 +% polygon attributes % +/PAttr_ExtWidth 1 def +/PAttr_IntWidth 1 def +/PAttr_Grid 1 def +% polygon procedures +/LoopSet { %def +% set up for loop condition +% STACK: start end LoopSet low gridwidth high + 2 copy lt { exch } if + % make grid line up to absolute coordinates + PAttr_Grid div truncate PAttr_Grid mul exch + PAttr_Grid exch +} bind def +/Hatch { %def +% draw cross hatch pattern in current path +% STACK: - Hatch - + pathbbox + /ury exch def + /urx exch def + /lly exch def + /llx exch def + clip + newpath + llx urx LoopSet + { % x loop + dup lly exch ury moveto lineto + } for + lly ury LoopSet + { % y loop + llx exch dup urx exch moveto lineto + } for + PAttr_IntWidth setlinewidth + stroke +} bind def +/PPoly { %def +% Command from driver: draw a plygon +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + closepath + gsave + PAttr_IntWidth PAttr_Grid ge {fill} {Hatch} ifelse + grestore + PAttr_ExtWidth setlinewidth + stroke +} bind def +%%EndProcSet: Polygon 1.0 0 +%%BeginProcSet: Text 1.0 0 +% text attributes % +/TAttr_Mirr 0 def +/TAttr_Orient 0 def +/TAttr_Width 1 def +% text procedures +/Text { %def +% Command from driver: Draw text +% STACK: x y width string Text - + gsave + 4 2 roll + translate + TAttr_Mirr 0 gt + { + -1 1 scale + } if + TAttr_Orient rotate + 0 0 moveto + dup length dup 1 gt + { + exch dup stringwidth pop + 4 -1 roll + exch 2 copy + lt + { + div 1 scale show + } + { + sub + 3 -1 roll 1 sub div + 0 3 -1 roll ashow + } + ifelse + } + { + pop + show + } ifelse + grestore +} bind def +%%EndProcSet: Text 1.0 0 +%%BeginProcSet: FlashSymbols 1.0 0 +% flash symbol attributes % +/FAttr_Type /PRndPad def +/FAttr_Width 0 def +/FAttr_Length 1 def +/FAttr_Orient 0 def +% flash symbol procedures +/PRndPad { %def +% Command from driver: draw an circular pad +% STACK: - PCirclePad - + FAttr_Width dup scale + 0 0 .5 Circle + fill +} bind def +/PSqrPad { %def +% Draw an Square pad +% STACK: - PRectPad - + FAttr_Width dup scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/PRectPad { %def +% Draw an rectangular pad +% STACK: - PRectPad - + FAttr_Length FAttr_Width scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/POvalPad { %def +% Draw an oval pad +% STACK: - POvalPad - + FAttr_Width setlinewidth + FAttr_Length FAttr_Width sub 2 div dup + neg 0 moveto + 0 lineto + RndAper + stroke +} bind def +/Anl { %def + 0 0 .5 Circle + fill + FAttr_Length FAttr_Width lt + { % inner circle + 0 0 + FAttr_Length 0 gt { FAttr_Length FAttr_Width div } { .5 } ifelse + 2 div Circle + 1 setgray + fill + glev setgray + } if +} bind def +/PAnlPad { %def +% Draw an annular pad +% STACK: - PAnlPad - + FAttr_Width dup scale + Anl +} bind def +/PRelPad { %def +% Draw an thermal relief pad +% STACK: - PRelPad - + PAnlPad + 1 setgray + .17 setlinewidth + 0 setlinecap % the x + 45 rotate + .5 0 moveto -.5 0 lineto + 0 .5 moveto 0 -.5 lineto + stroke + glev setgray +} bind def +/Flash { %def +% Command from driver: Flash a symbol +% STACK: x y Flash - + FAttr_Width 0 gt + { + gsave + translate + FAttr_Orient rotate + FAttr_Type load exec + grestore + } if +} def +%%EndProcSet: FlashSymbols 1.0 0 +%%BeginProcSet: SetAttr 1.0 0 +/SetLine { %def +% Set the width of the lines +% STACK: linewidth SetLine - + /LAttr_Width exch def + RndAper +} bind def +/SetPoly { %def +% Set attribute of polygon +% STACK: external_width internal_grid_width grid_spacing SetPoly - + /PAttr_Grid exch def + /PAttr_IntWidth exch def + /PAttr_ExtWidth exch def + RndAper +} bind def +/SetFlash { %def +% Set Attributed of flash pad +% STACK: orientation_angle length width aperture_type SetFlash - + /FAttr_Type exch def + FAttr_Type /PSqrPad eq FAttr_Type /PRectPad eq or + { SqrAper } { RndAper } ifelse + /FAttr_Width exch def + /FAttr_Length exch def + /FAttr_Orient exch 10 div def +} bind def +/SetMkr { %def +% Set attributes of markers +% STACK: linewidth size type SetMkr - + /MAttr_Type exch def + /MAttr_Size exch def + /MAttr_Width exch def + RndAper +} bind def +/SetText1 { %def +% Set attributes of text +% STACK: fontname height orient mirror SetMkr - + /TAttr_Mirr exch def + /TAttr_Orient exch 10 div def + exch findfont exch scalefont setfont + RndAper +} bind def +/SetText2 { %def +% Set attributes of text +% STACK: linewidth height mirror orient SetMkr - + /TAttr_Width exch def + RndAper +} bind def +%%EndProcSet: SetAttr 1.0 0 +%%BeginProcSet: Initialize 1.0 0 +/Init { %def +% Initialize the driver +% STACK: Init - + 72 1000 div dup scale % Scale to 1/1000 inch + 250 250 translate % make origin 1/4 inch from bottom left + 1.5 setmiterlimit 1 RndAper % set line defaults + 0 setgray % set color default + /glev 0 def +} def +%%EndProcSet: Initialize 1.0 0 +%%EndProlog +/Helvetica findfont 12 scalefont setfont +35 760 moveto +(gadget.job - Fri Aug 21 03:35:02 1992) show +gsave +Init +8000 10500 Clipto +4000 2800 translate +-1 1 scale +0 rotate +1 1 div dup scale +75 sg +50 sg +25 sg +0 sg +10 SetLine +-1350 4700 [ -1350 4900 ] PLine +-1350 4900 [ -1150 4900 ] PLine +10 SetLine +1150 4900 [ 1350 4900 ] PLine +1350 4900 [ 1350 4700 ] PLine +10 SetLine +1150 0 [ 1350 0 ] PLine +1350 0 [ 1350 200 ] PLine +10 SetLine +-1350 200 [ -1350 0 ] PLine +-1350 0 [ -1150 0 ] PLine +0 0 60 /PRndPad SetFlash +-1100 1450 Flash +-1100 1150 Flash +300 3300 Flash +-100 3300 Flash +-100 3100 Flash +300 3100 Flash +300 3500 Flash +-100 3500 Flash +-400 3700 Flash +-1200 3700 Flash +-100 1300 Flash +-900 1300 Flash +-200 2800 Flash +600 2800 Flash +-1200 2800 Flash +-400 2800 Flash +0 2500 Flash +0 2100 Flash +-1200 3400 Flash +-1200 3000 Flash +-900 2300 Flash +-1200 2300 Flash +-1200 2500 Flash +-900 2500 Flash +800 2800 Flash +1100 2800 Flash +1250 1900 Flash +450 1900 Flash +-100 900 Flash +-1200 900 Flash +-700 4000 Flash +-1100 4000 Flash +1100 3000 Flash +700 3000 Flash +-300 3700 Flash +0 3700 Flash +0 0 60 /PSqrPad SetFlash +100 900 Flash +0 0 60 /PRndPad SetFlash +600 900 Flash +0 0 60 /PSqrPad SetFlash +700 3700 Flash +0 0 60 /PRndPad SetFlash +200 3700 Flash +0 0 70 /PRndPad SetFlash +-750 550 Flash +-750 450 Flash +0 550 Flash +0 450 Flash +750 550 Flash +750 450 Flash +-648 4479 Flash +-540 4479 Flash +-432 4479 Flash +-324 4479 Flash +-216 4479 Flash +-108 4479 Flash +0 4479 Flash +108 4479 Flash +216 4479 Flash +324 4479 Flash +432 4479 Flash +540 4479 Flash +648 4479 Flash +-594 4593 Flash +-486 4593 Flash +-378 4593 Flash +-270 4593 Flash +-162 4593 Flash +-54 4593 Flash +54 4593 Flash +162 4593 Flash +270 4593 Flash +378 4593 Flash +486 4593 Flash +594 4593 Flash +0 0 177 /PRndPad SetFlash +940 4536 Flash +-940 4536 Flash +0 0 60 /PSqrPad SetFlash +950 150 Flash +0 0 60 /PRndPad SetFlash +1050 150 Flash +0 0 60 /PSqrPad SetFlash +-50 150 Flash +0 0 60 /PRndPad SetFlash +50 150 Flash +0 0 60 /PSqrPad SetFlash +-1050 150 Flash +0 0 60 /PRndPad SetFlash +-950 150 Flash +0 0 50 /PRndPad SetFlash +950 3524 Flash +1026 3612 Flash +950 3700 Flash +0 0 60 /PSqrPad SetFlash +-1200 1600 Flash +0 0 60 /PRndPad SetFlash +-1100 1700 Flash +-1200 1800 Flash +300 1700 Flash +-100 1700 Flash +200 1300 Flash +600 1300 Flash +-700 2300 Flash +-300 2300 Flash +-700 4200 Flash +-1100 4200 Flash +1100 3200 Flash +700 3200 Flash +-700 2500 Flash +-300 2500 Flash +-700 2100 Flash +-300 2100 Flash +-800 2100 Flash +-1200 2100 Flash +600 1100 Flash +200 1100 Flash +0 0 60 /PSqrPad SetFlash +1200 2450 Flash +0 0 60 /PRndPad SetFlash +1100 2350 Flash +1200 2250 Flash +-100 1900 Flash +300 1900 Flash +0 1500 Flash +400 1500 Flash +0 0 60 /PSqrPad SetFlash +-900 1600 Flash +0 0 60 /PRndPad SetFlash +-800 1600 Flash +-700 1600 Flash +-600 1600 Flash +-500 1600 Flash +-400 1600 Flash +-300 1600 Flash +-300 1900 Flash +-400 1900 Flash +-500 1900 Flash +-600 1900 Flash +-700 1900 Flash +-800 1900 Flash +-900 1900 Flash +0 0 60 /PSqrPad SetFlash +200 2200 Flash +0 0 60 /PRndPad SetFlash +300 2200 Flash +400 2200 Flash +500 2200 Flash +600 2200 Flash +700 2200 Flash +800 2200 Flash +900 2200 Flash +900 2500 Flash +800 2500 Flash +700 2500 Flash +600 2500 Flash +500 2500 Flash +400 2500 Flash +300 2500 Flash +200 2500 Flash +0 0 60 /PSqrPad SetFlash +200 3900 Flash +0 0 60 /PRndPad SetFlash +300 3900 Flash +400 3900 Flash +500 3900 Flash +600 3900 Flash +700 3900 Flash +800 3900 Flash +900 3900 Flash +1000 3900 Flash +1100 3900 Flash +1100 4200 Flash +1000 4200 Flash +900 4200 Flash +800 4200 Flash +700 4200 Flash +600 4200 Flash +500 4200 Flash +400 4200 Flash +300 4200 Flash +200 4200 Flash +0 0 60 /PSqrPad SetFlash +-1000 3100 Flash +0 0 60 /PRndPad SetFlash +-900 3100 Flash +-800 3100 Flash +-700 3100 Flash +-600 3100 Flash +-500 3100 Flash +-400 3100 Flash +-300 3100 Flash +-300 3400 Flash +-400 3400 Flash +-500 3400 Flash +-600 3400 Flash +-700 3400 Flash +-800 3400 Flash +-900 3400 Flash +-1000 3400 Flash +0 0 70 /PRndPad SetFlash +900 800 Flash +1100 800 Flash +1000 800 Flash +0 0 177 /PRndPad SetFlash +1000 1550 Flash +0 0 60 /PRndPad SetFlash +0 4000 Flash +0 4200 Flash +0 0 250 /PRndPad SetFlash +-1100 450 Flash +1100 450 Flash +0 0 60 /PRndPad SetFlash +1100 3400 Flash +700 3400 Flash +10 SetText2 +0 300 4725 [ [ -31 56 -27 62 -20 65 -11 65 -4 62 0 56 0 50 -2 43 -4 40 -9 37 -22 31 -27 28 -29 25 -31 18 -31 9 -27 3 -20 0 -11 0 -4 3 0 9 ] ] Char +0 248 4725 [ [ 0 65 0 0 ] ] Char +0 228 4725 [ [ 0 65 0 0 ] [ 0 65 -15 65 -22 62 -27 56 -29 50 -31 40 -31 25 -29 15 -27 9 -22 3 -15 0 0 0 ] ] Char +0 176 4725 [ [ 0 65 0 0 ] [ 0 65 -29 65 ] [ 0 34 -18 34 ] [ 0 0 -29 0 ] ] Char +0 74 4725 [ [ -2 50 -2 53 -4 59 -6 62 -11 65 -20 65 -25 62 -27 59 -29 53 -29 46 -27 40 -22 31 0 0 -31 0 ] ] Char +12 SetLine +700 3700 [ 750 3650 ] PLine +750 3650 [ 750 800 ] PLine +750 800 [ 900 800 ] PLine +0 550 [ 300 550 ] PLine +300 550 [ 300 1100 ] PLine +300 2200 [ 250 2150 ] PLine +250 2150 [ 250 1600 ] PLine +250 1600 [ 300 1550 ] PLine +300 1550 [ 300 1100 ] PLine +-700 2500 [ -550 2500 ] PLine +-550 2500 [ -550 1700 ] PLine +-550 1700 [ -700 1700 ] PLine +-700 1700 [ -700 1600 ] PLine +300 3500 [ 175 3500 ] PLine +175 3500 [ 175 3100 ] PLine +175 3100 [ 300 3100 ] PLine +300 4200 [ 250 4150 ] PLine +250 4150 [ 250 3800 ] PLine +250 3800 [ 300 3750 ] PLine +300 3750 [ 300 3500 ] PLine +-300 2500 [ -250 2550 ] PLine +-250 2550 [ -250 3300 ] PLine +-250 3300 [ -100 3300 ] PLine +300 4200 [ 400 4200 ] PLine +-900 1600 [ -800 1600 ] PLine +-800 1600 [ -800 1500 ] PLine +-800 1500 [ -500 1500 ] PLine +-500 1500 [ -500 1600 ] PLine +1000 2650 [ 1000 2250 ] PLine +1000 2250 [ 1200 2250 ] PLine +400 1500 [ 400 2200 ] PLine +400 2200 [ 400 2300 ] PLine +400 2300 [ 700 2300 ] PLine +700 2300 [ 700 2500 ] PLine +-450 2100 [ -450 1650 ] PLine +-450 1650 [ -400 1600 ] PLine +-500 3400 [ -500 3150 ] PLine +-500 3150 [ -650 3150 ] PLine +-650 3150 [ -650 2600 ] PLine +-100 2600 [ -100 2250 ] PLine +-1200 2500 [ -1200 2300 ] PLine +-300 2100 [ -250 2050 ] PLine +-250 2050 [ -250 1650 ] PLine +-250 1650 [ -300 1600 ] PLine +800 1800 [ 800 2200 ] PLine +600 900 [ 600 550 ] PLine +600 550 [ 750 550 ] PLine +700 2200 [ 700 1900 ] PLine +600 1700 [ 600 2200 ] PLine +1050 150 [ 1050 250 ] PLine +1050 250 [ 500 250 ] PLine +500 250 [ 500 1600 ] PLine +0 4200 [ 0 4100 ] PLine +900 4100 [ 900 3900 ] PLine +800 3900 [ 800 3000 ] PLine +600 3700 [ 600 3900 ] PLine +600 4200 [ 600 4075 ] PLine +600 4075 [ 450 4075 ] PLine +450 4075 [ 450 2700 ] PLine +-400 2700 [ -400 2300 ] PLine +300 3300 [ 350 3350 ] PLine +350 3350 [ 350 3800 ] PLine +-1200 2800 [ -1000 2800 ] PLine +-1000 2800 [ -1000 3100 ] PLine +-900 3100 [ -850 3150 ] PLine +-850 3150 [ -850 3700 ] PLine +50 150 [ 400 150 ] PLine +400 150 [ 400 1300 ] PLine +-500 3100 [ -500 3000 ] PLine +-500 3000 [ -350 3000 ] PLine +-350 3000 [ -350 1300 ] PLine +-350 1300 [ -100 1300 ] PLine +200 3700 [ 150 3750 ] PLine +150 3750 [ 150 4425 ] PLine +150 4425 [ 108 4479 ] PLine +108 4479 [ 54 4593 ] PLine +-108 4479 [ 50 4600 ] PLine +50 4600 [ 54 4593 ] PLine +-324 4479 [ -216 4479 ] PLine +-1100 1700 [ -1100 1450 ] PLine +-1050 1050 [ -1050 1800 ] PLine +-1050 1800 [ -1200 1800 ] PLine +950 3524 [ 950 3200 ] PLine +950 3700 [ 850 3700 ] PLine +850 3700 [ 850 1200 ] PLine +-600 1200 [ -600 150 ] PLine +-600 150 [ -950 150 ] PLine +-540 4479 [ -550 4479 ] PLine +-550 4479 [ -550 3900 ] PLine +-350 3900 [ -350 3150 ] PLine +-350 3150 [ -300 3100 ] PLine +-432 4479 [ -450 4479 ] PLine +-450 4479 [ -450 3150 ] PLine +-450 3150 [ -382 3100 ] PLine +-382 3100 [ -400 3100 ] PLine +-800 4300 [ -800 3400 ] PLine +-750 4350 [ -750 3450 ] PLine +-750 3450 [ -700 3400 ] PLine +400 3900 [ 400 3400 ] PLine +1100 3400 [ 1100 3600 ] PLine +1100 3600 [ 1026 3600 ] PLine +1026 3600 [ 1026 3612 ] PLine +50 SetLine +-100 3100 [ 0 3100 ] PLine +0 3100 [ 0 2500 ] PLine +-200 2350 [ -200 1900 ] PLine +-200 1900 [ -100 1900 ] PLine +-200 1900 [ -200 1500 ] PLine +-200 1500 [ 0 1500 ] PLine +0 1500 [ 200 1500 ] PLine +200 1500 [ 200 1300 ] PLine +800 4200 [ 800 4050 ] PLine +800 4050 [ 700 4050 ] PLine +700 4050 [ 700 3900 ] PLine +-750 450 [ -900 450 ] PLine +-900 450 [ -900 1300 ] PLine +-1200 1600 [ -1275 1600 ] PLine +-1275 1600 [ -1275 900 ] PLine +-900 900 [ -1275 900 ] PLine +-600 1900 [ -600 1750 ] PLine +-600 1750 [ -975 1750 ] PLine +-975 1750 [ -975 1300 ] PLine +-975 1300 [ -900 1300 ] PLine +-1200 2100 [ -1275 2100 ] PLine +-1275 2100 [ -1275 1600 ] PLine +-1200 3000 [ -1275 3000 ] PLine +-1275 3000 [ -1275 2100 ] PLine +-900 3400 [ -900 3525 ] PLine +-900 3525 [ -1275 3525 ] PLine +-1100 4000 [ -1275 4000 ] PLine +-1275 4000 [ -1275 3000 ] PLine +75 3500 [ 75 2100 ] PLine +75 2100 [ 0 2100 ] PLine +75 2200 [ 200 2200 ] PLine +0 4479 [ 0 4400 ] PLine +0 4400 [ 75 4400 ] PLine +75 4400 [ 75 3500 ] PLine +-300 3700 [ -300 3500 ] PLine +-300 3500 [ 75 3500 ] PLine +900 2500 [ 900 2200 ] PLine +1000 4000 [ 1000 4200 ] PLine +0 0 55 /PRndPad SetFlash +-200 2350 Flash +-200 1750 Flash +200 1400 Flash +0 0 55 /PRndPad SetFlash +300 1100 Flash +0 0 55 /PRndPad SetFlash +175 3300 Flash +0 0 55 /PRndPad SetFlash +1000 2650 Flash +0 0 55 /PRndPad SetFlash +-450 2100 Flash +0 0 55 /PRndPad SetFlash +-650 2600 Flash +-100 2600 Flash +-100 2250 Flash +0 0 55 /PRndPad SetFlash +800 1800 Flash +0 0 55 /PRndPad SetFlash +700 1900 Flash +0 0 55 /PRndPad SetFlash +600 1700 Flash +0 0 55 /PRndPad SetFlash +500 1600 Flash +0 0 55 /PRndPad SetFlash +0 4100 Flash +900 4100 Flash +0 0 55 /PRndPad SetFlash +800 3000 Flash +0 0 55 /PRndPad SetFlash +600 3700 Flash +0 0 55 /PRndPad SetFlash +450 2700 Flash +-400 2700 Flash +-400 2300 Flash +0 0 55 /PRndPad SetFlash +350 3800 Flash +0 0 55 /PRndPad SetFlash +-850 3700 Flash +0 0 55 /PRndPad SetFlash +400 1300 Flash +0 0 55 /PRndPad SetFlash +-1050 1050 Flash +0 0 55 /PRndPad SetFlash +0 4475 Flash +75 4000 Flash +1000 4000 Flash +0 0 55 /PRndPad SetFlash +950 3200 Flash +0 0 55 /PRndPad SetFlash +850 1200 Flash +-600 1200 Flash +0 0 55 /PRndPad SetFlash +-550 3900 Flash +-350 3900 Flash +0 0 55 /PRndPad SetFlash +-800 4300 Flash +0 0 55 /PRndPad SetFlash +-750 4350 Flash +0 0 55 /PRndPad SetFlash +400 3400 Flash +grestore +showpage diff --git a/contrib/xntpd/gadget/dd0124.lpr b/contrib/xntpd/gadget/dd0124.lpr new file mode 100644 index 0000000000..f6474d4386 --- /dev/null +++ b/contrib/xntpd/gadget/dd0124.lpr @@ -0,0 +1,813 @@ +%!PS-Adobe-2.0 +%%Title: PADS Postscript Driver Header +%%Creator: Andy Montalvo, 18 Lupine St., Lowell, MA 01851 +%%CreationDate: 06/08/90 +%%For: CAD Software, Littleton, MA +%%EndComments +%%BeginProcSet: Markers 1.0 0 +% marker attributes +/MAttr_Width 1 def +/MAttr_Size 0 def +/MAttr_Type /M1 def +% procedures +/M1 { %def +% draw marker 1: plus +% Stack: - M1 - + -2 0 rmoveto + 4 0 rlineto + -2 2 rmoveto + 0 -4 rlineto +} bind def +/M2 { %def +% draw marker 2: cross +% Stack: - M2 - + -2 -2 rmoveto + 4 4 rlineto + -4 0 rmoveto + 4 -4 rlineto +} bind def +/M3 { %def +% draw marker 3: square +% Stack: - M3 - + 0 2 rlineto + 2 0 rlineto + 0 -4 rlineto + -4 0 rlineto + 0 4 rlineto + 2 0 rlineto +} bind def +/M4 { %def +% draw marker 4: diamond +% Stack: - M4 - + 0 2 rlineto + 2 -2 rlineto + -2 -2 rlineto + -2 2 rlineto + 2 2 rlineto +} bind def +/M5 { %def +% draw marker 5: hourglass +% Stack: - M5 - + 2 2 rlineto + -4 0 rlineto + 4 -4 rlineto + -4 0 rlineto + 2 2 rlineto +} bind def +/M6 { %def +% draw marker 6: bowtie +% Stack: - M6 - + 2 2 rlineto + 0 -4 rlineto + -4 4 rlineto + 0 -4 rlineto + 2 2 rlineto +} bind def +/M7 { %def +% draw marker 7: small plus (goes with char marker) +% Stack: - M7 - + -1 0 rmoveto + 2 0 rlineto + -1 1 rmoveto + 0 -2 rlineto +} bind def +/Marker { %def +% Command from driver: draw marker +% STACK: x y Marker - + MAttr_Size 0 gt + { + gsave + moveto + MAttr_Size 4 div dup scale + MAttr_Type load exec + 4 MAttr_Size div dup scale + MAttr_Width setlinewidth + stroke + grestore + } if +} def +%%EndProcSet: Markers 1.0 0 +%%BeginProcSet: Lib 1.0 0 +/sg { %def +% Command from driver: set the gray scale 0 - 100 +% STACK: greylevel sg + 100 div dup setgray /glev exch def +} bind def +/Circle { %def +% draw a circle +% STACK: x y radius Circle - + 0 360 arc +} bind def +/RndAper { %def +% select a round aperture +% STACK: - RndAper - + 1 setlinejoin + 1 setlinecap +} bind def +/SqrAper { %def +% select a square aperture +% STACK: - SqrAper - + 0 setlinejoin + 2 setlinecap +} bind def +/Line { %def +% draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] Line - + 3 1 roll + moveto + true + exch + % This pushes the x then the y then does lineto + { exch { false } { lineto true } ifelse } forall + pop +} bind def +/Clipto { %def +% set clipping rectangle from 0,0 to new values +% STACK: x y Clipto - + 0 0 moveto + dup 0 exch lineto + 2 copy lineto + pop + 0 lineto + closepath + clip + newpath +} bind def +/Clip4 { %def +% set clipping rectangle from xmin,ymin to xmax,ymax +% STACK: xmin ymin xmax ymax Clip4 - + 4 copy pop pop moveto + 4 copy pop exch lineto pop + 2 copy lineto + exch pop exch pop lineto + closepath + clip + newpath +} bind def +%%EndProcSet: Lib 1.0 0 +%%BeginProcSet: Lines 1.0 0 +% line attributes % +/LAttr_Width 1 def +% line procedures +/PLine { %def +% Cammand from driver: draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + LAttr_Width setlinewidth + stroke +} bind def % PLine +/Char { %def +% Command from driver: draw a character at the current position +% STACK: type x y stroke_array Char - +% stroke array -- [ stroke1 stroke2 ... stroken ] +% stroke -- connected staight lines +% type = 0 if text 1 if marker + gsave + 4 1 roll + translate + 0 eq { TAttr_Width } { MAttr_Width } ifelse setlinewidth + { + dup length 2 gt + { + dup dup 0 get exch 1 get % get starting point + 3 -1 roll % put x y before array + dup length 2 sub 2 exch getinterval % delete first items from array + Line + stroke + } + { + aload pop currentlinewidth 2 div Circle fill + } ifelse + } forall + grestore +} bind def % Char +/PArc { %def +% Command from driver: draw an arc +% STACK: x y radius startangle deltaangle Arc - + 10 div exch 10 div exch + 2 copy pop add + arc + LAttr_Width setlinewidth + stroke +} bind def +/PCircle { %def +% Command from driver: draw an circle +% STACK: x y radius PCircle - + Circle + LAttr_Width setlinewidth + stroke +} bind def +%%EndProcSet: Lines 1.0 0 +%%BeginProcSet: Polygon 1.0 0 +% polygon attributes % +/PAttr_ExtWidth 1 def +/PAttr_IntWidth 1 def +/PAttr_Grid 1 def +% polygon procedures +/LoopSet { %def +% set up for loop condition +% STACK: start end LoopSet low gridwidth high + 2 copy lt { exch } if + % make grid line up to absolute coordinates + PAttr_Grid div truncate PAttr_Grid mul exch + PAttr_Grid exch +} bind def +/Hatch { %def +% draw cross hatch pattern in current path +% STACK: - Hatch - + pathbbox + /ury exch def + /urx exch def + /lly exch def + /llx exch def + clip + newpath + llx urx LoopSet + { % x loop + dup lly exch ury moveto lineto + } for + lly ury LoopSet + { % y loop + llx exch dup urx exch moveto lineto + } for + PAttr_IntWidth setlinewidth + stroke +} bind def +/PPoly { %def +% Command from driver: draw a plygon +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + closepath + gsave + PAttr_IntWidth PAttr_Grid ge {fill} {Hatch} ifelse + grestore + PAttr_ExtWidth setlinewidth + stroke +} bind def +%%EndProcSet: Polygon 1.0 0 +%%BeginProcSet: Text 1.0 0 +% text attributes % +/TAttr_Mirr 0 def +/TAttr_Orient 0 def +/TAttr_Width 1 def +% text procedures +/Text { %def +% Command from driver: Draw text +% STACK: x y width string Text - + gsave + 4 2 roll + translate + TAttr_Mirr 0 gt + { + -1 1 scale + } if + TAttr_Orient rotate + 0 0 moveto + dup length dup 1 gt + { + exch dup stringwidth pop + 4 -1 roll + exch 2 copy + lt + { + div 1 scale show + } + { + sub + 3 -1 roll 1 sub div + 0 3 -1 roll ashow + } + ifelse + } + { + pop + show + } ifelse + grestore +} bind def +%%EndProcSet: Text 1.0 0 +%%BeginProcSet: FlashSymbols 1.0 0 +% flash symbol attributes % +/FAttr_Type /PRndPad def +/FAttr_Width 0 def +/FAttr_Length 1 def +/FAttr_Orient 0 def +% flash symbol procedures +/PRndPad { %def +% Command from driver: draw an circular pad +% STACK: - PCirclePad - + FAttr_Width dup scale + 0 0 .5 Circle + fill +} bind def +/PSqrPad { %def +% Draw an Square pad +% STACK: - PRectPad - + FAttr_Width dup scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/PRectPad { %def +% Draw an rectangular pad +% STACK: - PRectPad - + FAttr_Length FAttr_Width scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/POvalPad { %def +% Draw an oval pad +% STACK: - POvalPad - + FAttr_Width setlinewidth + FAttr_Length FAttr_Width sub 2 div dup + neg 0 moveto + 0 lineto + RndAper + stroke +} bind def +/Anl { %def + 0 0 .5 Circle + fill + FAttr_Length FAttr_Width lt + { % inner circle + 0 0 + FAttr_Length 0 gt { FAttr_Length FAttr_Width div } { .5 } ifelse + 2 div Circle + 1 setgray + fill + glev setgray + } if +} bind def +/PAnlPad { %def +% Draw an annular pad +% STACK: - PAnlPad - + FAttr_Width dup scale + Anl +} bind def +/PRelPad { %def +% Draw an thermal relief pad +% STACK: - PRelPad - + PAnlPad + 1 setgray + .17 setlinewidth + 0 setlinecap % the x + 45 rotate + .5 0 moveto -.5 0 lineto + 0 .5 moveto 0 -.5 lineto + stroke + glev setgray +} bind def +/Flash { %def +% Command from driver: Flash a symbol +% STACK: x y Flash - + FAttr_Width 0 gt + { + gsave + translate + FAttr_Orient rotate + FAttr_Type load exec + grestore + } if +} def +%%EndProcSet: FlashSymbols 1.0 0 +%%BeginProcSet: SetAttr 1.0 0 +/SetLine { %def +% Set the width of the lines +% STACK: linewidth SetLine - + /LAttr_Width exch def + RndAper +} bind def +/SetPoly { %def +% Set attribute of polygon +% STACK: external_width internal_grid_width grid_spacing SetPoly - + /PAttr_Grid exch def + /PAttr_IntWidth exch def + /PAttr_ExtWidth exch def + RndAper +} bind def +/SetFlash { %def +% Set Attributed of flash pad +% STACK: orientation_angle length width aperture_type SetFlash - + /FAttr_Type exch def + FAttr_Type /PSqrPad eq FAttr_Type /PRectPad eq or + { SqrAper } { RndAper } ifelse + /FAttr_Width exch def + /FAttr_Length exch def + /FAttr_Orient exch 10 div def +} bind def +/SetMkr { %def +% Set attributes of markers +% STACK: linewidth size type SetMkr - + /MAttr_Type exch def + /MAttr_Size exch def + /MAttr_Width exch def + RndAper +} bind def +/SetText1 { %def +% Set attributes of text +% STACK: fontname height orient mirror SetMkr - + /TAttr_Mirr exch def + /TAttr_Orient exch 10 div def + exch findfont exch scalefont setfont + RndAper +} bind def +/SetText2 { %def +% Set attributes of text +% STACK: linewidth height mirror orient SetMkr - + /TAttr_Width exch def + RndAper +} bind def +%%EndProcSet: SetAttr 1.0 0 +%%BeginProcSet: Initialize 1.0 0 +/Init { %def +% Initialize the driver +% STACK: Init - + 72 1000 div dup scale % Scale to 1/1000 inch + 250 250 translate % make origin 1/4 inch from bottom left + 1.5 setmiterlimit 1 RndAper % set line defaults + 0 setgray % set color default + /glev 0 def +} def +%%EndProcSet: Initialize 1.0 0 +%%EndProlog +/Helvetica findfont 12 scalefont setfont +35 760 moveto +(gadget.job - Fri Aug 21 03:35:28 1992) show +gsave +Init +8000 10500 Clipto +4002 3763 translate +0 rotate +1 1 div dup scale +75 sg +50 sg +25 sg +0 sg +10 SetLine +-1350 0 [ -1350 4900 ] PLine +-1350 4900 [ 1350 4900 ] PLine +1350 4900 [ 1350 0 ] PLine +1350 0 [ -1350 0 ] PLine +10 SetLine +-1350 4700 [ -1350 4900 ] PLine +-1350 4900 [ -1150 4900 ] PLine +10 SetLine +1150 4900 [ 1350 4900 ] PLine +1350 4900 [ 1350 4700 ] PLine +10 SetLine +1150 0 [ 1350 0 ] PLine +1350 0 [ 1350 200 ] PLine +10 SetLine +-1350 200 [ -1350 0 ] PLine +-1350 0 [ -1150 0 ] PLine +10 80 /M4 SetMkr +-1100 1450 Marker +-1100 1150 Marker +300 3300 Marker +-100 3300 Marker +-100 3100 Marker +300 3100 Marker +300 3500 Marker +-100 3500 Marker +-400 3700 Marker +-1200 3700 Marker +-100 1300 Marker +-900 1300 Marker +-200 2800 Marker +600 2800 Marker +-1200 2800 Marker +-400 2800 Marker +0 2500 Marker +0 2100 Marker +-1200 3400 Marker +-1200 3000 Marker +-900 2300 Marker +-1200 2300 Marker +-1200 2500 Marker +-900 2500 Marker +800 2800 Marker +1100 2800 Marker +1250 1900 Marker +450 1900 Marker +-100 900 Marker +-1200 900 Marker +-700 4000 Marker +-1100 4000 Marker +1100 3000 Marker +700 3000 Marker +-300 3700 Marker +0 3700 Marker +10 80 /M7 SetMkr +100 900 Marker +1 113 913 [ [ 25 52 0 0 ] [ 0 52 25 52 ] [ 0 0 25 0 ] ] Char +600 900 Marker +1 613 913 [ [ 25 52 0 0 ] [ 0 52 25 52 ] [ 0 0 25 0 ] ] Char +700 3700 Marker +1 713 3713 [ [ 25 52 0 0 ] [ 0 52 25 52 ] [ 0 0 25 0 ] ] Char +200 3700 Marker +1 213 3713 [ [ 25 52 0 0 ] [ 0 52 25 52 ] [ 0 0 25 0 ] ] Char +10 80 /M4 SetMkr +-750 550 Marker +-750 450 Marker +0 550 Marker +0 450 Marker +750 550 Marker +750 450 Marker +-648 4479 Marker +-540 4479 Marker +-432 4479 Marker +-324 4479 Marker +-216 4479 Marker +-108 4479 Marker +0 4479 Marker +108 4479 Marker +216 4479 Marker +324 4479 Marker +432 4479 Marker +540 4479 Marker +648 4479 Marker +-594 4593 Marker +-486 4593 Marker +-378 4593 Marker +-270 4593 Marker +-162 4593 Marker +-54 4593 Marker +54 4593 Marker +162 4593 Marker +270 4593 Marker +378 4593 Marker +486 4593 Marker +594 4593 Marker +10 80 /M7 SetMkr +940 4536 Marker +1 953 4549 [ [ 0 52 14 27 14 0 ] [ 29 52 14 27 ] ] Char +-940 4536 Marker +1 -927 4549 [ [ 0 52 14 27 14 0 ] [ 29 52 14 27 ] ] Char +10 80 /M4 SetMkr +950 150 Marker +1050 150 Marker +-50 150 Marker +50 150 Marker +-1050 150 Marker +-950 150 Marker +10 80 /M7 SetMkr +950 3524 Marker +1 963 3537 [ [ 0 52 25 0 ] [ 25 52 0 0 ] ] Char +1026 3612 Marker +1 1039 3625 [ [ 0 52 25 0 ] [ 25 52 0 0 ] ] Char +950 3700 Marker +1 963 3713 [ [ 0 52 25 0 ] [ 25 52 0 0 ] ] Char +10 80 /M7 SetMkr +-1200 1600 Marker +1 -1187 1613 [ [ 0 52 9 0 ] [ 18 52 9 0 ] [ 18 52 27 0 ] [ 36 52 27 0 ] ] Char +-1100 1700 Marker +1 -1087 1713 [ [ 0 52 9 0 ] [ 18 52 9 0 ] [ 18 52 27 0 ] [ 36 52 27 0 ] ] Char +-1200 1800 Marker +1 -1187 1813 [ [ 0 52 9 0 ] [ 18 52 9 0 ] [ 18 52 27 0 ] [ 36 52 27 0 ] ] Char +10 80 /M4 SetMkr +300 1700 Marker +-100 1700 Marker +200 1300 Marker +600 1300 Marker +-700 2300 Marker +-300 2300 Marker +-700 4200 Marker +-1100 4200 Marker +1100 3200 Marker +700 3200 Marker +-700 2500 Marker +-300 2500 Marker +-700 2100 Marker +-300 2100 Marker +-800 2100 Marker +-1200 2100 Marker +600 1100 Marker +200 1100 Marker +10 80 /M7 SetMkr +1200 2450 Marker +1 1213 2463 [ [ 0 52 9 0 ] [ 18 52 9 0 ] [ 18 52 27 0 ] [ 36 52 27 0 ] ] Char +1100 2350 Marker +1 1113 2363 [ [ 0 52 9 0 ] [ 18 52 9 0 ] [ 18 52 27 0 ] [ 36 52 27 0 ] ] Char +1200 2250 Marker +1 1213 2263 [ [ 0 52 9 0 ] [ 18 52 9 0 ] [ 18 52 27 0 ] [ 36 52 27 0 ] ] Char +10 80 /M4 SetMkr +-100 1900 Marker +300 1900 Marker +0 1500 Marker +400 1500 Marker +-900 1600 Marker +-800 1600 Marker +-700 1600 Marker +-600 1600 Marker +-500 1600 Marker +-400 1600 Marker +-300 1600 Marker +-300 1900 Marker +-400 1900 Marker +-500 1900 Marker +-600 1900 Marker +-700 1900 Marker +-800 1900 Marker +-900 1900 Marker +200 2200 Marker +300 2200 Marker +400 2200 Marker +500 2200 Marker +600 2200 Marker +700 2200 Marker +800 2200 Marker +900 2200 Marker +900 2500 Marker +800 2500 Marker +700 2500 Marker +600 2500 Marker +500 2500 Marker +400 2500 Marker +300 2500 Marker +200 2500 Marker +200 3900 Marker +300 3900 Marker +400 3900 Marker +500 3900 Marker +600 3900 Marker +700 3900 Marker +800 3900 Marker +900 3900 Marker +1000 3900 Marker +1100 3900 Marker +1100 4200 Marker +1000 4200 Marker +900 4200 Marker +800 4200 Marker +700 4200 Marker +600 4200 Marker +500 4200 Marker +400 4200 Marker +300 4200 Marker +200 4200 Marker +-1000 3100 Marker +-900 3100 Marker +-800 3100 Marker +-700 3100 Marker +-600 3100 Marker +-500 3100 Marker +-400 3100 Marker +-300 3100 Marker +-300 3400 Marker +-400 3400 Marker +-500 3400 Marker +-600 3400 Marker +-700 3400 Marker +-800 3400 Marker +-900 3400 Marker +-1000 3400 Marker +900 800 Marker +1100 800 Marker +1000 800 Marker +10 80 /M7 SetMkr +1000 1550 Marker +1 1013 1563 [ [ 0 52 14 27 14 0 ] [ 29 52 14 27 ] ] Char +10 80 /M4 SetMkr +0 4000 Marker +0 4200 Marker +10 80 /M7 SetMkr +-1100 450 Marker +1 -1087 463 [ [ 0 52 14 27 14 0 ] [ 29 52 14 27 ] ] Char +1100 450 Marker +1 1113 463 [ [ 0 52 14 27 14 0 ] [ 29 52 14 27 ] ] Char +10 80 /M4 SetMkr +1100 3400 Marker +700 3400 Marker +10 80 /M4 SetMkr +-200 2350 Marker +-200 1750 Marker +200 1400 Marker +10 80 /M4 SetMkr +300 1100 Marker +10 80 /M4 SetMkr +175 3300 Marker +10 80 /M4 SetMkr +1000 2650 Marker +10 80 /M4 SetMkr +-450 2100 Marker +10 80 /M4 SetMkr +-650 2600 Marker +-100 2600 Marker +-100 2250 Marker +10 80 /M4 SetMkr +800 1800 Marker +10 80 /M4 SetMkr +700 1900 Marker +10 80 /M4 SetMkr +600 1700 Marker +10 80 /M4 SetMkr +500 1600 Marker +10 80 /M4 SetMkr +0 4100 Marker +900 4100 Marker +10 80 /M4 SetMkr +800 3000 Marker +10 80 /M4 SetMkr +600 3700 Marker +10 80 /M4 SetMkr +450 2700 Marker +-400 2700 Marker +-400 2300 Marker +10 80 /M4 SetMkr +350 3800 Marker +10 80 /M4 SetMkr +-850 3700 Marker +10 80 /M4 SetMkr +400 1300 Marker +10 80 /M4 SetMkr +-1050 1050 Marker +10 80 /M4 SetMkr +0 4475 Marker +75 4000 Marker +1000 4000 Marker +10 80 /M4 SetMkr +950 3200 Marker +10 80 /M4 SetMkr +850 1200 Marker +-600 1200 Marker +10 80 /M4 SetMkr +-550 3900 Marker +-350 3900 Marker +10 80 /M4 SetMkr +-800 4300 Marker +10 80 /M4 SetMkr +-750 4350 Marker +10 80 /M4 SetMkr +400 3400 Marker +10 SetLine +-1355 -485 [ -275 -485 ] PLine +-1355 -725 [ -275 -725 ] PLine +-1355 -965 [ -275 -965 ] PLine +-1355 -1205 [ -275 -1205 ] PLine +-1355 -1445 [ -275 -1445 ] PLine +-1355 -1685 [ -275 -1685 ] PLine +-1355 -1925 [ -275 -1925 ] PLine +-1355 -485 [ -1355 -1925 ] PLine +-995 -485 [ -995 -1925 ] PLine +-635 -485 [ -635 -1925 ] PLine +-275 -485 [ -275 -1925 ] PLine +10 SetText2 +0 -1295 -665 [ [ 38 67 32 75 24 78 13 78 5 75 0 67 0 60 2 52 5 48 10 45 27 37 32 33 35 30 38 22 38 11 32 3 24 0 13 0 5 3 0 11 ] ] Char +0 -1233 -665 [ [ 0 78 0 0 ] ] Char +0 -1209 -665 [ [ 38 78 0 0 ] [ 0 78 38 78 ] [ 0 0 38 0 ] ] Char +0 -1147 -665 [ [ 0 78 0 0 ] [ 0 78 35 78 ] [ 0 41 21 41 ] [ 0 0 35 0 ] ] Char +10 SetText2 +0 -873 -665 [ [ 16 78 10 75 5 67 2 60 0 48 0 30 2 18 5 11 10 3 16 0 27 0 32 3 38 11 40 18 43 30 43 48 40 60 38 67 32 75 27 78 16 78 ] [ 24 15 40 -7 ] ] Char +0 -805 -665 [ [ 19 78 19 0 ] [ 0 78 38 78 ] ] Char +0 -743 -665 [ [ 0 78 21 41 21 0 ] [ 43 78 21 41 ] ] Char +10 SetText2 +0 -575 -665 [ [ 38 67 32 75 24 78 13 78 5 75 0 67 0 60 2 52 5 48 10 45 27 37 32 33 35 30 38 22 38 11 32 3 24 0 13 0 5 3 0 11 ] ] Char +0 -513 -665 [ [ 0 78 21 41 21 0 ] [ 43 78 21 41 ] ] Char +0 -445 -665 [ [ 0 78 0 0 ] [ 0 78 21 0 ] [ 43 78 21 0 ] [ 43 78 43 0 ] ] Char +10 SetText2 +0 -1233 -905 [ [ 5 78 35 78 19 48 27 48 32 45 35 41 38 30 38 22 35 11 30 3 21 0 13 0 5 3 2 7 0 15 ] ] Char +0 -1171 -905 [ [ 38 78 10 0 ] [ 0 78 38 78 ] ] Char +10 SetText2 +0 -873 -905 [ [ 2 60 2 63 5 71 8 75 13 78 24 78 30 75 32 71 35 63 35 56 32 48 27 37 0 0 38 0 ] ] Char +0 -811 -905 [ [ 16 78 8 75 2 63 0 45 0 33 2 15 8 3 16 0 21 0 30 3 35 15 38 33 38 45 35 63 30 75 21 78 16 78 ] ] Char +0 -749 -905 [ [ 27 78 0 26 40 26 ] [ 27 78 27 0 ] ] Char +10 120 /M4 SetMkr +-455 -845 Marker +10 SetText2 +0 -1233 -1145 [ [ 27 78 0 26 40 26 ] [ 27 78 27 0 ] ] Char +0 -1168 -1145 [ [ 0 63 5 67 13 78 13 0 ] ] Char +10 SetText2 +0 -749 -1145 [ [ 32 67 30 75 21 78 16 78 8 75 2 63 0 45 0 26 2 11 8 3 16 0 19 0 27 3 32 11 35 22 35 26 32 37 27 45 19 48 16 48 8 45 2 37 0 26 ] ] Char +10 SetText2 +0 -515 -1145 [ [ 0 78 13 0 ] [ 27 78 13 0 ] [ 27 78 40 0 ] [ 54 78 40 0 ] ] Char +10 SetText2 +0 -1233 -1385 [ [ 5 78 35 78 19 48 27 48 32 45 35 41 38 30 38 22 35 11 30 3 21 0 13 0 5 3 2 7 0 15 ] ] Char +0 -1171 -1385 [ [ 2 60 2 63 5 71 8 75 13 78 24 78 30 75 32 71 35 63 35 56 32 48 27 37 0 0 38 0 ] ] Char +10 SetText2 +0 -749 -1385 [ [ 5 78 35 78 19 48 27 48 32 45 35 41 38 30 38 22 35 11 30 3 21 0 13 0 5 3 2 7 0 15 ] ] Char +10 SetText2 +0 -515 -1385 [ [ 0 78 38 0 ] [ 38 78 0 0 ] ] Char +10 SetText2 +0 -1295 -1625 [ [ 0 63 5 67 13 78 13 0 ] ] Char +0 -1257 -1625 [ [ 2 60 2 63 5 71 8 75 13 78 24 78 30 75 32 71 35 63 35 56 32 48 27 37 0 0 38 0 ] ] Char +0 -1195 -1625 [ [ 16 78 8 75 2 63 0 45 0 33 2 15 8 3 16 0 21 0 30 3 35 15 38 33 38 45 35 63 30 75 21 78 16 78 ] ] Char +10 SetText2 +0 -749 -1625 [ [ 35 78 8 78 5 45 8 48 16 52 24 52 32 48 38 41 40 30 38 22 35 11 30 3 21 0 13 0 5 3 2 7 0 15 ] ] Char +10 SetText2 +0 -515 -1625 [ [ 0 78 21 41 21 0 ] [ 43 78 21 41 ] ] Char +10 SetText2 +0 -1233 -1865 [ [ 5 78 35 78 19 48 27 48 32 45 35 41 38 30 38 22 35 11 30 3 21 0 13 0 5 3 2 7 0 15 ] ] Char +0 -1171 -1865 [ [ 35 78 8 78 5 45 8 48 16 52 24 52 32 48 38 41 40 30 38 22 35 11 30 3 21 0 13 0 5 3 2 7 0 15 ] ] Char +10 SetText2 +0 -749 -1865 [ [ 27 78 0 26 40 26 ] [ 27 78 27 0 ] ] Char +10 SetText2 +0 -515 -1865 [ [ 38 78 0 0 ] [ 0 78 38 78 ] [ 0 0 38 0 ] ] Char +grestore +showpage diff --git a/contrib/xntpd/gadget/gadget.lst b/contrib/xntpd/gadget/gadget.lst new file mode 100644 index 0000000000..a10aff3054 --- /dev/null +++ b/contrib/xntpd/gadget/gadget.lst @@ -0,0 +1,332 @@ + + + +--------------------------------------------------------------------------- + DESIGN RULE CHECK Tue Sep 15 01:23:56 1992 PAGE 1 + 1-PPS/RS232 CONVERTER 100-0001-001 REV 1A 26 JUNE 1992 +--------------------------------------------------------------------------- + + + +FLOATING INPUTS: + NONE FOUND + +NETS WITH NO DRIVING SOURCE: + NONE FOUND + +NETS WITH MULTIPLE DRIVING SOURCES: + NONE FOUND + +NETS WITH MORE THAN ONE LABEL: + NONE FOUND + +NETS WITH A SINGLE PIN: + NONE FOUND + +REFERENCE DESIGNATORS USED TWO OR MORE TIMES: + NONE FOUND + + + +--------------------------------------------------------------------------- + REPORT REF. DES. Tue Sep 15 01:23:56 1992 PAGE 1 + 1-PPS/RS232 CONVERTER 100-0001-001 REV 1A 26 JUNE 1992 +--------------------------------------------------------------------------- + + +C1 DCAP A/01 +C10 DCAP A/01 +C11 DCAP A/01 +C12 DCAPE A/01 +C13 DCAP A/01 +C14 DCAP A/01 +C15 DCAP A/01 +C16 DCAPE A/01 +C17 DCAPE A/01 +C18 DCAPE A/01 +C2 DCAP A/01 +C3 DCAPE A/01 +C4 DCAP A/01 +C5 DCAP A/01 +C6 DCAP A/01 +C7 DCAP A/01 +C8 DCAP A/01 +C9 DCAPE A/01 +D1 DDIODE A/01 +D2 DDIODE A/01 +J1 DB25 A/01 +J2 DBNC A/01 +J3 DBNC A/01 +J4 DBNC A/01 +LED1 DLED A/01 +LED2 DLED A/01 +LED3 DLED A/01 +Q1 DPNP A/01 +R1 DRES A/01 +R10 DRES A/01 +R11 DRES A/01 +R12 DRES A/01 +R13 DRES A/01 +R14 DRES A/01 +R2 DRES A/01 +R3 DRES A/01 +R4 DRES A/01 +R5 DRES A/01 +R6 DRES A/01 +R7 DPOT A/01 +R8 DPOT A/01 +R9 DRES A/01 +U1 ICL232 A/01 +U2 MC145443 A/01 +U3A 74LS123 A/01 +U3B 74LS123 B/01 +U4A LM324 A/01 +U4B LM324 B/01 + + + +--------------------------------------------------------------------------- + REPORT REF. DES. Tue Sep 15 01:23:57 1992 PAGE 2 + 1-PPS/RS232 CONVERTER 100-0001-001 REV 1A 26 JUNE 1992 +--------------------------------------------------------------------------- + + +U5 LM7805 A/01 +X1 DXTAL A/01 + + + +--------------------------------------------------------------------------- + REPORT LABEL Tue Sep 15 01:23:57 1992 PAGE 1 + 1-PPS/RS232 CONVERTER 100-0001-001 REV 1A 26 JUNE 1992 +--------------------------------------------------------------------------- + + ++12 01 ++5 01 +AGND 01 +CGND 01 +GND 01 +VCC 01 + + + +--------------------------------------------------------------------------- + WIRE LIST Tue Sep 15 01:23:57 1992 PAGE 1 + 1-PPS/RS232 CONVERTER 100-0001-001 REV 1A 26 JUNE 1992 +--------------------------------------------------------------------------- + + +1 +12 C18-T D1-C D2-C + U5-1 + +2 +5 C1-T C13-T C2-T + C3-B C7-T R11-T + R12-L R2-T R7-1 + R7-2 R9-L U1-16 + U2-13 U2-14 U2-6 + U3A-16 U3B-16 U5-3 + +3 01007018 J2-1 R8-1 + +4 01007039 J3-1 R13-T U3A-2 + +5 01011019 C15-L R8-2 + +6 01013019 C15-R R3-T U4A-3 + +7 01013024 C5-T C6-B C7-B + C8-B R3-B U2-18 + U2-19 + +8 01015020 U4A-1 U4A-2 U4B-5 + +9 01017033 C14-T R7-3 U3A-15 + +10 01019043 R11-B U3A-3 U3B-11 + +11 01020035 C14-B U3A-14 + +12 01022016 C11-L R6-L U4B-6 + +13 01022039 U3A-13 U3B-10 + +14 01022040 U1-11 U3A-4 + +15 01024023 C10-L C11-R R5-T + +16 01027016 C10-R R4-L R6-R + U4B-7 + +17 01029043 C17-T R9-R U3B-7 + +18 01030057 D2-A J4-1 + +19 01031045 C17-B U3B-6 + +20 01033049 R10-L U3B-5 + +21 01036049 LED3-A R10-R + + + + +--------------------------------------------------------------------------- + WIRE LIST Tue Sep 15 01:23:57 1992 PAGE 2 + 1-PPS/RS232 CONVERTER 100-0001-001 REV 1A 26 JUNE 1992 +--------------------------------------------------------------------------- + + +22 01037023 U2-9 X1-L + +23 01038014 Q1-E R2-B + +24 01038017 LED1-A Q1-C + +25 01040015 Q1-B R14-L + +26 01041023 U2-8 X1-R + +27 01042022 C8-T U2-7 + +28 01045015 C4-B U2-4 + +29 01045018 R14-R U2-3 + +30 01045020 U1-10 U2-5 + +31 01046010 R1-L R4-R U2-16 + +32 01046025 C6-T U2-10 + +33 01047042 C9-T U1-1 + +34 01047044 C9-B U1-3 + +35 01048033 J1-2 U1-8 + +36 01049034 J1-11 U1-13 + +37 01051047 C3-T U1-2 + +38 01052057 LED2-A R12-R + +39 01054021 R1-R U2-15 + +40 01054025 U1-9 U2-11 + +41 01054047 C16-T U1-6 + +42 01055053 D1-A J1-20 J1-6 + J1-8 + +43 01057040 J1-12 U1-14 + +44 01057041 J1-3 U1-7 + +45 01057042 C12-T U1-4 + +46 01057044 C12-B U1-5 + + + + +--------------------------------------------------------------------------- + WIRE LIST Tue Sep 15 01:23:57 1992 PAGE 3 + 1-PPS/RS232 CONVERTER 100-0001-001 REV 1A 26 JUNE 1992 +--------------------------------------------------------------------------- + + +47 01068042 J1-4 J1-5 + +48 AGND C4-T C5-B LED1-C + R5-B R8-3 U2-2 + U4A-11 U4B-11 + +49 CGND J2-2 J3-2 J4-2 + +50 GND C1-B C13-B C16-B + C18-B C2-B J1-1 + J1-7 LED2-C LED3-C + R13-B U1-15 U2-12 + U3A-1 U3A-8 U3B-8 + U3B-9 U5-2 + +51 VCC U4A-4 U4B-4 + + + + +--------------------------------------------------------------------------------------------------------------- +BILL OF MATERIALS XYZ COMPUTER CORP. LORAN 150-0001-001 REV 1A Tue Sep 15 01:23:57 1992 PAGE 1 +--------------------------------------------------------------------------------------------------------------- + + + ITEM QUAN. PART NUMBER DESCRIPTION REF. DES. + + 1 7 CAPACITOR,100N, C1,C13,C2,C5,C6 + C7,C8 + + 2 1 CAPACITOR,100U C18 + + 3 5 CAPACITOR,10N, C10,C11,C14,C15 + C4 + + 4 5 CAPACITOR,22U C12,C16,C17,C3 + C9 + + 5 1 CRYSTAL, 3.59MHZ X1 + + 6 2 DIODE, 1N4002 D1,D2 + + 7 1 LIGHT EMITTING DIODE, AMBER LED3 + + 8 1 LIGHT EMITTING DIODE, GRN LED1 + + 9 1 LIGHT EMITTING DIODE, RED LED2 + + 10 1 PNP TRANSISTOR, 2N2907 Q1 + + 11 1 POTENTIOMETER, 10K R8 + + 12 1 POTENTIOMETER, 20K R7 + + 13 2 RESISTOR,100K, R13,R3 + + 14 1 RESISTOR,10K, R1 + + 15 1 RESISTOR,1MEG, R4 + + 16 2 RESISTOR,3.3K, R11,R14 + + 17 3 RESISTOR,330, R10,R12,R2 + + 18 1 RESISTOR,33K, R9 + + 19 1 RESISTOR,680, R5 + + 20 1 RESISTOR,68K, R6 + + 21 3 010-0002-001 CONNECTOR, BNC CHASSIS J2,J3,J4 + + 22 1 010-DB25-001 DB25 - 25-PIN CONNECTOR J1 + + 23 2 300-0123-001 74LS123 - LS TTL RETRIG MONOSTABLE MULTIVIBRATORS U3A,U3B + + + +--------------------------------------------------------------------------------------------------------------- +BILL OF MATERIALS XYZ COMPUTER CORP. LORAN 150-0001-001 REV 1A Tue Sep 15 01:23:57 1992 PAGE 2 +--------------------------------------------------------------------------------------------------------------- + + + ITEM QUAN. PART NUMBER DESCRIPTION REF. DES. + + 24 2 302-0324-001 LM324A - LOW POWER QUAD OP-AMP U4A,U4B + + 25 1 302-7805-001 LM7805C - VOLTAGE REGULATOR, +5VDC U5 + + 26 1 306-5443-001 MC145443 - 300-BPS MODEM U2 + + 27 1 310-0232-001 ICL232 - POWERED RS232 TRANSMITTER/RECEIVER U1 + diff --git a/contrib/xntpd/gadget/gadget.s01 b/contrib/xntpd/gadget/gadget.s01 new file mode 100644 index 0000000000..314f7ba18a --- /dev/null +++ b/contrib/xntpd/gadget/gadget.s01 @@ -0,0 +1,2277 @@ +%!PS-Adobe-23.0 EPSF-1.2 +%%Creator: SCHEMA +%%BoundingBox: 0 0 1343.0 1023.0 +/scl 511804.0 0.072 mul 65536.0 div def +scl scl scale + +% Landscape Orientation +/xoff 256.0 65536.0 mul 511804.0 div def +/yoff 1343.0 -256.0 65536.0 mul 511804.0 div sub def +xoff yoff translate +-90 rotate + +0 setgray + +/a { 1 setlinewidth newpath arcn stroke } def +/fa { 3 setlinewidth newpath arcn stroke } def +/c { 1 setlinewidth newpath 0 360 arc stroke } def +/fc { 1 setlinewidth newpath 0 360 arc fill } def +/l { 1 setlinewidth newpath moveto lineto stroke } def +/t { 3 setlinewidth newpath moveto lineto stroke } def +/ds { [4 4] 0 setdash 1 setlinewidth + newpath moveto lineto stroke [] 0 setdash } def +/dt { [2 2] 0 setdash 1 setlinewidth + newpath moveto lineto stroke [] 0 setdash } def + +8 7 8 1015 t +1328 7 912 7 t +1336 1015 8 1015 t +1336 7 1336 1015 t +912 7 8 7 t +1336 7 1328 7 t + +/reencsmalldict 12 dict def %% Schema font definitions +/ReEncodeSmall + { reencsmalldict begin + /newcodesandnames exch def + /newfontname exch def + /basefontname exch def + /basefontdict basefontname findfont def + /newfont basefontdict maxlength dict def + basefontdict + { exch dup /FID ne + { dup /Encoding eq + { exch dup length array copy newfont 3 1 roll put } + { exch newfont 3 1 roll put } + ifelse + } + { pop pop } + ifelse + } forall + newfont /FontName newfontname put + newcodesandnames aload pop + newcodesandnames length 2 idiv + { newfont /Encoding get 3 1 roll put } + repeat + newfontname newfont definefont pop + end + } def +/schfontvec [ 8#200 /Ccedilla 8#201 /udieresis 8#202 /eacute 8#203 /acircumflex +8#204 /adieresis 8#205 /agrave 8#207 /ccedilla 8#210 /ecircumflex +8#211 /edieresis 8#212 /egrave 8#213 /idieresis 8#214 /icircumflex +8#215 /igrave 8#216 /Adieresis 8#220 /Eacute 8#223 /ocircumflex +8#224 /odieresis 8#225 /ograve 8#226 /ucircumflex 8#227 /ugrave +8#230 /ydieresis 8#231 /Odieresis 8#232 /Udieresis 8#240 /aacute 8#241 /iacute +8#242 /oacute 8#243 /uacute 8#244 /ntilde 8#245 /Ntilde ] def +/schsymbvec [ 8#341 /beta 8#346 /mu 8#352 /Omega ] def +/Courier-Bold /Schfont schfontvec ReEncodeSmall +/Symbol /Schsymb schsymbvec ReEncodeSmall + + +/htdict 4 dict def %% HTEXT - variable spacing horizontal text routine +/ht + { htdict begin + /textstring exch def + /xskip exch def + 0 text_height neg rmoveto + /Schfont findfont text_height scalefont setfont + textstring + { + /charcode exch def + /thechar ( ) dup 0 charcode put def + gsave + charcode 8#245 gt + { /Schsymb findfont text_height scalefont setfont + thechar show + /Schfont findfont text_height scalefont setfont } + { thechar show } + ifelse + grestore + currentpoint moveto + xskip 0 rmoveto + } forall + end + } def + +/text_height 12 def +/text_width 6 def +1304 27 moveto 9 (2) ht +/text_height 12 def +/text_width 6 def +1272 27 moveto 9 (OF) ht +/text_height 12 def +/text_width 6 def +1248 27 moveto 9 (1) ht +/text_height 12 def +/text_width 6 def +1192 27 moveto 9 (SHEET) ht +1176 31 1176 7 l +1336 55 992 55 l +1336 31 992 31 l +992 7 992 87 t +1336 87 992 87 t +/text_height 20 def +/text_width 9 def +1032 87 moveto 13 (1-PPS/RS232 Converter) ht +/text_height 12 def +/text_width 6 def +1040 27 moveto 9 (26 June 1992) ht +1176 55 1176 31 l +/text_height 12 def +/text_width 6 def +1032 51 moveto 9 (100-0001-001) ht +/text_height 12 def +/text_width 6 def +1216 51 moveto 9 (REV) ht +/text_height 12 def +/text_width 6 def +1264 51 moveto 9 (1A) ht +584 54 568 54 l +576 54 576 63 l +581 51 571 51 l +578 48 574 48 l +/b { newpath 0.5 0 360 arc fill } def +576 45 b +760 54 744 54 l +752 54 752 63 l +757 51 747 51 l +754 48 750 48 l +752 45 b +752 103 752 95 l +752 103 2 fc +288 487 288 455 l +320 487 288 487 l +288 487 2 fc +248 383 248 367 l +456 103 8 c +456 71 456 95 l +/text_height 12 def +/text_width 6 def +441 129 moveto 9 (J4) ht +456 105 b +457 105 b +455 104 b +456 104 b +457 104 b +458 104 b +455 103 b +456 103 b +457 103 b +458 103 b +456 102 b +457 102 b +480 103 456 103 l +583 81 569 81 l +576 59 18 111 69 a +576 81 576 95 l +576 63 576 77 l +/text_height 12 def +/text_width 6 def +589 81 moveto 9 (100U) ht +/text_height 12 def +/text_width 6 def +590 94 moveto 9 (C18) ht +/text_height 12 def +/text_width 6 def +561 96 moveto 9 (+) ht +/text_height 12 def +/text_width 6 def +765 94 moveto 9 (C1) ht +/text_height 12 def +/text_width 6 def +765 81 moveto 9 (100N) ht +759 81 745 81 l +752 59 18 111 69 a +752 81 752 95 l +752 63 752 77 l +509 109 b +509 108 b +510 108 b +515 108 b +509 107 b +510 107 b +511 107 b +515 107 b +509 106 b +510 106 b +511 106 b +512 106 b +515 106 b +509 105 b +510 105 b +511 105 b +512 105 b +513 105 b +515 105 b +509 104 b +510 104 b +511 104 b +512 104 b +513 104 b +514 104 b +515 104 b +509 103 b +510 103 b +511 103 b +512 103 b +513 103 b +514 103 b +515 103 b +509 102 b +510 102 b +511 102 b +512 102 b +513 102 b +514 102 b +515 102 b +509 101 b +510 101 b +511 101 b +512 101 b +513 101 b +515 101 b +509 100 b +510 100 b +511 100 b +512 100 b +515 100 b +509 99 b +510 99 b +511 99 b +515 99 b +509 98 b +510 98 b +515 98 b +509 97 b +516 103 b +510 103 496 103 l +528 103 517 103 l +/text_height 12 def +/text_width 6 def +496 99 moveto 9 (1N4002) ht +/text_height 12 def +/text_width 6 def +497 124 moveto 9 (D2) ht +576 103 576 95 l +560 103 528 103 l +560 103 2 fc +592 103 576 103 l +576 103 560 103 l +576 103 2 fc +496 103 480 103 l +240 695 240 671 l +328 671 240 671 l +328 703 328 671 l +240 711 208 711 l +208 711 208 687 l +384 703 328 703 l +136 735 112 735 l +392 767 352 767 l +384 687 352 687 l +408 647 408 631 l +208 676 208 687 l +/text_height 12 def +/text_width 6 def +218 677 moveto 9 (R3) ht +/text_height 12 def +/text_width 6 def +218 664 moveto 9 (100K) ht +213 673 208 675 l +213 657 204 653 l +213 657 204 661 l +213 665 204 669 l +213 665 204 661 l +208 649 208 651 l +208 652 204 653 l +208 639 208 650 l +213 673 204 669 l +208 675 208 677 l +208 650 208 652 l +208 711 2 fc +328 703 2 fc +352 687 352 647 l +352 767 352 687 l +352 687 2 fc +432 647 408 647 l +408 647 384 647 l +408 647 2 fc +904 751 872 751 l +904 735 872 735 l +968 687 872 687 l +968 703 968 687 l +/text_height 12 def +/text_width 6 def +616 695 moveto 9 (X1) ht +/text_height 12 def +/text_width 6 def +616 683 moveto 9 (3.59MHZ) ht +628 645 628 665 l +637 645 637 665 l +634 667 631 667 l +634 643 634 667 l +634 643 631 643 l +631 643 631 667 l +628 655 600 655 l +664 655 637 655 l +920 607 904 607 l +920 655 920 647 l +744 575 744 559 l +752 623 744 623 l +744 623 744 607 l +752 671 696 671 l +752 655 664 655 l +600 655 600 639 l +752 639 600 639 l +680 575 680 559 l +680 671 680 607 l +752 703 728 703 l +712 815 712 751 l +752 751 712 751 l +728 783 728 719 l +752 719 728 719 l +696 671 680 671 l +888 863 736 863 l +688 863 480 863 l +/text_height 12 def +/text_width 6 def +590 855 moveto 9 (+5) ht +744 559 2 fc +904 607 2 fc +920 655 872 655 l +920 655 2 fc +920 703 888 703 l +888 703 872 703 l +888 703 2 fc +728 815 712 815 l +712 815 696 815 l +712 815 2 fc +888 863 888 703 l +904 607 904 559 l +904 735 904 607 l +904 751 904 735 l +904 735 2 fc +248 399 128 399 l +128 399 2 fc +136 342 120 342 l +128 342 128 351 l +133 339 123 339 l +130 336 126 336 l +128 333 b +256 358 240 358 l +248 358 248 367 l +253 355 243 355 l +250 352 246 352 l +248 349 b +560 175 560 103 l +464 327 464 295 l +496 327 464 327 l +880 94 864 94 l +872 94 872 103 l +877 91 867 91 l +874 88 870 88 l +872 85 b +872 103 864 103 l +424 223 424 207 l +416 327 400 327 l +400 327 400 303 l +400 255 400 167 l +480 167 400 167 l +432 198 416 198 l +424 198 424 207 l +429 195 419 195 l +426 192 422 192 l +424 189 b +464 327 2 fc +480 767 440 767 l +480 767 480 695 l +480 863 480 767 l +480 767 2 fc +480 695 480 647 l +480 647 464 647 l +480 695 2 fc +88 735 8 c +88 703 88 727 l +/text_height 12 def +/text_width 6 def +73 761 moveto 9 (J2) ht +88 737 b +89 737 b +87 736 b +88 736 b +89 736 b +90 736 b +87 735 b +88 735 b +89 735 b +90 735 b +88 734 b +89 734 b +112 735 88 735 l +/text_height 12 def +/text_width 6 def +333 486 moveto 9 (C14) ht +/text_height 12 def +/text_width 6 def +333 473 moveto 9 (10N) ht +327 473 313 473 l +320 451 18 111 69 a +320 473 320 487 l +320 455 320 469 l +698 863 688 863 l +736 863 726 863 l +/text_height 12 def +/text_width 6 def +691 883 moveto 9 (1MEG) ht +/text_height 12 def +/text_width 6 def +691 895 moveto 9 (R4) ht +702 868 700 863 l +706 859 702 868 l +710 868 706 859 l +714 859 710 868 l +718 868 714 859 l +722 859 718 868 l +724 863 722 859 l +726 863 724 863 l +700 863 699 863 l +930 703 920 703 l +968 703 958 703 l +/text_height 12 def +/text_width 6 def +923 723 moveto 9 (10K) ht +/text_height 12 def +/text_width 6 def +923 735 moveto 9 (R1) ht +934 708 932 703 l +938 699 934 708 l +942 708 938 699 l +946 699 942 708 l +950 708 946 699 l +954 699 950 708 l +956 703 954 699 l +958 703 956 703 l +932 703 931 703 l +784 103 768 103 l +768 103 752 103 l +288 487 272 487 l +480 695 472 695 l +920 607 920 599 l +920 615 920 607 l +920 607 2 fc +792 399 776 399 l +792 383 360 383 l +728 703 728 367 l +792 367 728 367 l +400 292 400 303 l +/text_height 12 def +/text_width 6 def +410 293 moveto 9 (R11) ht +/text_height 12 def +/text_width 6 def +410 280 moveto 9 (3.3K) ht +405 289 400 291 l +405 273 396 269 l +405 273 396 277 l +405 281 396 285 l +405 281 396 277 l +400 265 400 267 l +400 268 396 269 l +400 255 400 266 l +405 289 396 285 l +400 291 400 293 l +400 266 400 268 l +128 388 128 399 l +/text_height 12 def +/text_width 6 def +138 389 moveto 9 (R13) ht +/text_height 12 def +/text_width 6 def +138 376 moveto 9 (100K) ht +133 385 128 387 l +133 369 124 365 l +133 369 124 373 l +133 377 124 381 l +133 377 124 373 l +128 361 128 363 l +128 364 124 365 l +128 351 128 362 l +133 385 124 381 l +128 387 128 389 l +128 362 128 364 l +88 399 8 c +88 367 88 391 l +/text_height 12 def +/text_width 6 def +73 425 moveto 9 (J3) ht +88 401 b +89 401 b +87 400 b +88 400 b +89 400 b +90 400 b +87 399 b +88 399 b +89 399 b +90 399 b +88 398 b +89 398 b +112 399 88 399 l +128 399 112 399 l +376 399 360 399 l +376 399 376 239 l +424 239 376 239 l +608 836 608 847 l +/text_height 12 def +/text_width 6 def +618 837 moveto 9 (R2) ht +/text_height 12 def +/text_width 6 def +618 824 moveto 9 (330) ht +613 833 608 835 l +613 817 604 813 l +613 817 604 821 l +613 825 604 829 l +613 825 604 821 l +608 809 608 811 l +608 812 604 813 l +608 799 608 810 l +613 833 604 829 l +608 835 608 837 l +608 810 608 812 l +224 487 208 487 l +400 327 360 327 l +224 487 2 fc +400 327 2 fc +/text_height 12 def +/text_width 6 def +190 495 moveto 9 (+5) ht +/text_height 12 def +/text_width 6 def +342 335 moveto 9 (+5) ht +944 655 920 655 l +680 559 208 559 l +744 559 680 559 l +208 639 208 559 l +680 559 2 fc +/text_height 12 def +/text_width 6 def +947 663 moveto 9 (+5) ht +768 127 768 103 l +768 103 2 fc + +/vtdict 4 dict def %% VTEXT - variable spacing verticle text routine +/vt + { vtdict begin + /thestring exch def + /yskip exch def + 0 text_height neg rmoveto + /Schfont findfont text_height scalefont setfont + thestring + { + /charcode exch def + /thechar ( ) dup 0 charcode put def + gsave + charcode 8#245 gt + { /Schsymb findfont text_height scalefont setfont + thechar show + /Schfont findfont text_height scalefont setfont } + { thechar show } + ifelse + grestore + currentpoint moveto + 0 yskip neg rmoveto + } forall + end + } def + +/text_height 12 def +/text_width 6 def +765 153 moveto 11 (+5) vt +234 487 224 487 l +272 487 262 487 l +238 492 b +238 491 b +237 490 b +239 490 b +237 489 b +239 489 b +236 488 b +240 488 b +235 487 b +236 487 b +240 487 b +241 486 b +241 485 b +246 492 b +246 491 b +245 490 b +247 490 b +245 489 b +247 489 b +244 488 b +248 488 b +244 487 b +248 487 b +243 486 b +243 485 b +242 484 b +242 483 b +254 492 b +254 491 b +253 490 b +255 490 b +253 489 b +255 489 b +252 488 b +252 487 b +249 486 b +251 486 b +249 485 b +251 485 b +250 484 b +250 483 b +256 488 b +256 487 b +260 487 b +261 487 b +257 486 b +259 486 b +257 485 b +259 485 b +258 484 b +258 483 b +248 463 248 479 l +248 481 b +247 480 b +248 480 b +249 480 b +246 479 b +247 479 b +248 479 b +249 479 b +250 479 b +245 478 b +246 478 b +247 478 b +248 478 b +249 478 b +250 478 b +244 477 b +245 477 b +246 477 b +247 477 b +248 477 b +249 477 b +250 477 b +251 478 b +251 477 b +252 477 b +/text_height 12 def +/text_width 6 def +233 508 moveto 9 (R7) ht +/text_height 12 def +/text_width 6 def +225 488 moveto 9 (1) ht +/text_height 12 def +/text_width 6 def +238 478 moveto 9 (2) ht +/text_height 12 def +/text_width 6 def +263 488 moveto 9 (3) ht +/text_height 12 def +/text_width 6 def +257 475 moveto 9 (20K) ht +752 103 736 103 l +672 54 656 54 l +664 54 664 63 l +669 51 659 51 l +666 48 662 48 l +664 45 b +/text_height 12 def +/text_width 6 def +272 811 moveto 9 (2000+-500 Hz) ht +/text_height 12 def +/text_width 6 def +256 827 moveto 9 (bandpass filter) ht +/text_height 12 def +/text_width 6 def +272 515 moveto 9 (\(for 38.4 baud\)) ht +/text_height 12 def +/text_width 6 def +280 531 moveto 9 (26-us one-shot) ht +/text_height 12 def +/text_width 6 def +448 363 moveto 9 (200-ms one shot) ht +224 487 224 463 l +248 463 224 463 l +304 327 304 167 l +400 167 304 167 l +400 167 2 fc +/text_height 12 def +/text_width 6 def +384 99 moveto 9 (\(6-12V\)) ht +/text_height 12 def +/text_width 6 def +32 731 moveto 9 (\(BNC\)) ht +/text_height 12 def +/text_width 6 def +32 747 moveto 9 (audio) ht +/text_height 12 def +/text_width 6 def +40 411 moveto 9 (1pps) ht +/text_height 12 def +/text_width 6 def +32 395 moveto 9 (\(BNC\)) ht +/text_height 12 def +/text_width 6 def +400 115 moveto 9 (power) ht +767 337 753 337 l +760 315 18 111 69 a +760 337 760 351 l +760 319 760 333 l +/text_height 12 def +/text_width 6 def +773 337 moveto 9 (22U) ht +/text_height 12 def +/text_width 6 def +774 350 moveto 9 (C9) ht +/text_height 12 def +/text_width 6 def +745 352 moveto 9 (+) ht +935 337 921 337 l +928 315 18 111 69 a +928 337 928 351 l +928 319 928 333 l +/text_height 12 def +/text_width 6 def +941 337 moveto 9 (22U) ht +/text_height 12 def +/text_width 6 def +942 350 moveto 9 (C12) ht +/text_height 12 def +/text_width 6 def +913 352 moveto 9 (+) ht +880 257 880 271 l +880 239 880 253 l +/text_height 12 def +/text_width 6 def +893 257 moveto 9 (22U) ht +/text_height 12 def +/text_width 6 def +894 270 moveto 9 (C16) ht +873 259 b +874 259 b +875 258 b +876 258 b +877 258 b +878 257 b +879 257 b +873 254 b +874 254 b +875 254 b +876 254 b +877 254 b +878 254 b +879 254 b +886 259 b +883 258 b +884 258 b +885 258 b +880 257 b +881 257 b +882 257 b +880 254 b +881 254 b +882 254 b +883 254 b +884 254 b +885 254 b +886 254 b +887 259 b +887 254 b +/text_height 12 def +/text_width 6 def +865 255 moveto 9 (+) ht +831 257 817 257 l +824 235 18 111 69 a +824 257 824 271 l +824 239 824 253 l +/text_height 12 def +/text_width 6 def +837 257 moveto 9 (22U) ht +/text_height 12 def +/text_width 6 def +838 270 moveto 9 (C3) ht +/text_height 12 def +/text_width 6 def +809 272 moveto 9 (+) ht +888 230 872 230 l +880 230 880 239 l +885 227 875 227 l +882 224 878 224 l +880 221 b +792 351 760 351 l +792 319 760 319 l +928 351 912 351 l +928 319 912 319 l +832 271 824 271 l +880 271 872 271 l +/text_height 12 def +/text_width 6 def +821 240 moveto 11 (+5) vt +/text_height 12 def +/text_width 6 def +624 307 moveto 9 (EIA level converter) ht +936 399 912 399 l +872 671 872 655 l +872 655 2 fc +/text_height 12 def +/text_width 6 def +752 835 moveto 9 (300-baud modem) ht +88 359 88 367 l +81 357 b +80 356 b +79 355 b +78 354 b +77 353 b +76 352 b +75 351 b +82 358 b +88 357 b +87 356 b +86 355 b +85 354 b +84 353 b +83 352 b +82 351 b +89 358 b +95 357 b +94 356 b +93 355 b +92 354 b +91 353 b +90 352 b +89 351 b +96 358 b +96 358 82 358 l +88 695 88 703 l +81 693 b +80 692 b +79 691 b +78 690 b +77 689 b +76 688 b +75 687 b +82 694 b +88 693 b +87 692 b +86 691 b +85 690 b +84 689 b +83 688 b +82 687 b +89 694 b +95 693 b +94 692 b +93 691 b +92 690 b +91 689 b +90 688 b +89 687 b +96 694 b +96 694 82 694 l +456 63 456 71 l +449 61 b +448 60 b +447 59 b +446 58 b +445 57 b +444 56 b +443 55 b +450 62 b +456 61 b +455 60 b +454 59 b +453 58 b +452 57 b +451 56 b +450 55 b +457 62 b +463 61 b +462 60 b +461 59 b +460 58 b +459 57 b +458 56 b +457 55 b +464 62 b +464 62 450 62 l +696 807 696 815 l +688 806 b +689 806 b +690 806 b +691 806 b +692 806 b +693 806 b +694 806 b +689 805 b +690 804 b +691 803 b +692 802 b +693 801 b +694 800 b +696 807 b +695 806 b +696 806 b +697 806 b +698 806 b +699 806 b +700 806 b +701 806 b +701 803 b +700 802 b +699 801 b +698 800 b +695 799 b +697 799 b +696 798 b +702 806 b +703 806 b +704 806 b +703 805 b +702 804 b +920 559 920 567 l +912 558 b +913 558 b +914 558 b +915 558 b +916 558 b +917 558 b +918 558 b +913 557 b +914 556 b +915 555 b +916 554 b +917 553 b +918 552 b +920 559 b +919 558 b +920 558 b +921 558 b +922 558 b +923 558 b +924 558 b +925 558 b +925 555 b +924 554 b +923 553 b +922 552 b +919 551 b +921 551 b +920 550 b +926 558 b +927 558 b +928 558 b +927 557 b +926 556 b +136 679 136 687 l +128 678 b +129 678 b +130 678 b +131 678 b +132 678 b +133 678 b +134 678 b +129 677 b +130 676 b +131 675 b +132 674 b +133 673 b +134 672 b +136 679 b +135 678 b +136 678 b +137 678 b +138 678 b +139 678 b +140 678 b +141 678 b +141 675 b +140 674 b +139 673 b +138 672 b +135 671 b +137 671 b +136 670 b +142 678 b +143 678 b +144 678 b +143 677 b +142 676 b +408 575 408 583 l +400 574 b +401 574 b +402 574 b +403 574 b +404 574 b +405 574 b +406 574 b +401 573 b +402 572 b +403 571 b +404 570 b +405 569 b +406 568 b +408 575 b +407 574 b +408 574 b +409 574 b +410 574 b +411 574 b +412 574 b +413 574 b +413 571 b +412 570 b +411 569 b +410 568 b +407 567 b +409 567 b +408 566 b +414 574 b +415 574 b +416 574 b +415 573 b +414 572 b +794 103 784 103 l +832 103 822 103 l +/text_height 12 def +/text_width 6 def +787 123 moveto 9 (330) ht +/text_height 12 def +/text_width 6 def +787 135 moveto 9 (R12) ht +798 108 796 103 l +802 99 798 108 l +806 108 802 99 l +810 99 806 108 l +814 108 810 99 l +818 99 814 108 l +820 103 818 99 l +822 103 820 103 l +796 103 795 103 l +/text_height 12 def +/text_width 6 def +528 118 moveto 9 (+12) ht +712 119 616 119 l +712 87 712 119 l +616 87 616 119 l +712 87 616 87 l +616 103 592 103 l +664 63 664 87 l +/text_height 12 def +/text_width 6 def +652 101 moveto 9 (GND) ht +/text_height 12 def +/text_width 6 def +619 111 moveto 9 (IN) ht +/text_height 12 def +/text_width 6 def +685 111 moveto 9 (OUT) ht +/text_height 12 def +/text_width 6 def +602 118 moveto 9 (1) ht +/text_height 12 def +/text_width 6 def +640 136 moveto 9 (LM7805) ht +/text_height 12 def +/text_width 6 def +640 149 moveto 9 (U5) ht +/text_height 12 def +/text_width 6 def +667 83 moveto 9 (2) ht +736 103 712 103 l +/text_height 12 def +/text_width 6 def +720 118 moveto 9 (3) ht +862 180 b +867 180 b +862 179 b +866 179 b +867 179 b +862 178 b +865 178 b +866 178 b +867 178 b +862 177 b +864 177 b +865 177 b +866 177 b +867 177 b +862 176 b +863 176 b +864 176 b +865 176 b +866 176 b +867 176 b +861 175 b +862 175 b +863 175 b +864 175 b +865 175 b +866 175 b +867 175 b +862 174 b +863 174 b +864 174 b +865 174 b +866 174 b +867 174 b +862 173 b +864 173 b +865 173 b +866 173 b +867 173 b +862 172 b +865 172 b +866 172 b +867 172 b +862 171 b +866 171 b +867 171 b +862 170 b +867 170 b +868 181 b +868 180 b +868 179 b +868 178 b +868 177 b +868 176 b +868 175 b +868 174 b +868 173 b +868 172 b +868 171 b +868 170 b +868 169 b +862 175 848 175 l +880 175 867 175 l +/text_height 12 def +/text_width 6 def +850 196 moveto 9 (D1) ht +/text_height 12 def +/text_width 6 def +849 171 moveto 9 (1N4002) ht +848 175 560 175 l +810 383 792 383 l +813 383 3 c +810 367 792 367 l +813 367 3 c +816 415 792 415 l +816 399 792 399 l +891 399 3 c +912 399 894 399 l +912 383 888 383 l +912 367 888 367 l +891 415 3 c +912 415 894 415 l +/text_height 12 def +/text_width 6 def +903 430 moveto 16 (2 4) vt +/text_height 12 def +/text_width 6 def +796 430 moveto 16 (1 11) vt +/text_height 12 def +/text_width 6 def +870 424 moveto 16 (12122 2) vt +912 351 888 351 l +912 319 888 319 l +816 351 792 351 l +816 319 792 319 l +/text_height 12 def +/text_width 6 def +804 430 moveto 16 (38101 3) vt +888 431 816 431 l +/text_height 12 def +/text_width 6 def +879 424 moveto 16 (OOOO+ -) vt +/text_height 12 def +/text_width 6 def +895 430 moveto 16 (19174 5) vt +/text_height 12 def +/text_width 6 def +836 288 moveto 9 (2) ht +/text_height 12 def +/text_width 6 def +875 288 moveto 9 (6) ht +888 295 816 295 l +832 271 832 295 l +872 271 872 295 l +816 295 816 431 l +888 295 888 431 l +/text_height 12 def +/text_width 6 def +820 447 moveto 9 (ICL232) ht +/text_height 12 def +/text_width 6 def +831 460 moveto 9 (U1) ht +/text_height 12 def +/text_width 6 def +820 424 moveto 16 (RRTTC C) vt +/text_height 12 def +/text_width 6 def +829 424 moveto 16 (12121 1) vt +/text_height 12 def +/text_width 6 def +837 424 moveto 16 (IIII+ -) vt +/text_height 12 def +/text_width 6 def +861 424 moveto 16 (RRTTC C) vt +/text_height 12 def +/text_width 6 def +827 313 moveto 9 (V+) ht +/text_height 12 def +/text_width 6 def +865 313 moveto 9 (V-) ht +992 471 792 471 l +776 487 776 399 l +792 471 792 415 l +936 503 936 399 l +776 655 752 655 l +776 703 752 703 l +776 671 752 671 l +848 607 776 607 l +872 735 848 735 l +872 719 848 719 l +/text_height 12 def +/text_width 6 def +780 776 moveto 16 (DLCCR CXXF) vt +776 623 752 623 l +776 639 752 639 l +776 767 752 767 l +/text_height 12 def +/text_width 6 def +764 782 moveto 16 (12345 7890) vt +776 719 752 719 l +770 751 752 751 l +773 751 3 c +/text_height 12 def +/text_width 6 def +756 782 moveto 16 ( 1) vt +770 735 752 735 l +773 735 3 c +872 751 848 751 l +872 703 848 703 l +872 687 848 687 l +872 671 848 671 l +872 655 848 655 l +872 623 848 623 l +/text_height 12 def +/text_width 6 def +852 782 moveto 16 (21111111 1) vt +/text_height 12 def +/text_width 6 def +860 782 moveto 16 (09876543 1) vt +872 767 848 767 l +/text_height 12 def +/text_width 6 def +821 776 moveto 16 (TUETRRSO T) vt +/text_height 12 def +/text_width 6 def +797 776 moveto 16 (I TD A) vt +/text_height 12 def +/text_width 6 def +788 776 moveto 16 (SBDDX DIOB) vt +/text_height 12 def +/text_width 6 def +812 664 moveto 9 (M) ht +848 783 776 783 l +776 607 776 783 l +848 607 848 783 l +/text_height 12 def +/text_width 6 def +779 799 moveto 9 (MC145443) ht +/text_height 12 def +/text_width 6 def +790 812 moveto 9 (U2) ht +/text_height 12 def +/text_width 6 def +839 776 moveto 16 (AGLA12TE D) vt +/text_height 12 def +/text_width 6 def +830 776 moveto 16 (LAXXXXQD X) vt +904 559 744 559 l +880 623 872 623 l +880 623 880 503 l +936 503 880 503 l +1040 726 1024 726 l +1032 726 1032 735 l +1037 723 1027 723 l +1034 720 1030 720 l +1032 717 b +1096 726 1080 726 l +1088 726 1088 735 l +1093 723 1083 723 l +1090 720 1086 720 l +1088 717 b +1088 767 1032 767 l +1088 799 1088 767 l +/text_height 12 def +/text_width 6 def +1085 825 moveto 11 (+5) vt +1088 767 2 fc +/text_height 12 def +/text_width 6 def +1024 715 moveto 9 (U2) ht +/text_height 12 def +/text_width 6 def +1080 715 moveto 9 (U4) ht +1096 351 1096 335 l +1096 319 1032 319 l +1096 287 1032 287 l +1032 319 1032 287 l +1032 287 2 fc +1032 287 1032 175 l +/text_height 12 def +/text_width 6 def +1072 363 moveto 9 (RS) ht +/text_height 12 def +/text_width 6 def +1072 347 moveto 9 (CS) ht +/text_height 12 def +/text_width 6 def +1040 451 moveto 9 (\(DB25 female DCE\)) ht +1096 303 1064 303 l +1008 487 776 487 l +1072 270 1056 270 l +1064 270 1064 279 l +1069 267 1059 267 l +1066 264 1062 264 l +1064 261 b +1064 303 1064 279 l +1064 303 2 fc +1184 175 1032 175 l +1032 175 880 175 l +1032 175 2 fc +1096 399 1064 399 l +1064 399 1064 303 l +/text_height 12 def +/text_width 6 def +1112 467 moveto 9 (modem) ht +/text_height 12 def +/text_width 6 def +1074 415 moveto 9 (FG) ht +/text_height 12 def +/text_width 6 def +1074 398 moveto 9 (TD) ht +/text_height 12 def +/text_width 6 def +1074 383 moveto 9 (RD) ht +/text_height 12 def +/text_width 6 def +1073 334 moveto 9 (MR) ht +/text_height 12 def +/text_width 6 def +1073 318 moveto 9 (CG) ht +/text_height 12 def +/text_width 6 def +1073 302 moveto 9 (CD) ht +/text_height 12 def +/text_width 6 def +1069 254 moveto 9 (STD) ht +1114 367 1096 367 l +1117 367 3 c +1114 351 1096 351 l +1117 351 3 c +1114 335 1096 335 l +1117 335 3 c +1114 319 1096 319 l +1117 319 3 c +1114 303 1096 303 l +1117 303 3 c +1114 287 1096 287 l +1117 287 3 c +1114 239 1096 239 l +1117 239 3 c +1114 223 1096 223 l +1117 223 3 c +1114 271 1096 271 l +1117 271 3 c +1131 375 3 c +1152 375 1134 375 l +1131 359 3 c +1152 359 1134 359 l +1131 343 3 c +1152 343 1134 343 l +1131 327 3 c +1152 327 1134 327 l +1131 311 3 c +1152 311 1134 311 l +1131 295 3 c +1152 295 1134 295 l +1131 263 3 c +1152 263 1134 263 l +1131 247 3 c +1152 247 1134 247 l +1131 231 3 c +1152 231 1134 231 l +1131 215 3 c +1152 215 1134 215 l +/text_height 12 def +/text_width 6 def +1097 270 moveto 16 (1111) vt +/text_height 12 def +/text_width 6 def +1136 405 moveto 16 (111111222222) vt +/text_height 12 def +/text_width 6 def +1144 405 moveto 16 (456789012345) vt +/text_height 12 def +/text_width 6 def +1105 414 moveto 16 (1234567890123) vt +1131 391 3 c +1152 391 1134 391 l +1114 255 1096 255 l +1117 255 3 c +1114 207 1096 207 l +1117 207 3 c +1114 383 1096 383 l +1117 383 3 c +1114 399 1096 399 l +1117 399 3 c +1131 279 3 c +1152 279 1134 279 l +/text_height 12 def +/text_width 6 def +1118 420 moveto 9 (DB25) ht +/text_height 12 def +/text_width 6 def +1118 432 moveto 9 (J1) ht +/text_height 12 def +/text_width 6 def +1069 238 moveto 9 (SRD) ht +1184 295 1152 295 l +/text_height 12 def +/text_width 6 def +1160 315 moveto 9 (TR) ht +1184 295 1184 175 l +190 704 190 718 l +213 711 18 201 159 a +190 711 176 711 l +208 711 195 711 l +/text_height 12 def +/text_width 6 def +179 734 moveto 9 (C15) ht +/text_height 12 def +/text_width 6 def +173 704 moveto 9 (10N) ht +366 640 366 654 l +389 647 18 201 159 a +366 647 352 647 l +384 647 371 647 l +/text_height 12 def +/text_width 6 def +355 670 moveto 9 (C11) ht +/text_height 12 def +/text_width 6 def +349 640 moveto 9 (10N) ht +446 640 446 654 l +469 647 18 201 159 a +446 647 432 647 l +464 647 451 647 l +/text_height 12 def +/text_width 6 def +435 670 moveto 9 (C10) ht +/text_height 12 def +/text_width 6 def +429 640 moveto 9 (10N) ht +/text_height 12 def +/text_width 6 def +693 606 moveto 9 (C8) ht +/text_height 12 def +/text_width 6 def +693 593 moveto 9 (100N) ht +687 593 673 593 l +680 571 18 111 69 a +680 593 680 607 l +680 575 680 589 l +/text_height 12 def +/text_width 6 def +933 598 moveto 9 (C5) ht +/text_height 12 def +/text_width 6 def +933 585 moveto 9 (100N) ht +927 585 913 585 l +920 563 18 111 69 a +920 585 920 599 l +920 567 920 581 l +/text_height 12 def +/text_width 6 def +933 646 moveto 9 (C7) ht +/text_height 12 def +/text_width 6 def +933 633 moveto 9 (100N) ht +927 633 913 633 l +920 611 18 111 69 a +920 633 920 647 l +920 615 920 629 l +/text_height 12 def +/text_width 6 def +741 814 moveto 9 (C4) ht +/text_height 12 def +/text_width 6 def +741 801 moveto 9 (10N) ht +735 801 721 801 l +728 779 18 111 69 a +728 801 728 815 l +728 783 728 797 l +/text_height 12 def +/text_width 6 def +757 606 moveto 9 (C6) ht +/text_height 12 def +/text_width 6 def +757 593 moveto 9 (100N) ht +751 593 737 593 l +744 571 18 111 69 a +744 593 744 607 l +744 575 744 589 l +/text_height 12 def +/text_width 6 def +1045 766 moveto 9 (C13) ht +/text_height 12 def +/text_width 6 def +1045 753 moveto 9 (100N) ht +1039 753 1025 753 l +1032 731 18 111 69 a +1032 753 1032 767 l +1032 735 1032 749 l +/text_height 12 def +/text_width 6 def +1101 766 moveto 9 (C2) ht +/text_height 12 def +/text_width 6 def +1101 753 moveto 9 (100N) ht +1095 753 1081 753 l +1088 731 18 111 69 a +1088 753 1088 767 l +1088 735 1088 749 l +546 239 536 239 l +584 239 574 239 l +/text_height 12 def +/text_width 6 def +539 259 moveto 9 (330) ht +/text_height 12 def +/text_width 6 def +539 271 moveto 9 (R10) ht +550 244 548 239 l +554 235 550 244 l +558 244 554 235 l +562 235 558 244 l +566 244 562 235 l +570 235 566 244 l +572 239 570 235 l +574 239 572 239 l +548 239 547 239 l +845 109 b +845 108 b +846 108 b +851 108 b +845 107 b +846 107 b +847 107 b +851 107 b +845 106 b +846 106 b +847 106 b +848 106 b +851 106 b +845 105 b +846 105 b +847 105 b +848 105 b +849 105 b +851 105 b +845 104 b +846 104 b +847 104 b +848 104 b +849 104 b +850 104 b +851 104 b +845 103 b +846 103 b +847 103 b +848 103 b +849 103 b +850 103 b +851 103 b +845 102 b +846 102 b +847 102 b +848 102 b +849 102 b +850 102 b +851 102 b +845 101 b +846 101 b +847 101 b +848 101 b +849 101 b +851 101 b +845 100 b +846 100 b +847 100 b +848 100 b +851 100 b +845 99 b +846 99 b +847 99 b +851 99 b +845 98 b +846 98 b +851 98 b +845 97 b +852 103 b +846 103 832 103 l +864 103 853 103 l +/text_height 12 def +/text_width 6 def +832 131 moveto 9 (LED2) ht +859 116 b +857 115 b +858 115 b +857 114 b +858 114 b +856 113 b +855 112 b +855 111 b +856 111 b +857 111 b +858 111 b +859 111 b +860 111 b +860 110 b +859 109 b +858 108 b +857 107 b +/text_height 12 def +/text_width 6 def +833 97 moveto 9 (RED) ht +/text_height 12 def +/text_width 6 def +584 219 moveto 9 (1 pps) ht +/text_height 12 def +/text_width 6 def +832 83 moveto 9 (power) ht +328 703 304 703 l +264 679 264 727 l +264 711 240 711 l +264 695 240 695 l +/text_height 12 def +/text_width 6 def +267 719 moveto 9 (+) ht +/text_height 12 def +/text_width 6 def +267 703 moveto 9 (-) ht +/text_height 12 def +/text_width 6 def +250 726 moveto 9 (3) ht +/text_height 12 def +/text_width 6 def +250 710 moveto 9 (2) ht +/text_height 12 def +/text_width 6 def +312 718 moveto 9 (1) ht +/text_height 12 def +/text_width 6 def +264 744 moveto 9 (LM324) ht +/text_height 12 def +/text_width 6 def +264 757 moveto 9 (U4A) ht +304 703 264 727 l +304 703 264 679 l +472 695 448 695 l +408 671 408 719 l +/text_height 12 def +/text_width 6 def +411 711 moveto 9 (+) ht +/text_height 12 def +/text_width 6 def +411 695 moveto 9 (-) ht +/text_height 12 def +/text_width 6 def +408 736 moveto 9 (LM324) ht +/text_height 12 def +/text_width 6 def +408 749 moveto 9 (U4B) ht +408 703 384 703 l +408 687 384 687 l +/text_height 12 def +/text_width 6 def +394 718 moveto 9 (5) ht +/text_height 12 def +/text_width 6 def +394 702 moveto 9 (6) ht +/text_height 12 def +/text_width 6 def +456 710 moveto 9 (7) ht +448 695 408 719 l +448 695 408 671 l +336 431 272 431 l +272 351 272 431 l +336 351 272 351 l +336 351 336 431 l +272 399 248 399 l +266 383 248 383 l +269 383 3 c +360 399 336 399 l +288 431 288 455 l +320 431 320 455 l +304 345 304 327 l +304 348 3 c +/text_height 12 def +/text_width 6 def +275 407 moveto 16 (BA) vt +/text_height 12 def +/text_width 6 def +277 433 moveto 9 (R/C) ht +/text_height 12 def +/text_width 6 def +313 433 moveto 9 (CE) ht +/text_height 12 def +/text_width 6 def +297 366 moveto 9 (CL) ht +/text_height 12 def +/text_width 6 def +258 414 moveto 16 (21) vt +/text_height 12 def +/text_width 6 def +344 414 moveto 9 (13) ht +/text_height 12 def +/text_width 6 def +344 398 moveto 9 (4) ht +/text_height 12 def +/text_width 6 def +307 347 moveto 9 (3) ht +/text_height 12 def +/text_width 6 def +344 448 moveto 9 (74LS123) ht +/text_height 12 def +/text_width 6 def +344 461 moveto 9 (U3A) ht +/text_height 12 def +/text_width 6 def +292 457 moveto 11 (15) vt +/text_height 12 def +/text_width 6 def +324 457 moveto 11 (14) vt +/text_height 12 def +/text_width 6 def +327 407 moveto 16 (QQ) vt +/text_height 12 def +/text_width 6 def +326 403 moveto 9 (_) ht +339 383 3 c +360 383 342 383 l +512 271 448 271 l +448 191 448 271 l +512 191 448 191 l +512 191 512 271 l +464 271 464 295 l +496 271 496 295 l +/text_height 12 def +/text_width 6 def +451 247 moveto 16 (BA) vt +/text_height 12 def +/text_width 6 def +453 273 moveto 9 (R/C) ht +/text_height 12 def +/text_width 6 def +489 273 moveto 9 (CE) ht +/text_height 12 def +/text_width 6 def +473 206 moveto 9 (CL) ht +480 185 480 167 l +480 188 3 c +536 239 512 239 l +448 239 424 239 l +442 223 424 223 l +445 223 3 c +/text_height 12 def +/text_width 6 def +425 254 moveto 9 (10) ht +/text_height 12 def +/text_width 6 def +434 238 moveto 9 (9) ht +/text_height 12 def +/text_width 6 def +520 238 moveto 9 (12) ht +/text_height 12 def +/text_width 6 def +520 254 moveto 9 (5) ht +/text_height 12 def +/text_width 6 def +483 198 moveto 11 ( 11) vt +/text_height 12 def +/text_width 6 def +467 291 moveto 9 (7) ht +/text_height 12 def +/text_width 6 def +499 291 moveto 9 (6) ht +/text_height 12 def +/text_width 6 def +520 288 moveto 9 (74LS123) ht +/text_height 12 def +/text_width 6 def +520 301 moveto 9 (U3B) ht +/text_height 12 def +/text_width 6 def +503 247 moveto 16 (QQ) vt +/text_height 12 def +/text_width 6 def +502 243 moveto 9 (_) ht +515 223 3 c +536 223 518 223 l +136 724 b +136 723 b +137 723 b +138 722 b +138 720 b +136 719 b +137 719 b +134 718 b +135 718 b +132 717 b +133 717 b +134 716 b +135 716 b +136 715 b +137 715 b +138 714 b +138 712 b +136 711 b +137 711 b +134 710 b +135 710 b +132 709 b +133 709 b +134 708 b +135 708 b +136 707 b +137 707 b +138 706 b +138 704 b +136 703 b +137 703 b +134 702 b +135 702 b +132 701 b +133 701 b +134 700 b +135 700 b +136 699 b +139 722 b +140 721 b +141 721 b +139 720 b +139 714 b +140 713 b +141 713 b +139 712 b +139 706 b +140 705 b +141 705 b +139 704 b +136 724 136 735 l +136 687 136 698 l +176 711 152 711 l +147 715 b +146 714 b +147 714 b +145 713 b +146 713 b +147 713 b +144 712 b +145 712 b +146 712 b +147 712 b +143 711 b +144 711 b +145 711 b +146 711 b +147 711 b +148 711 b +149 711 b +144 710 b +145 710 b +146 710 b +147 710 b +145 709 b +146 709 b +147 709 b +146 708 b +147 708 b +147 707 b +150 711 b +151 711 b +152 711 b +153 711 b +/text_height 12 def +/text_width 6 def +148 708 moveto 9 (10K) ht +/text_height 12 def +/text_width 6 def +128 736 moveto 9 (1) ht +/text_height 12 def +/text_width 6 def +126 702 moveto 9 (3) ht +/text_height 12 def +/text_width 6 def +150 726 moveto 9 (2) ht +/text_height 12 def +/text_width 6 def +144 738 moveto 9 (R8) ht +608 751 608 762 l +640 775 616 775 l +616 767 616 783 l +608 788 608 799 l +614 768 b +613 767 b +612 766 b +611 765 b +610 764 b +609 763 b +608 762 b +616 770 b +615 769 b +608 788 b +609 787 b +610 786 b +613 786 b +611 785 b +612 785 b +613 785 b +611 784 b +612 784 b +613 784 b +610 783 b +611 783 b +612 783 b +613 783 b +614 783 b +613 782 b +614 782 b +615 781 b +616 780 b +613 775 16 c +/text_height 12 def +/text_width 6 def +632 795 moveto 9 (2N2907) ht +/text_height 12 def +/text_width 6 def +632 808 moveto 9 (Q1) ht +608 711 608 719 l +600 710 b +601 710 b +602 710 b +603 710 b +604 710 b +605 710 b +606 710 b +601 709 b +602 708 b +603 707 b +604 706 b +605 705 b +606 704 b +608 711 b +607 710 b +608 710 b +609 710 b +610 710 b +611 710 b +612 710 b +613 710 b +613 707 b +612 706 b +611 705 b +610 704 b +607 703 b +609 703 b +608 702 b +614 710 b +615 710 b +616 710 b +615 709 b +614 708 b +/text_height 12 def +/text_width 6 def +624 723 moveto 9 (car det) ht +664 775 664 735 l +664 775 640 775 l +1096 367 912 367 l +1008 487 1008 383 l +1096 383 1008 383 l +992 471 992 239 l +1096 239 992 239 l +976 383 912 383 l +976 383 976 223 l +1096 223 976 223 l +602 738 b +603 738 b +604 738 b +605 738 b +606 738 b +607 738 b +608 738 b +603 737 b +604 737 b +605 737 b +606 737 b +607 737 b +608 737 b +604 736 b +605 736 b +606 736 b +607 736 b +608 736 b +605 735 b +606 735 b +607 735 b +608 735 b +606 734 b +607 734 b +608 734 b +607 733 b +608 733 b +603 732 b +604 732 b +605 732 b +606 732 b +607 732 b +608 732 b +608 731 b +609 738 b +610 738 b +611 738 b +612 738 b +613 738 b +614 738 b +609 737 b +610 737 b +611 737 b +612 737 b +613 737 b +609 736 b +610 736 b +611 736 b +612 736 b +609 735 b +610 735 b +611 735 b +609 734 b +610 734 b +609 733 b +609 732 b +610 732 b +611 732 b +612 732 b +613 732 b +608 738 608 751 l +608 719 608 731 l +593 738 b +592 737 b +591 736 b +591 735 b +592 735 b +593 735 b +594 735 b +595 735 b +595 734 b +593 733 b +594 733 b +593 732 b +594 732 b +592 731 b +/text_height 12 def +/text_width 6 def +619 737 moveto 9 (GRN) ht +/text_height 12 def +/text_width 6 def +619 750 moveto 9 (LED1) ht +682 735 672 735 l +720 735 710 735 l +/text_height 12 def +/text_width 6 def +675 755 moveto 9 (3.3K) ht +/text_height 12 def +/text_width 6 def +675 767 moveto 9 (R14) ht +686 740 684 735 l +690 731 686 740 l +694 740 690 731 l +698 731 694 740 l +702 740 698 731 l +706 731 702 740 l +708 735 706 731 l +710 735 708 735 l +684 735 683 735 l +672 735 664 735 l +752 735 720 735 l +597 245 b +597 244 b +598 244 b +603 244 b +597 243 b +598 243 b +599 243 b +603 243 b +597 242 b +598 242 b +599 242 b +600 242 b +603 242 b +597 241 b +598 241 b +599 241 b +600 241 b +601 241 b +603 241 b +597 240 b +598 240 b +599 240 b +600 240 b +601 240 b +602 240 b +603 240 b +597 239 b +598 239 b +599 239 b +600 239 b +601 239 b +602 239 b +603 239 b +597 238 b +598 238 b +599 238 b +600 238 b +601 238 b +602 238 b +603 238 b +597 237 b +598 237 b +599 237 b +600 237 b +601 237 b +603 237 b +597 236 b +598 236 b +599 236 b +600 236 b +603 236 b +597 235 b +598 235 b +599 235 b +603 235 b +597 234 b +598 234 b +603 234 b +597 233 b +604 239 b +598 239 584 239 l +616 239 605 239 l +/text_height 12 def +/text_width 6 def +584 267 moveto 9 (LED3) ht +611 252 b +609 251 b +610 251 b +609 250 b +610 250 b +608 249 b +607 248 b +607 247 b +608 247 b +609 247 b +610 247 b +611 247 b +612 247 b +612 246 b +611 245 b +610 244 b +609 243 b +/text_height 12 def +/text_width 6 def +585 233 moveto 9 (AMBER) ht +648 230 632 230 l +640 230 640 239 l +645 227 635 227 l +642 224 638 224 l +640 221 b +640 239 616 239 l +402 767 392 767 l +440 767 430 767 l +/text_height 12 def +/text_width 6 def +395 787 moveto 9 (68K) ht +/text_height 12 def +/text_width 6 def +395 799 moveto 9 (R6) ht +406 772 404 767 l +410 763 406 772 l +414 772 410 763 l +418 763 414 772 l +422 772 418 763 l +426 763 422 772 l +428 767 426 763 l +430 767 428 767 l +404 767 403 767 l +408 620 408 631 l +/text_height 12 def +/text_width 6 def +418 621 moveto 9 (R5) ht +/text_height 12 def +/text_width 6 def +418 608 moveto 9 (680) ht +413 617 408 619 l +413 601 404 597 l +413 601 404 605 l +413 609 404 613 l +413 609 404 605 l +408 593 408 595 l +408 596 404 597 l +408 583 408 594 l +413 617 404 613 l +408 619 408 621 l +408 594 408 596 l +426 327 416 327 l +464 327 454 327 l +/text_height 12 def +/text_width 6 def +419 347 moveto 9 (33K) ht +/text_height 12 def +/text_width 6 def +419 359 moveto 9 (R9) ht +430 332 428 327 l +434 323 430 332 l +438 332 434 323 l +442 323 438 332 l +446 332 442 323 l +450 323 446 332 l +452 327 450 323 l +454 327 452 327 l +428 327 427 327 l +503 313 489 313 l +496 291 18 111 69 a +496 313 496 327 l +496 295 496 309 l +/text_height 12 def +/text_width 6 def +509 313 moveto 9 (22U) ht +/text_height 12 def +/text_width 6 def +510 326 moveto 9 (C17) ht +/text_height 12 def +/text_width 6 def +481 328 moveto 9 (+) ht + +showpage diff --git a/contrib/xntpd/gadget/gadget.s02 b/contrib/xntpd/gadget/gadget.s02 new file mode 100644 index 0000000000..6af4a6ec77 --- /dev/null +++ b/contrib/xntpd/gadget/gadget.s02 @@ -0,0 +1,288 @@ +%!PS-Adobe-23.0 EPSF-1.2 +%%Creator: SCHEMA +%%BoundingBox: 0 0 1343.0 1023.0 +/scl 511804.0 0.072 mul 65536.0 div def +scl scl scale + +% Landscape Orientation +/xoff 256.0 65536.0 mul 511804.0 div def +/yoff 1343.0 -256.0 65536.0 mul 511804.0 div sub def +xoff yoff translate +-90 rotate + +0 setgray + +/a { 1 setlinewidth newpath arcn stroke } def +/fa { 3 setlinewidth newpath arcn stroke } def +/c { 1 setlinewidth newpath 0 360 arc stroke } def +/fc { 1 setlinewidth newpath 0 360 arc fill } def +/l { 1 setlinewidth newpath moveto lineto stroke } def +/t { 3 setlinewidth newpath moveto lineto stroke } def +/ds { [4 4] 0 setdash 1 setlinewidth + newpath moveto lineto stroke [] 0 setdash } def +/dt { [2 2] 0 setdash 1 setlinewidth + newpath moveto lineto stroke [] 0 setdash } def + +8 7 8 1015 t +1328 7 912 7 t +1336 1015 8 1015 t +1336 7 1336 1015 t +912 7 8 7 t +1336 7 1328 7 t + +/reencsmalldict 12 dict def %% Schema font definitions +/ReEncodeSmall + { reencsmalldict begin + /newcodesandnames exch def + /newfontname exch def + /basefontname exch def + /basefontdict basefontname findfont def + /newfont basefontdict maxlength dict def + basefontdict + { exch dup /FID ne + { dup /Encoding eq + { exch dup length array copy newfont 3 1 roll put } + { exch newfont 3 1 roll put } + ifelse + } + { pop pop } + ifelse + } forall + newfont /FontName newfontname put + newcodesandnames aload pop + newcodesandnames length 2 idiv + { newfont /Encoding get 3 1 roll put } + repeat + newfontname newfont definefont pop + end + } def +/schfontvec [ 8#200 /Ccedilla 8#201 /udieresis 8#202 /eacute 8#203 /acircumflex +8#204 /adieresis 8#205 /agrave 8#207 /ccedilla 8#210 /ecircumflex +8#211 /edieresis 8#212 /egrave 8#213 /idieresis 8#214 /icircumflex +8#215 /igrave 8#216 /Adieresis 8#220 /Eacute 8#223 /ocircumflex +8#224 /odieresis 8#225 /ograve 8#226 /ucircumflex 8#227 /ugrave +8#230 /ydieresis 8#231 /Odieresis 8#232 /Udieresis 8#240 /aacute 8#241 /iacute +8#242 /oacute 8#243 /uacute 8#244 /ntilde 8#245 /Ntilde ] def +/schsymbvec [ 8#341 /beta 8#346 /mu 8#352 /Omega ] def +/Courier-Bold /Schfont schfontvec ReEncodeSmall +/Symbol /Schsymb schsymbvec ReEncodeSmall + + +/htdict 4 dict def %% HTEXT - variable spacing horizontal text routine +/ht + { htdict begin + /textstring exch def + /xskip exch def + 0 text_height neg rmoveto + /Schfont findfont text_height scalefont setfont + textstring + { + /charcode exch def + /thechar ( ) dup 0 charcode put def + gsave + charcode 8#245 gt + { /Schsymb findfont text_height scalefont setfont + thechar show + /Schfont findfont text_height scalefont setfont } + { thechar show } + ifelse + grestore + currentpoint moveto + xskip 0 rmoveto + } forall + end + } def + +/text_height 12 def +/text_width 6 def +1304 27 moveto 9 (2) ht +/text_height 12 def +/text_width 6 def +1272 27 moveto 9 (OF) ht +/text_height 12 def +/text_width 6 def +1192 27 moveto 9 (SHEET) ht +1176 31 1176 7 l +1336 55 992 55 l +1336 31 992 31 l +992 7 992 87 t +1336 87 992 87 t +/text_height 20 def +/text_width 9 def +1032 87 moveto 13 (1-PPS/RS232 Converter) ht +/text_height 12 def +/text_width 6 def +1040 27 moveto 9 (26 June 1992) ht +1176 55 1176 31 l +/text_height 12 def +/text_width 6 def +1032 51 moveto 9 (100-0001-001) ht +/text_height 12 def +/text_width 6 def +1216 51 moveto 9 (REV) ht +/text_height 12 def +/text_width 6 def +1264 51 moveto 9 (1A) ht +640 303 240 303 l +240 463 240 303 l +640 463 240 463 l +640 463 640 303 l +240 783 240 543 l +640 543 240 543 l +640 783 640 543 l +640 783 240 783 l +1040 463 800 463 l +800 463 800 303 l +1040 463 1040 303 l +1040 303 800 303 l +632 327 248 327 l +632 335 632 327 l +248 335 248 327 l +632 335 248 335 l +656 367 640 367 l +656 367 656 351 l +656 351 640 351 l +640 367 624 367 l +624 367 624 351 l +640 351 624 351 l +248 335 240 335 l +224 367 224 335 l +240 335 224 335 l +624 359 616 359 l +616 359 616 335 l +288 367 288 335 l +288 367 224 367 l +624 327 624 303 l +592 327 592 303 l +844 419 20 c +996 419 20 c +1032 335 808 335 ds +1032 327 1032 335 ds +808 327 808 335 ds +1032 327 808 327 ds +816 303 816 327 ds +848 303 848 327 ds +1024 303 1024 327 ds +992 303 992 327 ds +632 775 248 775 l +632 775 632 551 l +632 551 248 551 l +248 775 248 551 l +288 751 248 751 l +288 575 248 575 l +288 751 288 575 l +600 751 16 c +/text_height 20 def +/text_width 9 def +344 223 moveto 13 (Assembly Drawing) ht +/text_height 12 def +/text_width 6 def +896 283 moveto 9 (End View) ht +/text_height 12 def +/text_width 6 def +280 163 moveto 9 (Material: 2" x 3" x 5" aluminum minibox) ht +600 575 16 c +842 357 10 c +1002 357 10 c +920 418 20 c +921 358 10 c +/text_height 12 def +/text_width 6 def +976 395 moveto 9 (POWER) ht +/text_height 12 def +/text_width 6 def +824 395 moveto 9 (AUDIO) ht +/text_height 12 def +/text_width 6 def +912 395 moveto 9 (PPS) ht +384 735 224 735 ds +384 591 224 591 ds +600 751 520 751 ds +600 575 520 575 ds +272 399 200 399 l +272 439 200 439 l +272 439 272 399 l +200 439 200 399 l +280 423 272 423 l +272 759 200 759 l +288 599 224 599 l +272 607 272 567 l +288 727 224 727 l +272 719 200 719 l +272 759 272 719 l +200 759 200 719 l +656 575 624 575 l +656 591 656 575 l +656 591 624 591 l +624 591 624 575 l +656 751 624 751 l +656 751 656 735 l +656 735 624 735 l +624 751 624 735 l +656 655 624 655 l +656 671 656 655 l +624 671 624 655 l +656 671 624 671 l +280 423 280 415 l +280 415 272 415 l +280 591 272 591 l +280 591 280 583 l +280 583 272 583 l +272 663 272 655 l +272 743 272 735 l +280 735 272 735 l +280 743 280 735 l +280 743 272 743 l +273 683 201 683 l +201 682 201 642 l +272 683 272 643 l +273 643 201 643 l +281 667 273 667 l +280 658 272 658 l +280 666 280 658 l +232 607 232 567 l +272 607 232 607 l +272 567 232 567 l +232 439 232 399 l +/text_height 12 def +/text_width 6 def +672 587 moveto 9 (LED1 \(green\)) ht +/text_height 12 def +/text_width 6 def +136 355 moveto 9 (J1 \(DB25\)) ht +/text_height 12 def +/text_width 6 def +120 747 moveto 9 (J2 \(BNC\)) ht +/text_height 12 def +/text_width 6 def +120 675 moveto 9 (J3 \(BNC\)) ht +/text_height 12 def +/text_width 6 def +128 611 moveto 9 (J4 \(power\)) ht +224 727 224 599 l +/text_height 12 def +/text_width 6 def +352 283 moveto 9 (Side View \(cover removed\)) ht +/text_height 12 def +/text_width 6 def +344 523 moveto 9 (Top View \(cover removed\)) ht +384 591 384 735 ds +528 575 528 751 ds +608 599 608 727 ds +/text_height 12 def +/text_width 6 def +416 619 moveto 9 (#4 x 1/4" spacers \(2\)) ht +/text_height 12 def +/text_width 6 def +400 699 moveto 9 (#4 screws \(4\)) ht +/text_height 12 def +/text_width 6 def +1248 27 moveto 9 (2) ht +/text_height 12 def +/text_width 6 def +672 667 moveto 9 (LED2 \(red\)) ht +/text_height 12 def +/text_width 6 def +672 747 moveto 9 (LED3 \(amber\)) ht + +showpage diff --git a/contrib/xntpd/gadget/gen0102.lpr b/contrib/xntpd/gadget/gen0102.lpr new file mode 100644 index 0000000000..cc4fd8e5a3 --- /dev/null +++ b/contrib/xntpd/gadget/gen0102.lpr @@ -0,0 +1,1973 @@ +%!PS-Adobe-2.0 +%%Title: PADS Postscript Driver Header +%%Creator: Andy Montalvo, 18 Lupine St., Lowell, MA 01851 +%%CreationDate: 06/08/90 +%%For: CAD Software, Littleton, MA +%%EndComments +%%BeginProcSet: Markers 1.0 0 +% marker attributes +/MAttr_Width 1 def +/MAttr_Size 0 def +/MAttr_Type /M1 def +% procedures +/M1 { %def +% draw marker 1: plus +% Stack: - M1 - + -2 0 rmoveto + 4 0 rlineto + -2 2 rmoveto + 0 -4 rlineto +} bind def +/M2 { %def +% draw marker 2: cross +% Stack: - M2 - + -2 -2 rmoveto + 4 4 rlineto + -4 0 rmoveto + 4 -4 rlineto +} bind def +/M3 { %def +% draw marker 3: square +% Stack: - M3 - + 0 2 rlineto + 2 0 rlineto + 0 -4 rlineto + -4 0 rlineto + 0 4 rlineto + 2 0 rlineto +} bind def +/M4 { %def +% draw marker 4: diamond +% Stack: - M4 - + 0 2 rlineto + 2 -2 rlineto + -2 -2 rlineto + -2 2 rlineto + 2 2 rlineto +} bind def +/M5 { %def +% draw marker 5: hourglass +% Stack: - M5 - + 2 2 rlineto + -4 0 rlineto + 4 -4 rlineto + -4 0 rlineto + 2 2 rlineto +} bind def +/M6 { %def +% draw marker 6: bowtie +% Stack: - M6 - + 2 2 rlineto + 0 -4 rlineto + -4 4 rlineto + 0 -4 rlineto + 2 2 rlineto +} bind def +/M7 { %def +% draw marker 7: small plus (goes with char marker) +% Stack: - M7 - + -1 0 rmoveto + 2 0 rlineto + -1 1 rmoveto + 0 -2 rlineto +} bind def +/Marker { %def +% Command from driver: draw marker +% STACK: x y Marker - + MAttr_Size 0 gt + { + gsave + moveto + MAttr_Size 4 div dup scale + MAttr_Type load exec + 4 MAttr_Size div dup scale + MAttr_Width setlinewidth + stroke + grestore + } if +} def +%%EndProcSet: Markers 1.0 0 +%%BeginProcSet: Lib 1.0 0 +/sg { %def +% Command from driver: set the gray scale 0 - 100 +% STACK: greylevel sg + 100 div dup setgray /glev exch def +} bind def +/Circle { %def +% draw a circle +% STACK: x y radius Circle - + 0 360 arc +} bind def +/RndAper { %def +% select a round aperture +% STACK: - RndAper - + 1 setlinejoin + 1 setlinecap +} bind def +/SqrAper { %def +% select a square aperture +% STACK: - SqrAper - + 0 setlinejoin + 2 setlinecap +} bind def +/Line { %def +% draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] Line - + 3 1 roll + moveto + true + exch + % This pushes the x then the y then does lineto + { exch { false } { lineto true } ifelse } forall + pop +} bind def +/Clipto { %def +% set clipping rectangle from 0,0 to new values +% STACK: x y Clipto - + 0 0 moveto + dup 0 exch lineto + 2 copy lineto + pop + 0 lineto + closepath + clip + newpath +} bind def +/Clip4 { %def +% set clipping rectangle from xmin,ymin to xmax,ymax +% STACK: xmin ymin xmax ymax Clip4 - + 4 copy pop pop moveto + 4 copy pop exch lineto pop + 2 copy lineto + exch pop exch pop lineto + closepath + clip + newpath +} bind def +%%EndProcSet: Lib 1.0 0 +%%BeginProcSet: Lines 1.0 0 +% line attributes % +/LAttr_Width 1 def +% line procedures +/PLine { %def +% Cammand from driver: draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + LAttr_Width setlinewidth + stroke +} bind def % PLine +/Char { %def +% Command from driver: draw a character at the current position +% STACK: type x y stroke_array Char - +% stroke array -- [ stroke1 stroke2 ... stroken ] +% stroke -- connected staight lines +% type = 0 if text 1 if marker + gsave + 4 1 roll + translate + 0 eq { TAttr_Width } { MAttr_Width } ifelse setlinewidth + { + dup length 2 gt + { + dup dup 0 get exch 1 get % get starting point + 3 -1 roll % put x y before array + dup length 2 sub 2 exch getinterval % delete first items from array + Line + stroke + } + { + aload pop currentlinewidth 2 div Circle fill + } ifelse + } forall + grestore +} bind def % Char +/PArc { %def +% Command from driver: draw an arc +% STACK: x y radius startangle deltaangle Arc - + 10 div exch 10 div exch + 2 copy pop add + arc + LAttr_Width setlinewidth + stroke +} bind def +/PCircle { %def +% Command from driver: draw an circle +% STACK: x y radius PCircle - + Circle + LAttr_Width setlinewidth + stroke +} bind def +%%EndProcSet: Lines 1.0 0 +%%BeginProcSet: Polygon 1.0 0 +% polygon attributes % +/PAttr_ExtWidth 1 def +/PAttr_IntWidth 1 def +/PAttr_Grid 1 def +% polygon procedures +/LoopSet { %def +% set up for loop condition +% STACK: start end LoopSet low gridwidth high + 2 copy lt { exch } if + % make grid line up to absolute coordinates + PAttr_Grid div truncate PAttr_Grid mul exch + PAttr_Grid exch +} bind def +/Hatch { %def +% draw cross hatch pattern in current path +% STACK: - Hatch - + pathbbox + /ury exch def + /urx exch def + /lly exch def + /llx exch def + clip + newpath + llx urx LoopSet + { % x loop + dup lly exch ury moveto lineto + } for + lly ury LoopSet + { % y loop + llx exch dup urx exch moveto lineto + } for + PAttr_IntWidth setlinewidth + stroke +} bind def +/PPoly { %def +% Command from driver: draw a plygon +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + closepath + gsave + PAttr_IntWidth PAttr_Grid ge {fill} {Hatch} ifelse + grestore + PAttr_ExtWidth setlinewidth + stroke +} bind def +%%EndProcSet: Polygon 1.0 0 +%%BeginProcSet: Text 1.0 0 +% text attributes % +/TAttr_Mirr 0 def +/TAttr_Orient 0 def +/TAttr_Width 1 def +% text procedures +/Text { %def +% Command from driver: Draw text +% STACK: x y width string Text - + gsave + 4 2 roll + translate + TAttr_Mirr 0 gt + { + -1 1 scale + } if + TAttr_Orient rotate + 0 0 moveto + dup length dup 1 gt + { + exch dup stringwidth pop + 4 -1 roll + exch 2 copy + lt + { + div 1 scale show + } + { + sub + 3 -1 roll 1 sub div + 0 3 -1 roll ashow + } + ifelse + } + { + pop + show + } ifelse + grestore +} bind def +%%EndProcSet: Text 1.0 0 +%%BeginProcSet: FlashSymbols 1.0 0 +% flash symbol attributes % +/FAttr_Type /PRndPad def +/FAttr_Width 0 def +/FAttr_Length 1 def +/FAttr_Orient 0 def +% flash symbol procedures +/PRndPad { %def +% Command from driver: draw an circular pad +% STACK: - PCirclePad - + FAttr_Width dup scale + 0 0 .5 Circle + fill +} bind def +/PSqrPad { %def +% Draw an Square pad +% STACK: - PRectPad - + FAttr_Width dup scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/PRectPad { %def +% Draw an rectangular pad +% STACK: - PRectPad - + FAttr_Length FAttr_Width scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/POvalPad { %def +% Draw an oval pad +% STACK: - POvalPad - + FAttr_Width setlinewidth + FAttr_Length FAttr_Width sub 2 div dup + neg 0 moveto + 0 lineto + RndAper + stroke +} bind def +/Anl { %def + 0 0 .5 Circle + fill + FAttr_Length FAttr_Width lt + { % inner circle + 0 0 + FAttr_Length 0 gt { FAttr_Length FAttr_Width div } { .5 } ifelse + 2 div Circle + 1 setgray + fill + glev setgray + } if +} bind def +/PAnlPad { %def +% Draw an annular pad +% STACK: - PAnlPad - + FAttr_Width dup scale + Anl +} bind def +/PRelPad { %def +% Draw an thermal relief pad +% STACK: - PRelPad - + PAnlPad + 1 setgray + .17 setlinewidth + 0 setlinecap % the x + 45 rotate + .5 0 moveto -.5 0 lineto + 0 .5 moveto 0 -.5 lineto + stroke + glev setgray +} bind def +/Flash { %def +% Command from driver: Flash a symbol +% STACK: x y Flash - + FAttr_Width 0 gt + { + gsave + translate + FAttr_Orient rotate + FAttr_Type load exec + grestore + } if +} def +%%EndProcSet: FlashSymbols 1.0 0 +%%BeginProcSet: SetAttr 1.0 0 +/SetLine { %def +% Set the width of the lines +% STACK: linewidth SetLine - + /LAttr_Width exch def + RndAper +} bind def +/SetPoly { %def +% Set attribute of polygon +% STACK: external_width internal_grid_width grid_spacing SetPoly - + /PAttr_Grid exch def + /PAttr_IntWidth exch def + /PAttr_ExtWidth exch def + RndAper +} bind def +/SetFlash { %def +% Set Attributed of flash pad +% STACK: orientation_angle length width aperture_type SetFlash - + /FAttr_Type exch def + FAttr_Type /PSqrPad eq FAttr_Type /PRectPad eq or + { SqrAper } { RndAper } ifelse + /FAttr_Width exch def + /FAttr_Length exch def + /FAttr_Orient exch 10 div def +} bind def +/SetMkr { %def +% Set attributes of markers +% STACK: linewidth size type SetMkr - + /MAttr_Type exch def + /MAttr_Size exch def + /MAttr_Width exch def + RndAper +} bind def +/SetText1 { %def +% Set attributes of text +% STACK: fontname height orient mirror SetMkr - + /TAttr_Mirr exch def + /TAttr_Orient exch 10 div def + exch findfont exch scalefont setfont + RndAper +} bind def +/SetText2 { %def +% Set attributes of text +% STACK: linewidth height mirror orient SetMkr - + /TAttr_Width exch def + RndAper +} bind def +%%EndProcSet: SetAttr 1.0 0 +%%BeginProcSet: Initialize 1.0 0 +/Init { %def +% Initialize the driver +% STACK: Init - + 72 1000 div dup scale % Scale to 1/1000 inch + 250 250 translate % make origin 1/4 inch from bottom left + 1.5 setmiterlimit 1 RndAper % set line defaults + 0 setgray % set color default + /glev 0 def +} def +%%EndProcSet: Initialize 1.0 0 +%%EndProlog +/Helvetica findfont 12 scalefont setfont +35 760 moveto +(gadget.job - Fri Aug 21 03:34:44 1992) show +gsave +Init +8000 10500 Clipto +4015 2626 translate +0 rotate +1 1 div dup scale +75 sg +50 sg +12 SetLine +-100 900 [ -100 800 ] PLine +-100 800 [ 100 800 ] PLine +100 900 [ 100 800 ] PLine +100 800 [ 900 800 ] PLine +300 1100 [ 600 1100 ] PLine +-1100 1150 [ -700 1150 ] PLine +-700 1150 [ -700 1600 ] PLine +175 3300 [ -100 3300 ] PLine +700 3000 [ 300 3000 ] PLine +300 3000 [ 300 3100 ] PLine +300 2500 [ 300 2650 ] PLine +300 2650 [ 800 2650 ] PLine +800 2800 [ 800 2650 ] PLine +800 2650 [ 1000 2650 ] PLine +400 2500 [ 400 2600 ] PLine +400 2600 [ 1100 2600 ] PLine +1100 2600 [ 1100 2800 ] PLine +-900 2300 [ -700 2100 ] PLine +-700 2100 [ -450 2100 ] PLine +500 2500 [ 550 2550 ] PLine +550 2550 [ 750 2550 ] PLine +750 2550 [ 800 2500 ] PLine +-650 2600 [ -100 2600 ] PLine +-100 2250 [ 450 2250 ] PLine +450 2250 [ 500 2200 ] PLine +-1200 2300 [ -1050 2300 ] PLine +-1050 2300 [ -1050 2100 ] PLine +-1050 2100 [ -800 2100 ] PLine +-900 2500 [ -700 2300 ] PLine +-700 2300 [ -700 2200 ] PLine +-700 2200 [ -300 2200 ] PLine +-300 2200 [ -300 2100 ] PLine +1250 1900 [ 1250 1800 ] PLine +1250 1800 [ 800 1800 ] PLine +300 1900 [ 300 1800 ] PLine +300 1800 [ 800 1800 ] PLine +700 1900 [ 450 1900 ] PLine +300 1700 [ 600 1700 ] PLine +500 1600 [ -100 1600 ] PLine +-100 1600 [ -100 1700 ] PLine +1000 3900 [ 1050 3950 ] PLine +1050 3950 [ 1050 4050 ] PLine +1050 4050 [ 50 4050 ] PLine +50 4050 [ 0 4000 ] PLine +0 4100 [ 900 4100 ] PLine +800 3000 [ 1100 3000 ] PLine +0 3700 [ 0 3850 ] PLine +0 3850 [ 450 3850 ] PLine +450 3850 [ 500 3900 ] PLine +-400 3400 [ -400 3600 ] PLine +-400 3600 [ 300 3600 ] PLine +300 3600 [ 300 3700 ] PLine +300 3700 [ 600 3700 ] PLine +450 2700 [ -400 2700 ] PLine +-400 2300 [ -300 2300 ] PLine +-700 4200 [ -650 4250 ] PLine +-650 4250 [ 550 4250 ] PLine +550 4250 [ 600 4200 ] PLine +350 3800 [ 1100 3800 ] PLine +1100 3800 [ 1100 3900 ] PLine +-800 3100 [ -800 2800 ] PLine +-800 2800 [ -400 2800 ] PLine +-850 3700 [ -400 3700 ] PLine +400 1300 [ 600 1300 ] PLine +-1100 4200 [ -1050 4150 ] PLine +-1050 4150 [ 650 4150 ] PLine +650 4150 [ 700 4200 ] PLine +-300 3400 [ -250 3350 ] PLine +-250 3350 [ 1200 3350 ] PLine +1200 3350 [ 1200 4200 ] PLine +1200 4200 [ 1100 4200 ] PLine +-700 3100 [ -700 2875 ] PLine +-700 2875 [ -200 2875 ] PLine +-200 2875 [ -200 2800 ] PLine +-600 3100 [ -600 2950 ] PLine +-600 2950 [ 600 2950 ] PLine +600 2950 [ 600 2800 ] PLine +-750 550 [ -750 1050 ] PLine +-750 1050 [ -1050 1050 ] PLine +950 3200 [ 700 3200 ] PLine +850 1200 [ -600 1200 ] PLine +-550 3900 [ -350 3900 ] PLine +540 4479 [ 540 4300 ] PLine +540 4300 [ -800 4300 ] PLine +432 4479 [ 432 4350 ] PLine +432 4350 [ -750 4350 ] PLine +400 3400 [ 700 3400 ] PLine +50 SetLine +-1000 3400 [ -1000 3250 ] PLine +-1000 3250 [ -200 3250 ] PLine +-200 3250 [ -200 3100 ] PLine +-200 3100 [ -100 3100 ] PLine +0 2500 [ 0 2350 ] PLine +0 2350 [ 200 2350 ] PLine +200 2350 [ 200 2500 ] PLine +0 2350 [ -200 2350 ] PLine +-1000 3400 [ -1200 3400 ] PLine +200 2350 [ 1100 2350 ] PLine +1100 2350 [ 1100 2450 ] PLine +1100 2450 [ 1200 2450 ] PLine +-600 1600 [ -600 1750 ] PLine +-600 1750 [ -200 1750 ] PLine +-1200 3700 [ -1000 3700 ] PLine +-1000 3700 [ -1000 3400 ] PLine +1100 3200 [ 1250 3200 ] PLine +1250 3200 [ 1250 2450 ] PLine +1250 2450 [ 1200 2450 ] PLine +900 4200 [ 900 4300 ] PLine +900 4300 [ 1250 4300 ] PLine +1250 4300 [ 1250 3200 ] PLine +-700 4000 [ -1000 4000 ] PLine +-1000 4000 [ -1000 3700 ] PLine +900 4200 [ 800 4200 ] PLine +200 1400 [ 1100 1400 ] PLine +1100 1400 [ 1100 800 ] PLine +-50 450 [ -50 150 ] PLine +950 150 [ 1100 450 ] PLine +1100 450 [ 1000 800 ] PLine +-250 450 [ -250 1000 ] PLine +-250 1000 [ 200 1000 ] PLine +200 1000 [ 200 1100 ] PLine +0 450 [ -750 450 ] PLine +-750 450 [ -1100 450 ] PLine +0 4475 [ 0 4400 ] PLine +0 4400 [ -648 4400 ] PLine +-648 4400 [ -648 4479 ] PLine +75 4000 [ 300 4000 ] PLine +300 4000 [ 300 3900 ] PLine +1100 450 [ 750 450 ] PLine +750 450 [ 0 450 ] PLine +900 2200 [ 900 2000 ] PLine +900 2000 [ 75 2000 ] PLine +75 2000 [ 75 2200 ] PLine +75 2200 [ 200 2200 ] PLine +300 4000 [ 1000 4000 ] PLine +-1100 450 [ -1050 150 ] PLine +-600 1900 [ -600 2000 ] PLine +-600 2000 [ 75 2000 ] PLine +75 2100 [ 0 2100 ] PLine +12 SetLine +700 3700 [ 750 3650 ] PLine +750 3650 [ 750 800 ] PLine +750 800 [ 900 800 ] PLine +0 550 [ 300 550 ] PLine +300 550 [ 300 1100 ] PLine +300 2200 [ 250 2150 ] PLine +250 2150 [ 250 1600 ] PLine +250 1600 [ 300 1550 ] PLine +300 1550 [ 300 1100 ] PLine +-700 2500 [ -550 2500 ] PLine +-550 2500 [ -550 1700 ] PLine +-550 1700 [ -700 1700 ] PLine +-700 1700 [ -700 1600 ] PLine +300 3500 [ 175 3500 ] PLine +175 3500 [ 175 3100 ] PLine +175 3100 [ 300 3100 ] PLine +300 4200 [ 250 4150 ] PLine +250 4150 [ 250 3800 ] PLine +250 3800 [ 300 3750 ] PLine +300 3750 [ 300 3500 ] PLine +-300 2500 [ -250 2550 ] PLine +-250 2550 [ -250 3300 ] PLine +-250 3300 [ -100 3300 ] PLine +300 4200 [ 400 4200 ] PLine +-900 1600 [ -800 1600 ] PLine +-800 1600 [ -800 1500 ] PLine +-800 1500 [ -500 1500 ] PLine +-500 1500 [ -500 1600 ] PLine +1000 2650 [ 1000 2250 ] PLine +1000 2250 [ 1200 2250 ] PLine +400 1500 [ 400 2200 ] PLine +400 2200 [ 400 2300 ] PLine +400 2300 [ 700 2300 ] PLine +700 2300 [ 700 2500 ] PLine +-450 2100 [ -450 1650 ] PLine +-450 1650 [ -400 1600 ] PLine +-500 3400 [ -500 3150 ] PLine +-500 3150 [ -650 3150 ] PLine +-650 3150 [ -650 2600 ] PLine +-100 2600 [ -100 2250 ] PLine +-1200 2500 [ -1200 2300 ] PLine +-300 2100 [ -250 2050 ] PLine +-250 2050 [ -250 1650 ] PLine +-250 1650 [ -300 1600 ] PLine +800 1800 [ 800 2200 ] PLine +600 900 [ 600 550 ] PLine +600 550 [ 750 550 ] PLine +700 2200 [ 700 1900 ] PLine +600 1700 [ 600 2200 ] PLine +1050 150 [ 1050 250 ] PLine +1050 250 [ 500 250 ] PLine +500 250 [ 500 1600 ] PLine +0 4200 [ 0 4100 ] PLine +900 4100 [ 900 3900 ] PLine +800 3900 [ 800 3000 ] PLine +600 3700 [ 600 3900 ] PLine +600 4200 [ 600 4075 ] PLine +600 4075 [ 450 4075 ] PLine +450 4075 [ 450 2700 ] PLine +-400 2700 [ -400 2300 ] PLine +300 3300 [ 350 3350 ] PLine +350 3350 [ 350 3800 ] PLine +-1200 2800 [ -1000 2800 ] PLine +-1000 2800 [ -1000 3100 ] PLine +-900 3100 [ -850 3150 ] PLine +-850 3150 [ -850 3700 ] PLine +50 150 [ 400 150 ] PLine +400 150 [ 400 1300 ] PLine +-500 3100 [ -500 3000 ] PLine +-500 3000 [ -350 3000 ] PLine +-350 3000 [ -350 1300 ] PLine +-350 1300 [ -100 1300 ] PLine +200 3700 [ 150 3750 ] PLine +150 3750 [ 150 4425 ] PLine +150 4425 [ 108 4479 ] PLine +108 4479 [ 54 4593 ] PLine +-108 4479 [ 50 4600 ] PLine +50 4600 [ 54 4593 ] PLine +-324 4479 [ -216 4479 ] PLine +-1100 1700 [ -1100 1450 ] PLine +-1050 1050 [ -1050 1800 ] PLine +-1050 1800 [ -1200 1800 ] PLine +950 3524 [ 950 3200 ] PLine +950 3700 [ 850 3700 ] PLine +850 3700 [ 850 1200 ] PLine +-600 1200 [ -600 150 ] PLine +-600 150 [ -950 150 ] PLine +-540 4479 [ -550 4479 ] PLine +-550 4479 [ -550 3900 ] PLine +-350 3900 [ -350 3150 ] PLine +-350 3150 [ -300 3100 ] PLine +-432 4479 [ -450 4479 ] PLine +-450 4479 [ -450 3150 ] PLine +-450 3150 [ -382 3100 ] PLine +-382 3100 [ -400 3100 ] PLine +-800 4300 [ -800 3400 ] PLine +-750 4350 [ -750 3450 ] PLine +-750 3450 [ -700 3400 ] PLine +400 3900 [ 400 3400 ] PLine +1100 3400 [ 1100 3600 ] PLine +1100 3600 [ 1026 3600 ] PLine +1026 3600 [ 1026 3612 ] PLine +50 SetLine +-100 3100 [ 0 3100 ] PLine +0 3100 [ 0 2500 ] PLine +-200 2350 [ -200 1900 ] PLine +-200 1900 [ -100 1900 ] PLine +-200 1900 [ -200 1500 ] PLine +-200 1500 [ 0 1500 ] PLine +0 1500 [ 200 1500 ] PLine +200 1500 [ 200 1300 ] PLine +800 4200 [ 800 4050 ] PLine +800 4050 [ 700 4050 ] PLine +700 4050 [ 700 3900 ] PLine +-750 450 [ -900 450 ] PLine +-900 450 [ -900 1300 ] PLine +-1200 1600 [ -1275 1600 ] PLine +-1275 1600 [ -1275 900 ] PLine +-900 900 [ -1275 900 ] PLine +-600 1900 [ -600 1750 ] PLine +-600 1750 [ -975 1750 ] PLine +-975 1750 [ -975 1300 ] PLine +-975 1300 [ -900 1300 ] PLine +-1200 2100 [ -1275 2100 ] PLine +-1275 2100 [ -1275 1600 ] PLine +-1200 3000 [ -1275 3000 ] PLine +-1275 3000 [ -1275 2100 ] PLine +-900 3400 [ -900 3525 ] PLine +-900 3525 [ -1275 3525 ] PLine +-1100 4000 [ -1275 4000 ] PLine +-1275 4000 [ -1275 3000 ] PLine +75 3500 [ 75 2100 ] PLine +75 2100 [ 0 2100 ] PLine +75 2200 [ 200 2200 ] PLine +0 4479 [ 0 4400 ] PLine +0 4400 [ 75 4400 ] PLine +75 4400 [ 75 3500 ] PLine +-300 3700 [ -300 3500 ] PLine +-300 3500 [ 75 3500 ] PLine +900 2500 [ 900 2200 ] PLine +1000 4000 [ 1000 4200 ] PLine +25 sg +0 sg +10 SetLine +-1350 0 [ -1350 4900 ] PLine +-1350 4900 [ 1350 4900 ] PLine +1350 4900 [ 1350 0 ] PLine +1350 0 [ -1350 0 ] PLine +10 SetLine +-1350 4700 [ -1350 4900 ] PLine +-1350 4900 [ -1150 4900 ] PLine +10 SetLine +1150 4900 [ 1350 4900 ] PLine +1350 4900 [ 1350 4700 ] PLine +10 SetLine +1150 0 [ 1350 0 ] PLine +1350 0 [ 1350 200 ] PLine +10 SetLine +-1350 200 [ -1350 0 ] PLine +-1350 0 [ -1150 0 ] PLine +10 SetLine +-1050 1400 [ -1050 1200 ] PLine +-1050 1200 [ -1150 1200 ] PLine +-1150 1200 [ -1150 1400 ] PLine +-1150 1400 [ -1050 1400 ] PLine +10 SetLine +-50 3300 [ -100 3300 ] PLine +10 SetLine +250 3235 [ -50 3235 ] PLine +-50 3235 [ -50 3365 ] PLine +-50 3365 [ 250 3365 ] PLine +250 3365 [ 250 3235 ] PLine +10 SetLine +300 3300 [ 250 3300 ] PLine +10 SetLine +250 3100 [ 300 3100 ] PLine +10 SetLine +-50 3165 [ 250 3165 ] PLine +250 3165 [ 250 3035 ] PLine +250 3035 [ -50 3035 ] PLine +-50 3035 [ -50 3165 ] PLine +10 SetLine +-100 3100 [ -50 3100 ] PLine +10 SetLine +-50 3500 [ -100 3500 ] PLine +10 SetLine +250 3435 [ -50 3435 ] PLine +-50 3435 [ -50 3565 ] PLine +-50 3565 [ 250 3565 ] PLine +250 3565 [ 250 3435 ] PLine +10 SetLine +300 3500 [ 250 3500 ] PLine +10 SetLine +-1150 3700 [ -1200 3700 ] PLine +10 SetLine +-450 3575 [ -1150 3575 ] PLine +-1150 3575 [ -1150 3825 ] PLine +-1150 3825 [ -450 3825 ] PLine +-450 3825 [ -450 3575 ] PLine +10 SetLine +-400 3700 [ -450 3700 ] PLine +10 SetLine +-850 1300 [ -900 1300 ] PLine +10 SetLine +-150 1175 [ -850 1175 ] PLine +-850 1175 [ -850 1425 ] PLine +-850 1425 [ -150 1425 ] PLine +-150 1425 [ -150 1175 ] PLine +10 SetLine +-100 1300 [ -150 1300 ] PLine +10 SetLine +550 2800 [ 600 2800 ] PLine +10 SetLine +-150 2925 [ 550 2925 ] PLine +550 2925 [ 550 2675 ] PLine +550 2675 [ -150 2675 ] PLine +-150 2675 [ -150 2925 ] PLine +10 SetLine +-200 2800 [ -150 2800 ] PLine +10 SetLine +-450 2800 [ -400 2800 ] PLine +10 SetLine +-1150 2925 [ -450 2925 ] PLine +-450 2925 [ -450 2675 ] PLine +-450 2675 [ -1150 2675 ] PLine +-1150 2675 [ -1150 2925 ] PLine +10 SetLine +-1200 2800 [ -1150 2800 ] PLine +10 SetLine +0 2150 [ 0 2100 ] PLine +10 SetLine +65 2450 [ 65 2150 ] PLine +65 2150 [ -65 2150 ] PLine +-65 2150 [ -65 2450 ] PLine +-65 2450 [ 65 2450 ] PLine +10 SetLine +0 2500 [ 0 2450 ] PLine +10 SetLine +-1200 3050 [ -1200 3000 ] PLine +10 SetLine +-1135 3350 [ -1135 3050 ] PLine +-1135 3050 [ -1265 3050 ] PLine +-1265 3050 [ -1265 3350 ] PLine +-1265 3350 [ -1135 3350 ] PLine +10 SetLine +-1200 3400 [ -1200 3350 ] PLine +10 SetLine +-950 2250 [ -1150 2250 ] PLine +-1150 2250 [ -1150 2350 ] PLine +-1150 2350 [ -950 2350 ] PLine +-950 2350 [ -950 2250 ] PLine +10 SetLine +-1150 2550 [ -950 2550 ] PLine +-950 2550 [ -950 2450 ] PLine +-950 2450 [ -1150 2450 ] PLine +-1150 2450 [ -1150 2550 ] PLine +10 SetLine +850 2850 [ 1050 2850 ] PLine +1050 2850 [ 1050 2750 ] PLine +1050 2750 [ 850 2750 ] PLine +850 2750 [ 850 2850 ] PLine +10 SetLine +500 1900 [ 450 1900 ] PLine +10 SetLine +1200 1775 [ 500 1775 ] PLine +500 1775 [ 500 2025 ] PLine +500 2025 [ 1200 2025 ] PLine +1200 2025 [ 1200 1775 ] PLine +10 SetLine +1250 1900 [ 1200 1900 ] PLine +10 SetLine +-1150 900 [ -1200 900 ] PLine +10 SetLine +-150 725 [ -1150 725 ] PLine +-1150 725 [ -1150 1075 ] PLine +-1150 1075 [ -150 1075 ] PLine +-150 1075 [ -150 725 ] PLine +10 SetLine +-100 900 [ -150 900 ] PLine +10 SetLine +-1050 4000 [ -1100 4000 ] PLine +10 SetLine +-750 3935 [ -1050 3935 ] PLine +-1050 3935 [ -1050 4065 ] PLine +-1050 4065 [ -750 4065 ] PLine +-750 4065 [ -750 3935 ] PLine +10 SetLine +-700 4000 [ -750 4000 ] PLine +10 SetLine +750 3000 [ 700 3000 ] PLine +10 SetLine +1050 2935 [ 750 2935 ] PLine +750 2935 [ 750 3065 ] PLine +750 3065 [ 1050 3065 ] PLine +1050 3065 [ 1050 2935 ] PLine +10 SetLine +1100 3000 [ 1050 3000 ] PLine +10 SetLine +-250 3750 [ -50 3750 ] PLine +-50 3750 [ -50 3650 ] PLine +-50 3650 [ -250 3650 ] PLine +-250 3650 [ -250 3750 ] PLine +10 SetLine +200 900 [ 150 900 ] PLine +10 SetLine +270 950 [ 270 850 ] PLine +10 SetLine +200 850 [ 200 950 ] PLine +200 950 [ 500 950 ] PLine +500 950 [ 500 850 ] PLine +500 850 [ 200 850 ] PLine +10 SetLine +500 900 [ 550 900 ] PLine +10 SetLine +250 850 [ 250 950 ] PLine +10 SetLine +260 850 [ 260 950 ] PLine +10 SetLine +600 3700 [ 650 3700 ] PLine +10 SetLine +530 3650 [ 530 3750 ] PLine +10 SetLine +600 3750 [ 600 3650 ] PLine +600 3650 [ 300 3650 ] PLine +300 3650 [ 300 3750 ] PLine +300 3750 [ 600 3750 ] PLine +10 SetLine +300 3700 [ 250 3700 ] PLine +10 SetLine +550 3750 [ 550 3650 ] PLine +10 SetLine +540 3750 [ 540 3650 ] PLine +10 SetLine +-750 550 100 PCircle +10 SetLine +0 550 100 PCircle +10 SetLine +750 550 100 PCircle +10 SetLine +768 5000 [ 768 5248 ] PLine +768 5248 [ -768 5248 ] PLine +-768 5248 [ -768 5000 ] PLine +10 SetLine +1058 4900 [ -1058 4900 ] PLine +10 SetLine +1058 5000 [ 1058 4408 ] PLine +1058 4408 [ -1058 4408 ] PLine +-1058 4408 [ -1058 5000 ] PLine +-1058 5000 [ 1058 5000 ] PLine +10 SetLine +1058 5000 [ -1058 5000 ] PLine +10 SetLine +768 4900 [ 768 4408 ] PLine +10 SetLine +-768 4900 [ -768 4408 ] PLine +10 SetLine +900 200 [ 1100 200 ] PLine +1100 200 [ 1100 100 ] PLine +1100 100 [ 900 100 ] PLine +900 100 [ 900 200 ] PLine +10 SetLine +-100 200 [ 100 200 ] PLine +100 200 [ 100 100 ] PLine +100 100 [ -100 100 ] PLine +-100 100 [ -100 200 ] PLine +10 SetLine +-1100 200 [ -900 200 ] PLine +-900 200 [ -900 100 ] PLine +-900 100 [ -1100 100 ] PLine +-1100 100 [ -1100 200 ] PLine +10 SetLine +916 3493 [ 900 3456 ] PLine +900 3456 [ 939 3442 ] PLine +939 3442 [ 953 3477 ] PLine +10 SetLine +988 3612 140 PCircle +10 SetLine +-1000 1529 [ -1039 1490 ] PLine +10 SetLine +-1000 1490 [ -1000 1910 ] PLine +-1000 1910 [ -1300 1910 ] PLine +-1300 1910 [ -1300 1490 ] PLine +-1300 1490 [ -1000 1490 ] PLine +10 SetLine +200 1730 [ 200 1670 ] PLine +200 1670 [ 0 1670 ] PLine +0 1670 [ 0 1730 ] PLine +0 1730 [ 200 1730 ] PLine +10 SetLine +200 1700 [ 260 1700 ] PLine +10 SetLine +0 1700 [ -50 1700 ] PLine +10 SetLine +300 1270 [ 300 1330 ] PLine +300 1330 [ 500 1330 ] PLine +500 1330 [ 500 1270 ] PLine +500 1270 [ 300 1270 ] PLine +10 SetLine +300 1300 [ 240 1300 ] PLine +10 SetLine +500 1300 [ 550 1300 ] PLine +10 SetLine +-600 2270 [ -600 2330 ] PLine +-600 2330 [ -400 2330 ] PLine +-400 2330 [ -400 2270 ] PLine +-400 2270 [ -600 2270 ] PLine +10 SetLine +-600 2300 [ -660 2300 ] PLine +10 SetLine +-400 2300 [ -350 2300 ] PLine +10 SetLine +-800 4230 [ -800 4170 ] PLine +-800 4170 [ -1000 4170 ] PLine +-1000 4170 [ -1000 4230 ] PLine +-1000 4230 [ -800 4230 ] PLine +10 SetLine +-800 4200 [ -740 4200 ] PLine +10 SetLine +-1000 4200 [ -1050 4200 ] PLine +10 SetLine +1000 3230 [ 1000 3170 ] PLine +1000 3170 [ 800 3170 ] PLine +800 3170 [ 800 3230 ] PLine +800 3230 [ 1000 3230 ] PLine +10 SetLine +1000 3200 [ 1060 3200 ] PLine +10 SetLine +800 3200 [ 750 3200 ] PLine +10 SetLine +-600 2470 [ -600 2530 ] PLine +-600 2530 [ -400 2530 ] PLine +-400 2530 [ -400 2470 ] PLine +-400 2470 [ -600 2470 ] PLine +10 SetLine +-600 2500 [ -660 2500 ] PLine +10 SetLine +-400 2500 [ -350 2500 ] PLine +10 SetLine +-600 2070 [ -600 2130 ] PLine +-600 2130 [ -400 2130 ] PLine +-400 2130 [ -400 2070 ] PLine +-400 2070 [ -600 2070 ] PLine +10 SetLine +-600 2100 [ -660 2100 ] PLine +10 SetLine +-400 2100 [ -350 2100 ] PLine +10 SetLine +-900 2130 [ -900 2070 ] PLine +-900 2070 [ -1100 2070 ] PLine +-1100 2070 [ -1100 2130 ] PLine +-1100 2130 [ -900 2130 ] PLine +10 SetLine +-900 2100 [ -840 2100 ] PLine +10 SetLine +-1100 2100 [ -1150 2100 ] PLine +10 SetLine +500 1130 [ 500 1070 ] PLine +500 1070 [ 300 1070 ] PLine +300 1070 [ 300 1130 ] PLine +300 1130 [ 500 1130 ] PLine +10 SetLine +500 1100 [ 560 1100 ] PLine +10 SetLine +300 1100 [ 250 1100 ] PLine +10 SetLine +1000 2521 [ 1039 2560 ] PLine +10 SetLine +1000 2560 [ 1000 2140 ] PLine +1000 2140 [ 1300 2140 ] PLine +1300 2140 [ 1300 2560 ] PLine +1300 2560 [ 1000 2560 ] PLine +10 SetLine +0 1870 [ 0 1930 ] PLine +0 1930 [ 200 1930 ] PLine +200 1930 [ 200 1870 ] PLine +200 1870 [ 0 1870 ] PLine +10 SetLine +0 1900 [ -60 1900 ] PLine +10 SetLine +200 1900 [ 250 1900 ] PLine +10 SetLine +100 1470 [ 100 1530 ] PLine +100 1530 [ 300 1530 ] PLine +300 1530 [ 300 1470 ] PLine +300 1470 [ 100 1470 ] PLine +10 SetLine +100 1500 [ 40 1500 ] PLine +10 SetLine +300 1500 [ 350 1500 ] PLine +10 SetLine +-950 1650 [ -250 1650 ] PLine +-250 1650 [ -250 1850 ] PLine +-250 1850 [ -950 1850 ] PLine +-950 1850 [ -950 1775 ] PLine +-950 1775 [ -900 1775 ] PLine +-900 1775 [ -900 1725 ] PLine +-900 1725 [ -950 1725 ] PLine +-950 1725 [ -950 1650 ] PLine +10 SetLine +150 2250 [ 950 2250 ] PLine +950 2250 [ 950 2450 ] PLine +950 2450 [ 150 2450 ] PLine +150 2450 [ 150 2375 ] PLine +150 2375 [ 200 2375 ] PLine +200 2375 [ 200 2325 ] PLine +200 2325 [ 150 2325 ] PLine +150 2325 [ 150 2250 ] PLine +10 SetLine +150 3950 [ 1150 3950 ] PLine +1150 3950 [ 1150 4150 ] PLine +1150 4150 [ 150 4150 ] PLine +150 4150 [ 150 4075 ] PLine +150 4075 [ 200 4075 ] PLine +200 4075 [ 200 4025 ] PLine +200 4025 [ 150 4025 ] PLine +150 4025 [ 150 3950 ] PLine +10 SetLine +-1050 3150 [ -250 3150 ] PLine +-250 3150 [ -250 3350 ] PLine +-250 3350 [ -1050 3350 ] PLine +-1050 3350 [ -1050 3275 ] PLine +-1050 3275 [ -1000 3275 ] PLine +-1000 3275 [ -1000 3225 ] PLine +-1000 3225 [ -1050 3225 ] PLine +-1050 3225 [ -1050 3150 ] PLine +10 SetLine +800 1075 [ 800 1675 ] PLine +800 1675 [ 1200 1675 ] PLine +1200 1675 [ 1200 1075 ] PLine +1200 1075 [ 800 1075 ] PLine +10 SetLine +875 1075 [ 875 825 ] PLine +875 825 [ 925 825 ] PLine +925 825 [ 925 1075 ] PLine +10 SetLine +1075 1075 [ 1075 825 ] PLine +1075 825 [ 1125 825 ] PLine +1125 825 [ 1125 1075 ] PLine +10 SetLine +975 1075 [ 975 825 ] PLine +975 825 [ 1025 825 ] PLine +1025 825 [ 1025 1075 ] PLine +10 SetLine +996 1549 75 PCircle +10 SetLine +800 1425 [ 1200 1425 ] PLine +10 SetLine +-100 4200 [ -25 4200 ] PLine +10 SetLine +-100 3900 [ -100 4300 ] PLine +-100 4300 [ -500 4300 ] PLine +-500 4300 [ -500 3900 ] PLine +-500 3900 [ -100 3900 ] PLine +10 SetLine +-100 4000 [ -25 4000 ] PLine +10 SetLine +-1100 450 100 PCircle +10 SetLine +1100 450 100 PCircle +10 SetLine +1000 3430 [ 1000 3370 ] PLine +1000 3370 [ 800 3370 ] PLine +800 3370 [ 800 3430 ] PLine +800 3430 [ 1000 3430 ] PLine +10 SetLine +1000 3400 [ 1060 3400 ] PLine +10 SetLine +800 3400 [ 750 3400 ] PLine +10 SetText2 +0 -1175 1225 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -1175 1279 [ [ -53 0 -56 4 -65 11 0 11 ] ] Char +0 -1175 1310 [ [ -65 29 -65 6 -37 4 -40 6 -43 13 -43 20 -40 27 -34 31 -25 34 -18 31 -9 29 -3 25 0 18 0 11 -3 4 -6 2 -12 0 ] ] Char +10 SetText2 +0 75 3375 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 129 3375 [ [ 27 56 25 62 18 65 13 65 6 62 2 53 0 37 0 21 2 9 6 3 13 0 15 0 22 3 27 9 29 18 29 21 27 31 22 37 15 40 13 40 6 37 2 31 0 21 ] ] Char +10 SetText2 +0 75 3175 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 129 3175 [ [ 31 65 9 0 ] [ 0 65 31 65 ] ] Char +10 SetText2 +0 75 3575 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 129 3575 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -825 3850 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -771 3850 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -575 1450 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -521 1450 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -490 1450 [ [ 27 56 25 62 18 65 13 65 6 62 2 53 0 37 0 21 2 9 6 3 13 0 15 0 22 3 27 9 29 18 29 21 27 31 22 37 15 40 13 40 6 37 2 31 0 21 ] ] Char +10 SetText2 +0 125 2950 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 179 2950 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 210 2950 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -825 2950 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -771 2950 [ [ 29 43 27 34 22 28 15 25 13 25 6 28 2 34 0 43 0 46 2 56 6 62 13 65 15 65 22 62 27 56 29 43 29 28 27 12 22 3 15 0 11 0 4 3 2 9 ] ] Char +10 SetText2 +0 -100 2250 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -100 2304 [ [ -53 0 -56 4 -65 11 0 11 ] ] Char +0 -100 2335 [ [ -65 4 -65 29 -40 15 -40 22 -37 27 -34 29 -25 31 -18 31 -9 29 -3 25 0 18 0 11 -3 4 -6 2 -12 0 ] ] Char +10 SetText2 +0 -1275 3200 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -1275 3254 [ [ -50 2 -53 2 -59 4 -62 6 -65 11 -65 20 -62 25 -59 27 -53 29 -46 29 -40 27 -31 22 0 0 0 31 ] ] Char +10 SetText2 +0 -1100 2375 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -1046 2375 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -1015 2375 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1100 2575 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -1046 2575 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -1015 2575 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 900 2875 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 954 2875 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 985 2875 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 800 2050 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 854 2050 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 885 2050 [ [ 31 65 9 0 ] [ 0 65 31 65 ] ] Char +10 SetText2 +0 -675 1100 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -621 1100 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -590 1100 [ [ 11 65 4 62 2 56 2 50 4 43 9 40 18 37 25 34 29 28 31 21 31 12 29 6 27 3 20 0 11 0 4 3 2 6 0 12 0 21 2 28 6 34 13 37 22 40 27 43 29 50 29 56 27 62 20 65 11 65 ] ] Char +10 SetText2 +0 -925 4075 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -871 4075 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 875 3075 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 929 3075 [ [ 11 65 4 62 2 56 2 50 4 43 9 40 18 37 25 34 29 28 31 21 31 12 29 6 27 3 20 0 11 0 4 3 2 6 0 12 0 21 2 28 6 34 13 37 22 40 27 43 29 50 29 56 27 62 20 65 11 65 ] ] Char +10 SetText2 +0 -200 3775 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -146 3775 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 325 975 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 377 975 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 450 3775 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 502 3775 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -775 675 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 -732 675 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -50 675 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 -7 675 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 700 675 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 743 675 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 -1175 4650 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 -1132 4650 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1125 125 [ [ 0 65 0 0 27 0 ] ] Char +0 1172 125 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 1222 125 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 1274 125 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 125 125 [ [ 0 65 0 0 27 0 ] ] Char +0 172 125 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 222 125 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 274 125 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -875 125 [ [ 0 65 0 0 27 0 ] ] Char +0 -828 125 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -778 125 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -726 125 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1075 3425 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] [ 20 12 34 -6 ] ] Char +0 1131 3425 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1075 1475 [ [ 0 -65 0 0 ] [ 0 -65 -20 -65 -27 -62 -29 -59 -31 -53 -31 -46 -29 -40 -27 -37 -20 -34 0 -34 ] [ -15 -34 -31 0 ] ] Char +0 -1127 1475 [ [ -11 -65 -4 -62 -2 -56 -2 -50 -4 -43 -9 -40 -18 -37 -25 -34 -29 -28 -31 -21 -31 -12 -29 -6 -27 -3 -20 0 -11 0 -4 -3 -2 -6 0 -12 0 -21 -2 -28 -6 -34 -13 -37 -22 -40 -27 -43 -29 -50 -29 -56 -27 -62 -20 -65 -11 -65 ] ] Char +10 SetText2 +0 25 1750 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 77 1750 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 108 1750 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 350 1350 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 402 1350 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 433 1350 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -550 2350 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -498 2350 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 -925 4250 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -873 4250 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 850 3250 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 902 3250 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -550 2550 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -498 2550 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -550 2150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -498 2150 [ [ 27 56 25 62 18 65 13 65 6 62 2 53 0 37 0 21 2 9 6 3 13 0 15 0 22 3 27 9 29 18 29 21 27 31 22 37 15 40 13 40 6 37 2 31 0 21 ] ] Char +10 SetText2 +0 -1025 2150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -973 2150 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 350 1150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 402 1150 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 433 1150 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 1200 2125 [ [ 0 -65 0 0 ] [ 0 -65 -20 -65 -27 -62 -29 -59 -31 -53 -31 -46 -29 -40 -27 -37 -20 -34 0 -34 ] [ -15 -34 -31 0 ] ] Char +0 1148 2125 [ [ -31 -65 -9 0 ] [ 0 -65 -31 -65 ] ] Char +10 SetText2 +0 50 1950 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 102 1950 [ [ 29 43 27 34 22 28 15 25 13 25 6 28 2 34 0 43 0 46 2 56 6 62 13 65 15 65 22 62 27 56 29 43 29 28 27 12 22 3 15 0 11 0 4 3 2 9 ] ] Char +10 SetText2 +0 150 1550 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 202 1550 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 233 1550 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -675 1950 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 -623 1950 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 450 2550 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 502 2550 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 500 4275 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 552 4275 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -675 3450 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 -623 3450 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 950 1700 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 1002 1700 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -350 4325 [ [ 0 65 31 0 ] [ 31 65 0 0 ] ] Char +0 -298 4325 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1225 600 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 -1169 600 [ [ 0 65 0 0 ] [ 31 65 31 0 ] [ 0 34 31 34 ] ] Char +0 -1117 600 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1125 600 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 1181 600 [ [ 0 65 0 0 ] [ 31 65 31 0 ] [ 0 34 31 34 ] ] Char +0 1233 600 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 800 3450 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 852 3450 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 883 3450 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +0 0 60 /PRndPad SetFlash +-1100 1450 Flash +-1100 1150 Flash +300 3300 Flash +-100 3300 Flash +-100 3100 Flash +300 3100 Flash +300 3500 Flash +-100 3500 Flash +-400 3700 Flash +-1200 3700 Flash +-100 1300 Flash +-900 1300 Flash +-200 2800 Flash +600 2800 Flash +-1200 2800 Flash +-400 2800 Flash +0 2500 Flash +0 2100 Flash +-1200 3400 Flash +-1200 3000 Flash +-900 2300 Flash +-1200 2300 Flash +-1200 2500 Flash +-900 2500 Flash +800 2800 Flash +1100 2800 Flash +1250 1900 Flash +450 1900 Flash +-100 900 Flash +-1200 900 Flash +-700 4000 Flash +-1100 4000 Flash +1100 3000 Flash +700 3000 Flash +-300 3700 Flash +0 3700 Flash +0 0 60 /PSqrPad SetFlash +100 900 Flash +0 0 60 /PRndPad SetFlash +600 900 Flash +0 0 60 /PSqrPad SetFlash +700 3700 Flash +0 0 60 /PRndPad SetFlash +200 3700 Flash +0 0 70 /PRndPad SetFlash +-750 550 Flash +-750 450 Flash +0 550 Flash +0 450 Flash +750 550 Flash +750 450 Flash +-648 4479 Flash +-540 4479 Flash +-432 4479 Flash +-324 4479 Flash +-216 4479 Flash +-108 4479 Flash +0 4479 Flash +108 4479 Flash +216 4479 Flash +324 4479 Flash +432 4479 Flash +540 4479 Flash +648 4479 Flash +-594 4593 Flash +-486 4593 Flash +-378 4593 Flash +-270 4593 Flash +-162 4593 Flash +-54 4593 Flash +54 4593 Flash +162 4593 Flash +270 4593 Flash +378 4593 Flash +486 4593 Flash +594 4593 Flash +0 0 177 /PRndPad SetFlash +940 4536 Flash +-940 4536 Flash +0 0 60 /PSqrPad SetFlash +950 150 Flash +0 0 60 /PRndPad SetFlash +1050 150 Flash +0 0 60 /PSqrPad SetFlash +-50 150 Flash +0 0 60 /PRndPad SetFlash +50 150 Flash +0 0 60 /PSqrPad SetFlash +-1050 150 Flash +0 0 60 /PRndPad SetFlash +-950 150 Flash +0 0 50 /PRndPad SetFlash +950 3524 Flash +1026 3612 Flash +950 3700 Flash +0 0 60 /PSqrPad SetFlash +-1200 1600 Flash +0 0 60 /PRndPad SetFlash +-1100 1700 Flash +-1200 1800 Flash +300 1700 Flash +-100 1700 Flash +200 1300 Flash +600 1300 Flash +-700 2300 Flash +-300 2300 Flash +-700 4200 Flash +-1100 4200 Flash +1100 3200 Flash +700 3200 Flash +-700 2500 Flash +-300 2500 Flash +-700 2100 Flash +-300 2100 Flash +-800 2100 Flash +-1200 2100 Flash +600 1100 Flash +200 1100 Flash +0 0 60 /PSqrPad SetFlash +1200 2450 Flash +0 0 60 /PRndPad SetFlash +1100 2350 Flash +1200 2250 Flash +-100 1900 Flash +300 1900 Flash +0 1500 Flash +400 1500 Flash +0 0 60 /PSqrPad SetFlash +-900 1600 Flash +0 0 60 /PRndPad SetFlash +-800 1600 Flash +-700 1600 Flash +-600 1600 Flash +-500 1600 Flash +-400 1600 Flash +-300 1600 Flash +-300 1900 Flash +-400 1900 Flash +-500 1900 Flash +-600 1900 Flash +-700 1900 Flash +-800 1900 Flash +-900 1900 Flash +0 0 60 /PSqrPad SetFlash +200 2200 Flash +0 0 60 /PRndPad SetFlash +300 2200 Flash +400 2200 Flash +500 2200 Flash +600 2200 Flash +700 2200 Flash +800 2200 Flash +900 2200 Flash +900 2500 Flash +800 2500 Flash +700 2500 Flash +600 2500 Flash +500 2500 Flash +400 2500 Flash +300 2500 Flash +200 2500 Flash +0 0 60 /PSqrPad SetFlash +200 3900 Flash +0 0 60 /PRndPad SetFlash +300 3900 Flash +400 3900 Flash +500 3900 Flash +600 3900 Flash +700 3900 Flash +800 3900 Flash +900 3900 Flash +1000 3900 Flash +1100 3900 Flash +1100 4200 Flash +1000 4200 Flash +900 4200 Flash +800 4200 Flash +700 4200 Flash +600 4200 Flash +500 4200 Flash +400 4200 Flash +300 4200 Flash +200 4200 Flash +0 0 60 /PSqrPad SetFlash +-1000 3100 Flash +0 0 60 /PRndPad SetFlash +-900 3100 Flash +-800 3100 Flash +-700 3100 Flash +-600 3100 Flash +-500 3100 Flash +-400 3100 Flash +-300 3100 Flash +-300 3400 Flash +-400 3400 Flash +-500 3400 Flash +-600 3400 Flash +-700 3400 Flash +-800 3400 Flash +-900 3400 Flash +-1000 3400 Flash +0 0 70 /PRndPad SetFlash +900 800 Flash +1100 800 Flash +1000 800 Flash +0 0 177 /PRndPad SetFlash +1000 1550 Flash +0 0 60 /PRndPad SetFlash +0 4000 Flash +0 4200 Flash +0 0 250 /PRndPad SetFlash +-1100 450 Flash +1100 450 Flash +0 0 60 /PRndPad SetFlash +1100 3400 Flash +700 3400 Flash +0 0 60 /PRndPad SetFlash +-1100 1450 Flash +-1100 1150 Flash +300 3300 Flash +-100 3300 Flash +-100 3100 Flash +300 3100 Flash +300 3500 Flash +-100 3500 Flash +-400 3700 Flash +-1200 3700 Flash +-100 1300 Flash +-900 1300 Flash +-200 2800 Flash +600 2800 Flash +-1200 2800 Flash +-400 2800 Flash +0 2500 Flash +0 2100 Flash +-1200 3400 Flash +-1200 3000 Flash +-900 2300 Flash +-1200 2300 Flash +-1200 2500 Flash +-900 2500 Flash +800 2800 Flash +1100 2800 Flash +1250 1900 Flash +450 1900 Flash +-100 900 Flash +-1200 900 Flash +-700 4000 Flash +-1100 4000 Flash +1100 3000 Flash +700 3000 Flash +-300 3700 Flash +0 3700 Flash +0 0 60 /PSqrPad SetFlash +100 900 Flash +0 0 60 /PRndPad SetFlash +600 900 Flash +0 0 60 /PSqrPad SetFlash +700 3700 Flash +0 0 60 /PRndPad SetFlash +200 3700 Flash +0 0 70 /PRndPad SetFlash +-750 550 Flash +-750 450 Flash +0 550 Flash +0 450 Flash +750 550 Flash +750 450 Flash +-648 4479 Flash +-540 4479 Flash +-432 4479 Flash +-324 4479 Flash +-216 4479 Flash +-108 4479 Flash +0 4479 Flash +108 4479 Flash +216 4479 Flash +324 4479 Flash +432 4479 Flash +540 4479 Flash +648 4479 Flash +-594 4593 Flash +-486 4593 Flash +-378 4593 Flash +-270 4593 Flash +-162 4593 Flash +-54 4593 Flash +54 4593 Flash +162 4593 Flash +270 4593 Flash +378 4593 Flash +486 4593 Flash +594 4593 Flash +0 0 177 /PRndPad SetFlash +940 4536 Flash +-940 4536 Flash +0 0 60 /PSqrPad SetFlash +950 150 Flash +0 0 60 /PRndPad SetFlash +1050 150 Flash +0 0 60 /PSqrPad SetFlash +-50 150 Flash +0 0 60 /PRndPad SetFlash +50 150 Flash +0 0 60 /PSqrPad SetFlash +-1050 150 Flash +0 0 60 /PRndPad SetFlash +-950 150 Flash +0 0 50 /PRndPad SetFlash +950 3524 Flash +1026 3612 Flash +950 3700 Flash +0 0 60 /PSqrPad SetFlash +-1200 1600 Flash +0 0 60 /PRndPad SetFlash +-1100 1700 Flash +-1200 1800 Flash +300 1700 Flash +-100 1700 Flash +200 1300 Flash +600 1300 Flash +-700 2300 Flash +-300 2300 Flash +-700 4200 Flash +-1100 4200 Flash +1100 3200 Flash +700 3200 Flash +-700 2500 Flash +-300 2500 Flash +-700 2100 Flash +-300 2100 Flash +-800 2100 Flash +-1200 2100 Flash +600 1100 Flash +200 1100 Flash +0 0 60 /PSqrPad SetFlash +1200 2450 Flash +0 0 60 /PRndPad SetFlash +1100 2350 Flash +1200 2250 Flash +-100 1900 Flash +300 1900 Flash +0 1500 Flash +400 1500 Flash +0 0 60 /PSqrPad SetFlash +-900 1600 Flash +0 0 60 /PRndPad SetFlash +-800 1600 Flash +-700 1600 Flash +-600 1600 Flash +-500 1600 Flash +-400 1600 Flash +-300 1600 Flash +-300 1900 Flash +-400 1900 Flash +-500 1900 Flash +-600 1900 Flash +-700 1900 Flash +-800 1900 Flash +-900 1900 Flash +0 0 60 /PSqrPad SetFlash +200 2200 Flash +0 0 60 /PRndPad SetFlash +300 2200 Flash +400 2200 Flash +500 2200 Flash +600 2200 Flash +700 2200 Flash +800 2200 Flash +900 2200 Flash +900 2500 Flash +800 2500 Flash +700 2500 Flash +600 2500 Flash +500 2500 Flash +400 2500 Flash +300 2500 Flash +200 2500 Flash +0 0 60 /PSqrPad SetFlash +200 3900 Flash +0 0 60 /PRndPad SetFlash +300 3900 Flash +400 3900 Flash +500 3900 Flash +600 3900 Flash +700 3900 Flash +800 3900 Flash +900 3900 Flash +1000 3900 Flash +1100 3900 Flash +1100 4200 Flash +1000 4200 Flash +900 4200 Flash +800 4200 Flash +700 4200 Flash +600 4200 Flash +500 4200 Flash +400 4200 Flash +300 4200 Flash +200 4200 Flash +0 0 60 /PSqrPad SetFlash +-1000 3100 Flash +0 0 60 /PRndPad SetFlash +-900 3100 Flash +-800 3100 Flash +-700 3100 Flash +-600 3100 Flash +-500 3100 Flash +-400 3100 Flash +-300 3100 Flash +-300 3400 Flash +-400 3400 Flash +-500 3400 Flash +-600 3400 Flash +-700 3400 Flash +-800 3400 Flash +-900 3400 Flash +-1000 3400 Flash +0 0 70 /PRndPad SetFlash +900 800 Flash +1100 800 Flash +1000 800 Flash +0 0 177 /PRndPad SetFlash +1000 1550 Flash +0 0 60 /PRndPad SetFlash +0 4000 Flash +0 4200 Flash +0 0 250 /PRndPad SetFlash +-1100 450 Flash +1100 450 Flash +0 0 60 /PRndPad SetFlash +1100 3400 Flash +700 3400 Flash +10 SetText2 +0 -225 875 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +10 SetText2 +0 1125 1875 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +10 SetText2 +0 -125 2775 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +10 SetText2 +0 -1125 2775 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +10 SetText2 +0 -525 3675 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +10 SetText2 +0 -700 4325 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -750 275 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 34 25 ] [ 22 25 34 25 ] ] Char +0 -696 275 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -640 275 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -588 275 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 34 25 ] [ 22 25 34 25 ] ] Char +0 -534 275 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -484 275 [ [ 15 65 15 0 ] [ 0 65 31 65 ] ] Char +0 -380 275 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 ] [ 0 34 20 34 27 31 29 28 31 21 31 12 29 6 27 3 20 0 0 0 ] ] Char +0 -328 275 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +0 -272 275 [ [ 0 65 31 0 ] [ 31 65 0 0 ] ] Char +0 -168 275 [ [ 0 28 40 28 ] ] Char +0 -55 275 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 -3 275 [ [ 0 65 0 0 ] [ 0 65 31 0 ] [ 31 65 31 0 ] ] Char +0 49 275 [ [ 0 65 0 0 ] ] Char +0 69 275 [ [ 0 65 18 0 ] [ 36 65 18 0 ] ] Char +0 177 275 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +0 233 275 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] ] Char +0 335 275 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 387 275 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 437 275 [ [ 0 65 0 0 27 0 ] ] Char +0 484 275 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 540 275 [ [ 0 65 11 0 ] [ 22 65 11 0 ] [ 22 65 34 0 ] [ 45 65 34 0 ] ] Char +0 605 275 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 661 275 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 713 275 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +10 SetText2 +0 125 600 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 177 600 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 229 600 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 500 600 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +0 561 600 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 592 600 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -625 600 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -569 600 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 -517 600 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -465 600 [ [ 0 65 0 0 ] ] Char +0 -445 600 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +10 SetText2 +0 -300 4725 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +0 -248 4725 [ [ 0 65 0 0 ] ] Char +0 -228 4725 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -176 4725 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -74 4725 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 300 4725 [ [ -31 56 -27 62 -20 65 -11 65 -4 62 0 56 0 50 -2 43 -4 40 -9 37 -22 31 -27 28 -29 25 -31 18 -31 9 -27 3 -20 0 -11 0 -4 3 0 9 ] ] Char +0 248 4725 [ [ 0 65 0 0 ] ] Char +0 228 4725 [ [ 0 65 0 0 ] [ 0 65 -15 65 -22 62 -27 56 -29 50 -31 40 -31 25 -29 15 -27 9 -22 3 -15 0 0 0 ] ] Char +0 176 4725 [ [ 0 65 0 0 ] [ 0 65 -29 65 ] [ 0 34 -18 34 ] [ 0 0 -29 0 ] ] Char +0 74 4725 [ [ -2 50 -2 53 -4 59 -6 62 -11 65 -20 65 -25 62 -27 59 -29 53 -29 46 -27 40 -22 31 0 0 -31 0 ] ] Char +10 SetText2 +0 1100 2075 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1050 1925 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 875 675 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1075 675 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 975 675 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -925 1475 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 175 3775 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1050 2975 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 625 4325 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 656 4325 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -825 1275 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +0 0 55 /PRndPad SetFlash +-200 2350 Flash +-200 1750 Flash +200 1400 Flash +0 0 55 /PRndPad SetFlash +-200 2350 Flash +-200 1750 Flash +200 1400 Flash +0 0 55 /PRndPad SetFlash +300 1100 Flash +0 0 55 /PRndPad SetFlash +300 1100 Flash +0 0 55 /PRndPad SetFlash +175 3300 Flash +0 0 55 /PRndPad SetFlash +175 3300 Flash +0 0 55 /PRndPad SetFlash +1000 2650 Flash +0 0 55 /PRndPad SetFlash +1000 2650 Flash +0 0 55 /PRndPad SetFlash +-450 2100 Flash +0 0 55 /PRndPad SetFlash +-450 2100 Flash +0 0 55 /PRndPad SetFlash +-650 2600 Flash +-100 2600 Flash +-100 2250 Flash +0 0 55 /PRndPad SetFlash +-650 2600 Flash +-100 2600 Flash +-100 2250 Flash +0 0 55 /PRndPad SetFlash +800 1800 Flash +0 0 55 /PRndPad SetFlash +800 1800 Flash +0 0 55 /PRndPad SetFlash +700 1900 Flash +0 0 55 /PRndPad SetFlash +700 1900 Flash +0 0 55 /PRndPad SetFlash +600 1700 Flash +0 0 55 /PRndPad SetFlash +600 1700 Flash +0 0 55 /PRndPad SetFlash +500 1600 Flash +0 0 55 /PRndPad SetFlash +500 1600 Flash +0 0 55 /PRndPad SetFlash +0 4100 Flash +900 4100 Flash +0 0 55 /PRndPad SetFlash +0 4100 Flash +900 4100 Flash +0 0 55 /PRndPad SetFlash +800 3000 Flash +0 0 55 /PRndPad SetFlash +800 3000 Flash +0 0 55 /PRndPad SetFlash +600 3700 Flash +0 0 55 /PRndPad SetFlash +600 3700 Flash +0 0 55 /PRndPad SetFlash +450 2700 Flash +-400 2700 Flash +-400 2300 Flash +0 0 55 /PRndPad SetFlash +450 2700 Flash +-400 2700 Flash +-400 2300 Flash +0 0 55 /PRndPad SetFlash +350 3800 Flash +0 0 55 /PRndPad SetFlash +350 3800 Flash +0 0 55 /PRndPad SetFlash +-850 3700 Flash +0 0 55 /PRndPad SetFlash +-850 3700 Flash +0 0 55 /PRndPad SetFlash +400 1300 Flash +0 0 55 /PRndPad SetFlash +400 1300 Flash +0 0 55 /PRndPad SetFlash +-1050 1050 Flash +0 0 55 /PRndPad SetFlash +-1050 1050 Flash +0 0 55 /PRndPad SetFlash +0 4475 Flash +75 4000 Flash +1000 4000 Flash +0 0 55 /PRndPad SetFlash +0 4475 Flash +75 4000 Flash +1000 4000 Flash +0 0 55 /PRndPad SetFlash +950 3200 Flash +0 0 55 /PRndPad SetFlash +950 3200 Flash +0 0 55 /PRndPad SetFlash +850 1200 Flash +-600 1200 Flash +0 0 55 /PRndPad SetFlash +850 1200 Flash +-600 1200 Flash +0 0 55 /PRndPad SetFlash +-550 3900 Flash +-350 3900 Flash +0 0 55 /PRndPad SetFlash +-550 3900 Flash +-350 3900 Flash +0 0 55 /PRndPad SetFlash +-800 4300 Flash +0 0 55 /PRndPad SetFlash +-800 4300 Flash +0 0 55 /PRndPad SetFlash +-750 4350 Flash +0 0 55 /PRndPad SetFlash +-750 4350 Flash +0 0 55 /PRndPad SetFlash +400 3400 Flash +0 0 55 /PRndPad SetFlash +400 3400 Flash +grestore +showpage diff --git a/contrib/xntpd/gadget/sm0228.lpr b/contrib/xntpd/gadget/sm0228.lpr new file mode 100644 index 0000000000..cd39c9ca92 --- /dev/null +++ b/contrib/xntpd/gadget/sm0228.lpr @@ -0,0 +1,744 @@ +%!PS-Adobe-2.0 +%%Title: PADS Postscript Driver Header +%%Creator: Andy Montalvo, 18 Lupine St., Lowell, MA 01851 +%%CreationDate: 06/08/90 +%%For: CAD Software, Littleton, MA +%%EndComments +%%BeginProcSet: Markers 1.0 0 +% marker attributes +/MAttr_Width 1 def +/MAttr_Size 0 def +/MAttr_Type /M1 def +% procedures +/M1 { %def +% draw marker 1: plus +% Stack: - M1 - + -2 0 rmoveto + 4 0 rlineto + -2 2 rmoveto + 0 -4 rlineto +} bind def +/M2 { %def +% draw marker 2: cross +% Stack: - M2 - + -2 -2 rmoveto + 4 4 rlineto + -4 0 rmoveto + 4 -4 rlineto +} bind def +/M3 { %def +% draw marker 3: square +% Stack: - M3 - + 0 2 rlineto + 2 0 rlineto + 0 -4 rlineto + -4 0 rlineto + 0 4 rlineto + 2 0 rlineto +} bind def +/M4 { %def +% draw marker 4: diamond +% Stack: - M4 - + 0 2 rlineto + 2 -2 rlineto + -2 -2 rlineto + -2 2 rlineto + 2 2 rlineto +} bind def +/M5 { %def +% draw marker 5: hourglass +% Stack: - M5 - + 2 2 rlineto + -4 0 rlineto + 4 -4 rlineto + -4 0 rlineto + 2 2 rlineto +} bind def +/M6 { %def +% draw marker 6: bowtie +% Stack: - M6 - + 2 2 rlineto + 0 -4 rlineto + -4 4 rlineto + 0 -4 rlineto + 2 2 rlineto +} bind def +/M7 { %def +% draw marker 7: small plus (goes with char marker) +% Stack: - M7 - + -1 0 rmoveto + 2 0 rlineto + -1 1 rmoveto + 0 -2 rlineto +} bind def +/Marker { %def +% Command from driver: draw marker +% STACK: x y Marker - + MAttr_Size 0 gt + { + gsave + moveto + MAttr_Size 4 div dup scale + MAttr_Type load exec + 4 MAttr_Size div dup scale + MAttr_Width setlinewidth + stroke + grestore + } if +} def +%%EndProcSet: Markers 1.0 0 +%%BeginProcSet: Lib 1.0 0 +/sg { %def +% Command from driver: set the gray scale 0 - 100 +% STACK: greylevel sg + 100 div dup setgray /glev exch def +} bind def +/Circle { %def +% draw a circle +% STACK: x y radius Circle - + 0 360 arc +} bind def +/RndAper { %def +% select a round aperture +% STACK: - RndAper - + 1 setlinejoin + 1 setlinecap +} bind def +/SqrAper { %def +% select a square aperture +% STACK: - SqrAper - + 0 setlinejoin + 2 setlinecap +} bind def +/Line { %def +% draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] Line - + 3 1 roll + moveto + true + exch + % This pushes the x then the y then does lineto + { exch { false } { lineto true } ifelse } forall + pop +} bind def +/Clipto { %def +% set clipping rectangle from 0,0 to new values +% STACK: x y Clipto - + 0 0 moveto + dup 0 exch lineto + 2 copy lineto + pop + 0 lineto + closepath + clip + newpath +} bind def +/Clip4 { %def +% set clipping rectangle from xmin,ymin to xmax,ymax +% STACK: xmin ymin xmax ymax Clip4 - + 4 copy pop pop moveto + 4 copy pop exch lineto pop + 2 copy lineto + exch pop exch pop lineto + closepath + clip + newpath +} bind def +%%EndProcSet: Lib 1.0 0 +%%BeginProcSet: Lines 1.0 0 +% line attributes % +/LAttr_Width 1 def +% line procedures +/PLine { %def +% Cammand from driver: draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + LAttr_Width setlinewidth + stroke +} bind def % PLine +/Char { %def +% Command from driver: draw a character at the current position +% STACK: type x y stroke_array Char - +% stroke array -- [ stroke1 stroke2 ... stroken ] +% stroke -- connected staight lines +% type = 0 if text 1 if marker + gsave + 4 1 roll + translate + 0 eq { TAttr_Width } { MAttr_Width } ifelse setlinewidth + { + dup length 2 gt + { + dup dup 0 get exch 1 get % get starting point + 3 -1 roll % put x y before array + dup length 2 sub 2 exch getinterval % delete first items from array + Line + stroke + } + { + aload pop currentlinewidth 2 div Circle fill + } ifelse + } forall + grestore +} bind def % Char +/PArc { %def +% Command from driver: draw an arc +% STACK: x y radius startangle deltaangle Arc - + 10 div exch 10 div exch + 2 copy pop add + arc + LAttr_Width setlinewidth + stroke +} bind def +/PCircle { %def +% Command from driver: draw an circle +% STACK: x y radius PCircle - + Circle + LAttr_Width setlinewidth + stroke +} bind def +%%EndProcSet: Lines 1.0 0 +%%BeginProcSet: Polygon 1.0 0 +% polygon attributes % +/PAttr_ExtWidth 1 def +/PAttr_IntWidth 1 def +/PAttr_Grid 1 def +% polygon procedures +/LoopSet { %def +% set up for loop condition +% STACK: start end LoopSet low gridwidth high + 2 copy lt { exch } if + % make grid line up to absolute coordinates + PAttr_Grid div truncate PAttr_Grid mul exch + PAttr_Grid exch +} bind def +/Hatch { %def +% draw cross hatch pattern in current path +% STACK: - Hatch - + pathbbox + /ury exch def + /urx exch def + /lly exch def + /llx exch def + clip + newpath + llx urx LoopSet + { % x loop + dup lly exch ury moveto lineto + } for + lly ury LoopSet + { % y loop + llx exch dup urx exch moveto lineto + } for + PAttr_IntWidth setlinewidth + stroke +} bind def +/PPoly { %def +% Command from driver: draw a plygon +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + closepath + gsave + PAttr_IntWidth PAttr_Grid ge {fill} {Hatch} ifelse + grestore + PAttr_ExtWidth setlinewidth + stroke +} bind def +%%EndProcSet: Polygon 1.0 0 +%%BeginProcSet: Text 1.0 0 +% text attributes % +/TAttr_Mirr 0 def +/TAttr_Orient 0 def +/TAttr_Width 1 def +% text procedures +/Text { %def +% Command from driver: Draw text +% STACK: x y width string Text - + gsave + 4 2 roll + translate + TAttr_Mirr 0 gt + { + -1 1 scale + } if + TAttr_Orient rotate + 0 0 moveto + dup length dup 1 gt + { + exch dup stringwidth pop + 4 -1 roll + exch 2 copy + lt + { + div 1 scale show + } + { + sub + 3 -1 roll 1 sub div + 0 3 -1 roll ashow + } + ifelse + } + { + pop + show + } ifelse + grestore +} bind def +%%EndProcSet: Text 1.0 0 +%%BeginProcSet: FlashSymbols 1.0 0 +% flash symbol attributes % +/FAttr_Type /PRndPad def +/FAttr_Width 0 def +/FAttr_Length 1 def +/FAttr_Orient 0 def +% flash symbol procedures +/PRndPad { %def +% Command from driver: draw an circular pad +% STACK: - PCirclePad - + FAttr_Width dup scale + 0 0 .5 Circle + fill +} bind def +/PSqrPad { %def +% Draw an Square pad +% STACK: - PRectPad - + FAttr_Width dup scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/PRectPad { %def +% Draw an rectangular pad +% STACK: - PRectPad - + FAttr_Length FAttr_Width scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/POvalPad { %def +% Draw an oval pad +% STACK: - POvalPad - + FAttr_Width setlinewidth + FAttr_Length FAttr_Width sub 2 div dup + neg 0 moveto + 0 lineto + RndAper + stroke +} bind def +/Anl { %def + 0 0 .5 Circle + fill + FAttr_Length FAttr_Width lt + { % inner circle + 0 0 + FAttr_Length 0 gt { FAttr_Length FAttr_Width div } { .5 } ifelse + 2 div Circle + 1 setgray + fill + glev setgray + } if +} bind def +/PAnlPad { %def +% Draw an annular pad +% STACK: - PAnlPad - + FAttr_Width dup scale + Anl +} bind def +/PRelPad { %def +% Draw an thermal relief pad +% STACK: - PRelPad - + PAnlPad + 1 setgray + .17 setlinewidth + 0 setlinecap % the x + 45 rotate + .5 0 moveto -.5 0 lineto + 0 .5 moveto 0 -.5 lineto + stroke + glev setgray +} bind def +/Flash { %def +% Command from driver: Flash a symbol +% STACK: x y Flash - + FAttr_Width 0 gt + { + gsave + translate + FAttr_Orient rotate + FAttr_Type load exec + grestore + } if +} def +%%EndProcSet: FlashSymbols 1.0 0 +%%BeginProcSet: SetAttr 1.0 0 +/SetLine { %def +% Set the width of the lines +% STACK: linewidth SetLine - + /LAttr_Width exch def + RndAper +} bind def +/SetPoly { %def +% Set attribute of polygon +% STACK: external_width internal_grid_width grid_spacing SetPoly - + /PAttr_Grid exch def + /PAttr_IntWidth exch def + /PAttr_ExtWidth exch def + RndAper +} bind def +/SetFlash { %def +% Set Attributed of flash pad +% STACK: orientation_angle length width aperture_type SetFlash - + /FAttr_Type exch def + FAttr_Type /PSqrPad eq FAttr_Type /PRectPad eq or + { SqrAper } { RndAper } ifelse + /FAttr_Width exch def + /FAttr_Length exch def + /FAttr_Orient exch 10 div def +} bind def +/SetMkr { %def +% Set attributes of markers +% STACK: linewidth size type SetMkr - + /MAttr_Type exch def + /MAttr_Size exch def + /MAttr_Width exch def + RndAper +} bind def +/SetText1 { %def +% Set attributes of text +% STACK: fontname height orient mirror SetMkr - + /TAttr_Mirr exch def + /TAttr_Orient exch 10 div def + exch findfont exch scalefont setfont + RndAper +} bind def +/SetText2 { %def +% Set attributes of text +% STACK: linewidth height mirror orient SetMkr - + /TAttr_Width exch def + RndAper +} bind def +%%EndProcSet: SetAttr 1.0 0 +%%BeginProcSet: Initialize 1.0 0 +/Init { %def +% Initialize the driver +% STACK: Init - + 72 1000 div dup scale % Scale to 1/1000 inch + 250 250 translate % make origin 1/4 inch from bottom left + 1.5 setmiterlimit 1 RndAper % set line defaults + 0 setgray % set color default + /glev 0 def +} def +%%EndProcSet: Initialize 1.0 0 +%%EndProlog +/Helvetica findfont 12 scalefont setfont +35 760 moveto +(gadget.job - Fri Aug 21 03:35:33 1992) show +gsave +Init +8000 10500 Clipto +4000 2800 translate +0 rotate +1 1 div dup scale +75 sg +50 sg +25 sg +0 sg +10 SetLine +-1350 4700 [ -1350 4900 ] PLine +-1350 4900 [ -1150 4900 ] PLine +10 SetLine +1150 4900 [ 1350 4900 ] PLine +1350 4900 [ 1350 4700 ] PLine +10 SetLine +1150 0 [ 1350 0 ] PLine +1350 0 [ 1350 200 ] PLine +10 SetLine +-1350 200 [ -1350 0 ] PLine +-1350 0 [ -1150 0 ] PLine +0 0 70 /PRndPad SetFlash +-1100 1450 Flash +-1100 1150 Flash +300 3300 Flash +-100 3300 Flash +-100 3100 Flash +300 3100 Flash +300 3500 Flash +-100 3500 Flash +-400 3700 Flash +-1200 3700 Flash +-100 1300 Flash +-900 1300 Flash +-200 2800 Flash +600 2800 Flash +-1200 2800 Flash +-400 2800 Flash +0 2500 Flash +0 2100 Flash +-1200 3400 Flash +-1200 3000 Flash +-900 2300 Flash +-1200 2300 Flash +-1200 2500 Flash +-900 2500 Flash +800 2800 Flash +1100 2800 Flash +1250 1900 Flash +450 1900 Flash +-100 900 Flash +-1200 900 Flash +-700 4000 Flash +-1100 4000 Flash +1100 3000 Flash +700 3000 Flash +-300 3700 Flash +0 3700 Flash +0 0 70 /PSqrPad SetFlash +100 900 Flash +0 0 70 /PRndPad SetFlash +600 900 Flash +0 0 70 /PSqrPad SetFlash +700 3700 Flash +0 0 70 /PRndPad SetFlash +200 3700 Flash +0 0 80 /PRndPad SetFlash +-750 550 Flash +-750 450 Flash +0 550 Flash +0 450 Flash +750 550 Flash +750 450 Flash +-648 4479 Flash +-540 4479 Flash +-432 4479 Flash +-324 4479 Flash +-216 4479 Flash +-108 4479 Flash +0 4479 Flash +108 4479 Flash +216 4479 Flash +324 4479 Flash +432 4479 Flash +540 4479 Flash +648 4479 Flash +-594 4593 Flash +-486 4593 Flash +-378 4593 Flash +-270 4593 Flash +-162 4593 Flash +-54 4593 Flash +54 4593 Flash +162 4593 Flash +270 4593 Flash +378 4593 Flash +486 4593 Flash +594 4593 Flash +0 0 187 /PRndPad SetFlash +940 4536 Flash +-940 4536 Flash +0 0 70 /PSqrPad SetFlash +950 150 Flash +0 0 70 /PRndPad SetFlash +1050 150 Flash +0 0 70 /PSqrPad SetFlash +-50 150 Flash +0 0 70 /PRndPad SetFlash +50 150 Flash +0 0 70 /PSqrPad SetFlash +-1050 150 Flash +0 0 70 /PRndPad SetFlash +-950 150 Flash +0 0 60 /PRndPad SetFlash +950 3524 Flash +1026 3612 Flash +950 3700 Flash +0 0 70 /PSqrPad SetFlash +-1200 1600 Flash +0 0 70 /PRndPad SetFlash +-1100 1700 Flash +-1200 1800 Flash +300 1700 Flash +-100 1700 Flash +200 1300 Flash +600 1300 Flash +-700 2300 Flash +-300 2300 Flash +-700 4200 Flash +-1100 4200 Flash +1100 3200 Flash +700 3200 Flash +-700 2500 Flash +-300 2500 Flash +-700 2100 Flash +-300 2100 Flash +-800 2100 Flash +-1200 2100 Flash +600 1100 Flash +200 1100 Flash +0 0 70 /PSqrPad SetFlash +1200 2450 Flash +0 0 70 /PRndPad SetFlash +1100 2350 Flash +1200 2250 Flash +-100 1900 Flash +300 1900 Flash +0 1500 Flash +400 1500 Flash +0 0 70 /PSqrPad SetFlash +-900 1600 Flash +0 0 70 /PRndPad SetFlash +-800 1600 Flash +-700 1600 Flash +-600 1600 Flash +-500 1600 Flash +-400 1600 Flash +-300 1600 Flash +-300 1900 Flash +-400 1900 Flash +-500 1900 Flash +-600 1900 Flash +-700 1900 Flash +-800 1900 Flash +-900 1900 Flash +0 0 70 /PSqrPad SetFlash +200 2200 Flash +0 0 70 /PRndPad SetFlash +300 2200 Flash +400 2200 Flash +500 2200 Flash +600 2200 Flash +700 2200 Flash +800 2200 Flash +900 2200 Flash +900 2500 Flash +800 2500 Flash +700 2500 Flash +600 2500 Flash +500 2500 Flash +400 2500 Flash +300 2500 Flash +200 2500 Flash +0 0 70 /PSqrPad SetFlash +200 3900 Flash +0 0 70 /PRndPad SetFlash +300 3900 Flash +400 3900 Flash +500 3900 Flash +600 3900 Flash +700 3900 Flash +800 3900 Flash +900 3900 Flash +1000 3900 Flash +1100 3900 Flash +1100 4200 Flash +1000 4200 Flash +900 4200 Flash +800 4200 Flash +700 4200 Flash +600 4200 Flash +500 4200 Flash +400 4200 Flash +300 4200 Flash +200 4200 Flash +0 0 70 /PSqrPad SetFlash +-1000 3100 Flash +0 0 70 /PRndPad SetFlash +-900 3100 Flash +-800 3100 Flash +-700 3100 Flash +-600 3100 Flash +-500 3100 Flash +-400 3100 Flash +-300 3100 Flash +-300 3400 Flash +-400 3400 Flash +-500 3400 Flash +-600 3400 Flash +-700 3400 Flash +-800 3400 Flash +-900 3400 Flash +-1000 3400 Flash +0 0 80 /PRndPad SetFlash +900 800 Flash +1100 800 Flash +1000 800 Flash +0 0 187 /PRndPad SetFlash +1000 1550 Flash +0 0 70 /PRndPad SetFlash +0 4000 Flash +0 4200 Flash +0 0 260 /PRndPad SetFlash +-1100 450 Flash +1100 450 Flash +0 0 70 /PRndPad SetFlash +1100 3400 Flash +700 3400 Flash +0 0 65 /PRndPad SetFlash +-200 2350 Flash +-200 1750 Flash +200 1400 Flash +0 0 65 /PRndPad SetFlash +300 1100 Flash +0 0 65 /PRndPad SetFlash +175 3300 Flash +0 0 65 /PRndPad SetFlash +1000 2650 Flash +0 0 65 /PRndPad SetFlash +-450 2100 Flash +0 0 65 /PRndPad SetFlash +-650 2600 Flash +-100 2600 Flash +-100 2250 Flash +0 0 65 /PRndPad SetFlash +800 1800 Flash +0 0 65 /PRndPad SetFlash +700 1900 Flash +0 0 65 /PRndPad SetFlash +600 1700 Flash +0 0 65 /PRndPad SetFlash +500 1600 Flash +0 0 65 /PRndPad SetFlash +0 4100 Flash +900 4100 Flash +0 0 65 /PRndPad SetFlash +800 3000 Flash +0 0 65 /PRndPad SetFlash +600 3700 Flash +0 0 65 /PRndPad SetFlash +450 2700 Flash +-400 2700 Flash +-400 2300 Flash +0 0 65 /PRndPad SetFlash +350 3800 Flash +0 0 65 /PRndPad SetFlash +-850 3700 Flash +0 0 65 /PRndPad SetFlash +400 1300 Flash +0 0 65 /PRndPad SetFlash +-1050 1050 Flash +0 0 65 /PRndPad SetFlash +0 4475 Flash +75 4000 Flash +1000 4000 Flash +0 0 65 /PRndPad SetFlash +950 3200 Flash +0 0 65 /PRndPad SetFlash +850 1200 Flash +-600 1200 Flash +0 0 65 /PRndPad SetFlash +-550 3900 Flash +-350 3900 Flash +0 0 65 /PRndPad SetFlash +-800 4300 Flash +0 0 65 /PRndPad SetFlash +-750 4350 Flash +0 0 65 /PRndPad SetFlash +400 3400 Flash +grestore +showpage diff --git a/contrib/xntpd/gadget/sst0126.lpr b/contrib/xntpd/gadget/sst0126.lpr new file mode 100644 index 0000000000..c3f19867cd --- /dev/null +++ b/contrib/xntpd/gadget/sst0126.lpr @@ -0,0 +1,1118 @@ +%!PS-Adobe-2.0 +%%Title: PADS Postscript Driver Header +%%Creator: Andy Montalvo, 18 Lupine St., Lowell, MA 01851 +%%CreationDate: 06/08/90 +%%For: CAD Software, Littleton, MA +%%EndComments +%%BeginProcSet: Markers 1.0 0 +% marker attributes +/MAttr_Width 1 def +/MAttr_Size 0 def +/MAttr_Type /M1 def +% procedures +/M1 { %def +% draw marker 1: plus +% Stack: - M1 - + -2 0 rmoveto + 4 0 rlineto + -2 2 rmoveto + 0 -4 rlineto +} bind def +/M2 { %def +% draw marker 2: cross +% Stack: - M2 - + -2 -2 rmoveto + 4 4 rlineto + -4 0 rmoveto + 4 -4 rlineto +} bind def +/M3 { %def +% draw marker 3: square +% Stack: - M3 - + 0 2 rlineto + 2 0 rlineto + 0 -4 rlineto + -4 0 rlineto + 0 4 rlineto + 2 0 rlineto +} bind def +/M4 { %def +% draw marker 4: diamond +% Stack: - M4 - + 0 2 rlineto + 2 -2 rlineto + -2 -2 rlineto + -2 2 rlineto + 2 2 rlineto +} bind def +/M5 { %def +% draw marker 5: hourglass +% Stack: - M5 - + 2 2 rlineto + -4 0 rlineto + 4 -4 rlineto + -4 0 rlineto + 2 2 rlineto +} bind def +/M6 { %def +% draw marker 6: bowtie +% Stack: - M6 - + 2 2 rlineto + 0 -4 rlineto + -4 4 rlineto + 0 -4 rlineto + 2 2 rlineto +} bind def +/M7 { %def +% draw marker 7: small plus (goes with char marker) +% Stack: - M7 - + -1 0 rmoveto + 2 0 rlineto + -1 1 rmoveto + 0 -2 rlineto +} bind def +/Marker { %def +% Command from driver: draw marker +% STACK: x y Marker - + MAttr_Size 0 gt + { + gsave + moveto + MAttr_Size 4 div dup scale + MAttr_Type load exec + 4 MAttr_Size div dup scale + MAttr_Width setlinewidth + stroke + grestore + } if +} def +%%EndProcSet: Markers 1.0 0 +%%BeginProcSet: Lib 1.0 0 +/sg { %def +% Command from driver: set the gray scale 0 - 100 +% STACK: greylevel sg + 100 div dup setgray /glev exch def +} bind def +/Circle { %def +% draw a circle +% STACK: x y radius Circle - + 0 360 arc +} bind def +/RndAper { %def +% select a round aperture +% STACK: - RndAper - + 1 setlinejoin + 1 setlinecap +} bind def +/SqrAper { %def +% select a square aperture +% STACK: - SqrAper - + 0 setlinejoin + 2 setlinecap +} bind def +/Line { %def +% draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] Line - + 3 1 roll + moveto + true + exch + % This pushes the x then the y then does lineto + { exch { false } { lineto true } ifelse } forall + pop +} bind def +/Clipto { %def +% set clipping rectangle from 0,0 to new values +% STACK: x y Clipto - + 0 0 moveto + dup 0 exch lineto + 2 copy lineto + pop + 0 lineto + closepath + clip + newpath +} bind def +/Clip4 { %def +% set clipping rectangle from xmin,ymin to xmax,ymax +% STACK: xmin ymin xmax ymax Clip4 - + 4 copy pop pop moveto + 4 copy pop exch lineto pop + 2 copy lineto + exch pop exch pop lineto + closepath + clip + newpath +} bind def +%%EndProcSet: Lib 1.0 0 +%%BeginProcSet: Lines 1.0 0 +% line attributes % +/LAttr_Width 1 def +% line procedures +/PLine { %def +% Cammand from driver: draw a set of connected lines +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + LAttr_Width setlinewidth + stroke +} bind def % PLine +/Char { %def +% Command from driver: draw a character at the current position +% STACK: type x y stroke_array Char - +% stroke array -- [ stroke1 stroke2 ... stroken ] +% stroke -- connected staight lines +% type = 0 if text 1 if marker + gsave + 4 1 roll + translate + 0 eq { TAttr_Width } { MAttr_Width } ifelse setlinewidth + { + dup length 2 gt + { + dup dup 0 get exch 1 get % get starting point + 3 -1 roll % put x y before array + dup length 2 sub 2 exch getinterval % delete first items from array + Line + stroke + } + { + aload pop currentlinewidth 2 div Circle fill + } ifelse + } forall + grestore +} bind def % Char +/PArc { %def +% Command from driver: draw an arc +% STACK: x y radius startangle deltaangle Arc - + 10 div exch 10 div exch + 2 copy pop add + arc + LAttr_Width setlinewidth + stroke +} bind def +/PCircle { %def +% Command from driver: draw an circle +% STACK: x y radius PCircle - + Circle + LAttr_Width setlinewidth + stroke +} bind def +%%EndProcSet: Lines 1.0 0 +%%BeginProcSet: Polygon 1.0 0 +% polygon attributes % +/PAttr_ExtWidth 1 def +/PAttr_IntWidth 1 def +/PAttr_Grid 1 def +% polygon procedures +/LoopSet { %def +% set up for loop condition +% STACK: start end LoopSet low gridwidth high + 2 copy lt { exch } if + % make grid line up to absolute coordinates + PAttr_Grid div truncate PAttr_Grid mul exch + PAttr_Grid exch +} bind def +/Hatch { %def +% draw cross hatch pattern in current path +% STACK: - Hatch - + pathbbox + /ury exch def + /urx exch def + /lly exch def + /llx exch def + clip + newpath + llx urx LoopSet + { % x loop + dup lly exch ury moveto lineto + } for + lly ury LoopSet + { % y loop + llx exch dup urx exch moveto lineto + } for + PAttr_IntWidth setlinewidth + stroke +} bind def +/PPoly { %def +% Command from driver: draw a plygon +% STACK: x1 y1 [ x2 y2 ... xn yn ] PLine - + Line + closepath + gsave + PAttr_IntWidth PAttr_Grid ge {fill} {Hatch} ifelse + grestore + PAttr_ExtWidth setlinewidth + stroke +} bind def +%%EndProcSet: Polygon 1.0 0 +%%BeginProcSet: Text 1.0 0 +% text attributes % +/TAttr_Mirr 0 def +/TAttr_Orient 0 def +/TAttr_Width 1 def +% text procedures +/Text { %def +% Command from driver: Draw text +% STACK: x y width string Text - + gsave + 4 2 roll + translate + TAttr_Mirr 0 gt + { + -1 1 scale + } if + TAttr_Orient rotate + 0 0 moveto + dup length dup 1 gt + { + exch dup stringwidth pop + 4 -1 roll + exch 2 copy + lt + { + div 1 scale show + } + { + sub + 3 -1 roll 1 sub div + 0 3 -1 roll ashow + } + ifelse + } + { + pop + show + } ifelse + grestore +} bind def +%%EndProcSet: Text 1.0 0 +%%BeginProcSet: FlashSymbols 1.0 0 +% flash symbol attributes % +/FAttr_Type /PRndPad def +/FAttr_Width 0 def +/FAttr_Length 1 def +/FAttr_Orient 0 def +% flash symbol procedures +/PRndPad { %def +% Command from driver: draw an circular pad +% STACK: - PCirclePad - + FAttr_Width dup scale + 0 0 .5 Circle + fill +} bind def +/PSqrPad { %def +% Draw an Square pad +% STACK: - PRectPad - + FAttr_Width dup scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/PRectPad { %def +% Draw an rectangular pad +% STACK: - PRectPad - + FAttr_Length FAttr_Width scale + .5 .5 moveto + -.5 .5 lineto + -.5 -.5 lineto + .5 -.5 lineto + closepath + fill +} bind def +/POvalPad { %def +% Draw an oval pad +% STACK: - POvalPad - + FAttr_Width setlinewidth + FAttr_Length FAttr_Width sub 2 div dup + neg 0 moveto + 0 lineto + RndAper + stroke +} bind def +/Anl { %def + 0 0 .5 Circle + fill + FAttr_Length FAttr_Width lt + { % inner circle + 0 0 + FAttr_Length 0 gt { FAttr_Length FAttr_Width div } { .5 } ifelse + 2 div Circle + 1 setgray + fill + glev setgray + } if +} bind def +/PAnlPad { %def +% Draw an annular pad +% STACK: - PAnlPad - + FAttr_Width dup scale + Anl +} bind def +/PRelPad { %def +% Draw an thermal relief pad +% STACK: - PRelPad - + PAnlPad + 1 setgray + .17 setlinewidth + 0 setlinecap % the x + 45 rotate + .5 0 moveto -.5 0 lineto + 0 .5 moveto 0 -.5 lineto + stroke + glev setgray +} bind def +/Flash { %def +% Command from driver: Flash a symbol +% STACK: x y Flash - + FAttr_Width 0 gt + { + gsave + translate + FAttr_Orient rotate + FAttr_Type load exec + grestore + } if +} def +%%EndProcSet: FlashSymbols 1.0 0 +%%BeginProcSet: SetAttr 1.0 0 +/SetLine { %def +% Set the width of the lines +% STACK: linewidth SetLine - + /LAttr_Width exch def + RndAper +} bind def +/SetPoly { %def +% Set attribute of polygon +% STACK: external_width internal_grid_width grid_spacing SetPoly - + /PAttr_Grid exch def + /PAttr_IntWidth exch def + /PAttr_ExtWidth exch def + RndAper +} bind def +/SetFlash { %def +% Set Attributed of flash pad +% STACK: orientation_angle length width aperture_type SetFlash - + /FAttr_Type exch def + FAttr_Type /PSqrPad eq FAttr_Type /PRectPad eq or + { SqrAper } { RndAper } ifelse + /FAttr_Width exch def + /FAttr_Length exch def + /FAttr_Orient exch 10 div def +} bind def +/SetMkr { %def +% Set attributes of markers +% STACK: linewidth size type SetMkr - + /MAttr_Type exch def + /MAttr_Size exch def + /MAttr_Width exch def + RndAper +} bind def +/SetText1 { %def +% Set attributes of text +% STACK: fontname height orient mirror SetMkr - + /TAttr_Mirr exch def + /TAttr_Orient exch 10 div def + exch findfont exch scalefont setfont + RndAper +} bind def +/SetText2 { %def +% Set attributes of text +% STACK: linewidth height mirror orient SetMkr - + /TAttr_Width exch def + RndAper +} bind def +%%EndProcSet: SetAttr 1.0 0 +%%BeginProcSet: Initialize 1.0 0 +/Init { %def +% Initialize the driver +% STACK: Init - + 72 1000 div dup scale % Scale to 1/1000 inch + 250 250 translate % make origin 1/4 inch from bottom left + 1.5 setmiterlimit 1 RndAper % set line defaults + 0 setgray % set color default + /glev 0 def +} def +%%EndProcSet: Initialize 1.0 0 +%%EndProlog +/Helvetica findfont 12 scalefont setfont +35 760 moveto +(gadget.job - Fri Aug 21 03:35:07 1992) show +gsave +Init +8000 10500 Clipto +4015 2626 translate +0 rotate +1 1 div dup scale +75 sg +50 sg +25 sg +0 sg +10 SetLine +-1350 4700 [ -1350 4900 ] PLine +-1350 4900 [ -1150 4900 ] PLine +10 SetLine +1150 4900 [ 1350 4900 ] PLine +1350 4900 [ 1350 4700 ] PLine +10 SetLine +1150 0 [ 1350 0 ] PLine +1350 0 [ 1350 200 ] PLine +10 SetLine +-1350 200 [ -1350 0 ] PLine +-1350 0 [ -1150 0 ] PLine +10 SetLine +-1050 1400 [ -1050 1200 ] PLine +-1050 1200 [ -1150 1200 ] PLine +-1150 1200 [ -1150 1400 ] PLine +-1150 1400 [ -1050 1400 ] PLine +10 SetLine +-50 3300 [ -100 3300 ] PLine +10 SetLine +250 3235 [ -50 3235 ] PLine +-50 3235 [ -50 3365 ] PLine +-50 3365 [ 250 3365 ] PLine +250 3365 [ 250 3235 ] PLine +10 SetLine +300 3300 [ 250 3300 ] PLine +10 SetLine +250 3100 [ 300 3100 ] PLine +10 SetLine +-50 3165 [ 250 3165 ] PLine +250 3165 [ 250 3035 ] PLine +250 3035 [ -50 3035 ] PLine +-50 3035 [ -50 3165 ] PLine +10 SetLine +-100 3100 [ -50 3100 ] PLine +10 SetLine +-50 3500 [ -100 3500 ] PLine +10 SetLine +250 3435 [ -50 3435 ] PLine +-50 3435 [ -50 3565 ] PLine +-50 3565 [ 250 3565 ] PLine +250 3565 [ 250 3435 ] PLine +10 SetLine +300 3500 [ 250 3500 ] PLine +10 SetLine +-1150 3700 [ -1200 3700 ] PLine +10 SetLine +-450 3575 [ -1150 3575 ] PLine +-1150 3575 [ -1150 3825 ] PLine +-1150 3825 [ -450 3825 ] PLine +-450 3825 [ -450 3575 ] PLine +10 SetLine +-400 3700 [ -450 3700 ] PLine +10 SetLine +-850 1300 [ -900 1300 ] PLine +10 SetLine +-150 1175 [ -850 1175 ] PLine +-850 1175 [ -850 1425 ] PLine +-850 1425 [ -150 1425 ] PLine +-150 1425 [ -150 1175 ] PLine +10 SetLine +-100 1300 [ -150 1300 ] PLine +10 SetLine +550 2800 [ 600 2800 ] PLine +10 SetLine +-150 2925 [ 550 2925 ] PLine +550 2925 [ 550 2675 ] PLine +550 2675 [ -150 2675 ] PLine +-150 2675 [ -150 2925 ] PLine +10 SetLine +-200 2800 [ -150 2800 ] PLine +10 SetLine +-450 2800 [ -400 2800 ] PLine +10 SetLine +-1150 2925 [ -450 2925 ] PLine +-450 2925 [ -450 2675 ] PLine +-450 2675 [ -1150 2675 ] PLine +-1150 2675 [ -1150 2925 ] PLine +10 SetLine +-1200 2800 [ -1150 2800 ] PLine +10 SetLine +0 2150 [ 0 2100 ] PLine +10 SetLine +65 2450 [ 65 2150 ] PLine +65 2150 [ -65 2150 ] PLine +-65 2150 [ -65 2450 ] PLine +-65 2450 [ 65 2450 ] PLine +10 SetLine +0 2500 [ 0 2450 ] PLine +10 SetLine +-1200 3050 [ -1200 3000 ] PLine +10 SetLine +-1135 3350 [ -1135 3050 ] PLine +-1135 3050 [ -1265 3050 ] PLine +-1265 3050 [ -1265 3350 ] PLine +-1265 3350 [ -1135 3350 ] PLine +10 SetLine +-1200 3400 [ -1200 3350 ] PLine +10 SetLine +-950 2250 [ -1150 2250 ] PLine +-1150 2250 [ -1150 2350 ] PLine +-1150 2350 [ -950 2350 ] PLine +-950 2350 [ -950 2250 ] PLine +10 SetLine +-1150 2550 [ -950 2550 ] PLine +-950 2550 [ -950 2450 ] PLine +-950 2450 [ -1150 2450 ] PLine +-1150 2450 [ -1150 2550 ] PLine +10 SetLine +850 2850 [ 1050 2850 ] PLine +1050 2850 [ 1050 2750 ] PLine +1050 2750 [ 850 2750 ] PLine +850 2750 [ 850 2850 ] PLine +10 SetLine +500 1900 [ 450 1900 ] PLine +10 SetLine +1200 1775 [ 500 1775 ] PLine +500 1775 [ 500 2025 ] PLine +500 2025 [ 1200 2025 ] PLine +1200 2025 [ 1200 1775 ] PLine +10 SetLine +1250 1900 [ 1200 1900 ] PLine +10 SetLine +-1150 900 [ -1200 900 ] PLine +10 SetLine +-150 725 [ -1150 725 ] PLine +-1150 725 [ -1150 1075 ] PLine +-1150 1075 [ -150 1075 ] PLine +-150 1075 [ -150 725 ] PLine +10 SetLine +-100 900 [ -150 900 ] PLine +10 SetLine +-1050 4000 [ -1100 4000 ] PLine +10 SetLine +-750 3935 [ -1050 3935 ] PLine +-1050 3935 [ -1050 4065 ] PLine +-1050 4065 [ -750 4065 ] PLine +-750 4065 [ -750 3935 ] PLine +10 SetLine +-700 4000 [ -750 4000 ] PLine +10 SetLine +750 3000 [ 700 3000 ] PLine +10 SetLine +1050 2935 [ 750 2935 ] PLine +750 2935 [ 750 3065 ] PLine +750 3065 [ 1050 3065 ] PLine +1050 3065 [ 1050 2935 ] PLine +10 SetLine +1100 3000 [ 1050 3000 ] PLine +10 SetLine +-250 3750 [ -50 3750 ] PLine +-50 3750 [ -50 3650 ] PLine +-50 3650 [ -250 3650 ] PLine +-250 3650 [ -250 3750 ] PLine +10 SetLine +200 900 [ 150 900 ] PLine +10 SetLine +270 950 [ 270 850 ] PLine +10 SetLine +200 850 [ 200 950 ] PLine +200 950 [ 500 950 ] PLine +500 950 [ 500 850 ] PLine +500 850 [ 200 850 ] PLine +10 SetLine +500 900 [ 550 900 ] PLine +10 SetLine +250 850 [ 250 950 ] PLine +10 SetLine +260 850 [ 260 950 ] PLine +10 SetLine +600 3700 [ 650 3700 ] PLine +10 SetLine +530 3650 [ 530 3750 ] PLine +10 SetLine +600 3750 [ 600 3650 ] PLine +600 3650 [ 300 3650 ] PLine +300 3650 [ 300 3750 ] PLine +300 3750 [ 600 3750 ] PLine +10 SetLine +300 3700 [ 250 3700 ] PLine +10 SetLine +550 3750 [ 550 3650 ] PLine +10 SetLine +540 3750 [ 540 3650 ] PLine +10 SetLine +-750 550 100 PCircle +10 SetLine +0 550 100 PCircle +10 SetLine +750 550 100 PCircle +10 SetLine +768 5000 [ 768 5248 ] PLine +768 5248 [ -768 5248 ] PLine +-768 5248 [ -768 5000 ] PLine +10 SetLine +1058 4900 [ -1058 4900 ] PLine +10 SetLine +1058 5000 [ 1058 4408 ] PLine +1058 4408 [ -1058 4408 ] PLine +-1058 4408 [ -1058 5000 ] PLine +-1058 5000 [ 1058 5000 ] PLine +10 SetLine +1058 5000 [ -1058 5000 ] PLine +10 SetLine +768 4900 [ 768 4408 ] PLine +10 SetLine +-768 4900 [ -768 4408 ] PLine +10 SetLine +900 200 [ 1100 200 ] PLine +1100 200 [ 1100 100 ] PLine +1100 100 [ 900 100 ] PLine +900 100 [ 900 200 ] PLine +10 SetLine +-100 200 [ 100 200 ] PLine +100 200 [ 100 100 ] PLine +100 100 [ -100 100 ] PLine +-100 100 [ -100 200 ] PLine +10 SetLine +-1100 200 [ -900 200 ] PLine +-900 200 [ -900 100 ] PLine +-900 100 [ -1100 100 ] PLine +-1100 100 [ -1100 200 ] PLine +10 SetLine +916 3493 [ 900 3456 ] PLine +900 3456 [ 939 3442 ] PLine +939 3442 [ 953 3477 ] PLine +10 SetLine +988 3612 140 PCircle +10 SetLine +-1000 1529 [ -1039 1490 ] PLine +10 SetLine +-1000 1490 [ -1000 1910 ] PLine +-1000 1910 [ -1300 1910 ] PLine +-1300 1910 [ -1300 1490 ] PLine +-1300 1490 [ -1000 1490 ] PLine +10 SetLine +200 1730 [ 200 1670 ] PLine +200 1670 [ 0 1670 ] PLine +0 1670 [ 0 1730 ] PLine +0 1730 [ 200 1730 ] PLine +10 SetLine +200 1700 [ 260 1700 ] PLine +10 SetLine +0 1700 [ -50 1700 ] PLine +10 SetLine +300 1270 [ 300 1330 ] PLine +300 1330 [ 500 1330 ] PLine +500 1330 [ 500 1270 ] PLine +500 1270 [ 300 1270 ] PLine +10 SetLine +300 1300 [ 240 1300 ] PLine +10 SetLine +500 1300 [ 550 1300 ] PLine +10 SetLine +-600 2270 [ -600 2330 ] PLine +-600 2330 [ -400 2330 ] PLine +-400 2330 [ -400 2270 ] PLine +-400 2270 [ -600 2270 ] PLine +10 SetLine +-600 2300 [ -660 2300 ] PLine +10 SetLine +-400 2300 [ -350 2300 ] PLine +10 SetLine +-800 4230 [ -800 4170 ] PLine +-800 4170 [ -1000 4170 ] PLine +-1000 4170 [ -1000 4230 ] PLine +-1000 4230 [ -800 4230 ] PLine +10 SetLine +-800 4200 [ -740 4200 ] PLine +10 SetLine +-1000 4200 [ -1050 4200 ] PLine +10 SetLine +1000 3230 [ 1000 3170 ] PLine +1000 3170 [ 800 3170 ] PLine +800 3170 [ 800 3230 ] PLine +800 3230 [ 1000 3230 ] PLine +10 SetLine +1000 3200 [ 1060 3200 ] PLine +10 SetLine +800 3200 [ 750 3200 ] PLine +10 SetLine +-600 2470 [ -600 2530 ] PLine +-600 2530 [ -400 2530 ] PLine +-400 2530 [ -400 2470 ] PLine +-400 2470 [ -600 2470 ] PLine +10 SetLine +-600 2500 [ -660 2500 ] PLine +10 SetLine +-400 2500 [ -350 2500 ] PLine +10 SetLine +-600 2070 [ -600 2130 ] PLine +-600 2130 [ -400 2130 ] PLine +-400 2130 [ -400 2070 ] PLine +-400 2070 [ -600 2070 ] PLine +10 SetLine +-600 2100 [ -660 2100 ] PLine +10 SetLine +-400 2100 [ -350 2100 ] PLine +10 SetLine +-900 2130 [ -900 2070 ] PLine +-900 2070 [ -1100 2070 ] PLine +-1100 2070 [ -1100 2130 ] PLine +-1100 2130 [ -900 2130 ] PLine +10 SetLine +-900 2100 [ -840 2100 ] PLine +10 SetLine +-1100 2100 [ -1150 2100 ] PLine +10 SetLine +500 1130 [ 500 1070 ] PLine +500 1070 [ 300 1070 ] PLine +300 1070 [ 300 1130 ] PLine +300 1130 [ 500 1130 ] PLine +10 SetLine +500 1100 [ 560 1100 ] PLine +10 SetLine +300 1100 [ 250 1100 ] PLine +10 SetLine +1000 2521 [ 1039 2560 ] PLine +10 SetLine +1000 2560 [ 1000 2140 ] PLine +1000 2140 [ 1300 2140 ] PLine +1300 2140 [ 1300 2560 ] PLine +1300 2560 [ 1000 2560 ] PLine +10 SetLine +0 1870 [ 0 1930 ] PLine +0 1930 [ 200 1930 ] PLine +200 1930 [ 200 1870 ] PLine +200 1870 [ 0 1870 ] PLine +10 SetLine +0 1900 [ -60 1900 ] PLine +10 SetLine +200 1900 [ 250 1900 ] PLine +10 SetLine +100 1470 [ 100 1530 ] PLine +100 1530 [ 300 1530 ] PLine +300 1530 [ 300 1470 ] PLine +300 1470 [ 100 1470 ] PLine +10 SetLine +100 1500 [ 40 1500 ] PLine +10 SetLine +300 1500 [ 350 1500 ] PLine +10 SetLine +-950 1650 [ -250 1650 ] PLine +-250 1650 [ -250 1850 ] PLine +-250 1850 [ -950 1850 ] PLine +-950 1850 [ -950 1775 ] PLine +-950 1775 [ -900 1775 ] PLine +-900 1775 [ -900 1725 ] PLine +-900 1725 [ -950 1725 ] PLine +-950 1725 [ -950 1650 ] PLine +10 SetLine +150 2250 [ 950 2250 ] PLine +950 2250 [ 950 2450 ] PLine +950 2450 [ 150 2450 ] PLine +150 2450 [ 150 2375 ] PLine +150 2375 [ 200 2375 ] PLine +200 2375 [ 200 2325 ] PLine +200 2325 [ 150 2325 ] PLine +150 2325 [ 150 2250 ] PLine +10 SetLine +150 3950 [ 1150 3950 ] PLine +1150 3950 [ 1150 4150 ] PLine +1150 4150 [ 150 4150 ] PLine +150 4150 [ 150 4075 ] PLine +150 4075 [ 200 4075 ] PLine +200 4075 [ 200 4025 ] PLine +200 4025 [ 150 4025 ] PLine +150 4025 [ 150 3950 ] PLine +10 SetLine +-1050 3150 [ -250 3150 ] PLine +-250 3150 [ -250 3350 ] PLine +-250 3350 [ -1050 3350 ] PLine +-1050 3350 [ -1050 3275 ] PLine +-1050 3275 [ -1000 3275 ] PLine +-1000 3275 [ -1000 3225 ] PLine +-1000 3225 [ -1050 3225 ] PLine +-1050 3225 [ -1050 3150 ] PLine +10 SetLine +800 1075 [ 800 1675 ] PLine +800 1675 [ 1200 1675 ] PLine +1200 1675 [ 1200 1075 ] PLine +1200 1075 [ 800 1075 ] PLine +10 SetLine +875 1075 [ 875 825 ] PLine +875 825 [ 925 825 ] PLine +925 825 [ 925 1075 ] PLine +10 SetLine +1075 1075 [ 1075 825 ] PLine +1075 825 [ 1125 825 ] PLine +1125 825 [ 1125 1075 ] PLine +10 SetLine +975 1075 [ 975 825 ] PLine +975 825 [ 1025 825 ] PLine +1025 825 [ 1025 1075 ] PLine +10 SetLine +996 1549 75 PCircle +10 SetLine +800 1425 [ 1200 1425 ] PLine +10 SetLine +-100 4200 [ -25 4200 ] PLine +10 SetLine +-100 3900 [ -100 4300 ] PLine +-100 4300 [ -500 4300 ] PLine +-500 4300 [ -500 3900 ] PLine +-500 3900 [ -100 3900 ] PLine +10 SetLine +-100 4000 [ -25 4000 ] PLine +10 SetLine +-1100 450 100 PCircle +10 SetLine +1100 450 100 PCircle +10 SetLine +1000 3430 [ 1000 3370 ] PLine +1000 3370 [ 800 3370 ] PLine +800 3370 [ 800 3430 ] PLine +800 3430 [ 1000 3430 ] PLine +10 SetLine +1000 3400 [ 1060 3400 ] PLine +10 SetLine +800 3400 [ 750 3400 ] PLine +10 SetText2 +0 -1175 1225 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -1175 1279 [ [ -53 0 -56 4 -65 11 0 11 ] ] Char +0 -1175 1310 [ [ -65 29 -65 6 -37 4 -40 6 -43 13 -43 20 -40 27 -34 31 -25 34 -18 31 -9 29 -3 25 0 18 0 11 -3 4 -6 2 -12 0 ] ] Char +10 SetText2 +0 75 3375 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 129 3375 [ [ 27 56 25 62 18 65 13 65 6 62 2 53 0 37 0 21 2 9 6 3 13 0 15 0 22 3 27 9 29 18 29 21 27 31 22 37 15 40 13 40 6 37 2 31 0 21 ] ] Char +10 SetText2 +0 75 3175 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 129 3175 [ [ 31 65 9 0 ] [ 0 65 31 65 ] ] Char +10 SetText2 +0 75 3575 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 129 3575 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -825 3850 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -771 3850 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -575 1450 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -521 1450 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -490 1450 [ [ 27 56 25 62 18 65 13 65 6 62 2 53 0 37 0 21 2 9 6 3 13 0 15 0 22 3 27 9 29 18 29 21 27 31 22 37 15 40 13 40 6 37 2 31 0 21 ] ] Char +10 SetText2 +0 125 2950 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 179 2950 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 210 2950 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -825 2950 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -771 2950 [ [ 29 43 27 34 22 28 15 25 13 25 6 28 2 34 0 43 0 46 2 56 6 62 13 65 15 65 22 62 27 56 29 43 29 28 27 12 22 3 15 0 11 0 4 3 2 9 ] ] Char +10 SetText2 +0 -100 2250 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -100 2304 [ [ -53 0 -56 4 -65 11 0 11 ] ] Char +0 -100 2335 [ [ -65 4 -65 29 -40 15 -40 22 -37 27 -34 29 -25 31 -18 31 -9 29 -3 25 0 18 0 11 -3 4 -6 2 -12 0 ] ] Char +10 SetText2 +0 -1275 3200 [ [ -50 34 -56 31 -62 27 -65 22 -65 13 -62 9 -56 4 -50 2 -40 0 -25 0 -15 2 -9 4 -3 9 0 13 0 22 -3 27 -9 31 -15 34 ] ] Char +0 -1275 3254 [ [ -50 2 -53 2 -59 4 -62 6 -65 11 -65 20 -62 25 -59 27 -53 29 -46 29 -40 27 -31 22 0 0 0 31 ] ] Char +10 SetText2 +0 -1100 2375 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -1046 2375 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -1015 2375 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1100 2575 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -1046 2575 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -1015 2575 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 900 2875 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 954 2875 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 985 2875 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 800 2050 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 854 2050 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 885 2050 [ [ 31 65 9 0 ] [ 0 65 31 65 ] ] Char +10 SetText2 +0 -675 1100 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -621 1100 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 -590 1100 [ [ 11 65 4 62 2 56 2 50 4 43 9 40 18 37 25 34 29 28 31 21 31 12 29 6 27 3 20 0 11 0 4 3 2 6 0 12 0 21 2 28 6 34 13 37 22 40 27 43 29 50 29 56 27 62 20 65 11 65 ] ] Char +10 SetText2 +0 -925 4075 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -871 4075 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 875 3075 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 929 3075 [ [ 11 65 4 62 2 56 2 50 4 43 9 40 18 37 25 34 29 28 31 21 31 12 29 6 27 3 20 0 11 0 4 3 2 6 0 12 0 21 2 28 6 34 13 37 22 40 27 43 29 50 29 56 27 62 20 65 11 65 ] ] Char +10 SetText2 +0 -200 3775 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 ] ] Char +0 -146 3775 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 325 975 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 377 975 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 450 3775 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 502 3775 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -775 675 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 -732 675 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -50 675 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 -7 675 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 700 675 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 743 675 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 -1175 4650 [ [ 22 65 22 15 20 6 18 3 13 0 9 0 4 3 2 6 0 15 0 21 ] ] Char +0 -1132 4650 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1125 125 [ [ 0 65 0 0 27 0 ] ] Char +0 1172 125 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 1222 125 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 1274 125 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 125 125 [ [ 0 65 0 0 27 0 ] ] Char +0 172 125 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 222 125 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 274 125 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -875 125 [ [ 0 65 0 0 27 0 ] ] Char +0 -828 125 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -778 125 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -726 125 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1075 3425 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] [ 20 12 34 -6 ] ] Char +0 1131 3425 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1075 1475 [ [ 0 -65 0 0 ] [ 0 -65 -20 -65 -27 -62 -29 -59 -31 -53 -31 -46 -29 -40 -27 -37 -20 -34 0 -34 ] [ -15 -34 -31 0 ] ] Char +0 -1127 1475 [ [ -11 -65 -4 -62 -2 -56 -2 -50 -4 -43 -9 -40 -18 -37 -25 -34 -29 -28 -31 -21 -31 -12 -29 -6 -27 -3 -20 0 -11 0 -4 -3 -2 -6 0 -12 0 -21 -2 -28 -6 -34 -13 -37 -22 -40 -27 -43 -29 -50 -29 -56 -27 -62 -20 -65 -11 -65 ] ] Char +10 SetText2 +0 25 1750 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 77 1750 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 108 1750 [ [ 13 65 6 62 2 53 0 37 0 28 2 12 6 3 13 0 18 0 25 3 29 12 31 28 31 37 29 53 25 62 18 65 13 65 ] ] Char +10 SetText2 +0 350 1350 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 402 1350 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 433 1350 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -550 2350 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -498 2350 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 -925 4250 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -873 4250 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 850 3250 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 902 3250 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -550 2550 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -498 2550 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -550 2150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -498 2150 [ [ 27 56 25 62 18 65 13 65 6 62 2 53 0 37 0 21 2 9 6 3 13 0 15 0 22 3 27 9 29 18 29 21 27 31 22 37 15 40 13 40 6 37 2 31 0 21 ] ] Char +10 SetText2 +0 -1025 2150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 -973 2150 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 350 1150 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 402 1150 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 433 1150 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 1200 2125 [ [ 0 -65 0 0 ] [ 0 -65 -20 -65 -27 -62 -29 -59 -31 -53 -31 -46 -29 -40 -27 -37 -20 -34 0 -34 ] [ -15 -34 -31 0 ] ] Char +0 1148 2125 [ [ -31 -65 -9 0 ] [ 0 -65 -31 -65 ] ] Char +10 SetText2 +0 50 1950 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 102 1950 [ [ 29 43 27 34 22 28 15 25 13 25 6 28 2 34 0 43 0 46 2 56 6 62 13 65 15 65 22 62 27 56 29 43 29 28 27 12 22 3 15 0 11 0 4 3 2 9 ] ] Char +10 SetText2 +0 150 1550 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 202 1550 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 233 1550 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -675 1950 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 -623 1950 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 450 2550 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 502 2550 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 500 4275 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 552 4275 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -675 3450 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 -623 3450 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 950 1700 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 1002 1700 [ [ 29 65 6 65 4 37 6 40 13 43 20 43 27 40 31 34 34 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -350 4325 [ [ 0 65 31 0 ] [ 31 65 0 0 ] ] Char +0 -298 4325 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1225 600 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 -1169 600 [ [ 0 65 0 0 ] [ 31 65 31 0 ] [ 0 34 31 34 ] ] Char +0 -1117 600 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1125 600 [ [ 0 65 0 0 ] [ 0 65 18 0 ] [ 36 65 18 0 ] [ 36 65 36 0 ] ] Char +0 1181 600 [ [ 0 65 0 0 ] [ 31 65 31 0 ] [ 0 34 31 34 ] ] Char +0 1233 600 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 800 3450 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 852 3450 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 883 3450 [ [ 22 65 0 21 34 21 ] [ 22 65 22 0 ] ] Char +10 SetText2 +0 -225 875 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +10 SetText2 +0 1125 1875 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +10 SetText2 +0 -125 2775 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +10 SetText2 +0 -1125 2775 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +10 SetText2 +0 -525 3675 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +10 SetText2 +0 -700 4325 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -750 275 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 34 25 ] [ 22 25 34 25 ] ] Char +0 -696 275 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -640 275 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -588 275 [ [ 34 50 31 56 27 62 22 65 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 34 25 ] [ 22 25 34 25 ] ] Char +0 -534 275 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 -484 275 [ [ 15 65 15 0 ] [ 0 65 31 65 ] ] Char +0 -380 275 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 ] [ 0 34 20 34 27 31 29 28 31 21 31 12 29 6 27 3 20 0 0 0 ] ] Char +0 -328 275 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +0 -272 275 [ [ 0 65 31 0 ] [ 31 65 0 0 ] ] Char +0 -168 275 [ [ 0 28 40 28 ] ] Char +0 -55 275 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 -3 275 [ [ 0 65 0 0 ] [ 0 65 31 0 ] [ 31 65 31 0 ] ] Char +0 49 275 [ [ 0 65 0 0 ] ] Char +0 69 275 [ [ 0 65 18 0 ] [ 36 65 18 0 ] ] Char +0 177 275 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +0 233 275 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] ] Char +0 335 275 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 387 275 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +0 437 275 [ [ 0 65 0 0 27 0 ] ] Char +0 484 275 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 540 275 [ [ 0 65 11 0 ] [ 22 65 11 0 ] [ 22 65 34 0 ] [ 45 65 34 0 ] ] Char +0 605 275 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 661 275 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 46 29 40 27 37 20 34 0 34 ] [ 15 34 31 0 ] ] Char +0 713 275 [ [ 0 65 0 0 ] [ 0 65 29 65 ] [ 0 34 18 34 ] [ 0 0 29 0 ] ] Char +10 SetText2 +0 125 600 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 177 600 [ [ 0 65 0 0 ] [ 0 65 20 65 27 62 29 59 31 53 31 43 29 37 27 34 20 31 0 31 ] ] Char +0 229 600 [ [ 31 56 27 62 20 65 11 65 4 62 0 56 0 50 2 43 4 40 9 37 22 31 27 28 29 25 31 18 31 9 27 3 20 0 11 0 4 3 0 9 ] ] Char +10 SetText2 +0 500 600 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +0 561 600 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 592 600 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 -625 600 [ [ 18 65 0 0 ] [ 18 65 36 0 ] [ 6 21 29 21 ] ] Char +0 -569 600 [ [ 0 65 0 18 2 9 6 3 13 0 18 0 25 3 29 9 31 18 31 65 ] ] Char +0 -517 600 [ [ 0 65 0 0 ] [ 0 65 15 65 22 62 27 56 29 50 31 40 31 25 29 15 27 9 22 3 15 0 0 0 ] ] Char +0 -465 600 [ [ 0 65 0 0 ] ] Char +0 -445 600 [ [ 13 65 9 62 4 56 2 50 0 40 0 25 2 15 4 9 9 3 13 0 22 0 27 3 31 9 34 15 36 25 36 40 34 50 31 56 27 62 22 65 13 65 ] ] Char +10 SetText2 +0 1100 2075 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1050 1925 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 875 675 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 1075 675 [ [ 2 50 2 53 4 59 6 62 11 65 20 65 25 62 27 59 29 53 29 46 27 40 22 31 0 0 31 0 ] ] Char +10 SetText2 +0 975 675 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -925 1475 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 175 3775 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 -1050 2975 [ [ 0 53 4 56 11 65 11 0 ] ] Char +10 SetText2 +0 625 4325 [ [ 0 53 4 56 11 65 11 0 ] ] Char +0 656 4325 [ [ 4 65 29 65 15 40 22 40 27 37 29 34 31 25 31 18 29 9 25 3 18 0 11 0 4 3 2 6 0 12 ] ] Char +10 SetText2 +0 -825 1275 [ [ 20 56 20 0 ] [ 0 28 40 28 ] ] Char +grestore +showpage diff --git a/contrib/xntpd/hints/README b/contrib/xntpd/hints/README new file mode 100644 index 0000000000..f7fdb72aaa --- /dev/null +++ b/contrib/xntpd/hints/README @@ -0,0 +1,12 @@ +README file for directory ./hints of the NTP Version 3 distribution + +This directory contains files with hints for particular architectures. + +All files are derived from the earlier README. files. +I have tried to adjust these files to match the current state of +affairs of this xntp distribution. The information contained in the +files may or may not be completely correct. But these files contain +valuable hints for specific architectures. + +Frank Kardel 93/12/3 + diff --git a/contrib/xntpd/hints/aux b/contrib/xntpd/hints/aux new file mode 100644 index 0000000000..aa7ccbb2c4 --- /dev/null +++ b/contrib/xntpd/hints/aux @@ -0,0 +1,159 @@ +Last revision: 09-Aug-1993 + +Included in this distribution of XNTP V3 is a configuration file suitable +for use under Apple's A/UX Version 3.0.x While it may work with +other versions, it has not been tested. To make the executables follow +the steps outlined below. + +*** NOTE: You must have gcc installed to successfully compile the current +distribution; the native cc supplied with A/UX will NOT correctly compile +this source. See the FAQ in comp.unix.aux for places to obtain gcc from +and how to install it. + +Now, you need to create the makefiles: + + % make refconf + +First of all, you need to edit Config.local to make sure that BINDIR is +correct for where you wish the programs to be "installed". The default +(and what I use) is /usr/local/etc. Make sure that DEFS_LOCAL and +CLOCKDEFS are commented out! + + +After this is done (you should be told that your system is A/UX 3), make +xntpd (the options to 'gcc' are held in compilers/aux3.gcc): + + % make + +I do not normally use the `make install' option and so have not verified its +compatibility with A/UX. Rather, I pull out each of the executables and +place them in the locally appropriate locations. + +At this point you need to set things up so that 'xntpd' is started upon +boot-up. You can do this in 1 of 2 ways: either add entries in /etc/inittab +or create and use an /etc/rc.local file. + +By default, A/UX doesn't have one, so you'll need to add the following to +/etc/inittab: + + net6:2:wait:/etc/syslogd # set to "wait" to run a syslog daemon ++ jmj0:2:wait:/etc/rc.local 1>/dev/syscon 2>&1 # Local stuff + dbg2::wait:/etc/telinit v # turn off init's verbose mode + +Now, the look of /etc/rc.local is as follows: + + #!/bin/sh + : + : rc.local + : + # @(#)Copyright Apple Computer 1987 Version 1.17 of rc.sh on 91/11/08 15:56:21 (ATT 1.12) + + + # Push line discipline/set the device so it will print + /etc/line_sane 1 + echo " " + echo "Entering rc.local..." + + set `/bin/who -r` + if [ "$7" = 2 ] + then + /bin/echo " now setting the time..." + /usr/local/etc/ntpdate -s -b + sleep 5 + # + # start up xntpd if we want + # + if [ -f /etc/ntp.conf ] + then + /bin/echo " setting tick and tickadj..." + /usr/local/etc/tickadj -t 16672 -a 54 + sleep 5 + /bin/echo " starting xntpd..." + /usr/local/etc/xntpd <&- > /dev/null 2>&1 + sleep 5 + fi + # + fi + + echo "Leaving rc.local..." + +There are a few things to notice about the above: + + o When run, 'ntpdate' forces your clock to the time returned by the + host(s) specified by (you'll need to replace this + be the IP address(es) of your timehosts. This is good since it gets + things close to start off with. + + o 'tickadj' is also called. This does two things: changes the + default value of 'tick' (which the the amount of time, in ms, that + is added to the clock every 1/60 seconds) and changes the value + of 'tickadj' which the the amount that is added or subtracted + from 'tickadj' when adjtime() is called. + + Now Mac clocks are pretty bad and tend to be slow. Sooo, instead of + having A/UX add the default of 16666ms every 1/60th of a second, + you want it to add more so that it keeps better time. The above + value works for me but your "best" value may be different and will + likely require some fooling around to find the best value. + + A/UX's default value of 'tickadj' is 1666 which is too big for + 'xntpd'... so it also needs to be adjusted. + + +Finally, before A/UX and 'xntpd' will work happily together, you need to +patch the kernel. This is due to the fact that A/UX attempts to keep the +UNIX-software clock and the Mac-hardware clock in sync. Now both of these +are too good. Also, 'xntpd' will be attempting to adjust the software +clock as well, so having A/UX muck around with it is asking for headaches. +What you therefore need to do is tell the kernel _not_ to sync the s/w clock +with the h/w one. This is done using 'adb'. The following is a shell script +that will do the patch for you: + + #! /bin/sh + adb -w /unix < (as in default.375 or default.850) + 3. default + + * Ok, make sure adjtimed is running (just start it up for now with + "/usr/local/etc/adjtimed"). Using -z as an option will get you + a usage message. + + * Now start up xntpd and watch it work. + + * Make sure that adjtimed gets started at boot right before xntpd. + We do this in /etc/netbsdsrc. They must both run as root !! + +Possible problems ? + + * On some 320's and 835's we have had to run adjtimed with "-p 45" or + so to get rid of syslog messages about "last adjust did not finish". + +Anything else ... just drop me a line at ken@sdd.hp.com diff --git a/contrib/xntpd/hints/notes-xntp-v3 b/contrib/xntpd/hints/notes-xntp-v3 new file mode 100644 index 0000000000..ba027f2105 --- /dev/null +++ b/contrib/xntpd/hints/notes-xntp-v3 @@ -0,0 +1,119 @@ +Notes for NTP Version 3 + +This version operates in much the same manner as Version 2 with the +following changes and additions: + +1. The protocol machinery operates in conformance with the RFC1305 NTP + Version 3 specification. The most visible characteristic of this + version is that the poll intervals for all polls, even selected + ones, is significantly increased. This is especially desirable when + serving a large client population. This implementation supports + previous versions as non-configured peers; for version-2 configured + peers a "version 2" keyword should be included on the "peer" line. + +2. The configuration file has a new keyword: statfile , where + is the name of a statistics file." When present, each clock + update generates an entry of the form: + + . + + where is the modified Julian day, . is the time of + day, is the peer address and is the peer status. + The , and are the measured offset, delay and + dispersion, respectively, of the peer clock relative to the local + clock. About once per day the current file is closed and a new one + created with names ., where starts at one and + increments for each new generation. + +3. A number of additional platforms are supported. See ./Config file + for details. + +4. A driver for the TrueTime 468DC GOES Synchronized Clock is + included. This driver (refclock_goes.c) should also work for other + TrueTime radio clocks, since all use the same format. + +5. A replacement driver for the Spectracom 8170 WWVB Synchronized + Clock is included. This driver (refclock_wwvb.c) (a) does not + require a 1-pulse-per-second signal, (b) supports both format 0 + (original 8170) and format 2 (Netclock/2 and upgraded 8170), (c) + can be connected to more than one computer and (d) automatically + compensates for all serial baud rates. + +6. A driver for the German time/frequency station DCF77 is included. + This requires a special STREAMS module. + +7. In Version 2 special line-discipline modules were required for the + CHU and WWVB drivers. This code continues to work in Version 3, + although it is no longer needed for the WWVB driver. However, this + code does not work under STREAMS, as used in SunOS 4.1.1. + Equivalent STREAMS modules are supplied with Version 3. + +8. Support for an external 1-pulse-per-second (pps) signal is + provided. The signal is connected to a serial port (see + xntpd/ntp_loopfilter.c for details). When present the leading edge + of the pulse establishes the on-time epoch within an interval + established by the selected radio clock or other NTP time server. + Use of the pps is indicated when the tattletale displayed by ntpq + changes from "*" to "o". + +9. The clock-selection and poll-update procedures have been modified + slightly in order to achieve better performance on high speed LANs + with compromise in performance on typical WANs. + +10. In order to comply with U.S. Commerce Department regulations, the DES + encryption routine lib/authdes.c cannot be exported. For exportable + versions of this distribution a DES-encrypted version of this routine + lib/authdes.c.des is included along with an unencrypted version + lib/authdes.c.export, which allows normal operation, but without the + NTP authentication feature. Further information is available in the + lib/authdes.c.export file. + +11. As an alternative to the DES-based authentication mechanism, an + implementation of the RSA Message Digest 5 algorithm is provided. + (see applicable copyright information in the library files). + +12. A driver for the Magnavox MX4200 GPS clock. + +13. A STREAMS module which captures carrier-detect data-lead transitions to + connect a precision source of 1-pps, yet avoid the ugly overhead in the + usual STREAMS processing. See the ppsclock subdirectory. + +14. Support for the Apple A/UX operating system and enhanced support for the + Hewlet-Packard HP/UX operating system. See the various README and Config + files for further information. + +See the COPYRIGHT file for authors and copyright information. Note that some +modules in this distribution contain copyright information that supersedes +the copyright information in that file. + +If I missed something or neglected to give due credit, please advise. + +David L. Mills +University of Delaware +31 May 1992, amended 23 July 1992, 25 October 1992 + +Bugs and notes + +A bug in the original tty_clk_STREAMS.c module has been fixed. + +The poll-interval randomization feature of poll_update (in +xntpd/ntp_proto.c) has been extended to apply when the poll interval is +increased, as well as reduced. This spreads the update messages in time +and helps avoid unpleasant bursts of messages. + +In the clock_select algorithm the peers selected for combining are +limited to those survivors at the lowest stratum, not the entire list. +This helps avoid whiplash when large numbers of peers are at the same +stratum. + +The number formerly displayed by ntpq as "compliance" is now the time +constant of integration. + +The DNS resolver xntpd/ntp_intres.c is now integrated into xntpd, making +configuration of multiple hosts easier. + +System and peer event are now written to the system log at priority +LOG_INFO. + +The leap-second code was fixed to avoid broadcasting leap warnings on +all except the last day of June and December. diff --git a/contrib/xntpd/hints/parse b/contrib/xntpd/hints/parse new file mode 100644 index 0000000000..d2523515e8 --- /dev/null +++ b/contrib/xntpd/hints/parse @@ -0,0 +1,105 @@ +Compilation: + Usual thing: rm -f Config.local ; make for vanilla + make refconf for reference clock (e. g. DCF77) + +Directory contents: + + hints/PARSE - this file + + xntpd/refclock_parse.c + - reference clock support for DCF77/GPS in xntp + parse/parse.c + - Reference clock data parser framework + parse/parse_conf.c + - parser configuration (clock types) + parse/clk_meinberg.c + - Meinberg clock formats (DCF U/A 31, PZF 535, GPS166) + parse/clk_schmid.c + - Schmid receiver (DCF77) + parse/clk_rawdcf.c + - 100/200ms pulses via 50 Baud line (DCF77) + parse/clk_dcf7000.c + - ELV DCF7000 (DCF77) + parse/clk_trimble.c + - Trimble SV6 GPS receiver + + If you want to add new clock types please check + with kardel@informatik.uni-erlangen.de. These files + implement the conversion of RS232 data streams into + timing information used by refclock_parse.c which is + mostly generic except for NTP configuration constants. + + parse/Makefile.kernel + - *SIMPLE* makefile to build a loadable STREAMS + module for SunOS 4.x / SunOS 5.x systems + + parse/parsestreams.c + - SUN Streams module (loadable) for radio clocks + This streams module is designed for SunOS 4.1.X. + + parse/parsesolaris.c + - SUN Streams module (loadable) for radio clocks. + This streams module is designed for SunOS 5.x + Beware this is still new - so it might crash + your machine (we have seen it working, though). + + parse/parsetest.c + - simple test program for STREAMS module. Its so simple, + that it doesn't even set TTY-modes, thus they got to + be correct on startup - works for Meinberg receivers + + parse/testdcf.c + - test program for raw DCF77 (100/200ms pulses) + receivers + + include/parse.h - interface to "parse" module and more + include/parse_conf.h + - interface to "parse" configuration + + include/sys/parsestreams.h + - STREAMS specific definitions + + scripts/support + - scripts (perl & sh) for statistics and rc startup + the startup scripts are used in Erlangen for + starting the daemon on a variety of Suns and HPs + and for Reference Clock startup on Suns + These scripts may or may not be helpful to you. + +Supported clocks: + Meinberg DCF U/A 31 + Meinberg PZF535/TCXO (Software revision PZFUERL 4.6) + Meinberg PZF535/OCXO (Software revision PZFUERL 4.6) + Meinberg GPS166 (Software version for Uni-Erlangen) + ELV DCF7000 (not recommended - casual/emergency use only) + Conrad DCF77 receiver (email: time@informatik.uni-erlangen.de) + + level converter + TimeBrick (email: time@informatik.uni-erlangen.de) + Schmid Receiver Kit + Trimble SV6 GPS receiver + +Addresses: + Meinberg Funkuhren + Auf der Landwehr 22 + 31812 Bad Pyrmont + Germany + Tel.: 05281/20 18 + FAX: 05281/60 81 80 + + ELV Kundenservice + Postfach 1000 + 26787 Leer + Germany + Tel.: 0491/60 08 88 + + Walter Schmidt + Eichwisrain 14 + 8634 Hombrechtikon + Switzerland + +If you have problems mail to: + + time@informatik.uni-erlangen.de + +We'll help (conditions permitting) + diff --git a/contrib/xntpd/hints/refclocks b/contrib/xntpd/hints/refclocks new file mode 100644 index 0000000000..34b2ea9344 --- /dev/null +++ b/contrib/xntpd/hints/refclocks @@ -0,0 +1,32 @@ +This is a short overview for the reference clocks currently supported +by xntp V3. (Ultimate wisdom can be obtained from xntpd/refclock_*.c +this file was derived from that information - unfortunately some comments +in the files tend to get stale - so use with caution) + +Refclock address Type +127.127.0.x no clock (fails to configure) +127.127.1.x local clock - use local clock as reference +127.127.2.x no clock (fails to configure) +127.127.3.x PSTI 1010/1020 WWV Clock +127.127.4.x SPECTRACOM WWVB receiver 8170 and Netclock/2 +127.127.5.x Kinimetric Truetime 468-DC GOES receiver +127.127.6.x IRIG audio decode (Sun & modified BSD audio driver) +127.127.7.x CHU Timecode (via normal receiver & Bell 103 modem) +127.127.8.x PARSE (generic driver for a bunch of DCF/GPS clocks + can be extended for other clocks too) + 8.0-3 Meinberg PZF535/TCXO + 8.4-7 Meinberg PZF535/OCXO + 8.8-11 Meinberg DCF U/A 31 + 8.12-15 ELV DCF7000 + 8.16-19 Walter Schmid DCF receiver (Kit) + 8.20-23 Conrad DCF77 receiver module + level converter (Kit) + 8.24-27 TimeBrick (limited availability ask + time@informatik.uni-erlangen.de) + 8.28-31 Meinberg GPS166 + 8.32-35 Trimble SV6 GPS receiver +127.127.9.x MX4200 GPS receiver +127.127.10.x Austron 2201A GPS Timing Receiver +127.127.11.x Kinemetrics Truetime OM-DC OMEGA Receiver +127.127.12.x KSI/Odetecs TPRO-S IRIG-B / TPRO-SAT GPS +127.127.13.x Leitch: CSD 5300 Master Clock System Driver +127.127.14.x MSFEES diff --git a/contrib/xntpd/hints/rs6000 b/contrib/xntpd/hints/rs6000 new file mode 100644 index 0000000000..8561ac29b1 --- /dev/null +++ b/contrib/xntpd/hints/rs6000 @@ -0,0 +1,56 @@ +15.7.1993 +xntp3 compiles now again on AIX. I have disabled prototyping and added +the switch -D_NO_PROTO which disables prototyping in the system include +files. + +Matthias Ernst maer@nmr.lpc.ethz.ch +-------------------------------------------------------------------------------- +Xntp version 3 now support the cc compiler for AIX. +The Config.aix will now use cc by default. You can still compile xntp +with the bsd compiler by changing "COMP= cc" to "COMP= bsdcc" and +and removing the "-DSTUPID_SIGNAL" option from the "DEFS" option. + +xntp and tickadj was also modified so that the value of tickadj is read +form the kernel and can be set by tickadj. For now I would not set +tickadj below 40 us. + +Bill Jones +jones@chpc.utexas.edu +------------------------------------------------------------------------------- + +This is a modified version of xntp version 3 for the RS6000. It works for +AIX 3.2 and these are the same changes as have been applied tothe version 2 +implementation of xntp. It works fine for us but I have not tested all of +the features, especially the local clock support for the RS6000 is not tested +at all. + +Matthias Ernst, ETH-Zuerich, Switzerland - maer@nmr.lpc.ethz.ch + +-------------------------------------------------------------------------------- + +Here the original README.rs6000 for the version 2 implementation: + +A hacked version of xntp for the IBM RS/6000 under AIX 3.1 can be found +in xntp.rs6000.tar.Z. [ if still available at all - Frank Kardel 93/12/3 ] + +This will not work on older versions of AIX due to a kernel bug; to find +out whether you have the kernel bug, compile and run testrs6000.c (see +comments in the code for instructions). + +xntp and testrs6000 require "bsdcc" to compile. This is simply another +entry point into the xlc compiler with various options set for BSD +compatibility. If your system does not have bsdcc, do the following: + +link /bin/bsdcc to /bin/xlc + +put the following into /etc/xlc.cfg: + +* BSD compatibility +bsdcc: use = DEFLT + crt = /lib/crt0.o + mcrt = /lib/mcrt0.o + gcrt = /lib/gcrt0.o + libraries = -lbsd, -lc + proflibs = -L/lib/profiled,-L/usr/lib/profiled + options = -H512,-T512, -qlanglvl=extended, -qnoro, -D_BSD, -D_NONSTD_TYPES, -D_NO_PROTO, -tp,-B/lib/ + diff --git a/contrib/xntpd/hints/sgi b/contrib/xntpd/hints/sgi new file mode 100644 index 0000000000..5e4f7de6d5 --- /dev/null +++ b/contrib/xntpd/hints/sgi @@ -0,0 +1,74 @@ +adjtime, tick and tickadj: +-------------------------- + +The SGI value for HZ is 100 under Irix 4, with the system clock running +in nominal mode (ftimer off), so the value for tick is 10000 usec. +Tickadj is a bit more tricky because of the behaviour of adjtime(), +which seems to try to perform the correction over 100-200 seconds, with +a rate limit of 0.04 secs/sec for large corrections. Corrections of +less than 0.017 seconds generally complete in less than a second, +however. + +Some measured rates are as follows: + + Delta Rate (sec/sec) + + > 1 0.04 + 0.75 0.04 + 0.6 0.004 + 0.5 0.004 + 0.4 0.0026 + 0.3 0.0026 + 0.2 0.0013 + 0.1 0.0015 + 0.05 0.0015 + 0.02 0.0003 + 0.01 0.015 +Strange. Anyway, since adjtime will complete adjustments of less than +17msec in less than a second, whether the fast clock is on or off, I +have used a value of 150usec/tick for the tickadj value. + +Fast clock: +----------- + +I get smoother timekeeping if I turn on the fast clock, thereby making +the clock tick at 1kHz rather than 100Hz. With the fast clock off, I +see a sawtooth clock offset with an amplitude of 5msec. With it on, +the amplitude drops to 0.5msec (surprise!). This may be a consequence +of having a local reference clock which spits out the time at exactly +one-second intervals - I am probably seeing sampling aliasing between +that and the machine clock. This may all be irrelevant for machines +without a local reference clock. Fiddling with the fast clock doesn't +seem to compromise the above choices for tick and tickadj. + +I use the "ftimer" program to switch the fast clock on when the system +goes into multiuser mode, but you can set the "fastclock" flag in +/usr/sysgen/master.d/kernel to have it on by default. See ftimer(1). + +timetrim: +--------- + +Irix has a kernel variable called timetrim which adjusts the system +time increment, effectively trimming the clock frequency. Xntpd could +use this rather than adjtime() to do it's frequency trimming, but I +haven't the time to explore this. There is a utility program, +"timetrim", in the util directory which allows manipulation of the +timetrim value in both SGI and xntpd native units. You can fiddle with +default timetrim value in /usr/sysgen/master.d/kernel, but I think +that's ugly. I just use xntpd to figure out the right value for +timetrim for a particular CPU and then set it using "timetrim" when +going to multiuser mode. + +Serial I/O latency: +------------------- + +If you use a local clock on an RS-232 line, look into the kernel +configuration stuff with regard to improving the input latency (check +out /usr/sysgen/master.d/[sduart|cdsio]). I have a Kinemetrics OM-DC +hooked onto /dev/ttyd2 (the second CPU board RS-232 port) on an SGI +Crimson, and setting the duart_rsrv_duration flag to 0 improves things +a bit. + + +12 Jan 93 +Steve Clift, CSIRO Marine Labs, Hobart, Australia (clift@ml.csiro.au) diff --git a/contrib/xntpd/hints/solaris b/contrib/xntpd/hints/solaris new file mode 100644 index 0000000000..038d65f996 --- /dev/null +++ b/contrib/xntpd/hints/solaris @@ -0,0 +1,88 @@ + A quick summary of how to compile under Solaris: + + If you are running Solaris 2.0, you should upgrade to a later version of +Solaris immediately. + If you are running Solaris 2.1, you should use Config.solaris2.1 + If you are running Solaris 2.2 or later, you should use Config.solaris2.2 + + Solaris 2.1 contains fairly traditional clock code, with tick and tickadj. +Solaris 2.2 and later contains completely re-written clock code to provide +high resolution microsecond timers. A benefit of the re-written clock code +is that adjtime does not round off its adjustments, so xntp does not have to +compensate for this rounding. On Solaris 2.2 and later we #define +ADJTIME_IS_ACCURATE, and do not look for the tickadj kernel variable. + + If you are running both Solaris 2.1 and 2.2 on your net, you will need to +maintain two sets of xntp binaries. The Config.solaris2.2 file will compile +on Solaris 2.1, but the resulting binaries will not work correctly. + +ADDITIONAL NOTES FOR SOLARIS 2.1 +(by William L. Jones jones@chpc.utexas.edu) + +Since settimeofday under Solaris 2.1 only sets the seconds part of timeval +care must be used in starting xntpd. I suggest the following start +up script: + + tickadj -s -a 1000 + ntpdate -v server1 server2 + sleep 20 + ntpdate -v server1 server2 + sleep 20 + tickadj -a 200 + xntpd + +The first tickadj turns of the time of day clock and sets the tick adjust +value to 1 ms. This will insure that an adjtime value of at most 2 +seconds will complete in 20 seconds. + +The first ntpdate will set the time to within two seconds +using settimeofday or it will adjust time using adjtime. + +The first sleep insures the adjtime has completed for the first ntpdate. + +The second ntpdate will use adjtime to set the time of day since the +clock should be within 2 seconds of the correct time. + +The second tickadj set the tick adjust system value to 5 us. + +The second sleeps insure that adjtime will complete before starting +the next xntpd. + +I tried running with a tickadj of 5 us with out much success. +200 us seems to work well. + + +ADDITIONAL NOTES FOR SOLARIS 2.2 AND LATER: + You still need to turn off dosynctodr for XNTP to be able to keep accurate +time. You can either do this in the /etc/system file (consulted at boot to set +various kernel variables) by putting in the following line: +set dosynctodr=0 +or you can use the tickadj program to force the variable to 0 in the running +kernel. Fiddling with a running kernel is almost never a good idea, I'd +recommend using /etc/system. + I would recommend starting xntp from the following script, placed in +/etc/rc2.d and named S99xntpd + +#!/bin/sh + +if [ $1 = "start" ]; then + if [ -x /usr/local/bin/xntpd ]; then + echo "Starting NTP daemon, takes about 1 minute... " + # The following line is unnecessary if you turn off + # dosynctodr in /etc/system. + /usr/local/bin/tickadj -s + /usr/local/bin/ntpdate -v server1 server2 + sleep 5 + /usr/local/bin/xntpd + fi +else + if [ $1 = "stop" ]; then + pid=`/usr/bin/ps -e | /usr/bin/grep xntpd | /usr/bin/sed -e 's/^ *//' -e 's/ .*//'` + if [ "${pid}" != "" ]; then + echo "Stopping Network Time Protocol daemon " + /usr/bin/kill ${pid} + fi + fi +fi + +Denny Gentry denny@eng.sun.com diff --git a/contrib/xntpd/hints/svr4-dell b/contrib/xntpd/hints/svr4-dell new file mode 100644 index 0000000000..b6d015752d --- /dev/null +++ b/contrib/xntpd/hints/svr4-dell @@ -0,0 +1,6 @@ +Notes on the DELL SVR4. + +You should use -DSETTIMEOFDAY_BROKEN. + +Philip.Gladstone@mail.citicorp.com + diff --git a/contrib/xntpd/include/README b/contrib/xntpd/include/README new file mode 100644 index 0000000000..5127b70a1b --- /dev/null +++ b/contrib/xntpd/include/README @@ -0,0 +1,6 @@ +README file for directory ./include of the NTP Version 3 distribution + +This directory contains the include files used by most programs in this +distribution. The ./sys directory in this directory contains system +header files used by the clock discipline and STREAMS modules in the +../kernel directory. diff --git a/contrib/xntpd/include/l_stdlib.h b/contrib/xntpd/include/l_stdlib.h new file mode 100644 index 0000000000..7a4383dcd2 --- /dev/null +++ b/contrib/xntpd/include/l_stdlib.h @@ -0,0 +1,228 @@ +/* + * Proto types for machines that are not ANSI and POSIX compliant. + * This is optionaly + */ + +#ifndef _l_stdlib_h +#define _l_stdlib_h + +#if defined(NTP_POSIX_SOURCE) +#include +#endif + +#ifndef P +#if defined(__STDC__) || defined(USE_PROTOTYPES) +#define P(x) x +#else +#define P(x) () +#if !defined(const) +#define const +#endif +#endif +#endif + +/* + * Unprottyped library functions for SunOS 4.x.x + */ +#ifdef SYS_SUNOS4 +extern void closelog P((void)); +extern void openlog P((char *, int, int)); +extern void syslog P((int, char *, ...)); +extern int setlogmask P((int)); + +extern char * getpass P((char *)); + +extern int setpriority P((int ,int ,int)); + +extern long strtol P((char *, char **, int)); + +#if !defined(NTP_POSIX_SOURCE) +extern int atoi P((char *)); +extern void bcopy P((char *, char *, int)); +extern int dup2 P((int, int)); +extern int execve P((char *, char **,char **)); +extern int fork P((void)); +extern int getdtablesize P((void)); +extern int qsort P((void *, int , int, + int (*compar)(void *, void *))); +extern int rand P((void)); +extern int setpgrp P((int, int)); +extern void srand P((unsigned int)); +#endif + +#ifndef bzero /* XXX macro prototyping clash */ +extern void bzero P((char *, int)); +extern int bcmp P((char *, char *, int)); +#endif +extern char *mktemp P((char *)); + +extern int tolower P((int)); + +extern int isatty P((int)); + +extern unsigned sleep P((unsigned )); +extern unsigned int alarm P((unsigned int)); +extern int pause P((void)); + +extern int getpid P((void)); +extern int getppid P((void)); + +extern int close P((int)); +extern int ioctl P((int, int, char *)); +extern int read P((int, char *, unsigned)); +extern int rename P((char *, char *)); +extern int write P((int, char *, int)); +extern int unlink P((char *)); +extern int link P((char *, char *)); + +#ifdef FILE +extern int fclose P((FILE *)); +extern int fflush P((FILE *)); +extern int fprintf P((FILE *, char *, ...)); +extern int fputs P((char *, FILE *)); +extern int fputc P((char, FILE *)); +extern int fread P((char *, int, int, FILE *)); +extern int printf P((char *, ...)); +extern int setbuf P((FILE *, char *)); +extern int setvbuf P((FILE *, char *, int, int)); +extern int scanf P((char *, ...)); +extern int vsprintf P((char *, char *, ...)); +extern int _flsbuf P((int, FILE *)); +extern int _filbuf P((FILE *)); +extern void perror P((char *)); +#ifndef NTP_POSIX_SOURCE +extern int setlinebuf P((FILE *)); +#endif +#endif + +#ifdef _ntp_string_h +#ifdef NTP_POSIX_SOURCE /* these are builtins */ +extern char *memcpy(); +extern char *memset(); +extern int memcmp(); +#endif +#endif + +#ifdef _sys_socket_h +extern int bind P((int, struct sockaddr *, int)); +extern int connect P((int, struct sockaddr *, int)); +extern int sendto P((int, char *, int, int, struct sockaddr *, int)); +extern int setsockopt P((int, int, int, char *, int)); +extern int socket P((int, int, int)); +extern int recvfrom P((int, char *, int, int, struct sockaddr *, int *)); +#endif /* _sys_socket_h */ + +#ifdef _ntp_select_h +extern int select P((int, fd_set *, fd_set *, fd_set *, struct timeval *)); +#endif + +#ifdef _sys_time_h +extern int adjtime P((struct timeval *, struct timeval *)); +extern int setitimer P((int , struct itimerval *, struct itimerval *)); +#ifdef SYSV_TIMEOFDAY +extern int gettimeofday P((struct timeval *)); +extern int settimeofday P((struct timeval *)); +#else /* ! SYSV_TIMEOFDAY */ +extern int gettimeofday P((struct timeval *, struct timezone *)); +extern int settimeofday P((struct timeval *, struct timezone *)); +#endif /* SYSV_TIMEOFDAY */ +#endif /* _sys_time_h */ + +#ifdef __time_h +extern time_t time P((time_t *)); +#endif + +#ifdef __setjmp_h +extern int setjmp P((jmp_buf)); +extern void longjmp P((jmp_buf, int)); +#endif + +#ifdef _sys_resource_h +extern int getrusage P((int, struct rusage *)); +#endif + +#ifdef _nlist_h +extern int nlist P((char *, struct nlist *)); +#endif + +#endif /* SYS_SUNOS4 */ + +/* + * Unprototyped library functions for ULTRIX. + */ +#ifdef SYS_ULTRIX +extern int close P((int)); +extern char * getpass P((char *)); +extern int getpid P((void)); +extern int ioctl P((int, int, char *)); +extern char *mktemp P((char *)); +extern int unlink P((const char *)); +extern int link P((const char *, const char *)); + +#if defined(LOG_DEBUG) +extern void closelog P((void)); +extern void syslog P((int, char *, ...)); +#ifndef LOG_DAEMON +extern void openlog P((char *, int)); +#else +extern void openlog P((char *, int, int)); +#endif +#endif + +extern int setpriority P((int ,int ,int )); + +#ifdef SOCK_DGRAM +extern int bind P((int, struct sockaddr *, int)); +extern int connect P((int, struct sockaddr *, int)); +extern int socket P((int, int, int)); +extern int sendto P((int, char *, int, int, struct sockaddr *, int)); +extern int setsockopt P((int, int, int, char *, int)); +extern int recvfrom P((int, char *, int, int, struct sockaddr *, int *)); +#endif /* SOCK_STREAM */ + +#ifdef _TIME_H_ +extern int adjtime P((struct timeval *, struct timeval *)); +extern int select P((int, fd_set *, fd_set *, fd_set *, struct timeval *)); +extern int setitimer P((int , struct itimerval *, struct itimerval *)); +#endif /* _TIME_H_ */ + +#ifdef N_UNDF +extern int nlist P((char *, struct nlist *)); +#endif + +#ifndef NTP_POSIX_SOURCE +extern int atoi P((char *)); +extern void bcopy P((char *, char *, int)); +extern void bzero P((char *, int)); +extern int bcmp P((char *, char *, int)); +extern void bcopy P((char *, char *, int)); +extern int execve P((char *, char **,char **)); +extern int fork P((void)); +extern int getdtablesize P((void)); +extern int ran P((void)); +extern int rand P((void)); +extern void srand P((unsigned int)); +#if defined(_STDIO_H_) +extern int setlinebuf P((FILE *)); +#endif +#ifdef _TIME_H_ +extern int gettimeofday P((struct timeval *, struct timezone *)); +#endif +#endif + +#endif /* SYS_ULTIRX */ + +#if defined(__convex__) +extern char * getpass P((char *)); +#endif + +#ifdef SYS_IRIX4 +extern char * getpass P((char *)); +#endif /* IRIX4 */ + +#ifdef SYS_VAX +extern char * getpass P((char *)); +#endif /* VAX */ + +#endif /* l_stdlib_h */ + diff --git a/contrib/xntpd/include/md5.h b/contrib/xntpd/include/md5.h new file mode 100644 index 0000000000..c13f63905e --- /dev/null +++ b/contrib/xntpd/include/md5.h @@ -0,0 +1,56 @@ +/* md5.h,v 3.1 1993/07/06 01:06:44 jbj Exp + *********************************************************************** + ** md5.h -- header file for implementation of MD5 ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** + ** Revised (for MD5): RLR 4/27/91 ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#include "ntp_types.h" + +/* typedef a 32-bit type */ +typedef unsigned LONG UINT4; + +/* Data structure for MD5 (Message-Digest) computation */ +typedef struct { + UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ + UINT4 buf[4]; /* scratch buffer */ + unsigned char in[64]; /* input buffer */ + unsigned char digest[16]; /* actual digest after MD5Final call */ +} MD5_CTX; + +void MD5Init (); +void MD5Update (); +void MD5Final (); + +/* + *********************************************************************** + ** End of md5.h ** + ******************************** (cut) ******************************** + */ diff --git a/contrib/xntpd/include/mx4200.h b/contrib/xntpd/include/mx4200.h new file mode 100644 index 0000000000..5a9e49651c --- /dev/null +++ b/contrib/xntpd/include/mx4200.h @@ -0,0 +1,42 @@ +/* @(#) mx4200.h,v 3.1 1993/07/06 01:06:46 jbj Exp */ + + +/* records transmitted from extern CDU to MX 4200 */ +#define PMVXG_S_INITMODEA 0 /* initialization/mode part A */ +#define PMVXG_S_INITMODEB 1 /* initialization/mode part B*/ +#define PMVXG_S_SATHEALTH 2 /* satellite health control */ +#define PMVXG_S_DIFFNAV 3 /* differential navigation control */ +#define PMVXG_S_PORTCONF 7 /* control port configuration */ +#define PMVXG_S_GETSELFTEST 3 /* self test (request results) */ +#define PMVXG_S_RTCMCONF 16 /* RTCM port configuration */ +#define PMVXG_S_PASSTHRU 17 /* equipment port pass-thru config */ +#define PMVXG_S_RESTART 18 /* restart control */ +#define PMVXG_S_OSCPARAM 19 /* oscillator parameter */ +#define PMVXG_S_DOSELFTEST 20 /* self test (activate a test) */ +#define PMVXG_S_TRECOVCONF 23 /* time recovery configuration */ +#define PMVXG_S_RAWDATASEL 24 /* raw data port data selection */ +#define PMVXG_S_EQUIPCONF 26 /* equipment port configuration */ +#define PMVXG_S_RAWDATACONF 27 /* raw data port configuration */ + +/* records transmitted from MX 4200 to external CDU */ +#define PMVXG_D_STATUS 0 /* status */ +#define PMVXG_D_POSITION 1 /* position */ +#define PMVXG_D_OPDOPS 3 /* (optimum) DOPs */ +#define PMVXG_D_MODEDATA 4 /* mode data */ +#define PMVXG_D_SATPRED 5 /* satellite predictions */ +#define PMVXG_D_SATHEALTH 6 /* satellite health status */ +#define PMVXG_D_UNRECOG 7 /* unrecognized request response */ +#define PMVXG_D_SIGSTRLOC 8 /* sig strength & location (sats 1-4) */ +#define PMVXG_D_SPEEDHEAD 11 /* speed/heading data */ +#define PMVXG_D_OSELFTEST 12 /* (old) self-test results */ +#define PMVXG_D_SIGSTRLOC2 18 /* sig strength & location (sats 5-8) */ +#define PMVXG_D_OSCPARAM 19 /* oscillator parameter */ +#define PMVXG_D_SELFTEST 20 /* self test results */ +#define PMVXG_D_PHV 21 /* position, height & velocity */ +#define PMVXG_D_DOPS 22 /* DOPs */ +#define PMVXG_D_SOFTCONF 30 /* software configuration */ +#define PMVXG_D_DIFFGPSMODE 503 /* differential gps moding */ +#define PMVXG_D_TRECOVUSEAGE 523 /* time recovery usage */ +#define PMVXG_D_RAWDATAOUT 524 /* raw data port data output */ +#define PMVXG_D_TRECOVRESULT 828 /* time recovery results */ +#define PMVXG_D_TRECOVOUT 830 /* time recovery output message */ diff --git a/contrib/xntpd/include/ntp.h b/contrib/xntpd/include/ntp.h new file mode 100644 index 0000000000..98a083aa17 --- /dev/null +++ b/contrib/xntpd/include/ntp.h @@ -0,0 +1,681 @@ +/* ntp.h,v 3.1 1993/07/06 01:06:47 jbj Exp + * ntp.h - NTP definitions for the masses + */ + +#include "ntp_types.h" + +/* + * How to get signed characters. On machines where signed char works, + * use it. On machines where signed char doesn't work, char had better + * be signed. + */ +#if !defined(S_CHAR_DEFINED) +#if defined(NO_SIGNED_CHAR_DECL) +typedef char s_char; +#else +typedef signed char s_char; +#endif +#ifdef sequent +#undef SO_RCVBUF +#undef SO_SNDBUF +#endif +#endif + +/* + * NTP protocol parameters. See section 3.2.6 of the specification. + */ +#define NTP_VERSION ((u_char)3) /* current version number */ +#define NTP_OLDVERSION ((u_char)1) /* oldest credible version */ +#define NTP_PORT 123 /* included for sake of non-unix machines */ +#define NTP_MAXSTRATUM ((u_char)15) /* max stratum, infinity a la Bellman-Ford */ +#define NTP_MAXAGE 86400 /* one day in seconds */ +#define NTP_MAXSKEW 1 /* 1 sec, skew after NTP_MAXAGE w/o updates */ +#define NTP_SKEWINC 49170 /* skew increment for clock updates (l_f) */ +#define NTP_SKEWFACTOR 16 /* approximation of factor for peer calcs */ +#define NTP_MAXDISTANCE (1*FP_SECOND) /* max. rootdelay for synchr. */ +#define NTP_MINDPOLL 6 /* default min poll (64 sec) */ +#define NTP_MINPOLL 4 /* absolute min poll (16 sec) */ +#define NTP_MAXPOLL 10 /* actually 1<<10, or 1024 sec */ +#define NTP_MINCLOCK 3 /* minimum for outlyer detection */ +#define NTP_MAXCLOCK 10 /* maximum select list size */ +#define NTP_MINDISPERSE 0x28f /* 0.01 sec in fp format */ +#define NTP_MAXDISPERSE (16*FP_SECOND) /* maximum dispersion (fp 16) */ +#define NTP_DISPFACTOR 20 /* MAXDISPERSE as a shift */ +#define NTP_WINDOW 8 /* reachability register size */ +#define NTP_SHIFT 8 /* 8 suitable for crystal time base */ +#define NTP_MAXKEY 65535 /* maximum authentication key number */ + +/* + * Loop filter parameters. See section 5.1 of the specification. + * + * Note that these are appropriate for a crystal time base. If your + * system clock is line frequency controlled you should read the + * specification for appropriate modifications. Note that the + * loop filter code will have to change if you change CLOCK_MAX + * to be greater than or equal to 500 ms. + * + * Note these parameters have been rescaled for a time constant range from + * 0 through 10, with 2 corresoponding to the old time constant of 0. + */ +#define CLOCK_MINSTEP 900 /* step timeout (sec) */ +#define CLOCK_ADJ 0 /* log2 adjustment interval (1 sec) */ +#define CLOCK_DSCALE 20 /* skew reg. scale: unit is 2**-20 ~= 1 ppm */ +#define CLOCK_FREQ 16 /* log2 frequency weight (65536) */ +#define CLOCK_PHASE 6 /* log2 phase weight (64) */ +#define CLOCK_WEIGHTTC 5 /* log2 time constant weight (32) */ +#define CLOCK_HOLDTC 128 /* time constant hold (sec) */ + +#define CLOCK_MAX_F 0x20c49ba6 /* 128 ms, in time stamp format */ +#define CLOCK_MAX_I 0x0 /* both fractional and integral parts */ + +#define CLOCK_WAYTOOBIG 1000 /* if clock 1000 sec off, forget it */ + +/* + * Unspecified default. sys.precision defaults to -6 unless otherwise + * adjusted. + */ +#define DEFAULT_SYS_PRECISION (-6) + +/* + * Event timers are actually implemented as a sorted queue of expiry + * times. The queue is slotted, with each slot holding timers which + * expire in a 2**(NTP_MINPOLL-1) (8) second period. The timers in + * each slot are sorted by increasing expiry time. The number of + * slots is 2**(NTP_MAXPOLL-(NTP_MINPOLL-1)), or 128, to cover a time + * period of 2**NTP_MAXPOLL (1024) seconds into the future before + * wrapping. + */ +#define EVENT_TIMEOUT CLOCK_ADJ + +struct event { + struct event *next; /* next in chain */ + struct event *prev; /* previous in chain */ + struct peer *peer; /* peer this counter belongs to */ + void (*event_handler)(); /* routine to call to handle event */ + U_LONG event_time; /* expiry time of counter */ +}; + +#define TIMER_SLOTTIME (1<<(NTP_MINPOLL-1)) +#define TIMER_NSLOTS (1<<(NTP_MAXPOLL-(NTP_MINPOLL-1))) +#define TIMER_SLOT(t) (((t) >> (NTP_MINPOLL-1)) & (TIMER_NSLOTS-1)) + +/* + * TIMER_ENQUEUE() puts stuff on the timer queue. It takes as + * arguments (ea), an array of event slots, and (iev), the event + * to be inserted. This one searches the hash bucket from the + * end, and is about optimum for the timing requirements of + * NTP peers. + */ +#define TIMER_ENQUEUE(ea, iev) \ + do { \ + register struct event *ev; \ + \ + ev = (ea)[TIMER_SLOT((iev)->event_time)].prev; \ + while (ev->event_time > (iev)->event_time) \ + ev = ev->prev; \ + (iev)->prev = ev; \ + (iev)->next = ev->next; \ + (ev)->next->prev = (iev); \ + (ev)->next = (iev); \ + } while(0) + +/* + * TIMER_INSERT() also puts stuff on the timer queue, but searches the + * bucket from the top. This is better for things that do very short + * time outs, like clock support. + */ +#define TIMER_INSERT(ea, iev) \ + do { \ + register struct event *ev; \ + \ + ev = (ea)[TIMER_SLOT((iev)->event_time)].next; \ + while (ev->event_time != 0 && \ + ev->event_time < (iev)->event_time) \ + ev = ev->next; \ + (iev)->next = ev; \ + (iev)->prev = ev->prev; \ + (ev)->prev->next = (iev); \ + (ev)->prev = (iev); \ + } while(0) + +/* + * Remove an event from the queue. + */ +#define TIMER_DEQUEUE(ev) \ + do { \ + if ((ev)->next != 0) { \ + (ev)->next->prev = (ev)->prev; \ + (ev)->prev->next = (ev)->next; \ + (ev)->next = (ev)->prev = 0; \ + } \ + } while (0) + +/* + * The interface structure is used to hold the addresses and socket + * numbers of each of the interfaces we are using. + */ +struct interface { + int fd; /* socket this is opened on */ + int bfd; /* socket for receiving broadcasts */ + struct sockaddr_in sin; /* interface address */ + struct sockaddr_in bcast; /* broadcast address */ + struct sockaddr_in mask; /* interface mask */ + char name[8]; /* name of interface */ + int flags; /* interface flags */ + LONG received; /* number of incoming packets */ + LONG sent; /* number of outgoing packets */ + LONG notsent; /* number of send failures */ +}; + +/* + * Flags for interfaces + */ +#define INT_BROADCAST 1 /* can broadcast out this interface */ +#define INT_BCASTOPEN 2 /* broadcast socket is open */ +#define INT_LOOPBACK 4 /* the loopback interface */ + +/* + * Define flasher bits (tests 1 through 8 in packet procedure) + * These reveal the state at the last grumble from the peer and are + * most handy for diagnosing problems, even if not strictly a state + * variable in the spec. These are recorded in the peer structure. + */ +#define TEST1 0x01 /* duplicate packet received */ +#define TEST2 0x02 /* bogus packet received */ +#define TEST3 0x04 /* protocol unsynchronized */ +#define TEST4 0x08 /* peer delay/dispersion bounds check */ +#define TEST5 0x10 /* peer authentication failed */ +#define TEST6 0x20 /* peer clock unsynchronized */ +#define TEST7 0x40 /* peer stratum out of bounds */ +#define TEST8 0x80 /* root delay/dispersion bounds check */ + +/* + * The peer structure. Holds state information relating to the guys + * we are peering with. Most of this stuff is from section 3.2 of the + * spec. + */ +struct peer { + struct peer *next; + struct peer *ass_next; /* link pointer in associd hash */ + struct sockaddr_in srcadr; /* address of remote host */ + struct interface *dstadr; /* pointer to address on local host */ + u_char leap; /* leap indicator */ + u_char hmode; /* association mode with this peer */ + u_char pmode; /* peer's association mode */ + u_char stratum; /* stratum of remote peer */ + s_char precision; /* peer's clock precision */ + u_char ppoll; /* peer poll interval */ + u_char hpoll; /* local host poll interval */ + u_char minpoll; /* min local host poll interval */ + u_char maxpoll; /* max local host poll interval */ + u_char version; /* version number */ + u_char flags; /* peer flags */ + u_char flash; /* peer flashers (for maint) */ + u_char refclktype; /* reference clock type */ + u_char refclkunit; /* reference clock unit number */ + u_char sstclktype; /* clock type for system status word */ + s_fp rootdelay; /* distance from primary clock */ + u_fp rootdispersion; /* peer clock dispersion */ + U_LONG refid; /* peer reference ID */ + l_fp reftime; /* time of peer's last update */ + struct event event_timer; /* event queue entry */ + U_LONG keyid; /* encription key ID */ + U_LONG pkeyid; /* keyid used to encrypt last message */ + u_short associd; /* association ID, a unique integer */ + u_char unused; +/* **Start of clear-to-zero area.*** */ +/* Everything that is cleared to zero goes below here */ + u_char valid; /* valid counter */ +#define clear_to_zero valid + u_char reach; /* reachability, NTP_WINDOW bits */ + u_char unreach; /* unreachable count */ + u_short filter_nextpt; /* index into filter shift register */ + s_fp filter_delay[NTP_SHIFT]; /* delay part of shift register */ + l_fp filter_offset[NTP_SHIFT]; /* offset part of shift register */ + s_fp filter_soffset[NTP_SHIFT]; /* offset in s_fp format, for disp */ + l_fp org; /* originate time stamp */ + l_fp rec; /* receive time stamp */ + l_fp xmt; /* transmit time stamp */ +/* ***End of clear-to-zero area.*** */ +/* Everything that is cleared to zero goes above here */ + u_char filter_order[NTP_SHIFT]; /* we keep the filter sorted here */ +#define end_clear_to_zero filter_order[0] + u_fp filter_error[NTP_SHIFT]; /* error part of shift register */ + LONG update; /* base sys_clock for skew calc.s */ + s_fp delay; /* filter estimated delay */ + u_fp dispersion; /* filter estimated dispersion */ + l_fp offset; /* filter estimated clock offset */ + s_fp soffset; /* fp version of above */ + s_fp synch; /* synch distance from above */ + u_fp selectdisp; /* select dispersion */ + + /* + * Stuff related to the experimental broadcast delay + * determination code. The registers will probably go away + * later. + */ + U_LONG estbdelay; /* broadcast delay, as a ts fraction */ + + /* + * statistic counters + */ + U_LONG timereset; /* time stat counters were reset */ + U_LONG sent; /* number of updates sent */ + U_LONG received; /* number of frames received */ + U_LONG timereceived; /* last time a frame received */ + U_LONG timereachable; /* last reachable/unreachable event */ + U_LONG processed; /* processed by the protocol */ + U_LONG badauth; /* bad credentials detected */ + U_LONG bogusorg; /* rejected due to bogus origin */ + U_LONG bogusrec; /* rejected due to bogus receive */ + U_LONG bogusdelay; /* rejected due to bogus delay */ + U_LONG disttoolarge; /* rejected due to large distance */ + U_LONG oldpkt; /* rejected as duplicate packet */ + U_LONG seldisptoolarge; /* too much dispersion for selection */ + U_LONG selbroken; /* broken NTP detected in selection */ + U_LONG seltooold; /* too LONG since sync in selection */ + u_char candidate; /* position after candidate selection */ + u_char select; /* position at end of falseticker sel */ + u_char was_sane; /* set to 1 if it passed sanity check */ + u_char correct; /* set to 1 if it passed correctness check */ + u_char last_event; /* set to code for last peer error */ + u_char num_events; /* num. of events which have occurred */ +}; + +/* + * Values for peer.leap, sys_leap + */ +#define LEAP_NOWARNING 0x0 /* normal, no leap second warning */ +#define LEAP_ADDSECOND 0x1 /* last minute of day has 61 seconds */ +#define LEAP_DELSECOND 0x2 /* last minute of day has 59 seconds */ +#define LEAP_NOTINSYNC 0x3 /* overload, clock is free running */ + +/* + * Values for peer.mode + */ +#define MODE_UNSPEC 0 /* unspecified (probably old NTP version) */ +#define MODE_ACTIVE 1 /* symmetric active */ +#define MODE_PASSIVE 2 /* symmetric passive */ +#define MODE_CLIENT 3 /* client mode */ +#define MODE_SERVER 4 /* server mode */ +#define MODE_BROADCAST 5 /* broadcast mode */ +#define MODE_CONTROL 6 /* control mode packet */ +#define MODE_PRIVATE 7 /* implementation defined function */ + +#define MODE_BCLIENT 8 /* a pseudo mode, used internally */ + + +/* + * Values for peer.stratum, sys_stratum + */ +#define STRATUM_REFCLOCK ((u_char)0) /* stratum claimed by primary clock */ +#define STRATUM_PRIMARY ((u_char)1) /* host has a primary clock */ +#define STRATUM_INFIN ((u_char)NTP_MAXSTRATUM) /* infinity a la Bellman-Ford */ +/* A stratum of 0 in the packet is mapped to 16 internally */ +#define STRATUM_PKT_UNSPEC ((u_char)0) /* unspecified in packet */ +#define STRATUM_UNSPEC ((u_char)(NTP_MAXSTRATUM+(u_char)1)) /* unspecified */ + +/* + * Values for peer.flags + */ +#define FLAG_CONFIG 0x1 /* association was configured */ +#define FLAG_AUTHENABLE 0x2 /* this guy needs authentication */ +#define FLAG_UNUSED 0x4 /* (not used) */ +#define FLAG_DEFBDELAY 0x8 /* using default bdelay */ +#define FLAG_AUTHENTIC 0x10 /* last message was authentic */ +#define FLAG_REFCLOCK 0x20 /* this is actually a reference clock */ +#define FLAG_SYSPEER 0x40 /* this is one of the selected peers */ +#define FLAG_PREFER 0x80 /* this is the preferred peer */ + +/* + * Definitions for the clear() routine. We use bzero() to clear + * the parts of the peer structure which go to zero. These are + * used to calculate the start address and length of the area. + */ +#define CLEAR_TO_ZERO(p) ((char *)&((p)->clear_to_zero)) +#define END_CLEAR_TO_ZERO(p) ((char *)&((p)->end_clear_to_zero)) +#define LEN_CLEAR_TO_ZERO (END_CLEAR_TO_ZERO((struct peer *)0) \ + - CLEAR_TO_ZERO((struct peer *)0)) +/* + * Reference clock identifiers (for pps signal) + */ +#define PPSREFID "PPS " /* used when pps controls stratum > 1 */ + +/* + * Reference clock types. Added as necessary. + */ +#define REFCLK_NONE 0 /* unknown or missing */ +#define REFCLK_LOCALCLOCK 1 /* external (e.g., ACTS) */ +#define REFCLK_WWV_HEATH 2 /* Heath GC-1000 WWV/H */ +#define REFCLK_WWV_PST 3 /* PST/Traconex 1020 WWV/H */ +#define REFCLK_WWVB_SPECTRACOM 4 /* Spectracom 8170/Netclock WWVB */ +#define REFCLK_GOES_TRUETIME 5 /* TrueTime 468-DC GOES */ +#define REFCLK_IRIG_AUDIO 6 /* IRIG-B audio decoder */ +#define REFCLK_CHU 7 /* scratchbuilt CHU (Canada) */ +#define REFCLK_PARSE 8 /* generic driver (usually DCF77,GPS) */ +#define REFCLK_GPS_MX4200 9 /* Magnavox MX4200 GPS */ +#define REFCLK_GPS_AS2201 10 /* Austron 2201A GPS */ +#define REFCLK_OMEGA_TRUETIME 11 /* TrueTime OM-DC OMEGA */ +#define REFCLK_IRIG_TPRO 12 /* KSI/Odetics TPRO-S IRIG */ +#define REFCLK_ATOM_LEITCH 13 /* Leitch CSD 5300 Master Clock */ +#define REFCLK_MSF_EES 14 /* reserved for Piete Brooks */ + +/* + * We tell reference clocks from real peers by giving the reference + * clocks an address of the form 127.127.t.u, where t is the type and + * u is the unit number. We define some of this here since we will need + * some sanity checks to make sure this address isn't interpretted as + * that of a normal peer. + */ +#define REFCLOCK_ADDR 0x7f7f0000 /* 127.127.0.0 */ +#define REFCLOCK_MASK 0xffff0000 /* 255.255.0.0 */ + +#define ISREFCLOCKADR(srcadr) ((SRCADR(srcadr) & REFCLOCK_MASK) \ + == REFCLOCK_ADDR) + +/* + * Macro for checking for invalid addresses. This is really, really + * gross, but is needed so no one configures a host on net 127 now that + * we're encouraging it the the configuration file. + */ +#define LOOPBACKADR 0x7f000001 +#define LOOPNETMASK 0xff000000 + +#define ISBADADR(srcadr) (((SRCADR(srcadr) & LOOPNETMASK) \ + == (LOOPBACKADR & LOOPNETMASK)) \ + && (SRCADR(srcadr) != LOOPBACKADR)) + +/* + * Utilities for manipulating addresses and port numbers + */ +#define NSRCADR(src) ((src)->sin_addr.s_addr) /* address in net byte order */ +#define NSRCPORT(src) ((src)->sin_port) /* port in net byte order */ +#define SRCADR(src) (ntohl(NSRCADR((src)))) /* address in host byte order */ +#define SRCPORT(src) (ntohs(NSRCPORT((src)))) /* host port */ + +/* + * NTP packet format. The mac field is optional. It isn't really + * an l_fp either, but for now declaring it that way is convenient. + * See Appendix A in the specification. + * + * Note that all u_fp and l_fp values arrive in network byte order + * and must be converted (except the mac, which isn't, really). + */ +struct pkt { + u_char li_vn_mode; /* contains leap indicator, version and mode */ + u_char stratum; /* peer's stratum */ + u_char ppoll; /* the peer polling interval */ + s_char precision; /* peer clock precision */ + s_fp rootdelay; /* distance to primary clock */ + u_fp rootdispersion; /* clock dispersion */ + U_LONG refid; /* reference clock ID */ + l_fp reftime; /* time peer clock was last updated */ + l_fp org; /* originate time stamp */ + l_fp rec; /* receive time stamp */ + l_fp xmt; /* transmit time stamp */ + +#define MIN_MAC_LEN (sizeof(U_LONG) + 8) /* DES */ +#define MAX_MAC_LEN (sizeof(U_LONG) + 16) /* MD5 */ + + U_LONG keyid; /* key identification */ + u_char mac[MAX_MAC_LEN-sizeof(U_LONG)];/* message-authentication code */ + /*l_fp mac;*/ +}; + +/* + * Packets can come in two flavours, one with a mac and one without. + */ +#define LEN_PKT_NOMAC (sizeof(struct pkt) - MAX_MAC_LEN) + +/* + * Minimum size of packet with a MAC: has to include at least a key number. + */ +#define LEN_PKT_MAC (LEN_PKT_NOMAC + sizeof(U_LONG)) + +/* + * Stuff for extracting things from li_vn_mode + */ +#define PKT_MODE(li_vn_mode) ((u_char)((li_vn_mode) & 0x7)) +#define PKT_VERSION(li_vn_mode) ((u_char)(((li_vn_mode) >> 3) & 0x7)) +#define PKT_LEAP(li_vn_mode) ((u_char)(((li_vn_mode) >> 6) & 0x3)) + +/* + * Stuff for putting things back into li_vn_mode + */ +#define PKT_LI_VN_MODE(li, vn, md) \ + ((u_char)((((li) << 6) & 0xc0) | (((vn) << 3) & 0x38) | ((md) & 0x7))) + + +/* + * Dealing with stratum. 0 gets mapped to 16 incoming, and back to 0 + * on output. + */ +#define PKT_TO_STRATUM(s) ((u_char)(((s) == (STRATUM_PKT_UNSPEC)) ?\ + (STRATUM_UNSPEC) : (s))) + +#define STRATUM_TO_PKT(s) ((u_char)(((s) == (STRATUM_UNSPEC)) ?\ + (STRATUM_PKT_UNSPEC) : (s))) + +/* + * Format of a recvbuf. These are used by the asynchronous receive + * routine to store incoming packets and related information. + */ + +/* + * the maximum length NTP packet is a full length NTP control message with + * the maximum length message authenticator. I hate to hard-code 468 and 12, + * but only a few modules include ntp_control.h... + */ +#define RX_BUFF_SIZE (468+12+MAX_MAC_LEN) + +struct recvbuf { + struct recvbuf *next; /* next buffer in chain */ + union { + struct sockaddr_in X_recv_srcadr; + caddr_t X_recv_srcclock; + } X_from_where; +#define recv_srcadr X_from_where.X_recv_srcadr +#define recv_srcclock X_from_where.X_recv_srcclock + struct sockaddr_in srcadr; /* where packet came from */ + struct interface *dstadr; /* interface datagram arrived thru */ + l_fp recv_time; /* time of arrival */ + void (*receiver)(); /* routine to receive buffer */ + int recv_length; /* number of octets received */ + union { + struct pkt X_recv_pkt; + char X_recv_buffer[RX_BUFF_SIZE]; + } recv_space; +#define recv_pkt recv_space.X_recv_pkt +#define recv_buffer recv_space.X_recv_buffer +}; + + +/* + * Event codes. Used for reporting errors/events to the control module + */ +#define PEER_EVENT 0x80 /* this is a peer event */ + +#define EVNT_UNSPEC 0 +#define EVNT_SYSRESTART 1 +#define EVNT_SYSFAULT 2 +#define EVNT_SYNCCHG 3 +#define EVNT_PEERSTCHG 4 +#define EVNT_CLOCKRESET 5 +#define EVNT_BADDATETIM 6 +#define EVNT_CLOCKEXCPT 7 + +#define EVNT_PEERIPERR (1|PEER_EVENT) +#define EVNT_PEERAUTH (2|PEER_EVENT) +#define EVNT_UNREACH (3|PEER_EVENT) +#define EVNT_REACH (4|PEER_EVENT) +#define EVNT_PEERCLOCK (5|PEER_EVENT) + +/* + * Clock event codes + */ +#define CEVNT_NOMINAL 0 +#define CEVNT_TIMEOUT 1 +#define CEVNT_BADREPLY 2 +#define CEVNT_FAULT 3 +#define CEVNT_PROP 4 +#define CEVNT_BADDATE 5 +#define CEVNT_BADTIME 6 +#define CEVNT_MAX CEVNT_BADTIME + +/* + * Very misplaced value. Default port through which we send traps. + */ +#define TRAPPORT 18447 + + +/* + * To speed lookups, peers are hashed by the low order bits of the remote + * IP address. These definitions relate to that. + */ +#define HASH_SIZE 32 +#define HASH_MASK (HASH_SIZE-1) +#define HASH_ADDR(src) ((SRCADR((src))^(SRCADR((src))>>8)) & HASH_MASK) + + +/* + * The poll update procedure takes an extra argument which controls + * how a random perturbation is applied to peer.timer. The choice is + * to not randomize at all, to randomize only if we're going to update + * peer.timer, and to randomize no matter what (almost, the algorithm + * is that we apply the random value if it is less than the current + * timer count). + */ +#define POLL_NOTRANDOM 0 /* don't randomize */ +#define POLL_RANDOMCHANGE 1 /* if you change, change randomly */ +#define POLL_MAKERANDOM 2 /* randomize next interval */ + + +/* + * How we randomize polls. The poll interval is a power of two. + * We chose a random value which is between 1/4 and 3/4 of the + * poll interval we would normally use and which is an even multiple + * of the EVENT_TIMEOUT. The random number routine, given an argument + * spread value of n, returns an integer between 0 and (1< (b)) ? (a) : (b)) +#define min3(a,b,c) min(min((a),(b)), (c)) + + +/* + * Configuration items. These are for the protocol module (proto_config()) + */ +#define PROTO_BROADCLIENT 1 +#define PROTO_PRECISION 2 +#define PROTO_AUTHENTICATE 3 +#define PROTO_BROADDELAY 4 +#define PROTO_AUTHDELAY 5 +#define PROTO_MAXSKEW 6 +#define PROTO_SELECT 7 + +/* + * Configuration items for the loop filter + */ +#define LOOP_DRIFTCOMP 1 /* set frequency offset */ +#define LOOP_PPSDELAY 2 /* set pps delay */ +#define LOOP_PPSBAUD 3 /* set pps baud rate */ + +/* + * Configuration items for the stats printer + */ +#define STATS_FREQ_FILE 1 /* configure drift file */ +#define STATS_STATSDIR 2 /* directory prefix for stats files */ +#define STATS_PID_FILE 3 /* configure xntpd PID file */ + +#define MJD_1970 40587 /* MJD for 1 Jan 1970 */ + +/* + * Default parameters. We use these in the absense of something better. + */ +#define DEFPRECISION (-5) /* conservatively low */ +#define DEFBROADDELAY (0x020c49ba) /* 8 ms. This is round trip delay */ + +/* + * Structure used optionally for monitoring when this is turned on. + */ +struct mon_data { + struct mon_data *hash_next; /* next structure in hash list */ + struct mon_data *hash_prev; /* previous structure in hash list */ + struct mon_data *mru_next; /* next structure in MRU list */ + struct mon_data *mru_prev; /* previous structure in MRU list */ + U_LONG lasttime; /* last time data updated */ + U_LONG firsttime; /* time structure initialized */ + U_LONG count; /* count we have seen */ + U_LONG rmtadr; /* address of remote host */ + u_short rmtport; /* remote port last came from */ + u_char mode; /* mode of incoming packet */ + u_char version; /* version of incoming packet */ +}; + + +/* + * Structure used for restrictlist entries + */ +struct restrictlist { + struct restrictlist *next; /* link to next entry */ + U_LONG addr; /* host address (host byte order) */ + U_LONG mask; /* mask for address (host byte order) */ + U_LONG count; /* number of packets matched */ + u_short flags; /* accesslist flags */ + u_short mflags; /* match flags */ +}; + +/* + * Access flags + */ +#define RES_IGNORE 0x1 /* ignore if matched */ +#define RES_DONTSERVE 0x2 /* don't give him any time */ +#define RES_DONTTRUST 0x4 /* don't trust if matched */ +#define RES_NOQUERY 0x8 /* don't allow queries if matched */ +#define RES_NOMODIFY 0x10 /* don't allow him to modify server */ +#define RES_NOPEER 0x20 /* don't allocate memory resources */ +#define RES_NOTRAP 0x40 /* don't allow him to set traps */ +#define RES_LPTRAP 0x80 /* traps set by him are low priority */ + +#define RES_ALLFLAGS \ + (RES_IGNORE|RES_DONTSERVE|RES_DONTTRUST|RES_NOQUERY\ + |RES_NOMODIFY|RES_NOPEER|RES_NOTRAP|RES_LPTRAP) + +/* + * Match flags + */ +#define RESM_INTERFACE 0x1 /* this is an interface */ +#define RESM_NTPONLY 0x2 /* match ntp port only */ + +/* + * Restriction configuration ops + */ +#define RESTRICT_FLAGS 1 /* add flags to restrict entry */ +#define RESTRICT_UNFLAG 2 /* remove flags from restrict entry */ +#define RESTRICT_REMOVE 3 /* remove a restrict entry */ + + +/* + * Experimental alternate selection algorithm identifiers + */ +#define SELECT_1 1 +#define SELECT_2 2 +#define SELECT_3 3 +#define SELECT_4 4 +#define SELECT_5 5 + +/* + * Endpoint structure for the select algorithm + */ +struct endpoint { + s_fp val; /* offset of endpoint */ + int type; /* interval entry/exit */ +}; diff --git a/contrib/xntpd/include/ntp_calendar.h b/contrib/xntpd/include/ntp_calendar.h new file mode 100644 index 0000000000..fc12f0b294 --- /dev/null +++ b/contrib/xntpd/include/ntp_calendar.h @@ -0,0 +1,80 @@ +/* ntp_calendar.h,v 3.1 1993/07/06 01:06:48 jbj Exp + * ntp_calendar.h - definitions for the calendar time-of-day routine + */ + +#include "ntp_types.h" + +struct calendar { + u_short year; /* year (A.D.) */ + u_short yearday; /* day of year, 1 = January 1 */ + u_char month; /* month, 1 = January */ + u_char monthday; /* day of month */ + u_char hour; /* hour of day, midnight = 0 */ + u_char minute; /* minute of hour */ + u_char second; /* second of minute */ +}; + +/* + * Days in each month. 30 days hath September... + */ +#define JAN 31 +#define FEB 28 +#define FEBLEAP 29 +#define MAR 31 +#define APR 30 +#define MAY 31 +#define JUN 30 +#define JUL 31 +#define AUG 31 +#define SEP 30 +#define OCT 31 +#define NOV 30 +#define DEC 31 + +/* + * We deal in a 4 year cycle starting at March 1, 1900. We assume + * we will only want to deal with dates since then, and not to exceed + * the rollover day in 2036. + */ +#define SECSPERMIN (60) /* seconds per minute */ +#define MINSPERHR (60) /* minutes per hour */ +#define HRSPERDAY (24) /* hours per day */ +#define DAYSPERYEAR (365) /* days per year */ + +#define SECSPERDAY (SECSPERMIN*MINSPERHR*HRSPERDAY) +#define SECSPERYEAR (365 * SECSPERDAY) /* regular year */ +#define SECSPERLEAPYEAR (366 * SECSPERDAY) /* leap year */ + +#define MAR1900 ((JAN+FEB) * SECSPERDAY) /* no leap year in 1900 */ +#define DAYSPERCYCLE (365+365+365+366) /* 3 normal years plus leap */ +#define SECSPERCYCLE (DAYSPERCYCLE*SECSPERDAY) +#define YEARSPERCYCLE 4 + +/* + * Gross hacks. I have illicit knowlege that there won't be overflows + * here, the compiler often can't tell this. + */ +#define TIMES60(val) ((((val)<<4) - (val))<<2) /* *(16 - 1) * 4 */ +#define TIMES24(val) (((val)<<4) + ((val)<<3)) /* *16 + *8 */ +#define TIMES7(val) (((val)<<3) - (val)) /* *8 - *1 */ +#define TIMESDPERC(val) (((val)<<10) + ((val)<<8) \ + + ((val)<<7) + ((val)<<5) \ + + ((val)<<4) + ((val)<<2) + (val)) /* *big* hack */ + +/* + * Another big hack. Cycle 22 started on March 1, 1988. This is + * STARTCYCLE22 seconds after the start of cycle 0. + */ +#define CYCLE22 (22) +#define STARTCYCLE22 (U_LONG)(0xa586b500) /* 2777068800 */ +#define MAR1988 (U_LONG)(STARTCYCLE22 + (U_LONG)MAR1900) + +/* + * The length of January + February in leap and non-leap years. + */ +#define JANFEBNOLEAP ((JAN+FEB) * SECSPERDAY) +#define JANFEBLEAP ((JAN+FEBLEAP) * SECSPERDAY) + +extern void caljulian P((U_LONG, struct calendar *)); +extern U_LONG caltontp P((const struct calendar *)); + diff --git a/contrib/xntpd/include/ntp_control.h b/contrib/xntpd/include/ntp_control.h new file mode 100644 index 0000000000..89f62298d4 --- /dev/null +++ b/contrib/xntpd/include/ntp_control.h @@ -0,0 +1,249 @@ +/* ntp_control.h,v 3.1 1993/07/06 01:06:50 jbj Exp + * ntp_control.h - definitions related to NTP mode 6 control messages + */ + +#include "ntp_types.h" + +struct ntp_control { + u_char li_vn_mode; /* leap, version, mode */ + u_char r_m_e_op; /* response, more, error, opcode */ + u_short sequence; /* sequence number of request */ + u_short status; /* status word for association */ + u_short associd; /* association ID */ + u_short offset; /* offset of this batch of data */ + u_short count; /* count of data in this packet */ + u_char data[(480 + MAX_MAC_LEN)]; /* data + auth */ +}; + +/* + * Length of the control header, in octets + */ +#define CTL_HEADER_LEN 12 +#define CTL_MAX_DATA_LEN 468 + + +/* + * Limits and things + */ +#define CTL_MAXTRAPS 3 /* maximum number of traps we allow */ +#define CTL_TRAPTIME (60*60) /* time out traps in 1 hour */ +#define CTL_MAXAUTHSIZE 64 /* maximum size of an authen'ed req */ + +/* + * Decoding for the r_m_e_op field + */ +#define CTL_RESPONSE 0x80 +#define CTL_ERROR 0x40 +#define CTL_MORE 0x20 +#define CTL_OP_MASK 0x1f + +#define CTL_ISRESPONSE(r_m_e_op) (((r_m_e_op) & 0x80) != 0) +#define CTL_ISMORE(r_m_e_op) (((r_m_e_op) & 0x20) != 0) +#define CTL_ISERROR(r_m_e_op) (((r_m_e_op) & 0x40) != 0) +#define CTL_OP(r_m_e_op) ((r_m_e_op) & CTL_OP_MASK) + +/* + * Opcodes + */ +#define CTL_OP_UNSPEC 0 +#define CTL_OP_READSTAT 1 +#define CTL_OP_READVAR 2 +#define CTL_OP_WRITEVAR 3 +#define CTL_OP_READCLOCK 4 +#define CTL_OP_WRITECLOCK 5 +#define CTL_OP_SETTRAP 6 +#define CTL_OP_ASYNCMSG 7 +#define CTL_OP_UNSETTRAP 31 + +/* + * {En,De}coding of the system status word + */ +#define CTL_SST_TS_UNSPEC 0 /* time source unspecified */ +#define CTL_SST_TS_ATOM 1 /* time source calibrated atomic */ +#define CTL_SST_TS_LF 2 /* time source VLF or LF radio */ +#define CTL_SST_TS_HF 3 /* time source HF radio */ +#define CTL_SST_TS_UHF 4 /* time source UHF radio */ +#define CTL_SST_TS_LOCAL 5 /* time source LOCAL */ +#define CTL_SST_TS_NTP 6 /* time source NTP */ +#define CTL_SST_TS_UDPTIME 7 /* time source UDP/TIME */ +#define CTL_SST_TS_WRSTWTCH 8 /* time source is wristwatch */ +#define CTL_SST_TS_TELEPHONE 9 /* time source is telephone modem */ + +#define CTL_SYS_MAXEVENTS 15 + +#define CTL_SYS_STATUS(li, source, nevnt, evnt) \ + (((((unsigned short)(li))<< 14)&0xc000) | \ + (((source)<<8)&0x3f00) | \ + (((nevnt)<<4)&0x00f0) | \ + ((evnt)&0x000f)) + +#define CTL_SYS_LI(status) (((status)>>14) & 0x3) +#define CTL_SYS_SOURCE(status) (((status)>>8) & 0x3f) +#define CTL_SYS_NEVNT(status) (((status)>>4) & 0xf) +#define CTL_SYS_EVENT(status) ((status) & 0xf) + +/* + * {En,De}coding of the peer status word + */ +#define CTL_PST_CONFIG 0x80 +#define CTL_PST_AUTHENABLE 0x40 +#define CTL_PST_AUTHENTIC 0x20 +#define CTL_PST_REACH 0x10 +#define CTL_PST_UNSPEC 0x08 + +#define CTL_PST_SEL_REJECT 0 /* rejected */ +#define CTL_PST_SEL_SANE 1 /* passed sanity checks */ +#define CTL_PST_SEL_CORRECT 2 /* passed correctness checks */ +#define CTL_PST_SEL_SELCAND 3 /* passed candidate checks */ +#define CTL_PST_SEL_SYNCCAND 4 /* passed outlyer checks */ +#define CTL_PST_SEL_DISTSYSPEER 5 /* selected, distance exceeded */ +#define CTL_PST_SEL_SYSPEER 6 /* selected */ +#define CTL_PST_SEL_PPS 7 /* selected, pps signal override */ + +#define CTL_PEER_MAXEVENTS 15 + +#define CTL_PEER_STATUS(status, nevnt, evnt) \ + ((((status)<<8) & 0xff00) | \ + (((nevnt)<<4) & 0x00f0) | \ + ((evnt) & 0x000f)) + +#define CTL_PEER_STATVAL(status)(((status)>>8) & 0xff) +#define CTL_PEER_NEVNT(status) (((status)>>4) & 0xf) +#define CTL_PEER_EVENT(status) ((status) & 0xf) + +/* + * {En,De}coding of the clock status word + */ +#define CTL_CLK_OKAY 0 +#define CTL_CLK_NOREPLY 1 +#define CTL_CLK_BADFORMAT 2 +#define CTL_CLK_FAULT 3 +#define CTL_CLK_PROPAGATION 4 +#define CTL_CLK_BADDATE 5 +#define CTL_CLK_BADTIME 6 + +#define CTL_CLK_STATUS(status, event) \ + ((((status)<<8) & 0xff00) | \ + ((event) & 0x00ff)) + +/* + * Error code responses returned when the E bit is set. + */ +#define CERR_UNSPEC 0 +#define CERR_PERMISSION 1 +#define CERR_BADFMT 2 +#define CERR_BADOP 3 +#define CERR_BADASSOC 4 +#define CERR_UNKNOWNVAR 5 +#define CERR_BADVALUE 6 +#define CERR_RESTRICT 7 + +#define CERR_NORESOURCE CERR_PERMISSION /* wish there was a different code */ + + +/* + * System variables we understand + */ +#define CS_LEAP 1 +#define CS_STRATUM 2 +#define CS_PRECISION 3 +#define CS_ROOTDELAY 4 +#define CS_ROOTDISPERSION 5 +#define CS_REFID 6 +#define CS_REFTIME 7 +#define CS_POLL 8 +#define CS_PEERID 9 +#define CS_OFFSET 10 +#define CS_DRIFT 11 +#define CS_COMPLIANCE 12 +#define CS_CLOCK 13 +#define CS_LEAPIND 14 +#define CS_LEAPWARNING 15 +#define CS_PROCESSOR 16 +#define CS_SYSTEM 17 +#define CS_KEYID 18 +#define CS_REFSKEW 19 +#define CS_VERSION 20 + +#define CS_MAXCODE CS_VERSION + +/* + * Peer variables we understand + */ +#define CP_CONFIG 1 +#define CP_AUTHENABLE 2 +#define CP_AUTHENTIC 3 +#define CP_SRCADR 4 +#define CP_SRCPORT 5 +#define CP_DSTADR 6 +#define CP_DSTPORT 7 +#define CP_LEAP 8 +#define CP_HMODE 9 +#define CP_STRATUM 10 +#define CP_PPOLL 11 +#define CP_HPOLL 12 +#define CP_PRECISION 13 +#define CP_ROOTDELAY 14 +#define CP_ROOTDISPERSION 15 +#define CP_REFID 16 +#define CP_REFTIME 17 +#define CP_ORG 18 +#define CP_REC 19 +#define CP_XMT 20 +#define CP_REACH 21 +#define CP_VALID 22 +#define CP_TIMER 23 +#define CP_DELAY 24 +#define CP_OFFSET 25 +#define CP_DISPERSION 26 +#define CP_KEYID 27 +#define CP_FILTDELAY 28 +#define CP_FILTOFFSET 29 +#define CP_PMODE 30 +#define CP_RECEIVED 31 +#define CP_SENT 32 +#define CP_FILTERROR 33 +#define CP_FLASH 34 +#define CP_DISP 35 +#define CP_MAXCODE CP_DISP + +/* + * Clock variables we understand + */ +#define CC_TYPE 1 +#define CC_TIMECODE 2 +#define CC_POLL 3 +#define CC_NOREPLY 4 +#define CC_BADFORMAT 5 +#define CC_BADDATA 6 +#define CC_FUDGETIME1 7 +#define CC_FUDGETIME2 8 +#define CC_FUDGEVAL1 9 +#define CC_FUDGEVAL2 10 +#define CC_FLAGS 11 +#define CC_DEVICE 12 + +#define CC_MAXCODE CC_DEVICE + +/* + * Definition of the structure used internally to hold trap information. + * ntp_request.c wants to see this. + */ +struct ctl_trap { + struct sockaddr_in tr_addr; /* address of trap recipient */ + struct interface *tr_localaddr; /* interface to send this through */ + U_LONG tr_settime; /* time trap was set */ + U_LONG tr_count; /* async messages sent to this guy */ + U_LONG tr_origtime; /* time trap was originally set */ + U_LONG tr_resets; /* count of resets for this trap */ + u_short tr_sequence; /* trap sequence id */ + u_char tr_flags; /* trap flags */ + u_char tr_version; /* version number of trapper */ +}; + +/* + * Flag bits + */ +#define TRAP_INUSE 0x1 /* this trap is active */ +#define TRAP_NONPRIO 0x2 /* this trap is non-priority */ +#define TRAP_CONFIGURED 0x4 /* this trap was configured */ diff --git a/contrib/xntpd/include/ntp_filegen.h b/contrib/xntpd/include/ntp_filegen.h new file mode 100644 index 0000000000..263f56118f --- /dev/null +++ b/contrib/xntpd/include/ntp_filegen.h @@ -0,0 +1,51 @@ +/* + * ntp_filegen.h,v 3.6 1993/09/01 21:51:24 kardel Exp + * + * definitions for NTP file generations support + * + * + * Copyright (c) 1992 + * Rainer Pruy Friedrich-Alexander Unuiversitaet Erlangen-Nuernberg + * + * This code may be modified and used freely + * provided the credits remain intact. + */ + +#include "ntp_types.h" + +/* + * supported file generation types + */ + +#define FILEGEN_NONE 255 /* no generations - use plain file name */ +#define FILEGEN_PID 1 /* one filegen per process incarnation */ +#define FILEGEN_DAY 2 /* one filegen per day */ +#define FILEGEN_WEEK 3 /* one filegen per week */ +#define FILEGEN_MONTH 4 /* one filegen per month */ +#define FILEGEN_YEAR 5 /* one filegen per year */ +#define FILEGEN_AGE 6 /* change filegen each FG_AGE_SECS */ + +/* + * supported file generation flags + */ + +#define FGEN_FLAG_LINK 0x01 /* make a link to base name */ + +#define FGEN_FLAG_ENABLED 0x80 /* set this to really create files */ + /* without this, open is suppressed */ + +typedef struct FILEGEN + { + FILE *fp; /* file referring to current generation */ + char *prefix; /* filename prefix and basename to be used*/ + char *basename; /* for constructing filename of generation file */ + /* WARNING: must be malloced !!! will be fed to free()*/ + U_LONG id; /* id of current generation */ + u_char type; /* type of file generation */ + u_char flag; /* flags modifying processing of file generation */ + } FILEGEN; + +extern void filegen_setup P((FILEGEN *, U_LONG)); +extern void filegen_config P((FILEGEN *, char *, u_int, u_int)); +extern FILEGEN *filegen_get P((char *)); +extern void filegen_register P((char *, FILEGEN *)); diff --git a/contrib/xntpd/include/ntp_fp.h b/contrib/xntpd/include/ntp_fp.h new file mode 100644 index 0000000000..327306054b --- /dev/null +++ b/contrib/xntpd/include/ntp_fp.h @@ -0,0 +1,315 @@ +/* ntp_fp.h,v 3.1 1993/07/06 01:06:54 jbj Exp + * ntp_fp.h - definitions for NTP fixed point arithmetic + */ + +#include +#include +#include + +#include "ntp_types.h" + +/* + * NTP uses two fixed point formats. The first (l_fp) is the "long" format + * and is 64 bits LONG with the decimal between bits 31 and 32. This + * is used for time stamps in the NTP packet header (in network byte + * order) and for internal computations of offsets (in local host byte + * order). We use the same structure for both signed and unsigned values, + * which is a big hack but saves rewriting all the operators twice. Just + * to confuse this, we also sometimes just carry the fractional part in + * calculations, in both signed and unsigned forms. Anyway, an l_fp looks + * like: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Integral Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Fractional Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +typedef struct { + union { + U_LONG Xl_ui; + LONG Xl_i; + } Ul_i; + union { + U_LONG Xl_uf; + LONG Xl_f; + } Ul_f; +} l_fp; + +#define l_ui Ul_i.Xl_ui /* unsigned integral part */ +#define l_i Ul_i.Xl_i /* signed integral part */ +#define l_uf Ul_f.Xl_uf /* unsigned fractional part */ +#define l_f Ul_f.Xl_f /* signed fractional part */ + +/* + * Fractional precision (of an l_fp) is actually the number of + * bits in a long. + */ +#define FRACTION_PREC (32) + + +/* + * The second fixed point format is 32 bits, with the decimal between + * bits 15 and 16. There is a signed version (s_fp) and an unsigned + * version (u_fp). This is used to represent synchronizing distance + * and synchronizing dispersion in the NTP packet header (again, in + * network byte order) and internally to hold both distance and + * dispersion values (in local byte order). In network byte order + * it looks like: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Integer Part | Fraction Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +typedef LONG s_fp; +typedef U_LONG u_fp; + +/* + * A unit second in fp format. Actually 2**(half_the_bits_in_a_long) + */ +#define FP_SECOND (0x10000) + +/* + * Byte order conversions + */ +#define HTONS_FP(x) (htonl(x)) +#define HTONL_FP(h, n) do { (n)->l_ui = htonl((h)->l_ui); \ + (n)->l_uf = htonl((h)->l_uf); } while (0) +#define NTOHS_FP(x) (ntohl(x)) +#define NTOHL_FP(n, h) do { (h)->l_ui = ntohl((n)->l_ui); \ + (h)->l_uf = ntohl((n)->l_uf); } while (0) +#define NTOHL_MFP(ni, nf, hi, hf) \ + do { (hi) = ntohl(ni); (hf) = ntohl(nf); } while (0) +#define HTONL_MFP(hi, hf, ni, nf) \ + do { (ni) = ntohl(hi); (nf) = ntohl(hf); } while (0) + +/* funny ones. Converts ts fractions to net order ts */ +#define HTONL_UF(uf, nts) \ + do { (nts)->l_ui = 0; (nts)->l_uf = htonl(uf); } while (0) +#define HTONL_F(f, nts) do { (nts)->l_uf = htonl(f); \ + if ((f) & 0x80000000) \ + (nts)->l_i = -1; \ + else \ + (nts)->l_i = 0; \ + } while (0) + +/* + * Conversions between the two fixed point types + */ +#define MFPTOFP(x_i, x_f) (((x_i)<<16) | (((x_f)>>16)&0xffff)) +#define LFPTOFP(v) MFPTOFP((v)->l_ui, (v)->l_uf) + +#define UFPTOLFP(x, v) ((v)->l_ui = (u_fp)(x)>>16, (v)->l_uf = (x)<<16) +#define FPTOLFP(x, v) (UFPTOLFP((x), (v)), (x) < 0 ? (v)->l_ui -= 0x10000 : 0) + +/* + * Primitive operations on LONG fixed point values. If these are + * reminiscent of assembler op codes it's only because some may + * be replaced by inline assembler for particular machines someday. + * These are the (kind of inefficient) run-anywhere versions. + */ +#define M_NEG(v_i, v_f) /* v = -v */ \ + do { \ + if ((v_f) == 0) \ + (v_i) = -(v_i); \ + else { \ + (v_f) = -(v_f); \ + (v_i) = ~(v_i); \ + } \ + } while(0) + +#define M_NEGM(r_i, r_f, a_i, a_f) /* r = -a */ \ + do { \ + if ((a_f) == 0) { \ + (r_f) = 0; \ + (r_i) = -(a_i); \ + } else { \ + (r_f) = -(a_f); \ + (r_i) = ~(a_i); \ + } \ + } while(0) + +#define M_ADD(r_i, r_f, a_i, a_f) /* r += a */ \ + do { \ + register U_LONG lo_tmp; \ + register U_LONG hi_tmp; \ + \ + lo_tmp = ((r_f) & 0xffff) + ((a_f) & 0xffff); \ + hi_tmp = (((r_f) >> 16) & 0xffff) + (((a_f) >> 16) & 0xffff); \ + if (lo_tmp & 0x10000) \ + hi_tmp++; \ + (r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \ + \ + (r_i) += (a_i); \ + if (hi_tmp & 0x10000) \ + (r_i)++; \ + } while (0) + +#define M_ADD3(r_ovr, r_i, r_f, a_ovr, a_i, a_f) /* r += a, three word */ \ + do { \ + register U_LONG lo_tmp; \ + register U_LONG hi_tmp; \ + \ + lo_tmp = ((r_f) & 0xffff) + ((a_f) & 0xffff); \ + hi_tmp = (((r_f) >> 16) & 0xffff) + (((a_f) >> 16) & 0xffff); \ + if (lo_tmp & 0x10000) \ + hi_tmp++; \ + (r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \ + \ + lo_tmp = ((r_i) & 0xffff) + ((a_i) & 0xffff); \ + if (hi_tmp & 0x10000) \ + lo_tmp++; \ + hi_tmp = (((r_i) >> 16) & 0xffff) + (((a_i) >> 16) & 0xffff); \ + if (lo_tmp & 0x10000) \ + hi_tmp++; \ + (r_i) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \ + \ + (r_ovr) += (a_ovr); \ + if (hi_tmp & 0x10000) \ + (r_ovr)++; \ + } while (0) + +#define M_SUB(r_i, r_f, a_i, a_f) /* r -= a */ \ + do { \ + register U_LONG lo_tmp; \ + register U_LONG hi_tmp; \ + \ + if ((a_f) == 0) { \ + (r_i) -= (a_i); \ + } else { \ + lo_tmp = ((r_f) & 0xffff) + ((-(a_f)) & 0xffff); \ + hi_tmp = (((r_f) >> 16) & 0xffff) \ + + (((-(a_f)) >> 16) & 0xffff); \ + if (lo_tmp & 0x10000) \ + hi_tmp++; \ + (r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \ + \ + (r_i) += ~(a_i); \ + if (hi_tmp & 0x10000) \ + (r_i)++; \ + } \ + } while (0) + +#define M_RSHIFTU(v_i, v_f) /* v >>= 1, v is unsigned */ \ + do { \ + (v_f) = (U_LONG)(v_f) >> 1; \ + if ((v_i) & 01) \ + (v_f) |= 0x80000000; \ + (v_i) = (U_LONG)(v_i) >> 1; \ + } while (0) + +#define M_RSHIFT(v_i, v_f) /* v >>= 1, v is signed */ \ + do { \ + (v_f) = (U_LONG)(v_f) >> 1; \ + if ((v_i) & 01) \ + (v_f) |= 0x80000000; \ + if ((v_i) & 0x80000000) \ + (v_i) = ((v_i) >> 1) | 0x80000000; \ + else \ + (v_i) = (v_i) >> 1; \ + } while (0) + +#define M_LSHIFT(v_i, v_f) /* v <<= 1 */ \ + do { \ + (v_i) <<= 1; \ + if ((v_f) & 0x80000000) \ + (v_i) |= 0x1; \ + (v_f) <<= 1; \ + } while (0) + +#define M_LSHIFT3(v_ovr, v_i, v_f) /* v <<= 1, with overflow */ \ + do { \ + (v_ovr) <<= 1; \ + if ((v_i) & 0x80000000) \ + (v_ovr) |= 0x1; \ + (v_i) <<= 1; \ + if ((v_f) & 0x80000000) \ + (v_i) |= 0x1; \ + (v_f) <<= 1; \ + } while (0) + +#define M_ADDUF(r_i, r_f, uf) /* r += uf, uf is U_LONG fraction */ \ + M_ADD((r_i), (r_f), 0, (uf)) /* let optimizer worry about it */ + +#define M_SUBUF(r_i, r_f, uf) /* r -= uf, uf is U_LONG fraction */ \ + M_SUB((r_i), (r_f), 0, (uf)) /* let optimizer worry about it */ + +#define M_ADDF(r_i, r_f, f) /* r += f, f is a LONG fraction */ \ + do { \ + if ((f) > 0) \ + M_ADD((r_i), (r_f), 0, (f)); \ + else if ((f) < 0) \ + M_ADD((r_i), (r_f), (-1), (f));\ + } while(0) + +#define M_ISNEG(v_i, v_f) /* v < 0 */ \ + (((v_i) & 0x80000000) != 0) + +#define M_ISHIS(a_i, a_f, b_i, b_f) /* a >= b unsigned */ \ + (((U_LONG)(a_i)) > ((U_LONG)(b_i)) || \ + ((a_i) == (b_i) && ((U_LONG)(a_f)) >= ((U_LONG)(b_f)))) + +#define M_ISGEQ(a_i, a_f, b_i, b_f) /* a >= b signed */ \ + (((LONG)(a_i)) > ((LONG)(b_i)) || \ + ((a_i) == (b_i) && ((U_LONG)(a_f)) >= ((U_LONG)(b_f)))) + +#define M_ISEQU(a_i, a_f, b_i, b_f) /* a == b unsigned */ \ + ((a_i) == (b_i) && (a_f) == (b_f)) + +/* + * Operations on the LONG fp format + */ +#define L_ADD(r, a) M_ADD((r)->l_ui, (r)->l_uf, (a)->l_ui, (a)->l_uf) +#define L_SUB(r, a) M_SUB((r)->l_ui, (r)->l_uf, (a)->l_ui, (a)->l_uf) +#define L_NEG(v) M_NEG((v)->l_ui, (v)->l_uf) +#define L_ADDUF(r, uf) M_ADDUF((r)->l_ui, (r)->l_uf, (uf)) +#define L_SUBUF(r, uf) M_SUBUF((r)->l_ui, (r)->l_uf, (uf)) +#define L_ADDF(r, f) M_ADDF((r)->l_ui, (r)->l_uf, (f)) +#define L_RSHIFT(v) M_RSHIFT((v)->l_i, (v)->l_uf) +#define L_RSHIFTU(v) M_RSHIFT((v)->l_ui, (v)->l_uf) +#define L_LSHIFT(v) M_LSHIFT((v)->l_ui, (v)->l_uf) +#define L_CLR(v) ((v)->l_ui = (v)->l_uf = 0) + +#define L_ISNEG(v) (((v)->l_ui & 0x80000000) != 0) +#define L_ISHIS(a, b) ((a)->l_ui > (b)->l_ui || \ + ((a)->l_ui == (b)->l_ui && (a)->l_uf >= (b)->l_uf)) +#define L_ISGEQ(a, b) ((a)->l_i > (b)->l_i || \ + ((a)->l_i == (b)->l_i && (a)->l_uf >= (b)->l_uf)) +#define L_ISEQU(a, b) M_ISEQU((a)->l_ui, (a)->l_uf, (b)->l_ui, (b)->l_uf) + +extern char * dofptoa P((u_fp, int, int, int)); +extern char * dolfptoa P((U_LONG, U_LONG, int, int, int)); + +extern int atolfp P((const char *, l_fp *)); +extern int buftvtots P((const char *, l_fp *)); +extern void gettstamp P((l_fp *)); +extern char * fptoa P((s_fp, int)); +extern char * fptoms P((s_fp, int)); +extern char * fptoms P((s_fp, int)); +extern int hextolfp P((const char *, l_fp *)); +extern int mstolfp P((const char *, l_fp *)); +extern char * prettydate P((l_fp *)); +extern char * uglydate P((l_fp *)); + +extern void get_systime P((l_fp *)); +extern int step_systime P((l_fp *)); +extern int step_systime_real P((l_fp *)); +extern int adj_systime P((l_fp *)); + +#define lfptoa(_fpv, _ndec) mfptoa((_fpv)->l_ui, (_fpv)->l_uf, (_ndec)) +#define lfptoms(_fpv, _ndec) mfptoms((_fpv)->l_ui, (_fpv)->l_uf, (_ndec)) + +#define ntoa(_sin) numtoa((_sin)->sin_addr.s_addr) +#define ntohost(_sin) numtohost((_sin)->sin_addr.s_addr) + +#define ufptoa(_fpv, _ndec) dofptoa((_fpv), 0, (_ndec), 0) +#define ufptoms(_fpv, _ndec) dofptoa((_fpv), 0, (_ndec), 1) +#define ulfptoa(_fpv, _ndec) dolfptoa((_fpv)->l_ui, (_fpv)->l_uf, 0, (_ndec), 0) +#define ulfptoms(_fpv, _ndec) dolfptoa((_fpv)->l_ui, (_fpv)->l_uf, 0, (_ndec), 1) +#define umfptoa(_fpi, _fpf, _ndec) dolfptoa((_fpi), (_fpf), 0, (_ndec), 0) diff --git a/contrib/xntpd/include/ntp_if.h b/contrib/xntpd/include/ntp_if.h new file mode 100644 index 0000000000..1a76ca02da --- /dev/null +++ b/contrib/xntpd/include/ntp_if.h @@ -0,0 +1,43 @@ +/* + * Sockets are not standard. + * So hide uglyness in include file. + */ +#if defined(SYS_CONVEXOS9) +#include "/sys/sync/queue.h" +#include "/sys/sync/sema.h" +#endif + +#if defined(SYS_AIX) +#include +#include +#endif + +#if defined(SOLARIS)&&!defined(bsd) +#include +#endif + +#if defined(SYS_PTX) || defined(SYS_SINIXM) +#include +#include +#endif + +#if defined(SYS_SVR4) +#if !defined(USE_STREAMS_DEVICE_FOR_IF_CONFIG) +#include +#else /* USE_STREAMS_DEVICE_FOR_IF_CONFIG */ +#include +#undef SIOCGIFCONF +#undef SIOCGIFFLAGS +#undef SIOCGIFADDR +#undef SIOCGIFBRDADDR +#undef SIOCGIFNETMASK +#define SIOCGIFCONF IPIOC_GETIFCONF +#define SIOCGIFFLAGS IPIOC_GETIFFLAGS +#define SIOCGIFADDR IPIOC_GETIFADDR +#define SIOCGIFBRDADDR IPIOC_GETIFBRDADDR +#define SIOCGIFNETMASK IPIOC_GETIFNETMASK +#endif /* USE_STREAMS_DEVICE_FOR_IF_CONFIG */ + +#endif /* SYS_SVR4 */ + +#include diff --git a/contrib/xntpd/include/ntp_io.h b/contrib/xntpd/include/ntp_io.h new file mode 100644 index 0000000000..c3b79be061 --- /dev/null +++ b/contrib/xntpd/include/ntp_io.h @@ -0,0 +1,24 @@ +/* + * POSIX says use to get O_* symbols and + * SEEK_SET symbol form . + */ +#if defined(NTP_POSIX_SOURCE) +/* + * POSIX way + */ +#include +#if defined(HAVE_SIGNALED_IO) && (defined(SYS_AUX2) || defined(SYS_AUX3) || defined(SYS_PTX)) +#include +#endif +#include +#include +#else +/* + * BSD way + */ +#include +#include +#if !defined(SEEK_SET) && defined(L_SET) +#define SEEK_SET L_SET +#endif +#endif diff --git a/contrib/xntpd/include/ntp_machine.h b/contrib/xntpd/include/ntp_machine.h new file mode 100644 index 0000000000..97f5729f42 --- /dev/null +++ b/contrib/xntpd/include/ntp_machine.h @@ -0,0 +1,457 @@ +/* ntp_compat.h,v 3.1 1993/07/06 01:06:49 jbj Exp + * Collect all machine dependent idiosyncrasies in one place. + */ + +#ifndef __ntp_machine +#define __ntp_machine + +/* + Various options. + They can defined with the DEFS directive in the Config file if they + are not defined here. + +WHICH NICE + + HAVE_ATT_NICE - Use att nice(priority_change) + HAVE_BSD_NICE - Use bsd setprioirty(which, who, priority) + HAVE_NO_NICE - Don't have (or use) either + +KERNEL MUCKING - If you porting to a new system see xntpd/ntp_unixclock.c and + util/tickadj.c to see what these do. This is very system + dependent stuff!!! + + HAVE_LIBKVM - Use libkvm to read kernal memory + HAVE_READKMEM - Use read to read kernal memory + NOKMEM - Don't read kmem + HAVE_N_UN - Have u_nn nlist struct. + +WHICH SETPGRP TO USE - Not needed if NTP_POSIX_SOURCE is defined since you + better of setsid! + + HAVE_ATT_SETPGRP - setpgrp(void) instead of setpgrp(int, int) + + +Signaled IO - Signled IO defines. + + HAVE_SIGNALED_IO - Enable signaled io. Assumes you are going to use SIGIO + for tty and udp io. + USE_UDP_SIGPOLL - Use SIGPOLL on socket io. This assumes that the + sockets routines are defined on top of streams. + USE_TTY_SIGPOLL - Use SIGPOLL on tty io. This assumes streams. + UDP_BACKWARDS_SETOWN - SunOS 3.5 or Ultirx 2.0 system. + + +WHICH TERMINAL MODEL TO USE - I would assume HAVE_POSIX_TTYS if + NTP_POSIX_SOURCE was set but cann't. The + posix tty driver is too restrictive on most systems. + It defined if you define STREAMS. + + HAVE_SYSV_TTYS - Use SYSV termio.h + HAVE_BSD_TTYS - Use BSD stty.h + HAVE_POSIX_TTYS - "struct termios" has c_line defined + +THIS MAKES PORTS TO NEW SYSTEMS EASY - You only have to wory about + kernal mucking. + + NTP_POSIX_SOURCE - Use POSIX functions over bsd functions and att functions. + This is NOT the same as _POSIX_SOURCE. + It is much weeker! + + +STEP SLEW OR TWO STEP - The Default is to step. + + SLEWALWAYS - setttimeofday can not be used to set the time of day at + all. + STEP_SLEW - setttimeofday can not set the seconds part of time + time use setttimeofday to set the seconds part of the + time and the slew the seconds. + FORCE_NTPDATE_STEP - even if SLEWALWAYS is defined, force a step of + of the systemtime (via settimeofday()). Only takes + affect if STEP_SLEW isn't defined. + +WHICH TIMEOFDAY() + + SYSV_TIMEOFDAY - [sg]ettimeofday(struct timeval *) as opposed to BSD + [sg]ettimeofday(struct timeval *, struct timezone *) + +INFO ON NEW KERNEL PLL SYS CALLS + + NTP_SYSCALLS_STD - use the "normal" ones + NTP_SYSCALL_GET - SYS_ntp_gettime id + NTP_SYSCALL_ADJ - SYS_ntp_adjtime id + +WHAT DOES IOCTL(SIOCGIFCONF) RETURN IN THE BUFFER + + UNIX V.4 machines implement a sockets library on top of streams. + When requesting the IP interface configuration with an ioctl(2) calll, + an arrat of ifreq structures are placed in the provided buffer. Some + implementations also place the length of the buffer information in + the first integer position of the buffer. + + SIZE_RETURNED_IN_BUFFER - size integer is in the buffer + +WILL IOCTL(SIOCGIFCONF) WORK ON A SOCKET + + Some UNIX V.4 machines do not appear to support ioctl() requests for the + IP interface configuration on a socket. They appear to require the use + of the streams device instead. + + USE_STREAMS_DEVICE_FOR_IF_CONFIG - use the /dev/ip device for configuration + +MISC + + USE_PROTOTYPES - Prototype functions + DOSYNCTODR - Resync TODR clock every hour. + RETSIGTYPE - Define signal function type. + NO_SIGNED_CHAR_DECL - No "signed char" see include/ntp.h + LOCK_PROCESS - Have plock. + UDP_WILDCARD_DELIVERY + - these systems deliver broadcast pakets to the wildcard + port instead to a port bound to the interface bound + to the correct broadcast address - are these + implementations broken or did the spec change ? + + HAVE_UNISTD_H - Maybe should be part of NTP_POSIX_SOURCE ? + +You could just put the defines on the DEFS line in machines/ file. +I don't since there are lost of different types compiler that a systemm might +have, some that can do proto typing and others that cannot on the saem system. +I get a chanse to twiddle some of the configuration paramasters at compile +time based on compler/machine combinatsions by using this include file. +See convex, aix and sun configurations see how complex it get. + +*/ + + +/* + * RS6000 running AIX. + */ +#if defined(SYS_AIX) +#define HAVE_SIGNALED_IO +#ifndef _BSD +#define NTP_STDC +#define NTP_POSIX_SOURCE +/* + * Keep USE_PROTOTYPES and _NO_PROTO in step. + */ +#if defined(_NO_PROTO)&&defined(USE_PROTOTYPES) +#undef USE_PROTOTYPES +#endif +#if !defined(_NO_PROTO)&&!defined(USE_PROTOTYPES) +#define USE_PROTOTYPES +#endif +#endif /*_BSD */ +#define HAVE_BSD_NICE +#endif /* RS6000 */ + +/* + * SunOS 4.X.X + * Note: posix version has NTP_POSIX_SOURCE and HAVE_SIGNALED_IO + */ +#if defined(SYS_SUNOS4) +#define NO_SIGNED_CHAR_DECL +#define HAVE_LIBKVM +#define HAVE_MALLOC_H +#define HAVE_BSD_NICE +#define RETSIGTYPE void +#define NTP_SYSCALL_GET 132 +#define NTP_SYSCALL_ADJ 147 +#endif + +/* + * Sinix-M + */ +#if defined(SYS_SINIXM) +#undef HAVE_SIGNALED_IO +#undef USE_TTY_SIGPOLL +#undef USE_UDP_SIGPOLL +#define NO_SIGNED_CHAR_DECL +#define STEP_SLEW /* TWO step */ +#define RETSIGTYPE void +#define NTP_POSIX_SOURCE +#define HAVE_ATT_SETPGRP +#define HAVE_ATT_NICE +#endif + +/* + * SunOS 5.1 or SunOS 5.2 or Solaris 2.1 or Solaris 2.2 + */ +#if defined(SYS_SOLARIS) +#define HAVE_SIGNALED_IO +#define USE_TTY_SIGPOLL +#define USE_UDP_SIGPOLL +#define NO_SIGNED_CHAR_DECL +#define STEP_SLEW /* TWO step */ +#define RETSIGTYPE void +#define NTP_POSIX_SOURCE +#define HAVE_ATT_SETPGRP +#define HAVE_ATT_NICE +#define UDP_WILDCARD_DELIVERY +#endif + +/* + * Convex + */ +#if defined(SYS_CONVEXOS10)||defined(SYS_CONVEXOS9) +#define HAVE_SIGNALED_IO +#define HAVE_N_UN +#define HAVE_READKMEM +#define HAVE_BSD_NICE +#if defined(convex) +#define RETSIGTYPE int +#define NO_SIGNED_CHAR_DECL +#else +#if defined(__stdc__)&&!defined(USE_PROTOTYPES) +#define USE_PROTOTYPES +#endif +#if !defined(__stdc__)&&defined(USE_PROTOTYPES) +#undef USE_PROTOTYPES +#endif +#define NTP_POSIX_SOURCE +#define HAVE_ATT_SETPGRP +#endif +#endif + +/* + * IRIX 4.X and IRIX 5.x + */ +#if defined(SYS_IRIX4)||defined(SYS_IRIX5) +#define HAVE_SIGNALED_IO +#define USE_TTY_SIGPOLL +#define ADJTIME_IS_ACCURATE +#define LOCK_PROCESS +#define USE_PROTOTYPES +#define HAVE_ATT_SETPGRP +#define HAVE_BSD_NICE +#define NTP_POSIX_SOURCE +#endif + +/* + * Ultrix + * Note: posix version has NTP_POSIX_SOURCE and HAVE_SIGNALED_IO + */ +#if defined(SYS_ULTRIX) +#define S_CHAR_DEFINED +#define HAVE_READKMEM +#define HAVE_BSD_NICE +#define RETSIGTYPE void +#define NTP_SYSCALLS_STD +#endif + +/* + * AUX + */ +#if defined(SYS_AUX2)||defined(SYS_AUX3) +#define NO_SIGNED_CHAR_DECL +#define HAVE_READKMEM +#define HAVE_ATT_NICE +#define LOCK_PROCESS +#define NTP_POSIX_SOURCE +/* + * This requires that _POSIX_SOURCE be forced on the + * compiler command flag. We can't do it here since this + * file is included _after_ the system header files and we + * need to let _them_ know we're POSIX. We do this in + * compilers/aux3.gcc... + */ +#define SLEWALWAYS +#define FORCE_NTPDATE_STEP +#define RETSIGTYPE void +#define HAVE_ATT_SETPGRP +#define HAVE_BSD_TTYS +#define LOG_NTP LOG_LOCAL1 +#define HAVE_SIGNALED_IO +#endif + +/* + * Next + */ +#if defined(SYS_NEXT) +#define DOSYNCTODR +#define HAVE_READKMEM +#define HAVE_BSD_NICE +#define HAVE_N_UN +#undef NTP_POSIX_SOURCE +#endif + +/* + * HPUX + */ +#if defined(SYS_HPUX) +#define NTP_POSIX_SOURCE +#define HAVE_SIGNALED_IO +#define HAVE_UNISTD_H +#define NO_SIGNED_CHAR_DECL +#define LOCK_PROCESS +#define HAVE_NO_NICE /* HPUX uses rtprio instead */ +#define RETSIGTYPE void +#if (SYS_HPUX < 10) +#define NOKMEM +#else +#define HAVE_READKMEM +#endif +#endif + +/* + * bsdi + */ +#if defined(SYS_BSDI) +#define HAVE_SIGNALED_IO +#define HAVE_LIBKVM +#define NTP_POSIX_SOURCE +#define HAVE_BSD_NICE +#endif + +/* + * Linux + */ +#if defined(SYS_LINUX) +#undef HAVE_SIGNALED_IO +#define RETSIGTYPE void +#define NTP_POSIX_SOURCE +#define ADJTIME_IS_ACCURATE +#define HAVE_SYS_TIMEX_H +#define ntp_adjtime adjtimex +#define HAVE_BSD_NICE +#endif + +/* + * 386BSD and any variants 8-) - should really have only ONE define + * for this bunch. + */ +#if defined(SYS_386BSD) || defined(SYS_FREEBSD) || defined(SYS_NETBSD) +#define HAVE_SIGNALED_IO +#define HAVE_READKMEM +#define NTP_POSIX_SOURCE +#define HAVE_BSD_NICE +#endif + +/* + * DECOSF1 + */ +#if defined(SYS_DECOSF1) +#define HAVE_SIGNALED_IO +#define HAVE_READKMEM +#define NTP_POSIX_SOURCE +#define NTP_SYSCALLS_STD +#define HAVE_BSD_NICE +#endif + +/* + * I386 + */ +#if defined(SYS_I386) +#define HAVE_READKMEM +#define S_CHAR_DEFINED +#define HAVE_BSD_NICE +#endif + +/* + * Mips + */ +#if defined(SYS_MIPS) +#define NOKMEM +#define HAVE_BSD_NICE +#endif + +/* + * SEQUENT + */ +#if defined(SYS_SEQUENT) +#define HAVE_BSD_NICE +#endif + +/* + * PTX + */ +#if defined(SYS_PTX) +#define NO_SIGNED_CHAR_DECL +#ifndef HAVE_SYSV_TTYS +#define HAVE_SYSV_TTYS +#endif +#define HAVE_ATT_SETPGRP +#define HAVE_SIGNALED_IO +#define USE_UDP_SIGPOLL +#define USE_TTY_SIGPOLL +#undef ADJTIME_IS_ACCURATE /* not checked yet */ +#define LOCK_PROCESS +#define HAVE_ATT_SETPGRP +#define HAVE_ATT_NICE +#define STEP_SLEW /* TWO step */ +#define SYSV_GETTIMEOFDAY +#define HAVE_READKMEM +#define UDP_WILDCARD_DELIVERY +#define NTP_POSIX_SOURCE +struct timezone { int __0; }; /* unused placebo */ +/* + * no comment !@! + */ +typedef unsigned int u_int; +#ifndef _NETINET_IN_SYSTM_INCLUDED /* i am about to comment... */ +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned long u_long; +#endif +#endif + + +/* + * Sony + */ +#if defined(SYS_SONY) +#define NO_SIGNED_CHAR_DECL +#define HAVE_READKMEM +#define HAVE_BSD_NICE +#endif + +/* + * VAX + */ +#if defined(SYS_VAX) +#define NO_SIGNED_CHAR_DECL +#define HAVE_READKMEM +#define HAVE_BSD_NICE +#endif + +/* + * UNIX V.4 on and NCR 3000 + */ +#if defined(SYS_SVR4) +#define HAVE_ATT_SETPGRP +#define USE_PROTOTYPES +#define HAVE_UNISTD_H +#define NTP_POSIX_SOURCE +#define HAVE_ATT_NICE +#define HAVE_READKMEM +#define HAVE_SIGNALED_IO +#define USE_TTY_SIGPOLL +#define USE_UDP_SIGPOLL +#define STREAM +#define STEP_SLEW /* TWO step */ +#define LOCK_PROCESS +#define SYSV_TIMEOFDAY +#define SIZE_RETURNED_IN_BUFFER +#endif + +#ifndef RETSIGTYPE +#if defined(NTP_POSIX_SOURCE) +#define RETSIGTYPE void +#else +#define RETSIGTYPE int +#endif +#endif + +#ifdef NTP_SYSCALLS_STD +#ifndef NTP_SYSCALL_GET +#define NTP_SYSCALL_GET 235 +#endif +#ifndef NTP_SYSCALL_ADJ +#define NTP_SYSCALL_ADJ 236 +#endif +#endif /* NTP_SYSCALLS_STD */ + +#if !defined(HAVE_ATT_NICE) && !defined(HAVE_BSD_NICE) && !defined(HAVE_NO_NICE) + ERROR You_must_define_one_of_the_HAVE_xx_NICE_defines +#endif + +#endif /* __ntp_machine */ diff --git a/contrib/xntpd/include/ntp_malloc.h b/contrib/xntpd/include/ntp_malloc.h new file mode 100644 index 0000000000..0079cb700e --- /dev/null +++ b/contrib/xntpd/include/ntp_malloc.h @@ -0,0 +1,15 @@ +/* + * Define malloc and friends. + */ +#ifndef _ntp_malloc_h + +#define _ntp_malloc_h +#ifdef NTP_POSIX_SOURCE +#include +#else /* NTP_POSIX_SOURCE */ +#ifdef HAVE_MALLOC_H +#include +#endif +#endif /* NTP_POSIX_SOURCE */ + +#endif /* _ntp_malloc_h */ diff --git a/contrib/xntpd/include/ntp_refclock.h b/contrib/xntpd/include/ntp_refclock.h new file mode 100644 index 0000000000..96e63ac8bb --- /dev/null +++ b/contrib/xntpd/include/ntp_refclock.h @@ -0,0 +1,142 @@ +/* + * ntp_refclock.h - definitions for reference clock support + */ + +#include "ntp_types.h" + +#if !defined(SYSV_TTYS) && !defined(STREAM) & !defined(BSD_TTYS) +#define BSD_TTYS +#endif /* SYSV_TTYS STREAM BSD_TTYS */ + +/* + * Macros to determine the clock type and unit numbers from a + * 127.127.t.u address. + */ +#define REFCLOCKTYPE(srcadr) ((SRCADR(srcadr) >> 8) & 0xff) +#define REFCLOCKUNIT(srcadr) (SRCADR(srcadr) & 0xff) + +/* + * list of reference clock names + * see lib/clocktypes.c (must also agree with xntpd/refclock_conf.c) + */ +struct clktype { + int code; /* driver "major" number */ + char *clocktype; /* LONG description */ + char *abbrev; /* short description */ +}; + +/* + * Definitions for default values + */ +#define noentry 0 /* flag for null routine */ + +/* + * Definitions for flags + */ +#define NOFLAGS 0 +#define REF_FLAG_BCLIENT 0x1 /* clock prefers to run as a bclient */ + +/* + * Flag values + */ +#define CLK_HAVETIME1 0x1 +#define CLK_HAVETIME2 0x2 +#define CLK_HAVEVAL1 0x4 +#define CLK_HAVEVAL2 0x8 + +#define CLK_FLAG1 0x1 +#define CLK_FLAG2 0x2 +#define CLK_FLAG3 0x4 +#define CLK_FLAG4 0x8 + +#define CLK_HAVEFLAG1 0x10 +#define CLK_HAVEFLAG2 0x20 +#define CLK_HAVEFLAG3 0x40 +#define CLK_HAVEFLAG4 0x80 + +/* + * Structure for returning clock status + */ +struct refclockstat { + u_char type; + u_char flags; + u_char haveflags; + u_short lencode; /* ahem, we do have some longer "time-codes" */ + char *lastcode; + U_LONG polls; + U_LONG noresponse; + U_LONG badformat; + U_LONG baddata; + U_LONG timereset; + char *clockdesc; /* description of clock, in ASCII */ + l_fp fudgetime1; + l_fp fudgetime2; + LONG fudgeval1; + LONG fudgeval2; + u_char currentstatus; + u_char lastevent; + u_char unused[1]; +}; + + +/* + * Reference clock I/O structure. Used to provide an interface between + * the reference clock drivers and the I/O module. + */ +struct refclockio { + struct refclockio *next; + void (*clock_recv)(); + caddr_t srcclock; /* pointer to clock structure */ + int datalen; + int fd; + U_LONG recvcount; +}; + + +/* + * Sizes of things we return for debugging + */ +#define NCLKBUGVALUES 16 +#define NCLKBUGTIMES 32 + +/* + * Structure for returning debugging info + */ +struct refclockbug { + u_char nvalues; + u_char ntimes; + u_short svalues; + U_LONG stimes; + U_LONG values[NCLKBUGVALUES]; + l_fp times[NCLKBUGTIMES]; +}; + +/* + * Struct refclock provides the interface between the reference + * clock support and particular clock drivers. There are entries + * to open and close a unit, optional values to specify the + * timer interval for calls to the transmit procedure and to + * specify a polling routine to be called when the transmit + * procedure executes. There is an entry which is called when + * the transmit routine is about to shift zeroes into the + * filter register, and entries for stuffing fudge factors into + * the driver and getting statistics from it. + */ +struct refclock { + int (*clock_start) P((u_int, struct peer *)); /* start a clock unit */ + void (*clock_shutdown) P((int)); /* shut a clock down */ + void (*clock_poll) P((int, struct peer *)); /* called from the xmit routine */ + void (*clock_control) P((u_int, struct refclockstat *, struct refclockstat *)); /* set fudge values, return stats */ + void (*clock_init) P((void)); /* initialize driver data at startup */ + void (*clock_buginfo) P((int, struct refclockbug *)); /* get clock dependent bug info */ + U_LONG clock_flags; /* flag values */ +}; + +extern int io_addclock_simple P((struct refclockio *)); +extern int io_addclock P((struct refclockio *)); +extern void io_closeclock P((struct refclockio *)); + +#ifdef REFCLOCK +extern void refclock_buginfo P((struct sockaddr_in *, struct refclockbug *)); +extern void refclock_control P((struct sockaddr_in *, struct refclockstat *, struct refclockstat *)); +#endif /* REFCLOCK */ diff --git a/contrib/xntpd/include/ntp_request.h b/contrib/xntpd/include/ntp_request.h new file mode 100644 index 0000000000..e94cb452aa --- /dev/null +++ b/contrib/xntpd/include/ntp_request.h @@ -0,0 +1,713 @@ +/* ntp_request.h,v 3.1 1993/07/06 01:06:57 jbj Exp + * ntp_request.h - definitions for the xntpd remote query facility + */ + +#include "ntp_types.h" + +/* + * A mode 7 packet is used exchanging data between an NTP server + * and a client for purposes other than time synchronization, e.g. + * monitoring, statistics gathering and configuration. A mode 7 + * packet has the following format: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |R|M| VN | Mode|A| Sequence | Implementation| Req Code | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Err | Number of data items | MBZ | Size of data item | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | Data (Minimum 0 octets, maximum 500 octets) | + * | | + * [...] + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Encryption Keyid (when A bit set) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | Message Authentication Code (when A bit set) | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * where the fields are (note that the client sends requests, the server + * responses): + * + * Response Bit: This packet is a response (if clear, packet is a request). + * + * More Bit: Set for all packets but the last in a response which + * requires more than one packet. + * + * Version Number: 2 for current version + * + * Mode: Always 7 + * + * Authenticated bit: If set, this packet is authenticated. + * + * Sequence number: For a multipacket response, contains the sequence + * number of this packet. 0 is the first in the sequence, + * 127 (or less) is the last. The More Bit must be set in + * all packets but the last. + * + * Implementation number: The number of the implementation this request code + * is defined by. An implementation number of zero is used + * for requst codes/data formats which all implementations + * agree on. Implementation number 255 is reserved (for + * extensions, in case we run out). + * + * Request code: An implementation-specific code which specifies the + * operation to be (which has been) performed and/or the + * format and semantics of the data included in the packet. + * + * Err: Must be 0 for a request. For a response, holds an error + * code relating to the request. If nonzero, the operation + * requested wasn't performed. + * + * 0 - no error + * 1 - incompatable implementation number + * 2 - unimplemented request code + * 3 - format error (wrong data items, data size, packet size etc.) + * 4 - no data available (e.g. request for details on unknown peer) + * 5-6 I don't know + * 7 - authentication failure (i.e. permission denied) + * + * Number of data items: number of data items in packet. 0 to 500 + * + * MBZ: A reserved data field, must be zero in requests and responses. + * + * Size of data item: size of each data item in packet. 0 to 500 + * + * Data: Variable sized area containing request/response data. For + * requests and responses the size in octets must be greater + * than or equal to the product of the number of data items + * and the size of a data item. For requests the data area + * must be exactly 40 octets in length. For responses the + * data area may be any length between 0 and 500 octets + * inclusive. + * + * Message Authentication Code: Same as NTP spec, in definition and function. + * May optionally be included in requests which require + * authentication, is never included in responses. + * + * The version number, mode and keyid have the same function and are + * in the same location as a standard NTP packet. The request packet + * is the same size as a standard NTP packet to ease receive buffer + * management, and to allow the same encryption procedure to be used + * both on mode 7 and standard NTP packets. The mac is included when + * it is required that a request be authenticated, the keyid should be + * zero in requests in which the mac is not included. + * + * The data format depends on the implementation number/request code pair + * and whether the packet is a request or a response. The only requirement + * is that data items start in the octet immediately following the size + * word and that data items be concatenated without padding between (i.e. + * if the data area is larger than data_items*size, all padding is at + * the end). Padding is ignored, other than for encryption purposes. + * Implementations using encryption might want to include a time stamp + * or other data in the request packet padding. The key used for requests + * is implementation defined, but key 15 is suggested as a default. + */ + +/* + * A request packet. These are almost a fixed length. + */ +struct req_pkt { + u_char rm_vn_mode; /* response, more, version, mode */ + u_char auth_seq; /* key, sequence number */ + u_char implementation; /* implementation number */ + u_char request; /* request number */ + u_short err_nitems; /* error code/number of data items */ + u_short mbz_itemsize; /* item size */ + char data[32]; /* data area */ + l_fp tstamp; /* time stamp, for authentication */ + U_LONG keyid; /* encryption key */ + char mac[MAX_MAC_LEN-sizeof(U_LONG)]; /* (optional) 8 byte auth code */ +}; + +/* + * Input packet lengths. One with the mac, one without. + */ +#define REQ_LEN_MAC (sizeof(struct req_pkt)) +#define REQ_LEN_NOMAC (sizeof(struct req_pkt) - MAX_MAC_LEN) + +/* + * A response packet. The length here is variable, this is a + * maximally sized one. Note that this implementation doesn't + * authenticate responses. + */ +#define RESP_HEADER_SIZE (8) +#define RESP_DATA_SIZE (500) + +struct resp_pkt { + u_char rm_vn_mode; /* response, more, version, mode */ + u_char auth_seq; /* key, sequence number */ + u_char implementation; /* implementation number */ + u_char request; /* request number */ + u_short err_nitems; /* error code/number of data items */ + u_short mbz_itemsize; /* item size */ + char data[RESP_DATA_SIZE]; /* data area */ +}; + + +/* + * Information error codes + */ +#define INFO_OKAY 0 +#define INFO_ERR_IMPL 1 /* incompatable implementation */ +#define INFO_ERR_REQ 2 /* unknown request code */ +#define INFO_ERR_FMT 3 /* format error */ +#define INFO_ERR_NODATA 4 /* no data for this request */ +#define INFO_ERR_AUTH 7 /* authentication failure */ + +/* + * Maximum sequence number. + */ +#define MAXSEQ 127 + + +/* + * Bit setting macros for multifield items. + */ +#define RESP_BIT 0x80 +#define MORE_BIT 0x40 + +#define ISRESPONSE(rm_vn_mode) (((rm_vn_mode)&RESP_BIT)!=0) +#define ISMORE(rm_vn_mode) (((rm_vn_mode)&MORE_BIT)!=0) +#define INFO_VERSION(rm_vn_mode) ((u_char)(((rm_vn_mode)>>3)&0x7)) +#define INFO_MODE(rm_vn_mode) ((rm_vn_mode)&0x7) + +#define RM_VN_MODE(resp, more) ((u_char)(((resp)?RESP_BIT:0)\ + |((more)?MORE_BIT:0)\ + |((NTP_VERSION)<<3)\ + |(MODE_PRIVATE))) + +#define INFO_IS_AUTH(auth_seq) (((auth_seq) & 0x80) != 0) +#define INFO_SEQ(auth_seq) ((auth_seq)&0x7f) +#define AUTH_SEQ(auth, seq) ((u_char)((((auth)!=0)?0x80:0)|((seq)&0x7f))) + +#define INFO_ERR(err_nitems) ((u_short)((ntohs(err_nitems)>>12)&0xf)) +#define INFO_NITEMS(err_nitems) ((u_short)(ntohs(err_nitems)&0xfff)) +#define ERR_NITEMS(err, nitems) (htons((((u_short)(err)<<12)&0xf000)\ + |((u_short)(nitems)&0xfff))) + +#define INFO_MBZ(mbz_itemsize) ((ntohs(mbz_itemsize)>>12)&0xf) +#define INFO_ITEMSIZE(mbz_itemsize) (ntohs(mbz_itemsize)&0xfff) +#define MBZ_ITEMSIZE(itemsize) (htons((u_short)(itemsize))) + + +/* + * Implementation numbers. One for universal use and one for xntpd. + */ +#define IMPL_UNIV 0 +#define IMPL_XNTPD 2 + +/* + * Some limits related to authentication. Frames which are + * authenticated must include a time stamp which differs from + * the receive time stamp by no more than 10 seconds. + */ +#define INFO_TS_MAXSKEW_UI 10 +#define INFO_TS_MAXSKEW_UF 0 + +/* + * Universal request codes go here. There aren't any. + */ + +/* + * XNTPD request codes go here. + */ +#define REQ_PEER_LIST 0 /* return list of peers */ +#define REQ_PEER_LIST_SUM 1 /* return summary info for all peers */ +#define REQ_PEER_INFO 2 /* get standard information on peer */ +#define REQ_PEER_STATS 3 /* get statistics for peer */ +#define REQ_SYS_INFO 4 /* get system information */ +#define REQ_SYS_STATS 5 /* get system stats */ +#define REQ_IO_STATS 6 /* get I/O stats */ +#define REQ_MEM_STATS 7 /* stats related to peer list maint */ +#define REQ_LOOP_INFO 8 /* info from the loop filter */ +#define REQ_TIMER_STATS 9 /* get timer stats */ +#define REQ_CONFIG 10 /* configure a new peer */ +#define REQ_UNCONFIG 11 /* unconfigure an existing peer */ +#define REQ_SET_SYS_FLAG 12 /* set system flags */ +#define REQ_CLR_SYS_FLAG 13 /* clear system flags */ +#define REQ_MONITOR 14 /* monitor clients */ +#define REQ_NOMONITOR 15 /* stop monitoring clients */ +#define REQ_GET_RESTRICT 16 /* return restrict list */ +#define REQ_RESADDFLAGS 17 /* add flags to restrict list */ +#define REQ_RESSUBFLAGS 18 /* remove flags from restrict list */ +#define REQ_UNRESTRICT 19 /* remove entry from restrict list */ +#define REQ_MON_GETLIST 20 /* return data collected by monitor */ +#define REQ_RESET_STATS 21 /* reset stat counters */ +#define REQ_RESET_PEER 22 /* reset peer stat counters */ +#define REQ_REREAD_KEYS 23 /* reread the encryption key file */ +#define REQ_DO_DIRTY_HACK 24 /* historical interest */ +#define REQ_DONT_DIRTY_HACK 25 /* Ibid. */ +#define REQ_TRUSTKEY 26 /* add a trusted key */ +#define REQ_UNTRUSTKEY 27 /* remove a trusted key */ +#define REQ_AUTHINFO 28 /* return authentication info */ +#define REQ_TRAPS 29 /* return currently set traps */ +#define REQ_ADD_TRAP 30 /* add a trap */ +#define REQ_CLR_TRAP 31 /* clear a trap */ +#define REQ_REQUEST_KEY 32 /* define a new request keyid */ +#define REQ_CONTROL_KEY 33 /* define a new control keyid */ +#define REQ_GET_CTLSTATS 34 /* get stats from the control module */ +#define REQ_GET_LEAPINFO 35 /* get leap information */ +#define REQ_GET_CLOCKINFO 36 /* get clock information */ +#define REQ_SET_CLKFUDGE 37 /* set clock fudge factors */ +#define REQ_SET_MAXSKEW 38 /* set the maximum skew factor */ +#define REQ_GET_CLKBUGINFO 39 /* get clock debugging info */ +#define REQ_SET_SELECT_CODE 40 /* set selection algorithm */ +#define REQ_SET_PRECISION 41 /* set clock precision */ + + +/* + * Flags in the information returns + */ +#define INFO_FLAG_CONFIG 0x1 +#define INFO_FLAG_SYSPEER 0x2 +#define INFO_FLAG_MINPOLL 0x4 +#define INFO_FLAG_REFCLOCK 0x8 +#define INFO_FLAG_BCLIENT 0x10 +#define INFO_FLAG_PREFER 0x10 /* SHARES BCLIENT bit - ok since mutually exclusive - Oh why ist flags a u_char ? */ +#define INFO_FLAG_AUTHENABLE 0x20 +#define INFO_FLAG_SEL_CANDIDATE 0x40 +#define INFO_FLAG_SHORTLIST 0x80 + +/* + * Peer list structure. Used to return raw lists of peers. It goes + * without saying that everything returned is in network byte order. + */ +struct info_peer_list { + U_LONG address; /* address of peer */ + u_short port; /* port number of peer */ + u_char hmode; /* mode for this peer */ + u_char flags; /* flags (from above) */ +}; + + +/* + * Peer summary structure. Sort of the info that ntpdc returns by default. + */ +struct info_peer_summary { + U_LONG dstadr; /* local address (zero for undetermined) */ + U_LONG srcadr; /* source address */ + u_short srcport; /* source port */ + u_char stratum; /* stratum of peer */ + s_char hpoll; /* host polling interval */ + s_char ppoll; /* peer polling interval */ + u_char reach; /* reachability register */ + u_char flags; /* flags, from above */ + u_char hmode; /* peer mode */ + s_fp delay; /* peer.estdelay */ + l_fp offset; /* peer.estoffset */ + u_fp dispersion; /* peer.estdisp */ +}; + + +/* + * Peer information structure. + */ +struct info_peer { + U_LONG dstadr; /* local address */ + U_LONG srcadr; /* remote address */ + u_short srcport; /* remote port */ + u_char flags; /* peer flags */ + u_char leap; /* peer.leap */ + u_char hmode; /* peer.hmode */ + u_char pmode; /* peer.pmode */ + u_char stratum; /* peer.stratum */ + u_char ppoll; /* peer.ppoll */ + u_char hpoll; /* peer.hpoll */ + s_char precision; /* peer.precision */ + u_char version; /* peer.version */ + u_char valid; /* peer.valid */ + u_char reach; /* peer.reach */ + u_char unreach; /* peer.unreach */ + u_char trust; /* peer.trust */ + u_char unused1; + u_char unused2; + u_char unused3; + u_short associd; /* association ID */ + U_LONG keyid; /* auth key in use */ + U_LONG pkeyid; /* peer.pkeyid */ + U_LONG refid; /* peer.refid */ + U_LONG timer; /* peer.timer */ + s_fp rootdelay; /* peer.distance */ + u_fp rootdispersion; /* peer.dispersion */ + l_fp reftime; /* peer.reftime */ + l_fp org; /* peer.org */ + l_fp rec; /* peer.rec */ + l_fp xmt; /* peer.xmt */ + s_fp filtdelay[NTP_SHIFT]; /* delay shift register */ + l_fp filtoffset[NTP_SHIFT]; /* offset shift register */ + u_char order[NTP_SHIFT]; /* order of peers from last filter */ + s_fp delay; /* peer.estdelay */ + u_fp dispersion; /* peer.estdisp */ + l_fp offset; /* peer.estoffset */ + U_LONG bdelay[NTP_SHIFT]; /* broadcast delay filters */ + U_LONG estbdelay; /* broadcast delay */ +}; + + +/* + * Peer statistics structure + */ +struct info_peer_stats { + U_LONG dstadr; /* local address */ + U_LONG srcadr; /* remote address */ + u_short srcport; /* remote port */ + u_short flags; /* peer flags */ + U_LONG timereset; /* time counters were reset */ + U_LONG timereceived; /* time since a packet received */ + U_LONG timetosend; /* time until a packet sent */ + U_LONG timereachable; /* time peer has been reachable */ + U_LONG sent; /* number sent */ + U_LONG received; /* number received */ + U_LONG processed; /* number processed */ + U_LONG badlength; /* rejected due to bad length */ + U_LONG badauth; /* rejected due to bad auth */ + U_LONG bogusorg; /* funny org time stamps */ + U_LONG oldpkt; /* duplicate packets */ + U_LONG baddelay; /* dropped due to bad delays */ + U_LONG seldelay; /* not selected due to delay */ + U_LONG seldisp; /* not selected due to dispersion */ + U_LONG selbroken; /* not selected because of brokenness */ + U_LONG selold; /* not selected because too old */ + u_char candidate; /* order after falseticker candidate select */ + u_char falseticker; /* order after resort for falseticker */ + u_char select; /* order after select */ + u_char select_total; /* number who made it to selection */ +}; + + +/* + * Loop filter variables + */ +struct info_loop { + l_fp last_offset; + l_fp drift_comp; + U_LONG compliance; + U_LONG watchdog_timer; +}; + + +/* + * System info. Mostly the sys.* variables, plus a few unique to + * the implementation. + */ +struct info_sys { + U_LONG peer; /* system peer address */ + u_char peer_mode; /* mode we are syncing to peer in */ + u_char leap; /* system leap bits */ + u_char stratum; /* our stratum */ + s_char precision; /* local clock precision */ + s_fp rootdelay; /* distance from sync source */ + u_fp rootdispersion; /* dispersion from sync source */ + U_LONG refid; /* reference ID of sync source */ + l_fp reftime; /* system reference time */ + U_LONG poll; /* system poll interval */ + u_short flags; /* system flags */ + u_char selection; /* selection algorithm code */ + u_char unused; + l_fp bdelay; /* default broadcast delay, a ts fraction */ + l_fp authdelay; /* default authentication delay */ + u_fp maxskew; /* maximum skew parameter (obsolete) */ +}; + + +/* + * System stats. These are collected in the protocol module + */ +struct info_sys_stats { + U_LONG timeup; /* time we have been up and running */ + U_LONG timereset; /* time since these were last cleared */ + U_LONG badstratum; /* packets claiming an invalid stratum */ + U_LONG oldversionpkt; /* old version packets received */ + U_LONG newversionpkt; /* new version packets received */ + U_LONG unknownversion; /* don't know version packets */ + U_LONG badlength; /* packets with bad length */ + U_LONG processed; /* packets processed */ + U_LONG badauth; /* packets dropped because of authorization */ + U_LONG wanderhold; +}; + + +/* + * Peer memory statistics. Collected in the peer module. + */ +struct info_mem_stats { + U_LONG timereset; /* time since reset */ + u_short totalpeermem; + u_short freepeermem; + U_LONG findpeer_calls; + U_LONG allocations; + U_LONG demobilizations; + u_char hashcount[HASH_SIZE]; +}; + + +/* + * I/O statistics. Collected in the I/O module + */ +struct info_io_stats { + U_LONG timereset; /* time since reset */ + u_short totalrecvbufs; /* total receive bufs */ + u_short freerecvbufs; /* free buffers */ + u_short fullrecvbufs; /* full buffers */ + u_short lowwater; /* number of times we've added buffers */ + U_LONG dropped; /* dropped packets */ + U_LONG ignored; /* ignored packets */ + U_LONG received; /* received packets */ + U_LONG sent; /* packets sent */ + U_LONG notsent; /* packets not sent */ + U_LONG interrupts; /* interrupts we've handled */ + U_LONG int_received; /* received by interrupt handler */ +}; + + +/* + * Timer stats. Guess where from. + */ +struct info_timer_stats { + U_LONG timereset; /* time since reset */ + U_LONG alarms; /* alarms we've handled */ + U_LONG overflows; /* timer overflows */ + U_LONG xmtcalls; /* calls to xmit */ +}; + + +/* + * Structure for passing peer configuration information + */ +struct conf_peer { + U_LONG peeraddr; /* address to poll */ + u_char hmode; /* mode, either broadcast, active or client */ + u_char version; /* version number to poll with */ + u_char minpoll; /* min host poll interval */ + u_char maxpoll; /* max host poll interval */ + u_char flags; /* flags for this request */ + u_char unused; + U_LONG keyid; /* key to use for this association */ +}; + +#define CONF_FLAG_AUTHENABLE 0x1 +#define CONF_FLAG_MINPOLL 0x2 +#define CONF_FLAG_PREFER 0x4 + +/* + * Structure for passing peer deletion information. Currently + * we only pass the address and delete all configured peers with + * this addess. + */ +struct conf_unpeer { + U_LONG peeraddr; /* address of peer */ +}; + + +/* + * Structure for carrying system flags. + */ +struct conf_sys_flags { + U_LONG flags; +}; + +/* + * System flags we can set/clear + */ +#define SYS_FLAG_BCLIENT 0x1 +#define SYS_FLAG_AUTHENTICATE 0x2 + +/* + * Structure used for returning restrict entries + */ +struct info_restrict { + U_LONG addr; /* match address */ + U_LONG mask; /* match mask */ + U_LONG count; /* number of packets matched */ + u_short flags; /* restrict flags */ + u_short mflags; /* match flags */ +}; + + +/* + * Structure used for specifying restrict entries + */ +struct conf_restrict { + U_LONG addr; /* match address */ + U_LONG mask; /* match mask */ + u_short flags; /* restrict flags */ + u_short mflags; /* match flags */ +}; + + +/* + * Structure used for returning monitor data + */ +struct info_monitor { + U_LONG lasttime; /* last packet from this host */ + U_LONG firsttime; /* first time we received a packet */ + U_LONG count; /* count of packets received */ + U_LONG addr; /* host address */ + u_short port; /* port number of last reception */ + u_char mode; /* mode of last packet */ + u_char version; /* version number of last packet */ +}; + + +/* + * Structure used for passing indication of flags to clear + */ +struct reset_flags { + U_LONG flags; +}; + +#define RESET_FLAG_ALLPEERS 0x01 +#define RESET_FLAG_IO 0x02 +#define RESET_FLAG_SYS 0x04 +#define RESET_FLAG_MEM 0x08 +#define RESET_FLAG_TIMER 0x10 +#define RESET_FLAG_AUTH 0x20 +#define RESET_FLAG_CTL 0x40 + +#define RESET_ALLFLAGS \ + (RESET_FLAG_ALLPEERS|RESET_FLAG_IO|RESET_FLAG_SYS \ + |RESET_FLAG_MEM|RESET_FLAG_TIMER|RESET_FLAG_AUTH|RESET_FLAG_CTL) + +/* + * Structure used to return information concerning the authentication + * module. + */ +struct info_auth { + U_LONG timereset; /* time counters were reset */ + U_LONG numkeys; /* number of keys we know */ + U_LONG numfreekeys; /* number of free keys */ + U_LONG keylookups; /* calls to authhavekey() */ + U_LONG keynotfound; /* requested key unknown */ + U_LONG encryptions; /* number of encryptions */ + U_LONG decryptions; /* number of decryptions */ + U_LONG decryptok; /* number of successful decryptions */ + U_LONG keyuncached; /* calls to encrypt/decrypt with uncached key */ +}; + + +/* + * Structure used to pass trap information to the client + */ +struct info_trap { + U_LONG local_address; /* local interface address */ + U_LONG trap_address; /* remote client's address */ + u_short trap_port; /* remote port number */ + u_short sequence; /* sequence number */ + U_LONG settime; /* time trap last set */ + U_LONG origtime; /* time trap originally set */ + U_LONG resets; /* number of resets on this trap */ + U_LONG flags; /* trap flags, as defined in ntp_control.h */ +}; + +/* + * Structure used to pass add/clear trap information to the client + */ +struct conf_trap { + U_LONG local_address; /* local interface address */ + U_LONG trap_address; /* remote client's address */ + u_short trap_port; /* remote client's port */ + u_short unused; +}; + + +/* + * Structure used to return statistics from the control module + */ +struct info_control { + U_LONG ctltimereset; + U_LONG numctlreq; /* number of requests we've received */ + U_LONG numctlbadpkts; /* number of bad control packets */ + U_LONG numctlresponses; /* # resp packets sent */ + U_LONG numctlfrags; /* # 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; /* # input pkts with err bit set */ + U_LONG numctlbadoffset; /* # input pkts with nonzero offset */ + U_LONG numctlbadversion; /* # 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; /* # async messages we've sent */ +}; + + +/* + * Structure used to return leap information. + */ +struct info_leap { + u_char sys_leap; /* current sys_leap */ + u_char leap_indicator; /* current leap indicator */ + u_char leap_warning; /* current leap warning */ + u_char leap_bits; /* leap flags */ + U_LONG leap_timer; /* seconds to next interrupt */ + U_LONG leap_processcalls; /* calls to the leap process */ + U_LONG leap_notclose; /* found leap was not close */ + U_LONG leap_monthofleap; /* in month of leap */ + U_LONG leap_dayofleap; /* in day of leap */ + U_LONG leap_hoursfromleap; /* leap within two hours */ + U_LONG leap_happened; /* leap second happened */ +}; + +#define INFO_LEAP_MASK 0x3 /* flag for leap_bits */ +#define INFO_LEAP_SEENSTRATUM1 0x4 /* server has seen stratum 1 */ +#define INFO_LEAP_OVERRIDE 0x8 /* server will override the leap information */ + +/* + * Structure used to return clock information + */ +struct info_clock { + U_LONG clockadr; + u_char type; + u_char flags; + u_char lastevent; + u_char currentstatus; + U_LONG polls; + U_LONG noresponse; + U_LONG badformat; + U_LONG baddata; + U_LONG timestarted; + l_fp fudgetime1; + l_fp fudgetime2; + LONG fudgeval1; + LONG fudgeval2; +}; + + +/* + * Structure used for setting clock fudge factors + */ +struct conf_fudge { + U_LONG clockadr; + U_LONG which; + l_fp fudgetime; + LONG fudgeval_flags; +}; + +#define FUDGE_TIME1 1 +#define FUDGE_TIME2 2 +#define FUDGE_VAL1 3 +#define FUDGE_VAL2 4 +#define FUDGE_FLAGS 5 + + +/* + * Structure used for returning clock debugging info + */ +#define NUMCBUGVALUES 16 +#define NUMCBUGTIMES 32 + +struct info_clkbug { + U_LONG clockadr; + u_char nvalues; + u_char ntimes; + u_short svalues; + U_LONG stimes; + U_LONG values[NUMCBUGVALUES]; + l_fp times[NUMCBUGTIMES]; +}; diff --git a/contrib/xntpd/include/ntp_select.h b/contrib/xntpd/include/ntp_select.h new file mode 100644 index 0000000000..5dd1868210 --- /dev/null +++ b/contrib/xntpd/include/ntp_select.h @@ -0,0 +1,20 @@ +/* + * Not all machines define FD_SET in sys/types.h + */ +#ifndef _ntp_select_h +#define _ntp_select_h + +#if (defined(RS6000)||defined(SYS_PTX))&&!defined(_BSD) +#include +#endif + +#ifndef FD_SET +#define NFDBITS 32 +#define FD_SETSIZE 32 +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) +#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) +#endif + +#endif /* _ntp_select_h */ diff --git a/contrib/xntpd/include/ntp_stdlib.h b/contrib/xntpd/include/ntp_stdlib.h new file mode 100644 index 0000000000..fcccd6e7e7 --- /dev/null +++ b/contrib/xntpd/include/ntp_stdlib.h @@ -0,0 +1,92 @@ +/* ntp_stdlib.h,v 3.1 1993/07/06 01:06:58 jbj Exp + * ntp_stdlib.h - Prototypes for XNTP lib. + */ +#include + +#include "ntp_types.h" +#include "ntp_string.h" +#include "l_stdlib.h" + +#ifndef P +#if defined(__STDC__) || defined(USE_PROTOTYPES) +#define P(x) x +#else +#define P(x) () +#if !defined(const) +#define const +#endif +#endif +#endif + +#if defined(__STDC__) +extern void msyslog P((int, char *, ...)); +#else +extern void msyslog P(()); +#endif + +extern void auth_des P((U_LONG *, u_char *)); +extern void auth_delkeys P((void)); +extern int auth_havekey P((U_LONG)); +extern int auth_parity P((U_LONG *)); +extern void auth_setkey P((U_LONG, U_LONG *)); +extern void auth_subkeys P((U_LONG *, u_char *, u_char *)); +extern int authistrusted P((U_LONG)); +extern int authusekey P((U_LONG, int, const char *)); + +extern void auth_delkeys P((void)); + +extern void auth1crypt P((U_LONG, U_LONG *, int)); +extern int auth2crypt P((U_LONG, U_LONG *, int)); +extern int authdecrypt P((U_LONG, U_LONG *, int)); +extern int authencrypt P((U_LONG, U_LONG *, int)); +extern int authhavekey P((U_LONG)); +extern int authreadkeys P((const char *)); +extern void authtrust P((U_LONG, int)); +extern void calleapwhen P((U_LONG, U_LONG *, U_LONG *)); +extern U_LONG calyearstart P((U_LONG)); +extern const char *clockname P((int)); +extern int clocktime P((int, int, int, int, int, U_LONG, U_LONG *, U_LONG *)); +extern char * emalloc P((u_int)); +extern int getopt_l P((int, char **, char *)); +extern void init_auth P((void)); +extern void init_lib P((void)); +extern void init_random P((void)); + +#ifdef DES +extern void DESauth1crypt P((U_LONG, U_LONG *, int)); +extern int DESauth2crypt P((U_LONG, U_LONG *, int)); +extern int DESauthdecrypt P((U_LONG, const U_LONG *, int)); +extern int DESauthencrypt P((U_LONG, U_LONG *, int)); +extern void DESauth_setkey P((U_LONG, const U_LONG *)); +extern void DESauth_subkeys P((const U_LONG *, u_char *, u_char *)); +extern void DESauth_des P((U_LONG *, u_char *)); +extern int DESauth_parity P((U_LONG *)); +#endif /* DES */ + +#ifdef MD5 +extern void MD5auth1crypt P((U_LONG, U_LONG *, int)); +extern int MD5auth2crypt P((U_LONG, U_LONG *, int)); +extern int MD5authdecrypt P((U_LONG, const U_LONG *, int)); +extern int MD5authencrypt P((U_LONG, U_LONG *, int)); +extern void MD5auth_setkey P((U_LONG, const U_LONG *)); +#endif /* MD5 */ + +extern int atoint P((const char *, LONG *)); +extern int atouint P((const char *, U_LONG *)); +extern int hextoint P((const char *, U_LONG *)); +extern char * humandate P((U_LONG)); +extern char * inttoa P((LONG)); +extern char * mfptoa P((U_LONG, U_LONG, int)); +extern char * mfptoms P((U_LONG, U_LONG, int)); +extern char * modetoa P((int)); +extern char * numtoa P((U_LONG)); +extern char * numtohost P((U_LONG)); +extern int octtoint P((const char *, U_LONG *)); +extern U_LONG ranp2 P((int)); +extern char * refnumtoa P((U_LONG)); +extern int tsftomsu P((U_LONG, int)); +extern char * uinttoa P((U_LONG)); + +extern int decodenetnum P((const char *, U_LONG *)); + +extern RETSIGTYPE signal_no_reset P((int, RETSIGTYPE (*func)())); diff --git a/contrib/xntpd/include/ntp_string.h b/contrib/xntpd/include/ntp_string.h new file mode 100644 index 0000000000..f17905ea8f --- /dev/null +++ b/contrib/xntpd/include/ntp_string.h @@ -0,0 +1,29 @@ +/* + * Define bcopy, bzero, and bcmp and string op's + */ + +#ifndef _ntp_string_h +#define _ntp_string_h + +#ifdef NTP_POSIX_SOURCE + +#if defined(HAVE_MEMORY_H) +#include +#endif + +#include + +#define bcopy(s1,s2,n) memcpy(s2, s1, n) +#define bzero(s,n) memset(s, 0, n) +#define bcmp(s1,s2,n) memcmp(s1, s2, n) + +#else /* NTP_POSIX_SOURCE */ + +#include + +#define strrchr rindex +#define strchr index + +#endif /* NTP_POSIX_SOURCE */ + +#endif /* _ntp_string_h */ diff --git a/contrib/xntpd/include/ntp_syslog.h b/contrib/xntpd/include/ntp_syslog.h new file mode 100644 index 0000000000..0d5dff8cc4 --- /dev/null +++ b/contrib/xntpd/include/ntp_syslog.h @@ -0,0 +1,15 @@ +/* ntp_syslog.h,v 3.1 1993/07/06 01:06:59 jbj Exp + * A hack for platforms which require specially built syslog facilities + */ +#ifdef GIZMO +#include "gizmo_syslog.h" +#else /* !GIZMO */ +#include +#ifdef SYSLOG_FILE +#include +#endif +#endif /* GIZMO */ +#ifdef SYSLOG_FILE +extern FILE *syslog_file; +#define syslog msyslog +#endif diff --git a/contrib/xntpd/include/ntp_timex.h b/contrib/xntpd/include/ntp_timex.h new file mode 100644 index 0000000000..1756e2e07f --- /dev/null +++ b/contrib/xntpd/include/ntp_timex.h @@ -0,0 +1,158 @@ +/****************************************************************************** + * * + * Copyright (c) David L. Mills 1993 * + * * + * 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. * + * * + ******************************************************************************/ + +/* + * Modification history timex.h + * + * 28 Nov 93 David L. Mills + * Adjusted parameters to improve stability and increase poll interval + * + * 10 Oct 93 Torsten Duwe + * Changed to ntp_timex.h (#ifdef'd HAVE_SYS_TIMEX_H) + * + * 17 Sep 93 David L. Mills + * Created file + */ +/* + * This header file defines the Network Time Protocol (NTP) interfaces + * for user and daemon application programs. These are implemented using + * private syscalls and data structures and require specific kernel + * support. + * + * NAME + * ntp_gettime - NTP user application interface + * + * SYNOPSIS + * #include + * + * int syscall(SYS_ntp_gettime, tptr) + * + * int SYS_ntp_gettime defined in syscall.h header file + * struct ntptimeval *tptr pointer to ntptimeval structure + * + * NAME + * ntp_adjtime - NTP daemon application interface + * + * SYNOPSIS + * #include + * + * int syscall(SYS_ntp_adjtime, mode, tptr) + * + * int SYS_ntp_adjtime defined in syscall.h header file + * struct timex *tptr pointer to timex structure + * + */ +#ifndef _NTP_TIMEX_H +#define _NTP_TIMEX_H + +/* + * Include system timex.h (if appropriate) + */ +#ifdef HAVE_SYS_TIMEX_H +#include +#else /* provide definitions */ +#include + +extern int syscall P((int, void *, ...)); + +#define ntp_gettime(t) syscall(SYS_ntp_gettime, (t)) +#define ntp_adjtime(t) syscall(SYS_ntp_adjtime, (t)) + +/* + * The following defines establish the engineering parameters of the PLL + * model. The HZ variable establishes the timer interrupt frequency, 100 Hz + * for the SunOS kernel, 256 Hz for the Ultrix kernel and 1024 Hz for the + * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the + * nearest power of two in order to avoid hardware multiply operations. + */ +#define SHIFT_HZ 7 /* log2(HZ) */ + +/* + * The SHIFT_KG and SHIFT_KF defines establish the damping of the PLL + * and are chosen by analysis for a slightly underdamped convergence + * characteristic. The MAXTC define establishes the maximum time constant + * of the PLL. With the parameters given and the default time constant of + * zero, the PLL will converge in about 15 minutes. + */ +#define SHIFT_KG 6 /* shift for phase increment */ +#define SHIFT_KF 16 /* shift for frequency increment */ +#define MAXTC 6 /* maximum time constant (shift) */ + +/* + * The SHIFT_SCALE define establishes the decimal point of the time_phase + * variable which serves as a an extension to the low-order bits of the + * system clock variable. The SHIFT_UPDATE define establishes the decimal + * point of the time_offset variable which represents the current offset + * with respect to standard time. The SHIFT_USEC define represents 1 us in + * external units (shift), while the FINEUSEC define represents 1 us in + * internal units. + */ +#define SHIFT_SCALE 23 /* shift for phase scale factor */ +#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* shift for offset scale factor */ +#define SHIFT_USEC 16 /* shift for 1 us in external units */ +#define FINEUSEC (1 << SHIFT_SCALE) /* 1 us in internal units */ + +/* + * Mode codes (timex.mode) + */ +#define ADJ_OFFSET 0x0001 /* time offset */ +#define ADJ_FREQUENCY 0x0002 /* frequency offset */ +#define ADJ_MAXERROR 0x0004 /* maximum time error */ +#define ADJ_ESTERROR 0x0008 /* estimated time error */ +#define ADJ_STATUS 0x0010 /* clock status */ +#define ADJ_TIMECONST 0x0020 /* pll time constant */ + +/* + * Clock command/status codes (timex.status) + */ +#define TIME_OK 0 /* clock synchronized */ +#define TIME_INS 1 /* insert leap second */ +#define TIME_DEL 2 /* delete leap second */ +#define TIME_OOP 3 /* leap second in progress */ +#define TIME_BAD 4 /* clock not synchronized */ + +/* + * NTP user interface - used to read kernel clock values + * Note: maximum error = NTP synch distance = dispersion + delay / 2; + * estimated error = NTP dispersion. + */ +struct ntptimeval { + struct timeval time; /* current time */ + long maxerror; /* maximum error (usec) */ + long esterror; /* estimated error (usec) */ +}; + +/* + * NTP daemon interface - used to discipline kernel clock oscillator + */ +struct timex { + int mode; /* mode selector */ + long offset; /* time offset (usec) */ + long frequency; /* frequency offset (scaled ppm) */ + long maxerror; /* maximum error (usec) */ + long esterror; /* estimated error (usec) */ + int status; /* clock command/status */ + long time_constant; /* pll time constant */ + long precision; /* clock precision (usec) (read only) */ + long tolerance; /* clock frequency tolerance (ppm) + * (read only) + */ +}; + +#endif /* HAVE_SYS_TIMEX_H */ + +#endif /* _NTP_TIMEX_H */ + diff --git a/contrib/xntpd/include/ntp_types.h b/contrib/xntpd/include/ntp_types.h new file mode 100644 index 0000000000..7a2a3474bd --- /dev/null +++ b/contrib/xntpd/include/ntp_types.h @@ -0,0 +1,60 @@ +/* ntp_types.h,v 3.1 1993/07/06 01:07:00 jbj Exp + * ntp_types.h - defines how LONG and U_LONG are treated. For 64 bit systems + * like the DEC Alpha, they has to be defined as int and u_int. for 32 bit + * systems, define them as long and u_long + */ +#include "ntp_machine.h" + +#ifndef _NTP_TYPES_ +#define _NTP_TYPES_ + +/* + * This is another naming conflict. + * On NetBSD for MAC the macro "mac" is defined as 1 + * this is fun for a as a paket structure contains an + * optional "mac" member - severe confusion results 8-) + * As we hopefully do not have to rely on that macro we + * just undefine that. + */ +#ifdef mac +#undef mac +#endif + +/* + * Set up for prototyping + */ +#ifndef P +#if defined(__STDC__) || defined(USE_PROTOTYPES) +#define P(x) x +#else /* __STDC__ USE_PROTOTYPES */ +#define P(x) () +#if !defined(const) +#define const +#endif /* const */ +#endif /* __STDC__ USE_PROTOTYPES */ +#endif /* P */ + +/* + * DEC Alpha systems need LONG and U_LONG defined as int and u_int + */ +#ifdef __alpha +#ifndef LONG +#define LONG int +#endif /* LONG */ +#ifndef U_LONG +#define U_LONG u_int +#endif /* U_LONG */ +/* + * All other systems fall into this part + */ +#else /* __alpha */ +#ifndef LONG +#define LONG long +#endif /* LONG */ +#ifndef U_LONG +#define U_LONG u_long +#endif /* U_LONG */ +#endif /* __ alplha */ + +#endif /* _NTP_TYPES_ */ + diff --git a/contrib/xntpd/include/ntp_unixtime.h b/contrib/xntpd/include/ntp_unixtime.h new file mode 100644 index 0000000000..c1ab573f4d --- /dev/null +++ b/contrib/xntpd/include/ntp_unixtime.h @@ -0,0 +1,119 @@ +/* ntp_unixtime.h,v 3.1 1993/07/06 01:07:02 jbj Exp + * ntp_unixtime.h - contains constants and macros for converting between + * NTP time stamps (l_fp) and Unix times (struct timeval) + */ + +#include "ntp_types.h" +#include + +/* gettimeofday() takes two args in BSD and only one in SYSV */ +#ifdef SYSV_TIMEOFDAY +# define GETTIMEOFDAY(a, b) (gettimeofday(a)) +# define SETTIMEOFDAY(a, b) (settimeofday(a)) +#else /* ! SYSV_TIMEOFDAY */ +# define GETTIMEOFDAY(a, b) (gettimeofday(a, b)) +# define SETTIMEOFDAY(a, b) (settimeofday(a, b)) +#endif /* SYSV_TIMEOFDAY */ + +/* + * Time of day conversion constant. Ntp's time scale starts in 1900, + * Unix in 1970. + */ +#define JAN_1970 0x83aa7e80 /* 2208988800 1970 - 1900 in seconds */ + +/* + * These constants are used to round the time stamps computed from + * a struct timeval to the microsecond (more or less). This keeps + * things neat. + */ +#define TS_MASK 0xfffff000 /* mask to usec, for time stamps */ +#define TS_ROUNDBIT 0x00000800 /* round at this bit */ + + +/* + * Convert usec to a time stamp fraction. If you use this the program + * must include the following declarations: + */ +extern U_LONG ustotslo[]; +extern U_LONG ustotsmid[]; +extern U_LONG ustotshi[]; + +#define TVUTOTSF(tvu, tsf) \ + (tsf) = ustotslo[(tvu) & 0xff] \ + + ustotsmid[((tvu) >> 8) & 0xff] \ + + ustotshi[((tvu) >> 16) & 0xf] + +/* + * Convert a struct timeval to a time stamp. + */ +#define TVTOTS(tv, ts) \ + do { \ + (ts)->l_ui = (unsigned LONG)(tv)->tv_sec; \ + TVUTOTSF((tv)->tv_usec, (ts)->l_uf); \ + } while(0) + +#define sTVTOTS(tv, ts) \ + do { \ + int isneg = 0; \ + LONG usec; \ + (ts)->l_ui = (tv)->tv_sec; \ + usec = (tv)->tv_usec; \ + if (((tv)->tv_sec < 0) || ((tv)->tv_usec < 0)) { \ + usec = -usec; \ + (ts)->l_ui = -(ts)->l_ui; \ + isneg = 1; \ + } \ + TVUTOTSF(usec, (ts)->l_uf); \ + if (isneg) { \ + L_NEG((ts)); \ + } \ + } while(0) + +/* + * TV_SHIFT is used to turn the table result into a usec value. To round, + * add in TV_ROUNDBIT before shifting + */ +#define TV_SHIFT 3 +#define TV_ROUNDBIT 0x4 + + +/* + * Convert a time stamp fraction to microseconds. The time stamp + * fraction is assumed to be unsigned. To use this in a program, declare: + */ +extern LONG tstouslo[]; +extern LONG tstousmid[]; +extern LONG tstoushi[]; + +#define TSFTOTVU(tsf, tvu) \ + (tvu) = (tstoushi[((tsf) >> 24) & 0xff] \ + + tstousmid[((tsf) >> 16) & 0xff] \ + + tstouslo[((tsf) >> 9) & 0x7f] \ + + TV_ROUNDBIT) >> TV_SHIFT +/* + * Convert a time stamp to a struct timeval. The time stamp + * has to be positive. + */ +#define TSTOTV(ts, tv) \ + do { \ + (tv)->tv_sec = (ts)->l_ui; \ + TSFTOTVU((ts)->l_uf, (tv)->tv_usec); \ + if ((tv)->tv_usec == 1000000) { \ + (tv)->tv_sec++; \ + (tv)->tv_usec = 0; \ + } \ + } while (0) + +/* + * Convert milliseconds to a time stamp fraction. This shouldn't be + * here, but it is convenient since the guys who use the definition will + * often be including this file anyway. + */ +extern U_LONG msutotsflo[]; +extern U_LONG msutotsfhi[]; + +#define MSUTOTSF(msu, tsf) \ + (tsf) = msutotsfhi[((msu) >> 5) & 0x1f] + msutotsflo[(msu) & 0x1f] + +extern char * tvtoa P((const struct timeval *)); +extern char * utvtoa P((const struct timeval *)); diff --git a/contrib/xntpd/include/ntpd.h b/contrib/xntpd/include/ntpd.h new file mode 100644 index 0000000000..85a812520f --- /dev/null +++ b/contrib/xntpd/include/ntpd.h @@ -0,0 +1,142 @@ +/* ntpd.h,v 3.1 1993/07/06 01:07:03 jbj Exp + * ntpd.h - Prototypes for xntpd. + */ + +#include "ntp_syslog.h" +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_malloc.h" + +/* ntp_config.c */ +extern void getstartup P((int, char **)); +extern void getconfig P((int, char **)); + +/* ntp_config.c */ +extern void ctl_clr_stats P((void)); +extern int ctlclrtrap P((struct sockaddr_in *, struct interface *, int)); +extern u_short ctlpeerstatus P((struct peer *)); +extern int ctlsettrap P((struct sockaddr_in *, struct interface *, int, int)); +extern u_short ctlsysstatus P((void)); +extern void init_control P((void)); +extern void process_control P((struct recvbuf *, int)); +extern void report_event P((int, struct peer *)); + +/* ntp_intres.c */ +extern void ntp_intres P((void)); + +/* ntp_io.c */ +extern struct interface *findbcastinter P((struct sockaddr_in *)); +extern struct interface *findinterface P((struct sockaddr_in *)); +extern void freerecvbuf P((struct recvbuf *)); +extern struct recvbuf *getrecvbufs P((void)); +extern void init_io P((void)); +extern void input_handler P((l_fp *)); +extern void io_clr_stats P((void)); +extern void io_setbclient P((void)); +extern void io_unsetbclient P((void)); +extern void sendpkt P((struct sockaddr_in *, struct interface *, struct pkt *, int)); +#ifdef HAVE_SIGNALED_IO +extern void wait_for_signal P((void)); +extern void unblock_io_and_alarm P((void)); +extern void block_io_and_alarm P((void)); +#endif + +/* ntp_leap.c */ +extern void init_leap P((void)); +extern void leap_process P((void)); +extern int leap_setleap P((int, int)); +/* + * there seems to be a bug in the IRIX 4 compiler which prevents + * u_char from beeing used in prototyped functions. + * This is also true AIX compiler. + * So give up and define it to be int. WLJ + */ +extern int leap_actual P((int)); + +/* ntp_loopfilter.c */ +extern void init_loopfilter P((void)); +extern int local_clock P((l_fp *, struct peer *)); +extern void adj_host_clock P((void)); +extern void loop_config P((int, l_fp *, int)); +#if defined(PPS) || defined(PPSPPS) || defined(PPSCD) +extern int pps_sample P((l_fp *)); +#endif /* PPS || PPSDEV || PPSCD */ + +/* ntp_monitor.c */ +extern void init_mon P((void)); +extern void mon_start P((void)); +extern void mon_stop P((void)); +extern void monitor P((struct recvbuf *)); + +/* ntp_peer.c */ +extern void init_peer P((void)); +extern struct peer *findexistingpeer P((struct sockaddr_in *, struct peer *)); +extern struct peer *findpeer P((struct sockaddr_in *, struct interface *)); +extern struct peer *findpeerbyassoc P((int)); +extern struct peer *newpeer P((struct sockaddr_in *, struct interface *, int, int, int, int, U_LONG)); +extern void peer_all_reset P((void)); +extern void peer_clr_stats P((void)); +extern struct peer *peer_config P((struct sockaddr_in *, struct interface *, int, int, int, int, U_LONG, int)); +extern void peer_reset P((struct peer *)); +extern int peer_unconfig P((struct sockaddr_in *, struct interface *)); +extern void unpeer P((struct peer *)); + +/* ntp_proto.c */ +extern void transmit P((struct peer *)); +extern void receive P((struct recvbuf *)); +extern void peer_clear P((struct peer *)); +extern int process_packet P((struct peer *, struct pkt *, l_fp *, int, int)); +extern void clock_update P((struct peer *)); + +/* + * there seems to be a bug in the IRIX 4 compiler which prevents + * u_char from beeing used in prototyped functions. + * This is also true AIX compiler. + * So give up and define it to be int. WLJ + */ +extern void poll_update P((struct peer *, unsigned int, int)); + +extern void clear P((struct peer *)); +extern void clock_filter P((struct peer *, l_fp *, s_fp, u_fp)); +extern void clock_select P((void)); +extern void clock_combine P((struct peer **, int)); +extern void fast_xmit P((struct recvbuf *, int, int)); +extern void init_proto P((void)); +extern void proto_config P((int, LONG)); +extern void proto_clr_stats P((void)); + +#ifdef REFCLOCK +/* ntp_refclock.c */ +extern int refclock_newpeer P((struct peer *)); +extern void refclock_unpeer P((struct peer *)); +extern void refclock_receive P((struct peer *, l_fp *, s_fp, u_fp, l_fp *, l_fp *, int)); +extern void refclock_leap P((void)); +extern void init_refclock P((void)); +#endif /* REFCLOCK */ + +/* ntp_request.c */ +extern void init_request P((void)); +extern void process_private P((struct recvbuf *, int)); + +/* ntp_restrict.c */ +extern void init_restrict P((void)); +extern int restrictions P((struct sockaddr_in *)); +extern void restrict P((int, struct sockaddr_in *, struct sockaddr_in *, int, int)); + +/* ntp_timer.c */ +extern void init_timer P((void)); +extern void timer P((void)); +extern void timer_clr_stats P((void)); + +/* ntp_unixclock.c */ +extern void init_systime P((void)); + +/* ntp_util.c */ +extern void init_util P((void)); +extern void hourly_stats P((void)); +extern void stats_config P((int, char *)); +extern void record_peer_stats P((struct sockaddr_in *, int, l_fp *, s_fp, u_fp)); +extern void record_loop_stats P((l_fp *, s_fp *, int)); +extern void record_clock_stats P((struct sockaddr_in *, char *)); +extern void getauthkeys P((char *)); +extern void rereadkeys P((void)); diff --git a/contrib/xntpd/include/parse.h b/contrib/xntpd/include/parse.h new file mode 100644 index 0000000000..9c8befee7b --- /dev/null +++ b/contrib/xntpd/include/parse.h @@ -0,0 +1,401 @@ +/* + * /src/NTP/REPOSITORY/v3/include/parse.h,v 3.11 1993/11/11 11:20:18 kardel Exp + * + * parse.h,v 3.11 1993/11/11 11:20:18 kardel Exp + * + * Copyright (c) 1989,1990,1991,1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#ifndef __PARSE_H__ +#define __PARSE_H__ +#if !(defined(lint) || defined(__GNUC__)) + static char parsehrcsid[]="parse.h,v 3.11 1993/11/11 11:20:18 kardel Exp FAU"; +#endif + +#include "ntp_types.h" + +#include "parse_conf.h" + +/* + * we use the following datastructures in two modes + * either in the NTP itself where we use NTP time stamps at some places + * or in the kernel, where only struct timeval will be used. + */ +#undef PARSEKERNEL +#if defined(KERNEL) || defined(_KERNEL) +#ifndef PARSESTREAM +#define PARSESTREAM +#endif +#endif +#if defined(PARSESTREAM) && defined(STREAM) +#define PARSEKERNEL +#endif +#ifdef PARSEKERNEL +#ifndef _KERNEL +extern caddr_t kmem_alloc P((unsigned int)); +extern caddr_t kmem_free P((caddr_t, unsigned int)); +extern int splx(); +extern int splhigh(); +#define MALLOC(_X_) (char *)kmem_alloc(_X_) +#define FREE(_X_, _Y_) kmem_free((caddr_t)_X_, _Y_) +#else +#include +#define MALLOC(_X_) (char *)kmem_alloc(_X_, KM_SLEEP) +#define FREE(_X_, _Y_) kmem_free((caddr_t)_X_, _Y_) +#endif +#else +/* extern char *malloc(); XXX defined elsewhere */ +#define MALLOC(_X_) malloc(_X_) +#define FREE(_X_, _Y_) free(_X_) +#endif + +#if defined(PARSESTREAM) && defined(STREAM) +#include "sys/stream.h" +#include "sys/stropts.h" +#ifndef _KERNEL +extern int printf(); +#endif +#else /* STREAM */ +#include +#include "ntp_syslog.h" +#ifdef DEBUG +extern int debug; +#define DD_PARSE 5 +#define DD_RAWDCF 4 +#define parseprintf(LEVEL, ARGS) if (debug > LEVEL) printf ARGS +#else /* DEBUG */ +#define parseprintf(LEVEL, ARGS) +#endif /* DEBUG */ +#endif /* PARSESTREAM */ + +#ifndef TIMES10 +#define TIMES10(_X_) (((_X_) << 3) + ((_X_) << 1)) +#endif + +/* + * state flags + */ +#define PARSEB_ANNOUNCE 0x0001 /* switch time zone warning (DST switch) */ +#define PARSEB_POWERUP 0x0002 /* no synchronisation */ +#define PARSEB_NOSYNC 0x0004 /* timecode currently not confirmed */ +#define PARSEB_DST 0x0008 /* DST in effect */ +#define PARSEB_UTC 0x0010 /* UTC time */ +#define PARSEB_LEAP 0x0020 /* LEAP warning (1 hour prior to occurence) */ +#define PARSEB_ALTERNATE 0x0040 /* alternate antenna used */ +#define PARSEB_POSITION 0x0080 /* position available */ +#define PARSEB_LEAPSECOND 0x0100 /* actual leap second */ + +#define PARSEB_S_LEAP 0x0200 /* supports LEAP */ +#define PARSEB_S_ANTENNA 0x0400 /* supports antenna information */ +#define PARSEB_S_PPS 0x0800 /* supports PPS time stamping */ +#define PARSEB_S_POSITION 0x1000 /* supports position information (GPS) */ + +#define PARSEB_TIMECODE 0x2000 /* valid time code sample */ +#define PARSEB_PPS 0x4000 /* valid PPS sample */ + +#define PARSE_TCINFO (PARSEB_ANNOUNCE|PARSEB_POWERUP|PARSEB_NOSYNC|PARSEB_DST|\ + PARSEB_UTC|PARSEB_LEAP|PARSEB_ALTERNATE|PARSEB_S_LEAP|\ + PARSEB_S_LOCATION|PARSEB_TIMECODE) + +#define PARSE_POWERUP(x) ((x) & PARSEB_POWERUP) +#define PARSE_NOSYNC(x) (((x) & (PARSEB_POWERUP|PARSEB_NOSYNC)) == PARSEB_NOSYNC) +#define PARSE_SYNC(x) (((x) & (PARSEB_POWERUP|PARSEB_NOSYNC)) == 0) +#define PARSE_ANNOUNCE(x) ((x) & PARSEB_ANNOUNCE) +#define PARSE_DST(x) ((x) & PARSEB_DST) +#define PARSE_UTC(x) ((x) & PARSEB_UTC) +#define PARSE_LEAP(x) (PARSE_SYNC(x) && ((x) & PARSEB_LEAP)) +#define PARSE_ALTERNATE(x) ((x) & PARSEB_ALTERNATE) +#define PARSE_LEAPSECOND(x) (PARSE_SYNC(x) && ((x) & PARSEB_LEAP_SECOND)) + +#define PARSE_S_LEAP(x) ((x) & PARSEB_S_LEAP) +#define PARSE_S_ANTENNA(x) ((x) & PARSEB_S_ANTENNA) +#define PARSE_S_PPS(x) ((x) & PARSEB_S_PPS) +#define PARSE_S_POSITION(x) ((x) & PARSEB_S_POSITION) + +#define PARSE_TIMECODE(x) ((x) & PARSEB_TIMECODE) +#define PARSE_PPS(x) ((x) & PARSEB_PPS) +#define PARSE_POSITION(x) ((x) & PARSEB_POSITION) + +/* + * operation flags - some are also fudge flags + */ +#define PARSE_STAT_FLAGS 0x03 /* interpreted by io module */ +#define PARSE_STAT_FILTER 0x01 /* filter incoming data */ +#define PARSE_STAT_AVG 0x02 /* 1:median average / 0: median point */ +#define PARSE_LEAP_DELETE 0x04 /* delete leap */ +#define PARSE_FIXED_FMT 0x10 /* fixed format */ +#define PARSE_PPSCLOCK 0x20 /* try to get PPS time stamp via ppsclock ioctl */ + +typedef union timestamp +{ + struct timeval tv; /* timeval - usually kernel view */ + l_fp fp; /* fixed point - xntp view */ +} timestamp_t; + +/* + * standard time stamp structure + */ +struct parsetime +{ + unsigned LONG parse_status; /* data status - CVT_OK, CVT_NONE, CVT_FAIL ... */ + timestamp_t parse_time; /* PARSE timestamp */ + timestamp_t parse_stime; /* telegram sample timestamp */ + timestamp_t parse_ptime; /* PPS time stamp */ + LONG parse_usecerror; /* sampled/filtered usec error */ + LONG parse_usecdisp; /* sampled usecdispersion */ + unsigned LONG parse_state; /* current receiver state */ + unsigned short parse_format; /* format code */ +}; + +typedef struct parsetime parsetime_t; + +/*---------- STREAMS interface ----------*/ + +#ifdef STREAM +/* + * ioctls + */ +#define PARSEIOC_ENABLE (('D'<<8) + 'E') +#define PARSEIOC_DISABLE (('D'<<8) + 'D') +#define PARSEIOC_SETSTAT (('D'<<8) + 'S') +#define PARSEIOC_GETSTAT (('D'<<8) + 'G') +#define PARSEIOC_SETFMT (('D'<<8) + 'f') +#define PARSEIOC_GETFMT (('D'<<8) + 'F') +#define PARSEIOC_SETCS (('D'<<8) + 'C') +#define PARSEIOC_TIMECODE (('D'<<8) + 'T') + +#endif + +/*------ IO handling flags (sorry) ------*/ + +#define PARSE_IO_CSIZE 0x00000003 +#define PARSE_IO_CS5 0x00000000 +#define PARSE_IO_CS6 0x00000001 +#define PARSE_IO_CS7 0x00000002 +#define PARSE_IO_CS8 0x00000003 + +/* + * sizes + */ +#define PARSE_TCMAX 128 + +/* + * ioctl structure + */ +union parsectl +{ + struct parsestatus + { + unsigned LONG flags; /* new/old flags */ + } parsestatus; + + struct parsegettc + { + unsigned LONG parse_state; /* last state */ + unsigned LONG parse_badformat; /* number of bad packets since last query */ + unsigned short parse_format;/* last decoded format */ + unsigned short parse_count; /* count of valid time code bytes */ + char parse_buffer[PARSE_TCMAX+1]; /* timecode buffer */ + } parsegettc; + + struct parseformat + { + unsigned short parse_format;/* number of examined format */ + unsigned short parse_count; /* count of valid string bytes */ + char parse_buffer[PARSE_TCMAX+1]; /* format code string */ + } parseformat; + + struct parsesetcs + { + unsigned LONG parse_cs; /* character size (needed for stripping) */ + } parsesetcs; +}; + +typedef union parsectl parsectl_t; + +/*------ for conversion routines --------*/ + +#define PARSE_DELTA 16 + +struct parse /* parse module local data */ +{ + int parse_flags; /* operation and current status flags */ + + int parse_ioflags; /* io handling flags (5-8 Bit control currently) */ + int parse_syncflags; /* possible sync events (START/END/character) */ + /* + * RS232 input parser information + */ + unsigned char parse_startsym[32]; /* possible start packet values */ + unsigned char parse_endsym[32]; /* possible end packet values */ + unsigned char parse_syncsym[32]; /* sync characters */ + struct timeval parse_timeout; /* max gap between characters (us) */ + + /* + * PPS 'input' buffer + */ + struct timeval parse_lastone; /* time stamp of last PPS 1 transition */ + struct timeval parse_lastzero; /* time stamp of last PPS 0 transition */ + + /* + * character input buffer + */ + timestamp_t parse_lastchar; /* time stamp of last received character */ + + /* + * time code input buffer (from RS232 or PPS) + */ + unsigned short parse_index; /* current buffer index */ + char *parse_data; /* data buffer */ + unsigned short parse_dsize; /* size of data buffer */ + unsigned short parse_lformat; /* last format used */ + unsigned LONG parse_lstate; /* last state code */ + char *parse_ldata; /* last data buffer */ + unsigned short parse_ldsize; /* last data buffer length */ + unsigned LONG parse_badformat; /* number of unparsable pakets */ + + /* + * time stamp filtering + */ + LONG parse_delta[PARSE_DELTA]; /* delta buffer */ + int parse_dindex; + + parsetime_t parse_dtime; /* external data prototype */ +}; + +typedef struct parse parse_t; + +struct clocktime /* clock time broken up from time code */ +{ + LONG day; + LONG month; + LONG year; + LONG hour; + LONG minute; + LONG second; + LONG usecond; + LONG utcoffset; /* in seconds */ + LONG flags; /* current clock status */ +}; + +typedef struct clocktime clocktime_t; + +/* + * clock formats specify routines to be called to + * convert the buffer into a struct clock. + * functions are called + * fn(buffer, data, clock) -> CVT_NONE, CVT_FAIL, CVT_OK + * + * the private data pointer can be used to + * distingush between different formats of a common + * base type + */ +#define F_START 0x00000001 /* start packet delimiter */ +#define F_END 0x00000002 /* end packet delimiter */ +#define SYNC_TIMEOUT 0x00000004 /* packet restart after timeout */ +#define SYNC_START 0x00000008 /* packet start is sync event */ +#define SYNC_END 0x00000010 /* packet end is sync event */ +#define SYNC_CHAR 0x00000020 /* special character is sync event */ +#define SYNC_ONE 0x00000040 /* PPS synchronize on 'ONE' transition */ +#define SYNC_ZERO 0x00000080 /* PPS synchronize on 'ZERO' transition */ +#define SYNC_SYNTHESIZE 0x00000100 /* generate intermediate time stamps */ +#define CVT_FIXEDONLY 0x00010000 /* convert only in fixed configuration */ + +/* + * parser related return/error codes + */ +#define CVT_MASK 0x0000000F /* conversion exit code */ +#define CVT_NONE 0x00000001 /* format not applicable */ +#define CVT_FAIL 0x00000002 /* conversion failed - error code returned */ +#define CVT_OK 0x00000004 /* conversion succeeded */ +#define CVT_BADFMT 0x00000010 /* general format error - (unparsable) */ +#define CVT_BADDATE 0x00000020 /* date field incorrect */ +#define CVT_BADTIME 0x00000040 /* time field incorrect */ + +struct clockformat +{ + unsigned LONG (*convert)(); /* conversion routine */ + void (*syncevt)(); /* routine for handling RS232 sync events (time stamps) */ + unsigned LONG (*syncpps)(); /* PPS input routine */ + unsigned LONG (*synth)(); /* time code synthesizer */ + void *data; /* local parameters */ + char *name; /* clock format name */ + unsigned short length; /* maximum length of data packet */ + unsigned LONG flags; /* valid start symbols etc. */ + struct timeval timeout; /* buffer restart after timeout (us) */ + unsigned char startsym; /* start symbol */ + unsigned char endsym; /* end symbol */ + unsigned char syncsym; /* sync symbol */ +}; + +typedef struct clockformat clockformat_t; + +/* + * parse interface + */ +extern int parse_ioinit(/* parse_t *parseio */); +extern void parse_ioend(/* parse_t *parseio */); +extern int parse_ioread(/* parse_t *parseio, char ch, timestamp_t *ctime */); +extern int parse_iopps(/* parse_t *parseio, int status, struct timeval *ptime, parsetime_t *dtime */); +extern void parse_iodone(/* parse_t *parseio */); + +extern int parse_getstat(/* parsectl_t *dct, parse_t *parse */); +extern int parse_setstat(/* parsectl_t *dct, parse_t *parse */); +extern int parse_timecode(/* parsectl_t *dct, parse_t *parse */); +extern int parse_getfmt(/* parsectl_t *dct, parse_t *parse */); +extern int parse_setfmt(/* parsectl_t *dct, parse_t *parse */); +extern int parse_setcs(/* parsectl_t *dct, parse_t *parse */); + +extern int Strok P((char *, char *)); +extern int Stoi P((char *, LONG *, int)); + +extern time_t parse_to_unixtime P((clocktime_t *, unsigned LONG *)); +extern unsigned LONG updatetimeinfo P((parse_t *, time_t, unsigned LONG, unsigned LONG)); +extern void syn_simple P((parse_t *, timestamp_t *, struct format *, unsigned LONG)); +extern unsigned LONG pps_simple P((parse_t *, int status, timestamp_t *)); +#endif + +/* + * History: + * + * parse.h,v + * Revision 3.11 1993/11/11 11:20:18 kardel + * declaration fixes + * + * Revision 3.10 1993/11/01 19:59:48 kardel + * parse Solaris support (initial version) + * + * Revision 3.9 1993/10/06 00:14:57 kardel + * include fixes + * + * Revision 3.8 1993/10/05 23:15:41 kardel + * more STREAM protection + * + * Revision 3.7 1993/10/05 22:56:10 kardel + * STREAM must be defined for PARSESTREAMS + * + * Revision 3.6 1993/10/03 19:10:28 kardel + * restructured I/O handling + * + * Revision 3.5 1993/09/26 23:41:13 kardel + * new parse driver logic + * + * Revision 3.4 1993/09/01 21:46:31 kardel + * conditional cleanup + * + * Revision 3.3 1993/08/27 00:29:29 kardel + * compilation cleanup + * + * Revision 3.2 1993/07/09 11:37:05 kardel + * Initial restructured version + GPS support + * + * Revision 3.1 1993/07/06 09:59:12 kardel + * DCF77 driver goes generic... + * + */ diff --git a/contrib/xntpd/include/parse_conf.h b/contrib/xntpd/include/parse_conf.h new file mode 100644 index 0000000000..3cc634891e --- /dev/null +++ b/contrib/xntpd/include/parse_conf.h @@ -0,0 +1,54 @@ +/* + * /src/NTP/REPOSITORY/v3/include/parse_conf.h,v 3.3 1993/10/22 14:27:10 kardel Exp + * + * parse_conf.h,v 3.3 1993/10/22 14:27:10 kardel Exp + * + * Copyright (c) 1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#ifndef __PARSE_CONF_H__ +#define __PARSE_CONF_H__ +#if !(defined(lint) || defined(__GNUC__)) + static char dcfhrcsid[]="parse_conf.h,v 3.3 1993/10/22 14:27:10 kardel Exp FAU"; +#endif + +/* + * field location structure (Meinberg clocks/simple format) + */ +#define O_DAY 0 +#define O_MONTH 1 +#define O_YEAR 2 +#define O_HOUR 3 +#define O_MIN 4 +#define O_SEC 5 +#define O_WDAY 6 +#define O_FLAGS 7 +#define O_ZONE 8 +#define O_UTCHOFFSET 9 +#define O_UTCMOFFSET 10 +#define O_UTCSOFFSET 11 +#define O_COUNT (O_UTCSOFFSET+1) + +#define MBG_EXTENDED 0x00000001 + +/* + * see below for field offsets + */ + +struct format +{ + struct foff + { + char offset; /* offset into buffer */ + char length; /* length of field */ + } field_offsets[O_COUNT]; + char *fixed_string; /* string with must be chars (blanks = wildcards) */ + unsigned LONG flags; +}; +#endif diff --git a/contrib/xntpd/include/sys/bsd_audioirig.h b/contrib/xntpd/include/sys/bsd_audioirig.h new file mode 100644 index 0000000000..1daeec700b --- /dev/null +++ b/contrib/xntpd/include/sys/bsd_audioirig.h @@ -0,0 +1,101 @@ +/* + * $Header: bsd_audioirig.h,v 1.0 93/08/02 12:42:00 + */ + +#ifndef _BSD_AUDIOIRIG_H_ +#define _BSD_AUDIOIRIG_H_ + +#include + +/********************************************************************/ +/* user interface */ + +/* + * irig ioctls + */ +#if (defined(sun) || defined(ibm032)) && !defined(__GNUC__) +#define AUDIO_IRIG_OPEN _IO(A, 50) +#define AUDIO_IRIG_CLOSE _IO(A, 51) +#define AUDIO_IRIG_SETFORMAT _IOWR(A, 52, int) +#else +#define AUDIO_IRIG_OPEN _IO('A', 50) +#define AUDIO_IRIG_CLOSE _IO('A', 51) +#define AUDIO_IRIG_SETFORMAT _IOWR('A', 52, int) +#endif + +/* + * irig error codes + */ +#define AUDIO_IRIG_BADSIGNAL 0x01 +#define AUDIO_IRIG_BADDATA 0x02 +#define AUDIO_IRIG_BADSYNC 0x04 +#define AUDIO_IRIG_BADCLOCK 0x08 +#define AUDIO_IRIG_OLDDATA 0x10 + +/********************************************************************/ + +/* + * auib definitions + */ +#define AUIB_SIZE (0x0040) +#define AUIB_INC (0x0008) +#define AUIB_MOD(k) ((k) & 0x0038) +#define AUIB_INIT(ib) ((ib)->ib_head = (ib)->ib_tail = (ib)->ib_lock = \ + (ib)->phase = (ib)->shi = (ib)->slo = (ib)->high = \ + (ib)->level0 = (ib)->level1 = \ + (ib)->shift[0] = (ib)->shift[1] = (ib)->shift[2] = \ + (ib)->shift[3] = (ib)->sdata[0] = (ib)->sdata[1] = \ + (ib)->sdata[2] = (ib)->sdata[3] = (ib)->err = 0) +#define AUIB_EMPTY(ib) ((ib)->ib_head == (ib)->ib_tail) +#define AUIB_LEN(ib) (AUIB_MOD((ib)->ib_tail - (ib)->ib_head)) +#define AUIB_LEFT(ib) (AUIB_MOD((ib)->ib_head - (ib)->ib_tail - 1)) +#define IRIGDELAY 3 +#define IRIGLEVEL 1355 + +#ifndef LOCORE +/* + * irig_time holds IRIG data for one second + */ +struct irig_time { + struct timeval stamp; /* timestamp */ + u_char bits[13]; /* 100 irig data bits */ + u_char status; /* status byte */ + char time[14]; /* time string */ +}; + +/* + * auib's are used for IRIG data communication between the trap + * handler and the software interrupt. + */ +struct auib { + /* driver variables */ + u_short active; /* 0=inactive, else=active */ + u_short format; /* time output format */ + struct irig_time timestr; /* time structure */ + char buffer[14]; /* output formation buffer */ + + /* hardware interrupt variables */ + struct timeval tv1,tv2,tv3; /* time stamps (median filter) */ + int level0,level1; /* lo/hi input levels */ + int level; /* decision level */ + int high; /* recent largest sample */ + int sl0,sl1; /* recent sample levels */ + int lasts; /* last sample value */ + u_short scount; /* sample count */ + u_long eacc; /* 10-bit element accumulator */ + u_long ebit; /* current bit in element */ + u_char r_level,mmr1; /* recording level 0-255 */ + int shi,slo,phase; /* AGC variables */ + u_long err; /* error status bits */ + int ecount; /* count of elements this second */ + long shift[4]; /* shift register of pos ident */ + long sdata[4]; /* shift register of symbols */ + + int ib_head; /* queue head */ + int ib_tail; /* queue tail */ + u_short ib_lock; /* queue head lock */ + u_long ib_data[AUIB_SIZE]; /* data buffer */ +}; +#endif + +#endif /* _BSD_AUDIOIRIG_H_ */ diff --git a/contrib/xntpd/include/sys/chudefs.h b/contrib/xntpd/include/sys/chudefs.h new file mode 100644 index 0000000000..50f82527f4 --- /dev/null +++ b/contrib/xntpd/include/sys/chudefs.h @@ -0,0 +1,22 @@ +/* chudefs.h,v 3.1 1993/07/06 01:07:11 jbj Exp + * Definitions for the CHU line discipline v2.0 + */ + +/* + * The CHU time code consists of 10 BCD digits and is repeated + * twice for a total of 10 characters. A time is taken after + * the arrival of each character. The following structure is + * used to return this stuff. + */ +#define NCHUCHARS (10) + +struct chucode { + u_char codechars[NCHUCHARS]; /* code characters */ + u_char ncodechars; /* number of code characters */ + u_char chutype; /* packet type */ + struct timeval codetimes[NCHUCHARS]; /* arrival times */ +}; + +#define CHU_TIME 0 /* second half is equal to first half */ +#define CHU_YEAR 1 /* second half is one's complement */ + diff --git a/contrib/xntpd/include/sys/clkdefs.h b/contrib/xntpd/include/sys/clkdefs.h new file mode 100644 index 0000000000..b2596e1105 --- /dev/null +++ b/contrib/xntpd/include/sys/clkdefs.h @@ -0,0 +1,31 @@ +/* clkdefs.h,v 3.1 1993/07/06 01:07:12 jbj Exp + * Defines for the "clk" timestamping STREAMS module + */ + +#include + +/* + * First, we need to define the maximum size of the set of + * characters to timestamp. 32 is MORE than enough. + */ + +#define CLK_MAXSTRSIZE 32 + +/* + * ioctl(fd, CLK_SETSTR, (char*)c ); + * + * will tell the driver that any char in the null-terminated + * string c should be timestamped. It is possible, though + * unlikely that this ioctl number could collide with an + * existing one on your system. If so, change the 'K' + * to some other letter. However, once you've compiled + * the kernel with this include file, you should NOT + * change this file. + */ + +#if __STDC__ +#define CLK_SETSTR _IOWN('K',01,CLK_MAXSTRSIZE) +#else +#define CLK_SETSTR _IOWN(K,01,CLK_MAXSTRSIZE) +#endif + diff --git a/contrib/xntpd/include/sys/parsestreams.h b/contrib/xntpd/include/sys/parsestreams.h new file mode 100644 index 0000000000..91786c163f --- /dev/null +++ b/contrib/xntpd/include/sys/parsestreams.h @@ -0,0 +1,66 @@ +/* + * /src/NTP/REPOSITORY/v3/include/sys/parsestreams.h,v 3.9 1993/11/01 19:59:57 kardel Exp + * + * parsestreams.h,v 3.9 1993/11/01 19:59:57 kardel Exp + * + * Copyright (c) 1989,1990,1991,1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#if !(defined(lint) || defined(__GNUC__)) + static char parse77hrcsid[]="parsestreams.h,v 3.9 1993/11/01 19:59:57 kardel Exp"; +#endif + +#undef PARSEKERNEL +#if defined(KERNEL) || defined(_KERNEL) +#ifndef PARSESTREAM +#define PARSESTREAM +#endif +#endif +#if defined(PARSESTREAM) && defined(STREAM) +#define PARSEKERNEL +#include + +struct parsestream /* parse module local data */ +{ + queue_t *parse_queue; /* read stream for this channel */ + queue_t *parse_dqueue; /* driver queue entry (PPS support) */ + unsigned long parse_status; /* operation flags */ + void *parse_data; /* local data space (PPS support) */ + parse_t parse_io; /* io structure */ + struct ppsclockev parse_ppsclockev; /* copy of last pps event */ +}; + +typedef struct parsestream parsestream_t; + +#define PARSE_ENABLE 0x0001 + +/*--------------- debugging support ---------------------------------*/ + +#ifdef DEBUG_DCF + +extern int parsedebug; + +#define DD_OPEN 0x00000001 +#define DD_CLOSE 0x00000002 +#define DD_RPUT 0x00000004 +#define DD_WPUT 0x00000008 +#define DD_RSVC 0x00000010 +#define DD_PARSE 0x00000020 +#define DD_INSTALL 0x00000040 +#define DD_ISR 0x00000080 +#define DD_RAWDCF 0x00000100 + +#define parseprintf(X, Y) if ((X) & parsedebug) printf Y + +#else + +#define parseprintf(X, Y) + +#endif +#endif diff --git a/contrib/xntpd/include/sys/ppsclock.h b/contrib/xntpd/include/sys/ppsclock.h new file mode 100644 index 0000000000..952a57bff1 --- /dev/null +++ b/contrib/xntpd/include/sys/ppsclock.h @@ -0,0 +1,59 @@ +/* ppsclock.h,v 3.1 1993/07/06 01:07:14 jbj Exp */ +/* + * 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. + */ + +#define PPSCLOCKSTR "ppsclock" + +struct ppsclockev { + struct timeval tv; + u_int serial; +}; + +#if defined(__STDC__) || defined(SYS_HPUX) +#ifdef _IOR +#define CIOGETEV _IOR('C', 0, struct ppsclockev) /* get last pps event */ +#else /* XXX SOLARIS is different */ +#define CIO ('C'<<8) +#define CIOGETEV (CIO|0) /* get last pps event */ +#endif /* _IOR */ +#else /* __STDC__ */ +#ifdef _IOR +#define CIOGETEV _IOR(C, 0, struct ppsclockev) /* get last pps event */ +#else /* XXX SOLARIS is different */ +#define CIO ('C'<<8) +#define CIOGETEV (CIO|0) /* get last pps event */ +#endif /* _IOR */ +#endif /* __STDC__ */ diff --git a/contrib/xntpd/include/sys/tpro.h b/contrib/xntpd/include/sys/tpro.h new file mode 100644 index 0000000000..1cdaf9c8e6 --- /dev/null +++ b/contrib/xntpd/include/sys/tpro.h @@ -0,0 +1,34 @@ +/* tpro.h,v 3.1 1993/07/06 01:07:07 jbj Exp + * Structure for the KSI/Odetics TPRO-S data returned in reponse to a + * read() call. Note that these are driver-specific and not dependent on + * 32/64-bit architecture. + */ +struct tproval { + u_short day100; /* days * 100 */ + u_short day10; /* days * 10 */ + u_short day1; /* days * 1 */ + u_short hour10; /* hours * 10 */ + u_short hour1; /* hours * 1 */ + u_short min10; /* minutes * 10 */ + u_short min1; /* minutes * 1 */ + u_short sec10; /* seconds * 10 */ + u_short sec1; /* seconds * 1*/ + u_short ms100; /* milliseconds * 100 */ + u_short ms10; /* milliseconds * 10 */ + u_short ms1; /* milliseconds * 1 */ + u_short usec100; /* microseconds * 100 */ + u_short usec10; /* microseconds * 10 */ + u_short usec1; /* microseconds * 1 */ + long tv_sec; /* seconds */ + long tv_usec; /* microseconds */ + u_short status; /* status register */ +}; + +/* + * Status register bits + */ +#define TIMEAVAIL 0x0001 /* time available */ +#define NOSIGNAL 0x0002 /* insufficient IRIG-B signal */ +#define NOSYNC 0x0004 /* local oscillator not synchronized */ + +/* end of tpro.h */ diff --git a/contrib/xntpd/kernel/Makefile.tmpl b/contrib/xntpd/kernel/Makefile.tmpl new file mode 100644 index 0000000000..700efa6925 --- /dev/null +++ b/contrib/xntpd/kernel/Makefile.tmpl @@ -0,0 +1,39 @@ +# +# /src/NTP/REPOSITORY/v3/kernel/Makefile.tmpl,v 3.4 1993/11/05 23:51:26 kardel Exp +# +# +# parse routine that could be used in two places +# +COMPILER= cc +COPTS= -O +AUTHDEFS=-DDES +LIBDEFS= -DBIG_ENDIAN +RANLIB= ranlib +INSTALL= install +CLOCKDEFS= +DEFS= +DEFS_OPT= +DEFS_LOCAL= +# +INCL=-I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +# + +all: + @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \ + awk '/-DREFCLOCK/ && ( /-D.*CLK/ || /-D.*PPS/ ) { makeit=1; }\ + END { if (makeit) \ + { print ""; \ + print "### STREAMS kernel modules ppsclock, ppsclocd or line disciplines must"; \ + print "### be installed manually if needed"; \ + print "### see kernel/README* for details"; \ + print "### The parse reclock implementation has their own support in"; \ + print "### parse/*."; } }' + +clean: + -@rm -f *~ *.o *.out *.ln make.log Makefile.bak \ + lintlib.errs lint.errs + +distclean: clean + -@rm -f *.orig *.rej .version Makefile diff --git a/contrib/xntpd/kernel/README b/contrib/xntpd/kernel/README new file mode 100644 index 0000000000..cf69b13728 --- /dev/null +++ b/contrib/xntpd/kernel/README @@ -0,0 +1,90 @@ +This directory contains code for two line disciplines which may +work with BSD-style terminal drivers. While I'll try to cover +installation details for the more useful one here as best I can, +you really should know what you are doing before attempting to +put one of these in your kernel since the details seem to vary +from BSD variant to BSD variant. + +Tty_clk.c contains a generic clock support line discipline. +The terminal driver is actually run in raw mode, giving you an +eight bit data path. Instead of delivering the data +character-by-character, however, the line discipline collects +characters until one of two magic characters (your current erase +and kill characters. Don't throw up) is received. A timestamp +is then taken (by calling microtime()), inserted in the input +buffer after the magic character, and the whole mess made available +for input by the application. Both select() and SIGIO are supported +by the discipline. + +Tty_chu.c is a special purpose line discipline for receiving +the CHU time code. It understands enough about the format of the +code CHU transmits to filter out errors, and delivers an entire +ten character code group to the application all at once, including +a timestamp for each character. The structure the code group is +delivered in is defined in chudefs.h. Note that this line discipline +is old and could use some rewriting for better portability. Please +drop me a line if you are interested in using this. + +To install the clock line discipline, do something like the following: + +(1) Copy tty_clk.c into /sys/sys + +(2) Edit /sys/sys/tty_conf.c. You will want to include some facsimile + of the following lines: + +#include "clk.h" +#if NCLK > 0 +int clkopen(), clkclose(), clkwrite(), clkinput(), clkioctl(); +#endif + +#if NCLK > 0 + { clkopen, clkclose, ttread, clkwrite, clkioctl, + clkinput, nodev, nulldev, ttstart, nullmodem, /* 10- CLKLDISC */ + ttselect }, +#else + { nodev, nodev, nodev, nodev, nodev, + nodev, nodev, nodev, nodev, nodev, + nodev }, +#endif + + In Ultrix 4.2a and 4.3 the file to edit is /sys/data/tty_conf_data.c. + The lines should be + +#if NCLK > 0 + clkopen, clkclose, ttread, clkwrite, clkioctl, /* 10 */ + clkinput, nodev, nulldev, ttstart, nulldev, +#else + nodev, nodev, nodev, nodev, nodev, + nodev, nodev, nodev, nodev, nodev, +#endif + + Note that if your kernel doesn't include the ??select() entry in + the structure (i.e. there are only 10 entry points in the structure) + just leave it out. Also note that the number you give the line + discipline (10 in my kernel) will be specific to your kernel and + will depend on what is in there already. The entries sould be in + order with no missing space; that is, if there are only seven + disciplines already defined and you want to use 10 for good reason, + you should define a dummy 9th entry like this + + nodev, nodev, nodev, nodev, nodev, /* 9 */ + nodev, nodev, nodev, nodev, nodev, + +(3) Edit /sys/h/ioctl.h and include a line (somewhere near where other + line disciplines are defined) like: + +#define CLKLDISC 10 /* clock line discipline */ + + The `10' should match what you used in /sys/sys/tty_conf.c. + +(4) Edit /sys/conf/files and add a line which looks like: + +sys/tty_clk.c optional clk + +(5) Edit the configuration file for the machine you want to use + the clock line discipline on to include the following: + +pseudo-device clk 4 + +(6) Run config, then make clean, then make depend, then make vmunix. + Then reboot the new kernel. diff --git a/contrib/xntpd/kernel/README.kern b/contrib/xntpd/kernel/README.kern new file mode 100644 index 0000000000..64ba9c5bf3 --- /dev/null +++ b/contrib/xntpd/kernel/README.kern @@ -0,0 +1,596 @@ +Precision Time and Frequency Synchronization Using Modified Kernels + +1. Introduction + +This memo describes replacements for certain SunOS and Ultrix kernel +routines that manage the system clock and timer functions. They provide +improved accuracy and stability through the use of a disciplined clock +interface for use with the Network Time Protocol (NTP) or similar time- +synchronization protocol. In addition, for certain models of the +DECstation 5000 product line, the new routines provide improved +precision to +-1 microsecond (us) (SunOS 4.1.1 already does provide +precision to +-1 us). The current public NTP distribution cooperates +with these kernel routines to provide synchronization in principle to +within a microsecond, but in practice this is limited by the short-term +stability of the oscillator that drives the timer interrupt. + +This memo describes the principles behind the design and operation of +the software. There are two versions of the software, one that operates +with the SunOS 4.1.1 kernel and the other that operates with the Ultrix +4.2a kernel (and probably the 4.3 kernel, although this has not been +tested). A detailed description of the variables and algorithms is given +in the hope that similar improvements can be incorporated in Unix +kernels for other machines. The software itself is not included in this +memo, since it involves licensed code. Detailed instructions on where to +obtain it for either SunOS or Ultrix will be given separately. + +The principle function added to the SunOS and Ultrix kernels is to +change the way the system clock is controlled, in order to provide +precision time and frequency adjustments. Another function utilizes an +undocumented counter in the DECstation hardware to provide precise time +to the microsecond. This function can be used only with the DECstation +5000/240 and possibly others that use the same input/output chipset. + +2. Design Principles + +In order to understand how these routines work, it is useful to consider +how most Unix systems maintain the system clock. In the original design +a hardware timer interrupts the kernel at some fixed rate, such as 100 +Hz in the SunOS kernel and 256 Hz in the Ultrix kernel. Since 256 does +not evenly divide the second in microseconds, the kernel inserts 64 us +once each second so that the system clock stays in step with real time. +The time returned by the gettimeofday() routine is thus characterized by +255 advances of 3906 us plus one of 3970 us. + +Also in the original design it is possible to slew the system clock to a +new offset using the adjtime() system call. To do this the clock +frequency is changed by adding or subtracting a fixed amount (tickadj) +at each timer interrupt (tick) for a calculated number of ticks. Since +this calculation involves dividing the requested offset by tickadj, it +is possible to slew to a new offset with a precision only of tickadj, +which is usually in the neighborhood of 5 us, but sometimes much higher. + +In order to maintain the system clock within specified bounds with this +scheme, it is necessary to call adjtime() on a regular basis. For +instance, let the bound be set at 100 us, which is a reasonable value +for NTP-synchronized hosts on a local network, and let the onboard +oscillator tolerance be 100 ppm, which is a reasonably conservative +assumption. This requires that adjtime() be called at intervals not +exceeding 1 second (s), which is in fact what the unmodified NTP +software daemon does. + +In the modified kernel routines this scheme is replaced by another that +extends the low-order bits of the system clock to provide very precise +clock adjustments. At each timer interrupt a precisely calibrated time +adjustment is added to the composite time value and overflows handled as +required. The quantity to add is computed from the adjtime() call and, +in addition a frequency adjustment, which is automatically calculated +from previous time adjustments. This implementation operates as an +adaptive-parameter, first-order, type-II, phase-lock loop (PLL), which +in principle provides precision control of the system clock phase to +within +-1 us and frequency to within +-5 nanoseconds (ns) per day. + +This PLL model is identical to the one implemented in NTP, except that +in NTP the software daemon has to simulate the PLL using only the +original adjtime() system call. The daemon is considerably complicated +by the need to parcel time adjustments at frequent intervals in order to +maintain the accuracy to specified bounds. The kernel routines do this +directly, allowing vast gobs of ugly daemon code to be avoided at the +expense of only a small amount of new code in the kernel. In fact, the +amount of code added to the kernel for the new scheme is about the +amount removed for the old scheme. The new adjtime() routine needs to be +called only as each new time update is determined, which in NTP occurs +at intervals of from 64 s to 1024 s. In addition, doing the frequency +correction in the kernel means that the system time runs true even if +the daemon were to cease operation or the network paths to the primary +reference source fail. + +Note that the degree to which the adjtime() adjustment can be made is +limited to a specific maximum value, presently +-128 milliseconds (ms), +in order to achieve microsecond resolution. It is the intent in the +design that settimeofday() be used for changes in system time greater +than +-128 ms. It has been the Internet experience that the need to +change the system time in increments greater than +-128 milliseconds is +extremely rare and is usually associated with a hardware or software +malfunction. Nevertheless, the limit applies to each adjtime() call and +it is possible, but not recommended, that this routine is called at +intervals smaller than 64 seconds, which is the NTP lower limit. + +For the most accurate and stable operation, adjtime() should be called +at specified intervals; however, the PLL is quite forgiving and neither +moderate loss of updates nor variations in the length of the interval is +serious. The current engineering parameters have been optimized for +intervals not greater than about 64 s. For larger intervals the PLL time +constant can be adjusted to optimize the dynamic response up to +intervals of 1024 s. Normally, this is automatically done by NTP. In any +case, if updates are suspended, the PLL coasts at the frequency last +determinated, which usually results in errors increasing only to a few +tens of milliseconds over a day. + +The new code needs to know the initial frequency offset and time +constant for the PLL, and the daemon needs to know the current frequency +offset computed by the kernel for monitoring purposes. This is provided +by a small change in the second argument of the kernel adjtime() calling +sequence, which is documented later in this memo. Ordinarily, only the +daemon will call the adjtime() routine, so the modified calling sequence +is easily accommodated. Other than this change, the operation of +adjtime() is transparent to the original. + +In the DECstation 5000/240 and possibly other models there happens to be +an undocumented hardware register that counts system bus cycles at a +rate of 25 MHz. The new kernel routines test for the CPU type and, in +the case of the '240, use this register to interpolate system time +between hardware timer interrupts. This results in a precision of +-1 us +for all time values obtained via the gettimeofday() system call. This +routine calls the kernel routine microtime(), which returns the actual +interpolated value, but does not change the kernel time variable. +Therefore, other kernel routines that access the kernel time variable +directly and do not call either gettimeofday() or microtime() will +continue their present behavior. + +The new kernel routines include provisions for error statistics (maximum +error and estimated error), leap seconds and system clock status. These +are intended to support applications that need such things; however, +there are no applications other than the time-synchronization daemon +itself that presently use them. At issue is the manner in which these +data can be provided to application clients, such as new system calls +and data interfaces. While a proposed interface is described later in +this memo, it has not yet been implemented. This is an area for further +study. + +While any time-synchronization daemon can in principle be modified to +use the new code, the most likely will be users of the xntp3 +distribution of NTP. The code in the xntp3 distribution determines +whether the new kernel code is in use and automatically reconfigures as +required. When the new code is in use, the daemon reads the frequency +offset from a file and provides it and the initial time constant via +adjtime(). In subsequent calls to adjtime(), only the time adjustment +and time constant are affected. The daemon reads the frequency from the +kernel (returned as the second argument of adjtime()) at intervals of +one hour and writes it to the file. + +3. Technical Description + +Following is a technical description of how the new scheme works in +terms of the variables and algorithms involved. These components are +discussed as a distinct entity and do not involve coding details +specific to the Ultrix kernel. The algorithms involve only minor changes +to the system clock and interval timer routines, but do not in +themselves provide a conduit for application programs to learn the +system clock status or statistics of the time-synchronization process. +In a later section a number of new system calls are proposed to do this, +along with an interface specification. + +The new scheme works like the companion simulator called kern.c and +included in this directory. This stand-alone simulator includes code +fragments identical to those in the modified kernel routines and +operates in the same way. The system clock is implemented in the kernel +using a set of variables and algorithms defined below and in the +simulator. The algorithms are driven by explicit calls from the +synchronization protocol as each time update is computed. The clock is +read and set using the gettimeofday() and settimeofday() system calls, +which operate in the same way as the originals, but return a status word +describing the state of the system clock. + +Once the system clock has been set, the adjtime() system call is used to +provide periodic updates including the time offset and possibly +frequency offset and time constant. With NTP this occurs at intervals of +from 64 s to 1024 s, deending on the time constant value. The kernel +implements an adaptive-parameter, first-order, type-II, phase-lock loop +(PLL) in order to integrate this offset into the phase and frequency of +the system clock. The kernel keeps track of the time of the last update +and adjusts the maximum error to grow by an amount equal to the +oscillator frequency tolerance times the elapsed time since the last +update. + +Occasionally, it is necessary to adjust the PLL parameters in response +to environmental conditions, such as leap-second warning and oscillator +stability observations. While the interface to do this has not yet been +implemented, proposals to to that are included in a later section. A +system call (setloop()) is used on such occasions to communicate these +data. In addition, a system call (getloop())) is used to extract these +data from the kernel for monitoring purposes. + +All programs utilize the system clock status variable time_status, which +records whether the clock is synchronized, waiting for a leap second, +etc. The value of this variable is returned by each system call. It can +be set explicitly by the setloop() system call and implicitly by the +settimeofday() system call and in the timer-interrupt routine. Values +presently defined in the header file timex.h are as follows: + +int time_status = TIME_BAD; /* clock synchronization status */ + +#define TIME_UNS 0 /* unspecified or unknown */ +#define TIME_OK 1 /* operation succeeded */ +#define TIME_INS 1 /* insert leap second at end of current day */ +#define TIME_DEL 2 /* delete leap second at end of current day */ +#define TIME_OOP 3 /* leap second in progress */ +#define TIME_BAD 4 /* system clock is not synchronized */ +#define TIME_ADR -1 /* operation failed: invalid address */ +#define TIME_VAL -2 /* operation failed: invalid argument */ +#define TIME_PRV -3 /* operation failed: priviledged operation */ + +In case of a negative result code, the operation has failed; however, +some variables may have been modified before the error was detected. +Note that the new system calls never return a value of zero, so it is +possible to determine whether the old routines or the new ones are in +use. The syntax of the modified adjtime() is as follows: + +/* + * adjtime - adjuts system time + */ +#include + +int gettimexofday(tp, fiddle) + +struct timeval *tp; /* system time adjustment*/ +struct timeval *fiddle; /* sneak path */ + +On entry the "timeval" sneak path is coded: + +struct timeval { + long tv_sec = time_constant; /* time constant */ + long tv_usec = time_freq; /* new frequency offset */ +} + +However, the sneak is ignored if fiddle is the null pointer and the new +frequency offset is ignored if zero. + +The value returned on exit is the system clock status defined above. The +"timeval" sneak path is modified as follows: + +struct timeval { + long tv_sec = time_precision; /* system clock precision */ + long tv_usec = time_freq; /* current frequency offset */ +} + +3.1. Kernel Variables + +The following variables are used by the new code: + +long time_offset = 0; /* time adjustment (us) */ + +This variable is used by the PLL to adjust the system time in small +increments. It is scaled by (1 << SHIFT_UPDATE) in binary microseconds. +The maximum value that can be represented is about +-130 ms and the +minimum value or precision is about one nanosecond. + +long time_constant = SHIFT_TAU; /* pll time constant */ + +This variable determines the bandwidth or "stiffness" of the PLL. It is +used as a shift, with the effective value in positive powers of two. The +optimum value for this variable is equal to 1/64 times the update +interval. The default value SHIFT_TAU (0) corresponds to a PLL time +constant of about one hour or an update interval of about one minute, +which is appropriate for typical uncompensated quartz oscillators used +in most computing equipment. Values larger than four are not useful, +unless the local clock timebase is derived from a precision oscillator. + +long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */ + +This variable represents the maximum frequency error or tolerance of the +particular platform and is a property of the architecture. It is +expressed as a positive number greater than zero in parts-per-million +(ppm). The default MAXFREQ (100) is appropriate for conventional +workstations. + +long time_precision = 1000000 / HZ; /* clock precision (us) */ + +This variable represents the maximum error in reading the system clock. +It is expressed as a positive number greater than zero in microseconds +and is usually based on the number of microseconds between timer +interrupts, in the case of the Ultrix kernel, 3906. However, in cases +where the time can be interpolated between timer interrupts with +microsecond resolution, the precision is specified as 1. This variable +is computed by the kernel for use by the time-synchronization daemon, +but is otherwise not used by the kernel. + +struct timeval time_maxerror; /* maximum error */ + +This variable represents the maximum error, expressed as a Unix timeval, +of the system clock. For NTP, it is computed as the synchronization +distance, which is equal to one-half the root delay plus the root +dispersion. It is increased by a small amount (time_tolerance) each +second to reflect the clock frequency tolerance. This variable is +computed by the time-synchronization daemon and the kernel for use by +the application program, but is otherwise not used by the kernel. + +struct timeval time_esterror; /* estimated error */ + +This variable represents the best estimate of the actual error, +expressed as a Unix timeval, of the system clock based on its past +behavior, together with observations of multiple clocks within the peer +group. This variable is computed by the time-synchronization daemon for +use by the application program, but is otherwise not used by the kernel. + +The PLL itself is controlled by the following variables: + +long time_phase = 0; /* phase offset (scaled us) */ +long time_freq = 0; /* frequency offset (scaled ppm) */long +time_adj = 0; /* tick adjust (scaled 1 / HZ) */ + +These variables control the phase increment and the frequency increment +of the system clock at each tick of the clock. The time_phase variable +is scaled by (1 << SHIFT_SCALE) in binary microseconds, giving a minimum +value (time resolution) of 9.3e-10 us. The time_freq variable is scaled +by (1 << SHIFT_KF) in parts-per-million (ppm), giving it a maximum value +of about +-130 ppm and a minimum value (frequency resolution) of 6e-8 +ppm. The time_adj variable is the actual phase increment in scaled +microseconds to add to time_phase once each tick. It is computed from +time_phase and time_freq once per second. + +long time_reftime = 0; /* time at last adjustment (s) */ + +This variable is the second's portion of the system time on the last +call to adjtime(). It is used to adjust the time_freq variable as the +time since the last update increases. + +The HZ define establishes the timer interrupt frequency, 256 Hz for the +Ultrix kernel and 100 Hz for the SunOS kernel. The SHIFT_HZ define +expresses the same value as the nearest power of two in order to avoid +hardware multiply operations. These are the only parameters that need to +be changed for different timer interrupt rates. + +#define HZ 256 /* timer interrupt frequency (Hz) */ +#define SHIFT_HZ 8 /* log2(HZ) */ + +The following defines establish the engineering parameters of the PLL +model. They are chosen for an initial convergence time of about an hour, +an overshoot of about seven percent and a final convergence time of +several hours, depending on initial frequency error. + +#define SHIFT_KG 10 /* shift for phase increment */ +#define SHIFT_KF 24 /* shift for frequency increment */ +#define SHIFT_TAU 0 /* default time constant (shift) */ + +The SHIFT_SCALE define establishes the decimal point on the time_phase +variable which serves as a an extension to the low-order bits of the +system clock variable. The SHIFT_UPDATE define establishes the decimal +point of the phase portion of the adjtime() update. The FINEUSEC define +represents 1 us in scaled units. + +#define SHIFT_SCALE 28 /* shift for scale factor */ +#define SHIFT_UPDATE 14 /* shift for offset scale factor */ +#define FINEUSEC (1 << SHIFT_SCALE) /* 1 us in scaled units */ + +The FINETUNE define represents the residual, in ppm, to be added to the +system clock variable in addition to the integral 1-us value given by +tick. This allows a systematic frequency offset in cases where the timer +interrupt frequency does not exactly divide the second in microseconds. + +#define FINETUNE (1000000 - (1000000 / HZ) * HZ) /* frequency adjustment + * for non-isochronous HZ (ppm) */ + +The following four defines establish the performance envelope of the +PLL, one to bound the maximum phase error, another to bound the maximum +frequency error and the last two to bound the minimum and maximum time +between updates. The intent of these bounds is to force the PLL to +operate within predefined limits in order to conform to the correctness +models assumed by time-synchronization protocols like NTP and DTSS. An +excursion which exceeds these bounds is clamped to the bound and +operation proceeds accordingly. In practice, this can occur only if +something has failed or is operating out of tolerance, but otherwise the +PLL continues to operate in a stable mode. Note that the MAXPHASE define +conforms to the maximum offset allowed in NTP before the system time is +reset, rather than incrementally adjusted. + +#define MAXPHASE 128000 /* max phase error (us) */ +#define MINSEC 64 /* min interval between updates (s) */ +#define MAXFREQ 100 /* max frequency error (ppm) */ +#define MAXSEC 1024 /* max interval between updates (s) */ + +3.2. Code Segments + +The code segments illustrated in the simulator should make clear the +operations at various points in the code. These segments are not derived +from any licensed code. The hardupdate() fragment is called by adjtime() +to update the system clock phase and frequency. This is an +implementation of an adaptive-parameter, first-order, type-II phase-lock +loop. Note that the time constant is in units of powers of two, so that +multiplies can be done by simple shifts. The phase variable is computed +as the offset multiplied by the time constant. Then, the time since the +last update is computed and clamped to a maximum (for robustness) and to +zero if initializing. The offset is multiplied (sorry about the ugly +multiply) by the result and by the square of the time constant and then +added to the frequency variable. Finally, the frequency variable is +clamped not to exceed the tolerance. Note that all shifts are assumed to +be positive and that a shift of a signed quantity to the right requires +a litle dance. + +With the defines given, the maximum time offset is determined by the +size in bits of the long type (32) less the SHIFT_UPDATE (14) scale +factor or 18 bits (signed). The scale factor is chosen so that there is +no loss of significance in later steps, which may involve a right shift +up to 14 bits. This results in a maximum offset of about +-130 ms. Since +the time_constant must be greater than or equal to zero, the maximum +frequency offset is determined by the SHIFT_KF (24) scale factor, or +about +-130 ppm. In the addition step the value of offset * mtemp is +represented in 18 + 10 = 28 bits, which will not overflow a long add. +There could be a loss of precision due to the right shift of up to eight +bits, since time_constant is bounded at four. This results in a net +worst-case frequency error of about 2^-16 us or well down into the +oscillator phase noise. While the time_offset value is assumed checked +before entry, the time_phase variable is an accumulator, so is clamped +to the tolerance on every call. This helps to damp transients before the +oscillator frequency has been determined, as well as to satisfy the +correctness assertions if the time-synchronization protocol comes +unstuck. + +The hardclock() fragment is inserted in the hardware timer interrupt +routine at the point the system clock is to be incremented. The phase +adjustment (time_adj) is added to the clock phase (time_phase) and +tested for overflow of the microsecond. If an overflow occurs, the +microsecond (tick) in incremented or decremented. + +The second_overflow() fragment is inserted at the point where the +microseconds field of the system time variable is being checked for +overflow. On rollover of the second the maximum error is increased by +the tolerance. The time offset is divided by the phase weight (SHIFT_KG) +and time constant. The time offset is then reduced by the result and the +result is scaled and becomes the value of the phase adjustment. The +phase adjustment is then corrected for the calculated frequency offset +and a fixed offset FINETUNE which is a property of the architecture. On +rollover of the day the leap-warning indicator is checked and the +apparent time adjusted +-1 s accordingly. The gettimeofday() routine +insures that the reported time is always monotonically increasing. + +The simulator can be used to check the loop operation over the design +range of +-128 ms in time error and +-100 ppm in frequency error. This +confirms that no overflows occur and that the loop initially converges +in about 50-60 minutes for timer interrupt rates from 50 Hz to 1024 Hz. +The loop has a normal overshoot of about seven percent and a final +convergence time of several hours, depending on the initional frequency +error. + +3.3. Leap Seconds + +The leap-warning condition is determined by the synchronization protocol +(if remotely synchronized), by the timecode receiver (if available), or +by the operator (if awake). The time_status value must be set on the day +the leap event is to occur (30 June or 31 December) and is automatically +reset after the event. If the value is TIME_DEL, the kernel adds one +second to the system time immediately following second 23:59:58 and +resets time_status to TIME_OK. If the value is TIME_INS, the kernel +subtracts one second from the system time immediately following second +23:59:59 and resets time_status to TIME_OOP, in effect causing system +time to repeat second 59. Immediately following the repeated second, the +kernel resets time_status to TIME_OK. + +Depending upon the system call implementation, the reported time during +a leap second may repeat (with a return code set to advertise that fact) +or be monotonically adjusted until system time "catches up" to reported +time. With the latter scheme the reported time will be correct before +and after the leap second, but freeze or slowly advance during the leap +second itself. However, Most programs will probably use the ctime() +library routine to convert from timeval (seconds, microseconds) format +to tm format (seconds, minutes,...). If this routine is modified to +inspect the return code of the gettimeofday() routine, it could simply +report the leap second as second 60. + +To determine local midnight without fuss, the kernel simply finds the +residue of the time.tv_sec value mod 86,400, but this requires a messy +divide. Probably a better way to do this is to initialize an auxiliary +counter in the settimeofday() routine using an ugly divide and increment +the counter at the same time the time.tv_sec is incremented in the timer +interrupt routine. For future embellishment. + +4. Proposed Application Program Interface + +Most programs read the system clock using the gettimeofday() system +call, which returns the system time and time-zone data. In the modified +5000/240 kernel, the gettimeofday() routine calls the microtime() +routine, which interpolates between hardware timer interrupts to a +precision of +-1 microsecond. However, the synchronization protocol +provides additional information that will be of interest in many +applications. For some applications it is necessary to know the maximum +error of the reported time due to all causes, including those due to the +system clock reading error, oscillator frequency error and accumulated +errors due to intervening time servers on the path to a primary +reference source. However, for those protocols that adjust the system +clock frequency as well as the time offset, the errors expected in +actual use will almost always be much less than the maximum error. +Therefore, it is useful to report the estimated error, as well as the +maximum error. + +It does not seem useful to provide additional details private to the +kernel and synchronization protocol, such as stratum, reference +identifier, reference timestamp and so forth. It would in principle be +possible for the application to independently evaluate the quality of +time and project into the future how long this time might be "valid." +However, to do that properly would duplicate the functionality of the +synchronization protocol and require knowledge of many mundane details +of the platform architecture, such as the tick value, reachability +status and related variables. Therefore, the application interface does +not reveal anything except the time, timezone and error data. + +With respect to NTP, the data maintained by the protocol include the +roundtrip delay and total dispersion to the source of synchronization. +In terms of the above, the maximum error is computed as half the delay +plus the dispersion, while the estimated error is equal to the +dispersion. These are reported in timeval structures. A new system call +is proposed that includes all the data in the gettimeofday() plus the +two new timeval structures. + +The proposed interface involves modifications to the gettimeofday(), +settimeofday() and adjtime() system calls, as well as new system calls +to get and set various system parameters. In order to minimize +confusion, by convention the new system calls are named with an "x" +following the "time"; e.g., adjtime() becomes adjtimex(). The operation +of the modified gettimexofday(), settimexofday() and adjtimex() system +calls is identical to that of their prototypes, except for the error +quantities and certain other side effects, as documented below. By +convention, a NULL pointer can be used in place of any argument, in +which case the argument is ignored. + +The synchronization protocol daemon needs to set and adjust the system +clock and certain other kernel variables. It needs to read these +variables for monitoring purposes as well. The present list of these +include a subset of the variables defined previously: + +long time_precision +long time_timeconstant +long time_tolerance +long time_freq +long time_status + +/* + * gettimexofday, settimexofday - get/set date and time + */ +#include + +int gettimexofday(tp, tzp, tmaxp, testp) + +struct timeval *tp; /* system time */ +struct timezone *tzp; /* timezone */ +struct timeval *tmaxp; /* maximum error */ +struct timeval *testp; /* estimated error */ + +The settimeofday() syntax is identical. Note that a call to +settimexofday() automatically results in the system being declared +unsynchronized (TIME_BAD return code), since the synchronization +condition can only be achieved by the synchronization daemon using an +internal or external primary reference source and the adjtimex() system +call. + +/* + * adjtimex - adjust system time + */ +#include + +int adjtimex(tp, tzp, freq, tc) + +struct timeval *tp; /* system time */ +struct timezone *tzp; /* timezone */ +long freq; /* frequency adjustment */ +long tc; /* time constant */ + +/* + * getloop, setloop - get/set kernel time variables + */ +#include + +int getloop(code, argp) + +int code; /* operation code */ +long *argp; /* argument pointer */ + +The paticular kernal variables affected by these routines are selected +by the operation code. Values presently defined in the header file +timex.h are as follows: + +#define TIME_PREC 1 /* precision (log2(sec)) */ +#define TIME_TCON 2 /* time constant (log2(sec) */ +#define TIME_FREQ 3 /* frequency tolerance */ +#define TIME_FREQ 4 /* frequency offset (scaled) */ +#define TIME_STAT 5 /* status (see return codes) */ + +The getloop() syntax is identical. + +Comments welcome, but very little support is available: + +David L. Mills +Electrical Engineering Department +University of Delaware +Newark, DE 19716 +302 831 8247 fax 302 831 4316 +mills@udel.edu diff --git a/contrib/xntpd/kernel/README.streams b/contrib/xntpd/kernel/README.streams new file mode 100644 index 0000000000..26c2825b50 --- /dev/null +++ b/contrib/xntpd/kernel/README.streams @@ -0,0 +1,86 @@ +Some kernels don't support additional user defined line disciplines. +Especially notable in this regard is SunOS and System V. They +provide similar support in the form of "Streams". Accordingly, +included in this directory is a pair of STREAMS modules to +replace the line disciplines that provide clock support for +xntpd. Notice that the "clkdefs.h" file is not used in the +original line discipline, but the "chudefs.h" file is the +same one used in the original line discipline. + +TO INSTALL A NEW STREAMS DRIVER: + +1. Copy your choice to /sys/os, removing the "_STREAMS" in the +filename. + +2. Copy the appropriate *defs.h file to /usr/include/sys, +then link it (with ln) to /sys/sys. + +In the following steps, substitute "clk" for "chu" if you're +installing the clk driver. + +3. Append to /sys/conf.common/files.cmn: + +os/tty_chu.c optional chu + +4. Edit /sys/sun/str_conf.c. You'll want to add lines in three +places. It'll be sort of clear where when you see the file. + +. +. +. +#include "chu.h" +. +. +. +#if NCHU > 0 +extern struct streamtab chuinfo; +#endif +. +. +. +#if NCHU > 0 + { "chu", &chuinfo }, +#endif +. +. +. + +At this point, the kernel-making "config [k-name] ; cd ../[k-name] ; make" +should produce a kernel just as it did before. If it fouls up, +something's wrong. + +5. Edit /sys/[arch]/conf/[k-name] (substituting the architecture and +kernel name) to stick in: + +pseudo-device chu4 # CHU clock support + +You can change 4 to anything you like. It will limit the number +of instantiations of the chu driver you can use at the same time. + +6. Make a new kernel and boot it. + +HOW TO USE THE CHU STREAMS DRIVER: + +The driver should act exactly like the line discipline. +After setting the raw mode, and exclusive access (if you want), +pop off all the extra streams, then push the chu module +on. From then on, any reads from the file in question +will return chucode structures as defined in chudefs.h. +Depending on the settings of PEDANTIC and ANAL_RETENTIVE +used when compiling the kernel, some checking of the +data may or may not be necessary. + +HOW TO USE THE CLK STREAMS DRIVER: + +First, it should be noted that a new ioctl() has been defined. +The CLK_SETSTR ioctl takes a pointer to a string of no more +than CLK_MAXSTRSIZE characters. Until the first CLK_SETSTR +is performed, the driver will simply pass through characters. +Once it is passed a string, then any character in that string +will be immediately followed by a struct timeval. You can +change the string whenever you want by doing another +CLK_SETSTR. The character must be an exact, 8 bit match. +The character '\000' cannot, unfortunately, be stamped. +Passing an empty string to CLK_SETSTR turns off stamping. +Passing NULL will produce undefined results. + diff --git a/contrib/xntpd/kernel/tty_chu.c b/contrib/xntpd/kernel/tty_chu.c new file mode 100644 index 0000000000..4615875e77 --- /dev/null +++ b/contrib/xntpd/kernel/tty_chu.c @@ -0,0 +1,276 @@ +/* tty_chu.c,v 3.1 1993/07/06 01:07:30 jbj Exp + * tty_chu.c - CHU line driver + */ + +#include "chu.h" +#if NCHU > 0 + +#include "../h/param.h" +#include "../h/types.h" +#include "../h/systm.h" +#include "../h/dir.h" +#include "../h/user.h" +#include "../h/ioctl.h" +#include "../h/tty.h" +#include "../h/proc.h" +#include "../h/file.h" +#include "../h/conf.h" +#include "../h/buf.h" +#include "../h/uio.h" + +#include "../h/chudefs.h" + +/* + * Line discipline for receiving CHU time codes. + * Does elementary noise elimination, takes time stamps after + * the arrival of each character, returns a buffer full of the + * received 10 character code and the associated time stamps. + */ +#define NUMCHUBUFS 3 + +struct chudata { + u_char used; /* Set to 1 when structure in use */ + u_char lastindex; /* least recently used buffer */ + u_char curindex; /* buffer to use */ + u_char sleeping; /* set to 1 when we're sleeping on a buffer */ + struct chucode chubuf[NUMCHUBUFS]; +} chu_data[NCHU]; + +/* + * Number of microseconds we allow between + * character arrivals. The speed is 300 baud + * so this should be somewhat more than 30 msec + */ +#define CHUMAXUSEC (50*1000) /* 50 msec */ + +int chu_debug = 0; + +/* + * Open as CHU time discipline. Called when discipline changed + * with ioctl, and changes the interpretation of the information + * in the tty structure. + */ +/*ARGSUSED*/ +chuopen(dev, tp) + dev_t dev; + register struct tty *tp; +{ + register struct chudata *chu; + + /* + * Don't allow multiple opens. This will also protect us + * from someone opening /dev/tty + */ + if (tp->t_line == CHULDISC) + return (EBUSY); + ttywflush(tp); + for (chu = chu_data; chu < &chu_data[NCHU]; chu++) + if (!chu->used) + break; + if (chu >= &chu[NCHU]) + return (EBUSY); + chu->used++; + chu->lastindex = chu->curindex = 0; + chu->sleeping = 0; + chu->chubuf[0].ncodechars = 0; + tp->T_LINEP = (caddr_t) chu; + return (0); +} + +/* + * Break down... called when discipline changed or from device + * close routine. + */ +chuclose(tp) + register struct tty *tp; +{ + register int s = spl5(); + + ((struct chudata *) tp->T_LINEP)->used = 0; + tp->t_cp = 0; + tp->t_inbuf = 0; + tp->t_rawq.c_cc = 0; /* clear queues -- paranoid */ + tp->t_canq.c_cc = 0; + tp->t_line = 0; /* paranoid: avoid races */ + splx(s); +} + +/* + * Read a CHU buffer. Sleep on the current buffer + */ +churead(tp, uio) + register struct tty *tp; + struct uio *uio; +{ + register struct chudata *chu; + register struct chucode *chucode; + register int s; + + if ((tp->t_state&TS_CARR_ON)==0) + return (EIO); + + chu = (struct chudata *) (tp->T_LINEP); + + s = spl5(); + chucode = &(chu->chubuf[chu->lastindex]); + while (chu->curindex == chu->lastindex) { + chu->sleeping = 1; + sleep((caddr_t)chucode, TTIPRI); + } + chu->sleeping = 0; + if (++(chu->lastindex) >= NUMCHUBUFS) + chu->lastindex = 0; + splx(s); + + return (uiomove((caddr_t)chucode, sizeof(*chucode), UIO_READ, uio)); +} + +/* + * Low level character input routine. + * If the character looks okay, grab a time stamp. If the stuff in + * the buffer is too old, dump it and start fresh. If the character is + * non-BCDish, everything in the buffer too. + */ +chuinput(c, tp) + register int c; + register struct tty *tp; +{ + register struct chudata *chu = (struct chudata *) tp->T_LINEP; + register struct chucode *chuc; + register int i; + long sec, usec; + struct timeval tv; + + /* + * Do a check on the BSDness of the character. This delays + * the time stamp a bit but saves a fair amount of overhead + * when the static is bad. + */ + if (((c) & 0xf) > 9 || (((c)>>4) & 0xf) > 9) { + chuc = &(chu->chubuf[chu->curindex]); + chuc->ncodechars = 0; /* blow all previous away */ + return; + } + + /* + * Call microtime() to get the current time of day + */ + microtime(&tv); + + /* + * Compute the difference in this character's time stamp + * and the last. If it exceeds the margin, blow away all + * the characters currently in the buffer. + */ + chuc = &(chu->chubuf[chu->curindex]); + i = (int)chuc->ncodechars; + if (i > 0) { + sec = tv.tv_sec - chuc->codetimes[i-1].tv_sec; + usec = tv.tv_usec - chuc->codetimes[i-1].tv_usec; + if (usec < 0) { + sec -= 1; + usec += 1000000; + } + if (sec != 0 || usec > CHUMAXUSEC) { + i = 0; + chuc->ncodechars = 0; + } + } + + /* + * Store the character. If we're done, have to tell someone + */ + chuc->codechars[i] = (u_char)c; + chuc->codetimes[i] = tv; + + if (++i < NCHUCHARS) { + /* + * Not much to do here. Save the count and wait + * for another character. + */ + chuc->ncodechars = (u_char)i; + } else { + /* + * Mark this buffer full and point at next. If the + * next buffer is full we overwrite it by bumping the + * next pointer. + */ + chuc->ncodechars = NCHUCHARS; + if (++(chu->curindex) >= NUMCHUBUFS) + chu->curindex = 0; + if (chu->curindex == chu->lastindex) + if (++(chu->lastindex) >= NUMCHUBUFS) + chu->lastindex = 0; + chu->chubuf[chu->curindex].ncodechars = 0; + + /* + * Wake up anyone sleeping on this. Also wake up + * selectors and/or deliver a SIGIO as required. + */ + if (tp->t_rsel) { + selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); + tp->t_state &= ~TS_RCOLL; + tp->t_rsel = 0; + } + if (tp->t_state & TS_ASYNC) + gsignal(tp->t_pgrp, SIGIO); + if (chu->sleeping) + (void) wakeup((caddr_t)chuc); + } +} + +/* + * Handle ioctls. We reject all tty-style except those that + * change the line discipline. + */ +chuioctl(tp, cmd, data, flag) + struct tty *tp; + int cmd; + caddr_t data; + int flag; +{ + + if ((cmd>>8) != 't') + return (-1); + switch (cmd) { + case TIOCSETD: + case TIOCGETD: + case TIOCGETP: + case TIOCGETC: + return (-1); + } + return (ENOTTY); /* not quite appropriate */ +} + + +chuselect(dev, rw) + dev_t dev; + int rw; +{ + register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; + struct chudata *chu; + int s = spl5(); + + chu = (struct chudata *) (tp->T_LINEP); + + switch (rw) { + + case FREAD: + if (chu->curindex != chu->lastindex) + goto win; + if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_RCOLL; + else + tp->t_rsel = u.u_procp; + break; + + case FWRITE: + goto win; + } + splx(s); + return (0); +win: + splx(s); + return (1); +} +#endif NCHU diff --git a/contrib/xntpd/kernel/tty_chu_STREAMS.c b/contrib/xntpd/kernel/tty_chu_STREAMS.c new file mode 100644 index 0000000000..eea792d91c --- /dev/null +++ b/contrib/xntpd/kernel/tty_chu_STREAMS.c @@ -0,0 +1,444 @@ +/* tty_chu_STREAMS.c,v 3.1 1993/07/06 01:07:32 jbj Exp + * CHU STREAMS module for SunOS 4.1.x + * + * Version 2.1 + * + * Copyright 1991-1993, Nick Sayer + * + * Special thanks to Greg Onufer for his debug assists. + * Special thanks to Matthias Urlichs for the loadable driver support + * code. + * + * Should be PUSHed directly on top of a serial I/O channel. + * Provides complete chucode structures to user space. + * + * COMPILATION: + * + * To make a SunOS 4.1.x compatable loadable module (from the ntp kernel + * directory): + * + * % cc -c -I../include -DLOADABLE tty_chu_STREAMS.c + * + * The resulting .o file is the loadable module. Modload it + * with -entry _chuinit. + * + * You can also add it into the kernel by hacking it into the streams + * table in the kernel, then adding it to config: + * + * pseudo-device chuN + * + * where N is the maximum number of concurent chu sessions you expect + * to have. + * + * HISTORY: + * + * v2.1 - Added 'sixth byte' heuristics. + * v2.0 - first version with an actual version number. + * Added support for new CHU 'second 31' data format. + * Deleted PEDANTIC and ANAL_RETENTIVE. + * + */ + +#ifndef LOADABLE +# include "chu.h" +#else +# ifndef NCHU +# define NCHU 3 +# define KERNEL +# endif +#endif + +#if NCHU > 0 + +/* + * Number of microseconds we allow between + * character arrivals. The speed is 300 baud + * so this should be somewhat more than 30 msec + */ +#define CHUMAXUSEC (60*1000) /* 60 msec */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct module_info rminfo = { 0, "chu", 0, INFPSZ, 0, 0 }; +static struct module_info wminfo = { 0, "chu", 0, INFPSZ, 0, 0 }; +static int chuopen(), churput(), chuwput(), chuclose(); + +static struct qinit rinit = { churput, NULL, chuopen, chuclose, NULL, + &rminfo, NULL }; + +static struct qinit winit = { chuwput, NULL, NULL, NULL, NULL, + &wminfo, NULL }; + +struct streamtab chuinfo = { &rinit, &winit, NULL, NULL }; + +/* + * Here's our private data type and structs + */ +struct priv_data +{ + char in_use; + struct chucode chu_struct; +} our_priv_data[NCHU]; + +#ifdef LOADABLE + +#ifdef sun +#include +#include +#include +#include +#include + +static struct vdldrv vd = +{ + VDMAGIC_PSEUDO, + "chu", + NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0, +}; + +static struct fmodsw *chu_fmod; + +/*ARGSUSED*/ +chuinit (fc, vdp, vdi, vds) + unsigned int fc; + struct vddrv *vdp; + addr_t vdi; + struct vdstat *vds; +{ + switch (fc) { + case VDLOAD: + { + int dev, i; + + /* Find free entry in fmodsw */ + for (dev = 0; dev < fmodcnt; dev++) { + if (fmodsw[dev].f_str == NULL) + break; + } + if (dev == fmodcnt) + return (ENODEV); + chu_fmod = &fmodsw[dev]; + + /* If you think a kernel would have strcpy() you're mistaken. */ + for (i = 0; i <= FMNAMESZ; i++) + chu_fmod->f_name[i] = wminfo.mi_idname[i]; + + chu_fmod->f_str = &chuinfo; + } + vdp->vdd_vdtab = (struct vdlinkage *) & vd; + + { + int i; + + for (i=0; if_name[0] = '\0'; + chu_fmod->f_str = NULL; + return 0; + case VDSTAT: + return 0; + default: + return EIO; + } +} + +#endif + +#else + +char chu_first_open=1; + +#endif + +/*ARGSUSED*/ +static int chuopen(q, dev, flag, sflag) +queue_t *q; +dev_t dev; +int flag; +int sflag; +{ + int i; + +#ifndef LOADABLE + if (chu_first_open) + { + chu_first_open=0; + + for(i=0;iq_ptr))=&(our_priv_data[i]); + our_priv_data[i].in_use++; + our_priv_data[i].chu_struct.ncodechars = 0; + return 0; + } + + u.u_error = EBUSY; + return (OPENFAIL); + +} + +/*ARGSUSED*/ +static int chuclose(q, flag) +queue_t *q; +int flag; +{ + ((struct priv_data *) (q->q_ptr))->in_use=0; + + return (0); +} + +/* + * Now the crux of the biscuit. + * + * We will be passed data from the man downstairs. If it's not a data + * packet, it must be important, so pass it along unmunged. If, however, + * it is a data packet, we're gonna do special stuff to it. We're going + * to pass each character we get to the old line discipline code we + * include below for just such an occasion. When the old ldisc code + * gets a full chucode struct, we'll hand it back upstairs. + * + * chuinput takes a single character and q (as quickly as possible). + * passback takes a pointer to a chucode struct and q and sends it upstream. + */ + +void chuinput(); +void passback(); + +static int churput(q, mp) +queue_t *q; +mblk_t *mp; +{ + mblk_t *bp; + + switch(mp->b_datap->db_type) + { + case M_DATA: + for(bp=mp; bp!=NULL; bp=bp->b_cont) + { + while(bp->b_rptr < bp->b_wptr) + chuinput( ((u_char)*(bp->b_rptr++)) , q ); + } + freemsg(mp); + break; + default: + putnext(q,mp); + break; + } + +} + +/* + * Writing to a chu device doesn't make sense, but we'll pass them + * through in case they're important. + */ + +static int chuwput(q, mp) +queue_t *q; +mblk_t *mp; +{ + putnext(q,mp); +} + +/* + * Take a pointer to a filled chucode struct and a queue and + * send the chucode stuff upstream + */ + +void passback(outdata,q) +struct chucode *outdata; +queue_t *q; +{ + mblk_t *mp; + int j; + + mp=(mblk_t*) allocb(sizeof(struct chucode),BPRI_LO); + + if (mp==NULL) + { + log(LOG_ERR,"chu: cannot allocate message"); + return; + } + + for(j=0;jb_wptr++ = *( ((char*)outdata) + j ); + + putnext(q,mp); +} + +/* + * This routine was copied nearly verbatim from the old line discipline. + */ +void chuinput(c,q) +register u_char c; +queue_t *q; +{ + register struct chucode *chuc; + register int i; + long sec, usec; + struct timeval tv; + + /* + * Quick, Batman, get a timestamp! We need to do this + * right away. The time between the end of the stop bit + * and this point is critical, and should be as nearly + * constant and as short as possible. (Un)fortunately, + * the Sun's clock granularity is so big this isn't a + * major problem. + * + * uniqtime() is totally undocumented, but there you are. + */ + uniqtime(&tv); + + /* + * Now, locate the chu struct once so we don't have to do it + * over and over. + */ + chuc=&(((struct priv_data *) (q->q_ptr))->chu_struct); + + /* + * Compute the difference in this character's time stamp + * and the last. If it exceeds the margin, blow away all + * the characters currently in the buffer. + */ + i = (int)chuc->ncodechars; + if (i > 0) + { + sec = tv.tv_sec - chuc->codetimes[i-1].tv_sec; + usec = tv.tv_usec - chuc->codetimes[i-1].tv_usec; + if (usec < 0) + { + sec -= 1; + usec += 1000000; + } + if (sec != 0 || usec > CHUMAXUSEC) + { + i = 0; + chuc->ncodechars = 0; + } + } + + /* + * Store the character. + */ + chuc->codechars[i] = (u_char)c; + chuc->codetimes[i] = tv; + + /* + * Now we perform the 'sixth byte' heuristics. + * + * This is a long story. + * + * We used to be able to count on the first byte of the code + * having a '6' in the LSD. This prevented most code framing + * errors (garbage before the first byte wouldn't typically + * have a 6 in the LSD). That's no longer the case. + * + * We can get around this, however, by noting that the 6th byte + * must be either equal to or one's complement of the first. + * If we get a sixth byte that ISN'T like that, then it may + * well be that the first byte is garbage. The right thing + * to do is to left-shift the whole buffer one count and + * continue to wait for the sixth byte. + */ + if (i == NCHUCHARS/2) + { + register u_char temp_byte; + + temp_byte=chuc->codechars[i] ^ chuc->codechars[0]; + + if ( (temp_byte) && (temp_byte!=0xff) ) + { + register int t; + /* + * No match. Left-shift the buffer and try again + */ + for(t=0;t<=NCHUCHARS/2;t++) + { + chuc->codechars[t]=chuc->codechars[t+1]; + chuc->codetimes[t]=chuc->codetimes[t+1]; + } + + i--; /* This is because of the ++i immediately following */ + } + } + + /* + * We done yet? + */ + if (++i < NCHUCHARS) + { + /* + * We're not done. Not much to do here. Save the count and wait + * for another character. + */ + chuc->ncodechars = (u_char)i; + } + else + { + /* + * We are done. Mark this buffer full and pass it along. + */ + chuc->ncodechars = NCHUCHARS; + + /* + * Now we have a choice. Either the front half and back half + * have to match, or be one's complement of each other. + * + * So let's try the first byte and see + */ + + if(chuc->codechars[0] == chuc->codechars[NCHUCHARS/2]) + { + chuc->chutype = CHU_TIME; + for( i=0; i<(NCHUCHARS/2); i++) + if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) + { + chuc->ncodechars = 0; + return; + } + } + else + { + chuc->chutype = CHU_YEAR; + for( i=0; i<(NCHUCHARS/2); i++) + if (((chuc->codechars[i] ^ chuc->codechars[i+(NCHUCHARS/2)]) & 0xff) + != 0xff ) + { + chuc->ncodechars = 0; + return; + } + } + + passback(chuc,q); /* We're done! */ + chuc->ncodechars = 0; /* Start all over again! */ + } +} + +#endif diff --git a/contrib/xntpd/kernel/tty_clk.c b/contrib/xntpd/kernel/tty_clk.c new file mode 100644 index 0000000000..d1b4bbef64 --- /dev/null +++ b/contrib/xntpd/kernel/tty_clk.c @@ -0,0 +1,303 @@ +/* tty_clk.c,v 3.1 1993/07/06 01:07:33 jbj Exp + * tty_clk.c - Generic line driver for receiving radio clock timecodes + */ + +#include "clk.h" +#if NCLK > 0 + +#include "../h/param.h" +#include "../h/types.h" +#include "../h/systm.h" +#include "../h/dir.h" +#include "../h/user.h" +#include "../h/ioctl.h" +#include "../h/tty.h" +#include "../h/proc.h" +#include "../h/file.h" +#include "../h/conf.h" +#include "../h/buf.h" +#include "../h/uio.h" +#include "../h/clist.h" + +/* + * This line discipline is intended to provide well performing + * generic support for the reception and time stamping of radio clock + * timecodes. Most radio clock devices return a string where a + * particular character in the code (usually a \r) is on-time + * synchronized with the clock. The idea here is to collect characters + * until (one of) the synchronization character(s) (we allow two) is seen. + * When the magic character arrives we take a timestamp by calling + * microtime() and insert the eight bytes of struct timeval into the + * buffer after the magic character. We then wake up anyone waiting + * for the buffer and return the whole mess on the next read. + * + * To use this the calling program is expected to first open the + * port, and then to set the port into raw mode with the speed + * set appropriately with a TIOCSETP ioctl(), with the erase and kill + * characters set to those to be considered magic (yes, I know this + * is gross, but they were so convenient). If only one character is + * magic you can set then both the same, or perhaps to the alternate + * parity versions of said character. After getting all this set, + * change the line discipline to CLKLDISC and you are on your way. + * + * The only other bit of magic we do in here is to flush the receive + * buffers on writes if the CRMOD flag is set (hack, hack). + */ + +/* + * We run this very much like a raw mode terminal, with the exception + * that we store up characters locally until we hit one of the + * magic ones and then dump it into the rawq all at once. We keep + * the buffered data in clists since we can then often move it to + * the rawq without copying. For sanity we limit the number of + * characters between specials, and the total number of characters + * before we flush the rawq, as follows. + */ +#define CLKLINESIZE (256) +#define NCLKCHARS (CLKLINESIZE*4) + +struct clkdata { + int inuse; + struct clist clkbuf; +}; +#define clk_cc clkbuf.c_cc +#define clk_cf clkbuf.c_cf +#define clk_cl clkbuf.c_cl + +struct clkdata clk_data[NCLK]; + +/* + * Routine for flushing the internal clist + */ +#define clk_bflush(clk) (ndflush(&((clk)->clkbuf), (clk)->clk_cc)) + +int clk_debug = 0; + +/*ARGSUSED*/ +clkopen(dev, tp) + dev_t dev; + register struct tty *tp; +{ + register struct clkdata *clk; + + /* + * Don't allow multiple opens. This will also protect us + * from someone opening /dev/tty + */ + if (tp->t_line == CLKLDISC) + return (EBUSY); + ttywflush(tp); + for (clk = clk_data; clk < &clk_data[NCLK]; clk++) + if (!clk->inuse) + break; + if (clk >= &clk_data[NCLK]) + return (EBUSY); + clk->inuse++; + clk->clk_cc = 0; + clk->clk_cf = clk->clk_cl = NULL; + tp->T_LINEP = (caddr_t) clk; + return (0); +} + + +/* + * Break down... called when discipline changed or from device + * close routine. + */ +clkclose(tp) + register struct tty *tp; +{ + register struct clkdata *clk; + register int s = spltty(); + + clk = (struct clkdata *)tp->T_LINEP; + if (clk->clk_cc > 0) + clk_bflush(clk); + clk->inuse = 0; + tp->t_line = 0; /* paranoid: avoid races */ + splx(s); +} + + +/* + * Receive a write request. We pass these requests on to the terminal + * driver, except that if the CRMOD bit is set in the flags we + * first flush the input queues. + */ +clkwrite(tp, uio) + register struct tty *tp; + struct uio *uio; +{ + if (tp->t_flags & CRMOD) { + register struct clkdata *clk; + int s; + + s = spltty(); + if (tp->t_rawq.c_cc > 0) + ndflush(&tp->t_rawq, tp->t_rawq.c_cc); + clk = (struct clkdata *) tp->T_LINEP; + if (clk->clk_cc > 0) + clk_bflush(clk); + (void)splx(s); + } + ttwrite(tp, uio); +} + + +/* + * Low level character input routine. + * If the character looks okay, grab a time stamp. If the stuff in + * the buffer is too old, dump it and start fresh. If the character is + * non-BCDish, everything in the buffer too. + */ +clkinput(c, tp) + register int c; + register struct tty *tp; +{ + register struct clkdata *clk; + register int i; + register long s; + struct timeval tv; + + /* + * Check to see whether this isn't the magic character. If not, + * save the character and return. + */ +#ifdef ultrix + if (c != tp->t_cc[VERASE] && c != tp->t_cc[VKILL]) { +#else + if (c != tp->t_erase && c != tp->t_kill) { +#endif + clk = (struct clkdata *) tp->T_LINEP; + if (clk->clk_cc >= CLKLINESIZE) + clk_bflush(clk); + if (putc(c, &clk->clkbuf) == -1) { + /* + * Hopeless, no clists. Flush what we have + * and hope things improve. + */ + clk_bflush(clk); + } + return; + } + + /* + * Here we have a magic character. Get a timestamp and store + * everything. + */ + microtime(&tv); + clk = (struct clkdata *) tp->T_LINEP; + + if (putc(c, &clk->clkbuf) == -1) + goto flushout; + + s = tv.tv_sec; + for (i = 0; i < sizeof(long); i++) { + if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1) + goto flushout; + s <<= 8; + } + + s = tv.tv_usec; + for (i = 0; i < sizeof(long); i++) { + if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1) + goto flushout; + s <<= 8; + } + + /* + * If the length of the rawq exceeds our sanity limit, dump + * all the old crap in there before copying this in. + */ + if (tp->t_rawq.c_cc > NCLKCHARS) + ndflush(&tp->t_rawq, tp->t_rawq.c_cc); + + /* + * Now copy the buffer in. There is a special case optimization + * here. If there is nothing on the rawq at present we can + * just copy the clists we own over. Otherwise we must concatenate + * the present data on the end. + */ + s = (long)spltty(); + if (tp->t_rawq.c_cc <= 0) { + tp->t_rawq = clk->clkbuf; + clk->clk_cc = 0; + clk->clk_cl = clk->clk_cf = NULL; + (void) splx((int)s); + } else { + (void) splx((int)s); + catq(&clk->clkbuf, &tp->t_rawq); + clk_bflush(clk); + } + + /* + * Tell the world + */ + ttwakeup(tp); + return; + +flushout: + /* + * It would be nice if this never happened. Flush the + * internal clists and hope someone else frees some of them + */ + clk_bflush(clk); + return; +} + + +/* + * Handle ioctls. We reject most tty-style except those that + * change the line discipline and a couple of others.. + */ +clkioctl(tp, cmd, data, flag) + struct tty *tp; + int cmd; + caddr_t data; + int flag; +{ + int flags; + struct sgttyb *sg; + + if ((cmd>>8) != 't') + return (-1); + switch (cmd) { + case TIOCSETD: + case TIOCGETD: + case TIOCGETP: + case TIOCGETC: + case TIOCOUTQ: + return (-1); + + case TIOCSETP: + /* + * He likely wants to set new magic characters in. + * Do this part. + */ + sg = (struct sgttyb *)data; +#ifdef ultrix + tp->t_cc[VERASE] = sg->sg_erase; + tp->t_cc[VKILL] = sg->sg_kill; +#else + tp->t_erase = sg->sg_erase; + tp->t_kill = sg->sg_kill; +#endif + return (0); + + case TIOCFLUSH: + flags = *(int *)data; + if (flags == 0 || (flags & FREAD)) { + register struct clkdata *clk; + + clk = (struct clkdata *) tp->T_LINEP; + if (clk->clk_cc > 0) + clk_bflush(clk); + } + return (-1); + + default: + break; + } + return (ENOTTY); /* not quite appropriate */ +} +#endif NCLK diff --git a/contrib/xntpd/kernel/tty_clk_STREAMS.c b/contrib/xntpd/kernel/tty_clk_STREAMS.c new file mode 100644 index 0000000000..f41af285dc --- /dev/null +++ b/contrib/xntpd/kernel/tty_clk_STREAMS.c @@ -0,0 +1,265 @@ +/* tty_clk_STREAMS.c,v 3.1 1993/07/06 01:07:34 jbj Exp + * Timestamp STREAMS module for SunOS 4.1 + * + * Copyright 1991, Nick Sayer + * + * Special thanks to Greg Onufer for his debug assists. + * + * Should be PUSHed directly on top of a serial I/O channel. + * For any character in a user-designated set, adds a kernel + * timestamp to that character. + * + * BUGS: + * + * Only so many characters can be timestamped. This number, however, + * is adjustable. + * + * The null character ($00) cannot be timestamped. + * + * The M_DATA messages passed upstream will not be the same + * size as when they arrive from downstream, even if no + * timestamp character is in the message. This, however, + * should not affect anything. + * + */ + +#include "clk.h" +#if NCLK > 0 +/* + * How big should the messages we pass upstream be? + */ +#define MESSAGE_SIZE 128 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct module_info rminfo = { 0, "clk", 0, INFPSZ, 0, 0 }; +static struct module_info wminfo = { 0, "clk", 0, INFPSZ, 0, 0 }; +static int clkopen(), clkrput(), clkwput(), clkclose(); + +static struct qinit rinit = { clkrput, NULL, clkopen, clkclose, NULL, + &rminfo, NULL }; + +static struct qinit winit = { clkwput, NULL, NULL, NULL, NULL, + &wminfo, NULL }; + +struct streamtab clkinfo = { &rinit, &winit, NULL, NULL }; + +struct priv_data_type +{ + char in_use; + char string[CLK_MAXSTRSIZE]; +} priv_data[NCLK]; + +char first_open=1; + +/* + * God only knows why, but linking with strchr() and index() fail + * on my system, so here's a renamed copy. + */ + +u_char *str_chr(s,c) +u_char *s; +int c; +{ + while (*s) + if(*s++ == c) + return (s-1); + return NULL; +} + +/*ARGSUSED*/ +static int clkopen(q, dev, flag, sflag) +queue_t *q; +dev_t dev; +int flag; +int sflag; +{ + int i; + +/* Damn it! We can't even have the global data struct properly + initialized! So we have a mark to tell us to init the global + data on the first open */ + + if (first_open) + { + first_open=0; + + for(i=0;iq_ptr))=priv_data+i; + priv_data[i].string[0]=0; + return (0); + } + u.u_error = EBUSY; + return (OPENFAIL); +} + +/*ARGSUSED*/ +static int clkclose(q, flag) +queue_t *q; +int flag; +{ + ((struct priv_data_type *) (q->q_ptr))->in_use=0; + + return (0); +} + +/* + * Now the crux of the biscuit. + * + * If it's an M_DATA package, we take each character and pass + * it to clkchar. + */ + +void clkchar(); + +static int clkrput(q, mp) +queue_t *q; +mblk_t *mp; +{ + mblk_t *bp; + + switch(mp->b_datap->db_type) + { + case M_DATA: + clkchar(0,q,2); + for(bp=mp; bp!=NULL; bp=bp->b_cont) + { + while(bp->b_rptr < bp->b_wptr) + clkchar( ((u_char)*(bp->b_rptr++)) , q , 0 ); + } + clkchar(0,q,1); + freemsg(mp); + break; + default: + putnext(q,mp); + break; + } + +} + +/* + * If it's a matching M_IOCTL, handle it. + */ + +static int clkwput(q, mp) +queue_t *q; +mblk_t *mp; +{ + struct iocblk *iocp; + + switch(mp->b_datap->db_type) + { + case M_IOCTL: + iocp=(struct iocblk*) mp->b_rptr; + if (iocp->ioc_cmd==CLK_SETSTR) + { + strncpy( ((struct priv_data_type *) (RD(q)->q_ptr))->string, + (char *) mp->b_cont->b_rptr,CLK_MAXSTRSIZE); + /* make sure it's null terminated */ + ((struct priv_data_type *) (RD(q)->q_ptr))->string[CLK_MAXSTRSIZE-1]=0; + mp->b_datap->db_type = M_IOCACK; + qreply(q,mp); + } + else + putnext(q,mp); + break; + default: + putnext(q,mp); + break; + } +} + +/* + * Now clkchar. It takes a character, a queue pointer and an action + * flag and depending on the flag either: + * + * 0 - adds the character to the current message. If there's a + * timestamp to be done, do that too. If the message is less than + * 8 chars from being full, link in a new one, and set it up for + * the next call. + * + * 1 - sends the whole mess to Valhala. + * + * 2 - set things up. + * + * Yeah, it's an ugly hack. Complaints may be filed with /dev/null. + */ + + +void clkchar(c,q,f) + register u_char c; + queue_t *q; + char f; +{ + static char error; + static mblk_t *message,*mp; + struct timeval tv; + +/* Get a timestamp ASAP! */ + uniqtime(&tv); + + switch(f) + { + case 1: + if (!error) + putnext(q,message); + break; + case 2: + mp=message= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO); + error=(message==NULL); + if (error) + log(LOG_ERR,"clk: cannot allocate message - data lost"); + break; + case 0: + if (error) /* If we had an error, forget it. */ + return; + + *mp->b_wptr++=c; /* Put the char away first. + + /* If it's in the special string, append a struct timeval */ + + if (str_chr( ((struct priv_data_type *) (q->q_ptr))->string , + c )!=NULL) + { + int i; + + for (i=0;ib_wptr++= *( ((char*)&tv) + i ); + } + + /* If we don't have space for a complete struct timeval, and a + char, it's time for a new mp block */ + + if (((mp->b_wptr-mp->b_rptr)+sizeof(struct timeval)+2)>MESSAGE_SIZE) + { + mp->b_cont= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO); + error=(mp->b_cont==NULL); + if (error) + { + log(LOG_ERR,"clk: cannot allocate message - data lost"); + freemsg(message); + } + mp=mp->b_cont; + } + + break; + } +} + +#endif diff --git a/contrib/xntpd/lib/Makefile.tmpl b/contrib/xntpd/lib/Makefile.tmpl new file mode 100644 index 0000000000..697edcfe60 --- /dev/null +++ b/contrib/xntpd/lib/Makefile.tmpl @@ -0,0 +1,75 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:07:38 jbj Exp +# +LIBNAME= libntp +# +# xntp routines which are used a lot of places +# +COMPILER= cc +COPTS= -O +AUTHDEFS=-DDES +LIBDEFS= -DBIG_ENDIAN +RANLIB= ranlib +INSTALL= install +CLOCKDEFS= +DEFS= +DEFS_OPT= +DEFS_LOCAL= +# +INCL=-I../include +CFLAGS= $(COPTS) $(AUTHDEFS) $(LIBDEFS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +# +SOURCE= atoint.c atolfp.c atouint.c auth12crypt.c authdecrypt.c authdes.c \ + authencrypt.c authkeys.c authparity.c authreadkeys.c authusekey.c \ + buftvtots.c caljulian.c calleapwhen.c caltontp.c calyearstart.c \ + clocktime.c dofptoa.c dolfptoa.c emalloc.c fptoa.c fptoms.c getopt.c \ + gettstamp.c hextoint.c hextolfp.c humandate.c inttoa.c \ + lib_strbuf.c mfptoa.c mfptoms.c modetoa.c mstolfp.c \ + msutotsf.c numtoa.c refnumtoa.c numtohost.c octtoint.c \ + prettydate.c ranny.c tsftomsu.c tstotv.c tvtoa.c tvtots.c \ + uglydate.c uinttoa.c utvtoa.c machines.c clocktypes.c \ + md5.c a_md5encrypt.c a_md5decrypt.c \ + a_md512crypt.c decodenetnum.c systime.c msyslog.c syssignal.c \ + findconfig.c + +OBJS= atoint.o atolfp.o atouint.o auth12crypt.o authdecrypt.o authdes.o \ + authencrypt.o authkeys.o authparity.o authreadkeys.o authusekey.o \ + buftvtots.o caljulian.o calleapwhen.o caltontp.o calyearstart.o \ + clocktime.o dofptoa.o dolfptoa.o emalloc.o fptoa.o fptoms.o getopt.o \ + gettstamp.o hextoint.o hextolfp.o humandate.o inttoa.o \ + lib_strbuf.o mfptoa.o mfptoms.o modetoa.o mstolfp.o \ + msutotsf.o numtoa.o refnumtoa.o numtohost.o octtoint.o \ + prettydate.o ranny.o tsftomsu.o tstotv.o tvtoa.o tvtots.o \ + uglydate.o uinttoa.o utvtoa.o machines.o clocktypes.o \ + md5.o a_md5encrypt.o a_md5decrypt.o \ + a_md512crypt.o decodenetnum.o systime.o msyslog.o syssignal.o \ + findconfig.o + +$(LIBNAME).a: $(OBJS) + ar rv $@ $? + -rm -f $? + @if ( hp-pa || hp-mc680x0 ) > /dev/null 2>&1; then \ + ( cd ../adjtime && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" ) && ar rv $@ ../adjtime/adjtime.o; \ + else \ + :; \ + fi + $(RANLIB) $@ + +lintlib: llib-l$(LIBNAME).ln + +llib-l$(LIBNAME).ln: $(SOURCE) + lint -C$(LIBNAME) $(INCL) $(CLOCKDEFS) $(AUTHDEFS) $(LIBDEFS) $(SOURCE) >lintlib.errs + +lint: + lint -u $(DEFS) $(INCL) $(CLOCKDEFS) $(AUTHDEFS) $(LIBDEFS) $(SOURCE) >lint.errs + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(LIBNAME).a *.o *.out *.ln make.log Makefile.bak \ + lintlib.errs lint.errs + +distclean: clean + -@rm -f *.orig *.rej .version Makefile diff --git a/contrib/xntpd/lib/README b/contrib/xntpd/lib/README new file mode 100644 index 0000000000..c2b65d94cd --- /dev/null +++ b/contrib/xntpd/lib/README @@ -0,0 +1,5 @@ +README file for directory ./lib of the NTP Version 3 distribution + +This directory contains the sources for the NTP library used by most +programs in this distribution. See the README and RELNOTES files in the +parent directory for directions on how to make this library. diff --git a/contrib/xntpd/lib/a_md512crypt.c b/contrib/xntpd/lib/a_md512crypt.c new file mode 100644 index 0000000000..a3714a2408 --- /dev/null +++ b/contrib/xntpd/lib/a_md512crypt.c @@ -0,0 +1,86 @@ +/* authmd512crypt.c,v 3.1 1993/07/06 01:07:52 jbj Exp + * md5crypt - MD5 based authentication routines + */ + +#include "ntp_types.h" +#include "ntp_string.h" +#include "md5.h" +#include "ntp_stdlib.h" + +extern U_LONG cache_keyid; +extern char *cache_key; +extern int cache_keylen; + +/* + * Stat counters, imported from data base module + */ +extern U_LONG authencryptions; +extern U_LONG authdecryptions; +extern U_LONG authkeyuncached; +extern U_LONG authdecryptok; +extern U_LONG authnokey; + +/* + * For our purposes an NTP packet looks like: + * + * a variable amount of encrypted data, multiple of 8 bytes, followed by: + * NOCRYPT_OCTETS worth of unencrypted data, followed by: + * BLOCK_OCTETS worth of ciphered checksum. + */ +#define NOCRYPT_OCTETS 4 +#define BLOCK_OCTETS 16 + +#define NOCRYPT_LONGS ((NOCRYPT_OCTETS)/sizeof(U_LONG)) +#define BLOCK_LONGS ((BLOCK_OCTETS)/sizeof(U_LONG)) + +static MD5_CTX ctx; + +/* + * Do first stage of a two stage authenticator generation. + */ + +void +MD5auth1crypt(keyno, pkt, length) + U_LONG keyno; + U_LONG *pkt; + int length; /* length of all encrypted data */ +{ + + authencryptions++; + + if (keyno != cache_keyid) { + authkeyuncached++; + if (!authhavekey(keyno)) { + authnokey++; + return; + } + } + + MD5Init(&ctx); + MD5Update(&ctx, cache_key, cache_keylen); + MD5Update(&ctx, (char *)pkt, length - 8); + /* just leave the partially computed value in the static MD5_CTX */ +} + +/* + * Do second state of a two stage authenticator generation. + */ +int +MD5auth2crypt(keyno, pkt, length) + U_LONG keyno; + U_LONG *pkt; + int length; /* total length of encrypted area */ +{ + /* + * Don't bother checking the keys. The first stage would have + * handled that. Finish up the generation by also including the + * last 8 bytes of the data area. + */ + + MD5Update(&ctx, (char *)(pkt) + length - 8, 8); + MD5Final(&ctx); + + bcopy((char *)ctx.digest, (char *) &pkt[NOCRYPT_LONGS + length/sizeof(U_LONG)], + BLOCK_OCTETS); + return 4 + BLOCK_OCTETS; +} diff --git a/contrib/xntpd/lib/a_md5decrypt.c b/contrib/xntpd/lib/a_md5decrypt.c new file mode 100644 index 0000000000..892e52e606 --- /dev/null +++ b/contrib/xntpd/lib/a_md5decrypt.c @@ -0,0 +1,58 @@ +/* authmd5decrypt.c,v 3.1 1993/07/06 01:07:53 jbj Exp + * md5crypt - MD5 based authentication routines + */ + +#include "ntp_types.h" +#include "ntp_string.h" +#include "md5.h" +#include "ntp_stdlib.h" + +extern U_LONG cache_keyid; +extern char *cache_key; +extern int cache_keylen; + +/* + * Stat counters, imported from data base module + */ +extern U_LONG authencryptions; +extern U_LONG authdecryptions; +extern U_LONG authkeyuncached; +extern U_LONG authdecryptok; +extern U_LONG authnokey; + +/* + * For our purposes an NTP packet looks like: + * + * a variable amount of encrypted data, multiple of 8 bytes, followed by: + * NOCRYPT_OCTETS worth of unencrypted data, followed by: + * BLOCK_OCTETS worth of ciphered checksum. + */ +#define NOCRYPT_OCTETS 4 +#define BLOCK_OCTETS 16 + +#define NOCRYPT_LONGS ((NOCRYPT_OCTETS)/sizeof(U_LONG)) +#define BLOCK_LONGS ((BLOCK_OCTETS)/sizeof(U_LONG)) + +int +MD5authdecrypt(keyno, pkt, length) + U_LONG keyno; + const U_LONG *pkt; + int length; /* length of variable data in octets */ +{ + MD5_CTX ctx; + + authdecryptions++; + + if (keyno != cache_keyid) { + authkeyuncached++; + if (!authhavekey(keyno)) + return 0; + } + + MD5Init(&ctx); + MD5Update(&ctx, cache_key, cache_keylen); + MD5Update(&ctx, (char *)pkt, length); + MD5Final(&ctx); + + return (0 == bcmp((char *)ctx.digest, (char *)pkt + length + 4, BLOCK_OCTETS)); +} diff --git a/contrib/xntpd/lib/a_md5encrypt.c b/contrib/xntpd/lib/a_md5encrypt.c new file mode 100644 index 0000000000..a26e8f0d2a --- /dev/null +++ b/contrib/xntpd/lib/a_md5encrypt.c @@ -0,0 +1,68 @@ +/* authmd5encrypt.c,v 3.1 1993/07/06 01:07:54 jbj Exp + * md5crypt - MD5 based authentication routines + */ + +#include "ntp_types.h" +#include "ntp_string.h" +#include "md5.h" +#include "ntp_stdlib.h" + +extern U_LONG cache_keyid; +extern char *cache_key; +extern int cache_keylen; + +/* + * Stat counters, imported from data base module + */ +extern U_LONG authencryptions; +extern U_LONG authdecryptions; +extern U_LONG authkeyuncached; +extern U_LONG authdecryptok; +extern U_LONG authnokey; + +/* + * For our purposes an NTP packet looks like: + * + * a variable amount of encrypted data, multiple of 8 bytes, followed by: + * NOCRYPT_OCTETS worth of unencrypted data, followed by: + * BLOCK_OCTETS worth of ciphered checksum. + */ +#define NOCRYPT_OCTETS 4 +#define BLOCK_OCTETS 16 + +#define NOCRYPT_LONGS ((NOCRYPT_OCTETS)/sizeof(U_LONG)) +#define BLOCK_LONGS ((BLOCK_OCTETS)/sizeof(U_LONG)) + + +int +MD5authencrypt(keyno, pkt, length) + U_LONG keyno; + U_LONG *pkt; + int length; /* length of encrypted portion of packet */ +{ + MD5_CTX ctx; + int len; /* in 4 byte quantities */ + + authencryptions++; + + if (keyno != cache_keyid) { + authkeyuncached++; + if (!authhavekey(keyno)) { + authnokey++; + return 0; + } + } + + len = length / sizeof(U_LONG); + + /* + * Generate the authenticator. + */ + MD5Init(&ctx); + MD5Update(&ctx, cache_key, cache_keylen); + MD5Update(&ctx, (char *)pkt, length); + MD5Final(&ctx); + + bcopy((char *)ctx.digest, (char *) &pkt[NOCRYPT_LONGS + len], BLOCK_OCTETS); + return 4 + BLOCK_OCTETS; /* return size of key and MAC */ +} diff --git a/contrib/xntpd/lib/adjtimex.c b/contrib/xntpd/lib/adjtimex.c new file mode 100644 index 0000000000..03e9d79e35 --- /dev/null +++ b/contrib/xntpd/lib/adjtimex.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +_sccsid:.asciz "11/19/91 ULTRIX @(#)adjtime.c 6.1" +#endif not lint + +#include "SYS.h" + +SYSCALL(adjtimex) + ret + diff --git a/contrib/xntpd/lib/atoint.c b/contrib/xntpd/lib/atoint.c new file mode 100644 index 0000000000..0e8ea8f6fc --- /dev/null +++ b/contrib/xntpd/lib/atoint.c @@ -0,0 +1,48 @@ +/* atoint.c,v 3.1 1993/07/06 01:07:39 jbj Exp + * atoint - convert an ascii string to a signed long, with error checking + */ +#include +#include + +#include "ntp_types.h" + +int +atoint(str, ival) + const char *str; + LONG *ival; +{ + register U_LONG u; + register const char *cp; + register int isneg; + register int oflow_digit; + + cp = str; + + if (*cp == '-') { + cp++; + isneg = 1; + oflow_digit = '8'; + } else { + isneg = 0; + oflow_digit = '7'; + } + + if (*cp == '\0') + return 0; + + u = 0; + while (*cp != '\0') { + if (!isdigit(*cp)) + return 0; + if (u > 214748364 || (u == 214748364 && *cp > oflow_digit)) + return 0; /* overflow */ + u = (u << 3) + (u << 1); + u += *cp++ - '0'; /* ascii dependent */ + } + + if (isneg) + *ival = -((LONG)u); + else + *ival = (LONG)u; + return 1; +} diff --git a/contrib/xntpd/lib/atolfp.c b/contrib/xntpd/lib/atolfp.c new file mode 100644 index 0000000000..9e2d883014 --- /dev/null +++ b/contrib/xntpd/lib/atolfp.c @@ -0,0 +1,117 @@ +/* atolfp.c,v 3.1 1993/07/06 01:07:40 jbj Exp + * atolfp - convert an ascii string to an l_fp number + */ +#include +#include + +#include "ntp_fp.h" +#include "ntp_string.h" + +/* + * Powers of 10 + */ +static U_LONG ten_to_the_n[10] = { + 0, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, +}; + + +int +atolfp(str, lfp) + const char *str; + l_fp *lfp; +{ + register const char *cp; + register U_LONG dec_i; + register U_LONG dec_f; + char *ind; + int ndec; + int isneg; + static char *digits = "0123456789"; + + isneg = 0; + dec_i = dec_f = 0; + ndec = 0; + cp = str; + + /* + * We understand numbers of the form: + * + * [spaces][-|+][digits][.][digits][spaces|\n|\0] + */ + while (isspace(*cp)) + cp++; + + if (*cp == '-') { + cp++; + isneg = 1; + } + + if (*cp == '+') + cp++; + + if (*cp != '.' && !isdigit(*cp)) + return 0; + + while (*cp != '\0' && (ind = strchr(digits, *cp)) != NULL) { + dec_i = (dec_i << 3) + (dec_i << 1); /* multiply by 10 */ + dec_i += (ind - digits); + cp++; + } + + if (*cp != '\0' && !isspace(*cp)) { + if (*cp++ != '.') + return 0; + + while (ndec < 9 && *cp != '\0' + && (ind = strchr(digits, *cp)) != NULL) { + ndec++; + dec_f = (dec_f << 3) + (dec_f << 1); /* *10 */ + dec_f += (ind - digits); + cp++; + } + + while (isdigit(*cp)) + cp++; + + if (*cp != '\0' && !isspace(*cp)) + return 0; + } + + if (ndec > 0) { + register U_LONG tmp; + register U_LONG bit; + register U_LONG ten_fact; + + ten_fact = ten_to_the_n[ndec]; + + tmp = 0; + bit = 0x80000000; + while (bit != 0) { + dec_f <<= 1; + if (dec_f >= ten_fact) { + tmp |= bit; + dec_f -= ten_fact; + } + bit >>= 1; + } + if ((dec_f << 1) > ten_fact) + tmp++; + dec_f = tmp; + } + + if (isneg) + M_NEG(dec_i, dec_f); + + lfp->l_ui = dec_i; + lfp->l_uf = dec_f; + return 1; +} diff --git a/contrib/xntpd/lib/atouint.c b/contrib/xntpd/lib/atouint.c new file mode 100644 index 0000000000..b27653f60a --- /dev/null +++ b/contrib/xntpd/lib/atouint.c @@ -0,0 +1,33 @@ +/* atouint.c,v 3.1 1993/07/06 01:07:42 jbj Exp + * atouint - convert an ascii string to an unsigned long, with error checking + */ +#include +#include + +#include "ntp_types.h" + +int +atouint(str, uval) + const char *str; + U_LONG *uval; +{ + register U_LONG u; + register const char *cp; + + cp = str; + if (*cp == '\0') + return 0; + + u = 0; + while (*cp != '\0') { + if (!isdigit(*cp)) + return 0; + if (u > 429496729 || (u == 429496729 && *cp >= '6')) + return 0; /* overflow */ + u = (u << 3) + (u << 1); + u += *cp++ - '0'; /* ascii dependent */ + } + + *uval = u; + return 1; +} diff --git a/contrib/xntpd/lib/auth12crypt.c b/contrib/xntpd/lib/auth12crypt.c new file mode 100644 index 0000000000..a5d9889727 --- /dev/null +++ b/contrib/xntpd/lib/auth12crypt.c @@ -0,0 +1,125 @@ +/* auth12crypt.c,v 3.1 1993/07/06 01:07:43 jbj Exp + * auth12crypt.c - routines to support two stage NTP encryption + */ +#include "ntp_stdlib.h" + +/* + * For our purposes an NTP packet looks like: + * + * a variable amount of encrypted data, multiple of 8 bytes, which + * is encrypted in pass 1, followed by: + * an 8 byte chunk of data which is encrypted in pass 2 + * NOCRYPT_OCTETS worth of unencrypted data, followed by: + * BLOCK_OCTETS worth of ciphered checksum. + */ +#define NOCRYPT_OCTETS 4 +#define BLOCK_OCTETS 8 + +#define NOCRYPT_LONGS ((NOCRYPT_OCTETS)/sizeof(U_LONG)) +#define BLOCK_LONGS ((BLOCK_OCTETS)/sizeof(U_LONG)) + +/* + * Imported from the key data base module + */ +extern U_LONG cache_keyid; /* cached key ID */ +extern u_char DEScache_ekeys[]; /* cached decryption keys */ +extern u_char DESzeroekeys[]; /* zero key decryption keys */ + +/* + * Stat counters, from the database module + */ +extern U_LONG authencryptions; +extern U_LONG authkeyuncached; +extern U_LONG authnokey; + + +/* + * auth1crypt - do the first stage of a two stage encryption + */ +void +DESauth1crypt(keyno, pkt, length) + U_LONG keyno; + U_LONG *pkt; + int length; /* length of all encrypted data */ +{ + register U_LONG *pd; + register int i; + register u_char *keys; + U_LONG work[2]; + + authencryptions++; + + if (keyno == 0) { + keys = DESzeroekeys; + } else { + if (keyno != cache_keyid) { + authkeyuncached++; + if (!authhavekey(keyno)) { + authnokey++; + return; + } + } + keys = DEScache_ekeys; + } + + /* + * Do the first five encryptions. Stick the intermediate result + * in the mac field. The sixth encryption must wait until the + * caller freezes a transmit time stamp, and will be done in stage 2. + */ + pd = pkt; + work[0] = work[1] = 0; + + for (i = (length/BLOCK_OCTETS - 1); i > 0; i--) { + work[0] ^= *pd++; + work[1] ^= *pd++; + DESauth_des(work, keys); + } + + /* + * Space to the end of the packet and stick the intermediate + * result in the mac field. + */ + pd += BLOCK_LONGS + NOCRYPT_LONGS; + *pd++ = work[0]; + *pd = work[1]; +} + + +/* + * auth2crypt - do the second stage of a two stage encryption + */ +int +DESauth2crypt(keyno, pkt, length) + U_LONG keyno; + U_LONG *pkt; + int length; /* total length of encrypted area */ +{ + register U_LONG *pd; + register u_char *keys; + + /* + * Skip the key check. The call to the first stage should + * have got it. + */ + if (keyno == 0) + keys = DESzeroekeys; + else + keys = DEScache_ekeys; + + /* + * The mac currently should hold the results of the first `n' + * encryptions. We xor in the last block in data section and + * do the final encryption in place. + * + * Get a pointer to the MAC block. XOR in the last two words of + * the data area. Call the encryption routine. + */ + pd = pkt + (length/sizeof(U_LONG)) + NOCRYPT_LONGS; + + *pd ^= *(pd - NOCRYPT_LONGS - 2); + *(pd + 1) ^= *(pd - NOCRYPT_LONGS - 1); + DESauth_des(pd, keys); + + return 4 + 8; /* return size of key number and MAC */ +} diff --git a/contrib/xntpd/lib/authdecrypt.c b/contrib/xntpd/lib/authdecrypt.c new file mode 100644 index 0000000000..7ff1129a47 --- /dev/null +++ b/contrib/xntpd/lib/authdecrypt.c @@ -0,0 +1,85 @@ +/* authdecrypt.c,v 3.1 1993/07/06 01:07:44 jbj Exp + * authdecrypt - routine to decrypt a packet to see if this guy knows our key. + */ +#include "ntp_stdlib.h" + +/* + * For our purposes an NTP packet looks like: + * + * a variable amount of unencrypted data, multiple of 8 bytes, followed by: + * NOCRYPT_OCTETS worth of unencrypted data, followed by: + * BLOCK_OCTETS worth of ciphered checksum. + */ +#define NOCRYPT_OCTETS 4 +#define BLOCK_OCTETS 8 + +#define NOCRYPT_LONGS ((NOCRYPT_OCTETS)/sizeof(U_LONG)) +#define BLOCK_LONGS ((BLOCK_OCTETS)/sizeof(U_LONG)) + +/* + * Imported from the key data base module + */ +extern U_LONG cache_keyid; /* cached key ID */ +extern u_char DEScache_dkeys[]; /* cached decryption keys */ +extern u_char DESzerodkeys[]; /* zero key decryption keys */ + +/* + * Stat counters, imported from data base module + */ +extern U_LONG authdecryptions; +extern U_LONG authkeyuncached; +extern U_LONG authdecryptok; + +int +DESauthdecrypt(keyno, pkt, length) + U_LONG keyno; + const U_LONG *pkt; + int length; /* length of variable data in octets */ +{ + register const U_LONG *pd; + register int i; + register u_char *keys; + register int longlen; + U_LONG work[2]; + + authdecryptions++; + + if (keyno == 0) + keys = DESzerodkeys; + else { + if (keyno != cache_keyid) { + authkeyuncached++; + if (!authhavekey(keyno)) + return 0; + } + keys = DEScache_dkeys; + } + + /* + * Get encryption block data in host byte order and decrypt it. + */ + longlen = length / sizeof(U_LONG); + pd = pkt + longlen; /* points at NOCRYPT area */ + work[0] = *(pd + NOCRYPT_LONGS); + work[1] = *(pd + NOCRYPT_LONGS + 1); + + if (longlen & 0x1) { + DESauth_des(work, keys); + work[0] ^= *(--pd); + } + + for (i = longlen/2; i > 0; i--) { + DESauth_des(work, keys); + work[1] ^= *(--pd); + work[0] ^= *(--pd); + } + + /* + * Success if the encryption data is zero + */ + if ((work[0] == 0) && (work[1] == 0)) { + authdecryptok++; + return 1; + } + return 0; +} diff --git a/contrib/xntpd/lib/authdes.c b/contrib/xntpd/lib/authdes.c new file mode 100644 index 0000000000..36077fc0ad --- /dev/null +++ b/contrib/xntpd/lib/authdes.c @@ -0,0 +1,891 @@ +/* authdes.c,v 3.1 1993/07/06 01:07:45 jbj Exp + * authdes.c - an implementation of the DES cipher algorithm for NTP + */ +#include "ntp_stdlib.h" + +#if !defined(XNTP_BIG_ENDIAN) && !defined(XNTP_LITTLE_ENDIAN) + +#if defined(XNTP_AUTO_ENDIAN) +#include + +#if BYTE_ORDER == BIG_ENDIAN +#define XNTP_BIG_ENDIAN +#endif +#if BYTE_ORDER == LITTLE_ENDIAN +#define XNTP_LITTLE_ENDIAN +#endif + +#else /* AUTO */ + +#ifdef WORDS_BIGENDIAN +#define XNTP_BIG_ENDIAN 1 +#else +#define XNTP_LITTLE_ENDIAN 1 +#endif + +#endif /* AUTO */ + +#endif /* !BIG && !LITTLE */ + +/* + * There are two entries in here. auth_subkeys() called to + * compute the encryption and decryption key schedules, while + * auth_des() is called to do the actual encryption/decryption + */ + +/* + * Byte order woes. The DES code is sensitive to byte order. This + * used to be resolved by calling ntohl() and htonl() to swap things + * around, but this turned out to be quite costly on Vaxes where those + * things are actual functions. The code now straightens out byte + * order troubles on its own, with no performance penalty for little + * end first machines, but at great expense to cleanliness. + */ +#if !defined(XNTP_BIG_ENDIAN) && !defined(XNTP_LITTLE_ENDIAN) + /* + * Pick one or the other. + */ + BYTE_ORDER_NOT_DEFINED_FOR_AUTHENTICATION +#endif + +#if defined(XNTP_BIG_ENDIAN) && defined(XNTP_LITTLE_ENDIAN) + /* + * Pick one or the other. + */ + BYTE_ORDER_NOT_DEFINED_FOR_AUTHENTICATION +#endif + +/* + * Key setup. Here we entirely permute a key, saving the results + * for both the encryption and decryption. Note that while the + * decryption subkeys are simply the encryption keys reordered, + * we save both so that a common cipher routine may be used. + */ + +/* + * Permuted choice 1 tables. These are used to extract bits + * from the left and right parts of the key to form Ci and Di. + * The code that uses these tables knows which bits from which + * part of each key are used to form Ci and Di. + */ +static U_LONG PC1_CL[8] = { + 0x00000000, 0x00000010, 0x00001000, 0x00001010, + 0x00100000, 0x00100010, 0x00101000, 0x00101010 +}; + +static U_LONG PC1_DL[16] = { + 0x00000000, 0x00100000, 0x00001000, 0x00101000, + 0x00000010, 0x00100010, 0x00001010, 0x00101010, + 0x00000001, 0x00100001, 0x00001001, 0x00101001, + 0x00000011, 0x00100011, 0x00001011, 0x00101011 +}; + +static U_LONG PC1_CR[16] = { + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static U_LONG PC1_DR[8] = { + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100 +}; + + +/* + * At the start of some iterations of the key schedule we do + * a circular left shift by one place, while for others we do a shift by + * two places. This has bits set for the iterations where we do 2 bit + * shifts, starting at the low order bit. + */ +#define TWO_BIT_SHIFTS 0x7efc + +/* + * Permuted choice 2 tables. The first actually produces the low order + * 24 bits of the subkey Ki from the 28 bit value of Ci. The second produces + * the high order 24 bits from Di. The tables are indexed by six bit + * segments of Ci and Di respectively. The code is handcrafted to compute + * the appropriate 6 bit chunks. + * + * Note that for ease of computation, the 24 bit values are produced with + * six bits going into each byte. + */ +static U_LONG PC2_C[4][64] = { + { 0x00000000, 0x00040000, 0x01000000, 0x01040000, + 0x00000400, 0x00040400, 0x01000400, 0x01040400, + 0x00200000, 0x00240000, 0x01200000, 0x01240000, + 0x00200400, 0x00240400, 0x01200400, 0x01240400, + 0x00000001, 0x00040001, 0x01000001, 0x01040001, + 0x00000401, 0x00040401, 0x01000401, 0x01040401, + 0x00200001, 0x00240001, 0x01200001, 0x01240001, + 0x00200401, 0x00240401, 0x01200401, 0x01240401, + 0x02000000, 0x02040000, 0x03000000, 0x03040000, + 0x02000400, 0x02040400, 0x03000400, 0x03040400, + 0x02200000, 0x02240000, 0x03200000, 0x03240000, + 0x02200400, 0x02240400, 0x03200400, 0x03240400, + 0x02000001, 0x02040001, 0x03000001, 0x03040001, + 0x02000401, 0x02040401, 0x03000401, 0x03040401, + 0x02200001, 0x02240001, 0x03200001, 0x03240001, + 0x02200401, 0x02240401, 0x03200401, 0x03240401 }, + + { 0x00000000, 0x00000002, 0x00000800, 0x00000802, + 0x08000000, 0x08000002, 0x08000800, 0x08000802, + 0x00010000, 0x00010002, 0x00010800, 0x00010802, + 0x08010000, 0x08010002, 0x08010800, 0x08010802, + 0x00000100, 0x00000102, 0x00000900, 0x00000902, + 0x08000100, 0x08000102, 0x08000900, 0x08000902, + 0x00010100, 0x00010102, 0x00010900, 0x00010902, + 0x08010100, 0x08010102, 0x08010900, 0x08010902, + 0x00000010, 0x00000012, 0x00000810, 0x00000812, + 0x08000010, 0x08000012, 0x08000810, 0x08000812, + 0x00010010, 0x00010012, 0x00010810, 0x00010812, + 0x08010010, 0x08010012, 0x08010810, 0x08010812, + 0x00000110, 0x00000112, 0x00000910, 0x00000912, + 0x08000110, 0x08000112, 0x08000910, 0x08000912, + 0x00010110, 0x00010112, 0x00010910, 0x00010912, + 0x08010110, 0x08010112, 0x08010910, 0x08010912 }, + + { 0x00000000, 0x04000000, 0x00002000, 0x04002000, + 0x10000000, 0x14000000, 0x10002000, 0x14002000, + 0x00000020, 0x04000020, 0x00002020, 0x04002020, + 0x10000020, 0x14000020, 0x10002020, 0x14002020, + 0x00080000, 0x04080000, 0x00082000, 0x04082000, + 0x10080000, 0x14080000, 0x10082000, 0x14082000, + 0x00080020, 0x04080020, 0x00082020, 0x04082020, + 0x10080020, 0x14080020, 0x10082020, 0x14082020, + 0x20000000, 0x24000000, 0x20002000, 0x24002000, + 0x30000000, 0x34000000, 0x30002000, 0x34002000, + 0x20000020, 0x24000020, 0x20002020, 0x24002020, + 0x30000020, 0x34000020, 0x30002020, 0x34002020, + 0x20080000, 0x24080000, 0x20082000, 0x24082000, + 0x30080000, 0x34080000, 0x30082000, 0x34082000, + 0x20080020, 0x24080020, 0x20082020, 0x24082020, + 0x30080020, 0x34080020, 0x30082020, 0x34082020 }, + + { 0x00000000, 0x00100000, 0x00000008, 0x00100008, + 0x00000200, 0x00100200, 0x00000208, 0x00100208, + 0x00020000, 0x00120000, 0x00020008, 0x00120008, + 0x00020200, 0x00120200, 0x00020208, 0x00120208, + 0x00000004, 0x00100004, 0x0000000c, 0x0010000c, + 0x00000204, 0x00100204, 0x0000020c, 0x0010020c, + 0x00020004, 0x00120004, 0x0002000c, 0x0012000c, + 0x00020204, 0x00120204, 0x0002020c, 0x0012020c, + 0x00001000, 0x00101000, 0x00001008, 0x00101008, + 0x00001200, 0x00101200, 0x00001208, 0x00101208, + 0x00021000, 0x00121000, 0x00021008, 0x00121008, + 0x00021200, 0x00121200, 0x00021208, 0x00121208, + 0x00001004, 0x00101004, 0x0000100c, 0x0010100c, + 0x00001204, 0x00101204, 0x0000120c, 0x0010120c, + 0x00021004, 0x00121004, 0x0002100c, 0x0012100c, + 0x00021204, 0x00121204, 0x0002120c, 0x0012120c } +}; + +static U_LONG PC2_D[4][64] = { + { 0x00000000, 0x00000200, 0x00020000, 0x00020200, + 0x00000001, 0x00000201, 0x00020001, 0x00020201, + 0x08000000, 0x08000200, 0x08020000, 0x08020200, + 0x08000001, 0x08000201, 0x08020001, 0x08020201, + 0x00200000, 0x00200200, 0x00220000, 0x00220200, + 0x00200001, 0x00200201, 0x00220001, 0x00220201, + 0x08200000, 0x08200200, 0x08220000, 0x08220200, + 0x08200001, 0x08200201, 0x08220001, 0x08220201, + 0x00000002, 0x00000202, 0x00020002, 0x00020202, + 0x00000003, 0x00000203, 0x00020003, 0x00020203, + 0x08000002, 0x08000202, 0x08020002, 0x08020202, + 0x08000003, 0x08000203, 0x08020003, 0x08020203, + 0x00200002, 0x00200202, 0x00220002, 0x00220202, + 0x00200003, 0x00200203, 0x00220003, 0x00220203, + 0x08200002, 0x08200202, 0x08220002, 0x08220202, + 0x08200003, 0x08200203, 0x08220003, 0x08220203 }, + + { 0x00000000, 0x00000010, 0x20000000, 0x20000010, + 0x00100000, 0x00100010, 0x20100000, 0x20100010, + 0x00000800, 0x00000810, 0x20000800, 0x20000810, + 0x00100800, 0x00100810, 0x20100800, 0x20100810, + 0x04000000, 0x04000010, 0x24000000, 0x24000010, + 0x04100000, 0x04100010, 0x24100000, 0x24100010, + 0x04000800, 0x04000810, 0x24000800, 0x24000810, + 0x04100800, 0x04100810, 0x24100800, 0x24100810, + 0x00000004, 0x00000014, 0x20000004, 0x20000014, + 0x00100004, 0x00100014, 0x20100004, 0x20100014, + 0x00000804, 0x00000814, 0x20000804, 0x20000814, + 0x00100804, 0x00100814, 0x20100804, 0x20100814, + 0x04000004, 0x04000014, 0x24000004, 0x24000014, + 0x04100004, 0x04100014, 0x24100004, 0x24100014, + 0x04000804, 0x04000814, 0x24000804, 0x24000814, + 0x04100804, 0x04100814, 0x24100804, 0x24100814 }, + + { 0x00000000, 0x00001000, 0x00010000, 0x00011000, + 0x02000000, 0x02001000, 0x02010000, 0x02011000, + 0x00000020, 0x00001020, 0x00010020, 0x00011020, + 0x02000020, 0x02001020, 0x02010020, 0x02011020, + 0x00040000, 0x00041000, 0x00050000, 0x00051000, + 0x02040000, 0x02041000, 0x02050000, 0x02051000, + 0x00040020, 0x00041020, 0x00050020, 0x00051020, + 0x02040020, 0x02041020, 0x02050020, 0x02051020, + 0x00002000, 0x00003000, 0x00012000, 0x00013000, + 0x02002000, 0x02003000, 0x02012000, 0x02013000, + 0x00002020, 0x00003020, 0x00012020, 0x00013020, + 0x02002020, 0x02003020, 0x02012020, 0x02013020, + 0x00042000, 0x00043000, 0x00052000, 0x00053000, + 0x02042000, 0x02043000, 0x02052000, 0x02053000, + 0x00042020, 0x00043020, 0x00052020, 0x00053020, + 0x02042020, 0x02043020, 0x02052020, 0x02053020 }, + + { 0x00000000, 0x00000400, 0x01000000, 0x01000400, + 0x00000100, 0x00000500, 0x01000100, 0x01000500, + 0x10000000, 0x10000400, 0x11000000, 0x11000400, + 0x10000100, 0x10000500, 0x11000100, 0x11000500, + 0x00080000, 0x00080400, 0x01080000, 0x01080400, + 0x00080100, 0x00080500, 0x01080100, 0x01080500, + 0x10080000, 0x10080400, 0x11080000, 0x11080400, + 0x10080100, 0x10080500, 0x11080100, 0x11080500, + 0x00000008, 0x00000408, 0x01000008, 0x01000408, + 0x00000108, 0x00000508, 0x01000108, 0x01000508, + 0x10000008, 0x10000408, 0x11000008, 0x11000408, + 0x10000108, 0x10000508, 0x11000108, 0x11000508, + 0x00080008, 0x00080408, 0x01080008, 0x01080408, + 0x00080108, 0x00080508, 0x01080108, 0x01080508, + 0x10080008, 0x10080408, 0x11080008, 0x11080408, + 0x10080108, 0x10080508, 0x11080108, 0x11080508 } +}; + + + +/* + * Permute the key to give us our key schedule. + */ +void +DESauth_subkeys(key, encryptkeys, decryptkeys) + const U_LONG *key; + u_char *encryptkeys; + u_char *decryptkeys; +{ + register U_LONG tmp; + register U_LONG c, d; + register u_char *ek, *dk; + register int two_bit_shifts; + register int i; + + /* + * The first permutted choice gives us the 28 bits for C0 and + * 28 for D0. C0 gets 12 bits from the left key and 16 from + * the right, while D0 gets 16 from the left and 12 from the + * right. The code knows which bits go where. + */ + tmp = *key; /* left part of key */ + c = PC1_CL[(tmp >> 29) & 0x7] + | (PC1_CL[(tmp >> 21) & 0x7] << 1) + | (PC1_CL[(tmp >> 13) & 0x7] << 2) + | (PC1_CL[(tmp >> 5) & 0x7] << 3); + d = PC1_DL[(tmp >> 25) & 0xf] + | (PC1_DL[(tmp >> 17) & 0xf] << 1) + | (PC1_DL[(tmp >> 9) & 0xf] << 2) + | (PC1_DL[(tmp >> 1) & 0xf] << 3); + + tmp = *(key+1); /* right part of key */ + c |= PC1_CR[(tmp >> 28) & 0xf] + | (PC1_CR[(tmp >> 20) & 0xf] << 1) + | (PC1_CR[(tmp >> 12) & 0xf] << 2) + | (PC1_CR[(tmp >> 4) & 0xf] << 3); + d |= PC1_DR[(tmp >> 25) & 0x7] + | (PC1_DR[(tmp >> 17) & 0x7] << 1) + | (PC1_DR[(tmp >> 9) & 0x7] << 2) + | (PC1_DR[(tmp >> 1) & 0x7] << 3); + + /* + * Now iterate to compute the key schedule. Note that we + * record the entire set of subkeys in 6 bit chunks since + * they are used that way. At 6 bits/char, we need + * 48/6 char's/subkey * 16 subkeys/encryption == 128 chars. + * encryptkeys and decryptkeys must be this big. + */ + ek = encryptkeys; + dk = decryptkeys + (8 * 15); + two_bit_shifts = TWO_BIT_SHIFTS; + for (i = 16; i > 0; i--) { + /* + * Do the rotation. One bit and two bit rotations + * are done separately. Note C and D are 28 bits. + */ + if (two_bit_shifts & 0x1) { + c = ((c << 2) & 0xffffffc) | (c >> 26); + d = ((d << 2) & 0xffffffc) | (d >> 26); + } else { + c = ((c << 1) & 0xffffffe) | (c >> 27); + d = ((d << 1) & 0xffffffe) | (d >> 27); + } + two_bit_shifts >>= 1; + + /* + * Apply permutted choice 2 to C to get the first + * 24 bits worth of keys. Note that bits 9, 18, 22 + * and 25 (using DES numbering) in C are unused. The + * shift-mask stuff is done to delete these bits from + * the indices, since this cuts the table size in half. + */ + tmp = PC2_C[0][((c >> 22) & 0x3f)] + | PC2_C[1][((c >> 15) & 0xf) | ((c >> 16) & 0x30)] + | PC2_C[2][((c >> 4) & 0x3) | ((c >> 9) & 0x3c)] + | PC2_C[3][((c ) & 0x7) | ((c >> 4) & 0x38)]; + *ek++ = *dk++ = (u_char)(tmp >> 24); + *ek++ = *dk++ = (u_char)(tmp >> 16); + *ek++ = *dk++ = (u_char)(tmp >> 8); + *ek++ = *dk++ = (u_char)tmp; + + /* + * Apply permutted choice 2 to D to get the other half. + * Here, bits 7, 10, 15 and 26 go unused. The sqeezing + * actually turns out to be cheaper here. + */ + tmp = PC2_D[0][((d >> 22) & 0x3f)] + | PC2_D[1][((d >> 14) & 0xf) | ((d >> 15) & 0x30)] + | PC2_D[2][((d >> 7) & 0x3f)] + | PC2_D[3][((d ) & 0x3) | ((d >> 1) & 0x3c)]; + *ek++ = *dk++ = (u_char)(tmp >> 24); + *ek++ = *dk++ = (u_char)(tmp >> 16); + *ek++ = *dk++ = (u_char)(tmp >> 8); + *ek++ = *dk++ = (u_char)tmp; + + /* + * We are filling in the decryption subkeys from the end. + * Space it back 16 elements to get to the start of the + * next set. + */ + dk -= 16; + } +} + +/* + * The DES algorithm. This is intended to be fairly speedy at the + * expense of some memory. + * + * This uses all the standard hacks. The S boxes and the P permutation + * are precomputed into one table. The E box never actually appears + * explicitly since it is easy to apply this algorithmically. The + * initial permutation and final (inverse initial) permuation are + * computed from tables designed to permute four bits at a time. This + * should run pretty fast on machines with 32 bit words and + * bit field/multiple bit shift instructions which are fast. + */ + +/* + * The initial permutation array. This is used to compute both the + * left and the right halves of the initial permutation using bytes + * from words made from the following operations: + * + * ((left & 0x55555555) << 1) | (right & 0x55555555) for left half + * (left & 0xaaaaaaaa) | ((right & 0xaaaaaaaa) >> 1) for right half + * + * The scheme is that we index into the table using each byte. The + * result from the high order byte is or'd with the result from the + * next byte shifted left once is or'd with the result from the next + * byte shifted left twice if or'd with the result from the low order + * byte shifted left by three. Clear? + */ +static U_LONG IP[256] = { + 0x00000000, 0x00000010, 0x00000001, 0x00000011, + 0x00001000, 0x00001010, 0x00001001, 0x00001011, + 0x00000100, 0x00000110, 0x00000101, 0x00000111, + 0x00001100, 0x00001110, 0x00001101, 0x00001111, + 0x00100000, 0x00100010, 0x00100001, 0x00100011, + 0x00101000, 0x00101010, 0x00101001, 0x00101011, + 0x00100100, 0x00100110, 0x00100101, 0x00100111, + 0x00101100, 0x00101110, 0x00101101, 0x00101111, + 0x00010000, 0x00010010, 0x00010001, 0x00010011, + 0x00011000, 0x00011010, 0x00011001, 0x00011011, + 0x00010100, 0x00010110, 0x00010101, 0x00010111, + 0x00011100, 0x00011110, 0x00011101, 0x00011111, + 0x00110000, 0x00110010, 0x00110001, 0x00110011, + 0x00111000, 0x00111010, 0x00111001, 0x00111011, + 0x00110100, 0x00110110, 0x00110101, 0x00110111, + 0x00111100, 0x00111110, 0x00111101, 0x00111111, + 0x10000000, 0x10000010, 0x10000001, 0x10000011, + 0x10001000, 0x10001010, 0x10001001, 0x10001011, + 0x10000100, 0x10000110, 0x10000101, 0x10000111, + 0x10001100, 0x10001110, 0x10001101, 0x10001111, + 0x10100000, 0x10100010, 0x10100001, 0x10100011, + 0x10101000, 0x10101010, 0x10101001, 0x10101011, + 0x10100100, 0x10100110, 0x10100101, 0x10100111, + 0x10101100, 0x10101110, 0x10101101, 0x10101111, + 0x10010000, 0x10010010, 0x10010001, 0x10010011, + 0x10011000, 0x10011010, 0x10011001, 0x10011011, + 0x10010100, 0x10010110, 0x10010101, 0x10010111, + 0x10011100, 0x10011110, 0x10011101, 0x10011111, + 0x10110000, 0x10110010, 0x10110001, 0x10110011, + 0x10111000, 0x10111010, 0x10111001, 0x10111011, + 0x10110100, 0x10110110, 0x10110101, 0x10110111, + 0x10111100, 0x10111110, 0x10111101, 0x10111111, + 0x01000000, 0x01000010, 0x01000001, 0x01000011, + 0x01001000, 0x01001010, 0x01001001, 0x01001011, + 0x01000100, 0x01000110, 0x01000101, 0x01000111, + 0x01001100, 0x01001110, 0x01001101, 0x01001111, + 0x01100000, 0x01100010, 0x01100001, 0x01100011, + 0x01101000, 0x01101010, 0x01101001, 0x01101011, + 0x01100100, 0x01100110, 0x01100101, 0x01100111, + 0x01101100, 0x01101110, 0x01101101, 0x01101111, + 0x01010000, 0x01010010, 0x01010001, 0x01010011, + 0x01011000, 0x01011010, 0x01011001, 0x01011011, + 0x01010100, 0x01010110, 0x01010101, 0x01010111, + 0x01011100, 0x01011110, 0x01011101, 0x01011111, + 0x01110000, 0x01110010, 0x01110001, 0x01110011, + 0x01111000, 0x01111010, 0x01111001, 0x01111011, + 0x01110100, 0x01110110, 0x01110101, 0x01110111, + 0x01111100, 0x01111110, 0x01111101, 0x01111111, + 0x11000000, 0x11000010, 0x11000001, 0x11000011, + 0x11001000, 0x11001010, 0x11001001, 0x11001011, + 0x11000100, 0x11000110, 0x11000101, 0x11000111, + 0x11001100, 0x11001110, 0x11001101, 0x11001111, + 0x11100000, 0x11100010, 0x11100001, 0x11100011, + 0x11101000, 0x11101010, 0x11101001, 0x11101011, + 0x11100100, 0x11100110, 0x11100101, 0x11100111, + 0x11101100, 0x11101110, 0x11101101, 0x11101111, + 0x11010000, 0x11010010, 0x11010001, 0x11010011, + 0x11011000, 0x11011010, 0x11011001, 0x11011011, + 0x11010100, 0x11010110, 0x11010101, 0x11010111, + 0x11011100, 0x11011110, 0x11011101, 0x11011111, + 0x11110000, 0x11110010, 0x11110001, 0x11110011, + 0x11111000, 0x11111010, 0x11111001, 0x11111011, + 0x11110100, 0x11110110, 0x11110101, 0x11110111, + 0x11111100, 0x11111110, 0x11111101, 0x11111111 +}; + +/* + * The final permutation array. Like the IP array, used + * to compute both the left and right results from the nibbles + * of words computed from: + * + * ((left & 0x0f0f0f0f) << 4) | (right & 0x0f0f0f0f) for left result + * (left & 0xf0f0f0f0) | ((right & 0xf0f0f0f0) >> 4) for right result + * + * The result from the high order byte is shifted left 6 bits and + * or'd with the result from the next byte shifted left 4 bits, which + * is or'd with the result from the next byte shifted left 2 bits, + * which is or'd with the result from the low byte. + * + * There is one of these for big end machines (the natural order for + * DES) and a second for little end machines. One is a byte swapped + * version of the other. + */ +#ifndef XNTP_LITTLE_ENDIAN + /* + * Big end version + */ +static U_LONG FP[256] = { + 0x00000000, 0x02000000, 0x00020000, 0x02020000, + 0x00000200, 0x02000200, 0x00020200, 0x02020200, + 0x00000002, 0x02000002, 0x00020002, 0x02020002, + 0x00000202, 0x02000202, 0x00020202, 0x02020202, + 0x01000000, 0x03000000, 0x01020000, 0x03020000, + 0x01000200, 0x03000200, 0x01020200, 0x03020200, + 0x01000002, 0x03000002, 0x01020002, 0x03020002, + 0x01000202, 0x03000202, 0x01020202, 0x03020202, + 0x00010000, 0x02010000, 0x00030000, 0x02030000, + 0x00010200, 0x02010200, 0x00030200, 0x02030200, + 0x00010002, 0x02010002, 0x00030002, 0x02030002, + 0x00010202, 0x02010202, 0x00030202, 0x02030202, + 0x01010000, 0x03010000, 0x01030000, 0x03030000, + 0x01010200, 0x03010200, 0x01030200, 0x03030200, + 0x01010002, 0x03010002, 0x01030002, 0x03030002, + 0x01010202, 0x03010202, 0x01030202, 0x03030202, + 0x00000100, 0x02000100, 0x00020100, 0x02020100, + 0x00000300, 0x02000300, 0x00020300, 0x02020300, + 0x00000102, 0x02000102, 0x00020102, 0x02020102, + 0x00000302, 0x02000302, 0x00020302, 0x02020302, + 0x01000100, 0x03000100, 0x01020100, 0x03020100, + 0x01000300, 0x03000300, 0x01020300, 0x03020300, + 0x01000102, 0x03000102, 0x01020102, 0x03020102, + 0x01000302, 0x03000302, 0x01020302, 0x03020302, + 0x00010100, 0x02010100, 0x00030100, 0x02030100, + 0x00010300, 0x02010300, 0x00030300, 0x02030300, + 0x00010102, 0x02010102, 0x00030102, 0x02030102, + 0x00010302, 0x02010302, 0x00030302, 0x02030302, + 0x01010100, 0x03010100, 0x01030100, 0x03030100, + 0x01010300, 0x03010300, 0x01030300, 0x03030300, + 0x01010102, 0x03010102, 0x01030102, 0x03030102, + 0x01010302, 0x03010302, 0x01030302, 0x03030302, + 0x00000001, 0x02000001, 0x00020001, 0x02020001, + 0x00000201, 0x02000201, 0x00020201, 0x02020201, + 0x00000003, 0x02000003, 0x00020003, 0x02020003, + 0x00000203, 0x02000203, 0x00020203, 0x02020203, + 0x01000001, 0x03000001, 0x01020001, 0x03020001, + 0x01000201, 0x03000201, 0x01020201, 0x03020201, + 0x01000003, 0x03000003, 0x01020003, 0x03020003, + 0x01000203, 0x03000203, 0x01020203, 0x03020203, + 0x00010001, 0x02010001, 0x00030001, 0x02030001, + 0x00010201, 0x02010201, 0x00030201, 0x02030201, + 0x00010003, 0x02010003, 0x00030003, 0x02030003, + 0x00010203, 0x02010203, 0x00030203, 0x02030203, + 0x01010001, 0x03010001, 0x01030001, 0x03030001, + 0x01010201, 0x03010201, 0x01030201, 0x03030201, + 0x01010003, 0x03010003, 0x01030003, 0x03030003, + 0x01010203, 0x03010203, 0x01030203, 0x03030203, + 0x00000101, 0x02000101, 0x00020101, 0x02020101, + 0x00000301, 0x02000301, 0x00020301, 0x02020301, + 0x00000103, 0x02000103, 0x00020103, 0x02020103, + 0x00000303, 0x02000303, 0x00020303, 0x02020303, + 0x01000101, 0x03000101, 0x01020101, 0x03020101, + 0x01000301, 0x03000301, 0x01020301, 0x03020301, + 0x01000103, 0x03000103, 0x01020103, 0x03020103, + 0x01000303, 0x03000303, 0x01020303, 0x03020303, + 0x00010101, 0x02010101, 0x00030101, 0x02030101, + 0x00010301, 0x02010301, 0x00030301, 0x02030301, + 0x00010103, 0x02010103, 0x00030103, 0x02030103, + 0x00010303, 0x02010303, 0x00030303, 0x02030303, + 0x01010101, 0x03010101, 0x01030101, 0x03030101, + 0x01010301, 0x03010301, 0x01030301, 0x03030301, + 0x01010103, 0x03010103, 0x01030103, 0x03030103, + 0x01010303, 0x03010303, 0x01030303, 0x03030303 +}; +#else + /* + * Byte swapped for little end machines. + */ +static U_LONG FP[256] = { + 0x00000000, 0x00000002, 0x00000200, 0x00000202, + 0x00020000, 0x00020002, 0x00020200, 0x00020202, + 0x02000000, 0x02000002, 0x02000200, 0x02000202, + 0x02020000, 0x02020002, 0x02020200, 0x02020202, + 0x00000001, 0x00000003, 0x00000201, 0x00000203, + 0x00020001, 0x00020003, 0x00020201, 0x00020203, + 0x02000001, 0x02000003, 0x02000201, 0x02000203, + 0x02020001, 0x02020003, 0x02020201, 0x02020203, + 0x00000100, 0x00000102, 0x00000300, 0x00000302, + 0x00020100, 0x00020102, 0x00020300, 0x00020302, + 0x02000100, 0x02000102, 0x02000300, 0x02000302, + 0x02020100, 0x02020102, 0x02020300, 0x02020302, + 0x00000101, 0x00000103, 0x00000301, 0x00000303, + 0x00020101, 0x00020103, 0x00020301, 0x00020303, + 0x02000101, 0x02000103, 0x02000301, 0x02000303, + 0x02020101, 0x02020103, 0x02020301, 0x02020303, + 0x00010000, 0x00010002, 0x00010200, 0x00010202, + 0x00030000, 0x00030002, 0x00030200, 0x00030202, + 0x02010000, 0x02010002, 0x02010200, 0x02010202, + 0x02030000, 0x02030002, 0x02030200, 0x02030202, + 0x00010001, 0x00010003, 0x00010201, 0x00010203, + 0x00030001, 0x00030003, 0x00030201, 0x00030203, + 0x02010001, 0x02010003, 0x02010201, 0x02010203, + 0x02030001, 0x02030003, 0x02030201, 0x02030203, + 0x00010100, 0x00010102, 0x00010300, 0x00010302, + 0x00030100, 0x00030102, 0x00030300, 0x00030302, + 0x02010100, 0x02010102, 0x02010300, 0x02010302, + 0x02030100, 0x02030102, 0x02030300, 0x02030302, + 0x00010101, 0x00010103, 0x00010301, 0x00010303, + 0x00030101, 0x00030103, 0x00030301, 0x00030303, + 0x02010101, 0x02010103, 0x02010301, 0x02010303, + 0x02030101, 0x02030103, 0x02030301, 0x02030303, + 0x01000000, 0x01000002, 0x01000200, 0x01000202, + 0x01020000, 0x01020002, 0x01020200, 0x01020202, + 0x03000000, 0x03000002, 0x03000200, 0x03000202, + 0x03020000, 0x03020002, 0x03020200, 0x03020202, + 0x01000001, 0x01000003, 0x01000201, 0x01000203, + 0x01020001, 0x01020003, 0x01020201, 0x01020203, + 0x03000001, 0x03000003, 0x03000201, 0x03000203, + 0x03020001, 0x03020003, 0x03020201, 0x03020203, + 0x01000100, 0x01000102, 0x01000300, 0x01000302, + 0x01020100, 0x01020102, 0x01020300, 0x01020302, + 0x03000100, 0x03000102, 0x03000300, 0x03000302, + 0x03020100, 0x03020102, 0x03020300, 0x03020302, + 0x01000101, 0x01000103, 0x01000301, 0x01000303, + 0x01020101, 0x01020103, 0x01020301, 0x01020303, + 0x03000101, 0x03000103, 0x03000301, 0x03000303, + 0x03020101, 0x03020103, 0x03020301, 0x03020303, + 0x01010000, 0x01010002, 0x01010200, 0x01010202, + 0x01030000, 0x01030002, 0x01030200, 0x01030202, + 0x03010000, 0x03010002, 0x03010200, 0x03010202, + 0x03030000, 0x03030002, 0x03030200, 0x03030202, + 0x01010001, 0x01010003, 0x01010201, 0x01010203, + 0x01030001, 0x01030003, 0x01030201, 0x01030203, + 0x03010001, 0x03010003, 0x03010201, 0x03010203, + 0x03030001, 0x03030003, 0x03030201, 0x03030203, + 0x01010100, 0x01010102, 0x01010300, 0x01010302, + 0x01030100, 0x01030102, 0x01030300, 0x01030302, + 0x03010100, 0x03010102, 0x03010300, 0x03010302, + 0x03030100, 0x03030102, 0x03030300, 0x03030302, + 0x01010101, 0x01010103, 0x01010301, 0x01010303, + 0x01030101, 0x01030103, 0x01030301, 0x01030303, + 0x03010101, 0x03010103, 0x03010301, 0x03010303, + 0x03030101, 0x03030103, 0x03030301, 0x03030303 +}; +#endif + + +/* + * The SP table is actually the S boxes and the P permutation + * table combined. + */ +static U_LONG SP[8][64] = { + { 0x00808200, 0x00000000, 0x00008000, 0x00808202, + 0x00808002, 0x00008202, 0x00000002, 0x00008000, + 0x00000200, 0x00808200, 0x00808202, 0x00000200, + 0x00800202, 0x00808002, 0x00800000, 0x00000002, + 0x00000202, 0x00800200, 0x00800200, 0x00008200, + 0x00008200, 0x00808000, 0x00808000, 0x00800202, + 0x00008002, 0x00800002, 0x00800002, 0x00008002, + 0x00000000, 0x00000202, 0x00008202, 0x00800000, + 0x00008000, 0x00808202, 0x00000002, 0x00808000, + 0x00808200, 0x00800000, 0x00800000, 0x00000200, + 0x00808002, 0x00008000, 0x00008200, 0x00800002, + 0x00000200, 0x00000002, 0x00800202, 0x00008202, + 0x00808202, 0x00008002, 0x00808000, 0x00800202, + 0x00800002, 0x00000202, 0x00008202, 0x00808200, + 0x00000202, 0x00800200, 0x00800200, 0x00000000, + 0x00008002, 0x00008200, 0x00000000, 0x00808002 }, + + { 0x40084010, 0x40004000, 0x00004000, 0x00084010, + 0x00080000, 0x00000010, 0x40080010, 0x40004010, + 0x40000010, 0x40084010, 0x40084000, 0x40000000, + 0x40004000, 0x00080000, 0x00000010, 0x40080010, + 0x00084000, 0x00080010, 0x40004010, 0x00000000, + 0x40000000, 0x00004000, 0x00084010, 0x40080000, + 0x00080010, 0x40000010, 0x00000000, 0x00084000, + 0x00004010, 0x40084000, 0x40080000, 0x00004010, + 0x00000000, 0x00084010, 0x40080010, 0x00080000, + 0x40004010, 0x40080000, 0x40084000, 0x00004000, + 0x40080000, 0x40004000, 0x00000010, 0x40084010, + 0x00084010, 0x00000010, 0x00004000, 0x40000000, + 0x00004010, 0x40084000, 0x00080000, 0x40000010, + 0x00080010, 0x40004010, 0x40000010, 0x00080010, + 0x00084000, 0x00000000, 0x40004000, 0x00004010, + 0x40000000, 0x40080010, 0x40084010, 0x00084000 }, + + { 0x00000104, 0x04010100, 0x00000000, 0x04010004, + 0x04000100, 0x00000000, 0x00010104, 0x04000100, + 0x00010004, 0x04000004, 0x04000004, 0x00010000, + 0x04010104, 0x00010004, 0x04010000, 0x00000104, + 0x04000000, 0x00000004, 0x04010100, 0x00000100, + 0x00010100, 0x04010000, 0x04010004, 0x00010104, + 0x04000104, 0x00010100, 0x00010000, 0x04000104, + 0x00000004, 0x04010104, 0x00000100, 0x04000000, + 0x04010100, 0x04000000, 0x00010004, 0x00000104, + 0x00010000, 0x04010100, 0x04000100, 0x00000000, + 0x00000100, 0x00010004, 0x04010104, 0x04000100, + 0x04000004, 0x00000100, 0x00000000, 0x04010004, + 0x04000104, 0x00010000, 0x04000000, 0x04010104, + 0x00000004, 0x00010104, 0x00010100, 0x04000004, + 0x04010000, 0x04000104, 0x00000104, 0x04010000, + 0x00010104, 0x00000004, 0x04010004, 0x00010100 }, + + { 0x80401000, 0x80001040, 0x80001040, 0x00000040, + 0x00401040, 0x80400040, 0x80400000, 0x80001000, + 0x00000000, 0x00401000, 0x00401000, 0x80401040, + 0x80000040, 0x00000000, 0x00400040, 0x80400000, + 0x80000000, 0x00001000, 0x00400000, 0x80401000, + 0x00000040, 0x00400000, 0x80001000, 0x00001040, + 0x80400040, 0x80000000, 0x00001040, 0x00400040, + 0x00001000, 0x00401040, 0x80401040, 0x80000040, + 0x00400040, 0x80400000, 0x00401000, 0x80401040, + 0x80000040, 0x00000000, 0x00000000, 0x00401000, + 0x00001040, 0x00400040, 0x80400040, 0x80000000, + 0x80401000, 0x80001040, 0x80001040, 0x00000040, + 0x80401040, 0x80000040, 0x80000000, 0x00001000, + 0x80400000, 0x80001000, 0x00401040, 0x80400040, + 0x80001000, 0x00001040, 0x00400000, 0x80401000, + 0x00000040, 0x00400000, 0x00001000, 0x00401040 }, + + { 0x00000080, 0x01040080, 0x01040000, 0x21000080, + 0x00040000, 0x00000080, 0x20000000, 0x01040000, + 0x20040080, 0x00040000, 0x01000080, 0x20040080, + 0x21000080, 0x21040000, 0x00040080, 0x20000000, + 0x01000000, 0x20040000, 0x20040000, 0x00000000, + 0x20000080, 0x21040080, 0x21040080, 0x01000080, + 0x21040000, 0x20000080, 0x00000000, 0x21000000, + 0x01040080, 0x01000000, 0x21000000, 0x00040080, + 0x00040000, 0x21000080, 0x00000080, 0x01000000, + 0x20000000, 0x01040000, 0x21000080, 0x20040080, + 0x01000080, 0x20000000, 0x21040000, 0x01040080, + 0x20040080, 0x00000080, 0x01000000, 0x21040000, + 0x21040080, 0x00040080, 0x21000000, 0x21040080, + 0x01040000, 0x00000000, 0x20040000, 0x21000000, + 0x00040080, 0x01000080, 0x20000080, 0x00040000, + 0x00000000, 0x20040000, 0x01040080, 0x20000080 }, + + { 0x10000008, 0x10200000, 0x00002000, 0x10202008, + 0x10200000, 0x00000008, 0x10202008, 0x00200000, + 0x10002000, 0x00202008, 0x00200000, 0x10000008, + 0x00200008, 0x10002000, 0x10000000, 0x00002008, + 0x00000000, 0x00200008, 0x10002008, 0x00002000, + 0x00202000, 0x10002008, 0x00000008, 0x10200008, + 0x10200008, 0x00000000, 0x00202008, 0x10202000, + 0x00002008, 0x00202000, 0x10202000, 0x10000000, + 0x10002000, 0x00000008, 0x10200008, 0x00202000, + 0x10202008, 0x00200000, 0x00002008, 0x10000008, + 0x00200000, 0x10002000, 0x10000000, 0x00002008, + 0x10000008, 0x10202008, 0x00202000, 0x10200000, + 0x00202008, 0x10202000, 0x00000000, 0x10200008, + 0x00000008, 0x00002000, 0x10200000, 0x00202008, + 0x00002000, 0x00200008, 0x10002008, 0x00000000, + 0x10202000, 0x10000000, 0x00200008, 0x10002008 }, + + { 0x00100000, 0x02100001, 0x02000401, 0x00000000, + 0x00000400, 0x02000401, 0x00100401, 0x02100400, + 0x02100401, 0x00100000, 0x00000000, 0x02000001, + 0x00000001, 0x02000000, 0x02100001, 0x00000401, + 0x02000400, 0x00100401, 0x00100001, 0x02000400, + 0x02000001, 0x02100000, 0x02100400, 0x00100001, + 0x02100000, 0x00000400, 0x00000401, 0x02100401, + 0x00100400, 0x00000001, 0x02000000, 0x00100400, + 0x02000000, 0x00100400, 0x00100000, 0x02000401, + 0x02000401, 0x02100001, 0x02100001, 0x00000001, + 0x00100001, 0x02000000, 0x02000400, 0x00100000, + 0x02100400, 0x00000401, 0x00100401, 0x02100400, + 0x00000401, 0x02000001, 0x02100401, 0x02100000, + 0x00100400, 0x00000000, 0x00000001, 0x02100401, + 0x00000000, 0x00100401, 0x02100000, 0x00000400, + 0x02000001, 0x02000400, 0x00000400, 0x00100001 }, + + { 0x08000820, 0x00000800, 0x00020000, 0x08020820, + 0x08000000, 0x08000820, 0x00000020, 0x08000000, + 0x00020020, 0x08020000, 0x08020820, 0x00020800, + 0x08020800, 0x00020820, 0x00000800, 0x00000020, + 0x08020000, 0x08000020, 0x08000800, 0x00000820, + 0x00020800, 0x00020020, 0x08020020, 0x08020800, + 0x00000820, 0x00000000, 0x00000000, 0x08020020, + 0x08000020, 0x08000800, 0x00020820, 0x00020000, + 0x00020820, 0x00020000, 0x08020800, 0x00000800, + 0x00000020, 0x08020020, 0x00000800, 0x00020820, + 0x08000800, 0x00000020, 0x08000020, 0x08020000, + 0x08020020, 0x08000000, 0x00020000, 0x08000820, + 0x00000000, 0x08020820, 0x00020020, 0x08000020, + 0x08020000, 0x08000800, 0x08000820, 0x00000000, + 0x08020820, 0x00020800, 0x00020800, 0x00000820, + 0x00000820, 0x00020020, 0x08000000, 0x08020800 } +}; + + + +/* + * DESauth_des - perform an in place DES encryption on 64 bits + * + * Note that the `data' argument is always in big-end-first + * byte order, i.e. *(char *)data is the high order byte of + * the 8 byte data word. We modify the initial and final + * permutation computations for little-end-first machines to + * swap bytes into the natural host order at the beginning and + * back to big-end order at the end. This is unclean but avoids + * a byte swapping performance penalty on Vaxes (which are slow already). + */ +void +DESauth_des(data, subkeys) + U_LONG *data; + u_char *subkeys; +{ + register U_LONG left, right; + register U_LONG temp; + register u_char *kp; + register int i; + + /* + * Do the initial permutation. The first operation gets + * all the bits which are used to form the left half of the + * permutted result in one word, which is then used to + * index the appropriate table a byte at a time. + */ + temp = ((*data & 0x55555555) << 1) | (*(data+1) & 0x55555555); +#ifdef XNTP_LITTLE_ENDIAN + /* + * Modify the computation to use the opposite set of bytes. + */ + left = (IP[(temp >> 24) & 0xff] << 3) + | (IP[(temp >> 16) & 0xff] << 2) + | (IP[(temp >> 8) & 0xff] << 1) + | IP[temp & 0xff]; +#else + left = IP[(temp >> 24) & 0xff] + | (IP[(temp >> 16) & 0xff] << 1) + | (IP[(temp >> 8) & 0xff] << 2) + | (IP[temp & 0xff] << 3); +#endif + + /* + * Same thing again except for the right half. + */ + temp = (*data & 0xaaaaaaaa) | ((*(data+1) & 0xaaaaaaaa) >> 1); +#ifdef XNTP_LITTLE_ENDIAN + right = (IP[(temp >> 24) & 0xff] << 3) + | (IP[(temp >> 16) & 0xff] << 2) + | (IP[(temp >> 8) & 0xff] << 1) + | IP[temp & 0xff]; +#else + right = IP[(temp >> 24) & 0xff] + | (IP[(temp >> 16) & 0xff] << 1) + | (IP[(temp >> 8) & 0xff] << 2) + | (IP[temp & 0xff] << 3); +#endif + + /* + * Do the 16 rounds through the cipher function. We actually + * do two at a time, one on the left half and one on the right + * half. + */ + kp = subkeys; + for (i = 0; i < 8; i++) { + /* + * The E expansion is easy to compute algorithmically. + * Take a look at its form and compare it to + * everything involving temp below. Note that + * since SP[0-7] don't have any bits in common set + * it is okay to do the successive xor's. + */ + temp = (right >> 1) | ((right & 1) ? 0x80000000 : 0); + left ^= SP[0][((temp >> 26) & 0x3f) ^ *kp++]; + left ^= SP[1][((temp >> 22) & 0x3f) ^ *kp++]; + left ^= SP[2][((temp >> 18) & 0x3f) ^ *kp++]; + left ^= SP[3][((temp >> 14) & 0x3f) ^ *kp++]; + left ^= SP[4][((temp >> 10) & 0x3f) ^ *kp++]; + left ^= SP[5][((temp >> 6) & 0x3f) ^ *kp++]; + left ^= SP[6][((temp >> 2) & 0x3f) ^ *kp++]; + left ^= SP[7][(((right << 1) | ((right & 0x80000000)?1:0)) + & 0x3f) ^ *kp++]; + + /* + * Careful here. Right now `right' is actually the + * left side and `left' is the right side. Do the + * same thing again, except swap `left' and `right' + */ + temp = (left >> 1) | ((left & 1) ? 0x80000000 : 0); + right ^= SP[0][((temp >> 26) & 0x3f) ^ *kp++]; + right ^= SP[1][((temp >> 22) & 0x3f) ^ *kp++]; + right ^= SP[2][((temp >> 18) & 0x3f) ^ *kp++]; + right ^= SP[3][((temp >> 14) & 0x3f) ^ *kp++]; + right ^= SP[4][((temp >> 10) & 0x3f) ^ *kp++]; + right ^= SP[5][((temp >> 6) & 0x3f) ^ *kp++]; + right ^= SP[6][((temp >> 2) & 0x3f) ^ *kp++]; + right ^= SP[7][(((left << 1) | ((left & 0x80000000)?1:0)) + & 0x3f) ^ *kp++]; + + /* + * By the time we get here, all is straightened out + * again. `left' is left and `right' is right. + */ + } + + /* + * Now the final permutation. Note this is like the IP above + * except that the data is computed from + * + * ((left & 0x0f0f0f0f) << 4) | (right & 0x0f0f0f0f) for left result + * (left & 0xf0f0f0f0) | ((right & 0xf0f0f0f0) >> 4) for right result + * + * Just to confuse things more, we're supposed to swap the right + * and the left halves before doing this. Instead, we'll just + * switch which goes where when computing the temporary. + * + * This operation also byte swaps stuff back into big end byte + * order. This is accomplished by modifying the FP table for + * little end machines, however, so we don't have to worry about + * it here. + */ + temp = ((right & 0x0f0f0f0f) << 4) | (left & 0x0f0f0f0f); + *data = (FP[(temp >> 24) & 0xff] << 6) + | (FP[(temp >> 16) & 0xff] << 4) + | (FP[(temp >> 8) & 0xff] << 2) + | FP[temp & 0xff]; + + temp = (right & 0xf0f0f0f0) | ((left & 0xf0f0f0f0) >> 4); + *(data+1) = (FP[(temp >> 24) & 0xff] << 6) + | (FP[(temp >> 16) & 0xff] << 4) + | (FP[(temp >> 8) & 0xff] << 2) + | FP[temp & 0xff]; +} diff --git a/contrib/xntpd/lib/authdes.c.des b/contrib/xntpd/lib/authdes.c.des new file mode 100644 index 0000000000000000000000000000000000000000..93058c745d59a8041cbb12d39f58b608f23167db GIT binary patch literal 35168 zcmV(jK=!|Uc`c6e0=ig?XMQ3c0H$AXASLXMT}3b#wfKK-QwkB*M%`Rao8 zp)-3uF^9Ip_T_#e_?YtQ8dfaVMN7Mtv8t{}kuZTQ!BY@|8HUdiQcSSAP%^+xUhJ6~ zi>L!Fw1Nl?W3>zaaOy^8Mu<1ga6Q zA*5)a;F^acWuIWnG}j7IbiHBcmTe)aHsnSYZbkFy#Zmqsvd1Urj+7N&bq2+3Wd`Og z!}J>Tly9lJf)NIT>RwoK^KEJ4UGIK81wQnD845F$<0%jx+po^14r1##A326CLa)74 zeVggT;$ON@5Ep*#8S_gx72@lsL7Z$*6K&q|$hu5kvnVdx-RQk}cd^fZ#@gK>2-DUU zb?h8QXj~s?YI7Jkd|nZja=Vq*$luc9%8&mJFs+}$>S0&WvXB~XAAK}44#?C_)XtBq z)4mACnQ z%*2w$JfHZ48D6}0-d;1RD($BHNvaY`ZP}cDh(e<40isx$N2H}bGQwsf0-t*&ZNAUu$? zxcgB1zC`W3k>Ioi*Ak5sn5aC+lp;zoDCrJwA7WZr`~@ICp|041Mi5!riQtq0*Gi{c zj5X?a=kppI)2)pL+N2P-Za3F z)ILFF@&$5<&25R_x&M&{Un0Q_JP?aVIw1!B>Tq5KVvy8r3d?0*O=09Ok?s4+ zqyH8dnJKXx=KV|jUmzr%WmvNuK??NZ=y+}%3NILwolWvYIu0$!?mVM9!aw58A!)pDm;oCiQ%EyQL4~G^e@cg!-b6gO#O8`11%K4S+;fiysW{F`FAci%%tM z!Y{WjXiO?b*qi!M%e&KFvWCsjby#|d5bL)Gf2NWr%UrEQaAdS-{ki37o+DB7ORJ`< zbEF6)g3`g#&Qb!)*5Tr!c9r=eV`{V&VU(Is2Y;=0d3uvD&QJtT7k_nL-4WVc~#cY!pm#TBaKyL!f?^* zq;ihEd1i*yRz%9L{q(>9>6VsMIEkE)7Wi2_C}NVY-m(EkknjpBO3J_ammqR^MoVE* zG8})zQ(Wp-p@bm*wt3H$#B(_3)J8+|7Uf{6~?-@;>qt&YLBw6j0|&D(2`G5%o4cKXEGOqh%?3r zSL#@dN=&$^C>Dg^-A*ep0L)@hE8su&z{Y;fx<0&4uh|3caiDO5dPF-{SLyCHGGMI2 z(uv$pt_n4IsYYvIu4mp23RWBpU$uCauvqH zslh{DCD{4PXO4`6O$Bq}^78utJkf;MJ%EKEi;DM)?MNkF4eYMRF5-~>Kr{AxEVNBZ z5s(cuUTjmM#@zL$)2z(9?TPBas@|B58}8!6@uluP(N?mHkiu}GfZ9@<+?cK30{%v9_WGgClY`$dhH>YqG$!$4g8M-0Dx+zZ2k&*Aw!6}NAS1s zieqzz`*5vQz)M;%*d43_T~Nqi`2SM~^ac1w@h0)`9r`zc!kFg54j$cWzn?>HoTC%BU)x|+6?QKmG-}sNTc4rQf@16Og6$|uDR6Q zKNuw~AZwsCCZ#*6!BkOjJ?!XB&5%g~ejkeNOWh~xgr2#D#yX!2$8Yrsn1!OBlu){vlEj8vdo7YpP|F-V<*(?O44DTix9 z$|1kf$326v5YNsnM0eDT`VbA4L*O!@^iR*{(9rnO7)z)cTu}IHCO>!&x=VYn-=Rc2 zGGE&J6$;UGFHe>{6NG$|+l;Mv#+wL;a)+I+r@#oWT4WqcHg0u0qp_Kr)E%#CfX+o2 z#kzrk1H&A7Y4cSY{YIfX6@mDCV@Qs0Xb2fm3_&?V*T!;)l7N}*IR@=?5Z{}EVKki# zPpZ0?L-*eFIrzM+=5(;G{uKGf`1HBs-ybF(z|Ch+>NRBc&T*d0Gw?XE^+^A@IO2<) zf!phBoE0oc!TQ^yMg2RJ%CHz`P>unYt9_-JT{mL&7{jwhWO#oz$z4p$E%f-g%M32q zW04W%0{;GJ321$>7(6J~DxgdZ*xdQ~HYZN7fP(cZ{4ao}7)QH7h}muePq%#$2waZn zZ7|4EG8O(lv2zeTR&mOg_HIq;b(*AnD+7!;=_)Oeg~bip7>P)x(dW2EaoMwTQN%bBL!VOdgjvDFrC;RVq>A`KfFG?_&;`Bs!H3tIdAJpGvK8cR9 z2kP5xK%l&cXGg2jOxWy=ADLP5;PcNFLmcH3YXcLA8S+&-ap&Xh5{X@gd2|^>s6zlu zP6MaSr@B2iSbELJGeeQc?y1|8L6+GijKdpVS;uGBbxq5Z zU{o2022eAWRjlQ0m`(`3(6sAT>j#Q)7yf{Jwv?=gV&3M+-iKk>mSbH19YfSJC47>Z zk?v>SbI>G;ZsUrGYC?f-L#^k>X|9B~8d@tox5>X>Bi)MO1YiYGR?~tYtph7#v!bjH z+y??{>-bwQwl#?NskdJec_Zo=bjBv>jHCBw&jjcX;A*LvUs@a~T3vftxC}KXqzTb(~LX8BPePq0=#%2Ny4(;*iUb!$+ljw z@Rs?-r%)Z)&y~2IL!36MUYDZu(mwF+O|fzzo3{f5I@GvGlGLKr$x&vQ@mdmnrWUbs1LoUlMS!l-)*Le(2Op6Z388#uR<684VqDt(ak@ zJ4bR{;wA^O2!j)cCCchRWb|E)f@EKIQX;I0RePRB7OViHpGzBqmL@E`MYj%;;F#Ci<78OzPw2};MGZvH3*Os zpY&=sHshXxWv6I}&Z#Gn1i;Tbu}s)I&etpTK3&N%zSL)s@05^aU`$upgKubA9;@Ee zu(5IGK%qAPidYu)L5MK351`kK*O=YI3))pq17ZV0N4cO-_GUBO;{WHfnw!?5UVI6c z$GPAn)SA71bk=dKgpbo=KcFuc>dbEdhJj(}cy(bxuNR?Q6*#1exmSR#rU03kW!)O; zD}L?!xwyS!pBlQvbG!SuEZ%>ZzssTY<4rW72V-t;28K_lBmeU;K_HL@iHLfaKe^sH zU)P`;Lt}2Y)OhZz=Qan?73iiIczn41FKLyd+d1@FET^%f1xsU)n;y<9SgPfYP5{4^ z<@54W@O*8wu=Y&C9zeU9JeG_&q?$E)(+RN0~DCKWC5TCnQ^ zL>1?GHphjeP#M`Ku%I&TE zHVVu%mp%`fy7nOGh&NeS5z;Qtt0fT$jLap=wviXehDK#s0ybqmjHukxh!wS_Oh(5j z0(96&8e_EgfK=A~&bz7f1`(ygrXt2!K=WrVK|cq%>(&tS-Zan|YSc83=G*id;A}K1 z=xK=m^v^2@uzV{MU`PW#&}i8+HOEmghdk+$XnHkODjM@ZW(E0C+9aQUaLVcI_Z9UxC)Y=SxN%#}T%D`+jk1Eg;-Z4)=`U$+$5>pK5 zbp@v2=5xvZIFT=Xo071zEqjFjs3S05W&K*_%Qbf*<(uM$w0ev`j3|k}c<9f+44fMWNu-fC#2C+){{ZZc-k|C$3E7 zUk8#vqK)-^1KtJmmN?}YUFHk%mB>2%rjfEAG5CbW`{&Yna~h*PcPzjT$?g01_Qmun z$j~6p&7T_7Hp+D_C-Fy>YjX)JHhg77XON9~yqX=+7!;0QlU)oRq403VR6}2HV{->G zf8JgM|HvFMlbLNpwMgGdLfw5S(^pNNQHGzz4O`%gqI_dRq;gL{V;;8k+>0M-bHwaf z^8mOzBZCi}kB-GwLW(Rq9hsK0G#|s1fcQm>~jL6xAhn%WL z`ub#g1OcTm%$up@r;Ev;Y*lkx%C(&Z6zAz$4y|4|7|#?>h80uHd=fRa zdmj~m4gE%IHq(C)`-E1-E9u9}Th0E-A3L;q{n@+EH)x$miM@!ZD83*1d=?V9z4C4G z{$`IP`#-0wQAmn5q6}LYUxlyik@t33bm`W zvy3+c_wGk`f-x#LU$uq~LET_tH5SI>t$0jSBqu#eT-}|lmj-%+B(A&$`NFAuGavUj z)58_aJxnsv?|MFQPuqq30YQ)k$?bEW^#G*vOJKs-o}F-t%~Ee#kXp~d&9-x5SK7{z zaCI_C?s^KO?Re%wFp8vrS5e`)Vbk&^KVENC`zaCr?_vyHB`*VT?s=8lCeN69!6DT^ zJQ10Jv5hoUGFk=vI`O9+nxEe*vO@6pDm5COqii@37VD<{yiA5QeI=>$tH$ur{2086 zldly1B4eh!j3Yane@WjcR?EifG)F8dPQEUrJ|^R!oX7P-p9%d_rc4fW*n}k=BX2|M z$+|-$wh&xX{d7w(K~i2Pe$SjDy9(-&LfT!R-U+72n1MB&JeeJF4 zHlT~?WR!s+F>3vm^J9FF#w1L?W3OFU^U;^KIyqFMD{3)&>#S$%KW$6iU_Y7ivBx4M zzWiQdQfuA#xt=!E=Nic3Y31Zco z9F^w{j$dw8fc;6nkI6Ri#wrE5Uc{vlQsDeL=4WdlH1Q>I#i=55Ur|vfy>+(C+Jf{; zwK=8-P(Ru1=Gnqn4e>_>~mda~cES5$K-@d8l=Mkfvv_e)Y|Z-(fH zb~Cw6IeKBJr{#Ld2%LN{p?1L<)7*M2=yDKpnGVl=#Fc{^+O{WM5$eF#+@U8#^aka z-zub=P)NqNYh5h4;B&cmR6-&;BLNnf`2G-1`5&*LM^wboN2>PnO(?~-?nc3tvV;@3a32)E9pL+h zSvxTvr5(FQBuGw;4)Imv!74mPVvMSBZQw5W+F(Gq)2gBED}_zU?+o9Q?7y1p5u4f0 z%E)9UEu;MCKkKbYA@1$#Zwk?tc2ZTxkB!6I(u9~7+WM&ye3n#i$4;4P^6AGXsUL`~ z?x%`P9SRAZ&8(NmVyU2aL8No!NM(x~r&T{5iu}IUtZswChJ%yfdS9F?n`o%ZEilS} z;tcFyI0%X3Ore6}j0Ex72Xm8VynDW;LKFHmIfy^WPe3udur?-yY`%gCws|TEH%4C- zou;KTR4@XIE!Fc3r@B&%7!D=-qmW?xclY|5p6pOO3d%RN5oe0&I7`xvN5_tiUc+`) zdcfKTG8nnV3~I?NGO?F3MD)+~6_W^Y#ae=Z#bXk&Hp{hL7Kt;CnFYoxo0C{kk`@y?L}i(@f#G9@vZwWMUVmju zvIFFScK>bn&EI7SU-Je9vIxz?=c~%(1^uh!rZeruuvZ3O?TQ9bViVd`A4(*pBb$OuWh< z5|(iE&t?!rr}1c1Hf&W+jP2%2 zU#5$#&*HA3r)%1mqHa=*vnSssvrfaj@ihs8M<*C7Z8j0F0j|eYBDKVCO+KsulVdon z2{Ib4u`I$@vtL09DoZ4QV;&p4Z0>LlsE@BU1YI@c=J z(+Dntg+Iv?p?F;zyrS;0Hn&nRn0Z9B97Z2rQ&~(Oc{lEp0|tqtS6({K97dPb5XYmX z*Ch`?O{v@C00`(He~slx!UVoM#ZWjx9V^UzMS8v>7&gP;skpAFeBZ-I8Z_!_BqtT9 zKo36%SyfFCvi$M9&&auM@zmGr-==$=oyUFqxwK_6jR|or$j$OaPv-L8+M=Lm)vSWZ zqHXaIJH7~?WK3|^zs94TWBKEb>b)pC`(?gXO4!rAUq~+NPfy018pVs%d5>9=IGqsw zNMk7ORfpB2z`%A`TXp|}EEMb>`#Wj<$y1~-$M6_y6D({ZB zP6r}blKd#L+K!4(y82@`KCcUDJr+&urmT~43m|Z4441x01^C42ebg+53_fK5BY@ZQ zeAX+g;h^dOm0}RQGmOKX(9Oe4A*+B0UYsY2BsY$+@Vly&<$S-0J}$6QTY9AIVf^n5 z6IQj*_cwFQE((FoXSKSL1yX}_l^3Jeg%#fE2yYzbbBA%ikQU^h)YSB~3g`qNhdDcP6NsXo<6j7kFZ$yEO@ zWVfD1;S^6rHYHq0Oaj~siPS{V<4@X+P??0D)wV4gqBnhVccbg1K|UMtr`}q?w763c z{XdM0mQWnErR(&Yp8$as<4fp+y*v~}XM=w&Uj9f{zj(+4`?kSc*^-Cyle!aq1;|Ijwt^x2_)~38@o=x;eik(_6U#wxlr0Yl%-3eBG-3v=T{P~zv_Zy95GQ%^YS|Dov0(X>WW)6AD zeyUq_H%VjKueM>Mo;>qBm{*rf*SleO^$i!av$|yy6JHGj4d~t>lBVT65~i7wdJQ3p zmF*V@jr$*(yL5LFOi;p@;$Su9vTxT=9=>0P66o!&9ol2ai4Q8tliA%?Cf<4p`r7sj zx_J{G9euhtj(a`&%r|-uV^nnCpw5Wk$-jWB#*AwvY0`Cu$O7VDgE&!}9zOns!dH|y zHwPr;k$tXm(Jk(C()wl1#_;<7<~g$?NmW!qQx#uG_L|gIM4pE1jS~vh;3KY8D=y`s z9hrY9Rddy^@-??Al5$6|)?Vs-lQvlzz|?S}6R%|EyD5WfVaKs#yFy&RjU4u=z~||> zbmgNwP^5-^__UHW@1c< zB7@|h`b+b#79NK@j_|v1Jy}d^?)qOD$7W}};P+&^^Xyhz{!++-;_AL}t9i?XDqX?DH zcp>0Ws|91OfTQD*ypsLT8t6+slw!O@Ur^MRn(Pdkh#B`{h%O;gz-1K>G2nQ^rrskT z(QF{W5Q(zXOw2fTEjT;=&c6b`nIHZCvzoTsQ$Amo9@_{OW=3FnK+tqt|6&8JDE|ZM z#_JS|YX8`!QO|Sgo1Z5rwW2`0NEw$L1_y_dUcyZ;7f=+t3Dxo*@jOo!DGY-&0Q0iWEn&d|2KwOf0{|Duxu%O z5mtn3LnZP`BCf6x4*xe(tI?CnM@N}BBENQlvUj%P3n&yXte5#-ZSe=*Cx)OPaWe12 z_=n^3;HTC0719&g?!UfX+=+U(t$7XWN^a5qM0qUXT4?A1%OM3BIWF z;diff|K9RScHn}j0{C%t-A*hV$=Xh`)fYtwdh?KFj*4uP~ZM?JWuSy%$ zMy-?S*7q4Kn`tO5ReMP`ll>nv-zfELVh88uFu;s2Lktw-$Z@`HwEVh=>r$EcEP9Wd zHX{>kBh|Oom+eKQcclEJ8377wm@|4wU&F=3+NhgtN4^f52oA|~1%(T#a@Asx1}=&2 zml@RyTD^w_Bk=!_!MLygCD7cdy=`zmH!dgnMdPO>`*H;COam8wxk$r*-Ou|d=(tYS zZu8mQt3}<3qR*e%(c@v~53I8m?IYf&F=#Z&$cAj0>>aiSfdFVOi&CZ|VKuq!V*M1@ zUm^#YkAf&Xj9(PMWG()}Em%XUf=Aa{b#3k*M@4BtrdcEBK?{XD+LtsAtBa0nq0qgo zarBrlYlvHvn1(5h-^JE9#FqvnJ~|40EeU`nyP_Go%;Vru%hBQ=R|(fWzwisAV?g|X z{SYVgm{E6KHzzNWBSs`>c6}xnhgXtA%g~`Vn_0w*$b)VcGPFXHX_Xn1qlaq`ITDv) z#AY?V?sBM+QwjhpN4aTb0Zb${SSW#-r=`Jq;CdlJX_)ARL$XHiLbf}4mA8E3uQ3*N z$dwk0q?W7KZ>9ZWk&#a|c68C}(AEA@YfQ?lLU6-It9R)C*^7l`*KlPQT1@9f_2VP>fFtux}nphM)OtVsJ$QnA?$2fa=9Pa%uoO(#kb2@aVi1y1~a^{tEMu$ zQLNoRAsD1&a)&V=C2yiy3i2f7z6@UNLX@>nSC~pQ)Lkyu1|`=wJ=Gnf;=4TvVl*9= zb1x@i@mOE67ATje=QWqxqUA1CCZB&G95xFE?MiBc25PaWV{Z3fkgK0^xTw5b3`>&d zHb(zu%DAgYH0tL7koBPZR(;Ec}bvdf=l1Wtl)XW^_IG7(TQT^i$bfO35UZ{?8PT66^Y`BgY+`aUj)`V$3nJ z31h4bY>kcW?%XE+vVKM)-JOeD@DP`VWFunc#;~2aEjnNCpL*Qi{5HwrB769Y-Aq2U z?@IdoVSi(%Su?D7FD+^ke3-{$`jpSPyw1MJ0!siK!-Fiz?uRI=w{{Y#a$lP6tr?JI z5MX&&SaMAEE2qfuoT0&Rk)IYSjVy0!Wnec~FgSRHJl@af^Ug9UIP8ZL*`s*}NW4Q0 z$R4q9$ea_hl-}A_g}sQL)#9ll6qn2@He#*7X2$Kf?Z;_;?q8lnr->(;>P{z>&JJVu z0Q~x@w_}~x^PI_A*Ew6CTU3(~1zGU)(#J!H~JyCEw4rRYj0wMg~Lg9{xs>_V^vlLWf8IQQA6 zwb|0r6iBbJ-eG@O(}iCNoMuK(L8oZn&S^=%`ehcgnJjTNIN*q8VT!IvVTKoVQk! zTO6kqI1W~zio;j3&wP)|%@Q#K79_gebcG)o=DWCaE)m!MZWlomMi-RVPQ^yU#MG_* zXb|%V>Y1by|Igb^6!41Y1f?LW-I_X>%4rfvs|MAFCjY_jK2BCM;4m!wT~l~J$NjUl z2%zq(rakZ*N+i?AXPo#+!rIkU3snW&{=Kq<#WF0`@09JUZcdXXNx+dP* z_pAiX(3Oz3gA`w!9hSjsmPEY4kri^Kp#5%bWmMwSLP36n;rng{ThMPYVgbq&okzVY z7x??U_T|Exl68Nl7$lSiD2>zq)y`RCw_&mD7;!^6Pom*GJgLD~_NuQDRS$LfB`$-TVA z&G);ewiLPLWu?MVvUqAV)J3tiJ1ULdK|l6C%<}9@?X+GGOZ?KmGg+hSbc=ac90hHi z39xisrDQC$(W@)LP(bl#G;Ntrj((Epq6Jq|X8T1;Y3+=`*7Ga(G_Qb?^1<=AWY!jz zmRaA@Y20YQ?e>cWrp!+YDKHH7LX}H^3FikW=GpLsdq)2Ytim!BbQM7ZxTGlA1=h`* z*y*NExm7dYOgxA!r zliVyzGx-SI!!dllj`1;$T%ql;3-`vyT0GrWmLi;!e9Cd+*X8ozWlPvKD{p(hGz`@O zz&3j|C@9~ZBw!M;_{M%MJY)tIiJkuY4BG4yCXE~l#V43H6;4mD(|t(GN97{^2|3MY z98_o?_iNUdRobQ1OMx5M^84hYnH8F!8qi6QEU-tVuW>(u>KI>A_S&O3BJE1un5#r` zwgF{!ZOSAZCkT9t;0C6OL~C8IUmu-mOMKTZQt*Vs+JpG6l2ZLf#V`V=&J%mMG_-__ z;`6nTJ>z`?Lc9nHF4^G_j1yh-lR43}&fx`n)lweG+cDx#RWI$%-^~;)aQg0x%n}>5 z<|}7fM@rErx{%|M3fz4*SvAMr3caqr9vh^h!i?dB%`{uNbBIyF{?H?`@zHlM!cGn9rB!R5JA z_oOTo1g$2SFOBx}Cv|aiy&{zM^|%iA{uLmid_q#CbMg>q5H0Yb(hgBnb2Bge#v|BpiuFN5NdysWU|M6O*IriH+doU4K9lRQ>+z(eWfj5T z8L7I+gmU8@lHP{1MEpz*a6q*d{9nZq6LvinO!Ujk77*l$Qnt^)q`bU6>PA zy&{`(MEU=heB6p8_L4po6N>OFs5KpfCS!-%pfH*_z@LeGqb@Y`Vur=yl+Dc^<<2+}e~RQgUklSaTu2`o<&iPml?U*7fe4StTru9Kf$6Qydf3BG@t4m^U|7!~c} z6RNo`#o0f5d(5X(>)0HB7#X`AcZOV;q@jIbYW#vKK_mIjyw~1^8${5uS}ow8R8XMs zbzhaXHO!o&uh&y{Kmx9omOH>ynzIh3Suw@x+DwEEsLPI!I<7)=`;Zt#y zL@L>3ZJ<2V;u#Rbmp0fLZQQ$%RnlG8USzGA`%$E>UC5Y5SV3oIXz=l;ToG_uFn#n8 z`;GR&&{^igfdtmuICu|hVD++6z-;ZNA@wzLAsF+osXe2890j>5*D?T(z2Rnswhh)% z)D@n5V1QGPytJ*0$+vu`Vlo@xQ`-O^`QHHydT}33fP=xxWkbVfi0in)ou^6_&;!{_ z;VPl%r2y>`S&f4MWLCHtD5W`)u{n)WEZjW_*oOrW8l*Xo2M)Pw=xe{bqi7DwL`H|F zliit6rF5_qnJXOrlOJTpK5@k#Qi6+Xp>+aoPJE*b$av^sB(W{!RR(%EM(IUrhE#)Aw2fFf8Fz{c(a<+}(S;Wow0XE8+RTq>}LZ@aIO!L~OMw|5%?8ZzgAJeN0p)(*mn0~) zZN08#n@N*;3I>#`Mmhi0C?DJnTyM_Gt(?MJOD{J!55SPK>G@Mv!ePahe=pBy(F7Sx zK9mMnwm!FO%!EBGjs;v3K$u4O|^$&>LTk!xaAU6cc4H6yl>H4&M}~ zQDJL`w7lfO2onJK3?@(}YTQ7Y?ea#`>@r{3cL_rZo0nD*3XMwq@wv+)y!>8Db$yC| zS#lHHZ^26Dhl?h7#CWP-e{gIhY)X}awi%Yp-HL}|W!EC(BEFbH=rNxm<0zvV)w@xT z!vcoq_PKiC??>p?0gi6~$j<4mgFqv2Q3uhx#=!qCQ;nXVyN+>z$zNNsuAOz^)Yx^+ zO8UC`#VCnVi_G@$p$K0B`gf?Ua0T;dF_0|3y`4=yU^S>N`IyF`2_7kvP{q3d{cc4f z2Qr86cbtDAD&KIN57@-m9cyr;Dh?KQX4`wmBUdxhx1aAei<+j&0sl5fm+~C@qy@I~ z?)qJ;S?jSu;Y|$l97Y-^0G+#2q5{7K&bF>9FzOGkTTg6fJo!m`Ex*iEZFWedALH(t z=kOgmP|8Pc-QoNDp=2Ihr`T0{w}$Qa&#uBDeh~8K(iEzMdJ&!2)dYMaYGU8FZ=C!H z)&%K&P8ubyZvi0h5|II$3O7k)wN092OEjlPtGo}AOIERNS8GwSSI?lC>AE5jb^G{A z$TYuLm32k-LR+wGm0{Aqx=bZWsB*s6A|gRbJ}C@t<`wGqCMCrQrZ%f3&=B7{$Z=U9 z1%=sx7uF`Aeu2iDm*@W%dd?qDbPJT)P}|wuw65KVd0aP*i{1NOL-i@=YY6DUQ3C%v zJ>2>laO#_AX&9Ylf*0V9I~BCx=&!Bod#iD|Xk-u+vf{kz{l5@1LbAK5=-~kP?cPDE zCrW!QP{tXQ@EXfRDBbMRELg^Qy`iBL7Uj!b<$?LtbBMT>eIhCejNZ)v=PA6ElU4r} zpBWaR=d(PF-#hZ(lm3OgMH&a_O9|a)JjvJFOl0glV8oNBk*lsxEeY{0R0HSEFzQ%C zHDoD@EYtJ*(~NU#X!&BZjhqVG)LHg=6furDUST0^3#&h}GJB&_SWsS8%J>%;hBD%4 zHCJ%5ReZN`>ApSpz`821mI+Ob4iQew$yT+U>V-GF@PVZego_iYOO)+~CyVX9AV-&mI8}01BouX}b{0ZwBi$*_d2j zRCLnPpMa#<_DZ$&v{0mRpVE%PWqKRzET+t2>q)wrU{G$21xarcUuuFiDv^9N*zPC{ zPP~HEL5fQ(=g4#oMx~q+ojmd7`CdX-az9_o6hT3|V?**Y4G#GM?HUy$$(L9eS|vMK zh5Ij(g-V^b*w*9;v6_7(^FA}qWHsVva#a=KV*G0LoIhnAUVm7Okt;qj9}=#k5Vc5m z-myyrvPaAs)o7e5Qn2z`PS~=5l zgwuod3<~4TqYE5Nr|9hqU6HV57>g~^#iZXMJ|^_kVGAGh$1F0PHm0^g#rH_LVuX0^ zDR!0a2XZD8!Mm$ak=A6@Fp6oqkIQo0h#f{^@Q;y!_Rg=_n}-pn5{WL{PSx>K-AdlX zKpkm0@8QgyXvUXS(r{@Fh}am&KvsFaX;BMd4`Z2KczwTjZTEpzQwUOE;icrX{zF?L z$_0a@n^J$W#;E*p&Vh8~3(>)qYDTy5Vmh8_sDvN@4&i|jAqiT3xVDZDIu3_vd?-&h zcRr}dpJVdDKUEz+023Lt-2O){=AWy-0@z(q?z(~Mn#{-EBSaCv8ysV@I(XfH8b;CK zh{X~j}{aziB&T0v6StnmI33r9<{M==C#}ZL27r~?V_wagN4@B=BaH` zA98|e=)Gdg30K6@SAtxN2J81Ju4!Mgpgn+*z&)`Q=wddAgoA2TW&5%sLKUrAq9jZM z(HB@MOpUsox)g;>zYSI|6xB7Z!`=D;qf{FfC2o(OD`*R>ppCh8q17JoM&(TS4N@bt zNtE5am-y1!2)?LEFAV8cD%?^!_T=e|RifuSMirzrtOBWElhqGSWNY#eypPM9weSt2 zJ)wqrd^+N62*L`p9eeL~u{ud~O{BNu4 z#BB19K)Gh5yx>ho*Hz*%Y;L$2QzzQxS+}76db)_XKj~9@<6j3mF1eb|_X%Z;k6vLZ zdL+!fD@kE{R>hZ!V!bHHYVi$PBO2luRh)_;#{Op`&;hsgeQGypj%Wb7)*a4bc zu%~EM`HTv0*qWn0&qWnJtke8@vHQbAD?&e{rG%g6HeX{CPDDi75KsRUfId*OeIsI5 zhzgTVP)2-w7f>eQZ{y=bi91o}Y;QK07X6(!5(!z9X+hy{MOR3N+kCe}R`M#K<$E_lf7N7lIqi3f=DGNrA3KA=)#C^e{ z{W1-qnodAyWGY4)MKdAtbo z!mNu1&1Z#JD~0#gT9-hIhZQQ3I)*D~vdeoy7wg|aO3DRyTc*^LqqEWs!-RXhO)I&4-E@9;heNOT6iS8K?Qn43mtG{Uysxu1gRSfE(RCD9#Mxcy@U zkq?2lrM!DElwTD8JEX3A(rZsr4S}?5m8OrVnq79mwDWoq+CMj_HM0g7kLe%hk()0@ zH8l~S5_|doi@<$l42Hk2xYSjymok3C|LL9MF&f#8l2Ly)yO#Y4@s!C1ovg?0_XWPl zyi&>YSipyZhmx43S(%=dBqo94z;0}Omr%O@+IX8{9>_{fOjd&Olm-DubyB~lYEc(w z8ZxcMat7+_+VDYwaMG8|NP zC#aKo{^Ns)a5Pz+VqckOSu<*C8bw7*teRY-8dYLMBH?tqVS$=wtD`H{=$CSBcFi>q znmb&^Wb^hoVASbdMwsH&R5Bj8JQy+gB+X|A6e|`zzK=JMX{bR+T^q^d;?@~mvJ62| zH?N$`|33~r9bL8Q^*ONwT8^-D*x}Adcucxy5shz{8m+mb0&Vzqhcuv8&`JKV7@Uj5 zp_aLoSaRz_!@@URbH3kTdQfpL;9b!wU&_iO1tuJ zRB+}2wJbGLDX2JKuhEDG=uqn)3Jk2SNneiqO}DBFam;p5JkiP1U`PfY>e@17mTh3d3;4Ao6W140+nKxS~-Vq4A~;(mhU2ZY!!~dI3C< zMI%onK^JwWlJ%ivC3_8|?F521hrax&xJXxAx5m*(N=uO}j6|F$Bg+gK(#n@GS=Esc zxPpN>W$0qD!CUQS+=0HuoI8gSHialI+)X2A6R_l!WtEnN&2#V1QvfXLfOws>rV?O| zmI;comrITP&3I_sOrHJ?gNk5*wtiS1D7X4~spv}n3}`<=2)aZT zJOUiMP4N~KF^J%r@M|IG5A4!o6*p7avA~pz3!u+nX*w5x3>R_7OSBTs{%RoFu1IFL z?t&+Q58>ixAHel$rIz1HfJ*yfR>YqO6WW7JutX)E+A)M$V$mkAtg$oQBZDy$mZ{VP zlZX3B=bwQick5-|>51kp8wL6GLCrWv5p|nI-q6@l8fmf z!*!1!TB2_;!WqN%q)~e8%_Ake!Bo?hK)?A#6svoC}8+t;kHbZ2TT^ z6!3xcjJ_aLCWOK&QnZ+;+_;x~T$;md8m6t6j>yF!y%YY26Kp|QFBu@LM5@=&W)1zk zBExx){V4ws9zb13{D;^ci{PDmHjFi;U7h z7+7&8Y-`w;CXf-qgkW}r7*YHC+I<(hLYp;*FVg~Jo02ScDDFb;xVEs#6fXt9Bv?`} znT9pyrE%U~&=!QkHZiDvQOSRHC19?z;m_T|-={b1E6_ZP(x?7m z?4mA;_@sQqZNFU>Mq0W^d(+KTi`E4ZVl{-tjD>|q9c@4d%C}JkpNlpbPm@At$7s3vwa*&6P=&HRFZ_zBx=-qxXT@ zwVhdLCljJLNvoXc+PGxF?eB}RIpEBL&`%ZKDvETR8^v24f(7=g2&g= z_m}V%)g7uKPutp<%1jis{Lt65rJlwTeM9Sv2=tEv&-VjBGv^BMi7g8gXH;eno1u-7 z`isFOxs4%YRoa-e@5GatA<;ML+PiAnA-Lodsy%iqg3>7N4w5 z#0Ig6a2wuJ*DR9Fa|hpX0O0YEF=BzMoYajt5Z61wDE^^j=qvxMCY#|n5USq7pg;=3 zXk}^sJRqE)Ws8}Q?x_)`?Ol)BID?|DyPTdi@GuS@L1)%F9$ijXnkh6$mH9b$kW$6T zOT>rGiwXi~DnT=GsqrtHVuiU)_gDiTOm>(jD4n+y-A z*=#0uQhdplp5l}(uWl6$jp{uR56#QyB!0au;W5J~_{RDQ^|tS43nOxRb_pUH*X924 z4)2hmi7QWWWs^RwuA$aTAz;gA^kAt7!s4K+5^7ku_a1|4QIYkOckeCuE94$3>-JII z+?8LI)5FR8M9M5}XpHA13UjYF z>Soc$T)aEtf)4x&vEMtB6|8O68bv^&*mr+0R!fq64m2S=B|>V=!^U~)2`O2wKkJh z5(m&_%JYA`K2Wti&3d8+P2E^zpPGw|#nPKguXAb9N>w)+&MaS-jxDy-^zbMYB;T@l z;ny5lfZc*IJruk63R8d0Y3mZex%bZ;0oV!g)s2=)FE&*zkW$42z9eCG_z0PGHL>vY zFe!<#Y>Xm+TaDqy(vi7%YUA`^Y?)QuDJcC$DGYd&%iZ5c3xhM{N){oZ+PXXO)p_xc z{WQGYvydhru)2c0;tNe`ray!lJ1Ln?2T)pEa4`=A9cigvZFD+NMXa>QIaL)~_8O5E z`>(H^nWZYQQIV-@eG;T(%$!I+U3YfkfL&Vqk^-{NvBC!+!X2mBrPi1;q{pT5#&xaO zYy~J`S!uj2st+@X$@X>;#5#3F)Yd<)6er$?nsYcgL+D@Iw=@M(dM3<7D;JN~%0ql_-L%_qUXcEhIqn!8@k3)cr2bWVz!l^4NhK6FOKZQrGn6zV|)d)9P>VZWniloBaL> zhA?SPM&?;-|KHSR|00+>2FB8fn-o)Ai=zXoXxQ#0!k*+%>}%)qRkp|kx;4)q;*qck z|4=^0ydy5A!P3bGLce*9rPfknc`(01`8z9&?WKMB)a2l4m~@{RFcO=Zb>m#2H}S)Z zy0M%mZVm3JVtLQ*inaHTcp zpsh+8bBnKl{UHVl1Vj-oY+G7ZHQG@EPW9hBwBNIWX2Hi~qr1T)0D;cf+P!$x5m&ZMSLe>hxyX`cO1#VAN(++6kGR~U;s zGe6_JGPp$1S@2)prkT}Lg`(dinpMrFe2*Xlz8jg6FlY`nUl5d~QXN;wiW=p~2Qlk; zeHNmq-ei_|WxJr}UJ_=O+~1!wxQ8UQQEqDrKC)MGe+quPfj5Pq&G}LAq2c0b2K5kh;#LHX_0hT3U zkXR6f0gDhIE?x;e@du*r2@KWp&!KkcK|4ZXBs7wIvC7f$3N0u2jl)ZCHu&68oO=h~Z)B>MdYp!Pk zE=T{`3*s9=%QoURCv&{S2>OkS?#nuAO9z|E)?(;FCM?h!MSPOCt{@eqeJ(&o^AGT; zwfl!zG#q;D?}QsHjpKrE>nsm;;7l?ia1XsuN37(!gl6YkSRfFjtlaf0a?Af{obo`t zaSgl*kfdXa|+WiriGa*XuePuj6A3y=nWFKlQ-O=Q}CF*p_2BDl`<( z)?*k|#9ua_ukYWvQbJ=2XlPOLD4J+Gm3nc<$As4N;eeYlPdx0Zfp|#LmM4d&nx<&i z%PqO%ijO)MoM&^tat#(9l9N6goj{gm1 zoWaqDjaoJ1#bY{CIF$|la;}zRa6v>sBLFG)&!JJ6p{X!9|EoK z>nmhH&(K;(a|zA#BZB8y9&iazy5}nbGR#qo_oJ|tpc1h%n8knB@n9Xr%s>U~RP$(! zc-i)%S9MT|_or1RO70*++y;^`DWID57U>ji=`%yx-mQx2{Ar}Gh1usw)6ce#o26)P z_$Ki>2a4LtI0c0|88|C0La5AY0v%>!00eFxf*XWO9Vd=M4^aIZVF{-_peD|#;233j z)d=Rb<&dG#=8#o&Ze}|X#50M<$S7^}2!7>{eeNe`M+|JU*^-*dHITdx3phtI^#&iWvD zyrD8AgBelCOx&Oo8O|xxQVK>CdrU3PST{HkqPY74`>rH_G^Y^_X_a7cb3md)-y;|* z7K2%~f@CI{s`zuo4;k>I5uO%Jh&sf$i%(S?HrN`x&AkEobDhO7SEbe&tnN{r!P&zt zY5~7u@A^;omQb)PN&TUZgo(M_5gvGrOIIm#49DK@vZ#rBKdxG5MudNx!E{c?dzWdc zcaUh=`D{0=da`qnL_D?I*F9_Y!mU08<6P$~bH$i#$y8+0I>jL9n|S>7De_3e)z$u;5zhv3T`$BOQDve z3!L?8oO;=%gNId05!m%5a$F275oPFxR^)r-4_P-`C>M@}@9kChN$Ld+rN%AWo;+_l z^{qD&FPnJS1MYKKKkZ}bJO(8j?pM7n%{~z9GXyJd#DzYrKuB!ib;?Mtr~#Z9t+;KE zHy2ww9$U-6MS8s;4T59btztsm+MyOlR6KztKoT4f**IUF!36!CcUDecWX4(=2)OA! z3)X57LQSC%Q13DfeFZlH54S1yw4`t))E^|y)wzmtYhXqC@kpe zMoyBcKedi9=Z*5dh5103OY05j1$A}xZ>m4w31$Y6g*pYW*>P`%mlOm~bHI8KAuaPv zm{7QC<0b=#sa!p!?4U5nieR4lC>(}d{(8B+3R;*FHKf~9W$NKhX-!9JMs(WTuWYp!nx06aW$hk%MS z=ddl&l)?1da*Kv&@BVb`PsxkZbc4+_J2$lq>>D7I7Nf1JnvY^keW=m_>D{jr2~Edn zZ3bqOeC#5brXH{!6u|Wq2^*ZLA7>E0t|MTx(|=8)m;7~tBK5JfwdU`J!sFyzOaX~0HbKH zjCHBawb?Qc4RIxrujGan)5Mn3i>auS0B>#g4NF>+ zyiP3c5aj7T%6YTk2(C>EA8@|CABB4{1ENHGupp?hCab zS>!4`C{JPP^o|E%Ed{Mj**lRheLxx3>AYnx5uO`LA%U^iCb~>>U-EskPWlU>O`jJqNr5Ogr&(5B~ zhr(zimLv*?@J?35zb@cUWC>`Ibc+=NPar{`S+>cDr0Qz`;LMDaf2okC5t7cVf zqnDkMfXtYXftg>F4LIWkMN{Co;JM8JB$Ng=3rVAmq&K>D^mNZmUP*%1U>rqiguO&j zlsC<4!rjV;TR^mOc_<+Nv+^Y5Te$0BB_UJ8^<@iA2Mm+>je9K#9X|5I&n5nNWyA81#iA+E*>F5gZi5f%0^$sPlqr+8lTru z+zLA!F*z<&0bCG9bsQ_bYhKu~$&#>d^Ml}g0^Q2#d|qj(JSV!@KM~?*%F`_rB6Hj| zt^Zm~J}yiFj-QS=K2FdC2++xm^f#xLg+l)8NdQmnooDe1KrfGf zA4^P&0M{4i0yAf#*y>LuyfFKnWM_gPQz7>5uX=52{Zc=CXG@htwM)x;lXZ+Zw{~$b zgf!{@h-l7+EKu4%)RQW%YgI^FndSfI{Oaf@pJIrB1{mKOhXGwip-gUegO+c@v2q1^ z@*sNjzpm3A&GUIeLyf-@3e8Yn?zabrE$0uwPygxbgQW%9tMf zmq1s;aVr=}RFzpL(Fdrz_bIU3%ail>tEtCuBde`xs<8tpd6Oy8|@!j>iEHmVdSin!gmXd3q2!8Jwc z_8J*HQvZu;P*GsUg010mq}*mf`9&rVX}W0gB_pK z3x6r+&9I|BzW+Mu-WlNCqv*aNpAnI;`;C~)gu7A7lovOtt1Amywqe=zAA8LUZo`h( zN1A#nRmr|X2lgOCwI?%5J=XVyEyt-nlYR{#%H8_0v-LE)%2=L&-*^u8NNW<|y(%0k z_m7C$QF=Tq0BK*~_f8N_w9*2LEew1k;s3_)zCAI{_(jG(43N>s>eiqr?7`3$~j zVmQJ9z&@PrsD22>`9Zh=@DSP$LQIB0f>SscdvONx^U|xcwwH0;D=|A1myET-FS!xA zCDR^b6a+?s?6aQ*#z?!%y`*pW#-)D+{d~oxS6ibjee1^Vjh4#F&ozYYYC3RO$YWgY zZ+?FYhn4H$pQLdn!GB=I&9-QaYj4BD&5kKOgV0C3)?1+mgu(}EHZ@B4kabEI>)vK@ zdqrXV*$Xp77h$lb?Jwv2H|ig{9Ui?`Al>BM>9mpPr!bCV{(7txg2! z6NZ98Hjua~gvo+Jn@^txm1%%X>1CL=@`h89$qJl%_9P#*1SLXPU@IA%5yjo# zSyaS91hz?rN#u6i^kzg9QjVf5D|ErgvtUr8u<%9YbR!$~LZ zaYxYSOHQ}6A;TPlL5d|@Aig0NeP;J{+J&)g^u-|4Yg1`WU}cF7RAk}zSu;!`qwrg#y2fSJz*R!j(}M~K>wY}Lmw0l35nze4t0`f4 zv)Ovnjdu6JV8QDI7vTQ-MvD0kb_BUUbMTB^c+U26GA;+?{8|5bafzR}x)`7~>7q=A z6?3Ngja|rVkNbq&m&?gsQ`Hx0;V8DfGrmn~X3wD8z;}BNO)G9|6{~d9(Qe3V@;Tag zR;EeJCY3Ztgw=76h%|ik=78llo7ExsSZbVVm>bNVLO-`*{PyB%xi@(+R0JOeIXG{E z{{3Y&2Gx!S&rP6)kIZAam3CNJZ5gc1@n*T)KITCMCjIr?dZR(r98$_*uFTw97>&dZ z7EiS&gL~<6A?->-R`EmwSNb`8KZ1!0+>bVbke<21QaQpU;$4dR;b1usU{Dfs(Ks@T_t+Zou2`7awT)8d_Er)F` zJ-?LX`KYfHt>J}vOPtqoNL?wL9FU*b!9yxg->j55c@@7{53z3xz$bCtEQD=Zi^H{rj%&Bh< z_y+u6plVX#*CZx6)u(Gy4sUqoJXjQP*U;Ka5B>ddzIJ^!c=R+p-JYHUCgj{!ndwm5UKL^xs+DS#!}-Arqw3C!;Q*5TMul0=;}`l%QXo zI)v&ixHtQxnjcw9TL=aI4OW#=Y3_-uVZMqZ=;nW9f&4$~y>od|L3#wrn~U-EoAZ&= zm7kOrzs)!U%8;thycC<$gJYg2VkK4qkV%8wk zE`UVm4)%e5NwFYv`x9`u%5Y?l(1KomIVAckeUj0fHs^rzW=~=ZNK9I}cIi1$>_nE) z904~b26|5`|3^j>b&ew8wn~1$b*AcOt)ELLqyI~}q z<*A^rlNpaoK;oe`Mehe+cK6uLgQn8Zi{0R(_I9xy-){QbmZ(D{P&qju%QxMH1{rk+ z^8Ni%(k#>h5p?ABaNu>cTkOV2bc$wj3S|$xceg;eR@lk*^j~p)#zN*~;eR-Ev6S5zyEh8czZsI3OE+N!s1- z>Bw0e87sZ2%RXgQ6<~8ZFpi1K<$!HB=2e)hUY42^!r^o2OhHCzVZ3xAH&S{Cyu81b zFXmEMZx7m=fR+wKQXg!7R*DSRPTR^AH29S1fXhOBk5#fvO1gX!V64?!BjuJC z7E{OI_ceFrOAq`r;e8*zz2?lS@iZc}ufY0sTM_XKX*udoEua(%t~ysbR2 zeOg?K+WR0|0;t|_PCOx0c&qZcqE)HeU+HKY3!gHBucCZ%-N-}Ma9xUatz_DeEB-07~Mje-sn9Y zwV7z49z2X!lxcVY&w1oj7p7gH46lSrx5>M^NT2pw)gQ^!RmdTO7@j6c(olCzk4d%g zDbRSEYc1OOSs3TkJ53hGdVsFk1F=rEF*%2<;Hi_ADpdIpXx;PmaUF>9p5i;ZX5N%o z-eG}&kb4RGOF8_jH7^QO*jh7(7~CaIR27tdnLR_7udas*;_OpSnpY|N$ytwvg-toI zMga?B!N#)z(5}hhW+0MG!YA4SNl;clWd9db--Q9m84fO#nOq_d4M=L(z4Zy^6Cv%jr~DLK7AtRT zRk%yPDpANtjJgNw+}rz#Lmg>lveeGsRD1mkeo# zC|Kd@;%=r_N9jEh!TeE&?Q}_N|9%AT@gE?7lXsz^+c~OwLq~`h?N3>bd%AqM(fdeu zHVl_X+}3KOfy8GhoU4w*c*X~<4`m`tAa_pV>TpP&u0!>H-(A@Vo9MG`n-51wtZ*o> zD@4G9kk=d1Xj30*TdW!^45DoVxik%WzWScreJSav@sx4LoO*85vNcM-3G)%^ARNAp znetiRsT1@ngj8)qlW-@6sE(PrzKn->lD*!ih3k{nHwkkgNuc43e z<(3i*{<)e7wOAtcs&Wx+Rs0kDuUGI`m>@jUy0;b0g%KU~7Cp*f+ zM7CBof1|y#Q06=X%@W4+1w33S_4($#Z)JdbV&wYc&#)?aRw6aF%RyG4AQ_KX)c51w ze^ptT=#y%FQDud2Fm8c_R4Y?wj;#Po1Q6er=W}vVijWeU-4#l_lUK-`8lFN%urj&h zGWDKXT<_=OmhE@{QvFa~)!_4RQKssXXfRZbF2+XBWd}pQvT*b{xb#GCHIVd0osIhI zF)l7XPo<2mT84G+3Dr*J$$Wi_ifLAn|J%*lgE(amG!J}c8zxM5$od;Mo2%M1+$&)T zE+M`(Wh(2=k%7ziyr*A$@N^d}!oB9jCOn`cP+3NMH_)jrxklYCkI-YHC9vXla;2&m zJWSFay(|avHUi3l?(ZV1(Ys4Aii=gk_lzNbqD1!g-zMxncztrrV&|iJeo{m2o_h+o z6suZk;2F2T_mKVk`}cJx6op0*l;K;HVYxEI!NI`Lu{7{X$@j9;J)Y}?vOFO5P-l(L z!1OZNAQxx=+VAbsT(B2Q`WAM*wfle__>s|>t?)WqNnDB;q{_jnw10dL3kj%fH4UNB zGuO=F$E+I_{T6c45a`g&okzk>O$Q+y!aV^jYW<|^`;$c^(ncw;ht?<)v@1cJf2Ap-*AM@Au z>B>~I>r~9yE(%be4ZV7l93f6l+W#c&hgm;F0c`McPPN+sMi-gf$w`quPX#^7r`WZo z8aHAbz8H61hYaR@cz}N-adeQT8OA;$=^UZ6KSE2`zw9<(XV@*wn5|9UU!W9derIH8 zv#PqgdV!w3!F*2QJE6azzvgx7VX}WYF3iCDd zsD$55=Ni5O?tUm-WjOQn$FBlgAY>bQ)ff@c;V(IqbwQK+x`y%@b(_t3X3o6E(YvXQ znD5f_W6YD3Yu}=~@x5DoM(nYrj$MuJM0EWrjRy**H*G zaAIKxh>7EM5_wyl`=7hz|J7D`xNg^aMIZT^BfrgX;LoVSw(4uQ^Ua!YX7Hw=u7HVG zJ|okNFJRHEyq5=-92AZEr>ICmR2LIDHH&mDlu=_XKaDC+cAL$s%|R!a58ykaqnK*$ ziH?Afa(SM0NZYGKqLs@V{q^0?*ALp92hUbWWbypY9)H&`l?VS8(Yc`dF2xfF%>$W`X{PzN9 z0ZvdP*vlenkGtZ+i)>-MHx>$&uWW!})&91S#6P7g6wwWL=n+r2ZGle7+k=BxT;rO5G z^JExCaq}aIQc#A)MT^p)$a~mp2KfRrMMnxrwswY{p<_w!U1ulZS72C0jU{iHbu#!3 zU{KxR+-q^>w0Sc@O^{gB{Gbv>T}w0D-!GYx=M>-75D{5*0aA0Gytfy929tSlMsOkr*YE*Px<#0^_{1xX4R5P4Y3ANHMN4KwDA6(T_ah;)V?gCFtxAp- zZtcVi`Ig?K$CoumtT>l^kJC9zocPE2lG3ZPd!!Bt@V#Yc<*3lO?L%ONP`JMLo0#1+ zkD^s0c5T`UVkNNDTGc*KZr=g$=g_-^m6 zpSU)c*qE`jAty~48h3``3)a+9{qh-ve{|fLzr2`R197U+Hbr?t60@_GypJ$cfmon` z#SsWx|5rF)#ztrSQjQQ^A7t}g(r{`LhlhCepKy3NjRkA$Hj z#`gZ45Jx;s1k1eh0SZ+tkrz2l-qR3D?di#B;b`xE*|?eQ&y8{~W2%r_G5>Z5f3hx- zvj#%LGUbtT8vC;=ueIBw$Um#Ye&l?{Cy%v$Tpa54X%+?6ApR?_uOsWvBuoor;B`q{ z0O*#>>#;7>fo#_0UJD+#u1MO%peqm@@U*s=X8=6WB#VU;mk0gLSg)tHXmPeu#ki{` zJh}&xJR%vE6l`*b4>-`Mwao7kq@yjV$H|Mur)RWcW^CGomLs-%j!rIm_;O*tBTV(Mwn>DVG0Uh@Y{_XM4BOL@GHK@jT$z z)t-etN12Y)2HAXHUr!tv;}B0z>MH80a^cv>SzI~De!s9=h?D{Z32lBS&GUklY4W;(l=vRLWkH8ftsal6IfD};`2b_rH)_fg3}?Pqom zSKKu4+9t2#Tb;&;S^Yk~s3Fcr6%Ig^^jvcVr0vg@poHEL0zs~WJcLt4PDAYvv8{x! zx^MWb&jOP}T-;3dN=f&0l9(=COAIlzW==EMTK^|K(rSJ_2U`UQrJ&T)SX7YAP5(?+ zXI^7MHS-JSDvZh}c5qaRwu21rdBf zpfO-N|3Hx)9%&hUs2Jna5gPx3=$WlWhgN&s0ffK~cs32jd+-P5o1X||x8woQ8$JLq z0x54oN5Ou2%L0eAiEb{H)?Tot{E*4g{xEQ*25CHaQfL#z`L`MiuHEiH%@gVpPtf;2 znWJlw4hU&68~Wo}$LRsml7-AJKq?Y6{V}5T>eS^)2LLES(53l##;sT}5b zJlselepCCQDi^6bi;Cvd{i?E5I3(3_CQrkoI6<8|5%N9HMKm}r!_dbT-1-HBV$P^} zv6FF~1I+xTG@;%jgX=_Om@=>9f?#vFE%ewwdI{J%&irJJODjS%hXiwVz)HmUl-vqV zhX5cG!HeRbb>ZaM)w0s&=>Uyw6vdcRejG8<4cxeu_;E`;Yg`UH=uVev8_|ytA8Q(C z!CQ=TmP)KSVp2%V1u*Q%M@(=x zs3@)Dr;e+{V+fl{bynJ_M>F zhE=V;X^6zh`j#cmIehD*W}CC#SSS0x`D`8gASiNAeS=VJ6fH>Hw7a2&D*g?rFn-fp zGt>!iI;mAjvm3wY-MlmQp43Vl7=l7^wx>R`06DMskf@5 zUv9(n;4}NyJg>8436hhIZdEFKD=t993*Dv~JICYXexm74E7Vp>QLUr5veCl89BO*! zGZq7Kc{My!BAXEo?*SOfdWVKz5ilRSXFe4$?S5nSOtg&wV0wET-dt4Fl%M^{++j zql4Rd^@o4GCsQ$PcJVH2Mtq_;{r{hqd_>Z7Zm63v|>zSBaNt8~L@ZuWkav|>Y*^?$dBVMa} zzgAGI+Tm+argli)S9*v^8foy__YYm{C*4ymTgu?mXevZq`i&w{CI7a@>Zm8h;3! z{V{~Pg&s?kQcnymSD#R(?GTXlXPgAoN@qJGA8{|YiKlKPYK0%zcxuy+EdoNf7hEiC z6warr{Yy09RmYj?%AHMO{y3~}!zFOXZ(6+=y$-#nw@v@pX1`{B%@K&C6Twt-xaU#C z`95ygQYi*i#JePS9oPc|wFCgO_K?DZ!Nm#%6u6BmvVbErrs9luvSsNqN#$byFiHLY zVicl=V3n>oDi9jWt8E2`DGx&PAK1?9Q)=F5FBMn00k`8EW|=&gs!AhkA{avwF3!S{ zcdQ$%9=dHHO<#}XW!~%GhP7i|wXUA?2sEzMJ08&6glnRyKGb6++W}{A18|Oqc^0o^ zjK9o2gYcBnmq4Dl-n@C3j&K&SZr04@{t$H*L;cO%=;&g&9hUt(Y^0UiufHTUSZc#( z9FtvixRVh0OzkltHP;vj}W{2UDapa{8FQSAb!m)`V9e^01US%qK=?_ zjJXqhO$Y--94saokg+ffK=MwT9L&mJF+NuXe3ajiklw|D4skZ{zY)=dJf*-GT>Cx{ z&I2D86}q&l;LFtKG7CXdiSu_*4fXe4?rYOhfVFKqrr^{Q5MftwQC)UnM zyxfFeVE<(IBn4k2an`=8IR6M(+AteSRL#3G?7_$TXEc~6PQO%)>cbYL2#n#@8~Z{d zIFR}!eHt1{DvKoA=)2YrSv{|;kQ&w2NtA;Q0%39#K!32HbbI1o3Bgq*fW}=z1Lv;w ze0vDs+v&Ms1N1`LgMv6-9qC-?M-WDueNCWA&!3=^x<;f?HF+MDG7Ocz7Mrd6S5bqB z!>(g?^^P<;-N{DWM+TiC1h8_Xu!tTUCi<^yMwqOctH8WtMCp_l9>&Wpm1r=ZvC(Tw zw|1?bRRog>MfQlOElY!)>bUb-V&%H)ALUuXN9OI!$j=MlX_E6Ag++2Q?hD1}dCM0cyqh6S_!^ z_mTB!%~8$_0lMPCbm;wgX?>L$>UkI$z9An z2Wj-d|E-HYTG{^rzZFYMYW=N?+k;dy0@mSNz#UKIZFOYu1hCx#lzUJEDN)zk?cZ%4 z)1o^vim1Vniyp?)Ja44V#iGP;*80U)!=Yx=gup5icPlJyH-#Htz)Yje1u5ZMmaeYW zDlz4rX?Jy6(T&!=N;dmd)Y&x9l}ZMBiC^Vv2yDfXLIHx{BoD_>+RNOjOf=6lbxX@O zcI0`&>Q#T{5hpw4WY7?qGWG0!)Yr@CZ50;0y)wOuz2gChsKy{vpO#R-@iF?44m2M) zwuU5Uv3K_fhn!!@Tnk+MI~th^-4%=@1iaYYz*LMp(w#n<_?Iu>BU2oO-M9M=m{Rm< z=!~uI!?Br9Ifa3i4J6EVxwc5uMnUcZ=l5SU&T&fMwn@}WyOw@=7jZi`P$UZ?jdNj8 zGnIP|mjD40B`Ww}5CYlKZP8q553T=Kwe_M}{c7$`E8EYMT@6Y@->=q|3f>^Vb==BXmcev1{M5c!tyJ<-;cg_5~+EiRa}}S8vK&b&fgK2q}1w04MvT zntu+Tt2cv~y1Q~Mf&mrLBRW95b$h*~UGz4f?$BZ`iL`PpMA z!sNpq;rwDQk$`H$ALPg|`Id!WQ%~gsCy&VCtPy-exa!;$bXwWHz0yK{PGlrl$JHx} ztNdlugShwNO8&}>I6BR+<;b_+gy5YjAHh_)=bBc&To_94hR$x0*!Y8yBb9)h`=qRp zT>zqDtEj|7l%;)nXm5>8D+FdC!I;xLB8J|ppGwuC{V^3bTpMgSW!B1gPj1E$>-}#) zOJTsrTYU4>GazgJLUq#k1<_f>%Gl%+$!7?shS@%vhjl+DEUA;O?tCrSA1h{JS?bXL zHF)Ti_M`*Fv7Ry`Q*!ArZKxp|k>6jC%2D2an{UHmEA|HCY3`FZJok%l+%GerHSp=F z)^-YV!d}4%_PU2^7H`Zhf2?1n@l3 z0yF;b#X*b$26>6q?FP8v;1_|ghd027dwY~cc62)<%k1hu?hgOks4Wh@#Fw>W*;?xa z%HcMkk`==qke}L;WZ^#8s*PU2M+yRc>w7?M>YW3`GElYfE{n^N1A95Z3g9US*o)Vlk@ygT!M#D3=AQxBz3I(T3&>|HS+yFL-SO%I(ckBunTs&g@SS z&JHDnu}M8WeMJ$dKl#pWK39R~o9fvF9};dO3t`e{0;ql6zc5eI6WuC71Uc`_Dx7B? z%7kilggjCCAZMQoZd{upQ>5lu>T4*@AoHg91rSkRJXDMWu--qqv^{PTJI&ypLiQZd z-$0@uyv33ZH~auWO2emaLK1-pXe@o}b%dm(Rmc0Arg0<{{9Mb20>_;vU^6)r;(55* zKVHXP3|UVsVWzY`Q+`vN<$Lk_v^Cr{#`LU47Na7iat2hEeM;NdV2%CWVl0|t)9@Xv z7P+o$TvRq0^HZ=Uw{n=K81+YA^F!h9Rt}SrBH0~)*yyOp#ixpzH@SV^M=BX$YTpw! zDCr;r4Q8~kki?c9J=xSRTDHW^AW1zC?2DUbFC6}2I9_9{=l@s#X=II1?N7ugJb!J+ zx5R4I)8=+=upv|auRQ{;2KP29!6OM62YHRq$-e*gh-n9($Q8YZ1zU?W1Cudz`KYl_ z-a5lrZm*vs1)uMzB^BjzG7I{NY+H_d570J)9xWK36$_Nz#i-i-IS@ap2DWq7{#CkV zUoX-4xGUKpfs0}*q5C8h22<<)oQz*>-WC0y&=lJq6eN|!RZIS0Mk!VWU%EO&rx^Ab z3V3=hAxok-@(ZyI$OD8IHt!ks&E?pMyl<>y(Wf@65!1p8;q0?&*u_=vtwM80GIdpU7C5K9HYB``3;*=SWnu$gY<-B|@4tAsBrBm3*%@6a;5#IT zos6jZCC&yu=g{x&7K(ews2wj^%d2$+bk_oBnp!QM5d2D z6t(d0Y!O+)k&P6BTavbEG=xF_K|#=|^I2gC$vx|7 z(1p$^WJZ%UFw0Fs@@cK5iqjaA$f7z367Vg8FK5JCcV%59cb+}s#~~;-`+GsiTScb2 z0UGU6rXt&6S*?nYG?*1O{e;}c+?mgCT|Epakj#Hrl^5;cfl(Uz{C>^HAQJX9Vp9yG z8Zo=5$sgE6GWq3gdnDge-fa9sU=p2MUE?ORv-~B4fJ;NG4Th{gA~lGU-&1CewD$DOR88p>Rxxj!;sRun%*E>YeSE z49e04+aqQ~DSZpr0^V{;4R0^iezVm#YqK=)?Mb&-@@ZRJ5f&MY#{J4!W~NRYxclM{ z)-NBsa2CVP>b2Kr-dRLoimU~3GZVLy`f|LSb{q?w+tTKFM>*2|1k%0e(@&Hxht6r4 z{@X_lF@3O9ZMKk~fa|%BSp^KS{_dER3bZll$*#dQdX#76vpTjT(%9{Ntb005-0#F? zp%PDiA)l1yAAvyfD`kGp3_yiEa?1C;?)M=Uo(Cn9&-)0i!bs|{H#st5yt=uMg}Y>n zw)Fb#;aA=^+x{6-H3^RtGfBxtU$g@#T=71_fAfts;hvE9foTPk5{P}*kg;lMiNfyF7EUfVKt+Jw%03!WQJ6qRB*2sQBO$iypk~UFopR&W>$AK-|DMg=P`R=GT2}RTuLPGh>q(GBCV#rAoy%lSbdr zKUa|&cDzaPt_i@zC~H) z@TA-F(S<-VBVIuN9Wy?l%~o*6C?$m^3w{7NgKgHkef{ThbmLf=@ZLHmiQwxT`a%B@ z6u=7R5H3k$&XzZ2RQWQ!U zUW4I;rkK#w=ES9&NDFUWA{ex`6OG${xgd73y*v4#oea~`t$Ux_49m1u&gJR)xV?{s zwn@~O7+yT&nkvW@1Qu?OnqNG=Ux0fIbX(tBV`So_Hz4)UfiKwZ(-Q}MO|srbd$NbF z6}0bJ$i1?Okmp$w=G(VO)2FJJ6q}{uVQD)=Cq*Ard2e>8KO9?fkE^uDrzr@bevk}^ z@&y?zPEnR0pT`(QZ7a31s>(BR*!~;t&$0Rgb~HU?k>*X(^RAk=f~y2CQ$qb;pfUm3 zz%*}8Ad7o@opzq8kw>cEMR_%`(=uG1|E~3_0*%pzZ61l;T=DCVCFTgGz*hwnIsx?D zuQj?A&?B>4;jqW4^Hls9m`WTCm_G1}5MqgV*=YF}Ah&g#6V66?ltv3;v+NF{hsON0 z#EGqQt|1^x+BuC$Tl8>$V>IPk7v`-HB7r;3`LFW-2on~Ht9iB_6$ZXkD0#Y22*cyg zLM2-X9?G8okX4FPl;-U8zcfSM)s7djta?EMihNHztudGMmIj1b4&klSkSyAc z1Hr?MhW;K>u{KJ#I9S#@*PB+UwPkT3?f+&C>`+4|T@MtG@(tbB;neD+$ zrr`+^=tZI8pi%KaxhxA^HeXV@AmpzGo8rE#U?jU+PGR>su;%+XsZt+wFpzuVI+;9j zTj-%AoXD8o>ytG+$_0C$7A;;v!DrxJVcYOqqW;BvpUh`m<}(Eigt8F(W&S~?)g9wB z6PR1IRv8IJh;~QE{hV^w>%#hwbRnC1xU&ljxnmiQD(E}HgSh5^QoE2=+O78D`+7u9 zT-FT9deGM$StzjM&<{NN2R#OXfn;LH9)IB=j%cJ+T2Zr&V4ip?45Pj7s&ZJ}W@b!< zvxRR+v~=$S(NL9q*7_9qFw935bI{`cn-!c-)2hNvr;=DqPZlt2US}bVM z!BT7T#k{Qg4nsb-Wc39gcA(Rn-5S)dNMt)(wVP~xtg=QMa^Ps|q$>nyvWf%*IPJ$i z4$?M#cAYGZ@-`&{@S&q3wP&ay)zn5(i`YxEkc(R=bYG!f`ppf;Q>ZR;0K+2nMp;=% z?Hd!OH^y@Rq_hOuvJ7f`l`mK3 zF|7*8e&!U`7`Km**t&oq`?5kxf+iOv)$iM|Cp+W+EDA;Urg}@Z`B7}-+RNc*j@MkT z$so}wPm%Z>sam9U2nSVIZvmCg!Y~dF-9{mM`3V`pxHqFf()zQGT40Z8HwrJgN#h!z zbaQL?eTixbh_*7jY3bW;M&Bhz*-LZ`v(d`JsD%cAJSsLcN+=QPQn=#MS*kLcF04mu z3PEFB^5fkj<^P+_;>&}=+tqVCj$e0-wt*DNt%qFo4=^|Om%|~)oiCuF+O<&;0nkmt z-~v!}`{6@@(QgM2$53u4H2{biB@_#|A5}>&JLm546b*y&j~mi(Vrt;fH(NZ+B=i26e#j})xcA*~F31vKxtb?-QN$BP>%*KzA0eXOB@A`Qb&?42=+;9m9ky%&|Ek^@ z<`jco?qk|<01J27kd={n|HxlTWq8Fl?sfC46S0<8QepDMbx(X@;7R)DajqmU-gxH{ zNC~46gp#BG0k5N-72s*7GGw?NuQR_t?knv^u5eqg35`QN)bBV;ay}8*i`(QoA^5Qw zX0zVExcUs;Uuob?FvYe`Mm-JTgT3+Q`<~nO+sV&fi~m0hUS#gj zy1U`cM!J~E)9%xqMfXcq_n`(!Y#{?&wETGgQyb#&OmvnHL{vo**nAkQgIJLiZr9<> zi0>28AVhfX^Lb6jakA82x={TcQ~>-E>AxlrzGdC1Owe?VwSm?^>X1@z|Lo5E=rc7Z zBPDv9mP*M8NlaCd5O#hDzu;YFNNKi3RQqiXnLS=Y7+?MX6ndTqfIm=#CoF?AP68(0Dy(*FJ zTi@kWu)`~7;$@bqztf#2Qp?5nItAiv-1?#ym#VpOfY871Pl}4&-Dp)}`+0OuosoXje^rQa8^{q2$62Irif)B~`OhY-P{JPvfhrSX6eY){(DDDGCo zwUiY_j8a?78vO@2=2sT<6ZKvb5sfc3`Ct9`;_{bAg5>Pl9>OUPck3NuM(Q9La!~p* zyZDscv_Mou)>8GIeOn?NN48$4+vbZ+twktuaZBf*?Rdk5x7g&y_(E&}gGX1tc)d zi5$f?`hvW4I}{aCM}~50Ej|?4o-N!y^O*hTt0_uugCk%qgjVtfiDi&W8fN(GN59VE z2%d(drNi`{xGl00= z)IeS*jbFQ-7m9R=r^wNfN*-xXhnsmn7?zvFdxlxD{09)*lc6C+0C8`(@(z5c0*i52 k!I=3}PAR_O2$Tw|VglbN%%bRt@*(aJOG?^`v*Z=?k literal 0 HcmV?d00001 diff --git a/contrib/xntpd/lib/authdes.c.export b/contrib/xntpd/lib/authdes.c.export new file mode 100644 index 0000000000..b0323a0a6b --- /dev/null +++ b/contrib/xntpd/lib/authdes.c.export @@ -0,0 +1,40 @@ +/* authdes.c.export,v 3.1 1993/07/06 01:07:48 jbj Exp + * authdes.c - dummy encryption routines for destinations outside the USA. + * + * Sorry, folks; I hate this, too. Send me your e-mail address in an + * envelope bearing a US postmark and I'll send you the decryption key + * for the des program normally distributed with Unix in the USA. Outside + * the USA you are on your own; however, you should be able quickly to + * obtain the source from lots of places, homegrown or otherwise. + * + * to decrypt the des routine, mumble the following: + * + * des -d -k key authdes.c.des authdes.c + * + * , where key is as above, and rebuild. To restore the distribution + * to its exportable state, copy this file to authdes.c . + */ +#include + +/* + * This routine is normally called to compute the key schedule. + */ +void +DESauth_subkeys(key, encryptkeys, decryptkeys) + U_LONG *key; + u_char *encryptkeys; + u_char *decryptkeys; +{ +}; + +/* + * This routine is normally called to encrypt and decrypt the data. This + * is done in-place using the Digital Encryption Standard (DES) Cipher- + * Block Chaining (CBC) method as described in the NTP specification. + */ +void +DESauth_des(data, subkeys) + U_LONG *data; + u_char *subkeys; +{ +}; diff --git a/contrib/xntpd/lib/authencrypt.c b/contrib/xntpd/lib/authencrypt.c new file mode 100644 index 0000000000..66b5281b7a --- /dev/null +++ b/contrib/xntpd/lib/authencrypt.c @@ -0,0 +1,88 @@ +/* authencrypt.c,v 3.1 1993/07/06 01:07:50 jbj Exp + * authencrypt - compute and encrypt the mac field in an NTP packet + */ +#include "ntp_stdlib.h" + +/* + * For our purposes an NTP packet looks like: + * + * a variable amount of encrypted data, multiple of 8 bytes, followed by: + * NOCRYPT_OCTETS worth of unencrypted data, followed by: + * BLOCK_OCTETS worth of ciphered checksum. + */ +#define NOCRYPT_OCTETS 4 +#define BLOCK_OCTETS 8 + +#define NOCRYPT_LONGS ((NOCRYPT_OCTETS)/sizeof(U_LONG)) +#define BLOCK_LONGS ((BLOCK_OCTETS)/sizeof(U_LONG)) + +/* + * Imported from the key data base module + */ +extern U_LONG cache_keyid; /* cached key ID */ +extern u_char DEScache_ekeys[]; /* cached decryption keys */ +extern u_char DESzeroekeys[]; /* zero key decryption keys */ + +/* + * Stat counters from the database module + */ +extern U_LONG authencryptions; +extern U_LONG authkeyuncached; +extern U_LONG authnokey; + +int +DESauthencrypt(keyno, pkt, length) + U_LONG keyno; + U_LONG *pkt; + int length; /* length of encrypted portion of packet */ +{ + register U_LONG *pd; + register int i; + register u_char *keys; + register int len; + U_LONG work[2]; + + authencryptions++; + + if (keyno == 0) { + keys = DESzeroekeys; + } else { + if (keyno != cache_keyid) { + authkeyuncached++; + if (!authhavekey(keyno)) { + authnokey++; + return 0; + } + } + keys = DEScache_ekeys; + } + + /* + * Do the encryption. Work our way forward in the packet, eight + * bytes at a time, encrypting as we go. Note that the byte order + * issues are handled by the DES routine itself + */ + pd = pkt; + work[0] = work[1] = 0; + len = length / sizeof(U_LONG); + + for (i = (len/2); i > 0; i--) { + work[0] ^= *pd++; + work[1] ^= *pd++; + DESauth_des(work, keys); + } + + if (len & 0x1) { + work[0] ^= *pd++; + DESauth_des(work, keys); + } + + /* + * Space past the keyid and stick the result back in the mac field + */ + pd += NOCRYPT_LONGS; + *pd++ = work[0]; + *pd = work[1]; + + return 4 + BLOCK_OCTETS; /* return size of key and MAC */ +} diff --git a/contrib/xntpd/lib/authkeys.c b/contrib/xntpd/lib/authkeys.c new file mode 100644 index 0000000000..2d46eee393 --- /dev/null +++ b/contrib/xntpd/lib/authkeys.c @@ -0,0 +1,602 @@ +/* authkeys.c,v 3.1 1993/07/06 01:07:51 jbj Exp + * authkeys.c - routines to manage the storage of authentication keys + */ +#include + +#include "ntp_types.h" +#include "ntp_string.h" +#include "ntp_malloc.h" +#include "ntp_stdlib.h" + +/* + * Structure to store keys in in the hash table. + */ +struct savekey { + struct savekey *next; + union { +#ifdef DES + U_LONG DES_key[2]; +#endif +#ifdef MD5 + char MD5_key[32]; +#endif + } k; + U_LONG keyid; + u_short flags; +#ifdef MD5 + int keylen; +#endif +}; + +#define KEY_TRUSTED 0x1 /* this key is trusted */ +#define KEY_KNOWN 0x2 /* this key is known */ + +#ifdef DES +#define KEY_DES 0x100 /* this is a DES type key */ +#endif + +#ifdef MD5 +#define KEY_MD5 0x200 /* this is a MD5 type key */ +#endif + +/* + * The hash table. This is indexed by the low order bits of the + * keyid. We make this fairly big for potentially busy servers. + */ +#define HASHSIZE 64 +#define HASHMASK ((HASHSIZE)-1) +#define KEYHASH(keyid) ((keyid) & HASHMASK) + +struct savekey *key_hash[HASHSIZE]; + +U_LONG authkeynotfound; +U_LONG authkeylookups; +U_LONG authnumkeys; +U_LONG authuncached; +U_LONG authkeyuncached; +U_LONG authnokey; /* calls to encrypt with no key */ +U_LONG authencryptions; +U_LONG authdecryptions; +U_LONG authdecryptok; + +/* + * Storage for free key structures. We malloc() such things but + * never free them. + */ +struct savekey *authfreekeys; +int authnumfreekeys; + +#define MEMINC 12 /* number of new free ones to get at once */ + + +#ifdef DES +/* + * Size of the key schedule + */ +#define KEY_SCHED_SIZE 128 /* number of octets to store key schedule */ + +/* + * The zero key, which we always have. Store the permutted key + * zero in here. + */ +#define ZEROKEY_L 0x01010101 /* odd parity zero key */ +#define ZEROKEY_R 0x01010101 /* right half of same */ +u_char DESzeroekeys[KEY_SCHED_SIZE]; +u_char DESzerodkeys[KEY_SCHED_SIZE]; +u_char DEScache_ekeys[KEY_SCHED_SIZE]; +u_char DEScache_dkeys[KEY_SCHED_SIZE]; +#endif + +/* + * The key cache. We cache the last key we looked at here. + */ +U_LONG cache_keyid; +u_short cache_flags; + +#ifdef MD5 +int cache_keylen; +char *cache_key; +#endif + +/* + * init_auth - initialize internal data + */ +void +init_auth() +{ + U_LONG zerokey[2]; + + /* + * Initialize hash table and free list + */ + bzero((char *)key_hash, sizeof key_hash); + cache_flags = cache_keyid = 0; + + authnumfreekeys = authkeynotfound = authkeylookups = 0; + authnumkeys = authuncached = authkeyuncached = authnokey = 0; + authencryptions = authdecryptions = authdecryptok = 0; + +#ifdef DES + /* + * Initialize the zero key + */ + zerokey[0] = ZEROKEY_L; + zerokey[1] = ZEROKEY_R; + /* could just zero all */ + DESauth_subkeys(zerokey, DESzeroekeys, DESzerodkeys); +#endif +} + + +/* + * auth_findkey - find a key in the hash table + */ +struct savekey * +auth_findkey(keyno) + U_LONG keyno; +{ + register struct savekey *sk; + + sk = key_hash[KEYHASH(keyno)]; + while (sk != 0) { + if (keyno == sk->keyid) + return sk; + sk = sk->next; + } + return 0; +} + + +/* + * auth_havekey - return whether a key is known + */ +int +auth_havekey(keyno) + U_LONG keyno; +{ + register struct savekey *sk; + + if (keyno == 0 || (keyno == cache_keyid)) + return 1; + + sk = key_hash[KEYHASH(keyno)]; + while (sk != 0) { + if (keyno == sk->keyid) { + if (sk->flags & KEY_KNOWN) + return 1; + else { + authkeynotfound++; + return 0; + } + } + sk = sk->next; + } + authkeynotfound++; + return 0; +} + + +/* + * authhavekey - return whether a key is known. Permute and cache + * the key as a side effect. + */ +int +authhavekey(keyno) + U_LONG keyno; +{ + register struct savekey *sk; + + authkeylookups++; + if (keyno == 0 || keyno == cache_keyid) + return 1; + + sk = key_hash[KEYHASH(keyno)]; + while (sk != 0) { + if (keyno == sk->keyid) + break; + sk = sk->next; + } + + if (sk == 0 || !(sk->flags & KEY_KNOWN)) { + authkeynotfound++; + return 0; + } + + cache_keyid = sk->keyid; + cache_flags = sk->flags; +#ifdef MD5 + if (sk->flags & KEY_MD5) { + cache_keylen = sk->keylen; + cache_key = (char *) sk->k.MD5_key; /* XXX */ + return 1; + } +#endif + +#ifdef DES + if (sk->flags & KEY_DES) { + DESauth_subkeys(sk->k.DES_key, DEScache_ekeys, DEScache_dkeys); + return 1; + } +#endif + return 0; +} + + +/* + * auth_moremem - get some more free key structures + */ +int +auth_moremem() +{ + register struct savekey *sk; + register int i; + + sk = (struct savekey *)malloc(MEMINC * sizeof(struct savekey)); + if (sk == 0) + return 0; + + for (i = MEMINC; i > 0; i--) { + sk->next = authfreekeys; + authfreekeys = sk++; + } + authnumfreekeys += MEMINC; + return authnumfreekeys; +} + + +/* + * authtrust - declare a key to be trusted/untrusted + */ +void +authtrust(keyno, trust) + U_LONG keyno; + int trust; +{ + register struct savekey *sk; + + sk = key_hash[KEYHASH(keyno)]; + while (sk != 0) { + if (keyno == sk->keyid) + break; + sk = sk->next; + } + + if (sk == 0 && !trust) + return; + + if (sk != 0) { + if (cache_keyid == keyno) + cache_flags = cache_keyid = 0; + + if (trust) { + sk->flags |= KEY_TRUSTED; + return; + } + + sk->flags &= ~KEY_TRUSTED; + if (!(sk->flags & KEY_KNOWN)) { + register struct savekey *skp; + + skp = key_hash[KEYHASH(keyno)]; + if (skp == sk) { + key_hash[KEYHASH(keyno)] = sk->next; + } else { + while (skp->next != sk) + skp = skp->next; + skp->next = sk->next; + } + authnumkeys--; + + sk->next = authfreekeys; + authfreekeys = sk; + authnumfreekeys++; + } + return; + } + + if (authnumfreekeys == 0) + if (auth_moremem() == 0) + return; + + sk = authfreekeys; + authfreekeys = sk->next; + authnumfreekeys--; + + sk->keyid = keyno; + sk->flags = KEY_TRUSTED; + sk->next = key_hash[KEYHASH(keyno)]; + key_hash[KEYHASH(keyno)] = sk; + authnumkeys++; + return; +} + + +/* + * authistrusted - determine whether a key is trusted + */ +int +authistrusted(keyno) + U_LONG keyno; +{ + register struct savekey *sk; + + if (keyno == cache_keyid) + return ((cache_flags & KEY_TRUSTED) != 0); + + authkeyuncached++; + + sk = key_hash[KEYHASH(keyno)]; + while (sk != 0) { + if (keyno == sk->keyid) + break; + sk = sk->next; + } + + if (sk == 0 || !(sk->flags & KEY_TRUSTED)) + return 0; + return 1; +} + + + +#ifdef DES +/* + * DESauth_setkey - set a key into the key array + */ +void +DESauth_setkey(keyno, key) + U_LONG keyno; + const U_LONG *key; +{ + register struct savekey *sk; + + /* + * See if we already have the key. If so just stick in the + * new value. + */ + sk = key_hash[KEYHASH(keyno)]; + while (sk != 0) { + if (keyno == sk->keyid) { + sk->k.DES_key[0] = key[0]; + sk->k.DES_key[1] = key[1]; + sk->flags |= KEY_KNOWN | KEY_DES; + if (cache_keyid == keyno) + cache_flags = cache_keyid = 0; + return; + } + sk = sk->next; + } + + /* + * Need to allocate new structure. Do it. + */ + if (authnumfreekeys == 0) { + if (auth_moremem() == 0) + return; + } + + sk = authfreekeys; + authfreekeys = sk->next; + authnumfreekeys--; + + sk->k.DES_key[0] = key[0]; + sk->k.DES_key[1] = key[1]; + sk->keyid = keyno; + sk->flags = KEY_KNOWN | KEY_DES; + sk->next = key_hash[KEYHASH(keyno)]; + key_hash[KEYHASH(keyno)] = sk; + authnumkeys++; + return; +} +#endif + +#ifdef MD5 +void +MD5auth_setkey(keyno, key) + U_LONG keyno; + const U_LONG *key; +{ + register struct savekey *sk; + + /* + * See if we already have the key. If so just stick in the + * new value. + */ + sk = key_hash[KEYHASH(keyno)]; + while (sk != 0) { + if (keyno == sk->keyid) { + strncpy(sk->k.MD5_key, (char *)key, sizeof(sk->k.MD5_key)); + if ((sk->keylen = strlen((char *)key)) > + sizeof(sk->k.MD5_key)) + sk->keylen = sizeof(sk->k.MD5_key); + + sk->flags |= KEY_KNOWN | KEY_MD5; + if (cache_keyid == keyno) + cache_flags = cache_keyid = 0; + return; + } + sk = sk->next; + } + + /* + * Need to allocate new structure. Do it. + */ + if (authnumfreekeys == 0) { + if (auth_moremem() == 0) + return; + } + + sk = authfreekeys; + authfreekeys = sk->next; + authnumfreekeys--; + + strncpy(sk->k.MD5_key, (char *)key, sizeof(sk->k.MD5_key)); + if ((sk->keylen = strlen((char *)key)) > sizeof(sk->k.MD5_key)) + sk->keylen = sizeof(sk->k.MD5_key); + + sk->keyid = keyno; + sk->flags = KEY_KNOWN | KEY_MD5; + sk->next = key_hash[KEYHASH(keyno)]; + key_hash[KEYHASH(keyno)] = sk; + authnumkeys++; + return; +} +#endif + +/* + * auth_delkeys - delete all known keys, in preparation for rereading + * the keys file (presumably) + */ +void +auth_delkeys() +{ + register struct savekey *sk; + register struct savekey **skp; + register int i; + + for (i = 0; i < HASHSIZE; i++) { + skp = &(key_hash[i]); + sk = key_hash[i]; + while (sk != 0) { + sk->flags &= ~(KEY_KNOWN +#ifdef MD5 + | KEY_MD5 +#endif +#ifdef DES + | KEY_DES +#endif + ); + if (sk->flags == 0) { + *skp = sk->next; + authnumkeys--; + sk->next = authfreekeys; + authfreekeys = sk; + authnumfreekeys++; + sk = *skp; + } else { + skp = &(sk->next); + sk = sk->next; + } + } + } +} + + +/* + * auth1crypt - support for two stage encryption, part 1. + */ +void +auth1crypt(keyno, pkt, length) + U_LONG keyno; + U_LONG *pkt; + int length; /* length of all encrypted data */ +{ + if (keyno && keyno != cache_keyid) { + authkeyuncached++; + if (!authhavekey(keyno)) { + authnokey++; + return; + } + } + +#ifdef DES + if (!keyno || (cache_flags & KEY_DES)) { + DESauth1crypt(keyno, pkt, length); + return; + } +#endif + +#ifdef MD5 + if (cache_flags & KEY_MD5) { + MD5auth1crypt(keyno, pkt, length); + return; + } +#endif +} + + +/* + * auth1crypt - support for two stage encryption, part 1. + */ +int +auth2crypt(keyno, pkt, length) + U_LONG keyno; + U_LONG *pkt; + int length; /* total length of encrypted area */ +{ + if (keyno && keyno != cache_keyid) { + authkeyuncached++; + if (!authhavekey(keyno)) { + authnokey++; + return 0; + } + } + +#ifdef DES + if (!keyno || (cache_flags & KEY_DES)) + return DESauth2crypt(keyno, pkt, length); +#endif + +#ifdef MD5 + if (cache_flags & KEY_MD5) + return MD5auth2crypt(keyno, pkt, length); +#endif + + return 0; +} + +int +authencrypt(keyno, pkt, length) + U_LONG keyno; + U_LONG *pkt; + int length; /* length of encrypted portion of packet */ +{ + int sendlength = 0; + + if (keyno && keyno != cache_keyid) { + authkeyuncached++; + if (!authhavekey(keyno)) { + authnokey++; + return 0; + } + } + +#ifdef DES + if (!keyno || (cache_flags & KEY_DES)) + return sendlength = DESauthencrypt(keyno, pkt, length); +#endif + +#ifdef MD5 + if (cache_flags & KEY_MD5) + return MD5authencrypt(keyno, pkt, length); +#endif + return 0; +} + + +int +authdecrypt(keyno, pkt, length) + U_LONG keyno; + U_LONG *pkt; + int length; /* length of variable data in octets */ +{ + if (keyno && (keyno != cache_keyid)) { + authkeyuncached++; + if (!authhavekey(keyno)) { + authnokey++; + return 0; + } + } + +#ifdef DES + if (!keyno || (cache_flags & KEY_DES)) + return DESauthdecrypt(keyno, pkt, length); +#endif + +#ifdef MD5 + if (cache_flags & KEY_MD5) + return MD5authdecrypt(keyno, pkt, length); +#endif + + return 0; +} diff --git a/contrib/xntpd/lib/authparity.c b/contrib/xntpd/lib/authparity.c new file mode 100644 index 0000000000..33562cb4b1 --- /dev/null +++ b/contrib/xntpd/lib/authparity.c @@ -0,0 +1,58 @@ +/* authparity.c,v 3.1 1993/07/06 01:07:55 jbj Exp + * auth_parity - set parity on a key/check for odd parity + */ +#include "ntp_stdlib.h" + +int +DESauth_parity(key) + U_LONG *key; +{ + U_LONG mask; + int parity_err; + int bitcount; + int half; + int byte; + int i; + + /* + * Go through counting bits in each byte. Check to see if + * each parity bit was set correctly. If not, note the error + * and set it right. + */ + parity_err = 0; + for (half = 0; half < 2; half++) { /* two halves of key */ + mask = 0x80000000; + for (byte = 0; byte < 4; byte++) { /* 4 bytes per half */ + bitcount = 0; + for (i = 0; i < 7; i++) { /* 7 data bits / byte */ + if (key[half] & mask) + bitcount++; + mask >>= 1; + } + + /* + * If bitcount is even, parity must be set. If + * bitcount is odd, parity must be clear. + */ + if ((bitcount & 0x1) == 0) { + if (!(key[half] & mask)) { + parity_err++; + key[half] |= mask; + } + } else { + if (key[half] & mask) { + parity_err++; + key[half] &= ~mask; + } + } + mask >>= 1; + } + } + + /* + * Return the result of the parity check. + */ + return (parity_err == 0); +} + + diff --git a/contrib/xntpd/lib/authreadkeys.c b/contrib/xntpd/lib/authreadkeys.c new file mode 100644 index 0000000000..5800186dc8 --- /dev/null +++ b/contrib/xntpd/lib/authreadkeys.c @@ -0,0 +1,191 @@ +/* authreadkeys.c,v 3.1 1993/07/06 01:07:57 jbj Exp + * authreadkeys.c - routines to support the reading of the key file + */ +#include +#include + +#include "ntp_stdlib.h" +#include "ntp_syslog.h" + +#ifdef DES +/* + * Types of ascii representations for keys. "Standard" means a 64 bit + * hex number in NBS format, i.e. with the low order bit of each byte + * a parity bit. "NTP" means a 64 bit key in NTP format, with the + * high order bit of each byte a parity bit. "Ascii" means a 1-to-8 + * character string whose ascii representation is used as the key. + */ +#define KEY_TYPE_STD 1 +#define KEY_TYPE_NTP 2 +#define KEY_TYPE_ASCII 3 +#endif + +#ifdef MD5 +/* + * Arbitrary LONG string of ASCII characters. + */ +#define KEY_TYPE_MD5 4 +#endif + +/* + * nexttok - basic internal tokenizing routine + */ +static char * +nexttok(str) + char **str; +{ + register char *cp; + char *starttok; + + cp = *str; + + /* + * Space past white space + */ + while (*cp == ' ' || *cp == '\t') + cp++; + + /* + * Save this and space to end of token + */ + starttok = cp; + while (*cp != '\0' && *cp != '\n' && *cp != ' ' + && *cp != '\t' && *cp != '#') + cp++; + + /* + * If token length is zero return an error, else set end of + * token to zero and return start. + */ + if (starttok == cp) + return 0; + + if (*cp == ' ' || *cp == '\t') + *cp++ = '\0'; + else + *cp = '\0'; + + *str = cp; + return starttok; +} + + +/* + * authreadkeys - (re)read keys from a file. + */ +int +authreadkeys(file) + const char *file; +{ + FILE *fp; + char *line; + char *token; + U_LONG keyno; + int keytype; + char buf[512]; /* lots of room for line? */ +extern FILE * fopen P((const char *filename, const char *type)); +extern int fclose P((FILE *stream)); + + /* + * Open file. Complain and return if it can't be opened. + */ + fp = fopen(file, "r"); + if (fp == NULL) { + syslog(LOG_ERR, "can't open key file %s: %m", file); + return 0; + } + + /* + * Remove all existing keys + */ + auth_delkeys(); + + /* + * Now read lines from the file, looking for key entries + */ + while ((line = fgets(buf, sizeof buf, fp)) != NULL) { + token = nexttok(&line); + if (token == 0) + continue; + + /* + * First is key number. See if it is okay. + */ + keyno = (U_LONG)atoi(token); + if (keyno == 0) { + syslog(LOG_ERR, + "cannot change keyid 0, key entry `%s' ignored", + token); + continue; + } + + /* + * Next is keytype. See if that is all right. + */ + token = nexttok(&line); + if (token == 0) { + syslog(LOG_ERR, + "no key type for key number %d, entry ignored", + keyno); + continue; + } + switch (*token) { +#ifdef DES + case 'S': + case 's': + keytype = KEY_TYPE_STD; break; + + case 'N': + case 'n': + keytype = KEY_TYPE_NTP; break; + + case 'A': + case 'a': + keytype = KEY_TYPE_ASCII; break; +#endif +#ifdef MD5 + case 'M': + case 'm': + keytype = KEY_TYPE_MD5; break; +#endif + default: + syslog(LOG_ERR, + "invalid key type for key number %d, entry ignored", + keyno); + continue; + } + + /* + * Finally, get key and insert it + */ + token = nexttok(&line); + if (token == 0) { + syslog(LOG_ERR, + "no key for number %d entry, entry ignored", + keyno); + } else { + switch(keytype) { +#ifdef DES + case KEY_TYPE_STD: + case KEY_TYPE_NTP: + case KEY_TYPE_ASCII: + if (!authusekey(keyno, keytype, token)) + syslog(LOG_ERR, + "format/parity error for DES key %d, not used", + keyno); + break; +#endif +#ifdef MD5 + case KEY_TYPE_MD5: + if (!authusekey(keyno, keytype, token)) + syslog(LOG_ERR, + "format/parity error for MD5 key %d, not used", + keyno); + break; +#endif + } + } + } + (void) fclose(fp); + return 1; +} diff --git a/contrib/xntpd/lib/authusekey.c b/contrib/xntpd/lib/authusekey.c new file mode 100644 index 0000000000..0452031fb0 --- /dev/null +++ b/contrib/xntpd/lib/authusekey.c @@ -0,0 +1,132 @@ +/* authusekey.c,v 3.1 1993/07/06 01:07:58 jbj Exp + * authusekey - decode a key from ascii and use it + */ +#include +#include + +#include "ntp_types.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" + +/* + * Types of ascii representations for keys. "Standard" means a 64 bit + * hex number in NBS format, i.e. with the low order bit of each byte + * a parity bit. "NTP" means a 64 bit key in NTP format, with the + * high order bit of each byte a parity bit. "Ascii" means a 1-to-8 + * character string whose ascii representation is used as the key. + */ +#ifdef DES +#define KEY_TYPE_STD 1 +#define KEY_TYPE_NTP 2 +#define KEY_TYPE_ASCII 3 + +#define STD_PARITY_BITS 0x01010101 + +#endif + +#ifdef MD5 +#define KEY_TYPE_MD5 4 +#endif + +int +authusekey(keyno, keytype, str) + U_LONG keyno; + int keytype; + const char *str; +{ + U_LONG key[2]; + u_char keybytes[8]; + const char *cp; + char *xdigit; + int len; + int i; + static char *hex = "0123456789abcdef"; + + cp = str; + len = strlen(cp); + if (len == 0) + return 0; + + switch(keytype) { +#ifdef DES + case KEY_TYPE_STD: + case KEY_TYPE_NTP: + if (len != 16) /* Lazy. Should define constant */ + return 0; + /* + * Decode hex key. + */ + key[0] = 0; + key[1] = 0; + for (i = 0; i < 16; i++) { + if (!isascii(*cp)) + return 0; + xdigit = strchr(hex, isupper(*cp) ? tolower(*cp) : *cp); + cp++; + if (xdigit == 0) + return 0; + key[i>>3] <<= 4; + key[i>>3] |= (U_LONG)(xdigit - hex) & 0xf; + } + + /* + * If this is an NTP format key, put it into NBS format + */ + if (keytype == KEY_TYPE_NTP) { + for (i = 0; i < 2; i++) + key[i] = ((key[i] << 1) & ~STD_PARITY_BITS) + | ((key[i] >> 7) & STD_PARITY_BITS); + } + + /* + * Check the parity, reject the key if the check fails + */ + if (!DESauth_parity(key)) { + return 0; + } + + /* + * We can't find a good reason not to use this key. + * So use it. + */ + DESauth_setkey(keyno, key); + break; + + case KEY_TYPE_ASCII: + /* + * Make up key from ascii representation + */ + bzero((char *) keybytes, sizeof(keybytes)); + for (i = 0; i < 8 && i < len; i++) + keybytes[i] = *cp++ << 1; + key[0] = (U_LONG)keybytes[0] << 24 | (U_LONG)keybytes[1] << 16 + | (U_LONG)keybytes[2] << 8 | (U_LONG)keybytes[3]; + key[1] = (U_LONG)keybytes[4] << 24 | (U_LONG)keybytes[5] << 16 + | (U_LONG)keybytes[6] << 8 | (U_LONG)keybytes[7]; + + /* + * Set parity on key + */ + (void)DESauth_parity(key); + + /* + * Now set key in. + */ + DESauth_setkey(keyno, key); + break; +#endif + +#ifdef MD5 + case KEY_TYPE_MD5: + /* XXX FIXME: MD5auth_setkey() casts arg2 back to (char *) */ + MD5auth_setkey(keyno, (U_LONG *)str); + break; +#endif + + default: + /* Oh, well */ + return 0; + } + + return 1; +} diff --git a/contrib/xntpd/lib/buftvtots.c b/contrib/xntpd/lib/buftvtots.c new file mode 100644 index 0000000000..d9b484db2d --- /dev/null +++ b/contrib/xntpd/lib/buftvtots.c @@ -0,0 +1,61 @@ +/* buftvtots.c,v 3.1 1993/07/06 01:07:59 jbj Exp + * buftvtots - pull a Unix-format (struct timeval) time stamp out of + * an octet stream and convert it to a l_fp time stamp. + * This is useful when using the clock line discipline. + */ +#include "ntp_fp.h" +#include "ntp_unixtime.h" + +int +buftvtots(bufp, ts) + const char *bufp; + l_fp *ts; +{ + register const u_char *bp; + register U_LONG sec; + register U_LONG usec; + +#ifdef XNTP_BIG_ENDIAN + bp = (u_char *)bufp; + + sec = (U_LONG)*bp++ & 0xff; + sec <<= 8; + sec += (U_LONG)*bp++ & 0xff; + sec <<= 8; + sec += (U_LONG)*bp++ & 0xff; + sec <<= 8; + sec += (U_LONG)*bp++ & 0xff; + + usec = (U_LONG)*bp++ & 0xff; + usec <<= 8; + usec += (U_LONG)*bp++ & 0xff; + usec <<= 8; + usec += (U_LONG)*bp++ & 0xff; + usec <<= 8; + usec += (U_LONG)*bp & 0xff; +#else + bp = (u_char *)bufp + 7; + + usec = (U_LONG)*bp-- & 0xff; + usec <<= 8; + usec += (U_LONG)*bp-- & 0xff; + usec <<= 8; + usec += (U_LONG)*bp-- & 0xff; + usec <<= 8; + usec += (U_LONG)*bp-- & 0xff; + + sec = (U_LONG)*bp-- & 0xff; + sec <<= 8; + sec += (U_LONG)*bp-- & 0xff; + sec <<= 8; + sec += (U_LONG)*bp-- & 0xff; + sec <<= 8; + sec += (U_LONG)*bp & 0xff; +#endif + if (usec > 999999) + return 0; + + ts->l_ui = sec + (U_LONG)JAN_1970; + TVUTOTSF(usec, ts->l_uf); + return 1; +} diff --git a/contrib/xntpd/lib/caljulian.c b/contrib/xntpd/lib/caljulian.c new file mode 100644 index 0000000000..92d6d742a6 --- /dev/null +++ b/contrib/xntpd/lib/caljulian.c @@ -0,0 +1,105 @@ +/* caljulian.c,v 3.1 1993/07/06 01:08:00 jbj Exp + * caljulian - determine the Julian date from an NTP time. + */ +#include + +#include "ntp_types.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * calmonthtab - month start offsets from the beginning of a cycle. + */ +static u_short calmonthtab[12] = { + 0, /* March */ + MAR, /* April */ + (MAR+APR), /* May */ + (MAR+APR+MAY), /* June */ + (MAR+APR+MAY+JUN), /* July */ + (MAR+APR+MAY+JUN+JUL), /* August */ + (MAR+APR+MAY+JUN+JUL+AUG), /* September */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP), /* October */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT), /* November */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV), /* December */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC), /* January */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC+JAN), /* February */ +}; + +/* + * caldaytab - calendar year start day offsets + */ +static u_short caldaytab[YEARSPERCYCLE] = { + (DAYSPERYEAR - (JAN + FEB)), + ((DAYSPERYEAR * 2) - (JAN + FEB)), + ((DAYSPERYEAR * 3) - (JAN + FEB)), + ((DAYSPERYEAR * 4) - (JAN + FEB)), +}; + +void +caljulian(ntptime, jt) + U_LONG ntptime; + register struct calendar *jt; +{ + register int i; + register U_LONG nt; + register u_short snt; + register int cyear; + + /* + * Find the start of the cycle this is in. + */ + nt = ntptime; + if (nt >= MAR1988) { + cyear = CYCLE22; + nt -= MAR1988; + } else { + cyear = 0; + nt -= MAR1900; + } + while (nt >= SECSPERCYCLE) { + nt -= SECSPERCYCLE; + cyear++; + } + + /* + * Seconds, minutes and hours are too hard to do without + * divides, so we don't. + */ + jt->second = nt % SECSPERMIN; + nt /= SECSPERMIN; /* nt in minutes */ + jt->minute = nt % MINSPERHR; + snt = nt / MINSPERHR; /* snt in hours */ + jt->hour = snt % HRSPERDAY; + snt /= HRSPERDAY; /* nt in days */ + + /* + * snt is now the number of days into the cycle, from 0 to 1460. + */ + cyear <<= 2; + if (snt < caldaytab[0]) { + jt->yearday = snt + JAN + FEBLEAP + 1; /* first year is leap */ + } else { + for (i = 1; i < YEARSPERCYCLE; i++) + if (snt < caldaytab[i]) + break; + jt->yearday = snt - caldaytab[i-1] + 1; + cyear += i; + } + jt->year = cyear + 1900; + + /* + * One last task, to compute the month and day. Normalize snt to + * a day within a cycle year. + */ + while (snt >= DAYSPERYEAR) + snt -= DAYSPERYEAR; + for (i = 0; i < 11; i++) + if (snt < calmonthtab[i+1]) + break; + + if (i > 9) + jt->month = i - 9; /* January or February */ + else + jt->month = i + 3; /* March through December */ + jt->monthday = snt - calmonthtab[i] + 1; +} diff --git a/contrib/xntpd/lib/calleapwhen.c b/contrib/xntpd/lib/calleapwhen.c new file mode 100644 index 0000000000..379643f095 --- /dev/null +++ b/contrib/xntpd/lib/calleapwhen.c @@ -0,0 +1,61 @@ +/* calleapwhen.c,v 3.1 1993/07/06 01:08:02 jbj Exp + * calleapwhen - determine the number of seconds to the next possible + * leap occurance and the last one. + */ +#include + +#include "ntp_types.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * calleaptab - leaps occur at the end of December and June + */ +LONG calleaptab[10] = { + -(JAN+FEBLEAP)*SECSPERDAY, /* leap previous to cycle */ + (MAR+APR+MAY+JUN)*SECSPERDAY, /* end of June */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC)*SECSPERDAY, /* end of Dec */ + (MAR+APR+MAY+JUN)*SECSPERDAY + SECSPERYEAR, + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC)*SECSPERDAY + SECSPERYEAR, + (MAR+APR+MAY+JUN)*SECSPERDAY + 2*SECSPERYEAR, + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC)*SECSPERDAY + 2*SECSPERYEAR, + (MAR+APR+MAY+JUN)*SECSPERDAY + 3*SECSPERYEAR, + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC)*SECSPERDAY + 3*SECSPERYEAR, + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC+JAN+FEBLEAP+MAR+APR+MAY+JUN) + *SECSPERDAY + 3*SECSPERYEAR, /* next after current cycle */ +}; + +void +calleapwhen(ntpdate, leaplast, leapnext) + U_LONG ntpdate; + U_LONG *leaplast; + U_LONG *leapnext; +{ + register U_LONG dateincycle; + register int i; + + /* + * Find the offset from the start of the cycle + */ + dateincycle = ntpdate; + if (dateincycle >= MAR1988) + dateincycle -= MAR1988; + else + dateincycle -= MAR1900; + + while (dateincycle >= SECSPERCYCLE) + dateincycle -= SECSPERCYCLE; + + /* + * Find where we are with respect to the leap events. + */ + for (i = 1; i < 9; i++) + if (dateincycle < (U_LONG)calleaptab[i]) + break; + + /* + * i points at the next leap. Compute the last and the next. + */ + *leaplast = (U_LONG)((LONG)dateincycle - calleaptab[i-1]); + *leapnext = (U_LONG)(calleaptab[i] - (LONG)dateincycle); +} diff --git a/contrib/xntpd/lib/caltontp.c b/contrib/xntpd/lib/caltontp.c new file mode 100644 index 0000000000..f5da0ab761 --- /dev/null +++ b/contrib/xntpd/lib/caltontp.c @@ -0,0 +1,90 @@ +/* caltontp.c,v 3.1 1993/07/06 01:08:04 jbj Exp + * caltontp - convert a julian date to an NTP time + */ +#include + +#include "ntp_types.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * calmonthtab - month start offsets from the beginning of a cycle. + */ +static u_short calmonthtab[12] = { + 0, /* March */ + MAR, /* April */ + (MAR+APR), /* May */ + (MAR+APR+MAY), /* June */ + (MAR+APR+MAY+JUN), /* July */ + (MAR+APR+MAY+JUN+JUL), /* August */ + (MAR+APR+MAY+JUN+JUL+AUG), /* September */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP), /* October */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT), /* November */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV), /* December */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC), /* January */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC+JAN), /* February */ +}; + +U_LONG +caltontp(jt) + register const struct calendar *jt; +{ + register int cyear; + register int resyear; + register U_LONG nt; + register int yearday; + + /* + * Find the start of the cycle this is in. + */ + cyear = (int)(jt->year - 1900) >> 2; + resyear = (jt->year - 1900) - (cyear << 2); + yearday = 0; + if (resyear == 0) { + if (jt->yearday == 0) { + if (jt->month == 1 || jt->month == 2) { + cyear--; + resyear = 3; + } + } else { + if (jt->yearday <= (u_short)(JAN+FEBLEAP)) { + cyear--; + resyear = 3; + yearday = calmonthtab[10] + jt->yearday; + } else { + yearday = jt->yearday - (JAN+FEBLEAP); + } + } + } else { + if (jt->yearday == 0) { + if (jt->month == 1 || jt->month == 2) + resyear--; + } else { + if (jt->yearday <= (u_short)(JAN+FEB)) { + resyear--; + yearday = calmonthtab[10] + jt->yearday; + } else { + yearday = jt->yearday - (JAN+FEB); + } + } + } + + if (yearday == 0) { + if (jt->month >= 3) { + yearday = calmonthtab[jt->month - 3] + jt->monthday; + } else { + yearday = calmonthtab[jt->month + 9] + jt->monthday; + } + } + + nt = TIMESDPERC((U_LONG)cyear); + while (resyear-- > 0) + nt += DAYSPERYEAR; + nt += (U_LONG) (yearday - 1); + + nt = TIMES24(nt) + (U_LONG)jt->hour; + nt = TIMES60(nt) + (U_LONG)jt->minute; + nt = TIMES60(nt) + (U_LONG)jt->second; + + return nt + MAR1900; +} diff --git a/contrib/xntpd/lib/calyearstart.c b/contrib/xntpd/lib/calyearstart.c new file mode 100644 index 0000000000..1bb3321f72 --- /dev/null +++ b/contrib/xntpd/lib/calyearstart.c @@ -0,0 +1,62 @@ +/* calyearstart.c,v 3.1 1993/07/06 01:08:06 jbj Exp + * calyearstart - determine the NTP time at midnight of January 1 in + * the year of the given date. + */ +#include + +#include "ntp_types.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * calyeartab - year start offsets from the beginning of a cycle + */ +U_LONG calyeartab[YEARSPERCYCLE] = { + (SECSPERLEAPYEAR-JANFEBLEAP), + (SECSPERLEAPYEAR-JANFEBLEAP) + SECSPERYEAR, + (SECSPERLEAPYEAR-JANFEBLEAP) + 2*SECSPERYEAR, + (SECSPERLEAPYEAR-JANFEBLEAP) + 3*SECSPERYEAR +}; + +U_LONG +calyearstart(dateinyear) + register U_LONG dateinyear; +{ + register U_LONG cyclestart; + register U_LONG nextyear, lastyear; + register int i; + + /* + * Find the start of the cycle this is in. + */ + if (dateinyear >= MAR1988) + cyclestart = MAR1988; + else + cyclestart = MAR1900; + while ((cyclestart + SECSPERCYCLE) <= dateinyear) + cyclestart += SECSPERCYCLE; + + /* + * If we're in the first year of the cycle, January 1 is + * two months back from the cyclestart and the year is + * a leap year. + */ + lastyear = cyclestart + calyeartab[0]; + if (dateinyear < lastyear) + return (cyclestart - JANFEBLEAP); + + /* + * Look for an intermediate year + */ + for (i = 1; i < YEARSPERCYCLE; i++) { + nextyear = cyclestart + calyeartab[i]; + if (dateinyear < nextyear) + return lastyear; + lastyear = nextyear; + } + + /* + * Not found, must be in last two months of cycle + */ + return nextyear; +} diff --git a/contrib/xntpd/lib/clocktime.c b/contrib/xntpd/lib/clocktime.c new file mode 100644 index 0000000000..36b967e9a1 --- /dev/null +++ b/contrib/xntpd/lib/clocktime.c @@ -0,0 +1,131 @@ +/* clocktime.c,v 3.1 1993/07/06 01:08:07 jbj Exp + * clocktime - compute the NTP date from a day of year, hour, minute + * and second. + */ +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +/* + * Hacks to avoid excercising the multiplier. I have no pride. + */ +#define MULBY10(x) (((x)<<3) + ((x)<<1)) +#define MULBY60(x) (((x)<<6) - ((x)<<2)) /* watch overflow */ +#define MULBY24(x) (((x)<<4) + ((x)<<3)) + +/* + * Two days, in seconds. + */ +#define TWODAYS (2*24*60*60) + +/* + * We demand that the time be within CLOSETIME seconds of the receive + * time stamp. This is about 4 hours, which hopefully should be + * wide enough to collect most data, while close enough to keep things + * from getting confused. + */ +#define CLOSETIME (4*60*60) + + +int +clocktime(yday, hour, minute, second, tzoff, rec_ui, yearstart, ts_ui) + int yday; + int hour; + int minute; + int second; + int tzoff; + U_LONG rec_ui; + U_LONG *yearstart; + U_LONG *ts_ui; +{ + register LONG tmp; + register U_LONG date; + register U_LONG yst; + + /* + * Compute the offset into the year in seconds. Note that + * this could come out to be a negative number. + */ + tmp = (LONG)(MULBY24((yday-1)) + hour + tzoff); + tmp = MULBY60(tmp) + (LONG)minute; + tmp = MULBY60(tmp) + (LONG)second; + + /* + * Initialize yearstart, if necessary. + */ + yst = *yearstart; + if (yst == 0) { + yst = calyearstart(rec_ui); + *yearstart = yst; + } + + /* + * Now the fun begins. We demand that the received clock time + * be within CLOSETIME of the receive timestamp, but + * there is uncertainty about the year the timestamp is in. + * Use the current year start for the first check, this should + * work most of the time. + */ + date = (U_LONG)(tmp + (LONG)yst); + if (date < (rec_ui + CLOSETIME) && + date > (rec_ui - CLOSETIME)) { + *ts_ui = date; + return 1; + } + + /* + * Trouble. Next check is to see if the year rolled over and, if + * so, try again with the new year's start. + */ + yst = calyearstart(rec_ui); + if (yst != *yearstart) { + date = (U_LONG)((LONG)yst + tmp); + *ts_ui = date; + if (date < (rec_ui + CLOSETIME) && + date > (rec_ui - CLOSETIME)) { + *yearstart = yst; + return 1; + } + } + + /* + * Here we know the year start matches the current system + * time. One remaining possibility is that the time code + * is in the year previous to that of the system time. This + * is only worth checking if the receive timestamp is less + * than a couple of days into the new year. + */ + if ((rec_ui - yst) < TWODAYS) { + yst = calyearstart(yst - TWODAYS); + if (yst != *yearstart) { + date = (U_LONG)(tmp + (LONG)yst); + if (date < (rec_ui + CLOSETIME) && + date > (rec_ui - CLOSETIME)) { + *yearstart = yst; + *ts_ui = date; + return 1; + } + } + } + + /* + * One last possibility is that the time stamp is in the year + * following the year the system is in. Try this one before + * giving up. + */ + yst = calyearstart(rec_ui + TWODAYS); + if (yst != *yearstart) { + date = (U_LONG)((LONG)yst + tmp); + if (date < (rec_ui + CLOSETIME) && + date > (rec_ui - CLOSETIME)) { + *yearstart = yst; + *ts_ui = date; + return 1; + } + } + + /* + * Give it up. + */ + return 0; +} diff --git a/contrib/xntpd/lib/clocktypes.c b/contrib/xntpd/lib/clocktypes.c new file mode 100644 index 0000000000..f6fc003699 --- /dev/null +++ b/contrib/xntpd/lib/clocktypes.c @@ -0,0 +1,45 @@ +/* clocktypes.c,v 3.1 1993/07/06 01:08:09 jbj Exp + * Data for pretty printing clock types + */ +#include + +#include "ntp_fp.h" +#include "ntp.h" +#include "lib_strbuf.h" +#include "ntp_refclock.h" + +struct clktype clktypes[] = { + { REFCLK_NONE, "unspecified type (0)", "UNKNOWN" }, + { REFCLK_LOCALCLOCK, "local clock synchronization (1)", "LOCAL" }, + { REFCLK_WWV_HEATH, "Heathkit WWV clock (2)", "WWV_HEATH" }, + { REFCLK_WWV_PST, "Precision Standard Time WWV clock (3)", "WWV_PST" }, + { REFCLK_WWVB_SPECTRACOM, "Spectracom WWVB clock (4)", "WWVB_SPEC" }, + { REFCLK_GOES_TRUETIME, "True Time GPS/GOES clock (5)", "GPS_GOES_TRUE" }, + { REFCLK_IRIG_AUDIO, "IRIG audio decoder (6)", "IRIG_AUDIO" }, + { REFCLK_CHU, "Direct synced to CHU (7)", "CHU" }, + { REFCLK_PARSE, "Generic reference clock driver (8)", "GENERIC" }, + { REFCLK_GPS_MX4200, "Magnavox MX4200 GPS clock (9)", "GPS_MX4200" }, + { REFCLK_GPS_AS2201, "Austron 2201A GPS clock (10)", "GPS_AS2201" }, + { REFCLK_OMEGA_TRUETIME, "TrueTime OMEGA clock (11)", "OMEGA_TRUE" }, + { REFCLK_IRIG_TPRO, "Odetics/KSI TPRO IRIG decoder (12)", "IRIG_TPRO" }, + { REFCLK_ATOM_LEITCH, "Leitch CSD 5300 controller (13)", "ATOM_LEITCH" }, + { REFCLK_MSF_EES, "MSF EES M201, UK (14)", "MSF_EES" }, + { -1, "", "" } +}; + +const char * +clockname(num) + int num; +{ + register struct clktype *clk; + + for (clk = clktypes; clk->code != -1; clk++) + { + if (num == clk->code) + { + return clk->abbrev; + } + } + + return NULL; +} diff --git a/contrib/xntpd/lib/decodenetnum.c b/contrib/xntpd/lib/decodenetnum.c new file mode 100644 index 0000000000..32320a24b8 --- /dev/null +++ b/contrib/xntpd/lib/decodenetnum.c @@ -0,0 +1,58 @@ +/* decodenetnum.c,v 3.1 1993/07/06 01:08:11 jbj Exp + * decodenetnum - return a net number (this is crude, but careful) + */ +#include +#include +#include +#include + +#include "ntp_stdlib.h" + +int +decodenetnum(num, netnum) + const char *num; + U_LONG *netnum; +{ + register const char *cp; + register char *bp; + register int i; + register int temp; + register int eos; + char buf[80]; /* will core dump on really stupid stuff */ + + cp = num; + *netnum = 0; + + if (*cp == '[') { + eos = ']'; + cp++; + } else { + eos = '\0'; + } + + for (i = 0; i < 4; i++) { + bp = buf; + while (isdigit(*cp)) + *bp++ = *cp++; + if (bp == buf) + break; + + if (i < 3) { + if (*cp++ != '.') + break; + } else if (*cp != eos) + break; + + *bp = '\0'; + temp = atoi(buf); + if (temp > 255) + break; + *netnum <<= 8; + *netnum += temp; + } + + if (i < 4) + return 0; + *netnum = htonl(*netnum); + return 1; +} diff --git a/contrib/xntpd/lib/dofptoa.c b/contrib/xntpd/lib/dofptoa.c new file mode 100644 index 0000000000..c6e317f69d --- /dev/null +++ b/contrib/xntpd/lib/dofptoa.c @@ -0,0 +1,117 @@ +/* dofptoa.c,v 3.1 1993/07/06 01:08:12 jbj Exp + * dofptoa - do the grunge work to convert an fp number to ascii + */ +#include + +#include "ntp_fp.h" +#include "lib_strbuf.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" + +char * +dofptoa(fpv, neg, ndec, msec) + u_fp fpv; + int neg; + int ndec; + int msec; +{ + register u_char *cp, *cpend; + register U_LONG val; + register short dec; + u_char cbuf[12]; + u_char *cpdec; + char *buf; + char *bp; + + /* + * Get a string buffer before starting + */ + LIB_GETBUF(buf); + + /* + * Zero out the buffer + */ + bzero((char *)cbuf, sizeof cbuf); + + /* + * Set the pointers to point at the first + * decimal place. Get a local copy of the value. + */ + cp = cpend = &cbuf[5]; + val = fpv; + + /* + * If we have to, decode the integral part + */ + if (!(val & 0xffff0000)) + cp--; + else { + register u_short sv = (u_short)(val >> 16); + register u_short tmp; + register u_short ten = 10; + + do { + tmp = sv; + sv /= ten; + *(--cp) = tmp - ((sv<<3) + (sv<<1)); + } while (sv != 0); + } + + /* + * Figure out how much of the fraction to do + */ + if (msec) { + dec = ndec + 3; + if (dec < 3) + dec = 3; + cpdec = &cbuf[8]; + } else { + dec = ndec; + cpdec = cpend; + } + + if (dec > 6) + dec = 6; + + if (dec > 0) { + do { + val &= 0xffff; + val = (val << 3) + (val << 1); + *cpend++ = (u_char)(val >> 16); + } while (--dec > 0); + } + + if (val & 0x8000) { + register u_char *tp; + /* + * Round it. Ick. + */ + tp = cpend; + *(--tp) += 1; + while (*tp >= 10) { + *tp = 0; + *(--tp) += 1; + } + } + + /* + * Remove leading zeroes if necessary + */ + while (cp < (cpdec -1) && *cp == 0) + cp++; + + /* + * Copy it into the buffer, asciizing as we go. + */ + bp = buf; + if (neg) + *bp++ = '-'; + + while (cp < cpend) { + if (cp == cpdec) + *bp++ = '.'; + *bp++ = (char)(*cp++ + '0'); + } + *bp = '\0'; + return buf; +} diff --git a/contrib/xntpd/lib/dolfptoa.c b/contrib/xntpd/lib/dolfptoa.c new file mode 100644 index 0000000000..ff341536ee --- /dev/null +++ b/contrib/xntpd/lib/dolfptoa.c @@ -0,0 +1,162 @@ +/* dolfptoa.c,v 3.1 1993/07/06 01:08:14 jbj Exp + * dolfptoa - do the grunge work of converting an l_fp number to decimal + */ +#include + +#include "ntp_fp.h" +#include "lib_strbuf.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" + +char * +dolfptoa(fpi, fpv, neg, ndec, msec) + U_LONG fpi; + U_LONG fpv; + int neg; + int ndec; + int msec; +{ + register u_char *cp, *cpend; + register U_LONG work_i; + register int dec; + u_char cbuf[24]; + u_char *cpdec; + char *buf; + char *bp; + + /* + * Get a string buffer before starting + */ + LIB_GETBUF(buf); + + /* + * Zero the character buffer + */ + bzero((char *) cbuf, sizeof(cbuf)); + + /* + * Work on the integral part. This is biased by what I know + * compiles fairly well for a 68000. + */ + cp = cpend = &cbuf[10]; + work_i = fpi; + if (work_i & 0xffff0000) { + register U_LONG lten = 10; + register U_LONG ltmp; + + do { + ltmp = work_i; + work_i /= lten; + ltmp -= (work_i<<3) + (work_i<<1); + *--cp = (u_char)ltmp; + } while (work_i & 0xffff0000); + } + if (work_i != 0) { + register u_short sten = 10; + register u_short stmp; + register u_short swork = (u_short)work_i; + + do { + stmp = swork; + swork /= sten; + stmp -= (swork<<3) + (swork<<1); + *--cp = (u_char)stmp; + } while (swork != 0); + } + + /* + * Done that, now deal with the problem of the fraction. First + * determine the number of decimal places. + */ + if (msec) { + dec = ndec + 3; + if (dec < 3) + dec = 3; + cpdec = &cbuf[13]; + } else { + dec = ndec; + if (dec < 0) + dec = 0; + cpdec = &cbuf[10]; + } + if (dec > 12) + dec = 12; + + /* + * If there's a fraction to deal with, do so. + */ + if (fpv != 0) { + register U_LONG work_f; + + work_f = fpv; + while (dec > 0) { + register U_LONG tmp_i; + register U_LONG tmp_f; + + dec--; + /* + * The scheme here is to multiply the + * fraction (0.1234...) by ten. This moves + * a junk of BCD into the units part. + * record that and iterate. + */ + work_i = 0; + M_LSHIFT(work_i, work_f); + tmp_i = work_i; + tmp_f = work_f; + M_LSHIFT(work_i, work_f); + M_LSHIFT(work_i, work_f); + M_ADD(work_i, work_f, tmp_i, tmp_f); + *cpend++ = (u_char)work_i; + if (work_f == 0) + break; + } + + /* + * Rounding is rotten + */ + if (work_f & 0x80000000) { + register u_char *tp = cpend; + + *(--tp) += 1; + while (*tp >= 10) { + *tp = 0; + *(--tp) += 1; + }; + if (tp < cp) + cp = tp; + } + } + cpend += dec; + + + /* + * We've now got the fraction in cbuf[], with cp pointing at + * the first character, cpend pointing past the last, and + * cpdec pointing at the first character past the decimal. + * Remove leading zeros, then format the number into the + * buffer. + */ + while (cp < cpdec) { + if (*cp != 0) + break; + cp++; + } + if (cp == cpdec) + --cp; + + bp = buf; + if (neg) + *bp++ = '-'; + while (cp < cpend) { + if (cp == cpdec) + *bp++ = '.'; + *bp++ = (char)(*cp++ + '0'); /* ascii dependent? */ + } + *bp = '\0'; + + /* + * Done! + */ + return buf; +} diff --git a/contrib/xntpd/lib/emalloc.c b/contrib/xntpd/lib/emalloc.c new file mode 100644 index 0000000000..d2a8e789f0 --- /dev/null +++ b/contrib/xntpd/lib/emalloc.c @@ -0,0 +1,20 @@ +/* emalloc.c,v 3.1 1993/07/06 01:08:15 jbj Exp + * emalloc - return new memory obtained from the system. Belch if none. + */ +#include "ntp_types.h" +#include "ntp_malloc.h" +#include "ntp_stdlib.h" +#include "ntp_syslog.h" + +char * +emalloc(size) + unsigned int size; +{ + char *mem; + + if ((mem = (char *)malloc(size)) == 0) { + syslog(LOG_ERR, "No more memory!"); + exit(1); + } + return mem; +} diff --git a/contrib/xntpd/lib/findconfig.c b/contrib/xntpd/lib/findconfig.c new file mode 100644 index 0000000000..83126686b4 --- /dev/null +++ b/contrib/xntpd/lib/findconfig.c @@ -0,0 +1,62 @@ +#ifdef SYS_HPUX +#include +#include +#include +#include +#include + +char * +FindConfig(base) + char *base; +{ + static char result[BUFSIZ]; + char hostname[BUFSIZ], *cp; + struct stat sbuf; + struct utsname unamebuf; + + /* All keyed by initial target being a directory */ + (void) strcpy(result, base); + if (stat(result, &sbuf) == 0) { + if (S_ISDIR(sbuf.st_mode)) { + + /* First choice is my hostname */ + if (gethostname(hostname, BUFSIZ) >= 0) { + (void) sprintf(result, "%s/%s", base, hostname); + if (stat(result, &sbuf) == 0) { + goto outahere; + } else { + + /* Second choice is of form default.835 */ + (void) uname(&unamebuf); + if (strncmp(unamebuf.machine, "9000/", 5) == 0) + cp = unamebuf.machine + 5; + else + cp = unamebuf.machine; + (void) sprintf(result, "%s/default.%s", base, cp); + if (stat(result, &sbuf) == 0) { + goto outahere; + } else { + + /* Last choice is just default */ + (void) sprintf(result, "%s/default", base); + if (stat(result, &sbuf) == 0) { + goto outahere; + } else { + (void) strcpy(result, "/not/found"); + } + } + } + } + } + } +outahere: + return(result); +} +#else +char * +FindConfig(base) + char *base; +{ + return base; +} +#endif diff --git a/contrib/xntpd/lib/fptoa.c b/contrib/xntpd/lib/fptoa.c new file mode 100644 index 0000000000..d245e9fa69 --- /dev/null +++ b/contrib/xntpd/lib/fptoa.c @@ -0,0 +1,24 @@ +/* fptoa.c,v 3.1 1993/07/06 01:08:16 jbj Exp + * fptoa - return an asciized representation of an s_fp number + */ +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +char * +fptoa(fpv, ndec) + s_fp fpv; + int ndec; +{ + u_fp plusfp; + int neg; + + if (fpv < 0) { + plusfp = (u_fp)(-fpv); + neg = 1; + } else { + plusfp = (u_fp)fpv; + neg = 0; + } + + return dofptoa(plusfp, neg, ndec, 0); +} diff --git a/contrib/xntpd/lib/fptoms.c b/contrib/xntpd/lib/fptoms.c new file mode 100644 index 0000000000..fb850c5362 --- /dev/null +++ b/contrib/xntpd/lib/fptoms.c @@ -0,0 +1,23 @@ +/* fptoms.c,v 3.1 1993/07/06 01:08:17 jbj Exp + * fptoms - return an asciized s_fp number in milliseconds + */ +#include "ntp_fp.h" + +char * +fptoms(fpv, ndec) + s_fp fpv; + int ndec; +{ + u_fp plusfp; + int neg; + + if (fpv < 0) { + plusfp = (u_fp)(-fpv); + neg = 1; + } else { + plusfp = (u_fp)fpv; + neg = 0; + } + + return dofptoa(plusfp, neg, ndec, 1); +} diff --git a/contrib/xntpd/lib/getopt.c b/contrib/xntpd/lib/getopt.c new file mode 100644 index 0000000000..0ab3c2917f --- /dev/null +++ b/contrib/xntpd/lib/getopt.c @@ -0,0 +1,106 @@ +/* getopt.c,v 3.1 1993/07/06 01:08:18 jbj Exp + * getopt - get option letter from argv + * + * This is a version of the public domain getopt() implementation by + * Henry Spencer, changed for 4.3BSD compatibility (in addition to System V). + * It allows rescanning of an option list by setting optind to 0 before + * calling. Thanks to Dennis Ferguson for the appropriate modifications. + * + * This file is in the Public Domain. + */ + +/*LINTLIBRARY*/ + +#include + +#include "ntp_stdlib.h" + +#ifdef lint +#undef putc +#define putc fputc +#endif /* lint */ + +char *optarg; /* Global argument pointer. */ +#ifndef __convex__ +int optind = 0; /* Global argv index. */ +#else /* __convex__ */ +extern int optind; /* Global argv index. */ +#endif /* __convex__ */ + +/* + * N.B. use following at own risk + */ +#ifndef __convex__ +int opterr = 1; /* for compatibility, should error be printed? */ +#else /* __convex__ */ +extern int opterr; /* for compatibility, should error be printed? */ +#endif /* __convex__ */ +int optopt; /* for compatibility, option character checked */ + +static char *scan = NULL; /* Private scan pointer. */ + +/* + * Print message about a bad option. Watch this definition, it's + * not a single statement. + */ +#define BADOPT(mess, ch) if (opterr) { \ + fputs(argv[0], stderr); \ + fputs(mess, stderr); \ + (void) putc(ch, stderr); \ + (void) putc('\n', stderr); \ + } \ + return('?') + +int +getopt_l(argc, argv, optstring) + int argc; + char *argv[]; + char *optstring; +{ + register char c; + register char *place; + + optarg = NULL; + + if (optind == 0) { + scan = NULL; + optind++; + } + + if (scan == NULL || *scan == '\0') { + if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') + return EOF; + if (argv[optind][1] == '-' && argv[optind][2] == '\0') { + optind++; + return EOF; + } + + scan = argv[optind]+1; + optind++; + } + + c = *scan++; + optopt = c & 0377; + for (place = optstring; place != NULL && *place != '\0'; ++place) + if (*place == c) + break; + + if (place == NULL || *place == '\0' || c == ':' || c == '?') { + BADOPT(": unknown option -", c); + } + + place++; + if (*place == ':') { + if (*scan != '\0') { + optarg = scan; + scan = NULL; + } else if (optind >= argc) { + BADOPT(": option requires argument -", c); + } else { + optarg = argv[optind]; + optind++; + } + } + + return c&0377; +} diff --git a/contrib/xntpd/lib/gettstamp.c b/contrib/xntpd/lib/gettstamp.c new file mode 100644 index 0000000000..19bcb0c638 --- /dev/null +++ b/contrib/xntpd/lib/gettstamp.c @@ -0,0 +1,29 @@ +/* gettstamp.c,v 3.1 1993/07/06 01:08:20 jbj Exp + * gettstamp - return the system time in timestamp format + */ +#include +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +void +gettstamp(ts) + l_fp *ts; +{ + struct timeval tv; + + /* + * Quickly get the time of day and convert it + */ + (void) GETTIMEOFDAY(&tv, (struct timezone *)NULL); + if (tv.tv_usec >= 1000000) { /* bum solaris */ + tv.tv_usec -= 1000000; + tv.tv_sec++; + } + TVTOTS(&tv, ts); + ts->l_uf += TS_ROUNDBIT; /* guaranteed not to overflow */ + ts->l_ui += JAN_1970; + ts->l_uf &= TS_MASK; +} diff --git a/contrib/xntpd/lib/hextoint.c b/contrib/xntpd/lib/hextoint.c new file mode 100644 index 0000000000..90329c4136 --- /dev/null +++ b/contrib/xntpd/lib/hextoint.c @@ -0,0 +1,38 @@ +/* hextoint.c,v 3.1 1993/07/06 01:08:21 jbj Exp + * hextoint - convert an ascii string in hex to an unsigned + * long, with error checking + */ +#include + +#include "ntp_stdlib.h" + +int +hextoint(str, ival) + const char *str; + U_LONG *ival; +{ + register U_LONG u; + register const char *cp; + + cp = str; + + if (*cp == '\0') + return 0; + + u = 0; + while (*cp != '\0') { + if (!isxdigit(*cp)) + return 0; + if (u >= 0x10000000) + return 0; /* overflow */ + u <<= 4; + if (*cp <= '9') /* very ascii dependent */ + u += *cp++ - '0'; + else if (*cp >= 'a') + u += *cp++ - 'a' + 10; + else + u += *cp++ - 'A' + 10; + } + *ival = u; + return 1; +} diff --git a/contrib/xntpd/lib/hextolfp.c b/contrib/xntpd/lib/hextolfp.c new file mode 100644 index 0000000000..6473c7c3db --- /dev/null +++ b/contrib/xntpd/lib/hextolfp.c @@ -0,0 +1,66 @@ +/* hextolfp.c,v 3.1 1993/07/06 01:08:22 jbj Exp + * hextolfp - convert an ascii hex string to an l_fp number + */ +#include +#include + +#include "ntp_fp.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" + +int +hextolfp(str, lfp) + const char *str; + l_fp *lfp; +{ + register const char *cp; + register const char *cpstart; + register U_LONG dec_i; + register U_LONG dec_f; + char *ind = NULL; + static char *digits = "0123456789abcdefABCDEF"; + + dec_i = dec_f = 0; + cp = str; + + /* + * We understand numbers of the form: + * + * [spaces]8_hex_digits[.]8_hex_digits[spaces|\n|\0] + */ + while (isspace(*cp)) + cp++; + + cpstart = cp; + while (*cp != '\0' && (cp - cpstart) < 8 && + (ind = strchr(digits, *cp)) != NULL) { + dec_i = dec_i << 4; /* multiply by 16 */ + dec_i += ((ind - digits) > 15) ? (ind - digits) - 6 + : (ind - digits); + cp++; + } + + if ((cp - cpstart) < 8 || ind == NULL) + return 0; + if (*cp == '.') + cp++; + + cpstart = cp; + while (*cp != '\0' && (cp - cpstart) < 8 && + (ind = strchr(digits, *cp)) != NULL) { + dec_f = dec_f << 4; /* multiply by 16 */ + dec_f += ((ind - digits) > 15) ? (ind - digits) - 6 + : (ind - digits); + cp++; + } + + if ((cp - cpstart) < 8 || ind == NULL) + return 0; + + if (*cp != '\0' && !isspace(*cp)) + return 0; + + lfp->l_ui = dec_i; + lfp->l_uf = dec_f; + return 1; +} diff --git a/contrib/xntpd/lib/humandate.c b/contrib/xntpd/lib/humandate.c new file mode 100644 index 0000000000..464ed6ba4d --- /dev/null +++ b/contrib/xntpd/lib/humandate.c @@ -0,0 +1,61 @@ +/* humandate.c,v 3.1 1993/07/06 01:08:24 jbj Exp + * humandate - convert an NTP (or the current) time to something readable + */ +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +#ifdef NTP_POSIX_SOURCE +#include +#endif + +static char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; +static char *days[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +char * +humandate(ntptime) + U_LONG ntptime; +{ + char *bp; + struct tm *tm; + U_LONG sec; + + LIB_GETBUF(bp); + + sec = ntptime - JAN_1970; + tm = localtime((LONG *)&sec); + + (void) sprintf(bp, "%s, %s %2d %4d %2d:%02d:%02d", + days[tm->tm_wday], months[tm->tm_mon], tm->tm_mday, + 1900+tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec); + + return bp; +} + + +/* This is used in msyslog.c; we don't want to clutter up the log with + the year and day of the week, etc.; just the minimal date and time. */ + +char * +humanlogtime() +{ + char *bp; + time_t cursec = time((time_t *) 0); + struct tm *tm = localtime(&cursec); + + LIB_GETBUF(bp); + + (void) sprintf(bp, "%2d %s %02d:%02d:%02d", + tm->tm_mday, months[tm->tm_mon], + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return bp; +} diff --git a/contrib/xntpd/lib/inttoa.c b/contrib/xntpd/lib/inttoa.c new file mode 100644 index 0000000000..25ce26cb81 --- /dev/null +++ b/contrib/xntpd/lib/inttoa.c @@ -0,0 +1,19 @@ +/* inttoa.c,v 3.1 1993/07/06 01:08:25 jbj Exp + * inttoa - return an asciized signed integer + */ +#include + +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +inttoa(ival) + LONG ival; +{ + register char *buf; + + LIB_GETBUF(buf); + + (void) sprintf(buf, "%ld", ival); + return buf; +} diff --git a/contrib/xntpd/lib/lib_strbuf.c b/contrib/xntpd/lib/lib_strbuf.c new file mode 100644 index 0000000000..15661ab980 --- /dev/null +++ b/contrib/xntpd/lib/lib_strbuf.c @@ -0,0 +1,21 @@ +/* lib_strbuf.c,v 3.1 1993/07/06 01:08:27 jbj Exp + * lib_strbuf - library string storage + */ + +#include "lib_strbuf.h" + +/* + * Storage declarations + */ +char lib_stringbuf[LIB_NUMBUFS][LIB_BUFLENGTH]; +int lib_nextbuf; + + +/* + * initialization routine. Might be needed if the code is ROMized. + */ +void +init_lib() +{ + lib_nextbuf = 0; +} diff --git a/contrib/xntpd/lib/lib_strbuf.h b/contrib/xntpd/lib/lib_strbuf.h new file mode 100644 index 0000000000..20720fd589 --- /dev/null +++ b/contrib/xntpd/lib/lib_strbuf.h @@ -0,0 +1,22 @@ +/* lib_strbuf.h,v 3.1 1993/07/06 01:08:28 jbj Exp + * lib_strbuf.h - definitions for routines which use the common string buffers + */ + +/* + * Sizes of things + */ +#define LIB_NUMBUFS 20 +#define LIB_BUFLENGTH 80 + +/* + * Macro to get a pointer to the next buffer + */ +#define LIB_GETBUF(buf) \ + do { \ + buf = &lib_stringbuf[lib_nextbuf][0]; \ + if (++lib_nextbuf >= LIB_NUMBUFS) \ + lib_nextbuf = 0; \ + } while (0) + +extern char lib_stringbuf[LIB_NUMBUFS][LIB_BUFLENGTH]; +extern int lib_nextbuf; diff --git a/contrib/xntpd/lib/machines.c b/contrib/xntpd/lib/machines.c new file mode 100644 index 0000000000..f7a400c1d5 --- /dev/null +++ b/contrib/xntpd/lib/machines.c @@ -0,0 +1,118 @@ +/* + * provide special support for peculiar architectures + * + * Real bummers unite ! + */ + +#ifdef SYS_PTX +#include +#include +int settimeofday(tvp) + struct timeval *tvp; +{ + return stime(&tvp->tv_sec); /* lie as bad as SysVR4 */ +} + +int gettimeofday(tvp) + struct timeval *tvp; +{ + /* + * hi, this is Sequents sneak path to get to a clock + * this is also the most logical syscall for such a function + */ + return get_process_stats(tvp, PS_SELF, (struct procstats *) 0, + (struct procstats *) 0); +} +#endif + +#ifdef SYS_HPUX +/* hpux.c,v 3.1 1993/07/06 01:08:23 jbj Exp + * hpux.c -- compatibility routines for HP-UX. + * XXX many of these are not needed anymore. + */ +#include "ntp_machine.h" + +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "ntp_stdlib.h" + +#if (SYS_HPUX < 8) +char +*index(s, c) +register char *s; +register int c; +{ + return strchr (s, c); +} + + +char +*rindex(s, c) +register char *s; +register int c; +{ + return strrchr (s, c); +} + + +int +bcmp(a, b, count) +register char *a, *b; +register int count; +{ + return memcmp (a, b, count); +} + + +void +bcopy(from, to, count) +register char *from; +register char *to; +register int count; +{ + if ((to == from) || (count <= 0)) + return; + + if ((to > from) && (to <= (from + count))) { + to += count; + from += count; + + do { + *--to = *--from; + } while (--count); + } + else { + do { + *to++ = *from++; + } while (--count); + } +} + + +void +bzero(area, count) +register char *area; +register int count; +{ + memset(area, 0, count); +} +#endif + + +getdtablesize() +{ + return(sysconf(_SC_OPEN_MAX)); +} + + +int +setlinebuf(a_stream) + FILE *a_stream; +{ + return setvbuf(a_stream, (char *) NULL, _IOLBF, 0); +} + +#endif diff --git a/contrib/xntpd/lib/md5.c b/contrib/xntpd/lib/md5.c new file mode 100644 index 0000000000..77644cb32a --- /dev/null +++ b/contrib/xntpd/lib/md5.c @@ -0,0 +1,322 @@ +/* md5.c,v 3.1 1993/07/06 01:08:29 jbj Exp + *********************************************************************** + ** md5.c -- the source code for MD5 routines ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version ** + ** Revised (for MD5): RLR 4/27/91 ** + ** -- G modified to have y&~z instead of y&z ** + ** -- FF, GG, HH modified to add in last register done ** + ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** + ** -- distinct additive constant for each step ** + ** -- round 4 added, working mod 7 ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#include "md5.h" + +/* + *********************************************************************** + ** Message-digest routines: ** + ** To form the message digest for a message M ** + ** (1) Initialize a context buffer mdContext using MD5Init ** + ** (2) Call MD5Update on mdContext and M ** + ** (3) Call MD5Final on mdContext ** + ** The message digest is now in mdContext->digest[0...15] ** + *********************************************************************** + */ + +/* forward declaration */ +static void Transform (); + +#ifdef __STDC__ +static const +#else +static +#endif +unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G, H and I are basic MD5 functions */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#if defined(FAST_MD5) && defined(__GNUC__) && defined(mc68000) +/* + * If we're on a 68000 based CPU and using a GNU C compiler with + * inline assembly code, we can speed this up a bit. + */ +inline UINT4 ROTATE_LEFT(UINT4 x, int n) +{ + asm("roll %2,%0" : "=d" (x) : "0" (x), "Ir" (n)); + return x; +} +#else +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) +#endif + + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* The routine MD5Init initializes the message-digest context + mdContext. All fields are set to zero. + */ +void MD5Init (mdContext) +MD5_CTX *mdContext; +{ + mdContext->i[0] = mdContext->i[1] = (UINT4)0; + + /* Load magic initialization constants. + */ + mdContext->buf[0] = (UINT4)0x67452301; + mdContext->buf[1] = (UINT4)0xefcdab89; + mdContext->buf[2] = (UINT4)0x98badcfe; + mdContext->buf[3] = (UINT4)0x10325476; +} + +/* The routine MD5Update updates the message-digest context to + account for the presence of each of the characters inBuf[0..inLen-1] + in the message whose digest is being computed. + */ +void MD5Update (mdContext, inBuf, inLen) +MD5_CTX *mdContext; +unsigned char *inBuf; +unsigned int inLen; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((UINT4)inLen << 3); + mdContext->i[1] += ((UINT4)inLen >> 29); + + while (inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if (mdi == 0x40) { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + mdi = 0; + } + } +} + +/* The routine MD5Final terminates the message-digest computation and + ends with the desired message digest in mdContext->digest[0...15]. + */ + +void MD5Final (mdContext) +MD5_CTX *mdContext; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5Update (mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + + /* store buffer in digest */ + for (i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii+1] = + (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii+2] = + (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii+3] = + (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } +} + +/* Basic MD5 step. Transforms buf based on in. + */ +static void Transform (buf, in) +UINT4 *buf; +UINT4 *in; +{ + UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + + FF ( a, b, c, d, in[ 0], S11, 0xd76aa478); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, 0xe8c7b756); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, 0x242070db); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, 0xc1bdceee); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, 0xf57c0faf); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, 0x4787c62a); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, 0xa8304613); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, 0xfd469501); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, 0x698098d8); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, 0x8b44f7af); /* 10 */ + FF ( c, d, a, b, in[10], S13, 0xffff5bb1); /* 11 */ + FF ( b, c, d, a, in[11], S14, 0x895cd7be); /* 12 */ + FF ( a, b, c, d, in[12], S11, 0x6b901122); /* 13 */ + FF ( d, a, b, c, in[13], S12, 0xfd987193); /* 14 */ + FF ( c, d, a, b, in[14], S13, 0xa679438e); /* 15 */ + FF ( b, c, d, a, in[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, 0xf61e2562); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, 0xc040b340); /* 18 */ + GG ( c, d, a, b, in[11], S23, 0x265e5a51); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, 0xd62f105d); /* 21 */ + GG ( d, a, b, c, in[10], S22, 0x2441453); /* 22 */ + GG ( c, d, a, b, in[15], S23, 0xd8a1e681); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, 0x21e1cde6); /* 25 */ + GG ( d, a, b, c, in[14], S22, 0xc33707d6); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, 0xf4d50d87); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, 0x455a14ed); /* 28 */ + GG ( a, b, c, d, in[13], S21, 0xa9e3e905); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, 0xfcefa3f8); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, 0x676f02d9); /* 31 */ + GG ( b, c, d, a, in[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, 0xfffa3942); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, 0x8771f681); /* 34 */ + HH ( c, d, a, b, in[11], S33, 0x6d9d6122); /* 35 */ + HH ( b, c, d, a, in[14], S34, 0xfde5380c); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, 0xa4beea44); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, 0x4bdecfa9); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, 0xf6bb4b60); /* 39 */ + HH ( b, c, d, a, in[10], S34, 0xbebfbc70); /* 40 */ + HH ( a, b, c, d, in[13], S31, 0x289b7ec6); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, 0xeaa127fa); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, 0xd4ef3085); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, 0x4881d05); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, 0xd9d4d039); /* 45 */ + HH ( d, a, b, c, in[12], S32, 0xe6db99e5); /* 46 */ + HH ( c, d, a, b, in[15], S33, 0x1fa27cf8); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, 0xf4292244); /* 49 */ + II ( d, a, b, c, in[ 7], S42, 0x432aff97); /* 50 */ + II ( c, d, a, b, in[14], S43, 0xab9423a7); /* 51 */ + II ( b, c, d, a, in[ 5], S44, 0xfc93a039); /* 52 */ + II ( a, b, c, d, in[12], S41, 0x655b59c3); /* 53 */ + II ( d, a, b, c, in[ 3], S42, 0x8f0ccc92); /* 54 */ + II ( c, d, a, b, in[10], S43, 0xffeff47d); /* 55 */ + II ( b, c, d, a, in[ 1], S44, 0x85845dd1); /* 56 */ + II ( a, b, c, d, in[ 8], S41, 0x6fa87e4f); /* 57 */ + II ( d, a, b, c, in[15], S42, 0xfe2ce6e0); /* 58 */ + II ( c, d, a, b, in[ 6], S43, 0xa3014314); /* 59 */ + II ( b, c, d, a, in[13], S44, 0x4e0811a1); /* 60 */ + II ( a, b, c, d, in[ 4], S41, 0xf7537e82); /* 61 */ + II ( d, a, b, c, in[11], S42, 0xbd3af235); /* 62 */ + II ( c, d, a, b, in[ 2], S43, 0x2ad7d2bb); /* 63 */ + II ( b, c, d, a, in[ 9], S44, 0xeb86d391); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + *********************************************************************** + ** End of md5.c ** + ******************************** (cut) ******************************** + */ diff --git a/contrib/xntpd/lib/mfptoa.c b/contrib/xntpd/lib/mfptoa.c new file mode 100644 index 0000000000..4e513d24f8 --- /dev/null +++ b/contrib/xntpd/lib/mfptoa.c @@ -0,0 +1,22 @@ +/* mfptoa.c,v 3.1 1993/07/06 01:08:30 jbj Exp + * mfptoa - Return an asciized representation of a signed LONG fp number + */ +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +char * +mfptoa(fpi, fpf, ndec) + U_LONG fpi; + U_LONG fpf; + int ndec; +{ + int isneg; + + if (M_ISNEG(fpi, fpf)) { + isneg = 1; + M_NEG(fpi, fpf); + } else + isneg = 0; + + return dolfptoa(fpi, fpf, isneg, ndec, 0); +} diff --git a/contrib/xntpd/lib/mfptoms.c b/contrib/xntpd/lib/mfptoms.c new file mode 100644 index 0000000000..f686d413ed --- /dev/null +++ b/contrib/xntpd/lib/mfptoms.c @@ -0,0 +1,22 @@ +/* mfptoms.c,v 3.1 1993/07/06 01:08:31 jbj Exp + * mfptoms - Return an asciized signed LONG fp number in milliseconds + */ +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +char * +mfptoms(fpi, fpf, ndec) + U_LONG fpi; + U_LONG fpf; + int ndec; +{ + int isneg; + + if (M_ISNEG(fpi, fpf)) { + isneg = 1; + M_NEG(fpi, fpf); + } else + isneg = 0; + + return dolfptoa(fpi, fpf, isneg, ndec, 1); +} diff --git a/contrib/xntpd/lib/modetoa.c b/contrib/xntpd/lib/modetoa.c new file mode 100644 index 0000000000..483327186a --- /dev/null +++ b/contrib/xntpd/lib/modetoa.c @@ -0,0 +1,33 @@ +/* modetoa.c,v 3.1 1993/07/06 01:08:33 jbj Exp + * modetoa - return an asciized mode + */ +#include + +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +modetoa(mode) + int mode; +{ + char *bp; + static char *modestrings[] = { + "unspec", + "sym_active", + "sym_passive", + "client", + "server", + "broadcast", + "control", + "private", + "bclient", + }; + + if (mode < 0 || mode >= (sizeof modestrings)/sizeof(char *)) { + LIB_GETBUF(bp); + (void)sprintf(bp, "mode#%d", mode); + return bp; + } + + return modestrings[mode]; +} diff --git a/contrib/xntpd/lib/mstolfp.c b/contrib/xntpd/lib/mstolfp.c new file mode 100644 index 0000000000..8a642cf0a5 --- /dev/null +++ b/contrib/xntpd/lib/mstolfp.c @@ -0,0 +1,99 @@ +/* mstolfp.c,v 3.1 1993/07/06 01:08:34 jbj Exp + * mstolfp - convert an ascii string in milliseconds to an l_fp number + */ +#include +#include + +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +int +mstolfp(str, lfp) + const char *str; + l_fp *lfp; +{ + register const char *cp; + register char *bp; + register const char *cpdec; + char buf[100]; + + /* + * We understand numbers of the form: + * + * [spaces][-][digits][.][digits][spaces|\n|\0] + * + * This is one enormous hack. Since I didn't feel like + * rewriting the decoding routine for milliseconds, what + * is essentially done here is to make a copy of the string + * with the decimal moved over three places so the seconds + * decoding routine can be used. + */ + bp = buf; + cp = str; + while (isspace(*cp)) + cp++; + + if (*cp == '-') { + *bp++ = '-'; + cp++; + } + + if (*cp != '.' && !isdigit(*cp)) + return 0; + + + /* + * Search forward for the decimal point or the end of the string. + */ + cpdec = cp; + while (isdigit(*cpdec)) + cpdec++; + + /* + * Found something. If we have more than three digits copy the + * excess over, else insert a leading 0. + */ + if ((cpdec - cp) > 3) { + do { + *bp++ = (char)*cp++; + } while ((cpdec - cp) > 3); + } else { + *bp++ = '0'; + } + + /* + * Stick the decimal in. If we've got less than three digits in + * front of the millisecond decimal we insert the appropriate number + * of zeros. + */ + *bp++ = '.'; + if ((cpdec - cp) < 3) { + register int i = 3 - (cpdec - cp); + + do { + *bp++ = '0'; + } while (--i > 0); + } + + /* + * Copy the remainder up to the millisecond decimal. If cpdec + * is pointing at a decimal point, copy in the trailing number too. + */ + while (cp < cpdec) + *bp++ = (char)*cp++; + + if (*cp == '.') { + cp++; + while (isdigit(*cp)) + *bp++ = (char)*cp++; + } + *bp = '\0'; + + /* + * Check to make sure the string is properly terminated. If + * so, give the buffer to the decoding routine. + */ + if (*cp != '\0' && !isspace(*cp)) + return 0; + return atolfp(buf, lfp); +} diff --git a/contrib/xntpd/lib/msutotsf.c b/contrib/xntpd/lib/msutotsf.c new file mode 100644 index 0000000000..412cfbd1ed --- /dev/null +++ b/contrib/xntpd/lib/msutotsf.c @@ -0,0 +1,35 @@ +/* msutotsf.c,v 3.1 1993/07/06 01:08:35 jbj Exp + * msutotsf - tables for converting from a subsecond millisecond value + * to a time stamp fraction. + */ +#include + +#include "ntp_types.h" + +/* + * Index each of these tables with five bits of the (less than) 10 + * bit millisecond value. Note that the tables are rounded (not + * truncated). The error in the result will thus be +-1 low order + * bit in the time stamp fraction. + */ +U_LONG msutotsflo[32] = { + 0x00000000, 0x00418937, 0x0083126f, 0x00c49ba6, + 0x010624dd, 0x0147ae14, 0x0189374c, 0x01cac083, + 0x020c49ba, 0x024dd2f2, 0x028f5c29, 0x02d0e560, + 0x03126e98, 0x0353f7cf, 0x03958106, 0x03d70a3d, + 0x04189375, 0x045a1cac, 0x049ba5e3, 0x04dd2f1b, + 0x051eb852, 0x05604189, 0x05a1cac1, 0x05e353f8, + 0x0624dd2f, 0x06666666, 0x06a7ef9e, 0x06e978d5, + 0x072b020c, 0x076c8b44, 0x07ae147b, 0x07ef9db2 +}; + +U_LONG msutotsfhi[32] = { + 0x00000000, 0x083126e9, 0x10624dd3, 0x189374bc, + 0x20c49ba6, 0x28f5c28f, 0x3126e979, 0x39581062, + 0x4189374c, 0x49ba5e35, 0x51eb851f, 0x5a1cac08, + 0x624dd2f2, 0x6a7ef9db, 0x72b020c5, 0x7ae147ae, + 0x83126e98, 0x8b439581, 0x9374bc6a, 0x9ba5e354, + 0xa3d70a3d, 0xac083127, 0xb4395810, 0xbc6a7efa, + 0xc49ba5e3, 0xcccccccd, 0xd4fdf3b6, 0xdd2f1aa0, + 0xe5604189, 0xed916873, 0xf5c28f5c, 0xfdf3b646 +}; diff --git a/contrib/xntpd/lib/msyslog.c b/contrib/xntpd/lib/msyslog.c new file mode 100644 index 0000000000..a8df27d3b9 --- /dev/null +++ b/contrib/xntpd/lib/msyslog.c @@ -0,0 +1,107 @@ +/* msyslog.c,v 3.1 1993/07/06 01:08:36 jbj Exp + * msyslog - either send a message to the terminal or print it on + * the standard output. + * + * Converted to use varargs, much better ... jks + */ +#include +#include + +/* alternative, as Solaris 2.x defines __STDC__ as 0 in a largely standard + conforming environment + #if __STDC__ || (defined(SOLARIS) && defined(__STDC__)) +*/ +#ifdef __STDC__ +#include +#else +#include +#endif + +#include "ntp_types.h" +#include "ntp_string.h" +#include "ntp_syslog.h" +#include "ntp_stdlib.h" + +#undef syslog + +int syslogit = 1; +FILE *syslog_file = NULL; + +extern int errno; +extern char *progname; + +#if defined(__STDC__) +void msyslog(int level, char *fmt, ...) +#else +/*VARARGS*/ +void msyslog(va_alist) + va_dcl +#endif +{ +#ifndef __STDC__ + int level; + char *fmt; +#endif + va_list ap; + char buf[1025], nfmt[256], xerr[50], *err; + register int c, l; + register char *n, *f, *prog; + extern int sys_nerr; + extern char *sys_errlist[]; + int olderrno; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); + + level = va_arg(ap, int); + fmt = va_arg(ap, char *); +#endif + + olderrno = errno; + n = nfmt; + f = fmt; + while ((c = *f++) != '\0' && c != '\n' && n < &nfmt[252]) { + if (c != '%') { + *n++ = c; + continue; + } + if ((c = *f++) != 'm') { + *n++ = '%'; + *n++ = c; + continue; + } + if ((unsigned)olderrno > sys_nerr) + sprintf((err = xerr), "error %d", olderrno); + else + err = sys_errlist[olderrno]; + if (n + (l = strlen(err)) < &nfmt[254]) { + strcpy(n, err); + n += strlen(err); + } + } + *n++ = '\n'; + *n = '\0'; + + vsprintf(buf, nfmt, ap); + if (syslogit) + syslog(level, buf); + else { + extern char * humanlogtime P((void)); + + FILE *out_file = syslog_file ? syslog_file + : level <= LOG_ERR ? stderr : stdout; + /* syslog() provides the timestamp, so if we're not using + syslog, we must provide it. */ + prog = strrchr(progname, '/'); + if (prog == NULL) + prog = progname; + else + prog++; + (void) fprintf(out_file, "%s ", humanlogtime ()); + (void) fprintf(out_file, "%s: %s", prog, buf); + fflush (out_file); + } + va_end(ap); +} diff --git a/contrib/xntpd/lib/numtoa.c b/contrib/xntpd/lib/numtoa.c new file mode 100644 index 0000000000..c36885d19e --- /dev/null +++ b/contrib/xntpd/lib/numtoa.c @@ -0,0 +1,24 @@ +/* numtoa.c,v 3.1 1993/07/06 01:08:38 jbj Exp + * numtoa - return asciized network numbers store in local array space + */ +#include + +#include "ntp_fp.h" +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +numtoa(num) + U_LONG num; +{ + register U_LONG netnum; + register char *buf; + + netnum = ntohl(num); + LIB_GETBUF(buf); + + (void) sprintf(buf, "%d.%d.%d.%d", (netnum>>24)&0xff, + (netnum>>16)&0xff, (netnum>>8)&0xff, netnum&0xff); + + return buf; +} diff --git a/contrib/xntpd/lib/numtohost.c b/contrib/xntpd/lib/numtohost.c new file mode 100644 index 0000000000..c8b532f1fd --- /dev/null +++ b/contrib/xntpd/lib/numtohost.c @@ -0,0 +1,39 @@ +/* numtohost.c,v 3.1 1993/07/06 01:08:40 jbj Exp + * numtohost - convert network number to host name. + */ +#include +#include + +#include "ntp_fp.h" +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +#define LOOPBACKNET 0x7f000000 +#define LOOPBACKHOST 0x7f000001 +#define LOOPBACKNETMASK 0xff000000 + +char * +numtohost(netnum) + U_LONG netnum; +{ + char *bp; + struct hostent *hp; + + /* + * This is really gross, but saves lots of hanging looking for + * hostnames for the radio clocks. Don't bother looking up + * addresses on the loopback network except for the loopback + * host itself. + */ + if ((((ntohl(netnum) & LOOPBACKNETMASK) == LOOPBACKNET) + && (ntohl(netnum) != LOOPBACKHOST)) + || ((hp = gethostbyaddr((char *)&netnum, sizeof netnum, AF_INET)) + == 0)) + return numtoa(netnum); + + LIB_GETBUF(bp); + + bp[LIB_BUFLENGTH-1] = '\0'; + (void) strncpy(bp, hp->h_name, LIB_BUFLENGTH-1); + return bp; +} diff --git a/contrib/xntpd/lib/octtoint.c b/contrib/xntpd/lib/octtoint.c new file mode 100644 index 0000000000..1f25b1d576 --- /dev/null +++ b/contrib/xntpd/lib/octtoint.c @@ -0,0 +1,34 @@ +/* octtoint.c,v 3.1 1993/07/06 01:08:41 jbj Exp + * octtoint - convert an ascii string in octal to an unsigned + * long, with error checking + */ +#include +#include + +#include "ntp_stdlib.h" + +int +octtoint(str, ival) + const char *str; + U_LONG *ival; +{ + register U_LONG u; + register const char *cp; + + cp = str; + + if (*cp == '\0') + return 0; + + u = 0; + while (*cp != '\0') { + if (!isdigit(*cp) || *cp == '8' || *cp == '9') + return 0; + if (u >= 0x20000000) + return 0; /* overflow */ + u <<= 3; + u += *cp++ - '0'; /* ascii dependent */ + } + *ival = u; + return 1; +} diff --git a/contrib/xntpd/lib/prettydate.c b/contrib/xntpd/lib/prettydate.c new file mode 100644 index 0000000000..ad679bd872 --- /dev/null +++ b/contrib/xntpd/lib/prettydate.c @@ -0,0 +1,44 @@ +/* prettydate.c,v 3.1 1993/07/06 01:08:42 jbj Exp + * prettydate - convert a time stamp to something readable + */ +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +#ifdef NTP_POSIX_SOURCE +#include +#endif + +char * +prettydate(ts) + l_fp *ts; +{ + char *bp; + struct tm *tm; + U_LONG sec; + U_LONG msec; + static char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + static char *days[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + + LIB_GETBUF(bp); + + sec = ts->l_ui - JAN_1970; + msec = ts->l_uf / 4294967; /* fract / (2**32/1000) */ + + tm = localtime((LONG *)&sec); + + (void) sprintf(bp, "%08x.%08x %s, %s %2d %4d %2d:%02d:%02d.%03d", + ts->l_ui, ts->l_uf, days[tm->tm_wday], months[tm->tm_mon], + tm->tm_mday, 1900+tm->tm_year, tm->tm_hour, tm->tm_min, + tm->tm_sec, msec); + + return bp; +} diff --git a/contrib/xntpd/lib/ranny.c b/contrib/xntpd/lib/ranny.c new file mode 100644 index 0000000000..2a47e03f59 --- /dev/null +++ b/contrib/xntpd/lib/ranny.c @@ -0,0 +1,97 @@ +/* ranny.c,v 3.1 1993/07/06 01:08:43 jbj Exp + * Random number generator is: + * + * Copyright 1988 by Rayan S. Zachariassen, all rights reserved. + * This will be free software, but only when it is finished. + * + * Used in xntp by permission of the author. If copyright is + * annoying to you, read no further. Instead, look up the reference, + * write me an equivalent to this and send it back to me. + */ + +/* + * Random number generator; see Knuth Vol 2. 2nd ed. p.27 (section 3.2.2) + */ +#include "ntp_stdlib.h" + +extern time_t time P((time_t *loc)); + +/* + * 55 random numbers, not all even. Note we don't initialize ran_y + * directly since I have had thoughts of putting this in an EPROM + */ +static U_LONG ran_y[55]; + +static U_LONG init_ran_y[55] = { + 1860909544, 231033423, 437666411, 1349655137, 2014584962, + 504613712, 656256107, 1246027206, 573713775, 643466871, + 540235388, 1630565153, 443649364, 729302839, 1933991552, + 944681982, 949111118, 406212522, 1065063137, 1712954727, + 73280612, 787623973, 1874130997, 801658492, 73395958, + 739165367, 596047144, 490055249, 1131094323, 662727104, + 483614097, 844520219, 893760527, 921280508, 46691708, + 760861842, 1425894220, 702947816, 2006889048, 1999607995, + 1346414687, 399640789, 1482689501, 1790064052, 1128943628, + 1269197405, 587262386, 2078054746, 1675409928, 1652325524, + 1643525825, 1748690540, 292465849, 1370173174, 402865384 +}; + +static int ran_j; +static int ran_k; + + +/* + * ranp2 - return a random integer in the range 0 .. (1< + +#include "ntp_fp.h" +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +refnumtoa(num) + U_LONG num; +{ + register U_LONG netnum; + register char *buf; + register const char *rclock; + + netnum = ntohl(num); + + LIB_GETBUF(buf); + + rclock = clockname((int)((netnum>>8)&0xff)); + + if (rclock != NULL) + { + (void) sprintf(buf, "%s(%d)", clockname((int)((netnum>>8)&0xff)), netnum&0xff); + } + else + { + (void) sprintf(buf, "REFCLK(%d,%d)", (netnum>>8)&0xff, netnum&0xff); + } + + return buf; +} diff --git a/contrib/xntpd/lib/syssignal.c b/contrib/xntpd/lib/syssignal.c new file mode 100644 index 0000000000..f8abfddfe4 --- /dev/null +++ b/contrib/xntpd/lib/syssignal.c @@ -0,0 +1,45 @@ +#include +#include +#include + +#include "ntp_stdlib.h" + +#if defined(NTP_POSIX_SOURCE) +#include + +extern int errno; + +void +signal_no_reset(sig, func) +int sig; +void (*func)(); +{ + int n; + struct sigaction vec; + + vec.sa_handler = func; + sigemptyset(&vec.sa_mask); + vec.sa_flags = 0; + + while (1) { + n = sigaction(sig, &vec, NULL); + if (n == -1 && errno == EINTR) continue; + break; + } + if (n == -1) { + perror("sigaction"); + exit(1); + } +} + +#else +RETSIGTYPE +signal_no_reset(sig, func) +int sig; +RETSIGTYPE (*func)(); +{ + signal(sig, func); + +} +#endif + diff --git a/contrib/xntpd/lib/systime.c b/contrib/xntpd/lib/systime.c new file mode 100644 index 0000000000..99e715a54a --- /dev/null +++ b/contrib/xntpd/lib/systime.c @@ -0,0 +1,371 @@ +/* systime.c,v 3.1 1993/07/06 01:08:46 jbj Exp + * systime -- routines to fiddle a UNIX clock. + */ +#include +#include +#if defined(SYS_HPUX) || defined(sgi) || defined(__bsdi__) +#include +#include +#endif + +#ifdef SYS_LINUX +#include +#endif + +#include "ntp_fp.h" +#include "ntp_syslog.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +#if defined(STEP_SLEW) +#define SLEWALWAYS +#endif + +extern int debug; + +/* + * These routines (init_systime, get_systime, step_systime, adj_systime) + * implement an interface between the (more or less) system independent + * bits of NTP and the peculiarities of dealing with the Unix system + * clock. These routines will run with good precision fairly independently + * of your kernel's value of tickadj. I couldn't tell the difference + * between tickadj==40 and tickadj==5 on a microvax, though I prefer + * to set tickadj == 500/hz when in doubt. At your option you + * may compile this so that your system's clock is always slewed to the + * correct time even for large corrections. Of course, all of this takes + * a lot of code which wouldn't be needed with a reasonable tickadj and + * a willingness to let the clock be stepped occasionally. Oh well. + */ + +/* + * Clock variables. We round calls to adjtime() to adj_precision + * microseconds, and limit the adjustment to tvu_maxslew microseconds + * (tsf_maxslew fractional sec) in one adjustment interval. As we are + * thus limited in the speed and precision with which we can adjust the + * clock, we compensate by keeping the known "error" in the system time + * in sys_clock_offset. This is added to timestamps returned by get_systime(). + * We also remember the clock precision we computed from the kernel in + * case someone asks us. + */ + LONG adj_precision; /* adj precision in usec (tickadj) */ + LONG tvu_maxslew; /* maximum adjust doable in 1<l_uf += TS_ROUNDBIT; /* guaranteed not to overflow */ +#else + /* + * Get the time of day, convert to time stamp format + * and add in the current time offset. Then round + * appropriately. + */ + (void) GETTIMEOFDAY(&tv, (struct timezone *)0); + TVTOTS(&tv, ts); + L_ADD(ts, &sys_clock_offset); + if (ts->l_uf & TS_ROUNDBIT) + L_ADDUF(ts, (unsigned LONG) TS_ROUNDBIT); +#endif /* !defined(SLEWALWAYS) */ + ts->l_ui += JAN_1970; + ts->l_uf &= TS_MASK; + + sys_clock = ts->l_ui; +} + +/* + * step_systime - do a step adjustment in the system time (at least from + * NTP's point of view. + */ +int +step_systime(ts) + l_fp *ts; +{ +#ifdef SLEWALWAYS +#ifdef STEP_SLEW + register U_LONG tmp_ui; + register U_LONG tmp_uf; + int isneg; + int n; + + /* + * Take the absolute value of the offset + */ + tmp_ui = ts->l_ui; + tmp_uf = ts->l_uf; + if (M_ISNEG(tmp_ui, tmp_uf)) { + M_NEG(tmp_ui, tmp_uf); + isneg = 1; + } else + isneg = 0; + + if (tmp_ui >= 3) { /* Step it and slew we might win */ + n = step_systime_real(ts); + if (!n) return n; + if (isneg) + ts->l_ui = ~0; + else + ts->l_ui = ~0; + } +#endif + /* + * Just add adjustment into the current offset. The update + * routine will take care of bringing the system clock into + * line. + */ + L_ADD(&sys_clock_offset, ts); + return 1; +#else /* SLEWALWAYS */ + return step_systime_real(ts); +#endif /* SLEWALWAYS */ +} + +int max_no_complete = 20; + +/* + * adj_systime - called once every 1<l_f; + int rval; + + adjtv.tv_sec = adjtv.tv_usec = 0; + + /* + * Move the current offset into the registers + */ + offset_i = sys_clock_offset.l_ui; + offset_f = sys_clock_offset.l_uf; + + /* + * Add the new adjustment into the system offset. Adjust the + * system clock to minimize this. + */ + M_ADDF(offset_i, offset_f, adj); + if (M_ISNEG(offset_i, offset_f)) { + isneg = 1; + M_NEG(offset_i, offset_f); + } +#ifdef DEBUG + if (debug > 4) + syslog(LOG_DEBUG, "adj_systime(%s): offset = %s%s\n", + mfptoa((adj<0?-1:0), adj, 9), isneg?"-":"", + umfptoa(offset_i, offset_f, 9)); +#endif + + adjtv.tv_sec = 0; + if (offset_i > 0 || offset_f >= tsf_maxslew) { + /* + * Slew is bigger than we can complete in + * the adjustment interval. Make a maximum + * sized slew and reduce sys_clock_offset by this + * much. + */ + M_SUBUF(offset_i, offset_f, tsf_maxslew); + if (!isneg) { + adjtv.tv_usec = tvu_maxslew; + } else { + adjtv.tv_usec = -tvu_maxslew; + M_NEG(offset_i, offset_f); + } + +#ifdef DEBUG + if (debug > 4) + syslog(LOG_DEBUG, + "maximum slew: %s%s, remainder = %s\n", + isneg?"-":"", umfptoa(0, tsf_maxslew, 9), + mfptoa(offset_i, offset_f, 9)); +#endif + } else { + /* + * We can do this slew in the time period. Do our + * best approximation (rounded), save residual for + * next adjustment. + * + * Note that offset_i is guaranteed to be 0 here. + */ + TSFTOTVU(offset_f, temp); +#ifndef ADJTIME_IS_ACCURATE + /* + * Round value to be an even multiple of adj_precision + */ + residual = temp % adj_precision; + temp -= residual; + if (residual << 1 >= adj_precision) + temp += adj_precision; +#endif /* ADJTIME_IS_ACCURATE */ + TVUTOTSF(temp, residual); + M_SUBUF(offset_i, offset_f, residual); + if (isneg) { + adjtv.tv_usec = -temp; + M_NEG(offset_i, offset_f); + } else { + adjtv.tv_usec = temp; + } +#ifdef DEBUG + if (debug > 4) + syslog(LOG_DEBUG, + "slew adjtv = %s, adjts = %s, sys_clock_offset = %s\n", + tvtoa(&adjtv), umfptoa(0, residual, 9), + mfptoa(offset_i, offset_f, 9)); +#endif + } + + sys_clock_offset.l_ui = offset_i; + sys_clock_offset.l_uf = offset_f; + + if (adjtime(&adjtv, &oadjtv) < 0) { + syslog(LOG_ERR, "Can't do time adjustment: %m"); + rval = 0; + } else + rval = 1; + +#ifdef DEBUGRS6000 + syslog(LOG_ERR, "adj_systime(%s): offset = %s%s\n", + mfptoa((adj<0?-1:0), adj, 9), isneg?"-":"", + umfptoa(offset_i, offset_f, 9)); + syslog(LOG_ERR, "%d %d %d %d\n", (int) adjtv.tv_sec, + (int) adjtv.tv_usec, (int) oadjtv.tv_sec, (int) + oadjtv.tv_usec); +#endif /* DEBUGRS6000 */ + + if ((oadjtv.tv_sec != 0 || oadjtv.tv_usec != 0) && (max_no_complete > 0)) { + sTVTOTS(&oadjtv, &oadjts); + L_ADD(&sys_clock_offset, &oadjts); + syslog(LOG_WARNING, "Previous time adjustment didn't complete"); +#ifdef DEBUG + if (debug > 4) + syslog(LOG_DEBUG, + "Previous adjtime() incomplete, residual = %s\n", + tvtoa(&oadjtv)); +#endif + if (--max_no_complete == 0) syslog(LOG_WARNING, + "*** No more 'Prev time adj didn't complete'"); + } + return(rval); +} + + +/* + * This is used by ntpdate even when xntpd does not use it! WLJ + */ +int +step_systime_real(ts) + l_fp *ts; +{ + struct timeval timetv, adjtv; + int isneg = 0; +#if defined(SYS_HPUX) + struct utmp ut; + time_t oldtime; +#endif + + /* + * We can afford to be sloppy here since if this is called + * the time is really screwed and everything is being reset. + */ + L_ADD(&sys_clock_offset, ts); + + if (L_ISNEG(&sys_clock_offset)) { + isneg = 1; + L_NEG(&sys_clock_offset); + } + TSTOTV(&sys_clock_offset, &adjtv); + + (void) GETTIMEOFDAY(&timetv, (struct timezone *)0); +#if defined(SYS_HPUX) + oldtime = timetv.tv_sec; +#endif +#ifdef DEBUG + if (debug > 3) + syslog(LOG_DEBUG, "step: %s, sys_clock_offset = %s, adjtv = %s, timetv = %s\n", + lfptoa(ts, 9), lfptoa(&sys_clock_offset, 9), tvtoa(&adjtv), + utvtoa(&timetv)); +#endif + if (isneg) { + timetv.tv_sec -= adjtv.tv_sec; + timetv.tv_usec -= adjtv.tv_usec; + if (timetv.tv_usec < 0) { + timetv.tv_sec--; + timetv.tv_usec += 1000000; + } + } else { + timetv.tv_sec += adjtv.tv_sec; + timetv.tv_usec += adjtv.tv_usec; + if (timetv.tv_usec >= 1000000) { + timetv.tv_sec++; + timetv.tv_usec -= 1000000; + } + } + if (SETTIMEOFDAY(&timetv, (struct timezone *)0) != 0) { + syslog(LOG_ERR, "Can't set time of day: %m"); + return 0; + } +#ifdef DEBUG + if (debug > 3) + syslog(LOG_DEBUG, "step: new timetv = %s\n", utvtoa(&timetv)); +#endif + sys_clock_offset.l_ui = sys_clock_offset.l_uf = 0; +#if defined(SYS_HPUX) +#if (SYS_HPUX < 10) + /* + * CHECKME: is this correct when called by ntpdate????? + */ + _clear_adjtime(); +#endif + /* + * Write old and new time entries in utmp and wtmp if step adjustment + * is greater than one second. + */ + if (oldtime != timetv.tv_sec) { + bzero((char *)&ut, sizeof(ut)); + ut.ut_type = OLD_TIME; + ut.ut_time = oldtime; + (void)strcpy(ut.ut_line, OTIME_MSG); + pututline(&ut); + setutent(); + ut.ut_type = NEW_TIME; + ut.ut_time = timetv.tv_sec; + (void)strcpy(ut.ut_line, NTIME_MSG); + pututline(&ut); + utmpname(WTMP_FILE); + ut.ut_type = OLD_TIME; + ut.ut_time = oldtime; + (void)strcpy(ut.ut_line, OTIME_MSG); + pututline(&ut); + ut.ut_type = NEW_TIME; + ut.ut_time = timetv.tv_sec; + (void)strcpy(ut.ut_line, NTIME_MSG); + pututline(&ut); + endutent(); + } +#endif + return 1; +} diff --git a/contrib/xntpd/lib/tsftomsu.c b/contrib/xntpd/lib/tsftomsu.c new file mode 100644 index 0000000000..b9161141d3 --- /dev/null +++ b/contrib/xntpd/lib/tsftomsu.c @@ -0,0 +1,37 @@ +/* tsftomsu.c,v 3.1 1993/07/06 01:08:47 jbj Exp + * tsftomsu - convert from a time stamp fraction to milliseconds + */ +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +int +tsftomsu(tsf, round) + U_LONG tsf; + int round; +{ + register U_LONG val_ui, val_uf; + register U_LONG tmp_ui, tmp_uf; + register int i; + + /* + * Essentially, multiply by 10 three times in l_fp form. + * The integral part is the milliseconds. + */ + val_ui = 0; + val_uf = tsf; + for (i = 3; i > 0; i--) { + M_LSHIFT(val_ui, val_uf); + tmp_ui = val_ui; + tmp_uf = val_uf; + M_LSHIFT(val_ui, val_uf); + M_LSHIFT(val_ui, val_uf); + M_ADD(val_ui, val_uf, tmp_ui, tmp_uf); + } + + /* + * Round the value if need be, then return it. + */ + if (round && (val_uf & 0x80000000)) + val_ui++; + return (int)val_ui; +} diff --git a/contrib/xntpd/lib/tstotod.c b/contrib/xntpd/lib/tstotod.c new file mode 100644 index 0000000000..a78aea1c2e --- /dev/null +++ b/contrib/xntpd/lib/tstotod.c @@ -0,0 +1,21 @@ +#ifdef ELIMINATE +/* tstotod.c,v 3.1 1993/07/06 01:08:48 jbj Exp + * tstotod - compute calendar time given an NTP timestamp + */ +#include + +#include "ntp_fp.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +void +tstotod(ts, tod) + l_fp *ts; + struct calendar *tod; +{ + register U_LONG cyclesecs; + + cyclesecs = ts.l_ui - MAR_1900; /* bump forward to March 1900 */ + +} +#endif /* ELIMINATE */ diff --git a/contrib/xntpd/lib/tstotv.c b/contrib/xntpd/lib/tstotv.c new file mode 100644 index 0000000000..c9b0d1c036 --- /dev/null +++ b/contrib/xntpd/lib/tstotv.c @@ -0,0 +1,135 @@ +/* tstotv.c,v 3.1 1993/07/06 01:08:49 jbj Exp + * tstotv - tables for converting from NTP time stamps to struct timeval + */ + +#include "ntp_types.h" + +/* + * Tables to convert from a time stamp fraction to usecs. Note that + * the units of these tables are actually (usec<<3). We carry three + * guard bits so that the result can be properly truncated (or rounded) + * to be correct to the least significant bit. + * + * These tables are rounded. + */ + +LONG tstoushi[256] = { + 0x000000, 0x007a12, 0x00f424, 0x016e36, + 0x01e848, 0x02625a, 0x02dc6c, 0x03567e, + 0x03d090, 0x044aa2, 0x04c4b4, 0x053ec6, + 0x05b8d8, 0x0632ea, 0x06acfc, 0x07270e, + 0x07a120, 0x081b32, 0x089544, 0x090f56, + 0x098968, 0x0a037a, 0x0a7d8c, 0x0af79e, + 0x0b71b0, 0x0bebc2, 0x0c65d4, 0x0cdfe6, + 0x0d59f8, 0x0dd40a, 0x0e4e1c, 0x0ec82e, + 0x0f4240, 0x0fbc52, 0x103664, 0x10b076, + 0x112a88, 0x11a49a, 0x121eac, 0x1298be, + 0x1312d0, 0x138ce2, 0x1406f4, 0x148106, + 0x14fb18, 0x15752a, 0x15ef3c, 0x16694e, + 0x16e360, 0x175d72, 0x17d784, 0x185196, + 0x18cba8, 0x1945ba, 0x19bfcc, 0x1a39de, + 0x1ab3f0, 0x1b2e02, 0x1ba814, 0x1c2226, + 0x1c9c38, 0x1d164a, 0x1d905c, 0x1e0a6e, + 0x1e8480, 0x1efe92, 0x1f78a4, 0x1ff2b6, + 0x206cc8, 0x20e6da, 0x2160ec, 0x21dafe, + 0x225510, 0x22cf22, 0x234934, 0x23c346, + 0x243d58, 0x24b76a, 0x25317c, 0x25ab8e, + 0x2625a0, 0x269fb2, 0x2719c4, 0x2793d6, + 0x280de8, 0x2887fa, 0x29020c, 0x297c1e, + 0x29f630, 0x2a7042, 0x2aea54, 0x2b6466, + 0x2bde78, 0x2c588a, 0x2cd29c, 0x2d4cae, + 0x2dc6c0, 0x2e40d2, 0x2ebae4, 0x2f34f6, + 0x2faf08, 0x30291a, 0x30a32c, 0x311d3e, + 0x319750, 0x321162, 0x328b74, 0x330586, + 0x337f98, 0x33f9aa, 0x3473bc, 0x34edce, + 0x3567e0, 0x35e1f2, 0x365c04, 0x36d616, + 0x375028, 0x37ca3a, 0x38444c, 0x38be5e, + 0x393870, 0x39b282, 0x3a2c94, 0x3aa6a6, + 0x3b20b8, 0x3b9aca, 0x3c14dc, 0x3c8eee, + 0x3d0900, 0x3d8312, 0x3dfd24, 0x3e7736, + 0x3ef148, 0x3f6b5a, 0x3fe56c, 0x405f7e, + 0x40d990, 0x4153a2, 0x41cdb4, 0x4247c6, + 0x42c1d8, 0x433bea, 0x43b5fc, 0x44300e, + 0x44aa20, 0x452432, 0x459e44, 0x461856, + 0x469268, 0x470c7a, 0x47868c, 0x48009e, + 0x487ab0, 0x48f4c2, 0x496ed4, 0x49e8e6, + 0x4a62f8, 0x4add0a, 0x4b571c, 0x4bd12e, + 0x4c4b40, 0x4cc552, 0x4d3f64, 0x4db976, + 0x4e3388, 0x4ead9a, 0x4f27ac, 0x4fa1be, + 0x501bd0, 0x5095e2, 0x510ff4, 0x518a06, + 0x520418, 0x527e2a, 0x52f83c, 0x53724e, + 0x53ec60, 0x546672, 0x54e084, 0x555a96, + 0x55d4a8, 0x564eba, 0x56c8cc, 0x5742de, + 0x57bcf0, 0x583702, 0x58b114, 0x592b26, + 0x59a538, 0x5a1f4a, 0x5a995c, 0x5b136e, + 0x5b8d80, 0x5c0792, 0x5c81a4, 0x5cfbb6, + 0x5d75c8, 0x5defda, 0x5e69ec, 0x5ee3fe, + 0x5f5e10, 0x5fd822, 0x605234, 0x60cc46, + 0x614658, 0x61c06a, 0x623a7c, 0x62b48e, + 0x632ea0, 0x63a8b2, 0x6422c4, 0x649cd6, + 0x6516e8, 0x6590fa, 0x660b0c, 0x66851e, + 0x66ff30, 0x677942, 0x67f354, 0x686d66, + 0x68e778, 0x69618a, 0x69db9c, 0x6a55ae, + 0x6acfc0, 0x6b49d2, 0x6bc3e4, 0x6c3df6, + 0x6cb808, 0x6d321a, 0x6dac2c, 0x6e263e, + 0x6ea050, 0x6f1a62, 0x6f9474, 0x700e86, + 0x708898, 0x7102aa, 0x717cbc, 0x71f6ce, + 0x7270e0, 0x72eaf2, 0x736504, 0x73df16, + 0x745928, 0x74d33a, 0x754d4c, 0x75c75e, + 0x764170, 0x76bb82, 0x773594, 0x77afa6, + 0x7829b8, 0x78a3ca, 0x791ddc, 0x7997ee +}; + +LONG tstousmid[256] = { + 0x0000, 0x007a, 0x00f4, 0x016e, 0x01e8, 0x0262, 0x02dc, 0x0356, + 0x03d1, 0x044b, 0x04c5, 0x053f, 0x05b9, 0x0633, 0x06ad, 0x0727, + 0x07a1, 0x081b, 0x0895, 0x090f, 0x0989, 0x0a03, 0x0a7e, 0x0af8, + 0x0b72, 0x0bec, 0x0c66, 0x0ce0, 0x0d5a, 0x0dd4, 0x0e4e, 0x0ec8, + 0x0f42, 0x0fbc, 0x1036, 0x10b0, 0x112b, 0x11a5, 0x121f, 0x1299, + 0x1313, 0x138d, 0x1407, 0x1481, 0x14fb, 0x1575, 0x15ef, 0x1669, + 0x16e3, 0x175d, 0x17d8, 0x1852, 0x18cc, 0x1946, 0x19c0, 0x1a3a, + 0x1ab4, 0x1b2e, 0x1ba8, 0x1c22, 0x1c9c, 0x1d16, 0x1d90, 0x1e0a, + 0x1e84, 0x1eff, 0x1f79, 0x1ff3, 0x206d, 0x20e7, 0x2161, 0x21db, + 0x2255, 0x22cf, 0x2349, 0x23c3, 0x243d, 0x24b7, 0x2531, 0x25ac, + 0x2626, 0x26a0, 0x271a, 0x2794, 0x280e, 0x2888, 0x2902, 0x297c, + 0x29f6, 0x2a70, 0x2aea, 0x2b64, 0x2bde, 0x2c59, 0x2cd3, 0x2d4d, + 0x2dc7, 0x2e41, 0x2ebb, 0x2f35, 0x2faf, 0x3029, 0x30a3, 0x311d, + 0x3197, 0x3211, 0x328b, 0x3306, 0x3380, 0x33fa, 0x3474, 0x34ee, + 0x3568, 0x35e2, 0x365c, 0x36d6, 0x3750, 0x37ca, 0x3844, 0x38be, + 0x3938, 0x39b3, 0x3a2d, 0x3aa7, 0x3b21, 0x3b9b, 0x3c15, 0x3c8f, + 0x3d09, 0x3d83, 0x3dfd, 0x3e77, 0x3ef1, 0x3f6b, 0x3fe5, 0x405f, + 0x40da, 0x4154, 0x41ce, 0x4248, 0x42c2, 0x433c, 0x43b6, 0x4430, + 0x44aa, 0x4524, 0x459e, 0x4618, 0x4692, 0x470c, 0x4787, 0x4801, + 0x487b, 0x48f5, 0x496f, 0x49e9, 0x4a63, 0x4add, 0x4b57, 0x4bd1, + 0x4c4b, 0x4cc5, 0x4d3f, 0x4db9, 0x4e34, 0x4eae, 0x4f28, 0x4fa2, + 0x501c, 0x5096, 0x5110, 0x518a, 0x5204, 0x527e, 0x52f8, 0x5372, + 0x53ec, 0x5466, 0x54e1, 0x555b, 0x55d5, 0x564f, 0x56c9, 0x5743, + 0x57bd, 0x5837, 0x58b1, 0x592b, 0x59a5, 0x5a1f, 0x5a99, 0x5b13, + 0x5b8d, 0x5c08, 0x5c82, 0x5cfc, 0x5d76, 0x5df0, 0x5e6a, 0x5ee4, + 0x5f5e, 0x5fd8, 0x6052, 0x60cc, 0x6146, 0x61c0, 0x623a, 0x62b5, + 0x632f, 0x63a9, 0x6423, 0x649d, 0x6517, 0x6591, 0x660b, 0x6685, + 0x66ff, 0x6779, 0x67f3, 0x686d, 0x68e7, 0x6962, 0x69dc, 0x6a56, + 0x6ad0, 0x6b4a, 0x6bc4, 0x6c3e, 0x6cb8, 0x6d32, 0x6dac, 0x6e26, + 0x6ea0, 0x6f1a, 0x6f94, 0x700f, 0x7089, 0x7103, 0x717d, 0x71f7, + 0x7271, 0x72eb, 0x7365, 0x73df, 0x7459, 0x74d3, 0x754d, 0x75c7, + 0x7641, 0x76bc, 0x7736, 0x77b0, 0x782a, 0x78a4, 0x791e, 0x7998 +}; + +LONG tstouslo[128] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, + 0x1f, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, + 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, + 0x5c, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, + 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x71, + 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79 +}; diff --git a/contrib/xntpd/lib/tvtoa.c b/contrib/xntpd/lib/tvtoa.c new file mode 100644 index 0000000000..778caa1cee --- /dev/null +++ b/contrib/xntpd/lib/tvtoa.c @@ -0,0 +1,33 @@ +/* tvtoa.c,v 3.1 1993/07/06 01:08:50 jbj Exp + * tvtoa - return an asciized representation of a struct timeval + */ +#include +#include + +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +tvtoa(tv) + struct timeval *tv; +{ + register char *buf; + register U_LONG sec; + register U_LONG usec; + register int isneg; + + if (tv->tv_sec < 0 || tv->tv_usec < 0) { + sec = -tv->tv_sec; + usec = -tv->tv_usec; + isneg = 1; + } else { + sec = tv->tv_sec; + usec = tv->tv_usec; + isneg = 0; + } + + LIB_GETBUF(buf); + + (void) sprintf(buf, "%s%lu.%06lu", (isneg?"-":""), sec, usec); + return buf; +} diff --git a/contrib/xntpd/lib/tvtots.c b/contrib/xntpd/lib/tvtots.c new file mode 100644 index 0000000000..befc480559 --- /dev/null +++ b/contrib/xntpd/lib/tvtots.c @@ -0,0 +1,159 @@ +/* tvtots.c,v 3.1 1993/07/06 01:08:51 jbj Exp + * tvtots - tables for converting from Unix struct timeval's to + * NTP time stamp format. + */ +#include + +#include "ntp_types.h" + +/* + * Tables to calculate time stamp fractions from usecs. The entries + * in these tables are offset into using each of the two low order + * bytes plus the next 4 bits in a usec value (from a struct timeval). + * These are summed to produce the time stamp fraction. + * + * Note that these tables are rounded (not truncated) to the nearest + * low order bit in the fraction. The timestamp computed should be + * +- 1.5 low order bits. + */ + +U_LONG ustotslo[256] = { + 0x00000000, 0x000010c7, 0x0000218e, 0x00003255, + 0x0000431c, 0x000053e3, 0x000064aa, 0x00007571, + 0x00008638, 0x000096ff, 0x0000a7c6, 0x0000b88d, + 0x0000c954, 0x0000da1b, 0x0000eae2, 0x0000fba9, + 0x00010c6f, 0x00011d36, 0x00012dfd, 0x00013ec4, + 0x00014f8b, 0x00016052, 0x00017119, 0x000181e0, + 0x000192a7, 0x0001a36e, 0x0001b435, 0x0001c4fc, + 0x0001d5c3, 0x0001e68a, 0x0001f751, 0x00020818, + 0x000218df, 0x000229a6, 0x00023a6d, 0x00024b34, + 0x00025bfb, 0x00026cc2, 0x00027d89, 0x00028e50, + 0x00029f17, 0x0002afde, 0x0002c0a5, 0x0002d16c, + 0x0002e233, 0x0002f2fa, 0x000303c0, 0x00031487, + 0x0003254e, 0x00033615, 0x000346dc, 0x000357a3, + 0x0003686a, 0x00037931, 0x000389f8, 0x00039abf, + 0x0003ab86, 0x0003bc4d, 0x0003cd14, 0x0003dddb, + 0x0003eea2, 0x0003ff69, 0x00041030, 0x000420f7, + 0x000431be, 0x00044285, 0x0004534c, 0x00046413, + 0x000474da, 0x000485a1, 0x00049668, 0x0004a72f, + 0x0004b7f6, 0x0004c8bd, 0x0004d984, 0x0004ea4b, + 0x0004fb12, 0x00050bd8, 0x00051c9f, 0x00052d66, + 0x00053e2d, 0x00054ef4, 0x00055fbb, 0x00057082, + 0x00058149, 0x00059210, 0x0005a2d7, 0x0005b39e, + 0x0005c465, 0x0005d52c, 0x0005e5f3, 0x0005f6ba, + 0x00060781, 0x00061848, 0x0006290f, 0x000639d6, + 0x00064a9d, 0x00065b64, 0x00066c2b, 0x00067cf2, + 0x00068db9, 0x00069e80, 0x0006af47, 0x0006c00e, + 0x0006d0d5, 0x0006e19c, 0x0006f263, 0x00070329, + 0x000713f0, 0x000724b7, 0x0007357e, 0x00074645, + 0x0007570c, 0x000767d3, 0x0007789a, 0x00078961, + 0x00079a28, 0x0007aaef, 0x0007bbb6, 0x0007cc7d, + 0x0007dd44, 0x0007ee0b, 0x0007fed2, 0x00080f99, + 0x00082060, 0x00083127, 0x000841ee, 0x000852b5, + 0x0008637c, 0x00087443, 0x0008850a, 0x000895d1, + 0x0008a698, 0x0008b75f, 0x0008c826, 0x0008d8ed, + 0x0008e9b4, 0x0008fa7b, 0x00090b41, 0x00091c08, + 0x00092ccf, 0x00093d96, 0x00094e5d, 0x00095f24, + 0x00096feb, 0x000980b2, 0x00099179, 0x0009a240, + 0x0009b307, 0x0009c3ce, 0x0009d495, 0x0009e55c, + 0x0009f623, 0x000a06ea, 0x000a17b1, 0x000a2878, + 0x000a393f, 0x000a4a06, 0x000a5acd, 0x000a6b94, + 0x000a7c5b, 0x000a8d22, 0x000a9de9, 0x000aaeb0, + 0x000abf77, 0x000ad03e, 0x000ae105, 0x000af1cc, + 0x000b0292, 0x000b1359, 0x000b2420, 0x000b34e7, + 0x000b45ae, 0x000b5675, 0x000b673c, 0x000b7803, + 0x000b88ca, 0x000b9991, 0x000baa58, 0x000bbb1f, + 0x000bcbe6, 0x000bdcad, 0x000bed74, 0x000bfe3b, + 0x000c0f02, 0x000c1fc9, 0x000c3090, 0x000c4157, + 0x000c521e, 0x000c62e5, 0x000c73ac, 0x000c8473, + 0x000c953a, 0x000ca601, 0x000cb6c8, 0x000cc78f, + 0x000cd856, 0x000ce91d, 0x000cf9e4, 0x000d0aaa, + 0x000d1b71, 0x000d2c38, 0x000d3cff, 0x000d4dc6, + 0x000d5e8d, 0x000d6f54, 0x000d801b, 0x000d90e2, + 0x000da1a9, 0x000db270, 0x000dc337, 0x000dd3fe, + 0x000de4c5, 0x000df58c, 0x000e0653, 0x000e171a, + 0x000e27e1, 0x000e38a8, 0x000e496f, 0x000e5a36, + 0x000e6afd, 0x000e7bc4, 0x000e8c8b, 0x000e9d52, + 0x000eae19, 0x000ebee0, 0x000ecfa7, 0x000ee06e, + 0x000ef135, 0x000f01fb, 0x000f12c2, 0x000f2389, + 0x000f3450, 0x000f4517, 0x000f55de, 0x000f66a5, + 0x000f776c, 0x000f8833, 0x000f98fa, 0x000fa9c1, + 0x000fba88, 0x000fcb4f, 0x000fdc16, 0x000fecdd, + 0x000ffda4, 0x00100e6b, 0x00101f32, 0x00102ff9, + 0x001040c0, 0x00105187, 0x0010624e, 0x00107315, + 0x001083dc, 0x001094a3, 0x0010a56a, 0x0010b631, +}; + +U_LONG ustotsmid[256] = { + 0x00000000, 0x0010c6f8, 0x00218def, 0x003254e7, + 0x00431bde, 0x0053e2d6, 0x0064a9ce, 0x007570c5, + 0x008637bd, 0x0096feb4, 0x00a7c5ac, 0x00b88ca4, + 0x00c9539b, 0x00da1a93, 0x00eae18a, 0x00fba882, + 0x010c6f7a, 0x011d3671, 0x012dfd69, 0x013ec460, + 0x014f8b58, 0x01605250, 0x01711947, 0x0181e03f, + 0x0192a736, 0x01a36e2e, 0x01b43526, 0x01c4fc1d, + 0x01d5c315, 0x01e68a0c, 0x01f75104, 0x020817fc, + 0x0218def3, 0x0229a5eb, 0x023a6ce3, 0x024b33da, + 0x025bfad2, 0x026cc1c9, 0x027d88c1, 0x028e4fb9, + 0x029f16b0, 0x02afdda8, 0x02c0a49f, 0x02d16b97, + 0x02e2328f, 0x02f2f986, 0x0303c07e, 0x03148775, + 0x03254e6d, 0x03361565, 0x0346dc5c, 0x0357a354, + 0x03686a4b, 0x03793143, 0x0389f83b, 0x039abf32, + 0x03ab862a, 0x03bc4d21, 0x03cd1419, 0x03dddb11, + 0x03eea208, 0x03ff6900, 0x04102ff7, 0x0420f6ef, + 0x0431bde7, 0x044284de, 0x04534bd6, 0x046412cd, + 0x0474d9c5, 0x0485a0bd, 0x049667b4, 0x04a72eac, + 0x04b7f5a3, 0x04c8bc9b, 0x04d98393, 0x04ea4a8a, + 0x04fb1182, 0x050bd879, 0x051c9f71, 0x052d6669, + 0x053e2d60, 0x054ef458, 0x055fbb4f, 0x05708247, + 0x0581493f, 0x05921036, 0x05a2d72e, 0x05b39e25, + 0x05c4651d, 0x05d52c15, 0x05e5f30c, 0x05f6ba04, + 0x060780fb, 0x061847f3, 0x06290eeb, 0x0639d5e2, + 0x064a9cda, 0x065b63d2, 0x066c2ac9, 0x067cf1c1, + 0x068db8b8, 0x069e7fb0, 0x06af46a8, 0x06c00d9f, + 0x06d0d497, 0x06e19b8e, 0x06f26286, 0x0703297e, + 0x0713f075, 0x0724b76d, 0x07357e64, 0x0746455c, + 0x07570c54, 0x0767d34b, 0x07789a43, 0x0789613a, + 0x079a2832, 0x07aaef2a, 0x07bbb621, 0x07cc7d19, + 0x07dd4410, 0x07ee0b08, 0x07fed200, 0x080f98f7, + 0x08205fef, 0x083126e6, 0x0841edde, 0x0852b4d6, + 0x08637bcd, 0x087442c5, 0x088509bc, 0x0895d0b4, + 0x08a697ac, 0x08b75ea3, 0x08c8259b, 0x08d8ec92, + 0x08e9b38a, 0x08fa7a82, 0x090b4179, 0x091c0871, + 0x092ccf68, 0x093d9660, 0x094e5d58, 0x095f244f, + 0x096feb47, 0x0980b23e, 0x09917936, 0x09a2402e, + 0x09b30725, 0x09c3ce1d, 0x09d49514, 0x09e55c0c, + 0x09f62304, 0x0a06e9fb, 0x0a17b0f3, 0x0a2877ea, + 0x0a393ee2, 0x0a4a05da, 0x0a5accd1, 0x0a6b93c9, + 0x0a7c5ac1, 0x0a8d21b8, 0x0a9de8b0, 0x0aaeafa7, + 0x0abf769f, 0x0ad03d97, 0x0ae1048e, 0x0af1cb86, + 0x0b02927d, 0x0b135975, 0x0b24206d, 0x0b34e764, + 0x0b45ae5c, 0x0b567553, 0x0b673c4b, 0x0b780343, + 0x0b88ca3a, 0x0b999132, 0x0baa5829, 0x0bbb1f21, + 0x0bcbe619, 0x0bdcad10, 0x0bed7408, 0x0bfe3aff, + 0x0c0f01f7, 0x0c1fc8ef, 0x0c308fe6, 0x0c4156de, + 0x0c521dd5, 0x0c62e4cd, 0x0c73abc5, 0x0c8472bc, + 0x0c9539b4, 0x0ca600ab, 0x0cb6c7a3, 0x0cc78e9b, + 0x0cd85592, 0x0ce91c8a, 0x0cf9e381, 0x0d0aaa79, + 0x0d1b7171, 0x0d2c3868, 0x0d3cff60, 0x0d4dc657, + 0x0d5e8d4f, 0x0d6f5447, 0x0d801b3e, 0x0d90e236, + 0x0da1a92d, 0x0db27025, 0x0dc3371d, 0x0dd3fe14, + 0x0de4c50c, 0x0df58c03, 0x0e0652fb, 0x0e1719f3, + 0x0e27e0ea, 0x0e38a7e2, 0x0e496ed9, 0x0e5a35d1, + 0x0e6afcc9, 0x0e7bc3c0, 0x0e8c8ab8, 0x0e9d51b0, + 0x0eae18a7, 0x0ebedf9f, 0x0ecfa696, 0x0ee06d8e, + 0x0ef13486, 0x0f01fb7d, 0x0f12c275, 0x0f23896c, + 0x0f345064, 0x0f45175c, 0x0f55de53, 0x0f66a54b, + 0x0f776c42, 0x0f88333a, 0x0f98fa32, 0x0fa9c129, + 0x0fba8821, 0x0fcb4f18, 0x0fdc1610, 0x0fecdd08, + 0x0ffda3ff, 0x100e6af7, 0x101f31ee, 0x102ff8e6, + 0x1040bfde, 0x105186d5, 0x10624dcd, 0x107314c4, + 0x1083dbbc, 0x1094a2b4, 0x10a569ab, 0x10b630a3, +}; + +U_LONG ustotshi[16] = { + 0x00000000, 0x10c6f79a, 0x218def35, 0x3254e6cf, + 0x431bde6a, 0x53e2d604, 0x64a9cd9f, 0x7570c539, + 0x8637bcd3, 0x96feb46e, 0xa7c5ac08, 0xb88ca3a3, + 0xc9539b3d, 0xda1a92d7, 0xeae18a72, 0xfba8820c, +}; diff --git a/contrib/xntpd/lib/uglydate.c b/contrib/xntpd/lib/uglydate.c new file mode 100644 index 0000000000..308c703362 --- /dev/null +++ b/contrib/xntpd/lib/uglydate.c @@ -0,0 +1,53 @@ +/* uglydate.c,v 3.1 1993/07/06 01:08:53 jbj Exp + * uglydate - convert a time stamp to something barely readable + * The string returned is 37 characters long. + */ +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "lib_strbuf.h" +#include "ntp_stdlib.h" +#ifdef NTP_POSIX_SOURCE +#include +#endif + +char * +uglydate(ts) + l_fp *ts; +{ + char *bp; + char *timep; + struct tm *tm; + U_LONG sec; + U_LONG msec; + int year; + + timep = ulfptoa(ts, 6); /* returns max 17 characters */ + + LIB_GETBUF(bp); + + sec = ts->l_ui - JAN_1970; + msec = ts->l_uf / 4294967; /* fract / (2**32/1000) */ + tm = gmtime((LONG *)&sec); + if (ts->l_ui == 0) { + /* + * Probably not a real good thing to do. Oh, well. + */ + year = 0; + tm->tm_yday = 0; + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + } else { + year = tm->tm_year; + while (year >= 100) + year -= 100; + } + + (void) sprintf(bp, "%17s %02d:%03d:%02d:%02d:%02d.%03d", + timep, year, tm->tm_yday, tm->tm_hour, tm->tm_min, + tm->tm_sec, msec); + + return bp; +} diff --git a/contrib/xntpd/lib/uinttoa.c b/contrib/xntpd/lib/uinttoa.c new file mode 100644 index 0000000000..ce29390342 --- /dev/null +++ b/contrib/xntpd/lib/uinttoa.c @@ -0,0 +1,19 @@ +/* uinttoa.c,v 3.1 1993/07/06 01:08:54 jbj Exp + * uinttoa - return an asciized unsigned integer + */ +#include + +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +uinttoa(uval) + U_LONG uval; +{ + register char *buf; + + LIB_GETBUF(buf); + + (void) sprintf(buf, "%lu", uval); + return buf; +} diff --git a/contrib/xntpd/lib/utvtoa.c b/contrib/xntpd/lib/utvtoa.c new file mode 100644 index 0000000000..b573f187a3 --- /dev/null +++ b/contrib/xntpd/lib/utvtoa.c @@ -0,0 +1,21 @@ +/* utvtoa.c,v 3.1 1993/07/06 01:08:55 jbj Exp + * utvtoa - return an asciized representation of an unsigned struct timeval + */ +#include +#include + +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +utvtoa(tv) + struct timeval *tv; +{ + register char *buf; + + LIB_GETBUF(buf); + + (void) sprintf(buf, "%lu.%06lu", (U_LONG)tv->tv_sec, + (U_LONG)tv->tv_usec); + return buf; +} diff --git a/contrib/xntpd/machines/README b/contrib/xntpd/machines/README new file mode 100644 index 0000000000..d40d8cb0f6 --- /dev/null +++ b/contrib/xntpd/machines/README @@ -0,0 +1,5 @@ +README file for directory ./machines of the NTP Version 3 distribution + +This directory contains configuration files for the various machines +and compilers supported by the distribution. README and RELNOTES files in the +parent directory for directions on how to use these files. diff --git a/contrib/xntpd/machines/aix3.2 b/contrib/xntpd/machines/aix3.2 new file mode 100644 index 0000000000..70607d81a6 --- /dev/null +++ b/contrib/xntpd/machines/aix3.2 @@ -0,0 +1,10 @@ +RANLIB= : +DEFS_LOCAL= -DREFCLOCK +DEFS= -DRS6000 -DSYS_AIX +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= +INSTALL= /usr/ucb/install +COPTS= -O +COMPAT= diff --git a/contrib/xntpd/machines/aux2 b/contrib/xntpd/machines/aux2 new file mode 100644 index 0000000000..c31c80d35c --- /dev/null +++ b/contrib/xntpd/machines/aux2 @@ -0,0 +1,9 @@ +RANLIB= true # ar does the work of ranlib under System V +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSYS_AUX2 +AUTHDEFS= -DDES -DMD5 -DFASTMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= +COMPAT= -lposix -lbsd -lmalloc -s +INSTALL=$(TOP)scripts/install.sh diff --git a/contrib/xntpd/machines/aux3 b/contrib/xntpd/machines/aux3 new file mode 100644 index 0000000000..98dc655314 --- /dev/null +++ b/contrib/xntpd/machines/aux3 @@ -0,0 +1,9 @@ +RANLIB= true # ar does the work of ranlib under System V +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSYS_AUX3 +AUTHDEFS= -DDES -DMD5 -DFASTMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= +COMPAT= -lposix -lbsd -lmalloc -s +INSTALL=$(TOP)scripts/install.sh diff --git a/contrib/xntpd/machines/bsdi b/contrib/xntpd/machines/bsdi new file mode 100644 index 0000000000..040bab4fe1 --- /dev/null +++ b/contrib/xntpd/machines/bsdi @@ -0,0 +1,9 @@ +RANLIB= ranlib +DEFS_LOCAL=-DREFCLOCK +DEFS= -DSYS_BSDI +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lkvm +RESLIB= +COPTS= -g + diff --git a/contrib/xntpd/machines/convexos10 b/contrib/xntpd/machines/convexos10 new file mode 100644 index 0000000000..ba6afed688 --- /dev/null +++ b/contrib/xntpd/machines/convexos10 @@ -0,0 +1,10 @@ +RANLIB= ranlib +DEFS_LOCAL=-DREFCLOCK +DEFS= -DSYS_CONVEXOS10 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +RESLIB= +COPTS= -O +ADJLIB= +COMPAT= + diff --git a/contrib/xntpd/machines/convexos9 b/contrib/xntpd/machines/convexos9 new file mode 100644 index 0000000000..c742c2aff7 --- /dev/null +++ b/contrib/xntpd/machines/convexos9 @@ -0,0 +1,9 @@ +RANLIB= ranlib +DEFS_LOCAL=-DREFCLOCK +DEFS= -DSYS_CONVEXOS9 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +RESLIB= +COPTS= -O +ADJLIB= +COMPAT= diff --git a/contrib/xntpd/machines/decosf1 b/contrib/xntpd/machines/decosf1 new file mode 100644 index 0000000000..c404d6a525 --- /dev/null +++ b/contrib/xntpd/machines/decosf1 @@ -0,0 +1,9 @@ +RANLIB= ranlib +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSTREAM -DSYS_DECOSF1 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= +COPTS= +INSTALL=$(TOP)scripts/install.sh diff --git a/contrib/xntpd/machines/freebsd b/contrib/xntpd/machines/freebsd new file mode 100644 index 0000000000..1914de0de4 --- /dev/null +++ b/contrib/xntpd/machines/freebsd @@ -0,0 +1,8 @@ +RANLIB= ranlib +DEFS_LOCAL=-DREFCLOCK +DEFS= -DSYS_FREEBSD -DSYS_386BSD +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lcrypt +RESLIB= +COPTS= -O2 diff --git a/contrib/xntpd/machines/hpux b/contrib/xntpd/machines/hpux new file mode 100644 index 0000000000..60ec6780d3 --- /dev/null +++ b/contrib/xntpd/machines/hpux @@ -0,0 +1,8 @@ +SHELL= /bin/sh +RANLIB= ls # ar does the work of ranlib under System V +DEFS_LOCAL= -DREFCLOCK +DEFS= -DHAVE_SYSV_TTYS -DSYS_HPUX=8 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +COPTS= +INSTALL=$(TOP)scripts/install.sh diff --git a/contrib/xntpd/machines/hpux10+ b/contrib/xntpd/machines/hpux10+ new file mode 100644 index 0000000000..f4b420c149 --- /dev/null +++ b/contrib/xntpd/machines/hpux10+ @@ -0,0 +1,8 @@ +SHELL= /bin/sh +RANLIB= ls # ar does the work of ranlib under System V +DEFS_LOCAL= -DREFCLOCK +DEFS= -DHAVE_SYSV_TTYS -DSYS_HPUX=10 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +COPTS= +INSTALL=$(TOP)scripts/install.sh diff --git a/contrib/xntpd/machines/i386 b/contrib/xntpd/machines/i386 new file mode 100644 index 0000000000..8fb6f94f81 --- /dev/null +++ b/contrib/xntpd/machines/i386 @@ -0,0 +1,7 @@ +RANLIB= ranlib +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSYS_I386 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +COMPAT= diff --git a/contrib/xntpd/machines/i386svr4 b/contrib/xntpd/machines/i386svr4 new file mode 100644 index 0000000000..b33e3c3b8b --- /dev/null +++ b/contrib/xntpd/machines/i386svr4 @@ -0,0 +1,9 @@ +SHELL= /bin/sh +RANLIB= ls # ar does the work of ranlib under System V +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSYS_SVR4 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lnsl -lsocket -lelf +RESLIB= -lnsl -lsocket -lelf +INSTALL= /usr/ucb/install diff --git a/contrib/xntpd/machines/irix4 b/contrib/xntpd/machines/irix4 new file mode 100644 index 0000000000..ae2bbf8ba8 --- /dev/null +++ b/contrib/xntpd/machines/irix4 @@ -0,0 +1,9 @@ +SHELL= /bin/sh +RANLIB= ls # ar does the work of ranlib under System V +DEFS_LOCAL= -DREFCLOCK +DEFS= -DHAVE_SYSV_TTYS -DSYS_IRIX4 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lmld +RESLIB= +INSTALL=$(TOP)scripts/install.sh diff --git a/contrib/xntpd/machines/irix5 b/contrib/xntpd/machines/irix5 new file mode 100644 index 0000000000..a808b9767c --- /dev/null +++ b/contrib/xntpd/machines/irix5 @@ -0,0 +1,9 @@ +SHELL= /bin/sh +RANLIB= ls # ar does the work of ranlib under System V +DEFS_LOCAL= -DREFCLOCK +DEFS= -DHAVE_SYSV_TTYS -DSYS_IRIX5 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lmld +RESLIB= +INSTALL=$(TOP)scripts/install.sh diff --git a/contrib/xntpd/machines/linux b/contrib/xntpd/machines/linux new file mode 100644 index 0000000000..853654aceb --- /dev/null +++ b/contrib/xntpd/machines/linux @@ -0,0 +1,8 @@ +SHELL= /bin/sh +RANLIB= ranlib +DEFS= -DSYS_LINUX -DHAVE_SYSV_TTYS +AUTHDEFS= -DDES -DMD5 +INCL= -I../include -I/usr/include/bsd +CLOCKDEFS= +DAEMONLIBS= +COMPAT= diff --git a/contrib/xntpd/machines/mips b/contrib/xntpd/machines/mips new file mode 100644 index 0000000000..283c1c0965 --- /dev/null +++ b/contrib/xntpd/machines/mips @@ -0,0 +1,9 @@ +#RANLIB= ranlib +DEFS_LOCAL= -DREFCLOCK +DEFS= +AUTHDEFS= -DDES -DMD5 -DSYS_MIPS +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lmld +RESLIB= +COMPAT= + diff --git a/contrib/xntpd/machines/netbsd b/contrib/xntpd/machines/netbsd new file mode 100644 index 0000000000..c1995eabb6 --- /dev/null +++ b/contrib/xntpd/machines/netbsd @@ -0,0 +1,8 @@ +RANLIB= ranlib +DEFS_LOCAL=-DREFCLOCK +DEFS= -DSYS_NETBSD -DSYS_386BSD +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lcrypt -lutil +RESLIB= +COPTS= -O diff --git a/contrib/xntpd/machines/next b/contrib/xntpd/machines/next new file mode 100644 index 0000000000..e0e86cebea --- /dev/null +++ b/contrib/xntpd/machines/next @@ -0,0 +1,9 @@ +RANLIB= ranlib -c -s +DEFS= -DSYS_NEXT +AUTHDEFS= -DDES -DMD5 -DFAST_MD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= +COPTS= -O -pipe +COMPAT= + diff --git a/contrib/xntpd/machines/ptx b/contrib/xntpd/machines/ptx new file mode 100644 index 0000000000..c1d9da2e5d --- /dev/null +++ b/contrib/xntpd/machines/ptx @@ -0,0 +1,8 @@ +RANLIB= : +DEFS_LOCAL= -DREFCLOCK +DEFS= -DREADKMEM -DSYS_PTX -DHAVE_SYSV_TTYS +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= -lseq -lsocket -linet -lnsl +COPTS= -O diff --git a/contrib/xntpd/machines/sequent b/contrib/xntpd/machines/sequent new file mode 100644 index 0000000000..309b11bf91 --- /dev/null +++ b/contrib/xntpd/machines/sequent @@ -0,0 +1,8 @@ +RANLIB= ranlib +DEFS_LOCAL= -DREFCLOCK +DEFS= -DREADKMEM -DSYS_SEQUENT +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= +COPTS= -O diff --git a/contrib/xntpd/machines/sinix-m b/contrib/xntpd/machines/sinix-m new file mode 100644 index 0000000000..e26a81299b --- /dev/null +++ b/contrib/xntpd/machines/sinix-m @@ -0,0 +1,11 @@ +RANLIB= : +DEFS_LOCAL=-DREFCLOCK +DEFS= -DSYS_SINIXM +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= +COPTS= -O +ADJLIB= +COMPAT= -lsocket -lnsl -lelf +INSTALL=$(TOP)scripts/install.sh diff --git a/contrib/xntpd/machines/sony b/contrib/xntpd/machines/sony new file mode 100644 index 0000000000..cfeef74867 --- /dev/null +++ b/contrib/xntpd/machines/sony @@ -0,0 +1,6 @@ +RANLIB= ranlib +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSYS_SONY +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lmld diff --git a/contrib/xntpd/machines/sunos4.bsd b/contrib/xntpd/machines/sunos4.bsd new file mode 100644 index 0000000000..82be85d342 --- /dev/null +++ b/contrib/xntpd/machines/sunos4.bsd @@ -0,0 +1,11 @@ +RANLIB= ranlib +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSYS_SUNOS4 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lkvm +RESLIB= +COPTS= -O +ADJLIB= +COMPAT= + diff --git a/contrib/xntpd/machines/sunos4.posix b/contrib/xntpd/machines/sunos4.posix new file mode 100644 index 0000000000..86716e18c2 --- /dev/null +++ b/contrib/xntpd/machines/sunos4.posix @@ -0,0 +1,11 @@ +RANLIB= ranlib +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSTREAM -DSYS_SUNOS4 -DNTP_POSIX_SOURCE -DHAVE_SIGNALED_IO +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= -lkvm +RESLIB= +COPTS= -O +ADJLIB= +COMPAT= + diff --git a/contrib/xntpd/machines/sunos5.1 b/contrib/xntpd/machines/sunos5.1 new file mode 100644 index 0000000000..55cccad59e --- /dev/null +++ b/contrib/xntpd/machines/sunos5.1 @@ -0,0 +1,11 @@ +RANLIB= : +DEFS_LOCAL=-DREFCLOCK +DEFS= -DSTREAM -DSOLARIS -DSYS_SOLARIS +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= +COPTS= -O +ADJLIB= +COMPAT= -lsocket -lnsl -lelf +INSTALL=$(TOP)scripts/install.sh diff --git a/contrib/xntpd/machines/sunos5.2 b/contrib/xntpd/machines/sunos5.2 new file mode 100644 index 0000000000..3e09c15714 --- /dev/null +++ b/contrib/xntpd/machines/sunos5.2 @@ -0,0 +1,11 @@ +RANLIB= : +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSTREAM -DSOLARIS -DSYS_SOLARIS -DADJTIME_IS_ACCURATE +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= +COPTS= -O +ADJLIB= +COMPAT= -lsocket -lnsl -lelf +INSTALL=$(TOP)scripts/install.sh diff --git a/contrib/xntpd/machines/svr4 b/contrib/xntpd/machines/svr4 new file mode 100644 index 0000000000..1cf90f58ca --- /dev/null +++ b/contrib/xntpd/machines/svr4 @@ -0,0 +1,10 @@ +SHELL= /bin/sh +RANLIB= ls # ar does the work of ranlib under System V +DEFS= -DSYS_SVR4 +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= +DAEMONLIBS= -lnet -lnsl -lsocket -lelf +RESLIB= -lnet -lnsl -lsocket -lelf +INSTALL=$(TOP)scripts/install.sh +SHELL= /bin/sh +RANLIB= ls # ar does the work of ranlib under System V diff --git a/contrib/xntpd/machines/ultrix.bsd b/contrib/xntpd/machines/ultrix.bsd new file mode 100644 index 0000000000..22d405996e --- /dev/null +++ b/contrib/xntpd/machines/ultrix.bsd @@ -0,0 +1,7 @@ +RANLIB= ranlib +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSYS_ULTRIX +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +COMPAT= diff --git a/contrib/xntpd/machines/ultrix.posix b/contrib/xntpd/machines/ultrix.posix new file mode 100644 index 0000000000..c55e555ddf --- /dev/null +++ b/contrib/xntpd/machines/ultrix.posix @@ -0,0 +1,7 @@ +RANLIB= ranlib +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSYS_ULTRIX -DNTP_POSIX_SOURCE -DHAVE_SIGNALED_IO +AUTHDEFS= -DDES -DMD5 +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +COMPAT= diff --git a/contrib/xntpd/machines/vax b/contrib/xntpd/machines/vax new file mode 100644 index 0000000000..86030467bc --- /dev/null +++ b/contrib/xntpd/machines/vax @@ -0,0 +1,6 @@ +RANLIB= ranlib +DEFS_LOCAL= -DREFCLOCK +DEFS= -DSYS_VAX +CLOCKDEFS= -DLOCAL_CLOCK +DAEMONLIBS= +RESLIB= diff --git a/contrib/xntpd/ntpdate/Makefile.tmpl b/contrib/xntpd/ntpdate/Makefile.tmpl new file mode 100644 index 0000000000..170625f0e3 --- /dev/null +++ b/contrib/xntpd/ntpdate/Makefile.tmpl @@ -0,0 +1,70 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:09:20 jbj Exp +# +PROGRAM= ntpdate +# +# ntpdate - private mode query program for ntpdate +# +COMPILER= cc +COPTS= -O +BINDIR= /usr/local +INSTALL= install +DEFS= +DEFS_OPT= +DEFS_LOCAL= +RESLIB= +ADJLIB= +COMPAT= +# +INCL= -I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +LIB= ../lib/libntp.a +LINTLIB= ../lib/llib-llibntp.ln +MAKE= make +TOP=../ +# +OBJS= ntpdate.o +SOURCE= ntpdate.c + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) $(LIB) version.o + $(CC) $(COPTS) -o $@ $(OBJS) version.o $(LIB) $(RESLIB) \ + $(ADJLIB) $(COMPAT) + +install: $(BINDIR)/$(PROGRAM) + +$(BINDIR)/$(PROGRAM): $(PROGRAM) + $(INSTALL) -c -m 0755 $(PROGRAM) $(BINDIR) + +tags: + ctags *.c *.h + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(PROGRAM) *.o *.out tags make.log Makefile.bak lint.errs .version + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +lint: $(LINTLIB) + lint -x -u $(DEFS) $(DEFS_LOCAL) $(INCL) $(LINTLIB) $(SOURCE) >lint.errs + +../lib/llib-llibntp.ln: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" lintlib + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" + +# +# we want to build the current version string here +# +version.o: ../VERSION + ../scripts/mkversion $(PROGRAM) + $(CC) $(COPTS) $(INCL) -c version.c + +../VERSION: + -@rm -f .version diff --git a/contrib/xntpd/ntpdate/README b/contrib/xntpd/ntpdate/README new file mode 100644 index 0000000000..fd2dbe2e2c --- /dev/null +++ b/contrib/xntpd/ntpdate/README @@ -0,0 +1,7 @@ +README file for directory ./ntpdate of the NTP Version 3 distribution + +This directory contains the sources for the ntpdate utility program. See +the README and RELNOTES files in the parent directory for directions on +how to make and install this program. The current version number of this +program is in the version.c file. + diff --git a/contrib/xntpd/ntpdate/ntpdate.c b/contrib/xntpd/ntpdate/ntpdate.c new file mode 100644 index 0000000000..e144d8c1eb --- /dev/null +++ b/contrib/xntpd/ntpdate/ntpdate.c @@ -0,0 +1,1598 @@ +/* ntpdate.c,v 3.1 1993/07/06 01:09:22 jbj Exp + * ntpdate - set the time of day by polling one or more NTP servers + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __STDC__ +#include +#else +#include +#endif + +#if defined(SYS_HPUX) +#include +#endif + +#ifdef SYS_LINUX +#include +#endif + +#ifndef SYSLOG_FILE +#define SYSLOG_FILE /* we want to go through the syslog/printf/file code */ +#endif + +#include "ntp_select.h" +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntpdate.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" +#include "ntp_syslog.h" + +/* + * Scheduling priority we run at + */ +#define NTPDATE_PRIO (-12) + +/* + * Compatibility stuff for Version 2 + */ +#define NTP_MAXSKW 0x28f /* 0.01 sec in fp format */ +#define NTP_MINDIST 0x51f /* 0.02 sec in fp format */ +#define PEER_MAXDISP (64*FP_SECOND) /* maximum dispersion (fp 64) */ +#define NTP_INFIN 15 /* max stratum, infinity a la Bellman-Ford */ +#define NTP_MAXWGT (8*FP_SECOND) /* maximum select weight 8 seconds */ +#define NTP_MAXLIST 5 /* maximum select list size */ +#define PEER_SHIFT 8 /* 8 suitable for crystal time base */ + +/* + * Debugging flag + */ +int debug = 0; + +/* + * File descriptor masks etc. for call to select + */ +int fd; +fd_set fdmask; + +/* + * Initializing flag. All async routines watch this and only do their + * thing when it is clear. + */ +int initializing = 1; + +/* + * Alarm flag. Set when an alarm occurs + */ +int alarm_flag = 0; + +/* + * Simple query flag. + */ +int simple_query = 0; + +/* + * Program name. + */ +char *progname; + +/* + * Systemwide parameters and flags + */ +int sys_samples = DEFSAMPLES; /* number of samples/server */ +U_LONG sys_timeout = DEFTIMEOUT; /* timeout time, in TIMER_HZ units */ +struct server **sys_servers; /* the server list */ +int sys_numservers = 0; /* number of servers to poll */ +int sys_maxservers = 0; /* max number of servers to deal with */ +int sys_authenticate = 0; /* true when authenticating */ +U_LONG sys_authkey = 0; /* set to authentication key in use */ +U_LONG sys_authdelay = 0; /* authentication delay */ +int sys_version = NTP_VERSION; /* version to poll with */ + +/* + * The current internal time + */ +U_LONG current_time = 0; + +/* + * Counter for keeping track of completed servers + */ +int complete_servers = 0; + +/* + * File of encryption keys + */ +#ifndef KEYFILE +#define KEYFILE "/etc/ntp.keys" +#endif /* KEYFILE */ + +char *key_file = KEYFILE; + +/* + * Miscellaneous flags + */ +extern int syslogit; +int verbose = 0; +int always_step = 0; + +extern int errno; + +static void transmit P((struct server *)); +static void receive P((struct recvbuf *)); +static void server_data P((struct server *, s_fp, l_fp *, u_fp)); +static void clock_filter P((struct server *)); +static struct server *clock_select P((void)); +static int clock_adjust P((void)); +static void addserver P((char *)); +static struct server *findserver P((struct sockaddr_in *)); +static void timer P((void)); +static void init_alarm P((void)); +static RETSIGTYPE alarming P((int)); +static void init_io P((void)); +static struct recvbuf *getrecvbufs P((void)); +static void freerecvbuf P((struct recvbuf *)); +static void sendpkt P((struct sockaddr_in *, struct pkt *, int)); +static void input_handler P((void)); + +static int l_adj_systime P((l_fp *)); +static int l_step_systime P((l_fp *)); + +static int getnetnum P((char *, U_LONG *)); +static void printserver P((struct server *, FILE *)); + +/* + * Main program. Initialize us and loop waiting for I/O and/or + * timer expiries. + */ +void +main(argc, argv) + int argc; + char *argv[]; +{ + int was_alarmed; + struct recvbuf *rbuflist; + struct recvbuf *rbuf; + l_fp tmp; + int errflg; + int c; + extern char *optarg; + extern int optind; + extern char *Version; + + errflg = 0; + progname = argv[0]; + syslogit = 0; + + /* + * Decode argument list + */ + while ((c = getopt_l(argc, argv, "a:bde:k:o:p:qst:v")) != EOF) + switch (c) { + case 'a': + c = atoi(optarg); + sys_authenticate = 1; + sys_authkey = (U_LONG)c; + break; + case 'b': + always_step++; + break; + case 'd': + ++debug; + break; + case 'e': + if (!atolfp(optarg, &tmp) + || tmp.l_ui != 0) { + (void) fprintf(stderr, + "%s: encryption delay %s is unlikely\n", + progname, optarg); + errflg++; + } else { + sys_authdelay = tmp.l_uf; + } + break; + case 'k': + key_file = optarg; + break; + case 'o': + sys_version = atoi(optarg); + break; + case 'p': + c = atoi(optarg); + if (c <= 0 || c > NTP_SHIFT) { + (void) fprintf(stderr, + "%s: number of samples (%d) is invalid\n", + progname, c); + errflg++; + } else { + sys_samples = c; + } + break; + case 'q': + simple_query = 1; + break; + case 's': + syslogit = 1; + break; + case 't': + if (!atolfp(optarg, &tmp)) { + (void) fprintf(stderr, + "%s: timeout %s is undecodeable\n", + progname, optarg); + errflg++; + } else { + sys_timeout = ((LFPTOFP(&tmp) * TIMER_HZ) + + 0x8000) >> 16; + if (sys_timeout == 0) + sys_timeout = 1; + } + break; + case 'v': + verbose = 1; + break; + case '?': + ++errflg; + break; + default: + break; + } + + sys_maxservers = argc - optind; + if (errflg || sys_maxservers == 0) { + (void) fprintf(stderr, +"usage: %s [-bqs] [-a key#] [-k file] [-p samples] [-t timeo] server ...\n", + progname); + exit(2); + } + + sys_servers = (struct server **) + emalloc(sys_maxservers * sizeof(struct server *)); + + if (debug || simple_query) { +#ifdef NTP_POSIX_SOURCE + static char buf[BUFSIZ]; + setvbuf(stdout, buf, _IOLBF, BUFSIZ); +#else + setlinebuf(stdout); +#endif + } + + /* + * Logging. Open the syslog if we have to + */ + if (syslogit) { +#ifndef LOG_DAEMON + openlog("ntpdate", LOG_PID); +#else + +#ifndef LOG_NTP +#define LOG_NTP LOG_DAEMON +#endif + openlog("ntpdate", LOG_PID | LOG_NDELAY, LOG_NTP); + if (debug) + setlogmask(LOG_UPTO(LOG_DEBUG)); + else + setlogmask(LOG_UPTO(LOG_INFO)); +#endif /* LOG_DAEMON */ + } + + if (debug || verbose) + syslog(LOG_NOTICE, "%s", Version); + + /* + * Add servers we are going to be polling + */ + for ( ; optind < argc; optind++) + addserver(argv[optind]); + + if (sys_numservers == 0) { + syslog(LOG_ERR, "no servers can be used, exiting"); + exit(1); + } + + /* + * Initialize the time of day routines and the I/O subsystem + */ + if (sys_authenticate) { + init_auth(); + if (!authreadkeys(key_file)) { + syslog(LOG_ERR, "no key file, exitting"); + exit(1); + } + if (!authhavekey(sys_authkey)) { + char buf[10]; + + (void) sprintf(buf, "%u", sys_authkey); + syslog(LOG_ERR, "authentication key %s unknown", buf); + exit(1); + } + } + init_io(); + init_alarm(); + + /* + * Set the priority. + */ +#if defined(HAVE_ATT_NICE) + nice (NTPDATE_PRIO); +#endif +#if defined(HAVE_BSD_NICE) + (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO); +#endif + + initializing = 0; + + was_alarmed = 0; + rbuflist = (struct recvbuf *)0; + while (complete_servers < sys_numservers) { + fd_set rdfdes; + int nfound; + + if (alarm_flag) { /* alarmed? */ + was_alarmed = 1; + alarm_flag = 0; + } + rbuflist = getrecvbufs(); /* get received buffers */ + + if (!was_alarmed && rbuflist == (struct recvbuf *)0) { + /* + * Nothing to do. Wait for something. + */ + rdfdes = fdmask; + nfound = select(fd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, (struct timeval *)0); + if (nfound > 0) + input_handler(); + + else if (nfound == -1 && errno != EINTR) { + syslog(LOG_ERR, "select() error: %m"); + } + if (alarm_flag) { /* alarmed? */ + was_alarmed = 1; + alarm_flag = 0; + } + rbuflist = getrecvbufs(); /* get received buffers */ + + } + + /* + * Out here, signals are unblocked. Call receive + * procedure for each incoming packet. + */ + while (rbuflist != (struct recvbuf *)0) { + rbuf = rbuflist; + rbuflist = rbuf->next; + receive(rbuf); + freerecvbuf(rbuf); + } + + /* + * Call timer to process any timeouts + */ + if (was_alarmed) { + timer(); + was_alarmed = 0; + } + + /* + * Go around again + */ + } + + /* + * When we get here we've completed the polling of all servers. + * Adjust the clock, then exit. + */ + exit(clock_adjust()); +} + + +/* + * transmit - transmit a packet to the given server, or mark it completed. + * This is called by the timeout routine and by the receive + * procedure. + */ +static void +transmit(server) + register struct server *server; +{ + struct pkt xpkt; + + if (debug) + printf("transmit(%s)\n", ntoa(&server->srcadr)); + + if (server->filter_nextpt < server->xmtcnt) { + l_fp ts; + /* + * Last message to this server timed out. Shift + * zeros into the filter. + */ + ts.l_ui = ts.l_uf = 0; + server_data(server, 0, &ts, 0); + } + + if ((int)server->filter_nextpt >= sys_samples) { + /* + * Got all the data we need. Mark this guy + * completed and return. + */ + server->event_time = 0; + complete_servers++; + return; + } + + /* + * If we're here, send another message to the server. Fill in + * the packet and let 'er rip. + */ + xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC, + sys_version, MODE_CLIENT); + xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC); + xpkt.ppoll = NTP_MINPOLL; + xpkt.precision = NTPDATE_PRECISION; + xpkt.rootdelay = htonl(NTPDATE_DISTANCE); + xpkt.rootdispersion = htonl(NTPDATE_DISP); + xpkt.refid = htonl(NTPDATE_REFID); + xpkt.reftime.l_ui = xpkt.reftime.l_uf = 0; + xpkt.org.l_ui = xpkt.org.l_uf = 0; + xpkt.rec.l_ui = xpkt.rec.l_uf = 0; + + /* + * Determine whether to authenticate or not. If so, + * fill in the extended part of the packet and do it. + * If not, just timestamp it and send it away. + */ + if (sys_authenticate) { + int len; + + xpkt.keyid = htonl(sys_authkey); + auth1crypt(sys_authkey, (U_LONG *)&xpkt, LEN_PKT_NOMAC); + get_systime(&server->xmt); + L_ADDUF(&server->xmt, sys_authdelay); + HTONL_FP(&server->xmt, &xpkt.xmt); + len = auth2crypt(sys_authkey, (U_LONG *)&xpkt, LEN_PKT_NOMAC); + sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC + len); + + if (debug > 1) + printf("transmit auth to %s\n", + ntoa(&(server->srcadr))); + } else { + get_systime(&(server->xmt)); + HTONL_FP(&server->xmt, &xpkt.xmt); + sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC); + + if (debug > 1) + printf("transmit to %s\n", ntoa(&(server->srcadr))); + } + + /* + * Update the server timeout and transmit count + */ + server->event_time = current_time + sys_timeout; + server->xmtcnt++; +} + + +/* + * receive - receive and process an incoming frame + */ +static void +receive(rbufp) + struct recvbuf *rbufp; +{ + register struct pkt *rpkt; + register struct server *server; + register s_fp di; + register U_LONG t10_ui, t10_uf; + register U_LONG t23_ui, t23_uf; + l_fp org; + l_fp rec; + l_fp ci; + int has_mac; + int is_authentic; + + if (debug) + printf("receive(%s)\n", ntoa(&rbufp->srcadr)); + /* + * Check to see if the packet basically looks like something + * intended for us. + */ + if (rbufp->recv_length == LEN_PKT_NOMAC) + has_mac = 0; + else if (rbufp->recv_length >= LEN_PKT_NOMAC) + has_mac = 1; + else { + if (debug) + printf("receive: packet length %d\n", + rbufp->recv_length); + return; /* funny length packet */ + } + + rpkt = &(rbufp->recv_pkt); + if (PKT_VERSION(rpkt->li_vn_mode) == NTP_OLDVERSION) { +#ifdef notdef + /* + * Fuzzballs do encryption but still claim + * to be version 1. + */ + if (has_mac) + return; +#endif + } else if (PKT_VERSION(rpkt->li_vn_mode) != NTP_VERSION) { + return; + } + + if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER + && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) + || rpkt->stratum > NTP_MAXSTRATUM) { + if (debug) + printf("receive: mode %d stratum %d\n", + PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); + return; + } + + /* + * So far, so good. See if this is from a server we know. + */ + server = findserver(&(rbufp->srcadr)); + if (server == NULL) { + if (debug) + printf("receive: server not found\n"); + return; + } + + /* + * Decode the org timestamp and make sure we're getting a response + * to our last request. + */ + NTOHL_FP(&rpkt->org, &org); + if (!L_ISEQU(&org, &server->xmt)) { + if (debug) + printf("receive: pkt.org and peer.xmt differ\n"); + return; + } + + /* + * Check out the authenticity if we're doing that. + */ + if (!sys_authenticate) + is_authentic = 1; + else { + is_authentic = 0; + + if (debug > 3) + printf("receive: rpkt keyid=%d sys_authkey=%d decrypt=%d\n", + ntohl(rpkt->keyid), sys_authkey, + authdecrypt(sys_authkey, (U_LONG *)rpkt, + LEN_PKT_NOMAC)); + + if (has_mac && ntohl(rpkt->keyid) == sys_authkey && + authdecrypt(sys_authkey, (U_LONG *)rpkt, LEN_PKT_NOMAC)) + is_authentic = 1; + if (debug) + printf("receive: authentication %s\n", + is_authentic ? "passed" : "failed"); + } + server->trust <<= 1; + if (!is_authentic) + server->trust |= 1; + + /* + * Looks good. Record info from the packet. + */ + server->leap = PKT_LEAP(rpkt->li_vn_mode); + server->stratum = PKT_TO_STRATUM(rpkt->stratum); + server->precision = rpkt->precision; + server->rootdelay = ntohl(rpkt->rootdelay); + server->rootdispersion = ntohl(rpkt->rootdispersion); + server->refid = rpkt->refid; + NTOHL_FP(&rpkt->reftime, &server->reftime); + NTOHL_FP(&rpkt->rec, &rec); + NTOHL_FP(&rpkt->xmt, &server->org); + + /* + * Make sure the server is at least somewhat sane. If not, try + * again. + */ + if ((rec.l_ui == 0 && rec.l_uf == 0) || !L_ISHIS(&server->org, &rec)) { + transmit(server); + return; + } + + /* + * Calculate the round trip delay (di) and the clock offset (ci). + * We use the equations (reordered from those in the spec): + * + * d = (t2 - t3) - (t1 - t0) + * c = ((t2 - t3) + (t1 - t0)) / 2 + */ + t10_ui = server->org.l_ui; /* pkt.xmt == t1 */ + t10_uf = server->org.l_uf; + M_SUB(t10_ui, t10_uf, rbufp->recv_time.l_ui, + rbufp->recv_time.l_uf); /* recv_time == t0*/ + + t23_ui = rec.l_ui; /* pkt.rec == t2 */ + t23_uf = rec.l_uf; + M_SUB(t23_ui, t23_uf, org.l_ui, org.l_uf); /* pkt->org == t3 */ + + /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */ + ci.l_ui = t10_ui; + ci.l_uf = t10_uf; + M_ADD(ci.l_ui, ci.l_uf, t23_ui, t23_uf); + M_RSHIFT(ci.l_i, ci.l_uf); + + /* + * Calculate di in t23 in full precision, then truncate + * to an s_fp. + */ + M_SUB(t23_ui, t23_uf, t10_ui, t10_uf); + di = MFPTOFP(t23_ui, t23_uf); + + if (debug > 3) + printf("offset: %s, delay %s\n", lfptoa(&ci, 9), fptoa(di, 4)); + + di += (FP_SECOND >> (-(int)NTPDATE_PRECISION)) + + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW; + + if (di <= 0) { /* value still too raunchy to use? */ + ci.l_ui = ci.l_uf = 0; + di = 0; + } else { + di = max(di, NTP_MINDIST); + } + + /* + * Shift this data in, then transmit again. + */ + server_data(server, (u_fp) di, &ci, 0); + transmit(server); +} + + +/* + * server_data - add a sample to the server's filter registers + */ +static void +server_data(server, d, c, e) + register struct server *server; + s_fp d; + l_fp *c; + u_fp e; +{ + register int i; + + i = server->filter_nextpt; + if (i < NTP_SHIFT) { + server->filter_delay[i] = d; + server->filter_offset[i] = *c; + server->filter_soffset[i] = MFPTOFP(c->l_ui, c->l_uf); + server->filter_error[i] = e; + server->filter_nextpt = i + 1; + } +} + + +/* + * clock_filter - determine a server's delay, dispersion and offset + */ +static void +clock_filter(server) + register struct server *server; +{ + register int i, j; + int ord[NTP_SHIFT]; + + /* + * Sort indices into increasing delay order + */ + for (i = 0; i < sys_samples; i++) + ord[i] = i; + + for (i = 0; i < (sys_samples-1); i++) { + for (j = i+1; j < sys_samples; j++) { + if (server->filter_delay[ord[j]] == 0) + continue; + if (server->filter_delay[ord[i]] == 0 + || (server->filter_delay[ord[i]] + > server->filter_delay[ord[j]])) { + register int tmp; + + tmp = ord[i]; + ord[i] = ord[j]; + ord[j] = tmp; + } + } + } + + /* + * Now compute the dispersion, and assign values to delay and + * offset. If there are no samples in the register, delay and + * offset go to zero and dispersion is set to the maximum. + */ + if (server->filter_delay[ord[0]] == 0) { + server->delay = 0; + server->offset.l_ui = server->offset.l_uf = 0; + server->soffset = 0; + server->dispersion = PEER_MAXDISP; + } else { + register s_fp d; + + server->delay = server->filter_delay[ord[0]]; + server->offset = server->filter_offset[ord[0]]; + server->soffset = LFPTOFP(&server->offset); + server->dispersion = 0; + for (i = 1; i < sys_samples; i++) { + if (server->filter_delay[ord[i]] == 0) + d = PEER_MAXDISP; + else { + d = server->filter_soffset[ord[i]] + - server->filter_soffset[ord[0]]; + if (d < 0) + d = -d; + if (d > PEER_MAXDISP) + d = PEER_MAXDISP; + } + /* + * XXX This *knows* PEER_FILTER is 1/2 + */ + server->dispersion += (u_fp)(d) >> i; + } + } + /* + * We're done + */ +} + + +/* + * clock_select - select the pick-of-the-litter clock from the samples + * we've got. + */ +static struct server * +clock_select() +{ + register struct server *server; + register int i; + register int nlist; + register s_fp d; + register int j; + register int n; + s_fp local_threshold; + struct server *server_list[NTP_MAXCLOCK]; + u_fp server_badness[NTP_MAXCLOCK]; + struct server *sys_server; + + /* + * This first chunk of code is supposed to go through all + * servers we know about to find the NTP_MAXLIST servers which + * are most likely to succeed. We run through the list + * doing the sanity checks and trying to insert anyone who + * looks okay. We are at all times aware that we should + * only keep samples from the top two strata and we only need + * NTP_MAXLIST of them. + */ + nlist = 0; /* none yet */ + for (n = 0; n < sys_numservers; n++) { + server = sys_servers[n]; + if (server->delay == 0) + continue; /* no data */ + if (server->stratum > NTP_INFIN) + continue; /* stratum no good */ + if (server->delay > NTP_MAXWGT) { + continue; /* too far away */ + } + if (server->leap == LEAP_NOTINSYNC) + continue; /* he's in trouble */ + if (server->org.l_ui < server->reftime.l_ui) { + continue; /* very broken host */ + } + if ((server->org.l_ui - server->reftime.l_ui) + >= NTP_MAXAGE) { + continue; /* too LONG without sync */ + } + if (server->trust != 0) { + continue; + } + + /* + * This one seems sane. Find where he belongs + * on the list. + */ + d = server->dispersion + server->dispersion; + for (i = 0; i < nlist; i++) + if (server->stratum <= server_list[i]->stratum) + break; + for ( ; i < nlist; i++) { + if (server->stratum < server_list[i]->stratum) + break; + if (d < server_badness[i]) + break; + } + + /* + * If i points past the end of the list, this + * guy is a loser, else stick him in. + */ + if (i >= NTP_MAXLIST) + continue; + for (j = nlist; j > i; j--) + if (j < NTP_MAXLIST) { + server_list[j] = server_list[j-1]; + server_badness[j] + = server_badness[j-1]; + } + + server_list[i] = server; + server_badness[i] = d; + if (nlist < NTP_MAXLIST) + nlist++; + } + + /* + * Got the five-or-less best. Cut the list where the number of + * strata exceeds two. + */ + j = 0; + for (i = 1; i < nlist; i++) + if (server_list[i]->stratum > server_list[i-1]->stratum) + if (++j == 2) { + nlist = i; + break; + } + + /* + * Whew! What we should have by now is 0 to 5 candidates for + * the job of syncing us. If we have none, we're out of luck. + * If we have one, he's a winner. If we have more, do falseticker + * detection. + */ + + if (nlist == 0) + sys_server = 0; + else if (nlist == 1) { + sys_server = server_list[0]; + } else { + /* + * Re-sort by stratum, bdelay estimate quality and + * server.delay. + */ + for (i = 0; i < nlist-1; i++) + for (j = i+1; j < nlist; j++) { + if (server_list[i]->stratum + < server_list[j]->stratum) + break; /* already sorted by stratum */ + if (server_list[i]->delay + < server_list[j]->delay) + continue; + server = server_list[i]; + server_list[i] = server_list[j]; + server_list[j] = server; + } + + /* + * Calculate the fixed part of the dispersion limit + */ + local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION)) + + NTP_MAXSKW; + + /* + * Now drop samples until we're down to one. + */ + while (nlist > 1) { + for (n = 0; n < nlist; n++) { + server_badness[n] = 0; + for (j = 0; j < nlist; j++) { + if (j == n) /* with self? */ + continue; + d = server_list[j]->soffset + - server_list[n]->soffset; + if (d < 0) /* absolute value */ + d = -d; + /* + * XXX This code *knows* that + * NTP_SELECT is 3/4 + */ + for (i = 0; i < j; i++) + d = (d>>1) + (d>>2); + server_badness[n] += d; + } + } + + /* + * We now have an array of nlist badness + * coefficients. Find the badest. Find + * the minimum precision while we're at + * it. + */ + i = 0; + n = server_list[0]->precision;; + for (j = 1; j < nlist; j++) { + if (server_badness[j] >= server_badness[i]) + i = j; + if (n > server_list[j]->precision) + n = server_list[j]->precision; + } + + /* + * i is the index of the server with the worst + * dispersion. If his dispersion is less than + * the threshold, stop now, else delete him and + * continue around again. + */ + if (server_badness[i] < (local_threshold + + (FP_SECOND >> (-n)))) + break; + for (j = i + 1; j < nlist; j++) + server_list[j-1] = server_list[j]; + nlist--; + } + + /* + * What remains is a list of less than 5 servers. Take + * the best. + */ + sys_server = server_list[0]; + } + + /* + * That's it. Return our server. + */ + return sys_server; +} + + +/* + * clock_adjust - process what we've received, and adjust the time + * if we got anything decent. + */ +static int +clock_adjust() +{ + register int i; + register struct server *server; + s_fp absoffset; + int dostep; + + for (i = 0; i < sys_numservers; i++) + clock_filter(sys_servers[i]); + server = clock_select(); + + if (debug || simple_query) { + for (i = 0; i < sys_numservers; i++) + printserver(sys_servers[i], stdout); + } + + if (server == 0) { + syslog(LOG_ERR, + "no server suitable for synchronization found"); + return(1); + } + + dostep = 1; + if (!always_step) { + absoffset = server->soffset; + if (absoffset < 0) + absoffset = -absoffset; + if (absoffset < NTPDATE_THRESHOLD) + dostep = 0; + } + + if (dostep) { + if (simple_query || l_step_systime(&server->offset)) { + syslog(LOG_NOTICE, "step time server %s offset %s", + ntoa(&server->srcadr), + lfptoa(&server->offset, 7)); + } + } else { + if (simple_query || l_adj_systime(&server->offset)) { + syslog(LOG_NOTICE, "adjust time server %s offset %s", + ntoa(&server->srcadr), + lfptoa(&server->offset, 7)); + } + } + return(0); +} + + +/* XXX ELIMINATE: merge BIG slew into adj_systime in lib/systime.c */ +/* + * addserver - determine a server's address and allocate a new structure + * for it. + */ +static void +addserver(serv) + char *serv; +{ + register struct server *server; + U_LONG netnum; + static int toomany = 0; + + if (sys_numservers >= sys_maxservers) { + if (!toomany) { + /* + * This is actually a `can't happen' now. Leave + * the error message in anyway, though + */ + toomany = 1; + syslog(LOG_ERR, + "too many servers (> %d) specified, remainder not used", + sys_maxservers); + } + return; + } + + if (!getnetnum(serv, &netnum)) { + syslog(LOG_ERR, "can't find host %s\n", serv); + return; + } + + server = (struct server *)emalloc(sizeof(struct server)); + bzero((char *)server, sizeof(struct server)); + + server->srcadr.sin_family = AF_INET; + server->srcadr.sin_addr.s_addr = netnum; + server->srcadr.sin_port = htons(NTP_PORT); + + sys_servers[sys_numservers++] = server; + server->event_time = (U_LONG)sys_numservers; +} + + +/* + * findserver - find a server in the list given its address + */ +static struct server * +findserver(addr) + struct sockaddr_in *addr; +{ + register int i; + register U_LONG netnum; + + if (htons(addr->sin_port) != NTP_PORT) + return 0; + netnum = addr->sin_addr.s_addr; + + for (i = 0; i < sys_numservers; i++) { + if (netnum == sys_servers[i]->srcadr.sin_addr.s_addr) + return sys_servers[i]; + } + return 0; +} + + +/* + * timer - process a timer interrupt + */ +static void +timer() +{ + register int i; + + /* + * Bump the current idea of the time + */ + current_time++; + + /* + * Search through the server list looking for guys + * who's event timers have expired. Give these to + * the transmit routine. + */ + for (i = 0; i < sys_numservers; i++) { + if (sys_servers[i]->event_time != 0 + && sys_servers[i]->event_time <= current_time) + transmit(sys_servers[i]); + } +} + + + +/* + * init_alarm - set up the timer interrupt + */ +static void +init_alarm() +{ + struct itimerval itimer; + + alarm_flag = 0; + + /* + * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ) + * seconds from now and they continue on every 1/TIMER_HZ seconds. + */ + (void) signal_no_reset(SIGALRM, alarming); + itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; + itimer.it_interval.tv_usec = 1000000/TIMER_HZ; + itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1); + setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); +} + + +/* + * alarming - record the occurance of an alarm interrupt + */ +static RETSIGTYPE +alarming(sig) +int sig; +{ + alarm_flag++; +} + + +/* + * 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 if the socket is ready and read the + * packets from it 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 allocate a number of recvbufs equal to the number of servers + * plus 2. This should be plenty. + */ + +/* + * recvbuf lists + */ +struct recvbuf *freelist; /* free buffers */ +struct recvbuf *fulllist; /* buffers with data */ + +int full_recvbufs; /* number of full ones */ +int free_recvbufs; + + +/* + * init_io - initialize I/O data and open socket + */ +static void +init_io() +{ + register int i; + register struct recvbuf *rb; + + /* + * Init buffer free list and stat counters + */ + rb = (struct recvbuf *) + emalloc((sys_numservers + 2) * sizeof(struct recvbuf)); + freelist = 0; + for (i = sys_numservers + 2; i > 0; i--) { + rb->next = freelist; + freelist = rb; + rb++; + } + + fulllist = 0; + full_recvbufs = 0; + free_recvbufs = sys_numservers + 2; + + /* + * Open the socket + */ + + /* create a datagram (UDP) socket */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "socket() failed: %m"); + exit(1); + /*NOTREACHED*/ + } + + /* + * bind the socket to the NTP port + */ + if (!debug && !simple_query) { + struct sockaddr_in addr; + + bzero((char *)&addr, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(NTP_PORT); + addr.sin_addr.s_addr = INADDR_ANY; + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + if (errno == EADDRINUSE) + syslog(LOG_ERR, + "the NTP socket is in use, exiting"); + else + syslog(LOG_ERR, "bind() fails: %m"); + exit(1); + } + } + + FD_ZERO(&fdmask); + FD_SET(fd, &fdmask); + + /* + * set non-blocking, + */ +#if defined(O_NONBLOCK) + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + syslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#else /* O_NONBLOCK */ +#if defined(FNDELAY) + if (fcntl(fd, F_SETFL, FNDELAY) < 0) { + syslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#else /* FNDELAY */ +Need non blocking I/O +#endif /* FNDELAY */ +#endif /* O_NONBLOCK */ +} + + +/* XXX ELIMINATE getrecvbufs (almost) identical to ntpdate.c, ntptrace.c, ntp_io.c */ +/* + * getrecvbufs - get receive buffers which have data in them + * + * ***N.B. must be called with SIGIO blocked*** + */ +static struct recvbuf * +getrecvbufs() +{ + struct recvbuf *rb; + + if (full_recvbufs == 0) { + return (struct recvbuf *)0; /* nothing has arrived */ + } + + /* + * Get the fulllist chain and mark it empty + */ + rb = fulllist; + fulllist = 0; + full_recvbufs = 0; + + /* + * Return the chain + */ + return rb; +} + + +/* XXX ELIMINATE freerecvbuf (almost) identical to ntpdate.c, ntptrace.c, ntp_io.c */ +/* + * freerecvbuf - make a single recvbuf available for reuse + */ +static void +freerecvbuf(rb) + struct recvbuf *rb; +{ + + rb->next = freelist; + freelist = rb; + free_recvbufs++; +} + + +/* + * sendpkt - send a packet to the specified destination + */ +static void +sendpkt(dest, pkt, len) + struct sockaddr_in *dest; + struct pkt *pkt; + int len; +{ + int cc; + + cc = sendto(fd, (char *)pkt, len, 0, (struct sockaddr *)dest, + sizeof(struct sockaddr_in)); + if (cc == -1) { + if (errno != EWOULDBLOCK && errno != ENOBUFS) + syslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + } +} + + +/* + * input_handler - receive packets asynchronously + */ +static void +input_handler() +{ + register int n; + register struct recvbuf *rb; + struct timeval tvzero; + int fromlen; + l_fp ts; + fd_set fds; + + /* + * Do a poll to see if we have data + */ + for (;;) { + fds = fdmask; + tvzero.tv_sec = tvzero.tv_usec = 0; + n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero); + + /* + * If nothing to do, just return. If an error occurred, + * complain and return. If we've got some, freeze a + * timestamp. + */ + if (n == 0) + return; + else if (n == -1) { + syslog(LOG_ERR, "select() error: %m"); + return; + } + get_systime(&ts); + + /* + * 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 (initializing || free_recvbufs == 0) { + char buf[100]; + + (void) read(fd, buf, sizeof buf); + continue; + } + + rb = freelist; + freelist = rb->next; + free_recvbufs--; + + fromlen = sizeof(struct sockaddr_in); + rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt, + sizeof(rb->recv_pkt), 0, + (struct sockaddr *)&rb->srcadr, &fromlen); + if (rb->recv_length == -1) { + rb->next = freelist; + freelist = rb; + free_recvbufs++; + continue; + } + + /* + * Got one. Mark how and when it got here, + * put it on the full list. + */ + rb->recv_time = ts; + rb->next = fulllist; + fulllist = rb; + full_recvbufs++; + } +} + + +/* + * adj_systime - do a big LONG slew of the system time + */ +static int +l_adj_systime(ts) + l_fp *ts; +{ + struct timeval adjtv, oadjtv; + int isneg = 0; + l_fp offset; + l_fp overshoot; + + /* + * Take the absolute value of the offset + */ + offset = *ts; + if (L_ISNEG(&offset)) { + isneg = 1; + L_NEG(&offset); + } + +#ifndef STEP_SLEW + /* + * Calculate the overshoot. XXX N.B. This code *knows* + * ADJ_OVERSHOOT is 1/2. + */ + overshoot = offset; + L_RSHIFTU(&overshoot); + if (overshoot.l_ui != 0 || (overshoot.l_uf > ADJ_MAXOVERSHOOT)) { + overshoot.l_ui = 0; + overshoot.l_uf = ADJ_MAXOVERSHOOT; + } + L_ADD(&offset, &overshoot); +#endif + TSTOTV(&offset, &adjtv); + + if (isneg) { + adjtv.tv_sec = -adjtv.tv_sec; + adjtv.tv_usec = -adjtv.tv_usec; + } + + if (adjtv.tv_usec != 0 && !debug) { + if (adjtime(&adjtv, &oadjtv) < 0) { + syslog(LOG_ERR, "Can't adjust the time of day: %m"); + return 0; + } + } + return 1; +} + + +/* + * This fuction is not the same as lib/systime step_systime!!! + */ +static int +l_step_systime(ts) + l_fp *ts; +{ +#ifdef SLEWALWAYS +#ifdef STEP_SLEW + register U_LONG tmp_ui; + register U_LONG tmp_uf; + int isneg; + int n; + + if (debug) return 1; + /* + * Take the absolute value of the offset + */ + tmp_ui = ts->l_ui; + tmp_uf = ts->l_uf; + if (M_ISNEG(tmp_ui, tmp_uf)) { + M_NEG(tmp_ui, tmp_uf); + isneg = 1; + } else + isneg = 0; + + if (tmp_ui >= 3) { /* Step it and slew - we might win */ + n = step_systime_real(ts); + if (!n) return n; + if (isneg) + ts->l_ui = ~0; + else + ts->l_ui = ~0; + } + /* + * Just add adjustment into the current offset. The update + * routine will take care of bringing the system clock into + * line. + */ +#endif + if (debug) return 1; +#ifdef FORCE_NTPDATE_STEP + return step_systime_real(ts); +#else + l_adj_systime(ts); + return 1; +#endif +#else /* SLEWALWAYS */ + if (debug) return 1; + return step_systime_real(ts); +#endif /* SLEWALWAYS */ +} + +/* + * getnetnum - given a host name, return its net number + */ +static int +getnetnum(host, num) + char *host; + U_LONG *num; +{ + struct hostent *hp; + + if (decodenetnum(host, num)) { + return 1; + } else if ((hp = gethostbyname(host)) != 0) { + bcopy(hp->h_addr, (char *)num, sizeof(U_LONG)); + return 1; + } + return 0; +} + +/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */ +/* + * printserver - print detail information for a server + */ +static void +printserver(pp, fp) + register struct server *pp; + FILE *fp; +{ + register int i; + char junk[5]; + char *str; + + if (!debug) { + (void) fprintf(fp, "server %s, stratum %d, offset %s, delay %s\n", + ntoa(&pp->srcadr), pp->stratum, + lfptoa(&pp->offset, 7), ufptoa(pp->delay, 4)); + return; + } + + (void) fprintf(fp, "server %s, port %d\n", + ntoa(&pp->srcadr), ntohs(pp->srcadr.sin_port)); + + (void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n", + pp->stratum, pp->precision, + pp->leap & 0x2 ? '1' : '0', + pp->leap & 0x1 ? '1' : '0', + pp->trust); + + if (pp->stratum == 1) { + junk[4] = 0; + bcopy((char *)&pp->refid, junk, 4); + str = junk; + } else { + str = numtoa(pp->refid); + } + (void) fprintf(fp, + "refid [%s], delay %s, dispersion %s\n", + str, fptoa(pp->delay, 4), + ufptoa(pp->dispersion, 4)); + + (void) fprintf(fp, "transmitted %d, in filter %d\n", + pp->xmtcnt, pp->filter_nextpt); + + (void) fprintf(fp, "reference time: %s\n", + prettydate(&pp->reftime)); + (void) fprintf(fp, "originate timestamp: %s\n", + prettydate(&pp->org)); + (void) fprintf(fp, "transmit timestamp: %s\n", + prettydate(&pp->xmt)); + + (void) fprintf(fp, "filter delay: "); + for (i = 0; i < NTP_SHIFT; i++) { + (void) fprintf(fp, " %-8.8s", ufptoa(pp->filter_delay[i],4)); + if (i == (NTP_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "filter offset:"); + for (i = 0; i < PEER_SHIFT; i++) { + (void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 5)); + if (i == (PEER_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "delay %s, dispersion %s\n", + ufptoa(pp->delay, 4), ufptoa(pp->dispersion, 4)); + + (void) fprintf(fp, "offset %s\n\n", + lfptoa(&pp->offset, 7)); +} + +#if defined(NEED_VSPRINTF) +/* + * This nugget for pre-tahoe 4.3bsd systems + */ +#if !defined(__STDC__) || !__STDC__ +#define const +#endif + +int +vsprintf(str, fmt, ap) + char *str; + const char *fmt; + va_list ap; +{ + FILE f; + int len; + + f._flag = _IOWRT+_IOSTRG; + f._ptr = str; + f._cnt = 32767; + len = _doprnt(fmt, ap, &f); + *f._ptr = 0; + return (len); +} +#endif + diff --git a/contrib/xntpd/ntpdate/ntpdate.h b/contrib/xntpd/ntpdate/ntpdate.h new file mode 100644 index 0000000000..4a8ff746e7 --- /dev/null +++ b/contrib/xntpd/ntpdate/ntpdate.h @@ -0,0 +1,86 @@ +/* ntpdate.h,v 3.1 1993/07/06 01:09:23 jbj Exp + * ntpdate.h - declarations for the ntpdate program + */ + +#include "ntp_malloc.h" + +/* + * The server structure is a much simplified version of the + * peer structure, for ntpdate's use. Since we always send + * in client mode and expect to receive in server mode, this + * leaves only a very limited number of things we need to + * remember about the server. + */ +struct server { + struct sockaddr_in srcadr; /* address of remote host */ + u_char leap; /* leap indicator */ + u_char stratum; /* stratum of remote server */ + s_char precision; /* server's clock precision */ + u_char trust; /* trustability of the filtered data */ + u_fp rootdelay; /* distance from primary clock */ + u_fp rootdispersion; /* peer clock dispersion */ + U_LONG refid; /* peer reference ID */ + l_fp reftime; /* time of peer's last update */ + U_LONG event_time; /* time for next timeout */ + u_short xmtcnt; /* number of packets transmitted */ + u_short filter_nextpt; /* index into filter shift register */ + s_fp filter_delay[NTP_SHIFT]; /* delay part of shift register */ + l_fp filter_offset[NTP_SHIFT]; /* offset part of shift register */ + s_fp filter_soffset[NTP_SHIFT]; /* offset in s_fp format, for disp */ + u_fp filter_error[NTP_SHIFT]; /* error part of shift register */ + l_fp org; /* peer's originate time stamp */ + l_fp xmt; /* transmit time stamp */ + u_fp delay; /* filter estimated delay */ + u_fp dispersion; /* filter estimated dispersion */ + l_fp offset; /* filter estimated clock offset */ + s_fp soffset; /* fp version of above */ +}; + + +/* + * ntpdate runs everything on a simple, short timeout. It sends a + * packet and sets the timeout (by default, to a small value suitable + * for a LAN). If it receives a response it sends another request. + * If it times out it shifts zeroes into the filter and sends another + * request. + * + * The timer routine is run often (once every 1/5 second currently) + * so that time outs are done with reasonable precision. + */ +#define TIMER_HZ (5) /* 5 per second */ + +/* + * ntpdate will make a LONG adjustment using adjtime() if the times + * are close, or step the time if the times are farther apart. The + * following defines what is "close". + */ +#define NTPDATE_THRESHOLD (FP_SECOND >> 1) /* 1/2 second */ + +/* + * When doing adjustments, ntpdate actually overadjusts (currently + * by 50%, though this may change). While this will make it take longer + * to reach a steady state condition, it will typically result in + * the clock keeping more accurate time, on average. The amount of + * overshoot is limited. + */ +#ifdef NOTNOW +#define ADJ_OVERSHOOT 1/2 /* this is hard coded */ +#endif /* NOTNOW */ +#define ADJ_MAXOVERSHOOT 0x10000000 /* 50 ms as a ts fraction */ + +/* + * Since ntpdate isn't aware of some of the things that normally get + * put in an NTP packet, we fix some values. + */ +#define NTPDATE_PRECISION (-6) /* use this precision */ +#define NTPDATE_DISTANCE FP_SECOND /* distance is 1 sec */ +#define NTPDATE_DISP FP_SECOND /* so is the dispersion */ +#define NTPDATE_REFID (0) /* reference ID to use */ + + +/* + * Some defaults + */ +#define DEFTIMEOUT 5 /* 5 timer increments */ +#define DEFSAMPLES 4 /* get 4 samples per server */ +#define DEFPRECISION (-5) /* the precision we claim */ diff --git a/contrib/xntpd/ntpq/Makefile.tmpl b/contrib/xntpd/ntpq/Makefile.tmpl new file mode 100644 index 0000000000..e80286123c --- /dev/null +++ b/contrib/xntpd/ntpq/Makefile.tmpl @@ -0,0 +1,68 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:09:28 jbj Exp +# +PROGRAM= ntpq +# +# ntpq - control mode query program +# +COMPILER= cc +COPTS= -O +BINDIR= /usr/local +INSTALL= install +DEFS= +DEFS_OPT= +DEFS_LOCAL= +RESLIB= +COMPAT= +# +INCL= -I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +LIB= ../lib/libntp.a +LINTLIB= ../lib/llib-llibntp.ln +MAKE= make +TOP=../ +# +OBJS= ntpq.o ntpq_ops.o +SOURCE= ntpq.c ntpq_ops.c + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) $(LIB) version.o + $(CC) $(COPTS) -o $@ $(OBJS) version.o $(LIB) $(RESLIB) $(COMPAT) + +install: $(BINDIR)/$(PROGRAM) + +$(BINDIR)/$(PROGRAM): $(PROGRAM) + $(INSTALL) -c -m 0755 $(PROGRAM) $(BINDIR) + +tags: + ctags *.c *.h + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(PROGRAM) *.o *.out tags make.log Makefile.bak lint.errs .version + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +lint: $(LINTLIB) + lint -x -u $(DEFS) $(DEFS_LOCAL) $(INCL) $(LINTLIB) $(SOURCE) >lint.errs + +../lib/llib-llibntp.ln: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" lintlib + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" + +# +# we want to build the current version string here +# +version.o: ../VERSION + ../scripts/mkversion $(PROGRAM) + $(CC) $(COPTS) $(INCL) -c version.c + +../VERSION: + -@rm -f .version diff --git a/contrib/xntpd/ntpq/README b/contrib/xntpd/ntpq/README new file mode 100644 index 0000000000..117c66ce97 --- /dev/null +++ b/contrib/xntpd/ntpq/README @@ -0,0 +1,6 @@ +README file for directory ./ntpq of the NTP Version 3 distribution + +This directory contains the sources for the ntpq utility program. See +the README and RELNOTES files in the parent directory for directions on +how to make and install this program. The current version number of this +program is in the version.c file. diff --git a/contrib/xntpd/ntpq/ntpq.c b/contrib/xntpd/ntpq/ntpq.c new file mode 100644 index 0000000000..e9db0086c0 --- /dev/null +++ b/contrib/xntpd/ntpq/ntpq.c @@ -0,0 +1,3059 @@ +/* ntpq.c,v 3.1 1993/07/06 01:09:29 jbj Exp + * ntpq - query an NTP server using mode 6 commands + */ +#include +#include +#include +#include +#include +#include +#include + +#include "ntp_select.h" +#include "ntpq.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" +#include "ntp_io.h" +#include "ntp_stdlib.h" + +/* + * Because we potentially understand a lot of commands we will run + * interactive if connected to a terminal. + */ +int interactive = 0; /* set to 1 when we should prompt */ +char *prompt = "ntpq> "; /* prompt to ask him about */ + + +/* + * Keyid used for authenticated requests. Obtained on the fly. + */ +U_LONG info_auth_keyid = -1; + +/* + * Type of key md5 or des + */ +#define KEY_TYPE_DES 3 +#define KEY_TYPE_MD5 4 + +int info_auth_keytype = KEY_TYPE_DES; /* DES */ + +/* + * Flag which indicates we should always send authenticated requests + */ +int always_auth = 0; + +/* + * Flag which indicates raw mode output. + */ +int rawmode = 0; + +/* + * Packet version number we use + */ +u_char pktversion = NTP_VERSION; + +/* + * Don't jump if no set jmp. + */ +int jump = 0; + +/* + * Format values + */ +#define PADDING 0 +#define TS 1 /* time stamp */ +#define FL 2 /* l_fp type value */ +#define FU 3 /* u_fp type value */ +#define FS 4 /* s_fp type value */ +#define UI 5 /* unsigned integer value */ +#define IN 6 /* signed integer value */ +#define HA 7 /* host address */ +#define NA 8 /* network address */ +#define ST 9 /* string value */ +#define RF 10 /* refid (sometimes string, sometimes not) */ +#define LP 11 /* leap (print in binary) */ +#define OC 12 /* integer, print in octal */ +#define MD 13 /* mode */ +#define AR 14 /* array of times */ +#define EOV 255 /* end of table */ + + +/* + * System variable values. The array can be indexed by + * the variable index to find the textual name. + */ +struct ctl_var sys_var[] = { + { 0, PADDING, "" }, /* 0 */ + { CS_LEAP, LP, "leap" }, /* 1 */ + { CS_STRATUM, UI, "stratum" }, /* 2 */ + { CS_PRECISION, IN, "precision" }, /* 3 */ + { CS_ROOTDELAY, FU, "rootdelay" }, /* 4 */ + { CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */ + { CS_REFID, RF, "refid" }, /* 6 */ + { CS_REFTIME, TS, "reftime" }, /* 7 */ + { CS_POLL, UI, "poll" }, /* 8 */ + { CS_PEERID, UI, "peer" }, /* 9 */ + { CS_OFFSET, FL, "phase" }, /* 10 */ + { CS_DRIFT, FS, "freq" }, /* 11 */ + { CS_COMPLIANCE, UI, "compliance" }, /* 12 */ + { CS_CLOCK, TS, "clock" }, /* 13 */ + { CS_LEAPIND, LP, "leapindicator" }, /* 14 */ + { CS_LEAPWARNING, LP, "leapwarning" }, /* 15 */ + { CS_PROCESSOR, ST, "processor" }, /* 16 */ + { CS_SYSTEM, ST, "system" }, /* 17 */ + { CS_KEYID, UI, "keyid" }, /* 18 */ + { CS_REFSKEW, FL, "refskew" }, /* 19 */ + { 0, EOV, "" } +}; + + +/* + * Peer variable list + */ +struct ctl_var peer_var[] = { + { 0, PADDING, "" }, /* 0 */ + { CP_CONFIG, UI, "config" }, /* 1 */ + { CP_AUTHENABLE, UI, "authenable" }, /* 2 */ + { CP_AUTHENTIC, UI, "authentic" }, /* 3 */ + { CP_SRCADR, HA, "srcadr" }, /* 4 */ + { CP_SRCPORT, UI, "srcport" }, /* 5 */ + { CP_DSTADR, NA, "dstadr" }, /* 6 */ + { CP_DSTPORT, UI, "dstport" }, /* 7 */ + { CP_LEAP, LP, "leap" }, /* 8 */ + { CP_HMODE, MD, "hmode" }, /* 9 */ + { CP_STRATUM, UI, "stratum" }, /* 10 */ + { CP_PPOLL, UI, "ppoll" }, /* 11 */ + { CP_HPOLL, UI, "hpoll" }, /* 12 */ + { CP_PRECISION, IN, "precision" }, /* 13 */ + { CP_ROOTDELAY, FS, "rootdelay" }, /* 14 */ + { CP_ROOTDISPERSION, FU, "rootdispersion" }, /* 15 */ + { CP_REFID, RF, "refid" }, /* 16 */ + { CP_REFTIME, TS, "reftime" }, /* 17 */ + { CP_ORG, TS, "org" }, /* 18 */ + { CP_REC, TS, "rec" }, /* 19 */ + { CP_XMT, TS, "xmt" }, /* 20 */ + { CP_REACH, OC, "reach" }, /* 21 */ + { CP_VALID, UI, "valid" }, /* 22 */ + { CP_TIMER, UI, "timer" }, /* 23 */ + { CP_DELAY, AR, "delay" }, /* 24 */ + { CP_OFFSET, AR, "offset" }, /* 25 */ + { CP_DISPERSION, FU, "dispersion" }, /* 26 */ + { CP_KEYID, UI, "keyid" }, /* 27 */ + { CP_FILTDELAY, AR, "filtdelay" }, /* 28 */ + { CP_FILTOFFSET, AR, "filtoffset" }, /* 29 */ + { CP_PMODE, ST, "pmode" }, /* 30 */ + { CP_RECEIVED, UI, "received" }, /* 31 */ + { CP_SENT, UI, "sent" }, /* 32 */ + { CP_FILTERROR, AR, "filterror" }, /* 33 */ + { CP_FLASH, ST, "flash"}, /* 34 */ + { CP_DISP, AR, "disp" }, /* 35 */ + /* + * These are duplicate entires so that we can + * process deviant version of the xntp protocal. + */ + { CP_SRCADR, HA, "peeraddr" }, /* 4 */ + { CP_SRCPORT, UI, "peerport" }, /* 5 */ + { CP_PPOLL, UI, "peerpoll" }, /* 11 */ + { CP_HPOLL, UI, "hostpoll" }, /* 12 */ + { 0, EOV, "" } +}; + + +/* + * Clock variable list + */ +struct ctl_var clock_var[] = { + { 0, PADDING, "" }, /* 0 */ + { CC_TYPE, UI, "type" }, /* 1 */ + { CC_TIMECODE, ST, "timecode" }, /* 2 */ + { CC_POLL, UI, "poll" }, /* 3 */ + { CC_NOREPLY, UI, "noreply" }, /* 4 */ + { CC_BADFORMAT, UI, "badformat" }, /* 5 */ + { CC_BADDATA, UI, "baddata" }, /* 6 */ + { CC_FUDGETIME1, FL, "fudgetime1" }, /* 7 */ + { CC_FUDGETIME2, FL, "fudgetime2" }, /* 8 */ + { CC_FUDGEVAL1, IN, "fudgeval1" }, /* 9 */ + { CC_FUDGEVAL2, IN, "fudgeval2" }, /* 10 */ + { CC_FLAGS, UI, "flags" }, /* 11 */ + { CC_DEVICE, ST, "device" }, /* 12 */ + { 0, EOV, "" } +}; + + +/* + * Structure for turning various constants into a readable string. + */ +struct codestring { + int code; + char *string; +}; + +/* + * Leap values + */ +struct codestring leap_codes[] = { + { 0, "leap_none" }, + { 1, "leap_add_sec" }, + { 2, "leap_del_sec" }, + { 3, "sync_alarm" }, + { -1, "leap" } +}; + + +/* + * Clock source + */ +struct codestring sync_codes[] = { + { CTL_SST_TS_UNSPEC, "sync_unspec" }, + { CTL_SST_TS_ATOM, "sync_atomic" }, + { CTL_SST_TS_LF, "sync_lf_clock" }, + { CTL_SST_TS_HF, "sync_hf_clock" }, + { CTL_SST_TS_UHF, "sync_uhf_clock" }, + { CTL_SST_TS_LOCAL, "sync_local_proto" }, + { CTL_SST_TS_NTP, "sync_ntp" }, + { CTL_SST_TS_UDPTIME, "sync_udp/time" }, + { CTL_SST_TS_WRSTWTCH, "sync_wristwatch" }, + { CTL_SST_TS_TELEPHONE, "sync_telephone" }, + { -1, "sync" } +}; + + +/* + * Peer selection + */ +struct codestring select_codes[] = { + { CTL_PST_SEL_REJECT, "sel_reject" }, + { CTL_PST_SEL_SANE, "sel_sane" }, + { CTL_PST_SEL_CORRECT, "sel_correct" }, + { CTL_PST_SEL_SELCAND, "sel_candidate" }, + { CTL_PST_SEL_SYNCCAND, "sel_sync" }, + { CTL_PST_SEL_DISTSYSPEER, "sel_sys.peer, hi_dist" }, + { CTL_PST_SEL_SYSPEER, "sel_sys.peer" }, + { -1, "sel" } +}; + + +/* + * Clock status + */ +struct codestring clock_codes[] = { + { CTL_CLK_OKAY, "clk_okay" }, + { CTL_CLK_NOREPLY, "clk_noreply" }, + { CTL_CLK_BADFORMAT, "clk_badformat" }, + { CTL_CLK_FAULT, "clk_fault" }, + { CTL_CLK_PROPAGATION, "clk_propagation" }, + { CTL_CLK_BADDATE, "clk_baddate" }, + { CTL_CLK_BADTIME, "clk_badtime" }, + { -1, "clk" } +}; + + +/* + * System Events + */ +struct codestring sys_codes[] = { + { EVNT_UNSPEC, "event_unspec" }, + { EVNT_SYSRESTART, "event_restart" }, + { EVNT_SYSFAULT, "event_fault" }, + { EVNT_SYNCCHG, "event_sync_chg" }, + { EVNT_PEERSTCHG, "event_peer/strat_chg" }, + { EVNT_CLOCKRESET, "event_clock_reset" }, + { EVNT_BADDATETIM, "event_bad_date" }, + { EVNT_CLOCKEXCPT, "event_clock_excptn" }, + { -1, "event" } +}; + +/* + * Peer Events + */ +struct codestring peer_codes[] = { + { EVNT_UNSPEC, "event_unspec" }, + { EVNT_PEERIPERR & ~PEER_EVENT, "event_ip_err" }, + { EVNT_PEERAUTH & ~PEER_EVENT, "event_authen" }, + { EVNT_UNREACH & ~PEER_EVENT, "event_unreach" }, + { EVNT_REACH & ~PEER_EVENT, "event_reach" }, +#if 0 + { EVNT_PEERSTRAT & ~PEER_EVENT, "event_stratum_chg" }, +#endif + { -1, "event" } +}; + + +/* + * Built in command handler declarations + */ +static int openhost P((char *)); +static int sendpkt P((char *, int)); +static int getresponse P((int, int, u_short *, int *, char **, int)); +static int sendrequest P((int, int, int, int, char *)); +static void getcmds P((void)); +static RETSIGTYPE abortcmd P((int)); +static void docmd P((char *)); +static void tokenize P((char *, char **, int *)); +static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **)); +static int getarg P((char *, int, arg_v *)); +static int rtdatetolfp P((char *, l_fp *)); + +#ifdef UNUSED +static int decodereach P((char *, U_LONG *)); +#endif /* UNUSED */ + +static int decodearr P((char *, int *, l_fp *)); +static char * getcode P((int, struct codestring *)); +static void help P((struct parse *, FILE *)); +#if defined(sgi) +static int helpsort P((const void *, const void *)); +#else +static int helpsort P((char **, char **)); +#endif /* sgi */ +static void printusage P((struct xcmd *, FILE *)); +static void timeout P((struct parse *, FILE *)); +static void delay P((struct parse *, FILE *)); +static void host P((struct parse *, FILE *)); +static void ntp_poll P((struct parse *, FILE *)); +static void keyid P((struct parse *, FILE *)); +static void keytype P((struct parse *, FILE *)); +static void passwd P((struct parse *, FILE *)); +static void hostnames P((struct parse *, FILE *)); +static void setdebug P((struct parse *, FILE *)); +static void quit P((struct parse *, FILE *)); +static void version P((struct parse *, FILE *)); +static void raw P((struct parse *, FILE *)); +static void cooked P((struct parse *, FILE *)); +static void authenticate P((struct parse *, FILE *)); +static void ntpversion P((struct parse *, FILE *)); +static void warning P((char *, char *, char *)); +static void error P((char *, char *, char *)); +static U_LONG getkeyid P((char *)); +static void atoascii P((int, char *, char *)); +static void makeascii P((int, char *, FILE *)); +static char * getevents P((int)); +static char * statustoa P((int, int)); +static void rawprint P((int, int, char *, int, FILE *)); +static void startoutput P((void)); +static void output P((FILE *, char *, char *)); +static void endoutput P((FILE *)); +static void outputarr P((FILE *, char *, int, l_fp *)); +static void cookedprint P((int, int, char *, int, FILE *)); +#if defined(sgi) +static int assoccmp P((const void *, const void *)); +#else +static int assoccmp P((struct association *, struct association *)); +#endif /* sgi */ + + +/* + * Built-in commands we understand + */ +struct xcmd builtins[] = { + { "?", help, { OPT|STR, NO, NO, NO }, + { "command", "", "", "" }, + "tell the use and syntax of commands" }, + { "help", help, { OPT|STR, NO, NO, NO }, + { "command", "", "", "" }, + "tell the use and syntax of commands" }, + { "timeout", timeout, { OPT|UINT, NO, NO, NO }, + { "msec", "", "", "" }, + "set the primary receive time out" }, + { "delay", delay, { OPT|INT, NO, NO, NO }, + { "msec", "", "", "" }, + "set the delay added to encryption time stamps" }, + { "host", host, { OPT|STR, NO, NO, NO }, + { "hostname", "", "", "" }, + "specify the host whose NTP server we talk to" }, + { "poll", ntp_poll, { OPT|UINT, OPT|STR, NO, NO }, + { "n", "verbose", "", "" }, + "poll an NTP server in client mode `n' times" }, + { "passwd", passwd, { NO, NO, NO, NO }, + { "", "", "", "" }, + "specify a password to use for authenticated requests"}, + { "hostnames", hostnames, { OPT|STR, NO, NO, NO }, + { "yes|no", "", "", "" }, + "specify whether hostnames or net numbers are printed"}, + { "debug", setdebug, { OPT|STR, NO, NO, NO }, + { "no|more|less", "", "", "" }, + "set/change debugging level" }, + { "quit", quit, { NO, NO, NO, NO }, + { "", "", "", "" }, + "exit ntpq" }, + { "keyid", keyid, { OPT|UINT, NO, NO, NO }, + { "key#", "", "", "" }, + "set keyid to use for authenticated requests" }, + { "version", version, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print version number" }, + { "raw", raw, { NO, NO, NO, NO }, + { "", "", "", "" }, + "do raw mode variable output" }, + { "cooked", cooked, { NO, NO, NO, NO }, + { "", "", "", "" }, + "do cooked mode variable output" }, + { "authenticate", authenticate, { OPT|STR, NO, NO, NO }, + { "yes|no", "", "", "" }, + "always authenticate requests to this server" }, + { "ntpversion", ntpversion, { OPT|UINT, NO, NO, NO }, + { "version number", "", "", "" }, + "set the NTP version number to use for requests" }, + { "keytype", keytype, { STR, NO, NO, NO }, + { "key type (md5|des)", "", "", "" }, + "set key type to use for authenticated requests (des|md5)" }, + { 0, 0, { NO, NO, NO, NO }, + { "", "", "", "" }, "" } +}; + + +/* + * Default values we use. + */ +#define DEFTIMEOUT (5) /* 5 second time out */ +#define DEFSTIMEOUT (2) /* 2 second time out after first */ +#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ +#define DEFHOST "localhost" /* default host name */ +#define LENHOSTNAME 256 /* host name is 256 characters LONG */ +#define MAXCMDS 100 /* maximum commands on cmd line */ +#define MAXHOSTS 100 /* maximum hosts on cmd line */ +#define MAXLINE 512 /* maximum line length */ +#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ +#define MAXVARLEN 256 /* maximum length of a variable name */ +#define MAXVALLEN 256 /* maximum length of a variable value */ +#define MAXOUTLINE 72 /* maximum length of an output line */ + +/* + * Some variables used and manipulated locally + */ +struct timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ +struct timeval tvsout = { DEFSTIMEOUT, 0 }; /* secondary time out */ +l_fp delay_time; /* delay time */ +char currenthost[LENHOSTNAME]; /* current host name */ +struct sockaddr_in hostaddr = { 0 }; /* host address */ +int showhostnames = 1; /* show host names by default */ + +int sockfd; /* fd socket is openned on */ +int havehost = 0; /* set to 1 when host open */ +struct servent *server_entry = NULL; /* server entry for ntp */ + +/* + * Sequence number used for requests. It is incremented before + * it is used. + */ +u_short sequence; + +/* + * Holds data returned from queries. Declare buffer LONG to be sure of + * alignment. + */ +#define MAXFRAGS 24 /* maximum number of fragments */ +#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */ +LONG pktdata[DATASIZE/sizeof(LONG)]; + +/* + * Holds association data for use with the &n operator. + */ +struct association assoc_cache[MAXASSOC]; +int numassoc = 0; /* number of cached associations */ + +/* + * For commands typed on the command line (with the -c option) + */ +int numcmds = 0; +char *ccmds[MAXCMDS]; +#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) + +/* + * When multiple hosts are specified. + */ +int numhosts = 0; +char *chosts[MAXHOSTS]; +#define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp) + +/* + * Error codes for internal use + */ +#define ERR_UNSPEC 256 +#define ERR_INCOMPLETE 257 +#define ERR_TIMEOUT 258 +#define ERR_TOOMUCH 259 + +/* + * Macro definitions we use + */ +#define ISSPACE(c) ((c) == ' ' || (c) == '\t') +#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +/* + * Jump buffer for longjumping back to the command level + */ +jmp_buf interrupt_buf; + +/* + * Points at file being currently printed into + */ +FILE *current_output; + +/* + * Command table imported from ntpdc_ops.c + */ +extern struct xcmd opcmds[]; + +char *progname; +int debug; + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + + delay_time.l_ui = 0; + delay_time.l_uf = DEFDELAY; + + progname = argv[0]; + while ((c = getopt_l(argc, argv, "c:dinp")) != EOF) + switch (c) { + case 'c': + ADDCMD(optarg); + break; + case 'd': + ++debug; + break; + case 'i': + interactive = 1; + break; + case 'n': + showhostnames = 0; + break; + case 'p': + ADDCMD("peers"); + break; + default: + errflg++; + break; + } + if (errflg) { + (void) fprintf(stderr, + "usage: %s [-dinp] [-c cmd] host ...\n", + progname); + exit(2); + } + if (optind == argc) { + ADDHOST(DEFHOST); + } else { + for (; optind < argc; optind++) + ADDHOST(argv[optind]); + } + + if (numcmds == 0 && interactive == 0 + && isatty(fileno(stdin)) && isatty(fileno(stderr))) { + interactive = 1; + } + + if (interactive) + (void) signal_no_reset(SIGINT, abortcmd); + + if (numcmds == 0) { + (void) openhost(chosts[0]); + getcmds(); + } else { + int ihost; + int icmd; + + for (ihost = 0; ihost < numhosts; ihost++) { + if (openhost(chosts[ihost])) + for (icmd = 0; icmd < numcmds; icmd++) + docmd(ccmds[icmd]); + } + } + exit(0); +} + + +/* + * openhost - open a socket to a host + */ +static int +openhost(hname) + char *hname; +{ + U_LONG netnum; + char temphost[LENHOSTNAME]; + + if (server_entry == NULL) { + server_entry = getservbyname("ntp", "udp"); + if (server_entry == NULL) { + (void) fprintf(stderr, "%s: ntp/udp: unknown service\n", + progname); + exit(1); + } + if (debug > 2) + printf("Got ntp/udp service entry\n"); + } + + if (!getnetnum(hname, &netnum, temphost)) + return 0; + + if (debug > 2) + printf("Opening host %s\n", temphost); + + if (havehost == 1) { + if (debug > 2) + printf("Closing old host %s\n", currenthost); + (void) close(sockfd); + havehost = 0; + } + (void) strcpy(currenthost, temphost); + + hostaddr.sin_family = AF_INET; + hostaddr.sin_port = server_entry->s_port; + hostaddr.sin_addr.s_addr = netnum; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) + error("socket", "", ""); + +#if defined(SYS_HPUX) && (SYS_HPUX < 8) +#ifdef SO_RCVBUF + { int rbufsize = DATASIZE + 2048; /* 2K for slop */ + if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, + &rbufsize, sizeof(int)) == -1) + error("setsockopt", "", ""); + } +#endif +#endif + + if (connect(sockfd, (struct sockaddr *)&hostaddr, + sizeof(hostaddr)) == -1) + error("connect", "", ""); + + havehost = 1; + return 1; +} + + +/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ +/* + * sendpkt - send a packet to the remote host + */ +static int +sendpkt(xdata, xdatalen) + char *xdata; + int xdatalen; +{ + if (debug >= 3) + printf("Sending %d octets\n", xdatalen); + + if (write(sockfd, xdata, xdatalen) == -1) { + warning("write to %s failed", currenthost, ""); + return -1; + } + + if (debug >= 4) { + int first = 8; + printf("Packet data:\n"); + while (xdatalen-- > 0) { + if (first-- == 0) { + printf("\n"); + first = 7; + } + printf(" %02x", *xdata++ & 0xff); + } + printf("\n"); + } + return 0; +} + + + +/* + * getresponse - get a (series of) response packet(s) and return the data + */ +static int +getresponse(opcode, associd, rstatus, rsize, rdata, timeo) + int opcode; + int associd; + u_short *rstatus; + int *rsize; + char **rdata; + int timeo; +{ + struct ntp_control rpkt; + struct timeval tvo; + u_short offsets[MAXFRAGS+1]; + u_short counts[MAXFRAGS+1]; + u_short offset; + u_short count; + int numfrags; + int seenlastfrag; + fd_set fds; + int n; + + /* + * This is pretty tricky. We may get between 1 and MAXFRAG packets + * back in response to the request. We peel the data out of + * each packet and collect it in one LONG block. When the last + * packet in the sequence is received we'll know how much data we + * should have had. Note we use one LONG time out, should reconsider. + */ + *rsize = 0; + if (rstatus) + *rstatus = 0; + *rdata = (char *)pktdata; + + numfrags = 0; + seenlastfrag = 0; + + FD_ZERO(&fds); + +again: + if (numfrags == 0) + tvo = tvout; + else + tvo = tvsout; + + FD_SET(sockfd, &fds); + n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo); + + if (debug >= 1) + printf("select() returns %d\n", n); + + if (n == -1) { + warning("select fails", "", ""); + return -1; + } + if (n == 0) { + /* + * Timed out. Return what we have + */ + if (numfrags == 0) { + if (timeo) + (void) fprintf(stderr, + "%s: timed out, nothing received\n", + currenthost); + return ERR_TIMEOUT; + } else { + if (timeo) + (void) fprintf(stderr, + "%s: timed out with incomplete data\n", + currenthost); + if (debug) { + printf("Received fragments:\n"); + for (n = 0; n < numfrags; n++) + printf("%4d %d\n", offsets[n], + counts[n]); + if (seenlastfrag) + printf("last fragment received\n"); + else + printf("last fragment not received\n"); + } + return ERR_INCOMPLETE; + } + } + + n = read(sockfd, (char *)&rpkt, sizeof(rpkt)); + if (n == -1) { + warning("read", "", ""); + return -1; + } + + if (debug >= 4) { + int len = n, first = 8; + char *data = (char *)&rpkt; + + printf("Packet data:\n"); + while (len-- > 0) { + if (first-- == 0) { + printf("\n"); + first = 7; + } + printf(" %02x", *data++ & 0xff); + } + printf("\n"); + } + + /* + * Check for format errors. Bug proofing. + */ + if (n < CTL_HEADER_LEN) { + if (debug) + printf("Short (%d byte) packet received\n", n); + goto again; + } + if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION + || PKT_VERSION(rpkt.li_vn_mode) <= NTP_OLDVERSION) { + if (debug) + printf("Packet received with version %d\n", + PKT_VERSION(rpkt.li_vn_mode)); + goto again; + } + if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { + if (debug) + printf("Packet received with mode %d\n", + PKT_MODE(rpkt.li_vn_mode)); + goto again; + } + if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { + if (debug) + printf("Received request packet, wanted response\n"); + goto again; + } + + /* + * Check opcode and sequence number for a match. + * Could be old data getting to us. + */ + if (ntohs(rpkt.sequence) != sequence) { + if (debug) + printf( + "Received sequnce number %d, wanted %d\n", + ntohs(rpkt.sequence), sequence); + goto again; + } + if (CTL_OP(rpkt.r_m_e_op) != opcode) { + if (debug) + printf( + "Received opcode %d, wanted %d (sequence number okay)\n", + CTL_OP(rpkt.r_m_e_op), opcode); + goto again; + } + + /* + * Check the error code. If non-zero, return it. + */ + if (CTL_ISERROR(rpkt.r_m_e_op)) { + int errcode; + + errcode = (ntohs(rpkt.status) >> 8) & 0xff; + if (debug && CTL_ISMORE(rpkt.r_m_e_op)) { + printf("Error code %d received on not-final packet\n", + errcode); + } + if (errcode == CERR_UNSPEC) + return ERR_UNSPEC; + return errcode; + } + + /* + * Check the association ID to make sure it matches what + * we sent. + */ + if (ntohs(rpkt.associd) != associd) { + if (debug) + printf("Association ID %d doesn't match expected %d\n", + ntohs(rpkt.associd), associd); + /* + * Hack for silly fuzzballs which, at the time of writing, + * return an assID of sys.peer when queried for system variables. + */ +#ifdef notdef + goto again; +#endif + } + + /* + * Collect offset and count. Make sure they make sense. + */ + offset = ntohs(rpkt.offset); + count = ntohs(rpkt.count); + + if (debug >= 3) { + int shouldbesize; + U_LONG key; + U_LONG *lpkt; + int maclen; + + /* + * Usually we ignore authentication, but for debugging purposes + * we watch it here. + */ + shouldbesize = CTL_HEADER_LEN + count; + + /* round to 8 octet boundary */ + shouldbesize = (shouldbesize + 7) & ~7; + + if (n & 0x3) { + printf("Packet not padded, size = %d\n", n); + } if ((maclen = n - shouldbesize) >= MIN_MAC_LEN) { + printf( +"Packet shows signs of authentication (total %d, data %d, mac %d)\n", + n, shouldbesize, maclen); + lpkt = (U_LONG *)&rpkt; + printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", + ntohl(lpkt[(n - maclen)/sizeof(U_LONG) - 3]), + ntohl(lpkt[(n - maclen)/sizeof(U_LONG) - 2]), + ntohl(lpkt[(n - maclen)/sizeof(U_LONG) - 1]), + ntohl(lpkt[(n - maclen)/sizeof(U_LONG)]), + ntohl(lpkt[(n - maclen)/sizeof(U_LONG) + 1]), + ntohl(lpkt[(n - maclen)/sizeof(U_LONG) + 2])); + key = ntohl(lpkt[(n - maclen) / sizeof(U_LONG)]); + printf("Authenticated with keyid %lu\n", key); + if (key != 0 && key != info_auth_keyid) { + printf("We don't know that key\n"); + } else { + if (authdecrypt(key, (U_LONG *)&rpkt, + (n - maclen))) { + printf("Auth okay!\n"); + } else { + printf("Auth failed!\n"); + } + } + } + } + + if (debug >= 2) + printf("Got packet, size = %d\n", n); + if (count > (u_short)(n-CTL_HEADER_LEN)) { + if (debug) + printf( + "Received count of %d octets, data in packet is %d\n", + count, n-CTL_HEADER_LEN); + goto again; + } + if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { + if (debug) + printf("Received count of 0 in non-final fragment\n"); + goto again; + } + if (offset + count > sizeof(pktdata)) { + if (debug) + printf("Offset %d, count %d, too big for buffer\n", + offset, count); + return ERR_TOOMUCH; + } + if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { + if (debug) + printf("Received second last fragment packet\n"); + goto again; + } + + /* + * So far, so good. Record this fragment, making sure it doesn't + * overlap anything. + */ + if (debug >= 2) + printf("Packet okay\n");; + + if (numfrags == MAXFRAGS) { + if (debug) + printf("Number of fragments exceeds maximum\n"); + return ERR_TOOMUCH; + } + + for (n = 0; n < numfrags; n++) { + if (offset == offsets[n]) + goto again; /* duplicate */ + if (offset < offsets[n]) + break; + } + + if ((u_short)(n > 0 && offsets[n-1] + counts[n-1]) > offset) + goto overlap; + if (n < numfrags && (u_short)(offset + count) > offsets[n]) + goto overlap; + + { + register int i; + + for (i = numfrags; i > n; i--) { + offsets[i] = offsets[i-1]; + counts[i] = counts[i-1]; + } + } + offsets[n] = offset; + counts[n] = count; + numfrags++; + + /* + * Got that stuffed in right. Figure out if this was the last. + * Record status info out of the last packet. + */ + if (!CTL_ISMORE(rpkt.r_m_e_op)) { + seenlastfrag = 1; + if (rstatus != 0) + *rstatus = ntohs(rpkt.status); + } + + /* + * Copy the data into the data buffer. + */ + bcopy((char *)rpkt.data, (char *)pktdata + offset, count); + + /* + * If we've seen the last fragment, look for holes in the sequence. + * If there aren't any, we're done. + */ + if (seenlastfrag && offsets[0] == 0) { + for (n = 1; n < numfrags; n++) { + if (offsets[n-1] + counts[n-1] != offsets[n]) + break; + } + if (n == numfrags) { + *rsize = offsets[numfrags-1] + counts[numfrags-1]; + return 0; + } + } + goto again; + +overlap: + /* + * Print debugging message about overlapping fragments + */ + if (debug) + printf("Overlapping fragments returned in response\n"); + goto again; +} + + +/* + * sendrequest - format and send a request packet + */ +static int +sendrequest(opcode, associd, auth, qsize, qdata) + int opcode; + int associd; + int auth; + int qsize; + char *qdata; +{ + struct ntp_control qpkt; + int pktsize; + + /* + * Check to make sure the data will fit in one packet + */ + if (qsize > CTL_MAX_DATA_LEN) { + (void) fprintf(stderr, + "***Internal error! qsize (%d) too large\n", + qsize); + return 1; + } + + /* + * Fill in the packet + */ + qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); + qpkt.r_m_e_op = (u_char)opcode & CTL_OP_MASK; + qpkt.sequence = htons(sequence); + qpkt.status = 0; + qpkt.associd = htons((u_short)associd); + qpkt.offset = 0; + qpkt.count = htons((u_short)qsize); + + /* + * If we have data, copy it in and pad it out to a 64 + * bit boundary. + */ + if (qsize > 0) { + bcopy(qdata, (char *)qpkt.data, qsize); + pktsize = qsize + CTL_HEADER_LEN; + while (pktsize & (sizeof(U_LONG)-1)) { + qpkt.data[qsize++] = 0; + pktsize++; + } + } else { + pktsize = CTL_HEADER_LEN; + } + + /* + * If it isn't authenticated we can just send it. Otherwise + * we're going to have to think about it a little. + */ + if (!auth && !always_auth) { + return sendpkt((char *)&qpkt, pktsize); + } else { + char *pass; + + /* + * Pad out packet to a multiple of 8 octets to be sure + * receiver can handle it. + */ + while (pktsize & 7) { + qpkt.data[qsize++] = 0; + pktsize++; + } + + /* + * Get the keyid and the password if we don't have one. + */ + if (info_auth_keyid == -1) { + info_auth_keyid = getkeyid("Keyid: "); + if (info_auth_keyid == -1) { + (void) fprintf(stderr, + "Keyid must be defined, request not sent\n"); + return 1; + } + } + if (!auth_havekey(info_auth_keyid)) { + pass = getpass("Password: "); + if (*pass != '\0') + authusekey(info_auth_keyid, + info_auth_keytype, pass); + } + if (auth_havekey(info_auth_keyid)) { + int maclen; + + /* + * Stick the keyid in the packet where + * cp currently points. Cp should be aligned + * properly. Then do the encryptions. + */ + *(U_LONG *)(&qpkt.data[qsize]) = htonl(info_auth_keyid); + maclen = authencrypt(info_auth_keyid, (U_LONG *)&qpkt, + pktsize); + return sendpkt((char *)&qpkt, pktsize + maclen); + } else { + (void) fprintf(stderr, + "No password, request not sent\n"); + return 1; + } + } + /*NOTREACHED*/ +} + + +/* + * doquery - send a request and process the response + */ +int +doquery(opcode, associd, auth, qsize, qdata, rstatus, rsize, rdata) + int opcode; + int associd; + int auth; + int qsize; + char *qdata; + u_short *rstatus; + int *rsize; + char **rdata; +{ + int res; + int done; + + /* + * Check to make sure host is open + */ + if (!havehost) { + (void) fprintf(stderr, "***No host open, use `host' command\n"); + return -1; + } + + done = 0; + sequence++; + +again: + /* + * send a request + */ + res = sendrequest(opcode, associd, auth, qsize, qdata); + if (res != 0) + return res; + + /* + * Get the response. If we got a standard error, print a message + */ + res = getresponse(opcode, associd, rstatus, rsize, rdata, done); + + if (res > 0) { + if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { + if (res == ERR_INCOMPLETE) { + /* + * better bump the sequence so we don't + * get confused about differing fragments. + */ + sequence++; + } + done = 1; + goto again; + } + switch(res) { + case CERR_BADFMT: + (void) fprintf(stderr, + "***Server reports a bad format request packet\n"); + break; + case CERR_PERMISSION: + (void) fprintf(stderr, + "***Server disallowed request (authentication?)\n"); + break; + case CERR_BADOP: + (void) fprintf(stderr, + "***Server reports a bad opcode in request\n"); + break; + case CERR_BADASSOC: + (void) fprintf(stderr, + "***Association ID %d unknown to server\n",associd); + break; + case CERR_UNKNOWNVAR: + (void) fprintf(stderr, + "***A request variable was unknown to the server\n"); + break; + case CERR_BADVALUE: + (void) fprintf(stderr, + "***Server indicates a request variable was bad\n"); + break; + case ERR_UNSPEC: + (void) fprintf(stderr, + "***Server returned an unspecified error\n"); + break; + case ERR_TIMEOUT: + (void) fprintf(stderr, "***Request timed out\n"); + break; + case ERR_INCOMPLETE: + (void) fprintf(stderr, + "***Response from server was incomplete\n"); + break; + case ERR_TOOMUCH: + (void) fprintf(stderr, + "***Buffer size exceeded for returned data\n"); + break; + default: + (void) fprintf(stderr, + "***Server returns unknown error code %d\n", res); + break; + } + } + return res; +} + + +/* + * getcmds - read commands from the standard input and execute them + */ +static void +getcmds() +{ + char line[MAXLINE]; + + for (;;) { + if (interactive) { + (void) fputs(prompt, stderr); + (void) fflush(stderr); + } + + if (fgets(line, sizeof line, stdin) == NULL) + return; + + docmd(line); + } +} + + +/* + * abortcmd - catch interrupts and abort the current command + */ +static RETSIGTYPE +abortcmd(sig) +int sig; +{ + if (current_output == stdout) + (void) fflush(stdout); + putc('\n', stderr); + (void) fflush(stderr); + if (jump) longjmp(interrupt_buf, 1); +} + + +/* + * docmd - decode the command line and execute a command + */ +static void +docmd(cmdline) + char *cmdline; +{ + char *tokens[1+MAXARGS+2]; + struct parse pcmd; + int ntok; + static int i; + struct xcmd *xcmd; + + /* + * Tokenize the command line. If nothing on it, return. + */ + tokenize(cmdline, tokens, &ntok); + if (ntok == 0) + return; + + /* + * Find the appropriate command description. + */ + i = findcmd(tokens[0], builtins, opcmds, &xcmd); + if (i == 0) { + (void) fprintf(stderr, "***Command `%s' unknown\n", + tokens[0]); + return; + } else if (i >= 2) { + (void) fprintf(stderr, "***Command `%s' ambiguous\n", + tokens[0]); + return; + } + + /* + * Save the keyword, then walk through the arguments, interpreting + * as we go. + */ + pcmd.keyword = tokens[0]; + pcmd.nargs = 0; + for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { + if ((i+1) >= ntok) { + if (!(xcmd->arg[i] & OPT)) { + printusage(xcmd, stderr); + return; + } + break; + } + if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) + break; + if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) + return; + pcmd.nargs++; + } + + i++; + if (i < ntok && *tokens[i] == '>') { + char *fname; + + if (*(tokens[i]+1) != '\0') + fname = tokens[i]+1; + else if ((i+1) < ntok) + fname = tokens[i+1]; + else { + (void) fprintf(stderr, "***No file for redirect\n"); + return; + } + + current_output = fopen(fname, "w"); + if (current_output == NULL) { + (void) fprintf(stderr, "***Error opening %s: ", fname); + perror(""); + return; + } + i = 1; /* flag we need a close */ + } else { + current_output = stdout; + i = 0; /* flag no close */ + } + + if (interactive && setjmp(interrupt_buf)) { + return; + } else { + jump++; + (xcmd->handler)(&pcmd, current_output); + if (i) (void) fclose(current_output); + } +} + + +/* + * tokenize - turn a command line into tokens + */ +static void +tokenize(line, tokens, ntok) + char *line; + char **tokens; + int *ntok; +{ + register char *cp; + register char *sp; + static char tspace[MAXLINE]; + + sp = tspace; + cp = line; + for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { + tokens[*ntok] = sp; + while (ISSPACE(*cp)) + cp++; + if (ISEOL(*cp)) + break; + do { + *sp++ = *cp++; + } while (!ISSPACE(*cp) && !ISEOL(*cp)); + + *sp++ = '\0'; + } +} + + + +/* + * findcmd - find a command in a command description table + */ +static int +findcmd(str, clist1, clist2, cmd) + register char *str; + struct xcmd *clist1; + struct xcmd *clist2; + struct xcmd **cmd; +{ + register struct xcmd *cl; + register int clen; + int nmatch; + struct xcmd *nearmatch = NULL; + struct xcmd *clist; + + clen = strlen(str); + nmatch = 0; + if (clist1 != 0) + clist = clist1; + else if (clist2 != 0) + clist = clist2; + else + return 0; + +again: + for (cl = clist; cl->keyword != 0; cl++) { + /* do a first character check, for efficiency */ + if (*str != *(cl->keyword)) + continue; + if (strncmp(str, cl->keyword, clen) == 0) { + /* + * Could be extact match, could be approximate. + * Is exact if the length of the keyword is the + * same as the str. + */ + if (*((cl->keyword) + clen) == '\0') { + *cmd = cl; + return 1; + } + nmatch++; + nearmatch = cl; + } + } + + /* + * See if there is more to do. If so, go again. Sorry about the + * goto, too much looking at BSD sources... + */ + if (clist == clist1 && clist2 != 0) { + clist = clist2; + goto again; + } + + /* + * If we got extactly 1 near match, use it, else return number + * of matches. + */ + if (nmatch == 1) { + *cmd = nearmatch; + return 1; + } + return nmatch; +} + + +/* + * getarg - interpret an argument token + */ +static int +getarg(str, code, argp) + char *str; + int code; + arg_v *argp; +{ + int isneg; + char *cp, *np; + static char *digits = "0123456789"; + + switch (code & ~OPT) { + case STR: + argp->string = str; + break; + case ADD: + if (!getnetnum(str, &(argp->netnum), (char *)0)) { + return 0; + } + break; + case INT: + case UINT: + isneg = 0; + np = str; + if (*np == '&') { + np++; + isneg = atoi(np); + if (isneg <= 0) { + (void) fprintf(stderr, + "***Association value `%s' invalid/undecodable\n", str); + return 0; + } + if (isneg > numassoc) { + (void) fprintf(stderr, + "***Association for `%s' unknown (max &%d)\n", + str, numassoc); + return 0; + } + argp->uval = assoc_cache[isneg-1].assid; + break; + } + + if (*np == '-') { + np++; + isneg = 1; + } + + argp->uval = 0; + do { + cp = strchr(digits, *np); + if (cp == NULL) { + (void) fprintf(stderr, + "***Illegal integer value %s\n", str); + return 0; + } + argp->uval *= 10; + argp->uval += (cp - digits); + } while (*(++np) != '\0'); + + if (isneg) { + if ((code & ~OPT) == UINT) { + (void) fprintf(stderr, + "***Value %s should be unsigned\n", str); + return 0; + } + argp->ival = -argp->ival; + } + break; + } + + return 1; +} + + +/* + * getnetnum - given a host name, return its net number + * and (optional) full name + */ +int +getnetnum(host, num, fullhost) + char *host; + U_LONG *num; + char *fullhost; +{ + struct hostent *hp; + + if (decodenetnum(host, num)) { + if (fullhost != 0) { + (void) sprintf(fullhost, + "%d.%d.%d.%d", ((htonl(*num)>>24)&0xff), + ((htonl(*num)>>16)&0xff), ((htonl(*num)>>8)&0xff), + (htonl(*num)&0xff)); + } + return 1; + } else if ((hp = gethostbyname(host)) != 0) { + bcopy(hp->h_addr, (char *)num, sizeof(U_LONG)); + if (fullhost != 0) + (void) strcpy(fullhost, hp->h_name); + return 1; + } else { + (void) fprintf(stderr, "***Can't find host %s\n", host); + return 0; + } + /*NOTREACHED*/ +} + +/* + * nntohost - convert network number to host name. This routine enforces + * the showhostnames setting. + */ +char * +nntohost(netnum) + U_LONG netnum; +{ + if (!showhostnames) + return numtoa(netnum); + if ((ntohl(netnum) & REFCLOCK_MASK) == REFCLOCK_ADDR) + return refnumtoa(netnum); + return numtohost(netnum); +} + + +/* + * rtdatetolfp - decode an RT-11 date into an l_fp + */ +static int +rtdatetolfp(str, lfp) + char *str; + l_fp *lfp; +{ + register char *cp; + register int i; + struct calendar cal; + char buf[4]; + static char *months[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + cal.yearday = 0; + + /* + * An RT-11 date looks like: + * + * d[d]-Mth-y[y] hh:mm:ss + */ + cp = str; + if (!isdigit(*cp)) { + if (*cp == '-') { + /* + * Catch special case + */ + lfp->l_ui = lfp->l_uf = 0; + return 1; + } + return 0; + } + + cal.monthday = *cp++ - '0'; /* ascii dependent */ + if (isdigit(*cp)) { + cal.monthday = (cal.monthday << 3) + (cal.monthday << 1); + cal.monthday += *cp++ - '0'; + } + + if (*cp++ != '-') + return 0; + + for (i = 0; i < 3; i++) + buf[i] = *cp++; + buf[3] = '\0'; + + for (i = 0; i < 12; i++) + if (STREQ(buf, months[i])) + break; + if (i == 12) + return 0; + cal.month = i + 1; + + if (*cp++ != '-') + return 0; + + if (!isdigit(*cp)) + return 0; + cal.year = *cp++ - '0'; + if (isdigit(*cp)) { + cal.year = (cal.year << 3) + (cal.year << 1); + cal.year += *cp++ - '0'; + } + + /* + * Catch special case. If cal.year == 0 this is a zero timestamp. + */ + if (cal.year == 0) { + lfp->l_ui = lfp->l_uf = 0; + return 1; + } + + if (*cp++ != ' ' || !isdigit(*cp)) + return 0; + cal.hour = *cp++ - '0'; + if (isdigit(*cp)) { + cal.hour = (cal.hour << 3) + (cal.hour << 1); + cal.hour += *cp++ - '0'; + } + + if (*cp++ != ':' || !isdigit(*cp)) + return 0; + cal.minute = *cp++ - '0'; + if (isdigit(*cp)) { + cal.minute = (cal.minute << 3) + (cal.minute << 1); + cal.minute += *cp++ - '0'; + } + + if (*cp++ != ':' || !isdigit(*cp)) + return 0; + cal.second = *cp++ - '0'; + if (isdigit(*cp)) { + cal.second = (cal.second << 3) + (cal.second << 1); + cal.second += *cp++ - '0'; + } + + cal.year += 1900; + lfp->l_ui = caltontp(&cal); + lfp->l_uf = 0; + return 1; +} + + +/* + * decodets - decode a timestamp into an l_fp format number, with + * consideration of fuzzball formats. + */ +int +decodets(str, lfp) + char *str; + l_fp *lfp; +{ + /* + * If it starts with a 0x, decode as hex. + */ + if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) + return hextolfp(str+2, lfp); + + /* + * If it starts with a '"', try it as an RT-11 date. + */ + if (*str == '"') { + register char *cp = str+1; + register char *bp; + char buf[30]; + + bp = buf; + while (*cp != '"' && *cp != '\0' && bp < &buf[29]) + *bp++ = *cp++; + *bp = '\0'; + return rtdatetolfp(buf, lfp); + } + + /* + * Might still be hex. Check out the first character. Talk + * about heuristics! + */ + if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) + return hextolfp(str, lfp); + + /* + * Try it as a decimal. If this fails, try as an unquoted + * RT-11 date. This code should go away eventually. + */ + if (atolfp(str, lfp)) + return 1; + return rtdatetolfp(str, lfp); +} + + +/* + * decodetime - decode a time value. It should be in milliseconds + */ +int +decodetime(str, lfp) + char *str; + l_fp *lfp; +{ + return mstolfp(str, lfp); +} + + +#ifdef UNUSED +/* + * decodereach - decode a (possibly octal or hex, damn fuzzballs) reachability + */ +static int +decodereach(str, uval) + char *str; + U_LONG *uval; +{ + U_LONG u; + + if (*str == '0') { + /* + * Could be octal or hex + */ + if (*(str+1) == 'x' || *(str+1) == 'X') + return hextoint(str+2, uval); + return octtoint(str, uval); + } + + if (!atouint(str, &u)) + return 0; + + if (u > 255) + return octtoint(str, uval); + *uval = u; + return 1; +} +#endif /* UNUSED */ + + +/* + * decodeint - decode an integer + */ +int +decodeint(str, val) + char *str; + LONG *val; +{ + if (*str == '0') { + if (*(str+1) == 'x' || *(str+1) == 'X') + return hextoint(str+2, (U_LONG *)val); + return octtoint(str, (U_LONG *)val); + } + return atoint(str, val); +} + + +/* + * decodeuint - decode an unsigned integer + */ +int +decodeuint(str, val) + char *str; + U_LONG *val; +{ + if (*str == '0') { + if (*(str+1) == 'x' || *(str+1) == 'X') + return hextoint(str+2, val); + return octtoint(str, val); + } + return atouint(str, val); +} + + +/* + * decodearr - decode an array of time values + */ +static int +decodearr(str, narr, lfparr) + char *str; + int *narr; + l_fp *lfparr; +{ + register char *cp, *bp; + register l_fp *lfp; + char buf[60]; + + lfp = lfparr; + cp = str; + *narr = 0; + + while (*narr < 8) { + while (isspace(*cp)) + cp++; + if (*cp == '\0') + break; + + bp = buf; + while (!isspace(*cp) && *cp != '\0') + *bp++ = *cp++; + *bp++ = '\0'; + + if (!decodetime(buf, lfp)) + return 0; + (*narr)++; + lfp++; + } + return 1; +} + + + + +/* + * getcode - return string corresponding to code + */ +static char * +getcode(code, codetab) + int code; + struct codestring *codetab; +{ + static char buf[30]; + + while (codetab->code != -1) { + if (codetab->code == code) + return codetab->string; + codetab++; + } + (void) sprintf(buf, "%s_%d", codetab->string, code); + return buf; +} + + +/* + * Finally, the built in command handlers + */ + +/* + * help - tell about commands, or details of a particular command + */ +static void +help(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int i; + int n; + struct xcmd *xcp; + char *cmd; + char *cmdsort[100]; + int length[100]; + int maxlength; + int numperline; + static char *spaces = " "; /* 20 spaces */ + + if (pcmd->nargs == 0) { + n = 0; + for (xcp = builtins; xcp->keyword != 0; xcp++) { + if (*(xcp->keyword) != '?') + cmdsort[n++] = xcp->keyword; + } + for (xcp = opcmds; xcp->keyword != 0; xcp++) + cmdsort[n++] = xcp->keyword; + +#if defined(sgi) + qsort((void *)cmdsort, n, sizeof(char *), helpsort); +#else + qsort((char *)cmdsort, n, sizeof(char *), helpsort); +#endif /* sgi */ + + maxlength = 0; + for (i = 0; i < n; i++) { + length[i] = strlen(cmdsort[i]); + if (length[i] > maxlength) + maxlength = length[i]; + } + maxlength++; + numperline = 76 / maxlength; + + (void) fprintf(fp, "Commands available:\n"); + for (i = 0; i < n; i++) { + if ((i % numperline) == (numperline-1) + || i == (n-1)) + (void) fprintf(fp, "%s\n", cmdsort[i]); + else + (void) fprintf(fp, "%s%s", cmdsort[i], + spaces+20-maxlength+length[i]); + } + } else { + cmd = pcmd->argval[0].string; + n = findcmd(cmd, builtins, opcmds, &xcp); + if (n == 0) { + (void) fprintf(stderr, + "Command `%s' is unknown\n", cmd); + return; + } else if (n >= 2) { + (void) fprintf(stderr, + "Command `%s' is ambiguous\n", cmd); + return; + } + (void) fprintf(fp, "function: %s\n", xcp->comment); + printusage(xcp, fp); + } +} + + +/* + * helpsort - do hostname qsort comparisons + */ +static int +#if defined(sgi) +helpsort(t1, t2) + const void *t1; + const void *t2; +{ + const char **name1 = (const char **)t1; + const char **name2 = (const char **)t2; +#else +helpsort(name1, name2) + char **name1; + char **name2; +{ +#endif /* sgi */ + return strcmp(*name1, *name2); +} + + +/* + * printusage - print usage information for a command + */ +static void +printusage(xcp, fp) + struct xcmd *xcp; + FILE *fp; +{ + register int i; + + (void) fprintf(fp, "usage: %s", xcp->keyword); + for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { + if (xcp->arg[i] & OPT) + (void) fprintf(fp, " [ %s ]", xcp->desc[i]); + else + (void) fprintf(fp, " %s", xcp->desc[i]); + } + (void) fprintf(fp, "\n"); +} + + +/* + * timeout - set time out time + */ +static void +timeout(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int val; + + if (pcmd->nargs == 0) { + val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000; + (void) fprintf(fp, "primary timeout %d ms\n", val); + } else { + tvout.tv_sec = pcmd->argval[0].uval / 1000; + tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000)) + * 1000; + } +} + + +/* + * delay - set delay for auth requests + */ +static void +delay(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int isneg; + U_LONG val; + + if (pcmd->nargs == 0) { + val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; + (void) fprintf(fp, "delay %d ms\n", val); + } else { + if (pcmd->argval[0].ival < 0) { + isneg = 1; + val = (U_LONG)(-pcmd->argval[0].ival); + } else { + isneg = 0; + val = (U_LONG)pcmd->argval[0].ival; + } + + delay_time.l_ui = val / 1000; + val %= 1000; + delay_time.l_uf = val * 4294967; /* 2**32/1000 */ + + if (isneg) + L_NEG(&delay_time); + } +} + + +/* + * host - set the host we are dealing with. + */ +static void +host(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) { + if (havehost) + (void) fprintf(fp, "current host is %s\n", currenthost); + else + (void) fprintf(fp, "no current host\n"); + } else if (openhost(pcmd->argval[0].string)) { + (void) fprintf(fp, "current host set to %s\n", currenthost); + numassoc = 0; + } else { + if (havehost) + (void) fprintf(fp, + "current host remains %s\n", currenthost); + else + (void) fprintf(fp, "still no current host\n"); + } +} + + +/* + * poll - do one (or more) polls of the host via NTP + */ +/*ARGSUSED*/ +static void +ntp_poll(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + (void) fprintf(fp, "poll not implemented yet\n"); +} + + +/* + * keyid - get a keyid to use for authenticating requests + */ +static void +keyid(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) { + if (info_auth_keyid == -1) + (void) fprintf(fp, "no keyid defined\n"); + else + (void) fprintf(fp, "keyid is %u\n", info_auth_keyid); + } else { + info_auth_keyid = pcmd->argval[0].uval; + } +} + +/* + * keytype - get type of key to use for authenticating requests + */ +static void +keytype(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) + fprintf(fp, "keytype is %s", + (info_auth_keytype == KEY_TYPE_MD5) ? "md5" : "des"); + else + switch (*(pcmd->argval[0].string)) { + case 'm': + case 'M': + info_auth_keytype = KEY_TYPE_MD5; + break; + + case 'd': + case 'D': + info_auth_keytype = KEY_TYPE_DES; + break; + + default: + fprintf(fp, "keytype must be 'md5' or 'des'\n"); + } +} + + + +/* + * passwd - get an authentication key + */ +/*ARGSUSED*/ +static void +passwd(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + char *pass; + + if (info_auth_keyid == -1) { + info_auth_keyid = getkeyid("Keyid: "); + if (info_auth_keyid == -1) { + (void)fprintf(fp, "Keyid must be defined\n"); + return; + } + } + pass = getpass("Password: "); + if (*pass == '\0') + (void) fprintf(fp, "Password unchanged\n"); + else + authusekey(info_auth_keyid, info_auth_keytype, pass); +} + + +/* + * hostnames - set the showhostnames flag + */ +static void +hostnames(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) { + if (showhostnames) + (void) fprintf(fp, "hostnames being shown\n"); + else + (void) fprintf(fp, "hostnames not being shown\n"); + } else { + if (STREQ(pcmd->argval[0].string, "yes")) + showhostnames = 1; + else if (STREQ(pcmd->argval[0].string, "no")) + showhostnames = 0; + else + (void)fprintf(stderr, "What?\n"); + } +} + + + +/* + * setdebug - set/change debugging level + */ +static void +setdebug(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) { + (void) fprintf(fp, "debug level is %d\n", debug); + return; + } else if (STREQ(pcmd->argval[0].string, "no")) { + debug = 0; + } else if (STREQ(pcmd->argval[0].string, "more")) { + debug++; + } else if (STREQ(pcmd->argval[0].string, "less")) { + debug--; + } else { + (void) fprintf(fp, "What?\n"); + return; + } + (void) fprintf(fp, "debug level set to %d\n", debug); +} + + +/* + * quit - stop this nonsense + */ +/*ARGSUSED*/ +static void +quit(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (havehost) + (void) close(sockfd); /* cleanliness next to godliness */ + exit(0); +} + + +/* + * version - print the current version number + */ +/*ARGSUSED*/ +static void +version(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + extern char *Version; + + (void) fprintf(fp, "%s\n", Version); +} + + +/* + * raw - set raw mode output + */ +/*ARGSUSED*/ +static void +raw(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + rawmode = 1; + (void) fprintf(fp, "Output set to raw\n"); +} + + +/* + * cooked - set cooked mode output + */ +/*ARGSUSED*/ +static void +cooked(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + rawmode = 0; + (void) fprintf(fp, "Output set to cooked\n"); + return; +} + + +/* + * authenticate - always authenticate requests to this host + */ +static void +authenticate(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) { + if (always_auth) { + (void) fprintf(fp, + "authenticated requests being sent\n"); + } else + (void) fprintf(fp, + "unauthenticated requests being sent\n"); + } else { + if (STREQ(pcmd->argval[0].string, "yes")) { + always_auth = 1; + } else if (STREQ(pcmd->argval[0].string, "no")) { + always_auth = 0; + } else + (void)fprintf(stderr, "What?\n"); + } +} + + +/* + * ntpversion - choose the NTP version to use + */ +static void +ntpversion(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) { + (void) fprintf(fp, + "NTP version being claimed is %d\n", pktversion); + } else { + if (pcmd->argval[0].uval <= NTP_OLDVERSION + || pcmd->argval[0].uval > NTP_VERSION) { + (void) fprintf(stderr, "versions %d to %d, please\n", + NTP_OLDVERSION+1, NTP_VERSION); + } else { + pktversion = pcmd->argval[0].uval; + } + } +} + + +/* + * warning - print a warning message + */ +static void +warning(fmt, st1, st2) + char *fmt; + char *st1; + char *st2; +{ + (void) fprintf(stderr, "%s: ", progname); + (void) fprintf(stderr, fmt, st1, st2); + (void) fprintf(stderr, ": "); + perror(""); +} + + +/* + * error - print a message and exit + */ +static void +error(fmt, st1, st2) + char *fmt; + char *st1; + char *st2; +{ + warning(fmt, st1, st2); + exit(1); +} + +/* + * getkeyid - prompt the user for a keyid to use + */ +static U_LONG +getkeyid(prompt) +char *prompt; +{ + register char *p; + register c; + FILE *fi; + char pbuf[20]; + + if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) + fi = stdin; + else + setbuf(fi, (char *)NULL); + fprintf(stderr, "%s", prompt); fflush(stderr); + for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) { + if (p < &pbuf[18]) + *p++ = c; + } + *p = '\0'; + if (fi != stdin) + fclose(fi); + if (strcmp(pbuf, "0") == 0) + return 0; + + return (U_LONG) atoi(pbuf); +} + + +/* + * atoascii - printable-ize possibly ascii data using the character + * transformations cat -v uses. + */ +static void +atoascii(length, data, outdata) + int length; + char *data; + char *outdata; +{ + register u_char *cp; + register u_char *ocp; + register u_char c; + + if (!data) + { + *outdata = '\0'; + return; + } + + ocp = (u_char *)outdata; + for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) { + c = *cp; + if (c == '\0') + break; + if (c == '\0') + break; + if (c > 0177) { + *ocp++ = 'M'; + *ocp++ = '-'; + c &= 0177; + } + + if (c < ' ') { + *ocp++ = '^'; + *ocp++ = c + '@'; + } else if (c == 0177) { + *ocp++ = '^'; + *ocp++ = '?'; + } else { + *ocp++ = c; + } + if (ocp >= ((u_char *)outdata + length - 4)) + break; + } + *ocp++ = '\0'; +} + + + +/* + * makeascii - print possibly ascii data using the character + * transformations that cat -v uses. + */ +static void +makeascii(length, data, fp) + int length; + char *data; + FILE *fp; +{ + register u_char *cp; + register int c; + + for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) { + c = (int)*cp; + if (c > 0177) { + putc('M', fp); + putc('-', fp); + c &= 0177; + } + + if (c < ' ') { + putc('^', fp); + putc(c+'@', fp); + } else if (c == 0177) { + putc('^', fp); + putc('?', fp); + } else { + putc(c, fp); + } + } +} + + +/* + * asciize - same thing as makeascii except add a newline + */ +void +asciize(length, data, fp) + int length; + char *data; + FILE *fp; +{ + makeascii(length, data, fp); + putc('\n', fp); +} + + +/* + * Some circular buffer space + */ +#define CBLEN 80 +#define NUMCB 6 + +char circ_buf[NUMCB][CBLEN]; +int nextcb = 0; + + +/* + * getevents - return a descriptive string for the event count + */ +static char * +getevents(cnt) + int cnt; +{ + static char buf[20]; + + if (cnt == 0) + return "no events"; + (void) sprintf(buf, "%d event%s", cnt, (cnt==1) ? "" : "s"); + return buf; +} + + +/* + * statustoa - return a descriptive string for a peer status + */ +static char * +statustoa(type, st) + int type; + int st; +{ + char *cb; + u_char pst; + + cb = &circ_buf[nextcb][0]; + if (++nextcb >= NUMCB) + nextcb = 0; + + switch (type) { + case TYPE_SYS: + (void)strcpy(cb, getcode(CTL_SYS_LI(st), leap_codes)); + (void)strcat(cb, ", "); + (void)strcat(cb, getcode(CTL_SYS_SOURCE(st), sync_codes)); + (void)strcat(cb, ", "); + (void)strcat(cb, getevents(CTL_SYS_NEVNT(st))); + (void)strcat(cb, ", "); + (void)strcat(cb, getcode(CTL_SYS_EVENT(st), sys_codes)); + break; + + case TYPE_PEER: + /* + * Handcraft the bits + */ + pst = CTL_PEER_STATVAL(st); + if (!(pst & CTL_PST_REACH)) { + (void)strcpy(cb, "unreach"); + } else { + (void)strcpy(cb, "reach"); +#if 0 + if (!(pst & CTL_PST_DISP)) { + (void)strcat(cb, ", hi_disp"); + } else { + if (pst & CTL_PST_SANE) { + if ((pst & 0x3) == CTL_PST_SEL_REJECT) + (void)strcat(cb, ", sane"); + } else { + (void)strcat(cb, ", insane"); + } + } +#endif + } + if (pst & CTL_PST_CONFIG) + (void)strcat(cb, ", conf"); + if (pst & CTL_PST_AUTHENABLE) { + if (!(pst & CTL_PST_REACH) || (pst & CTL_PST_AUTHENTIC)) + (void)strcat(cb, ", auth"); + else + (void)strcat(cb, ", unauth"); + } + + /* + * Now the codes + */ + if ((pst & 0x7) != CTL_PST_SEL_REJECT) { + (void)strcat(cb, ", "); + (void)strcat(cb, getcode(pst & 0x7, select_codes)); + } + (void)strcat(cb, ", "); + (void)strcat(cb, getevents(CTL_PEER_NEVNT(st))); + if (CTL_PEER_EVENT(st) != EVNT_UNSPEC) { + (void)strcat(cb, ", "); + (void)strcat(cb, getcode(CTL_PEER_EVENT(st), + peer_codes)); + } + break; + + case TYPE_CLOCK: + (void)strcpy(cb, getcode(((st)>>8) & 0xff, clock_codes)); + (void)strcat(cb, ", last_"); + (void)strcat(cb, getcode((st) & 0xff, clock_codes)); + break; + } + return cb; +} + + +/* + * nextvar - find the next variable in the buffer + */ +int +nextvar(datalen, datap, vname, vvalue) + int *datalen; + char **datap; + char **vname; + char **vvalue; +{ + register char *cp; + register char *np; + register char *cpend; + static char name[MAXVARLEN]; + static char value[MAXVALLEN]; + + cp = *datap; + cpend = cp + *datalen; + + /* + * Space past commas and white space + */ + while (cp < cpend && (*cp == ',' || isspace(*cp))) + cp++; + if (cp == cpend) + return 0; + + /* + * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace + * over any white space and terminate it. + */ + np = name; + while (cp < cpend && *cp != ',' && *cp != '=' + && *cp != '\r' && *cp != '\n') + *np++ = *cp++; + while (isspace(*(np-1))) + np--; + *np = '\0'; + *vname = name; + + /* + * Check if we hit the end of the buffer or a ','. If so we are done. + */ + if (cp == cpend || *cp == ',' || *cp == '\r' || *cp == '\n') { + if (cp != cpend) + cp++; + *datap = cp; + *datalen = cpend - cp; + *vvalue = (char *)0; + return 1; + } + + /* + * So far, so good. Copy out the value + */ + cp++; /* past '=' */ + while (cp < cpend && (isspace(*cp) && *cp != '\r' && *cp != '\n')) + cp++; + np = value; + while (cp < cpend && *cp != ',') + *np++ = *cp++; + while (np > value && isspace(*(np-1))) + np--; + *np = '\0'; + + /* + * Return this. All done. + */ + if (cp != cpend) + cp++; + *datap = cp; + *datalen = cpend - cp; + *vvalue = value; + return 1; +} + + +/* + * findvar - see if this variable is known to us + */ +int +findvar(varname, varlist) + char *varname; + struct ctl_var *varlist; +{ + register char *np; + register struct ctl_var *vl; + + vl = varlist; + np = varname; + while (vl->fmt != EOV) { + if (vl->fmt != PADDING && STREQ(np, vl->text)) + return vl->code; + vl++; + } + return 0; +} + + + +/* + * printvars - print variables returned in response packet + */ +void +printvars(length, data, status, sttype, fp) + int length; + char *data; + int status; + int sttype; + FILE *fp; +{ + if (rawmode) + rawprint(sttype, length, data, status, fp); + else + cookedprint(sttype, length, data, status, fp); +} + + +/* + * rawprint - do a printout of the data in raw mode + */ +static void +rawprint(datatype, length, data, status, fp) + int datatype; + int length; + char *data; + int status; + FILE *fp; +{ + register char *cp; + register char *cpend; + + /* + * Essentially print the data as is. We reformat unprintables, though. + */ + cp = data; + cpend = data + length; + + (void) fprintf(fp, "status=%04x %s\n", status, + statustoa(datatype, status)); + + while (cp < cpend) { + if (*cp == '\r') { + /* + * If this is a \r and the next character is a + * \n, supress this, else pretty print it. Otherwise + * just output the character. + */ + if (cp == (cpend-1) || *(cp+1) != '\n') + makeascii(1, cp, fp); + } else if (isspace(*cp) || isprint(*cp)) { + putc(*cp, fp); + } else { + makeascii(1, cp, fp); + } + cp++; + } +} + + +/* + * Global data used by the cooked output routines + */ +int out_chars; /* number of characters output */ +int out_linecount; /* number of characters output on this line */ + + +/* + * startoutput - get ready to do cooked output + */ +static void +startoutput() +{ + out_chars = 0; + out_linecount = 0; +} + + +/* + * output - output a variable=value combination + */ +static void +output(fp, name, value) + FILE *fp; + char *name; + char *value; +{ + int lenname; + int lenvalue; + + lenname = strlen(name); + lenvalue = strlen(value); + + if (out_chars != 0) { + putc(',', fp); + out_chars++; + out_linecount++; + if ((out_linecount + lenname + lenvalue + 3) > MAXOUTLINE) { + putc('\n', fp); + out_chars++; + out_linecount = 0; + } else { + putc(' ', fp); + out_chars++; + out_linecount++; + } + } + + fputs(name, fp); + putc('=', fp); + fputs(value, fp); + out_chars += lenname + 1 + lenvalue; + out_linecount += lenname + 1 + lenvalue; +} + + +/* + * endoutput - terminate a block of cooked output + */ +static void +endoutput(fp) + FILE *fp; +{ + if (out_chars != 0) + putc('\n', fp); +} + + +/* + * outputarr - output an array of values + */ +static void +outputarr(fp, name, narr, lfp) + FILE *fp; + char *name; + int narr; + l_fp *lfp; +{ + register char *bp; + register char *cp; + register int i; + register int len; + char buf[256]; + + bp = buf; + /* + * Hack to align delay and offset values + */ + if ((int)strlen(name) < 10) + *bp++ = ' '; + + for (i = narr; i > 0; i--) { + if (i != narr) + *bp++ = ' '; + cp = lfptoms(lfp, 2); + len = strlen(cp); + while (len < 7) { + *bp++ = ' '; + len++; + } + while (*cp != '\0') + *bp++ = *cp++; + lfp++; + } + *bp = '\0'; + output(fp, name, buf); +} + + + +/* + * cookedprint - output variables in cooked mode + */ +static void +cookedprint(datatype, length, data, status, fp) + int datatype; + int length; + char *data; + int status; + FILE *fp; +{ + register int varid; + char *name; + char *value; + int output_raw; + int fmt; + struct ctl_var *varlist; + l_fp lfp; + LONG ival; + U_LONG uval; + l_fp lfparr[8]; + int narr; + + switch (datatype) { + case TYPE_PEER: + varlist = peer_var; + break; + case TYPE_SYS: + varlist = sys_var; + break; + case TYPE_CLOCK: + varlist = clock_var; + break; + default: + (void) fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n", datatype); + return; + break; + } + + (void) fprintf(fp, "status=%04x %s\n", status, + statustoa(datatype, status)); + + startoutput(); + while (nextvar(&length, &data, &name, &value)) { + varid = findvar(name, varlist); + if (varid == 0) { + output_raw = '*'; + } else { + output_raw = 0; + switch((fmt = varlist[varid].fmt)) { + case TS: + if (!decodets(value, &lfp)) + output_raw = '?'; + else + output(fp, name, prettydate(&lfp)); + break; + case FL: + case FU: + case FS: + if (!decodetime(value, &lfp)) + output_raw = '?'; + else { + switch (fmt) { + case FL: + output(fp, name, + lfptoms(&lfp, 3)); + break; + case FU: + output(fp, name, + ulfptoms(&lfp, 2)); + break; + case FS: + output(fp, name, + lfptoms(&lfp, 2)); + break; + } + } + break; + + case UI: + if (!decodeuint(value, &uval)) + output_raw = '?'; + else + output(fp, name, uinttoa(uval)); + break; + + case IN: + if (!decodeint(value, &ival)) + output_raw = '?'; + else + output(fp, name, inttoa(ival)); + break; + + case HA: + case NA: + if (!decodenetnum(value, &uval)) + output_raw = '?'; + else if (fmt == HA) + output(fp, name, nntohost(uval)); + else + output(fp, name, numtoa(uval)); + break; + + case ST: + output_raw = '*'; + break; + + case RF: + if (decodenetnum(value, &uval)) + output(fp, name, nntohost(uval)); + else if ((int)strlen(value) <= 4) + output(fp, name, value); + else + output_raw = '?'; + break; + + case LP: + if (!decodeuint(value, &uval) || uval > 3) + output_raw = '?'; + else { + char b[3]; + b[0] = b[1] = '0'; + if (uval & 0x2) + b[0] = '1'; + if (uval & 0x1) + b[1] = '1'; + b[2] = '\0'; + output(fp, name, b); + } + break; + + case OC: + if (!decodeuint(value, &uval)) + output_raw = '?'; + else { + char b[10]; + + (void) sprintf(b, "%03o", uval); + output(fp, name, b); + } + break; + + case MD: + if (!decodeuint(value, &uval)) + output_raw = '?'; + else + output(fp, name, uinttoa(uval)); + break; + + case AR: + if (!decodearr(value, &narr, lfparr)) + output_raw = '?'; + else + outputarr(fp, name, narr, lfparr); + break; + + default: + (void) fprintf(stderr, + "Internal error in cookedprint, %s=%s, fmt %d\n", + name, value, fmt); + break; + } + + } + if (output_raw != 0) { + char bn[401]; + char bv[401]; + int len; + + atoascii(400, name, bn); + atoascii(400, value, bv); + if (output_raw != '*') { + len = strlen(bv); + bv[len] = output_raw; + bv[len+1] = '\0'; + } + output(fp, bn, bv); + } + } + endoutput(fp); +} + + +/* + * sortassoc - sort associations in the cache into ascending order + */ +void +sortassoc() +{ + if (numassoc > 1) +#if defined(sgi) + qsort((void *)assoc_cache, numassoc, + sizeof(struct association), assoccmp); +#else + qsort((char *)assoc_cache, numassoc, + sizeof(struct association), assoccmp); +#endif /* sgi */ +} + + +/* + * assoccmp - compare two associations + */ +static int +#if defined(sgi) +assoccmp(t1, t2) + const void *t1; + const void *t2; +{ + const struct association *ass1 = (const struct association *)t1; + const struct association *ass2 = (const struct association *)t2; +#else +assoccmp(ass1, ass2) + struct association *ass1; + struct association *ass2; +{ +#endif /* sgi */ + if (ass1->assid < ass2->assid) + return -1; + if (ass1->assid > ass2->assid) + return 1; + return 0; +} diff --git a/contrib/xntpd/ntpq/ntpq.h b/contrib/xntpd/ntpq/ntpq.h new file mode 100644 index 0000000000..edfc9b5990 --- /dev/null +++ b/contrib/xntpd/ntpq/ntpq.h @@ -0,0 +1,97 @@ +/* ntpq.h,v 3.1 1993/07/06 01:09:30 jbj Exp + * ntpq.h - definitions of interest to ntpq + */ +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_control.h" +#include "ntp_string.h" +#include "ntp_malloc.h" + +/* + * Maximum number of arguments + */ +#define MAXARGS 4 + +/* + * Flags for forming descriptors. + */ +#define OPT 0x80 /* this argument is optional, or'd with type */ + +#define NO 0x0 +#define STR 0x1 /* string argument */ +#define UINT 0x2 /* unsigned integer */ +#define INT 0x3 /* signed integer */ +#define ADD 0x4 /* IP network address */ + +/* + * Arguments are returned in a union + */ +typedef union { + char *string; + LONG ival; + U_LONG uval; + U_LONG netnum; +} arg_v; + +/* + * Structure for passing parsed command line + */ +struct parse { + char *keyword; + arg_v argval[MAXARGS]; + int nargs; +}; + +/* + * xntpdc includes a command parser which could charitably be called + * crude. The following structure is used to define the command + * syntax. + */ +struct xcmd { + char *keyword; /* command key word */ + void (*handler) P((struct parse *, FILE *)); /* command handler */ + u_char arg[MAXARGS]; /* descriptors for arguments */ + char *desc[MAXARGS]; /* descriptions for arguments */ + char *comment; +}; + +/* + * Types of things we may deal with + */ +#define TYPE_SYS 1 +#define TYPE_PEER 2 +#define TYPE_CLOCK 3 + + +/* + * Structure to hold association data + */ +struct association { + u_short assid; + u_short status; +}; + +#define MAXASSOC 1024 + +/* + * Structure for translation tables between text format + * variable indices and text format. + */ +struct ctl_var { + u_short code; + u_short fmt; + char *text; +}; + +extern void asciize P((int, char *, FILE *)); +extern int getnetnum P((char *, U_LONG *, char *)); +extern void sortassoc P((void)); +extern int doquery P((int, int, int, int, char *, u_short *, int *, char **)); +extern char * nntohost P((U_LONG)); +extern int decodets P((char *, l_fp *)); +extern int decodeuint P((char *, U_LONG *)); +extern int nextvar P((int *, char **, char **, char **)); +extern int decodetime P((char *, l_fp *)); +extern void printvars P((int, char *, int, int, FILE *)); +extern int decodeint P((char *, LONG *)); +extern int findvar P((char *, struct ctl_var *)); diff --git a/contrib/xntpd/ntpq/ntpq_ops.c b/contrib/xntpd/ntpq/ntpq_ops.c new file mode 100644 index 0000000000..17929ac2f1 --- /dev/null +++ b/contrib/xntpd/ntpq/ntpq_ops.c @@ -0,0 +1,1600 @@ +/* ntpq_ops.c,v 3.1 1993/07/06 01:09:32 jbj Exp + * ntpdc_ops.c - subroutines which are called to perform operations by xntpdc + */ +#include +#include +#include +#include +#include + +#include "ntpq.h" +#include "ntp_stdlib.h" + +extern char * chosts[]; +extern char currenthost[]; +extern int numhosts; +int maxhostlen; + +/* + * Declarations for command handlers in here + */ +static int checkassocid P((U_LONG)); +static char * strsave P((char *)); +static struct varlist *findlistvar P((struct varlist *, char *)); +static void doaddvlist P((struct varlist *, char *)); +static void dormvlist P((struct varlist *, char *)); +static void doclearvlist P((struct varlist *)); +static void makequerydata P((struct varlist *, int *, char *)); +static int doquerylist P((struct varlist *, int, int, int, u_short *, int *, char **)); +static void doprintvlist P((struct varlist *, FILE *)); +static void addvars P((struct parse *, FILE *)); +static void rmvars P((struct parse *, FILE *)); +static void clearvars P((struct parse *, FILE *)); +static void showvars P((struct parse *, FILE *)); +static int dolist P((struct varlist *, int, int, int, FILE *)); +static void readlist P((struct parse *, FILE *)); +static void writelist P((struct parse *, FILE *)); +static void readvar P((struct parse *, FILE *)); +static void writevar P((struct parse *, FILE *)); +static void clocklist P((struct parse *, FILE *)); +static void clockvar P((struct parse *, FILE *)); +static int findassidrange P((U_LONG, U_LONG, int *, int *)); +static void mreadlist P((struct parse *, FILE *)); +static void mreadvar P((struct parse *, FILE *)); +static int dogetassoc P((FILE *)); +static void printassoc P((int, FILE *)); +static void associations P((struct parse *, FILE *)); +static void lassociations P((struct parse *, FILE *)); +static void passociations P((struct parse *, FILE *)); +static void lpassociations P((struct parse *, FILE *)); + +#ifdef UNUSED +static void radiostatus P((struct parse *, FILE *)); +#endif /* UNUSED */ + +static void pstatus P((struct parse *, FILE *)); +static char * fixup P((int, char *)); +static char * when P((l_fp *, l_fp *, l_fp *)); +static int doprintpeers P((struct varlist *, int, int, int, char *, FILE *)); +static int dogetpeers P((struct varlist *, int, FILE *)); +static void dopeers P((int, FILE *)); +static void peers P((struct parse *, FILE *)); +static void lpeers P((struct parse *, FILE *)); +static void doopeers P((int, FILE *)); +static void opeers P((struct parse *, FILE *)); +static void lopeers P((struct parse *, FILE *)); + + +/* + * Commands we understand. Ntpdc imports this. + */ +struct xcmd opcmds[] = { + { "associations", associations, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print list of association ID's and statuses for the server's peers" }, + { "passociations", passociations, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print list of associations returned by last associations command" }, + { "lassociations", lassociations, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print list of associations including all client information" }, + { "lpassociations", lpassociations, { NO, NO, NO, NO }, + { "", "", "", "" }, +"print last obtained list of associations, including client information" }, + { "addvars", addvars, { STR, NO, NO, NO }, + { "name[=value][,...]", "", "", "" }, + "add variables to the variable list or change their values" }, + { "rmvars", rmvars, { STR, NO, NO, NO }, + { "name[,...]", "", "", "" }, + "remove variables from the variable list" }, + { "clearvars", clearvars, { NO, NO, NO, NO }, + { "", "", "", "" }, + "remove all variables from the variable list" }, + { "showvars", showvars, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print variables on the variable list" }, + { "readlist", readlist, { OPT|UINT, NO, NO, NO }, + { "assocID", "", "", "" }, + "read the system or peer variables included in the variable list" }, + { "rl", readlist, { OPT|UINT, NO, NO, NO }, + { "assocID", "", "", "" }, + "read the system or peer variables included in the variable list" }, + { "writelist", writelist, { OPT|UINT, NO, NO, NO }, + { "assocID", "", "", "" }, + "write the system or peer variables included in the variable list" }, + { "readvar", readvar, { OPT|UINT, OPT|STR, NO, NO }, + { "assocID", "name=value[,...]", "", "" }, + "read system or peer variables" }, + { "rv", readvar, { OPT|UINT, OPT|STR, NO, NO }, + { "assocID", "name=value[,...]", "", "" }, + "read system or peer variables" }, + { "writevar", writevar, { UINT, STR, NO, NO }, + { "assocID", "name=value,[...]", "", "" }, + "write system or peer variables" }, + { "mreadlist", mreadlist, { UINT, UINT, NO, NO }, + { "assocID", "assocID", "", "" }, + "read the peer variables in the variable list for multiple peers" }, + { "mrl", mreadlist, { UINT, UINT, NO, NO }, + { "assocID", "assocID", "", "" }, + "read the peer variables in the variable list for multiple peers" }, + { "mreadvar", mreadvar, { UINT, UINT, OPT|STR, NO }, + { "assocID", "assocID", "name=value[,...]", "" }, + "read peer variables from multiple peers" }, + { "mrv", mreadvar, { UINT, UINT, OPT|STR, NO }, + { "assocID", "assocID", "name=value[,...]", "" }, + "read peer variables from multiple peers" }, + { "clocklist", clocklist, { OPT|UINT, NO, NO, NO }, + { "assocID", "", "", "" }, + "read the clock variables included in the variable list" }, + { "cl", clocklist, { OPT|UINT, NO, NO, NO }, + { "assocID", "", "", "" }, + "read the clock variables included in the variable list" }, + { "clockvar", clockvar, { OPT|UINT, OPT|STR, NO, NO }, + { "assocID", "name=value[,...]", "", "" }, + "read clock variables" }, + { "cv", clockvar, { OPT|UINT, OPT|STR, NO, NO }, + { "assocID", "name=value[,...]", "", "" }, + "read clock variables" }, + { "pstatus", pstatus, { UINT, NO, NO, NO }, + { "assocID", "", "", "" }, + "print status information returned for a peer" }, + { "peers", peers, { NO, NO, NO, NO }, + { "", "", "", "" }, + "obtain and print a list of the server's peers" }, + { "lpeers", lpeers, { NO, NO, NO, NO }, + { "", "", "", "" }, + "obtain and print a list of all peers and clients" }, + { "opeers", opeers, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print peer list the old way, with dstadr shown rather than refid" }, + { "lopeers", lopeers, { NO, NO, NO, NO }, + { "", "", "", "" }, + "obtain and print a list of all peers and clients showing dstadr" }, + { 0, 0, { NO, NO, NO, NO }, + { "", "", "", "" }, "" } +}; + + +/* + * Variable list data space + */ +#define MAXLIST 64 /* maximum number of variables in list */ +#define LENHOSTNAME 256 /* host name is 256 characters LONG */ +/* + * Old CTL_PST defines for version 2. + */ +#define OLD_CTL_PST_CONFIG 0x80 +#define OLD_CTL_PST_AUTHENABLE 0x40 +#define OLD_CTL_PST_AUTHENTIC 0x20 +#define OLD_CTL_PST_REACH 0x10 +#define OLD_CTL_PST_SANE 0x08 +#define OLD_CTL_PST_DISP 0x04 +#define OLD_CTL_PST_SEL_REJECT 0 +#define OLD_CTL_PST_SEL_SELCAND 1 +#define OLD_CTL_PST_SEL_SYNCCAND 2 +#define OLD_CTL_PST_SEL_SYSPEER 3 + + +char flash2[] = " .+* "; /* flash decode for version 2 */ +char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */ + +struct varlist { + char *name; + char *value; +} varlist[MAXLIST] = { { 0, 0 } }; + +/* + * Imported from ntpq.c + */ +extern int showhostnames; +extern int rawmode; +extern int debug; +extern struct servent *server_entry; +extern struct association assoc_cache[]; +extern int numassoc; +extern u_char pktversion; + +/* + * For quick string comparisons + */ +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + + +/* + * checkassocid - return the association ID, checking to see if it is valid + */ +static int +checkassocid(value) + U_LONG value; +{ + if (value == 0 || value >= 65536) { + (void) fprintf(stderr, "***Invalid association ID specified\n"); + return 0; + } + return (int)value; +} + + +/* + * strsave - save a string + */ +static char * +strsave(str) + char *str; +{ + char *cp; + u_int len; + + len = strlen(str) + 1; + if ((cp = (char *)malloc(len)) == NULL) { + (void) fprintf(stderr, "Malloc failed!!\n"); + exit(1); + } + + bcopy(str, cp, len); + return cp; +} + + +/* + * findlistvar - look for the named variable in a list and return if found + */ +static struct varlist * +findlistvar(list, name) + struct varlist *list; + char *name; +{ + register struct varlist *vl; + + for (vl = list; vl < list + MAXLIST && vl->name != 0; vl++) + if (STREQ(name, vl->name)) + return vl; + if (vl < list + MAXLIST) + return vl; + return (struct varlist *)0; +} + + +/* + * doaddvlist - add variable(s) to the variable list + */ +static void +doaddvlist(vlist, vars) + struct varlist *vlist; + char *vars; +{ + register struct varlist *vl; + int len; + char *name; + char *value; + + len = strlen(vars); + while (nextvar(&len, &vars, &name, &value)) { + vl = findlistvar(vlist, name); + if (vl == 0) { + (void) fprintf(stderr, "Variable list full\n"); + return; + } + + if (vl->name == 0) { + vl->name = strsave(name); + } else if (vl->value != 0) { + (void) free(vl->value); + vl->value = 0; + } + + if (value != 0) + vl->value = strsave(value); + } +} + + +/* + * dormvlist - remove variable(s) from the variable list + */ +static void +dormvlist(vlist, vars) + struct varlist *vlist; + char *vars; +{ + register struct varlist *vl; + int len; + char *name; + char *value; + + len = strlen(vars); + while (nextvar(&len, &vars, &name, &value)) { + vl = findlistvar(vlist, name); + if (vl == 0 || vl->name == 0) { + (void) fprintf(stderr, "Variable `%s' not found\n", + name); + } else { + (void) free(vl->name); + if (vl->value != 0) + (void) free(vl->value); + for ( ; (vl+1) < (varlist+MAXLIST) + && (vl+1)->name != 0; vl++) { + vl->name = (vl+1)->name; + vl->value = (vl+1)->value; + } + vl->name = vl->value = 0; + } + } +} + + +/* + * doclearvlist - clear a variable list + */ +static void +doclearvlist(vlist) + struct varlist *vlist; +{ + register struct varlist *vl; + + for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) { + (void) free(vl->name); + vl->name = 0; + if (vl->value != 0) { + (void) free(vl->value); + vl->value = 0; + } + } +} + + +/* + * makequerydata - form a data buffer to be included with a query + */ +static void +makequerydata(vlist, datalen, data) + struct varlist *vlist; + int *datalen; + char *data; +{ + register struct varlist *vl; + register char *cp, *cpend; + register int namelen, valuelen; + register int totallen; + + cp = data; + cpend = data + *datalen; + + for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) { + namelen = strlen(vl->name); + if (vl->value == 0) + valuelen = 0; + else + valuelen = strlen(vl->value); + totallen = namelen + valuelen + (valuelen != 0) + (cp != data); + if (cp + totallen > cpend) + break; + + if (cp != data) + *cp++ = ','; + bcopy(vl->name, cp, namelen); + cp += namelen; + if (valuelen != 0) { + *cp++ = '='; + bcopy(vl->value, cp, valuelen); + cp += valuelen; + } + } + *datalen = cp - data; +} + + +/* + * doquerylist - send a message including variables in a list + */ +static int +doquerylist(vlist, op, associd, auth, rstatus, dsize, datap) + struct varlist *vlist; + int op; + int associd; + int auth; + u_short *rstatus; + int *dsize; + char **datap; +{ + char data[CTL_MAX_DATA_LEN]; + int datalen; + + datalen = sizeof(data); + makequerydata(vlist, &datalen, data); + + return doquery(op, associd, auth, datalen, data, rstatus, + dsize, datap); +} + + +/* + * doprintvlist - print the variables on a list + */ +static void +doprintvlist(vlist, fp) + struct varlist *vlist; + FILE *fp; +{ + register struct varlist *vl; + + if (vlist->name == 0) { + (void) fprintf(fp, "No variables on list\n"); + } else { + for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) { + if (vl->value == 0) { + (void) fprintf(fp, "%s\n", vl->name); + } else { + (void) fprintf(fp, "%s=%s\n", + vl->name, vl->value); + } + } + } +} + + +/* + * addvars - add variables to the variable list + */ +/*ARGSUSED*/ +static void +addvars(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + doaddvlist(varlist, pcmd->argval[0].string); +} + + +/* + * rmvars - remove variables from the variable list + */ +/*ARGSUSED*/ +static void +rmvars(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + dormvlist(varlist, pcmd->argval[0].string); +} + + +/* + * clearvars - clear the variable list + */ +/*ARGSUSED*/ +static void +clearvars(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + doclearvlist(varlist); +} + + +/* + * showvars - show variables on the variable list + */ +/*ARGSUSED*/ +static void +showvars(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + doprintvlist(varlist, fp); +} + + +/* + * dolist - send a request with the given list of variables + */ +static int +dolist(vlist, associd, op, type, fp) + struct varlist *vlist; + int associd; + int op; + int type; + FILE *fp; +{ + char *datap; + int res; + int dsize; + u_short rstatus; + + res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap); + + if (res != 0) + return 0; + + if (dsize == 0) { + if (associd == 0) + (void) fprintf(fp, "No system%s variables returned\n", + (type == TYPE_CLOCK) ? " clock" : ""); + else + (void) fprintf(fp, + "No information returned for%s association %u\n", + (type == TYPE_CLOCK) ? " clock" : "", associd); + return 1; + } + + printvars(dsize, datap, (int)rstatus, type, fp); + return 1; +} + + +/* + * readlist - send a read variables request with the variables on the list + */ +static void +readlist(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int associd; + + if (pcmd->nargs == 0) { + associd = 0; + } else { + if (pcmd->argval[0].uval == 0) + associd = 0; + else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) + return; + } + + (void) dolist(varlist, associd, CTL_OP_READVAR, + (associd == 0) ? TYPE_SYS : TYPE_PEER, fp); +} + + +/* + * writelist - send a write variables request with the variables on the list + */ +static void +writelist(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + char *datap; + int res; + int associd; + int dsize; + u_short rstatus; + + if (pcmd->nargs == 0) { + associd = 0; + } else { + if (pcmd->argval[0].uval == 0) + associd = 0; + else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) + return; + } + + res = doquerylist(varlist, CTL_OP_WRITEVAR, associd, 0, &rstatus, + &dsize, &datap); + + if (res != 0) + return; + + if (dsize == 0) + (void) fprintf(fp, "done! (no data returned)\n"); + else + printvars(dsize, datap, (int)rstatus, + (associd != 0) ? TYPE_PEER : TYPE_SYS, fp); + return; +} + + +/* + * readvar - send a read variables request with the specified variables + */ +static void +readvar(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int associd; + struct varlist tmplist[MAXLIST]; + + if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0) + associd = 0; + else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) + return; + + bzero((char *)tmplist, sizeof(tmplist)); + if (pcmd->nargs >= 2) + doaddvlist(tmplist, pcmd->argval[1].string); + + (void) dolist(tmplist, associd, CTL_OP_READVAR, + (associd == 0) ? TYPE_SYS : TYPE_PEER, fp); + + doclearvlist(tmplist); +} + + +/* + * writevar - send a write variables request with the specified variables + */ +static void +writevar(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + char *datap; + int res; + int associd; + int dsize; + u_short rstatus; + struct varlist tmplist[MAXLIST]; + + if (pcmd->argval[0].uval == 0) + associd = 0; + else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) + return; + + bzero((char *)tmplist, sizeof(tmplist)); + doaddvlist(tmplist, pcmd->argval[1].string); + + res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 0, &rstatus, + &dsize, &datap); + + doclearvlist(tmplist); + + if (res != 0) + return; + + if (dsize == 0) + (void) fprintf(fp, "done! (no data returned)\n"); + else + printvars(dsize, datap, (int)rstatus, + (associd != 0) ? TYPE_PEER : TYPE_SYS, fp); + return; +} + + +/* + * clocklist - send a clock variables request with the variables on the list + */ +static void +clocklist(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int associd; + + if (pcmd->nargs == 0) { + associd = 0; + } else { + if (pcmd->argval[0].uval == 0) + associd = 0; + else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) + return; + } + + (void) dolist(varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp); +} + + +/* + * clockvar - send a clock variables request with the specified variables + */ +static void +clockvar(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int associd; + struct varlist tmplist[MAXLIST]; + + if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0) + associd = 0; + else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) + return; + + bzero((char *)tmplist, sizeof(tmplist)); + if (pcmd->nargs >= 2) + doaddvlist(tmplist, pcmd->argval[1].string); + + (void) dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp); + + doclearvlist(tmplist); +} + + +/* + * findassidrange - verify a range of association ID's + */ +static int +findassidrange(assid1, assid2, from, to) + U_LONG assid1; + U_LONG assid2; + int *from; + int *to; +{ + register int i; + int f, t; + + if (assid1 == 0 || assid1 > 65535) { + (void) fprintf(stderr, + "***Invalid association ID %lu specified\n", assid1); + return 0; + } + + if (assid2 == 0 || assid2 > 65535) { + (void) fprintf(stderr, + "***Invalid association ID %lu specified\n", assid2); + return 0; + } + + f = t = -1; + for (i = 0; i < numassoc; i++) { + if (assoc_cache[i].assid == assid1) { + f = i; + if (t != -1) + break; + } + if (assoc_cache[i].assid == assid2) { + t = i; + if (f != -1) + break; + } + } + + if (f == -1 || t == -1) { + (void) fprintf(stderr, + "***Association ID %lu not found in list\n", + (f == -1) ? assid1 : assid2); + return 0; + } + + if (f < t) { + *from = f; + *to = t; + } else { + *from = t; + *to = f; + } + return 1; +} + + + +/* + * mreadlist - send a read variables request for multiple associations + */ +static void +mreadlist(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int i; + int from; + int to; + + if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval, + &from, &to)) + return; + + for (i = from; i <= to; i++) { + if (i != from) + (void) fprintf(fp, "\n"); + if (!dolist(varlist, (int)assoc_cache[i].assid, + CTL_OP_READVAR, TYPE_PEER, fp)) + return; + } + return; +} + + +/* + * mreadvar - send a read variables request for multiple associations + */ +static void +mreadvar(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int i; + int from; + int to; + struct varlist tmplist[MAXLIST]; + + if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval, + &from, &to)) + return; + + bzero((char *)tmplist, sizeof(tmplist)); + if (pcmd->nargs >= 3) + doaddvlist(tmplist, pcmd->argval[2].string); + + for (i = from; i <= to; i++) { + if (i != from) + (void) fprintf(fp, "\n"); + if (!dolist(varlist, (int)assoc_cache[i].assid, + CTL_OP_READVAR, TYPE_PEER, fp)) + break; + } + doclearvlist(tmplist); + return; +} + + +/* + * dogetassoc - query the host for its list of associations + */ +static int +dogetassoc(fp) + FILE *fp; +{ + u_short *datap; + int res; + int dsize; + u_short rstatus; + + res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus, + &dsize, (char **)&datap); + + if (res != 0) + return 0; + + if (dsize == 0) { + (void) fprintf(fp, "No association ID's returned\n"); + return 0; + } + + if (dsize & 0x3) { + (void) fprintf(stderr, + "***Server returned %d octets, should be multiple of 4\n", + dsize); + return 0; + } + + numassoc = 0; + while (dsize > 0) { + assoc_cache[numassoc].assid = ntohs(*datap); + datap++; + assoc_cache[numassoc].status = ntohs(*datap); + datap++; + if (++numassoc >= MAXASSOC) + break; + dsize -= sizeof(u_short) + sizeof(u_short); + } + sortassoc(); + return 1; +} + + +/* + * printassoc - print the current list of associations + */ +static void +printassoc(showall, fp) + int showall; + FILE *fp; +{ + register char *bp; + int i; + u_char statval; + int event; + U_LONG event_count; + char *conf; + char *reach; + char *auth; + char *condition = ""; + char *last_event; + char *cnt; + char buf[128]; + + if (numassoc == 0) { + (void) fprintf(fp, "No association ID's in list\n"); + return; + } + + /* + * Output a header + */ + (void) fprintf(fp, + "ind assID status conf reach auth condition last_event cnt\n"); + (void) fprintf(fp, + "===========================================================\n"); + for (i = 0; i < numassoc; i++) { + statval = CTL_PEER_STATVAL(assoc_cache[i].status); + if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH))) + continue; + event = CTL_PEER_EVENT(assoc_cache[i].status); + event_count = CTL_PEER_NEVNT(assoc_cache[i].status); + if (statval & CTL_PST_CONFIG) + conf = "yes"; + else + conf = "no"; + if (statval & CTL_PST_REACH) { + reach = "yes"; + if (statval & CTL_PST_AUTHENABLE) { + if (statval & CTL_PST_AUTHENTIC) + auth = "ok "; + else + auth = "bad"; + } else + auth = "none"; + + if (pktversion == NTP_VERSION) + switch (statval & 0x7) { + case CTL_PST_SEL_REJECT: + condition = "insane"; + break; + case CTL_PST_SEL_SANE: + condition = "falsetick"; + break; + case CTL_PST_SEL_CORRECT: + condition = "eliminate"; + break; + case CTL_PST_SEL_SELCAND: + condition = "outlyer"; + break; + case CTL_PST_SEL_SYNCCAND: + condition = "synchr."; + break; + case CTL_PST_SEL_DISTSYSPEER: + condition = "dist.peer"; + break; + case CTL_PST_SEL_SYSPEER: + condition = "sys.peer"; + break; + case CTL_PST_SEL_PPS: + condition = "pps.peer"; + break; + } + else + switch (statval & 0x3) { + case OLD_CTL_PST_SEL_REJECT: + if (!(statval & OLD_CTL_PST_SANE)) + condition = "insane"; + else if (!(statval & OLD_CTL_PST_DISP)) + condition = "hi_disp"; + else + condition = ""; + break; + case OLD_CTL_PST_SEL_SELCAND: + condition = "sel_cand"; + break; + case OLD_CTL_PST_SEL_SYNCCAND: + condition = "sync_cand"; + break; + case OLD_CTL_PST_SEL_SYSPEER: + condition = "sys.peer"; + break; + } + + } else { + reach = "no"; + auth = condition = ""; + } + + switch (PEER_EVENT|event) { + case EVNT_PEERIPERR: + last_event = "IP error"; + break; + case EVNT_PEERAUTH: + last_event = "auth fail"; + break; + case EVNT_UNREACH: + last_event = "lost reach"; + break; + case EVNT_REACH: + last_event = "reachable"; + break; + case EVNT_PEERCLOCK: + last_event = "clock expt"; + break; +#if 0 + case EVNT_PEERSTRAT: + last_event = "stratum chg"; + break; +#endif + default: + last_event = ""; + break; + } + + if (event_count != 0) + cnt = uinttoa(event_count); + else + cnt = ""; + (void) sprintf(buf, + "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2s", + i+1, assoc_cache[i].assid, assoc_cache[i].status, + conf, reach, auth, condition, last_event, cnt); + bp = &buf[strlen(buf)]; + while (bp > buf && *(bp-1) == ' ') + *(--bp) = '\0'; + (void) fprintf(fp, "%s\n", buf); + } +} + + + +/* + * associations - get, record and print a list of associations + */ +/*ARGSUSED*/ +static void +associations(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (dogetassoc(fp)) + printassoc(0, fp); +} + + +/* + * lassociations - get, record and print a LONG list of associations + */ +/*ARGSUSED*/ +static void +lassociations(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (dogetassoc(fp)) + printassoc(1, fp); +} + + +/* + * passociations - print the association list + */ +/*ARGSUSED*/ +static void +passociations(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + printassoc(0, fp); +} + + +/* + * lpassociations - print the LONG association list + */ +/*ARGSUSED*/ +static void +lpassociations(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + printassoc(1, fp); +} + + +#ifdef UNUSED +/* + * radiostatus - print the radio status returned by the server + */ +/*ARGSUSED*/ +static void +radiostatus(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + char *datap; + int res; + int dsize; + u_short rstatus; + + res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus, + &dsize, &datap); + + if (res != 0) + return; + + if (dsize == 0) { + (void) fprintf(fp, "No radio status string returned\n"); + return; + } + + asciize(dsize, datap, fp); +} +#endif /* UNUSED */ + +/* + * pstatus - print peer status returned by the server + */ +static void +pstatus(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + char *datap; + int res; + int associd; + int dsize; + u_short rstatus; + + if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) + return; + + res = doquery(CTL_OP_READSTAT, associd, 0, 0, (char *)0, &rstatus, + &dsize, &datap); + + if (res != 0) + return; + + if (dsize == 0) { + (void) fprintf(fp, + "No information returned for association %u\n", + associd); + return; + } + + printvars(dsize, datap, (int)rstatus, TYPE_PEER, fp); +} + + +/* + * fixup - fix up a string so we don't get a hanging decimal after it + */ +static char * +fixup(width, str) + int width; + char *str; +{ + if (str[width-1] == '.') + str[width-1] = '\0'; + return str; +} + + +/* + * when - print how LONG its been since his last packet arrived + */ +static char * +when(ts, rec, reftime) + l_fp *ts; + l_fp *rec; + l_fp *reftime; +{ + LONG diff; + l_fp *lasttime; + static char buf[20]; + + if (rec->l_ui != 0) + lasttime = rec; + else if (reftime->l_ui != 0) + lasttime = reftime; + else + return "-"; + + diff = (LONG)(ts->l_ui - lasttime->l_ui); + if (diff <= 0) { + /* + * Time warp? + */ + diff = 1; + } + + if (diff <= 2048) { + (void) sprintf(buf, "%d", diff); + return buf; + } + + diff = (diff + 29) / 60; + if (diff <= 300) { + (void) sprintf(buf, "%dm", diff); + return buf; + } + + diff = (diff + 29) / 60; + if (diff <= 96) { + (void) sprintf(buf, "%dh", diff); + return buf; + } + + diff = (diff + 11) / 24; + (void) sprintf(buf, "%dd", diff); + return buf; +} + + + +/* + * A list of variables required by the peers command + */ +struct varlist opeervarlist[] = { + { "srcadr", 0 }, /* 0 */ + { "dstadr", 0 }, /* 1 */ + { "stratum", 0 }, /* 2 */ + { "hpoll", 0 }, /* 3 */ + { "ppoll", 0 }, /* 4 */ + { "reach", 0 }, /* 5 */ + { "delay", 0 }, /* 6 */ + { "offset", 0 }, /* 7 */ + { "dispersion", 0 }, /* 8 */ + { "rec", 0 }, /* 9 */ + { "reftime", 0 }, /* 10 */ + { "srcport", 0 }, /* 11 */ + { 0, 0 } +}; + +struct varlist peervarlist[] = { + { "srcadr", 0 }, /* 0 */ + { "refid", 0 }, /* 1 */ + { "stratum", 0 }, /* 2 */ + { "hpoll", 0 }, /* 3 */ + { "ppoll", 0 }, /* 4 */ + { "reach", 0 }, /* 5 */ + { "delay", 0 }, /* 6 */ + { "offset", 0 }, /* 7 */ + { "dispersion", 0 }, /* 8 */ + { "rec", 0 }, /* 9 */ + { "reftime", 0 }, /* 10 */ + { "srcport", 0 }, /* 11 */ + { 0, 0 } +}; + +#define HAVE_SRCADR 0 +#define HAVE_DSTADR 1 +#define HAVE_REFID 1 +#define HAVE_STRATUM 2 +#define HAVE_HPOLL 3 +#define HAVE_PPOLL 4 +#define HAVE_REACH 5 +#define HAVE_DELAY 6 +#define HAVE_OFFSET 7 +#define HAVE_DISPERSION 8 +#define HAVE_REC 9 +#define HAVE_REFTIME 10 +#define HAVE_SRCPORT 11 +#define MAXHAVE 12 + +/* + * Decode an incoming data buffer and print a line in the peer list + */ +static int +doprintpeers(pvl, associd, rstatus, datalen, data, fp) + struct varlist *pvl; + int associd; + int rstatus; + int datalen; + char *data; + FILE *fp; +{ + char *name; + char *value; + int i; + int c; + + U_LONG srcadr; + U_LONG dstadr; + U_LONG srcport; + char *dstadr_refid = "0.0.0.0"; + U_LONG stratum; + LONG ppoll; + LONG hpoll; + U_LONG reach; + l_fp estdelay; + l_fp estoffset; + l_fp estdisp; + l_fp rec; + l_fp reftime; + l_fp ts; + u_char havevar[MAXHAVE]; + U_LONG poll; + char refid_string[10]; + extern struct ctl_var peer_var[]; + + bzero((char *)havevar, sizeof(havevar)); + gettstamp(&ts); + + while (nextvar(&datalen, &data, &name, &value)) { + i = findvar(name, peer_var); + if (i == 0) + continue; /* don't know this one */ + switch (i) { + case CP_SRCADR: + if (decodenetnum(value, &srcadr)) + havevar[HAVE_SRCADR] = 1; + break; + case CP_DSTADR: + if (pvl == opeervarlist) { + if (decodenetnum(value, &dstadr)) { + havevar[HAVE_DSTADR] = 1; + dstadr_refid = numtoa(dstadr); + } + } + break; + case CP_REFID: + if (pvl == peervarlist) { + havevar[HAVE_REFID] = 1; + if (*value == '\0') { + dstadr_refid = "0.0.0.0"; + } else if (decodenetnum(value, &dstadr)) { + if (dstadr == 0) + dstadr_refid = "0.0.0.0"; + else + dstadr_refid = nntohost(dstadr); + } else if ((int)strlen(value) <= 4) { + refid_string[0] = '.'; + (void) strcpy(&refid_string[1], value); + i = strlen(refid_string); + refid_string[i] = '.'; + refid_string[i+1] = '\0'; + dstadr_refid = refid_string; + } else { + havevar[HAVE_REFID] = 0; + } + } + break; + case CP_STRATUM: + if (decodeuint(value, &stratum)) + havevar[HAVE_STRATUM] = 1; + break; + case CP_HPOLL: + if (decodeint(value, &hpoll)) { + havevar[HAVE_HPOLL] = 1; + if (hpoll < 0) + hpoll = NTP_MINPOLL; + } + break; + case CP_PPOLL: + if (decodeint(value, &ppoll)) { + havevar[HAVE_PPOLL] = 1; + if (ppoll < 0) + ppoll = NTP_MINPOLL; + } + break; + case CP_REACH: + if (decodeuint(value, &reach)) + havevar[HAVE_REACH] = 1; + break; + case CP_DELAY: + if (decodetime(value, &estdelay)) + havevar[HAVE_DELAY] = 1; + break; + case CP_OFFSET: + if (decodetime(value, &estoffset)) + havevar[HAVE_OFFSET] = 1; + break; + case CP_DISPERSION: + if (decodetime(value, &estdisp)) + havevar[HAVE_DISPERSION] = 1; + break; + case CP_REC: + if (decodets(value, &rec)) + havevar[HAVE_REC] = 1; + break; + case CP_SRCPORT: + if (decodeuint(value, &srcport)) + havevar[HAVE_SRCPORT] = 1; + break; + case CP_REFTIME: + havevar[HAVE_REFTIME] = 1; + if (!decodets(value, &reftime)) + reftime.l_ui = reftime.l_uf = 0; + break; + default: + break; + } + } + + /* + * Check to see if the srcport is NTP's port. If not this probably + * isn't a valid peer association. + */ + if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT) + return 1; + + /* + * Check to see if we got all of them. If not, return an + * error. + */ + for (i = 0; i < MAXHAVE; i++) + if (!havevar[i]) { + (void) fprintf(stderr, + "***Remote host didn't return peer.%s for association %d\n", + pvl[i].name, associd); + return 0; + } + + + /* + * Got everything, format the line + */ + poll = 1< 1) + (void) fprintf(fp, "%-*s ", maxhostlen, currenthost); + (void) fprintf(fp, + "%c%-15.15s %-15.15s %2d %4.4s %4d %3o %7.7s %7.7s %7.7s\n", + c, nntohost(srcadr), dstadr_refid, stratum, + when(&ts, &rec, &reftime), + poll, reach, fixup(7, lfptoms(&estdelay, 2)), + fixup(7, lfptoms(&estoffset, 2)), + fixup(7, lfptoms(&estdisp, 2))); + return 1; +} + +#undef HAVE_SRCADR +#undef HAVE_DSTADR +#undef HAVE_STRATUM +#undef HAVE_PPOLL +#undef HAVE_HPOLL +#undef HAVE_REACH +#undef HAVE_ESTDELAY +#undef HAVE_ESTOFFSET +#undef HAVE_ESTDISP +#undef HAVE_REFID +#undef HAVE_REC +#undef HAVE_SRCPORT +#undef HAVE_REFTIME +#undef MAXHAVE + + +/* + * dogetpeers - given an association ID, read and print the spreadsheet + * peer variables. + */ +static int +dogetpeers(pvl, associd, fp) + struct varlist *pvl; + int associd; + FILE *fp; +{ + char *datap; + int res; + int dsize; + u_short rstatus; + +#ifdef notdef + res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus, + &dsize, &datap); +#else + /* + * Damn fuzzballs + */ + res = doquery(CTL_OP_READVAR, associd, 0, 0, (char *)0, &rstatus, + &dsize, &datap); +#endif + + if (res != 0) + return 0; + + if (dsize == 0) { + (void) fprintf(stderr, + "***No information returned for association %d\n", + associd); + return 0; + } + + + return doprintpeers(pvl, associd, (int)rstatus, dsize, datap, fp); +} + + +/* + * peers - print a peer spreadsheet + */ +static void +dopeers(showall, fp) + int showall; + FILE *fp; +{ + register int i; + char fullname[LENHOSTNAME]; + U_LONG netnum; + + + if (!dogetassoc(fp)) + return; + + for (i = 0; i < numhosts; ++i) + { if(getnetnum(chosts[i],&netnum,fullname)) + if ((int)strlen(fullname) > maxhostlen) + maxhostlen = strlen(fullname); + } + if (numhosts > 1) + (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "host"); + (void) fprintf(fp, +" remote refid st when poll reach delay offset disp\n"); + if (numhosts > 1) + for (i = 0; i <= maxhostlen; ++i) + (void) fprintf(fp, "="); + (void) fprintf(fp, +"===========================================================================\n"); + + for (i = 0; i < numassoc; i++) { + if (!showall && + !(CTL_PEER_STATVAL(assoc_cache[i].status) + & (CTL_PST_CONFIG|CTL_PST_REACH))) + continue; + if (!dogetpeers(peervarlist, (int)assoc_cache[i].assid, fp)) { + return; + } + } + return; +} + + +/* + * peers - print a peer spreadsheet + */ +/*ARGSUSED*/ +static void +peers(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + dopeers(0, fp); +} + + +/* + * lpeers - print a peer spreadsheet including all fuzzball peers + */ +/*ARGSUSED*/ +static void +lpeers(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + dopeers(1, fp); +} + + +/* + * opeers - print a peer spreadsheet + */ +static void +doopeers(showall, fp) + int showall; + FILE *fp; +{ + register int i; + + if (!dogetassoc(fp)) + return; + + (void) fprintf(fp, +" remote local st when poll reach delay offset disp\n"); + (void) fprintf(fp, +"=========================================================================\n"); + + for (i = 0; i < numassoc; i++) { + if (!showall && + !(CTL_PEER_STATVAL(assoc_cache[i].status) + & (CTL_PST_CONFIG|CTL_PST_REACH))) + continue; + if (!dogetpeers(opeervarlist, (int)assoc_cache[i].assid, fp)) { + return; + } + } + return; +} + + +/* + * opeers - print a peer spreadsheet the old way + */ +/*ARGSUSED*/ +static void +opeers(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + doopeers(0, fp); +} + + +/* + * lopeers - print a peer spreadsheet including all fuzzball peers + */ +/*ARGSUSED*/ +static void +lopeers(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + doopeers(1, fp); +} diff --git a/contrib/xntpd/ntptrace/Makefile.tmpl b/contrib/xntpd/ntptrace/Makefile.tmpl new file mode 100644 index 0000000000..c98482da06 --- /dev/null +++ b/contrib/xntpd/ntptrace/Makefile.tmpl @@ -0,0 +1,70 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:09:37 jbj Exp +# +PROGRAM= ntptrace +# +# ntptrace - private mode query program for ntptrace +# +COMPILER= cc +COPTS= -O +BINDIR= /usr/local +INSTALL= install +DEFS= +DEFS_OPT= +DEFS_LOCAL= +RESLIB= +ADJLIB= +COMPAT= +# +INCL= -I../include +CFLAGS= $(COPTS) $(DEFS) $(INCL) +CC= $(COMPILER) +LIB= ../lib/libntp.a +LINTLIB= ../lib/llib-llibntp.ln +MAKE= make +TOP=../ +# +OBJS= ntptrace.o +SOURCE= ntptrace.c + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) $(LIB) version.o + $(CC) $(COPTS) -o $@ $(OBJS) version.o $(LIB) $(RESLIB) \ + $(ADJLIB) $(COMPAT) + +install: $(BINDIR)/$(PROGRAM) + +$(BINDIR)/$(PROGRAM): $(PROGRAM) + $(INSTALL) -c -m 0755 $(PROGRAM) $(BINDIR) + +tags: + ctags *.c *.h + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(PROGRAM) *.o *.out tags make.log Makefile.bak lint.errs .version + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +lint: $(LINTLIB) + lint -x -u $(DEFS) $(DEFS_LOCAL) $(INCL) $(LINTLIB) $(SOURCE) >lint.errs + +../lib/llib-llibntp.ln: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" lintlib + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" + +# +# we want to build the current version string here +# +version.o: ../VERSION + ../scripts/mkversion $(PROGRAM) + $(CC) $(COPTS) $(INCL) -c version.c + +../VERSION: + -@rm -f .version diff --git a/contrib/xntpd/ntptrace/README b/contrib/xntpd/ntptrace/README new file mode 100644 index 0000000000..b976cfdf22 --- /dev/null +++ b/contrib/xntpd/ntptrace/README @@ -0,0 +1,7 @@ +README file for directory ./ntptrace of the NTP Version 3 distribution + +This directory contains the sources for the ntptrace utility program. See +the README and RELNOTES files in the parent directory for directions on +how to make and install this program. The current version number of this +program is in the version.c file. + diff --git a/contrib/xntpd/ntptrace/ntptrace.c b/contrib/xntpd/ntptrace/ntptrace.c new file mode 100644 index 0000000000..57d86ba5ab --- /dev/null +++ b/contrib/xntpd/ntptrace/ntptrace.c @@ -0,0 +1,777 @@ +/* ntptrace.c,v 3.1 1993/07/06 01:09:38 jbj Exp + * ntptrace - show the chain from an NTP host leading back to + * its source of time + * + * Jeffrey Mogul DECWRL 13 January 1993 + * + * Inspired by a script written by Glenn Trewitt + * + * Large portions stolen from ntpdate.c + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef __STDC__ +#include +#else +#include +#endif + +#if defined(SYS_HPUX) +#include +#endif + +#include "ntp_select.h" +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntptrace.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" +#include "ntp_syslog.h" + +/* + * Debugging flag + */ +int debug = 0; + +int nonames = 0; /* if set, don't print hostnames */ + +/* + * Program name. + */ +char *progname; + +/* + * Systemwide parameters and flags + */ +int sys_retries = 5; /* # of retry attempts per server */ +U_LONG sys_timeout = 2; /* timeout time, in seconds */ +struct server **sys_servers; /* the server list */ +int sys_numservers = 0; /* number of servers to poll */ +int sys_maxservers = NTP_MAXSTRATUM+1; /* max number of servers to deal with */ +int sys_version = NTP_OLDVERSION; /* version to poll with */ + +/* + * recvbuf lists + */ +struct recvbuf *freelist; /* free buffers */ +struct recvbuf *fulllist; /* buffers with data */ + +int full_recvbufs; /* number of full ones */ +int free_recvbufs; + +/* + * File descriptor masks etc. for call to select + */ +int fd; +fd_set fdmask; + +/* + * Miscellaneous flags + */ +int verbose = 0; +int always_step = 0; + +extern int errno; + +static void DoTrace P((struct server *)); +static void DoTransmit P((struct server *)); +static int DoReceive P((struct server *)); +static int ReceiveBuf P((struct server *, struct recvbuf *)); +static struct server *addserver P((struct in_addr *)); +static struct server *addservbyname P((char *)); +static void setup_io P((void)); +static void freerecvbuf P((struct recvbuf *)); +static void sendpkt P((struct sockaddr_in *, struct pkt *, int)); +static int getipaddr P((char *, U_LONG *)); +static int decodeipaddr P((char *, U_LONG *)); +static void printserver P((struct server *, FILE *)); +static void printrefid P((FILE *, struct server *)); + +/* + * Main program. Initialize us and loop waiting for I/O and/or + * timer expiries. + */ +void +main(argc, argv) + int argc; + char *argv[]; +{ + struct server *firstserver; + int errflg; + int c; + extern char *optarg; + extern int optind; + extern char *Version; + + errflg = 0; + progname = argv[0]; + + /* + * Decode argument list + */ + while ((c = getopt_l(argc, argv, "do:nr:t:v")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + case 'n': + nonames = 1; + break; + case 'o': + sys_version = atoi(optarg); + break; + case 'r': + sys_retries = atoi(optarg); + if (sys_retries < 1) { + (void)fprintf(stderr, + "%s: retries (%d) too small\n", + progname, sys_retries); + errflg++; + } + break; + case 't': + sys_timeout = atoi(optarg); + if (sys_timeout < 1) { + (void)fprintf(stderr, + "%s: timeout (%d) too short\n", + progname, sys_timeout); + errflg++; + } + break; + case 'v': + verbose = 1; + break; + case '?': + ++errflg; + break; + default: + break; + } + + if (errflg || (argc - optind) > 1) { + (void) fprintf(stderr, + "usage: %s [-vnd] [-r retries] [-t timeout] [server]\n", + progname); + exit(2); + } + + sys_servers = (struct server **) + emalloc(sys_maxservers * sizeof(struct server *)); + + if (debug) { +#ifdef NTP_POSIX_SOURCE + static char buf[BUFSIZ]; + setvbuf(stdout, buf, _IOLBF, BUFSIZ); +#else + setlinebuf(stdout); +#endif + } + + if (debug || verbose) + syslog(LOG_NOTICE, "%s", Version); + + if ((argc - optind) == 1) + firstserver = addservbyname(argv[optind]); + else + firstserver = addservbyname("localhost"); + + if (firstserver == NULL) { + /* a message has already been printed */ + exit(2); + } + + /* + * Initialize the time of day routines and the I/O subsystem + */ + setup_io(); + + DoTrace(firstserver); + + exit(0); +} + +static void +DoTrace(server) +register struct server *server; +{ + int retries = sys_retries; + + if (!verbose) { + if (nonames) + printf("%s: ", ntoa(&server->srcadr)); + else + printf("%s: ", ntohost(&server->srcadr)); + fflush(stdout); + } + while (retries-- > 0) { + DoTransmit(server); + if (DoReceive(server)) + return; + } + if (verbose) { + if (nonames) + printf("%s:\t*Timeout*\n", ntoa(&server->srcadr)); + else + printf("%s:\t*Timeout*\n", ntohost(&server->srcadr)); + } + else + printf("\t*Timeout*\n"); +} + +/* + * Dotransmit - transmit a packet to the given server + */ +static void +DoTransmit(server) +register struct server *server; +{ + struct pkt xpkt; + + if (debug) + printf("DoTransmit(%s)\n", ntoa(&server->srcadr)); + + /* + * Fill in the packet and let 'er rip. + */ + xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC, + sys_version, MODE_CLIENT); + xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC); + xpkt.ppoll = NTP_MINPOLL; + xpkt.precision = NTPTRACE_PRECISION; + xpkt.rootdelay = htonl(NTPTRACE_DISTANCE); + xpkt.rootdispersion = htonl(NTPTRACE_DISP); + xpkt.refid = htonl(NTPTRACE_REFID); + xpkt.reftime.l_ui = xpkt.reftime.l_uf = 0; + xpkt.org.l_ui = xpkt.org.l_uf = 0; + xpkt.rec.l_ui = xpkt.rec.l_uf = 0; + + /* + * just timestamp packet and send it away. + */ + get_systime(&(server->xmt)); + HTONL_FP(&server->xmt, &xpkt.xmt); + sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC); + + if (debug) + printf("DoTransmit to %s\n", ntoa(&(server->srcadr))); +} + +/* + * DoReceive - attempt to receive a packet from a specific server + */ +static int +DoReceive(server) +register struct server *server; +{ + register int n; + fd_set fds; + struct timeval timeout; + l_fp ts; + register struct recvbuf *rb; + int fromlen; + int status; + + /* + * Loop until we see the packet we want or until we time out + */ + for (;;) { + fds = fdmask; + timeout.tv_sec = sys_timeout; + timeout.tv_usec = 0; + n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &timeout); + + if (n == 0) { /* timed out */ + if (debug) + printf("timeout\n"); + return(0); + } + else if (n == -1) { + syslog(LOG_ERR, "select() error: %m"); + return(0); + } + get_systime(&ts); + + if (free_recvbufs == 0) { + syslog(LOG_ERR, "no buffers"); + exit(1); + } + + rb = freelist; + freelist = rb->next; + free_recvbufs--; + + fromlen = sizeof(struct sockaddr_in); + rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt, + sizeof(rb->recv_pkt), 0, + (struct sockaddr *)&rb->srcadr, &fromlen); + if (rb->recv_length == -1) { + rb->next = freelist; + freelist = rb; + free_recvbufs++; + continue; + } + + /* + * Got one. Mark how and when it got here, + * put it on the full list. + */ + rb->recv_time = ts; + rb->next = fulllist; + fulllist = rb; + full_recvbufs++; + + status = ReceiveBuf(server, rb); + + freerecvbuf(rb); + + return(status); + } +} + +/* + * receive - receive and process an incoming frame + * Return 1 on success, 0 on failure + */ +static int +ReceiveBuf(server, rbufp) + struct server *server; + struct recvbuf *rbufp; +{ + register struct pkt *rpkt; + register s_fp di; + register U_LONG t10_ui, t10_uf; + register U_LONG t23_ui, t23_uf; + l_fp org; + l_fp rec; + l_fp ci; + struct server *nextserver; + struct in_addr nextia; + + + if (debug) { + printf("ReceiveBuf(%s, ", ntoa(&server->srcadr)); + printf("%s)\n", ntoa(&rbufp->srcadr)); + } + + /* + * Check to see if the packet basically looks like something + * intended for us. + */ + if (rbufp->recv_length < LEN_PKT_NOMAC) { + if (debug) + printf("receive: packet length %d\n", + rbufp->recv_length); + return(0); /* funny length packet */ + } + if (rbufp->srcadr.sin_addr.s_addr != server->srcadr.sin_addr.s_addr) { + if (debug) + printf("receive: wrong server\n"); + return(0); /* funny length packet */ + } + + rpkt = &(rbufp->recv_pkt); + + if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION) { + if (debug) + printf("receive: version %d\n", PKT_VERSION(rpkt->li_vn_mode)); + return(0); + } + if (PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) { + if (debug) + printf("receive: version %d\n", PKT_VERSION(rpkt->li_vn_mode)); + return(0); + } + + if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER + && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) + || rpkt->stratum > NTP_MAXSTRATUM) { + if (debug) + printf("receive: mode %d stratum %d\n", + PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); + return(0); + } + + /* + * Decode the org timestamp and make sure we're getting a response + * to our last request. + */ + NTOHL_FP(&rpkt->org, &org); + if (!L_ISEQU(&org, &server->xmt)) { + if (debug) + printf("receive: pkt.org and peer.xmt differ\n"); + return(0); + } + + /* + * Looks good. Record info from the packet. + */ + server->leap = PKT_LEAP(rpkt->li_vn_mode); + server->stratum = PKT_TO_STRATUM(rpkt->stratum); + server->precision = rpkt->precision; + server->rootdelay = ntohl(rpkt->rootdelay); + server->rootdispersion = ntohl(rpkt->rootdispersion); + server->refid = rpkt->refid; + NTOHL_FP(&rpkt->reftime, &server->reftime); + NTOHL_FP(&rpkt->rec, &rec); + NTOHL_FP(&rpkt->xmt, &server->org); + + /* + * Make sure the server is at least somewhat sane. If not, try + * again. + */ + if ((rec.l_ui == 0 && rec.l_uf == 0) || !L_ISHIS(&server->org, &rec)) { + return(0); + } + + /* + * Calculate the round trip delay (di) and the clock offset (ci). + * We use the equations (reordered from those in the spec): + * + * d = (t2 - t3) - (t1 - t0) + * c = ((t2 - t3) + (t1 - t0)) / 2 + */ + t10_ui = server->org.l_ui; /* pkt.xmt == t1 */ + t10_uf = server->org.l_uf; + M_SUB(t10_ui, t10_uf, rbufp->recv_time.l_ui, + rbufp->recv_time.l_uf); /* recv_time == t0*/ + + t23_ui = rec.l_ui; /* pkt.rec == t2 */ + t23_uf = rec.l_uf; + M_SUB(t23_ui, t23_uf, org.l_ui, org.l_uf); /* pkt->org == t3 */ + + /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */ + ci.l_ui = t10_ui; + ci.l_uf = t10_uf; + M_ADD(ci.l_ui, ci.l_uf, t23_ui, t23_uf); + M_RSHIFT(ci.l_i, ci.l_uf); + + /* + * Calculate di in t23 in full precision, then truncate + * to an s_fp. + */ + M_SUB(t23_ui, t23_uf, t10_ui, t10_uf); + di = MFPTOFP(t23_ui, t23_uf); + + server->offset = ci; + server->delay = di; + + printserver(server, stdout); + + /* End of recursion if we reach stratum 1 */ + if (server->stratum <= 1) + return(1); + + nextia.s_addr = server->refid; + nextserver = addserver(&nextia); + DoTrace(nextserver); + return(1); +} + +/* XXX ELIMINATE addserver (almost) identical to ntpdate.c, ntptrace.c */ +/* + * addserver - Allocate a new structure for server. + * Returns a pointer to that structure. + */ +static struct server * +addserver(iap) +struct in_addr *iap; +{ + register struct server *server; + static int toomany = 0; + + if (sys_numservers >= sys_maxservers) { + if (!toomany) { + toomany = 1; + syslog(LOG_ERR, + "too many servers (> %d) specified, remainder not used", + sys_maxservers); + } + return(NULL); + } + + server = (struct server *)emalloc(sizeof(struct server)); + bzero((char *)server, sizeof(struct server)); + + server->srcadr.sin_family = AF_INET; + server->srcadr.sin_addr = *iap; + server->srcadr.sin_port = htons(NTP_PORT); + + sys_servers[sys_numservers++] = server; + + return(server); +} +/* + * addservbyname - determine a server's address and allocate a new structure + * for it. Returns a pointer to that structure. + */ +static struct server * +addservbyname(serv) + char *serv; +{ + U_LONG ipaddr; + struct in_addr ia; + + if (!getipaddr(serv, &ipaddr)) { + syslog(LOG_ERR, "can't find host %s\n", serv); + return(NULL); + } + + ia.s_addr = ipaddr; + return(addserver(&ia)); +} + +/* XXX ELIMINATE getrecvbufs (almost) identical to ntpdate.c, ntptrace.c, ntp_io.c */ +/* + * setup_io - initialize I/O data and open socket + */ +static void +setup_io() +{ + register int i; + register struct recvbuf *rb; + + /* + * Init buffer free list and stat counters + */ + rb = (struct recvbuf *) + emalloc((sys_maxservers + 2) * sizeof(struct recvbuf)); + freelist = 0; + for (i = sys_maxservers + 2; i > 0; i--) { + rb->next = freelist; + freelist = rb; + rb++; + } + + fulllist = 0; + full_recvbufs = 0; + free_recvbufs = sys_maxservers + 2; + + /* create a datagram (UDP) socket */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "socket() failed: %m"); + exit(1); + /*NOTREACHED*/ + } + + FD_ZERO(&fdmask); + FD_SET(fd, &fdmask); +} + +/* XXX ELIMINATE freerecvbuf (almost) identical to ntpdate.c, ntptrace.c, ntp_io.c */ +/* + * freerecvbuf - make a single recvbuf available for reuse + */ +static void +freerecvbuf(rb) + struct recvbuf *rb; +{ + rb->next = freelist; + freelist = rb; + free_recvbufs++; +} + + +/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ +/* + * sendpkt - send a packet to the specified destination + */ +static void +sendpkt(dest, pkt, len) + struct sockaddr_in *dest; + struct pkt *pkt; + int len; +{ + int cc; + + cc = sendto(fd, (char *)pkt, len, 0, (struct sockaddr *)dest, + sizeof(struct sockaddr_in)); + if (cc == -1) { + if (errno != EWOULDBLOCK && errno != ENOBUFS) + syslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + } +} + +/* + * getipaddr - given a host name, return its host address + */ +static int +getipaddr(host, num) + char *host; + U_LONG *num; +{ + struct hostent *hp; + + if (decodeipaddr(host, num)) { + return 1; + } else if ((hp = gethostbyname(host)) != 0) { + bcopy(hp->h_addr, (char *)num, sizeof(U_LONG)); + return 1; + } + return 0; +} + +/* + * decodeipaddr - return a host address (this is crude, but careful) + */ +static int +decodeipaddr(num, ipaddr) + char *num; + U_LONG *ipaddr; +{ + register char *cp; + register char *bp; + register int i; + register int temp; + char buf[80]; /* will core dump on really stupid stuff */ + + cp = num; + *ipaddr = 0; + for (i = 0; i < 4; i++) { + bp = buf; + while (isdigit(*cp)) + *bp++ = *cp++; + if (bp == buf) + break; + + if (i < 3) { + if (*cp++ != '.') + break; + } else if (*cp != '\0') + break; + + *bp = '\0'; + temp = atoi(buf); + if (temp > 255) + break; + *ipaddr <<= 8; + *ipaddr += temp; + } + + if (i < 4) + return 0; + *ipaddr = htonl(*ipaddr); + return 1; +} + + +/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */ +/* + * printserver - print detail information for a server + */ +static void +printserver(pp, fp) + register struct server *pp; + FILE *fp; +{ + u_fp synchdist; + + synchdist = pp->rootdispersion + (pp->rootdelay/2); + + if (!verbose) { + (void) fprintf(fp, "stratum %d, offset %s, synch distance %s", + pp->stratum, + lfptoa(&pp->offset, 7), + ufptoa(synchdist, 7)); + if (pp->stratum == 1) { + (void) fprintf(fp, ", refid "); + printrefid(fp, pp); + } + (void) fprintf(fp, "\n"); + return; + } + + (void) fprintf(fp, "server %s, port %d\n", + ntoa(&pp->srcadr), ntohs(pp->srcadr.sin_port)); + + (void) fprintf(fp, "stratum %d, precision %d, leap %c%c\n", + pp->stratum, pp->precision, + pp->leap & 0x2 ? '1' : '0', + pp->leap & 0x1 ? '1' : '0'); + + (void) fprintf(fp, "refid "); + printrefid(fp, pp); + + (void) fprintf(fp, + " delay %s, dispersion %s ", + fptoa(pp->delay, 7), + ufptoa(pp->dispersion, 4)); + (void) fprintf(fp, "offset %s\n", + lfptoa(&pp->offset, 7)); + (void) fprintf(fp, "rootdelay %s, rootdispersion %s", + fptoa(pp->rootdelay, 7), ufptoa(pp->rootdispersion, 4)); + (void) fprintf(fp, ", synch dist %s\n", + ufptoa(synchdist, 7)); + + (void) fprintf(fp, "reference time: %s\n", + prettydate(&pp->reftime)); + (void) fprintf(fp, "originate timestamp: %s\n", + prettydate(&pp->org)); + (void) fprintf(fp, "transmit timestamp: %s\n", + prettydate(&pp->xmt)); + + (void) fprintf(fp, "\n"); + +} + +static void +printrefid(fp, pp) +FILE *fp; +struct server *pp; +{ + char junk[5]; + char *str; + + if (pp->stratum == 1) { + junk[4] = 0; + bcopy((char *)&pp->refid, junk, 4); + str = junk; + (void) fprintf(fp, "'%s'", str); + } else { + if (nonames) { + str = numtoa(pp->refid); + (void) fprintf(fp, "[%s]", str); + } + else { + str = numtohost(pp->refid); + (void) fprintf(fp, "%s", str); + } + } +} + +#if defined(NEED_VSPRINTF) +/* + * This nugget for pre-tahoe 4.3bsd systems + */ +#if !defined(__STDC__) || !__STDC__ +#define const +#endif + +int +vsprintf(str, fmt, ap) + char *str; + const char *fmt; + va_list ap; +{ + FILE f; + int len; + + f._flag = _IOWRT+_IOSTRG; + f._ptr = str; + f._cnt = 32767; + len = _doprnt(fmt, ap, &f); + *f._ptr = 0; + return (len); +} +#endif diff --git a/contrib/xntpd/ntptrace/ntptrace.h b/contrib/xntpd/ntptrace/ntptrace.h new file mode 100644 index 0000000000..3367c226a8 --- /dev/null +++ b/contrib/xntpd/ntptrace/ntptrace.h @@ -0,0 +1,36 @@ +/* ntptrace.h,v 3.1 1993/07/06 01:09:39 jbj Exp + * ntptrace.h - declarations for the ntptrace program + */ + +/* + * The server structure is a much simplified version of the + * peer structure, for ntptrace's use. Since we always send + * in client mode and expect to receive in server mode, this + * leaves only a very limited number of things we need to + * remember about the server. + */ +struct server { + struct sockaddr_in srcadr; /* address of remote host */ + u_char leap; /* leap indicator */ + u_char stratum; /* stratum of remote server */ + s_char precision; /* server's clock precision */ + u_fp rootdelay; /* distance from primary clock */ + u_fp rootdispersion; /* peer clock dispersion */ + U_LONG refid; /* peer reference ID */ + l_fp reftime; /* time of peer's last update */ + l_fp org; /* peer's originate time stamp */ + l_fp xmt; /* transmit time stamp */ + u_fp delay; /* filter estimated delay */ + u_fp dispersion; /* filter estimated dispersion */ + l_fp offset; /* filter estimated clock offset */ +}; + + +/* + * Since ntptrace isn't aware of some of the things that normally get + * put in an NTP packet, we fix some values. + */ +#define NTPTRACE_PRECISION (-6) /* use this precision */ +#define NTPTRACE_DISTANCE FP_SECOND /* distance is 1 sec */ +#define NTPTRACE_DISP FP_SECOND /* so is the dispersion */ +#define NTPTRACE_REFID (0) /* reference ID to use */ diff --git a/contrib/xntpd/parse/Makefile.kernel b/contrib/xntpd/parse/Makefile.kernel new file mode 100644 index 0000000000..36dcf86e72 --- /dev/null +++ b/contrib/xntpd/parse/Makefile.kernel @@ -0,0 +1,71 @@ +# +# very simple makefile (SunOS!) +# +# Possible defines: +# DEBUG_DCF: include debug code (STREAMS mechanism and parsing) +# DEBUG_CD: include signal propagation to sun4c LED (sun4c only) +# +# Possible defines (parsestreams variants only): +# KERNEL: must define +# VDDRV: loadable driver support - recommended +# KARCH: must define at make call for correct kernel module +# (currently only needed for parsestreams variants) +# +KARCH= +DEFS=-DSTREAM -DKERNEL -DVDDRV -D$(KARCH) +MICROTIME=../ppsclock/sys/$(KARCH)/microtime.s + +all: + @if [ -f /kernel/unix ]; then \ + $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" KARCH="`(arch -k) 2>/dev/null || uname -a | awk '{ print $5 }'`" -f Makefile.kernel parse; \ + else \ + $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" KARCH="`(arch -k) 2>/dev/null || uname -a | awk '{ print $5 }'`" -f Makefile.kernel parsestreams.o; \ + fi + +parse: parsesolaris.c libparse_kernel.a ../lib/libntp.a + @echo "--- WARNING: SunOS5 support is fresh and hardly tested" + @echo "--- This code could lead to kernel panics more" + @echo "--- easily than other streams modules" + $(CC) -c -I../include -D_KERNEL parsesolaris.c + ld -r -o parse parsesolaris.o libparse_kernel.a ../lib/libntp.a + @echo "--- Install 'parse' in /kernel/strmod for automatic loading" + +mparsestreams.o: parsestreams.c microtime.o ../lib/libntp.a libparse_kernel.a ../include/parse.h ../include/sys/parsestreams.h + cc -c -DMICROTIME $(DEFS) -I../include parsestreams.c + ld -r -o $@ parsestreams.o ../lib/libntp.a libparse_kernel.a \ + microtime.o + rm -f parsestreams.o + @echo "--- You may load mparsestreams.o via 'modload mparsestreams.o' into the kernel" + +parsestreams.o: parsestreams.c ../lib/libntp.a libparse_kernel.a ../include/parse.h ../include/sys/parsestreams.h + cc -c $(DEFS) -I../include parsestreams.c + ld -r -o $@ $@ ../lib/libntp.a libparse_kernel.a + @echo "--- You may load parsestreams.o via 'modload parsestreams.o' into the kernel" + +microtime.o: $(MICROTIME) assym.s + cc -E -I. $(MICROTIME) | sed -e '/\.global _uniqtime/d' > $@.i + as -o $@ $@.i + rm -f $@.i assym.s + +assym.s: genassym + ./genassym > $@ + +genassym: ../ppsclock/sys/genassym/genassym.c + cc -o $@ $? + +libparse_kernel.a: + $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" libparse_kernel.a + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" + +lint: parsestreams.c ../include/parse.h ../include/sys/parsestreams.h ../lib/llib-llibntp.ln + lint -u -I../include $(DEFS) parsestreams.c ../lib/llib-llibntp.ln + +../lib/llib-llibntp.ln: + cd ../lib && make lintlib + +clean: + rm -f *.o genassym assym.s parsestreams + +distclean: clean diff --git a/contrib/xntpd/parse/Makefile.tmpl b/contrib/xntpd/parse/Makefile.tmpl new file mode 100644 index 0000000000..173c91b3d8 --- /dev/null +++ b/contrib/xntpd/parse/Makefile.tmpl @@ -0,0 +1,111 @@ +# +# /src/NTP/REPOSITORY/v3/parse/Makefile.tmpl,v 3.6 1993/10/10 22:44:36 kardel Exp +# +LIBNAME= libparse +KLIBNAME= libparse_kernel +# +# parse routine that could be used in two places +# +COMPILER= cc +COPTS= -O +AUTHDEFS=-DDES +LIBDEFS= -DBIG_ENDIAN +RANLIB= ranlib +INSTALL= install +CLOCKDEFS= +DEFS= +DEFS_OPT= +DEFS_LOCAL= +# +INCL=-I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +# +SOURCE= parse.c parse_conf.c clk_meinberg.c clk_schmid.c clk_rawdcf.c \ + clk_dcf7000.c clk_trimble.c + +OBJS= parse.o parse_conf.o clk_meinberg.o clk_schmid.o clk_rawdcf.o \ + clk_dcf7000.o clk_trimble.o + +all: + @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \ + awk '/-DREFCLOCK/ && /-DPARSE/ && /-DCLOCK_/ { makeit=1; }\ + END { if (makeit) \ + { print "echo ; echo --- creating parse libraries ; $(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" MAKE=\"$(MAKE)\" libs"; } \ + else \ + { print "echo ; echo --- creating parse placebo libraries ; $(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" MAKE=\"$(MAKE)\" emptyplacebolibs";} }' |\ + sh + @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \ + awk '/-DREFCLOCK/ && /-DPARSE/ && /-DCLOCK_/ {makeit=1; }\ + END { if (makeit) \ + { print "echo ; echo --- creating utility programs ; cd util && $(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" MAKE=\"$(MAKE)\" -k"; } \ + else \ + { print ":";} }' |\ + sh + @if (sun) > /dev/null 2>&1; then \ + echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS); \ + else :; fi | \ + awk '/-DSTREAM/ && /-DREFCLOCK/ && /-DPARSE/ && /-DCLOCK_/ { makeit=1; }\ + END { if (makeit) \ + { print "echo ; echo --- creating kernel files ; $(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" MAKE=\"$(MAKE)\" -f Makefile.kernel"; } \ + else \ + { print ":";} }' |\ + sh + +emptyplacebolibs: empty.c + @if [ ! -f "$(LIBNAME).a" -o ! -f "$(KLIBNAME).a" ]; then \ + $(CC) -c empty.c; \ + rm -f $(LIBNAME).a $(KLIBNAME).a; \ + ar r $(LIBNAME).a empty.o; \ + $(RANLIB) $(LIBNAME).a; \ + ar r $(KLIBNAME).a empty.o; \ + $(RANLIB) $(KLIBNAME).a; \ + rm -f empty.o; \ + else \ + : sorry guys - but i always get bitten by the broken ultrix sh; \ + fi + +libs: $(LIBNAME).a $(KLIBNAME).a + +$(LIBNAME).a: $(SOURCE) + $(CC) -c $(CFLAGS) $(CLOCKDEFS) -UPARSESTREAM $(SOURCE) + ar rv $@ $(OBJS) + rm -f $(OBJS) + $(RANLIB) $@ + +$(KLIBNAME).a: $(SOURCE) $(LIBNAME).a + $(CC) -c $(CFLAGS) $(CLOCKDEFS) -DPARSESTREAM $(SOURCE) + ar rv $@ $(OBJS) + rm -f $(OBJS) + $(RANLIB) $@ + +lintlib: llib-l$(LIBNAME).ln + +llib-l$(LIBNAME).ln: $(SOURCE) + lint -C$(LIBNAME) $(INCL) $(CLOCKDEFS) $(AUTHDEFS) $(LIBDEFS) $(SOURCE) >lintlib.errs + +lint: + lint -u $(DEFS) $(INCL) $(CLOCKDEFS) $(AUTHDEFS) $(LIBDEFS) $(SOURCE) >lint.errs + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(LIBNAME).a $(KLIBNAME).a *.o *.out *.ln make.log Makefile.bak \ + lintlib.errs lint.errs genassym assym.s parsestreams parse + -@cd util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl clean + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + -@cd util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl distclean + +install: all + @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \ + awk '/-DREFCLOCK/ && /-DPARSE/ && /-DCLOCK_/ { makeit=1; }\ + END { if (makeit) \ + { print "echo --- installing utility programs ; cd util && $(MAKE) MAKE=\"$(MAKE)\" $@"; } \ + else \ + { print ":";} }' |\ + sh + @echo "--- Kernel modules like "parse" or "parsestreams.o" must be installed manually" + @echo "--- if applicable." diff --git a/contrib/xntpd/parse/README b/contrib/xntpd/parse/README new file mode 100644 index 0000000000..aa83aa7ae0 --- /dev/null +++ b/contrib/xntpd/parse/README @@ -0,0 +1,100 @@ +PARSE reference clock driver: + +This directory contains the files making up the parser for +the parse refclock driver. For reasonably sane clocks this refclock +drivers allows a refclock implementation by just providing a +conversion routine and the appropriate NTP parameters. Refclock +support can run as low a 3k code with the parse refclock driver. + +The modules in here are designed to live in two worlds. In userlevel +as part of the xntp daemon and in kernel land as part of a STREAMS module +or, if someone gets to it, as part of a line discipline. Currently only +SunOS4.x/SunOS5.x STREAMS are supported (volunteers for other vendors like HP?). +This structure means, that refclock_parse can work with or without kernel +support. Kernelsupport increases accuracy tremendingly. The current restriction +of the parse driver is that it only supports SYSV type ttys and that kernel +support is only available for Suns right now. + +Three kernel modules are part of this directory. These work only on +SunOS (SunOS4 and SunOS5 (not fully tested!)). + + SunOS4 (aka Solaris 1.x): + parsestreams.o - standard parse module for SunOS 4 + mparsestreams.o - parse module for SunOS 4 with better + clock reading code (assembler) + + Both modules can be loaded via modload . + + SunOS5 (aka Solaris 2.x): + parse - auto loadable streams module + (not fully tested - don't kill me if + it kills you machine) + + To install just drop "parse" into /kernel/strmod and + start the daemon (SunOS5 will do the rest). + +The structure of the parse reference clock driver is as follows: + + xntpd - contains NTP implementation and calls a reference clock + 127.127.8.x which is implemented by + refclock_parse.c + - which contains several refclock decriptions. These are + selected by the x part of the refclock address. + The lower two bits specify the device to use. Thus the + value (x % 4) determines the device to open + (/dev/refclock-0 - /dev/refclock-3). + + The kind of clock is selected by bits 2-6. This parameter + selects the clock type which deterimines how I/O is done, + the tty parameters and the NTP parameters. + + refclock_parse operates on an abstract reference clock + that delivers time stamps and stati. Offsets and sychron- + isation information is derived from this data and passed + on to refclock_receive of xntp which uses that data for + syncronisation. + + The abstract reference clock is generated by the parse* + routines. They parse the incoming data stream from the + clock and convert it to the appropriate time stamps. + The data is also mapped int the abstract clock states + POWERUP - clock has no valid phase and time code + information + + NOSYNC - Time code is not confirmed, phase is probably + ok. + SYNC - Time code and phase are correct. + + A clock is trusted for a certain time (type parameter) when + it leaves the SYNC state. This is derived from the + observation that quite a few clocks can still generate good + time code information when losing contact to their + synchronisation source. When the clock does not reagain + synchronisation in that trust period it will be deemed + unsynchronised until it regains synchronisation. The same + will happen if xntp sees the clock unsynchronised at + startup. + + The upper bit of x specifies that all samples delivered + from the clock should be used to discipline the NTP + loppfilter. For clock with accurate once a second time + information this means big improvements for time keeping. + A prerequisite for passing on the time stamps to + the loopfilter is, that the clock is in synchronised state. + + parse.c These are the general routines to parse the incoming data + stream. Usually these routines should not require + modification. + + clk_*.c These files hole the conversion code for the time stamps + and the description how the time code can be parsed and + where the time stamps are to be taken. + If you want to add a new clock type this is the file + you need to write in addition to mention it in + parse_conf.c and setting up the NTP and TTY parameters + in refclock_parse.c. + +Further information can be found in parse/README.parse and the various source +files. + +Frank Kardel diff --git a/contrib/xntpd/parse/README.parse b/contrib/xntpd/parse/README.parse new file mode 100644 index 0000000000..660973af31 --- /dev/null +++ b/contrib/xntpd/parse/README.parse @@ -0,0 +1,142 @@ +MINI INFO: +The following info pertains mainly to SunOS4.x in respect to installation. +Installation for SunOS5.x (Solaris 2.x) is very simple - just drop the parse +module into /kernel/strmod. +All others notes about the software structure refer to both environments. + +#ifdef ENGLISH +Installation of a Streams module requires knowledge in kernel generation +and possession of "superuser" rights. + +This directory contains the STREAMS module code for the supported DCF/GPS +receivers of the "parse" driver. +The dataformat should be easy to adept for other clocks. + +A suitable kernel module can be generated in two ways: + 1) loadable driver + 2) linking into the kernel + +Solution 1 has the advantage that the kernel module is present right at system startup, +while solution 2 avoids reconfigurating the kernel (except for VDDRV). + +Loadable Driver: (Kernel must be configured with VDDRV option like e.g. GENERIC) + make -f Makefile.kernel + +# make one module for each kernel architecture you intend to use this module for + + make -f Makefile.kernel mparsestreams.o +# use the above command for a version with increased time stamp precision +# (available only for sun4c and sun4m architectures (thanks Craig Leres) + +Integration into kernel (refer to the Manual for complete instructions) + Still possible, but not recommended + +if you run into trouble: time@informatik.uni-erlangen.de + +Porting to different clock formats: +The streams module is designed to be able to parse different time code +packets. The parser is very simple and expects at least a start or end of packet +character. In order to be able to distinguish time code packets a list +of several start/end pairs and conversion routines can be defined in the +clockformats structure. Whenever a packet delimited by any start/end pair is +detected the conversion routines are called in a RR fashion for converting the +time code into a clocktime structure. A return code of CVT_OK indicates a +correct conversion. +(This routine will be called first on the next conversion attempt). CVT_FAIL +indicates the the packet format was detected, but the actual conversion failed +(e.g. illegal time codes). A CVT_NONE indicates that this conversion routine +did not recognize the packet format. +See the simpleformat conversion routines for Meinberg clocks for examples. +It might be possible to parse other periodically sent time codes with a fixed +format with these simple conversion routines. +The parser can be found in parse/*.c + +The actual STREAMS module is parsestreams.c. It contains some fudge factors. +These are needed if a PPS hardware signal is sampled via the serial CD input. +There are some emperically determined valued for sun4c type machine in there. +Measurements have shown, that for full precision these values have to be +determined in the actual environment, as line lengths and capacities DO matter. +So for absolute precision you need a good oscilloscope and the license for +hardware work. +WARNING: DO NOT ATTEMPT TO MEASURE IF YOU ARE NOT ABSOLUTELY CERTAIN WHAT YOU +ARE DOING. + +This instructions are distributed in the hope that they will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +I will not be in any case responsible for any damage cause by this +Software/Instruction. + +USE AT YOUR OWN RISK. + +#else + +Die folgenden Hinweise zur Uebersetzung und Installation besiehen sich auf +SunOS 4.x (Solaris1.x). Die Installation auf SunOS5.x (Solaris 2.x) gestaltet +sich erheblich einfacher. Man muss nur die Daten "parse" in dem Verzeichnis +/kernel/strmod ablegen. +Alle anderen Hinweise zur Softwarestruktur sind fuer beide Umgebungen gueltig. + +Installation eines STREAMS Moduls setzt Kenntnisse in der Kerngenerierung +und "Superuser"-Rechte vorraus. + +Dieses Inhaltsverzeichnis enthaelt das aktuelle Streams Modul fuer Sun. + +Man kann dieses Modul auf zwei Weisen in den Kern integrieren: + 1) direkt durch Einbinden (neuer Kern) + 2) als ladbarer Treiber + +Loesung 1 hat den Vorteil, dass das Modul gleich nach Systemstart zur +Verfuegung steht. +Loesung 2 besticht dadurch, das man das Modul nachtraeglich laden und +auch debuggen kann, ohne einen neuen Kern zu booten. + +Fuer ein ladbares Modul muss der Kern mit der VDDRV option konfiguriert sein und das +parsestreams.c muss mit -DVDDRV uebersetzt werden. + +Uebersetzung fuer ladbaren Treiber (Kern muss mit VDDRV konfiguriert sein): + make -f Makefile.kernel + bitte einmal fuer jede Kernelarchitektur, fuer die dieses Modul + benoetigt wird durchfuehren. + + make -f Makefile.kernel mparsestreams.o + Das obige make erstellt eine Version, die die Rechneruhr besser + als SunOS abliest. Nur fur sun4c und sun4m Architekturen verfuegbar + +Uebersetzung als .o Modul oder vorherige Einbindung in die Kernbauumgebung: + Immer noch moeglich, wird aber nicht mehr empfohlen. + +Anpassung an andere Datenformate: +Das Streamsmodul ist in der Lage verschiedene Datenformate zu erkennen und +umzusetzen. Der Parser ist einfach gehalten und kann Datenpakete anhand von +Start und Endekennzeichen unterscheiden. Jedes so erkannte Paket wird einer +Liste von Konvertierroutinen vorgelegt (clockformats Struktur). Die +Konvertierroutinen koennen mit drei verschiedenen Rueckgabewerten angeben, +wie die Konvertierung verlaufen ist. CVT_OK heisst, dass die Konvertierung +in die clocktime Struktur erfolgreich verlaufen ist. Beim naechsten +Umsetzungsversuch wird diese Routine als erstes wieder befragt werden +(Optimierung). CVT_FAIL bedeutet, dass zwar das Format erkannt wurde, aber +die eigentliche Konvertierung fehlgeschlagen ist (z. B. illegale Feldwerte). +CVT_NONE heisst, dass das Format dieser Konvertierroutine nicht erkannt wurde. +Die simpleformat Routinen fuer Meinberg Uhren koennen als Vorlage fuer eigene +Anpassungen an Uhren mit periodischem Zeittelegramm und festem Format genommen werden. +Der Parser ist in parse/*.c zu finden. + +Das eigentliche STREAMSmodul ist parsestreams.c. Es enthaelt einige +Korrekturfaktoren, die beim Einsatz von Hardware-PPS Signalen benoetigt werden. +Einige empirische Werte fuer sun4c Maschinen sind schon vorgegeben. Bei exterm +hohen Genauigkeitsanforderungen muessen diese Werte aber in der aktuellen +Installation NEU ermittelt werden, weil die Zeiten unter anderem von +Leitunglaengen der PPS Leitung abhaengen. Wenn Sie diese Abstimmung +durchfuehren, benoetigen Sie ein gutes Oszilloskop und die Lizenz fuer +Hardwarearbeiten. + +ACHTUNG: VERSUCHEN SIE NICHT DIESE MESSUNGEN ZU MACHEN, WENN IHNEN DIE +VORAUSSETZUNGEN DAFUER FEHLEN ! + +WIR GEBEN KEINE GARANTIEN + +Bei Schwierigkeiten email an: time@informatik.uni-erlangen.de + +#endif diff --git a/contrib/xntpd/parse/clk_dcf7000.c b/contrib/xntpd/parse/clk_dcf7000.c new file mode 100644 index 0000000000..c1c01d2480 --- /dev/null +++ b/contrib/xntpd/parse/clk_dcf7000.c @@ -0,0 +1,142 @@ +#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_DCF7000) +/* + * /src/NTP/REPOSITORY/v3/parse/clk_dcf7000.c,v 3.8 1993/10/30 09:44:35 kardel Exp + * + * clk_dcf7000.c,v 3.8 1993/10/30 09:44:35 kardel Exp + * + * ELV DCF7000 module + * + * Copyright (c) 1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#include "sys/types.h" +#include "sys/time.h" +#include "sys/errno.h" +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +static struct format dcf7000_fmt = +{ /* ELV DCF7000 */ + { + { 6, 2}, { 3, 2}, { 0, 2}, + { 12, 2}, { 15, 2}, { 18, 2}, + { 9, 2}, { 21, 2}, + }, + " - - - - - - - \r", + 0 +}; + +static unsigned LONG cvt_dcf7000(); + +clockformat_t clock_dcf7000 = +{ + cvt_dcf7000, /* ELV DCF77 conversion */ + syn_simple, /* easy time stamps */ + (unsigned LONG (*)())0, /* no direct PPS monitoring */ + (unsigned LONG (*)())0, /* no time code synthesizer monitoring */ + (void *)&dcf7000_fmt, /* conversion configuration */ + "ELV DCF7000", /* ELV clock */ + 24, /* string buffer */ + F_END|SYNC_END, /* END packet delimiter / synchronisation */ + { 0, 0}, + '\0', + '\r', + '\0' +}; + +/* + * cvt_dcf7000 + * + * convert dcf7000 type format + */ +static unsigned LONG +cvt_dcf7000(buffer, size, format, clock) + register char *buffer; + register int size; + register struct format *format; + register clocktime_t *clock; +{ + if (!Strok(buffer, format->fixed_string)) + { + return CVT_NONE; + } + else + { + if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock->day, + format->field_offsets[O_DAY].length) || + Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock->month, + format->field_offsets[O_MONTH].length) || + Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock->year, + format->field_offsets[O_YEAR].length) || + Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock->hour, + format->field_offsets[O_HOUR].length) || + Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock->minute, + format->field_offsets[O_MIN].length) || + Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock->second, + format->field_offsets[O_SEC].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + else + { + char *f = &buffer[format->field_offsets[O_FLAGS].offset]; + LONG flags; + + clock->flags = 0; + clock->usecond = 0; + + if (Stoi(f, &flags, format->field_offsets[O_FLAGS].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + else + { + if (flags & 0x1) + clock->utcoffset = -2*60*60; + else + clock->utcoffset = -1*60*60; + + if (flags & 0x2) + clock->flags |= PARSEB_ANNOUNCE; + + if (flags & 0x4) + clock->flags |= PARSEB_NOSYNC; + } + return CVT_OK; + } + } +} +#endif /* defined(PARSE) && defined(CLOCK_DCF7000) */ + +/* + * History: + * + * clk_dcf7000.c,v + * Revision 3.6 1993/10/09 15:01:27 kardel + * file structure unified + * + * Revision 3.5 1993/10/03 19:10:41 kardel + * restructured I/O handling + * + * Revision 3.4 1993/09/27 21:08:02 kardel + * utcoffset now in seconds + * + * Revision 3.3 1993/09/26 23:40:20 kardel + * new parse driver logic + * + * Revision 3.2 1993/07/09 11:37:15 kardel + * Initial restructured version + GPS support + * + * Revision 3.1 1993/07/06 10:00:14 kardel + * DCF77 driver goes generic... + * + */ diff --git a/contrib/xntpd/parse/clk_meinberg.c b/contrib/xntpd/parse/clk_meinberg.c new file mode 100644 index 0000000000..363120b1eb --- /dev/null +++ b/contrib/xntpd/parse/clk_meinberg.c @@ -0,0 +1,444 @@ +#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_MEINBERG) +/* + * /src/NTP/REPOSITORY/v3/parse/clk_meinberg.c,v 3.9 1993/10/30 09:44:38 kardel Exp + * + * clk_meinberg.c,v 3.9 1993/10/30 09:44:38 kardel Exp + * + * Meinberg clock support + * + * Copyright (c) 1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#include "sys/types.h" +#include "sys/time.h" +#include "sys/errno.h" +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +/* + * The Meinberg receiver every second sends a datagram of the following form + * (Standard Format) + * + * D:
..;T:;U:::; + * pos: 0 00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2 2 3 3 3 + * 1 23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8 9 0 1 2 + * = '\002' ASCII start of text + * = '\003' ASCII end of text + *
,, = day, month, year(2 digits!!) + * = day of week (sunday= 0) + * ,, = hour, minute, second + * = '#' if never synced since powerup else ' ' for DCF U/A 31 + * '#' if not PZF sychronisation available else ' ' for PZF 535 + * = '*' if time comes from internal quartz else ' ' + * = 'S' if daylight saving time is active else ' ' + * = '!' during the hour preceeding an daylight saving time + * start/end change + * + * For the university of Erlangen a special format was implemented to support + * LEAP announcement and anouncement of alternate antenna. + * + * Version for UNI-ERLANGEN Software is: PZFUERL V4.6 (Meinberg) + * + * The use of this software release (or higher) is *ABSOLUTELY* + * recommended (ask for PZFUERL version as some minor HW fixes have + * been introduced) due to the LEAP second support and UTC indication. + * The standard timecode does not indicate when the timecode is in + * UTC (by front panel configuration) thus we have no chance to find + * the correct utc offset. For the standard format do not ever use + * UTC display as this is not detectable in the time code !!! + * + *
..; ; ::; + * pos: 0 00 0 00 0 00 11 1 11 11 1 11 2 22 22 2 2 2 2 2 3 3 3 + * 1 23 4 56 7 89 01 2 34 56 7 89 0 12 34 5 6 7 8 9 0 1 2 + * = '\002' ASCII start of text + * = '\003' ASCII end of text + *
,, = day, month, year(2 digits!!) + * = day of week (sunday= 0) + * ,, = hour, minute, second + * = 'U' UTC time display + * = '#' if never synced since powerup else ' ' for DCF U/A 31 + * '#' if not PZF sychronisation available else ' ' for PZF 535 + * = '*' if time comes from internal quartz else ' ' + * = 'S' if daylight saving time is active else ' ' + * = '!' during the hour preceeding an daylight saving time + * start/end change + * = 'A' LEAP second announcement + * = 'R' alternate antenna + * + * Meinberg GPS166 receiver + * + * You must get the Uni-Erlangen firmware for the GPS receiver support + * to work to full satisfaction ! + * + *
..; ; ::; <+/-><00:00>; ; + * + * 000000000111111111122222222223333333333444444444455555555556666666 + * 123456789012345678901234567890123456789012345678901234567890123456 + * \x0209.07.93; 5; 08:48:26; +00:00; ; 49.5736N 11.0280E 373m\x03 + * + * + * = '\002' ASCII start of text + * = '\003' ASCII end of text + *
,, = day, month, year(2 digits!!) + * = day of week (sunday= 0) + * ,, = hour, minute, second + * <+/->,<00:00> = offset to UTC + * = '#' if never synced since powerup else ' ' for DCF U/A 31 + * '#' if not PZF sychronisation available else ' ' for PZF 535 + * = 'U' UTC time display + * = '*' if time comes from internal quartz else ' ' + * = 'S' if daylight saving time is active else ' ' + * = '!' during the hour preceeding an daylight saving time + * start/end change + * = 'A' LEAP second announcement + * = 'R' alternate antenna (reminiscent of PZF535) usually ' ' + * = 'L' on 23:59:60 + */ + +static struct format meinberg_fmt[] = +{ + { + { + { 3, 2}, { 6, 2}, { 9, 2}, + { 18, 2}, { 21, 2}, { 24, 2}, + { 14, 1}, { 27, 4}, { 29, 1}, + }, + "\2D: . . ;T: ;U: . . ; \3", + 0 + }, + { /* special extended FAU Erlangen extended format */ + { + { 1, 2}, { 4, 2}, { 7, 2}, + { 14, 2}, { 17, 2}, { 20, 2}, + { 11, 1}, { 25, 4}, { 27, 1}, + }, + "\2 . . ; ; : : ; \3", + MBG_EXTENDED + }, + { /* special extended FAU Erlangen GPS format */ + { + { 1, 2}, { 4, 2}, { 7, 2}, + { 14, 2}, { 17, 2}, { 20, 2}, + { 11, 1}, { 32, 8}, { 35, 1}, + { 25, 2}, { 28, 2}, { 24, 1} + }, + "\2 . . ; ; : : ; : ; ; . . ", + 0 + } +}; + +static unsigned LONG cvt_meinberg(); +static unsigned LONG cvt_mgps(); + +clockformat_t clock_meinberg[] = +{ + { + cvt_meinberg, /* Meinberg conversion */ + syn_simple, /* easy time stamps for RS232 (fallback) */ + pps_simple, /* easy PPS monitoring */ + (unsigned LONG (*)())0, /* no time code synthesizer monitoring */ + (void *)&meinberg_fmt[0], /* conversion configuration */ + "Meinberg Standard", /* Meinberg simple format - beware */ + 32, /* string buffer */ + F_START|F_END|SYNC_START|SYNC_ONE, /* paket START/END delimiter, START synchronisation, PPS ONE sampling */ + { 0, 0}, + '\2', + '\3', + '\0' + }, + { + cvt_meinberg, /* Meinberg conversion */ + syn_simple, /* easy time stamps for RS232 (fallback) */ + pps_simple, /* easy PPS monitoring */ + (unsigned LONG (*)())0, /* no time code synthesizer monitoring */ + (void *)&meinberg_fmt[1], /* conversion configuration */ + "Meinberg Extended", /* Meinberg enhanced format */ + 32, /* string buffer */ + F_START|F_END|SYNC_START|SYNC_ONE, /* paket START/END delimiter, START synchronisation, PPS ONE sampling */ + { 0, 0}, + '\2', + '\3', + '\0' + }, + { + cvt_mgps, /* Meinberg GPS166 conversion */ + syn_simple, /* easy time stamps for RS232 (fallback) */ + pps_simple, /* easy PPS monitoring */ + (unsigned LONG (*)())0, /* no time code synthesizer monitoring */ + (void *)&meinberg_fmt[2], /* conversion configuration */ + "Meinberg GPS Extended", /* Meinberg FAU GPS format */ + 70, /* string buffer */ + F_START|F_END|SYNC_START|SYNC_ONE, /* paket START/END delimiter, START synchronisation, PPS ONE sampling */ + { 0, 0}, + '\2', + '\3', + '\0' + } +}; + +/* + * cvt_meinberg + * + * convert simple type format + */ +static unsigned LONG +cvt_meinberg(buffer, size, format, clock) + register char *buffer; + register int size; + register struct format *format; + register clocktime_t *clock; +{ + if (!Strok(buffer, format->fixed_string)) + { + return CVT_NONE; + } + else + { + if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock->day, + format->field_offsets[O_DAY].length) || + Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock->month, + format->field_offsets[O_MONTH].length) || + Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock->year, + format->field_offsets[O_YEAR].length) || + Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock->hour, + format->field_offsets[O_HOUR].length) || + Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock->minute, + format->field_offsets[O_MIN].length) || + Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock->second, + format->field_offsets[O_SEC].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + else + { + char *f = &buffer[format->field_offsets[O_FLAGS].offset]; + + clock->flags = 0; + clock->usecond = 0; + + /* + * in the extended timecode format we have also the + * indication that the timecode is in UTC + * for compatibilty reasons we start at the USUAL + * offset (POWERUP flag) and know that the UTC indication + * is the character before the powerup flag + */ + if ((format->flags & MBG_EXTENDED) && (f[-1] == 'U')) + { + /* + * timecode is in UTC + */ + clock->utcoffset = 0; /* UTC */ + clock->flags |= PARSEB_UTC; + } + else + { + /* + * only calculate UTC offset if MET/MED is in time code + * or we have the old time code format, where we do not + * know whether it is UTC time or MET/MED + * pray that nobody switches to UTC in the standard time code + * ROMS !!!! + */ + switch (buffer[format->field_offsets[O_ZONE].offset]) + { + case ' ': + clock->utcoffset = -1*60*60; /* MET */ + break; + + case 'S': + clock->utcoffset = -2*60*60; /* MED */ + break; + + default: + return CVT_FAIL|CVT_BADFMT; + } + } + + /* + * gather status flags + */ + if (buffer[format->field_offsets[O_ZONE].offset] == 'S') + clock->flags |= PARSEB_DST; + + if (f[0] == '#') + clock->flags |= PARSEB_POWERUP; + + if (f[1] == '*') + clock->flags |= PARSEB_NOSYNC; + + if (f[3] == '!') + clock->flags |= PARSEB_ANNOUNCE; + + if (format->flags & MBG_EXTENDED) + { + clock->flags |= PARSEB_S_LEAP; + clock->flags |= PARSEB_S_ANTENNA; + + if (f[4] == 'A') + clock->flags |= PARSEB_LEAP; + + if (f[5] == 'R') + clock->flags |= PARSEB_ALTERNATE; + } + return CVT_OK; + } + } +} + +/* + * cvt_mgps + * + * convert Meinberg GPS format + */ +static unsigned LONG +cvt_mgps(buffer, size, format, clock) + register char *buffer; + register int size; + register struct format *format; + register clocktime_t *clock; +{ + if (!Strok(buffer, format->fixed_string)) + { + return CVT_NONE; + } + else + { + if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock->day, + format->field_offsets[O_DAY].length) || + Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock->month, + format->field_offsets[O_MONTH].length) || + Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock->year, + format->field_offsets[O_YEAR].length) || + Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock->hour, + format->field_offsets[O_HOUR].length) || + Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock->minute, + format->field_offsets[O_MIN].length) || + Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock->second, + format->field_offsets[O_SEC].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + else + { + LONG h; + char *f = &buffer[format->field_offsets[O_FLAGS].offset]; + + clock->flags = PARSEB_S_LEAP|PARSEB_S_POSITION; + + clock->usecond = 0; + + /* + * calculate UTC offset + */ + if (Stoi(&buffer[format->field_offsets[O_UTCHOFFSET].offset], &h, + format->field_offsets[O_UTCHOFFSET].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + else + { + if (Stoi(&buffer[format->field_offsets[O_UTCMOFFSET].offset], &clock->utcoffset, + format->field_offsets[O_UTCMOFFSET].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + + clock->utcoffset += TIMES60(h); + + if (buffer[format->field_offsets[O_UTCSOFFSET].offset] != '-') + { + clock->utcoffset = -clock->utcoffset; + } + } + + /* + * gather status flags + */ + if (buffer[format->field_offsets[O_ZONE].offset] == 'S') + clock->flags |= PARSEB_DST; + + if ((f[0] == 'U') || + (clock->utcoffset == 0)) + clock->flags |= PARSEB_UTC; + + /* + * no sv's seen - no time & position + */ + if (f[1] == '#') + clock->flags |= PARSEB_POWERUP; + + /* + * at least one sv seen - time (for last position) + */ + if (f[2] == '*') + clock->flags |= PARSEB_NOSYNC; + else + if (!(clock->flags & PARSEB_POWERUP)) + clock->flags |= PARSEB_POSITION; + + /* + * oncoming zone switch + */ + if (f[4] == '!') + clock->flags |= PARSEB_ANNOUNCE; + + /* + * oncoming leap second + */ + if (f[5] == 'A') + clock->flags |= PARSEB_LEAP; + + /* + * this is the leap second + */ + if (f[7] == 'L') + clock->flags |= PARSEB_LEAPSECOND; + + return CVT_OK; + } + } +} +#endif /* defined(PARSE) && defined(CLOCK_MEINBERG) */ + +/* + * History: + * + * clk_meinberg.c,v + * Revision 3.9 1993/10/30 09:44:38 kardel + * conditional compilation flag cleanup + * + * Revision 3.8 1993/10/22 14:27:48 kardel + * Oct. 22nd 1993 reconcilation + * + * Revision 3.7 1993/10/09 15:01:30 kardel + * file structure unified + * + * Revision 3.6 1993/10/03 19:10:43 kardel + * restructured I/O handling + * + * Revision 3.5 1993/09/27 21:08:04 kardel + * utcoffset now in seconds + * + * Revision 3.4 1993/09/26 23:40:22 kardel + * new parse driver logic + * + * Revision 3.3 1993/08/18 09:29:32 kardel + * GPS format is somewhat variable length - variable length part holds position + * + * Revision 3.2 1993/07/09 11:37:16 kardel + * Initial restructured version + GPS support + * + * Revision 3.1 1993/07/06 10:00:17 kardel + * DCF77 driver goes generic... + * + */ diff --git a/contrib/xntpd/parse/clk_rawdcf.c b/contrib/xntpd/parse/clk_rawdcf.c new file mode 100644 index 0000000000..4a5ad5608a --- /dev/null +++ b/contrib/xntpd/parse/clk_rawdcf.c @@ -0,0 +1,553 @@ +#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_RAWDCF) +/* + * /src/NTP/REPOSITORY/v3/parse/clk_rawdcf.c,v 3.7 1993/10/30 09:44:41 kardel Exp + * + * clk_rawdcf.c,v 3.7 1993/10/30 09:44:41 kardel Exp + * + * Raw DCF77 pulse clock support + * + * Copyright (c) 1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#include "sys/types.h" +#include "sys/time.h" +#include "sys/errno.h" +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" +#ifdef PARSESTREAM +#include "sys/parsestreams.h" +#endif + +#ifndef PARSEKERNEL +#include "ntp_stdlib.h" +#endif + +/* + * DCF77 raw time code + * + * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig + * und Berlin, Maerz 1989 + * + * Timecode transmission: + * AM: + * time marks are send every second except for the second before the + * next minute mark + * time marks consist of a reduction of transmitter power to 25% + * of the nominal level + * the falling edge is the time indication (on time) + * time marks of a 100ms duration constitute a logical 0 + * time marks of a 200ms duration constitute a logical 1 + * FM: + * see the spec. (basically a (non-)inverted psuedo random phase shift) + * + * Encoding: + * Second Contents + * 0 - 10 AM: free, FM: 0 + * 11 - 14 free + * 15 R - alternate antenna + * 16 A1 - expect zone change (1 hour before) + * 17 - 18 Z1,Z2 - time zone + * 0 0 illegal + * 0 1 MEZ (MET) + * 1 0 MESZ (MED, MET DST) + * 1 1 illegal + * 19 A2 - expect leap insertion/deletion (1 hour before) + * 20 S - start of time code (1) + * 21 - 24 M1 - BCD (lsb first) Minutes + * 25 - 27 M10 - BCD (lsb first) 10 Minutes + * 28 P1 - Minute Parity (even) + * 29 - 32 H1 - BCD (lsb first) Hours + * 33 - 34 H10 - BCD (lsb first) 10 Hours + * 35 P2 - Hour Parity (even) + * 36 - 39 D1 - BCD (lsb first) Days + * 40 - 41 D10 - BCD (lsb first) 10 Days + * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday) + * 45 - 49 MO - BCD (lsb first) Month + * 50 MO0 - 10 Months + * 51 - 53 Y1 - BCD (lsb first) Years + * 54 - 57 Y10 - BCD (lsb first) 10 Years + * 58 P3 - Date Parity (even) + * 59 - usually missing (minute indication), except for leap insertion + */ + +static unsigned LONG cvt_rawdcf(); +static unsigned LONG pps_rawdcf(); +static unsigned LONG snt_rawdcf(); + +clockformat_t clock_rawdcf = +{ + cvt_rawdcf, /* raw dcf input conversion */ + (void (*)())0, /* no character bound synchronisation */ + pps_rawdcf, /* examining PPS information */ + snt_rawdcf, /* synthesize time code from input */ + (void *)0, /* buffer bit representation */ + "RAW DCF77 Timecode", /* direct decoding / time synthesis */ + 61, /* bit buffer */ + SYNC_ONE|SYNC_ZERO|SYNC_TIMEOUT|SYNC_SYNTHESIZE|CVT_FIXEDONLY, + /* catch all transitions, buffer restart on timeout, fixed configuration only */ + { 1, 500000}, /* restart after 1.5 seconds */ + '\0', + '\0', + '\0' +}; + +static struct dcfparam +{ + unsigned char onebits[60]; + unsigned char zerobits[60]; +} dcfparam = +{ + "###############RADMLS1248124P124812P1248121241248112481248P", /* 'ONE' representation */ + "--------------------s-------p------p----------------------p" /* 'ZERO' representation */ +}; + +static struct rawdcfcode +{ + char offset; /* start bit */ +} rawdcfcode[] = +{ + { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 }, + { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 } +}; + +#define DCF_M 0 +#define DCF_R 1 +#define DCF_A1 2 +#define DCF_Z 3 +#define DCF_A2 4 +#define DCF_S 5 +#define DCF_M1 6 +#define DCF_M10 7 +#define DCF_P1 8 +#define DCF_H1 9 +#define DCF_H10 10 +#define DCF_P2 11 +#define DCF_D1 12 +#define DCF_D10 13 +#define DCF_DW 14 +#define DCF_MO 15 +#define DCF_MO0 16 +#define DCF_Y1 17 +#define DCF_Y10 18 +#define DCF_P3 19 + +static struct partab +{ + char offset; /* start bit of parity field */ +} partab[] = +{ + { 21 }, { 29 }, { 36 }, { 59 } +}; + +#define DCF_P_P1 0 +#define DCF_P_P2 1 +#define DCF_P_P3 2 + +#define DCF_Z_MET 0x2 +#define DCF_Z_MED 0x1 + +static unsigned LONG ext_bf(buf, idx, zero) + register char *buf; + register int idx; + register char *zero; +{ + register unsigned LONG sum = 0; + register int i, first; + + first = rawdcfcode[idx].offset; + + for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--) + { + sum <<= 1; + sum |= (buf[i] != zero[i]); + } + return sum; +} + +static unsigned pcheck(buf, idx, zero) + register char *buf; + register int idx; + register char *zero; +{ + register int i,last; + register unsigned psum = 1; + + last = partab[idx+1].offset; + + for (i = partab[idx].offset; i < last; i++) + psum ^= (buf[i] != zero[i]); + + return psum; +} + +static unsigned LONG convert_rawdcf(buffer, size, dcfparam, clock) + register unsigned char *buffer; + register int size; + register struct dcfparam *dcfparam; + register clocktime_t *clock; +{ + register unsigned char *s = buffer; + register unsigned char *b = dcfparam->onebits; + register unsigned char *c = dcfparam->zerobits; + register int i; + + parseprintf(DD_RAWDCF,("parse: convert_rawdcf: \"%s\"\n", buffer)); + + if (size < 57) + { +#ifdef PARSEKERNEL + printf("parse: convert_rawdcf: INCOMPLETE DATA - time code only has %d bits\n", size); +#else + syslog(LOG_ERR, "parse: convert_rawdcf: INCOMPLETE DATA - time code only has %d bits\n", size); +#endif + return CVT_NONE; + } + + for (i = 0; i < 58; i++) + { + if ((*s != *b) && (*s != *c)) + { + /* + * we only have two types of bytes (ones and zeros) + */ +#ifdef PARSEKERNEL + printf("parse: convert_rawdcf: BAD DATA - no conversion for \"%s\"\n", buffer); +#else + syslog(LOG_ERR, "parse: convert_rawdcf: BAD DATA - no conversion for \"%s\"\n", buffer); +#endif + return CVT_NONE; + } + b++; + c++; + s++; + } + + /* + * check Start and Parity bits + */ + if ((ext_bf(buffer, DCF_S, dcfparam->zerobits) == 1) && + pcheck(buffer, DCF_P_P1, dcfparam->zerobits) && + pcheck(buffer, DCF_P_P2, dcfparam->zerobits) && + pcheck(buffer, DCF_P_P3, dcfparam->zerobits)) + { + /* + * buffer OK + */ + parseprintf(DD_RAWDCF,("parse: convert_rawdcf: parity check passed\n")); + + clock->flags = PARSEB_S_ANTENNA|PARSEB_S_LEAP; + clock->usecond= 0; + clock->second = 0; + clock->minute = ext_bf(buffer, DCF_M10, dcfparam->zerobits); + clock->minute = TIMES10(clock->minute) + ext_bf(buffer, DCF_M1, dcfparam->zerobits); + clock->hour = ext_bf(buffer, DCF_H10, dcfparam->zerobits); + clock->hour = TIMES10(clock->hour) + ext_bf(buffer, DCF_H1, dcfparam->zerobits); + clock->day = ext_bf(buffer, DCF_D10, dcfparam->zerobits); + clock->day = TIMES10(clock->day) + ext_bf(buffer, DCF_D1, dcfparam->zerobits); + clock->month = ext_bf(buffer, DCF_MO0, dcfparam->zerobits); + clock->month = TIMES10(clock->month) + ext_bf(buffer, DCF_MO, dcfparam->zerobits); + clock->year = ext_bf(buffer, DCF_Y10, dcfparam->zerobits); + clock->year = TIMES10(clock->year) + ext_bf(buffer, DCF_Y1, dcfparam->zerobits); + + switch (ext_bf(buffer, DCF_Z, dcfparam->zerobits)) + { + case DCF_Z_MET: + clock->utcoffset = -1*60*60; + break; + + case DCF_Z_MED: + clock->flags |= PARSEB_DST; + clock->utcoffset = -2*60*60; + break; + + default: + parseprintf(DD_RAWDCF,("parse: convert_rawdcf: BAD TIME ZONE\n")); + return CVT_FAIL|CVT_BADFMT; + } + + if (ext_bf(buffer, DCF_A1, dcfparam->zerobits)) + clock->flags |= PARSEB_ANNOUNCE; + + if (ext_bf(buffer, DCF_A2, dcfparam->zerobits)) + clock->flags |= PARSEB_LEAP; + + if (ext_bf(buffer, DCF_R, dcfparam->zerobits)) + clock->flags |= PARSEB_ALTERNATE; + + parseprintf(DD_RAWDCF,("parse: convert_rawdcf: TIME CODE OK: %d:%d, %d.%d.%d, flags 0x%x\n", + clock->hour, clock->minute, clock->day, clock->month, clock->year, + clock->flags)); + return CVT_OK; + } + else + { + /* + * bad format - not for us + */ +#ifdef PARSEKERNEL + printf("parse: convert_rawdcf: parity check FAILED for \"%s\"\n", buffer); +#else + syslog(LOG_ERR, "parse: convert_rawdcf: parity check FAILED for \"%s\"\n", buffer); +#endif + return CVT_FAIL|CVT_BADFMT; + } +} + +/* + * raw dcf input routine - needs to fix up 50 baud + * characters for 1/0 decision + */ +static unsigned LONG cvt_rawdcf(buffer, size, param, clock) + register unsigned char *buffer; + register int size; + register void *param; + register clocktime_t *clock; +{ + register unsigned char *s = buffer; + register unsigned char *e = buffer + size; + register unsigned char *b = dcfparam.onebits; + register unsigned char *c = dcfparam.zerobits; + register unsigned rtc = CVT_NONE; + register unsigned int i, lowmax, highmax, cutoff, span; +#define BITS 9 + unsigned char histbuf[BITS]; + /* + * the input buffer contains characters with runs of consecutive + * bits set. These set bits are an indication of the DCF77 pulse + * length. We assume that we receive the pulse at 50 Baud. Thus + * a 100ms pulse would generate a 4 bit train (20ms per bit and + * start bit) + * a 200ms pulse would create all zeroes (and probably a frame error) + */ + + for (i = 0; i < BITS; i++) + { + histbuf[i] = 0; + } + + cutoff = 0; + lowmax = 0; + + while (s < e) + { + register unsigned int ch = *s ^ 0xFF; + /* + * these lines are left as an excercise to the reader 8-) + */ + if (!((ch+1) & ch) || !*s) + { + + for (i = 0; ch; i++) + { + ch >>= 1; + } + + *s = i; + histbuf[i]++; + cutoff += i; + lowmax++; + } + else + { + parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: character check for 0x%x@%d FAILED\n", *s, s - buffer)); + *s = ~0; + rtc = CVT_FAIL|CVT_BADFMT; + } + s++; + } + + if (lowmax) + { + cutoff /= lowmax; + } + else + { + cutoff = 4; /* doesn't really matter - it'll fail anyway, but gives error output */ + } + + parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: average bit count: %d\n", cutoff)); + + lowmax = 0; + highmax = 0; + + parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: histogram:")); + for (i = 0; i <= cutoff; i++) + { + lowmax+=histbuf[i] * i; + highmax += histbuf[i]; + parseprintf(DD_RAWDCF,(" %d", histbuf[i])); + } + parseprintf(DD_RAWDCF, (" ")); + + lowmax += highmax / 2; + + if (highmax) + { + lowmax /= highmax; + } + else + { + lowmax = 0; + } + + highmax = 0; + cutoff = 0; + + for (; i < BITS; i++) + { + highmax+=histbuf[i] * i; + cutoff +=histbuf[i]; + parseprintf(DD_RAWDCF,(" %d", histbuf[i])); + } + parseprintf(DD_RAWDCF,("\n")); + + if (cutoff) + { + highmax /= cutoff; + } + else + { + highmax = BITS-1; + } + + span = cutoff = lowmax; + for (i = lowmax; i <= highmax; i++) + { + if (histbuf[cutoff] > histbuf[i]) + { + cutoff = i; + span = i; + } + else + if (histbuf[cutoff] == histbuf[i]) + { + span = i; + } + } + + cutoff = (cutoff + span) / 2; + + parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff)); + + s = buffer; + while ((s < e) && *c && *b) + { + if (*s == (unsigned char)~0) + { + *s = '?'; + } + else + { + *s = (*s >= cutoff) ? *b : *c; + } + s++; + b++; + c++; + } + + return (rtc == CVT_NONE) ? convert_rawdcf(buffer, size, &dcfparam, clock) : rtc; +} + +/* + * pps_rawdcf + * + * currently a very stupid version - should be extended to decode + * also ones and zeros (which is easy) + */ +/*ARGSUSED*/ +static unsigned LONG pps_rawdcf(parseio, status, ptime) + register parse_t *parseio; + register int status; + register timestamp_t *ptime; +{ + if (status == SYNC_ONE) + { + parseio->parse_dtime.parse_ptime = *ptime; + parseio->parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; + } + + return CVT_NONE; +} + +/*ARGSUSED*/ +static unsigned LONG snt_rawdcf(parseio, ptime) + register parse_t *parseio; + register timestamp_t *ptime; +{ + clocktime_t clock; + unsigned LONG cvtrtc; + time_t t; + + /* + * start at last sample and add second index - gross, may have to be much more careful + */ + if (convert_rawdcf(parseio->parse_ldata, parseio->parse_ldsize - 1, &dcfparam, &clock) == CVT_OK) + { + if ((t = parse_to_unixtime(&clock, &cvtrtc)) == -1) + { + parseprintf(DD_RAWDCF,("parse: snt_rawdcf: time conversion FAILED\n")); + return CVT_FAIL|cvtrtc; + } + } + else + { + parseprintf(DD_RAWDCF,("parse: snt_rawdcf: data conversion FAILED\n")); + return CVT_NONE; + } + + parseio->parse_dtime.parse_stime = *ptime; + + t += parseio->parse_index - 1; + + /* + * time stamp + */ +#ifdef PARSEKERNEL + parseio->parse_dtime.parse_time.tv.tv_sec = t; + parseio->parse_dtime.parse_time.tv.tv_usec = clock.usecond; +#else + parseio->parse_dtime.parse_time.fp.l_ui = t + JAN_1970; + TVUTOTSF(clock.usecond, parseio->parse_dtime.parse_time.fp.l_uf); +#endif + + parseprintf(DD_RAWDCF,("parse: snt_rawdcf: time stamp synthesized offset %d seconds\n", parseio->parse_index - 1)); + + return updatetimeinfo(parseio, t, clock.usecond, clock.flags); +} +#endif /* defined(PARSE) && defined(CLOCK_RAWDCF) */ + +/* + * History: + * + * clk_rawdcf.c,v + * Revision 3.7 1993/10/30 09:44:41 kardel + * conditional compilation flag cleanup + * + * Revision 3.6 1993/10/03 19:10:45 kardel + * restructured I/O handling + * + * Revision 3.5 1993/09/27 21:08:07 kardel + * utcoffset now in seconds + * + * Revision 3.4 1993/09/26 23:40:25 kardel + * new parse driver logic + * + * Revision 3.3 1993/09/01 21:44:54 kardel + * conditional cleanup + * + * Revision 3.2 1993/07/09 11:37:18 kardel + * Initial restructured version + GPS support + * + * Revision 3.1 1993/07/06 10:00:19 kardel + * DCF77 driver goes generic... + * + */ diff --git a/contrib/xntpd/parse/clk_schmid.c b/contrib/xntpd/parse/clk_schmid.c new file mode 100644 index 0000000000..12b06fdcc3 --- /dev/null +++ b/contrib/xntpd/parse/clk_schmid.c @@ -0,0 +1,195 @@ +#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_SCHMID) +/* + * /src/NTP/REPOSITORY/v3/parse/clk_schmid.c,v 3.8 1993/11/01 20:00:18 kardel Exp + * + * clk_schmid.c,v 3.8 1993/11/01 20:00:18 kardel Exp + * + * Schmid clock support + * + * Copyright (c) 1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#include "sys/types.h" +#include "sys/time.h" +#include "sys/errno.h" +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +/* + * Description courtesy of Adam W. Feigin et. al (Swisstime iis.ethz.ch) + * + * The command to Schmid's DCF77 clock is a single byte; each bit + * allows the user to select some part of the time string, as follows (the + * output for the lsb is sent first). + * + * Bit 0: time in MEZ, 4 bytes *binary, not BCD*; hh.mm.ss.tenths + * Bit 1: date 3 bytes *binary, not BCD: dd.mm.yy + * Bit 2: week day, 1 byte (unused here) + * Bit 3: time zone, 1 byte, 0=MET, 1=MEST. (unused here) + * Bit 4: clock status, 1 byte, 0=time invalid, + * 1=time from crystal backup, + * 3=time from DCF77 + * Bit 5: transmitter status, 1 byte, + * bit 0: backup antenna + * bit 1: time zone change within 1h + * bit 3,2: TZ 01=MEST, 10=MET + * bit 4: leap second will be + * added within one hour + * bits 5-7: Zero + * Bit 6: time in backup mode, units of 5 minutes (unused here) + * + */ +#define WS_TIME 0x01 +#define WS_SIGNAL 0x02 + +#define WS_ALTERNATE 0x01 +#define WS_ANNOUNCE 0x02 +#define WS_TZ 0x0c +#define WS_MET 0x08 +#define WS_MEST 0x04 +#define WS_LEAP 0x10 + +static unsigned LONG cvt_schmid(); + +clockformat_t clock_schmid = +{ + cvt_schmid, /* Schmid conversion */ + syn_simple, /* easy time stamps */ + (unsigned LONG (*)())0, /* not direct PPS monitoring */ + (unsigned LONG (*)())0, /* no time code synthesizer monitoring */ + (void *)0, /* conversion configuration */ + "Schmid", /* Schmid receiver */ + 12, /* binary data buffer */ + F_END|SYNC_START, /* END packet delimiter / synchronisation */ + { 0, 0}, + '\0', + (unsigned char)'\375', + '\0' +}; + + +static unsigned LONG +cvt_schmid(buffer, size, format, clock) + register char *buffer; + register int size; + register struct format *format; + register clocktime_t *clock; +{ + if ((size != 11) || (buffer[10] != '\375')) + { + return CVT_NONE; + } + else + { + if (buffer[0] > 23 || buffer[1] > 59 || buffer[2] > 59 || buffer[3] > 9 /* Time */ + || buffer[0] < 0 || buffer[1] < 0 || buffer[2] < 0 || buffer[3] < 0) + { + return CVT_FAIL|CVT_BADTIME; + } + else + if (buffer[4] < 1 || buffer[4] > 31 || buffer[5] < 1 || buffer[5] > 12 + || buffer[6] > 99) + { + return CVT_FAIL|CVT_BADDATE; + } + else + { + clock->hour = buffer[0]; + clock->minute = buffer[1]; + clock->second = buffer[2]; + clock->usecond = buffer[3] * 100000; + clock->day = buffer[4]; + clock->month = buffer[5]; + clock->year = buffer[6]; + + clock->flags = 0; + + switch (buffer[8] & WS_TZ) + { + case WS_MET: + clock->utcoffset = -1*60*60; + break; + + case WS_MEST: + clock->utcoffset = -2*60*60; + clock->flags |= PARSEB_DST; + break; + + default: + return CVT_FAIL|CVT_BADFMT; + } + + if (!(buffer[7] & WS_TIME)) + { + clock->flags |= PARSEB_POWERUP; + } + + if (!(buffer[7] & WS_SIGNAL)) + { + clock->flags |= PARSEB_NOSYNC; + } + + if (buffer[7] & WS_SIGNAL) + { + if (buffer[8] & WS_ALTERNATE) + { + clock->flags |= PARSEB_ALTERNATE; + } + + if (buffer[8] & WS_ANNOUNCE) + { + clock->flags |= PARSEB_ANNOUNCE; + } + + if (buffer[8] & WS_LEAP) + { + clock->flags |= PARSEB_LEAP; + } + } + + clock->flags |= PARSEB_S_LEAP|PARSEB_S_ANTENNA; + + return CVT_OK; + } + } +} +#endif /* defined(PARSE) && defined(CLOCK_SCHMID) */ + +/* + * History: + * + * clk_schmid.c,v + * Revision 3.8 1993/11/01 20:00:18 kardel + * parse Solaris support (initial version) + * + * Revision 3.7 1993/10/30 09:44:43 kardel + * conditional compilation flag cleanup + * + * Revision 3.6 1993/10/09 15:01:32 kardel + * file structure unified + * + * Revision 3.5 1993/10/03 19:10:47 kardel + * restructured I/O handling + * + * Revision 3.4 1993/09/27 21:08:09 kardel + * utcoffset now in seconds + * + * Revision 3.3 1993/09/26 23:40:27 kardel + * new parse driver logic + * + * Revision 3.2 1993/07/09 11:37:19 kardel + * Initial restructured version + GPS support + * + * Revision 3.1 1993/07/06 10:00:22 kardel + * DCF77 driver goes generic... + * + */ diff --git a/contrib/xntpd/parse/clk_trimble.c b/contrib/xntpd/parse/clk_trimble.c new file mode 100644 index 0000000000..c9c124ea4d --- /dev/null +++ b/contrib/xntpd/parse/clk_trimble.c @@ -0,0 +1,131 @@ +#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_TRIMSV6) +/* + * /src/NTP/REPOSITORY/v3/parse/clk_trimble.c,v 3.6 1993/10/30 09:44:45 kardel Exp + * + * Trimble SV6 clock support + */ + +#include "sys/types.h" +#include "sys/time.h" +#include "sys/errno.h" +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +/* 0000000000111111111122222222223333333 / char + * 0123456789012345678901234567890123456 \ posn + * >RTMhhmmssdddDDMMYYYYoodnnvrrrrr;*xx< Actual + * ----33445566600112222BB7__-_____--99- Parse + * >RTM 1 ;* <", Check + */ + +#define hexval(x) (('0' <= (x) && (x) <= '9') ? (x) - '0' : \ + ('a' <= (x) && (x) <= 'f') ? (x) - 'a' + 10 : \ + ('A' <= (x) && (x) <= 'F') ? (x) - 'A' + 10 : \ + -1) +#define O_USEC O_WDAY +#define O_GPSFIX O_FLAGS +#define O_CHKSUM O_UTCHOFFSET +static struct format trimsv6_fmt = +{ { { 13, 2 }, {15, 2}, { 17, 4}, /* Day, Month, Year */ + { 4, 2 }, { 6, 2}, { 8, 2}, /* Hour, Minute, Second */ + { 10, 3 }, {23, 1}, { 0, 0}, /* uSec, FIXes (WeekDAY, FLAGS, ZONE) */ + { 34, 2 }, { 0, 0}, { 21, 2}, /* cksum, -, utcS (UTC[HMS]OFFSET) */ + }, + ">RTM 1 ;* <", + 0 +}; + +static unsigned LONG cvt_trimsv6(); + +clockformat_t clock_trimsv6 = +{ cvt_trimsv6, /* Trimble conversion */ + syn_simple, /* easy time stamps for RS232 (fallback) */ + pps_simple, /* easy PPS monitoring */ + (unsigned LONG (*)())0, /* no time code synthesizer monitoring */ + (void *)&trimsv6_fmt, /* conversion configuration */ + "Trimble SV6", + 37, /* string buffer */ + F_START|F_END|SYNC_START|SYNC_ONE, /* paket START/END delimiter, START synchronisation, PPS ONE sampling */ + { 0, 0}, + '>', + '<', + '\0' +}; + +static unsigned LONG +cvt_trimsv6(buffer, size, format, clock) + register char *buffer; + register int size; + register struct format *format; + register clocktime_t *clock; +{ + LONG gpsfix; + u_char calc_csum = 0; + long recv_csum; + int i; + + if (!Strok(buffer, format->fixed_string)) return CVT_NONE; +#define OFFS(x) format->field_offsets[(x)].offset +#define STOI(x, y) \ + Stoi(&buffer[OFFS(x)], y, \ + format->field_offsets[(x)].length) + if ( STOI(O_DAY, &clock->day) || + STOI(O_MONTH, &clock->month) || + STOI(O_YEAR, &clock->year) || + STOI(O_HOUR, &clock->hour) || + STOI(O_MIN, &clock->minute) || + STOI(O_SEC, &clock->second) || + STOI(O_USEC, &clock->usecond)|| + STOI(O_GPSFIX, &gpsfix) + ) return CVT_FAIL|CVT_BADFMT; + + clock->usecond *= 1000; + /* Check that the checksum is right */ + for (i=OFFS(O_CHKSUM)-1; i >= 0; i--) calc_csum ^= buffer[i]; + recv_csum = (hexval(buffer[OFFS(O_CHKSUM)]) << 4) | + hexval(buffer[OFFS(O_CHKSUM)+1]); + if (recv_csum < 0) return CVT_FAIL|CVT_BADTIME; + if (((u_char) recv_csum) != calc_csum) return CVT_FAIL|CVT_BADTIME; + + clock->utcoffset = 0; + + /* What should flags be set to ? */ + clock->flags = PARSEB_UTC; + + /* if the current GPS fix is 9 (unknown), reject */ + if (0 > gpsfix || gpsfix > 9) clock->flags |= PARSEB_POWERUP; + + return CVT_OK; +} +#endif /* defined(PARSE) && defined(CLOCK_TRIMSV6) */ + +/* + * History: + * + * clk_trimble.c,v + * Revision 3.6 1993/10/30 09:44:45 kardel + * conditional compilation flag cleanup + * + * Revision 3.5 1993/10/09 15:01:35 kardel + * file structure unified + * + * revision 3.4 + * date: 1993/10/08 14:44:51; author: kardel; + * trimble - initial working version + * + * revision 3.3 + * date: 1993/10/03 19:10:50; author: kardel; + * restructured I/O handling + * + * revision 3.2 + * date: 1993/09/27 21:07:17; author: kardel; + * Trimble alpha integration + * + * revision 3.1 + * date: 1993/09/26 23:40:29; author: kardel; + * new parse driver logic + * + */ diff --git a/contrib/xntpd/parse/empty.c b/contrib/xntpd/parse/empty.c new file mode 100644 index 0000000000..91b777afe7 --- /dev/null +++ b/contrib/xntpd/parse/empty.c @@ -0,0 +1,7 @@ +/* + * Well, some ranlibs, ar's or compilers react funny + * if asked to do nothing but build empty valid files + * I would have preferred to a no or at least a static + * symbol here... + */ +char * _____empty__ = "empty .o file"; diff --git a/contrib/xntpd/parse/parse.c b/contrib/xntpd/parse/parse.c new file mode 100644 index 0000000000..7a360021e1 --- /dev/null +++ b/contrib/xntpd/parse/parse.c @@ -0,0 +1,1193 @@ +#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) +/* + * /src/NTP/REPOSITORY/v3/parse/parse.c,v 3.17 1993/11/11 11:20:29 kardel Exp + * + * parse.c,v 3.17 1993/11/11 11:20:29 kardel Exp + * + * Parser module for reference clock + * + * PARSEKERNEL define switches between two personalities of the module + * if PARSEKERNEL is defined this module can be used with dcf77sync.c as + * a PARSEKERNEL kernel module. In this case the time stamps will be + * a struct timeval. + * when PARSEKERNEL is not defined NTP time stamps will be used. + * + * Copyright (c) 1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#if !(defined(lint) || defined(__GNUC__)) +static char rcsid[] = "parse.c,v 3.17 1993/11/11 11:20:29 kardel Exp"; +#endif + +#include "sys/types.h" +#include "sys/time.h" +#include "sys/errno.h" + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +#if defined(PARSESTREAM) && (defined(SYS_SUNOS4) || defined(SYS_SOLARIS)) && defined(STREAM) +/* + * Sorry, but in SunOS 4.x kernels there are no + * mem* operations. I don't want them - bcopy, bzero + * are fine in the kernel + */ +#define _ntp_string_h +extern void bcopy(); +extern void bzero(); +#endif + +#include "ntp_stdlib.h" + +#ifdef PARSESTREAM +#include "sys/parsestreams.h" +#endif + +extern clockformat_t *clockformats[]; +extern unsigned short nformats; + +static unsigned LONG timepacket(); + +/* + * strings support usually not in kernel - duplicated, but what the heck + */ +static int +Strlen(s) + register char *s; +{ + register int c; + + c = 0; + if (s) + { + while (*s++) + { + c++; + } + } + return c; +} + +static int +Strcmp(s, t) + register char *s; + register char *t; +{ + register int c = 0; + + if (!s || !t || (s == t)) + { + return 0; + } + + while (!(c = *s++ - *t++) && *s && *t) + /* empty loop */; + + return c; +} + +static int +timedout(parseio, ctime) + register parse_t *parseio; + register timestamp_t *ctime; +{ + struct timeval delta; + +#ifdef PARSEKERNEL + delta.tv_sec = ctime->tv.tv_sec - parseio->parse_lastchar.tv.tv_sec; + delta.tv_usec = ctime->tv.tv_usec - parseio->parse_lastchar.tv.tv_usec; + if (delta.tv_usec < 0) + { + delta.tv_sec -= 1; + delta.tv_usec += 1000000; + } +#else + extern LONG tstouslo[]; + extern LONG tstousmid[]; + extern LONG tstoushi[]; + + l_fp delt; + + delt = ctime->fp; + L_SUB(&delt, &parseio->parse_lastchar.fp); + TSTOTV(&delt, &delta); +#endif + + if (timercmp(&delta, &parseio->parse_timeout, >)) + { + parseprintf(DD_PARSE, ("parse: timedout: TRUE\n")); + return 1; + } + else + { + parseprintf(DD_PARSE, ("parse: timedout: FALSE\n")); + return 0; + } +} + +/* + * setup_bitmaps + */ +static int +setup_bitmaps(parseio, low, high) + register parse_t *parseio; + register unsigned short low; + register unsigned short high; +{ + register unsigned short i; + register int f = 0; + register clockformat_t *fmt; + register unsigned index, mask; + + if ((low >= high) || + (high > nformats)) + { + parseprintf(DD_PARSE, ("setup_bitmaps: failed: bounds error (low=%d, high=%d, nformats=%d)\n", low, high, nformats)); + return 0; + } + + bzero(parseio->parse_startsym, sizeof (parseio->parse_startsym)); + bzero(parseio->parse_endsym, sizeof (parseio->parse_endsym)); + bzero(parseio->parse_syncsym, sizeof (parseio->parse_syncsym)); + parseio->parse_syncflags = 0; + parseio->parse_timeout.tv_sec = 0; + parseio->parse_timeout.tv_usec = 0; + + /* + * gather bitmaps of possible start and end values + */ + for (i=low; i < high; i++) + { + fmt = clockformats[i]; + + if (fmt->flags & F_START) + { + index = fmt->startsym / 8; + mask = 1 << (fmt->startsym % 8); + + if (parseio->parse_endsym[index] & mask) + { +#ifdef PARSEKERNEL + printf("parse: setup_bitmaps: failed: START symbol collides with END symbol (format %d)\n", i); +#else + syslog(LOG_ERR, "parse: setup_bitmaps: failed: START symbol collides with END symbol (format %d)\n", i); +#endif + return 0; + } + else + { + parseio->parse_startsym[index] |= mask; + f = 1; + } + } + + if (fmt->flags & F_END) + { + index = fmt->endsym / 8; + mask = 1 << (fmt->endsym % 8); + + if (parseio->parse_startsym[index] & mask) + { +#ifdef PARSEKERNEL + printf("parse: setup_bitmaps: failed: END symbol collides with START symbol (format %d)\n", i); +#else + syslog(LOG_ERR, "parse: setup_bitmaps: failed: END symbol collides with START symbol (format %d)\n", i); +#endif + return 0; + } + else + { + parseio->parse_endsym[index] |= mask; + f = 1; + } + } + + if (fmt->flags & SYNC_CHAR) + { + parseio->parse_syncsym[fmt->syncsym / 8] |= (1 << (fmt->syncsym % 8)); + } + + parseio->parse_syncflags |= fmt->flags & (SYNC_START|SYNC_END|SYNC_CHAR|SYNC_ONE|SYNC_ZERO|SYNC_TIMEOUT|SYNC_SYNTHESIZE); + + if ((fmt->flags & SYNC_TIMEOUT) && + ((parseio->parse_timeout.tv_sec || parseio->parse_timeout.tv_usec) ? timercmp(&parseio->parse_timeout, &fmt->timeout, >) : 1)) + { + parseio->parse_timeout = fmt->timeout; + } + + if (parseio->parse_dsize < fmt->length) + parseio->parse_dsize = fmt->length; + } + + if (!f && ((int)(high - low) > 1)) + { + /* + * need at least one start or end symbol + */ +#ifdef PARSEKERNEL + printf("parse: setup_bitmaps: failed: neither START nor END symbol defined\n"); +#else + syslog(LOG_ERR, "parse: setup_bitmaps: failed: neither START nor END symbol defined\n"); +#endif + return 0; + } + + return 1; +} + +/*ARGSUSED*/ +int +parse_ioinit(parseio) + register parse_t *parseio; +{ + parseprintf(DD_PARSE, ("parse_iostart\n")); + + if (!setup_bitmaps(parseio, 0, nformats)) + return 0; + + parseio->parse_data = MALLOC(parseio->parse_dsize * 2 + 2); + if (!parseio->parse_data) + { + parseprintf(DD_PARSE, ("init failed: malloc for data area failed\n")); + return 0; + } + + /* + * leave room for '\0' + */ + parseio->parse_ldata = parseio->parse_data + parseio->parse_dsize + 1; + parseio->parse_lformat = 0; + parseio->parse_badformat = 0; + parseio->parse_ioflags = PARSE_IO_CS7; /* usual unix default */ + parseio->parse_flags = 0; /* true samples */ + parseio->parse_index = 0; + parseio->parse_ldsize = 0; + + return 1; +} + +/*ARGSUSED*/ +void +parse_ioend(parseio) + register parse_t *parseio; +{ + parseprintf(DD_PARSE, ("parse_ioend\n")); + if (parseio->parse_data) + FREE(parseio->parse_data, parseio->parse_dsize * 2 + 2); +} + +/*ARGSUSED*/ +int +parse_ioread(parseio, ch, ctime) + register parse_t *parseio; + register unsigned char ch; + register timestamp_t *ctime; +{ + register unsigned updated = CVT_NONE; + register unsigned short low, high; + register unsigned index, mask; + + parseprintf(DD_PARSE, ("parse_ioread(0x%x, char=0x%x, ..., ...)\n", (unsigned int)parseio, ch & 0xFF)); + + if (parseio->parse_flags & PARSE_FIXED_FMT) + { + if (!clockformats[parseio->parse_lformat]->convert) + { + parseprintf(DD_PARSE, ("parse_ioread: input dropped.\n")); + return CVT_NONE; + } + low = parseio->parse_lformat; + high = low + 1; + } + else + { + low = 0; + high = nformats; + } + + /* + * within STREAMS CSx (x < 8) chars still have the upper bits set + * so we normalize the characters by masking unecessary bits off. + */ + switch (parseio->parse_ioflags & PARSE_IO_CSIZE) + { + case PARSE_IO_CS5: + ch &= 0x1F; + break; + + case PARSE_IO_CS6: + ch &= 0x3F; + break; + + case PARSE_IO_CS7: + ch &= 0x7F; + break; + + case PARSE_IO_CS8: + break; + } + + index = ch / 8; + mask = 1 << (ch % 8); + + if ((parseio->parse_syncflags & SYNC_CHAR) && + (parseio->parse_syncsym[index] & mask)) + { + register clockformat_t *fmt; + register unsigned short i; + /* + * got a sync event - call sync routine + */ + + for (i = low; i < high; i++) + { + fmt = clockformats[i]; + + if ((fmt->flags & SYNC_CHAR) && + (fmt->syncsym == ch)) + { + parseprintf(DD_PARSE, ("parse_ioread: SYNC_CHAR event\n")); + if (fmt->syncevt) + fmt->syncevt(parseio, ctime, fmt->data, SYNC_CHAR); + } + } + } + + if ((((parseio->parse_syncflags & SYNC_START) && + (parseio->parse_startsym[index] & mask)) || + (parseio->parse_index == 0)) || + ((parseio->parse_syncflags & SYNC_TIMEOUT) && + timedout(parseio, ctime))) + { + register unsigned short i; + /* + * packet start - re-fill buffer + */ + if (parseio->parse_index) + { + /* + * filled buffer - thus not end character found + * do processing now + */ + parseio->parse_data[parseio->parse_index] = '\0'; + + updated = timepacket(parseio); + bcopy(parseio->parse_data, parseio->parse_ldata, parseio->parse_index+1); + parseio->parse_ldsize = parseio->parse_index+1; + if (parseio->parse_syncflags & SYNC_TIMEOUT) + parseio->parse_dtime.parse_stime = *ctime; + } + + /* + * could be a sync event - call sync routine if needed + */ + if (parseio->parse_syncflags & SYNC_START) + for (i = low; i < high; i++) + { + register clockformat_t *fmt = clockformats[i]; + + if ((parseio->parse_index == 0) || + ((fmt->flags & SYNC_START) && (fmt->startsym == ch))) + { + parseprintf(DD_PARSE, ("parse_ioread: SYNC_START event\n")); + if (fmt->syncevt) + fmt->syncevt(parseio, ctime, fmt->data, SYNC_START); + } + } + parseio->parse_index = 1; + parseio->parse_data[0] = ch; + parseprintf(DD_PARSE, ("parse: parse_ioread: buffer start\n")); + } + else + { + register unsigned short i; + + if (parseio->parse_index < parseio->parse_dsize) + { + /* + * collect into buffer + */ + parseprintf(DD_PARSE, ("parse: parse_ioread: buffer[%d] = 0x%x\n", parseio->parse_index, ch)); + parseio->parse_data[parseio->parse_index++] = ch; + } + + if ((parseio->parse_endsym[index] & mask) || + (parseio->parse_index >= parseio->parse_dsize)) + { + /* + * packet end - process buffer + */ + if (parseio->parse_syncflags & SYNC_END) + for (i = low; i < high; i++) + { + register clockformat_t *fmt = clockformats[i]; + + if ((fmt->flags & SYNC_END) && (fmt->endsym == ch)) + { + parseprintf(DD_PARSE, ("parse_ioread: SYNC_END event\n")); + if (fmt->syncevt) + fmt->syncevt(parseio, ctime, fmt->data, SYNC_END); + } + } + parseio->parse_data[parseio->parse_index] = '\0'; + updated = timepacket(parseio); + bcopy(parseio->parse_data, parseio->parse_ldata, parseio->parse_index+1); + parseio->parse_ldsize = parseio->parse_index+1; + parseio->parse_index = 0; + parseprintf(DD_PARSE, ("parse: parse_ioread: buffer end\n")); + } + } + + if ((updated == CVT_NONE) && + (parseio->parse_flags & PARSE_FIXED_FMT) && + (parseio->parse_syncflags & SYNC_SYNTHESIZE) && + ((parseio->parse_dtime.parse_status & CVT_MASK) == CVT_OK) && + clockformats[parseio->parse_lformat]->synth) + { + updated = clockformats[parseio->parse_lformat]->synth(parseio, ctime); + } + + /* + * remember last character time + */ + parseio->parse_lastchar = *ctime; + +#ifdef DEBUG + if ((updated & CVT_MASK) != CVT_NONE) + parseprintf(DD_PARSE, ("parse_ioread: time sample accumulated (status=0x%x)\n", updated)); +#endif + + parseio->parse_dtime.parse_status = updated; + + return (updated & CVT_MASK) != CVT_NONE; +} + +/* + * parse_iopps + * + * take status line indication and derive synchronisation information + * from it. + * It can also be used to decode a serial serial data format (such as the + * ONE, ZERO, MINUTE sync data stream from DCF77) + */ +/*ARGSUSED*/ +int +parse_iopps(parseio, status, ptime) + register parse_t *parseio; + register int status; + register timestamp_t *ptime; +{ + register unsigned updated = CVT_NONE; + + /* + * PPS pulse information will only be delivered to ONE clock format + * this is either the last successful conversion module with a ppssync + * routine, or a fixed format with a ppssync routine + */ + parseprintf(DD_PARSE, ("parse_iopps: STATUS %s\n", (status == SYNC_ONE) ? "ONE" : "ZERO")); + + if (((parseio->parse_flags & PARSE_FIXED_FMT) || + ((parseio->parse_dtime.parse_status & CVT_MASK) == CVT_OK)) && + clockformats[parseio->parse_lformat]->syncpps && + (status & clockformats[parseio->parse_lformat]->flags)) + { + updated = clockformats[parseio->parse_lformat]->syncpps(parseio, status == SYNC_ONE, ptime); + parseprintf(DD_PARSE, ("parse_iopps: updated = 0x%x\n", updated)); + } + else + { + parseprintf(DD_PARSE, ("parse_iopps: STATUS dropped\n")); + } + + return (updated & CVT_MASK) != CVT_NONE; +} + +/* + * parse_iodone + * + * clean up internal status for new round + */ +/*ARGSUSED*/ +void +parse_iodone(parseio) + register parse_t *parseio; +{ + /* + * we need to clean up certain flags for the next round + */ + parseio->parse_dtime.parse_state = 0; /* no problems with ISRs */ +} + +/*---------- conversion implementation --------------------*/ + +/* + * convert a struct clock to UTC since Jan, 1st 1970 0:00 (the UNIX EPOCH) + */ +#define dysize(x) ((x) % 4 ? 365 : ((x % 400) ? 365 :366)) + +time_t +parse_to_unixtime(clock, cvtrtc) + register clocktime_t *clock; + register unsigned LONG *cvtrtc; +{ +#define SETRTC(_X_) { if (cvtrtc) *cvtrtc = (_X_); } + static int days_of_month[] = + { + 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + register int i; + time_t t; + + if (clock->year < 100) + clock->year += 1900; + + if (clock->year < 1970) + clock->year += 100; /* XXX this will do it till <2070 */ + + if (clock->year < 0) + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; + } + + /* + * sorry, slow section here - but it's not time critical anyway + */ + t = (clock->year - 1970) * 365; + t += (clock->year >> 2) - (1970 >> 2); + t -= clock->year / 400 - 1970 / 400; + + /* month */ + if (clock->month <= 0 || clock->month > 12) + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; /* bad month */ + } + /* adjust leap year */ + if (clock->month >= 3 && dysize(clock->year) == 366) + t++; + + for (i = 1; i < clock->month; i++) + { + t += days_of_month[i]; + } + /* day */ + if (clock->day < 1 || ((clock->month == 2 && dysize(clock->year) == 366) ? + clock->day > 29 : clock->day > days_of_month[clock->month])) + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; /* bad day */ + } + + t += clock->day - 1; + /* hour */ + if (clock->hour < 0 || clock->hour >= 24) + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad hour */ + } + + t = TIMES24(t) + clock->hour; + + /* min */ + if (clock->minute < 0 || clock->minute > 59) + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad min */ + } + + t = TIMES60(t) + clock->minute; + /* sec */ + + if (clock->second < 0 || clock->second > 60) /* allow for LEAPs */ + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad sec */ + } + + t = TIMES60(t) + clock->second; + + t += clock->utcoffset; /* warp to UTC */ + + /* done */ + return t; +} + +/*--------------- format conversion -----------------------------------*/ + +int +Stoi(s, zp, cnt) + char *s; + LONG *zp; + int cnt; +{ + char *b = s; + int f,z,v; + char c; + + f=z=v=0; + + while(*s == ' ') + s++; + + if (*s == '-') + { + s++; + v = 1; + } + else + if (*s == '+') + s++; + + for(;;) + { + c = *s++; + if (c == '\0' || c < '0' || c > '9' || (cnt && ((s-b) > cnt))) + { + if (f == 0) + { + return(-1); + } + if (v) + z = -z; + *zp = z; + return(0); + } + z = (z << 3) + (z << 1) + ( c - '0' ); + f=1; + } +} + + +int +Strok(s, m) + char *s; + char *m; +{ + if (!s || !m) + return 0; + + while(*s && *m) + { + if ((*m == ' ') ? 1 : (*s == *m)) + { + s++; + m++; + } + else + { + return 0; + } + } + return !*m; +} + +unsigned LONG +updatetimeinfo(parseio, t, usec, flags) + register parse_t *parseio; + register time_t t; + register unsigned LONG usec; + register unsigned LONG flags; +{ + register LONG usecoff; + register LONG mean; + LONG delta[PARSE_DELTA]; + +#ifdef PARSEKERNEL + usecoff = (t - parseio->parse_dtime.parse_stime.tv.tv_sec) * 1000000 + - parseio->parse_dtime.parse_stime.tv.tv_usec + usec; +#else + extern LONG tstouslo[]; + extern LONG tstousmid[]; + extern LONG tstoushi[]; + + TSFTOTVU(parseio->parse_dtime.parse_stime.fp.l_uf, usecoff); + usecoff = -usecoff; + usecoff += (t - parseio->parse_dtime.parse_stime.fp.l_ui + JAN_1970) * 1000000 + + usec; +#endif + + /* + * filtering (median) if requested + */ + if (parseio->parse_flags & PARSE_STAT_FILTER) + { + register int n, i, s, k; + + parseio->parse_delta[parseio->parse_dindex] = usecoff; + + parseio->parse_dindex = (parseio->parse_dindex + 1) % PARSE_DELTA; + + /* + * sort always - thus every sample gets its data + */ + bcopy((caddr_t)parseio->parse_delta, (caddr_t)delta, sizeof(delta)); + + for (s = 0; s < PARSE_DELTA; s++) + for (k = s+1; k < PARSE_DELTA; k++) + { /* Yes - it's slow sort */ + if (delta[s] > delta[k]) + { + register LONG tmp; + + tmp = delta[k]; + delta[k] = delta[s]; + delta[s] = tmp; + } + } + + i = 0; + n = PARSE_DELTA; + + /* + * you know this median loop if you have read the other code + */ + while ((n - i) > 8) + { + register LONG top = delta[n-1]; + register LONG mid = delta[(n+i)>>1]; + register LONG low = delta[i]; + + if ((top - mid) > (mid - low)) + { + /* + * cut off high end + */ + n--; + } + else + { + /* + * cut off low end + */ + i++; + } + } + + parseio->parse_dtime.parse_usecdisp = delta[n-1] - delta[i]; + + if (parseio->parse_flags & PARSE_STAT_AVG) + { + /* + * take the average of the median samples as this clock + * is a little bumpy + */ + mean = 0; + + while (i < n) + { + mean += delta[i++]; + } + + mean >>= 3; + } + else + { + mean = delta[(n+i)>>1]; + } + + parseio->parse_dtime.parse_usecerror = mean; + } + else + { + parseio->parse_dtime.parse_usecerror = usecoff; + parseio->parse_dtime.parse_usecdisp = 0; + } + + parseprintf(DD_PARSE,("parse: updatetimeinfo: T=%x+%d usec, useccoff=%d, usecerror=%d, usecdisp=%d\n", + t, usec, usecoff, parseio->parse_dtime.parse_usecerror, parseio->parse_dtime.parse_usecdisp)); + + +#ifdef PARSEKERNEL + { + int s = splhigh(); +#endif + + parseio->parse_lstate = parseio->parse_dtime.parse_state | flags | PARSEB_TIMECODE; + + parseio->parse_dtime.parse_state = parseio->parse_lstate; + +#ifdef PARSEKERNEL + (void)splx(s); + } +#endif + + return CVT_OK; /* everything fine and dandy... */ +} + + +/* + * syn_simple + * + * handle a sync time stamp + */ +/*ARGSUSED*/ +void +syn_simple(parseio, ts, format, why) + register parse_t *parseio; + register timestamp_t *ts; + register struct format *format; + register unsigned LONG why; +{ + parseio->parse_dtime.parse_stime = *ts; +} + +/* + * pps_simple + * + * handle a pps time stamp + */ +/*ARGSUSED*/ +unsigned LONG +pps_simple(parseio, status, ptime) + register parse_t *parseio; + register int status; + register timestamp_t *ptime; +{ + parseio->parse_dtime.parse_ptime = *ptime; + parseio->parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; + + return CVT_NONE; +} + +/* + * timepacket + * + * process a data packet + */ +static unsigned LONG +timepacket(parseio) + register parse_t *parseio; +{ + register int k; + register unsigned short format; + register time_t t; + register unsigned LONG cvtsum = 0;/* accumulated CVT_FAIL errors */ + unsigned LONG cvtrtc; /* current conversion result */ + clocktime_t clock; + + format = parseio->parse_lformat; + + k = 0; + + if (parseio->parse_flags & PARSE_FIXED_FMT) + { + switch ((cvtrtc = clockformats[format]->convert ? clockformats[format]->convert(parseio->parse_data, parseio->parse_index, clockformats[format]->data, &clock) : CVT_NONE) & CVT_MASK) + { + case CVT_FAIL: + parseio->parse_badformat++; + cvtsum = cvtrtc & ~CVT_MASK; + + /* + * may be too often ... but is nice to know when it happens + */ +#ifdef PARSEKERNEL + printf("parse: \"%s\" failed to convert\n", clockformats[format]->name); +#else + syslog(LOG_WARNING, "parse: \"%s\" failed to convert\n", clockformats[format]->name); +#endif + break; + + case CVT_NONE: + /* + * too bad - pretend bad format + */ + parseio->parse_badformat++; + cvtsum = CVT_BADFMT; + + break; + + case CVT_OK: + k = 1; + break; + + default: + /* shouldn't happen */ +#ifdef PARSEKERNEL + printf("parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format]->name); +#else + syslog(LOG_WARNING, "parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format]->name); +#endif + return CVT_FAIL|cvtrtc; + } + } + else + { + /* + * find correct conversion routine + * and convert time packet + * RR search starting at last successful conversion routine + */ + + if (nformats) /* very careful ... */ + { + do + { + switch ((cvtrtc = (clockformats[format]->convert && !(clockformats[format]->flags & CVT_FIXEDONLY)) ? + clockformats[format]->convert(parseio->parse_data, parseio->parse_index, clockformats[format]->data, &clock) : + CVT_NONE) & CVT_MASK) + { + case CVT_FAIL: + parseio->parse_badformat++; + cvtsum |= cvtrtc & ~CVT_MASK; + + /* + * may be too often ... but is nice to know when it happens + */ +#ifdef PARSEKERNEL + printf("parse: \"%s\" failed to convert\n", clockformats[format]->name); +#else + syslog(LOG_WARNING, "parse: \"%s\" failed to convert\n", clockformats[format]->name); +#endif + /*FALLTHROUGH*/ + case CVT_NONE: + format++; + break; + + case CVT_OK: + k = 1; + break; + + default: + /* shouldn't happen */ +#ifdef PARSEKERNEL + printf("parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format]->name); +#else + syslog(LOG_WARNING, "parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format]->name); +#endif + return CVT_BADFMT; + } + if (format >= nformats) + format = 0; + } + while (!k && (format != parseio->parse_lformat)); + } + } + + if (!k) + { +#ifdef PARSEKERNEL + printf("parse: time format \"%s\" not convertable\n", parseio->parse_data); +#else + syslog(LOG_WARNING, "parse: time format \"%s\" not convertable\n", parseio->parse_data); +#endif + return CVT_FAIL|cvtsum; + } + + if ((t = parse_to_unixtime(&clock, &cvtrtc)) == -1) + { +#ifdef PARSEKERNEL + printf("parse: bad time format \"%s\"\n", parseio->parse_data); +#else + syslog(LOG_WARNING,"parse: bad time format \"%s\"\n", parseio->parse_data); +#endif + return CVT_FAIL|cvtrtc; + } + + parseio->parse_lformat = format; + + /* + * time stamp + */ +#ifdef PARSEKERNEL + parseio->parse_dtime.parse_time.tv.tv_sec = t; + parseio->parse_dtime.parse_time.tv.tv_usec = clock.usecond; +#else + parseio->parse_dtime.parse_time.fp.l_ui = t + JAN_1970; + TVUTOTSF(clock.usecond, parseio->parse_dtime.parse_time.fp.l_uf); +#endif + + parseio->parse_dtime.parse_format = format; + + return updatetimeinfo(parseio, t, clock.usecond, clock.flags); +} + + +/* + * control operations + */ +/*ARGSUSED*/ +int +parse_getstat(dct, parse) + parsectl_t *dct; + parse_t *parse; +{ + dct->parsestatus.flags = parse->parse_flags & PARSE_STAT_FLAGS; + return 1; +} + + +/*ARGSUSED*/ +int +parse_setstat(dct, parse) + parsectl_t *dct; + parse_t *parse; +{ + parse->parse_flags = (parse->parse_flags & ~PARSE_STAT_FLAGS) | dct->parsestatus.flags; + return 1; +} + + +/*ARGSUSED*/ +int +parse_timecode(dct, parse) + parsectl_t *dct; + parse_t *parse; +{ + dct->parsegettc.parse_state = parse->parse_lstate; + dct->parsegettc.parse_format = parse->parse_lformat; + /* + * move out current bad packet count + * user program is expected to sum these up + * this is not a problem, as "parse" module are + * exclusive open only + */ + dct->parsegettc.parse_badformat = parse->parse_badformat; + parse->parse_badformat = 0; + + if (parse->parse_ldsize <= PARSE_TCMAX) + { + dct->parsegettc.parse_count = parse->parse_ldsize; + bcopy(parse->parse_ldata, dct->parsegettc.parse_buffer, dct->parsegettc.parse_count); + return 1; + } + else + { + return 0; + } +} + + +/*ARGSUSED*/ +int +parse_setfmt(dct, parse) + parsectl_t *dct; + parse_t *parse; +{ + if (dct->parseformat.parse_count <= PARSE_TCMAX) + { + if (dct->parseformat.parse_count) + { + register unsigned short i; + + for (i = 0; i < nformats; i++) + { + if (!Strcmp(dct->parseformat.parse_buffer, clockformats[i]->name)) + { + parse->parse_lformat = i; + parse->parse_flags |= PARSE_FIXED_FMT; /* set fixed format indication */ + return setup_bitmaps(parse, i, i+1); + } + } + + return 0; + } + else + { + parse->parse_flags &= ~PARSE_FIXED_FMT; /* clear fixed format indication */ + return setup_bitmaps(parse, 0, nformats); + } + } + else + { + return 0; + } +} + +/*ARGSUSED*/ +int +parse_getfmt(dct, parse) + parsectl_t *dct; + parse_t *parse; +{ + if (dct->parseformat.parse_format < nformats && + Strlen(clockformats[dct->parseformat.parse_format]->name) <= PARSE_TCMAX) + { + dct->parseformat.parse_count = Strlen(clockformats[dct->parseformat.parse_format]->name)+1; + bcopy(clockformats[dct->parseformat.parse_format]->name, dct->parseformat.parse_buffer, dct->parseformat.parse_count); + return 1; + } + else + { + return 0; + } +} + +/*ARGSUSED*/ +int +parse_setcs(dct, parse) + parsectl_t *dct; + parse_t *parse; +{ + parse->parse_ioflags &= ~PARSE_IO_CSIZE; + parse->parse_ioflags |= dct->parsesetcs.parse_cs & PARSE_IO_CSIZE; + return 1; +} + +#endif /* defined(REFCLOCK) && defined(PARSE) */ + +/* + * History: + * + * parse.c,v + * Revision 3.17 1993/11/11 11:20:29 kardel + * declaration fixes + * + * Revision 3.16 1993/11/06 22:26:07 duwe + * Linux cleanup after config change + * + * Revision 3.15 1993/11/04 11:14:18 kardel + * ansi/K&R traps + * + * Revision 3.14 1993/11/04 10:03:28 kardel + * disarmed ansiism + * + * Revision 3.13 1993/11/01 20:14:13 kardel + * useless comparision removed + * + * Revision 3.12 1993/11/01 20:00:22 kardel + * parse Solaris support (initial version) + * + * Revision 3.11 1993/10/30 09:41:25 kardel + * minor optimizations + * + * Revision 3.10 1993/10/22 14:27:51 kardel + * Oct. 22nd 1993 reconcilation + * + * Revision 3.9 1993/10/05 23:15:09 kardel + * more STREAM protection + * + * Revision 3.8 1993/09/27 21:08:00 kardel + * utcoffset now in seconds + * + * Revision 3.7 1993/09/26 23:40:16 kardel + * new parse driver logic + * + * Revision 3.6 1993/09/07 10:12:46 kardel + * September 7th reconcilation - 3.2 (alpha) + * + * Revision 3.5 1993/09/01 21:44:48 kardel + * conditional cleanup + * + * Revision 3.4 1993/08/27 00:29:39 kardel + * compilation cleanup + * + * Revision 3.3 1993/08/24 22:27:13 kardel + * cleaned up AUTOCONF DCF77 mess 8-) - wasn't too bad + * + * Revision 3.2 1993/07/09 11:37:11 kardel + * Initial restructured version + GPS support + * + * Revision 3.1 1993/07/06 10:00:08 kardel + * DCF77 driver goes generic... + * + */ diff --git a/contrib/xntpd/parse/parse_conf.c b/contrib/xntpd/parse/parse_conf.c new file mode 100644 index 0000000000..78ddb3a1c9 --- /dev/null +++ b/contrib/xntpd/parse/parse_conf.c @@ -0,0 +1,117 @@ +#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) +/* + * /src/NTP/REPOSITORY/v3/parse/parse_conf.c,v 3.11 1993/11/01 20:00:24 kardel Exp + * + * parse_conf.c,v 3.11 1993/11/01 20:00:24 kardel Exp + * + * Parser configuration module for reference clocks + * + * STREAM define switches between two personalities of the module + * if STREAM is defined this module can be used with dcf77sync.c as + * a STREAMS kernel module. In this case the time stamps will be + * a struct timeval. + * when STREAM is not defined NTP time stamps will be used. + * + * Copyright (c) 1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#include "sys/types.h" +#include "sys/time.h" +#include "sys/errno.h" +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +#ifdef CLOCK_SCHMID +extern clockformat_t clock_schmid; +#endif + +#ifdef CLOCK_DCF7000 +extern clockformat_t clock_dcf7000; +#endif + +#ifdef CLOCK_MEINBERG +extern clockformat_t clock_meinberg[]; +#endif + +#ifdef CLOCK_RAWDCF +extern clockformat_t clock_rawdcf; +#endif + +#ifdef CLOCK_TRIMSV6 +extern clockformat_t clock_trimsv6; +#endif + +/* + * format definitions + */ +clockformat_t *clockformats[] = +{ +#ifdef CLOCK_MEINBERG + &clock_meinberg[0], + &clock_meinberg[1], + &clock_meinberg[2], +#endif +#ifdef CLOCK_DCF7000 + &clock_dcf7000, +#endif +#ifdef CLOCK_SCHMID + &clock_schmid, +#endif +#ifdef CLOCK_RAWDCF + &clock_rawdcf, +#endif +#ifdef CLOCK_TRIMSV6 + &clock_trimsv6, +#endif +0}; + +unsigned short nformats = sizeof(clockformats) / sizeof(clockformats[0]) - 1; +#endif /* REFCLOCK PARSE */ + +/* + * History: + * + * parse_conf.c,v + * Revision 3.11 1993/11/01 20:00:24 kardel + * parse Solaris support (initial version) + * + * Revision 3.10 1993/10/09 15:01:37 kardel + * file structure unified + * + * Revision 3.9 1993/09/26 23:40:19 kardel + * new parse driver logic + * + * Revision 3.8 1993/09/02 23:20:57 kardel + * dragon extiction + * + * Revision 3.7 1993/09/01 21:44:52 kardel + * conditional cleanup + * + * Revision 3.6 1993/09/01 11:25:09 kardel + * patch accident 8-( + * + * Revision 3.5 1993/08/31 22:31:14 kardel + * SINIX-M SysVR4 integration + * + * Revision 3.4 1993/08/27 00:29:42 kardel + * compilation cleanup + * + * Revision 3.3 1993/07/14 09:04:45 kardel + * only when REFCLOCK && PARSE is defined + * + * Revision 3.2 1993/07/09 11:37:13 kardel + * Initial restructured version + GPS support + * + * Revision 3.1 1993/07/06 10:00:11 kardel + * DCF77 driver goes generic... + * + */ diff --git a/contrib/xntpd/parse/parsesolaris.c b/contrib/xntpd/parse/parsesolaris.c new file mode 100644 index 0000000000..0da27e7a08 --- /dev/null +++ b/contrib/xntpd/parse/parsesolaris.c @@ -0,0 +1,1170 @@ +/* + * /src/NTP/REPOSITORY/v3/parse/parsesolaris.c,v 3.4 1993/11/13 11:13:17 kardel Exp + * + * parsesolaris.c,v 3.4 1993/11/13 11:13:17 kardel Exp + * + * STREAMS module for reference clocks + * (SunOS5.x - not fully tested - buyer beware ! - OS KILLERS may still be + * lurking in the code!) + * + * Copyright (c) 1993 + * derived work from parsestreams.c ((c) 1991-1993, Frank Kardel) and + * dcf77sync.c((c) Frank Kardel) + * Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#ifndef lint +static char rcsid[] = "parsesolaris.c,v 3.4 1993/11/13 11:13:17 kardel Exp"; +#endif + +/* + * Well, the man spec says we have to do this junk - the + * header files tell a different story (i like that one more) + */ +#define SAFE_WR(q) (((q)->q_flag & QREADR) ? WR((q)) : (q)) +#define SAFE_RD(q) (((q)->q_flag & QREADR) ? (q) : RD((q))) + +/* + * needed to cope with Solaris 2.3 header file chaos + */ +#include +/* + * the Solaris 2.2 include list + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STREAM /* that's what we are here for */ + +#define HAVE_NO_NICE /* for the NTP headerfiles */ +#include "ntp_fp.h" +#include "parse.h" +#include "sys/parsestreams.h" + +static unsigned int parsebusy = 0; + +/*--------------- loadable driver section -----------------------------*/ + +static struct streamtab parseinfo; + +static struct fmodsw fmod_templ = +{ + "parse", /* module name */ + &parseinfo, /* module information */ + 0, /* not clean yet */ + /* lock ptr */ +}; + +extern struct mod_ops mod_strmodops; + +static struct modlstrmod modlstrmod = +{ + &mod_strmodops, /* a STREAMS module */ + "PARSE - NTP reference", /* name this baby - keep room for revision number */ + &fmod_templ +}; + +static struct modlinkage modlinkage = +{ + MODREV_1, + &modlstrmod, + NULL +}; + +/* + * strings support usually not in kernel + */ +static int Strlen(s) + register char *s; +{ + register int c; + + c = 0; + if (s) + { + while (*s++) + { + c++; + } + } + return c; +} + +static void Strncpy(t, s, c) + register char *t; + register char *s; + register int c; +{ + if (s && t) + { + while ((c-- > 0) && (*t++ = *s++)) + ; + } +} + +int Strcmp(s, t) + register char *s; + register char *t; +{ + register int c = 0; + + if (!s || !t || (s == t)) + { + return 0; + } + + while (!(c = *s++ - *t++) && *s && *t) + /* empty loop */; + + return c; +} + +/* + * module management routines + */ +/*ARGSUSED*/ +int _init(void) +{ + static char revision[] = "3.4"; + char *s, *S, *t; + + /* + * copy RCS revision into Drv_name + * + * are we forcing RCS here to do things it was not built for ? + */ + s = revision; + if (*s == '$') + { + /* + * skip "$Revision: " + * if present. - not necessary on a -kv co (cvs export) + */ + while (*s && (*s != ' ')) + { + s++; + } + if (*s == ' ') s++; + } + + t = modlstrmod.strmod_linkinfo; + while (*t && (*t != ' ')) + { + t++; + } + if (*t == ' ') t++; + + S = s; + while (*S && (((*S >= '0') && (*S <= '9')) || (*S == '.'))) + { + S++; + } + + if (*s && *t && (S > s)) + { + if (Strlen(t) >= (S - s)) + { + (void) Strncpy(t, s, S - s); + } + } + return (mod_install(&modlinkage)); +} + +/*ARGSUSED*/ +int _info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/*ARGSUSED*/ +int _fini(void) +{ + if (parsebusy > 0) + { + printf("_fini[%s]: STREAMS module has still %d instances active.\n", modlstrmod.strmod_linkinfo, parsebusy); + return (EBUSY); + } + else + return (mod_remove(&modlinkage)); +} + +/*--------------- stream module definition ----------------------------*/ + +static int parseopen(), parseclose(), parsewput(), parserput(), parsersvc(); + +static struct module_info driverinfo = +{ + 0, /* module ID number */ + fmod_templ.f_name, /* module name - why repeated here ? compat ?*/ + 0, /* minimum accepted packet size */ + INFPSZ, /* maximum accepted packet size */ + 1, /* high water mark - flow control */ + 0 /* low water mark - flow control */ +}; + +static struct qinit rinit = /* read queue definition */ +{ + parserput, /* put procedure */ + parsersvc, /* service procedure */ + parseopen, /* open procedure */ + parseclose, /* close procedure */ + NULL, /* admin procedure - NOT USED FOR NOW */ + &driverinfo, /* information structure */ + NULL /* statistics */ +}; + +static struct qinit winit = /* write queue definition */ +{ + parsewput, /* put procedure */ + NULL, /* service procedure */ + NULL, /* open procedure */ + NULL, /* close procedure */ + NULL, /* admin procedure - NOT USED FOR NOW */ + &driverinfo, /* information structure */ + NULL /* statistics */ +}; + +static struct streamtab parseinfo = /* stream info element for parse driver */ +{ + &rinit, /* read queue */ + &winit, /* write queue */ + NULL, /* read mux */ + NULL /* write mux */ +}; + +/*--------------- driver data structures ----------------------------*/ + +/* + * we usually have an inverted signal - but you + * can change this to suit your needs + */ +int cd_invert = 1; /* invert status of CD line - PPS support via CD input */ + +int parsedebug = ~0; + +extern void uniqtime(); + +/*--------------- module implementation -----------------------------*/ + +#define TIMEVAL_USADD(_X_, _US_) do {\ + (_X_)->tv_usec += (_US_);\ + if ((_X_)->tv_usec >= 1000000)\ + {\ + (_X_)->tv_sec++;\ + (_X_)->tv_usec -= 1000000;\ + }\ + } while (0) + +#if defined(sun4c) && defined(DEBUG_CD) +#include +#include +#define SET_LED(_X_) (((cpu & CPU_ARCH) == SUN4C_ARCH) ? *(u_char *)AUXIO_REG = AUX_MBO|AUX_EJECT|((_X_)?AUX_LED:0) : 0) +#else +#define SET_LED(_X_) +#endif + +static int init_linemon(); +static void close_linemon(); + +/* + * keep here MACHINE AND OS AND ENVIRONMENT DEPENDENT + * timing constants + * + * FOR ABSOLUTE PRECISION YOU NEED TO MEASURE THE TIMING + * SKEW BETWEEN THE HW-PPS SIGNAL AND KERNEL uniqtime() + * YOURSELF. + * + * YOU MUST BE QUALIFIED APPROPRIATELY FOR THESE TYPE + * OF HW MANIPULATION ! + * + * you need an oscilloscope and the permission for HW work + * in order to figure out these timing constants/variables + */ + +static unsigned long xsdelay = 10; /* assume an SS2 */ +static unsigned long stdelay = 350; + +struct delays +{ + unsigned char mask; /* what to check for */ + unsigned char type; /* what to match */ + unsigned long xsdelay; /* external status direct delay in us */ + unsigned long stdelay; /* STREAMS message delay (M_[UN]HANGUP) */ +} isr_delays[] = +{ + /* + * WARNING: must still be measured - currently taken from Craig Leres ppsdev + */ +#ifdef sun4c + {CPU_ARCH|CPU_MACH, CPU_SUN4C_50, 10, 350}, + {CPU_ARCH|CPU_MACH, CPU_SUN4C_65, 15, 700}, + {CPU_ARCH|CPU_MACH, CPU_SUN4C_75, 10, 350}, +#endif +#ifdef sun4m + {CPU_ARCH|CPU_MACH, CPU_SUN4M_50, 8, 250}, + {CPU_ARCH|CPU_MACH, CPU_SUN4M_690, 8, 250}, +#endif + {0,} +}; + +void setup_delays() +{ + register int i; + + if (cputype & OBP_ARCH) + { + printf("parse: WARNING: PPS kernel fudge factors no yet determinable (no dev tree walk yet) - assuming SS2 (Sun4/75)\n", cputype); + return; + } + + for (i = 0; isr_delays[i].mask; i++) + { + if ((cputype & isr_delays[i].mask) == isr_delays[i].type) + { + xsdelay = isr_delays[i].xsdelay; + stdelay = isr_delays[i].stdelay; + return; + } + } + printf("parse: WARNING: PPS kernel fudge factors unknown for this machine (Type 0x%x) - assuming SS2 (Sun4/75)\n", cputype); +} + +#define M_PARSE 0x0001 +#define M_NOPARSE 0x0002 + +static int +setup_stream(queue_t *q, int mode) +{ + register mblk_t *mp; + + parseprintf(DD_OPEN,("parse: SETUP_STREAM - setting up stream for q=%x\n", q)); + + mp = allocb(sizeof(struct stroptions), BPRI_MED); + if (mp) + { + struct stroptions *str = (struct stroptions *)mp->b_wptr; + + str->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT; + str->so_readopt = (mode == M_PARSE) ? RMSGD : RNORM; + str->so_hiwat = (mode == M_PARSE) ? sizeof(parsetime_t) : 256; + str->so_lowat = 0; + mp->b_datap->db_type = M_SETOPTS; + mp->b_wptr += sizeof(struct stroptions); + if (!q) + panic("NULL q - strange"); + putnext(q, mp); + return putctl1(SAFE_WR(q)->q_next, M_CTL, (mode == M_PARSE) ? MC_SERVICEIMM : + MC_SERVICEDEF); + } + else + { + parseprintf(DD_OPEN,("parse: setup_stream - FAILED - no MEMORY for allocb\n")); + return 0; + } +} + +/*ARGSUSED*/ +static int parseopen(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *credp) +{ + register mblk_t *mp; + register parsestream_t *parse; + static int notice = 0; + + parseprintf(DD_OPEN,("parse: OPEN - q=%x\n", q)); + + if (sflag != MODOPEN) + { /* open only for modules */ + parseprintf(DD_OPEN,("parse: OPEN - FAILED - not MODOPEN\n")); + return EIO; + } + + if (q->q_ptr != (caddr_t)NULL) + { + parseprintf(DD_OPEN,("parse: OPEN - FAILED - EXCLUSIVE ONLY\n")); + return EBUSY; + } + + parsebusy++; + + q->q_ptr = (caddr_t)kmem_alloc(sizeof(parsestream_t), KM_SLEEP); + parseprintf(DD_OPEN,("parse: OPEN - parse area q=%x, q->q_ptr=%x\n", q, q->q_ptr)); + SAFE_WR(q)->q_ptr = q->q_ptr; + parseprintf(DD_OPEN,("parse: OPEN - WQ parse area q=%x, q->q_ptr=%x\n", SAFE_WR(q), SAFE_WR(q)->q_ptr)); + + parse = (parsestream_t *) q->q_ptr; + bzero((caddr_t)parse, sizeof(*parse)); + parse->parse_queue = q; + parse->parse_status = PARSE_ENABLE; + parse->parse_ppsclockev.tv.tv_sec = 0; + parse->parse_ppsclockev.tv.tv_usec = 0; + parse->parse_ppsclockev.serial = 0; + + parseprintf(DD_OPEN,("parse: OPEN - initializing io subsystem q=%x\n", q)); + + if (!parse_ioinit(&parse->parse_io)) + { + /* + * ok guys - beat it + */ + kmem_free((caddr_t)parse, sizeof(parsestream_t)); + + parsebusy--; + + return EIO; + } + + parseprintf(DD_OPEN,("parse: OPEN - initializing stream q=%x\n", q)); + + if (setup_stream(q, M_PARSE)) + { + (void) init_linemon(q); /* hook up PPS ISR routines if possible */ + setup_delays(); + parseprintf(DD_OPEN,("parse: OPEN - SUCCEEDED\n")); + + /* + * I know that you know the delete key, but you didn't write this + * code, did you ? - So, keep the message in here. + */ + if (!notice) + { + printf("%s: Copyright (c) 1991-1993, Frank Kardel\n", modlstrmod.strmod_linkinfo); + notice = 1; + } + + return 0; + } + else + { + parsebusy--; + return EIO; + } +} + +/*ARGSUSED*/ +static int parseclose(queue_t *q, int flags) +{ + register parsestream_t *parse = (parsestream_t *)q->q_ptr; + register unsigned long s; + + parseprintf(DD_CLOSE,("parse: CLOSE\n")); + + s = splhigh(); + + if (parse->parse_dqueue) + close_linemon(parse->parse_dqueue, q); + parse->parse_dqueue = (queue_t *)0; + + (void) splx(s); + + parse_ioend(&parse->parse_io); + + kmem_free((caddr_t)parse, sizeof(parsestream_t)); + + q->q_ptr = (caddr_t)NULL; + SAFE_WR(q)->q_ptr = (caddr_t)NULL; + + parsebusy--; +} + +/* + * move unrecognized stuff upward + */ +static parsersvc(queue_t *q) +{ + mblk_t *mp; + + while (mp = getq(q)) + { + if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) + { + putnext(q, mp); + parseprintf(DD_RSVC,("parse: RSVC - putnext\n")); + } + else + { + putbq(q, mp); + parseprintf(DD_RSVC,("parse: RSVC - flow control wait\n")); + break; + } + } +} + +/* + * do ioctls and + * send stuff down - dont care about + * flow control + */ +static int parsewput(queue_t *q, mblk_t *mp) +{ + register int ok = 1; + register mblk_t *datap; + register struct iocblk *iocp; + parsestream_t *parse = (parsestream_t *)q->q_ptr; + + parseprintf(DD_WPUT,("parse: parsewput\n")); + + switch (mp->b_datap->db_type) + { + default: + putnext(q, mp); + break; + + case M_IOCTL: + iocp = (struct iocblk *)mp->b_rptr; + switch (iocp->ioc_cmd) + { + default: + parseprintf(DD_WPUT,("parse: parsewput - forward M_IOCTL\n")); + putnext(q, mp); + break; + + case CIOGETEV: + /* + * taken from Craig Leres ppsclock module (and modified) + */ + datap = allocb(sizeof(struct ppsclockev), BPRI_MED); + if (datap == NULL || mp->b_cont) + { + mp->b_datap->db_type = M_IOCNAK; + iocp->ioc_error = (datap == NULL) ? ENOMEM : EINVAL; + if (datap != NULL) + freeb(datap); + qreply(q, mp); + break; + } + + mp->b_cont = datap; + *(struct ppsclockev *)datap->b_wptr = parse->parse_ppsclockev; + datap->b_wptr += + sizeof(struct ppsclockev) / sizeof(*datap->b_wptr); + mp->b_datap->db_type = M_IOCACK; + iocp->ioc_count = sizeof(struct ppsclockev); + qreply(q, mp); + break; + + case PARSEIOC_ENABLE: + case PARSEIOC_DISABLE: + { + parse->parse_status = (parse->parse_status & ~PARSE_ENABLE) | + (iocp->ioc_cmd == PARSEIOC_ENABLE) ? + PARSE_ENABLE : 0; + if (!setup_stream(SAFE_RD(q), (parse->parse_status & PARSE_ENABLE) ? + M_PARSE : M_NOPARSE)) + { + mp->b_datap->db_type = M_IOCNAK; + } + else + { + mp->b_datap->db_type = M_IOCACK; + } + qreply(q, mp); + break; + } + + case PARSEIOC_SETSTAT: + case PARSEIOC_GETSTAT: + case PARSEIOC_TIMECODE: + case PARSEIOC_SETFMT: + case PARSEIOC_GETFMT: + case PARSEIOC_SETCS: + if (iocp->ioc_count == sizeof(parsectl_t)) + { + parsectl_t *dct = (parsectl_t *)mp->b_cont->b_rptr; + + switch (iocp->ioc_cmd) + { + case PARSEIOC_GETSTAT: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_GETSTAT\n")); + ok = parse_getstat(dct, &parse->parse_io); + break; + + case PARSEIOC_SETSTAT: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETSTAT\n")); + ok = parse_setstat(dct, &parse->parse_io); + break; + + case PARSEIOC_TIMECODE: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_TIMECODE\n")); + ok = parse_timecode(dct, &parse->parse_io); + break; + + case PARSEIOC_SETFMT: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETFMT\n")); + ok = parse_setfmt(dct, &parse->parse_io); + break; + + case PARSEIOC_GETFMT: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_GETFMT\n")); + ok = parse_getfmt(dct, &parse->parse_io); + break; + + case PARSEIOC_SETCS: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETCS\n")); + ok = parse_setcs(dct, &parse->parse_io); + break; + } + mp->b_datap->db_type = ok ? M_IOCACK : M_IOCNAK; + } + else + { + mp->b_datap->db_type = M_IOCNAK; + } + parseprintf(DD_WPUT,("parse: parsewput qreply - %s\n", (mp->b_datap->db_type == M_IOCNAK) ? "M_IOCNAK" : "M_IOCACK")); + qreply(q, mp); + break; + } + } +} + +/* + * read characters from streams buffers + */ +static unsigned long rdchar(mblk_t **mp) +{ + while (*mp != (mblk_t *)NULL) + { + if ((*mp)->b_wptr - (*mp)->b_rptr) + { + return (unsigned long)(*(unsigned char *)((*mp)->b_rptr++)); + } + else + { + register mblk_t *mmp = *mp; + + *mp = (*mp)->b_cont; + freeb(mmp); + } + } + return ~0; +} + +/* + * convert incoming data + */ +static int parserput(queue_t *q, mblk_t *imp) +{ + register unsigned char type; + mblk_t *mp = imp; + + switch (type = mp->b_datap->db_type) + { + default: + /* + * anything we don't know will be put on queue + * the service routine will move it to the next one + */ + parseprintf(DD_RPUT,("parse: parserput - forward type 0x%x\n", type)); + if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) + { + putnext(q, mp); + } + else + putq(q, mp); + break; + + case M_BREAK: + case M_DATA: + { + register parsestream_t * parse = (parsestream_t *)q->q_ptr; + register mblk_t *nmp; + register unsigned long ch; + timestamp_t ctime; + + /* + * get time on packet delivery + */ + uniqtime(&ctime.tv); + + if (!(parse->parse_status & PARSE_ENABLE)) + { + parseprintf(DD_RPUT,("parse: parserput - parser disabled - forward type 0x%x\n", type)); + if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) + { + putnext(q, mp); + } + else + putq(q, mp); + } + else + { + parseprintf(DD_RPUT,("parse: parserput - M_%s\n", (type == M_DATA) ? "DATA" : "BREAK")); + + if (type == M_DATA) + { + /* + * parse packet looking for start an end characters + */ + while (mp != (mblk_t *)NULL) + { + ch = rdchar(&mp); + if (ch != ~0 && parse_ioread(&parse->parse_io, (char)ch, &ctime)) + { + /* + * up up and away (hopefully ...) + * don't press it if resources are tight or nobody wants it + */ + nmp = (mblk_t *)NULL; + if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) + { + bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); + nmp->b_wptr += sizeof(parsetime_t); + putnext(parse->parse_queue, nmp); + } + else + if (nmp) freemsg(nmp); + parse_iodone(&parse->parse_io); + } + } + } + else + { + if (parse_ioread(&parse->parse_io, (char)0, &ctime)) + { + /* + * up up and away (hopefully ...) + * don't press it if resources are tight or nobody wants it + */ + nmp = (mblk_t *)NULL; + if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) + { + bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); + nmp->b_wptr += sizeof(parsetime_t); + putnext(parse->parse_queue, nmp); + } + else + if (nmp) freemsg(nmp); + parse_iodone(&parse->parse_io); + } + freemsg(mp); + } + break; + } + } + + /* + * CD PPS support for non direct ISR hack + */ + case M_HANGUP: + case M_UNHANGUP: + { + register parsestream_t * parse = (parsestream_t *)q->q_ptr; + timestamp_t ctime; + register mblk_t *nmp; + register int status = cd_invert ^ (type == M_HANGUP); + + SET_LED(status); + + uniqtime(&ctime.tv); + + TIMEVAL_USADD(&ctime.tv, stdelay); + + parseprintf(DD_RPUT,("parse: parserput - M_%sHANGUP\n", (type == M_HANGUP) ? "" : "UN")); + + if ((parse->parse_status & PARSE_ENABLE) && + parse_iopps(&parse->parse_io, status ? SYNC_ONE : SYNC_ZERO, &ctime)) + { + nmp = (mblk_t *)NULL; + if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) + { + bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); + nmp->b_wptr += sizeof(parsetime_t); + putnext(parse->parse_queue, nmp); + } + else + if (nmp) freemsg(nmp); + parse_iodone(&parse->parse_io); + } + + if (status) + { + parse->parse_ppsclockev.tv = ctime.tv; + ++(parse->parse_ppsclockev.serial); + } + } + } +} + +static int init_zs_linemon(); /* handle line monitor for "zs" driver */ +static void close_zs_linemon(); +static void zs_xsisr(); /* zs external status interupt handler */ + +/*-------------------- CD isr status monitor ---------------*/ + +static int init_linemon(queue_t *q) +{ + register queue_t *dq; + + dq = SAFE_WR(q); + /* + * we ARE doing very bad things down here (basically stealing ISR + * hooks) + * + * so we chase down the STREAMS stack searching for the driver + * and if this is a known driver we insert our ISR routine for + * status changes in to the ExternalStatus handling hook + */ + while (dq->q_next) + { + dq = dq->q_next; /* skip down to driver */ + } + + /* + * find appropriate driver dependent routine + */ + if (dq->q_qinfo && dq->q_qinfo->qi_minfo) + { + register char *dname = dq->q_qinfo->qi_minfo->mi_idname; + + parseprintf(DD_INSTALL, ("init_linemon: driver is \"%s\"\n", dname)); + +#ifdef sun + if (dname && !Strcmp(dname, "zs")) + { + return init_zs_linemon(dq, q); + } + else +#endif + { + parseprintf(DD_INSTALL, ("init_linemon: driver \"%s\" not suitable for CD monitoring\n", dname)); + return 0; + } + } + parseprintf(DD_INSTALL, ("init_linemon: cannot find driver\n")); + return 0; +} + +static void close_linemon(queue_t *q, queue_t *my_q) +{ + /* + * find appropriate driver dependent routine + */ + if (q->q_qinfo && q->q_qinfo->qi_minfo) + { + register char *dname = q->q_qinfo->qi_minfo->mi_idname; + +#ifdef sun + if (dname && !Strcmp(dname, "zs")) + { + close_zs_linemon(q, my_q); + return; + } + parseprintf(DD_INSTALL, ("close_linemon: cannot find driver close routine for \"%s\"\n", dname)); +#endif + } + parseprintf(DD_INSTALL, ("close_linemon: cannot find driver name\n")); +} + +#ifdef sun +#include +#include +#include +#include + +/* + * there should be some docs telling how to get to + * sz:zs_usec_delay and zs:initzsops() + */ +#define zs_usec_delay 5 + +struct savedzsops +{ + struct zsops zsops; + struct zsops *oldzsops; +}; + +static struct zsops *emergencyzs; + +static int init_zs_linemon(queue_t *q, queue_t *my_q) +{ + register struct zscom *zs; + register struct savedzsops *szs; + register parsestream_t *parsestream = (parsestream_t *)my_q->q_ptr; + /* + * we expect the zsaline pointer in the q_data pointer + * from there on we insert our on EXTERNAL/STATUS ISR routine + * into the interrupt path, before the standard handler + */ + zs = ((struct asyncline *)q->q_ptr)->za_common; + if (!zs) + { + /* + * well - not found on startup - just say no (shouldn't happen though) + */ + return 0; + } + else + { + unsigned long s; + + /* + * we do a direct replacement, in case others fiddle also + * if somebody else grabs our hook and we disconnect + * we are in DEEP trouble - panic is likely to be next, sorry + */ + szs = (struct savedzsops *) kmem_alloc(sizeof(struct savedzsops), KM_SLEEP); + + parsestream->parse_data = (void *)szs; + + mutex_enter(zs->zs_excl); + + parsestream->parse_dqueue = q; /* remember driver */ + + szs->zsops = *zs->zs_ops; + szs->zsops.zsop_xsint = (void (*)())zs_xsisr; /* place our bastard */ + szs->oldzsops = zs->zs_ops; + emergencyzs = zs->zs_ops; + + zs->zs_ops = &szs->zsops; /* hook it up */ + + mutex_exit(zs->zs_excl); + + parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor installed\n")); + + return 1; + } +} + +/* + * unregister our ISR routine - must call under splhigh() + */ +static void close_zs_linemon(queue_t *q, queue_t *my_q) +{ + register struct zscom *zs; + register parsestream_t *parsestream = (parsestream_t *)my_q->q_ptr; + + zs = ((struct asyncline *)q->q_ptr)->za_common; + if (!zs) + { + /* + * well - not found on startup - just say no (shouldn't happen though) + */ + return; + } + else + { + register struct savedzsops *szs = (struct savedzsops *)parsestream->parse_data; + + mutex_enter(zs->zs_excl); + + zs->zs_ops = szs->oldzsops; /* reset to previous handler functions */ + + mutex_exit(zs->zs_excl); + + kmem_free((caddr_t)szs, sizeof (struct savedzsops)); + + parseprintf(DD_INSTALL, ("close_zs_linemon: CD monitor deleted\n")); + return; + } +} + +#define MAXDEPTH 50 /* maximum allowed stream crawl */ + +/* + * take external status interrupt (only CD interests us) + */ +static void zs_xsisr(struct zscom *zs) +{ + register struct asyncline *za = (struct asyncline *)zs->zs_priv; + register queue_t *q; + register unsigned char zsstatus; + register int loopcheck; + register unsigned char cdstate; + register char *dname; + + /* + * pick up current state + */ + zsstatus = SCC_READ0(); + + if (za->za_rr0 ^ (cdstate = zsstatus & ZSRR0_CD)) + { + timestamp_t cdevent; + register int status; + + /* + * CONDITIONAL external measurement support + */ + SET_LED(cdstate); /* + * inconsistent with upper SET_LED, but this + * is for oscilloscope business anyway and we + * are just interested in edge delays in the + * lower us range + */ + + /* + * time stamp + */ + uniqtime(&cdevent.tv); + + TIMEVAL_USADD(&cdevent.tv, xsdelay); + + q = za->za_ttycommon.t_readq; + + /* + * logical state + */ + status = cd_invert ? cdstate == 0 : cdstate != 0; + + /* + * ok - now the hard part - find ourself + */ + loopcheck = MAXDEPTH; + + while (q) + { + if (q->q_qinfo && q->q_qinfo->qi_minfo) + { + dname = q->q_qinfo->qi_minfo->mi_idname; + + if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname)) + { + /* + * back home - phew (hopping along stream queues might + * prove dangerous to your health) + */ + + if ((((parsestream_t *)q->q_ptr)->parse_status & PARSE_ENABLE) && + parse_iopps(&((parsestream_t *)q->q_ptr)->parse_io, status ? SYNC_ONE : SYNC_ZERO, &cdevent)) + { + /* + * XXX - currently we do not pass up the message, as + * we should. + * for a correct behaviour wee need to block out + * processing until parse_iodone has been posted via + * a softcall-ed routine which does the message pass-up + * right now PPS information relies on input being + * received + */ + parse_iodone(&((parsestream_t *)q->q_ptr)->parse_io); + } + + if (status) + { + ((parsestream_t *)q->q_ptr)->parse_ppsclockev.tv = cdevent.tv; + ++(((parsestream_t *)q->q_ptr)->parse_ppsclockev.serial); + } + + parseprintf(DD_ISR, ("zs_xsisr: CD event %s has been posted for \"%s\"\n", status ? "ONE" : "ZERO", dname)); + break; + } + } + + q = q->q_next; + + if (!loopcheck--) + { + panic("zs_xsisr: STREAMS Queue corrupted - CD event"); + } + } + + /* + * only pretend that CD has been handled + */ + za->za_rr0 = za->za_rr0 & ~ZSRR0_CD | zsstatus & ZSRR0_CD; + + if (!((za->za_rr0 ^ zsstatus) & ~ZSRR0_CD)) + { + /* + * all done - kill status indication and return + */ + SCC_WRITE0(ZSWR0_RESET_STATUS); /* might kill other conditions here */ + return; + } + } + + /* + * we are now gathered here to process some unusual external status + * interrupts. + * any CD events have also been handled and shouldn't be processed + * by the original routine (unless we have a VERY busy port pin) + * some initializations are done here, which could have been done before for + * both code paths but have been avioded for minimum path length to + * the uniq_time routine + */ + dname = (char *) 0; + q = za->za_ttycommon.t_readq; + + loopcheck = MAXDEPTH; + + /* + * the real thing for everything else ... + */ + while (q) + { + if (q->q_qinfo && q->q_qinfo->qi_minfo) + { + dname = q->q_qinfo->qi_minfo->mi_idname; + if (!Strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname)) + { + register void (*zsisr)(); + + /* + * back home - phew (hopping along stream queues might + * prove dangerous to your health) + */ + if (zsisr = ((struct savedzsops *)((parsestream_t *)q->q_ptr)->parse_data)->oldzsops->zsop_xsint) + zsisr(zs); + else + panic("zs_xsisr: unable to locate original ISR"); + + parseprintf(DD_ISR, ("zs_xsisr: non CD event was processed for \"%s\"\n", dname)); + /* + * now back to our program ... + */ + return; + } + } + + q = q->q_next; + + if (!loopcheck--) + { + panic("zs_xsisr: STREAMS Queue corrupted - non CD event"); + } + } + + /* + * last resort - shouldn't even come here as it indicates + * corrupted TTY structures + */ + printf("zs_zsisr: looking for \"%s\" - found \"%s\" - taking EMERGENCY path\n", parseinfo.st_rdinit->qi_minfo->mi_idname, dname ? dname : "-NIL-"); + + if (emergencyzs && emergencyzs->zsop_xsint) + emergencyzs->zsop_xsint(zs); + else + panic("zs_xsisr: no emergency ISR handler"); +} +#endif /* sun */ + +/* + * History: + * + * parsesolaris.c,v + * Revision 3.4 1993/11/13 11:13:17 kardel + * Solaris 2.3 additional includes + * + * Revision 3.3 1993/11/11 11:20:33 kardel + * declaration fixes + * + * Revision 3.2 1993/11/05 15:40:25 kardel + * shut up nice feature detection + * + * Revision 3.1 1993/11/01 20:00:29 kardel + * parse Solaris support (initial version) + * + * + */ diff --git a/contrib/xntpd/parse/parsestreams.c b/contrib/xntpd/parse/parsestreams.c new file mode 100644 index 0000000000..56ce07c93e --- /dev/null +++ b/contrib/xntpd/parse/parsestreams.c @@ -0,0 +1,1277 @@ +/* + * /src/NTP/REPOSITORY/v3/parse/parsestreams.c,v 3.9 1993/11/05 15:34:55 kardel Exp + * + * parsestreams.c,v 3.9 1993/11/05 15:34:55 kardel Exp + * + * STREAMS module for reference clocks + * (SunOS4.x) + * + * Copyright (c) 1989,1990,1991,1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +#ifndef lint +static char rcsid[] = "parsestreams.c,v 3.9 1993/11/05 15:34:55 kardel Exp"; +#endif + +#include "sys/types.h" +#include "sys/conf.h" +#include "sys/buf.h" +#include "sys/param.h" +#include "sys/sysmacros.h" +#include "sys/errno.h" +#include "sys/time.h" +#include "sundev/mbvar.h" +#include "sun/autoconf.h" +#include "sys/stream.h" +#include "sys/stropts.h" +#include "sys/dir.h" +#include "sys/signal.h" +#include "sys/termios.h" +#include "sys/termio.h" +#include "sys/ttold.h" +#include "sys/user.h" +#include "sys/errno.h" +#include "sys/tty.h" +#include "machine/cpu.h" + +#ifdef VDDRV +#include "sun/vddrv.h" +#endif + +/* + * no protypes here ! + */ +#define P(x) () + +/* + * use microtime instead of uniqtime if advised to + */ +#ifdef MICROTIME +#define uniqtime microtime +#endif + +#define HAVE_NO_NICE /* for the NTP headerfiles */ +#include "ntp_fp.h" +#include "parse.h" +#include "sys/parsestreams.h" + +#ifdef VDDRV +static unsigned int parsebusy = 0; + +/*--------------- loadable driver section -----------------------------*/ + +extern struct streamtab parseinfo; + +struct vdldrv parsesync_vd = +{ + VDMAGIC_PSEUDO, /* nothing like a real driver - a STREAMS module */ + "PARSE ", /* name this baby - keep room for revision number */ +}; + +/* + * strings support usually not in kernel + */ +static int strlen(s) + register char *s; +{ + register int c; + + c = 0; + if (s) + { + while (*s++) + { + c++; + } + } + return c; +} + +static void strncpy(t, s, c) + register char *t; + register char *s; + register int c; +{ + if (s && t) + { + while ((c-- > 0) && (*t++ = *s++)) + ; + } +} + +static int strcmp(s, t) + register char *s; + register char *t; +{ + register int c = 0; + + if (!s || !t || (s == t)) + { + return 0; + } + + while (!(c = *s++ - *t++) && *s && *t) + /* empty loop */; + + return c; +} + +static int strncmp(s, t, n) + register char *s; + register char *t; + register int n; +{ + register int c = 0; + + if (!s || !t || (s == t)) + { + return 0; + } + + while (n-- && !(c = *s++ - *t++) && *s && *t) + /* empty loop */; + + return c; +} + +/* + * driver init routine + * since no mechanism gets us into and out of the fmodsw, we have to + * do it ourselves + */ +/*ARGSUSED*/ +int xxxinit(fc, vdp, vdi, vds) + unsigned int fc; + struct vddrv *vdp; + addr_t vdi; + struct vdstat *vds; +{ + extern struct fmodsw fmodsw[]; + extern int fmodcnt; + + struct fmodsw *fm = fmodsw; + struct fmodsw *fmend = &fmodsw[fmodcnt]; + struct fmodsw *ifm = (struct fmodsw *)0; + char *mname = parseinfo.st_rdinit->qi_minfo->mi_idname; + + switch (fc) + { + case VDLOAD: + vdp->vdd_vdtab = (struct vdlinkage *)&parsesync_vd; + /* + * now, jog along fmodsw scanning for an empty slot + * and deposit our name there + */ + while (fm <= fmend) + { + if (!strncmp(fm->f_name, mname, FMNAMESZ)) + { + printf("vddrinit[%s]: STREAMS module already loaded.\n", mname); + return(EBUSY); + } + else + if ((ifm == (struct fmodsw *)0) && + (fm->f_name[0] == '\0') && (fm->f_str == (struct streamtab *)0)) + { + /* + * got one - so move in + */ + ifm = fm; + break; + } + fm++; + } + + if (ifm == (struct fmodsw *)0) + { + printf("vddrinit[%s]: no slot free for STREAMS module\n", mname); + return (ENOSPC); + } + else + { + static char revision[] = "3.9"; + char *s, *S, *t; + + strncpy(ifm->f_name, mname, FMNAMESZ); + ifm->f_name[FMNAMESZ] = '\0'; + ifm->f_str = &parseinfo; + /* + * copy RCS revision into Drv_name + * + * are we forcing RCS here to do things it was not built for ? + */ + s = revision; + if (*s == '$') + { + /* + * skip "$Revision: " + * if present. - not necessary on a -kv co (cvs export) + */ + while (*s && (*s != ' ')) + { + s++; + } + if (*s == ' ') s++; + } + + t = parsesync_vd.Drv_name; + while (*t && (*t != ' ')) + { + t++; + } + if (*t == ' ') t++; + + S = s; + while (*S && (((*S >= '0') && (*S <= '9')) || (*S == '.'))) + { + S++; + } + + if (*s && *t && (S > s)) + { + if (strlen(t) >= (S - s)) + { + (void) strncpy(t, s, S - s); + } + } + return (0); + } + break; + + case VDUNLOAD: + if (parsebusy > 0) + { + printf("vddrinit[%s]: STREAMS module has still %d instances active.\n", mname, parsebusy); + return (EBUSY); + } + else + { + while (fm <= fmend) + { + if (!strncmp(fm->f_name, mname, FMNAMESZ)) + { + /* + * got it - kill entry + */ + fm->f_name[0] = '\0'; + fm->f_str = (struct streamtab *)0; + fm++; + + break; + } + fm++; + } + if (fm > fmend) + { + printf("vddrinit[%s]: cannot find entry for STREAMS module\n", mname); + return (ENXIO); + } + else + return (0); + } + + + case VDSTAT: + return (0); + + default: + return (EIO); + + } + return EIO; +} + +#endif + +/*--------------- stream module definition ----------------------------*/ + +static int parseopen(), parseclose(), parsewput(), parserput(), parsersvc(); + +static struct module_info driverinfo = +{ + 0, /* module ID number */ + "parse", /* module name */ + 0, /* minimum accepted packet size */ + INFPSZ, /* maximum accepted packet size */ + 1, /* high water mark - flow control */ + 0 /* low water mark - flow control */ +}; + +static struct qinit rinit = /* read queue definition */ +{ + parserput, /* put procedure */ + parsersvc, /* service procedure */ + parseopen, /* open procedure */ + parseclose, /* close procedure */ + NULL, /* admin procedure - NOT USED FOR NOW */ + &driverinfo, /* information structure */ + NULL /* statistics */ +}; + +static struct qinit winit = /* write queue definition */ +{ + parsewput, /* put procedure */ + NULL, /* service procedure */ + NULL, /* open procedure */ + NULL, /* close procedure */ + NULL, /* admin procedure - NOT USED FOR NOW */ + &driverinfo, /* information structure */ + NULL /* statistics */ +}; + +struct streamtab parseinfo = /* stream info element for dpr driver */ +{ + &rinit, /* read queue */ + &winit, /* write queue */ + NULL, /* read mux */ + NULL, /* write mux */ + NULL /* module auto push */ +}; + +/*--------------- driver data structures ----------------------------*/ + +/* + * we usually have an inverted signal - but you + * can change this to suit your needs + */ +int cd_invert = 1; /* invert status of CD line - PPS support via CD input */ + +int parsedebug = ~0; + +extern void uniqtime(); + +/*--------------- module implementation -----------------------------*/ + +#define TIMEVAL_USADD(_X_, _US_) {\ + (_X_)->tv_usec += (_US_);\ + if ((_X_)->tv_usec >= 1000000)\ + {\ + (_X_)->tv_sec++;\ + (_X_)->tv_usec -= 1000000;\ + }\ + } while (0) + +#if defined(sun4c) && defined(DEBUG_CD) +#include +#include +#define SET_LED(_X_) (((cpu & CPU_ARCH) == SUN4C_ARCH) ? *(u_char *)AUXIO_REG = AUX_MBO|AUX_EJECT|((_X_)?AUX_LED:0) : 0) +#else +#define SET_LED(_X_) +#endif + +static int init_linemon(); +static void close_linemon(); + +/* + * keep here MACHINE AND OS AND ENVIRONMENT DEPENDENT + * timing constants + * + * FOR ABSOLUTE PRECISION YOU NEED TO MEASURE THE TIMING + * SKEW BETWEEN THE HW-PPS SIGNAL AND KERNEL uniqtime() + * YOURSELF. + * + * YOU MUST BE QUALIFIED APPROPRIATELY FOR THESE TYPE + * OF HW MANIPULATION ! + * + * you need an oscilloscope and the permission for HW work + * in order to figure out these timing constants/variables + */ +#ifdef sun +static unsigned long xsdelay = 10; /* assume an SS2 */ +static unsigned long stdelay = 350; + +struct delays +{ + unsigned char mask; /* what to check for */ + unsigned char type; /* what to match */ + unsigned long xsdelay; /* external status direct delay in us */ + unsigned long stdelay; /* STREAMS message delay (M_[UN]HANGUP) */ +} isr_delays[] = +{ + /* + * WARNING: must still be measured - currently taken from Craig Leres ppsdev + */ +#ifdef sun4c + {CPU_ARCH|CPU_MACH, CPU_SUN4C_50, 10, 350}, + {CPU_ARCH|CPU_MACH, CPU_SUN4C_65, 15, 700}, + {CPU_ARCH|CPU_MACH, CPU_SUN4C_75, 10, 350}, +#endif +#ifdef sun4m + {CPU_ARCH|CPU_MACH, CPU_SUN4M_50, 8, 250}, + {CPU_ARCH|CPU_MACH, CPU_SUN4M_690, 8, 250}, +#endif + {0,} +}; + +void setup_delays() +{ + register int i; + + for (i = 0; isr_delays[i].mask; i++) + { + if ((cpu & isr_delays[i].mask) == isr_delays[i].type) + { + xsdelay = isr_delays[i].xsdelay; + stdelay = isr_delays[i].stdelay; + return; + } + } + printf("parse: WARNING: PPS kernel fudge factors unknown for this machine (Type 0x%x) - assuming SS2 (Sun4/75)\n", cpu); +} +#else +#define setup_delays() /* empty - no need for clobbering kernel with this */ +static unsigned long xsdelay = 0; /* assume nothing */ +static unsigned long stdelay = 0; +#endif + +#define M_PARSE 0x0001 +#define M_NOPARSE 0x0002 + +static int +setup_stream(q, mode) + queue_t *q; + int mode; +{ + mblk_t *mp; + + mp = allocb(sizeof(struct stroptions), BPRI_MED); + if (mp) + { + struct stroptions *str = (struct stroptions *)mp->b_rptr; + + str->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT; + str->so_readopt = (mode == M_PARSE) ? RMSGD : RNORM; + str->so_hiwat = (mode == M_PARSE) ? sizeof(parsetime_t) : 256; + str->so_lowat = 0; + mp->b_datap->db_type = M_SETOPTS; + mp->b_wptr += sizeof(struct stroptions); + putnext(q, mp); + return putctl1(WR(q)->q_next, M_CTL, (mode == M_PARSE) ? MC_SERVICEIMM : + MC_SERVICEDEF); + } + else + { + parseprintf(DD_OPEN,("parse: setup_stream - FAILED - no MEMORY for allocb\n")); + return 0; + } +} + +/*ARGSUSED*/ +static int parseopen(q, dev, flag, sflag) + queue_t *q; + dev_t dev; + int flag; + int sflag; +{ + register mblk_t *mp; + register parsestream_t *parse; + static int notice = 0; + + parseprintf(DD_OPEN,("parse: OPEN\n")); + + if (sflag != MODOPEN) + { /* open only for modules */ + parseprintf(DD_OPEN,("parse: OPEN - FAILED - not MODOPEN\n")); + return OPENFAIL; + } + + if (q->q_ptr != (caddr_t)NULL) + { + u.u_error = EBUSY; + parseprintf(DD_OPEN,("parse: OPEN - FAILED - EXCLUSIVE ONLY\n")); + return OPENFAIL; + } + +#ifdef VDDRV + parsebusy++; +#endif + + q->q_ptr = (caddr_t)kmem_alloc(sizeof(parsestream_t)); + WR(q)->q_ptr = q->q_ptr; + + parse = (parsestream_t *) q->q_ptr; + bzero((caddr_t)parse, sizeof(*parse)); + parse->parse_queue = q; + parse->parse_status = PARSE_ENABLE; + parse->parse_ppsclockev.tv.tv_sec = 0; + parse->parse_ppsclockev.tv.tv_usec = 0; + parse->parse_ppsclockev.serial = 0; + + if (!parse_ioinit(&parse->parse_io)) + { + /* + * ok guys - beat it + */ + kmem_free((caddr_t)parse, sizeof(parsestream_t)); +#ifdef VDDRV + parsebusy--; +#endif + return OPENFAIL; + } + + if (setup_stream(q, M_PARSE)) + { + (void) init_linemon(q); /* hook up PPS ISR routines if possible */ + setup_delays(); + parseprintf(DD_OPEN,("parse: OPEN - SUCCEEDED\n")); + + /* + * I know that you know the delete key, but you didn't write this + * code, did you ? - So, keep the message in here. + */ + if (!notice) + { + printf("%s: Copyright (c) 1991-1993, Frank Kardel\n", parsesync_vd.Drv_name); + notice = 1; + } + + return 1; + } + else + { +#ifdef VDDRV + parsebusy--; +#endif + return OPENFAIL; + } +} + +/*ARGSUSED*/ +static int parseclose(q, flags) + queue_t *q; + int flags; +{ + register parsestream_t *parse = (parsestream_t *)q->q_ptr; + register unsigned long s; + + parseprintf(DD_CLOSE,("parse: CLOSE\n")); + + s = splhigh(); + + if (parse->parse_dqueue) + close_linemon(parse->parse_dqueue, q); + parse->parse_dqueue = (queue_t *)0; + + (void) splx(s); + + parse_ioend(&parse->parse_io); + + kmem_free((caddr_t)parse, sizeof(parsestream_t)); + + q->q_ptr = (caddr_t)NULL; + WR(q)->q_ptr = (caddr_t)NULL; + +#ifdef VDDRV + parsebusy--; +#endif +} + +/* + * move unrecognized stuff upward + */ +static parsersvc(q) + queue_t *q; +{ + mblk_t *mp; + + while (mp = getq(q)) + { + if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) + { + putnext(q, mp); + parseprintf(DD_RSVC,("parse: RSVC - putnext\n")); + } + else + { + putbq(q, mp); + parseprintf(DD_RSVC,("parse: RSVC - flow control wait\n")); + break; + } + } +} + +/* + * do ioctls and + * send stuff down - dont care about + * flow control + */ +static int parsewput(q, mp) + queue_t *q; + register mblk_t *mp; +{ + register int ok = 1; + register mblk_t *datap; + register struct iocblk *iocp; + parsestream_t *parse = (parsestream_t *)q->q_ptr; + + parseprintf(DD_WPUT,("parse: parsewput\n")); + + switch (mp->b_datap->db_type) + { + default: + putnext(q, mp); + break; + + case M_IOCTL: + iocp = (struct iocblk *)mp->b_rptr; + switch (iocp->ioc_cmd) + { + default: + parseprintf(DD_WPUT,("parse: parsewput - forward M_IOCTL\n")); + putnext(q, mp); + break; + + case CIOGETEV: + /* + * taken from Craig Leres ppsclock module (and modified) + */ + datap = allocb(sizeof(struct ppsclockev), BPRI_MED); + if (datap == NULL || mp->b_cont) + { + mp->b_datap->db_type = M_IOCNAK; + iocp->ioc_error = (datap == NULL) ? ENOMEM : EINVAL; + if (datap != NULL) + freeb(datap); + qreply(q, mp); + break; + } + + mp->b_cont = datap; + *(struct ppsclockev *)datap->b_wptr = parse->parse_ppsclockev; + datap->b_wptr += + sizeof(struct ppsclockev) / sizeof(*datap->b_wptr); + mp->b_datap->db_type = M_IOCACK; + iocp->ioc_count = sizeof(struct ppsclockev); + qreply(q, mp); + break; + + case PARSEIOC_ENABLE: + case PARSEIOC_DISABLE: + { + parse->parse_status = (parse->parse_status & ~PARSE_ENABLE) | + (iocp->ioc_cmd == PARSEIOC_ENABLE) ? + PARSE_ENABLE : 0; + if (!setup_stream(RD(q), (parse->parse_status & PARSE_ENABLE) ? + M_PARSE : M_NOPARSE)) + { + mp->b_datap->db_type = M_IOCNAK; + } + else + { + mp->b_datap->db_type = M_IOCACK; + } + qreply(q, mp); + break; + } + + case PARSEIOC_SETSTAT: + case PARSEIOC_GETSTAT: + case PARSEIOC_TIMECODE: + case PARSEIOC_SETFMT: + case PARSEIOC_GETFMT: + case PARSEIOC_SETCS: + if (iocp->ioc_count == sizeof(parsectl_t)) + { + parsectl_t *dct = (parsectl_t *)mp->b_cont->b_rptr; + + switch (iocp->ioc_cmd) + { + case PARSEIOC_GETSTAT: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_GETSTAT\n")); + ok = parse_getstat(dct, &parse->parse_io); + break; + + case PARSEIOC_SETSTAT: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETSTAT\n")); + ok = parse_setstat(dct, &parse->parse_io); + break; + + case PARSEIOC_TIMECODE: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_TIMECODE\n")); + ok = parse_timecode(dct, &parse->parse_io); + break; + + case PARSEIOC_SETFMT: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETFMT\n")); + ok = parse_setfmt(dct, &parse->parse_io); + break; + + case PARSEIOC_GETFMT: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_GETFMT\n")); + ok = parse_getfmt(dct, &parse->parse_io); + break; + + case PARSEIOC_SETCS: + parseprintf(DD_WPUT,("parse: parsewput - PARSEIOC_SETCS\n")); + ok = parse_setcs(dct, &parse->parse_io); + break; + } + mp->b_datap->db_type = ok ? M_IOCACK : M_IOCNAK; + } + else + { + mp->b_datap->db_type = M_IOCNAK; + } + parseprintf(DD_WPUT,("parse: parsewput qreply - %s\n", (mp->b_datap->db_type == M_IOCNAK) ? "M_IOCNAK" : "M_IOCACK")); + qreply(q, mp); + break; + } + } +} + +/* + * read characters from streams buffers + */ +static unsigned long rdchar(mp) + register mblk_t **mp; +{ + while (*mp != (mblk_t *)NULL) + { + if ((*mp)->b_wptr - (*mp)->b_rptr) + { + return (unsigned long)(*(unsigned char *)((*mp)->b_rptr++)); + } + else + { + register mblk_t *mmp = *mp; + + *mp = (*mp)->b_cont; + freeb(mmp); + } + } + return ~0; +} + +/* + * convert incoming data + */ +static int parserput(q, mp) + queue_t *q; + mblk_t *mp; +{ + unsigned char type; + + switch (type = mp->b_datap->db_type) + { + default: + /* + * anything we don't know will be put on queue + * the service routine will move it to the next one + */ + parseprintf(DD_RPUT,("parse: parserput - forward type 0x%x\n", type)); + if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) + { + putnext(q, mp); + } + else + putq(q, mp); + break; + + case M_BREAK: + case M_DATA: + { + register parsestream_t * parse = (parsestream_t *)q->q_ptr; + register mblk_t *nmp; + register unsigned long ch; + timestamp_t ctime; + + /* + * get time on packet delivery + */ + uniqtime(&ctime.tv); + + if (!(parse->parse_status & PARSE_ENABLE)) + { + parseprintf(DD_RPUT,("parse: parserput - parser disabled - forward type 0x%x\n", type)); + if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL)) + { + putnext(q, mp); + } + else + putq(q, mp); + } + else + { + parseprintf(DD_RPUT,("parse: parserput - M_%s\n", (type == M_DATA) ? "DATA" : "BREAK")); + + if (type == M_DATA) + { + /* + * parse packet looking for start an end characters + */ + while (mp != (mblk_t *)NULL) + { + ch = rdchar(&mp); + if (ch != ~0 && parse_ioread(&parse->parse_io, (char)ch, &ctime)) + { + /* + * up up and away (hopefully ...) + * don't press it if resources are tight or nobody wants it + */ + nmp = (mblk_t *)NULL; + if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) + { + bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); + nmp->b_wptr += sizeof(parsetime_t); + putnext(parse->parse_queue, nmp); + } + else + if (nmp) freemsg(nmp); + parse_iodone(&parse->parse_io); + } + } + } + else + { + if (parse_ioread(&parse->parse_io, (char)0, &ctime)) + { + /* + * up up and away (hopefully ...) + * don't press it if resources are tight or nobody wants it + */ + nmp = (mblk_t *)NULL; + if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) + { + bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); + nmp->b_wptr += sizeof(parsetime_t); + putnext(parse->parse_queue, nmp); + } + else + if (nmp) freemsg(nmp); + parse_iodone(&parse->parse_io); + } + freemsg(mp); + } + break; + } + } + + /* + * CD PPS support for non direct ISR hack + */ + case M_HANGUP: + case M_UNHANGUP: + { + register parsestream_t * parse = (parsestream_t *)q->q_ptr; + timestamp_t ctime; + register mblk_t *nmp; + register int status = cd_invert ^ (type == M_HANGUP); + + SET_LED(status); + + uniqtime(&ctime.tv); + + TIMEVAL_USADD(&ctime.tv, stdelay); + + parseprintf(DD_RPUT,("parse: parserput - M_%sHANGUP\n", (type == M_HANGUP) ? "" : "UN")); + + if ((parse->parse_status & PARSE_ENABLE) && + parse_iopps(&parse->parse_io, status ? SYNC_ONE : SYNC_ZERO, &ctime)) + { + nmp = (mblk_t *)NULL; + if (canput(parse->parse_queue->q_next) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED))) + { + bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t)); + nmp->b_wptr += sizeof(parsetime_t); + putnext(parse->parse_queue, nmp); + } + else + if (nmp) freemsg(nmp); + parse_iodone(&parse->parse_io); + } + + if (status) + { + parse->parse_ppsclockev.tv = ctime.tv; + ++(parse->parse_ppsclockev.serial); + } + } + } +} + +static int init_zs_linemon(); /* handle line monitor for "zs" driver */ +static void close_zs_linemon(); +static void zs_xsisr(); /* zs external status interupt handler */ + +/*-------------------- CD isr status monitor ---------------*/ + +static int init_linemon(q) + register queue_t *q; +{ + register queue_t *dq; + + dq = WR(q); + /* + * we ARE doing very bad things down here (basically stealing ISR + * hooks) + * + * so we chase down the STREAMS stack searching for the driver + * and if this is a known driver we insert our ISR routine for + * status changes in to the ExternalStatus handling hook + */ + while (dq->q_next) + { + dq = dq->q_next; /* skip down to driver */ + } + + /* + * find appropriate driver dependent routine + */ + if (dq->q_qinfo && dq->q_qinfo->qi_minfo) + { + register char *dname = dq->q_qinfo->qi_minfo->mi_idname; + + parseprintf(DD_INSTALL, ("init_linemon: driver is \"%s\"\n", dname)); + +#ifdef sun + if (dname && !strcmp(dname, "zs")) + { + return init_zs_linemon(dq, q); + } + else +#endif + { + parseprintf(DD_INSTALL, ("init_linemon: driver \"%s\" not suitable for CD monitoring\n", dname)); + return 0; + } + } + parseprintf(DD_INSTALL, ("init_linemon: cannot find driver\n")); + return 0; +} + +static void close_linemon(q, my_q) + register queue_t *q; + register queue_t *my_q; +{ + /* + * find appropriate driver dependent routine + */ + if (q->q_qinfo && q->q_qinfo->qi_minfo) + { + register char *dname = q->q_qinfo->qi_minfo->mi_idname; + +#ifdef sun + if (dname && !strcmp(dname, "zs")) + { + close_zs_linemon(q, my_q); + return; + } + parseprintf(DD_INSTALL, ("close_linemon: cannot find driver close routine for \"%s\"\n", dname)); +#endif + } + parseprintf(DD_INSTALL, ("close_linemon: cannot find driver name\n")); +} + +#ifdef sun +#include +#include +#include + +struct savedzsops +{ + struct zsops zsops; + struct zsops *oldzsops; +}; + +struct zsops *emergencyzs; + +static int init_zs_linemon(q, my_q) + register queue_t *q; + register queue_t *my_q; +{ + register struct zscom *zs; + register struct savedzsops *szs; + register parsestream_t *parsestream = (parsestream_t *)my_q->q_ptr; + /* + * we expect the zsaline pointer in the q_data pointer + * from there on we insert our on EXTERNAL/STATUS ISR routine + * into the interrupt path, before the standard handler + */ + zs = ((struct zsaline *)q->q_ptr)->za_common; + if (!zs) + { + /* + * well - not found on startup - just say no (shouldn't happen though) + */ + return 0; + } + else + { + unsigned long s; + + /* + * we do a direct replacement, in case others fiddle also + * if somebody else grabs our hook and we disconnect + * we are in DEEP trouble - panic is likely to be next, sorry + */ + szs = (struct savedzsops *) kmem_alloc(sizeof(struct savedzsops)); + + parsestream->parse_data = (void *)szs; + + s = splhigh(); + + parsestream->parse_dqueue = q; /* remember driver */ + + szs->zsops = *zs->zs_ops; + szs->zsops.zsop_xsint = (int (*)())zs_xsisr; /* place our bastard */ + szs->oldzsops = zs->zs_ops; + emergencyzs = zs->zs_ops; + + zsopinit(zs, &szs->zsops); /* hook it up */ + + (void) splx(s); + + parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor installed\n")); + + return 1; + } +} + +/* + * unregister our ISR routine - must call under splhigh() + */ +static void close_zs_linemon(q, my_q) + register queue_t *q; + register queue_t *my_q; +{ + register struct zscom *zs; + register parsestream_t *parsestream = (parsestream_t *)my_q->q_ptr; + + zs = ((struct zsaline *)q->q_ptr)->za_common; + if (!zs) + { + /* + * well - not found on startup - just say no (shouldn't happen though) + */ + return; + } + else + { + register struct savedzsops *szs = (struct savedzsops *)parsestream->parse_data; + + zsopinit(zs, szs->oldzsops); /* reset to previous handler functions */ + + kmem_free((caddr_t)szs, sizeof (struct savedzsops)); + + parseprintf(DD_INSTALL, ("close_zs_linemon: CD monitor deleted\n")); + return; + } +} + +#define MAXDEPTH 50 /* maximum allowed stream crawl */ + +/* + * take external status interrupt (only CD interests us) + */ +static void zs_xsisr(zs) + register struct zscom *zs; +{ + register struct zsaline *za = (struct zsaline *)zs->zs_priv; + register struct zscc_device *zsaddr = zs->zs_addr; + register queue_t *q; + register unsigned char zsstatus; + register int loopcheck; + register unsigned char cdstate; + register char *dname; + + /* + * pick up current state + */ + zsstatus = zsaddr->zscc_control; + + if (za->za_rr0 ^ (cdstate = zsstatus & ZSRR0_CD)) + { + timestamp_t cdevent; + register int status; + + /* + * CONDITIONAL external measurement support + */ + SET_LED(cdstate); /* + * inconsistent with upper SET_LED, but this + * is for oscilloscope business anyway and we + * are just interested in edge delays in the + * lower us range + */ + + /* + * time stamp + */ + uniqtime(&cdevent.tv); + + TIMEVAL_USADD(&cdevent.tv, xsdelay); + + q = za->za_ttycommon.t_readq; + + /* + * logical state + */ + status = cd_invert ? cdstate == 0 : cdstate != 0; + + /* + * ok - now the hard part - find ourself + */ + loopcheck = MAXDEPTH; + + while (q) + { + if (q->q_qinfo && q->q_qinfo->qi_minfo) + { + dname = q->q_qinfo->qi_minfo->mi_idname; + + if (!strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname)) + { + /* + * back home - phew (hopping along stream queues might + * prove dangerous to your health) + */ + + if ((((parsestream_t *)q->q_ptr)->parse_status & PARSE_ENABLE) && + parse_iopps(&((parsestream_t *)q->q_ptr)->parse_io, status ? SYNC_ONE : SYNC_ZERO, &cdevent)) + { + /* + * XXX - currently we do not pass up the message, as + * we should. + * for a correct behaviour wee need to block out + * processing until parse_iodone has been posted via + * a softcall-ed routine which does the message pass-up + * right now PPS information relies on input being + * received + */ + parse_iodone(&((parsestream_t *)q->q_ptr)->parse_io); + } + + if (status) + { + ((parsestream_t *)q->q_ptr)->parse_ppsclockev.tv = cdevent.tv; + ++(((parsestream_t *)q->q_ptr)->parse_ppsclockev.serial); + } + + parseprintf(DD_ISR, ("zs_xsisr: CD event %s has been posted for \"%s\"\n", status ? "ONE" : "ZERO", dname)); + break; + } + } + + q = q->q_next; + + if (!loopcheck--) + { + panic("zs_xsisr: STREAMS Queue corrupted - CD event"); + } + } + + /* + * only pretend that CD has been handled + */ + za->za_rr0 = za->za_rr0 & ~ZSRR0_CD | zsstatus & ZSRR0_CD; + ZSDELAY(2); + + if (!((za->za_rr0 ^ zsstatus) & ~ZSRR0_CD)) + { + /* + * all done - kill status indication and return + */ + zsaddr->zscc_control = ZSWR0_RESET_STATUS; /* might kill other conditions here */ + return; + } + } + + /* + * we are now gathered here to process some unusual external status + * interrupts. + * any CD events have also been handled and shouldn't be processed + * by the original routine (unless we have a VERY busy port pin) + * some initializations are done here, which could have been done before for + * both code paths but have been avioded for minimum path length to + * the uniq_time routine + */ + dname = (char *) 0; + q = za->za_ttycommon.t_readq; + + loopcheck = MAXDEPTH; + + /* + * the real thing for everything else ... + */ + while (q) + { + if (q->q_qinfo && q->q_qinfo->qi_minfo) + { + dname = q->q_qinfo->qi_minfo->mi_idname; + if (!strcmp(dname, parseinfo.st_rdinit->qi_minfo->mi_idname)) + { + register int (*zsisr)(); + + /* + * back home - phew (hopping along stream queues might + * prove dangerous to your health) + */ + if (zsisr = ((struct savedzsops *)((parsestream_t *)q->q_ptr)->parse_data)->oldzsops->zsop_xsint) + (void)zsisr(zs); + else + panic("zs_xsisr: unable to locate original ISR"); + + parseprintf(DD_ISR, ("zs_xsisr: non CD event was processed for \"%s\"\n", dname)); + /* + * now back to our program ... + */ + return; + } + } + + q = q->q_next; + + if (!loopcheck--) + { + panic("zs_xsisr: STREAMS Queue corrupted - non CD event"); + } + } + + /* + * last resort - shouldn't even come here as it indicates + * corrupted TTY structures + */ + printf("zs_zsisr: looking for \"%s\" - found \"%s\" - taking EMERGENCY path\n", parseinfo.st_rdinit->qi_minfo->mi_idname, dname ? dname : "-NIL-"); + + if (emergencyzs && emergencyzs->zsop_xsint) + emergencyzs->zsop_xsint(zs); + else + panic("zs_xsisr: no emergency ISR handler"); +} +#endif /* sun */ + +/* + * History: + * + * parsestreams.c,v + * Revision 3.9 1993/11/05 15:34:55 kardel + * shut up nice feature detection + * + * Revision 3.8 1993/10/22 14:27:56 kardel + * Oct. 22nd 1993 reconcilation + * + * Revision 3.7 1993/10/10 18:13:53 kardel + * Makefile reorganisation, file relocation + * + * Revision 3.6 1993/10/09 15:01:18 kardel + * file structure unified + * + * Revision 3.5 1993/10/04 07:59:31 kardel + * Well, at least we should know that a the tv_usec field should be in the range 0..999999 + * + * Revision 3.4 1993/09/26 23:41:33 kardel + * new parse driver logic + * + * Revision 3.3 1993/09/11 00:38:34 kardel + * LINEMON must also cover M_[UN]HANGUP handling + * + * Revision 3.2 1993/07/06 10:02:56 kardel + * DCF77 driver goes generic... + * + */ diff --git a/contrib/xntpd/parse/util/Makefile b/contrib/xntpd/parse/util/Makefile new file mode 100644 index 0000000000..99caacffa6 --- /dev/null +++ b/contrib/xntpd/parse/util/Makefile @@ -0,0 +1,49 @@ +# +# /src/NTP/REPOSITORY/v3/parse/util/Makefile.tmpl,v 3.11 1993/11/17 13:34:12 kardel Exp +# +COMPILER= gcc +DEFS= -DSYS_FREEBSD -DSYS_386BSD +DEFS_OPT=-DDEBUG +DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DPPSPPS -DKERNEL_PLL +CLOCKDEFS= -DLOCAL_CLOCK -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH +INCL= +COPTS= -O2 +INSTALL= install +BINDIR= /usr/local/bin +# +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) -I../../include +CC= $(COMPILER) +TOP=../../ +# +EXECS=parsetest testdcf dcfd + +all: + @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \ + awk '/-DSTREAM/ && /-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \ + END { if (makeit) \ + { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" parsetest"; } \ + }' | \ + sh + @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \ + awk '/-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \ + END { if (makeit) \ + { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" testdcf"; } \ + }' | \ + sh + @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \ + awk '/-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \ + END { if (makeit) \ + { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" dcfd"; } \ + }' | \ + sh + +clean: + -@rm -f $(EXECS) *.o + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +install: + @echo "--- DCF77 utilities should be installed manually" + @#[ -f testdcf ] && $(INSTALL) -c -m 0755 testdcf $(BINDIR) || true + @#[ -f dcfd ] && $(INSTALL) -c -m 0755 dcfd $(BINDIR) || true diff --git a/contrib/xntpd/parse/util/Makefile.tmpl b/contrib/xntpd/parse/util/Makefile.tmpl new file mode 100644 index 0000000000..a72100f9ec --- /dev/null +++ b/contrib/xntpd/parse/util/Makefile.tmpl @@ -0,0 +1,49 @@ +# +# /src/NTP/REPOSITORY/v3/parse/util/Makefile.tmpl,v 3.11 1993/11/17 13:34:12 kardel Exp +# +COMPILER= cc +DEFS= +DEFS_OPT= +DEFS_LOCAL= +CLOCKDEFS= +INCL= +COPTS= -O +INSTALL= install +BINDIR= +# +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) -I../../include +CC= $(COMPILER) +TOP=../../ +# +EXECS=parsetest testdcf dcfd + +all: + @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \ + awk '/-DSTREAM/ && /-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \ + END { if (makeit) \ + { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" parsetest"; } \ + }' | \ + sh + @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \ + awk '/-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \ + END { if (makeit) \ + { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" testdcf"; } \ + }' | \ + sh + @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \ + awk '/-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \ + END { if (makeit) \ + { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" dcfd"; } \ + }' | \ + sh + +clean: + -@rm -f $(EXECS) *.o + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +install: + @echo "--- DCF77 utilities should be installed manually" + @#[ -f testdcf ] && $(INSTALL) -c -m 0755 testdcf $(BINDIR) || true + @#[ -f dcfd ] && $(INSTALL) -c -m 0755 dcfd $(BINDIR) || true diff --git a/contrib/xntpd/parse/util/README b/contrib/xntpd/parse/util/README new file mode 100644 index 0000000000..4f6dab08e9 --- /dev/null +++ b/contrib/xntpd/parse/util/README @@ -0,0 +1,12 @@ +This directory contains some DCF77 related programs. +They have not yet fully been ported to other architectures then Sun with +SunOS 4.x. So if you want to try them you are on your own - a little +porting may be necessary. + +parsetest: simple parse streams module test +testdcf: simple DCF77 raw impulse test program via 50Baud RS232 +dcfd: simple DCF77 raw impulse receiver with NTP loopfilter + mechanics for synchronisation (allows DCF77 synchronisation + without network code in a nutshell) + +Frank Kardel diff --git a/contrib/xntpd/parse/util/dcfd.c b/contrib/xntpd/parse/util/dcfd.c new file mode 100644 index 0000000000..723e2c8e8c --- /dev/null +++ b/contrib/xntpd/parse/util/dcfd.c @@ -0,0 +1,1206 @@ +/* + * /src/NTP/REPOSITORY/v3/parse/util/dcfd.c,v 3.8 1993/11/04 20:02:05 kardel Exp + * + * dcfd.c,v 3.8 1993/11/04 20:02:05 kardel Exp + * + * DCF77 100/200ms pulse synchronisation daemon program (via 50Baud serial line) + * + * Features: + * DCF77 decoding + * NTP loopfilter logic for local clock + * interactive display for debugging + * + * Lacks: + * Leap second handling (at that level you should switch to xntp3 - really!) + * + * Copyright (c) 1993 + * Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + * This program may not be sold or used for profit without prior + * written consent of the author. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_PROTOTYPES +#include "ntp_stdlib.h" +extern int sigvec P((int, struct sigvec *, struct sigvec *)); +extern int fscanf P((FILE *, char *, ...)); +#endif + +#ifdef SYS_LINUX +#include "ntp_timex.h" +#endif + +#if defined(HAVE_TERMIOS) || defined(STREAM) +#include +#define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) +#define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) +#endif + +#if defined(HAVE_TERMIO) || defined(HAVE_SYSV_TTYS) +#include +#define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) +#define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) +#endif + +#ifndef TTY_GETATTR +MUST DEFINE ONE OF "HAVE_TERMIOS" or "HAVE_TERMIO" +#endif + +#ifndef dysize +#define dysize(_x_) (((_x_) % 4) ? 365 : (((_x_) % 400) ? 365 : 366)) +#endif + +#define timernormalize(_a_, _b_) \ + if ((_a_)->tv_usec >= 1000000) \ + { \ + (_a_)->tv_sec += (_a_)->tv_usec / 1000000; \ + (_a_)->tv_usec -= (_a_)->tv_usec % 1000000; \ + } \ + +#define timeradd(_a_, _b_) \ + (_a_)->tv_sec += (_b_)->tv_sec; \ + (_a_)->tv_usec += (_b_)->tv_usec; \ + timernormalize((_a_), (_b_)) + +#define timersub(_a_, _b_) \ + (_a_)->tv_sec -= (_b_)->tv_sec; \ + (_a_)->tv_usec -= (_b_)->tv_usec; \ + timernormalize((_a_), (_b_)) + +#define PRINTF if (interactive) printf + +#ifdef DEBUG +#define dprintf(_x_) PRINTF _x_ +#else +#define dprintf(_x_) +#endif + +extern int errno; + +static int interactive = 0; +static int loop_filter_debug = 0; + +#define NO_SYNC 0x01 +#define SYNC 0x02 + +static int sync_state = NO_SYNC; +static time_t last_sync; + +static unsigned long ticks = 0; + +static char pat[] = "-\\|/"; + +#define LINES (24-2) /* error lines after which the two headlines are repeated */ + +#define MAX_UNSYNC (5*60) /* allow synchronisation loss for 5 minutes */ +#define NOTICE_INTERVAL (20*60) /* mention missing synchronisation every 20 minutes */ + +/* + * clock adjustment PLL - see NTP protocol spec (RFC1305) for details + */ + +#define USECSCALE 10 +#define TIMECONSTANT 0 +#define ADJINTERVAL 0 +#define FREQ_WEIGHT 18 +#define PHASE_WEIGHT 7 +#define MAX_DRIFT 0x3FFFFFFF + +#define R_SHIFT(_X_, _Y_) (((_X_) < 0) ? -(-(_X_) >> (_Y_)) : ((_X_) >> (_Y_))) + +static struct timeval max_adj_offset = { 0, 128000 }; + +static long clock_adjust = 0; /* current adjustment value (usec * 2^USECSCALE) */ +static long drift_comp = 0; /* accumulated drift value (usec / ADJINTERVAL) */ +static long adjustments = 0; +static char skip_adjust = 1; /* discard first adjustment (bad samples) */ + +/* + * state flags + */ +#define DCFB_ANNOUNCE 0x0001 /* switch time zone warning (DST switch) */ +#define DCFB_DST 0x0002 /* DST in effect */ +#define DCFB_LEAP 0x0004 /* LEAP warning (1 hour prior to occurence) */ +#define DCFB_ALTERNATE 0x0008 /* alternate antenna used */ + +struct clocktime /* clock time broken up from time code */ +{ + long wday; + long day; + long month; + long year; + long hour; + long minute; + long second; + long usecond; + long utcoffset; /* in minutes */ + long flags; /* current clock status */ +}; + +typedef struct clocktime clocktime_t; + +#define TIMES10(_X_) (((_X_) << 3) + ((_X_) << 1)) /* *8 + *2 */ +#define TIMES24(_X_) (((_X_) << 4) + ((_X_) << 3)) /* *16 + *8 */ +#define TIMES60(_X_) ((((_X_) << 4) - (_X_)) << 2) /* *(16 - 1) *4 */ +#define abs(_x_) (((_x_) < 0) ? -(_x_) : (_x_)) + +/* + * parser related return/error codes + */ +#define CVT_MASK 0x0000000F /* conversion exit code */ +#define CVT_NONE 0x00000001 /* format not applicable */ +#define CVT_FAIL 0x00000002 /* conversion failed - error code returned */ +#define CVT_OK 0x00000004 /* conversion succeeded */ +#define CVT_BADFMT 0x00000010 /* general format error - (unparsable) */ +#define CVT_BADDATE 0x00000020 /* invalid date */ +#define CVT_BADTIME 0x00000040 /* invalid time */ + +/* + * DCF77 raw time code + * + * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig + * und Berlin, Maerz 1989 + * + * Timecode transmission: + * AM: + * time marks are send every second except for the second before the + * next minute mark + * time marks consist of a reduction of transmitter power to 25% + * of the nominal level + * the falling edge is the time indication (on time) + * time marks of a 100ms duration constitute a logical 0 + * time marks of a 200ms duration constitute a logical 1 + * FM: + * see the spec. (basically a (non-)inverted psuedo random phase shift) + * + * Encoding: + * Second Contents + * 0 - 10 AM: free, FM: 0 + * 11 - 14 free + * 15 R - alternate antenna + * 16 A1 - expect zone change (1 hour before) + * 17 - 18 Z1,Z2 - time zone + * 0 0 illegal + * 0 1 MEZ (MET) + * 1 0 MESZ (MED, MET DST) + * 1 1 illegal + * 19 A2 - expect leap insertion/deletion (1 hour before) + * 20 S - start of time code (1) + * 21 - 24 M1 - BCD (lsb first) Minutes + * 25 - 27 M10 - BCD (lsb first) 10 Minutes + * 28 P1 - Minute Parity (even) + * 29 - 32 H1 - BCD (lsb first) Hours + * 33 - 34 H10 - BCD (lsb first) 10 Hours + * 35 P2 - Hour Parity (even) + * 36 - 39 D1 - BCD (lsb first) Days + * 40 - 41 D10 - BCD (lsb first) 10 Days + * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday) + * 45 - 49 MO - BCD (lsb first) Month + * 50 MO0 - 10 Months + * 51 - 53 Y1 - BCD (lsb first) Years + * 54 - 57 Y10 - BCD (lsb first) 10 Years + * 58 P3 - Date Parity (even) + * 59 - usually missing (minute indication), except for leap insertion + */ + +static struct rawdcfcode +{ + char offset; /* start bit */ +} rawdcfcode[] = +{ + { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 }, + { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 } +}; + +#define DCF_M 0 +#define DCF_R 1 +#define DCF_A1 2 +#define DCF_Z 3 +#define DCF_A2 4 +#define DCF_S 5 +#define DCF_M1 6 +#define DCF_M10 7 +#define DCF_P1 8 +#define DCF_H1 9 +#define DCF_H10 10 +#define DCF_P2 11 +#define DCF_D1 12 +#define DCF_D10 13 +#define DCF_DW 14 +#define DCF_MO 15 +#define DCF_MO0 16 +#define DCF_Y1 17 +#define DCF_Y10 18 +#define DCF_P3 19 + +static struct partab +{ + char offset; /* start bit of parity field */ +} partab[] = +{ + { 21 }, { 29 }, { 36 }, { 59 } +}; + +static struct dcfparam +{ + unsigned char onebits[60]; + unsigned char zerobits[60]; +} dcfparam = +{ + "###############RADMLS1248124P124812P1248121241248112481248P", /* 'ONE' representation */ + "--------------------s-------p------p----------------------p" /* 'ZERO' representation */ +}; + +#define DCF_P_P1 0 +#define DCF_P_P2 1 +#define DCF_P_P3 2 + +#define DCF_Z_MET 0x2 +#define DCF_Z_MED 0x1 + +static unsigned long ext_bf(buf, idx) + register unsigned char *buf; + register int idx; +{ + register unsigned long sum = 0; + register int i, first; + + first = rawdcfcode[idx].offset; + + for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--) + { + sum <<= 1; + sum |= (buf[i] != dcfparam.zerobits[i]); + } + return sum; +} + +static unsigned pcheck(buf, idx) + register unsigned char *buf; + register int idx; +{ + register int i,last; + register unsigned psum = 1; + + last = partab[idx+1].offset; + + for (i = partab[idx].offset; i < last; i++) + psum ^= (buf[i] != dcfparam.zerobits[i]); + + return psum; +} + +static unsigned long convert_rawdcf(buffer, size, clock) + register unsigned char *buffer; + register int size; + register clocktime_t *clock; +{ + if (size < 57) + { + PRINTF("%-30s", "*** INCOMPLETE"); + return CVT_NONE; + } + + /* + * check Start and Parity bits + */ + if ((ext_bf(buffer, DCF_S) == 1) && + pcheck(buffer, DCF_P_P1) && + pcheck(buffer, DCF_P_P2) && + pcheck(buffer, DCF_P_P3)) + { + /* + * buffer OK + */ + + clock->flags = 0; + clock->usecond= 0; + clock->second = 0; + clock->minute = ext_bf(buffer, DCF_M10); + clock->minute = TIMES10(clock->minute) + ext_bf(buffer, DCF_M1); + clock->hour = ext_bf(buffer, DCF_H10); + clock->hour = TIMES10(clock->hour) + ext_bf(buffer, DCF_H1); + clock->day = ext_bf(buffer, DCF_D10); + clock->day = TIMES10(clock->day) + ext_bf(buffer, DCF_D1); + clock->month = ext_bf(buffer, DCF_MO0); + clock->month = TIMES10(clock->month) + ext_bf(buffer, DCF_MO); + clock->year = ext_bf(buffer, DCF_Y10); + clock->year = TIMES10(clock->year) + ext_bf(buffer, DCF_Y1); + clock->wday = ext_bf(buffer, DCF_DW); + + switch (ext_bf(buffer, DCF_Z)) + { + case DCF_Z_MET: + clock->utcoffset = -60; + break; + + case DCF_Z_MED: + clock->flags |= DCFB_DST; + clock->utcoffset = -120; + break; + + default: + PRINTF("%-30s", "*** BAD TIME ZONE"); + return CVT_FAIL|CVT_BADFMT; + } + + if (ext_bf(buffer, DCF_A1)) + clock->flags |= DCFB_ANNOUNCE; + + if (ext_bf(buffer, DCF_A2)) + clock->flags |= DCFB_LEAP; + + if (ext_bf(buffer, DCF_R)) + clock->flags |= DCFB_ALTERNATE; + + return CVT_OK; + } + else + { + /* + * bad format - not for us + */ + PRINTF("%-30s", "*** BAD FORMAT (invalid/parity)"); + return CVT_FAIL|CVT_BADFMT; + } +} + +/* + * raw dcf input routine - fix up 50 baud + * characters for 1/0 decision + */ +static unsigned long cvt_rawdcf(buffer, size, clock) + register unsigned char *buffer; + register int size; + register clocktime_t *clock; +{ + register unsigned char *s = buffer; + register unsigned char *e = buffer + size; + register unsigned char *b = dcfparam.onebits; + register unsigned char *c = dcfparam.zerobits; + register unsigned rtc = CVT_NONE; + register unsigned int i, lowmax, highmax, cutoff, span; +#define BITS 9 + unsigned char histbuf[BITS]; + /* + * the input buffer contains characters with runs of consecutive + * bits set. These set bits are an indication of the DCF77 pulse + * length. We assume that we receive the pulse at 50 Baud. Thus + * a 100ms pulse would generate a 4 bit train (20ms per bit and + * start bit) + * a 200ms pulse would create all zeroes (and probably a frame error) + */ + + for (i = 0; i < BITS; i++) + { + histbuf[i] = 0; + } + + cutoff = 0; + lowmax = 0; + + while (s < e) + { + register unsigned int ch = *s ^ 0xFF; + /* + * these lines are left as an excercise to the reader 8-) + */ + if (!((ch+1) & ch) || !*s) + { + + for (i = 0; ch; i++) + { + ch >>= 1; + } + + *s = i; + histbuf[i]++; + cutoff += i; + lowmax++; + } + else + { + dprintf(("parse: cvt_rawdcf: character check for 0x%x@%d FAILED\n", *s, s - buffer)); + *s = ~0; + rtc = CVT_FAIL|CVT_BADFMT; + } + s++; + } + + if (lowmax) + { + cutoff /= lowmax; + } + else + { + cutoff = 4; /* doesn't really matter - it'll fail anyway, but gives error output */ + } + + dprintf(("parse: cvt_rawdcf: average bit count: %d\n", cutoff)); + + lowmax = 0; + highmax = 0; + + dprintf(("parse: cvt_rawdcf: histogram:")); + for (i = 0; i <= cutoff; i++) + { + lowmax+=histbuf[i] * i; + highmax += histbuf[i]; + dprintf((" %d", histbuf[i])); + } + dprintf((" ")); + + lowmax += highmax / 2; + + if (highmax) + { + lowmax /= highmax; + } + else + { + lowmax = 0; + } + + highmax = 0; + cutoff = 0; + + for (; i < BITS; i++) + { + highmax+=histbuf[i] * i; + cutoff +=histbuf[i]; + dprintf((" %d", histbuf[i])); + } + dprintf(("\n")); + + if (cutoff) + { + highmax /= cutoff; + } + else + { + highmax = BITS-1; + } + + span = cutoff = lowmax; + for (i = lowmax; i <= highmax; i++) + { + if (histbuf[cutoff] > histbuf[i]) + { + cutoff = i; + span = i; + } + else + if (histbuf[cutoff] == histbuf[i]) + { + span = i; + } + } + + cutoff = (cutoff + span) / 2; + + dprintf(("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff)); + + s = buffer; + while ((s < e) && *c && *b) + { + if (*s == (unsigned char)~0) + { + *s = '?'; + } + else + { + *s = (*s >= cutoff) ? *b : *c; + } + s++; + b++; + c++; + } + + return (rtc == CVT_NONE) ? convert_rawdcf(buffer, size, clock) : rtc; +} + +time_t +parse_to_unixtime(clock, cvtrtc) + register clocktime_t *clock; + register unsigned long *cvtrtc; +{ +#define SETRTC(_X_) { if (cvtrtc) *cvtrtc = (_X_); } + static int days_of_month[] = + { + 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + register int i; + time_t t; + + if (clock->year < 100) + clock->year += 1900; + + if (clock->year < 1970) + clock->year += 100; /* XXX this will do it till <2070 */ + + if (clock->year < 0) + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; + } + + /* + * sorry, slow section here - but it's not time critical anyway + */ + t = (clock->year - 1970) * 365; + t += (clock->year >> 2) - (1970 >> 2); + t -= clock->year / 400 - 1970 / 400; + + /* month */ + if (clock->month <= 0 || clock->month > 12) + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; /* bad month */ + } + /* adjust leap year */ + if (clock->month >= 3 && dysize(clock->year) == 366) + t++; + + for (i = 1; i < clock->month; i++) + { + t += days_of_month[i]; + } + /* day */ + if (clock->day < 1 || ((clock->month == 2 && dysize(clock->year) == 366) ? + clock->day > 29 : clock->day > days_of_month[clock->month])) + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; /* bad day */ + } + + t += clock->day - 1; + /* hour */ + if (clock->hour < 0 || clock->hour >= 24) + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad hour */ + } + + t = TIMES24(t) + clock->hour; + + /* min */ + if (clock->minute < 0 || clock->minute > 59) + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad min */ + } + + t = TIMES60(t) + clock->minute; + /* sec */ + + t += clock->utcoffset; /* warp to UTC */ + + if (clock->second < 0 || clock->second > 60) /* allow for LEAPs */ + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad sec */ + } + + t = TIMES60(t) + clock->second; + /* done */ + return t; +} + +/* + * cheap half baked 1/0 decision - for interactive operation only + */ +static char type(c) +unsigned char c; +{ + c ^= 0xFF; + return (c > 0xF); +} + +static char *wday[8] = +{ + "??", + "Mo", + "Tu", + "We", + "Th", + "Fr", + "Sa", + "Su" +}; + +static char * pr_timeval(val) + struct timeval *val; +{ + static char buf[20]; + + if (val->tv_sec == 0) + sprintf(buf, "%c0.%06d", (val->tv_usec < 0) ? '-' : '+', abs(val->tv_usec)); + else + sprintf(buf, "%d.%06d", val->tv_sec, abs(val->tv_usec)); + return buf; +} + +static void set_time(offset) + struct timeval *offset; +{ + struct timeval the_time; + /*XXX*/ if (loop_filter_debug) printf("set_time: %s ", pr_timeval(offset)); + if (gettimeofday(&the_time, 0L) == -1) + { + perror("gettimeofday()"); + } + else + { + timeradd(&the_time, offset); + if (settimeofday(&the_time, 0L) == -1) + { + perror("settimeofday()"); + } + } +} + +static void adj_time(offset) + register long offset; +{ + struct timeval time_offset; + + time_offset.tv_sec = offset / 1000000; + time_offset.tv_usec = offset % 1000000; + + /*XXX*/ if (loop_filter_debug) + printf("adj_time: %d us ", offset); + if (adjtime(&time_offset, 0L) == -1) + perror("adjtime()"); +} + +static void read_drift(drift_file) + char *drift_file; +{ + FILE *df; + + df = fopen(drift_file, "r"); + if (df != NULL) + { + int idrift, fdrift; + + fscanf(df, "%4d.%03d", &idrift, &fdrift); + fclose(df); + /*XXX*/ if (loop_filter_debug) + printf("read_drift: %d.%03d ppm ", idrift, fdrift); + + drift_comp = idrift << USECSCALE; + fdrift = (fdrift << USECSCALE) / 1000; + drift_comp += fdrift & (1<)) + { + /* + * hopeless - set the clock - and clear the timing + */ + set_time(offset); + clock_adjust = 0; + skip_adjust = 1; + return; + } + + usecoffset = offset->tv_sec * 1000000 + offset->tv_usec; + + clock_adjust = R_SHIFT(usecoffset, TIMECONSTANT); /* adjustment to make for next period */ + + tmp = 0; + while (adjustments > (1 << tmp)) + tmp++; + adjustments = 0; + if (tmp > FREQ_WEIGHT) + tmp = FREQ_WEIGHT; + + drift_comp += R_SHIFT(usecoffset << USECSCALE, TIMECONSTANT+TIMECONSTANT+FREQ_WEIGHT-tmp); + + if (drift_comp > MAX_DRIFT) /* clamp into interval */ + drift_comp = MAX_DRIFT; + else + if (drift_comp < -MAX_DRIFT) + drift_comp = -MAX_DRIFT; + + update_drift(drift_file, usecoffset, reftime); + /*XXX*/ if (loop_filter_debug) + printf("clock_adjust: %s, clock_adjust %d, drift_comp %d(%d) ", + pr_timeval(offset), R_SHIFT(clock_adjust, USECSCALE) , R_SHIFT(drift_comp, USECSCALE), drift_comp); +} + +static void periodic_adjust() +{ + register long adjustment; + + adjustments++; + + adjustment = R_SHIFT(clock_adjust, PHASE_WEIGHT); + + clock_adjust -= adjustment; + + adjustment += R_SHIFT(drift_comp, USECSCALE+ADJINTERVAL); + + adj_time(adjustment); +} + +static void tick() +{ + static unsigned long last_notice; + +#ifndef SV_ONSTACK + (void)signal(SIGALRM, tick); +#endif + + periodic_adjust(); + + ticks += 1< MAX_UNSYNC) && + ((last_notice - ticks) > NOTICE_INTERVAL)) + { + syslog(LOG_NOTICE, "still not synchronized - check receiver/signal"); + last_notice = ticks; + } + +#ifndef ITIMER_REAL + (void) alarm(1<] \n", program); + fprintf(stderr, "\t-i interactive\n"); + fprintf(stderr, "\t-t trace (print all datagrams)\n"); + fprintf(stderr, "\t-f print all databits (includes PTB private data)\n"); + fprintf(stderr, "\t-l print loop filter debug information\n"); + fprintf(stderr, "\t-o print offet average for current minute\n"); + fprintf(stderr, "\t-d specify alternate drift file\n"); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + unsigned char c; + char **a = argv; + int ac = argc; + char *file = NULL; + char *drift_file = "/etc/dcfd.drift"; + int fd; + int offset = 15; + int offsets = 0; + int trace = 0; + int errs = 0; + + while (--ac) + { + char *arg = *++a; + if (*arg == '-') + while ((c = *++arg)) + switch (c) + { + case 't': + trace = 1; + interactive = 1; + break; + + case 'f': + offset = 0; + interactive = 1; + break; + + case 'l': + loop_filter_debug = 1; + offsets = 1; + interactive = 1; + break; + + case 'o': + offsets = 1; + interactive = 1; + break; + + case 'i': + interactive = 1; + break; + + case 'd': + if (ac > 1) + { + drift_file = *++a; + ac--; + } + else + { + fprintf(stderr, "%s: -d requires file name argument\n", argv[0]); + errs=1; + } + break; + + default: + fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); + errs=1; + break; + } + else + if (file == NULL) + file = arg; + else + { + fprintf(stderr, "%s: device specified twice\n", argv[0]); + errs=1; + } + } + + if (errs) + { + usage(argv[0]); + exit(1); + } + else + if (file == NULL) + { + fprintf(stderr, "%s: device not specified\n", argv[0]); + usage(argv[0]); + exit(1); + } + + errs = LINES+1; + + fd = open(file, O_RDONLY); + if (fd == -1) + { + perror(file); + exit(1); + } + else + { + int i, rrc; + struct timeval t, tt, tlast; + struct timeval timeout; + struct timeval phase; + struct timeval time_offset; + char pbuf[61]; /* printable version */ + char buf[61]; /* raw data */ + clocktime_t clock; /* wall clock time */ + time_t utc_time = 0; + long usecerror = 0; + long lasterror = 0; +#if defined(HAVE_TERMIOS) || defined(STREAM) + struct termios term; +#endif +#if defined(HAVE_TERMIO) || defined(HAVE_SYSV_TTYS) + struct termio term; +#endif + int rtc = CVT_NONE; + + timeout.tv_sec = 1; + timeout.tv_usec = 500000; + + phase.tv_sec = 0; + phase.tv_usec = 230000; + + if (TTY_GETATTR(fd, &term) == -1) + { + perror("tcgetattr"); + exit(1); + } + + memset(term.c_cc, 0, sizeof(term.c_cc)); + term.c_cc[VMIN] = 1; + term.c_cflag = B50|CS8|CREAD|CLOCAL; + term.c_iflag = 0; + term.c_oflag = 0; + term.c_lflag = 0; + + if (TTY_SETATTR(fd, &term) == -1) + { + perror("tcsetattr"); + exit(1); + } + + if (!interactive) + detach(); + +#ifdef LOG_DAEMON + openlog("dcfd", LOG_PID, LOG_DAEMON); +#else + openlog("dcfd", LOG_PID); +#endif + +#ifdef SV_ONSTACK + { + struct sigvec vec; + + vec.sv_handler = tick; + vec.sv_mask = 0; + vec.sv_flags = 0; + + if (sigvec(SIGALRM, &vec, (struct sigvec *)0) == -1) + { + syslog(LOG_ERR, "sigvec(SIGALRM): %m"); + exit(1); + } + } +#else + (void) signal(SIGALRM, tick); +#endif + +#ifdef ITIMER_REAL + { + struct itimerval it; + + it.it_interval.tv_sec = 1< LINES) + { + PRINTF(" %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]); + PRINTF(" %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]); + errs = 0; + } + + if (timercmp(&t, &timeout, >)) + { + PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]); + + if ((rtc = cvt_rawdcf(buf, i, &clock)) != CVT_OK) + { + PRINTF("\n"); + if (sync_state == SYNC) + { + sync_state = NO_SYNC; + syslog(LOG_DEBUG, "DCF77 reception lost"); + } + errs++; + } + + buf[0] = c; + + if (((c^0xFF)+1) & (c^0xFF)) + pbuf[0] = '?'; + else + pbuf[0] = type(c) ? '#' : '-'; + + for ( i = 1; i < 60; i++) + pbuf[i] = '.'; + + i = 0; + } + else + { + buf[i] = c; + + /* + * initial guess (usually correct) + */ + if (((c^0xFF)+1) & (c^0xFF)) + pbuf[i] = '?'; + else + pbuf[i] = type(c) ? '#' : '-'; + + PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]); + } + + if (i == 0 && rtc == CVT_OK) + { + if ((utc_time = parse_to_unixtime(&clock, &rtc)) == -1) + { + PRINTF("*** BAD CONVERSION\n"); + } + + usecerror = 0; + } + + if (rtc == CVT_OK) + { + if (trace && (i == 0)) + { + PRINTF("\r %.*s ", 59 - offset, &buf[offset]); + } + + if (i == 0) + { + time_offset.tv_sec = lasterror / 1000000; + time_offset.tv_usec = lasterror % 1000000; + adjust_clock(&time_offset, drift_file, utc_time+i); + last_sync = ticks; + if (sync_state == NO_SYNC) + { + syslog(LOG_INFO, "receiving DCF77"); + } + sync_state = SYNC; + } + + time_offset.tv_sec = utc_time + i; + time_offset.tv_usec = 0; + + timeradd(&time_offset, &phase); + + usecerror += (time_offset.tv_sec - tt.tv_sec) * 1000000 + time_offset.tv_usec + -tt.tv_usec; + + PRINTF(offsets ? "%s, %2d:%02d:%02d, %d.%02d.%02d, <%s%s%s%s> (%c%d.%06ds)" : + "%s, %2d:%02d:%02d, %d.%02d.%02d, <%s%s%s%s>", + wday[clock.wday], + clock.hour, clock.minute, i, clock.day, clock.month, + clock.year, + (clock.flags & DCFB_ALTERNATE) ? "R" : "_", + (clock.flags & DCFB_ANNOUNCE) ? "A" : "_", + (clock.flags & DCFB_DST) ? "D" : "_", + (clock.flags & DCFB_LEAP) ? "L" : "_", + (lasterror < 0) ? '-' : '+', abs(lasterror) / 1000000, abs(lasterror) % 1000000 + ); + + if (trace && (i == 0)) + { + PRINTF("\n"); + errs++; + } + lasterror = usecerror / (i+1); + } + + PRINTF("\r"); + + if (i < 60) + { + i++; + } + + tlast = tt; + + if (interactive) + fflush(stdout); + } + } while ((rrc == -1) && (errno == EINTR)); + + syslog(LOG_ERR, "TERMINATING - cannot read from device %s", file); + + (void)close(fd); + } + + closelog(); + + return 0; +} diff --git a/contrib/xntpd/parse/util/parsetest.c b/contrib/xntpd/parse/util/parsetest.c new file mode 100644 index 0000000000..4f26a0a6a9 --- /dev/null +++ b/contrib/xntpd/parse/util/parsetest.c @@ -0,0 +1,268 @@ +/* + * /src/NTP/REPOSITORY/v3/kernel/parsetest.c,v 3.4 1993/03/17 17:16:57 kardel Exp + * + * parsetest.c,v 3.4 1993/03/17 17:16:57 kardel Exp + * + * Copyright (c) 1989,1990,1991,1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + * parsetest.c,v + * Revision 3.4 1993/03/17 17:16:57 kardel + * DEC OSF/1 ALPHA Integration - 930314 + * + * Revision 3.3 1993/01/18 09:24:33 kardel + * updated copyright conditions in conjunction with + * conditions set up in the COPYRIGHT file + * + * Revision 3.2 1993/01/17 13:43:00 kardel + * 1993 initial update + * + */ + +#ifndef STREAM +ONLY STREAM OPERATION SUPPORTED +#endif + +#define PARSESTREAM /* there is no other choice - TEST HACK */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define P(X) () + +#include "ntp_fp.h" +#ifdef USE_PROTOTYPES +#include "ntp_stdlib.h" +#endif +#include "parse.h" + +static char *strstatus(buffer, state) + char *buffer; + unsigned LONG state; +{ + static struct bits + { + unsigned LONG bit; + 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_LEAP, "LEAP WARNING" }, + { PARSEB_LEAPSECOND, "LEAP SECOND" }, + { PARSEB_ALTERNATE,"ALTERNATE ANTENNA" }, + { PARSEB_TIMECODE, "TIME CODE" }, + { PARSEB_PPS, "PPS" }, + { PARSEB_POSITION, "POSITION" }, + { 0 } + }; + + static struct sbits + { + unsigned LONG bit; + 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 & state) + { + if (buffer[0]) + strcat(buffer, "; "); + strcat(buffer, flagstrings[i].name); + } + i++; + } + + if (state & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION)) + { + register 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 & state) + { + 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(state, buffer) + unsigned LONG state; + char *buffer; +{ + static struct bits + { + unsigned LONG bit; + 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" }, + { 0 } + }; + int i; + + *buffer = '\0'; + + i = 0; + while (flagstrings[i].bit) + { + if (flagstrings[i].bit & state) + { + if (buffer[0]) + strcat(buffer, "; "); + strcat(buffer, flagstrings[i].name); + } + i++; + } + + return buffer; +} + +int +main(argc, argv) + int argc; + char **argv; +{ + if (argc != 2) + { + fprintf(stderr,"usage: %s \n", argv[0]); + exit(1); + } + else + { + int fd; + + fd = open(argv[1], O_RDWR); + if (fd == -1) + { + perror(argv[1]); + exit(1); + } + else + { + parsectl_t dct; + parsetime_t parsetime; + struct strioctl strioc; + + printf("parsetest.c,v 3.9 1993/10/10 21:18:49 kardel Exp\n"); + + while (ioctl(fd, I_POP, 0) == 0) + ; + + if (ioctl(fd, I_PUSH, "parse") == -1) + { + perror("ioctl(I_PUSH,\"parse\")"); + exit(1); + } + + strioc.ic_cmd = PARSEIOC_GETSTAT; + strioc.ic_timout = 0; + strioc.ic_dp = (char *)&dct; + strioc.ic_len = sizeof(parsectl_t); + + if (ioctl(fd, I_STR, &strioc) == -1) + { + perror("ioctl(fd, I_STR(PARSEIOC_GETSTAT))"); + exit(1); + } + printf("parse status: %04x\n", dct.parsestatus.flags); + + dct.parsestatus.flags |= PARSE_STAT_FILTER; + strioc.ic_cmd = PARSEIOC_SETSTAT; + + if (ioctl(fd, I_STR, &strioc) == -1) + { + perror("ioctl(fd, I_STR(PARSEIOC_SETSTAT))"); + exit(1); + } + printf("PARSE clock FILTERMODE\n"); + + if (ioctl(fd, I_STR, &strioc) == -1) + { + perror("ioctl(fd, I_STR(PARSEIOC_GETSTAT))"); + exit(1); + } + printf("parse status: %04x\n", dct.parsestatus.flags); + + while (read(fd, &parsetime, sizeof(parsetime)) == sizeof(parsetime)) + { + char tmp[200], tmp1[200], tmp2[60]; + + strncpy(tmp, asctime(localtime(&parsetime.parse_time.tv.tv_sec)), 30); + strncpy(tmp1,asctime(localtime(&parsetime.parse_stime.tv.tv_sec)), 30); + strncpy(tmp2,asctime(localtime(&parsetime.parse_ptime.tv.tv_sec)), 30); + tmp[24] = '\0'; + tmp1[24] = '\0'; + tmp2[24] = '\0'; + + printf("%s (+%06dus) %s PPS: %s (+%06dus), ", tmp1, parsetime.parse_stime.tv.tv_usec, tmp, tmp2, parsetime.parse_ptime.tv.tv_usec); + + strstatus(tmp, parsetime.parse_state); + printf("state: 0x%x (%s) error: %dus, dispersion: %dus, Status: 0x%x (%s)\n", + parsetime.parse_state, + tmp, + parsetime.parse_usecerror, + parsetime.parse_usecdisp, + parsetime.parse_status, + parsestatus(parsetime.parse_status, tmp1)); + } + + close(fd); + } + } + return 0; +} diff --git a/contrib/xntpd/parse/util/testdcf.c b/contrib/xntpd/parse/util/testdcf.c new file mode 100644 index 0000000000..e07bc0c1cc --- /dev/null +++ b/contrib/xntpd/parse/util/testdcf.c @@ -0,0 +1,485 @@ +/* + * /src/NTP/REPOSITORY/v3/parse/util/testdcf.c,v 3.7 1993/10/10 22:44:48 kardel Exp + * + * testdcf.c,v 3.7 1993/10/10 22:44:48 kardel Exp + * + * simple DCF77 100/200ms pulse test program (via 50Baud serial line) + * + * Copyright (c) 1993 + * Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + * This program may not be sold or used for profit without prior + * written consent of the author. + */ + +#include +#include +#include +#include +#include +#ifdef STREAM +#include +#include +#endif +#include + +#include "ntp_stdlib.h" + +/* + * state flags + */ +#define DCFB_ANNOUNCE 0x0001 /* switch time zone warning (DST switch) */ +#define DCFB_DST 0x0002 /* DST in effect */ +#define DCFB_LEAP 0x0004 /* LEAP warning (1 hour prior to occurence) */ +#define DCFB_ALTERNATE 0x0008 /* alternate antenna used */ + +struct clocktime /* clock time broken up from time code */ +{ + long wday; + long day; + long month; + long year; + long hour; + long minute; + long second; + long usecond; + long utcoffset; /* in minutes */ + long flags; /* current clock status */ +}; + +typedef struct clocktime clocktime_t; + +#define TIMES10(_X_) (((_X_) << 3) + ((_X_) << 1)) + +/* + * parser related return/error codes + */ +#define CVT_MASK 0x0000000F /* conversion exit code */ +#define CVT_NONE 0x00000001 /* format not applicable */ +#define CVT_FAIL 0x00000002 /* conversion failed - error code returned */ +#define CVT_OK 0x00000004 /* conversion succeeded */ +#define CVT_BADFMT 0x00000010 /* general format error - (unparsable) */ + +/* + * DCF77 raw time code + * + * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig + * und Berlin, Maerz 1989 + * + * Timecode transmission: + * AM: + * time marks are send every second except for the second before the + * next minute mark + * time marks consist of a reduction of transmitter power to 25% + * of the nominal level + * the falling edge is the time indication (on time) + * time marks of a 100ms duration constitute a logical 0 + * time marks of a 200ms duration constitute a logical 1 + * FM: + * see the spec. (basically a (non-)inverted psuedo random phase shift) + * + * Encoding: + * Second Contents + * 0 - 10 AM: free, FM: 0 + * 11 - 14 free + * 15 R - alternate antenna + * 16 A1 - expect zone change (1 hour before) + * 17 - 18 Z1,Z2 - time zone + * 0 0 illegal + * 0 1 MEZ (MET) + * 1 0 MESZ (MED, MET DST) + * 1 1 illegal + * 19 A2 - expect leap insertion/deletion (1 hour before) + * 20 S - start of time code (1) + * 21 - 24 M1 - BCD (lsb first) Minutes + * 25 - 27 M10 - BCD (lsb first) 10 Minutes + * 28 P1 - Minute Parity (even) + * 29 - 32 H1 - BCD (lsb first) Hours + * 33 - 34 H10 - BCD (lsb first) 10 Hours + * 35 P2 - Hour Parity (even) + * 36 - 39 D1 - BCD (lsb first) Days + * 40 - 41 D10 - BCD (lsb first) 10 Days + * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday) + * 45 - 49 MO - BCD (lsb first) Month + * 50 MO0 - 10 Months + * 51 - 53 Y1 - BCD (lsb first) Years + * 54 - 57 Y10 - BCD (lsb first) 10 Years + * 58 P3 - Date Parity (even) + * 59 - usually missing (minute indication), except for leap insertion + */ + +static struct rawdcfcode +{ + char offset; /* start bit */ +} rawdcfcode[] = +{ + { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 }, + { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 } +}; + +#define DCF_M 0 +#define DCF_R 1 +#define DCF_A1 2 +#define DCF_Z 3 +#define DCF_A2 4 +#define DCF_S 5 +#define DCF_M1 6 +#define DCF_M10 7 +#define DCF_P1 8 +#define DCF_H1 9 +#define DCF_H10 10 +#define DCF_P2 11 +#define DCF_D1 12 +#define DCF_D10 13 +#define DCF_DW 14 +#define DCF_MO 15 +#define DCF_MO0 16 +#define DCF_Y1 17 +#define DCF_Y10 18 +#define DCF_P3 19 + +static struct partab +{ + char offset; /* start bit of parity field */ +} partab[] = +{ + { 21 }, { 29 }, { 36 }, { 59 } +}; + +#define DCF_P_P1 0 +#define DCF_P_P2 1 +#define DCF_P_P3 2 + +#define DCF_Z_MET 0x2 +#define DCF_Z_MED 0x1 + +static unsigned long ext_bf(buf, idx) + register char *buf; + register int idx; +{ + register unsigned long sum = 0; + register int i, first; + + first = rawdcfcode[idx].offset; + + for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--) + { + sum <<= 1; + sum |= (buf[i] != '-'); + } + return sum; +} + +static unsigned pcheck(buf, idx) + register char *buf; + register int idx; +{ + register int i,last; + register unsigned psum = 1; + + last = partab[idx+1].offset; + + for (i = partab[idx].offset; i < last; i++) + psum ^= (buf[i] != '-'); + + return psum; +} + +static unsigned long convert_rawdcf(buffer, size, clock) + register unsigned char *buffer; + register int size; + register clocktime_t *clock; +{ + if (size < 57) + { + printf("%-30s", "*** INCOMPLETE"); + return CVT_NONE; + } + + /* + * check Start and Parity bits + */ + if ((ext_bf(buffer, DCF_S) == 1) && + pcheck(buffer, DCF_P_P1) && + pcheck(buffer, DCF_P_P2) && + pcheck(buffer, DCF_P_P3)) + { + /* + * buffer OK + */ + + clock->flags = 0; + clock->usecond= 0; + clock->second = 0; + clock->minute = ext_bf(buffer, DCF_M10); + clock->minute = TIMES10(clock->minute) + ext_bf(buffer, DCF_M1); + clock->hour = ext_bf(buffer, DCF_H10); + clock->hour = TIMES10(clock->hour) + ext_bf(buffer, DCF_H1); + clock->day = ext_bf(buffer, DCF_D10); + clock->day = TIMES10(clock->day) + ext_bf(buffer, DCF_D1); + clock->month = ext_bf(buffer, DCF_MO0); + clock->month = TIMES10(clock->month) + ext_bf(buffer, DCF_MO); + clock->year = ext_bf(buffer, DCF_Y10); + clock->year = TIMES10(clock->year) + ext_bf(buffer, DCF_Y1); + clock->wday = ext_bf(buffer, DCF_DW); + + switch (ext_bf(buffer, DCF_Z)) + { + case DCF_Z_MET: + clock->utcoffset = -60; + break; + + case DCF_Z_MED: + clock->flags |= DCFB_DST; + clock->utcoffset = -120; + break; + + default: + printf("%-30s", "*** BAD TIME ZONE"); + return CVT_FAIL|CVT_BADFMT; + } + + if (ext_bf(buffer, DCF_A1)) + clock->flags |= DCFB_ANNOUNCE; + + if (ext_bf(buffer, DCF_A2)) + clock->flags |= DCFB_LEAP; + + if (ext_bf(buffer, DCF_R)) + clock->flags |= DCFB_ALTERNATE; + + return CVT_OK; + } + else + { + /* + * bad format - not for us + */ + printf("%-30s", "*** BAD FORMAT (invalid/parity)"); + return CVT_FAIL|CVT_BADFMT; + } +} + +char type(c) +unsigned char c; +{ + c ^= 0xFF; + return (c > 0xF); +} + +static char *wday[8] = +{ + "??", + "Mo", + "Tu", + "We", + "Th", + "Fr", + "Sa", + "Su" +}; + +static char pat[] = "-\\|/"; + +#define LINES (24-2) /* error lines after which the two headlines are repeated */ + +int +main(argc, argv) + int argc; + char **argv; +{ + if ((argc != 2) && (argc != 3)) + { + fprintf(stderr, "usage: %s [-f|-t|-ft|-tf] \n", argv[0]); + exit(1); + } + else + { + unsigned char c; + char *file; + int fd; + int offset = 15; + int trace = 0; + int errs = LINES+1; + + /* + * SIMPLE(!) argument "parser" + */ + if (argc == 3) + { + if (strcmp(argv[1], "-f") == 0) + offset = 0; + if (strcmp(argv[1], "-t") == 0) + trace = 1; + if ((strcmp(argv[1], "-ft") == 0) || + (strcmp(argv[1], "-tf") == 0)) + { + offset = 0; + trace = 1; + } + file = argv[2]; + } + else + { + file = argv[1]; + } + + fd = open(file, O_RDONLY); + if (fd == -1) + { + perror(file); + exit(1); + } + else + { + int i; +#ifdef TIOCM_RTS + int on = TIOCM_RTS; +#endif + struct timeval t, tt, tlast; + char buf[61]; + clocktime_t clock; + struct termios term; + int rtc = CVT_NONE; + + if (tcgetattr(fd, &term) == -1) + { + perror("tcgetattr"); + exit(1); + } + + bzero(term.c_cc, sizeof(term.c_cc)); + term.c_cc[VMIN] = 1; + term.c_cflag = B50|CS8|CREAD|CLOCAL; + term.c_iflag = 0; + term.c_oflag = 0; + term.c_lflag = 0; + + if (tcsetattr(fd, TCSANOW, &term) == -1) + { + perror("tcsetattr"); + exit(1); + } + +#ifdef I_POP + while (ioctl(fd, I_POP, 0) == 0) + ; +#endif +#if defined(TIOCMBIC) && defined(TIOCM_RTS) + if (ioctl(fd, TIOCMBIC, (caddr_t)&on) == -1) + { + perror("TIOCM_RTS"); + } +#endif + + printf(" DCF77 monitor - Copyright 1993, Frank Kardel\n\n"); + + clock.hour = 0; + clock.minute = 0; + clock.day = 0; + clock.wday = 0; + clock.month = 0; + clock.year = 0; + clock.flags = 0; + buf[60] = '\0'; + for ( i = 0; i < 60; i++) + buf[i] = '.'; + + gettimeofday(&tlast, 0L); + i = 0; + while (read(fd, &c, 1) == 1) + { + gettimeofday(&t, 0L); + tt = t; + t.tv_sec -= tlast.tv_sec; + t.tv_usec -= tlast.tv_usec; + if (t.tv_usec < 0) + { + t.tv_usec += 1000000; + t.tv_sec -= 1; + } + + if (errs > LINES) + { + printf(" %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]); + printf(" %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]); + errs = 0; + } + + if (t.tv_sec > 1 || + t.tv_sec == 1 && + t.tv_usec > 500000) + { + printf("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &buf[offset]); + + if ((rtc = convert_rawdcf(buf, i, &clock)) != CVT_OK) + { + printf("\n"); + clock.hour = 0; + clock.minute = 0; + clock.day = 0; + clock.wday = 0; + clock.month = 0; + clock.year = 0; + clock.flags = 0; + errs++; + } + + if (((c^0xFF)+1) & (c^0xFF)) + buf[0] = '?'; + else + buf[0] = type(c) ? '#' : '-'; + + for ( i = 1; i < 60; i++) + buf[i] = '.'; + + i = 0; + } + else + { + if (((c^0xFF)+1) & (c^0xFF)) + buf[i] = '?'; + else + buf[i] = type(c) ? '#' : '-'; + + printf("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &buf[offset]); + } + + if (rtc == CVT_OK) + { + printf("%s, %2d:%02d:%02d, %d.%02d.%02d, <%s%s%s%s>", + wday[clock.wday], + clock.hour, clock.minute, i, clock.day, clock.month, + clock.year, + (clock.flags & DCFB_ALTERNATE) ? "R" : "_", + (clock.flags & DCFB_ANNOUNCE) ? "A" : "_", + (clock.flags & DCFB_DST) ? "D" : "_", + (clock.flags & DCFB_LEAP) ? "L" : "_" + ); + if (trace && (i == 0)) + { + printf("\n"); + errs++; + } + } + + printf("\r"); + + if (i < 60) + { + i++; + } + + tlast = tt; + + fflush(stdout); + } + close(fd); + } + } + return 0; +} diff --git a/contrib/xntpd/ppsclock/CHANGES b/contrib/xntpd/ppsclock/CHANGES new file mode 100644 index 0000000000..1fc66ba9ab --- /dev/null +++ b/contrib/xntpd/ppsclock/CHANGES @@ -0,0 +1,18 @@ +CHANGES,v 3.1 1993/07/06 01:09:43 jbj Exp + +Changes between ppsclock 1.2 beta and 1.3 beta + + - sys/sun4m: Added support for the sun4m (requires SunOS 4.1.3). + + - sys/genassym: Added "mini" genassym to support sites without full + SunOS source. + + - (general): Add support for non-source (e.g. OBJect only sites). + + - *.ps: Split schematics apart; now there is magnavox.ps for the + Magnavox Magnavox 538534-3 converter and b-and-b.ps for the B&B + Electronics 422CEC. + + - README: Fix typo in kernel configuration step (2). (Thanks to + Brian Tierney, tierney@george.lbl.gov.) Document need for revision + 1.3 or higher roms with the SS1. diff --git a/contrib/xntpd/ppsclock/Makefile b/contrib/xntpd/ppsclock/Makefile new file mode 100644 index 0000000000..807702285f --- /dev/null +++ b/contrib/xntpd/ppsclock/Makefile @@ -0,0 +1,7 @@ +# Makefile,v 3.1 1993/07/06 01:09:44 jbj Exp + +all: + +tar: + cwd=`pwd` ; dir=`basename $$cwd` ; set -x; \ + (cd .. ; tar cFFhf - $$dir) | compress > /tmp/$$dir.tar.Z diff --git a/contrib/xntpd/ppsclock/README b/contrib/xntpd/ppsclock/README new file mode 100644 index 0000000000..bf2beff9cf --- /dev/null +++ b/contrib/xntpd/ppsclock/README @@ -0,0 +1,229 @@ +# README,v 3.1 1993/07/06 01:09:46 jbj Exp + +PPSCLOCK 1.3 BETA Release + +Please send bugs and comments to ppsclock@ee.lbl.gov. + +This is SunOS 4 tty STREAMS module that can be used to interface +the one-pulse-per-second output of an accurate external clock +(e.g., a GPS receiver) to NTP. This module records the value of +the Unix clock each time the 1pps pulse happens. The recorded +value can then be read by an application using a CIOGETEV ioctl. + +We have been running this module with xntp3, SunOS 4.1.2 and a +Magnavox MX4200 GPS receiver (a very nice, relatively inexpensive +GPS box for use with NTP) and have been happy with the results: +The time from when the GPS sends the 1pps pulse to when this code +grabs the Unix time is an almost constant 15us on a SparcStation 1+ +and 9us on a SparcStation 2 (there is conditionally compiled code +in the driver that may help if you want to measure this interval +yourself -- see below). + +Since the GPS is typically connected via an RS-232 serial port +& since the SparcStation has too few serial ports, this module +gets the 1pps signal via the same port used to get the GPS data. +We do this by connecting the GPS 1pps output to `Carrier Detect' +(RS-232 pin 8) on serial cable between the GPS & the Sparc. +Since `Carrier Detect' transitions cause a high priority zs +`service' interrupt on the Sparc (which is separate from the zs +`data' interrupt used to collect ascii data from the GPS), this +is a cheap way to turn the 1pps pulse into a Sparc interrupt. +However, since `Carrier Detect' now has a non-standard meaning on +the clock serial line, *YOU MUST SET "SOFT CARRIER" ON THE CLOCK +SERIAL PORT* (i.e., the port you push this streams module onto). +But note that this module changes the meaning of the `Carrier +Detect' interrupt *only* on the port(s) it's pushed on; other +serial ports continue to work as they always have & the special +interpretation of `Carrier Detect' will go away whenever this +steams module is popped (e.g., if xntpd exits). + +In order to use the 1pps pulse to correct both the Unix clock +offset and frequency, the time between when the external clock +signals 1pps and when this module records the Unix clock should +be as small as possible and should be repeatable. The totally +braindead AT&T STREAMS code makes it very difficult to achieve +these objectives: The allocb/wput overhead adds about 700us of +latency on a SS-1+ and the worthless stream 'scheduler' combined +with doing everything at a relatively low interrupt priority +adds about +-400us of jitter. So, to get a high quality time +stamp, this module uses STREAMS *only* to get the ioctl request. +It gets the 1pps signal by avoiding STREAMS code entirely and +inserting itself directly into the hardware interrupt service path +for the 1pps pulse. It does this by being *very* chummy with +Sun's `zs' serial driver -- it basically steals the modem control +interrupt from the zs. So *THIS IS NOT A GENERIC STREAMS MODULE*. +It is designed to work with Sun's zs driver under SunOS 4. +Expect it to break under Solaris-2. Expect it to not run on +anything but a Sun. + +Also note that for our GPS clock, `1 second' seems to occur at the +leading edge of the pulse so that's when we grab the timestamp. If +your clock indicates 1pps on the trailing edge you should change the line: + if ((s0 & ZSRR0_CD) != 0) { +in ppsclock_intr to: + if ((s0 & ZSRR0_CD) == 0) { +to grab the time stamp on the trailing edge of the pulse. + +One final note about running this code on a Sun Sparcstation 1; we have +found that you need revision 1.3 or higher proms with the Sun 4/60; +this is because 1.2 and earlier roms listen to BOTH the A and B serial +ports while selftesting; if you have something like a GPS receiver +talking once a second at 4800 baud to a serial port, even if it's not +the console serial port, the system will see a "break" and abort +booting up. This makes it impossible to automatically reboot after a +crash. + + +Measuring Performance +--------------------- +We have frequently found the need for some non-invasive means +to measure internal system performance numbers such as interrupt +latencies. The following trick works pretty well: The SparcStation +has a front panel LED that the system turns on at boot time then +never changes. There is a register (the 'auxio' register) that the +kernel can write to change the state of this LED & it costs almost +exactly 1us to turn the LED off then on again. So, for example, +you can measure the interrupt latency to when we grab unix time +stamp by attaching a scope probe to the LED (it's easiest to stick +the probe into the LED's connector on the motherboard) then trigger +the scope off the appropriate edge of the 1pps pulse from the GPS. +If you want to measure the amount of time some system routine +takes, you can turn the LED off before calling the routine and +on afterwards so the pulse width on the scope is a direct measure +of the routine's execution time. If you want to play with this, +there's code in ppsclock.c (conditional on the define PPSCLOCKLED) +that will toggle the LED in the hardware interrupt handler for +the 1pps intr. The time from whichever edge of the 1pps pulse +you chose to stamp to when the LED goes off is the interrupt +latency & the LED off time is a measure of the cost to call Sun's +routine uniqtime (which reads the Unix time to 1us accuracy). + +By the way, if you try this & think the cost of calling Sun's +`uniqtime' is appalling (42-85us/call -- we thought this was +appalling) this distribution includes a replacement for it, +microtime.s, that runs 10 times faster than Sun's code (~3us/call) +& gives you a more accurate time. (If you install this, it will +improve anything that gets high-res unix kernel time, including +the gettimeofday system call that xntp uses). + + + +INSTALLATION +------------ +These are some (sketchy) notes on installation of the SunOS 4 pps clock +streams module. + +This directory contains: + + README - this file + RELEASE - version of this releasethis + CHANGES - description of differences between releases + magnavox.ps - PostScript schematic (Magnavox rs422/rs232 converter) + b-and-b.ps - PostScript schematic (B&B rs422/rs232 converter) + Makefile - compilation rules + ppstest - ppsclock test program (works with Magnavox + MX4200 GPS -- you can probably use this as + sample code illustrating the use of this + streams module if you have some other kind + of clock). + sys - SunOS 4 kernel modules + sys/genassym - genassym program for object-only (non-source) sites + +KERNEL CONFIGURATION +-------------------- + + (1) Copy sys/sundev/ppsclock.c to /sys/sundev. + + (2) Copy sys/sys/ppsclock.h to /sys/sys (and /usr/include/sys if it + is separate directory). + + (3) If you want to use the fast microtime module, copy + sys/sun4c/microtime.s to /sys/sun4c. + + (4) Use sys/sun/str_conf.c.patch to patch /sys/sun/str_conf.c. + Alternately, manually install the following lines in the + appropriate places: + + #include "zs.h" + [...] + #if NZS > 0 + #include "sys/ppsclock.h" + extern struct streamtab ppsclockinfo; + #endif + [...] + #if NZS > 0 + { PPSCLOCKSTR, &ppsclockinfo }, + #endif + + (5) Use sun4c/conf/files.patch to patch /sys/sun4c/conf/files. + Alternately, manually install the following line in the + appropriate place: + + sundev/ppsclock.c optional zs device-driver + + In addition, if you want to use the fast microtime module, + use sun4c/conf/files.microtime.patch to patch + /sys/sun4c/conf/files. Alternately, manually install the + following line in the appropriate place: + + sun4c/microtime.s standard + + If you are using SunOS 4.1.3 and wish to support the sun4m + architecture, apply the corresponding patches from the sun4m + tree. + + (6) If you want to use the fast microtime module, and have full + SunOS 4 source, use /sys/os/kern_clock.c.patch to patch + /sys/os/kern_clock.c. Alternately, edit /sys/os/kern_clock.c + and bracket the code for uniqtime() with the following two + lines: + + #if !defined(sun4c) && !defined(sun4m) + #endif + + If you DO NOT have full SunOS 4 source but still want to use + the fast microtime, change the symbol table entry in for + _uniqtime to _Uniqtime as follows: + + hell 1 % cd /sys/sun4c/OBJ # or /sys/sun4m + hell 2 % mv kern_clock.o kern_clock.o.virgin + hell 2 % cp kern_clock.o.virgin kern_clock.o + hell 3 % chmod +w kern_clock.o + hell 5 % strings -o -a kern_clock.o | grep -w _uniqtime + 7892 _uniqtime + hell 6 % adb -w kern_clock.o + ?m 0 0xffffffff 0 + 0t7892?s + _dk_ndrive+0x12cc: _uniqtime + .?x + _dk_ndrive+0x12cc: 5f75 + .?w5f55 + _dk_ndrive+0x12cc: 0x5f75 = 0x5f55 + .?s + _dk_ndrive+0x12cc: _Uniqtime + ^D + + (7) If you DO NOT have full SunOS 4 source, you are missing the + source to genassym. Copy the "mini" genassym source from + genassym/genassym.c to /sys/sun4c (and into /sys/sun4m if you + have SunOS 4.1.3 and wish to support the sun4m architecture). + + Next, use sun4c/conf/Makefile.src.patch to patch + /sys/sun4c/conf/Makefile.src (and possibly + /sys/sun4m/conf/Makefile.src). + + Alternately, manually install the following rules in the + prototype Makefile(s). + + assym.s: ${MACHINE}/genassym.c + ${CC} -E ${CPPOPTS} ${MACHINE}/genassym.c > ./a.out.c + cc ${COPTS} ./a.out.c + ./a.out >assym.s + rm -f ./a.out ./a.out.c + + (8) Config, build, and boot the new kernel. + + (9) If you have an MX4200, build the test program in the ppstest + directory and run it. It waits for a message at 4800 + baud and then prints both the message and the time stamp + of the last "carrier detect" transition. diff --git a/contrib/xntpd/ppsclock/RELEASE b/contrib/xntpd/ppsclock/RELEASE new file mode 100644 index 0000000000..3cedde5d5b --- /dev/null +++ b/contrib/xntpd/ppsclock/RELEASE @@ -0,0 +1 @@ +PPSCLOCK-1.3-BETA diff --git a/contrib/xntpd/ppsclock/b-and-b.ps b/contrib/xntpd/ppsclock/b-and-b.ps new file mode 100644 index 0000000000..1954285c65 --- /dev/null +++ b/contrib/xntpd/ppsclock/b-and-b.ps @@ -0,0 +1,2030 @@ +%!PS-Adobe-2.0 EPSF-1.2 +%%Creator: idraw +%%DocumentFonts: Helvetica-Bold Helvetica Courier +%%Pages: 1 +%%BoundingBox: 27 55 564 747 +%%EndComments + +%%BeginIdrawPrologue +/arrowhead { +0 begin +transform originalCTM itransform +/taily exch def +/tailx exch def +transform originalCTM itransform +/tipy exch def +/tipx exch def +/dy tipy taily sub def +/dx tipx tailx sub def +/angle dx 0 ne dy 0 ne or { dy dx atan } { 90 } ifelse def +gsave +originalCTM setmatrix +tipx tipy translate +angle rotate +newpath +arrowHeight neg arrowWidth 2 div moveto +0 0 lineto +arrowHeight neg arrowWidth 2 div neg lineto +patternNone not { +originalCTM setmatrix +/padtip arrowHeight 2 exp 0.25 arrowWidth 2 exp mul add sqrt brushWidth mul +arrowWidth div def +/padtail brushWidth 2 div def +tipx tipy translate +angle rotate +padtip 0 translate +arrowHeight padtip add padtail add arrowHeight div dup scale +arrowheadpath +ifill +} if +brushNone not { +originalCTM setmatrix +tipx tipy translate +angle rotate +arrowheadpath +istroke +} if +grestore +end +} dup 0 9 dict put def + +/arrowheadpath { +newpath +arrowHeight neg arrowWidth 2 div moveto +0 0 lineto +arrowHeight neg arrowWidth 2 div neg lineto +} def + +/leftarrow { +0 begin +y exch get /taily exch def +x exch get /tailx exch def +y exch get /tipy exch def +x exch get /tipx exch def +brushLeftArrow { tipx tipy tailx taily arrowhead } if +end +} dup 0 4 dict put def + +/rightarrow { +0 begin +y exch get /tipy exch def +x exch get /tipx exch def +y exch get /taily exch def +x exch get /tailx exch def +brushRightArrow { tipx tipy tailx taily arrowhead } if +end +} dup 0 4 dict put def + +%%EndIdrawPrologue + +/arrowHeight 10 def +/arrowWidth 5 def + +/IdrawDict 53 dict def +IdrawDict begin + +/reencodeISO { +dup dup findfont dup length dict begin +{ 1 index /FID ne { def }{ pop pop } ifelse } forall +/Encoding ISOLatin1Encoding def +currentdict end definefont +} def + +/ISOLatin1Encoding [ +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright +/parenleft/parenright/asterisk/plus/comma/minus/period/slash +/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon +/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N +/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright +/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m +/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve +/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut +/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar +/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot +/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior +/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine +/guillemotright/onequarter/onehalf/threequarters/questiondown +/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla +/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex +/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute +/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis +/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave +/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex +/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis +/yacute/thorn/ydieresis +] def +/Helvetica-Bold reencodeISO def +/Helvetica reencodeISO def +/Courier reencodeISO def + +/none null def +/numGraphicParameters 17 def +/stringLimit 65535 def + +/Begin { +save +numGraphicParameters dict begin +} def + +/End { +end +restore +} def + +/SetB { +dup type /nulltype eq { +pop +false /brushRightArrow idef +false /brushLeftArrow idef +true /brushNone idef +} { +/brushDashOffset idef +/brushDashArray idef +0 ne /brushRightArrow idef +0 ne /brushLeftArrow idef +/brushWidth idef +false /brushNone idef +} ifelse +} def + +/SetCFg { +/fgblue idef +/fggreen idef +/fgred idef +} def + +/SetCBg { +/bgblue idef +/bggreen idef +/bgred idef +} def + +/SetF { +/printSize idef +/printFont idef +} def + +/SetP { +dup type /nulltype eq { +pop true /patternNone idef +} { +dup -1 eq { +/patternGrayLevel idef +/patternString idef +} { +/patternGrayLevel idef +} ifelse +false /patternNone idef +} ifelse +} def + +/BSpl { +0 begin +storexyn +newpath +n 1 gt { +0 0 0 0 0 0 1 1 true subspline +n 2 gt { +0 0 0 0 1 1 2 2 false subspline +1 1 n 3 sub { +/i exch def +i 1 sub dup i dup i 1 add dup i 2 add dup false subspline +} for +n 3 sub dup n 2 sub dup n 1 sub dup 2 copy false subspline +} if +n 2 sub dup n 1 sub dup 2 copy 2 copy false subspline +patternNone not brushLeftArrow not brushRightArrow not and and { ifill } if +brushNone not { istroke } if +0 0 1 1 leftarrow +n 2 sub dup n 1 sub dup rightarrow +} if +end +} dup 0 4 dict put def + +/Circ { +newpath +0 360 arc +patternNone not { ifill } if +brushNone not { istroke } if +} def + +/CBSpl { +0 begin +dup 2 gt { +storexyn +newpath +n 1 sub dup 0 0 1 1 2 2 true subspline +1 1 n 3 sub { +/i exch def +i 1 sub dup i dup i 1 add dup i 2 add dup false subspline +} for +n 3 sub dup n 2 sub dup n 1 sub dup 0 0 false subspline +n 2 sub dup n 1 sub dup 0 0 1 1 false subspline +patternNone not { ifill } if +brushNone not { istroke } if +} { +Poly +} ifelse +end +} dup 0 4 dict put def + +/Elli { +0 begin +newpath +4 2 roll +translate +scale +0 0 1 0 360 arc +patternNone not { ifill } if +brushNone not { istroke } if +end +} dup 0 1 dict put def + +/Line { +0 begin +2 storexyn +newpath +x 0 get y 0 get moveto +x 1 get y 1 get lineto +brushNone not { istroke } if +0 0 1 1 leftarrow +0 0 1 1 rightarrow +end +} dup 0 4 dict put def + +/MLine { +0 begin +storexyn +newpath +n 1 gt { +x 0 get y 0 get moveto +1 1 n 1 sub { +/i exch def +x i get y i get lineto +} for +patternNone not brushLeftArrow not brushRightArrow not and and { ifill } if +brushNone not { istroke } if +0 0 1 1 leftarrow +n 2 sub dup n 1 sub dup rightarrow +} if +end +} dup 0 4 dict put def + +/Poly { +3 1 roll +newpath +moveto +-1 add +{ lineto } repeat +closepath +patternNone not { ifill } if +brushNone not { istroke } if +} def + +/Rect { +0 begin +/t exch def +/r exch def +/b exch def +/l exch def +newpath +l b moveto +l t lineto +r t lineto +r b lineto +closepath +patternNone not { ifill } if +brushNone not { istroke } if +end +} dup 0 4 dict put def + +/Text { +ishow +} def + +/idef { +dup where { pop pop pop } { exch def } ifelse +} def + +/ifill { +0 begin +gsave +patternGrayLevel -1 ne { +fgred bgred fgred sub patternGrayLevel mul add +fggreen bggreen fggreen sub patternGrayLevel mul add +fgblue bgblue fgblue sub patternGrayLevel mul add setrgbcolor +eofill +} { +eoclip +originalCTM setmatrix +pathbbox /t exch def /r exch def /b exch def /l exch def +/w r l sub ceiling cvi def +/h t b sub ceiling cvi def +/imageByteWidth w 8 div ceiling cvi def +/imageHeight h def +bgred bggreen bgblue setrgbcolor +eofill +fgred fggreen fgblue setrgbcolor +w 0 gt h 0 gt and { +l w add b translate w neg h scale +w h true [w 0 0 h neg 0 h] { patternproc } imagemask +} if +} ifelse +grestore +end +} dup 0 8 dict put def + +/istroke { +gsave +brushDashOffset -1 eq { +[] 0 setdash +1 setgray +} { +brushDashArray brushDashOffset setdash +fgred fggreen fgblue setrgbcolor +} ifelse +brushWidth setlinewidth +originalCTM setmatrix +stroke +grestore +} def + +/ishow { +0 begin +gsave +fgred fggreen fgblue setrgbcolor +/fontDict printFont printSize scalefont dup setfont def +/descender fontDict begin 0 [FontBBox] 1 get FontMatrix end +transform exch pop def +/vertoffset 1 printSize sub descender sub def { +0 vertoffset moveto show +/vertoffset vertoffset printSize sub def +} forall +grestore +end +} dup 0 3 dict put def +/patternproc { +0 begin +/patternByteLength patternString length def +/patternHeight patternByteLength 8 mul sqrt cvi def +/patternWidth patternHeight def +/patternByteWidth patternWidth 8 idiv def +/imageByteMaxLength imageByteWidth imageHeight mul +stringLimit patternByteWidth sub min def +/imageMaxHeight imageByteMaxLength imageByteWidth idiv patternHeight idiv +patternHeight mul patternHeight max def +/imageHeight imageHeight imageMaxHeight sub store +/imageString imageByteWidth imageMaxHeight mul patternByteWidth add string def +0 1 imageMaxHeight 1 sub { +/y exch def +/patternRow y patternByteWidth mul patternByteLength mod def +/patternRowString patternString patternRow patternByteWidth getinterval def +/imageRow y imageByteWidth mul def +0 patternByteWidth imageByteWidth 1 sub { +/x exch def +imageString imageRow x add patternRowString putinterval +} for +} for +imageString +end +} dup 0 12 dict put def + +/min { +dup 3 2 roll dup 4 3 roll lt { exch } if pop +} def + +/max { +dup 3 2 roll dup 4 3 roll gt { exch } if pop +} def + +/midpoint { +0 begin +/y1 exch def +/x1 exch def +/y0 exch def +/x0 exch def +x0 x1 add 2 div +y0 y1 add 2 div +end +} dup 0 4 dict put def + +/thirdpoint { +0 begin +/y1 exch def +/x1 exch def +/y0 exch def +/x0 exch def +x0 2 mul x1 add 3 div +y0 2 mul y1 add 3 div +end +} dup 0 4 dict put def + +/subspline { +0 begin +/movetoNeeded exch def +y exch get /y3 exch def +x exch get /x3 exch def +y exch get /y2 exch def +x exch get /x2 exch def +y exch get /y1 exch def +x exch get /x1 exch def +y exch get /y0 exch def +x exch get /x0 exch def +x1 y1 x2 y2 thirdpoint +/p1y exch def +/p1x exch def +x2 y2 x1 y1 thirdpoint +/p2y exch def +/p2x exch def +x1 y1 x0 y0 thirdpoint +p1x p1y midpoint +/p0y exch def +/p0x exch def +x2 y2 x3 y3 thirdpoint +p2x p2y midpoint +/p3y exch def +/p3x exch def +movetoNeeded { p0x p0y moveto } if +p1x p1y p2x p2y p3x p3y curveto +end +} dup 0 17 dict put def + +/storexyn { +/n exch def +/y n array def +/x n array def +n 1 sub -1 0 { +/i exch def +y i 3 2 roll put +x i 3 2 roll put +} for +} def + +/SSten { +fgred fggreen fgblue setrgbcolor +dup true exch 1 0 0 -1 0 6 -1 roll matrix astore +} def + +/FSten { +dup 3 -1 roll dup 4 1 roll exch +newpath +0 0 moveto +dup 0 exch lineto +exch dup 3 1 roll exch lineto +0 lineto +closepath +bgred bggreen bgblue setrgbcolor +eofill +SSten +} def + +/Rast { +exch dup 3 1 roll 1 0 0 -1 0 6 -1 roll matrix astore +} def + +%%EndProlog + +%I Idraw 10 Grid 8 8 + +%%Page: 1 1 + +Begin +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t +[ 0.799016 0 0 0.799016 0 0 ] concat +/originalCTM matrix currentmatrix def + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-bold-r-*-140-* +Helvetica-Bold 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 410.5 122.625 ] concat +%I +[ +(MX 4200) +] Text +End + +Begin %I Pict +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t +[ 1 0 0 1 0 8 ] concat + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 185.5 103 ] concat +%I +[ +(external power \(+\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 201.5 102 ] concat +%I +[ +(external power \(-\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 233.5 113 ] concat +%I +[ +(port 2 output \(+\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 281.5 120 ] concat +%I +[ +(port 2 input \(-\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 265.5 121 ] concat +%I +[ +(port 2 input \(+\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 249.5 112 ] concat +%I +[ +(port 2 output \(-\)) +] Text +End + +End %I eop + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-bold-r-*-140-* +Helvetica-Bold 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 410.5 454.625 ] concat +%I +[ +(RS422/RS232) +] Text +End + +Begin %I Poly +%I b 65535 +0 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 559 129.25 ] concat +%I 4 +287 127 +455 127 +455 399 +287 399 +4 Poly +End + +Begin %I Poly +%I b 65535 +0 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 559 -214.75 ] concat +%I 4 +287 127 +455 127 +455 399 +287 399 +4 Poly +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 313.5 ] concat +%I +[ +(white) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 313.5 ] concat +%I +[ +(green) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 313.5 ] concat +%I +[ +(black) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 184.5 318.5 ] concat +%I +[ +(red) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 200.5 313.5 ] concat +%I +[ +(black) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 306 ] concat +%I +[ +(\(shield\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 328.5 311 ] concat +%I +[ +(yellow) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 232.5 316 ] concat +%I +[ +(blue) +] Text +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +%I p +0.5 SetP +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 337.5 211.25 ] concat +%I +58 163 410 163 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +%I p +0.5 SetP +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 305.5 211.25 ] concat +%I +58 131 410 131 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +%I p +0.5 SetP +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 321.5 211.25 ] concat +%I +58 99 410 99 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +%I p +0.5 SetP +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 321.5 211.25 ] concat +%I +58 67 410 67 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +%I p +0.5 SetP +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 387.5 211.25 ] concat +%I +410 135 90 135 Line +%I 2 +End + +Begin %I Elli +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 387.5 211.25 ] concat +%I +90 103 16 16 Elli +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 387.5 211.25 ] concat +%I +90 119 90 135 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 531.5 249.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 451 253.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 595.5 253.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 499.5 253.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 515.5 253.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 547.5 249.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Elli +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 187.5 459.25 ] concat +%I +90 103 16 16 Elli +End + +Begin %I MLine +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 3.04199e-09 0.25 -0.25 3.04199e-09 432.5 346.25 ] concat +%I 4 +279 322 +215 322 +215 258 +279 258 +4 MLine +%I 4 +End + +Begin %I MLine +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 3.04199e-09 0.25 -0.25 3.04199e-09 464.5 346.25 ] concat +%I 4 +279 322 +215 322 +215 258 +279 258 +4 MLine +%I 4 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 3.04199e-09 0.25 -0.25 3.04199e-09 427.5 370.25 ] concat +%I +119 290 119 258 Line +%I 4 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 3.04199e-09 0.25 -0.25 3.04199e-09 459.5 370.25 ] concat +%I +119 290 119 258 Line +%I 4 +End + +Begin %I MLine +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 498.5 405.25 ] concat +%I 6 +-330 325 +-42 325 +-42 85 +422 85 +422 325 +358 325 +6 MLine +%I 2 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 830.5 295.25 ] concat +%I +305 495 313 495 Line +%I 1 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 750.5 298.25 ] concat +%I +305 495 313 495 Line +%I 1 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 766.5 295.25 ] concat +%I +305 495 313 495 Line +%I 1 +End + +Begin %I Poly +%I b 65535 +0 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 559 465.25 ] concat +%I 4 +287 127 +455 127 +455 399 +287 399 +4 Poly +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 405.75 538.5 ] concat +%I +91 300 427 300 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 405.75 538.5 ] concat +%I +91 268 427 268 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 405.75 538.5 ] concat +%I +91 236 427 236 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 405.75 538.5 ] concat +%I +91 172 427 172 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 814.5 299.25 ] concat +%I +305 495 313 495 Line +%I 1 +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 660 ] concat +%I +[ +(white) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 660 ] concat +%I +[ +(black) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 660 ] concat +%I +[ +(green) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 665 ] concat +%I +[ +(red) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 776 ] concat +%I +[ +(transmit) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 776 ] concat +%I +[ +(ground) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 776 ] concat +%I +[ +(receive) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 776 ] concat +%I +[ +(data carrier detect) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-bold-r-*-140-* +Helvetica-Bold 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 410.5 790.625 ] concat +%I +[ +(SparcStation) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 757.5 ] concat +%I +[ +(3) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 757.5 ] concat +%I +[ +(2) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 757.5 ] concat +%I +[ +(7) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 757.5 ] concat +%I +[ +(8) +] Text +End + +Begin %I Pict +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t u + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 184.5 219.5 ] concat +%I +[ +(13) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 200.5 219.5 ] concat +%I +[ +(12) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 232.5 223.5 ] concat +%I +[ +(3) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 219.5 ] concat +%I +[ +(15) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 223.5 ] concat +%I +[ +(2) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 219.5 ] concat +%I +[ +(14) +] Text +End + +End %I eop + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 328.5 208.5 ] concat +%I +[ +(PPS) +] Text +End + +Begin %I MLine +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 309.25 189.5 ] concat +%I 6 +613 346 +597 346 +597 410 +357 410 +357 202 +101 202 +6 MLine +%I 2 +End + +Begin %I MLine +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 308.75 219 ] concat +%I 5 +570 298 +570 442 +266 442 +266 234 +42 234 +5 MLine +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 467.5 253.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 232.5 442 ] concat +%I +[ +(\(+\) A in) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 442 ] concat +%I +[ +(\(-\) A in) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 442 ] concat +%I +[ +(\(-\) A out) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 442 ] concat +%I +[ +(ground) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 344.5 442 ] concat +%I +[ +(\(+\) B in) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 360.5 442 ] concat +%I +[ +(\(+\) B out) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 376.5 442 ] concat +%I +[ +(\(-\) B in) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 392.5 442 ] concat +%I +[ +(\(-\) B out) +] Text +End + +Begin %I Pict +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t +[ 1 0 0 1 0 8 ] concat + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 313.5 502 ] concat +%I +[ +(B transmit) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 329.5 504 ] concat +%I +[ +(B receive) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 503 ] concat +%I +[ +(A receive) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 506 ] concat +%I +[ +(A ground) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 501 ] concat +%I +[ +(A transmit) +] Text +End + +End %I eop + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 572.5 ] concat +%I +[ +(7) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 163.5 485.5 ] concat +%I +[ +(power) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-100-* +Courier 10 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 150 217 ] concat +%I +[ +(male) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-100-* +Courier 10 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 150 753 ] concat +%I +[ +(male) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-100-* +Courier 10 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 150 561 ] concat +%I +[ +(male) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-100-* +Courier 10 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 150 416.5 ] concat +%I +[ +(female) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 690.5 808.5 ] concat +%I +[ +(26-Mar-1993 \(cal\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 562.5 142.5 ] concat +%I +[ +(Notes:) +() +( The RS422/232 converter is a B&B Electronics 422CEC.) +( The PPS connector is a SMB female such as a Pomona 5378.) +( The power connector is a male 3/32 inch plug such as a Radio Shack 274-279) +( The data connectors are male and female DB-25s. ) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 442 ] concat +%I +[ +(\(+\) A out) +] Text +End + +Begin %I Pict +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t u + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 422.5 ] concat +%I +[ +(7) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 232.5 418.5 ] concat +%I +[ +(16) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 422.5 ] concat +%I +[ +(3) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 418.5 ] concat +%I +[ +(14) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 422.5 ] concat +%I +[ +(2) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 344.5 418.5 ] concat +%I +[ +(13) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 360.5 418.5 ] concat +%I +[ +(19) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 376.5 422.5 ] concat +%I +[ +(5) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 392.5 422.5 ] concat +%I +[ +(4) +] Text +End + +End %I eop + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 572.5 ] concat +%I +[ +(3) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 572.5 ] concat +%I +[ +(2) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 572.5 ] concat +%I +[ +(5) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 328.5 572.5 ] concat +%I +[ +(4) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-bold-r-*-140-* +Helvetica-Bold 14 SetF +%I t +[ -1.83691e-16 1 -1 -1.83691e-16 39.515 328.134 ] concat +%I +[ +(MX4200 cable \(B&B Electronics 422CEC version\)) +] Text +End + +End %I eop + +showpage + +%%Trailer + +end diff --git a/contrib/xntpd/ppsclock/magnavox.ps b/contrib/xntpd/ppsclock/magnavox.ps new file mode 100644 index 0000000000..415f2cf82b --- /dev/null +++ b/contrib/xntpd/ppsclock/magnavox.ps @@ -0,0 +1,2041 @@ +%!PS-Adobe-2.0 EPSF-1.2 +%%Creator: idraw +%%DocumentFonts: Helvetica-Bold Helvetica Courier +%%Pages: 1 +%%BoundingBox: 28 55 564 747 +%%EndComments + +%%BeginIdrawPrologue +/arrowhead { +0 begin +transform originalCTM itransform +/taily exch def +/tailx exch def +transform originalCTM itransform +/tipy exch def +/tipx exch def +/dy tipy taily sub def +/dx tipx tailx sub def +/angle dx 0 ne dy 0 ne or { dy dx atan } { 90 } ifelse def +gsave +originalCTM setmatrix +tipx tipy translate +angle rotate +newpath +arrowHeight neg arrowWidth 2 div moveto +0 0 lineto +arrowHeight neg arrowWidth 2 div neg lineto +patternNone not { +originalCTM setmatrix +/padtip arrowHeight 2 exp 0.25 arrowWidth 2 exp mul add sqrt brushWidth mul +arrowWidth div def +/padtail brushWidth 2 div def +tipx tipy translate +angle rotate +padtip 0 translate +arrowHeight padtip add padtail add arrowHeight div dup scale +arrowheadpath +ifill +} if +brushNone not { +originalCTM setmatrix +tipx tipy translate +angle rotate +arrowheadpath +istroke +} if +grestore +end +} dup 0 9 dict put def + +/arrowheadpath { +newpath +arrowHeight neg arrowWidth 2 div moveto +0 0 lineto +arrowHeight neg arrowWidth 2 div neg lineto +} def + +/leftarrow { +0 begin +y exch get /taily exch def +x exch get /tailx exch def +y exch get /tipy exch def +x exch get /tipx exch def +brushLeftArrow { tipx tipy tailx taily arrowhead } if +end +} dup 0 4 dict put def + +/rightarrow { +0 begin +y exch get /tipy exch def +x exch get /tipx exch def +y exch get /taily exch def +x exch get /tailx exch def +brushRightArrow { tipx tipy tailx taily arrowhead } if +end +} dup 0 4 dict put def + +%%EndIdrawPrologue + +/arrowHeight 10 def +/arrowWidth 5 def + +/IdrawDict 53 dict def +IdrawDict begin + +/reencodeISO { +dup dup findfont dup length dict begin +{ 1 index /FID ne { def }{ pop pop } ifelse } forall +/Encoding ISOLatin1Encoding def +currentdict end definefont +} def + +/ISOLatin1Encoding [ +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright +/parenleft/parenright/asterisk/plus/comma/minus/period/slash +/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon +/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N +/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright +/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m +/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve +/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut +/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar +/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot +/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior +/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine +/guillemotright/onequarter/onehalf/threequarters/questiondown +/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla +/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex +/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute +/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis +/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave +/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex +/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis +/yacute/thorn/ydieresis +] def +/Helvetica-Bold reencodeISO def +/Helvetica reencodeISO def +/Courier reencodeISO def + +/none null def +/numGraphicParameters 17 def +/stringLimit 65535 def + +/Begin { +save +numGraphicParameters dict begin +} def + +/End { +end +restore +} def + +/SetB { +dup type /nulltype eq { +pop +false /brushRightArrow idef +false /brushLeftArrow idef +true /brushNone idef +} { +/brushDashOffset idef +/brushDashArray idef +0 ne /brushRightArrow idef +0 ne /brushLeftArrow idef +/brushWidth idef +false /brushNone idef +} ifelse +} def + +/SetCFg { +/fgblue idef +/fggreen idef +/fgred idef +} def + +/SetCBg { +/bgblue idef +/bggreen idef +/bgred idef +} def + +/SetF { +/printSize idef +/printFont idef +} def + +/SetP { +dup type /nulltype eq { +pop true /patternNone idef +} { +dup -1 eq { +/patternGrayLevel idef +/patternString idef +} { +/patternGrayLevel idef +} ifelse +false /patternNone idef +} ifelse +} def + +/BSpl { +0 begin +storexyn +newpath +n 1 gt { +0 0 0 0 0 0 1 1 true subspline +n 2 gt { +0 0 0 0 1 1 2 2 false subspline +1 1 n 3 sub { +/i exch def +i 1 sub dup i dup i 1 add dup i 2 add dup false subspline +} for +n 3 sub dup n 2 sub dup n 1 sub dup 2 copy false subspline +} if +n 2 sub dup n 1 sub dup 2 copy 2 copy false subspline +patternNone not brushLeftArrow not brushRightArrow not and and { ifill } if +brushNone not { istroke } if +0 0 1 1 leftarrow +n 2 sub dup n 1 sub dup rightarrow +} if +end +} dup 0 4 dict put def + +/Circ { +newpath +0 360 arc +patternNone not { ifill } if +brushNone not { istroke } if +} def + +/CBSpl { +0 begin +dup 2 gt { +storexyn +newpath +n 1 sub dup 0 0 1 1 2 2 true subspline +1 1 n 3 sub { +/i exch def +i 1 sub dup i dup i 1 add dup i 2 add dup false subspline +} for +n 3 sub dup n 2 sub dup n 1 sub dup 0 0 false subspline +n 2 sub dup n 1 sub dup 0 0 1 1 false subspline +patternNone not { ifill } if +brushNone not { istroke } if +} { +Poly +} ifelse +end +} dup 0 4 dict put def + +/Elli { +0 begin +newpath +4 2 roll +translate +scale +0 0 1 0 360 arc +patternNone not { ifill } if +brushNone not { istroke } if +end +} dup 0 1 dict put def + +/Line { +0 begin +2 storexyn +newpath +x 0 get y 0 get moveto +x 1 get y 1 get lineto +brushNone not { istroke } if +0 0 1 1 leftarrow +0 0 1 1 rightarrow +end +} dup 0 4 dict put def + +/MLine { +0 begin +storexyn +newpath +n 1 gt { +x 0 get y 0 get moveto +1 1 n 1 sub { +/i exch def +x i get y i get lineto +} for +patternNone not brushLeftArrow not brushRightArrow not and and { ifill } if +brushNone not { istroke } if +0 0 1 1 leftarrow +n 2 sub dup n 1 sub dup rightarrow +} if +end +} dup 0 4 dict put def + +/Poly { +3 1 roll +newpath +moveto +-1 add +{ lineto } repeat +closepath +patternNone not { ifill } if +brushNone not { istroke } if +} def + +/Rect { +0 begin +/t exch def +/r exch def +/b exch def +/l exch def +newpath +l b moveto +l t lineto +r t lineto +r b lineto +closepath +patternNone not { ifill } if +brushNone not { istroke } if +end +} dup 0 4 dict put def + +/Text { +ishow +} def + +/idef { +dup where { pop pop pop } { exch def } ifelse +} def + +/ifill { +0 begin +gsave +patternGrayLevel -1 ne { +fgred bgred fgred sub patternGrayLevel mul add +fggreen bggreen fggreen sub patternGrayLevel mul add +fgblue bgblue fgblue sub patternGrayLevel mul add setrgbcolor +eofill +} { +eoclip +originalCTM setmatrix +pathbbox /t exch def /r exch def /b exch def /l exch def +/w r l sub ceiling cvi def +/h t b sub ceiling cvi def +/imageByteWidth w 8 div ceiling cvi def +/imageHeight h def +bgred bggreen bgblue setrgbcolor +eofill +fgred fggreen fgblue setrgbcolor +w 0 gt h 0 gt and { +l w add b translate w neg h scale +w h true [w 0 0 h neg 0 h] { patternproc } imagemask +} if +} ifelse +grestore +end +} dup 0 8 dict put def + +/istroke { +gsave +brushDashOffset -1 eq { +[] 0 setdash +1 setgray +} { +brushDashArray brushDashOffset setdash +fgred fggreen fgblue setrgbcolor +} ifelse +brushWidth setlinewidth +originalCTM setmatrix +stroke +grestore +} def + +/ishow { +0 begin +gsave +fgred fggreen fgblue setrgbcolor +/fontDict printFont printSize scalefont dup setfont def +/descender fontDict begin 0 [FontBBox] 1 get FontMatrix end +transform exch pop def +/vertoffset 1 printSize sub descender sub def { +0 vertoffset moveto show +/vertoffset vertoffset printSize sub def +} forall +grestore +end +} dup 0 3 dict put def +/patternproc { +0 begin +/patternByteLength patternString length def +/patternHeight patternByteLength 8 mul sqrt cvi def +/patternWidth patternHeight def +/patternByteWidth patternWidth 8 idiv def +/imageByteMaxLength imageByteWidth imageHeight mul +stringLimit patternByteWidth sub min def +/imageMaxHeight imageByteMaxLength imageByteWidth idiv patternHeight idiv +patternHeight mul patternHeight max def +/imageHeight imageHeight imageMaxHeight sub store +/imageString imageByteWidth imageMaxHeight mul patternByteWidth add string def +0 1 imageMaxHeight 1 sub { +/y exch def +/patternRow y patternByteWidth mul patternByteLength mod def +/patternRowString patternString patternRow patternByteWidth getinterval def +/imageRow y imageByteWidth mul def +0 patternByteWidth imageByteWidth 1 sub { +/x exch def +imageString imageRow x add patternRowString putinterval +} for +} for +imageString +end +} dup 0 12 dict put def + +/min { +dup 3 2 roll dup 4 3 roll lt { exch } if pop +} def + +/max { +dup 3 2 roll dup 4 3 roll gt { exch } if pop +} def + +/midpoint { +0 begin +/y1 exch def +/x1 exch def +/y0 exch def +/x0 exch def +x0 x1 add 2 div +y0 y1 add 2 div +end +} dup 0 4 dict put def + +/thirdpoint { +0 begin +/y1 exch def +/x1 exch def +/y0 exch def +/x0 exch def +x0 2 mul x1 add 3 div +y0 2 mul y1 add 3 div +end +} dup 0 4 dict put def + +/subspline { +0 begin +/movetoNeeded exch def +y exch get /y3 exch def +x exch get /x3 exch def +y exch get /y2 exch def +x exch get /x2 exch def +y exch get /y1 exch def +x exch get /x1 exch def +y exch get /y0 exch def +x exch get /x0 exch def +x1 y1 x2 y2 thirdpoint +/p1y exch def +/p1x exch def +x2 y2 x1 y1 thirdpoint +/p2y exch def +/p2x exch def +x1 y1 x0 y0 thirdpoint +p1x p1y midpoint +/p0y exch def +/p0x exch def +x2 y2 x3 y3 thirdpoint +p2x p2y midpoint +/p3y exch def +/p3x exch def +movetoNeeded { p0x p0y moveto } if +p1x p1y p2x p2y p3x p3y curveto +end +} dup 0 17 dict put def + +/storexyn { +/n exch def +/y n array def +/x n array def +n 1 sub -1 0 { +/i exch def +y i 3 2 roll put +x i 3 2 roll put +} for +} def + +/SSten { +fgred fggreen fgblue setrgbcolor +dup true exch 1 0 0 -1 0 6 -1 roll matrix astore +} def + +/FSten { +dup 3 -1 roll dup 4 1 roll exch +newpath +0 0 moveto +dup 0 exch lineto +exch dup 3 1 roll exch lineto +0 lineto +closepath +bgred bggreen bgblue setrgbcolor +eofill +SSten +} def + +/Rast { +exch dup 3 1 roll 1 0 0 -1 0 6 -1 roll matrix astore +} def + +%%EndProlog + +%I Idraw 10 Grid 8 8 + +%%Page: 1 1 + +Begin +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t +[ 0.799016 0 0 0.799016 0 0 ] concat +/originalCTM matrix currentmatrix def + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-bold-r-*-140-* +Helvetica-Bold 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 410.5 122.625 ] concat +%I +[ +(MX 4200) +] Text +End + +Begin %I Pict +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t +[ 1 0 0 1 0 8 ] concat + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 185.5 103 ] concat +%I +[ +(external power \(+\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 201.5 102 ] concat +%I +[ +(external power \(-\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 233.5 113 ] concat +%I +[ +(port 2 output \(+\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 281.5 120 ] concat +%I +[ +(port 2 input \(-\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 265.5 121 ] concat +%I +[ +(port 2 input \(+\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 249.5 112 ] concat +%I +[ +(port 2 output \(-\)) +] Text +End + +End %I eop + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-bold-r-*-140-* +Helvetica-Bold 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 410.5 454.625 ] concat +%I +[ +(RS422/RS232) +] Text +End + +Begin %I Poly +%I b 65535 +0 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 559 129.25 ] concat +%I 4 +287 127 +455 127 +455 399 +287 399 +4 Poly +End + +Begin %I Poly +%I b 65535 +0 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 559 -214.75 ] concat +%I 4 +287 127 +455 127 +455 399 +287 399 +4 Poly +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 313.5 ] concat +%I +[ +(white) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 313.5 ] concat +%I +[ +(green) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 313.5 ] concat +%I +[ +(black) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 184.5 318.5 ] concat +%I +[ +(red) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 200.5 313.5 ] concat +%I +[ +(black) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 306 ] concat +%I +[ +(\(shield\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 328.5 311 ] concat +%I +[ +(yellow) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 232.5 316 ] concat +%I +[ +(blue) +] Text +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +%I p +0.5 SetP +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 337.5 211.25 ] concat +%I +58 163 410 163 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +%I p +0.5 SetP +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 305.5 211.25 ] concat +%I +58 131 410 131 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +%I p +0.5 SetP +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 321.5 211.25 ] concat +%I +58 99 410 99 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +%I p +0.5 SetP +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 321.5 211.25 ] concat +%I +58 67 410 67 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +%I p +0.5 SetP +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 387.5 211.25 ] concat +%I +410 135 90 135 Line +%I 2 +End + +Begin %I Elli +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 387.5 211.25 ] concat +%I +90 103 16 16 Elli +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 387.5 211.25 ] concat +%I +90 119 90 135 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 531.5 249.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 451 253.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 595.5 253.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 499.5 253.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 515.5 253.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 547.5 249.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Elli +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 187.5 459.25 ] concat +%I +90 103 16 16 Elli +End + +Begin %I MLine +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 3.04199e-09 0.25 -0.25 3.04199e-09 432.5 346.25 ] concat +%I 4 +279 322 +215 322 +215 258 +279 258 +4 MLine +%I 4 +End + +Begin %I MLine +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 3.04199e-09 0.25 -0.25 3.04199e-09 464.5 346.25 ] concat +%I 4 +279 322 +215 322 +215 258 +279 258 +4 MLine +%I 4 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 3.04199e-09 0.25 -0.25 3.04199e-09 427.5 370.25 ] concat +%I +119 290 119 258 Line +%I 4 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 3.04199e-09 0.25 -0.25 3.04199e-09 459.5 370.25 ] concat +%I +119 290 119 258 Line +%I 4 +End + +Begin %I MLine +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 498.5 405.25 ] concat +%I 6 +-330 325 +-42 325 +-42 85 +422 85 +422 325 +358 325 +6 MLine +%I 2 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 830.5 295.25 ] concat +%I +305 495 313 495 Line +%I 1 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 750.5 298.25 ] concat +%I +305 495 313 495 Line +%I 1 +End + +Begin %I Line +%I b 65535 +2 1 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 766.5 295.25 ] concat +%I +305 495 313 495 Line +%I 1 +End + +Begin %I Poly +%I b 65535 +0 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 559 465.25 ] concat +%I 4 +287 127 +455 127 +455 399 +287 399 +4 Poly +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 405.75 538.5 ] concat +%I +91 300 427 300 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 405.75 538.5 ] concat +%I +91 268 427 268 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 405.75 538.5 ] concat +%I +91 236 427 236 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 405.75 538.5 ] concat +%I +91 172 427 172 Line +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 1.2168e-08 1 -1 1.2168e-08 814.5 299.25 ] concat +%I +305 495 313 495 Line +%I 1 +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 660 ] concat +%I +[ +(white) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 660 ] concat +%I +[ +(black) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 660 ] concat +%I +[ +(green) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-80-* +Courier 8 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 665 ] concat +%I +[ +(red) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 776 ] concat +%I +[ +(transmit) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 776 ] concat +%I +[ +(ground) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 776 ] concat +%I +[ +(receive) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 776 ] concat +%I +[ +(data carrier detect) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-bold-r-*-140-* +Helvetica-Bold 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 410.5 790.625 ] concat +%I +[ +(SparcStation) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 757.5 ] concat +%I +[ +(3) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 757.5 ] concat +%I +[ +(2) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 757.5 ] concat +%I +[ +(7) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 757.5 ] concat +%I +[ +(8) +] Text +End + +Begin %I Pict +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t +[ 1 0 0 1 0 2 ] concat + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 232.5 420.5 ] concat +%I +[ +(2) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 416.5 ] concat +%I +[ +(14) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 420.5 ] concat +%I +[ +(3) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 416.5 ] concat +%I +[ +(15) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 420.5 ] concat +%I +[ +(7) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 360.5 420.5 ] concat +%I +[ +(5) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 344.5 420.5 ] concat +%I +[ +(4) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 376.5 416.5 ] concat +%I +[ +(16) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 392.5 416.5 ] concat +%I +[ +(17) +] Text +End + +End %I eop + +Begin %I Pict +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t u + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 184.5 219.5 ] concat +%I +[ +(13) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 200.5 219.5 ] concat +%I +[ +(12) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 232.5 223.5 ] concat +%I +[ +(3) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 219.5 ] concat +%I +[ +(15) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 223.5 ] concat +%I +[ +(2) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 219.5 ] concat +%I +[ +(14) +] Text +End + +End %I eop + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 328.5 208.5 ] concat +%I +[ +(PPS) +] Text +End + +Begin %I MLine +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 309.25 189.5 ] concat +%I 6 +613 346 +597 346 +597 410 +357 410 +357 202 +101 202 +6 MLine +%I 2 +End + +Begin %I MLine +%I b 65535 +2 0 0 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 308.75 219 ] concat +%I 5 +570 298 +570 442 +266 442 +266 234 +42 234 +5 MLine +%I 2 +End + +Begin %I Line +%I b 65535 +2 0 1 [] 0 SetB +%I cfg Black +0 0 0 SetCFg +%I cbg White +1 1 1 SetCBg +none SetP %I p n +%I t +[ 6.08398e-09 0.5 -0.5 6.08398e-09 467.5 253.25 ] concat +%I +42 519 58 519 Line +%I 2 +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 232.5 442 ] concat +%I +[ +(\(+\) A in) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 442 ] concat +%I +[ +(\(-\) A in) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 442 ] concat +%I +[ +(\(-\) A out) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 442 ] concat +%I +[ +(\(+\) A out) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 442 ] concat +%I +[ +(ground) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 344.5 442 ] concat +%I +[ +(\(+\) B in) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 360.5 442 ] concat +%I +[ +(\(+\) B out) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 376.5 442 ] concat +%I +[ +(\(-\) B in) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 392.5 442 ] concat +%I +[ +(\(-\) B out) +] Text +End + +Begin %I Pict +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t +[ 1 0 0 1 0 8 ] concat + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 313.5 502 ] concat +%I +[ +(B transmit) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 329.5 504 ] concat +%I +[ +(B receive) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 503 ] concat +%I +[ +(A receive) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 506 ] concat +%I +[ +(A ground) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-120-* +Helvetica 12 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 501 ] concat +%I +[ +(A transmit) +] Text +End + +End %I eop + +Begin %I Pict +%I b u +%I cfg u +%I cbg u +%I f u +%I p u +%I t u + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 248.5 572.5 ] concat +%I +[ +(2) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 264.5 572.5 ] concat +%I +[ +(3) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 280.5 572.5 ] concat +%I +[ +(7) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 328.5 572.5 ] concat +%I +[ +(5) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 312.5 572.5 ] concat +%I +[ +(4) +] Text +End + +End %I eop + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 163.5 485.5 ] concat +%I +[ +(power) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-100-* +Courier 10 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 150 217 ] concat +%I +[ +(male) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-100-* +Courier 10 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 150 753 ] concat +%I +[ +(male) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-100-* +Courier 10 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 150 561 ] concat +%I +[ +(male) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-courier-medium-r-*-100-* +Courier 10 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 150 416.5 ] concat +%I +[ +(female) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 690.5 808.5 ] concat +%I +[ +(26-Mar-1993 \(cal\)) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-medium-r-*-140-* +Helvetica 14 SetF +%I t +[ 1.2168e-08 1 -1 1.2168e-08 562.5 142.5 ] concat +%I +[ +(Notes:) +() +( The RS422/232 converter is a Magnavox 538534-3.) +( The PPS connector is a SMB female such as a Pomona 5378.) +( The power connector is a male 3/32 inch plug such as a Radio Shack 274-279) +( The data connectors are male and female DB-25s. ) +] Text +End + +Begin %I Text +%I cfg Black +0 0 0 SetCFg +%I f *-helvetica-bold-r-*-140-* +Helvetica-Bold 14 SetF +%I t +[ -1.83691e-16 1 -1 -1.83691e-16 39.515 344.074 ] concat +%I +[ +(MX4200 cable \(Magnavox 538534-3 version\)) +] Text +End + +End %I eop + +showpage + +%%Trailer + +end diff --git a/contrib/xntpd/ppsclock/ppstest/Makefile b/contrib/xntpd/ppsclock/ppstest/Makefile new file mode 100644 index 0000000000..b383258b87 --- /dev/null +++ b/contrib/xntpd/ppsclock/ppstest/Makefile @@ -0,0 +1,10 @@ +# Makefile,v 3.1 1993/07/06 01:09:55 jbj Exp + +PROG= ppstest +CFLAGS= -g + +ppstest: ${PROG}.c + ${CC} ${CFLAGS} ${PROG}.c -o ${PROG} + +clean: + rm -f *.o ${PROG} diff --git a/contrib/xntpd/ppsclock/ppstest/ppstest.c b/contrib/xntpd/ppsclock/ppstest/ppstest.c new file mode 100644 index 0000000000..ece8dbee14 --- /dev/null +++ b/contrib/xntpd/ppsclock/ppstest/ppstest.c @@ -0,0 +1,132 @@ +#ifndef lint +static char rcsid[] = + "ppstest.c,v 3.1 1993/07/06 01:09:56 jbj Exp (LBL)"; +#endif +/* + * 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. + */ + +/* + * ppsclock test program + * + * This program is used to test the SunOS 4 pps clock streams module. + * It assumes a Magnavox MX4200 GPS receiver running at 4800 baud with + * its 1 PPS signal driving carrier detect. + */ + +#include +#include +#include +#include + +#include +#include +#include + +char *prog; + +main(argc, argv) + int argc; + char **argv; +{ + register int fd, i; + char *tty ="/dev/gps0"; + char buf[1024]; + struct ppsclockev ev; + + prog = argv[0]; + fd = open(tty, O_RDWR, 0); + if (fd < 0) { + fprintf(stderr, "%s: fopen ", prog); + perror(tty); + exit(1); + } + if (!gpsinit(fd)) + exit(1); + + i = read(fd, buf, sizeof(buf) - 1); + if (i < 0) { + fprintf(stderr, "%s: ", prog); + perror("read"); + exit(1); + } + buf[i] = '\0'; + + if (ioctl(fd, CIOGETEV, (char *)&ev) < 0) { + fprintf(stderr, "%s: ", prog); + perror("CIOGETEV"); + exit(1); + } + printf("%d.%06d (serial %d)\n\t\"%s\"\n", + ev.tv.tv_sec, ev.tv.tv_usec, ev.serial, buf); + + exit(0); +} + +int +gpsinit(fd) + register int fd; +{ + struct termios termios; + speed_t speed = B4800; + + bzero((char *)&termios, sizeof(termios)); + termios.c_cflag = CS8 | CREAD | CLOCAL; + termios.c_iflag = IGNCR; + termios.c_lflag = ICANON; + if (cfsetispeed(&termios, speed) < 0) { + fprintf(stderr, "%s: cfsetispeed failed\n", prog); + perror("cfsetispeed"); + return (0); + } + if (cfsetospeed(&termios, speed) < 0) { + fprintf(stderr, "%s: cfsetospeed failed\n", prog); + perror("cfsetospeed"); + return (0); + } + if (tcsetattr(fd, TCSAFLUSH, &termios) < 0) { + fprintf(stderr, "%s: ", prog); + perror("tcsetattr"); + return (0); + } + + if (ioctl(fd, I_PUSH, PPSCLOCKSTR) < 0) { + fprintf(stderr, "%s: I_PUSH: ", prog); + perror(PPSCLOCKSTR); + return (0); + } + + return (1); +} diff --git a/contrib/xntpd/ppsclock/sys/genassym/genassym.c b/contrib/xntpd/ppsclock/sys/genassym/genassym.c new file mode 100644 index 0000000000..c7c8ef5f46 --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/genassym/genassym.c @@ -0,0 +1,84 @@ +#ifndef lint +static char rcsid[] = + "genassym.c,v 3.1 1993/07/06 01:09:58 jbj Exp (LBL)"; +#endif +/* + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66. + * + * Copyright (c) 1993 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. + */ + +#include + +#include + +#include + +#ifndef offsetof +#define offsetof(str, mem) ((size_t)&((str *)0)->mem) +#endif + +#define off(what, str, mem) def(what, (int)offsetof(str, mem)) + +void +def(what, where) + char *what; + int where; +{ + + if (printf("#define\t%s\t%d\n", what, where) < 0) { + perror("printf"); + exit(1); + } +} + +void +flush() +{ + + if (fflush(stdout)) { + perror("fflush"); + exit(1); + } +} + +int +main() +{ + + off("CNTR_COUNTER10", struct counterregs, counter10); + + flush(); + + exit(0); +} diff --git a/contrib/xntpd/ppsclock/sys/os/kern_clock.c.patch b/contrib/xntpd/ppsclock/sys/os/kern_clock.c.patch new file mode 100644 index 0000000000..d97e4fb730 --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/os/kern_clock.c.patch @@ -0,0 +1,19 @@ +*** kern_clock.c.virgin Tue Feb 16 20:02:52 1993 +--- kern_clock.c Tue Feb 16 20:03:16 1993 +*************** +*** 879,884 **** +--- 879,885 ---- + #define HI_RES_CLOCK + #endif + ++ #if !defined(sun4c) && !defined(sun4m) + uniqtime(tv) + register struct timeval *tv; + { +*************** +*** 952,954 **** +--- 953,956 ---- + *tv = last; + (void) splx(s); + } ++ #endif diff --git a/contrib/xntpd/ppsclock/sys/sun/str_conf.c.patch b/contrib/xntpd/ppsclock/sys/sun/str_conf.c.patch new file mode 100644 index 0000000000..4fb9cca1ea --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sun/str_conf.c.patch @@ -0,0 +1,38 @@ +*** /tmp/,RCSt1a09603 Mon Sep 14 12:18:04 1992 +--- str_conf.c Fri Sep 4 21:43:04 1992 +*************** +*** 19,24 **** +--- 19,25 ---- + #include "tirw.h" + #include "db.h" + #include "sl.h" ++ #include "zs.h" + #ifdef sun4c + #include "audioamd.h" + #else +*************** +*** 52,57 **** +--- 53,63 ---- + #if NSL > 0 + extern struct streamtab if_slinfo; + #endif ++ #if NZS > 0 ++ #include "sys/time.h" ++ #include "sys/ppsclock.h" ++ extern struct streamtab ppsclockinfo; ++ #endif + + extern struct streamtab ldtrinfo; + extern struct streamtab ttycompatinfo; +*************** +*** 86,91 **** +--- 92,100 ---- + { "ttcompat", &ttycompatinfo }, + #if NSL > 0 + { "slip", &if_slinfo }, ++ #endif ++ #if NZS > 0 ++ { PPSCLOCKSTR, &ppsclockinfo }, + #endif + #ifdef VDDRV + { "", 0 }, /* reserved for loadable modules */ diff --git a/contrib/xntpd/ppsclock/sys/sun4c/conf/Makefile.src.patch b/contrib/xntpd/ppsclock/sys/sun4c/conf/Makefile.src.patch new file mode 100644 index 0000000000..3f1bb6ecee --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sun4c/conf/Makefile.src.patch @@ -0,0 +1,17 @@ +*** Makefile.src.virgin Tue Feb 16 20:12:31 1993 +--- Makefile.src Tue Feb 16 20:13:32 1993 +*************** +*** 130,135 **** +--- 130,141 ---- + + FRC: + ++ assym.s: ${MACHINE}/genassym.c ++ ${CC} -E ${CPPOPTS} ${MACHINE}/genassym.c > ./a.out.c ++ cc ${COPTS} ./a.out.c ++ ./a.out >assym.s ++ rm -f ./a.out ./a.out.c ++ + Locore.L: + @echo Locore.c: + @-(${CPP} ${LCOPTS} ${MACHINE}/Locore.c | \ diff --git a/contrib/xntpd/ppsclock/sys/sun4c/conf/files.microtime.patch b/contrib/xntpd/ppsclock/sys/sun4c/conf/files.microtime.patch new file mode 100644 index 0000000000..a8a5c958d3 --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sun4c/conf/files.microtime.patch @@ -0,0 +1,12 @@ +*** files.virgin Thu Aug 13 18:44:53 1992 +--- files Thu Aug 6 16:14:59 1992 +*************** +*** 121,126 **** +--- 121,127 ---- + sun4c/map.s standard + sun4c/mem.c standard + sun4c/memerr.c standard ++ sun4c/microtime.s standard + sun4c/mmu.c standard + sun4c/subr.s standard + sun4c/trap.c standard diff --git a/contrib/xntpd/ppsclock/sys/sun4c/conf/files.patch b/contrib/xntpd/ppsclock/sys/sun4c/conf/files.patch new file mode 100644 index 0000000000..082a29bef6 --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sun4c/conf/files.patch @@ -0,0 +1,12 @@ +*** /tmp/,RCSt1a11376 Thu Aug 6 16:15:15 1992 +--- files Thu Aug 6 16:14:59 1992 +*************** +*** 199,204 **** +--- 199,205 ---- + sundev/zs_isdlc.c optional zsi device-driver + sundev/zs_proto.c optional zs device-driver + sundev/zs_sdlc.c optional zss device-driver ++ sundev/ppsclock.c optional zs device-driver + sunif/dbx_sunif.c optional dbx INET symbolic-info + sunif/dcp.c optional dcp device-driver + sunif/ie_conf.c optional ie device-driver diff --git a/contrib/xntpd/ppsclock/sys/sun4c/microtime.s b/contrib/xntpd/ppsclock/sys/sun4c/microtime.s new file mode 100644 index 0000000000..998653175c --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sun4c/microtime.s @@ -0,0 +1,98 @@ +/* + * 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. + */ + +#include +#define LOCORE 1 +#include +#include "assym.s" /* to get CNTR_COUNTER10 */ + + .seg "text" + .asciz "microtime.s,v 3.1 1993/07/06 01:10:03 jbj Exp"; + .asciz "Copyright (c) 1992 Regents of the University of California"; + .align 4 +/* + * void microtime(struct timeval *tv) + * + * 'microtime' code taken from LBL's sparc bsd: We don't + * need to spl (so this routine can be a leaf routine) and + * we don't keep a 'last' timeval (there can't be two calls + * to this routine in a microsecond). This seems to be + * about 20 times faster than the Sun code on an SS-2. - vj + * + * Read time values from slowest-changing to fastest-changing, + * then re-read out to slowest. If the values read before + * the innermost match those read after, the innermost value + * is consistent with the outer values. If not, it may not + * be and we must retry. Typically this loop runs only once; + * occasionally it runs twice, and only rarely does it run longer. + */ + .globl _time + .globl _tick + + ENTRY(microtime) + ALTENTRY(uniqtime) + + sethi %hi(_time), %g2 + sethi %hi(COUNTER_ADDR+CNTR_COUNTER10), %g3 +again: + ldd [%g2+%lo(_time)], %o2 ! time.tv_sec & time.tv_usec + ld [%g3+%lo(COUNTER_ADDR+CNTR_COUNTER10)], %o4 ! usec counter + ldd [%g2+%lo(_time)], %g4 ! see if time values changed + cmp %g4, %o2 + bne again ! if time.tv_sec changed + cmp %g5, %o3 + bne again ! if time.tv_usec changed + tst %o4 + + bpos notAtLimit + srl %o4, CTR_USEC_SHIFT, %o4 ! convert counter to usec + sethi %hi(_tick), %g4 ! bump usec by 1 tick + ld [%g4+%lo(_tick)], %o1 + set CTR_USEC_MASK >> CTR_USEC_SHIFT, %g5 + add %o1, %o3, %o3 + and %o4, %g5, %o4 +notAtLimit: + add %o4, %o3, %o3 + set 1000000, %g5 ! normalize usec value + cmp %o3, %g5 + bl,a noOflo + st %o2, [%o0] ! (should be able to std here) + add %o2, 1, %o2 + sub %o3, %g5, %o3 + st %o2, [%o0] ! (should be able to std here) +noOflo: + retl + st %o3, [%o0+4] diff --git a/contrib/xntpd/ppsclock/sys/sun4m/conf/Makefile.src.patch b/contrib/xntpd/ppsclock/sys/sun4m/conf/Makefile.src.patch new file mode 100644 index 0000000000..3f1bb6ecee --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sun4m/conf/Makefile.src.patch @@ -0,0 +1,17 @@ +*** Makefile.src.virgin Tue Feb 16 20:12:31 1993 +--- Makefile.src Tue Feb 16 20:13:32 1993 +*************** +*** 130,135 **** +--- 130,141 ---- + + FRC: + ++ assym.s: ${MACHINE}/genassym.c ++ ${CC} -E ${CPPOPTS} ${MACHINE}/genassym.c > ./a.out.c ++ cc ${COPTS} ./a.out.c ++ ./a.out >assym.s ++ rm -f ./a.out ./a.out.c ++ + Locore.L: + @echo Locore.c: + @-(${CPP} ${LCOPTS} ${MACHINE}/Locore.c | \ diff --git a/contrib/xntpd/ppsclock/sys/sun4m/conf/files.microtime.patch b/contrib/xntpd/ppsclock/sys/sun4m/conf/files.microtime.patch new file mode 100644 index 0000000000..a8a5c958d3 --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sun4m/conf/files.microtime.patch @@ -0,0 +1,12 @@ +*** files.virgin Thu Aug 13 18:44:53 1992 +--- files Thu Aug 6 16:14:59 1992 +*************** +*** 121,126 **** +--- 121,127 ---- + sun4c/map.s standard + sun4c/mem.c standard + sun4c/memerr.c standard ++ sun4c/microtime.s standard + sun4c/mmu.c standard + sun4c/subr.s standard + sun4c/trap.c standard diff --git a/contrib/xntpd/ppsclock/sys/sun4m/conf/files.patch b/contrib/xntpd/ppsclock/sys/sun4m/conf/files.patch new file mode 100644 index 0000000000..082a29bef6 --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sun4m/conf/files.patch @@ -0,0 +1,12 @@ +*** /tmp/,RCSt1a11376 Thu Aug 6 16:15:15 1992 +--- files Thu Aug 6 16:14:59 1992 +*************** +*** 199,204 **** +--- 199,205 ---- + sundev/zs_isdlc.c optional zsi device-driver + sundev/zs_proto.c optional zs device-driver + sundev/zs_sdlc.c optional zss device-driver ++ sundev/ppsclock.c optional zs device-driver + sunif/dbx_sunif.c optional dbx INET symbolic-info + sunif/dcp.c optional dcp device-driver + sunif/ie_conf.c optional ie device-driver diff --git a/contrib/xntpd/ppsclock/sys/sun4m/microtime.s b/contrib/xntpd/ppsclock/sys/sun4m/microtime.s new file mode 100644 index 0000000000..1663a32cec --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sun4m/microtime.s @@ -0,0 +1,98 @@ +/* + * 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. + */ + +#include +#define LOCORE 1 +#include +#include "assym.s" /* to get CNTR_COUNTER10 */ + + .seg "text" + .asciz "microtime.s,v 3.1 1993/07/06 01:10:10 jbj Exp"; + .asciz "Copyright (c) 1992 Regents of the University of California"; + .align 4 +/* + * void microtime(struct timeval *tv) + * + * 'microtime' code taken from LBL's sparc bsd: We don't + * need to spl (so this routine can be a leaf routine) and + * we don't keep a 'last' timeval (there can't be two calls + * to this routine in a microsecond). This seems to be + * about 20 times faster than the Sun code on an SS-2. - vj + * + * Read time values from slowest-changing to fastest-changing, + * then re-read out to slowest. If the values read before + * the innermost match those read after, the innermost value + * is consistent with the outer values. If not, it may not + * be and we must retry. Typically this loop runs only once; + * occasionally it runs twice, and only rarely does it run longer. + */ + .globl _time + .globl _tick + + ENTRY(microtime) + ALTENTRY(uniqtime) + + sethi %hi(_time), %g2 + sethi %hi(COUNTER_ADDR+CNTR_COUNTER10), %g3 +again: + ldd [%g2+%lo(_time)], %o2 ! time.tv_sec & time.tv_usec + ld [%g3+%lo(COUNTER_ADDR+CNTR_COUNTER10)], %o4 ! usec counter + ldd [%g2+%lo(_time)], %g4 ! see if time values changed + cmp %g4, %o2 + bne again ! if time.tv_sec changed + cmp %g5, %o3 + bne again ! if time.tv_usec changed + tst %o4 + + bpos notAtLimit + srl %o4, CTR_USEC_SHIFT, %o4 ! convert counter to usec + sethi %hi(_tick), %g4 ! bump usec by 1 tick + ld [%g4+%lo(_tick)], %o1 + set CTR_USEC_MASK >> CTR_USEC_SHIFT, %g5 + add %o1, %o3, %o3 + and %o4, %g5, %o4 +notAtLimit: + add %o4, %o3, %o3 + set 1000000, %g5 ! normalize usec value + cmp %o3, %g5 + bl,a noOflo + st %o2, [%o0] ! (should be able to std here) + add %o2, 1, %o2 + sub %o3, %g5, %o3 + st %o2, [%o0] ! (should be able to std here) +noOflo: + retl + st %o3, [%o0+4] diff --git a/contrib/xntpd/ppsclock/sys/sundev/ppsclock.c b/contrib/xntpd/ppsclock/sys/sundev/ppsclock.c new file mode 100644 index 0000000000..cb0563be47 --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sundev/ppsclock.c @@ -0,0 +1,249 @@ +#ifndef lint +static char rcsid[] = + "ppsclock.c,v 3.1 1993/07/06 01:10:17 jbj Exp (LBL)"; +#endif +/* + * 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. + */ + +/* ppsclock streams module */ + +#define PPSCLOCKLED + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef PPSCLOCKLED +#include + +/* In case these aren't defined by auxio.h */ +#if !defined(LED_ON) && !defined(LED_OFF) +#define LED_ON *(u_char *)AUXIO_REG = AUX_MBO|AUX_EJECT|AUX_LED +#define LED_OFF *(u_char *)AUXIO_REG = AUX_MBO|AUX_EJECT +#endif + +int ppsclockled; +#endif + +int ppsclock_open(); +void ppsclock_close(); +void ppsclock_wput(); +static void ppsclock_intr(); + +static struct module_info stm_info = { + 0x434c, /* module id number (??) */ + PPSCLOCKSTR, /* module name */ + 0, /* minimum packet size */ + INFPSZ, /* infinite maximum packet size */ + STRHIGH, /* hi-water mark */ + STRLOW, /* lo-water mark */ +}; + +static struct qinit ppsclock_rinit = { + (int (*)())ppsclock_wput, /* put procedure */ + NULL, /* service procedure */ + ppsclock_open, /* called on startup */ + (int (*)())ppsclock_close, /* called on finish */ + NULL, /* for 3bnet only */ + &stm_info, /* module information structure */ + NULL /* module statistics structure */ +}; + +static struct qinit ppsclock_winit = { + (int (*)())ppsclock_wput, /* put procedure */ + NULL, /* service procedure */ + ppsclock_open, /* called on startup */ + (int (*)())ppsclock_close, /* called on finish */ + NULL, /* for 3bnet only */ + &stm_info, /* module information structure */ + NULL /* module statistics structure */ +}; + +struct streamtab ppsclockinfo = { + &ppsclock_rinit, /* qinit for read side */ + &ppsclock_winit, /* qinit for write side */ + NULL, /* mux qinit for read */ + NULL, /* mux qinit for write */ + NULL /* list of modules to be pushed */ +}; + +static struct ppsclockev ppsclockev; +static struct zsops *ppssavedzsops; +static struct zsops ppszsops; +static struct zscom *ppssavedzscom; + +#ifdef OPENPROMS +extern struct zsaline *zsaline; +#else +extern struct zsaline zsaline[]; +#endif + +/* + * open CLOCK STREAMS module + */ +/* ARGSUSED */ +int +ppsclock_open(q, dev, flag, sflag) + register queue_t *q; + register dev_t dev; + register int flag; + register int sflag; +{ + register struct zsaline *za; + register struct zscom *zs; + + /* We must be called with MODOPEN. */ + if (sflag != MODOPEN) + return (OPENFAIL); + + /* Hook up our external status interrupt handler */ + if (ppssavedzsops == NULL) { + za = &zsaline[minor(dev) & 0x7f]; + if ((zs = za->za_common) == NULL) + return (OPENFAIL); + ppssavedzsops = zs->zs_ops; + ppszsops = *ppssavedzsops; + ppszsops.zsop_xsint = (int (*)())ppsclock_intr; + zsopinit(zs, &ppszsops); + ppssavedzscom = zs; + } + return (0); +} + +void +ppsclock_close(q) + register queue_t *q; +{ + + /* Flush outstanding packets */ + flushq(WR(q), FLUSHALL); + + /* Unhook our external status interrupt handler */ + if (ppssavedzsops) { + zsopinit(ppssavedzscom, ppssavedzsops); + ppssavedzscom = NULL; + ppssavedzsops = NULL; + } +} + + +/* + * Read and write put procedure. Note that we can only get ioctl + * messages in the "write" case. + */ +void +ppsclock_wput(q, mp) + register queue_t *q; + register mblk_t *mp; +{ + register struct iocblk *iocp; + register mblk_t *datap; + + switch (mp->b_datap->db_type) { + + case M_FLUSH: + if (*mp->b_rptr & FLUSHW) + flushq(q, FLUSHDATA); + putnext(q, mp); + break; + + case M_IOCTL: + iocp = (struct iocblk *)mp->b_rptr; + if (iocp->ioc_cmd == CIOGETEV) { + datap = allocb(sizeof(struct ppsclockev), BPRI_HI); + if (datap == NULL) { + mp->b_datap->db_type = M_IOCNAK; + iocp->ioc_error = ENOMEM; + qreply(q, mp); + break; + } + if (mp->b_cont) + panic("ppsclock b_cont not null"); + mp->b_cont = datap; + *(struct ppsclockev *)datap->b_wptr = ppsclockev; + datap->b_wptr += + sizeof(struct ppsclockev) / sizeof(*datap->b_wptr); + mp->b_datap->db_type = M_IOCACK; + iocp->ioc_count = sizeof(struct ppsclockev); + qreply(q, mp); + break; + } + /* fall through */ + + default: + putnext(q, mp); + break; + } +} + +static void +ppsclock_intr(zs) + register struct zscom *zs; +{ + register struct zsaline *za = (struct zsaline *)zs->zs_priv; + register struct zscc_device *zsaddr = zs->zs_addr; + register u_char s0; + + s0 = zsaddr->zscc_control; + if ((s0 ^ za->za_rr0) & ZSRR0_CD) { + if ((s0 & ZSRR0_CD) != 0) { +#ifdef PPSCLOCKLED + if (ppsclockled) { + register struct timeval *tvp = &ppsclockev.tv; + LED_OFF; + uniqtime(tvp); + LED_ON; + } else +#endif + uniqtime(&ppsclockev.tv); + ++ppsclockev.serial; + } + za->za_rr0 = s0; + zsaddr->zscc_control = ZSWR0_RESET_STATUS; + return; + } + + /* Call real external status interrupt routine */ + (void)(*ppssavedzsops->zsop_xsint)(zs); +} diff --git a/contrib/xntpd/ppsclock/sys/sys/ppsclock.h b/contrib/xntpd/ppsclock/sys/sys/ppsclock.h new file mode 100644 index 0000000000..e72b8753a7 --- /dev/null +++ b/contrib/xntpd/ppsclock/sys/sys/ppsclock.h @@ -0,0 +1,49 @@ +/* ppsclock.h,v 3.1 1993/07/06 01:10:19 jbj Exp (LBL) */ +/* + * 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. + */ + +#define PPSCLOCKSTR "ppsclock" + +struct ppsclockev { + struct timeval tv; + u_int serial; +}; + +#if defined(__STDC__) +#define CIOGETEV _IOR('C', 0, struct ppsclockev) /* get last pps event */ +#else +#define CIOGETEV _IOR(C, 0, struct ppsclockev) /* get last pps event */ +#endif diff --git a/contrib/xntpd/refclocks/Dependencies b/contrib/xntpd/refclocks/Dependencies new file mode 100644 index 0000000000..d5e68d3da9 --- /dev/null +++ b/contrib/xntpd/refclocks/Dependencies @@ -0,0 +1,28 @@ +Clock Defines Restrictions AddDef Kernel +PPS PPS + PPSPPS /STREAM/ STREAM(ppsclock|ppsclocd) + PPSCLK /LD/||/STREAM/ LD||STREAM(tty_clock||tty_clk_streams) + PPSCD /STREAM/ STREAM(ppsclock|ppsclocd) +LOCAL LOCAL_CLOCK +PST PST + PSTCLK /LD/||/STREAM/ LD||STREAM(tty_clock||tty_clk_streams) + PSTPPS /PPSPPS/ +WWVB WWVB + WWVBCLK /LD/||/STREAM/ PPSPPS LD||STREAM(tty_clock||tty_clk_streams) + WWVBPPS /PPSPPS/ +CHU CHU /SUNOS4/ none +PARSE PARSE /SYS_V_TTYS/||/STREAM/ PPS any||STREAM(parse||ppsclock||ppsclocd) + PARSEPPS /SYS_V_TTYS/||/STREAM/ PPS any||STREAM(parse||ppsclock||ppsclocd) + CLOCK_* +MX4200 MX4200PPS /PPSPPS/ +AS2201 AS2201 + AS2201PPS /PPSPPS/ +GOES GOES + GOESPPS /PPSPPS/ +OMEGA OMEGA + OMEGAPPS /PPSPPS/ +TPRO TPRO /SUNOS/ +LEITCH LEITCH + LEITCHPPS /PPSPPS/ +MSFEES MSFEESPPS /PPSPPS/ +IRIG IRIG /SUNOS/ BSDAUDIO diff --git a/contrib/xntpd/refclocks/README b/contrib/xntpd/refclocks/README new file mode 100644 index 0000000000..b27b0064bd --- /dev/null +++ b/contrib/xntpd/refclocks/README @@ -0,0 +1,4 @@ +This directory contains shell scripts that should allow an interactive +refclock configuration. + +Frank Kardel diff --git a/contrib/xntpd/refclocks/check b/contrib/xntpd/refclocks/check new file mode 100644 index 0000000000..d1e8b19cd5 --- /dev/null +++ b/contrib/xntpd/refclocks/check @@ -0,0 +1,2 @@ +#!/bin/sh +`echo "$1" | awk '{ if ( '"$2"' ) { print ":"; } else { print "false"; } exit; }'`; diff --git a/contrib/xntpd/refclocks/echon b/contrib/xntpd/refclocks/echon new file mode 100644 index 0000000000..8750ae86c2 --- /dev/null +++ b/contrib/xntpd/refclocks/echon @@ -0,0 +1,2 @@ +#!/bin/sh +echo -n "$@"; diff --git a/contrib/xntpd/refclocks/query b/contrib/xntpd/refclocks/query new file mode 100644 index 0000000000..07e11ccf2f --- /dev/null +++ b/contrib/xntpd/refclocks/query @@ -0,0 +1,11 @@ +#!/bin/sh +echon "$1 (y/n) [$2] ? " +X="" +read X +if [ "$X" = "" ]; then + X="$2" +fi +case "$X" in + [yY]*) exit 0;; + *) exit 1;; +esac diff --git a/contrib/xntpd/refclocks/rclk.AS2201 b/contrib/xntpd/refclocks/rclk.AS2201 new file mode 100644 index 0000000000..9af89af409 --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.AS2201 @@ -0,0 +1,29 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +case "$CMD" in + info) + echo " AS2201 - Austron 2200A or 2201A GPS receiver" + ;; + check) + if check "$RCONFIG" '$0 ~ /AS2201/'; then + echo "AS2201 - Austron 2200A or 2201A GPS receiver" + fi + ;; + config) + if check "$REFCONF" '$0 ~ /AS2201/' || + ( [ ! "$REFCONF" ] && query "Include Austron 2200A or 2201A GPS receiver (AS2201)" n); then + if check "$PPSFEATURES" '$0 ~ /CD/' && + [ "$PPSOK" -eq 1 ] && + (check "$REFCONF" '$0 ~ /AS2201PPS/' || + ( [ ! "$REFCONF" ] && query " Use AS2201 for PPS" n)); then + echo "-DAS2201PPS" >> $RCONFIG + else + echo "-DAS2201" >> $RCONFIG + fi + fi + ;; +esac diff --git a/contrib/xntpd/refclocks/rclk.CHU b/contrib/xntpd/refclocks/rclk.CHU new file mode 100644 index 0000000000..fedd55c33d --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.CHU @@ -0,0 +1,24 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +if check "$DEFS" '$0 ~ /SYS_SUNOS4/'; then + case "$CMD" in + info) + echo " CHU - CHU via shortwave radio" + ;; + check) + if check "$RCONFIG" '$0 ~ /CHU/'; then + echo "CHU - CHU via shortwave radio" + fi + ;; + config) + if check "$REFCONF" '$0 ~ /CHU/' || + ( [ ! "$REFCONF" ] && query "Include CHU via shortwave radio (CHU)" n); then + echo "-DCHU" >> $RCONFIG + fi + ;; +esac +fi diff --git a/contrib/xntpd/refclocks/rclk.GOES b/contrib/xntpd/refclocks/rclk.GOES new file mode 100644 index 0000000000..cb87c63898 --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.GOES @@ -0,0 +1,32 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +case "$CMD" in + info) + echo " GOES - Kinemetrics/TrueTime 468-DC GOES receiver" + ;; + check) + if check "$RCONFIG" '$0 ~ /GOES/'; then + echo "GOES - Kinemetrics/TrueTime 468-DC GOES receiver" + fi + ;; + config) + if check "$REFCONF" '$0 ~ /GOES/' || + ( [ ! "$REFCONF" ] && query "Include Kinemetrics/TrueTime 468-DC GOES receiver (GOES)" n); then + if check "$PPSFEATURES" '$0 ~ /CD/'; then + if [ "$PPSOK" -eq 1 ] && + (check "$REFCONF" '$0 ~ /GOESPPS/' || + ( [ ! "$REFCONF" ] && query " Use GOES for PPS" n)); then + echo "-DGOESPPS" >> $RCONFIG + else + echo "-DGOES" >> $RCONFIG + fi + else + echo "-DGOES" >> $RCONFIG + fi + fi + ;; +esac diff --git a/contrib/xntpd/refclocks/rclk.IRIG b/contrib/xntpd/refclocks/rclk.IRIG new file mode 100644 index 0000000000..b480e90391 --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.IRIG @@ -0,0 +1,24 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +if check "$DEFS" '$0 ~ /SYS_SUNOS4/'; then + case "$CMD" in + info) + echo " IRIG - IRIG-B timecode timecode using the audio codec" + ;; + check) + if check "$RCONFIG" '$0 ~ /IRIG/'; then + echo "IRIG - IRIG-B timecode timecode using the audio codec" + fi + ;; + config) + if check "$REFCONF" '$0 ~ /IRIG/' || + ( [ ! "$REFCONF" ] && query "Include IRIG-B timecode timecode using the audio codec (IRIG)" n); then + echo "-DIRIG" >> $RCONFIG + fi + ;; + esac +fi diff --git a/contrib/xntpd/refclocks/rclk.LEITCH b/contrib/xntpd/refclocks/rclk.LEITCH new file mode 100644 index 0000000000..1bd5fb8011 --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.LEITCH @@ -0,0 +1,29 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +case "$CMD" in + info) + echo " LEITCH - Leitch CSD 5300 Master Clock System Driver" + ;; + check) + if check "$RCONFIG" '$0 ~ /LEITCH/'; then + echo "LEITCH - Leitch CSD 5300 Master Clock System Driver" + fi + ;; + config) + if check "$REFCONF" '$0 ~ /LEITCH/' || + ( [ ! "$REFCONF" ] && query "Include Leitch CSD 5300 Master Clock System Driver (LEITCH)" n); then + if check "$PPSFEATURES" '$0 ~ /CD/' && + [ "$PPSOK" -eq 1 ] && + (check "$REFCONF" '$0 ~ /LEITCHPPS/' || + ( [ ! "$REFCONF" ] && query " Use LEITCH for PPS" n)); then + echo "-DLEITCHPPS" >> $RCONFIG + else + echo "-DLEITCH" >> $RCONFIG + fi + fi + ;; +esac diff --git a/contrib/xntpd/refclocks/rclk.LOCAL_CLOCK b/contrib/xntpd/refclocks/rclk.LOCAL_CLOCK new file mode 100644 index 0000000000..e2f9e1afe7 --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.LOCAL_CLOCK @@ -0,0 +1,22 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +case "$CMD" in + info) + echo " LOCAL_CLOCK - use local clock as reference" + ;; + check) + if check "$RCONFIG" '$0 ~ /LOCAL_CLOCK/'; then + echo "LOCAL_CLOCK - local clock" + fi + ;; + config) + if check "$REFCONF" '$0 ~ /LOCAL_CLOCK/' || + ( [ ! "$REFCONF" ] && query "Include local clock reference support (LOCAL_CLOCK)" y); then + echo "-DLOCAL_CLOCK" >> $RCONFIG + fi + ;; +esac diff --git a/contrib/xntpd/refclocks/rclk.MSFEES b/contrib/xntpd/refclocks/rclk.MSFEES new file mode 100644 index 0000000000..aeb988af8d --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.MSFEES @@ -0,0 +1,26 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +case "$CMD" in + info) + if check "$DEFS" '$0 ~ /STREAM/'; then + echo " MSFEESPPS - EES M201 MSF receiver" + fi + ;; + check) + if check "$RCONFIG" '$0 ~ /MSFEESPPS/'; then + echo "MSFEESPPS - EES M201 MSF receiver" + fi + ;; + config) + if check "$PPSFEATURES" '$0 ~ /CD/' && + [ "$PPSOK" -eq 1 ] && + (check "$REFCONF" '$0 ~ /MSFEESPPS/' || + ( [ ! "$REFCONF" ] && query "Include EES M201 MSF receiver (MSFEESPPS)" n)); then + echo "-DMSFEESPPS" >> $RCONFIG + fi + ;; +esac diff --git a/contrib/xntpd/refclocks/rclk.MX4200 b/contrib/xntpd/refclocks/rclk.MX4200 new file mode 100644 index 0000000000..5d10712619 --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.MX4200 @@ -0,0 +1,27 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +case "$CMD" in + info) + if check "$DEFS" '$0 ~ /STREAM/'; then + echo " MX4200 - Magnavox 4200 GPS receiver" + fi + ;; + check) + if check "$RCONFIG" '$0 ~ /MX4200PPS/'; then + echo "MX4200 - Magnavox 4200 GPS receiver" + fi + ;; + config) + if check "$PPSFEATURES" '$0 ~ /CD/' && + [ "$PPSOK" -eq 1 ] && + (check "$REFCONF" '$0 ~ /MX4200PPS/' || + ( [ ! "$REFCONF" ] && query "Include Magnavox 4200 GPS receiver (MX4200PPS)" n)); then + echo "-DMX4200PPS" >> $RCONFIG + fi + ;; +esac + diff --git a/contrib/xntpd/refclocks/rclk.OMEGA b/contrib/xntpd/refclocks/rclk.OMEGA new file mode 100644 index 0000000000..62094e4613 --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.OMEGA @@ -0,0 +1,29 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +case "$CMD" in + info) + echo " OMEGA - Kinemetrics/TrueTime OM-DC OMEGA receiver" + ;; + check) + if check "$RCONFIG" '$0 ~ /OMEGA/'; then + echo "OMEGA - Kinemetrics/TrueTime OM-DC OMEGA receiver" + fi + ;; + config) + if check "$REFCONF" '$0 ~ /OMEGA/' || + ( [ ! "$REFCONF" ] && query "Include Kinemetrics/TrueTime OM-DC OMEGA receiver (OMEGA)" n); then + if check "$PPSFEATURES" '$0 ~ /CD/' && + [ "$PPSOK" -eq 1 ] && + (check "$REFCONF" '$0 ~ /OMEGAPPS/' || + ( [ ! "$REFCONF" ] && query " Use OMEGA for PPS" n)); then + echo "-DOMEGAPPS" >> $RCONFIG + else + echo "-DOMEGA" >> $RCONFIG + fi + fi + ;; +esac diff --git a/contrib/xntpd/refclocks/rclk.PARSE b/contrib/xntpd/refclocks/rclk.PARSE new file mode 100644 index 0000000000..0bcf6972eb --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.PARSE @@ -0,0 +1,51 @@ +#!/bin/sh +CMD="$1" +shift; + +. refclocks/setup + +if check "$DEFS" '$0 ~ /HAVE_SYSV_TTYS|STREAM/'; then + case "$CMD" in + info) + echo " PARSE - GENERIC refence clock driver" + echo " DCF77:" + echo " Meinberg DCF U/A 31, PZF 535" + echo " Schmid DCF77 receiver" + echo " ELV DCF7000" + echo " Raw DCF77 signal (100/200ms pulses)" + echo " GPS:" + echo " Meinberg GPS 166" + echo " Trimble GPS SV6" + ;; + check) + if check "$RCONFIG" '$0 ~ /PARSE/ && $0 ~ /CLOCK/'; then + echon "PARSE - GENERIC" + if check "$RCONFIG" '$0 ~ /PARSEPPS/'; then echon "/PPS"; fi + if check "$RCONFIG" '$0 ~ /CLOCK_MEINBERG/'; then echon ",MEINBERG"; fi + if check "$RCONFIG" '$0 ~ /CLOCK_SCHMID/'; then echon ",SCHMID"; fi + if check "$RCONFIG" '$0 ~ /CLOCK_DCF7000/'; then echon ",DCF7000"; fi + if check "$RCONFIG" '$0 ~ /CLOCK_TRIMSV6/'; then echon ",Trimble SV6"; fi + if check "$RCONFIG" '$0 ~ /CLOCK_RAWDCF/'; then echon ",Raw DCF77 pulses"; fi + echo + fi + ;; + config) + if check "$REFCONF" '$0 ~ /PARSE/' || + ( [ ! "$REFCONF" ] && query "Include PARSE generic driver support" n); then + if check "$REFCONF" '$0 ~ /PARSEPPS/' || + ( [ ! "$REFCONF" ] && query " Include support for PPS simulation" y); then echo "-DPARSEPPS" >> $RCONFIG; else echo "-DPARSE" >> $RCONFIG; fi + if check "$REFCONF" '$0 ~ /MEINBERG/' || + ( [ ! "$REFCONF" ] && query " Include support for Meinberg clocks" y); then echo "-DCLOCK_MEINBERG" >> $RCONFIG; fi + if check "$REFCONF" '$0 ~ /SCHMID/' || + ( [ ! "$REFCONF" ] && query " Include support for Schmid DCF77 clock" y); then echo "-DCLOCK_SCHMID" >> $RCONFIG; fi + if check "$REFCONF" '$0 ~ /DCF7000|ELV/' || + ( [ ! "$REFCONF" ] && query " Include support for ELV/DCF7000 clock" y); then echo "-DCLOCK_DCF7000" >> $RCONFIG; fi + if check "$REFCONF" '$0 ~ /TRIMBLE/' || + ( [ ! "$REFCONF" ] && query " Include support for Trimble SV6 GPS receiver" y); then echo "-DCLOCK_TRIMSV6" >> $RCONFIG; fi + if check "$REFCONF" '$0 ~ /RAWDCF/' || + ( [ ! "$REFCONF" ] && query " Include support for raw DCF77 time code" y); then echo "-DCLOCK_RAWDCF" >> $RCONFIG; fi + fi + ;; + esac +fi + diff --git a/contrib/xntpd/refclocks/rclk.PST b/contrib/xntpd/refclocks/rclk.PST new file mode 100644 index 0000000000..4f93c8e8f2 --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.PST @@ -0,0 +1,37 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +case "$CMD" in + info) + echo " PST - PST/Traconex 1020 WWV/H receiver" + ;; + check) + if check "$RCONFIG" '$0 ~ /PST/'; then + echo "PST - PST/Traconex 1020 WWV/H receiver" + fi + ;; + config) + if check "$REFCONF" '$0 ~ /PST/' || + ( [ ! "$REFCONF" ] && query "Include PST/Traconex 1020 WWV/H receiver (PST)" n); then + _PST=0 + if check "$PPSFEATURES" '$0 ~ /CLK/'; then + if (check "$REFCONF" '$0 ~ /PSTCLK/' || + ( [ ! "$REFCONF" ] && query " Support PPS via clk" y)); then + echo " -DPSTCLK" >> $RCONFIG + _PST=1 + fi + fi + if check "$PPSFEATURES" '$0 ~ /CD/' && + [ "$PPSOK" -eq 1 ] && + (check "$REFCONF" '$0 ~ /PSTPPS/' || + ( [ ! "$REFCONF" ] && query " Use PST for PPS" n)); then + echo " -DPSTPPS" >> $RCONFIG + else + [ "$_PST" -eq 0 ] && echo "-DPST" >> $RCONFIG + fi + fi + ;; +esac diff --git a/contrib/xntpd/refclocks/rclk.TPRO b/contrib/xntpd/refclocks/rclk.TPRO new file mode 100644 index 0000000000..74e5545211 --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.TPRO @@ -0,0 +1,24 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +if check "$DEFS" '$0 ~ /SYS_SUNOS/'; then + case "$CMD" in + info) + echo " TPRO - KSI/Odetics TPRO-S IRIG-B timecode reader" + ;; + check) + if check "$RCONFIG" '$0 ~ /TPRO/'; then + echo "TPRO - KSI/Odetics TPRO-S IRIG-B timecode reader" + fi + ;; + config) + if check "$REFCONF" '$0 ~ /TPRO/' || + ( [ ! "$REFCONF" ] && query "Include KSI/Odetics TPRO-S IRIG-B timecode reader (TPRO)" n); then + echo "-DTPRO" >> $RCONFIG + fi + ;; + esac +fi diff --git a/contrib/xntpd/refclocks/rclk.WWVB b/contrib/xntpd/refclocks/rclk.WWVB new file mode 100644 index 0000000000..2801ac70b1 --- /dev/null +++ b/contrib/xntpd/refclocks/rclk.WWVB @@ -0,0 +1,38 @@ +#!/bin/sh - +CMD="$1" +shift; + +. refclocks/setup + +case "$CMD" in + info) + echo " WWVB - Spectracom 8170 or Netclock/2 WWVB receiver" + ;; + check) + if check "$RCONFIG" '$0 ~ /WWVB/'; then + echo "WWVB - Spectracom 8170 or Netclock/2 WWVB receiver" + fi + ;; + config) + if check "$REFCONF" '$0 ~ /WWVB/' || + ( [ ! "$REFCONF" ] && query "Include Spectracom 8170 or Netclock/2 WWVB receiver (WWVB)" n); then + _WWV=0 + if check "$PPSFEATURES" '$0 ~ /CLK/'; then + if check "$REFCONF" '$0 ~ /WWVBCLK/' || + ( [ ! "$REFCONF" ] && query " Support PPS via clk" y); then + echo " -DWWVBCLK" >> $RCONFIG + _WWV=1 + fi + fi + if check "$PPSFEATURES" '$0 ~ /CD/'; then + if [ "$PPSOK" -eq 1 ] && + (check "$REFCONF" '$0 ~ /WWVBPPS/' || + ( [ ! "$REFCONF" ] && query " Use WWVB for PPS" n)); then + echo " -DWWVBPPS" >> $RCONFIG + fi + else + [ "$_WWV" -eq 0 ] && echo "-DWWVB" >> $RCONFIG + fi + fi + ;; +esac diff --git a/contrib/xntpd/refclocks/rconfig b/contrib/xntpd/refclocks/rconfig new file mode 100644 index 0000000000..727f0a8707 --- /dev/null +++ b/contrib/xntpd/refclocks/rconfig @@ -0,0 +1,119 @@ +#!/bin/sh - +# +# Refclock configuration script +# +# batch configuration options (optional arg 1) +# pps related +# PPS - general PPS support +# CLK - CLK line discipline or streams module +# CD - ppsclock or ppsclockd streams module +# LINE - dedicated line +PATH=refclocks:${PATH} +export PATH +RCONFIG=rconf +DLOCAL=dlocal +REFCONF=${1-""} + +. refclocks/setup + +rcfg="`echo refclocks/rclk.*`" + +if [ "$rcfg" = "refclocks/rclk.*" ]; then + echo "no reference clock configuration information available" +else + config="`egrep '^[ ]*CLOCKDEFS[ ]*=' Config.local | sed 's/\([^#]*\)#.*$/\1/g; s/[ ]*CLOCKDEFS[ ]*=//g; s/-D//g; s/[ ][ ]*/ /g; s/^ *//g; s/ *$//g;'`" + DEFS="`egrep '^[ ]*DEFS[ ]*=' Config | sed 's/\([^#]*\)#.*$/\1/g; s/[ ]*DEFS[ ]*=//g; s/-D//g; s/[ ][ ]*/ /g; s/^ *//g; s/ *$//g;'`" + if [ ! "$REFCONF" ]; then + echo + echo "Current configuration" + echo + for i in $rcfg + do + sh $i check "$config" "" "" "$DEFS" "$REFCONF" + done + echo + fi + if [ "$REFCONF" ] || query "Change Configuration" n; then + if [ ! "$REFCONF" ]; then + echo + echo 'Available reference clock drivers' + for i in $rcfg + do + sh $i info "" "" "" "$DEFS" "$REFCONF" + done + echo + fi + :>"$RCONFIG" + PPS="" + PPSFEATURES="" + PPSOK=0 + if check "$REFCONF" '$0 ~ /PLL/' || + ( [ ! "$REFCONF" ] && query "Include support for Kernel PLL" n); then + PPS="-DKERNEL_PLL $PPS" + fi + if check "$REFCONF" '$0 ~ /[^A-Za-z]PPS/' || + ( [ ! "$REFCONF" ] && query "Do you have a PPS (pulse per second) signal" n); then + if check "$DEFS" '$0 ~ /HAVE_BSD_TTYS|STREAM/' && + (check "$REFCONF" '$0 ~ /CLK/' || + ( [ ! "$REFCONF" ] && query "Is the clk line discipline available" n)); then + PPSFEATURES="CLK" + else + if check "$DEFS" '$0 ~ /STREAM/' && + (check "$REFCONF" '$0 ~ /CD/' || + ( [ ! "$REFCONF" ] && query "Is the ppsclock or ppsclocd STREAMS module available" n)); then + PPSFEATURES="CD $PPSFEATURES" + fi + fi + if check "$PPSFEATURES" '$0 ~ /CLK|CD/' && + (check "$REFCONF" '$0 ~ /LINE/' || + ( [ ! "$REFCONF" ] && query "Do you want to use a dedicated serial port for PPS signal" n)); then + if check "$PPSFEATURES" '$0 ~ /CLK/'; then + PPS="-DPPSCLK $PPS" + fi + if check "$PPSFEATURES" '$0 ~ /CD/'; then + PPS="-DPPSCD $PPS" + fi + else + PPSOK=1 + PPS="-DPPS $PPS" + fi + fi + for i in $rcfg + do + sh $i config "$RCONFIG" "$PPSFEATURES" "$PPSOK" "$DEFS" "$REFCONF" + if [ "$PPSOK" -eq 1 ] && egrep -s -e '-D..*PPS' "$RCONFIG" >/dev/null 2>&1; then + PPSOK=0 + fi + done + if egrep -s -e '-D..*PPS' "$RCONFIG" >/dev/null 2>&1; then + PPS="-DPPSPPS $PPS" + fi + CLOCKDEFS="`tr '\012' ' ' < $RCONFIG`" + if check "$CLOCKDEFS" '$0 !~ /^[ ]*$/'; then + PPS="-DREFCLOCK $PPS" + if [ ! "$REFCONF" ]; then + echo + echo "Do not forget to set up the appropriate device links in the /dev directory" + echo + fi + fi + if sed -e 's/^[ ]*CLOCKDEFS[ ]*=.*$/CLOCKDEFS='"$CLOCKDEFS"'/;' \ + -e 's/^[ ]*DEFS_LOCAL[ ]*=.*$/DEFS_LOCAL= $(DEFS_OPT) '"$PPS"'/;' \ + Config.local > Config.local.new; then + mv Config.local Config.local.old && + mv Config.local.new Config.local && + rm -f Config.local.old + echo + echo "New configuration defines:" + echo " CLOCKDEFS=$CLOCKDEFS" + echo " DEFS_LOCAL="'$(DEFS_OPT)'" $PPS" + echo + echo "Configuration updated" + else + echo "Configuration update FAILED" + fi + rm -f "$RCONFIG" + else + :; + fi +fi diff --git a/contrib/xntpd/refclocks/setup b/contrib/xntpd/refclocks/setup new file mode 100644 index 0000000000..461117841c --- /dev/null +++ b/contrib/xntpd/refclocks/setup @@ -0,0 +1,16 @@ +# +# gobble possible parameters +# +if [ $# -eq 5 ]; then + RCONFIG="$1" + PPSFEATURES="$2" + PPSOK="$3" + DEFS="$4" + REFCONF="$5" +fi +# +# shell dumbness detection +# +if (eval "_x () { :; }") >/dev/null 2>&1 ; then + . refclocks/setupfn +fi diff --git a/contrib/xntpd/refclocks/setupfn b/contrib/xntpd/refclocks/setupfn new file mode 100644 index 0000000000..5724dcb52d --- /dev/null +++ b/contrib/xntpd/refclocks/setupfn @@ -0,0 +1,27 @@ +# +# sh io functions +# +if [ "`echo -n`" = "-n" ]; then + echon () { echo "$@\\c"; } +else + echon () { echo -n "$@"; } +fi + +query() { + _Q="$1" + _A="$2" + echon "$_Q (y/n) [$_A] ? " + X="" + read X + if [ "$X" = "" ]; then + X="$_A" + fi + case "$X" in + [yY]*) return 0;; + *) return 1;; + esac +} + +check () { + `echo "$1" | awk '{ if ( '"$2"' ) { print ":"; } else { print "false"; } exit; }'`; +} diff --git a/contrib/xntpd/scripts/Guess.sh b/contrib/xntpd/scripts/Guess.sh new file mode 100644 index 0000000000..97fd4c7cb2 --- /dev/null +++ b/contrib/xntpd/scripts/Guess.sh @@ -0,0 +1,116 @@ +#! /bin/sh + +if [ -f /bin/uname -o -f /usr/bin/uname ]; then + set `uname -a | tr '[A-Z]' '[a-z]'` +# set `cat test | tr '[A-Z]' '[a-z]'` + case "$1" in + convexos) case "$3" in + 10.*) guess="convexos10" ;; + esac + ;; + aix) case "$4" in + 3) case "$3" in + 1) guess="aix3.1" ;; + 2) guess="aix3.2" ;; + esac + ;; + esac + ;; + sinix-m) + guess=sinix-m + ;; + sunos) case "$3" in + 4.1*) guess="sunos4" ;; + 5.1) guess="sunos5.1" ;; + 5.*) guess="sunos5.2" ;; + esac + ;; + irix) case "$3" in + 4.*) guess="irix4" ;; + 5.*) guess="irix5" ;; + esac + ;; + "a/ux") case "$3" in + 2.*) guess="aux2" ;; + 3.*) guess="aux3" ;; + esac + ;; + ultrix) + guess="ultrix" + ;; + hp-ux) case "$3" in + *.10.*) guess="hpux10+" ;; + *) guess="hpux" ;; + esac + ;; + linux) guess="linux" ;; + + osf1) case "$5" in + alpha) guess="decosf1" ;; + esac + ;; + "bsd/386") + guess="bsdi" + ;; + "freebsd") + guess="freebsd" + ;; + "netbsd") + guess="netbsd" + ;; + # now the fun starts - there are vendors that + # do not really identify their OS un uname. + # Fine - now I look at our version and hope + # that nobody else had this marvellous idea. + # I am not willing to mention the vendor explicitly + *) # Great ! - We are dealing with an industry standard ! + if [ -f /unix ]; then + # + # looks like this thing has the license + # to call itself Unix + # + case "$3" in + 3.2.*) + case "$4" in + v*) + (i386) >/dev/null 2>&1 && guess=ptx;; + esac + esac + fi + ;; + esac +fi + +if [ "0$guess" != "0" ]; then + echo $guess + exit 0 +fi + +if [ -f /bin/machine ]; then + echo `/bin/machine` + exit 0 +fi + +if [ -f /usr/convex/vers ]; then + set `/usr/convex/vers /vmunix` + case "$2" in + 9.0) echo "convexos9" + exit 0 ;; + esac +fi + +if [ -d /usr/lib/NextStep ]; then + echo next + exit 0 +fi + +if [ -f /netbsd ]; then + echo netbsd + exit 0 +fi + +case "$guess" in + '') guess="none" +esac + +echo $guess diff --git a/contrib/xntpd/scripts/README b/contrib/xntpd/scripts/README new file mode 100644 index 0000000000..79f1792a43 --- /dev/null +++ b/contrib/xntpd/scripts/README @@ -0,0 +1,41 @@ +README file for directory ./scripts of the NTP Version 3 distribution + +This directory contains shell and perl script files for the configuration, +monitoring and support of NTP installations. See the README and RELNOTES +files in the parent directory for directions on how to use these files. + +Guess.sh script to figure out what machine and operating system + is running this thing. Prizes awarded for new machines + added to the list. + +autoconf awesome script swiped from Jeff Johnson (who may have + swiped it from GNU) which delves deep into the system + files to reveal dark secrets necessary to port NTP to + everything exceptt sewing machines. Unfinished work. + +makeconfig.sh shell script that calles Guess.sh and then figures out + what compiler is available, then builds the + configuration file in the base directory. Finally, it + launches the sed script Config.sed in the base directory + to make the makefiles used by most programs. + +mklinks script useful to create directories for multiple + architecture maintenance + +mkversion script useful to create new version numbers for all + sources + +monitoring directory containing perl scripts useful for monitoring + operations + +ntp-groper script useful for reaching out and rattling the cages of + NTP peers to see if animals are inside the bars + +ntp-restart script useful for killing and restarting the NTP daemon + +stats directory containing awk ans shell scripts useful for + maintaining statistics summaries of clockstats, loopstats + and peerstats files + +support directory containing shell and perl scripts useful for + configuration and monitoring of NTP subnets diff --git a/contrib/xntpd/scripts/autoconf b/contrib/xntpd/scripts/autoconf new file mode 100644 index 0000000000..d1dc4c0bae --- /dev/null +++ b/contrib/xntpd/scripts/autoconf @@ -0,0 +1,885 @@ +#!/bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf. +# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp] [--no-create] +# [--prefix=PREFIX] [--exec-prefix=PREFIX] [--with-PACKAGE] [TARGET] +# Ignores all args except --srcdir, --prefix, --exec-prefix, --no-create, and +# --with-PACKAGE unless this script has special code to handle it. + + +for arg +do + # Handle --exec-prefix with a space before the argument. + if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix= + # Handle --host with a space before the argument. + elif test x$next_host = xyes; then next_host= + # Handle --prefix with a space before the argument. + elif test x$next_prefix = xyes; then prefix=$arg; next_prefix= + # Handle --srcdir with a space before the argument. + elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir= + else + case $arg in + # For backward compatibility, also recognize exact --exec_prefix. + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* | --exe=* | --ex=* | --e=*) + exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e) + next_exec_prefix=yes ;; + + -gas | --gas | --ga | --g) ;; + + -host=* | --host=* | --hos=* | --ho=* | --h=*) ;; + -host | --host | --hos | --ho | --h) + next_host=yes ;; + + -nfp | --nfp | --nf) ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre | --no-cr | --no-c | --no- | --no) + no_create=1 ;; + + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + next_prefix=yes ;; + + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=* | --s=*) + srcdir=`echo $arg | sed 's/[-a-z_]*=//'` ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s) + next_srcdir=yes ;; + + -with-* | --with-*) + package=`echo $arg|sed 's/-*with-//'` + # Delete all the valid chars; see if any are left. + if test -n "`echo $package|sed 's/[-a-zA-Z0-9_]*//g'`"; then + echo "configure: $package: invalid package name" >&2; exit 1 + fi + eval "with_`echo $package|sed s/-/_/g`=1" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb | --ver | --ve | --v) + verbose=yes ;; + + *) ;; + esac + fi +done + +trap 'rm -f conftest* core; exit 1' 1 3 15 + +# Needed for some versions of `tr' so that character classes in `[]' work. +if test "${LANG+set}" = "set" ; then + LANG=C +fi + +rm -f conftest* +compile='${CC-cc} $CFLAGS $DEFS conftest.c -o conftest $LIBS >/dev/null 2>&1' + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +unique_file=lib/msyslog.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + srcdirdefaulted=yes + # Try the directory containing this script, then `..'. + prog=$0 + confdir=`echo $prog|sed 's%/[^/][^/]*$%%'` + test "X$confdir" = "X$prog" && confdir=. + srcdir=$confdir + if test ! -r $srcdir/$unique_file; then + srcdir=.. + fi +fi +if test ! -r $srcdir/$unique_file; then + if test x$srcdirdefaulted = xyes; then + echo "configure: Can not find sources in \`${confdir}' or \`..'." 1>&2 + else + echo "configure: Can not find sources in \`${srcdir}'." 1>&2 + fi + exit 1 +fi +# Preserve a srcdir of `.' to avoid automounter screwups with pwd. +# But we can't avoid them for `..', to make subdirectories work. +case $srcdir in + .|/*|~*) ;; + *) srcdir=`cd $srcdir; pwd` ;; # Make relative path absolute. +esac + + +useresolv="" + +echo CONFIGURE -- initializing DEFS +test -z "$DEFS" && DEFS="-DDEBUG -DREFCLOCK" +echo CONFIGURE -- initializing AUTHDEFS +test -z "$AUTHDEFS" && AUTHDEFS="-DDES -DMD5" +echo CONFIGURE -- initializing CLOCKDEFS +test -z "$CLOCKDEFS" && CLOCKDEFS="-DAS2201 -DCHU -DGOES -DLEITCH -DLOCAL_CLOCK -DOMEGA -DPST -DWWVB" +echo CONFIGURE -- initializing COPTS +test -z "$COPTS" && COPTS="-O" + +test -z "$INCLUDE" && INCLUDE="-I../include" +test -z "$LIB" && LIB="../lib/libntp.a" + +test "`uname`" = "SunOS" && { + DEFS="$DEFS -DXNTP_RETROFIT_STDLIB" +} +test "`uname`" = "ULTRIX" && { + DEFS="$DEFS -DXNTP_RETROFIT_STDLIB -DPLL -DREADKMEM" +} +test "`uname`" = "BSD/386" && { + DEFS="$DEFS -D__bsdi__" +} +test -d /usr/lib/NextStep && { + DEFS="$DEFS -DREADKMEM -DSYNCTODR_SUCKS" +} + +SOLARIS="" +test -d /kernel && test -d /opt && isSOLARIS="1" + +echo TODO -- checking for HPUX + +# We want these before the checks, so the checks can modify their values. +test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1 +test -z "$LDFLAGS" && LDFLAGS=-g + +#========================================================================== +if test -z "$CC"; then + # Extract the first word of `gcc', so it can be a program name with args. + set dummy gcc; word=$2 + echo checking for $word + IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/$word; then + CC="gcc" + break + fi + done + IFS="$saveifs" +fi +test -z "$CC" && CC="cc" +test -n "$CC" -a -n "$verbose" && echo " setting CC to $CC" + +# Find out if we are using GNU C, under whatever name. +cat > conftest.c < conftest.out 2>&1 +if egrep yes conftest.out >/dev/null 2>&1; then + GCC=1 # For later tests. +fi +rm -f conftest* + + +# If we're using gcc and the user hasn't specified CFLAGS, add -O to CFLAGS. +test -n "$GCC" && test -n "$auto_cflags" && CFLAGS="$CFLAGS -O" + + +echo checking how to run the C preprocessor +if test -z "$CPP"; then + CPP='${CC-cc} -E' + cat > conftest.c < +EOF +err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + : +else + CPP=/lib/cpp +fi +rm -f conftest* +fi + +if test -n "$GCC"; then + echo checking whether -traditional is needed + pattern="Autoconf.*'x'" + prog='#include +Autoconf TIOCGETP' + cat > conftest.c < conftest.out 2>&1" +if egrep "$pattern" conftest.out >/dev/null 2>&1; then + need_trad=1 +fi +rm -f conftest* + + + if test -z "$need_trad"; then + prog='#include +Autoconf TCGETA' + cat > conftest.c < conftest.out 2>&1" +if egrep "$pattern" conftest.out >/dev/null 2>&1; then + need_trad=1 +fi +rm -f conftest* + + fi + test -n "$need_trad" && CC="$CC -traditional" +fi + +if test -z "$RANLIB"; then + # Extract the first word of `ranlib', so it can be a program name with args. + set dummy ranlib; word=$2 + echo checking for $word + IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/$word; then + RANLIB="ranlib" + break + fi + done + IFS="$saveifs" +fi +test -z "$RANLIB" && RANLIB=":" +test -n "$RANLIB" -a -n "$verbose" && echo " setting RANLIB to $RANLIB" + + +# aC_MEMORY_H +echo checking for ANSI C header files +cat > conftest.c < +#include +#include +#include +EOF +err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +echo '#include ' > conftest.c +eval "$CPP \$DEFS conftest.c > conftest.out 2>&1" +if egrep "memchr" conftest.out >/dev/null 2>&1; then + # SGI's /bin/cc from Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +cat > conftest.c < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e,f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +eval $compile +if test -s conftest && (./conftest; exit) 2>/dev/null; then + { +test -n "$verbose" && \ +echo ' defining' STDC_HEADERS +DEFS="$DEFS -DSTDC_HEADERS=1" +} + +fi +rm -f conftest* +fi +rm -f conftest* + +fi +rm -f conftest* + +for hdr in string.h memory.h +do +trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'` +echo checking for ${hdr} +cat > conftest.c < +EOF +err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + { +test -n "$verbose" && \ +echo ' defining' ${trhdr} +DEFS="$DEFS -D${trhdr}=1" +} + +fi +rm -f conftest* +done + +echo checking for unistd.h +cat > conftest.c < +EOF +err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + { +test -n "$verbose" && \ +echo ' defining' HAVE_UNISTD_H +DEFS="$DEFS -DHAVE_UNISTD_H=1" +} + +fi +rm -f conftest* + + +echo checking for mode_t in sys/types.h +echo '#include ' > conftest.c +eval "$CPP \$DEFS conftest.c > conftest.out 2>&1" +if egrep "mode_t" conftest.out >/dev/null 2>&1; then + : +else + { +test -n "$verbose" && \ +echo ' defining' mode_t to be 'int' +DEFS="$DEFS -Dmode_t=int" +} + +fi +rm -f conftest* + +echo checking for pid_t in sys/types.h +echo '#include ' > conftest.c +eval "$CPP \$DEFS conftest.c > conftest.out 2>&1" +if egrep "pid_t" conftest.out >/dev/null 2>&1; then + : +else + { +test -n "$verbose" && \ +echo ' defining' pid_t to be 'int' +DEFS="$DEFS -Dpid_t=int" +} + +fi +rm -f conftest* + +echo checking for return type of signal handlers +cat > conftest.c < +#include +#ifdef signal +#undef signal +#endif +extern void (*signal ()) (); +int main() { exit(0); } +int t() { int i; } +EOF +if eval $compile; then + { +test -n "$verbose" && \ +echo ' defining' RETSIGTYPE to be 'void' +DEFS="$DEFS -DRETSIGTYPE=void" +} + +else + { +test -n "$verbose" && \ +echo ' defining' RETSIGTYPE to be 'int' +DEFS="$DEFS -DRETSIGTYPE=int" +} + +fi +rm -f conftest* + + +echo checking for size_t in sys/types.h +echo '#include ' > conftest.c +eval "$CPP \$DEFS conftest.c > conftest.out 2>&1" +if egrep "size_t" conftest.out >/dev/null 2>&1; then + : +else + { +test -n "$verbose" && \ +echo ' defining' size_t to be 'unsigned' +DEFS="$DEFS -Dsize_t=unsigned" +} + +fi +rm -f conftest* + + +# aC_VPRINTF + +# aC_TIME_WITH_SYS_TIME +# aC_STRUCT_TM + +# aC_CHAR_UNSIGNED +echo checking for signed char declaration +cat > conftest.c </dev/null; then + : +else + { +test -n "$verbose" && \ +echo ' defining' NO_SIGNED_CHAR_DECL +DEFS="$DEFS -DNO_SIGNED_CHAR_DECL=1" +} + +fi +rm -f conftest* +echo checking for s_char in sys/types.h +echo '#include ' > conftest.c +eval "$CPP \$DEFS conftest.c > conftest.out 2>&1" +if egrep "s_char" conftest.out >/dev/null 2>&1; then + { +test -n "$verbose" && \ +echo ' defining' S_CHAR_DEFINED +DEFS="$DEFS -DS_CHAR_DEFINED=1" +} + +fi +rm -f conftest* + + +prog='/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +p = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25,17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +}' +echo checking for working const +cat > conftest.c < conftest.c < conftest.c < sizeof(int))); } +EOF +eval $compile +if test -s conftest && (./conftest; exit) 2>/dev/null; then + { +test -n "$verbose" && \ +echo ' defining' LONG to be 'int' +DEFS="$DEFS -DLONG=int" +} + { +test -n "$verbose" && \ +echo ' defining' U_LONG to be 'u_int' +DEFS="$DEFS -DU_LONG=u_int" +} + +fi +rm -f conftest* + +if test -n "$GCC"; then +{ +test -n "$verbose" && \ +echo ' defining' HAVE_LONG_DOUBLE +DEFS="$DEFS -DHAVE_LONG_DOUBLE=1" +} + +else +echo checking for long double +cat > conftest.c < conftest.c </dev/null; then + : +else + { +test -n "$verbose" && \ +echo ' defining' WORDS_BIGENDIAN +DEFS="$DEFS -DWORDS_BIGENDIAN=1" +} + +fi +rm -f conftest* + + +echo checking for restartable system calls +cat > conftest.c < +#include +ucatch (isig) { } +main () { + int i = fork (), status; + if (i == 0) { sleep (3); kill (getppid (), SIGINT); sleep (3); exit (0); } + signal (SIGINT, ucatch); + status = wait(&i); + if (status == -1) wait(&i); + exit (status == -1); +} + +EOF +eval $compile +if test -s conftest && (./conftest; exit) 2>/dev/null; then + { +test -n "$verbose" && \ +echo ' defining' HAVE_RESTARTABLE_SYSCALLS +DEFS="$DEFS -DHAVE_RESTARTABLE_SYSCALLS=1" +} + +fi +rm -f conftest* + + +havestreams="" +echo checking for sys/stream.h +cat > conftest.c < +EOF +err=`eval "($CPP \$DEFS conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + { +test -n "$verbose" && \ +echo ' defining' STREAM +DEFS="$DEFS -DSTREAM=1" +} + havestreams="1" +fi +rm -f conftest* + +echo checking clock options + +if test -f /dev/pps ; then + echo found ppsclk + DEFS="$DEFS -DPPSCLK" +fi +if test -f /dev/tpro ; then + echo found tpro + CLOCKDEFS="$CLOCKDEFS -DTPRO" +fi +if test -f /dev/irig ; then + echo found irig + CLOCKDEFS="$CLOCKDEFS -DIRIG" +fi + +echo TODO -- checking for adjtime/libadjtimed.a + +test -n "$useresolv" && { + LIBS_save="${LIBS}" +LIBS="${LIBS} -lresolv" +have_lib="" +echo checking for -lresolv +cat > conftest.c < conftest.c < conftest.c < conftest.c < conftest.c < conftest.c < conftest.c < config.status </dev/null | sed 1q`: +# +# $0 $* +PROGS='$PROGS' +CC='$CC' +CFLAGS='$CFLAGS' +LDFLAGS='$LDFLAGS' +CPP='$CPP' +RANLIB='$RANLIB' +bindir='$bindir' +AUTHDEFS='$AUTHDEFS' +CLOCKDEFS='$CLOCKDEFS' +COPTS='$COPTS' +INCLUDE='$INCLUDE' +LIB='$LIB' +ADJLIB='$ADJLIB' +RESLIB='$RESLIB' +COMPAT='$COMPAT' +LIBS='$LIBS' +srcdir='$srcdir' +DEFS='$DEFS' +prefix='$prefix' +exec_prefix='$exec_prefix' +prsub='$prsub' +EOF + diff --git a/contrib/xntpd/scripts/install.sh b/contrib/xntpd/scripts/install.sh new file mode 100644 index 0000000000..5dd98315d8 --- /dev/null +++ b/contrib/xntpd/scripts/install.sh @@ -0,0 +1,100 @@ +#!/bin/sh +# +# Emulate the BSD install command with cpset for System V +# Tom Moore - NCR Corporation +# +PATH=/bin:/etc:/usr/bin:/usr/ucb +export PATH + +# Default values +mode=0755 +owner=bin +group=bin +strip=FALSE +remove=TRUE + +USAGE="install [-s] [-c] [-m mode] [-o owner] [-g group] source file|directory" +set -- `getopt scm:o:g: $*` || { + echo $USAGE >&2 + exit 2 +} +for option in $* +do + case $option in + -s) # Strip the installed file + strip=TRUE + shift + ;; + -c) # Copy the source file rather than move it + remove=FALSE + shift + ;; + -m) # File mode + mode=$2 + shift 2 + ;; + -o) # File owner + owner=$2 + shift 2 + ;; + -g) # File group + group=$2 + shift 2 + ;; + --) # End of options + shift + break + ;; + esac +done + +case $# in +0) echo "install: no file or destination specified" >&2 + exit 2 + ;; +1) echo "install: no destination specified" >&2 + exit 2 + ;; +2) source=$1 + destination=$2 + ;; +*) echo "install: too many files specified" >&2 + exit 2 + ;; +esac + +[ $source = $destination -o $destination = . ] && { + echo "install: can't move $source onto itself" >&2 + exit 1 +} + +[ -f $source ] || { + echo "install: can't open $source" >&2 + exit 1 +} + +if [ -d $destination ] +then + file=`basename $source` + OLDdestination=$destination/OLD$file + destination=$destination/$file +else + dir=`dirname $destination` + file=`basename $destination` + OLDdestination=$dir/OLD$file +fi + +(cp $source $destination && + chmod $mode $destination && + chown $owner $destination && + chgrp $group $destination) || exit 1 + +# /bin/rm -f $OLDdestination + +[ $strip = TRUE ] && + strip $destination + +[ $remove = TRUE ] && + rm -f $source + +exit 0 diff --git a/contrib/xntpd/scripts/makeconfig.sh b/contrib/xntpd/scripts/makeconfig.sh new file mode 100644 index 0000000000..8842a86c6c --- /dev/null +++ b/contrib/xntpd/scripts/makeconfig.sh @@ -0,0 +1,85 @@ +#!/bin/sh + +MACHINE=${1-${OS}} +COMPILER=${2-${CC}} + +# +# Figure out which compiler to use. Stolen from Jeff Johnson. +# +if [ "0$COMPILER" = "0" ]; then + COMPILER="cc" + set dummy gcc; word=$2 + IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/$word; then + COMPILER="gcc" + break + fi + done + IFS="$saveifs" +fi + +# +# Figure out the byte order and word size. +# +if (cd util && rm -f longsize && $COMPILER -o longsize longsize.c ); then + if util/longsize >/dev/null 2>&1; then + LONG=`util/longsize` + else + echo "TROUBLE: executables built by your compiler don't work - bug your vendor" + exit 1 + fi +else + echo "TROUBLE: could not compile !" + echo "TROUBLE: either your compiler does not work / is not present" + echo "TROUBLE: or you have mangled the file tree" + exit 1 +fi +(cd util && rm -f byteorder && $COMPILER -o byteorder byteorder.c $LONG ) +BYTE=`util/byteorder ` +if [ "0$BYTE" = "0" ]; then + BYTE="XNTP_BIG_ENDIAN" +fi +(cd util && rm -f byteorder longsize) + +# +# Figure out which machine we have. +# +if [ "0$MACHINE" = "0" ]; then + GUESS=`scripts/Guess.sh` + if [ "0$GUESS" = "0none" ]; then + echo ' ' + echo "I don't know your system!" + echo "I do know about the following systems:" + (cd machines && ls -C *) + echo "Choose a system and type \"make OS=\"" + exit 1 + else + if [ -f machines/$GUESS ]; then + MACHINE=$GUESS + else + if [ -f machines/$GUESS.posix ]; then + MACHINE="$GUESS.posix" + else + MACHINE="$GUESS.bsd" + fi + fi + fi +fi + +echo "Configuring machines/$MACHINE compilers/$MACHINE.$COMPILER" + +if [ -f machines/$MACHINE ]; then + cat machines/$MACHINE >Config ; + if [ -f compilers/$MACHINE.$COMPILER ]; then + cat compilers/$MACHINE.$COMPILER >>Config + else + echo "COMPILER= $COMPILER" >>Config + fi + echo "LIBDEFS= -D$BYTE" >>Config + cat Config.local >>Config +else + echo "Don't know how to build xntpd for machine $MACHINE " ; + exit 1 +fi diff --git a/contrib/xntpd/scripts/mklinks b/contrib/xntpd/scripts/mklinks new file mode 100644 index 0000000000..8565d1ca35 --- /dev/null +++ b/contrib/xntpd/scripts/mklinks @@ -0,0 +1,9 @@ +#!/bin/sh +# call from the source root as 'mklinks ../sun4 ../src' +find . -type d -print | sort | sed "s-^\.-mkdir $1-" | sh +root=`echo $2 | sed "s-^\.\./--"` +find . ! -type d -a ! -name Config -print | sed "s-^\./--" | while read file + do + down=`echo $file | sed -e "s-[^/]*-..-g"` + ln -s $down/$root/$file $1/$file + done diff --git a/contrib/xntpd/scripts/mkversion b/contrib/xntpd/scripts/mkversion new file mode 100644 index 0000000000..07dbb775e1 --- /dev/null +++ b/contrib/xntpd/scripts/mkversion @@ -0,0 +1,33 @@ +#!/bin/sh - +PROG=${1-UNKNOWN} +if [ ! -f .version ]; then + echo 0 > .version +fi + +RUN="`cat .version`" +RUN="`expr $RUN + 1`" +echo $RUN > .version + +DATE="`date`" + +if [ -r VERSION ]; then + VERSION=VERSION +else + VERSION=../VERSION +fi + +if [ -f "$VERSION" ]; then + FLAGS="`egrep '^[0-9a-zA-Z_]+=' "$VERSION" | tr '\012' ';'` " +else + FLAGS="" +fi + +echo "Version $PROG ${FLAGS}${DATE} (${RUN})"; + +rm -f version.c +cat > version.c << -EoF- +/* + * version file for $PROG + */ +char * Version = "$PROG ${FLAGS}${DATE} (${RUN})"; +-EoF- diff --git a/contrib/xntpd/scripts/monitoring/README b/contrib/xntpd/scripts/monitoring/README new file mode 100644 index 0000000000..fa8ad8bb95 --- /dev/null +++ b/contrib/xntpd/scripts/monitoring/README @@ -0,0 +1,154 @@ +This directory contains support for monitoring the local clock of xntp daemons. + +WARNING: The scripts and routines contained in this directory are bete realease! + Do not depend on their correct operation. They are, however, in regular + use at University of Erlangen-Nuernberg. No severe problems are known + for this code. + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +PLEASE THINK TWICE BEFORE STARTING MONITORING REMOTE XNTP DEAMONS !!!! +MONITORING MAY INCREASE THE LOAD OF THE DEAMON MONITORED AND MAY +INCREASE THE NETWORK LOAD SIGNIFICANTLY +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +Files are: + +README: + This file + +ntptrap: + perl script to log ntp mode 6 trap messages. + + It sends a set_trap request to each server given and dumps the + trap messages received. It handles refresh of set_trap. + Currently it handles only NTP V2, however the NTP V3 servers + also accept v2 requests. It will not interpret v3 system and peer + stati correctly. + + usage: + ntptrap [-n] [-p ] [-l ] servers... + + -n: do not send set_trap requests + + port: port to listen for responses + useful if you have a configured trap + + debug-output: file to write trace output to (for debugging) + + This script convinced me that ntp trap messages are only of + little use. + +ntploopstat: + perl script to gather loop info statistics from xntpd via mode 7 + LOOP_INFO requests. + + This script collects data to allow monitoring of remote xntp servers + where it is not possible to directly access the loopstats file + produced by xntpd itself. Of course, it can be used to sample + a local server if it is not configured to produce a loopstats file. + + Please note, this program poses a high load on the server as + a communication takes place every delay seconds ! USE WITH CARE ! + + usage: + ntploopstat [-d] [-t] [-l ] [-v] [ntpserver] + + delay: number of seconds to wait between samples + default: 60 seconds + timeout: number of seconds to wait for reply + default 12 seconds + logfile: file to log samples to + default: loopstats:: + (note the trailing colon) + This name actually is a prefix. + The file name is dynamically derived by appending + the name of the month the sample belongs to. + Thus all samples of a month end up in the same file. + + the format of the files generated is identical to the format used by + xntpd with the loopstats file: + MJD offset frequency compliance + + if a timeout occurs the next sample is tried after delay/2 seconds + + The script will terminate after MAX_FAIL (currently 60) consecutive errors. + Errors are counted for: + - error on send call + - error on select call + - error on recv call + - short packet received + - bad packet + - error on open for logfile + +ntploopwatch: + perl script to display loop filter statistics collected by ntploopstat + or dumped directly by xntpd. + + Gnuplot is used to produce a graphical representation of the sample + values, that have been preprocessed and analysed by this script. + + It can either be called to produce a printout of specific data set or + used to continously monitor the values. Monitoring is achieved by + periodically reprocessing the logfiles, which are updated regularly + either by a running ntploopstat process or by the running xntpd. + + usage: + to watch statistics permanently: + ntploopwatch [-v[]] [-c ] [-d ] + + to get a single print out specify also + -P [-s] + [-S ] [-E ] + [-O ] [-o ] + + level: level of verbosity for debugging + config-file: file to read configurable settings from + On each iteration it is checked and reread + if it has been changed + default: loopwatch.config + working-dir: specify working directory for process, affects + interpretation of relative file names + + All other flags are only useful with printing plots, as otherwise + command line values would be replaced by settings from the config file. + + printer: specify printer to print plot + BSD print systems semantics apply; if printer is omitted + the name "ps" is used; plots are prepared using + PostScript, thus the printer should best accept + postscript input + + For the following see also the comments in loopwatch.config.SAMPLE + + samples: use last # samples from input data + start-time: ignore input samples before this date + end-time: ignore input samples after this date + if both start-time and end-time are specified + a given samples value is ignored + MaxOffs: + MinOffs: restrict value range + +loopwatch.config.SAMPLE: + sample config file for ntploopwatch + each configurable option is explained there + +lr.pl: + linear regression package used by ntploopwatch to compute + linear approximations for frequency and offset values + within display range + +timelocal.pl: + used during conversion of ISO_DATE_TIME values specified in loopwatch + config files to unix epoch values (seconds since 1970-01-01_00:00_00 UTC) + + A version of this file is distributed with perl-4.x, however, + it has a bug related to dates crossing 1970, causing endless loops.. + The version contained here has been fixed. + +ntp.pl: + perl support for ntp v2 mode 6 message handling + WARNING: This code is beta level - it triggers a memory leak; + as for now it is not quite clear, wether this is caused by a + bug in perl or by bad usage of perl within this script. + diff --git a/contrib/xntpd/scripts/monitoring/loopwatch.config.SAMPLE b/contrib/xntpd/scripts/monitoring/loopwatch.config.SAMPLE new file mode 100644 index 0000000000..8cefea395d --- /dev/null +++ b/contrib/xntpd/scripts/monitoring/loopwatch.config.SAMPLE @@ -0,0 +1,89 @@ +# sample configuration and control file for ntploowatch +# +# delay: sampling interval in seconds +delay=60 +# samples: use only last # samples +samples=600 +# DO NOT USE srcprefix in shared config files +# srcprefix: name of file to read samples from +# current time suffix (month name) is appended +# defaults to "./var@$STATHOST/loopstats." +# The string "$STATHOST"is replaced by the name of the host +# being monitored +#srcprefix=./var@$STATHOST/loopstats. +# +# showoffs: yes/no control display of offset values +showoffs=yes +# +# showfreq: yes/no control display of frequency values +showfreq=yes +# +# showcmpl: yes/no control display of compliance values +showcmpl=no +# +# showoreg: yes/no control display of linear regression of offset values +showoreg=no +# +# showfreg: yes/no control display of linear regression of frequency values +showfreg=no +# +# timebase: dynamic/ISO_DATE_TIME point of zero for linear regression +# ISO_DATE_TIME: yyyy-mm-dd_hh:mm:ss.ms +# values are interpreted using local time zone +# parts omitted from front default to current date/time +# parts omitted from end default to lowest permitted values +# to get aa:bb being interpreted as minutes:seconds use aa:bb.0 +# for dynamic '00:00:00.0 of current day' is used +timebase=dynamic +# +# freqbase: dynamic/ +# if a number is given, subtract this from sampling values for display +# if dynamic is selected, freqbase is adjusted to fit into the range of +# offset values +freqbase=dynamic +# +# cmplscale: dynamic/ +# if a number is given, the sampling values are divided by this number +# if dynamic is selected, cmplscale is adjusted to fit into the range of +# offset values +cmplscale=dynamic +# +# DumbScale: 0/1 +# 0 enables dynamic adjust of value ranges for freqbase and cmplscale +# timescale is labeled with human readable times +# 1 only uses explicit scaling for numbers +# timescale is labeled with hours relative to timebase +DumbScale=0 +# +# StartTime: none/ISO_DATE_TIME +# ignore any samples before the specified date +StartTime=none +# +# EndTime: none/ISO_DATE_TIME +# ignore any samples after the specified date +# +# if both StartTime and EndTime are specified +# the value specified for samples is ignored +EndTime=none +# +# MaxOffs: none/ +# limit display (y-axis) to values not larger than +MaxOffset=none +# +# MinOffs: none/ +# limit display (y-axis) to values not smaller than +MinOffset=none + +# +# verbose: +# specify level for debugging +# default is 0 for printing and 1 for monitoring +# level 1 will just print a timestamp for any display update +# (this is every delay seconds) +verbose=1 +# +# deltaT: +# mark `holes' in the sample data grater than +# by a break in the plot +# default: 512 seconds +deltaT=512 diff --git a/contrib/xntpd/scripts/monitoring/lr.pl b/contrib/xntpd/scripts/monitoring/lr.pl new file mode 100644 index 0000000000..02c7550ec3 --- /dev/null +++ b/contrib/xntpd/scripts/monitoring/lr.pl @@ -0,0 +1,145 @@ +;# +;# lr.pl,v 3.1 1993/07/06 01:09:08 jbj Exp +;# +;# +;# Linear Regression Package for perl +;# to be 'required' from perl +;# +;# Copyright (c) 1992 +;# Frank Kardel, Rainer Pruy +;# Friedrich-Alexander Universitaet Erlangen-Nuernberg +;# +;# +;############################################################# + +## +## y = A + Bx +## +## B = (n * Sum(xy) - Sum(x) * Sum(y)) / (n * Sum(x^2) - Sum(x)^2) +## +## A = (Sum(y) - B * Sum(x)) / n +## + +## +## interface +## +*lr_init = *lr'lr_init; #';# &lr_init(tag); initialize data set for tag +*lr_sample = *lr'lr_sample; #';# &lr_sample(x,y,tag); enter sample +*lr_Y = *lr'lr_Y; #';# &lr_Y(x,tag); compute y for given x +*lr_X = *lr'lr_X; #';# &lr_X(y,tag); compute x for given y +*lr_r = *lr'lr_r; #';# &lr_r(tag); regression coeffizient +*lr_cov = *lr'lr_cov; #';# &lr_cov(tag); covariance +*lr_A = *lr'lr_A; #';# &lr_A(tag); +*lr_B = *lr'lr_B; #';# &lr_B(tag); +*lr_sigma = *lr'lr_sigma; #';# &lr_sigma(tag); standard deviation +*lr_mean = *lr'lr_mean; #';# &lr_mean(tag); +######################### + +package lr; + +sub tagify +{ + local($tag) = @_; + if (defined($tag)) + { + *lr_n = eval "*${tag}_n"; + *lr_sx = eval "*${tag}_sx"; + *lr_sx2 = eval "*${tag}_sx2"; + *lr_sxy = eval "*${tag}_sxy"; + *lr_sy = eval "*${tag}_sy"; + *lr_sy2 = eval "*${tag}_sy2"; + } +} + +sub lr_init +{ + &tagify($_[$[]) if defined($_[$[]); + + $lr_n = 0; + $lr_sx = 0.0; + $lr_sx2 = 0.0; + $lr_sxy = 0.0; + $lr_sy = 0.0; + $lr_sy2 = 0.0; +} + +sub lr_sample +{ + local($_x, $_y) = @_; + + &tagify($_[$[+2]) if defined($_[$[+2]); + + $lr_n++; + $lr_sx += $_x; + $lr_sy += $_y; + $lr_sxy += $_x * $_y; + $lr_sx2 += $_x**2; + $lr_sy2 += $_y**2; +} + +sub lr_B +{ + &tagify($_[$[]) if defined($_[$[]); + + return 1 unless ($lr_n * $lr_sx2 - $lr_sx**2); + return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / ($lr_n * $lr_sx2 - $lr_sx**2); +} + +sub lr_A +{ + &tagify($_[$[]) if defined($_[$[]); + + return ($lr_sy - &lr_B * $lr_sx) / $lr_n; +} + +sub lr_Y +{ + &tagify($_[$[]) if defined($_[$[]); + + return &lr_A + &lr_B * $_[$[]; +} + +sub lr_X +{ + &tagify($_[$[]) if defined($_[$[]); + + return ($_[$[] - &lr_A) / &lr_B; +} + +sub lr_r +{ + &tagify($_[$[]) if defined($_[$[]); + + local($s) = ($lr_n * $lr_sx2 - $lr_sx**2) * ($lr_n * $lr_sy2 - $lr_sy**2); + + return 1 unless $s; + + return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / sqrt($s); +} + +sub lr_cov +{ + &tagify($_[$[]) if defined($_[$[]); + + return ($lr_sxy - $lr_sx * $lr_sy / $lr_n) / ($lr_n - 1); +} + +sub lr_sigma +{ + &tagify($_[$[]) if defined($_[$[]); + + return 0 if $lr_n <= 1; + return sqrt(($lr_sy2 - ($lr_sy * $lr_sy) / $lr_n) / ($lr_n)); +} + +sub lr_mean +{ + &tagify($_[$[]) if defined($_[$[]); + + return 0 if $lr_n <= 0; + return $lr_sy / $lr_n; +} + +&lr_init(); + +1; diff --git a/contrib/xntpd/scripts/monitoring/ntp.pl b/contrib/xntpd/scripts/monitoring/ntp.pl new file mode 100644 index 0000000000..f3bfd2bfe0 --- /dev/null +++ b/contrib/xntpd/scripts/monitoring/ntp.pl @@ -0,0 +1,477 @@ +#!/local/bin/perl +;# +;# ntp.pl,v 3.1 1993/07/06 01:09:09 jbj Exp +;# +;# process loop filter statistics file and either +;# - show statistics periodically using gnuplot +;# - or print a single plot +;# +;# Copyright (c) 1992 +;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg +;# +;# +;############################################################# + +package ntp; + +$NTP_version = 2; +$ctrl_mode=6; + +$byte1 = (($NTP_version & 0x7)<< 3) & 0x34 | ($ctrl_mode & 0x7); +$MAX_DATA = 468; + +$sequence = 0; # initial sequence number incred before used +$pad=4; +$do_auth=0; # no possibility today +$keyid=0; +;#list if known keys (passwords) +%KEYS = ( 0, "\200\200\200\200\200\200\200\200", + ); + +;#----------------------------------------------------------------------------- +;# access routines for ntp control packet + ;# NTP control message format + ;# C LI|VN|MODE LI 2bit=00 VN 3bit=2(3) MODE 3bit=6 : $byte1 + ;# C R|E|M|Op R response E error M more Op opcode + ;# n sequence + ;# n status + ;# n associd + ;# n offset + ;# n count + ;# a+ data (+ padding) + ;# optional authentication data + ;# N key + ;# N2 checksum + +;# first bye of packet +sub pkt_LI { return ($_[$[] >> 6) & 0x3; } +sub pkt_VN { return ($_[$[] >> 3) & 0x7; } +sub pkt_MODE { return ($_[$[] ) & 0x7; } + +;# second byte of packet +sub pkt_R { return ($_[$[] & 0x80) == 0x80; } +sub pkt_E { return ($_[$[] & 0x40) == 0x40; } +sub pkt_M { return ($_[$[] & 0x20) == 0x20; } +sub pkt_OP { return $_[$[] & 0x1f; } + +;#----------------------------------------------------------------------------- + +sub setkey +{ + local($id,$key) = @_; + + $KEYS{$id} = $key if (defined($key)); + if (! defined($KEYS{$id})) + { + warn "Key $id not yet specified - key not changed\n"; + return undef; + } + return ($keyid,$keyid = $id)[$[]; +} + +;#----------------------------------------------------------------------------- +sub numerical { $a <=> $b; } + +;#----------------------------------------------------------------------------- + +sub send #' +{ + local($fh,$opcode, $associd, $data,$address) = @_; + $fh = caller(0)."'$fh"; + + local($junksize,$junk,$packet,$offset,$ret); + $offset = 0; + + $sequence++; + while(1) + { + $junksize = length($data); + $junksize = $MAX_DATA if $junksize > $MAX_DATA; + + ($junk,$data) = $data =~ /^(.{$junksize})(.*)$/; + $packet + = pack("C2n5a".(($junk eq "") ? 0 : &pad($junksize+12,$pad)-12), + $byte1, + ($opcode & 0x1f) | ($data ? 0x20 : 0), + $sequence, + 0, $associd, + $offset, $junksize, $junk); + if ($do_auth) + { + ;# not yet + } + $offset += $junksize; + + if (defined($address)) + { + $ret = send($fh, $packet, 0, $address); + } + else + { + $ret = send($fh, $packet, 0); + } + + if (! defined($ret)) + { + warn "send failed: $!\n"; + return undef; + } + elsif ($ret != length($packet)) + { + warn "send failed: sent only $ret from ".length($packet). "bytes\n"; + return undef; + } + return $sequence unless $data; + } +} + +;#----------------------------------------------------------------------------- +;# status interpretation +;# +sub getval +{ + local($val,*list) = @_; + + return $list{$val} if defined($list{$val}); + return sprintf("%s#%d",$list{"-"},$val) if defined($list{"-"}); + return "unknown-$val"; +} + +;#--------------------------------- +;# system status +;# +;# format: |LI|CS|SECnt|SECode| LI=2bit CS=6bit SECnt=4bit SECode=4bit +sub ssw_LI { return ($_[$[] >> 14) & 0x3; } +sub ssw_CS { return ($_[$[] >> 8) & 0x3f; } +sub ssw_SECnt { return ($_[$[] >> 4) & 0xf; } +sub ssw_SECode { return $_[$[] & 0xf; } + +%LI = ( 0, "leap_none", 1, "leap_add_sec", 2, "leap_del_sec", 3, "sync_alarm", "-", "leap"); +%ClockSource = (0, "sync_unspec", + 1, "sync_lf_clock", + 2, "sync_uhf_clock", + 3, "sync_hf_clock", + 4, "sync_local_proto", + 5, "sync_ntp", + 6, "sync_udp/time", + 7, "sync_wristwatch", + "-", "ClockSource", + ); + +%SystemEvent = (0, "event_unspec", + 1, "event_restart", + 2, "event_fault", + 3, "event_sync_chg", + 4, "event_sync/strat_chg", + 5, "event_clock_reset", + 6, "event_bad_date", + 7, "event_clock_excptn", + "-", "event", + ); +sub LI +{ + &getval(&ssw_LI($_[$[]),*LI); +} +sub ClockSource +{ + &getval(&ssw_CS($_[$[]),*ClockSource); +} + +sub SystemEvent +{ + &getval(&ssw_SECode($_[$[]),*SystemEvent); +} + +sub system_status +{ + return sprintf("%s, %s, %d event%s, %s", &LI($_[$[]), &ClockSource($_[$[]), + &ssw_SECnt($_[$[]), ((&ssw_SECnt($_[$[])==1) ? "" : "s"), + &SystemEvent($_[$[])); +} +;#--------------------------------- +;# peer status +;# +;# format: |PStat|PSel|PCnt|PCode| Pstat=6bit PSel=2bit PCnt=4bit PCode=4bit +sub psw_PStat_config { return ($_[$[] & 0x8000) == 0x8000; } +sub psw_PStat_authenable { return ($_[$[] & 0x4000) == 0x4000; } +sub psw_PStat_authentic { return ($_[$[] & 0x2000) == 0x2000; } +sub psw_PStat_reach { return ($_[$[] & 0x1000) == 0x1000; } +sub psw_PStat_sane { return ($_[$[] & 0x0800) == 0x0800; } +sub psw_PStat_dispok { return ($_[$[] & 0x0400) == 0x0400; } +sub psw_PStat { return ($_[$[] >> 10) & 0x3f; } +sub psw_PSel { return ($_[$[] >> 8) & 0x3; } +sub psw_PCnt { return ($_[$[] >> 4) & 0xf; } +sub psw_PCode { return $_[$[] & 0xf; } + +%PeerSelection = (0, "sel_reject", + 1, "sel_candidate", + 2, "sel_selcand", + 3, "sel_sys.peer", + "-", "PeerSel", + ); +%PeerEvent = (0, "event_unspec", + 1, "event_ip_err", + 2, "event_authen", + 3, "event_unreach", + 4, "event_reach", + 5, "event_clock_excptn", + 6, "event_stratum_chg", + "-", "event", + ); + +sub PeerSelection +{ + &getval(&psw_PSel($_[$[]),*PeerSelection); +} +sub PeerEvent +{ + &getval(&psw_PCode($_[$[]),*PeerEvent); +} + +sub peer_status +{ + local($x) = (""); + $x .= "config," if &psw_PStat_config($_[$[]); + $x .= "authenable," if &psw_PStat_authenable($_[$[]); + $x .= "authentic," if &psw_PStat_authentic($_[$[]); + $x .= "reach," if &psw_PStat_reach($_[$[]); + $x .= &psw_PStat_sane($_[$[]) ? "sane," : "insane,"; + $x .= "hi_disp," unless &psw_PStat_dispok($_[$[]); + + $x .= sprintf(" %s, %d event%s, %s", &PeerSelection($_[$[]), + &psw_PCnt($_[$[]), ((&psw_PCnt($_[$[]) == 1) ? "" : "s"), + &PeerEvent($_[$[])); + return $x; +} + +;#--------------------------------- +;# clock status +;# +;# format: |CStat|CEvnt| CStat=8bit CEvnt=8bit +sub csw_CStat { return ($_[$[] >> 8) & 0xff; } +sub csw_CEvnt { return $_[$[] & 0xff; } + +%ClockStatus = (0, "clk_nominal", + 1, "clk_timeout", + 2, "clk_badreply", + 3, "clk_fault", + 4, "clk_prop", + 5, "clk_baddate", + 6, "clk_badtime", + "-", "clk", + ); + +sub clock_status +{ + return sprintf("%s, last %s", + &getval(&csw_CStat($_[$[]),*ClockStatus), + &getval(&csw_CEvnt($_[$[]),*ClockStatus)); +} + +;#--------------------------------- +;# error status +;# +;# format: |Err|reserved| Err=8bit +;# +sub esw_Err { return ($_[$[] >> 8) & 0xff; } + +%ErrorStatus = (0, "err_unspec", + 1, "err_auth_fail", + 2, "err_invalid_fmt", + 3, "err_invalid_opcode", + 4, "err_unknown_assoc", + 5, "err_unknown_var", + 6, "err_invalid_value", + 7, "err_adm_prohibit", + ); + +sub error_status +{ + return sprintf("%s", &getval(&esw_Err($_[$[]),*ErrorStatus)); +} + +;#----------------------------------------------------------------------------- +;# +;# cntrl op name translation + +%CntrlOpName = (1, "read_status", + 2, "read_variables", + 3, "write_variables", + 4, "read_clock_variables", + 5, "write_clock_variables", + 6, "set_trap", + 7, "trap_response", + 31, "unset_trap", # !!! unofficial !!! + "-", "cntrlop", + ); + +sub cntrlop_name +{ + return &getval($_[$[],*CntrlOpName); +} + +;#----------------------------------------------------------------------------- + +$STAT_short_pkt = 0; +$STAT_pkt = 0; + +;# process a NTP control message (response) packet +;# returns a list ($ret,$data,$status,$associd,$op,$seq,$auth_keyid) +;# $ret: undef --> not yet complete +;# "" --> complete packet received +;# "ERROR" --> error during receive, bad packet, ... +;# else --> error packet - list may contain useful info + + +sub handle_packet +{ + local($pkt,$from) = @_; # parameters + local($len_pkt) = (length($pkt)); +;# local(*FRAGS,*lastseen); + local($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data); + local($autch_keyid,$auth_cksum); + + $STAT_pkt++; + if ($len_pkt < 12) + { + $STAT_short_pkt++; + return ("ERROR","short packet received"); + } + + ;# now break packet apart + ($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data) = + unpack("C2n5a".($len_pkt-12),$pkt); + $data=substr($data,$[,$count); + if ((($len_pkt - 12) - &pad($count,4)) >= 12) + { + ;# looks like an authenticator + ($auth_keyid,$auth_cksum) = + unpack("Na8",substr($pkt,$len_pkt-12+$[,12)); + $STAT_auth++; + ;# no checking of auth_cksum (yet ?) + } + + if (&pkt_VN($li_vn_mode) != $NTP_version) + { + $STAT_bad_version++; + return ("ERROR","version ".&pkt_VN($li_vn_mode)."packet ignored"); + } + + if (&pkt_MODE($li_vn_mode) != $ctrl_mode) + { + $STAT_bad_mode++; + return ("ERROR", "mode ".&pkt_MODE($li_vn_mode)." packet ignored"); + } + + ;# handle single fragment fast + if ($offset == 0 && &pkt_M($r_e_m_op) == 0) + { + $STAT_single_frag++; + if (&pkt_E($r_e_m_op)) + { + $STAT_err_pkt++; + return (&error_status($status), + $data,$status,$associd,&pkt_OP($r_e_m_op),$seq, + $auth_keyid); + } + else + { + return ("", + $data,$status,$associd,&pkt_OP($r_e_m_op),$seq, + $auth_keyid); + } + } + else + { + ;# fragment - set up local name space + $id = "$from$seq".&pkt_OP($r_e_m_op); + $ID{$id} = 1; + *FRAGS = "$id FRAGS"; + *lastseen = "$id lastseen"; + + $STAT_frag++; + + $lastseen = 1 if !&pkt_M($r_e_m_op); + if (!defined(%FRAGS)) + { + (&pkt_M($r_e_m_op) ? " more" : "")."\n"; + $FRAGS{$offset} = $data; + ;# save other info + @FRAGS = ($status,$associd,&pkt_OP($r_e_m_op),$seq,$auth_keyid,$r_e_m_op); + } + else + { + (&pkt_M($r_e_m_op) ? " more" : "")."\n"; + ;# add frag to previous - combine on the fly + if (defined($FRAGS{$offset})) + { + $STAT_dup_frag++; + return ("ERROR","duplicate fragment at $offset seq=$seq"); + } + + $FRAGS{$offset} = $data; + + undef($loff); + foreach $off (sort numerical keys(%FRAGS)) + { + next unless defined($FRAGS{$off}); + if (defined($loff) && + ($loff + length($FRAGS{$loff})) == $off) + { + $FRAGS{$loff} .= $FRAGS{$off}; + delete $FRAGS{$off}; + last; + } + $loff = $off; + } + + ;# return packet if all frags arrived + ;# at most two frags with possible padding ??? + if ($lastseen && defined($FRAGS{0}) && + scalar(@x=sort numerical keys(%FRAGS)) <= 2 && + (length($FRAGS{0}) + 8) > $x[$[+1]) + { + @x=((&pkt_E($r_e_m_op) ? &error_status($status) : ""), + $FRAGS{0},@FRAGS); + &pkt_E($r_e_m_op) ? $STAT_err_frag++ : $STAT_frag_all++; + undef(%FRAGS); + undef(@FRAGS); + undef($lastseen); + delete $ID{$id}; + &main'clear_timeout($id); + return @x; + } + else + { + &main'set_timeout($id,time+$timeout,"&ntp'handle_packet_timeout(\"".unpack("H*",$id)."\");"); #'"; + } + } + return (undef); + } +} + +sub handle_packet_timeout +{ + local($id) = @_; + local($r_e_m_op,*FRAGS,*lastseen,@x) = (@FRAGS[$[+5]); + + *FRAGS = "$id FRAGS"; + *lastseen = "$id lastseen"; + + @x=((&pkt_E($r_e_m_op) ? &error_status($status) : "TIMEOUT"), + $FRAGS{0},@FRAGS[$[ .. $[+4]); + $STAT_frag_timeout++; + undef(%FRAGS); + undef(@FRAGS); + undef($lastseen); + delete $ID{$id}; + return @x; +} + + +sub pad +{ + return $_[$[+1] * int(($_[$[] + $_[$[+1] - 1) / $_[$[+1]); +} + +1; diff --git a/contrib/xntpd/scripts/monitoring/ntploopstat b/contrib/xntpd/scripts/monitoring/ntploopstat new file mode 100644 index 0000000000..75cdff227b --- /dev/null +++ b/contrib/xntpd/scripts/monitoring/ntploopstat @@ -0,0 +1,457 @@ +#!/local/bin/perl -w--*-perl-*- +;# +;# ntploopstat,v 3.1 1993/07/06 01:09:11 jbj Exp +;# +;# Poll NTP server using NTP mode 7 loopinfo request. +;# Log info and timestamp to file for processing by ntploopwatch. +;# +;# +;# Copyright (c) 1992 +;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg +;# +;################################################################# +;# +;# The format written to the logfile is the same as used by xntpd +;# for the loopstats file. +;# This script however allows to gather loop filter statistics from +;# remote servers where you do not have access to the loopstats logfile. +;# +;# Please note: Communication delays affect the accuracy of the +;# timestamps recorded. Effects from these delays will probably +;# not show up, as timestamps are recorded to the second only. +;# (Should have implemented &gettimeofday()..) +;# + +$0 =~ s!^.*/([^/]+)$!\1!; # beautify script name + +$ntpserver = 'localhost'; # default host to poll +$delay = 60; # default sampling rate + ;# keep it shorter than minpoll (=64) + ;# to get all values + +require "ctime.pl"; +;# handle bug in early ctime distributions +$ENV{'TZ'} = 'MET' unless defined($ENV{'TZ'}) || $] > 4.010; + +if (defined(@ctime'MoY)) +{ + *MonthName = *ctime'MoY; +} +else +{ + @MonthName = ('Jan','Feb','Mar','Apr','May','Jun', + 'Jul','Aug','Sep','Oct','Nov','Dec'); +} + +;# this routine can be redefined to point to syslog if necessary +sub msg +{ + return unless $verbose; + + print STDERR "$0: "; + printf STDERR @_; +} + +;############################################################# +;# +;# process command line +$usage = <<"E-O-S"; + +usage: + $0 [-d] [-t] [-l ] [-v] [ntpserver] +E-O-S + +while($_ = shift) +{ + /^-v(\d*)$/ && ($verbose=($1 eq '') ? 1 : $1,1) && next; + /^-d(\d*)$/ && + do { + ($1 ne '') && ($delay = $1,1) && next; + @ARGV || die("$0: delay value missing after -d\n$usage"); + $delay = shift; + ($delay >= 0) || die("$0: bad delay value \"$delay\"\n$usage"); + next; + }; + /^-l$/ && + do { + @ARGV || die("$0: logfile missing after -l\n$usage"); + $logfile = shift; + next; + }; + /^-t(\d*(\.\d*)?)$/ && + do { + ($1 ne '') && ($timeout = $1,1) && next; + @ARGV || die("$0: timeout value missing after -t\n$usage\n"); + $timeout = shift; + ($timeout > 0) || + die("$0: bad timeout value \"$timeout\"\n$usage"); + next; + }; + + /^-/ && die("$0: unknown option \"$_\"\n$usage"); + + ;# any other argument is server to poll + $ntpserver = $_; + last; +} + +if (@ARGV) +{ + warn("unexpected arguments: ".join(" ",@ARGV).".\n"); + die("$0: too many servers specified\n$usage"); +} + +;# logfile defaults to include server name +;# The name of the current month is appended and +;# the file is opened and closed for each sample. +;# +$logfile = "loopstats:$ntpserver." unless defined($logfile); +$timeout = 12.0 unless defined($timeout); # wait $timeout seconds for reply + +$MAX_FAIL = 60; # give up after $MAX_FAIL failed polls + + +$MJD_1970 = 40587; + +if (eval 'require "syscall.ph";') +{ + if (defined(&SYS_gettimeofday)) + { + ;# assume standard + ;# gettimeofday(struct timeval *tp,struct timezone *tzp) + ;# syntax for gettimeofday syscall + ;# tzp = NULL -> undef + ;# tp = (long,long) + eval 'sub time { local($tz) = pack("LL",0,0); + (&msg("gettimeofday failed: $!\n"), + return (time)) + unless syscall(&SYS_gettimeofday,$tz,undef) == 0; + local($s,$us) = unpack("LL",$tz); + return $s + $us/1000000; }'; + local($t1,$t2,$t3); + $t1 = time; + eval '$t2 = &time;'; + $t3 = time; + die("$0: gettimeofday failed: $@.\n") if defined($@) && $@; + die("$0: gettimeofday inconsistency time=$t1,gettimeofday=$t2,time=$t2\n") + if (int($t1) != int($t2) && int($t3) != int($t2)); + &msg("Using gettimeofday for timestamps\n"); + } + else + { + warn("No gettimeofday syscall found - using time builtin for timestamps\n"); + eval 'sub time { return time; }'; + } +} +else +{ + warn("No syscall.ph file found - using time builtin for timestamps\n"); + eval 'sub time { return time; }'; +} + + +;#------------------+ +;# from ntp_request.h +;#------------------+ + +;# NTP mode 7 packet format: +;# Byte 1: ResponseBit MoreBit Version(3bit) Mode(3bit)==7 +;# Byte 2: AuthBit Sequence # - 0 - 127 see MoreBit +;# Byte 3: Implementation # +;# Byte 4: Request Code +;# +;# Short 1: Err(3bit) NumItems(12bit) +;# Short 2: MBZ(3bit)=0 DataItemSize(12bit) +;# 0 - 500 byte Data +;# if AuthBit is set: +;# Long: KeyId +;# 2xLong: AuthCode + +;# +$IMPL_XNTPD = 2; +$REQ_LOOP_INFO = 8; + + +;# request packet for REQ_LOOP_INFO: +;# B1: RB=0 MB=0 V=2 M=7 +;# B2: S# = 0 +;# B3: I# = IMPL_XNTPD +;# B4: RC = REQ_LOOP_INFO +;# S1: E=0 NI=0 +;# S2: MBZ=0 DIS=0 +;# data: 32 byte 0 padding +;# 8byte timestamp if encryption, 0 padding otherwise +$loopinfo_reqpkt = + pack("CCCC nn x32 x8", 0x17, 0, $IMPL_XNTPD, $REQ_LOOP_INFO, 0, 0); + +;# ignore any auth data in packets +$loopinfo_response_size = + 1+1+1+1+2+2 # header size like request pkt + + 8 # l_fp last_offset + + 8 # l_fp drift_comp + + 4 # u_long compliance + + 4 # u_long watchdog_timer + ; +$loopinfo_response_fmt = "C4n2N2N2NN"; +$loopinfo_response_fmt_v2 = "C4n2N2N2N2N"; + +;# +;# prepare connection to server +;# + +;# workaround for broken socket.ph on dynix_ptx +eval 'sub INTEL {1;}' unless defined(&INTEL); +eval 'sub ATT {1;}' unless defined(&ATT); + +require "sys/socket.ph"; + +require 'netinet/in.ph'; + +;# if you do not have netinet/in.ph enable the following lines +;#eval 'sub INADDR_ANY { 0x00000000; }' unless defined(&INADDR_ANY); +;#eval 'sub IPPRORO_UDP { 17; }' unless defined(&IPPROTO_UDP); + +if ($ntpserver =~ /^((0x?)?\w+)\.((0x?)?\w+)\.((0x?)?\w+)\.((0x?)?\w+)$/) +{ + local($a,$b,$c,$d) = ($1,$3,$5,$7); + $a = oct($a) if defined($2); + $b = oct($b) if defined($4); + $c = oct($c) if defined($6); + $d = oct($d) if defined($8); + $server_addr = pack("C4", $a,$b,$c,$d); + + $server_mainname + = (gethostbyaddr($server_addr,&AF_INET))[$[] || $ntpserver; +} +else +{ + ($server_mainname,$server_addr) + = (gethostbyname($ntpserver))[$[,$[+4]; + + die("$0: host \"$ntpserver\" is unknown\n") + unless defined($server_addr); +} +&msg ("Address of server \"$ntpserver\" is \"%d.%d.%d.%d\"\n", + unpack("C4",$server_addr)); + +$proto_udp = (getprotobyname('udp'))[$[+2] || &IPPROTO_UDP; + +$ntp_port = + (getservbyname('ntp','udp'))[$[+2] || + (warn "Could not get port number for service \"ntp/udp\" using 123\n"), + ($ntp_port=123); + +;# +0 && &SOCK_DGRAM; # satisfy perl -w ... +socket(S, &AF_INET, &SOCK_DGRAM, $proto_udp) || + die("Cannot open socket: $!\n"); + +bind(S, pack("S n N x8", &AF_INET, 0, &INADDR_ANY)) || + die("Cannot bind: $!\n"); + +($my_port, $my_addr) = (unpack("S n a4 x8",getsockname(S)))[$[+1,$[+2]; + +&msg("Listening at address %d.%d.%d.%d port %d\n", + unpack("C4",$my_addr), $my_port); + +$server_inaddr = pack("Sna4x8", &AF_INET, $ntp_port, $server_addr); + +;############################################################ +;# +;# the main loop: +;# send request +;# get reply +;# wait til next sample time + +undef($lasttime); +$lostpacket = 0; + +while(1) +{ + $stime = &time; + + &msg("Sending request $stime...\n"); + + $ret = send(S,$loopinfo_reqpkt,0,$server_inaddr); + + if (! defined($ret) || $ret < length($loopinfo_reqpkt)) + { + warn("$0: send failed ret=($ret): $!\n"); + $fail++; + next; + } + + &msg("Waiting for reply...\n"); + + $mask = ""; vec($mask,fileno(S),1) = 1; + $ret = select($mask,undef,undef,$timeout); + + if (! defined($ret)) + { + warn("$0: select failed: $!\n"); + $fail++; + next; + } + elsif ($ret == 0) + { + warn("$0: request to $ntpserver timed out ($timeout seconds)\n"); + ;# do not count this event as failure + ;# it usually this happens due to dropped udp packets on noisy and + ;# havily loaded lines, so just try again; + $lostpacket = 1; + next; + } + + &msg("Receiving reply...\n"); + + $len = 520; # max size of a mode 7 packet + $reply = ""; # just make it defined for -w + $ret = recv(S,$reply,$len,0); + + if (!defined($ret)) + { + warn("$0: recv failed: $!\n"); + $fail++; + next; + } + + $etime = &time; + &msg("Received at\t$etime\n"); + + ;#$time = ($stime + $etime) / 2; # symmetric delay assumed + $time = $etime; # the above assumption breaks for X25 + ;# so taking etime makes timestamps be a + ;# little late, but keeps them increasing + ;# monotonously + + &msg(sprintf("Reply from %d.%d.%d.%d took %f seconds\n", + (unpack("SnC4",$ret))[$[+2 .. $[+5], ($etime - $stime))); + + if ($len < $loopinfo_response_size) + { + warn("$0: short packet ($len bytes) received ($loopinfo_response_size bytes expected\n"); + $fail++; + next; + } + + ($b1,$b2,$b3,$b4,$s1,$s2, + $offset_i,$offset_f,$drift_i,$drift_f,$compl,$watchdog) + = unpack($loopinfo_response_fmt,$reply); + + ;# check reply + if (($s1 >> 12) != 0) # error ! + { + die("$0: got error reply ".($s1>>12)."\n"); + } + if (($b1 != 0x97 && $b1 != 0x9f) || # Reply NotMore V=2 M=7 + ($b2 != 0 && $b2 != 0x80) || # S=0 Auth no/yes + $b3 != $IMPL_XNTPD || # ! IMPL_XNTPD + $b4 != $REQ_LOOP_INFO || # Ehh.. not loopinfo reply ? + $s1 != 1 || # ???? + ($s2 != 24 && $s2 != 28) # + ) + { + warn("$0: Bad/unexpected reply from server:\n"); + warn(" \"".unpack("H*",$reply)."\"\n"); + warn(" ".sprintf("b1=%x b2=%x b3=%x b4=%x s1=%d s2=%d\n", + $b1,$b2,$b3,$b4,$s1,$s2)); + $fail++; + next; + } + elsif ($s2 == 28) + { + ;# seems to be a version 2 xntpd + ($b1,$b2,$b3,$b4,$s1,$s2, + $offset_i,$offset_f,$drift_i,$drift_f,$compl_i,$compl_f,$watchdog) + = unpack($loopinfo_response_fmt_v2,$reply); + $compl = &lfptoa($compl_i, $compl_f); + } + + $time -= $watchdog; + + $offset = &lfptoa($offset_i, $offset_f); + $drift = &lfptoa($drift_i, $drift_f); + + &log($time,$offset,$drift,$compl) && ($fail = 0);; +} +continue +{ + die("$0: Too many failures - terminating\n") if $fail > $MAX_FAIL; + &msg("Sleeping " . ($lostpacket ? ($delay / 2) : $delay) . " seconds...\n"); + + sleep($lostpacket ? ($delay / 2) : $delay); + $lostpacket = 0; +} + +sub log +{ + local($time,$offs,$freq,$cmpl) = @_; + local($y,$m,$d); + local($fname,$suff) = ($logfile); + + + ;# silently drop sample if distance to last sample is too low + if (defined($lasttime) && ($lasttime + 2) >= $time) + { + &msg("Dropped packet - old sample\n"); + return 1; + } + + ;# $suff determines which samples end up in the same file + ;# could have used $year (;-) or WeekOfYear, DayOfYear,.... + ;# Change it to your suit... + + ($d,$m,$y) = (localtime($time))[$[+3 .. $[+5]; + $suff = sprintf("%04d%02d%02d",$y+1900,$m+1,$d); + $fname .= $suff; + if (!open(LOG,">>$fname")) + { + warn("$0: open($fname) failed: $!\n"); + $fail++; + return 0; + } + else + { + ;# file format + ;# MJD seconds offset drift compliance + printf LOG ("%d %.3lf %.8lf %.7lf %d\n", + int($time/86400)+$MJD_1970, + $time - int($time/86400) * 86400, + $offs,$freq,$cmpl); + close(LOG); + $lasttime = $time; + } + return 1; +} + +;# see ntp_fp.h to understand this +sub lfptoa +{ + local($i,$f) = @_; + local($sign) = 1; + + + if ($i & 0x80000000) + { + if ($f == 0) + { + $i = -$i; + } + else + { + $f = -$f; + $i = ~$i; + $i += 1; # 2s complement + } + $sign = -1; + ;#print "NEG: $i $f\n"; + } + else + { + ;#print "POS: $i $f\n"; + } + ;# unlike xntpd I have perl do the dirty work. + ;# Using floats here may affect precision, but + ;# currently these bits aren't significant anyway + return $sign * ($i + $f/2**32); +} diff --git a/contrib/xntpd/scripts/monitoring/ntploopwatch b/contrib/xntpd/scripts/monitoring/ntploopwatch new file mode 100644 index 0000000000..655ed7188c --- /dev/null +++ b/contrib/xntpd/scripts/monitoring/ntploopwatch @@ -0,0 +1,1631 @@ +#!/local/bin/perl -w--*-perl-*- +;# +;# ntploopwatch,v 3.1 1993/07/06 01:09:13 jbj Exp +;# +;# process loop filter statistics file and either +;# - show statistics periodically using gnuplot +;# - or print a single plot +;# +;# Copyright (c) 1992 +;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg +;# +;# +;############################################################# +$0 =~ s!^.*/([^/]+)$!\1!; +$F = ' ' x length($0); +$|=1; + +$ENV{'SHELL'} = '/bin/sh'; # use bourne shell + +undef($config); +undef($workdir); +undef($PrintIt); +undef($samples); +undef($StartTime); +undef($EndTime); +($a,$b) if 0; # keep -w happy +$usage = <<"E-O-P"; +usage: + to watch statistics permanently: + $0 [-v[]] [-c ] [-d ] + $F [-h ] + + to get a single print out specify also + $F -P[] [-s] + $F [-S ] [-E ] + $F [-Y ] [-y ] + +If You like long option names, You can use: + -help + -c +config + -d +directory + -h +host + -v +verbose[=] + -P +printer[=] + -s +samples[=] + -S +starttime + -E +endtime + -Y +maxy + -y +miny + +If contains a '/' (slash character) output is directed to +a file of this name instead of delivered to a printer. +E-O-P + +;# add directory to look for lr.pl and timelocal.pl (in front of current list) +unshift(@INC,"/src/NTP/v3/xntp/monitoring"); + +require "lr.pl"; # linear regresion routines + +$MJD_1970 = 40587; # from ntp.h (V3) +$RecordSize = 48; # usually a line fits into 42 bytes +$MinClip = 0.12; # clip Y scales with greater range than this + +;# largest extension of Y scale from mean value, factor for standart deviation +$FuzzLow = 2; # for side closer to zero +$FuzzBig = 1; # for side farther from zero + +require "ctime.pl"; +require "timelocal.pl"; +;# early distributions of ctime.pl had a bug +$ENV{'TZ'} = 'MET' unless defined $ENV{'TZ'} || $[ > 4.010; +if (defined(@ctime'MoY)) +{ + *Month=*ctime'MoY; + *Day=*ctime'DoW; +} +else +{ + @Month = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); + @Day = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); +} +;# max number of days per month +@MaxNumDaysPerMonth = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); + +;# config settable parameters +$delay = 60; +$srcprefix = "./var\@\$STATHOST/loopstats."; +$showoffs = 1; +$showfreq = 1; +$showcmpl = 0; +$showoreg = 0; +$showfreg = 0; +undef($timebase); +undef($freqbase); +undef($cmplscale); +undef($MaxY); +undef($MinY); +$deltaT = 512; # indicate sample data gaps greater than $deltaT seconds +$verbose = 1; + +while($_ = shift(@ARGV)) +{ + (/^[+-]help$/) && die($usage); + + (/^-c$/ || /^\+config$/) && + (@ARGV || die($usage), $config = shift(@ARGV), next); + + (/^-d$/ || /^\+directory$/) && + (@ARGV || die($usage), $workdir = shift(@ARGV), next); + + (/^-h$/ || /^\+host$/) && + (@ARGV || die($usage), $STATHOST = shift, next); + + (/^-v(\d*)$/ || /^\+verbose=?(\d*)$/) && + ($verbose=($1 eq "") ? 1 : $1, next); + + (/^-P(\S*)$/ || /^\+[Pp]rinter=?(\S*)$/) && + ($PrintIt = $1, $verbose==1 && ($verbose = 0), next); + + (/^-s(\d*)$/ || /^\+samples=?(\d*)$/) && + (($samples = ($1 eq "") ? (shift || die($usage)): $1), next); + + (/^-S$/ || /^\+[Ss]tart[Tt]ime$/) && + (@ARGV || die($usage), $StartTime=&date_time_spec2seconds(shift),next); + + (/^-E$/ || /^\+[Ee]nd[Tt]ime$/) && + (@ARGV || die($usage), $EndTime = &date_time_spec2seconds(shift),next); + + (/^-Y$/ || /^\+[Mm]ax[Yy]$/) && + (@ARGV || die($usage), $MaxY = shift, next); + + (/^-y$/ || /^\+[Mm]in[Yy]$/) && + (@ARGV || die($usage), $MinY = shift, next); + + die("$0: unexpected argument \"$_\"\n$usage"); +} + +if (defined($workdir)) +{ + chdir($workdir) || + die("$0: failed to change working dir to \"$workdir\": $!\n"); +} + +$PrintIt = "ps" if defined($PrintIt) && $PrintIt eq ""; + +if (!defined($PrintIt)) +{ + defined($samples) && + print "WARNING: your samples value may be shadowed by config file settings\n"; + defined($StartTime) && + print "WARNING: your StartTime value may be shadowed by config file settings\n"; + defined($EndTime) && + print "WARNING: your EndTime value may be shadowed by config file settings\n"; + defined($MaxY) && + print "WARNING: your MaxY value may be shadowed by config file settings\n"; + defined($MinY) && + print "WARNING: your MinY value may be shadowed by config file settings\n"; + + ;# check operating environment + ;# + ;# gnuplot usually has X support + ;# I vaguely remember there was one with sunview support + ;# + ;# If Your plotcmd can display graphics using some other method + ;# (Tek window,..) fix the following test + ;# (or may be, just disable it) + ;# + !(defined($ENV{'DISPLAY'}) || defined($ENV{'WINDOW_PARENT'})) && + die("Need window system to monitor statistics\n"); +} + +;# configuration file +$config = "loopwatch.config" unless defined($config); +($STATHOST = $config) =~ s!.*loopwatch\.config.([^/\.]*)$!\1! + unless defined($STATHOST); +($STATTAG = $STATHOST) =~ s/^([^\.\*\s]+)\..*$/\1/; + +$srcprefix =~ s/\$STATHOST/$STATHOST/g; + +;# plot command +@plotcmd=("gnuplot", + '-title', "Ntp loop filter statistics $STATHOST", + '-name', "NtpLoopWatch_$STATTAG"); +$tmpfile = "/tmp/ntpstat.$$"; + +;# other variables +$doplot = ""; # assembled command for @plotcmd to display plot +undef($laststat); + +;# plot value ranges +undef($mintime); +undef($maxtime); +undef($minoffs); +undef($maxoffs); +undef($minfreq); +undef($maxfreq); +undef($mincmpl); +undef($maxcmpl); +undef($miny); +undef($maxy); + +;# stop operation if plot command dies +sub sigchld +{ + local($pid) = wait; + unlink($tmpfile); + warn(sprintf("%s: %s died: exit status: %d signal %d\n", + $0, + (defined($Plotpid) && $Plotpid == $pid) + ? "plotcmd" : "unknown child $pid", + $?>>8,$? & 0xff)) if $?; + exit(1) if $? && defined($Plotpid) && $pid == $Plotpid; +} +&sigchld if 0; +$SIG{'CHLD'} = "sigchld"; +$SIG{'CLD'} = "sigchld"; + +sub abort +{ + unlink($tmpfile); + defined($Plotpid) && kill('TERM',$Plotpid); + die("$0: received signal SIG$_[$[] - exiting\n"); +} +&abort if 0; # make -w happy - &abort IS used +$SIG{'INT'} = $SIG{'HUP'} = $SIG{'QUIT'} = $SIG{'TERM'} = $SIG{'PIPE'} = "abort"; + +;# +sub abs +{ + ($_[$[] < 0) ? -($_[$[]) : $_[$[]; +} + +;##################### +;# start of real work + +print "starting plot command (" . join(" ",@plotcmd) . ")\n" if $verbose > 1; + +$Plotpid = open(PLOT,"|-"); +select((select(PLOT),$|=1)[$[]); # make PLOT line bufferd + +defined($Plotpid) || + die("$0: failed to start plot command: $!\n"); + +unless ($Plotpid) +{ + ;# child == plot command + close(STDOUT); + open(STDOUT,">&STDERR") || + die("$0: failed to redirect STDOUT of plot command: $!\n"); + + print STDOUT "plot command running as $$\n"; + + exec @plotcmd; + die("$0: failed to exec (@plotcmd): $!\n"); + exit(1); # in case ... +} + +sub read_config +{ + local($at) = (stat($config))[$[+9]; + local($_,$c,$v); + + (undef($laststat),(print("stat $config failed: $!\n")),return) if ! defined($at); + return if (defined($laststat) && ($laststat == $at)); + $laststat = $at; + + print "reading configuration from \"$config\"\n" if $verbose; + + open(CF,"<$config") || + (warn("$0: failed to read \"$config\" - using old settings ($!)\n"), + return); + while() + { + chop; + s/^([^\#]*[^\#\s]?)\s*\#.*$//; + next if /^\s*$/; + + s/^\s*([^=\s]*)\s*=\s*(.*\S)\s*$/\1=\2/; + + ($c,$v) = split(/=/,$_,2); + print "processing \"$c=$v\"\n" if $verbose > 3; + ($c eq "delay") && ($delay = $v,1) && next; + ($c eq 'samples') && (!defined($PrintIt) || !defined($samples)) && + ($samples = $v,1) && next; + ($c eq 'srcprefix') && (($srcprefix=$v)=~s/\$STATHOST/$STATHOST/g,1) + && next; + ($c eq 'showoffs') && + ($showoffs = ($v eq 'yes' || $v eq 'y' || $v != 0),1) && next; + ($c eq 'showfreq') && + ($showfreq = ($v eq 'yes' || $v eq 'y' || $v != 0),1) && next; + ($c eq 'showcmpl') && + ($showcmpl = ($v eq 'yes' || $v eq 'y' || $v != 0),1) && next; + ($c eq 'showoreg') && + ($showoreg = ($v eq 'yes' || $v eq 'y' || $v != 0),1) && next; + ($c eq 'showfreg') && + ($showfreg = ($v eq 'yes' || $v eq 'y' || $v != 0),1) && next; + + ($c eq 'exit') && (unlink($tmpfile),die("$0: exit by config request\n")); + + ($c eq 'freqbase' || + $c eq 'cmplscale') && + do { + if (! defined($v) || $v eq "" || $v eq 'dynamic') + { + eval "undef(\$$c);"; + } + else + { + eval "\$$c = \$v;"; + } + next; + }; + ($c eq 'timebase') && + do { + if (! defined($v) || $v eq "" || $v eq "dynamic") + { + undef($timebase); + } + else + { + $timebase=&date_time_spec2seconds($v); + } + }; + ($c eq 'EndTime') && + do { + next if defined($EndTime) && defined($PrintIt); + if (! defined($v) || $v eq "" || $v eq "none") + { + undef($EndTime); + } + else + { + $EndTime=&date_time_spec2seconds($v); + } + }; + ($c eq 'StartTime') && + do { + next if defined($StartTime) && defined($PrintIt); + if (! defined($v) || $v eq "" || $v eq "none") + { + undef($StartTime); + } + else + { + $StartTime=&date_time_spec2seconds($v); + } + }; + + ($c eq 'MaxY') && + do { + next if defined($MaxY) && defined($PrintIt); + if (! defined($v) || $v eq "" || $v eq "none") + { + undef($MaxY); + } + else + { + $MaxY=$v; + } + }; + + ($c eq 'MinY') && + do { + next if defined($MinY) && defined($PrintIt); + if (! defined($v) || $v eq "" || $v eq "none") + { + undef($MinY); + } + else + { + $MinY=$v; + } + }; + + ($c eq 'deltaT') && + do { + if (!defined($v) || $v eq "") + { + undef($deltaT); + } + else + { + $deltaT = $v; + } + next; + }; + ($c eq 'verbose') && ! defined($PrintIt) && + do { + if (!defined($v) || $v == 0) + { + $verbose = 0; + } + else + { + $verbose = $v; + } + next; + }; + ;# otherwise: silently ignore unrecognized config line + } + close(CF); + ;# set show defaults when nothing selected + $showoffs = $showfreq = $showcmpl = 1 + unless $showoffs || $showfreq || $showcmpl; + if ($verbose > 3) + { + print "new configuration:\n"; + print " delay\t= $delay\n"; + print " samples\t= $samples\n"; + print " srcprefix\t= $srcprefix\n"; + print " showoffs\t= $showoffs\n"; + print " showfreq\t= $showfreq\n"; + print " showcmpl\t= $showcmpl\n"; + print " showoreg\t= $showoreg\n"; + print " showfreg\t= $showfreg\n"; + printf " timebase\t= %s",defined($timebase)?&ctime($timebase):"dynamic\n"; + printf " freqbase\t= %s\n",defined($freqbase) ?"$freqbase":"dynamic"; + printf " cmplscale\t= %s\n",defined($cmplscale)?"$cmplscale":"dynamic"; + printf " StartTime\t= %s",defined($StartTime)?&ctime($StartTime):"none\n"; + printf " EndTime\t= %s", defined($EndTime) ? &ctime($EndTime):"none\n"; + printf " MaxY\t= %s",defined($MaxY)? $MaxY :"none\n"; + printf " MinY\t= %s",defined($MinY)? $MinY :"none\n"; + print " verbose\t= $verbose\n"; + } +print "configuration file read\n" if $verbose > 2; +} + +sub make_doplot +{ + local($c) = (""); + local($fmt) + = ("%s \"%s\" using 1:%d title '%s <%lf %lf> %6s' with lines"); + local($regfmt) + = ("%s ((%lf * x) + %lf) title 'lin. approx. %s (%f t[h]) %s %f <%f> %6s' with lines"); + + $doplot = " set title 'NTP loopfilter statistics for $STATHOST " . + "(last $LastCnt samples from $srcprefix*)'\n"; + + local($xts,$xte,$i,$t); + + local($s,$c) = (""); + + ;# number of integral seconds to get at least 12 tic marks on x axis + $t = int(($maxtime - $mintime) / 12 + 0.5); + $t = 1 unless $t; # prevent $t to be zero + foreach $i (30, + 60,5*60,15*60,30*60, + 60*60,2*60*60,6*60*60,12*60*60, + 24*60*60,48*60*60) + { + last if $t < $i; + $t = $t - ($t % $i); + } + print "time label resolution: $t seconds\n" if $verbose > 1; + + ;# make gnuplot use wall clock time labels instead of NTP seconds + for ($c="", $i = $mintime - ($mintime % $t); + $i <= $maxtime + $t; + $i += $t, $c=",") + { + $s .= $c; + ((int($i / $t) % 2) && + ($s .= sprintf("'' %lf",($i - $LastTimeBase)/3600))) || + (($t <= 60) && + ($s .= sprintf("'%d:%02d:%02d' %lf", + (localtime($i))[$[+2,$[+1,$[+0], + ($i - $LastTimeBase)/3600))) + || (($t <= 2*60*60) && + ($s .= sprintf("'%d:%02d' %lf", + (localtime($i))[$[+2,$[+1], + ($i - $LastTimeBase)/3600))) + || (($t <= 12*60*60) && + ($s .= sprintf("'%s %d:00' %lf", + $Day[(localtime($i))[$[+6]], + (localtime($i))[$[+2], + ($i - $LastTimeBase)/3600))) + || ($s .= sprintf("'%d.%d-%d:00' %lf", + (localtime($i))[$[+3,$[+4,$[+2], + ($i - $LastTimeBase)/3600)); + } + $doplot .= "set xtics ($s)\n"; + + chop($xts = &ctime($mintime)); + chop($xte = &ctime($maxtime)); + $doplot .= "set xlabel 'Start: $xts -- Time Scale -- End: $xte'\n"; + $doplot .= "set yrange [" ; + $doplot .= defined($MinY) ? sprintf("%lf", $MinY) : $miny; + $doplot .= ':'; + $doplot .= defined($MaxY) ? sprintf("%lf", $MaxY) : $maxy; + $doplot .= "]\n"; + + $doplot .= " plot"; + $c = ""; + $showoffs && + ($doplot .= sprintf($fmt,$c,$tmpfile,2, + "offset", + $minoffs,$maxoffs, + "[ms]"), + $c = ","); + $showcmpl && + ($doplot .= sprintf($fmt,$c,$tmpfile,4, + "compliance" . + (&abs($LastCmplScale) > 1 + ? " / $LastCmplScale" + : (&abs($LastCmplScale) == 1 ? "" : " * ".(1/$LastCmplScale))), + $mincmpl/$LastCmplScale,$maxcmpl/$LastCmplScale, + ""), + $c = ","); + $showfreq && + ($doplot .= sprintf($fmt,$c,$tmpfile,3, + "frequency" . + ($LastFreqBase > 0 + ? " - $LastFreqBaseString" + : ($LastFreqBase == 0 ? "" : " + $LastFreqBaseString")), + $minfreq * $FreqScale - $LastFreqBase, + $maxfreq * $FreqScale - $LastFreqBase, + "[${FreqScaleInv}ppm]"), + $c = ","); + $showoreg && $showoffs && + ($doplot .= sprintf($regfmt, $c, + &lr_B('offs'),&lr_A('offs'), + "offset ", + &lr_B('offs'), + ((&lr_A('offs')) < 0 ? '-' : '+'), + &abs(&lr_A('offs')), &lr_r('offs'), + "[ms]"), + $c = ","); + $showfreg && $showfreq && + ($doplot .= sprintf($regfmt, $c, + &lr_B('freq') * $FreqScale, + (&lr_A('freq') + $minfreq) * $FreqScale - $LastFreqBase, + "frequency", + &lr_B('freq') * $FreqScale, + ((&lr_A('freq') + $minfreq) * $FreqScale - $LastFreqBase) < 0 ? '-' : '+', + &abs((&lr_A('freq') + $minfreq) * $FreqScale - $LastFreqBase), + &lr_r('freq'), + "[${FreqScaleInv}ppm]"), + $c = ","); + $doplot .= "\n"; +} + +%F_key = (); +%F_name = (); +%F_size = (); +%F_mtime = (); +%F_first = (); +%F_last = (); + +sub genfile +{ + local($cnt,$in,$out,@fpos) = @_; + + local(@F,@t,$t,$lastT) = (); + local(@break,@time,@offs,@freq,@cmpl,@loffset,@filekey) = (); + local($lm,$l,@f); + + local($sdir,$sname); + + ;# allocate some storage for the tables + ;# otherwise realloc may get into troubles + if (defined($StartTime) && defined($EndTime)) + { + $l = ($EndTime-$StartTime) -$[+1 +1; # worst case: 1 sample per second + } + else + { + $l = $cnt + 10; + } + print "preextending arrays to $l entries\n" if $verbose > 2; + $#break = $l; for ($i=$[; $i<=$l;$i++) { $break[$i] = 0; } + $#time = $l; for ($i=$[; $i<=$l;$i++) { $time[$i] = 0; } + $#offs = $l; for ($i=$[; $i<=$l;$i++) { $offs[$i] = 0; } + $#freq = $l; for ($i=$[; $i<=$l;$i++) { $freq[$i] = 0; } + $#cmpl = $l; for ($i=$[; $i<=$l;$i++) { $cmpl[$i] = 0; } + $#loffset = $l; for ($i=$[; $i<=$l;$i++) { $loffset[$i] = 0; } + $#filekey = $l; for ($i=$[; $i<=$l;$i++) { $filekey[$i] = 0; } + ;# now reduce size again + $#break = $[ - 1; + $#time = $[ - 1; + $#offs = $[ - 1; + $#freq = $[ - 1; + $#cmpl = $[ - 1; + $#loffset = $[ - 1; + $#filekey = $[ - 1; + print "memory allocation ready\n" if $verbose > 2; + sleep(3) if $verbose > 1; + + if (index($in,"/") < $[) + { + $sdir = "."; + $sname = $in; + } + else + { + ($sdir,$sname) = ($in =~ m!^(.*)/([^/]*)!); + $sname = "" unless defined($sname); + } + + if (!defined($Lsdir) || $Lsdir ne $sdir || $Ltime != (stat($sdir))[$[+9] || + grep($F_mtime{$_} != (stat($F_name{$_}))[$[+9], @F_files)) + + { + print "rescanning directory \"$sdir\" for files \"$sname*\"\n" + if $verbose > 1; + + ;# rescan directory on changes + $Lsdir = $sdir; + $Ltime = (stat($sdir))[$[+9]; + if 0; # dummy line - calm down my formatter + local(@newfiles) = < ${in}*[0-9] >; + local($st_dev,$st_ino,$st_mtime,$st_size,$name,$key,$modified); + + foreach $name (@newfiles) + { + ($st_dev,$st_ino,$st_size,$st_mtime) = + (stat($name))[$[,$[+1,$[+7,$[+9]; + $modified = 0; + $key = sprintf("%lx|%lu", $st_dev, $st_ino); + + print "candidate file \"$name\"", + (defined($st_dev) ? "" : " failed: $!"),"\n" + if $verbose > 2; + + if (! defined($F_key{$name}) || $F_key{$name} ne $key) + { + $F_key{$name} = $key; + $modified++; + } + if (!defined($F_name{$key}) || $F_name{$key} != $name) + { + $F_name{$key} = $name; + $modified++; + } + if (!defined($F_size{$key}) || $F_size{$key} != $st_size) + { + $F_size{$key} = $st_size; + $modified++; + } + if (!defined($F_mtime{$key}) || $F_mtime{$key} != $st_mtime) + { + $F_mtime{$key} = $st_mtime; + $modified++; + } + if ($modified) + { + print "new data \"$name\" key: $key;\n" if $verbose > 1; + print " size: $st_size; mtime: $st_mtime;\n" + if $verbose > 1; + $F_last{$key} = $F_first{$key} = $st_mtime; + $F_first{$key}--; # prevent zero divide later on + ;# now compute derivated attributes + open(IN, "<$name") || + do { + warn "$0: failed to open \"$name\": $!"; + next; + }; + + while() + { + @F = split; + next if @F < 5; + next if $F[$[] eq ""; + $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; + $t += $F[$[+1]; + $F_first{$key} = $t; + print "\tfound first entry: $t ",&ctime($t) + if $verbose > 4; + last; + } + seek(IN, + ($st_size > 4*$RecordSize) ? $st_size - 4*$RecordSize : 0, + 0); + while() + { + @F = split; + next if @F < 5; + next if $F[$[] eq ""; + $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; + $t += $F[$[+1]; + $F_last{$key} = $t; + $_ = ; + print "\tfound last entry: $t ", &ctime($t) + if $verbose > 4 && ! defined($_); + last unless defined($_); + redo; + ;# Ok, calm down... + ;# using $_ = in conjunction with redo + ;# is semantically equivalent to the while loop, but + ;# I needed a one line look ahead and this solution + ;# was what I thought of first + ;# and.. If you do not like it dont look + } + close(IN); + print(" first: ",$F_first{$key}, + " last: ",$F_last{$key},"\n") if $verbose > 1; + } + } + ;# now reclaim memory used for files no longer referenced ... + local(%Names); + grep($Names{$_} = 1,@newfiles); + foreach (keys %F_key) + { + next if defined($Names{$_}); + delete $F_key{$_}; + $verbose > 2 && print "no longer referenced: \"$_\"\n"; + } + %Names = (); + + grep($Names{$_} = 1,values(%F_key)); + foreach (keys %F_name) + { + next if defined($Names{$_}); + delete $F_name{$_}; + $verbose > 2 && print "unref name($_)= $F_name{$_}\n"; + } + foreach (keys %F_size) + { + next if defined($Names{$_}); + delete $F_size{$_}; + $verbose > 2 && print "unref size($_)\n"; + } + foreach (keys %F_mtime) + { + next if defined($Names{$_}); + delete $F_mtime{$_}; + $verbose > 2 && print "unref mtime($_)\n"; + } + foreach (keys %F_first) + { + next if defined($Names{$_}); + delete $F_first{$_}; + $verbose > 2 && print "unref first($_)\n"; + } + foreach (keys %F_last) + { + next if defined($Names{$_}); + delete $F_last{$_}; + $verbose > 2 && print "unref last($_)\n"; + } + ;# create list sorted by time + @F_files = sort {$F_first{$a} <=> $F_first{$b}; } keys(%F_name); + if ($verbose > 1) + { + print "Resulting file list:\n"; + foreach (@F_files) + { + print "\t$_\t$F_name{$_}\n"; + } + } + } + + printf("processing %s; output \"$out\" (%d input files)\n", + ((defined($StartTime) && defined($EndTime)) + ? "time range" + : (defined($StartTime) ? "$cnt samples from StartTime" : + (defined($EndTime) ? "$cnt samples to EndTime" : + "last $cnt samples"))), + scalar(@F_files)) + if $verbose > 1; + + ;# open output file - will be input for plotcmd + open(OUT,">$out") || + do { + warn("$0: cannot create \"$out\": $!\n"); + }; + + @f = @F_files; + if (defined($StartTime)) + { + while (@f && ($F_last{$f[$[]} < $StartTime)) + { + print("shifting ", $F_name{$f[$[]}, + " last: ", $F_last{$f[$[]}, + " < StartTime: $StartTime\n") + if $verbose > 3; + shift(@f); + } + + + } + if (defined($EndTime)) + { + while (@f && ($F_first{$f[$#f]} > $EndTime)) + { + print("popping ", $F_name{$f[$#f]}, + " first: ", $F_first{$f[$#f]}, + " > EndTime: $EndTime\n") + if $verbose > 3; + pop(@f); + } + } + + if (@f) + { + if (defined($StartTime)) + { + print "guess start according to StartTime ($StartTime)\n" + if $verbose > 3; + + if ($fpos[$[] eq 'start') + { + if (grep($_ eq $fpos[$[+1],@f)) + { + shift(@f) while @f && $f[$[] ne $fpos[$[+1]; + } + else + { + @fpos = ('start', $f[$[], undef); + } + } + else + { + @fpos = ('start' , $f[$[], undef); + } + + if (!defined($fpos[$[+2])) + { + if ($StartTime <= $F_first{$f[$[]}) + { + $fpos[$[+2] = 0; + } + else + { + $fpos[$[+2] = + int($F_size{$f[$[]} * + (($StartTime - $F_first{$f[$[]})/ + ($F_last{$f[$[]} - $F_first{$f[$[]}))); + $fpos[$[+2] = ($fpos[$[+2] <= 2 * $RecordSize) + ? 0 : $fpos[$[+2] - 2 * $RecordSize; + ;# anyway as the data may contain "time holes" + ;# our heuristics may baldly fail + ;# so just start at 0 + $fpos[$[+2] = 0; + } + } + } + elsif (defined($EndTime)) + { + print "guess starting point according to EndTime ($EndTime)\n" + if $verbose > 3; + + if ($fpos[$[] eq 'end') + { + if (grep($_ eq $fpos[$[+1],@f)) + { + shift(@f) while @f && $f[$[] ne $fpos[$[+1]; + } + else + { + @fpos = ('end', $f[$[], undef); + } + } + else + { + @fpos = ('end', $f[$[], undef); + } + + if (!defined($fpos[$[+2])) + { + local(@x) = reverse(@f); + local($s,$c) = (0,$cnt); + if ($EndTime < $F_last{$x[$[]}) + { + ;# last file will only be used partially + $s = int($F_size{$x[$[]} * + (($EndTime - $F_first{$x[$[]}) / + ($F_last{$x[$[]} - $F_first{$x[$[]}))); + $s = int($s/$RecordSize); + $c -= $s - 1; + if ($c <= 0) + { + ;# start is in the same file + $fpos[$[+1] = $x[$[]; + $fpos[$[+2] = ($c >=-2) ? 0 : (-$c - 2) * $RecordSize; + shift(@f) while @f && ($f[$[] ne $x[$[]); + } + else + { + shift(@x); + } + } + + if (!defined($fpos[$[+2])) + { + local($_); + while($_ = shift(@x)) + { + $s = int($F_size{$_}/$RecordSize); + $c -= $s - 1; + if ($c <= 0) + { + $fpos[$[+1] = $_; + $fpos[$[+2] = ($c>-2) ? 0 : (-$c - 2) * $RecordSize; + shift(@f) while @f && ($f[$[] ne $_); + last; + } + } + } + } + } + else + { + print "guessing starting point according to count ($cnt)\n" + if $verbose > 3; + ;# guess offset to get last available $cnt samples + if ($fpos[$[] eq 'cnt') + { + if (grep($_ eq $fpos[$[+1],@f)) + { + print "old positioning applies\n" if $verbose > 3; + shift(@f) while @f && $f[$[] ne $fpos[$[+1]; + } + else + { + @fpos = ('cnt', $f[$[], undef); + } + } + else + { + @fpos = ('cnt', $f[$[], undef); + } + + if (!defined($fpos[$[+2])) + { + local(@x) = reverse(@f); + local($s,$c) = (0,$cnt); + + local($_); + while($_ = shift(@x)) + { + print "examing \"$_\" $c samples still needed\n" + if $verbose > 4; + $s = int($F_size{$_}/$RecordSize); + $c -= $s - 1; + if ($c <= 0) + { + $fpos[$[+1] = $_; + $fpos[$[+2] = ($c>-2) ? 0 : (-$c - 2) * $RecordSize; + shift(@f) while @f && ($f[$[] ne $_); + last; + } + } + if (!defined($fpos[$[+2])) + { + print "no starting point yet - using start of data\n" + if $verbose > 2; + $fpos[$[+2] = 0; + } + } + } + } + print "Ooops, no suitable input file ??\n" + if $verbose > 1 && @f <= 0; + + printf("Starting at (%s) \"%s\" offset %ld using %d files\n", + $fpos[$[+1], + $F_name{$fpos[$[+1]}, + $fpos[$[+2], + scalar(@f)) + if $verbose > 2; + + $lm = 1; + $l = 0; + foreach $key (@f) + { + $file = $F_name{$key}; + print "processing file \"$file\"\n" if $verbose > 2; + + open(IN,"<$file") || + (warn("$0: cannot read \"$file\": $!\n"), next); + + ;# try to seek to a position nearer to the start of the interesting lines + ;# should always affect only first item in @f + ($key eq $fpos[$[+1]) && + (($verbose > 1) && + print("Seeking to offset $fpos[$[+2]\n"), + seek(IN,$fpos[$[+2],0) || + warn("$0: seek(\"$F_name{$key}\" failed: $|\n")); + + while() + { + $l++; + ($verbose > 3) && + (($l % $lm) == 0 && print("\t$l lines read\n") && + (($l == 2) && ($lm = 10) || + ($l == 100) && ($lm = 100) || + ($l == 500) && ($lm = 500) || + ($l == 1000) && ($lm = 1000) || + ($l == 5000) && ($lm = 5000) || + ($l == 10000) && ($lm = 10000))); + + @F = split; + + next if @F < 5; # no valid input line is this short + next if $F[$[] eq ""; + ($F[$[] !~ /^\d+$/) && # A 'never should have happend' error + die("$0: unexpected input line: $_\n"); + + ;# modified Julian to UNIX epoch + $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; + $t += $F[$[+1]; # add seconds + fraction + + ;# multiply offset by 1000 to get ms - try to avoid float op + (($F[$[+2] =~ s/(\d*)\.(\d{3})(\d*)/\1\2.\3/) && + $F[$[+2] =~ s/0+([\d\.])/($1 eq '.') ? '0.' : $1/e) # strip leading zeros + || $F[$[+2] *= 1000; + + + ;# skip samples out of specified time range + next if (defined($StartTime) && $StartTime > $t); + next if (defined($EndTime) && $EndTime < $t); + + next if defined($lastT) && $t < $lastT; # backward in time ?? + + push(@offs,$F[$[+2]); + push(@freq,$F[$[+3] * (2**20/10**6)); + push(@cmpl,$F[$[+4]); + + push(@break, (defined($lastT) && ($t - $lastT > $deltaT))); + $lastT = $t; + push(@time,$t); + push(@loffset, tell(IN) - length($_)); + push(@filekey, $key); + + shift(@break),shift(@time),shift(@offs), + shift(@freq), shift(@cmpl),shift(@loffset), + shift(@filekey) + if @time > $cnt && + ! (defined($StartTime) && defined($EndTime)); + + last if @time >= $cnt && defined($StartTime) && !defined($EndTime); + } + close(IN); + last if @time >= $cnt && defined($StartTime) && !defined($EndTime); + } + print "input scanned ($l lines/",scalar(@time)," samples)\n" + if $verbose > 1; + + &lr_init('offs'); + &lr_init('freq'); + + if (@time) + { + local($_,@F); + + local($timebase) unless defined($timebase); + local($freqbase) unless defined($freqbase); + local($cmplscale) unless defined($cmplscale); + + undef($mintime,$maxtime,$minoffs,$maxoffs, + $minfreq,$maxfreq,$mincmpl,$maxcmpl, + $miny,$maxy); + + print "computing ranges\n" if $verbose > 2; + + $LastCnt = @time; + + ;# @time is in ascending order (;-) + $mintime = @time[$[]; + $maxtime = @time[$#time]; + unless (defined($timebase)) + { + local($time,@X) = (time); + @X = localtime($time); + + ;# compute today 00:00:00 + $timebase = $time - ((($X[$[+2]*60)+$X[$[+1])*60+$X[$[]); + + } + $LastTimeBase = $timebase; + + if ($showoffs) + { + local($i,$m,$f); + + $minoffs = &min(@offs); + $maxoffs = &max(@offs); + + ;# I know, it is not perl style using indices to access arrays, + ;# but I have to proccess two arrays in sync, non-destructively + ;# (otherwise a (shift(@a1),shift(a2)) would do), + ;# I dont like to make copies of these arrays as they may be huge + $i = $[; + &lr_sample(($time[$i]-$timebase)/3600,$offs[$i],'offs'),$i++ + while $i <= $#time; + + ($minoffs == $maxoffs) && ($minoffs -= 0.1,$maxoffs += 0.1); + + $i = &lr_sigma('offs'); + $m = &lr_mean('offs'); + + print "mean offset: $m sigma: $i\n" if $verbose > 2; + + if (($maxoffs - $minoffs) > $MinClip) + { + $f = (&abs($minoffs) < &abs($maxoffs)) ? $FuzzLow : $FuzzBig; + $miny = (($m - $minoffs) <= ($f * $i)) + ? $minoffs : ($m - $f * $i); + $f = ($f == $FuzzLow) ? $FuzzBig : $FuzzLow; + $maxy = (($maxoffs - $m) <= ($f * $i)) + ? $maxoffs : ($m + $f * $i); + } + else + { + $miny = $minoffs; + $maxy = $maxoffs; + } + ($maxy-$miny) == 0 && + (($maxy,$miny) + = (($maxoffs - $minoffs) > 0) + ? ($maxoffs,$minoffs) : ($MinClip,-$MinClip)); + + $maxy = $MaxY if defined($MaxY) && $MaxY < $maxy; + $miny = $MinY if defined($MinY) && $MinY > $miny; + + print "offset min clipped from $minoffs to $miny\n" + if $verbose > 2 && $minoffs != $miny; + print "offset max clipped from $maxoffs to $maxy\n" + if $verbose > 2 && $maxoffs != $maxy; + } + + if ($showfreq) + { + local($i,$m); + + $minfreq = &min(@freq); + $maxfreq = &max(@freq); + + $i = $[; + &lr_sample(($time[$i]-$timebase)/3600,$freq[$i]-$minfreq,'freq'), + $i++ + while $i <= $#time; + + $i = &lr_sigma('freq'); + $m = &lr_mean('freq') + $minfreq; + + print "mean frequency: $m sigma: $i\n" if $verbose > 2; + + if (defined($maxy)) + { + local($s) = + ($maxfreq - $minfreq) + ? ($maxy - $miny) / ($maxfreq - $minfreq) : 1; + + if (defined($freqbase)) + { + $FreqScale = 1; + $FreqScaleInv = ""; + } + else + { + $FreqScale = 1; + $FreqScale = 10 ** int(log($s)/log(10) - 0.8); + $FreqScaleInv = + ("$FreqScale" =~ /^10(0*)$/) ? "0.${1}1" : + ($FreqScale == 1 ? "" : (1/$FreqScale)); + + $freqbase = $m * $FreqScale; + $freqbase -= &lr_mean('offs'); + + ;# round resulting freqbase + ;# to precision of min max difference + $s = int(log(($maxfreq-$minfreq)*$FreqScale)/log(10))-1; + $s = 10 ** $s; + $freqbase = int($freqbase / $s) * $s; + } + } + else + { + $FreqScale = 1; + $FreqScaleInv = ""; + $freqbase = $m unless defined($freqbase); + if (($maxfreq - $minfreq) > $MinClip) + { + $f = (&abs($minfreq) < &abs($maxfreq)) + ? $FuzzLow : $FuzzBig; + $miny = (($freqbase - $minfreq) <= ($f * $i)) + ? ($minfreq-$freqbase) : (- $f * $i); + $f = ($f == $FuzzLow) ? $FuzzBig : $FuzzLow; + $maxy = (($maxfreq - $freqbase) <= ($f * $i)) + ? ($maxfreq-$freqbase) : ($f * $i); + } + else + { + $miny = $minfreq - $freqbase; + $maxy = $maxfreq - $freqbase; + } + ($maxy - $miny) == 0 && + (($maxy,$miny) = + (($maxfreq - $minfreq) > 0) + ? ($maxfreq-$freqbase,$minfreq-$freqbase) : (0.5,-0.5)); + + $maxy = $MaxY if defined($MaxY) && $MaxY < $maxy; + $miny = $MinY if defined($MinY) && $MinY > $miny; + + print("frequency min clipped from ",$minfreq-$freqbase, + " to $miny\n") + if $verbose > 2 && $miny != ($minfreq - $freqbase); + print("frequency max clipped from ",$maxfreq-$freqbase, + " to $maxy\n") + if $verbose > 2 && $maxy != ($maxfreq - $freqbase); + } + $LastFreqBaseString = + sprintf("%g",$freqbase >= 0 ? $freqbase : -$freqbase); + $LastFreqBase = $freqbase; + print "LastFreqBaseString now \"$LastFreqBaseString\"\n" + if $verbose > 5; + } + else + { + $FreqScale = 1; + $FreqScaleInv = ""; + $LastFreqBase = 0; + $LastFreqBaseString = ""; + } + + if ($showcmpl) + { + $mincmpl = &min(@cmpl); + $maxcmpl = &max(@cmpl); + + if (!defined($cmplscale)) + { + if (defined($maxy)) + { + local($cmp) + = (&abs($miny) > &abs($maxy)) ? &abs($miny) : $maxy; + $cmplscale = $cmp == $maxy ? 1 : -1; + + foreach (0.01, 0.02, 0.05, + 0.1, 0.2, 0.25, 0.4, 0.5, + 1, 2, 4, 5, + 10, 20, 25, 50, + 100, 200, 250, 500, 1000) + { + $cmplscale *= $_, last if $maxcmpl/$_ <= $cmp; + } + } + else + { + $cmplscale = 1; + $miny = $mincmpl ? 0 : -$MinClip; + $maxy = $maxcmpl+$MinClip; + } + } + $LastCmplScale = $cmplscale; + } + else + { + $LastCmplScale = 1; + } + + print "creating plot command input file\n" if $verbose > 2; + + + print OUT ("# preprocessed NTP statistics file for $STATHOST\n"); + print OUT ("# timebase is: ",&ctime($LastTimeBase)) + if defined($LastTimeBase); + print OUT ("# frequency is offset by ", + ($LastFreqBase >= 0 ? "+" : "-"), + "$LastFreqBaseString [${FreqScaleInv}ppm]\n"); + print OUT ("# compliance is scaled by $LastCmplScale\n"); + print OUT ("# time [h]\toffset [ms]\tfrequency [${FreqScaleInv}ppm]\tcompliance\n"); + + printf OUT ("%s%lf\t%lf\t%lf\t%lf\n", + (shift(@break) ? "\n" : ""), + (shift(@time) - $LastTimeBase)/3600, + shift(@offs), + shift(@freq) * $FreqScale - $LastFreqBase, + shift(@cmpl) / $LastCmplScale) + while(@time); + } + else + { + ;# prevent plotcmd from processing empty file + print "Creating plot command dummy...\n" if $verbose > 2; + print OUT "# dummy samples\n0 1 2 3\n1 1 2 3\n"; + &lr_sample(0,1,'offs'); + &lr_sample(1,1,'offs'); + &lr_sample(0,2,'freq'); + &lr_sample(1,2,'freq'); + @time = (0, 1); $maxtime = 1; $mintime = 0; + @offs = (1, 1); $maxoffs = 1; $minoffs = 1; + @freq = (2, 2); $maxfreq = 2; $minfreq = 2; + @cmpl = (3, 3); $maxcmpl = 3; $mincmpl = 3; + $LastCnt = 2; + $LastFreqBase = 0; + $LastCmplScale = 1; + $LastTimeBase = 0; + $miny = -$MinClip; + $maxy = 3 + $MinClip; + } + close(OUT); + + print "plot command input file created\n" + if $verbose > 2; + + if (($fpos[$[] eq 'cnt' && @loffset >= $cnt) || + ($fpos[$[] eq 'start' && $time[$[] <= $StartTime) || + ($fpos[$[] eq 'end')) + { + return ($fpos[$[],$filekey[$[],$loffset[$[]); + } + else # found to few lines - next time start search earlier in file + { + if ($fpos[$[] eq 'start') + { + ;# the timestamps we got for F_first and F_last guaranteed + ;# that no file is left out + ;# the only thing that could happen is: + ;# we guessed the starting point wrong + ;# compute a new guess from the first record found + ;# if this equals our last guess use data of first record + ;# otherwise try new guess + + if ($fpos[$[+1] eq $filekey[$[] && $loffset[$[] > $fpos[$[+2]) + { + local($noff); + $noff = $loffset[$[] - ($cnt - @loffset + 1) * $RecordSize; + $noff = 0 if $noff < 0; + + return (@fpos[$[,$[+1], ($noff == $fpos[$[+2]) ? $loffset[$[] : $noff); + } + return ($fpos[$[],$filekey[$[],$loffset[$[]); + } + elsif ($fpos[$[] eq 'end' || $fpos[$[] eq 'cnt') + { + ;# try to start earlier in file + ;# if we already started at the beginning + ;# try to use previous file + ;# this assumes distance to better starting point is at most one file + ;# the primary guess at top of genfile() should usually allow this + ;# assumption + ;# if the offset of the first sample used is within + ;# a different file than we guessed it must have occured later + ;# in the sequence of files + ;# this only can happen if our starting file did not contain + ;# a valid sample from the starting point we guessed + ;# however this does not invalidate our assumption, no check needed + local($noff,$key); + if ($fpos[$[+2] > 0) + { + $noff = $fpos[$[+2] - $RecordSize * ($cnt - @loffset + 1); + $noff = 0 if $noff < 0; + return (@fpos[$[,$[+1],$noff); + } + else + { + if ($fpos[$[+1] eq $F_files[$[]) + { + ;# first file - and not enough samples + ;# use data of first sample + return ($fpos[$[], $filekey[$[], $loffset[$[]); + } + else + { + ;# search key of previous file + $key = $F_files[$[]; + @F = reverse(@F_files); + while ($_ = shift(@F)) + { + if ($_ eq $fpos[$[+1]) + { + $key = shift(@F) if @F; + last; + } + } + $noff = int($F_size{$key} / $RecordSize); + $noff -= $cnt - @loffset; + $noff = 0 if $noff < 0; + $noff *= $RecordSize; + return ($fpos[$[], $key, $noff); + } + } + } + else + { + return (); + } + + return 0 if @loffset <= 1 || ($loffset[$#loffset] - $loffset[$[]) <= 1; + + ;# EOF - 1.1 * avg(line) * $cnt + local($val) = $loffset[$#loffset] + - $cnt * 11 * (($loffset[$#loffset] - $loffset[$[]) / @loffset) / 10; + return ($val < 0) ? 0 : $val; + } +} + +;# initial setup of plot +print "initialize plotting\n" if $verbose; +if (defined($PrintIt)) +{ + if ($PrintIt =~ m,/,) + { + print "Saving plot to file $PrintIt\n"; + print PLOT "set output '$PrintIt'\n"; + } + else + { + print "Printing plot on printer $PrintIt\n"; + print PLOT "set output '| lpr -P$PrintIt -h'\n"; + } + print PLOT "set terminal postscript landscape color solid 'Helvetica' 10\n"; +} +print PLOT "set grid\n"; +print PLOT "set tics out\n"; +print PLOT "set format y '%g '\n"; +printf PLOT "set time 47\n" unless defined($PrintIt); + +@filepos =(); +while(1) +{ + print &ctime(time) if $verbose; + + ;# update diplay characteristics + &read_config;# unless defined($PrintIt); + + unlink($tmpfile); + @filepos = &genfile($samples,$srcprefix,$tmpfile,@filepos); + + ;# make plotcmd display samples + &make_doplot; + print "Displaying plot...\n" if $verbose > 1; + print "command for plot sub process:\n$doplot----\n" if $verbose > 3; + print PLOT $doplot; +} +continue +{ + if (defined($PrintIt)) + { + delete $SIG{'CHLD'}; + print PLOT "quit\n"; + close(PLOT); + if ($PrintIt =~ m,/,) + { + print "Plot saved to file $PrintIt\n"; + } + else + { + print "Plot spooled to printer $PrintIt\n"; + } + unlink($tmpfile); + exit(0); + } + ;# wait $delay seconds + print "waiting $delay seconds ..." if $verbose > 2; + sleep($delay); + print " continuing\n" if $verbose > 2; + undef($LastFreqBaseString); +} + + +sub date_time_spec2seconds +{ + local($_) = @_; + ;# a date_time_spec consistes of: + ;# YYYY-MM-DD_HH:MM:SS.ms + ;# values can be omitted from the beginning and default than to + ;# values of current date + ;# values omitted from the end default to lowest possible values + + local($time) = time; + local($sec,$min,$hour,$mday,$mon,$year) + = localtime($time); + + local($last) = (); + + s/^\D*(.*\d)\D*/\1/; # strip off garbage + + PARSE: + { + if (s/^(\d{4})(-|$)//) + { + if ($1 < 1970) + { + warn("$0: can not handle years before 1970 - year $1 ignored\n"); + return undef; + } + elsif ( $1 >= 2070) + { + warn("$0: can not handle years past 2070 - year $1 ignored\n"); + return undef; + } + else + { + $year = $1 % 100; # 0<= $year < 100 + ;# - interpreted 70 .. 99,00 .. 69 + } + $last = $[ + 5; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec: \"$_\" found after YEAR\n"), + return(undef) + if $2 eq ''; + } + + if (s/^(\d{1,2})(-|$)//) + { + warn("$0: implausible month $1\n"),return(undef) + if $1 < 1 || $1 > 12; + $mon = $1 - 1; + $last = $[ + 4; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec: \"$_\" found after MONTH\n"), + return(undef) + if $2 eq ''; + } + else + { + warn("$0: bad date_time_spec \"$_\"\n"),return(undef) + if defined($last); + + } + + if (s/^(\d{1,2})([_ ]|$)//) + { + warn("$0: implausible month day $1 for month ".($mon+1)." (". + $MaxNumDaysPerMonth[$mon].")$mon\n"), + return(undef) + if $1 < 1 || $1 > $MaxNumDaysPerMonth[$mon]; + $mday = $1; + $last = $[ + 3; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec \"$_\" found after MDAY\n"), + return(undef) + if $2 eq ''; + } + else + { + warn("$0: bad date_time_spec \"$_\"\n"), return undef + if defined($last); + } + + ;# now we face a problem: + ;# if ! defined($last) a prefix of "07:" + ;# can be either 07:MM or 07:ss + ;# to get the second interpretation make the user add + ;# a msec fraction part and check for this special case + if (! defined($last) && s/^(\d{1,2}):(\d{1,2}\.\d+)//) + { + warn("$0: implausible minute $1\n"), return undef + if $1 < 0 || $1 >= 60; + warn("$0: implausible second $1\n"), return undef + if $2 < 0 || $2 >= 60; + $min = $1; + $sec = $2; + $last = $[ + 1; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec \"$_\" after SECONDS\n"); + return undef; + } + + if (s/^(\d{1,2})(:|$)//) + { + warn("$0: implausible hour $1\n"), return undef + if $1 < 0 || $1 > 24; + $hour = $1; + $last = $[ + 2; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec found \"$_\" after HOUR\n"), + return undef + if $2 eq ''; + } + else + { + warn("$0: bad date_time_spec \"$_\"\n"), return undef + if defined($last); + } + + if (s/^(\d{1,2})(:|$)//) + { + warn("$0: implausible minute $1\n"), return undef + if $1 < 0 || $1 >=60; + $min = $1; + $last = $[ + 1; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec found \"$_\" after MINUTE\n"), + return undef + if $2 eq ''; + } + else + { + warn("$0: bad date_time_spec \"$_\"\n"), return undef + if defined($last); + } + + if (s/^(\d{1,2}(\.\d+)?)//) + { + warn("$0: implausible second $1\n"), return undef + if $1 < 0 || $1 >=60; + $sec = $1; + $last = $[; + last PARSE if $_ eq ''; + warn("$0: bad date_time_spec found \"$_\" after SECOND\n"); + return undef; + } + } + + return $time unless defined($last); + + $sec = 0 if $last > $[; + $min = 0 if $last > $[ + 1; + $hour = 0 if $last > $[ + 2; + $mday = 1 if $last > $[ + 3; + $mon = 0 if $last > $[ + 4; + local($rtime) = &timelocal($sec,$min,$hour,$mday,$mon,$year, 0,0, 0); + + ;# $rtime may be off if daylight savings time is in effect at given date + return $rtime + ($sec - int($sec)) + if $hour == (localtime($rtime))[$[+2]; + return + &timelocal($sec,$min,$hour,$mday,$mon,$year, 0,0, 1) + + ($sec - int($sec)); +} + + +sub min +{ + local($m) = shift; + + grep((($m > $_) && ($m = $_),0),@_); + $m; +} + +sub max +{ + local($m) = shift; + + grep((($m < $_) && ($m = $_),0),@_); + $m; +} diff --git a/contrib/xntpd/scripts/monitoring/ntptrap b/contrib/xntpd/scripts/monitoring/ntptrap new file mode 100644 index 0000000000..69c66608af --- /dev/null +++ b/contrib/xntpd/scripts/monitoring/ntptrap @@ -0,0 +1,453 @@ +#!/local/bin/perl --*-perl-*- +;# +;# ntptrap,v 3.1 1993/07/06 01:09:15 jbj Exp +;# +;# a client for the xntp mode 6 trap mechanism +;# +;# Copyright (c) 1992 +;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg +;# +;# +;############################################################# +$0 =~ s!^.*/([^/]+)$!\1!; # strip to filename +;# enforce STDOUT and STDERR to be line buffered +$| = 1; +select((select(STDERR),$|=1)[$[]); + +;####################################### +;# load utility routines and definitions +;# +require('ntp.pl'); # implementation of the NTP protocol +eval { require('sys/socket.ph'); require('netinet/in.ph') unless defined(&INADDR_ANY); } || +do { + die("$0: $@") unless $[ == index($@, "Can't locate "); + warn "$0: $@"; + warn "$0: supplying some default definitions\n"; + eval 'sub INADDR_ANY { 0; } sub AF_INET {2;} sub SOCK_DGRAM {2;} 1;' || die "$0: $@"; +}; +require('getopts.pl'); # option parsing +require('ctime.pl'); # date/time formatting + +;###################################### +;# define some global constants +;# +$BASE_TIMEOUT=10; +$FRAG_TIMEOUT=10; +$MAX_TRY = 5; +$REFRESH_TIME=60*15; # 15 minutes (server uses 1 hour) +$ntp'timeout = $FRAG_TIMEOUT; #'; + +;###################################### +;# now process options +;# +sub usage +{ + die("usage: $0 [-n] [-p ] [-l ] [host] ...\n"); +} + +$opt_l = "/dev/null"; # where to write debug messages to +$opt_p = 0; # port to use locally - (0 does mean: will be choosen by kernel) + +&usage unless &Getopts('l:p:'); +&Getopts if 0; # make -w happy + +@Hosts = ($#ARGV < $[) ? ("localhost") : @ARGV; + +;# setup for debug output +$DEBUGFILE=$opt_l; +$DEBUGFILE="&STDERR" if $DEBUGFILE eq '-'; + +open(DEBUG,">>$DEBUGFILE") || die("Cannot open \"$DEBUGFILE\": $!\n"); +select((select(DEBUG),$|=1)[$[]); + +;# &log prints a single trap record (adding a (local) time stamp) +sub log +{ + chop($date=&ctime(time)); + print "$date ",@_,"\n"; +} + +sub debug +{ + print DEBUG @_,"\n"; +} +;# +$proto_udp = (getprotobyname('udp'))[$[+2] || + (warn("$0: Could not get protocoll number for 'udp' using 17"), 17); + +$ntp_port = (getservbyname('ntp','udp'))[$[+2] || + (warn("$0: Could not get port number for service ntp/udp using 123"), 123); + +;# +socket(S, &AF_INET, &SOCK_DGRAM, $proto_udp) || die("Cannot open socket: $!\n"); + +;# +bind(S, pack("S n N x8", &AF_INET, $opt_p, &INADDR_ANY)) || + die("Cannot bind: $!\n"); + +($my_port, $my_addr) = (unpack("S n a4 x8",getsockname(S)))[$[+1,$[+2]; +&log(sprintf("Listening at address %d.%d.%d.%d port %d", + unpack("C4",$my_addr), $my_port)); + +;# disregister with all servers in case of termination +sub cleanup +{ + &log("Aborted by signal \"$_[$[]\"") if defined($_[$[]); + + foreach (@Hosts) + { + &ntp'send(S,31,0,"",pack("Sna4x8",&AF_INET,$ntp_port,$Hosts{$_})); #'; + } + close(S); + exit(2); +} + +$SIG{'HUP'} = 'cleanup'; +$SIG{'INT'} = 'cleanup'; +$SIG{'QUIT'} = 'cleanup'; +$SIG{'TERM'} = 'cleanup'; + +0 && $a && $b; +sub timeouts # sort timeout id array +{ + $TIMEOUTS{$a} <=> $TIMEOUTS{$b}; +} + +;# a Request element looks like: pack("a4SC",addr,associd,op) +@Requests= (); + +;# compute requests for set trap control msgs to each host given +{ + local($name,$addr); + + foreach (@Hosts) + { + if (/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) + { + ($name,$addr) = + (gethostbyaddr(pack("C4",$1,$2,$3,$4),&AF_INET))[$[,$[+4]; + unless (defined($name)) + { + $name = sprintf("[[%d.%d.%d.%d]]",$1,$2,$3,$4); + $addr = pack("C4",$1,$2,$3,$4); + } + } + else + { + ($name,$addr) = (gethostbyname($_))[$[,$[+4]; + unless (defined($name)) + { + warn "$0: unknown host \"$_\" - ignored\n"; + next; + } + } + next if defined($Host{$name}); + $Host{$name} = $addr; + push(@Requests,pack("a4SC",$addr,0,6)); # schedule a set trap request for $name + } +} + +sub hostname +{ + local($addr) = @_; + return $HostName{$addr} if defined($HostName{$addr}); + local($name) = gethostbyaddr($addr,&AF_INET); + &debug(sprintf("hostname(%d.%d.%d.%d) = \"%s\"",unpack("C4",$addr),$name)) + if defined($name); + defined($name) && ($HostName{$addr} = $name) && (return $name); + &debug(sprintf("Failed to get name for %d.%d.%d.%d",unpack("C4",$addr))); + return sprintf("[%d.%d.%d.%d]",unpack("C4",$addr)); +} + +;# when no hosts were given on the commandline no requests have been scheduled +&usage unless (@Requests); + +&debug(sprintf("%d request(s) scheduled",scalar(@Requests))); +grep(&debug(" - ".$_),keys(%Host)); + +;# allocate variables; +$addr=""; +$assoc=0; +$op = 0; +$timeout = 0; +$ret=""; +%TIMEOUTS = (); +%TIMEOUT_PROCS = (); +@TIMEOUTS = (); + +$len = 512; +$buf = " " x $len; + +while (1) +{ + if (@Requests || @TIMEOUTS) # if there is some work pending + { + if (@Requests) + { + ($addr,$assoc,$op) = unpack("a4SC",($req = shift(@Requests))); + &debug(sprintf("Request: %s: %s(%d)",&hostname($addr), &ntp'cntrlop_name($op), $assoc)); #';)) + $ret = &ntp'send(S,$op,$assoc,"", #'( + pack("Sna4x8",&AF_INET,$ntp_port,$addr)); + &set_timeout("retry-".unpack("H*",$req),time+$BASE_TIMEOUT, + sprintf("&retry(\"%s\");",unpack("H*",$req))); + + last unless (defined($ret)); # warn called by ntp'send(); + + ;# if there are more requests just have a quick look for new messages + ;# otherwise grant server time for a response + $timeout = @Requests ? 0 : $BASE_TIMEOUT; + } + if ($timeout && @TIMEOUTS) + { + ;# ensure not to miss a timeout + if ($timeout + time > $TIMEOUTS{$TIMEOUTS[$[]}) + { + $timeout = $TIMEOUTS{$TIMEOUTS[$[]} - time; + $timeout = 0 if $timeout < 0; + } + } + } + else + { + ;# no work yet - wait for some messages dropping in + ;# usually this will not hapen as the refresh semantic will + ;# always have a pending timeout + undef($timeout); + } + + vec($mask="",fileno(S),1) = 1; + $ret = select($mask,undef,undef,$timeout); + + warn("$0: select: $!\n"),last if $ret < 0; # give up on error return from select + + if ($ret == 0) + { + ;# timeout + if (@TIMEOUTS && time > $TIMEOUTS{$TIMEOUTS[$[]}) + { + ;# handle timeout + $timeout_proc = + (delete $TIMEOUT_PROCS{$TIMEOUTS[$[]}, + delete $TIMEOUTS{shift(@TIMEOUTS)})[$[]; + eval $timeout_proc; + die "timeout eval (\"$timeout_proc\"): $@\n" if $@; + } + ;# else: there may be something to be sent + } + else + { + ;# data avail + $from = recv(S,$buf,$len,0); + ;# give up on error return from recv + warn("$0: recv: $!\n"), last unless (defined($from)); + + $from = (unpack("Sna4",$from))[$[+2]; # keep host addr only + ;# could check for ntp_port - but who cares + &debug("-Packet from ",&hostname($from)); + + ;# stuff packet into ntp mode 6 receive machinery + ($ret,$data,$status,$associd,$op,$seq,$auth_keyid) = + &ntp'handle_packet($buf,$from); # '; + &debug(sprintf("%s uses auth_keyid %d",&hostname($from),$auth_keyid)) if defined($auth_keyid); + next unless defined($ret); + + if ($ret eq "") + { + ;# handle packet + ;# simple trap response messages have neither timeout nor retries + &clear_timeout("retry-".unpack("H*",pack("a4SC",$from,$associd,$op))) unless $op == 7; + delete $RETRY{pack("a4SC",$from,$associd,$op)} unless $op == 7; + + &process_response($from,$ret,$data,$status,$associd,$op,$seq,$auth_keyid); + } + else + { + ;# some kind of error + &log(sprintf("%50s: %s: %s",(gethostbyaddr($from,&AF_INET))[$[],$ret,$data)); + if ($ret ne "TIMEOUT" && $ret ne "ERROR") + { + &clear_timeout("retry-".unpack("H*",pack("a4SC",$from,$associd,$op))); + } + } + } + +} + +warn("$0: terminating\n"); +&cleanup; +exit 0; + +;################################################## +;# timeout support +;# +sub set_timeout +{ + local($id,$time,$proc) = @_; + + $TIMEOUTS{$id} = $time; + $TIMEOUT_PROCS{$id} = $proc; + @TIMEOUTS = sort timeouts keys(%TIMEOUTS); + chop($date=&ctime($time)); + &debug(sprintf("Schedule timeout \"%s\" for %s", $id, $date)); +} + +sub clear_timeout +{ + local($id) = @_; + delete $TIMEOUTS{$id}; + delete $TIMEOUT_PROCS{$id}; + @TIMEOUTS = sort timeouts keys(%TIMEOUTS); + &debug("Clear timeout \"$id\""); +} + +0 && &refresh; +sub refresh +{ + local($addr) = @_; + $addr = pack("H*",$addr); + &debug(sprintf("Refreshing trap for %s", &hostname($addr))); + push(@Requests,pack("a4SC",$addr,0,6)); +} + +0 && &retry; +sub retry +{ + local($tag) = @_; + $tag = pack("H*",$tag); + $RETRY{$tag} = 0 if (!defined($RETRY{$tag})); + + if (++$RETRY{$tag} > $MAX_TRY) + { + &debug(sprintf("Retry failed: %s assoc %5d op %d", + &hostname(substr($tag,$[,4)), + unpack("x4SC",$tag))); + return; + } + &debug(sprintf("Retrying: %s assoc %5d op %d", + &hostname(substr($tag,$[,4)), + unpack("x4SC",$tag))); + push(@Requests,$tag); +} + +sub process_response +{ + local($from,$ret,$data,$status,$associd,$op,$seq,$auth_keyid) = @_; + + $msg=""; + if ($op == 7) # trap response + { + $msg .= sprintf("%40s trap#%-5d", + &hostname($from),$seq); + &debug (sprintf("\nTrap %d associd %d:\n%s\n===============\n",$seq,$associd,$data)); + if ($associd == 0) # system event + { + $msg .= " SYSTEM "; + $evnt = &ntp'SystemEvent($status); #'; + $msg .= "$evnt "; + ;# for special cases add additional info + ($stratum) = ($data =~ /stratum=(\d+)/); + ($refid) = ($data =~ /refid=([\w\.]+)/); + $msg .= "stratum=$stratum refid=$refid"; + if ($refid =~ /\[?(\d+)\.(\d+)\.(\d+)\.(\d+)/) + { + $msg .= " " . (gethostbyaddr(pack("C4",$1,$2,$3,$4),&AF_INET))[$[]; + } + if ($evnt eq "event_sync_chg") + { + $msg .= sprintf("%s %s ", + &ntp'LI($status), #', + &ntp'ClockSource($status) #' + ); + } + elsif ($evnt eq "event_sync/strat_chg") + { + ($peer) = ($data =~ /peer=([0-9]+)/); + $msg .= " peer=$peer"; + } + elsif ($evnt eq "event_clock_excptn") + { + if (($device) = ($data =~ /device=\"([^\"]+)\"/)) + { + ($cstatus) = ($data =~ /refclockstatus=0?x?([\da-fA-F]+)/); + $Cstatus = hex($cstatus); + $msg .= sprintf("- %-32s",&ntp'clock_status($Cstatus)); #'); + ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/); + $msg .= " \"$device\" \"$timecode\""; + } + else + { + push(@Requests,pack("a4SC",$from, $associd, 4)); + } + } + } + else # peer event + { + $msg .= sprintf("peer %5d ",$associd); + ($srcadr) = ($data =~ /srcadr=\[?([\d\.]+)/); + $msg .= sprintf("%-18s %40s ", "[$srcadr]", + &hostname(pack("C4",split(/\./,$srcadr)))); + $evnt = &ntp'PeerEvent($status); #'; + $msg .= "$evnt "; + ;# for special cases include additional info + if ($evnt eq "event_clock_excptn") + { + if (($device) = ($data =~ /device=\"([^\"]+)\"/)) + { + ;#&debug("----\n$data\n====\n"); + ($cstatus) = ($data =~ /refclockstatus=0?x?([\da-fA-F]+)/); + $Cstatus = hex($cstatus); + $msg .= sprintf("- %-32s",&ntp'clock_status($Cstatus)); #'); + ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/); + $msg .= " \"$device\" \"$timecode\""; + } + else + { + ;# no clockvars included - post a cv request + push(@Requests,pack("a4SC",$from, $associd, 4)); + } + } + elsif ($evnt eq "event_stratum_chg") + { + ($stratum) = ($data =~ /stratum=(\d+)/); + $msg .= "new stratum $stratum"; + } + } + } + elsif ($op == 6) # set trap resonse + { + &debug("Set trap ok from ",&hostname($from)); + &set_timeout("refresh-".unpack("H*",$from),time+$REFRESH_TIME, + sprintf("&refresh(\"%s\");",unpack("H*",$from))); + return; + } + elsif ($op == 4) # read clock variables response + { + ;# status of clock + $msg .= sprintf(" %40s ", &hostname($from)); + if ($associd == 0) + { + $msg .= "system clock status: "; + } + else + { + $msg .= sprintf("peer %5d clock",$associd); + } + $msg .= sprintf("%-32s",&ntp'clock_status($status)); #'); + ($device) = ($data =~ /device=\"([^\"]+)\"/); + ($timecode) = ($data =~ /timecode=\"([^\"]+)\"/); + $msg .= " \"$device\" \"$timecode\""; + } + elsif ($op == 31) # unset trap response (UNOFFICIAL op) + { + ;# clear timeout + &debug("Clear Trap ok from ",&hostname($from)); + &clear_timeout("refresh-".unpack("H*",$from)); + return; + } + else # unexpected response + { + $msg .= "unexpected response to op $op assoc=$associd"; + $msg .= sprintf(" status=%04x",$status); + } + &log($msg); +} diff --git a/contrib/xntpd/scripts/monitoring/timelocal.pl b/contrib/xntpd/scripts/monitoring/timelocal.pl new file mode 100644 index 0000000000..d0f73a2366 --- /dev/null +++ b/contrib/xntpd/scripts/monitoring/timelocal.pl @@ -0,0 +1,77 @@ +;# timelocal.pl +;# +;# Usage: +;# $time = timelocal($sec,$min,$hours,$mday,$mon,$year,$junk,$junk,$isdst); +;# $time = timegm($sec,$min,$hours,$mday,$mon,$year); + +;# These routines are quite efficient and yet are always guaranteed to agree +;# with localtime() and gmtime(). We manage this by caching the start times +;# of any months we've seen before. If we know the start time of the month, +;# we can always calculate any time within the month. The start times +;# themselves are guessed by successive approximation starting at the +;# current time, since most dates seen in practice are close to the +;# current date. Unlike algorithms that do a binary search (calling gmtime +;# once for each bit of the time value, resulting in 32 calls), this algorithm +;# calls it at most 6 times, and usually only once or twice. If you hit +;# the month cache, of course, it doesn't call it at all. + +;# timelocal is implemented using the same cache. We just assume that we're +;# translating a GMT time, and then fudge it when we're done for the timezone +;# and daylight savings arguments. The timezone is determined by examining +;# the result of localtime(0) when the package is initialized. The daylight +;# savings offset is currently assumed to be one hour. + +CONFIG: { + package timelocal; + + @epoch = localtime(0); + $tzmin = $epoch[2] * 60 + $epoch[1]; # minutes east of GMT + if ($tzmin > 0) { + $tzmin = 24 * 60 - $tzmin; # minutes west of GMT + $tzmin -= 24 * 60 if $epoch[5] == 70; # account for the date line + } + + $SEC = 1; + $MIN = 60 * $SEC; + $HR = 60 * $MIN; + $DAYS = 24 * $HR; + $YearFix = ((gmtime(946684800))[5] == 100) ? 100 : 0; +} + +sub timegm { + package timelocal; + + $ym = pack(C2, @_[5,4]); + $cheat = $cheat{$ym} || &cheat; + $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS; +} + +sub timelocal { + package timelocal; + + $ym = pack(C2, @_[5,4]); + $cheat = $cheat{$ym} || &cheat; + $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS + + $tzmin * $MIN - 60 * 60 * ($_[8] != 0); +} + +package timelocal; + +sub cheat { + $year = $_[5]; + $month = $_[4]; + $guess = $^T; + @g = gmtime($guess); + $year += $YearFix if $year < $epoch[5]; + while ($diff = $year - $g[5]) { + $guess += $diff * (364 * $DAYS); + @g = gmtime($guess); + } + while ($diff = $month - $g[4]) { + $guess += $diff * (28 * $DAYS); + @g = gmtime($guess); + } + $g[3]--; + $guess -= $g[0] * $SEC + $g[1] * $MIN + $g[2] * $HR + $g[3] * $DAYS; + $cheat{$ym} = $guess; +} diff --git a/contrib/xntpd/scripts/ntp-groper b/contrib/xntpd/scripts/ntp-groper new file mode 100644 index 0000000000..1fd0cfe4c2 --- /dev/null +++ b/contrib/xntpd/scripts/ntp-groper @@ -0,0 +1,95 @@ +#!/bin/sh +# +# ntpgroper host ... +# +# This script checks each hostname given as an argument to see if +# it is running NTP. It reports one of the following messages (assume +# the host is named "dumbo.hp.com": +# +# dumbo.hp.com not registered in DNS +# dumbo.hp.com not responding to ping +# dumbo.hp.com refused ntpq connection +# dumbo.hp.com not responding to NTP +# dumbo.hp.com answers NTP version 2, stratum: 3, ref: telford.nsa.hp.com +# dumbo.hp.com answers NTP version 3, stratum: 3, ref: telford.nsa.hp.com +# +# It ain't pretty, but it is kinda useful. +# +# Walter Underwood, 11 Feb 1993, wunder@hpl.hp.com +# +# converted to /bin/sh from /bin/ksh by scott@ee.udel.edu 24 Mar 1993 + +PATH="/usr/local/etc:$PATH" export PATH + +verbose=1 +logfile=/tmp/cntp-log$$ +ntpqlog=/tmp/cntp-ntpq$$ + +# I wrap the whole thing in parens so that it is possible to redirect +# all the output somewhere, if desired. +( +for host in $* +do + # echo "Trying $host." + + gethost $host > /dev/null 2>&1 + if [ $? -ne 0 ] + then + echo "$host not registered in DNS" + continue + fi + + ping $host 64 1 > /dev/null 2>&1 + if [ $? -ne 0 ] + then + echo "$host not responding to ping" + continue + fi + + # Attempt to contact with version 3 ntp, then try version 2. + for version in 3 2 + do + + ntpq -c "ntpversion $version" -p $host > $ntpqlog 2>&1 + + if fgrep -s 'Connection refused' $ntpqlog + then + echo "$host refused ntpq connection" + break + fi + + responding=1 + fgrep -s 'timed out, nothing received' $ntpqlog > /dev/null && responding=0 + + if [ $responding -eq 1 ] + then + ntpq -c "ntpversion $version" -c rl $host > $ntpqlog + + # First we extract the reference ID (usually a host or a clock) + synchost=`fgrep "refid=" $ntpqlog` + #synchost=${synchost##*refid=} # strip off the beginning of the line + #synchost=${synchost%%,*} # strip off the end + synchost=`expr "$synchost" : '.*refid=\([^,]*\),.*'` + + # Next, we get the stratum + stratum=`fgrep "stratum=" $ntpqlog` + #stratum=${stratum##*stratum=} + #stratum=${stratum%%,*} + stratum=`expr "$stratum" : '.*stratum=\([^,]*\),.*'` + + echo "$host answers NTP version $version, stratum: $stratum, ref: $synchost" + break; + fi + + if [ $version -eq 2 -a $responding -eq 0 ] + then + echo "$host not responding to NTP" + fi + done +done +) +# ) >> $logfile + +if [ -f $ntpqlog ]; then + rm $ntpqlog +fi diff --git a/contrib/xntpd/scripts/ntp-restart b/contrib/xntpd/scripts/ntp-restart new file mode 100644 index 0000000000..d2023f0b67 --- /dev/null +++ b/contrib/xntpd/scripts/ntp-restart @@ -0,0 +1,9 @@ +#!/bin/sh +# +# This script can be used to kill and restart the NTP daemon. Edit the +# /usr/local/bin/xntpd line to fit. +# +kill -INT `ps -ax | egrep "xntpd" | egrep -v "egrep" | sed 's/^\([ 0-9]*\) .*/\1'/` +sleep 10 +/usr/local/bin/xntpd +exit 0 diff --git a/contrib/xntpd/scripts/stats/README b/contrib/xntpd/scripts/stats/README new file mode 100644 index 0000000000..5aa64d4c1d --- /dev/null +++ b/contrib/xntpd/scripts/stats/README @@ -0,0 +1,32 @@ +Statistics processing scripts (README) + +This directory contains a number of scripts for use with the filegen +facility. Those files ending in .awk are for the Unix awk utility, while +those ending in .sh are for the csh utility. Normally, the summary.sh +script is called from a cron job once per day. This script calls the +peer.sh script to process the peerstats file and append the summary +statistics to the peer_summary file. Then, it callse the loop.sh script +to process the loopstats file and append the summary statistics to the +loop_summary file. Finally, it calls the clock.sh script to process the +clockstats file and append the summary statistics to the clock_summary +file. + +Each of the three shell scripts peer.sh, loop.sh and clock.sh invoke +one or more awk scripts to actually produce the data. This may result +in multiple scans of the same input file. The input file is deleted after +processing. In fact, the shell scripts will process all input files +found of the correct type in chronological order, deleting each one as +it is scanned, except the current day file. + +The psummary.awk script can be used to scan the peer_summary file and +construct an historical reprise of the daily summaries. + +The file formats are documented in the README.stats file and in the +scripts themselves. Further detail on the radio clock ASCII timecode +formats and related data are in the README.timecode file. + +David L. Mills +University of Delaware +mills@udel.edu +1 November 1993 + diff --git a/contrib/xntpd/scripts/stats/README.stats b/contrib/xntpd/scripts/stats/README.stats new file mode 100644 index 0000000000..aa8e77fb1b --- /dev/null +++ b/contrib/xntpd/scripts/stats/README.stats @@ -0,0 +1,246 @@ +Statistics file formats (README.stats) + +The xntp3 daemon can produce a variety of statistics files which are +useful for maintenance, evaluation and retrospective calibration +purposes. See the xntpd.8 man page for instructions on how to configure +this feature. Since these files can become rather large and cumbersome, +they are ordinarily reduced to summary form by running the summary.sh +shell script once per day, week or month, as appropriate. There are +three file collections presently defined: peerstats, loopstats and +clockstats, each of which is described in this note. + +peerstats + +The following data are collected in the peerstats files. The files are +reduced to summary data using the peer.sh shell script. See the peer.awk +script for further information. A line in the file is produced upon +reception of each valid update from a configured peer. + + 49236 30.756 140.173.96.1 9474 0.000603 0.37532 + + 49236 modified Julian day number + 30.756 time of day (s) past midnight UTC + 140.173.96.1 peer identifier (IP address or receiver identifier) + 9474 peer status word (hex) (see NTP specification) + 0.000603 offset (s) + 0.08929 delay (s) + 0.37532 dispersion (s) + +loopstats + +The following data are collected in the loopstats files. The files are +reduced to summary data using the loop.sh shell script. See the loop.awk +script for further information. A line in the file is produced at each +valid update of the local clock. + + 49236 11.897 -0.000004 -35.9384 0 + + 49236 modified Julian day number + 11.897 time of day (s) past midnight UTC + -0.000004 time offset (s) + -35.9384 frequency offset (ppm) + 0 phase-lock loop time constant + +clockstats + +The following data are collected in the clockstats files. The files are +reduced to summary data using the clock.sh shell script, which also +updates the ensemble, etf, itf and tdata data files as well. See the +clock.awk, ensemble.awk, etf.awk, itf.awk and tdta.awk scripts for +further information. A line in the file is produced at each valid update +received from a configured radio clock. Data are at present recorded for +several radios. The first part of each data line is similar for all +radios, e.g.: + + 49234 60517.826 127.127.4.1 93 247 16:48:21.814 + + 49234 modified Julian day number + 60517.826 time of day (s) past midnight UTC + 127.127.4.1 receiver identifier (Spectracom 8170/Netclock-2) + 93 247 16:48:21.814 timecode (format varies) + +In the case of the Austron GPS receiver, a good deal of additional +information is extracted from the radio, as described below. The formats +shown consist of one line with all the fields shown in order. The +timecode formats specific to each radio follow. See the file +README.timecodes for detailed information on the timecode formats used +by these radios. + +Spectracom 8170/Netclock-2 WWVB receiver + + 49234 60517.826 127.127.4.1 ?A93 247 16:48:21.814 + + The '?' and 'A' characters are present only when the receiver is + unsynchronized; otherwise, they are replaced by space ' ' characters. + +IRIG audio decoder + + 49234 60517.826 127.127.6.0 247 16:48:21? + + The '?' character is present only when the receiver is unsynchronized. + +Austron 2200A/2201A GPS receiver + + 49234 60580.843 127.127.10.1 93:247:16:49:24.814? + + The '?' character is present only when the receiver is unsynchronized. + +Depending on the installed options, the Austron 2200A/2201A recognizes a +number of special commands that report various data items. See the +refclock_as2201.c source module for a list of the commands used. These +data are collected only if the following line is included in the +configuration file ntp.conf: + + fudge 127.127.10.1 flag4 1 # enable extended statistics collection + +The format of each data line returned is summarized in the following +list. + +External time/frequency data (requires input buffer option IN) + +These data determine the deviations of external time/frequency inputs +relative to receiver oscillator time. The following data are typical +using an external cesium oscillator PPS and 5-MHz outputs. + + 49234 60580.843 127.127.10.1 93:247:16:49:24.814 ETF + + -85.9 time interval (ns) + -89.0 average time interval (ns) + 4.0 time interval sigma (ns) + +1.510E-11 time interval rate + -4.500E-11 deltaf/f + +1.592E-11 average deltaf/f + 5.297E-13 sigma deltaf/f + 500 number of samples + +Model and option identifiers + +These data show the receiver model number and option configuration. + + 49234 60708.848 127.127.10.1 93:247:16:51:32.817 ID;OPT;VER + + GPS 2201A model ident (must be "GPS 2200A" or "GPS 2201A") + TTY1 rs232 option present (required) + TC1 IRIG option present (optional) + LORAN LORAN assist option present (optional) + IN input buffer option present (optional) + OUT1 output buffer option present (required) + B.00 data processor software version ("B.00" or later) + B.00 signal processor software version ("B.00" or later) + 28-Apr-93 software version date ("28-Apr-93" or later) + +Internal time/frequency data + +These data determine the deviations of the receiver oscillator with +respect to satellite time. + + 49234 60564.846 127.127.10.1 93:247:16:49:08.816 ITF + + COCO current mode (must be "COCO") + 0 code coast mode (must be zero) + +6.6152E-08 code sigma (s) + -3.5053E-08 code delta t (s) + -4.0361E-11 deltat/t + -6.4746E-11 oscillator ageing rate + 500.00 loop time constant + 4.984072 electrical tuning (V) + +GPS/LORAN ensemble data (requires LORAN assist option LORAN) + +These data determine the deviations and weights to calculate ensemble +time from GPS and LORAN data. + + 49234 60596.852 127.127.10.1 93:247:16:49:40.812 LORAN ENSEMBLE + + +9.06E-08 GPS t (s) + +3.53E-08 GPS sigma (s) + .532 GPS weight + +3.71E-08 LORAN t (s) + +3.76E-08 LORAN sigma (s) + .468 LORAN weight + +6.56E-08 ensemble t + +6.94E-08 ensemble sigma (s) + +LORAN stationkeeping data (requires LORAN assist option LORAN) + +These data determine which stations of the LORAN chain are being +tracked, together with individual signal/noise ratios, deviations and +weights. + + 49234 60532.850 127.127.10.1 93:247:16:48:36.820 LORAN TDATA + + M station identifier; data follows + OK status (must be "OK" for tracking) + 0 cw flag + 0 sw flag + 1162.17 time of arrival + -4.6 snr (-30.0 if not "OK" status) + 1.67E-07 2-sample phase-time deviation + .507 weight (included only if "OK" status) + W AQ 0 0 3387.80 -31.0 station identifier and data + X OK 0 0 1740.27 -11.2 2.20E-07 .294 station identifier and data + Y OK 0 0 2180.71 -4.6 2.68E-07 .198 station identifier and data + Z CV 0 0 3392.94 -30.0 station identifier and data + +Oscillator status and environment + +These data determine the receiver oscillator type, mode, status and +environment. Nominal operating conditions are shown below. + + 49234 60628.847 127.127.10.1 93:247:16:50:12.817 OSC;ET;TEMP + + 1121 Software Control oscillator model and mode (must be + "Software Control") + Locked status (must be "Locked") + 4.979905 electrical tuning (V) + 44.81 oscillator cavity temperature + +Receiver position, status and offsets + +These data determine the receiver position and elevation, together with +programmable delay corrections for the antenna cable and receiver. + + 49234 60788.847 127.127.10.1 93:247:16:52:52.817 POS;PPS;PPSOFF + + +39:40:48.425 receiver latitude (N) + -075:45:02.392 receiver longitude (E) + +74.09 receiver elevation (m) + Stored position status (must be "Stored") + UTC PPS/PPM alignment (must be "UTC") + 0 receiver delay (ns) (should be zero for calibrated + receiver) + 200 cable delay (ns) + 0 user time bias (ns) (must be zero) + +Satellite tracking status + +These data determine how many satellites are being tracked. At the +present state of constellation development, there should be at least +three visible satellites in view. Much of the time the maximum of +seven are being tracked; rarely this number drops to two. + + 49234 60612.850 127.127.10.1 93:247:16:49:56.820 TRSTAT + + 24 T satellite prn and status (T = track, A = acquire) + 16 A 13 T 20 T 18 T 07 T 12 T list continued + +UTC leap-second information + +These data determine when the next leap second is to occur. The exact +method to use is obscure. + + 49234 60548.847 127.127.10.1 93:247:16:48:52.818 UTC + + -1.2107E-08 A0 term (s) + -1.2790E-13 A1 term (s) + +9.0000E+00 current leap seconds (s) + +2.0480E+05 time for leap seconds (s) + +2.0100E+02 week number for delta leap (weeks) + +1.9100E+02 week number for future leap (weeks) + +4.0000E+00 day number for future leap (days) + +9.0000E+00 future leap seconds (s) + +David L. Mills +University of Delaware +mills@udel.edu +23 October 1993 diff --git a/contrib/xntpd/scripts/stats/README.timecodes b/contrib/xntpd/scripts/stats/README.timecodes new file mode 100644 index 0000000000..00b5ba5458 --- /dev/null +++ b/contrib/xntpd/scripts/stats/README.timecodes @@ -0,0 +1,149 @@ +Radio Timecode Formats (README.timecodes) + +Following are examples of the serial timecode formats used by various +timecode receivers as given in the instruction manuals. These examples +are intended only for illustration and not as the basis of system +design. The following symbols are used to identify the timecode +character that begins a subfield. The values given after this symbol +represent the character offset from the beginning of the timecode string +as edited to remove control characters. + +C on-time character (start bit) +Y year of century +T time of day +D day of year or month/day +A alarm indicator (format specific) +Q quality indicator (format specific) + ASCII line feed (hex 0a) + ASCII carriage return (hex 0d) + ASCII space (hex 20) + +In order to promote uniform behavior in the various implementations, it +is useful to have a common interpretation of alarm conditions and signal +quality. When the alarm indicator it on, the receiver is not operating +correctly or has never synchronized to the broadcast signal. When the +alarm indicator is off and the quality indicator is on, the receiver has +synchronized to the broadcast signal, then lost the signal and is +coasting on its internal oscillator. + +In the following uppercase letters, punctuation marks and spaces +stand for themselves; lowercase letters stand for fields as described. +Special characters other than , and are preceded by ^. + +Spectracom 8170 and Netclock/2 WWV Synchonized Clock (format 0) + +"i ddd hh:mm:ss TZ=zz" + C A D T + + poll: ?; offsets: Y = none, D = 3, T = 7, A = 0, Q = none + i = synchronization flag ( = in synch, ? = out synch) + ddd = day of year + hh:mm:ss = hours, minutes, seconds + zz = timezone offset (hours from UTC) + + Note: alarm condition is indicated by other than at A, which + occurs during initial synchronization and when received signal has + been lost for about ten hours + + example: " 216 15:36:43 TZ=0" + A D T + +Netclock/2 WWV Synchonized Clock (format 2) + +"iqyy ddd hh:mm:ss.fff ld" + C AQY D T + + poll: ?; offsets: Y = 2, D = 5, T = 9, A = 0, Q = 1 + i = synchronization flag ( = in synch, ? = out synch) + q = quality indicator ( < 1ms, A < 10 ms, B < 100 ms, C < 500 + ms, D > 500 ms) + yy = year (as broadcast) + ddd = day of year + hh:mm:ss.fff = hours, minutes, seconds, milliseconds of day + l = leap-second warning (L indicates leap at end of month) + d = standard/daylight time indicator ( standard, D daylight) + + Note: alarm condition is indicated by other than at A, which + occurs during initial synchronization and when received signal has + been lost for about ten hours; unlock condition is indicated by + other than at Q, with time since last lock indicated by the + letter code A < 13 min, B < 1.5 hr, C < 7 hr, D > 7 hr. + + example: " 92 216 15:36:43.640 D" + AQ D T + +TrueTime 468-DC Satellite Synchronized Clock (and other TrueTime +receivers) + +"<^A>ddd:hh:mm:ssq" + D T QC + + poll: none; offsets: Y = none, D = 0, T = 4, A = 12, Q = 12 + hh:mm:ss = hours, minutes, seconds + q = quality/alarm indicator ( = locked, ? = alarm) + + Note: alarm condition is indicated by ? at A, which occurs during + initial synchronization and when received signal is lost for an + extended period; unlock condition is indicated by other than + at Q + + example: "216:15:36:43 " + D T Q + +Heath GC-1000 Most Accurate Clock (WWV/H) + +"hh:mm:ss.f dd/mm/yy" + C T A D + + poll: none; offsets: Y = none, D = 15, T = 0, A = 9, Q = none + hh:mm:ss = hours, minutes, seconds + f = deciseconds (? when out of spec) + dd/mm = day, month + yy = year of century (from DIPswitches) + + Note: 0?:??:??.? is displayed before synch is first established and + hh:mm:ss.? once synch is established and then lost again for about + a day. + + example: "15:36:43.6 04/08/91" + T A D Y + +PST/Traconex 1020 Time Source (WWV/H) (firmware revision V4.01) + +"frdzycchhSSFTttttuuxx" "ahh:mm:ss.fffs" "yy/dd/mm/ddd" + A Q T Y D + + poll: "QMQDQT"; offsets: Y = 0, D = 3 T = 1,, A = 11, Q = 13 + 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 = 1991) + 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 (1-5 = 2.5, 5, 10, 15, 20 MHz) + T = transmitter (C = WWV, H = WWVH) + tttt = time since last update (minutes) + uu = flush character (03 = ^C) + xx = 94 (unknown) (firmware revision X4.01.999 only) + + a = AM/PM indicator (A = AM, P = PM, - 24-hour format) + hh:mm:ss.fff = hours, minutes, seconds, milliseconds of day + s = daylight-saving indicator ( standard, D daylight) + + yy = year of century (from DIPswitches) + dd/mm/ddd = day of month, month of year, day of year + + Note: The alarm condition is indicated by other than ? at A, which + occurs during initial synchronization and when received signal is + lost for an extended period. A receiver unlock condition is + indicated by other than "0000" in the tttt subfield at Q. + + example: "O3@055281824C00000394 91/08/04/216 15:36:43.640" + T Y D T + +David L. Mills +University of Delaware +mills@udel.edu +23 October 1993 diff --git a/contrib/xntpd/scripts/stats/clock.awk b/contrib/xntpd/scripts/stats/clock.awk new file mode 100644 index 0000000000..f6afc994fd --- /dev/null +++ b/contrib/xntpd/scripts/stats/clock.awk @@ -0,0 +1,341 @@ +# awk program to scan clockstat files and report errors/statistics +# +# usage: awk -f check.awk clockstats +# +# This program works for Spectracom 8170/Netclock-2 receiver, Austron +# 2200A/2201A receiver and IRIG audio decoder. It is easily adapted to +# other receivers as required. See README.austron file for additional +# information on Austron receiver. +# +BEGIN { + etf_min = osc_vmin = osc_tmin = 1e9 + etf_max = osc_vmax = osc_tmax = -1e9 +} +# +# scan all records in file +# +{ + # + # select WWVB records + # see summary for decode + # + if (NF >= 4 && $3 == "127.127.4.1") { + if ($4 == "SIGNAL" || NF > 7) + printf "%s\n", $0 + else { + wwvb_count++ + if ($4 ~ /\?/) + wwvb_x++ + else if ($4 ~ /A/) + wwvb_a++ + else if ($4 ~ /B/) + wwvb_b++ + else if ($4 ~ /C/) + wwvb_c++ + else if ($4 ~ /D/) + wwvb_d++ + } + continue + } + # + # select IRIG records + # see summary for decode + # + if (NF >= 4 && $3 == "127.127.6.0") { + irig_count++ + if ($5 ~ /\?/) + irig_error++ + continue + } + # + # select LORAN ENSEMBLE records + # see summary for decode + # + else if (NF >= 13 && $6 == "ENSEMBLE") { + ensemble_count++ + if ($9 <= 0) + ensemble_badgps++ + else if ($12 <= 0) + ensemble_badloran++ + else { + if ($13 > 200e-9 || $13 < -200e-9) + ensemble_200++ + else if ($13 > 100e-9 || $13 < -100e-9) + ensemble_100++ + ensemble_mean += $13 + ensemble_rms += $13 * $13 + } + continue + } + # + # select LORAN TDATA records + # see summary for decode; note that signal quality log is simply + # copied to output + # + else if (NF >= 7 && $6 == "TDATA") { + tdata_count++ + for (i = 7; i < NF; i++) { + if ($i == "M" && $(i+1) == "OK") { + i += 5 + m += $i + tdata_m++ + } + else if ($i == "W" && $(i+1) == "OK") { + i += 5 + w += $i + tdata_w++ + } + else if ($i == "X" && $(i+1) == "OK") { + i += 5 + x += $i + tdata_x++ + } + else if ($i == "Y" && $(i+1) == "OK") { + i += 5 + y += $i + tdata_y++ + } + else if ($i == "Z" && $(i+1) == "OK") { + i += 5 + z += $i + tdata_z++ + } + } + continue + } + # + # select ITF records + # see summary for decode + # + else if (NF >= 13 && $5 == "ITF" && $12 >= 500) { + itf_count++ + if ($9 > 200e-9 || $9 < -200e-9) + itf_200++ + else if ($9 > 100e-9 || $9 < -100e-9) + itf_100++ + itf_mean += $9 + itf_rms += $9 * $9 + itf_var += $10 * $10 + continue + } + # + # select ETF records + # see summary for decode + # + else if (NF >= 13 && $5 == "ETF" && $13 >= 500) { + etf_count++ + if ($6 > etf_max) + etf_max = $6 + else if ($6 < etf_min) + etf_min = $6 + etf_mean += $6 + etf_rms += $6 * $6 + etf_var += $9 * $9 + continue + } + # + # select TRSTAT records + # see summary for decode + # + else if (NF >= 5 && $5 == "TRSTAT") { + trstat_count++ + j = 0 + for (i = 6; i <= NF; i++) + if ($i == "T") + j++ + trstat_sat[j]++ + continue + } + # + # select ID;OPT;VER records + # + # config GPS 2201A TTY1 TC1 LORAN IN OUT1 B.00 B.00 28-Apr-93 + # + # GPS 2201A receiver model + # TTY1 rs232 moduel + # TC1 IRIG module + # LORAN LORAN assist module + # IN input module + # OUT1 output module + # B.00 B.00 firmware revision + # 28-Apr-9 firmware date3 + # + else if (NF >= 5 && $5 == "ID;OPT;VER") { + id_count++ + id_temp = "" + for (i = 6; i <= NF; i++) + id_temp = id_temp " " $i + if (id_string != id_temp) + printf "config%s\n", id_temp + id_string = id_temp + continue + } + # + # select POS;PPS;PPSOFF records + # + # position +39:40:48.425 -075:45:02.392 +74.09 Stored UTC 0 200 0 + # + # +39:40:48.425 position north latitude + # -075:45:02.392 position east longitude + # +74.09 elevation (meters) + # Stored position is stored + # UTC time is relative to UTC + # 0 200 0 PPS offsets + # + else if (NF >= 5 && $5 == "POS;PPS;PPSOFF") { + pos_count++ + pos_temp = "" + for (i = 6; i <= NF; i++) + pos_temp = pos_temp " " $i + if (pos_string != pos_temp) + printf "position%s\n", pos_temp + pos_string = pos_temp + continue + } + # + # select OSC;ET;TEMP records + # + # loop 1121 Software Control Locked + # + # 1121 oscillator type + # Software Control loop is under software control + # Locked loop is locked + # + else if (NF >= 5 && $5 == "OSC;ET;TEMP") { + osc_count++ + osc_temp = $6 " " $7 " " $8 " " $9 + if (osc_status != osc_temp) + printf "loop %s\n", osc_temp + osc_status = osc_temp + if ($10 > osc_vmax) + osc_vmax = $10 + if ($10 < osc_vmin) + osc_vmin = $10 + if ($11 > osc_tmax) + osc_tmax = $11 + if ($11 < osc_tmin) + osc_tmin = $11 + continue + } + # + # select UTC records + # these ain't ready yet + # + else if (NF >= 5 && $5 == "UTC") { + utc_count++ + utc_temp = "" + for (i = 6; i <= NF; i++) + utc_temp = utc_temp " " $i + if (utc_string != utc_temp) +# printf "utc%s\n", utc_temp + utc_string = utc_temp + continue + } +} END { +# +# ensemble summary data +# +# ensemble record count +# badgps gps data unavailable +# badloran loran data unavailable +# rms ensemble rms error (ns) +# >200 ensemble error >200 ns +# >100 100 ns < ensemble error < 200 ns +# + if (ensemble_count > 0) { + ensemble_mean /= ensemble_count + ensemble_rms = sqrt(ensemble_rms / ensemble_count - ensemble_mean * ensemble_mean) * 1e9 + printf "ensemble %d, badgps %d, badloran %d, rms %.1f, >200 %d, >100 %d\n", ensemble_count, ensemble_badgps, ensemble_badloran, ensemble_rms, ensemble_200, ensemble_100 + } +# +# wwvb summary data +# +# wwvb record count +# ? unsynchronized +# >1 error > 1 ms +# >10 error > 10 ms +# >100 error > 100 ms +# >500 error > 500 ms +# + if (wwvb_count > 0) + printf "wwvb %d, ? %d, >1 %d, >10 %d, >100 %d, >500 %d\n", wwvb_count, wwvb_x, wwvb_a, wwvb_b, wwvb_c, wwvb_d +# +# irig summary data +# +# irig record count +# err error count +# + if (irig_count > 0) + printf "irig %d, err %d\n", irig_count, irig_error +# +# tdata summary data +# +# tdata record count +# m M master OK-count, mean level (dB) +# w W slave OK-count, mean level (dB) +# x X slave OK-count, mean level (dB) +# y Y slave OK-count, mean level (dB) +# z Z slave OK-count, mean level (dB) +# + if (tdata_count > 0 ) { + if (tdata_m > 0) + m /= tdata_count + if (tdata_x > 0) + w /= tdata_count + if (tdata_x > 0) + x /= tdata_count + if (tdata_y > 0) + y /= tdata_count + if (tdata_z > 0) + z /= tdata_count + printf "tdata %d, m %d %.1f, w %d %.1f, x %d %.1f, y %d %.1f, z %d %.1f\n", tdata_count, tdata_m, m, tdata_w, w, tdata_x, x, tdata_y, y, tdata_z, z + } +# +# itf summary data +# +# itf record count +# rms itf rms error (ns) +# >200 itf error > 200 ns +# >100 itf error > 100 ns +# var Allan variance +# + if (itf_count > 1) { + itf_mean /= itf_count + itf_rms = sqrt(itf_rms / itf_count - itf_mean * itf_mean) * 1e9 + itf_var = sqrt(itf_var / (2 * (itf_count - 1))) + printf "itf %d, rms %.1f, >200 %d, >100 %d, var %.2e\n", itf_count, itf_rms, itf_200, itf_100, itf_var + } +# +# etf summary data +# +# etf record count +# mean etf mean (ns) +# rms etf rms error (ns) +# max etf maximum (ns) +# min etf minimum (ns) +# var Allan variance +# + if (etf_count > 0) { + etf_mean /= etf_count + etf_rms = sqrt(etf_rms / etf_count - etf_mean * etf_mean) + etf_var = sqrt(etf_var / (2 * (etf_count - 1))) + printf "etf %d, mean %.1f, rms %.1f, max %d, min %d, var %.2e\n", etf_count, etf_mean, etf_rms, etf_max, etf_min, etf_var + } +# +# trstat summary data +# +# trstat record count +# sat histogram of tracked satellites (0 - 7) +# + if (trstat_count > 0) + printf "trstat %d, sat %d %d %d %d %d %d %d %d\n", trstat_count, trstat_sat[0], trstat_sat[1], trstat_sat[2], trstat_sat[2], trstat_sat[3], trstat_sat[4], trstat_sat[5], trstat_sat[6], trstat_sat[7] +# +# osc summary data +# +# osc record count +# control control midrange (V) +/- deviation (mV) +# temp oven temperature midrange +/- deviation (deg C) +# + if (osc_count > 0) + printf "osc %d, control %.3f+/-%.3f, temp %.1f+/-%.2f\n", osc_count, (osc_vmax + osc_vmin) / 2, (osc_vmax - osc_vmin) / 2 * 1e3, (osc_tmax + osc_tmin) / 2, (osc_tmax - osc_tmin) / 2 +} diff --git a/contrib/xntpd/scripts/stats/clock.sh b/contrib/xntpd/scripts/stats/clock.sh new file mode 100644 index 0000000000..1866d55640 --- /dev/null +++ b/contrib/xntpd/scripts/stats/clock.sh @@ -0,0 +1,17 @@ +#!/bin/csh +# +# Script to summarize clockstats files +# +set x = `ls clockstats.*` +foreach dayfile ( $x ) + if ($dayfile == $x[$#x]) continue + echo " " + echo $dayfile + awk -f clock.awk $dayfile + awk -f itf.awk $dayfile >>itf + awk -f etf.awk $dayfile >>etf + awk -f ensemble.awk $dayfile >>ensemble + awk -f tdata.awk $dayfile >>tdata + rm -f $dayfile +end + diff --git a/contrib/xntpd/scripts/stats/dupe.awk b/contrib/xntpd/scripts/stats/dupe.awk new file mode 100644 index 0000000000..3ddc1b6f97 --- /dev/null +++ b/contrib/xntpd/scripts/stats/dupe.awk @@ -0,0 +1,7 @@ +# program to delete duplicate lines in a file +# +{ + if (old != $0) + printf "%s\n", $0 + old = $0 +} diff --git a/contrib/xntpd/scripts/stats/ensemble.awk b/contrib/xntpd/scripts/stats/ensemble.awk new file mode 100644 index 0000000000..136b33da37 --- /dev/null +++ b/contrib/xntpd/scripts/stats/ensemble.awk @@ -0,0 +1,17 @@ +# program to produce loran ensemble statistics from clockstats files +# +# usage: awk -f ensemble.awk clockstats +# +# format of input record (time values in seconds) +# 49165 8.628 127.127.10.1 93:178:00:00:07.241 LORAN ENSEMBLE +# -6.43E-08 +5.02E-08 .091 +5.98E-08 +1.59E-08 .909 +4.85E-08 +3.52E-08 +# +# format of output record (time values in nanoseconds) +# MJD sec GPS wgt LORAN wgt avg sigma +# 49165 8.628 -64.3 0.091 59.8 0.909 48.5 35.2 +# +# select LORAN ENSEMBLE records with valid format and weights +{ + if (NF >= 14 && $6 == "ENSEMBLE" && $9 > 0 && $12 > 0) + printf "%5s %9.3f %7.1f %6.3f %7.1f %6.3f %7.1f %7.1f\n", $1, $2, $7*1e9, $9, $10*1e9, $12, $13*1e9, $14*1e9 +} diff --git a/contrib/xntpd/scripts/stats/etf.awk b/contrib/xntpd/scripts/stats/etf.awk new file mode 100644 index 0000000000..8e6e334c1e --- /dev/null +++ b/contrib/xntpd/scripts/stats/etf.awk @@ -0,0 +1,19 @@ +# program to produce external time/frequence statistics from clockstats files +# +# usage: awk -f etf.awk clockstats +# +# format of input record +# 49165 40.473 127.127.10.1 93:178:00:00:39.238 ETF +# +175.0 +176.8 2.0 +3.729E-11 +1.000E-10 +3.511E-11 4.005E-13 500 +# +# format of output record (time values in nanoseconds) +# MJD sec time freq +# 49165 40.473 175.0 3.729e-11 +# +# select ETF records with valid format +{ + if (NF >= 9 && $5 == "ETF") { + printf "%5s %9.3f %7.1f %10.3e\n", $1, $2, $6, $9 + } +} + diff --git a/contrib/xntpd/scripts/stats/itf.awk b/contrib/xntpd/scripts/stats/itf.awk new file mode 100644 index 0000000000..2b21c5b9b9 --- /dev/null +++ b/contrib/xntpd/scripts/stats/itf.awk @@ -0,0 +1,19 @@ +# program to produce intewrnal time/frequence statistics from clockstats files +# +# usage: awk -f itf.awk clockstats +# +# format of input record +# 49227 67.846 127.127.10.1 93:240:00:00:51.816 ITF +# COCO 0 +2.0579E-07 -3.1037E-08 -7.7723E-11 +6.5455E-10 500.00 4.962819 +# +# format of output record (time values in nanoseconds) +# MJD sec time freq +# 49227 67.846 +2.0579E-07 -7.7723E-11 +# +# select ITF records with valid format +{ + if (NF >= 10 && $5 == "ITF") { + printf "%5s %9.3f %7.1f %10.3e\n", $1, $2, $8 * 1e9, $10 + } +} + diff --git a/contrib/xntpd/scripts/stats/loop.awk b/contrib/xntpd/scripts/stats/loop.awk new file mode 100644 index 0000000000..25d0bdb97d --- /dev/null +++ b/contrib/xntpd/scripts/stats/loop.awk @@ -0,0 +1,49 @@ +# awk program to scan loopstats files and report errors/statistics +# +# usage: awk -f loop.awk loopstats +# +# format of loopstats record +# MJD sec time (s) freq (ppm) tc +# 49235 3.943 0.000016 22.4716 0 +# +BEGIN { + loop_tmax = loop_fmax = -1e9 + loop_tmin = loop_fmin = 1e9 +} +# +# scan all records in file +# +{ + if (NF >= 5) { + loop_count++ + if ($3 > loop_tmax) + loop_tmax = $3 + if ($3 < loop_tmin) + loop_tmin = $3 + if ($4 > loop_fmax) + loop_fmax = $4 + if ($4 < loop_fmin) + loop_fmin = $4 + loop_time += $3 + loop_time_rms += $3 * $3 + loop_freq += $4 + loop_freq_rms += $4 * $4 + } +} END { + if (loop_count > 0) { + loop_time /= loop_count + loop_time_rms = sqrt(loop_time_rms / loop_count - loop_time * loop_time) + loop_freq /= loop_count + loop_freq_rms = sqrt(loop_freq_rms / loop_count - loop_freq * loop_freq) + loop_tmax = loop_tmax - loop_time + loop_tmin = loop_time - loop_tmin + if (loop_tmin > loop_tmax) + loop_tmax = loop_tmin + loop_fmax = loop_fmax - loop_freq + loop_fmin = loop_time - loop_fmin + if (loop_fmin > loop_fmax) + loop_fmax = loop_fmin + printf "loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, rms %.3f\n", loop_count, loop_time * 1e6, loop_tmax * 1e6, loop_time_rms * 1e6, loop_freq, loop_fmax, loop_freq_rms + } +} + diff --git a/contrib/xntpd/scripts/stats/loop.sh b/contrib/xntpd/scripts/stats/loop.sh new file mode 100644 index 0000000000..619eeb8c66 --- /dev/null +++ b/contrib/xntpd/scripts/stats/loop.sh @@ -0,0 +1,13 @@ +#!/bin/csh +# +# Script to summarize loopstats files +# +set x = `ls loopstats.*` +foreach dayfile ( $x ) + if ($dayfile == $x[$#x]) continue + echo " " + echo $dayfile + awk -f loop.awk $dayfile + rm -f $dayfile +end + diff --git a/contrib/xntpd/scripts/stats/peer.awk b/contrib/xntpd/scripts/stats/peer.awk new file mode 100644 index 0000000000..4cb48cddb6 --- /dev/null +++ b/contrib/xntpd/scripts/stats/peer.awk @@ -0,0 +1,57 @@ +# awk program to scan peerstats files and report errors/statistics +# +# usage: awk -f peer.awk peerstats +# +# format of peerstats record +# MJD sec ident stat offset (s) delay (s) disp (s) +# 49235 11.632 128.4.2.7 f414 -0.000041 0.21910 0.00084 +# +BEGIN { + n = 0 + MAXDISTANCE = 1.0 +} +# +# scan all records in file +# +{ + if (NF >= 7 && ($7 + $6 / 2) < MAXDISTANCE) { + i = n + for (j = 0; j < n; j++) { + if ($3 == peer_ident[j]) + i = j + } + if (i == n) { + peer_ident[i] = $3 + peer_tmax[i] = peer_dist[i] = -1e9 + peer_tmin[i] = 1e9 + n++ + } + peer_count[i]++ + if ($5 > peer_tmax[i]) + peer_tmax[i] = $5 + if ($5 < peer_tmin[i]) + peer_tmin[i] = $5 + dist = $7 + $6 / 2 + if (dist > peer_dist[i]) + peer_dist[i] = dist + peer_time[i] += $5 + peer_time_rms[i] += $5 * $5 + peer_delay[i] += $6 + peer_disp[i] += $7 + } +} END { + printf " ident cnt mean rms max delay dist disp\n" + printf "==========================================================================\n" + for (i = 0; i < n; i++) { + peer_time[i] /= peer_count[i] + peer_time_rms[i] = sqrt(peer_time_rms[i] / peer_count[i] - peer_time[i] * peer_time[i]) + peer_delay[i] /= peer_count[i] + peer_disp[i] /= peer_count[i] + peer_tmax[i] = peer_tmax[i] - peer_time[i] + peer_tmin[i] = peer_time[i] - peer_tmin[i] + if (peer_tmin[i] > peer_tmax[i]) + peer_tmax[i] = peer_tmin[i] + printf "%15s%5d%9.3f%9.3f%9.3f%9.3f%9.3f%9.3f\n", peer_ident[i], peer_count[i], peer_time[i] * 1e3, peer_time_rms[i] * 1e3, peer_tmax[i] * 1e3, peer_delay[i] * 1e3, peer_dist[i] * 1e3, peer_disp[i] * 1e3 + } +} + diff --git a/contrib/xntpd/scripts/stats/peer.sh b/contrib/xntpd/scripts/stats/peer.sh new file mode 100644 index 0000000000..b5d8d29186 --- /dev/null +++ b/contrib/xntpd/scripts/stats/peer.sh @@ -0,0 +1,13 @@ +#!/bin/csh +# +# Script to summarize peerstats files +# +set x = `ls peerstats.*` +foreach dayfile ( $x ) + if ($dayfile == $x[$#x]) continue + echo " " + echo $dayfile + awk -f peer.awk $dayfile + rm -f $dayfile +end + diff --git a/contrib/xntpd/scripts/stats/psummary.awk b/contrib/xntpd/scripts/stats/psummary.awk new file mode 100644 index 0000000000..b7f0e922a7 --- /dev/null +++ b/contrib/xntpd/scripts/stats/psummary.awk @@ -0,0 +1,41 @@ +# program to scan peer_summary file and produce summary of daily summaries +# +{ + if (NF < 8 || $1 == "ident") + continue + i = n + for (j = 0; j < n; j++) { + if ($1 == peer_ident[j]) + i = j + } + if (i == n) { + peer_ident[i] = $1 + n++ + } + peer_count[i]++ + if (($7 - $6 / 2) < 400) { + peer_count[i]++ + peer_mean[i] += $3 + peer_var[i] += $4 * $4 + if ($5 > peer_max[i]) + peer_max[i] = $5 + if ($5 > 1) + peer_1[i]++ + if ($5 > 5) + peer_2[i]++ + if ($5 > 10) + peer_3[i]++ + if ($5 > 50) + peer_4[i]++ + } +} END { + printf " host cnt mean rms max >1 >5 >10 >50\n" + printf "=================================================================\n" + for (i = 0; i < n; i++) { + if (peer_count[i] <= 0) + continue + peer_mean[i] /= peer_count[i] + peer_var[i] = sqrt(peer_var[i] / peer_count[i]) + printf "%15s%4d%10.3f%10.3f%10.3f%4d%4d%4d%4d\n", peer_ident[i], peer_count[i], peer_mean[i], peer_var[i], peer_max[i], peer_1[i], peer_2[i], peer_3[i], peer_4[i] + } +} diff --git a/contrib/xntpd/scripts/stats/summary.sh b/contrib/xntpd/scripts/stats/summary.sh new file mode 100644 index 0000000000..e27ecfa946 --- /dev/null +++ b/contrib/xntpd/scripts/stats/summary.sh @@ -0,0 +1,12 @@ +#!/bin/csh +# +# Script to summarize ipeerstats, loopstats and clockstats files +# +# This script can be run from a cron job once per day, week or month. It +# runs the file-specific summary script and appends the summary data to +# designated files. +# +peer.sh >>peer_summary +loop.sh >>loop_summary +clock.sh >>clock_summary + diff --git a/contrib/xntpd/scripts/stats/tdata.awk b/contrib/xntpd/scripts/stats/tdata.awk new file mode 100644 index 0000000000..04d7e6ad32 --- /dev/null +++ b/contrib/xntpd/scripts/stats/tdata.awk @@ -0,0 +1,45 @@ +# program to produce loran tdata statistics from clockstats files +# +# usage: awk -f tdata.awk clockstats +# +# format of input record (missing replaced by -40.0) +# 49228 36.852 127.127.10.1 93:241:00:00:20.812 LORAN TDATA +# M OK 0 0 1169.14 -7.4 3.16E-07 .424 +# W CV 0 0 3329.30 -16.4 1.81E-06 +# X OK 0 0 1737.19 -10.5 3.44E-07 .358 +# Y OK 0 0 2182.07 -9.0 4.41E-07 .218 +# +# format of output record (signal values are in dB) +# MJD sec time M W X Y Z +# 49228 36.852 175.0 -7.4 -16.4 -10.5 -9.0 +# +# select LORAN TDATA records with valid format +{ + if (NF >= 7 && $6 == "TDATA") { + m = w = x = y = z = -40.0 + for (i = 7; i < NF - 5; i++) { + if ($i == "M" && $(i+1) == "OK") { + i += 5 + m = $i + } + else if ($i == "W" && $(i+1) == "OK") { + i += 5 + w = $i + } + else if ($i == "X" && $(i+1) == "OK") { + i += 5 + x = $i + } + else if ($i == "Y" && $(i+1) == "OK") { + i += 5 + y = $i + } + else if ($i == "Z" && $(i+1) == "OK") { + i += 5 + z = $i + } + } + printf "%5s %9.3f %6.1f %6.1f %6.1f %6.1f %6.1f\n", $1, $2, m, w, x, y, z + } +} + diff --git a/contrib/xntpd/scripts/support/README b/contrib/xntpd/scripts/support/README new file mode 100644 index 0000000000..812965bd09 --- /dev/null +++ b/contrib/xntpd/scripts/support/README @@ -0,0 +1,73 @@ +The bin and etc directories contain several scripts (sh and perl) that +should ease startup and configuration of NTP sites. + + bin/monl is a monitoring script that prints out new, current and + old customers of an NTP timeserver when monitoring is + in effect. + monl has following options: + -i (regular expression matchin IP addres to be ignored + -d where the current state is kept (default /tmp) + -v debug output + -n do not translate IP addresses into hostnames + host to be analyzed + + monl uses xntpdc for information gathering and is thus + limited to the NTP version xntpdc is compiled for. + + bin/mvstats moves compresses and removes statistics files (useful mainly + for reference servers + + etc/install creates the locally needed directories for NTP (if not residung in /etc) + + etc/rc starts up daemon with configuration file and key file + etc/cron cron called monitor statistic (uses bin/monl) + etc/crontab crontab prototype for reference time servers + etc/setup sh script sourced by the other scripts for variable setup + +YOU MUST EDIT THESE FILES TO REFLECT YOUR LOCAL SETUP ! + +READ THIS BEFORE USING THE STARTUP SCRIPTS + +The startupscript etc/rc has been written for Suns and HPs. They are not +guaranteed to work elsewhere. Following assumptions have been made: + + All NTP related files reside in ONE directory having following structure: + + bin/* - all executables (daemon, control, date, scripts) + etc/* - startup scripts and cron scripts + conf/* - NTP configuration files + +The variable NTPROOT (etc/rc, etc/install) must be edited to reflect +the NTP directory (e.g. /usr/local/NTP) + +NTP config files are located via Suns arch command and have the name +conf/`arch`.`arch -k`. +These are the default configurations (usually clients). If a file with the name +conf/`arch`.`arch -k`.`hostname` is present this file will be preferred (Reference host, +gateway). If the arch command is not available no-arch is used. The arch command +is usually a shell script which echoes a string unique the the current machine +architecture. + +The tickadj command has its own conf/tickconf file which is used to set host +specific tickadj values. The line with DEFAULT specifies the default tickadj +parameters, all other lines consists of +. These lines need only be entered if the specified host +needs parameters different from the default parameters. + +Reference clock support is provided for DCF77. If you need to initialize +certain things for reference clock support (e.g. loading STREAMS modules), +you need to edit etc/rc. + +The current config files of Erlangen are included in the conf directory. +They are just for reference, but might help you a bit in setting up a +synchronisation network. + +The advantage of keeping all config files centralized is the easier +administration. + +We replicate the NTP directory via NFS and rdist. + +When you have set up the local config files (YOUR OWN!) you can call +/etc/rc for daemon startup. + +For more information: time@informatik.uni-erlangen.de diff --git a/contrib/xntpd/scripts/support/bin/monl b/contrib/xntpd/scripts/support/bin/monl new file mode 100644 index 0000000000..44201d0d0f --- /dev/null +++ b/contrib/xntpd/scripts/support/bin/monl @@ -0,0 +1,212 @@ +#!/local/bin/perl + +%service = ( 0, "unspec", + 1, "Active", + 2, "Passive", + 3, "Client", + 4, "Server", + 5, "Broadcast", + 6, "Control", + 7, "Private" ); +%nc = (); +@ignpat = (); +$noname = 0; +$verbose = 0; +$retries = 5; +$lastkey = 0; + +sub timedelta { + local($tm, $days, $h, $m, $s); + + $tm = @_[$[]; + $days = 0; + $days = sprintf("%dd+", $days) if $days = int($tm / (60*60*24)); + $days = "" unless $days; + $tm = $tm % (60*60*24); + $h = int($tm / (60*60)); + $tm = $tm % (60*60); + $m = int($tm / 60); + $s = $tm % 60; + + return sprintf("%s%02d:%02d:%02d", $days, $h, $m, $s); +} + +sub listentry { + local($host, $mode) = split("$;" , @_[$[]); + local($count, $version, $firsttime) = split("$;" , $_[$[+1]); + local($name); + + if (grep($host =~ m/$_/, @ignpat)) + { + print "ignored $host ...\n" if $verbose; + return; + } + + return if ! $count; + + if (defined($nc{$host})) + { + $name = $nc{$host}; + } + else + { + if ($noname) + { + $nc{$host} = $name = $host; + } + else + { + $name = (gethostbyaddr(pack("C4", split(/\./, $host)), 2))[$[]; + $nc{$host} = $name = $host if ! defined($name); + } + } + + printf ($fmt, ($lastkey eq $host) ? "" : $name, $service{$mode}, $count, $version, &timedelta($firsttime), $firsttime / $count); + + if (@_[$[+2]) + { + $hostcnt++ if $lastkey ne $host; + $packcnt += $count; + $maxtime = $firsttime if $firsttime > $maxtime; + } + + $lastkey = $host; +} + +while ($ARGV[$[] =~ /^-[nvid]$/) + { + if ($ARGV[$[] eq "-i") + { + shift; + push(@ignpat, shift) unless ! defined($ARGV[$[]); + } + elsif ($ARGV[$[] eq "-d") + { + shift; + $dir = shift unless ! defined($ARGV[$[]); + } + elsif ($ARGV[$[] eq "-n") + { + shift; + $noname = 1; + } + elsif ($ARGV[$[] eq "-v") + { + shift; + $verbose = 1; + } + } + +$dir = "/tmp" unless defined($dir); +$gone = 60*60*48; +$fmt = "%48s %10s %7d %7d %13s %14.3f\n"; +$sfmt = "%48s %10s %7s %7s %13s %14s\n"; +@lbl = ("Host", "Mode", "Count", "Version", "Time active", "Packetinterval"); + +if (!defined($ARGV[$[])) + { + $hostname = `hostname`; + chop($hostname); + unshift(@ARGV, $hostname); + } + +foreach $hostname (@ARGV) + { + $dbmfile = $dir . "/monlstats-" . $hostname; + $monl = "xntpdc -c 'hostnames no' -c monl $hostname | tail +3 |"; + $hostcnt = 0; + $packcnt = 0; + $maxtime = 0; + %Seen = (); + %New = (); + %Old = (); + + print "Monitor Status of $hostname\n\n"; + + $cnt = $retries; + do + { + open(MONL, $monl) || die("$monl failed $!"); + @monlout = ; + close(MONL); + } while (! @monlout && $cnt--); + + if (! @monlout) + { + print "not available.\n"; + next; + } + + dbmopen(Clients, $dbmfile, 0644) || die("dbmopen(.., $dbmfile, ...): $!"); + + foreach (@monlout) + { + chop; + split; + ($host, $count, $mode, $version, $lasttime, $firsttime) = (@_[$[, $[+2 .. $[+6]); + + $Seen{$host, $mode} = 1; + + if (!defined($Clients{$host, $mode})) + { + if ($lasttime <= $gone) + { + ## got a new one + $Clients{$host, $mode} = $New{$host, $mode} = join("$;", $count, $version, $firsttime, $lasttime); + } + } + else + { + ## throw out the old ones + if ($lasttime > $gone) + { + $Old{$host, $mode} = $Clients{$host, $mode}; + delete $Clients{$host, $mode}; + } + else + { + $Clients{$host, $mode} = join("$;", $count, $version, $firsttime, $lasttime); + } + } + } + + grep(($Seen{$_} || ($Old{$_} = delete $Clients{$_})), keys(%Clients)); + + if (grep(($tmp = $_ , !grep($tmp =~ m/$_/, @ignpat)), keys(%New))) + { + print "New customers\n"; + print "-------------\n"; + printf $sfmt, @lbl; + grep( &listentry($_, $New{$_}, 1), sort(keys(%New)) ); + print "\n"; + } + + + if (grep((!defined($New{$_}) && ($tmp = $_, !grep($tmp =~ m/$_/, @ignpat))), keys(%Clients))) + { + print "Current customers\n"; + print "-----------------\n"; + printf $sfmt, @lbl; + grep( defined($New{$_}) || &listentry($_, $Clients{$_}, 1) , sort(keys(%Clients)) ); + print "\n"; + } + + if (grep(($tmp = $_, !grep($tmp =~ m/$_/, @ignpat)), keys(%Old))) + { + print "Discarded customers\n"; + print "-------------------\n"; + printf $sfmt, @lbl; + grep( &listentry($_, $Old{$_}, 0) , sort(keys(%Old)) ); + print "\n"; + } + + dbmclose(Clients); + + print "\nSummary:\n"; + print "--------\n"; + printf("Elapsed time: %13s\n", &timedelta($maxtime)); + printf(" Hosts: %13d\n", $hostcnt); + printf(" Packets: %13d\n", $packcnt); + printf(" Rate: %13.2f\n", $packcnt / $maxtime) if $maxtime; + print "\n"; + } diff --git a/contrib/xntpd/scripts/support/bin/mvstats b/contrib/xntpd/scripts/support/bin/mvstats new file mode 100644 index 0000000000..e33dc792e8 --- /dev/null +++ b/contrib/xntpd/scripts/support/bin/mvstats @@ -0,0 +1,23 @@ +#!/bin/sh +# +# mvstats,v 3.1 1993/07/06 01:10:24 jbj Exp +# +# mvstats is called by cron for keeping the log files together +# usually only used on reference hosts +# +# Files reside in /var/NTP +# Files older than 2 days will be compressed, +# Files older than 64 days will be removed. +# +# mvstats,v +# Revision 3.1 1993/07/06 01:10:24 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:58:24 kardel +# Prerelease NTP V3 / DCF +# +# +cd /var/NTP +find . ! -name '*.Z' -mtime +2 -exec compress -f {} \; +find . -mtime +64 -exec rm -f {} \; diff --git a/contrib/xntpd/scripts/support/conf/hp300.hp300 b/contrib/xntpd/scripts/support/conf/hp300.hp300 new file mode 100644 index 0000000000..7b18758422 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/hp300.hp300 @@ -0,0 +1,70 @@ +# +# FAU NTP client configuration file +# +# hp300.hp300,v 3.1 1993/07/06 01:10:27 jbj Exp +# +# hp300.hp300,v +# Revision 3.1 1993/07/06 01:10:27 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:58:29 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.2 1992/09/24 06:10:46 kardel +# authdelay adjust +# +# Revision 1.1 1992/09/24 06:09:23 kardel +# Initial revision +# +# Revision 1.2 1992/01/14 14:01:35 kardel +# update for joined INF4/INF1 nets +# +# +# Local fall back clock +# +precision -7 +# +# Local clock +# +peer 127.127.1.13 +# +broadcastclient yes +# broadcastdelay must be figured out + +# +# peers - local synch setup +# +#server ntps1-0 version 3 +#server ntps1-1 version 2 +#server ntps2-0 version 3 +# +# files +# +driftfile /+private/local/NTP/xntp.drift +# +# authentication stuff +# +authdelay 0.000436 # hp300 +controlkey 1006 +requestkey 1007 +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +# +restrict default notrust lowpriotrap nomodify +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.60.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.54.0 mask 255.255.255.0 # allow local hosts +# +restrict 127.0.0.1 mask 255.255.255.255 # local config +restrict 127.127.0.0 mask 255.255.0.0 # local clocks diff --git a/contrib/xntpd/scripts/support/conf/hp700.hp700 b/contrib/xntpd/scripts/support/conf/hp700.hp700 new file mode 100644 index 0000000000..911ff10a50 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/hp700.hp700 @@ -0,0 +1,67 @@ +# +# FAU NTP client configuration file +# +# hp700.hp700,v 3.1 1993/07/06 01:10:29 jbj Exp +# +# hp700.hp700,v +# Revision 3.1 1993/07/06 01:10:29 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:58:31 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.1 1992/09/24 06:09:02 kardel +# Initial revision +# +# Revision 1.2 1992/01/14 14:01:35 kardel +# update for joined INF4/INF1 nets +# +# +# Local fall back clock +# +precision -7 +# +# Local clock +# +peer 127.127.1.13 +# +broadcastclient yes +# broadcastdelay must be figured out + +# +# peers - local synch setup +# +#server ntps1-0 version 3 +#server ntps1-1 version 2 +#server ntps2-0 version 3 +# +# files +# +driftfile /+private/local/NTP/xntp.drift +# +# authentication stuff +# +authdelay 0.000016 # hp700 +controlkey 1006 +requestkey 1007 +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +# +restrict default notrust lowpriotrap nomodify +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.60.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.54.0 mask 255.255.255.0 # allow local hosts +# +restrict 127.0.0.1 mask 255.255.255.255 # local config +restrict 127.127.0.0 mask 255.255.0.0 # local clocks diff --git a/contrib/xntpd/scripts/support/conf/hp700.hp700.faui47 b/contrib/xntpd/scripts/support/conf/hp700.hp700.faui47 new file mode 100644 index 0000000000..80c72a6c2d --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/hp700.hp700.faui47 @@ -0,0 +1,71 @@ +# +# FAU NTP client configuration file +# +# hp700.hp700.faui47,v 3.1 1993/07/06 01:10:30 jbj Exp +# +# hp700.hp700.faui47,v +# Revision 3.1 1993/07/06 01:10:30 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:58:33 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.1 1992/09/24 14:53:10 kirschni +# Initial revision +# +# Revision 1.1 1992/09/24 06:09:02 kardel +# Initial revision +# +# Revision 1.2 1992/01/14 14:01:35 kardel +# update for joined INF4/INF1 nets +# +# +# Local fall back clock +# +precision -7 +# +# Local clock +# +peer 127.127.1.13 +# +broadcastclient yes +# broadcastdelay must be figured out +broadcast 131.188.54.255 + +# +# peers - local synch setup +# +#server ntps1-0 version 3 +#server ntps1-1 version 2 +#server ntps2-0 version 3 +# +# files +# +driftfile /+private/local/NTP/xntp.drift +# +# authentication stuff +# +authdelay 0.000016 # hp700 +controlkey 1006 +requestkey 1007 +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +# +restrict default notrust lowpriotrap nomodify +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.60.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.54.0 mask 255.255.255.0 # allow local hosts +# +restrict 127.0.0.1 mask 255.255.255.255 # local config +restrict 127.127.0.0 mask 255.255.0.0 # local clocks diff --git a/contrib/xntpd/scripts/support/conf/hp800.hp800 b/contrib/xntpd/scripts/support/conf/hp800.hp800 new file mode 100644 index 0000000000..58f47062a6 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/hp800.hp800 @@ -0,0 +1,70 @@ +# +# FAU NTP client configuration file +# +# hp800.hp800,v 3.1 1993/07/06 01:10:31 jbj Exp +# +# hp800.hp800,v +# Revision 3.1 1993/07/06 01:10:31 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:58:35 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.2 1992/09/24 06:10:46 kardel +# authdelay adjust +# +# Revision 1.1 1992/09/24 06:09:23 kardel +# Initial revision +# +# Revision 1.2 1992/01/14 14:01:35 kardel +# update for joined INF4/INF1 nets +# +# +# Local fall back clock +# +precision -7 +# +# Local clock +# +peer 127.127.1.13 +# +broadcastclient yes +# broadcastdelay must be figured out + +# +# peers - local synch setup +# +#server ntps1-0 version 3 +#server ntps1-1 version 2 +#server ntps2-0 version 3 +# +# files +# +driftfile /+private/local/NTP/xntp.drift +# +# authentication stuff +# +authdelay 0.000088 # hp800 +controlkey 1006 +requestkey 1007 +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +# +restrict default notrust lowpriotrap nomodify +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.60.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.54.0 mask 255.255.255.0 # allow local hosts +# +restrict 127.0.0.1 mask 255.255.255.255 # local config +restrict 127.127.0.0 mask 255.255.0.0 # local clocks diff --git a/contrib/xntpd/scripts/support/conf/ntp.conf b/contrib/xntpd/scripts/support/conf/ntp.conf new file mode 100644 index 0000000000..06f5482c43 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/ntp.conf @@ -0,0 +1,36 @@ +# +# peers - local synch setup +# +#server ntps1-0 key 0 version 2 +#server ntps1-1 key 0 version 2 +#server ntps2-0 key 0 version 2 +#server ntps2-1 key 0 version 2 +broadcastclient yes +#broadcastdelay # use default, until we measure something +# +# files +# +driftfile /+private/local/NTP/xntp.drift +resolver /local/NTP/bin/xntpres +# +# authentication stuff +# +authdelay 0.000629 +requestkey 65634 +controlkey 65635 +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +restrict default notrust lowpriotrap nopeer nomodify +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts +# +restrict 127.127.0.0 mask 255.255.0.0 # allow refclocks +restrict 127.0.0.1 mask 255.255.255.255 # allow local config +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify# allow local hosts diff --git a/contrib/xntpd/scripts/support/conf/ntp.keys b/contrib/xntpd/scripts/support/conf/ntp.keys new file mode 100644 index 0000000000..e69de29bb2 diff --git a/contrib/xntpd/scripts/support/conf/ntp.keys.dumb b/contrib/xntpd/scripts/support/conf/ntp.keys.dumb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/contrib/xntpd/scripts/support/conf/sun3.sun3 b/contrib/xntpd/scripts/support/conf/sun3.sun3 new file mode 100644 index 0000000000..06f5482c43 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/sun3.sun3 @@ -0,0 +1,36 @@ +# +# peers - local synch setup +# +#server ntps1-0 key 0 version 2 +#server ntps1-1 key 0 version 2 +#server ntps2-0 key 0 version 2 +#server ntps2-1 key 0 version 2 +broadcastclient yes +#broadcastdelay # use default, until we measure something +# +# files +# +driftfile /+private/local/NTP/xntp.drift +resolver /local/NTP/bin/xntpres +# +# authentication stuff +# +authdelay 0.000629 +requestkey 65634 +controlkey 65635 +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +restrict default notrust lowpriotrap nopeer nomodify +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts +# +restrict 127.127.0.0 mask 255.255.0.0 # allow refclocks +restrict 127.0.0.1 mask 255.255.255.255 # allow local config +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify# allow local hosts diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4.faui01 b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui01 new file mode 100644 index 0000000000..8927535ef8 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui01 @@ -0,0 +1,83 @@ +# +# NTP v3 configuration file for faui01 +# +# sun4.sun4.faui01,v 3.1 1993/07/06 01:10:37 jbj Exp +# +# sun4.sun4.faui01,v +# Revision 3.1 1993/07/06 01:10:37 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:58:44 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.3 1992/10/15 10:56:01 kardel +# -60 has 0 broadcasts now +# +# Revision 1.2 1992/09/17 12:46:53 kardel +# CIP network broadcasts +# +# Revision 1.1 1992/06/09 13:40:44 kardel +# Initial revision +# +# + +# +# Local clock definitions +# +precision -14 # kernel fix - HIREZ timer + +# +# Local clock +# +peer 127.127.1.6 # Fall back stratum 6 + +# +# get time from local network - hope this is reasonably stable +# +broadcastclient yes + +# +# files / programs +# +driftfile /+private/local/NTP/xntp.drift + +# +# authentication stuff +# +authdelay 0.000076 +requestkey 1007 +controlkey 1006 + +# +# service +# +broadcast 131.188.54.255 key 0 version 3 +broadcast 131.188.60.0 key 0 version 3 +broadcast 131.188.61.0 version 3 # inf1-net.revue (still on 2) +broadcast 131.188.62.0 version 3 # inf4-net1.revue (still on 2) + +# +# Statistics +# +monitor yes +#statfile /var/NTP/statistics + +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +restrict default notrust lowpriotrap nomodify + +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.1.0 mask 255.255.255.0 notrust # allow local hosts +# +restrict 127.127.0.0 mask 255.255.0.0 # local clocks +restrict 127.0.0.1 # localhost does it too +# +restrict 131.188.1.45 mask 255.255.255.255 # ntps1-0 +restrict 131.188.34.45 mask 255.255.255.255 # ntps1-0 +restrict 131.188.44.45 mask 255.255.255.255 # ntps1-0 diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4.faui10 b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui10 new file mode 100644 index 0000000000..3be93a920f --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui10 @@ -0,0 +1,176 @@ +# +# NTP v3 configuration file for faui45 +# +# sun4.sun4.faui10,v 3.1 1993/07/06 01:10:38 jbj Exp +# +# sun4.sun4.faui10,v +# Revision 3.1 1993/07/06 01:10:38 jbj +# XNTP release 3.1 +# +# +# Revision 1.2 1993/01/19 09:32:31 kardel +# Release 1993/01/19 DCF77/PPS +# +# Revision 1.1 1992/12/10 12:58:46 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.11 1992/10/28 07:38:09 kardel +# bear.zoo.bt.co.uk now also peer +# +# Revision 1.10 1992/09/17 12:56:22 kardel +# 61 and 62 have ZEROBROADCASTS +# +# Revision 1.9 1992/09/17 12:46:53 kardel +# CIP network broadcasts +# +# Revision 1.8 1992/08/14 21:51:04 kardel +# local clock is now preferred peer +# +# Revision 1.7 1992/07/19 14:19:26 kardel +# fixed broadcasts +# +# Revision 1.6 1992/07/17 17:12:43 kardel +# new statistics support +# +# Revision 1.5 1992/07/10 07:46:03 kardel +# added loopstats statistic file +# +# Revision 1.4 1992/06/26 07:30:32 kardel +# update for reference clock support +# +# Revision 1.3 1992/05/18 13:51:04 kardel +# precision fix +# +# Revision 1.2 1992/03/30 11:16:07 kardel +# ntps1-1 version 3 +# +# Revision 1.1 1992/01/14 12:30:21 kardel +# Initial revision +# +# + +# +# Local clock definitions +# +precision -18 # us resolution + +# DCF77 - 0 - REFERENCE CLOCK / Meinberg PZF 535/OCXO +# +# Supported clock types Base +# Meinberg DCF PZF535 TCXO 0 +# Meinberg DCF PZF535 OCXO 16 +# Meinberg DCF U/A 31 32 +# +# Option PPS support (CLOCKDEFS=-DDCF -DDCFPPS) +# PPS 128 +# +# The device to be used is added to the base (16 devices possible +# /dev/dcf77-0 - /dev/dcf77-15) +# +# If PPS support is to be used 128 has to be added to the base +# thus a DCF77 U/A 31 without PPS would be 127.127.8.32 (device 0 - /dev/dcf77-0) +# a DCF77 PZF535/TCXO with PPS would be 127.127.8.129 (device 1 - /dev/dcf77-1) +# a DCF77 PZF535/OCXO with PPS would be 127.127.8.146 (device 2 - /dev/dcf77-2) +# +peer 127.127.8.144 prefer # PZF 535/OCXO / PPS support +# +# We want to provide timed service too, thus (startup script magic) +# TIMED + +# +# Local clock +# +peer 127.127.1.6 # Fall back stratum 6 + +# +# peers - local synch setup +# +peer ntps1-0 key 0 version 3 +peer ntps2-0 key 0 version 3 + +# +# European servers +# +peer sunmanager.lrz-muenchen.de key 0 version 2 +peer rustime01.rus.uni-stuttgart.de version 2 +peer mailszrz.zrz.tu-berlin.de version 2 + +# +# UK servers +# +peer bear.zoo.bt.co.uk version 3 + +# US Servers +# +server truechimer.cso.uiuc.edu version 2 + +# +# files / programs +# +driftfile /+private/local/NTP/xntp.drift +resolver /local/NTP/bin/xntpres + +# +# authentication stuff +# +authdelay 0.000076 +requestkey 1007 +controlkey 1006 + +# +# service +# +broadcast 131.188.31.0 version 3 # inf1-net.revue +broadcast 131.188.34.0 version 3 # inf4-net1.revue +broadcast 131.188.44.0 version 3 # inf4-net2.revue +broadcast 131.188.1.255 version 3 # revue.revue +broadcast 131.188.54.255 key 0 version 3 +broadcast 131.188.60.255 key 0 version 3 +broadcast 131.188.61.0 key 0 version 3 +broadcast 131.188.62.0 key 0 version 3 + +# +# Statistics +# +monitor yes + +# +# file name prefix +# +statsdir /var/NTP/ +# +# file type enable|disable|link|nolink +filegen peerstats file peerstats type day link # generate . and link generic file name (without extension) +filegen loopstats file loopstats type day link +statistics peerstats loopstats # enable statistics + +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +restrict default notrust lowpriotrap nomodify + +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.31.0 mask 255.255.255.0 notrust # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 notrust # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 notrust # allow local hosts +restrict 131.188.40.0 mask 255.255.255.0 notrust # allow local hosts +# +restrict 127.127.0.0 mask 255.255.0.0 # local clocks +restrict 127.0.0.1 # localhost does it too +# +restrict 131.188.1.45 mask 255.255.255.255 # ntps1-0 +restrict 131.188.34.45 mask 255.255.255.255 # ntps1-0 +restrict 131.188.44.45 mask 255.255.255.255 # ntps1-0 +restrict 131.188.30.1 mask 255.255.255.255 # ntps1-1 +# +# external trust +# +restrict 130.126.174.40 mask 255.255.255.255 nomodify # truechimer.cso.uiuc.edu +restrict 129.69.1.153 mask 255.255.255.255 nomodify # rustime01.rus.uni-stuttgart.de +restrict 129.187.10.32 mask 255.255.255.255 nomodify # sunmanager.lrz-muenchen.de +restrict 130.149.4.11 mask 255.255.255.255 nomodify # mailszrz.zrz.tu-berlin.de +restrict 132.146.40.28 mask 255.255.255.255 nomodify # bear.zoo.bt.co.uk diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4.faui45 b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui45 new file mode 100644 index 0000000000..57e77f2749 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui45 @@ -0,0 +1,228 @@ +# +# NTP v3 configuration file for faui45 +# +# sun4.sun4.faui45,v 3.1 1993/07/06 01:10:39 jbj Exp +# +# sun4.sun4.faui45,v +# Revision 3.1 1993/07/06 01:10:39 jbj +# XNTP release 3.1 +# +# +# Revision 1.2 1993/01/19 09:32:33 kardel +# Release 1993/01/19 DCF77/PPS +# +# Revision 1.1 1992/12/10 12:58:48 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.28 1992/10/28 07:38:09 kardel +# bear.zoo.bt.co.uk now also peer +# +# Revision 1.27 1992/09/17 12:56:22 kardel +# 61 and 62 have ZEROBROADCASTS +# +# Revision 1.26 1992/09/17 12:46:53 kardel +# CIP network broadcasts +# +# Revision 1.25 1992/09/04 12:48:44 kardel +# dcn1 -> churchy +# +# Revision 1.24 1992/08/14 21:42:20 kardel +# local clock is now preferred peer +# +# Revision 1.23 1992/07/17 17:11:51 kardel +# new statistics support +# +# Revision 1.22 1992/07/05 22:41:18 root +# using default module settings now +# +# Revision 1.21 1992/07/02 11:47:26 root +# loop statistics added +# +# Revision 1.20 1992/06/26 07:30:51 kardel +# corrected examples +# +# Revision 1.19 1992/06/18 16:56:05 kardel +# running timed too (startup script magic) +# +# Revision 1.18 1992/06/18 13:58:45 kardel +# precision adjusted (us resolution) +# clock definition explanation +# +# Revision 1.17 1992/06/13 12:49:35 root +# allowed ntps1-1 +# +# Revision 1.16 1992/06/07 11:44:41 kardel +# switch to PPS support for dcf77-0 +# +# Revision 1.15 1992/06/03 14:02:58 kardel +# new version (fausup notrust) +# +# Revision 1.14 1992/05/18 13:49:45 kardel +# first precision update due to kernel patch +# +# Revision 1.13 1992/05/18 13:48:36 kardel +# more updates +# +# Revision 1.12 1992/03/24 08:43:49 kardel +# now trusting netserv.rz.uni-karlsruhe.de +# +# Revision 1.11 1992/03/23 15:03:43 kardel +# sunmanager.lrz-muenchen.de is a peer +# +# Revision 1.10 1992/03/12 22:49:53 kardel +# well, got to switch fudge too +# +# Revision 1.9 1992/03/12 22:47:07 kardel +# adjust for next xntpv3 alpha release +# +# Revision 1.8 1992/02/07 11:07:35 kardel +# switched to Meinberg PZF 535/OCXO +# +# Revision 1.7 1992/01/21 15:11:38 kardel +# netserv & sunmanager must be configured server (botch on other side) +# +# Revision 1.6 1992/01/17 17:54:34 kardel +# added ntps2-0, ntps2-1 to unrestricted list +# +# Revision 1.5 1992/01/10 10:49:03 kardel +# Authentication correction +# +# Revision 1.4 1992/01/10 08:08:06 kardel +# peer apple.com added +# ntps1-1 added to restrictionlist +# +# Revision 1.3 1991/12/19 10:23:56 kardel +# peers on STRATUM 1 +# add mailszrz +# +# Revision 1.2 1991/12/19 09:57:29 kardel +# upgrade NTP V3 +# +# + +# +# Local clock definitions +# +precision -18 # us resolution + +# DCF77 - 0 - REFERENCE CLOCK / Meinberg PZF 535/OCXO +# +# Supported clock types Base +# Meinberg DCF PZF535 TCXO 0 +# Meinberg DCF PZF535 OCXO 16 +# Meinberg DCF U/A 31 32 +# +# Option PPS support (CLOCKDEFS=-DDCF -DDCFPPS) +# PPS 128 +# +# The device to be used is added to the base (16 devices possible +# /dev/dcf77-0 - /dev/dcf77-15) +# +# If PPS support is to be used 128 has to be added to the base +# thus a DCF77 U/A 31 without PPS would be 127.127.8.32 (device 0 - /dev/dcf77-0) +# a DCF77 PZF535/TCXO with PPS would be 127.127.8.129 (device 1 - /dev/dcf77-1) +# a DCF77 PZF535/OCXO with PPS would be 127.127.8.146 (device 2 - /dev/dcf77-2) +# +peer 127.127.8.144 prefer # PZF 535/OCXO / PPS support +# +# We want to provide timed service too, thus (startup script magic) +# TIMED + +# +# Local clock +# +peer 127.127.1.6 # Fall back stratum 6 + +# +# peers - local synch setup +# +peer ntps1-1 key 0 version 2 # to be upgrade to version 3 +peer ntps2-0 key 0 version 2 # to be upgrade to version 3 + +# +# European servers +# +peer sunmanager.lrz-muenchen.de key 0 version 2 +peer iis.ethz.ch version 3 +server netserv.rz.uni-karlsruhe.de version 2 # sorry configuration error on other side +peer rustime01.rus.uni-stuttgart.de version 2 +peer mailszrz.zrz.tu-berlin.de version 2 + +# +# UK servers +# +peer bear.zoo.bt.co.uk version 3 + +# +# US Servers +# +peer apple.com version 2 +server churchy.udel.edu key 0 version 3 + +# +# files / programs +# +driftfile /+private/local/NTP/xntp.drift +resolver /local/NTP/bin/xntpres + +# +# authentication stuff +# +authdelay 0.000076 +requestkey 1007 +controlkey 1006 + +# +# service +# +broadcast 131.188.1.255 key 0 version 2 # revue.revue (still on 2) +broadcast 131.188.34.0 key 0 version 2 # inf4-net1.revue (still on 2) +broadcast 131.188.44.0 key 0 version 2 # inf4-net2.revue (still on 2) +broadcast 131.188.54.255 key 0 version 3 +broadcast 131.188.60.255 key 0 version 3 +broadcast 131.188.61.0 key 0 version 3 +broadcast 131.188.62.0 key 0 version 3 + +# +# Statistics +# +monitor yes +# +# file name prefix +# +statsdir /var/NTP/ +# +# file type enable|disable|link|nolink +filegen peerstats file peerstats type day link # generate . and link generic file name (without extension) +filegen loopstats file loopstats type day link +statistics peerstats loopstats # enable statistics + +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +restrict default notrust lowpriotrap nomodify + +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 notrust # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 notrust # allow local hosts +# +restrict 127.127.0.0 mask 255.255.0.0 # local clocks +restrict 127.0.0.1 # localhost does it too +# +restrict 131.188.1.41 mask 255.255.255.255 # ntps1-1 +restrict 131.188.31.1 mask 255.255.255.255 # ntps2-0, ntps2-1 +# +# external trust +# +restrict 130.43.2.2 mask 255.255.255.255 nomodify # apple.com +restrict 129.132.2.60 mask 255.255.255.255 nomodify # iis.ethz.ch +restrict 128.4.1.5 mask 255.255.255.255 nomodify # churchy.udel.edu +restrict 129.13.64.5 mask 255.255.255.255 nomodify # netserv.rz.uni-karlsruhe.de +restrict 129.69.1.153 mask 255.255.255.255 nomodify # rustime01.rus.uni-stuttgart.de +restrict 129.187.10.32 mask 255.255.255.255 nomodify # sunmanager.lrz-muenchen.de +restrict 132.146.40.28 mask 255.255.255.255 nomodify # bear.zoo.bt.co.uk +restrict 130.149.4.11 mask 255.255.255.255 nomodify # mailszrz.zrz.tu-berlin.de diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4c b/contrib/xntpd/scripts/support/conf/sun4.sun4c new file mode 100644 index 0000000000..e1ff902590 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/sun4.sun4c @@ -0,0 +1,63 @@ +# +# FAU NTP client configuration file +# +# sun4.sun4c,v 3.1 1993/07/06 01:10:41 jbj Exp +# +# sun4.sun4c,v +# Revision 3.1 1993/07/06 01:10:41 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:58:50 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.2 1992/01/14 14:01:35 kardel +# update for joined INF4/INF1 nets +# +# +# Local fall back clock +# +precision -7 +# +# Local clock +# +peer 127.127.1.13 +# +broadcastclient yes +# broadcastdelay must be figured out + +# +# peers - local synch setup +# +#server ntps1-0 version 3 +#server ntps1-1 version 2 +#server ntps2-0 version 3 +# +# files +# +driftfile /+private/local/NTP/xntp.drift +resolver /local/NTP/bin/xntpres +# +# authentication stuff +# +authdelay 0.000144 # sun4c +controlkey 1006 +requestkey 1007 +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +# +restrict default notrust lowpriotrap nomodify +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts +# +restrict 127.0.0.1 mask 255.255.255.255 # local config +restrict 127.127.0.0 mask 255.255.0.0 # local clocks diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4c.Lucifer b/contrib/xntpd/scripts/support/conf/sun4.sun4c.Lucifer new file mode 100644 index 0000000000..78d3ea8879 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/sun4.sun4c.Lucifer @@ -0,0 +1,174 @@ +# +# NTP v3 configuration file for Lucifer +# +# sun4.sun4c.Lucifer,v 3.1 1993/07/06 01:10:42 jbj Exp +# +# sun4.sun4c.Lucifer,v +# Revision 3.1 1993/07/06 01:10:42 jbj +# XNTP release 3.1 +# +# +# Revision 1.2 1993/01/19 09:32:35 kardel +# Release 1993/01/19 DCF77/PPS +# +# Revision 1.1 1992/12/10 12:58:52 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.8 1992/10/28 07:38:09 kardel +# bear.zoo.bt.co.uk now also peer +# +# Revision 1.7 1992/09/17 12:56:22 kardel +# 61 and 62 have ZEROBROADCASTS +# +# Revision 1.6 1992/09/17 12:46:53 kardel +# CIP network broadcasts +# +# Revision 1.5 1992/08/14 21:52:02 kardel +# local clock is now preferred peer +# +# Revision 1.4 1992/07/17 17:15:06 kardel +# adedd new statistics support +# +# Revision 1.3 1992/07/12 16:50:16 kardel +# new peers, restrictions, statistics, no timed +# +# Revision 1.2 1992/07/10 07:01:44 kardel +# authdelay fixed +# +# Revision 1.1 1992/07/10 07:00:30 kardel +# Initial revision +# +# +# +# Local clock definitions +# +precision -18 # us resolution + +# DCF77 - 0 - REFERENCE CLOCK / Meinberg PZF 535/OCXO +# +# Supported clock types Base +# Meinberg DCF PZF535 TCXO 0 +# Meinberg DCF PZF535 OCXO 16 +# Meinberg DCF U/A 31 32 +# ELV DCF7000 48 + +# +# Option PPS support (CLOCKDEFS=-DDCF -DDCFPPS) +# PPS 128 +# +# The device to be used is added to the base (16 devices possible +# /dev/dcf77-0 - /dev/dcf77-15) +# +# If PPS support is to be used 128 has to be added to the base +# thus a DCF77 U/A 31 without PPS would be 127.127.8.32 (device 0 - /dev/dcf77-0) +# a DCF77 PZF535/TCXO with PPS would be 127.127.8.129 (device 1 - /dev/dcf77-1) +# a DCF77 PZF535/OCXO with PPS would be 127.127.8.146 (device 2 - /dev/dcf77-2) +# +peer 127.127.8.144 prefer # PZF 535/OCXO / PPS support +# + +# +# Local clock +# +peer 127.127.1.6 # Fall back stratum 6 + +# +# peers - local synch setup +# +peer ntps1-1 key 0 version 3 +peer ntps1-2 key 0 version 3 +peer ntps2-0 key 0 version 3 + +# +# UK servers +# +peer bear.zoo.bt.co.uk version 3 + +# +# European servers +# +peer sunmanager.lrz-muenchen.de key 0 version 2 +peer iis.ethz.ch version 3 +server netserv.rz.uni-karlsruhe.de version 2 # sorry configuration error on other side +peer rustime01.rus.uni-stuttgart.de version 2 +peer mailszrz.zrz.tu-berlin.de version 2 + +# +# US Servers +# +peer apple.com version 2 +server dcn1.udel.edu key 0 version 3 + +# +# files / programs +# +driftfile /+private/local/NTP/xntp.drift +resolver /local/NTP/bin/xntpres + +# +# authentication stuff +# +authdelay 0.000144 # sun4c +requestkey 1007 +controlkey 1006 + +# +# service +# +broadcast 131.188.1.255 key 0 version 3 # revue.revue (still on 2) +broadcast 131.188.34.0 key 0 version 3 # inf4-net1.revue (still on 2) +broadcast 131.188.44.0 key 0 version 3 # inf4-net2.revue (still on 2) +broadcast 131.188.54.255 key 0 version 3 +broadcast 131.188.60.255 key 0 version 3 +broadcast 131.188.61.0 key 0 version 3 +broadcast 131.188.62.0 key 0 version 3 + +# +# Statistics +# +monitor yes + +# +# file name prefix +# +statsdir /var/NTP/ +# +# file type enable|disable|link|nolink +filegen peerstats file peerstats type day link # generate . and link generic file name (without extension) +filegen loopstats file loopstats type day link +statistics peerstats loopstats # enable statistics + +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +restrict default notrust lowpriotrap nomodify + +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 notrust # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 notrust # allow local hosts +# +restrict 127.127.0.0 mask 255.255.0.0 # local clocks +restrict 127.0.0.1 # localhost does it too +# +restrict 131.188.1.45 mask 255.255.255.255 # ntps1-1 +restrict 131.188.34.45 mask 255.255.255.255 # ntps1-1 +restrict 131.188.44.45 mask 255.255.255.255 # ntps1-1 +restrict 131.188.1.31 mask 255.255.255.255 # ntps1-2, ntps2-0, ntps2-1 +restrict 131.188.34.31 mask 255.255.255.255 # ntps1-2, ntps2-0, ntps2-1 +restrict 131.188.44.31 mask 255.255.255.255 # ntps1-2, ntps2-0, ntps2-1 +restrict 131.188.31.1 mask 255.255.255.255 # ntps1-2, ntps2-0, ntps2-1 +# +# external trust +# +restrict 130.43.2.2 mask 255.255.255.255 nomodify # apple.com +restrict 129.132.2.60 mask 255.255.255.255 nomodify # iis.ethz.ch +restrict 128.4.0.1 mask 255.255.255.255 nomodify # dcn1.umd.edu +restrict 129.13.64.5 mask 255.255.255.255 nomodify # netserv.rz.uni-karlsruhe.de +restrict 129.69.1.153 mask 255.255.255.255 nomodify # rustime01.rus.uni-stuttgart.de +restrict 129.187.10.32 mask 255.255.255.255 nomodify # sunmanager.lrz-muenchen.de +restrict 132.146.40.28 mask 255.255.255.255 nomodify # bear.zoo.bt.co.uk +restrict 130.149.4.11 mask 255.255.255.255 nomodify # mailszrz.zrz.tu-berlin.de diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4m b/contrib/xntpd/scripts/support/conf/sun4.sun4m new file mode 100644 index 0000000000..cf1e283cb1 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/sun4.sun4m @@ -0,0 +1,69 @@ +# +# FAU NTP client configuration file +# +# sun4.sun4m,v 3.1 1993/07/06 01:10:43 jbj Exp +# +# sun4.sun4m,v +# Revision 3.1 1993/07/06 01:10:43 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:58:55 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.2 1992/10/05 12:48:44 kardel +# sun4m authdelay +# +# Revision 1.1 1992/10/05 12:48:07 kardel +# Initial revision +# +# Revision 1.2 1992/01/14 14:01:35 kardel +# update for joined INF4/INF1 nets +# +# +# Local fall back clock +# +precision -7 +# +# Local clock +# +peer 127.127.1.13 +# +broadcastclient yes +# broadcastdelay must be figured out + +# +# peers - local synch setup +# +#server ntps1-0 version 3 +#server ntps1-1 version 2 +#server ntps2-0 version 3 +# +# files +# +driftfile /+private/local/NTP/xntp.drift +resolver /local/NTP/bin/xntpres +# +# authentication stuff +# +authdelay 0.000033 # sun4c +controlkey 1006 +requestkey 1007 +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +# +restrict default notrust lowpriotrap nomodify +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts +restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts +# +restrict 127.0.0.1 mask 255.255.255.255 # local config +restrict 127.127.0.0 mask 255.255.0.0 # local clocks diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui42 b/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui42 new file mode 100644 index 0000000000..acc919c85f --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui42 @@ -0,0 +1,152 @@ +# +# NTP v3 configuration file for faui42 +# +# sun4.sun4m.faui42,v 3.1 1993/07/06 01:10:44 jbj Exp +# +# sun4.sun4m.faui42,v +# Revision 3.1 1993/07/06 01:10:44 jbj +# XNTP release 3.1 +# +# +# Revision 1.2 1993/01/19 09:32:36 kardel +# Release 1993/01/19 DCF77/PPS +# +# Revision 1.1 1992/12/10 12:58:57 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.6 1992/09/15 16:19:10 kardel +# preferrred peer +# +# Revision 1.5 1992/09/15 15:57:36 kardel +# Stratum 1 again (may the Patches be with us...) +# +# Revision 1.4 1992/06/30 08:52:38 kardel +# sun4m machine don't have a clock (SunOS4.1.2) +# soory - just Stratum 2 +# +# Revision 1.3 1992/06/18 13:58:45 kardel +# precision adjusted (us resolution) +# clock definition explanation +# +# Revision 1.2 1992/06/13 11:42:49 kardel +# restrictions changed +# +# Revision 1.1 1992/06/13 11:27:11 kardel +# Initial revision +# +# + +# +# Local clock definitions +# +precision -18 # us resolution + +# +# DCF77 - 0 - REFERENCE CLOCK / Meinberg PZF 535/OCXO +# +# Supported clock types Base +# Meinberg DCF PZF535 TCXO 0 +# Meinberg DCF PZF535 OCXO 16 +# Meinberg DCF U/A 31 32 +# +# Option PPS support (CLOCKDEFS=-DDCF -DDCFPPS) +# PPS 128 +# +# The device to be used is added to the base (16 devices possible +# /dev/dcf77-0 - /dev/dcf77-15) +# +# If PPS support is to be used 128 has to be added to the base +# thus a DCF77 U/A 31 without PPS would be 127.127.8.32 (device 0 - /dev/dcf77-0) +# a DCF77 PZF535/TCXO with PPS would be 127.127.8.129 (device 1 - /dev/dcf77-1) +# a DCF77 PZF535/OCXO with PPS would be 127.127.8.146 (device 2 - /dev/dcf77-2) +# +peer 127.127.8.144 prefer # PZF 535/OCXO / PPS support +# +# Local clock +# +peer 127.127.1.6 # Fall back stratum 6 + +# +# peers - local synch setup +# +peer ntps1-0 key 0 version 2 # to be upgrade to version 3 +peer ntps2-0 key 0 version 2 # to be upgrade to version 3 + +# +# European servers +# +peer sunmanager.lrz-muenchen.de key 0 version 2 +peer iis.ethz.ch version 3 +#server netserv.rz.uni-karlsruhe.de version 2 # sorry configuration error on other side +peer rustime01.rus.uni-stuttgart.de version 2 +#peer mailszrz.zrz.tu-berlin.de version 2 + +# +# US Servers +# +#peer apple.com version 2 +#server dcn1.udel.edu key 0 version 3 + +# +# files / programs +# +driftfile /+private/local/NTP/xntp.drift +resolver /local/NTP/bin/xntpres + +# +# authentication stuff +# +authdelay 0.000047 +requestkey 1007 +controlkey 1006 + +# +# service +# +broadcast 131.188.1.255 key 0 version 3 # revue.revue (still on 2) +broadcast 131.188.40.0 key 0 version 3 # inf4-net2.revue (still on 2) + +# +# Statistics +# +monitor yes + +# +# file name prefix +# +statsdir /var/NTP/ +# +# file type enable|disable|link|nolink +filegen peerstats file peerstats type day link # generate . and link generic file name (without extension) +filegen loopstats file loopstats type day link +statistics peerstats loopstats # enable statistics + +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +restrict default notrust lowpriotrap nomodify + +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.40.0 mask 255.255.255.0 nomodify # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 nomodify # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 nomodify # allow local hosts +restrict 131.188.31.0 mask 255.255.255.0 nomodify # allow local hosts +restrict 131.188.1.0 mask 255.255.255.0 nomodify # allow local hosts +# +restrict 127.127.0.0 mask 255.255.0.0 # local clocks +restrict 127.0.0.1 # localhost does it too +# +# +# external trust +# +restrict 130.43.2.2 mask 255.255.255.255 nomodify # apple.com +restrict 129.132.2.60 mask 255.255.255.255 nomodify # iis.ethz.ch +restrict 128.4.0.1 mask 255.255.255.255 nomodify # dcn1.umd.edu +restrict 129.13.64.5 mask 255.255.255.255 nomodify # netserv.rz.uni-karlsruhe.de +restrict 129.69.1.153 mask 255.255.255.255 nomodify # rustime01.rus.uni-stuttgart.de +restrict 129.187.10.32 mask 255.255.255.255 nomodify # sunmanager.lrz-muenchen.de +restrict 130.149.4.11 mask 255.255.255.255 nomodify # mailszrz.zrz.tu-berlin.de diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui45m b/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui45m new file mode 100644 index 0000000000..2c75f67545 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui45m @@ -0,0 +1,165 @@ +# +# NTP v3 configuration file for Lucifer +# +# sun4.sun4m.faui45m,v 3.1 1993/07/06 01:10:45 jbj Exp +# +# sun4.sun4m.faui45m,v +# Revision 3.1 1993/07/06 01:10:45 jbj +# XNTP release 3.1 +# +# +# Revision 1.2 1993/01/19 09:32:38 kardel +# Release 1993/01/19 DCF77/PPS +# +# Revision 1.1 1992/12/10 12:58:59 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.7 1992/09/17 12:56:22 kardel +# 61 and 62 have ZEROBROADCASTS +# +# Revision 1.6 1992/09/17 12:46:53 kardel +# CIP network broadcasts +# +# Revision 1.5 1992/08/14 21:52:02 kardel +# local clock is now preferred peer +# +# Revision 1.4 1992/07/17 17:15:06 kardel +# adedd new statistics support +# +# Revision 1.3 1992/07/12 16:50:16 kardel +# new peers, restrictions, statistics, no timed +# +# Revision 1.2 1992/07/10 07:01:44 kardel +# authdelay fixed +# +# Revision 1.1 1992/07/10 07:00:30 kardel +# Initial revision +# +# +# +# Local clock definitions +# +precision -18 # us resolution + +# DCF77 - 0 - REFERENCE CLOCK / Meinberg PZF 535/OCXO +# +# Supported clock types Base +# Meinberg DCF PZF535 TCXO 0 +# Meinberg DCF PZF535 OCXO 16 +# Meinberg DCF U/A 31 32 +# ELV DCF7000 48 + +# +# Option PPS support (CLOCKDEFS=-DDCF -DDCFPPS) +# PPS 128 +# +# The device to be used is added to the base (16 devices possible +# /dev/dcf77-0 - /dev/dcf77-15) +# +# If PPS support is to be used 128 has to be added to the base +# thus a DCF77 U/A 31 without PPS would be 127.127.8.32 (device 0 - /dev/dcf77-0) +# a DCF77 PZF535/TCXO with PPS would be 127.127.8.129 (device 1 - /dev/dcf77-1) +# a DCF77 PZF535/OCXO with PPS would be 127.127.8.146 (device 2 - /dev/dcf77-2) +# +peer 127.127.8.144 prefer # PZF 535/OCXO / PPS support +# + +# +# Local clock +# +peer 127.127.1.6 # Fall back stratum 6 + +# +# peers - local synch setup +# +peer ntps1-1 key 0 version 3 +peer ntps1-2 key 0 version 3 +peer ntps2-0 key 0 version 3 + +# +# European servers +# +peer sunmanager.lrz-muenchen.de key 0 version 2 +peer iis.ethz.ch version 3 +server netserv.rz.uni-karlsruhe.de version 2 # sorry configuration error on other side +peer rustime01.rus.uni-stuttgart.de version 2 +peer mailszrz.zrz.tu-berlin.de version 2 + +# +# US Servers +# +peer apple.com version 2 +server dcn1.udel.edu key 0 version 3 + +# +# files / programs +# +driftfile /+private/local/NTP/xntp.drift +resolver /local/NTP/bin/xntpres + +# +# authentication stuff +# +authdelay 0.000033 # sun4m +requestkey 1007 +controlkey 1006 + +# +# service +# +broadcast 131.188.1.255 key 0 version 3 # revue.revue (still on 2) +broadcast 131.188.34.0 key 0 version 3 # inf4-net1.revue (still on 2) +broadcast 131.188.44.0 key 0 version 3 # inf4-net2.revue (still on 2) +broadcast 131.188.54.255 key 0 version 3 +broadcast 131.188.60.255 key 0 version 3 +broadcast 131.188.61.0 key 0 version 3 +broadcast 131.188.62.0 key 0 version 3 + +# +# Statistics +# +monitor yes + +# +# file name prefix +# +statsdir /var/NTP/ +# +# file type enable|disable|link|nolink +filegen peerstats file peerstats type day link # generate . and link generic file name (without extension) +filegen loopstats file loopstats type day link +statistics peerstats loopstats # enable statistics + +# +# restrictions +# +# provide cheap services to the world/ prevent modifications from there +restrict default notrust lowpriotrap nomodify + +# +# hosts on the local networks are allowed unrestricted access +# +restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts +restrict 131.188.34.0 mask 255.255.255.0 notrust # allow local hosts +restrict 131.188.44.0 mask 255.255.255.0 notrust # allow local hosts +# +restrict 127.127.0.0 mask 255.255.0.0 # local clocks +restrict 127.0.0.1 # localhost does it too +# +restrict 131.188.1.45 mask 255.255.255.255 # ntps1-1 +restrict 131.188.34.45 mask 255.255.255.255 # ntps1-1 +restrict 131.188.44.45 mask 255.255.255.255 # ntps1-1 +restrict 131.188.1.31 mask 255.255.255.255 # ntps1-2, ntps2-0, ntps2-1 +restrict 131.188.34.31 mask 255.255.255.255 # ntps1-2, ntps2-0, ntps2-1 +restrict 131.188.44.31 mask 255.255.255.255 # ntps1-2, ntps2-0, ntps2-1 +restrict 131.188.31.1 mask 255.255.255.255 # ntps1-2, ntps2-0, ntps2-1 +# +# external trust +# +restrict 130.43.2.2 mask 255.255.255.255 nomodify # apple.com +restrict 129.132.2.60 mask 255.255.255.255 nomodify # iis.ethz.ch +restrict 128.4.0.1 mask 255.255.255.255 nomodify # dcn1.umd.edu +restrict 129.13.64.5 mask 255.255.255.255 nomodify # netserv.rz.uni-karlsruhe.de +restrict 129.69.1.153 mask 255.255.255.255 nomodify # rustime01.rus.uni-stuttgart.de +restrict 129.187.10.32 mask 255.255.255.255 nomodify # sunmanager.lrz-muenchen.de +restrict 130.149.4.11 mask 255.255.255.255 nomodify # mailszrz.zrz.tu-berlin.de diff --git a/contrib/xntpd/scripts/support/conf/tickconf b/contrib/xntpd/scripts/support/conf/tickconf new file mode 100644 index 0000000000..b17dbe8347 --- /dev/null +++ b/contrib/xntpd/scripts/support/conf/tickconf @@ -0,0 +1,19 @@ +DEFAULT -A -p -s -q +Lucifer 55406cfa -a 1 -p -s -q -t 10001 +faui45 24000f9b -a 1 -p -s -q +faui10 2440213c -a 1 -p -s -q +faui1b 54001418 -A -p -s -q -t 10001 +faui4p 5100344d -A -p -s -q -t 9999 +faui02g 1200be20 -A -p -s -q -t 9999 +faui02e 1200bbab -A -p -s -q -t 9999 +faui02f 1200bedb -A -p -s -q -t 9999 +faui03b 1200b92b -A -p -s -q -t 9999 +faui45m 726001ac -A -p -s -q -t 10001 +faui45o 72600272 -A -p -s -q -t 10001 +faui45p 7260028f -A -p -s -q -t 10001 +faui45r 72400cc7 -A -p -s -q -t 10001 +faui45s 726045be -A -p -s -q -t 10001 +faui45v 72604487 -A -p -s -q -t 10001 +faui45x 726044eb -A -p -s -q -t 10001 +faui45y 7260476d -A -p -s -q -t 10001 +faui45z 726045a1 -A -p -s -q -t 10001 diff --git a/contrib/xntpd/scripts/support/etc/cron b/contrib/xntpd/scripts/support/etc/cron new file mode 100644 index 0000000000..07ed189498 --- /dev/null +++ b/contrib/xntpd/scripts/support/etc/cron @@ -0,0 +1,18 @@ +#!/bin/sh +# +# cron,v 3.1 1993/07/06 01:10:50 jbj Exp +# +# called by cron for statistics gathering +# +# cron,v +# Revision 3.1 1993/07/06 01:10:50 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:59:18 kardel +# Prerelease NTP V3 / DCF +# +# +PATH="${PATH}:/local/NTP/bin" +export PATH +monl -d /local/NTP/monitor -i '127\.0\.0\.1' faui10 faui45 lucifer rackety.udel.edu diff --git a/contrib/xntpd/scripts/support/etc/crontab b/contrib/xntpd/scripts/support/etc/crontab new file mode 100644 index 0000000000..2b2d19ced7 --- /dev/null +++ b/contrib/xntpd/scripts/support/etc/crontab @@ -0,0 +1,8 @@ +# +# NTP statistics periodic cleanup - REFERENCE SERVER ONLY +# +#55 23 * * * sh /local/NTP/etc/mvstats +# +# gather NTP client statistics - REFERENCE SERVER ONLY +# +0 8,18 * * * /local/NTP/etc/cron 2>/dev/null | /usr/ucb/mail -s "NTP statistics" time@informatik.uni-erlangen.de diff --git a/contrib/xntpd/scripts/support/etc/install b/contrib/xntpd/scripts/support/etc/install new file mode 100644 index 0000000000..169a7e5a06 --- /dev/null +++ b/contrib/xntpd/scripts/support/etc/install @@ -0,0 +1,67 @@ +#!/bin/sh +# +# install,v 3.1 1993/07/06 01:10:53 jbj Exp +# +# install,v +# Revision 3.1 1993/07/06 01:10:53 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:59:21 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.1 1992/06/18 14:50:08 kardel +# Initial revision +# +# +NTPROOT=/local/NTP # SITE SPECIFIC: where NTP resides +# +# where the local NTP state files reside (xntp.drift) ussualle /etc +# this directory must not be shared as machine dependent data ist stored there +# +NTPDIR="/+private/local/NTP" +# +# get the initial setup +# +if [ ! -r $NTPROOT/etc/setup ]; then + echo "ERROR: $NTPROOT/etc/setup missing - incorrect installation." + exit 1 +else + . $NTPROOT/etc/setup +fi + +umask 022 # SITE SPECIFIC: local policy - watch out for NFS and "root" rights + +Mkdir() { + p="" + IFS="/" + set -- $@ + IFS=' +' + for pnc do + if [ ! -d "$p/$pnc" ]; then + ECHO -n "creating directory $p/$pnc" + if mkdir "$p/$pnc"; then + ECHO "" + else + ECHO " - FAILED" + break; + fi + fi + p="$p/$pnc" + done +} + +if [ ! -d "$NTPDIR" ]; then + ECHO "installing NTP private data area ($NTPDIR)" + if Mkdir "$NTPDIR"; then + chmod 755 "$NTPDIR" + ECHO "$NTPDIR created." + fi +else + ECHO "NTP already installed." + if [ -f "$NTPDIR/xntp.drift" ]; then + ECHO "currently saved drift value:" `cat "$NTPDIR/xntp.drift"` + fi +fi + diff --git a/contrib/xntpd/scripts/support/etc/rc b/contrib/xntpd/scripts/support/etc/rc new file mode 100644 index 0000000000..ef8834a69f --- /dev/null +++ b/contrib/xntpd/scripts/support/etc/rc @@ -0,0 +1,198 @@ +#!/bin/sh +# NTP time synchronisation +# +# /src/NTP/REPOSITORY/v3/supportscripts/etc/rc,v 1.11 1993/07/09 13:17:00 kardel Exp +# +# rc,v +# Revision 1.11 1993/07/09 13:17:00 kardel +# local NTPROOT +# +# Revision 1.10 1993/07/09 11:37:29 kardel +# Initial restructured version + GPS support +# +# Revision 1.9 1993/06/23 14:10:36 kardel +# June 21st reconcilation +# +# Revision 1.7 1993/06/02 12:04:43 kardel +# May 28th reconcilation & clenaup +# +# +# non reference clock hosts will try to do an ntpdate on NTPSERVERS +# +NTPSERVERS="ntps1-0 ntps1-1 ntps2-0 ntps2-1" +NTPROOT=/local/NTP + +# +# get the initial setup +# +if [ ! -r $NTPROOT/etc/setup ]; then + echo "ERROR: $NTPROOT/etc/setup missing - incorrect installation." + exit 1 +else + . $NTPROOT/etc/setup +fi + +umask 022 # SITE SPECIFIC: local policy - watch out for NFS and "root" rights + +msg="" +# +# default configuration files are named $NTPROOT/conf/. +# +CF=$NTPROOT/conf/$ARCH.$KARCH # default configuration file +# +# Host specific config file (reference clocks) have the hostname tagged on +# +CFH="$CF"."$HOSTNAME" # specific configuration file +# +# where to find the tickadj command +# +KFIX=$NTPROOT/bin/tickadj # kernel variable fix +# +# where to find special tickadj parameters +# +TC=$NTPROOT/conf/tickconf # special tickadj parameters +# +# where to find the keys file (if not found $KEY.dumb will be used) +# +KEY=$NTPROOT/conf/ntp.keys # private key file +# +# the daemon +# +XD=$NTPROOT/bin/xntpd # NTP daemon +# +# HP adjtimed +# +ADJTIMED=$NTPROOT/bin/adjtimed # HP special (adjtime() emulation) +# +# ntpdate command +# +NTPDATE=$NTPROOT/bin/ntpdate + +# +# secondary timed support +# The word "TIMED" must be in the config file for timed to start +# Note that this times is a special version which does not ever set or +# adjust the time. Ask time@informatik.uni-erlangen.de for patches +# +TIMED=$NTPROOT/bin/timed # timed (Berkeley) secondary time service + # here used in a *HARMLESS* version + # to provide time to "inferior" systems +# +# ISREFHOST is a command that returns exit status 0 for a reference host +# Site specific: sample for dcf77 is given +# +ISREFHOST="[ -f $NTPROOT/.karch.$KARCH/sys/OBJ/parsestreams.o -a -f /dev/refclock-0 ]" +# +# SETUP_REFCLOCK +# +# what to do in order to set up a local reference clock +# usually this will load a STREAMS module or initialize other things +# needed +# +SETUP_REFCLOCK() { + if modstat | grep -s 'PARSE'; then + ECHO "loadable PARSER STREAMS module already loaded." + else + ECHO "attempting to load PARSER STREAMS module..." + MDLFILE="/tmp/mdl.$$" + if modload $NTPROOT/.karch.$KARCH/sys/OBJ/parsestreams.o -o $MDLFILE 2>&1; then + modstat + else + echo WARNING: load FAILED + fi | LOG + rm -f $MDLFILE + unset MDLFILE + fi +} + +kargs() { + MATCH=NO + HOSTID="`(hostid) 2>/dev/null || echo 000000`" + if [ -r "$TC" ]; then + exec 0< "$TC" + while [ "$MATCH" != "YES" ] && read HOST ID PARAM; do + if [ "$HOST" = "DEFAULT" ]; then + DEFAULT="$ID $PARAM" + else + if [ "$ID" = "$HOSTID" -o "$HOST" = "$HOSTNAME" ]; then + echo "$PARAM" + MATCH=YES + fi + fi + done + if [ "$MATCH" != "YES" ]; then + if [ -z "$DEFAULT" ]; then + echo "-A -p -s -q"; + else + echo "$DEFAULT"; + fi + fi + else + echo "-A -p -s -q"; + fi +} + +if [ -x $XD ]; then + if [ -x "$ADJTIMED" ]; then + $ADJTIMED && ECHO "adjusttimesupport: adjtimed." + fi + # + # WARNING: check ps command first, or you might kill things you don't want to + # + PID="`(ps -efa 2>/dev/null || ps auxww 2>/dev/null || echo "") | grep xntp | grep -v grep | awk '{ print $2 }'`" + + if [ ! -z "$PID" ]; then + ECHO "killing old NTP daemon (PID=$PID)" + # + # enable this after checking for correctness + # kill $PID + ECHO "should do a kill $PID, if this is the right PID - check rc script" + fi + # + # try an ntpdate when timeservers are configured + # + if [ ! -z "$NTPSERVERS" -a -x $NTPDATE ]; then + ECHO "NTP initial time setting" + $NTPDATE -v $NTPSERVERS | LOG + fi + # + # look for reference clock equipment + # + if $ISREFHOST; then + ECHO "REFERENCE CLOCK SUPPORT (initializing...)" + SETUP_REFCLOCK + fi + + if [ -r "$CFH" ]; then + CF="$CFH" + else + if [ ! -r "$KEY" ]; then + KEY="$KEY.dumb" + fi + fi + + ECHO "NTP configuration file: $CF" + ECHO -n "time daemon startup:" + + if [ -r "$CF" ]; then + if [ -x "$KFIX" ]; then + KARGS="`kargs`" + if [ ! -z "$KARGS" ]; then + $KFIX $KARGS && ECHO -n "tickadj $KARGS" + fi + fi + $XD -c "$CF" -k "$KEY" && ECHO -n ' xntpd' + if [ -x "$TIMED" ] && grep -s TIMED "$CF"; then + $TIMED -M -N && ECHO -n ' timed' + fi + else + msg="configuration file ($CF) not present." + fi +else + msg="daemon binary ($XD) not present." +fi +ECHO "." + +if [ "$msg" ]; then + NLECHO "WARNING: NO NTP time sychronisation: $msg" +fi diff --git a/contrib/xntpd/scripts/support/etc/setup b/contrib/xntpd/scripts/support/etc/setup new file mode 100644 index 0000000000..d4ea75ecfa --- /dev/null +++ b/contrib/xntpd/scripts/support/etc/setup @@ -0,0 +1,72 @@ +# +# setup,v 3.1 1993/07/06 01:10:55 jbj Exp +# +# /bin/sh sourced file for environment setup +# expects NTPROOT variable initialized +# +# if not set it will be initialized to /usr/local/NTP +# +# setup,v +# Revision 3.1 1993/07/06 01:10:55 jbj +# XNTP release 3.1 +# +# +# Revision 1.1 1992/12/10 12:59:25 kardel +# Prerelease NTP V3 / DCF +# +# Revision 1.1 1992/12/10 10:14:46 kardel +# Initial revision +# +# +NTPROOT=${NTPROOT-/usr/local/NTP} + +# +# we so use our own echos, as we somes want to substitute them with a +# file logging version durin the /etc/rc.local phase +# +set `type ECHO` + +PATH="${PATH}:$NTPROOT/bin" +export PATH + +if [ "$2" = "is" ]; then + : +else + # + # find out the way echos work (Rest of rc thinks BSD echo) + # + ECHOREP="`echo -n x`" + if [ "$ECHOREP" = "-n x" ]; then + ECHO () { + if [ "$1" = "-n" ]; then + shift + echo "$@\c" + else + echo "$@" + fi + } + #ECHO "System V style echo" + else + ECHO () { + echo "$@" + } + #ECHO "BSD style echo" + fi + + NLECHO () { + echo "$@" + } + + LOG () { + while read _line; do + ECHO "$_line" + done + } + # + # carefully find out some configuration Variables + # + ARCH="`(arch) 2>/dev/null || ((uname) > /dev/null && uname -a | awk '{ print $6; }') 2>/dev/null || echo 'no-arch'`" + KARCH="`(arch -k) 2>/dev/null || ((uname) > /dev/null && uname -a | awk '{ print $5 }') || echo 'no-arch'`" + HOSTNAME="`(hostname) 2>/dev/null || uname -n`" +fi + diff --git a/contrib/xntpd/util/Makefile.tmpl b/contrib/xntpd/util/Makefile.tmpl new file mode 100644 index 0000000000..1115ef83a7 --- /dev/null +++ b/contrib/xntpd/util/Makefile.tmpl @@ -0,0 +1,62 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:10:58 jbj Exp +# +PROGRAM= tickadj +# +# Makefile for utilities +# +COMPILER= cc +COPTS= -O +BINDIR= /usr/local +INSTALL= install +DEFS= +DEFS_OPT= +DEFS_LOCAL= +DAEMONLIBS= +RESLIB= +COMPAT= +# +INCL= -I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +LIB= ../lib/libntp.a +LINTLIB= ../lib/llib-llibntp.ln +MAKE= make +TOP=../ +# +SOURCE= tickadj.c ntptime.c +TKOBJS= tickadj.o +NTOBJS= ntptime.o +EXECS= ntptime jitter timetrim kern byteorder longsize precision + +all: $(PROGRAM) + +tickadj: $(TKOBJS) + $(CC) $(COPTS) -o $@ $(TKOBJS) $(DAEMONLIBS) $(RESLIB) $(COMPAT) + +ntptime: $(NTOBJS) + $(CC) $(COPTS) -o $@ $(NTOBJS) $(LIB) + +precision: precision.o + $(CC) $(COPTS) -o $@ $@.o + +install: $(BINDIR)/$(PROGRAM) + +$(BINDIR)/$(PROGRAM): $(PROGRAM) + $(INSTALL) -c -m 0755 $(PROGRAM) $(BINDIR) + +tags: + ctags *.c *.h + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(PROGRAM) $(EXECS) *.o *.out tags make.log Makefile.bak lint.errs + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) $(MFLAGS) MFLAGS="$(MFLAGS)" + diff --git a/contrib/xntpd/util/README b/contrib/xntpd/util/README new file mode 100644 index 0000000000..2aedb00683 --- /dev/null +++ b/contrib/xntpd/util/README @@ -0,0 +1,67 @@ +README file for directory ./util of the NTP Version 3 distribution + +This directory contains the sources for the various utility programs. See +the README and RELNOTES files in the parent directory for directions on +how to make and install these programs. + +The ntptime.c program checks the kernel configuration for the NTP user +interface syscalls ntp_gettime() and ntp_adjtime(). If present, the +current timekeeping data are displayed. If not, a dissapointment is +displayed. Do "make ntptime" in this directory to make the thing, +but be advised that, unless you have installed the kernel support, +there will probably be missing vital header files. See the README.kern +file in the doc directory of this distribution for further details. + +The jitter.c program can be used to determine the timing jitter due to +the operating system in a gettimeofday() call. For most systems the +dominant contribution to the jitter budget is the period of the hardware +interrupt, usually in the range 1-10 ms. For those systems with microsecond +counters, such as recent Sun and certain Ultrix systems, the jitter is +dominated only by the operating system. + +The timetrim.c program can be used with SGI machines to implement a +scheme to discipline the hardware clock frequency. See the source code +for further information. + +The byteorder.c and longsize.c programs are used during the configuration +process to determine the byte order (little or big endian) and longword +size (32 or 64 bits). See the ../scripts/makefile.sh script for further +details. + +The testrs6000.c program is used for testing purposes with the IBM +RS/6000 AIX machines. Bill Jones reports: +"I could not get a tickadj of less then 40 us to work on a RS6000. +If you set it less then 40 us do so at your own risk!" + +The tickadj.c program can be used to read and set various kernel +parameters affecting NTP operations. Comes now the rationale for its use. + +Then daemon's clock adjustment algorithms depend (too) strongly +on the internals of the kernel adjtime() call, and expect it to +match that which comes with Berkeley-flavour operating systems. +The daemon actually reads a couple of values from your kernel +using /dev/kmem (ugh!), the value of `tick' and the value of `tickadj'. +`tick' is expected to be the number of microseconds which are +added to the system time on timer interrupts when the clock isn't +being slewed. `tickadj' is the number of microseconds which are +added or subtracted from tick when the clock is being slewed. + +The program tickadj mimics the daemon's handling of these variables. +If you run it (as root) and it fails or produces bizarre looking +values you may have to torque ntp_unixclock.c in the daemon code. + +You can also use tickadj -a to set tickadj in the running kernel. +In addition, tickadj -A will compute the value to set based on the +kernel's value of tick, while the -t flag allows one to set the +value of tick and the -s flag will set the value of dosynctodr +to zero. This is an alternative for people who can't change the +values in the kernel's disk image. + +In addition, the -p flag will set the noprintf variable. This will +suppress any kernel messages. Kernel message can then only be seen via +syslog(3). This inhibits clockhopping due to kernel printf's. + +The target "ntptime" can only be compiled on systems with kernel PLL +support. This is currently only possible for SunOS4, Ultrix and DECOSF1. +You need the propriatary header files for that. So there is no need to +attempt to compile ntptime unless you have the above configuration. diff --git a/contrib/xntpd/util/byteorder.c b/contrib/xntpd/util/byteorder.c new file mode 100644 index 0000000000..665c146153 --- /dev/null +++ b/contrib/xntpd/util/byteorder.c @@ -0,0 +1,52 @@ +/* + * This works on: + * Crays + * Conven + * sparc's + * Dec mip machines + * Dec alpha machines + * RS6000 + * SGI's + */ + +#include +main() +{ + int i; + int big; + union { + unsigned long l; + char c[sizeof(long)]; + } u; + +#if defined(LONG8) + u.l = (((long)0x08070605) << 32) | (long)0x04030201; +#else + u.l = 0x04030201; +#endif + if (sizeof(long) > 4) { + if (u.c[0] == 0x08) big = 1; + else big = 0; + } else { + if (u.c[0] == 0x04) big = 1; + else big = 0; + } + for (i=0; i< sizeof(long); i++) { + if (big == 1 && (u.c[i] == (sizeof(long) - i))) { + continue; + } else if (big == 0 && (u.c[i] == (i+1))) { + continue; + } else { + big = -1; + break; + } + } + + if (big == 1) { + printf("XNTP_BIG_ENDIAN\n"); + } else if (big == 0) { + printf("XNTP_LITTLE_ENDIAN\n"); + } + exit(0); +} + diff --git a/contrib/xntpd/util/jitter.c b/contrib/xntpd/util/jitter.c new file mode 100644 index 0000000000..7201e87eba --- /dev/null +++ b/contrib/xntpd/util/jitter.c @@ -0,0 +1,73 @@ +/* + * This program can be used to calibrate the clock reading jitter of a + * particular CPU and operating system. It first tickles every element + * of an array, in order to force pages into memory, then repeatedly calls + * gettimeofday() and, finally, writes out the time values for later + * analysis. From this you can determine the jitter and if the clock ever + * runs backwards. + */ +#include +#include + +#define NBUF 10001 + +main() +{ + struct timeval tp, ts, tr; + struct timezone tzp; + long temp, j, i, gtod[NBUF]; + + gettimeofday(&ts, &tzp); + ts.tv_usec = 0; + + /* + * Force pages into memory + */ + for (i = 0; i < NBUF; i ++) + gtod[i] = 0; + + /* + * Construct gtod array + */ + for (i = 0; i < NBUF; i ++) { + gettimeofday(&tp, &tzp); + tr = tp; + tr.tv_sec -= ts.tv_sec; + tr.tv_usec -= ts.tv_usec; + if (tr.tv_usec < 0) { + tr.tv_usec += 1000000; + tr.tv_sec--; + } + gtod[i] = tr.tv_sec * 1000000 + tr.tv_usec; + } + + /* + * Write out gtod array for later processing with S + */ + for (i = 0; i < NBUF - 1; i++) { +/* + printf("%lu\n", gtod[i]); +*/ + gtod[i] = gtod[i + 1] - gtod[i]; + printf("%lu\n", gtod[i]); + } + + /* + * Sort the gtod array and display deciles + */ + for (i = 0; i < NBUF - 1; i++) { + for (j = 0; j <= i; j++) { + if (gtod[j] > gtod[i]) { + temp = gtod[j]; + gtod[j] = gtod[i]; + gtod[i] = temp; + } + } + } + fprintf(stderr, "First rank\n"); + for (i = 0; i < 10; i++) + fprintf(stderr, "%10ld%10ld\n", i, gtod[i]); + fprintf(stderr, "Last rank\n"); + for (i = NBUF - 11; i < NBUF - 1; i++) + fprintf(stderr, "%10ld%10ld\n", i, gtod[i]); +} diff --git a/contrib/xntpd/util/kern.c b/contrib/xntpd/util/kern.c new file mode 100644 index 0000000000..a2a667203a --- /dev/null +++ b/contrib/xntpd/util/kern.c @@ -0,0 +1,210 @@ +/* + * This program simulates a first-order, type-II phase-lock loop using + * actual code segments from modified kernel distributions for SunOS, + * Ultrix and OSF/1 kernels. These segments do not use any licensed code. + */ +#include +#include +#include +#include + +#include "timex.h" + +/* + * Phase-lock loop definitions + */ +#define HZ 100 /* timer interrupt frequency (Hz) */ +#define MAXPHASE 512000 /* max phase error (us) */ +#define MAXFREQ 200 /* max frequency error (ppm) */ +#define TAU 2 /* time constant (shift 0 - 6) */ +#define POLL 16 /* interval between updates (s) */ +#define MAXSEC 1200 /* max interval between updates (s) */ + +/* + * Function declarations + */ +void hardupdate(); +void hardclock(); +void second_overflow(); + +/* + * Kernel variables + */ +int tick; /* timer interrupt period (us) */ +int fixtick; /* amortization constant (ppm) */ +struct timeval timex; /* ripoff of kernel time variable */ + +/* + * Phase-lock loop variables + */ +int time_status = TIME_BAD; /* clock synchronization status */ +long time_offset = 0; /* time adjustment (us) */ +long time_constant = 0; /* pll time constant */ +long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */ +long time_precision = 1000000 / HZ; /* clock precision (us) */ +long time_maxerror = MAXPHASE; /* maximum error (us) */ +long time_esterror = MAXPHASE; /* estimated error (us) */ +long time_phase = 0; /* phase offset (scaled us) */ +long time_freq = 0; /* frequency offset (scaled ppm) */ +long time_adj = 0; /* tick adjust (scaled 1 / HZ) */ +long time_reftime = 0; /* time at last adjustment (s) */ + +/* + * Simulation variables + */ +double timey = 0; /* simulation time (us) */ +long timez = 0; /* current error (us) */ +long poll_interval = 0; /* poll counter */ + +/* + * Simulation test program + */ +void main() +{ + tick = 1000000 / HZ; + fixtick = 1000000 % HZ; + timex.tv_sec = 0; + timex.tv_usec = MAXPHASE; + time_freq = 0; + time_constant = TAU; + printf("tick %d us, fixtick %d us\n", tick, fixtick); + printf(" time offset freq _offset _freq _adj\n"); + + /* + * Grind the loop until ^C + */ + while (1) { + timey += (double)(1000000) / HZ; + if (timey >= 1000000) + timey -= 1000000; + hardclock(); + if (timex.tv_usec >= 1000000) { + timex.tv_usec -= 1000000; + timex.tv_sec++; + second_overflow(); + poll_interval++; + if (!(poll_interval % POLL)) { + timez = (long)timey - timex.tv_usec; + if (timez > 500000) + timez -= 1000000; + if (timez < -500000) + timez += 1000000; + hardupdate(timez); + printf("%10li%10li%10.2f %08lx %08lx %08lx\n", + timex.tv_sec, timez, + (double)time_freq / (1 << SHIFT_KF), + time_offset, time_freq, time_adj); + } + } + } +} + +/* + * This routine simulates the ntp_adjtime() call + * + * For default SHIFT_UPDATE = 12, offset is limited to +-512 ms, the + * maximum interval between updates is 4096 s and the maximum frequency + * offset is +-31.25 ms/s. + */ +void hardupdate(offset) +long offset; +{ + long ltemp, mtemp; + + time_offset = offset << SHIFT_UPDATE; + mtemp = timex.tv_sec - time_reftime; + time_reftime = timex.tv_sec; + if (mtemp > MAXSEC) + mtemp = 0; + + /* ugly multiply should be replaced */ + if (offset < 0) + time_freq -= (-offset * mtemp) >> + (time_constant + time_constant); + else + time_freq += (offset * mtemp) >> + (time_constant + time_constant); + ltemp = time_tolerance << SHIFT_KF; + if (time_freq > ltemp) + time_freq = ltemp; + else if (time_freq < -ltemp) + time_freq = -ltemp; + if (time_status == TIME_BAD) + time_status = TIME_OK; +} + +/* + * This routine simulates the timer interrupt + */ +void hardclock() +{ + int ltemp, time_update; + + time_update = tick; /* computed by adjtime() */ + time_phase += time_adj; + if (time_phase < -FINEUSEC) { + ltemp = -time_phase >> SHIFT_SCALE; + time_phase += ltemp << SHIFT_SCALE; + time_update -= ltemp; + } + else if (time_phase > FINEUSEC) { + ltemp = time_phase >> SHIFT_SCALE; + time_phase -= ltemp << SHIFT_SCALE; + time_update += ltemp; + } + timex.tv_usec += time_update; +} + +/* + * This routine simulates the overflow of the microsecond field + * + * With SHIFT_SCALE = 23, the maximum frequency adjustment is +-256 us + * per tick, or 25.6 ms/s at a clock frequency of 100 Hz. The time + * contribution is shifted right a minimum of two bits, while the frequency + * contribution is a right shift. Thus, overflow is prevented if the + * frequency contribution is limited to half the maximum or 15.625 ms/s. + */ +void second_overflow() +{ + int ltemp; + + time_maxerror += time_tolerance; + if (time_offset < 0) { + ltemp = -time_offset >> + (SHIFT_KG + time_constant); + time_offset += ltemp; + time_adj = -(ltemp << + (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE)); + } else { + ltemp = time_offset >> + (SHIFT_KG + time_constant); + time_offset -= ltemp; + time_adj = ltemp << + (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE); + } + if (time_freq < 0) + time_adj -= -time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE); + else + time_adj += time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE); + time_adj += fixtick << (SHIFT_SCALE - SHIFT_HZ); + + /* ugly divide should be replaced */ + if (timex.tv_sec % 86400 == 0) { + switch (time_status) { + + case TIME_INS: + timex.tv_sec--; /* !! */ + time_status = TIME_OOP; + break; + + case TIME_DEL: + timex.tv_sec++; + time_status = TIME_OK; + break; + + case TIME_OOP: + time_status = TIME_OK; + break; + } + } +} diff --git a/contrib/xntpd/util/longsize.c b/contrib/xntpd/util/longsize.c new file mode 100644 index 0000000000..6bdbdfeff5 --- /dev/null +++ b/contrib/xntpd/util/longsize.c @@ -0,0 +1,11 @@ +#include + +main() +{ + if (sizeof(long) == 8) { + printf("-DLONG8\n"); + } else if (sizeof(long) == 4) { + printf("-DLONG4\n"); + } + exit(0); +} diff --git a/contrib/xntpd/util/ntptime.c b/contrib/xntpd/util/ntptime.c new file mode 100644 index 0000000000..e528802f72 --- /dev/null +++ b/contrib/xntpd/util/ntptime.c @@ -0,0 +1,220 @@ +/* + * NTP test program + * + * This program tests to see if the NTP user interface routines + * ntp_gettime() and ntp_adjtime() have been implemented in the kernel. + * If so, each of these routines is called to display current timekeeping + * data. + * + * For more information, see the README.kern file in the doc directory + * of the xntp3 distribution. + */ +#include +#include +#include +#include +#include + +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +#ifndef SYS_DECOSF1 +#define BADCALL -1 /* this is supposed to be a bad syscall */ +#endif +#include "ntp_timex.h" + +#ifdef KERNEL_PLL +#ifndef SYS_ntp_adjtime +#define SYS_ntp_adjtime NTP_SYSCALL_ADJ +#endif +#ifndef SYS_ntp_gettime +#define SYS_ntp_gettime NTP_SYSCALL_GET +#endif +#endif /* KERNEL_PLL */ + +extern int sigvec P((int, struct sigvec *, struct sigvec *)); +void pll_trap P((void)); +extern int getopt_l P((int, char **, char *)); + +static struct sigvec newsigsys; /* new sigvec status */ +static struct sigvec sigsys; /* current sigvec status */ +static int pll_control; /* (0) daemon, (1) kernel loop */ + +static char* progname; +static char optargs[] = "ce:f:hm:o:rs:t:"; + +void +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + extern char *optarg; + int status; + struct ntptimeval ntv; + struct timex ntx, _ntx; + int times[20]; + double ftemp; + l_fp ts; + int c; + int errflg = 0; + int cost = 0; + int rawtime = 0; + + ntx.mode = 0; + progname = argv[0]; + while ((c = getopt_l(argc, argv, optargs)) != EOF) switch (c) { + case 'c': + cost++; + break; + case 'e': + ntx.mode |= ADJ_ESTERROR; + ntx.esterror = atoi(optarg); + break; + case 'f': + ntx.mode |= ADJ_FREQUENCY; + ntx.frequency = (int) (atof(optarg) * (1 << SHIFT_USEC)); + if (ntx.frequency < (-100 << SHIFT_USEC) + || ntx.frequency > ( 100 << SHIFT_USEC)) errflg++; + break; + case 'm': + ntx.mode |= ADJ_MAXERROR; + ntx.maxerror = atoi(optarg); + break; + case 'o': + ntx.mode |= ADJ_OFFSET; + ntx.offset = atoi(optarg); + break; + case 'r': + rawtime++; + break; + case 's': + ntx.mode |= ADJ_STATUS; + ntx.status = atoi(optarg); + if (ntx.status < 0 || ntx.status > 4) errflg++; + break; + case 't': + ntx.mode |= ADJ_TIMECONST; + ntx.time_constant = atoi(optarg); + if (ntx.time_constant < 0 || ntx.time_constant > MAXTC) + errflg++; + break; + default: + errflg++; + } + if (errflg || (optind != argc)) { + (void) fprintf(stderr, + "usage: %s [-%s]\n\n\ + -c display the time taken to call ntp_gettime (us)\n\ + -e esterror estimate of the error (us)\n\ + -f frequency Frequency error (-100 .. 100) (ppm)\n\ + -h display this help info\n\ + -m maxerror max possible error (us)\n\ + -o offset current offset (ms)\n\ + -r print the unix and NTP time raw\n\ + -s status Set the status (0 .. 4)\n\ + -t timeconstant log2 of PLL time constant (0 .. %d)\n", + progname, optargs, MAXTC); + exit(2); + } + + + /* + * Test to make sure the sigvec() works in case of invalid + * syscall codes. + */ + newsigsys.sv_handler = pll_trap; + newsigsys.sv_mask = 0; + newsigsys.sv_flags = 0; + if (sigvec(SIGSYS, &newsigsys, &sigsys)) { + perror("sigvec() fails to save SIGSYS trap"); + exit(1); + } + +#ifdef BADCALL + /* + * Make sure the trapcatcher works. + */ + pll_control = 1; + (void)syscall(BADCALL, &ntv); /* dummy parameter f. ANSI compilers */ + if (pll_control) + printf("sigvec() failed to catch an invalid syscall\n"); +#endif + + if (cost) { + for (c=0; c< sizeof times / sizeof times[0]; c++) { + (void)ntp_gettime(&ntv); + if (pll_control < 0) break; + times[c] = ntv.time.tv_usec; + } + if (pll_control >= 0) { + printf("[ usec %06d:", times[0]); + for (c=1; c< sizeof times / sizeof times[0]; c++) printf(" %d", times[c] - times[c-1]); + printf(" ]\n"); + } + } + (void)ntp_gettime(&ntv); + ntx.mode = 0; /* Ensure nothing is set */ + (void)ntp_adjtime(&_ntx); + if (pll_control < 0) { + printf("NTP user interface routines are not configured in this kernel.\n"); + goto lexit; + } + + /* + * Fetch timekeeping data and display. + */ + if ((status = ntp_gettime(&ntv)) < 0) + perror("ntp_gettime() call fails"); + else { + printf("ntp_gettime() returns code %d\n", status); + TVTOTS(&ntv.time, &ts); + ts.l_uf += TS_ROUNDBIT; /* guaranteed not to overflow */ + ts.l_ui += JAN_1970; + ts.l_uf &= TS_MASK; + printf(" time: %s, (.%06d)\n", + prettydate(&ts), ntv.time.tv_usec); + printf(" confidence interval: %ld usec, estimated error: %ld usec\n", + ntv.maxerror, ntv.esterror); + if (rawtime) printf(" ntptime=%x.%x unixtime=%x.%06d %s", + ts.l_ui, ts.l_uf, + ntv.time.tv_sec, ntv.time.tv_usec, + ctime(&ntv.time.tv_sec)); + } + if ((status = ntp_adjtime(&ntx)) < 0) perror((errno == EPERM) ? + ">> Must be root to set kernel values\n>> ntp_adjtime() call fails" : + ">> ntp_adjtime() call fails"); + else { + printf("ntp_adjtime() returns code %d\n", status); + ftemp = ntx.frequency; + ftemp /= (1 << SHIFT_USEC); + printf(" mode: %02x, offset: %ld usec, frequency: %6.3f ppm,\n", + ntx.mode, ntx.offset, ftemp); + printf(" confidence interval: %ld usec, estimated error: %ld usec,\n", + ntx.maxerror, ntx.esterror); + printf(" status: %d, time constant: %ld, precision: %ld usec, tolerance: %ld usec\n", + ntx.status, ntx.time_constant, ntx.precision, + ntx.tolerance); + } + + /* + * Put things back together the way we found them. + */ +lexit: if (sigvec(SIGSYS, &sigsys, (struct sigvec *)NULL)) { + perror("sigvec() fails to restore SIGSYS trap"); + exit(1); + } + exit(0); +} + +/* + * pll1_trap - trap processor for undefined syscalls + */ +void +pll_trap() +{ + pll_control--; +} diff --git a/contrib/xntpd/util/precision.c b/contrib/xntpd/util/precision.c new file mode 100644 index 0000000000..69af19fb92 --- /dev/null +++ b/contrib/xntpd/util/precision.c @@ -0,0 +1,81 @@ +#include +#include + +#define DEFAULT_SYS_PRECISION -99 + +int default_get_precision(); + +int +main() { + printf("log2(precision) = %d\n", default_get_precision()); + return 0; +} + +/* Find the precision of the system clock by watching how the current time + * changes as we read it repeatedly. + * + * struct timeval is only good to 1us, which may cause problems as machines + * get faster, but until then the logic goes: + * + * If a machine has precision (i.e. accurate timing info) > 1us, then it will + * probably use the "unused" low order bits as a counter (to force time to be + * a strictly increaing variable), incrementing it each time any process + * requests the time [[ or maybe time will stand still ? ]]. + * + * SO: the logic goes: + * + * IF the difference from the last time is "small" (< MINSTEP) + * THEN this machine is "counting" with the low order bits + * ELIF this is not the first time round the loop + * THEN this machine *WAS* counting, and has now stepped + * ELSE this machine has precision < time to read clock + * + * SO: if it exits on the first loop, assume "full accuracy" (1us) + * otherwise, take the log2(observered difference, rounded UP) + * + * MINLOOPS > 1 ensures that even if there is a STEP between the initial call + * and the first loop, it doesn't stop too early. + * Making it even greater allows MINSTEP to be reduced, assuming that the + * chance of MINSTEP-1 other processes getting in and calling gettimeofday + * between this processes's calls. + * Reducing MINSTEP may be necessary as this sets an upper bound for the time + * to actually call gettimeofday. + */ + +#define DUSECS 1000000 +#define HUSECS (1024 * 1024) +#define MINSTEP 5 /* some systems increment uS on each call */ + /* Don't use "1" as some *other* process may read too*/ + /*We assume no system actually *ANSWERS* in this time*/ +#define MAXLOOPS HUSECS /* Assume precision < .1s ! */ + +int default_get_precision() +{ + struct timeval tp; + struct timezone tzp; + long last; + int i; + long diff; + long val; + int minsteps = 2; /* need at least this many steps */ + + gettimeofday(&tp, &tzp); + last = tp.tv_usec; + for (i = - --minsteps; i< MAXLOOPS; i++) { + gettimeofday(&tp, &tzp); + diff = tp.tv_usec - last; + if (diff < 0) diff += DUSECS; + if (diff > MINSTEP) if (minsteps-- <= 0) break; + last = tp.tv_usec; + } + + printf("precision calculation given %dus after %d loop%s\n", + diff, i, (i==1) ? "" : "s"); + + diff = (diff *3)/2; + if (i >= MAXLOOPS) diff = 1; /* No STEP, so FAST machine */ + if (i == 0) diff = 1; /* time to read clock >= precision */ + for (i=0, val=HUSECS; val>0; i--, val >>= 1) if (diff >= val) return i; + return DEFAULT_SYS_PRECISION /* Something's BUST, so lie ! */; +} + diff --git a/contrib/xntpd/util/testrs6000.c b/contrib/xntpd/util/testrs6000.c new file mode 100644 index 0000000000..9a5e0cd776 --- /dev/null +++ b/contrib/xntpd/util/testrs6000.c @@ -0,0 +1,44 @@ +/* Checks for the RS/6000 AIX adjtime() bug, in which if a negative + * offset is given, the system gets messed up and never completes the + * adjustment. If the problem is fixed, this program will print the + * time, sit there for 10 seconds, and exit. If the problem isn't fixed, + * the program will print an occasional "result=nnnnnn" (the residual + * slew from adjtime()). + * + * Compile this with bsdcc and run it as root! + */ +#include +#include +#include +#include +int timeout(); +struct timeval adjustment, result; +main () { + struct itimerval value, oldvalue; + int i; + time_t curtime; + curtime = time(0); + printf("Starting: %s", ctime(&curtime)); + value.it_interval.tv_sec = value.it_value.tv_sec = 1; + value.it_interval.tv_usec = value.it_value.tv_usec = 0; + adjustment.tv_sec = 0; + adjustment.tv_usec = -2000; + signal(SIGALRM, timeout); + setitimer(ITIMER_REAL, &value, &oldvalue); + for (i=0; i<10; i++) { + pause(); + } +} + +int timeout(sig, code, scp) +int sig,code; +struct sigcontext *scp; +{ + signal (SIGALRM, timeout); + if (adjtime(&adjustment, &result)) + printf("adjtime call failed\n"); + if (result.tv_sec != 0 || result.tv_usec != 0) { + printf("result.u = %d.%06.6d ", (int) result.tv_sec, + (int) result.tv_usec); + } +} diff --git a/contrib/xntpd/util/tickadj.c b/contrib/xntpd/util/tickadj.c new file mode 100644 index 0000000000..da18e06603 --- /dev/null +++ b/contrib/xntpd/util/tickadj.c @@ -0,0 +1,518 @@ +/* tickadj.c,v 3.1 1993/07/06 01:11:05 jbj Exp + * tickadj - read, and possibly modify, the kernel `tick' and + * `tickadj' variables, as well as `dosynctodr'. Note that + * this operates on the running kernel only. I'd like to be + * able to read and write the binary as well, but haven't + * mastered this yet. + */ +#include +#include +#include +#include + +#if defined(SYS_AUX3) || defined(SYS_AUX2) +#include +#include +#include +#include +#include +#include +#else +#include +#endif + +#include "ntp_io.h" +#include "ntp_stdlib.h" + +#ifdef RS6000 +#undef hz +#endif /* RS6000 */ + +#if defined(SOLARIS)||defined(RS6000)||defined(SYS_SINIXM) +#if !defined(_SC_CLK_TCK) +#include +#endif +#endif + +#ifdef SYS_PTX +#define L_SET SEEK_SET +#endif + +#define KMEM "/dev/kmem" +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +char *progname; +int debug; + +int dokmem = 1; +int writetickadj = 0; +int writeopttickadj = 0; +int unsetdosync = 0; +int writetick = 0; +int quiet = 0; +int setnoprintf = 0; + +char *kmem = KMEM; +char *kernel = NULL; +char *file = NULL; +int fd = -1; + +static char * getoffsets P((char *, unsigned long *, unsigned long *, unsigned long *, unsigned long *)); +static int openfile P((char *, int)); +static void writevar P((int, unsigned long, int)); +static void readvar P((int, unsigned long, int *)); +#ifndef NTP_POSIX_SOURCE +extern int getopt P((int, char **, char *)); +#endif + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + unsigned long tickadj_offset; + unsigned long tick_offset; + unsigned long dosync_offset; + unsigned long noprintf_offset; + int tickadj; + int tick; + int dosynctodr; + int noprintf; + int hz, hz_hundredths; + int recommend_tickadj; + long tmp; + int openfile(); + char *getoffsets(); + void readvar(); + void writevar(); + + progname = argv[0]; + while ((c = getopt(argc, argv, "a:Adkqpst:")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + case 'k': + dokmem = 1; + break; + case 'p': + setnoprintf = 1; + break; + case 'q': + quiet = 1; + break; + case 'a': + writetickadj = atoi(optarg); + if (writetickadj <= 0) { + (void) fprintf(stderr, + "%s: unlikely value for tickadj: %s\n", + progname, optarg); + errflg++; + } + break; + case 'A': + writeopttickadj = 1; + break; + case 's': + unsetdosync = 1; + break; + case 't': + writetick = atoi(optarg); + if (writetick <= 0) { + (void) fprintf(stderr, + "%s: unlikely value for tick: %s\n", + progname, optarg); + errflg++; + } + break; + default: + errflg++; + break; + } + if (errflg || optind != argc) { + (void) fprintf(stderr, + "usage: %s [-Aqsp] [-a newadj] [-t newtick]\n", progname); + exit(2); + } + kernel = getoffsets(kernel, &tick_offset, + &tickadj_offset, &dosync_offset, &noprintf_offset); + + if (debug) { + (void) printf("tick offset = %lu\n", tick_offset); + (void) printf("tickadj offset = %lu\n", tickadj_offset); + (void) printf("dosynctodr offset = %lu\n", dosync_offset); + (void) printf("noprintf offset = %lu\n", noprintf_offset); + } + + if (setnoprintf && (noprintf_offset == 0)) { + (void) fprintf(stderr, + "No noprintf kernal variable\n"); + exit(1); + } + + if (unsetdosync && (dosync_offset == 0)) { + (void) fprintf(stderr, + "No dosynctodr kernal variable\n"); + exit(1); + } + + if (writeopttickadj && (tickadj_offset == 0)) { + (void) fprintf(stderr, + "No tickadj kernal variable\n"); + exit(1); + } + + if (writetick && (tick_offset == 0)) { + (void) fprintf(stderr, + "No tick kernal variable\n"); + exit(1); + } + + + if (tickadj_offset != 0) + readvar(fd, tickadj_offset, &tickadj); + +#if defined(SOLARIS)||defined(RS6000)||defined(SYS_SINIXM) + tick = 1000000/sysconf(_SC_CLK_TCK); +#else + readvar(fd, tick_offset, &tick); +#endif + + if (dosync_offset != 0) + readvar(fd, dosync_offset, &dosynctodr); + if (noprintf_offset != 0) + readvar(fd, noprintf_offset, &noprintf); + (void) close(fd); + + if (unsetdosync && dosync_offset == 0) { + (void) fprintf(stderr, + "%s: can't find dosynctodr in namelist\n", progname); + exit(1); + } + + if (!quiet) { + (void) printf("tick = %d us",tick); + if (tickadj_offset != 0) + (void) printf(", tickadj = %d us", tickadj); + if (dosync_offset != 0) + (void) printf(", dosynctodr is %s", dosynctodr ? "on" : "off"); + (void) printf("\n"); + if (noprintf_offset != 0) + (void) printf("kernel level printf's: %s\n", noprintf ? "off" : "on"); + } + + if (tick <= 0) { + (void) fprintf(stderr, "%s: the value of tick is silly!\n", + progname); + exit(1); + } + + hz = (int)(1000000L / (long)tick); + hz_hundredths = (int)((100000000L / (long)tick) - ((long)hz * 100L)); + if (!quiet) + (void) printf("calculated hz = %d.%02d Hz\n", hz, + hz_hundredths); + tmp = (long) tick * 500L; + recommend_tickadj = (int)(tmp / 1000000L); + if (tmp % 1000000L > 0) + recommend_tickadj++; + +#if defined(RS6000) + if (recommend_tickadj < 40) recommend_tickadj = 40; +#endif + + if ((!quiet) && (tickadj_offset != 0)) + (void) printf("recommended value of tickadj = %d us\n", + recommend_tickadj); + + if (writetickadj == 0 && !writeopttickadj && + !unsetdosync && writetick == 0 && !setnoprintf) + exit(0); + + if (writetickadj == 0 && writeopttickadj) + writetickadj = recommend_tickadj; + + fd = openfile(file, O_WRONLY); + + if (setnoprintf && (dosync_offset != 0)) { + if (!quiet) { + (void) fprintf(stderr, "setting noprintf: "); + (void) fflush(stderr); + } + writevar(fd, noprintf_offset, 1); + if (!quiet) + (void) fprintf(stderr, "done!\n"); + } + + if ((writetick > 0) && (tick_offset != 0)) { + if (!quiet) { + (void) fprintf(stderr, "writing tick, value %d: ", + writetick); + (void) fflush(stderr); + } + writevar(fd, tick_offset, writetick); + if (!quiet) + (void) fprintf(stderr, "done!\n"); + } + + if ((writetickadj > 0) && (tickadj_offset != 0)) { + if (!quiet) { + (void) fprintf(stderr, "writing tickadj, value %d: ", + writetickadj); + (void) fflush(stderr); + } + writevar(fd, tickadj_offset, writetickadj); + if (!quiet) + (void) fprintf(stderr, "done!\n"); + } + + if (unsetdosync && (dosync_offset != 0)) { + if (!quiet) { + (void) fprintf(stderr, "zeroing dosynctodr: "); + (void) fflush(stderr); + } + writevar(fd, dosync_offset, 0); + if (!quiet) + (void) fprintf(stderr, "done!\n"); + } + (void) close(fd); + exit(0); +} + +/* + * getoffsets - read the magic offsets from the specified file + */ +static char * +getoffsets(filex, tick_off, tickadj_off, dosync_off, noprintf_off) + char *filex; + unsigned long *tick_off; + unsigned long *tickadj_off; + unsigned long *dosync_off; + unsigned long *noprintf_off; +{ + char **kname; + +#if defined(SYS_AUX3) || defined(SYS_AUX2) +#define X_TICKADJ 0 +#define X_V 1 +#define X_TICK 2 +#define X_DEF + static struct nlist nl[4]; +#endif + +#ifdef NeXT +#define X_TICKADJ 0 +#define X_TICK 1 +#define X_DOSYNC 2 +#define X_NOPRINTF 3 +#define X_DEF + static struct nlist nl[] = + { {{"_tickadj"}}, + {{"_tick"}}, + {{"_dosynctodr"}}, + {{"_noprintf"}}, + {{""}}, + }; +#endif + +#if defined(SYS_SVR4) || defined(SYS_PTX) +#define X_TICKADJ 0 +#define X_TICK 1 +#define X_DOSYNC 2 +#define X_NOPRINTF 3 +#define X_DEF + static struct nlist nl[] = + { {{"tickadj"}}, + {{"tick"}}, + {{"doresettodr"}}, + {{"noprintf"}}, + {{""}}, + }; +#endif /* SYS_SVR4 */ + +#if defined(SOLARIS)||defined(RS6000)||defined(SYS_SINIXM) +#ifndef SOLARIS_HRTIME +#define X_TICKADJ 0 +#endif +#define X_DOSYNC 1 +#define X_NOPRINTF 2 +#define X_DEF + static struct nlist nl[] = + { {"tickadj"}, + {"dosynctodr"}, + {"noprintf"}, + {""}, + }; + +#if defined(RS6000) + int i; +#endif +#endif + +#if !defined(X_DEF) +#define X_TICKADJ 0 +#define X_TICK 1 +#define X_DOSYNC 2 +#define X_NOPRINTF 3 + static struct nlist nl[] = + { {"_tickadj"}, + {"_tick"}, + {"_dosynctodr"}, + {"_noprintf"}, + {""}, + }; +#endif + static char *kernels[] = { + "/vmunix", + "/unix", + "/mach", + "/kernel/unix", + "/386bsd", + "/netbsd", + NULL + }; + struct stat stbuf; + +#if defined(SYS_AUX3) || defined(SYS_AUX2) + strcpy (nl[X_TICKADJ].n_name, "tickadj"); + strcpy (nl[X_V].n_name, "v"); + strcpy (nl[X_TICK].n_name, "tick"); + nl[3].n_name[0] = '\0'; +#endif + + for (kname = kernels; *kname != NULL; kname++) { + if (stat(*kname, &stbuf) == -1) + continue; + if (nlist(*kname, nl) >= 0) + break; + } + if (*kname == NULL) { + (void) fprintf(stderr, + "%s: nlist fails: can't find/read /vmunix or /unix\n", + progname); + exit(1); + } + + if (dokmem) + file = kmem; + else + file = kernel; + + fd = openfile(file, O_RDONLY); +#if defined(RS6000) + /* + * Go one more round of indirection. + */ + for (i=0; i<(sizeof(nl)/sizeof(struct nlist)); i++) { + if (nl[i].n_value) { + readvar(fd, nl[i].n_value, &nl[i].n_value); + } + } +#endif + *tickadj_off = 0; + *tick_off = 0; + *dosync_off = 0; + *noprintf_off = 0; + +#if defined(X_TICKADJ) + *tickadj_off = nl[X_TICKADJ].n_value; +#endif + +#if defined(X_TICK) + *tick_off = nl[X_TICK].n_value; +#endif + +#if defined(X_DOSYNC) + *dosync_off = nl[X_DOSYNC].n_value; +#endif + +#if defined(X_NOPRINTF) + *noprintf_off = nl[X_NOPRINTF].n_value; +#endif + return *kname; +} + +#undef X_TICKADJ +#undef X_TICK +#undef X_DOSYNC +#undef X_NOPRINTF + + +/* + * openfile - open the file, check for errors + */ +static int +openfile(name, mode) + char *name; + int mode; +{ + int fd; + + fd = open(name, mode); + if (fd < 0) { + (void) fprintf(stderr, "%s: open %s: ", progname, name); + perror(""); + exit(1); + } + return fd; +} + + +/* + * writevar - write a variable into the file + */ +static void +writevar(fd, off, var) + int fd; + unsigned long off; + int var; +{ + + if (lseek(fd, off, L_SET) == -1) { + (void) fprintf(stderr, "%s: lseek fails: ", progname); + perror(""); + exit(1); + } + if (write(fd, (char *)&var, sizeof(int)) != sizeof(int)) { + (void) fprintf(stderr, "%s: write fails: ", progname); + perror(""); + exit(1); + } +} + + +/* + * readvar - read a variable from the file + */ +static void +readvar(fd, off, var) + int fd; + unsigned long off; + int *var; +{ + int i; + + if (lseek(fd, off, L_SET) == -1) { + (void) fprintf(stderr, "%s: lseek fails: ", progname); + perror(""); + exit(1); + } + i = read(fd, (char *)var, sizeof(int)); + if (i < 0) { + (void) fprintf(stderr, "%s: read fails: ", progname); + perror(""); + exit(1); + } + if (i != sizeof(int)) { + (void) fprintf(stderr, "%s: read expected %d, got %d\n", + progname, sizeof(int), i); + exit(1); + } +} diff --git a/contrib/xntpd/util/timetrim.c b/contrib/xntpd/util/timetrim.c new file mode 100644 index 0000000000..052a587a7d --- /dev/null +++ b/contrib/xntpd/util/timetrim.c @@ -0,0 +1,85 @@ +/* + * timetrim.c,v 3.1 1993/07/06 01:11:06 jbj Exp + * + * "timetrim" allows setting and adjustment of the system clock frequency + * trim parameter on Silicon Graphics machines. The trim value native + * units are nanoseconds per second (10**-9), so a trim value of 1 makes + * the system clock step ahead 1 nanosecond more per second than a value + * of zero. Xntpd currently uses units of 2**-20 secs for its frequency + * offset (drift) values; to convert to a timetrim value, multiply by + * 1E9 / 2**20 (about 954). + * + * "timetrim" with no arguments just prints out the current kernel value. + * With a numeric argument, the kernel value is set to the supplied value. + * The "-i" flag causes the supplied value to be added to the kernel value. + * The "-n" option causes all input and output to be in xntpd units rather + * than timetrim native units. + * + * Note that there is a limit of +-3000000 (0.3%) on the timetrim value + * which is (silently?) enforced by the kernel. + * + */ + +#include +#include +#include + +#define abs(X) (((X) < 0) ? -(X) : (X)) +#define USAGE "usage: timetrim [-n] [[-i] value]\n" +#define SGITONTP(X) ((double)(X) * 1048576.0/1.0e9) +#define NTPTOSGI(X) ((LONG)((X) * 1.0e9/1048576.0)) + +main(argc, argv) +int argc; +char **argv; +{ + char *rem; + int c, incremental = 0, ntpunits = 0; + LONG timetrim; + double value, strtod(); + + while (--argc && **++argv == '-' && isalpha(argv[0][1])) { + switch (argv[0][1]) { + case 'i': + incremental++; + break; + case 'n': + ntpunits++; + break; + default: + fprintf(stderr, USAGE); + exit(1); + } + } + + if (syssgi(SGI_GETTIMETRIM, &timetrim) < 0) { + perror("syssgi"); + exit(2); + } + + if (argc == 0) { + if (ntpunits) + fprintf(stdout, "%0.5lf\n", SGITONTP(timetrim)); + else + fprintf(stdout, "%ld\n", timetrim); + } else if (argc != 1) { + fprintf(stderr, USAGE); + exit(1); + } else { + value = strtod(argv[0], &rem); + if (*rem != '\0') { + fprintf(stderr, USAGE); + exit(1); + } + if (ntpunits) + value = NTPTOSGI(value); + if (incremental) + timetrim += value; + else + timetrim = value; + if (syssgi(SGI_SETTIMETRIM, timetrim) < 0) { + perror("syssgi"); + exit(2); + } + } +} diff --git a/contrib/xntpd/xntpd/Makefile.tmpl b/contrib/xntpd/xntpd/Makefile.tmpl new file mode 100644 index 0000000000..a51dbd7bec --- /dev/null +++ b/contrib/xntpd/xntpd/Makefile.tmpl @@ -0,0 +1,138 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:11:10 jbj Exp +# +PROGRAM= xntpd +# +# xntpd - NTP daemon +# +COMPILER= cc +COPTS= -O +BINDIR= /usr/local +INSTALL= install +DEFS= +DEFS_OPT= +DEFS_LOCAL= +CLOCKDEFS= +DAEMONLIBS= +RESLIB= +ADJLIB= +COMPAT= +# +INCL= -I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +LIB= ../lib/libntp.a ../parse/libparse.a +LINTLIB= ../lib/llib-llibntp.ln +MAKE= make +TOP=../ +# +SOURCE= ntp_config.c ntp_control.c ntp_io.c ntp_leap.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_unixclock.c ntp_util.c ntpd.c refclock_chu.c \ + refclock_conf.c refclock_local.c refclock_pst.c \ + refclock_wwvb.c refclock_goes.c refclock_mx4200.c \ + refclock_parse.c refclock_as2201.c refclock_omega.c \ + refclock_tpro.c refclock_leitch.c refclock_irig.c \ + refclock_msfees.c ntp_intres.c ntp_filegen.c + +OBJS= ntp_config.o ntp_control.o ntp_io.o ntp_leap.o \ + ntp_loopfilter.o ntp_monitor.o ntp_peer.o ntp_proto.o \ + ntp_refclock.o ntp_request.o ntp_restrict.o ntp_timer.o \ + ntp_unixclock.o ntp_util.o ntpd.o refclock_chu.o \ + refclock_conf.o refclock_local.o refclock_pst.o \ + refclock_wwvb.o refclock_goes.o refclock_mx4200.o \ + refclock_parse.o refclock_as2201.o refclock_omega.o \ + refclock_tpro.o refclock_leitch.o refclock_irig.o \ + refclock_msfees.o ntp_intres.o ntp_filegen.o + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) $(LIB) version.o + -rm -f $(PROGRAM) + $(CC) $(COPTS) -o $@ $(OBJS) version.o $(LIB) $(DAEMONLIBS) \ + $(RESLIB) $(ADJLIB) $(COMPAT) + +install: $(BINDIR)/$(PROGRAM) + +$(BINDIR)/$(PROGRAM): $(PROGRAM) + $(INSTALL) -c -m 0755 $(PROGRAM) $(BINDIR) + +tags: + ctags *.c *.h + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(PROGRAM) *.o *.out tags oxntpd make.log Makefile.bak lint.errs + -@rm -f .depend *~ .version + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +lint: $(LINTLIB) + lint -x -u $(DEFS) $(INCL) $(LINTLIB) $(SOURCE) >lint.errs + +../lib/llib-llibntp.ln: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" lintlib + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" + +../parse/libparse.a: + cd ../parse && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" + +# +# we want to build the current version string here +# +version.o: ../VERSION + ../scripts/mkversion $(PROGRAM) + $(CC) $(COPTS) $(INCL) -c version.c + +../VERSION: + -@rm -f .version +# +# These guys require knowledge of our clock configuration +# +refclock_chu.o: refclock_chu.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_conf.o: refclock_conf.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_local.o: refclock_local.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_pst.o: refclock_pst.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_goes.o: refclock_goes.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_wwvb.o: refclock_wwvb.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_parse.o: refclock_parse.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_mx4200.o: refclock_mx4200.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_as2201.o: refclock_as2201.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_omega.o: refclock_omega.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_tpro.o: refclock_tpro.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_leitch.o: refclock_leitch.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_irig.o: refclock_irig.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c + +refclock_msfees.o: refclock_msfees.c + $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c diff --git a/contrib/xntpd/xntpd/README b/contrib/xntpd/xntpd/README new file mode 100644 index 0000000000..45512762d1 --- /dev/null +++ b/contrib/xntpd/xntpd/README @@ -0,0 +1,6 @@ +README file for directory ./xntpd of the NTP Version 3 distribution + +This directory contains the sources for the xntpd daemon for Unix. See +the README and RELNOTES files in the parent directory for directions on +how to make and install this program. The current version number of this +program is in the version.c file. diff --git a/contrib/xntpd/xntpd/ntp_config.c b/contrib/xntpd/xntpd/ntp_config.c new file mode 100644 index 0000000000..1a0e9ef4bf --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_config.c @@ -0,0 +1,1849 @@ +/* ntp_config.c,v 3.1 1993/07/06 01:11:12 jbj Exp + * ntp_config.c - read and apply configuration information + */ +#define RESOLVE_INTERNAL /* gdt */ + +#include +#include +#include +#include +#include + +#ifdef RESOLVE_INTERNAL +#include +#endif + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_refclock.h" +#include "ntp_filegen.h" +#include "ntp_stdlib.h" + +/* + * 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. + */ + +/* + * Configuration file name + */ +#ifndef CONFIG_FILE +#if defined(__bsdi__) +#define CONFIG_FILE "/usr/local/etc/xntp.conf" +#else +#define CONFIG_FILE "/etc/ntp.conf" +#endif +#endif /* CONFIG_FILE */ + +/* + * We understand the following configuration entries and defaults. + * + * peer 128.100.1.1 [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * server 128.100.2.2 [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * precision -7 + * broadcast 128.100.224.255 [ version 3 ] [ key 0 ] + * broadcastclient yes|no + * broadcastdelay 0.0102 + * authenticate yes|no + * monitor yes|no + * authdelay 0.00842 + * pps [ delay 0.000247 ] [ baud 38400 ] + * restrict 128.100.100.0 [ mask 255.255.255.0 ] ignore|noserve|notrust|noquery + * driftfile file_name + * keys file_name + * statsdir /var/NTP/ + * filegen peerstats [ file peerstats ] [ type day ] [ link ] + * resolver /path/progname + * + * And then some. See the manual page. + */ + +/* + * Types of entries we understand. + */ +#define CONFIG_UNKNOWN 0 + +#define CONFIG_PEER 1 +#define CONFIG_SERVER 2 +#define CONFIG_PRECISION 3 +#define CONFIG_DRIFTFILE 4 +#define CONFIG_BROADCAST 5 +#define CONFIG_BROADCASTCLIENT 6 +#define CONFIG_AUTHENTICATE 7 +#define CONFIG_KEYS 8 +#define CONFIG_MONITOR 9 +#define CONFIG_AUTHDELAY 10 +#define CONFIG_RESTRICT 11 +#define CONFIG_BDELAY 12 +#define CONFIG_TRUSTEDKEY 13 +#define CONFIG_REQUESTKEY 14 +#define CONFIG_CONTROLKEY 15 +#define CONFIG_TRAP 16 +#define CONFIG_FUDGE 17 +#define CONFIG_MAXSKEW 18 +#define CONFIG_RESOLVER 19 +#define CONFIG_SELECT 20 +#define CONFIG_STATSDIR 21 +#define CONFIG_FILEGEN 22 +#define CONFIG_STATISTICS 23 +#define CONFIG_PPS 24 +#define CONFIG_PIDFILE 25 +#define CONFIG_LOGFILE 26 + +#define CONF_MOD_VERSION 1 +#define CONF_MOD_KEY 2 +#define CONF_MOD_MINPOLL 3 +#define CONF_MOD_MAXPOLL 4 +#define CONF_MOD_PREFER 5 + +#define CONF_PPS_DELAY 1 +#define CONF_PPS_BAUD 2 + +#define CONF_RES_MASK 1 +#define CONF_RES_IGNORE 2 +#define CONF_RES_NOSERVE 3 +#define CONF_RES_NOTRUST 4 +#define CONF_RES_NOQUERY 5 +#define CONF_RES_NOMODIFY 6 +#define CONF_RES_NOPEER 7 +#define CONF_RES_NOTRAP 8 +#define CONF_RES_LPTRAP 9 +#define CONF_RES_NTPPORT 10 + +#define CONF_TRAP_PORT 1 +#define CONF_TRAP_INTERFACE 2 + +#define CONF_FDG_TIME1 1 +#define CONF_FDG_TIME2 2 +#define CONF_FDG_VALUE1 3 +#define CONF_FDG_VALUE2 4 +#define CONF_FDG_FLAG1 5 +#define CONF_FDG_FLAG2 6 +#define CONF_FDG_FLAG3 7 +#define CONF_FDG_FLAG4 8 + +#define CONF_FGEN_FILE 1 +#define CONF_FGEN_TYPE 2 +#define CONF_FGEN_FLAG_LINK 3 +#define CONF_FGEN_FLAG_NOLINK 4 +#define CONF_FGEN_FLAG_ENABLE 5 +#define CONF_FGEN_FLAG_DISABLE 6 + +#define CONF_BAUD_300 1 +#define CONF_BAUD_600 2 +#define CONF_BAUD_1200 3 +#define CONF_BAUD_2400 4 +#define CONF_BAUD_4800 5 +#define CONF_BAUD_9600 6 +#define CONF_BAUD_19200 7 +#define CONF_BAUD_38400 8 + +/* + * Translation table - keywords to function index + */ +struct keyword { + char *text; + int keytype; +}; + +static struct keyword keywords[] = { + { "peer", CONFIG_PEER }, + { "server", CONFIG_SERVER }, + { "precision", CONFIG_PRECISION }, + { "driftfile", CONFIG_DRIFTFILE }, + { "broadcast", CONFIG_BROADCAST }, + { "broadcastclient", CONFIG_BROADCASTCLIENT }, + { "authenticate", CONFIG_AUTHENTICATE }, + { "keys", CONFIG_KEYS }, + { "monitor", CONFIG_MONITOR }, + { "authdelay", CONFIG_AUTHDELAY }, + { "pps", CONFIG_PPS }, + { "restrict", CONFIG_RESTRICT }, + { "broadcastdelay", CONFIG_BDELAY }, + { "trustedkey", CONFIG_TRUSTEDKEY }, + { "requestkey", CONFIG_REQUESTKEY }, + { "controlkey", CONFIG_CONTROLKEY }, + { "trap", CONFIG_TRAP }, + { "fudge", CONFIG_FUDGE }, + { "maxskew", CONFIG_MAXSKEW }, + { "resolver", CONFIG_RESOLVER }, + { "select", CONFIG_SELECT }, + { "statsdir", CONFIG_STATSDIR }, + { "filegen", CONFIG_FILEGEN }, + { "statistics", CONFIG_STATISTICS }, + { "pidfile", CONFIG_PIDFILE }, + { "logfile", CONFIG_LOGFILE }, + { "", CONFIG_UNKNOWN } +}; + +/* + * Modifier keywords + */ +static struct keyword mod_keywords[] = { + { "version", CONF_MOD_VERSION }, + { "key", CONF_MOD_KEY }, + { "minpoll", CONF_MOD_MINPOLL }, + { "maxpoll", CONF_MOD_MAXPOLL }, + { "prefer", CONF_MOD_PREFER }, + { "", CONFIG_UNKNOWN } +}; + +/* + * PPS modifier keywords + */ +static struct keyword pps_keywords[] = { + { "delay", CONF_PPS_DELAY }, + { "baud", CONF_PPS_BAUD }, + { "", CONFIG_UNKNOWN } +}; + +/* + * Special restrict keywords + */ +static struct keyword res_keywords[] = { + { "mask", CONF_RES_MASK }, + { "ignore", CONF_RES_IGNORE }, + { "noserve", CONF_RES_NOSERVE }, + { "notrust", CONF_RES_NOTRUST }, + { "noquery", CONF_RES_NOQUERY }, + { "nomodify", CONF_RES_NOMODIFY }, + { "nopeer", CONF_RES_NOPEER }, + { "notrap", CONF_RES_NOTRAP }, + { "lowpriotrap", CONF_RES_LPTRAP }, + { "ntpport", CONF_RES_NTPPORT }, + { "", CONFIG_UNKNOWN } +}; + +/* + * Baud rate keywords + */ +static struct keyword baud_keywords[] = { + { "300", CONF_BAUD_300 }, + { "600", CONF_BAUD_600 }, + { "1200", CONF_BAUD_1200 }, + { "2400", CONF_BAUD_2400 }, + { "4800", CONF_BAUD_4800 }, + { "9600", CONF_BAUD_9600 }, + { "19200", CONF_BAUD_19200 }, + { "38400", CONF_BAUD_38400 }, + { "", CONFIG_UNKNOWN } +}; + +/* + * Keywords for the trap command + */ +static struct keyword trap_keywords[] = { + { "port", CONF_TRAP_PORT }, + { "interface", CONF_TRAP_INTERFACE }, + { "", CONFIG_UNKNOWN } +}; + + +/* + * Keywords for the fudge command + */ +static struct keyword fudge_keywords[] = { + { "time1", CONF_FDG_TIME1 }, + { "time2", CONF_FDG_TIME2 }, + { "value1", CONF_FDG_VALUE1 }, + { "value2", CONF_FDG_VALUE2 }, + { "flag1", CONF_FDG_FLAG1 }, + { "flag2", CONF_FDG_FLAG2 }, + { "flag3", CONF_FDG_FLAG3 }, + { "flag4", CONF_FDG_FLAG4 }, + { "", CONFIG_UNKNOWN } +}; + + +/* + * Keywords for the filegen command + */ +static struct keyword filegen_keywords[] = { + { "file", CONF_FGEN_FILE }, + { "type", CONF_FGEN_TYPE }, + { "link", CONF_FGEN_FLAG_LINK }, + { "nolink", CONF_FGEN_FLAG_NOLINK }, + { "enable", CONF_FGEN_FLAG_ENABLE }, + { "disable", CONF_FGEN_FLAG_DISABLE }, + { "", CONFIG_UNKNOWN } +}; + +static struct keyword fgen_types[] = { + { "none", FILEGEN_NONE }, + { "pid", FILEGEN_PID }, + { "day", FILEGEN_DAY }, + { "week", FILEGEN_WEEK }, + { "month", FILEGEN_MONTH }, + { "year", FILEGEN_YEAR }, + { "age", FILEGEN_AGE }, + { "", CONFIG_UNKNOWN} +}; + + +/* + * Limits on things + */ +#define MAXTOKENS 20 /* 20 tokens on line */ +#define MAXLINE 1024 /* maximum length of line */ +#define MAXFILENAME 128 /* maximum length of a file name (alloca()?) */ + + +/* + * 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) + +/* + * File descriptor used by the resolver save routines, and temporary file + * name. + */ +static FILE *res_fp; +static char res_file[20]; /* enough for /tmp/xntpXXXXXX\0 */ +#define RES_TEMPFILE "/tmp/xntpXXXXXX" + +/* + * Definitions of things either imported from or exported to outside + */ +#ifdef DEBUG +extern int debug; +#endif +extern char *FindConfig(); + char *progname; +static char *xntp_options = "abc:de:f:k:l:p:r:s:t:"; + +static int gettokens P((FILE *, char *, char **, int *)); +static int matchkey P((char *, struct keyword *)); +static int getnetnum P((char *, struct sockaddr_in *, int)); +static void save_resolve P((char *, int, int, int, int, int, U_LONG)); +static void do_resolve P((char *, U_LONG, char *)); +#ifdef RESOLVE_INTERNAL +static void do_resolve_internal P((void)); +#endif /* RESOLVE_INTERNAL */ +static void abort_resolve P((void)); +static RETSIGTYPE catchchild P((int)); + +/* + * getstartup - search through the options looking for a debugging flag + */ +void +getstartup(argc, argv) + int argc; + char *argv[]; +{ +#ifdef DEBUG + int errflg; + int c; + extern int optind; + + debug = 0; /* no debugging by default */ + + /* + * 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 getopt_l() is explicitly reusable, by the + * way. Your own mileage may vary. + */ + errflg = 0; + progname = argv[0]; + + /* + * Decode argument list + */ + while ((c = getopt_l(argc, argv, xntp_options)) != EOF) + switch (c) { + case 'd': + ++debug; + break; + case '?': + ++errflg; + break; + default: + break; + } + + if (errflg || optind != argc) { + (void) fprintf(stderr, + "usage: %s [ -bd ] [ -c config_file ]\n", progname); + exit(2); + } + optind = 0; /* reset optind to restart getopt_l */ + + if (debug) { +#ifdef NTP_POSIX_SOURCE + static char buf[BUFSIZ]; + setvbuf(stdout, buf, _IOLBF, BUFSIZ); +#else + setlinebuf(stdout); +#endif + } + +#endif /* DEBUG */ +} + +/* + * getconfig - get command line options and read the configuration file + */ +void +getconfig(argc, argv) + int argc; + char *argv[]; +{ + register int i; + int c; + int errflg; + int peerversion; + int minpoll; + int maxpoll; + U_LONG peerkey; + int peerflags; + int hmode; + struct sockaddr_in peeraddr; + struct sockaddr_in maskaddr; + FILE *fp; + char line[MAXLINE]; + char *(tokens[MAXTOKENS]); + int ntokens; + int tok; + struct interface *localaddr; + char *config_file; + struct refclockstat clock; + int have_resolver; +#ifdef RESOLVE_INTERNAL + int resolve_internal; +#endif + char resolver_name[MAXFILENAME]; + int have_keyfile; + char keyfile[MAXFILENAME]; + extern int optind; + extern char *optarg; + extern U_LONG info_auth_keyid; + FILEGEN *filegen; + + /* + * Initialize, initialize + */ + errflg = 0; +#ifdef DEBUG + debug = 0; +#endif /* DEBUG */ + config_file = CONFIG_FILE; + progname = argv[0]; + res_fp = NULL; + have_resolver = have_keyfile = 0; + +#ifdef RESOLVE_INTERNAL + resolve_internal = 1; +#endif + + /* + * Decode argument list + */ + while ((c = getopt_l(argc, argv, xntp_options)) != EOF) { + switch (c) { + case 'a': + proto_config(PROTO_AUTHENTICATE, (LONG)1); + break; + case 'b': + proto_config(PROTO_BROADCLIENT, (LONG)1); + break; + case 'c': + config_file = optarg; + break; + case 'd': +#ifdef DEBUG + debug++; +#else + errflg++; +#endif /* DEBUG */ + break; + + case 'e': + do { + l_fp tmp; + + if (!atolfp(optarg, &tmp)) { + syslog(LOG_ERR, + "command line encryption delay value %s undecodable", + optarg); + errflg++; + } else if (tmp.l_ui != 0) { + syslog(LOG_ERR, + "command line encryption delay value %s is unlikely", + optarg); + errflg++; + } else { + proto_config(PROTO_AUTHDELAY, tmp.l_f); + } + } while (0); + break; + + case 'f': + stats_config(STATS_FREQ_FILE, optarg); + break; + + case 'k': + getauthkeys(optarg); + if ((int)strlen(optarg) >= MAXFILENAME) { + syslog(LOG_ERR, + "key file name too LONG (>%d, sigh), no name resolution possible", + MAXFILENAME); + } else { + have_keyfile = 1; + (void)strcpy(keyfile, optarg); + } + break; + + case 'p': + stats_config(STATS_PID_FILE, optarg); + break; + + case 'r': + do { + l_fp tmp; + + if (!atolfp(optarg, &tmp)) { + syslog(LOG_ERR, + "command line broadcast delay value %s undecodable", + optarg); + } else if (tmp.l_ui != 0) { + syslog(LOG_ERR, + "command line broadcast delay value %s is unlikely", + optarg); + } else { + proto_config(PROTO_BROADDELAY, tmp.l_f); + } + } while (0); + break; + + case 's': + stats_config(STATS_STATSDIR, optarg); + break; + + case 't': + do { + int tkey; + + tkey = atoi(optarg); + if (tkey <= 0 || tkey > NTP_MAXKEY) { + syslog(LOG_ERR, + "command line trusted key %s is unlikely", + optarg); + } else { + authtrust(tkey, (LONG)1); + } + } while (0); + break; + + + default: + errflg++; + break; + } + } + + if (errflg || optind != argc) { + (void) fprintf(stderr, + "usage: %s [ -bd ] [ -c config_file ]\n", progname); + exit(2); + } + + if ((fp = fopen(FindConfig(config_file), "r")) == NULL) { + /* + * Broadcast clients can sometimes run without + * a configuration file. + */ + return; + } + + while ((tok = gettokens(fp, line, tokens, &ntokens)) + != CONFIG_UNKNOWN) { + switch(tok) { + case CONFIG_PEER: + case CONFIG_SERVER: + case CONFIG_BROADCAST: + if (tok == CONFIG_PEER) + hmode = MODE_ACTIVE; + else if (tok == CONFIG_SERVER) + hmode = MODE_CLIENT; + else + hmode = MODE_BROADCAST; + + if (ntokens < 2) { + syslog(LOG_ERR, + "No address for %s, line ignored", + tokens[0]); + break; + } + + if (!getnetnum(tokens[1], &peeraddr, 0)) { + errflg = -1; + } else { + errflg = 0; + + if ( +#ifdef REFCLOCK + !ISREFCLOCKADR(&peeraddr) && +#endif + ISBADADR(&peeraddr)) { + syslog(LOG_ERR, + "attempt to configure invalid address %s", + ntoa(&peeraddr)); + break; + } + } + + peerversion = NTP_VERSION; + minpoll = NTP_MINDPOLL; + maxpoll = NTP_MAXPOLL; + peerkey = 0; + peerflags = 0; + for (i = 2; i < ntokens; i++) + switch (matchkey(tokens[i], mod_keywords)) { + case CONF_MOD_VERSION: + if (i >= ntokens-1) { + syslog(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) { + syslog(LOG_ERR, + "inappropriate version number %s, line ignored", + tokens[i]); + errflg = 1; + } + break; + + case CONF_MOD_KEY: + /* + * XXX + * This is bad because atoi + * returns 0 on errors. Do + * something later. + */ + if (i >= ntokens-1) { + syslog(LOG_ERR, + "key: argument required"); + errflg = 1; + break; + } + peerkey = (U_LONG)atoi(tokens[++i]); + peerflags |= FLAG_AUTHENABLE; + break; + + case CONF_MOD_MINPOLL: + if (i >= ntokens-1) { + syslog(LOG_ERR, + "minpoll: argument required"); + errflg = 1; + break; + } + minpoll = atoi(tokens[++i]); + if (minpoll < NTP_MINPOLL) + minpoll = NTP_MINPOLL; + break; + + case CONF_MOD_MAXPOLL: + if (i >= ntokens-1) { + syslog(LOG_ERR, + "maxpoll: argument required" +); + errflg = 1; + break; + } + maxpoll = atoi(tokens[++i]); + if (maxpoll > NTP_MAXPOLL) + maxpoll = NTP_MAXPOLL; + break; + + case CONF_MOD_PREFER: + peerflags |= FLAG_PREFER; + break; + + case CONFIG_UNKNOWN: + errflg = 1; + break; + } + if (minpoll > maxpoll) { + syslog(LOG_ERR, "config error: minpoll > maxpoll"); + errflg = 1; + } + if (errflg == 0) { + if (peer_config(&peeraddr, + (struct interface *)0, hmode, peerversion, + minpoll, maxpoll, peerkey, peerflags) == 0) { + syslog(LOG_ERR, + "configuration of %s failed", + ntoa(&peeraddr)); + } + } else if (errflg == -1) { + save_resolve(tokens[1], hmode, peerversion, + minpoll, maxpoll, peerflags, peerkey); + } + break; + + case CONFIG_PRECISION: + if (ntokens >= 2) { + i = atoi(tokens[1]); + if (i >= 0 || i < -25) + syslog(LOG_ERR, + "unlikely precision %s, line ignored", + tokens[1]); + else + proto_config(PROTO_PRECISION, (LONG)i); + } + 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_LOGFILE: { +#ifdef SYSLOG_FILE + extern int syslogit; + + syslogit = 0; + if (ntokens >= 2) { + FILE *new_file; + new_file = fopen(tokens[1], "a"); + if (new_file != NULL) { + if (syslog_file != NULL) + (void)fclose(syslog_file); + syslog_file = new_file; + } + else + syslog(LOG_ERR, + "Cannot open log file %s", + tokens[1]); + } + else + syslog(LOG_ERR, "logfile needs one argument"); + +#else + syslog(LOG_ERR, "logging to logfile not compiled into xntpd - logfile \"%s\" ignored", (ntokens == 2) ? tokens[1] : ""); +#endif + } break; + + case CONFIG_BROADCASTCLIENT: + errflg = 0; + if (ntokens >= 2) { + if (STREQ(tokens[1], "yes")) + proto_config(PROTO_BROADCLIENT, (LONG)1); + else if (STREQ(tokens[1], "no")) + proto_config(PROTO_BROADCLIENT, (LONG)0); + else + errflg++; + } else { + errflg++; + } + + if (errflg) + syslog(LOG_ERR, + "should be `broadcastclient yes|no'"); + break; + + case CONFIG_AUTHENTICATE: + errflg = 0; + if (ntokens >= 2) { + if (STREQ(tokens[1], "yes")) + proto_config(PROTO_AUTHENTICATE, (LONG)1); + else if (STREQ(tokens[1], "no")) + proto_config(PROTO_AUTHENTICATE, (LONG)0); + else + errflg++; + } else { + errflg++; + } + + if (errflg) + syslog(LOG_ERR, + "should be `authenticate yes|no'"); + break; + + case CONFIG_KEYS: + if (ntokens >= 2) { + getauthkeys(tokens[1]); + if ((int)strlen(tokens[1]) >= MAXFILENAME) { + syslog(LOG_ERR, + "key file name too LONG (>%d, sigh), no name resolution possible", + MAXFILENAME); + } else { + have_keyfile = 1; + (void)strcpy(keyfile, tokens[1]); + } + } + break; + + case CONFIG_MONITOR: + errflg = 0; + if (ntokens >= 2) { + if (STREQ(tokens[1], "yes")) + mon_start(); + else if (STREQ(tokens[1], "no")) + mon_stop(); + else + errflg++; + } else { + errflg++; + } + + if (errflg) + syslog(LOG_ERR, + "should be `monitor yes|no'"); + break; + + case CONFIG_AUTHDELAY: + if (ntokens >= 2) { + l_fp tmp; + + if (!atolfp(tokens[1], &tmp)) { + syslog(LOG_ERR, + "authdelay value %s undecodable", + tokens[1]); + } else if (tmp.l_ui != 0) { + syslog(LOG_ERR, + "authdelay value %s is unlikely", + tokens[1]); + } else { + proto_config(PROTO_AUTHDELAY, tmp.l_f); + } + } + break; + + case CONFIG_PPS: + for (i = 1 ; i < ntokens ; i++) { + switch(matchkey(tokens[i],pps_keywords)) { + case CONF_PPS_DELAY: + if (i >= ntokens-1) { + syslog(LOG_ERR, + "pps delay requires an argument"); + errflg = 1; + break; + } + { + l_fp tmp; + + if (!atolfp(tokens[++i],&tmp)) { + syslog(LOG_ERR, + "pps delay value %s undecodable", + tokens[i]); + } else { + loop_config(LOOP_PPSDELAY, &tmp, 0); + } + } + break; + case CONF_PPS_BAUD: + if (i >= ntokens-1) { + syslog(LOG_ERR, + "pps baud requires an argument"); + errflg = 1; + break; + } + { + int tmp; + + if (matchkey(tokens[++i],baud_keywords)) { + tmp = atoi(tokens[i]); + if (tmp < 19200) { + syslog(LOG_WARNING, + "pps baud %d unlikely\n", tmp); + } + loop_config(LOOP_PPSBAUD, NULL, tmp); + } + } + break; + case CONFIG_UNKNOWN: + errflg = 1; + break; + } + } + break; + + case CONFIG_RESTRICT: + if (ntokens < 2) { + syslog(LOG_ERR, "restrict requires an address"); + break; + } + if (STREQ(tokens[1], "default")) + peeraddr.sin_addr.s_addr = INADDR_ANY; + else if (!getnetnum(tokens[1], &peeraddr, 1)) + break; + + /* + * Use peerversion as flags, peerkey as mflags. Ick. + */ + peerversion = 0; + peerkey = 0; + errflg = 0; + maskaddr.sin_addr.s_addr = ~0; + for (i = 2; i < ntokens; i++) { + switch (matchkey(tokens[i], res_keywords)) { + case CONF_RES_MASK: + if (i >= ntokens-1) { + syslog(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 CONFIG_UNKNOWN: + errflg++; + break; + } + } + if (SRCADR(&peeraddr) == INADDR_ANY) + maskaddr.sin_addr.s_addr = 0; + if (!errflg) + restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr, + (int)peerkey, peerversion); + break; + + case CONFIG_BDELAY: + if (ntokens >= 2) { + l_fp tmp; + + if (!atolfp(tokens[1], &tmp)) { + syslog(LOG_ERR, + "broadcastdelay value %s undecodable", + tokens[1]); + } else if (tmp.l_ui != 0) { + syslog(LOG_ERR, + "broadcastdelay value %s is unlikely", + tokens[1]); + } else { + proto_config(PROTO_BROADDELAY, tmp.l_f); + } + } + break; + + case CONFIG_TRUSTEDKEY: + for (i = 1; i < ntokens; i++) { + U_LONG tkey; + + tkey = (U_LONG) atoi(tokens[i]); + if (tkey == 0) { + syslog(LOG_ERR, + "trusted key %s unlikely", + tokens[i]); + } else { + authtrust(tkey, 1); + } + } + break; + + case CONFIG_REQUESTKEY: + if (ntokens >= 2) { + U_LONG rkey; + + if (!atouint(tokens[1], &rkey)) { + syslog(LOG_ERR, + "%s is undecodeable as request key", + tokens[1]); + } else if (rkey == 0) { + syslog(LOG_ERR, + "%s makes a poor request keyid", + tokens[1]); + } else { +#ifdef DEBUG + if (debug > 3) + printf( + "set info_auth_key to %lu\n", rkey); +#endif + info_auth_keyid = rkey; + } + } + break; + + case CONFIG_CONTROLKEY: + if (ntokens >= 2) { + U_LONG ckey; + extern U_LONG ctl_auth_keyid; + + ckey = (U_LONG)atoi(tokens[1]); + if (ckey == 0) { + syslog(LOG_ERR, + "%s makes a poor control keyid", + tokens[1]); + } else { + ctl_auth_keyid = ckey; + } + } + break; + + case CONFIG_TRAP: + if (ntokens < 2) { + syslog(LOG_ERR, + "no address for trap command, line ignored"); + break; + } + if (!getnetnum(tokens[1], &peeraddr, 1)) + break; + + /* + * Use peerversion for port number. Barf. + */ + errflg = 0; + peerversion = 0; + localaddr = 0; + for (i = 2; i < ntokens-1; i++) + switch (matchkey(tokens[i], trap_keywords)) { + case CONF_TRAP_PORT: + if (i >= ntokens-1) { + syslog(LOG_ERR, + "trap port requires an argument"); + errflg = 1; + break; + } + peerversion = atoi(tokens[++i]); + if (peerversion <= 0 + || peerversion > 32767) { + syslog(LOG_ERR, + "invalid port number %s, trap ignored", + tokens[i]); + errflg = 1; + } + break; + + case CONF_TRAP_INTERFACE: + if (i >= ntokens-1) { + syslog(LOG_ERR, + "trap interface requires an argument"); + errflg = 1; + break; + } + + if (!getnetnum(tokens[++i], + &maskaddr, 1)) { + errflg = 1; + break; + } + + localaddr = findinterface(&maskaddr); + if (localaddr == NULL) { + syslog(LOG_ERR, + "can't find interface with address %s", + ntoa(&maskaddr)); + errflg = 1; + } + break; + + case CONFIG_UNKNOWN: + errflg++; + break; + } + + if (!errflg) { + extern struct interface *any_interface; + + if (peerversion != 0) + peeraddr.sin_port = htons(peerversion); + else + peeraddr.sin_port = htons(TRAPPORT); + if (localaddr == NULL) + localaddr = any_interface; + if (!ctlsettrap(&peeraddr, localaddr, 0, + NTP_VERSION)) + syslog(LOG_ERR, + "can't set trap for %s, no resources", + ntoa(&peeraddr)); + } + break; + + case CONFIG_FUDGE: + if (ntokens < 2) { + syslog(LOG_ERR, + "no address for fudge command, line ignored"); + break; + } + if (!getnetnum(tokens[1], &peeraddr, 1)) + break; + + if (!ISREFCLOCKADR(&peeraddr)) { + syslog(LOG_ERR, + "%s is inappropriate address for the fudge command, line ignored", + ntoa(&peeraddr)); + break; + } + + bzero((char *)&clock, sizeof clock); + errflg = 0; + for (i = 2; i < ntokens-1; i++) { + switch (c = matchkey(tokens[i], + fudge_keywords)) { + case CONF_FDG_TIME1: + if (!atolfp(tokens[++i], + &clock.fudgetime1)) { + syslog(LOG_ERR, + "fudge %s time1 value in error", + ntoa(&peeraddr)); + errflg = i; + break; + } + clock.haveflags |= CLK_HAVETIME1; + break; + + case CONF_FDG_TIME2: + if (!atolfp(tokens[++i], + &clock.fudgetime2)) { + syslog(LOG_ERR, + "fudge %s time2 value in error", + ntoa(&peeraddr)); + errflg = i; + break; + } + clock.haveflags |= CLK_HAVETIME2; + break; + + case CONF_FDG_VALUE1: + if (!atoint(tokens[++i], + &clock.fudgeval1)) { + syslog(LOG_ERR, + "fudge %s value1 value in error", + ntoa(&peeraddr)); + errflg = i; + break; + } + clock.haveflags |= CLK_HAVEVAL1; + break; + + case CONF_FDG_VALUE2: + if (!atoint(tokens[++i], + &clock.fudgeval2)) { + syslog(LOG_ERR, + "fudge %s value2 value in error", + ntoa(&peeraddr)); + errflg = i; + break; + } + clock.haveflags |= CLK_HAVEVAL2; + break; + + case CONF_FDG_FLAG1: + case CONF_FDG_FLAG2: + case CONF_FDG_FLAG3: + case CONF_FDG_FLAG4: + if (!atouint(tokens[++i], &peerkey) + || peerkey > 1) { + syslog(LOG_ERR, + "fudge %s flag value in error", + ntoa(&peeraddr)); + errflg = i; + break; + } + switch(c) { + case CONF_FDG_FLAG1: + c = CLK_FLAG1; + clock.haveflags|=CLK_HAVEFLAG1; + break; + case CONF_FDG_FLAG2: + c = CLK_FLAG2; + clock.haveflags|=CLK_HAVEFLAG2; + break; + case CONF_FDG_FLAG3: + c = CLK_FLAG3; + clock.haveflags|=CLK_HAVEFLAG3; + break; + case CONF_FDG_FLAG4: + c = CLK_FLAG4; + clock.haveflags|=CLK_HAVEFLAG4; + break; + } + if (peerkey == 0) + clock.flags &= ~c; + else + clock.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, + (struct refclockstat *)0); + } +#endif + break; + + case CONFIG_MAXSKEW: + if (ntokens >= 2) { + l_fp tmp; + u_fp utmp; + + if (!atolfp(tokens[1], &tmp)) { + syslog(LOG_ERR, + "maxskew value %s undecodable", + tokens[1]); + } else if (tmp.l_ui != 0) { + syslog(LOG_ERR, + "maxskew value %s is unlikely", + tokens[1]); + } else { + utmp = LFPTOFP(&tmp); + proto_config(PROTO_MAXSKEW, (LONG)utmp); + } + } + break; + + case CONFIG_RESOLVER: + if (ntokens >= 2) { + if (strlen(tokens[1]) >= (size_t)MAXFILENAME) { + syslog(LOG_ERR, + "resolver path name too LONG (>%d, sigh), no name resolution possible", + MAXFILENAME); + break; + } + strcpy(resolver_name, tokens[1]); + have_resolver = 1; +#ifdef RESOLVE_INTERNAL + resolve_internal = 0; +#endif + } + break; + + case CONFIG_SELECT: + if (ntokens >= 2) { + i = atoi(tokens[1]); + if (i < SELECT_1 || i > SELECT_5) + syslog(LOG_ERR, + "invalid selection algorithm %s, line ignored", + tokens[1]); + else + proto_config(PROTO_SELECT, (LONG)i); + } + 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) { + syslog(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) { + syslog(LOG_ERR, + "no id for filegen command, line ignored"); + break; + } + + filegen = filegen_get(tokens[1]); + if (filegen == NULL) { + syslog(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)) { + case CONF_FGEN_FILE: + if (i >= ntokens - 1) { + syslog(LOG_ERR, + "filegen %s file requires argument", + tokens[1]); + errflg = i; + break; + } + peerversion = ++i; + break; + case CONF_FGEN_TYPE: + if (i >= ntokens -1) { + syslog(LOG_ERR, + "filegen %s type requires argument", + tokens[1]); + errflg = i; + break; + } + peerkey = matchkey(tokens[++i], fgen_types); + if (peerkey == CONFIG_UNKNOWN) { + syslog(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; + + } + } + (void) fclose(fp); + + if (res_fp != NULL) { + /* + * Need name resolution + */ + errflg = 0; +#ifdef RESOLVE_INTERNAL + if ( resolve_internal ) + do_resolve_internal(); + else + { +#endif + + if (info_auth_keyid == 0) { + syslog(LOG_ERR, + "no request key defined, peer name resolution not possible"); + errflg++; + } + if (!have_resolver) { + syslog(LOG_ERR, + "no resolver defined, peer name resolution not possible"); + errflg++; + } + if (!have_keyfile) { + syslog(LOG_ERR, + "no key file specified, peer name resolution not possible"); + errflg++; + } + + if (!errflg) + + do_resolve(resolver_name, info_auth_keyid, keyfile); + else + abort_resolve(); +#ifdef RESOLVE_INTERNAL + } +#endif + } +} + + + +/* + * gettokens - read a line and return tokens + */ +static int +gettokens(fp, line, tokenlist, ntokens) + FILE *fp; + char *line; + char **tokenlist; + int *ntokens; +{ + register char *cp; + register int eol; + register int ntok; + + /* + * 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 + */ + eol = 0; + ntok = 0; + while (!eol) { + tokenlist[ntok++] = cp; + while (!ISEOL(*cp) && !ISSPACE(*cp)) + cp++; + if (ISEOL(*cp)) { + *cp = '\0'; + eol = 1; + } else { /* must be space */ + *cp++ = '\0'; + while (ISSPACE(*cp)) + cp++; + if (ISEOL(*cp)) + eol = 1; + } + if (ntok == MAXTOKENS) + eol = 1; + } + + /* + * Return the match + */ + *ntokens = ntok; + ntok = matchkey(tokenlist[0], keywords); + if (ntok == CONFIG_UNKNOWN) + goto again; + return ntok; +} + + + +/* + * matchkey - match a keyword to a list + */ +static int +matchkey(word, keys) + register char *word; + register struct keyword *keys; +{ + for (;;) { + if (keys->keytype == CONFIG_UNKNOWN) { + syslog(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(num, addr, complain) + char *num; + struct sockaddr_in *addr; + int complain; +{ + register char *cp; + register char *bp; + register int i; + register int temp; + char buf[80]; /* will core dump on really stupid stuff */ + U_LONG netnum; + +/* XXX ELIMINATE replace with decodenetnum */ + cp = num; + netnum = 0; + for (i = 0; i < 4; i++) { + bp = buf; + while (isdigit(*cp)) + *bp++ = *cp++; + if (bp == buf) + break; + + if (i < 3) { + if (*cp++ != '.') + break; + } else if (*cp != '\0') + break; + + *bp = '\0'; + temp = atoi(buf); + if (temp > 255) + break; + netnum <<= 8; + netnum += temp; +#ifdef DEBUG + if (debug > 3) + printf("getnetnum %s step %d buf %s temp %d netnum %d\n", + num, i, buf, temp, netnum); +#endif + } + + if (i < 4) { + if (complain) + syslog(LOG_ERR, + "configure: \"%s\" not valid host number, line ignored", + num); +#ifdef DEBUG + if (debug > 3) + printf( + "configure: \"%s\" not valid host number, line ignored\n", + num); +#endif + return 0; + } + + /* + * make up socket address. Clear it out for neatness. + */ + bzero((char *)addr, sizeof(struct sockaddr_in)); + addr->sin_family = AF_INET; + addr->sin_port = htons(NTP_PORT); + addr->sin_addr.s_addr = htonl(netnum); +#ifdef DEBUG + if (debug > 1) + printf("getnetnum given %s, got %s (%x)\n", + num, ntoa(addr), netnum); +#endif + return 1; +} + + +/* + * catchchild - receive the resolver's exit status + */ +static RETSIGTYPE +catchchild(sig) +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. + */ + (void) wait(0); +} + + +/* + * save_resolve - save configuration info into a file for later name resolution + */ +static void +save_resolve(name, mode, version, minpoll, maxpoll, flags, keyid) + char *name; + int mode; + int version; + int minpoll; + int maxpoll; + int flags; + U_LONG keyid; +{ + if (res_fp == NULL) { + (void) strcpy(res_file, RES_TEMPFILE); + (void) mktemp(res_file); + res_fp = fopen(res_file, "w"); + if (res_fp == NULL) { + syslog(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 %lu\n", name, mode, + version, minpoll, maxpoll, flags, keyid); +} + + +/* + * abort_resolve - terminate the resolver stuff and delete the file + */ +static void +abort_resolve() +{ + /* + * 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; + + (void) unlink(res_file); +} + + +/* + * do_resolve - start up the resolver program + */ +static void +do_resolve(program, auth_keyid, keyfile) + char *program; + U_LONG auth_keyid; + char *keyfile; +{ + register LONG i; + register char **ap; + /* 1 progname + 5 -d's + 1 -r + keyid + keyfile + tempfile + 1 */ + char *argv[15]; + char numbuf[15]; + /* + * Clean environment so the resolver is consistant + */ + static char *resenv[] = { + "HOME=/", + "SHELL=/bin/sh", + "TERM=dumb", + "USER=root", + NULL + }; + + if (res_fp == NULL) { + /* belch */ + syslog(LOG_ERR, "internal error in do_resolve: res_fp == NULL"); + exit(1); + } + (void) fclose(res_fp); + res_fp = NULL; + + ap = argv; + *ap++ = program; + + /* + * xntpres [-d ...] -r key# keyfile tempfile + */ +#ifdef DEBUG + i = debug; + if (i > 5) + i = 5; + while (i-- > 0) + *ap++ = "-d"; +#endif + *ap++ = "-r"; + + (void) sprintf(numbuf, "%lu", auth_keyid); + *ap++ = numbuf; + *ap++ = keyfile; + *ap++ = res_file; + *ap = NULL; + + (void) signal_no_reset(SIGCHLD, catchchild); + + i = fork(); + if (i == 0) { + /* + * In child here, close up all descriptors and + * exec the resolver program. Close the syslog() + * facility gracefully in case we must reopen it. + */ + (void) signal(SIGCHLD, SIG_DFL); + closelog(); +#if defined(NTP_POSIX_SOURCE) && !defined(SYS_386BSD) + i = sysconf(_SC_OPEN_MAX); +#else + i = getdtablesize(); +#endif +#ifdef DEBUG + while (i-- > 2) +#else + while (i-- > 0) +#endif + (void) close(i); + (void) execve(program, argv, resenv); + + /* + * If we got here, the exec screwed up. Open the log file + * and print something so we don't die without complaint + */ +#ifndef LOG_DAEMON + openlog("xntpd", LOG_PID); +#else +#ifndef LOG_NTP +#define LOG_NTP LOG_DAEMON +#endif + openlog("xntpd", LOG_PID | LOG_NDELAY, LOG_NTP); +#endif /* LOG_DAEMON */ + syslog(LOG_ERR, "exec of resolver %s failed!", program); + abort_resolve(); + exit(1); + } + + if (i == -1) { + syslog(LOG_ERR, "fork() failed, can't start %s", program); + (void) signal_no_reset(SIGCHLD, SIG_DFL); + abort_resolve(); + } +} + + +#ifdef RESOLVE_INTERNAL + +#define KEY_TYPE_ASCII 3 + +/* + * do_resolve_internal - start up the resolver function (not program) + */ +static void +do_resolve_internal() +{ + int i; + + extern U_LONG req_keyid; /* request keyid */ + extern char *req_file; /* name of the file with configuration info */ + extern U_LONG info_auth_keyid; + + if (res_fp == NULL) { + /* belch */ + syslog(LOG_ERR, "internal error in do_resolve_internal: res_fp == NULL"); + exit(1); + } + + /* we are done with this now */ + (void) fclose(res_fp); + res_fp = NULL; + + /* 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]; + struct timeval now; + + /* generate random key */ + GETTIMEOFDAY(&now, (struct timezone *)0); + srand(now.tv_sec * now.tv_usec); + + for ( i = 0; i < 8; i++ ) + rankey[i] = (rand() % 255) + 1; + rankey[8] = 0; + + authusekey(req_keyid, KEY_TYPE_ASCII, rankey); + } + + /* save keyid so we will accept config requests with it */ + info_auth_keyid = req_keyid; + + req_file = res_file; /* set up pointer to res file */ + + (void) signal_no_reset(SIGCHLD, catchchild); + + i = fork(); + if (i == 0) { + /* this used to close everything + * I don't think this is necessary */ + (void) signal_no_reset(SIGCHLD, SIG_DFL); + + ntp_intres(); + + /* + * If we got here, the intres code screwed up. + * Print something so we don't die without complaint + */ + syslog(LOG_ERR, "call to ntp_intres lost"); + abort_resolve(); + exit(1); + } + + if (i == -1) { + syslog(LOG_ERR, "fork() failed, can't start ntp_intres"); + (void) signal_no_reset(SIGCHLD, SIG_DFL); + abort_resolve(); + } +} +#endif diff --git a/contrib/xntpd/xntpd/ntp_control.c b/contrib/xntpd/xntpd/ntp_control.c new file mode 100644 index 0000000000..5e71196e4e --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_control.c @@ -0,0 +1,2305 @@ +/* ntp_control.c,v 3.1 1993/07/06 01:11:13 jbj Exp + * ntp_control.c - respond to control messages and send async traps + */ +#include +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_refclock.h" +#include "ntp_control.h" +#include "ntp_stdlib.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)(); /* routine to handle request */ +}; + +/* + * Only one flag. Authentication required or not. + */ +#define NOAUTH 0 +#define AUTH 1 + +/* + * Request processing routines + */ +static void ctl_error P((int)); +static u_short ctlclkstatus P((struct refclockstat *)); +static void ctl_flushpkt P((int)); +static void ctl_putdata P((char *, int, int)); +static void ctl_putstr P((char *, char *, int)); +static void ctl_putlfp P((char *, l_fp *)); + +#ifdef UNUSED +static void ctl_putulfp P((char *, l_fp *)); +#endif /* UNUSED */ + +static void ctl_putfp P((char *, s_fp)); +static void ctl_putufp P((char *, u_fp)); +static void ctl_putuint P((char *, U_LONG)); +static void ctl_puthex P((char *, U_LONG)); +static void ctl_putint P((char *, LONG)); +static void ctl_putts P((char *, l_fp *)); +static void ctl_putadr P((char *, U_LONG)); +static void ctl_putid P((char *, char *)); +static void ctl_putarray P((char *, s_fp *, 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 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_in *, 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 } +}; + + +/* + * Structure for translation tables between internal system + * variable indices and text format. + */ +struct ctl_var { + u_short code; + u_short flags; + char *text; +}; + +/* + * Flag values + */ +#define CAN_READ 0x1 +#define CAN_WRITE 0x2 +#define PADDING 0x80 +#define EOV 0x40 + +#define RO (CAN_READ) +#define WO (CAN_WRITE) +#define RW (CAN_READ|CAN_WRITE) + + +/* + * 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_OFFSET, RO, "phase" }, /* 10 */ + { CS_DRIFT, RO, "freq" }, /* 11 */ + { CS_COMPLIANCE, RO, "compliance" }, /* 12 */ + { CS_CLOCK, RO, "clock" }, /* 13 */ + { CS_LEAPIND, RW, "leapindicator" }, /* 14 */ + { CS_LEAPWARNING, RW, "leapwarning" }, /* 15 */ + { CS_PROCESSOR, RO, "processor" }, /* 16 */ + { CS_SYSTEM, RO, "system" }, /* 17 */ + { CS_KEYID, RO, "keyid" }, /* 18 */ + { CS_REFSKEW, RO, "refskew" }, /* 19 */ + { CS_VERSION, RO, "daemon_version" }, /* 20 */ + { 0, EOV, "" } +}; + +/* + * System variables we print by default (in fuzzball order, more-or-less) + */ +static u_char def_sys_var[] = { + CS_SYSTEM, + CS_LEAP, + CS_STRATUM, + CS_ROOTDELAY, + CS_ROOTDISPERSION, + CS_PEERID, + CS_REFID, + CS_REFTIME, + CS_POLL, + CS_CLOCK, + CS_OFFSET, + CS_DRIFT, + CS_COMPLIANCE, + CS_VERSION, + 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, "valid" }, /* 22 */ + { CP_TIMER, RO, "timer" }, /* 23 */ + { CP_DELAY, RO, "delay" }, /* 24 */ + { CP_OFFSET, RO, "offset" }, /* 25 */ + { CP_DISPERSION,RO, "dispersion" }, /* 26 */ + { CP_KEYID, RO, "keyid" }, /* 27 */ + { CP_FILTDELAY, RO, "filtdelay" }, /* 28 */ + { CP_FILTOFFSET, RO, "filtoffset" }, /* 29 */ + { CP_PMODE, RO, "pmode" }, /* 30 */ + { CP_RECEIVED, RO, "received" }, /* 31 */ + { CP_SENT, RO, "sent" }, /* 32 */ + { CP_FILTERROR, RO, "filterror" }, /* 33 */ + { CP_FLASH, RO, "flash" }, /* 34 */ + { 0, EOV, "" } +}; + + +/* + * Peer variables we print by default + */ +static u_char def_peer_var[] = { + CP_SRCADR, + CP_SRCPORT, + CP_DSTADR, + CP_DSTPORT, + CP_KEYID, + CP_STRATUM, + CP_PRECISION, + CP_ROOTDELAY, + CP_ROOTDISPERSION, + CP_REFID, + CP_REFTIME, + CP_DELAY, + CP_OFFSET, + CP_DISPERSION, + CP_REACH, + CP_VALID, + CP_HMODE, + CP_PMODE, + CP_HPOLL, + CP_PPOLL, + CP_LEAP, + CP_FLASH, + CP_ORG, + CP_REC, + CP_XMT, + CP_FILTDELAY, + CP_FILTOFFSET, + CP_FILTERROR, + 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, "fudgeval1" }, /* 9 */ + { CC_FUDGEVAL2, RO, "fudgeval2" }, /* 10 */ + { CC_FLAGS, RO, "flags" }, /* 11 */ + { CC_DEVICE, RO, "device" }, /* 12 */ + { 0, EOV, "" } +}; + + +/* + * 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. These will change for the gizmo board. + */ +#define STR_SYSTEM "UNIX" +#define STR_PROCESSOR "unknown" + +/* + * 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 */ + CTL_SST_TS_UNSPEC, /* REFCLK_LOCALCLOCK */ + CTL_SST_TS_HF, /* REFCLK_WWV_HEATH */ + CTL_SST_TS_HF, /* REFCLK_WWV_PST */ + CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM */ + CTL_SST_TS_UHF, /* REFCLK_GOES_TRUETIME */ + CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK */ + CTL_SST_TS_HF, /* REFCLK_CHU */ + CTL_SST_TS_LF, /* REFCLOCK_PARSE - default value - driver supplies actual value in peer->sstclktype */ + CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM_HP */ + CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 */ + CTL_SST_TS_LF, /* REFCLK_OMEGA_TRUETIME */ + CTL_SST_TS_UNSPEC, /* Future expansion */ + CTL_SST_TS_UNSPEC, /* Future expansion */ + CTL_SST_TS_UNSPEC, /* Future expansion */ + CTL_SST_TS_UNSPEC /* Future expansion */ +}; + + + +/* + * Keyid used for authenticating write requests. + */ +U_LONG 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 */ + +/* + * Imported from the I/O module + */ +extern struct interface *any_interface; + +/* + * Imported from the main routines + */ +extern int debug; + +/* + * Imported from the timer module + */ +extern U_LONG current_time; + +extern struct peer *assoc_hash[]; +extern int pps_control; /* flag for 1-pps signal present */ +/* + * Importations from the protocol module + */ +extern u_char sys_leap; +extern u_char sys_stratum; +extern s_char sys_precision; +extern s_fp sys_rootdelay; +extern u_fp sys_rootdispersion; +extern U_LONG sys_refid; +extern l_fp sys_reftime; +extern l_fp sys_refskew; +extern u_char sys_poll; +extern struct peer *sys_peer; +/* + * Imported from the loop filter module + */ +extern l_fp last_offset; +extern s_fp drift_comp; +extern int time_constant; +/* + * Imported from the leap module + */ +extern u_char leap_indicator; +extern u_char leap_warning; + +/* + * 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 u_short res_associd; +static int res_offset; +static u_char * datapt; +static u_char * dataend; +static int datalinelen; +static int datanotbinflag; +static struct sockaddr_in *rmt_addr; +static struct interface *lcl_inter; + +static u_char res_authenticate; +static u_char res_authokay; +static U_LONG 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() +{ + int i; + + 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(errcode) + 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 = CTL_RESPONSE|CTL_ERROR|(res_opcode & CTL_OP_MASK); + rpkt.status = htons((errcode<<8) & 0xff00); + rpkt.count = 0; + + /* + * send packet and bump counters + */ + if (res_authenticate) { + int maclen; + + *(U_LONG *)((u_char *)&rpkt + CTL_HEADER_LEN) + = htonl(res_keyid); + maclen = + authencrypt(res_keyid, (U_LONG *)&rpkt, CTL_HEADER_LEN); + sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt, + CTL_HEADER_LEN + maclen); + } else { + sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt, + CTL_HEADER_LEN); + } + numctlerrors++; +} + + +/* + * process_control - process an incoming control message + */ +void +process_control(rbufp, restrict) + struct recvbuf *rbufp; + int restrict; +{ + 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) + 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; + + if ((rbufp->recv_length & (sizeof(U_LONG)-1)) == 0 + && (maclen = (rbufp->recv_length - properlen)) >= MIN_MAC_LEN + && maclen <= MAX_MAC_LEN) { + + res_authenticate = 1; + res_keyid = ntohl(*(U_LONG *)((u_char *)pkt + properlen)); + +#ifdef DEBUG + if (debug >= 3) + printf( + "recv_len %d, properlen %d, wants auth with keyid %d, MAC length=%d\n", + rbufp->recv_length, properlen, res_keyid, maclen); +#endif + if (!authhavekey(res_keyid)) { +#ifdef DEBUG + if (debug >= 2) + printf("keyid %lu unknown\n", res_keyid); +#endif + } else if (authdecrypt(res_keyid, (U_LONG *)pkt, + rbufp->recv_length - maclen)) { +#ifdef DEBUG + if (debug >= 3) + printf("authenticated okay\n"); +#endif + res_authokay = 1; + } else { +#ifdef DEBUG + if (debug >= 3) + 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); + 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(peer) + register struct peer *peer; +{ + register u_short status; + + status = CTL_PST_SEL_REJECT; + if (peer->was_sane != 0) + status = CTL_PST_SEL_SANE; + if (peer->correct != 0) + status = CTL_PST_SEL_CORRECT; + if (peer->candidate != 0) + status = CTL_PST_SEL_SELCAND; + if (peer->select != 0) + status = CTL_PST_SEL_SYNCCAND; + if (peer == sys_peer) { + status = CTL_PST_SEL_DISTSYSPEER; + if (peer->synch < NTP_MAXDISTANCE) { + status = CTL_PST_SEL_SYSPEER; + if (pps_control) + status = CTL_PST_SEL_PPS; + } + } + 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 + */ +static u_short +ctlclkstatus(clock) + struct refclockstat *clock; +{ + return ((u_short)(clock->currentstatus) << 8) + | (u_short)(clock->lastevent); +} + + + +/* + * ctlsysstatus - return the system status word + */ +u_short +ctlsysstatus() +{ + register u_char clock; + + clock = CTL_SST_TS_UNSPEC; + if (sys_peer != 0) + if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) + clock = sys_peer->sstclktype; + else + if (sys_peer->refclktype < sizeof(clocktypes)) + clock = clocktypes[sys_peer->refclktype]; + + return (u_short)CTL_SYS_STATUS(sys_leap, 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(more) + 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 = CTL_RESPONSE|more|(res_opcode & CTL_OP_MASK); + rpkt.count = htons((u_short)dlen); + rpkt.offset = htons(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, + (struct pkt *)&rpkt, sendlen); + if (!more) + ctl_trap[i].tr_sequence++; + numasyncmsgs++; + } + } + } else { + if (res_authenticate) { + int maclen; + int totlen = sendlen; + + /* + * 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++; + } + *(U_LONG *)datapt = htonl(res_keyid); + maclen = + authencrypt(res_keyid, (U_LONG *)&rpkt, totlen); + + sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt, + totlen + maclen); + } else { + sendpkt(rmt_addr, lcl_inter, (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(dp, dlen, bin) + char *dp; + 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); + } + + bcopy(dp, (char *)datapt, dlen); + datapt += dlen; + datalinelen += dlen; +} + + +/* + * ctl_putstr - write a tagged string into the response packet + */ +static void +ctl_putstr(tag, data, len) + char *tag; + char *data; + int len; +{ + register char *cp, *cq; + char buffer[400]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + if (len > 0) { + *cp++ = '='; + *cp++ = '"'; + if (len > (sizeof(buffer) - (cp - buffer) - 1)) + len = sizeof(buffer) - (cp - buffer) - 1; + bcopy(data, cp, len); + cp += len; + *cp++ = '"'; + } + + ctl_putdata(buffer, cp - buffer, 0); +} + + + +/* + * ctl_putlfp - write a tagged, signed l_fp into the response packet + */ +static void +ctl_putlfp(tag, ts) + char *tag; + l_fp *ts; +{ + register char *cp, *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + cq = lfptoms(ts, 3); + while (*cq != '\0') + *cp++ = *cq++; + + ctl_putdata(buffer, cp - buffer, 0); +} + + +#ifdef UNUSED +/* + * ctl_putlfp - write a tagged, unsigned l_fp into the response + */ +static void +ctl_putulfp(tag, ts) + char *tag; + l_fp *ts; +{ + register char *cp, *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + cq = ulfptoms(ts, 3); + while (*cq != '\0') + *cp++ = *cq++; + + ctl_putdata(buffer, cp - buffer, 0); +} +#endif /* UNUSED */ + + +/* + * ctl_putfp - write a tagged s_fp number into the response + */ +static void +ctl_putfp(tag, fp) + char *tag; + s_fp fp; +{ + register char *cp, *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + cq = fptoms(fp, 2); + while (*cq != '\0') + *cp++ = *cq++; + + ctl_putdata(buffer, cp - buffer, 0); +} + + +/* + * ctl_putufp - write a tagged u_fp number into the response + */ +static void +ctl_putufp(tag, ufp) + char *tag; + u_fp ufp; +{ + register char *cp, *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + cq = ufptoms(ufp, 2); + while (*cq != '\0') + *cp++ = *cq++; + + ctl_putdata(buffer, cp - buffer, 0); +} + + +/* + * ctl_putuint - write a tagged unsigned integer into the response + */ +static void +ctl_putuint(tag, uval) + char *tag; + U_LONG uval; +{ + register char *cp, *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + (void) sprintf(cp, "%u", uval); + while (*cp != '\0') + cp++; + + ctl_putdata(buffer, cp - buffer, 0); +} + + +/* + * ctl_puthex - write a tagged unsigned integer, in hex, into the response + */ +static void +ctl_puthex(tag, uval) + char *tag; + U_LONG uval; +{ + register char *cp, *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, cp - buffer, 0); +} + + +/* + * ctl_putint - write a tagged signed integer into the response + */ +static void +ctl_putint(tag, ival) + char *tag; + LONG ival; +{ + register char *cp, *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + (void) sprintf(cp, "%d", ival); + while (*cp != '\0') + cp++; + + ctl_putdata(buffer, cp - buffer, 0); +} + + +/* + * ctl_putts - write a tagged timestamp, in hex, into the response + */ +static void +ctl_putts(tag, ts) + char *tag; + l_fp *ts; +{ + register char *cp, *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, cp - buffer, 0); +} + + +/* + * ctl_putadr - write a dotted quad IP address into the response + */ +static void +ctl_putadr(tag, addr) + char *tag; + U_LONG addr; +{ + register char *cp, *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + cq = numtoa(addr); + while (*cq != '\0') + *cp++ = *cq++; + + ctl_putdata(buffer, cp - buffer, 0); +} + + +/* + * ctl_putid - write a tagged clock ID into the response + */ +static void +ctl_putid(tag, id) + char *tag; + char *id; +{ + register char *cp, *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, cp - buffer, 0); +} + + +/* + * ctl_putarray - write a tagged eight element s_fp array into the response + */ +static void +ctl_putarray(tag, arr, start) + char *tag; + s_fp *arr; + int start; +{ + register char *cp, *cq; + char buffer[200]; + int i, ind; + int len; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + *cp++ = '='; + /* + * Hack. We know the tag is either filtdelay, filtoffset, + * or filterror. Space over the shorter words one space. + */ + if ((cp - buffer) < 11) + *cp++ = ' '; + + i = start; + ind = 0; + do { + if (i == 0) + i = NTP_SHIFT; + i--; + if (ind) { + *cp++ = ' '; + } else { + ind = 1; + } + cq = fptoms(arr[i], 2); + len = strlen(cq); + while (len < 7) { + *cp++ = ' '; + len++; + } + while (*cq != '\0') + *cp++ = *cq++; + } while(i != start); + + ctl_putdata(buffer, cp - buffer, 0); +} + + +/* + * ctl_putsys - output a system variable + */ +static void +ctl_putsys(varid) + int varid; +{ + extern char *Version; + l_fp tmp; + + switch (varid) { + case CS_LEAP: + ctl_putuint(sys_var[CS_LEAP].text, (U_LONG)sys_leap); + break; + case CS_STRATUM: + ctl_putuint(sys_var[CS_STRATUM].text, (U_LONG)sys_stratum); + break; + case CS_PRECISION: + ctl_putint(sys_var[CS_PRECISION].text, (LONG)sys_precision); + break; + case CS_ROOTDELAY: + ctl_putfp(sys_var[CS_ROOTDELAY].text, sys_rootdelay); + break; + case CS_ROOTDISPERSION: + ctl_putufp(sys_var[CS_ROOTDISPERSION].text, + sys_rootdispersion); + break; + case CS_REFID: + if (sys_stratum <= 1) + ctl_putid(sys_var[CS_REFID].text, (char *)&sys_refid); + else + ctl_putadr(sys_var[CS_REFID].text, 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, (U_LONG)sys_poll); + break; + case CS_PEERID: + if (sys_peer == NULL) + ctl_putuint(sys_var[CS_PEERID].text, (U_LONG)0); + else + ctl_putuint(sys_var[CS_PEERID].text, + (U_LONG)sys_peer->associd); + break; + case CS_OFFSET: + ctl_putlfp(sys_var[CS_OFFSET].text, &last_offset); + break; + case CS_DRIFT: + ctl_putfp(sys_var[CS_DRIFT].text, drift_comp); + break; + case CS_COMPLIANCE: + ctl_putuint(sys_var[CS_COMPLIANCE].text, (U_LONG)time_constant); + break; + case CS_CLOCK: + get_systime(&tmp); + ctl_putts(sys_var[CS_CLOCK].text, &tmp); + break; + case CS_LEAPIND: + ctl_putuint(sys_var[CS_LEAPIND].text, (U_LONG)leap_indicator); + break; + case CS_LEAPWARNING: + ctl_putuint(sys_var[CS_LEAPWARNING].text, (U_LONG)leap_warning); + break; + case CS_PROCESSOR: + ctl_putstr(sys_var[CS_PROCESSOR].text, STR_PROCESSOR, + sizeof(STR_PROCESSOR) - 1); + break; + case CS_SYSTEM: + ctl_putstr(sys_var[CS_SYSTEM].text, STR_SYSTEM, + sizeof(STR_SYSTEM) - 1); + break; + case CS_KEYID: + ctl_putuint(sys_var[CS_KEYID].text, (U_LONG)0); + break; + case CS_REFSKEW: + ctl_putlfp(sys_var[CS_REFSKEW].text, &sys_refskew); + break; + case CS_VERSION: + ctl_putstr(sys_var[CS_VERSION].text, Version, + strlen(Version)); + break; + } +} + + +/* + * ctl_putpeer - output a peer variable + */ +static void +ctl_putpeer(varid, peer) + int varid; + struct peer *peer; +{ + switch (varid) { + case CP_CONFIG: + ctl_putuint(peer_var[CP_CONFIG].text, + (U_LONG)((peer->flags & FLAG_CONFIG) != 0)); + break; + case CP_AUTHENABLE: + ctl_putuint(peer_var[CP_AUTHENABLE].text, + (U_LONG)((peer->flags & FLAG_AUTHENABLE) != 0)); + break; + case CP_AUTHENTIC: + ctl_putuint(peer_var[CP_AUTHENTIC].text, + (U_LONG)((peer->flags & FLAG_AUTHENTIC) != 0)); + break; + case CP_SRCADR: + ctl_putadr(peer_var[CP_SRCADR].text, + peer->srcadr.sin_addr.s_addr); + break; + case CP_SRCPORT: + ctl_putuint(peer_var[CP_SRCPORT].text, + (U_LONG)ntohs(peer->srcadr.sin_port)); + break; + case CP_DSTADR: + ctl_putadr(peer_var[CP_DSTADR].text, + peer->dstadr->sin.sin_addr.s_addr); + break; + case CP_DSTPORT: + ctl_putuint(peer_var[CP_DSTPORT].text, + (U_LONG)ntohs(peer->dstadr->sin.sin_port)); + break; + case CP_LEAP: + ctl_putuint(peer_var[CP_LEAP].text, (U_LONG)peer->leap); + break; + case CP_HMODE: + ctl_putuint(peer_var[CP_HMODE].text, (U_LONG)peer->hmode); + break; + case CP_STRATUM: + ctl_putuint(peer_var[CP_STRATUM].text, (U_LONG)peer->stratum); + break; + case CP_PPOLL: + ctl_putuint(peer_var[CP_PPOLL].text, (U_LONG)peer->ppoll); + break; + case CP_HPOLL: + ctl_putuint(peer_var[CP_HPOLL].text, (U_LONG)peer->hpoll); + break; + case CP_PRECISION: + ctl_putint(peer_var[CP_PRECISION].text, (LONG)peer->precision); + break; + case CP_ROOTDELAY: + ctl_putfp(peer_var[CP_ROOTDELAY].text, peer->rootdelay); + break; + case CP_ROOTDISPERSION: + ctl_putufp(peer_var[CP_ROOTDISPERSION].text, + peer->rootdispersion); + break; + case CP_REFID: + if (peer->stratum > 1) + ctl_putadr(peer_var[CP_REFID].text, peer->refid); + 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, (U_LONG)peer->reach); + break; + case CP_FLASH: + ctl_puthex(peer_var[CP_FLASH].text, (U_LONG)peer->flash); + break; + case CP_VALID: + ctl_putuint(peer_var[CP_VALID].text, (U_LONG)peer->valid); + break; + case CP_TIMER: + ctl_putuint(peer_var[CP_TIMER].text, + peer->event_timer.event_time - current_time); + break; + case CP_DELAY: + ctl_putfp(peer_var[CP_DELAY].text, peer->delay); + break; + case CP_OFFSET: + ctl_putlfp(peer_var[CP_OFFSET].text, &peer->offset); + break; + case CP_DISPERSION: + ctl_putufp(peer_var[CP_DISPERSION].text, peer->dispersion); + 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_soffset, (int)peer->filter_nextpt); + break; + case CP_FILTERROR: + ctl_putarray(peer_var[CP_FILTERROR].text, + (s_fp *)peer->filter_error, (int)peer->filter_nextpt); + break; + case CP_PMODE: + ctl_putuint(peer_var[CP_PMODE].text, (U_LONG)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; + } +} + + +#ifdef REFCLOCK +/* + * ctl_putclock - output clock variables + */ +static void +ctl_putclock(varid, clock, mustput) + int varid; + struct refclockstat *clock; + int mustput; +{ + switch(varid) { + case CC_TYPE: + if (mustput || clock->clockdesc == NULL + || *(clock->clockdesc) == '\0') { + ctl_putuint(clock_var[CC_TYPE].text, + (U_LONG)clock->type); + } + break; + case CC_TIMECODE: + ctl_putstr(clock_var[CC_TIMECODE].text, clock->lastcode, + (int)clock->lencode); + break; + case CC_POLL: + ctl_putuint(clock_var[CC_POLL].text, (U_LONG)clock->polls); + break; + case CC_NOREPLY: + ctl_putuint(clock_var[CC_NOREPLY].text, clock->noresponse); + break; + case CC_BADFORMAT: + ctl_putuint(clock_var[CC_BADFORMAT].text, clock->badformat); + break; + case CC_BADDATA: + ctl_putuint(clock_var[CC_BADDATA].text, clock->baddata); + break; + case CC_FUDGETIME1: + if (mustput || (clock->haveflags & CLK_HAVETIME1)) + ctl_putlfp(clock_var[CC_FUDGETIME1].text, + &clock->fudgetime1); + break; + case CC_FUDGETIME2: + if (mustput || (clock->haveflags & CLK_HAVETIME2)) + ctl_putlfp(clock_var[CC_FUDGETIME2].text, + &clock->fudgetime2); + break; + case CC_FUDGEVAL1: + if (mustput || (clock->haveflags & CLK_HAVEVAL1)) + ctl_putint(clock_var[CC_FUDGEVAL1].text, + clock->fudgeval1); + break; + case CC_FUDGEVAL2: + if (mustput || (clock->haveflags & CLK_HAVEVAL2)) + ctl_putint(clock_var[CC_FUDGEVAL2].text, + clock->fudgeval2); + break; + case CC_FLAGS: + if (mustput || (clock->haveflags & + (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))) + ctl_putuint(clock_var[CC_FLAGS].text, + (U_LONG)clock->flags); + break; + case CC_DEVICE: + if (clock->clockdesc == NULL || *(clock->clockdesc) == '\0') { + if (mustput) + ctl_putstr(clock_var[CC_DEVICE].text, "", 0); + } else { + ctl_putstr(clock_var[CC_DEVICE].text, clock->clockdesc, + strlen(clock->clockdesc)); + } + break; + } +} +#endif + + + +/* + * ctl_getitem - get the next data item from the incoming packet + */ +static struct ctl_var * +ctl_getitem(var_list, data) + struct ctl_var *var_list; + char **data; +{ + register struct ctl_var *v; + register char *cp, *tp; + static char buf[128]; + + /* + * Delete leading commas and white space + */ + while (reqpt < reqend && (*reqpt == ',' || isspace(*reqpt))) { + reqpt++; + } + + if (reqpt >= reqend) + return 0; + + /* + * 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' && cp < reqend && *cp == *tp) { + cp++; + tp++; + } + if (*tp == '\0') { + while (cp < reqend && isspace(*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(*cp)) + cp++; + while (cp < reqend && *cp != ',') + *tp++ = *cp++; + if (cp < reqend) + cp++; + *tp = '\0'; + while (isspace(*(tp-1))) + *(--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(rbufp, restrict) + struct recvbuf *rbufp; + int restrict; +{ + 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((int)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(rbufp, restrict) + struct recvbuf *rbufp; + int restrict; +{ + 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((int)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(rbufp, restrict) + struct recvbuf *rbufp; + int restrict; +{ + register struct ctl_var *v; + register int i; + char *valuep; + u_char wants[(CS_MAXCODE>CP_MAXCODE) ? (CS_MAXCODE+1) : (CP_MAXCODE+1)]; + int gotvar; + + 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; + bzero((char *)wants, CS_MAXCODE+1); + gotvar = 0; + while ((v = ctl_getitem(sys_var, &valuep)) != 0) { + if (v->flags & EOV) { + ctl_error(CERR_UNKNOWNVAR); + return; + } + wants[v->code] = 1; + gotvar = 1; + } + if (gotvar) { + for (i = 1; i <= CS_MAXCODE; i++) + if (wants[i]) + ctl_putsys(i); + } else { + register u_char *cs; + + for (cs = def_sys_var; *cs != 0; cs++) + ctl_putsys((int)*cs); + } + } else { + register struct peer *peer; + + /* + * Wants info for a particular peer. See if we know + * the guy. + */ + peer = findpeerbyassoc((int)res_associd); + if (peer == 0) { + ctl_error(CERR_BADASSOC); + return; + } + + rpkt.status = htons(ctlpeerstatus(peer)); + if (res_authokay) + peer->num_events = 0; + bzero((char*)wants, CP_MAXCODE+1); + gotvar = 0; + while ((v = ctl_getitem(peer_var, &valuep)) != 0) { + if (v->flags & EOV) { + ctl_error(CERR_UNKNOWNVAR); + 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); + } + } + ctl_flushpkt(0); +} + + +/* + * write_variables - write into variables. We only allow leap bit writing + * this way. + */ +/*ARGSUSED*/ +static void +write_variables(rbufp, restrict) + struct recvbuf *rbufp; + int restrict; +{ + register struct ctl_var *v; + char *valuep; + LONG val; + u_char leapind, leapwarn; + + /* + * 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()); + + /* + * Set flags to not-in-sync so we can tell when we get something. + */ + leapind = (u_char)~0; + leapwarn = (u_char)~0; + + /* + * Look through the variables. Dump out at the first sign of trouble. + */ + while ((v = ctl_getitem(sys_var, &valuep)) != 0) { + if (v->flags & EOV) { + ctl_error(CERR_UNKNOWNVAR); + return; + } + if (!(v->flags & CAN_WRITE)) { + ctl_error(CERR_PERMISSION); + return; + } + if (*valuep == '\0' || !atoint(valuep, &val)) { + ctl_error(CERR_BADFMT); + return; + } + if ((val & ~LEAP_NOTINSYNC) != 0) { + ctl_error(CERR_BADVALUE); + return; + } + + /* + * This one seems sane. Save it. + */ + switch(v->code) { + case CS_LEAP: + case CS_LEAPIND: + leapind = (u_char)val; + break; + case CS_LEAPWARNING: + leapwarn = (u_char)val; + break; + default: + ctl_error(CERR_UNSPEC); /* our fault, really */ + return; + } + } + + /* + * If we got anything, do it. + */ + if (leapind != (u_char)~0 || leapwarn != (u_char)~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(rbufp, restrict) + struct recvbuf *rbufp; + int restrict; +{ +#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[CC_MAXCODE+1]; + int gotvar; + struct refclockstat clock; + + 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((int)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. + */ + refclock_control(&peer->srcadr, (struct refclockstat *)0, &clock); + + /* + * Look for variables in the packet. + */ + rpkt.status = htons(ctlclkstatus(&clock)); + gotvar = 0; + bzero((char*)wants, CC_MAXCODE+1); + while ((v = ctl_getitem(sys_var, &valuep)) != 0) { + if (v->flags & EOV) { + ctl_error(CERR_UNKNOWNVAR); + return; + } + wants[v->code] = 1; + gotvar = 1; + } + + if (gotvar) { + for (i = 1; i <= CC_MAXCODE; i++) + if (wants[i]) + ctl_putclock(i, &clock, 1); + } else { + register u_char *cc; + + for (cc = def_clock_var; *cc != 0; cc++) + ctl_putclock((int)*cc, &clock, 0); + } + ctl_flushpkt(0); +#endif +} + + +/* + * write_clock_status - we don't do this + */ +/*ARGSUSED*/ +static void +write_clock_status(rbufp, restrict) + struct recvbuf *rbufp; + int restrict; +{ + 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(rbufp, restrict) + struct recvbuf *rbufp; + int restrict; +{ + int traptype; + + /* + * See if this guy is allowed + */ + if (restrict & RES_NOTRAP) { + ctl_error(CERR_PERMISSION); + return; + } + + /* + * Determine his allowed trap type. + */ + traptype = TRAP_TYPE_PRIO; + if (restrict & 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(rbufp, restrict) + struct recvbuf *rbufp; + int restrict; +{ + 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 & 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(raddr, linter, traptype, version) + struct sockaddr_in *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 = 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 clr a trap + */ +int +ctlclrtrap(raddr, linter, traptype) + struct sockaddr_in *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(raddr, linter) + struct sockaddr_in *raddr; + struct interface *linter; +{ + register struct ctl_trap *tp; + + for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) { + if (tp->tr_flags & TRAP_INUSE + && NSRCADR(raddr) == NSRCADR(&tp->tr_addr) + && NSRCPORT(raddr) == NSRCPORT(&tp->tr_addr) + && linter == tp->tr_localaddr) + return tp; + } + return (struct ctl_trap *)NULL; +} + + +/* + * report_event - report an event to the trappers + */ +void +report_event(err, peer) + 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)) { + if (ctl_sys_num_events < CTL_SYS_MAXEVENTS) + ctl_sys_num_events++; + if (ctl_sys_last_event != (u_char)err) + syslog(LOG_INFO, "system event %x status %x", + err, ctlsysstatus()); + ctl_sys_last_event = (u_char)err; + } else if (peer != 0) { + peer->last_event = (u_char)(err & ~PEER_EVENT); + if (peer->num_events < CTL_PEER_MAXEVENTS) + peer->num_events++; + syslog(LOG_INFO, "peer %s event %x status %x", + ntoa(&peer->srcadr), err, ctlpeerstatus(peer)); + } else { + syslog(LOG_ERR, "report_event: err %x, no peer", err); + 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. Maybe more selective later + */ + for (i = 1; i <= CS_MAXCODE; i++) + ctl_putsys(i); +#ifdef REFCLOCK + /* + * for clock exception events: + * add clock variables to reflect info on exception + */ + if (err == EVNT_CLOCKEXCPT) { + struct refclockstat clock; + refclock_control(&peer->srcadr, + (struct refclockstat *)0, + &clock); + ctl_puthex("refclockstatus", + (U_LONG)ctlclkstatus(&clock)); + for (i = 1; i <= CC_MAXCODE; i++) + ctl_putclock(i, &clock, 0); + } +#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++) + 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; + refclock_control(&peer->srcadr, + (struct refclockstat *)0, + &clock); + ctl_puthex("refclockstatus", + (U_LONG)ctlclkstatus(&clock)); + for (i = 1; i <= CC_MAXCODE; i++) + ctl_putclock(i, &clock, 0); + } +#endif /*REFCLOCK*/ + } + + /* + * We're done, return. + */ + ctl_flushpkt(0); +} + + +/* + * ctl_clr_stats - clear stat counters + */ +void +ctl_clr_stats() +{ + 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; +} diff --git a/contrib/xntpd/xntpd/ntp_filegen.c b/contrib/xntpd/xntpd/ntp_filegen.c new file mode 100644 index 0000000000..bbbd24270d --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_filegen.c @@ -0,0 +1,536 @@ +/* + * ntp_filegen.c,v 3.10 1993/12/03 03:55:35 pruy Exp + * + * implements file generations support for NTP + * logfiles and statistic files + * + * + * Copyright (c) 1992 + * Rainer Pruy Friedrich-Alexander Unuiversitaet Erlangen-Nuernberg + * + * This code may be modified and used freely + * provided credits remain intact. + */ + +#include +#include +#include +#include + +#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 + */ + + +/* + * to check reason on open failure + */ +extern int errno; + +/* + * imported from timer + */ +extern U_LONG current_time; + +/* + * 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 */ + +#ifdef DEBUG +extern int debug; +#endif + +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(gen, newid) + 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 = emalloc(len); + sprintf(basename, "%s%s", gen->prefix, gen->basename); + + switch(gen->type) { + default: + syslog(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 = emalloc(len); + sprintf(filename,"%s", basename); + break; + + case FILEGEN_PID: + filename = emalloc(len + 1 + 1 + 10); + sprintf(filename,"%s%c#%d", 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 = 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 = 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 = 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 = emalloc(len + 1 + 4); + sprintf(filename, "%s%c%04d", basename, SUFFIX_SEP, cal.year); + break; + + case FILEGEN_AGE: + filename = emalloc(len + 1 + 2 + 10); + sprintf(filename, "%s%ca%08d", 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 = emalloc(len + 1 + 1 + 10 + 10); + sprintf(savename, "%s%c%dC%lu", + basename, SUFFIX_SEP, getpid(), conflicts++); + if (rename(basename, savename) != 0) + syslog(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 (unlink(basename) != 0) + syslog(LOG_ERR, "couldn't unlink %s: %m", basename); + } + } else { + /* + * Ehh? Not a regular file ?? strange !!!! + */ + syslog(LOG_ERR, "expected regular file for %s (found mode 0%o)", + basename, stats.st_mode); + } + } else { + /* + * stat(..) failed, but it is absolutely correct for + * 'basename' not to exist + */ + if (errno != ENOENT) + syslog(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, 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 loosing output + * + * ignore errors due to missing directories + */ + + if (errno != ENOENT) + syslog(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.... + */ + + if (link(filename, basename) != 0) { + if (errno != EEXIST) + syslog(LOG_ERR, "can't link(%s, %s): %m", filename, basename); + } + + } /*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(gen,now) + FILEGEN *gen; + U_LONG now; +{ + U_LONG new_gen = ~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 days 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 -= 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(gen,basename,type,flag) + 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 = emalloc(strlen(basename) + 1); + strcpy(gen->basename, basename); + } + gen->type = type; + gen->flag = 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; + + gettstamp(&now); + filegen_setup(gen, now.l_ui); + } +} + + +/* + * check whether concatenating prefix and basename + * yields a legal filename + */ +static int +valid_fileref(prefix,basename) + char *prefix, *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(name) + char *name; +{ + struct filegen_entry *f = filegen_registry; + + while(f) { + if (f->name == name || strcmp(name, f->name) == 0) { +#ifdef DEBUG + 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(name, filegen) + char *name; + FILEGEN *filegen; +{ + struct filegen_entry **f = &filegen_registry; + +#ifdef DEBUG + 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 DEBUG + 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 = 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(name) + 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/xntpd/xntpd/ntp_intres.c b/contrib/xntpd/xntpd/ntp_intres.c new file mode 100644 index 0000000000..ebd3d52d05 --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_intres.c @@ -0,0 +1,792 @@ +/* ntp_intres.c,v 3.1 1993/07/06 01:11:16 jbj Exp + * ripped off from ../xnptres/xntpres.c by Greg Troxel 4/2/92 + * routine callable from xntpd, rather than separate program + * also, key info passed in via a global, so no key file needed. + */ + +/* + * xntpres - process configuration entries which require use of the resolver + * + * This is meant to be run by xntpd 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_select.h" +#include "ntp_io.h" +#include "ntp_request.h" +#include "ntp_stdlib.h" +#include "ntp_syslog.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +/* + * Each item we are to resolve and configure gets one of these + * structures defined for it. + */ +struct conf_entry { + struct conf_entry *ce_next; + char *ce_name; /* name we are trying to resolve */ + struct conf_peer ce_config; /* configuration info for peer */ +}; +#define ce_peeraddr ce_config.peeraddr +#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_keyid ce_config.keyid + +/* + * confentries is a pointer to the list of configuration entries + * we have left to do. + */ +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 int config_timer = 0; +static 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_KEYID 6 +#define NUMTOK 7 + +#define MAXLINESIZE 512 + + +/* + * File descriptor for ntp request code. + */ +static int sockfd = -1; + + +/* stuff to be filled in by caller */ + +U_LONG req_keyid; /* request keyid */ +char *req_file; /* name of the file with configuration info */ + +/* end stuff to be filled in */ + + +extern int debug; /* use global debug flag */ +extern int errno; + +static RETSIGTYPE bong P((int)); +static void checkparent P((void)); +static void removeentry P((struct conf_entry *)); +static void addentry P((char *, int, int, int, int, int, U_LONG)); +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)); + +/* + * assumes: req_key, req_keyid, conffile valid + * syslog still open + */ +void +ntp_intres() +{ + FILE *in; + + if ( debug ) + syslog(LOG_INFO, "ntp_intres running"); + + + /* check out auth stuff */ + if (!authhavekey(req_keyid)) { + syslog(LOG_ERR, "request keyid %lu not found", + 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) { + syslog(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) + exit(0); /* done that quick */ + + /* + * Here we've got some problem children. Set up the timer + * and wait for it. + */ + resolve_value = resolve_timer = MINRESOLVE; + config_timer = CONFIG_TIME; + (void) signal_no_reset(SIGALRM, bong); + alarm(ALARM_TIME); + + for (;;) { + if (confentries == NULL) + exit(0); + checkparent(); + if (resolve_timer == 0) { + if (resolve_value < MAXRESOLVE) + resolve_value <<= 1; + resolve_timer = resolve_value; + config_timer = CONFIG_TIME; + doconfigure(1); + continue; + } else if (config_timer == 0) { + config_timer = CONFIG_TIME; + doconfigure(0); + continue; + } + /* + * There is a race in here. Is okay, though, since + * all it does is delay things by 30 seconds. + */ + (void) pause(); + } +} + + +/* + * bong - service and reschedule an alarm() interrupt + */ +static RETSIGTYPE +bong(sig) +int sig; +{ + if (config_timer > 0) + config_timer--; + if (resolve_timer > 0) + resolve_timer--; + alarm(ALARM_TIME); +} + + +/* + * checkparent - see if our parent process is still running + */ +static void +checkparent() +{ + /* + * If our parent (the server) has died we will have been + * inherited by init. If so, exit. + */ + if (getppid() == 1) { + syslog(LOG_INFO, "parent died before we finished, exiting"); + exit(0); + } +} + + +/* + * removeentry - we are done with an entry, remove it from the list + */ +static void +removeentry(entry) + 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(name, mode, version, minpoll, maxpoll, flags, keyid) + char *name; + int mode; + int version; + int minpoll; + int maxpoll; + int flags; + U_LONG keyid; +{ + register char *cp; + register struct conf_entry *ce; + int len; + + len = strlen(name) + 1; + cp = emalloc((unsigned)len); + bcopy(name, cp, len); + + ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry)); + ce->ce_name = cp; + ce->ce_peeraddr = 0; + 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_keyid = htonl(keyid); + 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 + * + * The routine sticks the address into the entry's ce_peeraddr if it + * gets one. It returns 1 for "success" and 0 for an uncorrectable + * failure. Note that "success" includes try again errors. You can + * tell that you got a try again since ce_peeraddr will still be zero. + */ +static int +findhostaddr(entry) + struct conf_entry *entry; +{ + struct hostent *hp; + + checkparent(); /* make sure our guy is still running */ + + hp = gethostbyname(entry->ce_name); + + if (hp == NULL) { +#ifndef NODNS + /* + * If the resolver is in use, see if the failure is + * temporary. If so, return success. + */ + extern int h_errno; + + if (h_errno == TRY_AGAIN) + return 1; +#endif + return 0; + } + + /* + * Use the first address. We don't have any way to + * tell preferences and older gethostbyname() implementations + * only return one. + */ + (void) bcopy(hp->h_addr, (char *)&(entry->ce_peeraddr), + sizeof(struct in_addr)); + return 1; +} + + +/* + * openntp - open a socket to the ntp server + */ +static void +openntp() +{ + struct sockaddr_in saddr; + + if (sockfd >= 0) + return; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) { + syslog(LOG_ERR, "socket() failed: %m"); + exit(1); + } + + bzero((char *)&saddr, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(NTP_PORT); /* trash */ + saddr.sin_addr.s_addr = htonl(LOCALHOST); /* garbage */ + + /* + * Make the socket non-blocking. We'll wait with select() + */ +#if defined(O_NONBLOCK) + if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) { + syslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m"); + exit(1); + } +#else +#if defined(FNDELAY) + if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) { + syslog(LOG_ERR, "fcntl(FNDELAY) failed: %m"); + exit(1); + } +#else +NEED NON BLOCKING IO +#endif +#endif + + + if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { + syslog(LOG_ERR, "connect() failed: %m"); + exit(1); + } +} + + +/* + * request - send a configuration request to the server, wait for a response + */ +static int +request(conf) + struct conf_peer *conf; +{ + fd_set fdset; + struct timeval tvout; + struct req_pkt reqpkt; + l_fp ts; + int n; + + checkparent(); /* make sure our guy is still running */ + + if (sockfd < 0) + openntp(); + + /* + * 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) { + read(sockfd, (char *)&reqpkt, REQ_LEN_MAC); + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + } + + /* + * Make up a request packet with the configuration info + */ + bzero((char *)&reqpkt, sizeof(reqpkt)); + + reqpkt.rm_vn_mode = RM_VN_MODE(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)); + bcopy((char *)conf, reqpkt.data, sizeof(struct conf_peer)); + reqpkt.keyid = htonl(req_keyid); + + auth1crypt(req_keyid, (U_LONG *)&reqpkt, REQ_LEN_NOMAC); + gettstamp(&ts); + M_ADDUF(ts.l_ui, ts.l_uf, SKEWTIME); + HTONL_FP(&ts, &reqpkt.tstamp); + n = auth2crypt(req_keyid, (U_LONG *)&reqpkt, REQ_LEN_NOMAC); + + /* + * Done. Send it. + */ + n = write(sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n); + if (n < 0) { + syslog(LOG_ERR, "send to NTP server failed: %m"); + return 0; /* maybe should exit */ + } + + /* + * 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 (n < 0) + syslog(LOG_ERR, "select() fails: %m"); + return 0; + } + + n = read(sockfd, (char *)&reqpkt, REQ_LEN_MAC); + if (n <= 0) { + if (n < 0) { + syslog(LOG_ERR, "read() fails: %m"); + return 0; + } + continue; + } + + /* + * Got one. Check through to make sure it is what + * we expect. + */ + if (n < RESP_HEADER_SIZE) { + syslog(LOG_ERR, "received runt response (%d octets)", + n); + continue; + } + + if (!ISRESPONSE(reqpkt.rm_vn_mode)) { +#ifdef DEBUG + if (debug > 1) + printf("received non-response packet\n"); +#endif + continue; + } + + if (ISMORE(reqpkt.rm_vn_mode)) { +#ifdef DEBUG + if (debug > 1) + printf("received fragmented packet\n"); +#endif + continue; + } + + if (INFO_VERSION(reqpkt.rm_vn_mode) != NTP_VERSION + || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) { +#ifdef DEBUG + if (debug > 1) + printf("version (%d) or mode (%d) incorrect\n", + INFO_VERSION(reqpkt.rm_vn_mode), + INFO_MODE(reqpkt.rm_vn_mode)); +#endif + continue; + } + + if (INFO_SEQ(reqpkt.auth_seq) != 0) { +#ifdef DEBUG + if (debug > 1) + printf("nonzero sequence number (%d)\n", + INFO_SEQ(reqpkt.auth_seq)); +#endif + continue; + } + + if (reqpkt.implementation != IMPL_XNTPD || + reqpkt.request != REQ_CONFIG) { +#ifdef DEBUG + if (debug > 1) + printf( + "implementation (%d) or request (%d) incorrect\n", + 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) + printf( + "nitems (%d) mbz (%d) or itemsize (%d) nonzero\n", + 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: + syslog(LOG_ERR, + "server reports implementation mismatch!!"); + return 0; + + case INFO_ERR_REQ: + syslog(LOG_ERR, + "server claims configuration request is unknown"); + return 0; + + case INFO_ERR_FMT: + syslog(LOG_ERR, + "server indicates a format error occured(!!)"); + return 0; + + case INFO_ERR_NODATA: + syslog(LOG_ERR, + "server indicates no data available (shouldn't happen)"); + return 0; + + case INFO_ERR_AUTH: + syslog(LOG_ERR, + "server returns a permission denied error"); + return 0; + + default: + syslog(LOG_ERR, + "server returns unknown error code %d", n); + return 0; + } + } +} + + +/* + * nexttoken - return the next token from a line + */ +static char * +nexttoken(lptr) + 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(fp, name) + FILE *fp; + char *name; +{ + register int i; + char *token[NUMTOK]; + U_LONG intval[NUMTOK]; + 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) { + syslog(LOG_ERR, + "tokenizing error in file `%s', quitting", + name); + exit(1); + } + } + + for (i = 1; i < NUMTOK; i++) { + if (!atouint(token[i], &intval[i])) { + syslog(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) { + syslog(LOG_ERR, "invalid mode (%d) in file %s", + intval[TOK_HMODE], name); + exit(1); + } + + if (intval[TOK_VERSION] > NTP_VERSION || + intval[TOK_VERSION] < NTP_OLDVERSION) { + syslog(LOG_ERR, "invalid version (%d) in file %s", + intval[TOK_VERSION], name); + exit(1); + } + if (intval[TOK_MINPOLL] < NTP_MINPOLL || + intval[TOK_MINPOLL] > NTP_MAXPOLL) { + syslog(LOG_ERR, "invalid MINPOLL value (%d) in file %s", + intval[TOK_MINPOLL], name); + exit(1); + } + + if (intval[TOK_MAXPOLL] < NTP_MINPOLL || + intval[TOK_MAXPOLL] > NTP_MAXPOLL) { + syslog(LOG_ERR, "invalid MAXPOLL value (%d) in file %s", + intval[TOK_MAXPOLL], name); + exit(1); + } + + if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE|FLAG_PREFER)) + != 0) { + syslog(LOG_ERR, "invalid flags (%d) 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; + + /* + * 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, intval[TOK_KEYID]); + } +} + + +/* + * doconfigure - attempt to resolve names and configure the server + */ +static void +doconfigure(dores) + int dores; +{ + register struct conf_entry *ce; + register struct conf_entry *ceremove; + + ce = confentries; + while (ce != NULL) { + if (dores && ce->ce_peeraddr == 0) { + if (!findhostaddr(ce)) { + syslog(LOG_ERR, + "couldn't resolve `%s', giving up on it", + ce->ce_name); + ceremove = ce; + ce = ceremove->ce_next; + removeentry(ceremove); + continue; + } + } + + if (ce->ce_peeraddr != 0) { + if (request(&ce->ce_config)) { + ceremove = ce; + ce = ceremove->ce_next; + removeentry(ceremove); + continue; + } + } + ce = ce->ce_next; + } +} diff --git a/contrib/xntpd/xntpd/ntp_io.c b/contrib/xntpd/xntpd/ntp_io.c new file mode 100644 index 0000000000..e765b03f31 --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_io.c @@ -0,0 +1,1621 @@ +/* ntp_io.c,v 3.1 1993/07/06 01:11:17 jbj Exp + * xntp_io.c - input/output routines for xntpd. The socket-opening code + * was shamelessly stolen from ntpd. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_select.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" + +#if defined(BSD)&&!defined(sun)&&!defined(SYS_SINIXM) +#if BSD >= 199006 +#define HAVE_VARIABLE_IFR_LENGTH +#endif +#endif + +#if !defined(HAVE_VARIABLE_IFR_LENGTH) && defined(AF_LINK) && (defined(_SOCKADR_LEN) || !defined(SYS_DECOSF1)) +#define HAVE_VARIABLE_IFR_LENGTH +#endif + +#if defined(USE_TTY_SIGPOLL)||defined(USE_UDP_SIGPOLL) +#if defined(SYS_AIX)&&defined(_IO) +#undef _IO +#endif +#include +#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. + */ + +/* + * select network interfacing + */ +#if defined(SYS_SVR4) || defined(SYS_PTX) || defined(SYS_SINIXM) +#define STREAMS_TLI +#endif + +/* + * Block the interrupt, for critical sections. + */ + +#if defined(HAVE_SIGNALED_IO) +#define BLOCKIO() ((void) block_sigio()) +#define UNBLOCKIO() ((void) unblock_sigio()) +#else +#define BLOCKIO() +#define UNBLOCKIO() +#endif + +/* + * recvbuf memory management + */ +#define RECV_INIT 10 /* 10 buffers initially */ +#define RECV_LOWAT 3 /* when we're down to three buffers get more */ +#define RECV_INC 5 /* get 5 more at a time */ +#define RECV_TOOMANY 30 /* this is way too many buffers */ + +/* + * Memory allocation + */ +U_LONG full_recvbufs; /* number of recvbufs on fulllist */ +U_LONG free_recvbufs; /* number of recvbufs on freelist */ + +static struct recvbuf *freelist; /* free buffers */ +static struct recvbuf *fulllist; /* lifo buffers with data */ +static struct recvbuf *beginlist; /* fifo buffers with data */ + +U_LONG total_recvbufs; /* total recvbufs currently in use */ +U_LONG lowater_additions; /* number of times we have added memory */ + +static struct recvbuf initial_bufs[RECV_INIT]; /* initial allocation */ + + +/* + * Other statistics of possible interest + */ +U_LONG packets_dropped; /* total number of packets dropped on reception */ +U_LONG packets_ignored; /* packets received on wild card interface */ +U_LONG packets_received; /* total number of packets received */ +U_LONG packets_sent; /* total number of packets sent */ +U_LONG packets_notsent; /* total number of packets which couldn't be sent */ + +U_LONG handler_calls; /* number of calls to interrupt handler */ +U_LONG handler_pkts; /* number of pkts received by handler */ +U_LONG io_timereset; /* time counters were reset */ + +/* + * Interface stuff + */ +#define MAXINTERFACES 192 /* much better for big gateways with IP/X.25 and more ... */ +struct interface *any_interface; /* pointer to default interface */ +struct interface *loopback_interface; /* point to loopback interface */ +static struct interface inter_list[MAXINTERFACES]; +static int ninterfaces; + +#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 + +/* + * File descriptor masks etc. for call to select + */ +fd_set activefds; +int maxactivefd; + +/* + * Imported from ntp_timer.c + */ +extern U_LONG current_time; + +extern int errno; +extern int debug; + +static int create_sockets P((unsigned int)); +static int open_socket P((struct sockaddr_in *, int)); +static void close_socket P((int)); +#ifdef HAVE_SIGNALED_IO +static int init_clock_sig P(()); +static void init_socket_sig P((int)); +static void set_signal P(()); +static RETSIGTYPE sigio_handler P((int)); +static void block_sigio P((void)); +static void unblock_sigio P(()); +#endif +#ifndef STREAMS_TLI +extern char *inet_ntoa P((struct in_addr)); +#endif /* STREAMS_TLI */ + +/* + * init_io - initialize I/O data structures and call socket creation routine + */ +void +init_io() +{ + register int i; + + /* + * Init buffer free list and stat counters + */ + freelist = 0; + for (i = 0; i < RECV_INIT; i++) { + initial_bufs[i].next = freelist; + freelist = &initial_bufs[i]; + } + + fulllist = 0; + free_recvbufs = total_recvbufs = RECV_INIT; + full_recvbufs = lowater_additions = 0; + packets_dropped = packets_received = 0; + packets_ignored = 0; + packets_sent = packets_notsent = 0; + handler_calls = handler_pkts = 0; + io_timereset = 0; + loopback_interface = 0; + +#ifdef REFCLOCK + refio = 0; +#endif + +#if defined(HAVE_SIGNALED_IO) + (void) set_signal(); +#endif + + /* + * Create the sockets + */ + BLOCKIO(); + (void) create_sockets(htons(NTP_PORT)); + UNBLOCKIO(); + +#ifdef DEBUG + if (debug) + printf("init_io: maxactivefd %d\n", maxactivefd); +#endif +} + +/* + * create_sockets - create a socket for each interface plus a default + * socket for when we don't know where to send + */ +static int +create_sockets(port) + unsigned int port; +{ +#ifdef STREAMS_TLI + struct strioctl ioc; +#endif /* STREAMS_TLI */ + char buf[MAXINTERFACES*sizeof(struct ifreq)]; + struct ifconf ifc; + struct ifreq ifreq, *ifr; + int n, i, j, vs, size; + struct sockaddr_in resmask; + +#ifdef DEBUG + if (debug) + printf("create_sockets(%d)\n", ntohs(port)); +#endif + + /* + * create pseudo-interface with wildcard address + */ + inter_list[0].sin.sin_family = AF_INET; + inter_list[0].sin.sin_port = port; + inter_list[0].sin.sin_addr.s_addr = INADDR_ANY; + (void) strncpy(inter_list[0].name, "wildcard", + sizeof(inter_list[0].name)); + inter_list[0].mask.sin_addr.s_addr = htonl(~0); + inter_list[0].received = 0; + inter_list[0].sent = 0; + inter_list[0].notsent = 0; + inter_list[0].flags = INT_BROADCAST; + +#ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG + if ((vs = open("/dev/ip", O_RDONLY)) < 0) { +#else /* ! USE_STREAMS_DEVICE_FOR_IF_CONFIG */ + if ((vs = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { +#endif /* USE_STREAMS_DEVICE_FOR_IF_CONFIG */ + syslog(LOG_ERR, "vs=socket(AF_INET, SOCK_DGRAM) %m"); + exit(1); + } + + i = 1; + + ifc.ifc_len = sizeof(buf); +#ifdef STREAMS_TLI + ioc.ic_cmd = SIOCGIFCONF; + ioc.ic_timout = 0; + ioc.ic_dp = (caddr_t)buf; + ioc.ic_len = sizeof(buf); + if(ioctl(vs, I_STR, &ioc) < 0 || + ioc.ic_len < sizeof(struct ifreq)) { + syslog(LOG_ERR, "get interface configuration: %m"); + exit(1); + } +#ifdef SIZE_RETURNED_IN_BUFFER + ifc.ifc_len = ioc.ic_len - sizeof(int); + ifc.ifc_buf = buf + sizeof(int); +#else /* ! SIZE_RETURNED_IN_BUFFER */ + ifc.ifc_len = ioc.ic_len; + ifc.ifc_buf = buf; +#endif /* SIZE_RETURNED_IN_BUFFER */ + +#else /* ! STREAMS_TLI */ + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) { + syslog(LOG_ERR, "get interface configuration: %m"); + exit(1); + } +#endif /* STREAMS_TLI */ + + for(n = ifc.ifc_len, ifr = ifc.ifc_req; n > 0; + ifr = (struct ifreq *)((char *)ifr + size)) { + size = sizeof(*ifr); + +#ifdef HAVE_VARIABLE_IFR_LENGTH + if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr)) + size += ifr->ifr_addr.sa_len - sizeof(struct sockaddr); +#endif + n -= size; + if (ifr->ifr_addr.sa_family != AF_INET) + continue; + ifreq = *ifr; +#ifdef STREAMS_TLI + ioc.ic_cmd = SIOCGIFFLAGS; + ioc.ic_timout = 0; + ioc.ic_dp = (caddr_t)&ifreq; + ioc.ic_len = sizeof(struct ifreq); + if(ioctl(vs, I_STR, &ioc)) { +#else /* ! STREAMS_TLI */ + if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) { +#endif /* STREAMS_TLI */ + syslog(LOG_ERR, "get interface flags: %m"); + continue; + } + if ((ifreq.ifr_flags & IFF_UP) == 0) + continue; + inter_list[i].flags = 0; + if (ifreq.ifr_flags & IFF_BROADCAST) + inter_list[i].flags |= INT_BROADCAST; +#if !defined(SUN_3_3_STINKS) +#if defined(SYS_HPUX) && (SYS_HPUX < 8) + if (ifreq.ifr_flags & IFF_LOCAL_LOOPBACK) +#else + if (ifreq.ifr_flags & IFF_LOOPBACK) +#endif + { + inter_list[i].flags |= INT_LOOPBACK; + if (loopback_interface == 0) + loopback_interface = &inter_list[i]; + } +#endif + +#ifdef STREAMS_TLI + ioc.ic_cmd = SIOCGIFADDR; + ioc.ic_timout = 0; + ioc.ic_dp = (caddr_t)&ifreq; + ioc.ic_len = sizeof(struct ifreq); + if(ioctl(vs, I_STR, &ioc)) { +#else /* ! STREAMS_TLI */ + if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) { +#endif /* STREAMS_TLI */ + syslog(LOG_ERR, "get interface addr: %m"); + continue; + } + + (void)strncpy(inter_list[i].name, ifreq.ifr_name, + sizeof(inter_list[i].name)); + inter_list[i].sin = *(struct sockaddr_in *)&ifreq.ifr_addr; + inter_list[i].sin.sin_family = AF_INET; + inter_list[i].sin.sin_port = port; + +#if defined(SUN_3_3_STINKS) + /* + * Oh, barf! I'm too disgusted to even explain this + */ + if (SRCADR(&inter_list[i].sin) == 0x7f000001) { + inter_list[i].flags |= INT_LOOPBACK; + if (loopback_interface == 0) + loopback_interface = &inter_list[i]; + } +#endif + if (inter_list[i].flags & INT_BROADCAST) { +#ifdef STREAMS_TLI + ioc.ic_cmd = SIOCGIFBRDADDR; + ioc.ic_timout = 0; + ioc.ic_dp = (caddr_t)&ifreq; + ioc.ic_len = sizeof(struct ifreq); + if(ioctl(vs, I_STR, &ioc)) { +#else /* ! STREAMS_TLI */ + if (ioctl(vs, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { +#endif /* STREAMS_TLI */ + syslog(LOG_ERR, "SIOCGIFBRDADDR fails"); + exit(1); + } +#ifndef ifr_broadaddr + inter_list[i].bcast = + *(struct sockaddr_in *)&ifreq.ifr_addr; +#else + inter_list[i].bcast = + *(struct sockaddr_in *)&ifreq.ifr_broadaddr; +#endif + inter_list[i].bcast.sin_family = AF_INET; + inter_list[i].bcast.sin_port = port; + } +#ifdef STREAMS_TLI + ioc.ic_cmd = SIOCGIFNETMASK; + ioc.ic_timout = 0; + ioc.ic_dp = (caddr_t)&ifreq; + ioc.ic_len = sizeof(struct ifreq); + if(ioctl(vs, I_STR, &ioc)) { +#else /* ! STREAMS_TLI */ + if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) { +#endif /* STREAMS_TLI */ + syslog(LOG_ERR, "SIOCGIFNETMASK fails"); + exit(1); + } + inter_list[i].mask = *(struct sockaddr_in *)&ifreq.ifr_addr; + + /* + * look for an already existing source interface address. If + * the machine has multiple point to point interfaces, then + * the local address may appear more than once. + */ + for (j=0; j < i; j++) + if (inter_list[j].sin.sin_addr.s_addr == + inter_list[i].sin.sin_addr.s_addr) { + break; + } + if (j == i) + i++; + } + close(vs); + ninterfaces = i; + + maxactivefd = 0; + FD_ZERO(&activefds); + + for (i = 0; i < ninterfaces; i++) { + inter_list[i].fd = open_socket(&inter_list[i].sin, + inter_list[i].flags & INT_BROADCAST); + } + + /* + * Blacklist all bound interface addresses + */ + resmask.sin_addr.s_addr = ~0L; + for (i = 1; i < ninterfaces; i++) + restrict(RESTRICT_FLAGS, &inter_list[i].sin, &resmask, + RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE); + + any_interface = &inter_list[0]; +#ifdef DEBUG + if (debug > 2) { + 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", + inet_ntoa((inter_list[i].sin.sin_addr))); + if(inter_list[i].flags & INT_BROADCAST) + printf(" bcast=%s,", + inet_ntoa((inter_list[i].bcast.sin_addr))); + printf(" mask=%s\n", + inet_ntoa((inter_list[i].mask.sin_addr))); + } + } +#endif + return ninterfaces; +} + + +/* + * io_setbclient - open the broadcast client sockets + */ +void +io_setbclient() +{ + int i; + + for (i = 1; i < ninterfaces; i++) { + if (!(inter_list[i].flags & INT_BROADCAST)) + continue; + if (inter_list[i].flags & INT_BCASTOPEN) + continue; +#ifdef SOLARIS + inter_list[i].bcast.sin_addr.s_addr = INADDR_ANY; +#endif + inter_list[i].bfd = open_socket(&inter_list[i].bcast, 0); + inter_list[i].flags |= INT_BCASTOPEN; + } +} + + +/* + * io_unsetbclient - close the broadcast client sockets + */ +void +io_unsetbclient() +{ + int i; + + for (i = 1; i < ninterfaces; i++) { + if (!(inter_list[i].flags & INT_BCASTOPEN)) + continue; + close_socket(inter_list[i].bfd); + inter_list[i].flags &= ~INT_BCASTOPEN; + } +} + + + +/* + * open_socket - open a socket, returning the file descriptor + */ +static int +open_socket(addr, bcast) + struct sockaddr_in *addr; + int bcast; +{ + int fd; + int on = 1, off = 0; + + /* create a datagram (UDP) socket */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed: %m"); + exit(1); + /*NOTREACHED*/ + } + + if (fd > maxactivefd) + maxactivefd = fd; + FD_SET(fd, &activefds); + + /* 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))) { + syslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails: %m"); + } + + /* + * bind the local address. + */ + if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) { + char buff[160]; + sprintf(buff, "bind() fd %d, family %d, port %d, addr %08x, bcast=%d fails: %%m", + fd, + addr->sin_family, + addr->sin_port, + addr->sin_addr.s_addr, + bcast); + syslog(LOG_ERR, buff); + exit(1); + } + +#ifdef HAVE_SIGNALED_IO + init_socket_sig(fd); +#else /* HAVE_SIGNALED_IO */ + + /* + * set non-blocking, + */ +#if defined(O_NONBLOCK) + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + syslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#else /* O_NONBLOCK */ +#if defined(FNDELAY) + if (fcntl(fd, F_SETFL, FNDELAY) < 0) { + syslog(LOG_ERR, "fcntl(FNDELAY) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#else /* FNDELAY */ +Need non blocking I/O +#endif /* FNDELAY */ +#endif /* O_NONBLOCK */ +#endif /* 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 (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (char *)&off, sizeof(off))) { + syslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m"); + } + + +#ifdef SO_BROADCAST + /* if this interface can support broadcast, set SO_BROADCAST */ + if (bcast) { + if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, + (char *)&on, sizeof(on))) { + syslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m"); + } + } +#endif + +#ifdef DEBUG + if (debug > 1) + printf("flags for fd %d: 0%o\n", fd, + fcntl(fd, F_GETFL, 0)); +#endif + + return fd; +} + + +/* + * closesocket - close a socket and remove from the activefd list + */ +static void +close_socket(fd) + int fd; +{ + int i, newmax; + + (void) close(fd); + FD_CLR(fd, &activefds); + + if (fd >= maxactivefd) { + newmax = 0; + for (i = 0; i < maxactivefd; i++) + if (FD_ISSET(i, &activefds)) + newmax = i; + maxactivefd = newmax; + } +} + + + +/* + * findbcastinter - find broadcast interface corresponding to address + */ +struct interface * +findbcastinter(addr) + struct sockaddr_in *addr; +{ +#ifdef SIOCGIFCONF + register int i; + register U_LONG netnum; + + netnum = NSRCADR(addr); + for (i = 1; i < ninterfaces; i++) { + if (!(inter_list[i].flags & INT_BROADCAST)) + continue; + if (NSRCADR(&inter_list[i].bcast) == netnum) + return &inter_list[i]; + if ((NSRCADR(&inter_list[i].sin) & NSRCADR(&inter_list[i].mask)) + == (netnum & NSRCADR(&inter_list[i].mask))) + return &inter_list[i]; + } +#endif + return any_interface; +} + + +/* XXX ELIMINATE getrecvbufs (almost) identical to ntpdate.c, ntptrace.c, ntp_io.c */ +/* + * getrecvbufs - get receive buffers which have data in them + * + * ***N.B. must be called with SIGIO blocked*** + */ +struct recvbuf * +getrecvbufs() +{ + struct recvbuf *rb; + +#ifdef DEBUG + if (debug > 4) + printf("getrecvbufs: %d handler interrupts, %d frames\n", + handler_calls, handler_pkts); +#endif + + if (full_recvbufs == 0) { +#ifdef DEBUG + if (debug > 4) + printf("getrecvbufs called, no action here\n"); +#endif + return (struct recvbuf *)0; /* nothing has arrived */ + } + + /* + * Get the fulllist chain and mark it empty + */ +#ifdef DEBUG + if (debug > 4) + printf("getrecvbufs returning %d buffers\n", full_recvbufs); +#endif + rb = beginlist; + fulllist = 0; + full_recvbufs = 0; + + /* + * Check to see if we're below the low water mark. + */ + if (free_recvbufs <= RECV_LOWAT) { + register struct recvbuf *buf; + register int i; + + if (total_recvbufs >= RECV_TOOMANY) + syslog(LOG_ERR, "too many recvbufs allocated (%d)", + total_recvbufs); + else { + buf = (struct recvbuf *) + emalloc(RECV_INC*sizeof(struct recvbuf)); + for (i = 0; i < RECV_INC; i++) { + buf->next = freelist; + freelist = buf; + buf++; + } + + free_recvbufs += RECV_INC; + total_recvbufs += RECV_INC; + lowater_additions++; + } + } + + /* + * Return the chain + */ + return rb; +} + + +/* XXX ELIMINATE freerecvbuf (almost) identical to ntpdate.c, ntptrace.c, ntp_io.c */ +/* + * freerecvbuf - make a single recvbuf available for reuse + */ +void +freerecvbuf(rb) + struct recvbuf *rb; +{ + BLOCKIO(); + rb->next = freelist; + freelist = rb; + free_recvbufs++; + UNBLOCKIO(); +} + + +/* 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(dest, inter, pkt, len) + struct sockaddr_in *dest; + struct interface *inter; + struct pkt *pkt; + int len; +{ + int cc, slot; + /* + * Send error cache. Empty slots have port == 0 + * Set ERRORCACHESIZE to 0 to disable + */ + struct cache { + u_short port; + struct in_addr addr; + }; +#ifndef ERRORCACHESIZE +#define ERRORCACHESIZE 8 +#endif +#if ERRORCACHESIZE > 0 + static struct cache badaddrs[ERRORCACHESIZE]; +#else +#define badaddrs ((struct cache *)0) /* Only used in empty loops! */ +#endif + +#ifdef DEBUG + if (debug) + printf("sendpkt(%s, %s, %d)\n", ntoa(dest), + ntoa(&inter->sin), len); +#endif + + for (slot = ERRORCACHESIZE; --slot >= 0; ) + if (badaddrs[slot].port == dest->sin_port && + badaddrs[slot].addr.s_addr == dest->sin_addr.s_addr) + break; + + cc = sendto(inter->fd, (char *)pkt, len, 0, (struct sockaddr *)dest, + sizeof(struct sockaddr_in)); + if (cc == -1) { + inter->notsent++; + packets_notsent++; + if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0) { + /* + * Remember this, if there's an empty slot + */ + for (slot = ERRORCACHESIZE; --slot >= 0; ) + if (badaddrs[slot].port == 0) { + badaddrs[slot].port = dest->sin_port; + badaddrs[slot].addr = dest->sin_addr; + break; + } + syslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + } + } else { + inter->sent++; + packets_sent++; + /* + * He's not bad any more + */ + if (slot >= 0) + badaddrs[slot].port = 0; + } +} + + +/* + * input_handler - receive packets asynchronously + */ +void +input_handler(cts) + l_fp *cts; +{ + register int i, n; + register struct recvbuf *rb; + register int doing; + register int fd; + struct timeval tvzero; + int fromlen; + l_fp ts; + fd_set fds; + int first = 1; + + handler_calls++; + ts = *cts; + + /* + * Do a poll to see who has data + */ +again: + fds = activefds; + tvzero.tv_sec = tvzero.tv_usec = 0; + n = select(maxactivefd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero); + + /* + * If nothing to do, just return. If an error occurred, complain + * and return. If we've got some, freeze a timestamp. + */ + if (n == 0) + return; + else if (n == -1) { + syslog(LOG_ERR, "select() error: %m"); + return; + } + if (!first)get_systime(&ts); + first = 0; + handler_pkts += n; + +#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_recvbufs == 0) { + char buf[RX_BUFF_SIZE]; + + (void) read(fd, buf, sizeof buf); + packets_dropped++; + continue; + } + + rb = freelist; + freelist = rb->next; + free_recvbufs--; + + 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, i); + + if (rb->recv_length == -1) { + syslog(LOG_ERR, "clock read: %m"); + rb->next = freelist; + freelist = rb; + free_recvbufs++; + continue; + } + + /* + * 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->recv_time = ts; + rb->receiver = rp->clock_recv; + + if (fulllist == 0) { + beginlist = rb; + rb->next = 0; + } else { + rb->next = fulllist->next; + fulllist->next = rb; + } + fulllist = rb; + full_recvbufs++; + + rp->recvcount++; + packets_received++; + } + } + } +#endif + + /* + * 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_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. + */ +#ifdef UDP_WILDCARD_DELIVERY +/* + * these guys manage to put properly addressed packets into the wildcard queue + */ + if (free_recvbufs == 0) { +#else + if (i == 0 || free_recvbufs == 0) { +#endif + char buf[RX_BUFF_SIZE]; + +#ifndef UDP_WILDCARD_DELIVERY + (void) read(fd, buf, sizeof buf); +#else + fromlen = 0; + (void) recvfrom(fd, buf, sizeof(buf), 0, + (struct sockaddr *)0, + &fromlen); +#endif + + if (i == 0) + packets_ignored++; + else + packets_dropped++; + continue; + } + + rb = freelist; + freelist = rb->next; + free_recvbufs--; + + fromlen = sizeof(struct sockaddr_in); + rb->recv_length = recvfrom(fd, + (char *)&rb->recv_space, + sizeof(rb->recv_space), 0, + (struct sockaddr *)&rb->recv_srcadr, + &fromlen); + if (rb->recv_length == -1) { + syslog(LOG_ERR, "recvfrom: %m"); + rb->next = freelist; + freelist = rb; + free_recvbufs++; +#ifdef DEBUG + if (debug) + printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd); +#endif + continue; + } +#ifdef DEBUG + if (debug) + printf("input_handler: fd=%d length %d\n", fd, rb->recv_length); +#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->recv_time = ts; + rb->receiver = receive; + + + if (fulllist == 0) { + beginlist = rb; + rb->next = 0; + } else { + rb->next = fulllist->next; + fulllist->next = rb; + } + fulllist = rb; + full_recvbufs++; + + inter_list[i].received++; + packets_received++; + } + } + } + /* + * Done everything from that select. Poll again. + */ + goto again; +} + + +/* + * findinterface - utility used by other modules to find an interface + * given an address. + */ +struct interface * +findinterface(addr) + struct sockaddr_in *addr; +{ + register int i; + register U_LONG saddr; + + /* + * Just match the address portion. + */ + saddr = addr->sin_addr.s_addr; + for (i = 0; i < ninterfaces; i++) { + if (inter_list[i].sin.sin_addr.s_addr == saddr) + return &inter_list[i]; + } + return (struct interface *)0; +} + + +/* + * io_clr_stats - clear I/O module statistics + */ +void +io_clr_stats() +{ + 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(rio) + 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; + + if (rio->fd > maxactivefd) + maxactivefd = rio->fd; + FD_SET(rio->fd, &activefds); + UNBLOCKIO(); + return 1; +} + +/* + * io_addclock - add a reference clock to the list and arrange that we + * get SIGIO interrupts from it. + */ +int +io_addclock(rio) + 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)) { + UNBLOCKIO(); + return 0; + } +#endif + + if (rio->fd > maxactivefd) + maxactivefd = rio->fd; + FD_SET(rio->fd, &activefds); + + UNBLOCKIO(); + return 1; +} + +/* + * io_closeclock - close the clock in the I/O structure given + */ +void +io_closeclock(rio) + 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. + */ + syslog(LOG_ERR, + "internal error: refclockio structure not found"); + return; + } + } + + /* + * Close the descriptor. close_socket does the right thing despite + * the misnomer. + */ + close_socket(rio->fd); +} +#endif /* REFCLOCK */ + +/* + * SIGPOLL and SIGIO ROUTINES. + */ +#ifdef HAVE_SIGNALED_IO +/* + * Some systems (MOST) define SIGPOLL==SIGIO others SIGIO==SIGPOLL a few + * have seperate SIGIO and SIGPOLL signals. This code checks for the + * SIGIO==SIGPOLL case at compile time. + * Do not defined USE_SIGPOLL or USE_SIGIO. + * these are interal only to ntp_io.c! + */ +#if defined(USE_SIGPOLL) +#undef USE_SIGPOLL +#endif +#if defined(USE_SIGIO) +#undef USE_SIGIO +#endif + +#if defined(USE_TTY_SIGPOLL)||defined(USE_UDP_SIGPOLL) +#define USE_SIGPOLL +#endif + +#if !defined(USE_TTY_SIGPOLL)||!defined(USE_UDP_SIGPOLL) +#define USE_SIGIO +#endif + +#if defined(USE_SIGIO)&&defined(USE_SIGPOLL) +#if SIGIO==SIGPOLL +#define USE_SIGIO +#undef USE_SIGPOLL +#endif /* SIGIO==SIGPOLL */ +#endif /* USE_SIGIO && USE_SIGIO */ + + +/* + * TTY instialzation routeins. + */ +#ifndef USE_TTY_SIGPOLL +/* + * Spical cases first! + */ +#if defined(SYS_HPUX) +#define CLOCK_DONE +static int +init_clock_sig(rio) + struct refclockio *rio; +{ + int pgrp, on = 1; + + pgrp = getpid(); + if (ioctl(rio->fd, FIOSSAIOOWN, (char *)&pgrp) == -1) { + syslog(LOG_ERR, "ioctl(FIOSSAIOOWN) fails for clock I/O: %m"); + exit(1); + /*NOTREACHED*/ + } + + /* + * set non-blocking, async I/O on the descriptor + */ + if (ioctl(rio->fd, FIOSNBIO, (char *)&on) == -1) { + syslog(LOG_ERR, "ioctl(FIOSNBIO) fails for clock I/O: %m"); + exit(1); + /*NOTREACHED*/ + } + + if (ioctl(rio->fd, FIOSSAIOSTAT, (char *)&on) == -1) { + syslog(LOG_ERR, "ioctl(FIOSSAIOSTAT) fails for clock I/O: %m"); + exit(1); + /*NOTREACHED*/ + } + return 0; +} +#endif /* SYS_HPUX */ +#if defined(SYS_AIX)&&!defined(_BSD) +/* + * SYSV compatibility mode under AIX. + */ +#define CLOCK_DONE +static int +init_clock_sig(rio) + struct refclockio *rio; +{ + int pgrp, on = 1; + + if (ioctl(rio->fd, FIOASYNC, (char *)&on) == -1) { + syslog(LOG_ERR, "ioctl(FIOASYNC) fails for clock I/O: %m"); + return 1; + } + pgrp = -getpid(); + if (ioctl(rio->fd, FIOSETOWN, (char*)&pgrp) == -1) { + syslog(LOG_ERR, "ioctl(FIOSETOWN) fails for clock I/O: %m"); + return 1; + } + + if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0) { + syslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m"); + return 1; + } + return 0; +} +#endif /* AIX && !BSD */ +#ifndef CLOCK_DONE +static int +init_clock_sig(rio) + struct refclockio *rio; +{ + if (fcntl(rio->fd, F_SETOWN, getpid()) == -1) { + syslog(LOG_ERR, "fcntl(F_SETOWN) fails for clock I/O: %m"); + return 1; + } + + if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0) { + syslog(LOG_ERR, + "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m"); + return 1; + } + return 0; +} +#endif /* CLOCK_DONE */ +#else /* !USE_TTY_SIGPOLL */ +int +static init_clock_sig(rio) + struct refclockio *rio; +{ + if (ioctl(rio->fd, I_SETSIG, S_INPUT) < 0) { + syslog(LOG_ERR, + "ioctl(I_SETSIG, S_INPUT) fails for clock I/O: %m"); + return 1; + } + return 0; +} +#endif /* !USE_TTY_SIGPOLL */ + + + +#ifndef USE_UDP_SIGPOLL +/* + * Socket SIGPOLL initialization routines. + * Special cases first! + */ +#if defined(SYS_HPUX) || defined(SYS_LINUX) +#define SOCKET_DONE +static void +init_socket_sig(fd) + int fd; +{ + int pgrp, on = 1; + + /* + * Big difference here for HP-UX ... why can't life be easy ? + */ + if (ioctl(fd, FIOSNBIO, (char *)&on) == -1) { + syslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m"); + exit(1); + /*NOTREACHED*/ + } + + if (ioctl(fd, FIOASYNC, (char *)&on) == -1) { + syslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } + +#if (SYS_HPUX > 7) + pgrp = getpid(); +#else + pgrp = -getpid(); +#endif + if (ioctl(fd, SIOCSPGRP, (char *)&pgrp) == -1) { + syslog(LOG_ERR, "ioctl(SIOCSPGRP) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +} +#endif /* SYS_HPUX */ +#if defined(SYS_AIX)&&!defined(_BSD) +/* + * SYSV compatibility mod under AIX + */ +#define SOCKET_DONE +static void +init_socket_sig(fd) + int fd; +{ + int pgrp, on = 1; + + if (ioctl(fd, FIOASYNC, (char *)&on) == -1) { + syslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } + pgrp = -getpid(); + if (ioctl(fd, FIOSETOWN, (char*)&pgrp) == -1) { + syslog(LOG_ERR, "ioctl(FIOSETOWN) fails: %m"); + exit(1); + /*NOTREACHED*/ + } + + if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) { + syslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +} +#endif /* AIX && !BSD */ +#if defined(UDP_BACKWARDS_SETOWN) +/* + * SunOS 3.5 and Ultirx 2.0 + */ +#define SOCKET_DONE +static void +init_socket_sig(fd) + int fd; +{ + /* + * The way Sun did it as recently as SunOS 3.5. Only + * in the case of sockets, of course, just to confuse + * the issue. Don't they even bother to test the stuff + * they send out? Ibid for Ultrix 2.0 + */ + if (fcntl(fd, F_SETOWN, -getpid()) == -1) + { + syslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m"); + exit(1); + } + /* + * set non-blocking, async I/O on the descriptor + */ + if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) { + syslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +} +#endif /* UDP_BACKWARDS_SETOWN */ +#ifndef SOCKET_DONE +static void +init_socket_sig(fd) + int fd; +{ + if (fcntl(fd, F_SETOWN, getpid()) == -1) + { + syslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m"); + exit(1); + } + /* + * set non-blocking, async I/O on the descriptor + */ + if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) { + syslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +} +#endif /* SOCKET_DONE */ +#else /* !USE_UDP_SIGPOLL */ +static void +init_socket_sig(fd) + int fd; +{ + if (ioctl(fd, I_SETSIG, S_INPUT) < 0) { + syslog(LOG_ERR, + "ioctl(I_SETSIG, S_INPUT) fails for socket I/O: %m"); + exit(1); + } +} +#endif /* USE_UDP_SIGPOLL */ + +static RETSIGTYPE +sigio_handler(sig) +int sig; +{ + l_fp ts; + +#ifdef SYS_SVR4 + /* This should not be necessary for a signal previously set with + * sigset(). + */ +# if defined(USE_SIGIO) + (void) sigset(SIGIO, sigio_handler); +# endif +# if defined(USE_SIGPOLL) + (void) sigset(SIGPOLL, sigio_handler); +# endif +#endif /* SYS_SVR4 */ + + get_systime(&ts); + (void)input_handler(&ts); +} + +/* + * Signal support routines. + */ +#ifdef NTP_POSIX_SOURCE +static void +set_signal() +{ + int n; + struct sigaction vec; + + sigemptyset(&vec.sa_mask); + +#ifdef USE_SIGIO + sigaddset(&vec.sa_mask, SIGIO); +#endif +#ifdef USE_SIGPOLL + sigaddset(&vec.sa_mask, SIGPOLL); +#endif + vec.sa_flags = 0; + +#if defined(USE_SIGIO) + vec.sa_handler = sigio_handler; + + while (1) { + n = sigaction(SIGIO, &vec, NULL); + if (n == -1 && errno == EINTR) continue; + break; + } + + if (n == -1) { + perror("sigaction"); + exit(1); + } +#endif +#if defined(USE_SIGPOLL) + vec.sa_handler = sigio_handler; + + while (1) { + n = sigaction(SIGPOLL, &vec, NULL); + if (n == -1 && errno == EINTR) continue; + break; + } + + if (n == -1) { + perror("sigaction"); + exit(1); + } +#endif +} + +void +block_io_and_alarm() +{ + sigset_t set; + + sigemptyset(&set); +#if defined(USE_SIGIO) + sigaddset(&set, SIGIO); +#endif +#if defined(USE_SIGPOLL) + sigaddset(&set, SIGPOLL); +#endif + sigprocmask(SIG_BLOCK, &set, NULL); +} + +static void +block_sigio() +{ + sigset_t set; + + sigemptyset(&set); +#if defined(USE_SIGIO) + sigaddset(&set, SIGIO); +#endif +#if defined(USE_SIGPOLL) + sigaddset(&set, SIGPOLL); +#endif + sigaddset(&set, SIGALRM); + sigprocmask(SIG_BLOCK, &set, NULL); +} + +void +unblock_io_and_alarm() +{ + sigset_t unset; + + sigemptyset(&unset); + +#if defined(USE_SIGIO) + sigaddset(&unset, SIGIO); +#endif +#if defined(USE_SIGPOLL) + sigaddset(&unset, SIGPOLL); +#endif + sigaddset(&unset, SIGALRM); + sigprocmask(SIG_UNBLOCK, &unset, NULL); +} + +static +void +unblock_sigio() +{ + sigset_t unset; + + sigemptyset(&unset); + +#if defined(USE_SIGIO) + sigaddset(&unset, SIGIO); +#endif +#if defined(USE_SIGPOLL) + sigaddset(&unset, SIGPOLL); +#endif + sigprocmask(SIG_UNBLOCK, &unset, NULL); +} + +void +wait_for_signal() +{ + sigset_t old; + + sigprocmask(SIG_UNBLOCK, NULL, &old); + +#if defined(USE_SIGIO) + sigdelset(&old, SIGIO); +#endif +#if defined(USE_SIGPOLL) + sigdelset(&old, SIGPOLL); +#endif + sigdelset(&old, SIGALRM); + + sigsuspend(&old); +} + +#else +/* + * Must be an old bsd system. + * We assume there is no SIGPOLL. + */ + +void +block_io_and_alarm() +{ + int mask; + + mask = sigmask(SIGIO)|sigmask(SIGALRM); + (void)sigblock(mask); +} + +void +block_sigio() +{ + int mask; + + mask = sigmask(SIGIO); + (void)sigblock(mask); +} + +static void +set_signal() +{ + (void) signal_no_reset(SIGIO, sigio_handler); +} + +void +unblock_io_and_alarm() +{ + int mask, omask; + + mask = sigmask(SIGIO)|sigmask(SIGALRM); + omask = sigblock(0); + omask &= ~mask; + (void)sigsetmask(omask); +} + +void +unblock_sigio() +{ + int mask, omask; + + mask = sigmask(SIGIO); + omask = sigblock(0); + omask &= ~mask; + (void)sigsetmask(omask); +} + +void +wait_for_signal() +{ + int mask, omask; + + mask = sigmask(SIGIO)|sigmask(SIGALRM); + omask = sigblock(0); + omask &= ~mask; + sigpause(omask); +} +#endif /* NTP_POSIX_SOURCE */ +#endif /* HAVE_SIGNALED_IO */ + diff --git a/contrib/xntpd/xntpd/ntp_leap.c b/contrib/xntpd/xntpd/ntp_leap.c new file mode 100644 index 0000000000..aadbb09dc3 --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_leap.c @@ -0,0 +1,315 @@ +/* ntp_leap.c,v 3.1 1993/07/06 01:11:18 jbj Exp + * ntp_leap - maintain leap bits and take action when a leap occurs + */ +#include + +#include "ntpd.h" +#include "ntp_stdlib.h" + +/* + * This module is devoted to maintaining the leap bits and taking + * action when a leap second occurs. It probably has bugs since + * a leap second has never occurred to excercise the code. + * + * The code does two things when a leap second occurs. It first + * steps the clock one second in the appropriate direction. It + * then informs the reference clock code, if compiled in, that the + * leap second has occured so that any clocks which need to disable + * themselves can do so. This is done within the first few seconds + * after midnight, UTC. + * + * The code maintains two variables which may be written externally, + * leap_warning and leap_indicator. Leap_warning can be written + * any time in the month preceeding a leap second. 24 hours before + * the leap is to occur, leap_warning's contents are copied to + * leap_indicator. The latter is used by reference clocks to set + * their leap bits. + * + * The module normally maintains a timer which is arranged to expire + * just after 0000Z one day before the leap. On the day a leap might + * occur the interrupt is aimed at 2200Z and every 5 minutes thereafter + * until 1200Z to see if the leap bits appear. + */ + +/* + * The leap indicator and leap warning flags. Set by control messages + */ +u_char leap_indicator; +u_char leap_warning; +u_char leap_mask; /* set on day before a potential leap */ +/* + * Timer. The timer code imports this so it can call us prior to + * calling out any pending transmits. + */ +U_LONG leap_timer; + +/* + * We don't want to do anything drastic if the leap function is handled + * by the kernel. + */ +extern int pll_control; /* set nonzero if kernel pll in uss */ + +/* + * Internal leap bits. If we see leap bits set during the last + * hour we set these. + */ +u_char leapbits; + +/* + * Constants. + */ +#define OKAYTOSETWARNING (31*24*60*60) +#define DAYBEFORE (24*60*60) +#define TWOHOURSBEFORE (2*60*60) +#define FIVEMINUTES (5*60) +#define ONEMINUTE (60) + +/* + * Imported from the timer module. + */ +extern U_LONG current_time; + + +/* + * Some statistics counters + */ +U_LONG leap_processcalls; /* calls to leap_process */ +U_LONG leap_notclose; /* leap found to be a LONG time from now */ +U_LONG leap_monthofleap; /* in the month of a leap */ +U_LONG leap_dayofleap; /* This is the day of the leap */ +U_LONG leap_hoursfromleap; /* only 2 hours from leap */ +U_LONG leap_happened; /* leap process saw the leap */ + +/* + * Imported from the main module + */ +extern int debug; + + +static void setnexttimeout P((U_LONG)); + +/* + * init_leap - initialize the leap module's data. + */ +void +init_leap() +{ + /* + * Zero the indicators. Schedule an event for just after + * initialization so we can sort things out. + */ + leap_indicator = leap_warning = leap_mask = 0; + leap_timer = 1< OKAYTOSETWARNING) { + if (leaplast < ONEMINUTE) { + /* + * The golden moment! See if there's anything + * to do. + */ + leap_happened++; + bits = 0; + leap_mask = 0; + if (leap_indicator != 0) + bits = leap_indicator; + else if (leapbits != 0) + bits = leapbits; + + if (bits != 0 && !pll_control) { + l_fp tmp; + + /* + * Step the clock 1 second in the proper + * direction. + */ + if (bits == LEAP_DELSECOND) + tmp.l_i = 1; + else + tmp.l_i = -1; + tmp.l_uf = 0; + + step_systime(&tmp); +#ifdef SLEWALWAYS + syslog(LOG_NOTICE, + "leap second occured, slewed time %s 1 second", + tmp.l_i > 0 ? "forward" : "back"); +#else + syslog(LOG_NOTICE, + "leap second occured, stepped time %s 1 second", + tmp.l_i > 0 ? "forward" : "back"); +#endif + } + } else { + leap_notclose++; + } + leap_warning = 0; + } else { + if (leapnext > DAYBEFORE) + leap_monthofleap++; + else if (leapnext > TWOHOURSBEFORE) + leap_dayofleap++; + else + leap_hoursfromleap++; + } + + if (leapnext > DAYBEFORE) { + leap_indicator = 0; + leapbits = 0; + /* + * Berkeley's setitimer call does result in alarm + * signal drift despite rumours to the contrary. + * Schedule an event no more than 24 hours into + * the future to allow the event time to be + * recomputed. + */ + if ((leapnext - DAYBEFORE) >= DAYBEFORE) + setnexttimeout((U_LONG)DAYBEFORE); + else + setnexttimeout(leapnext - DAYBEFORE); + return; + } + + /* + * Here we're in the day of the leap. Set the leap indicator + * bits from the warning, if necessary. + */ + if (leap_indicator == 0 && leap_warning != 0) + leap_indicator = leap_warning; + leap_mask = LEAP_NOTINSYNC; + if (leapnext > TWOHOURSBEFORE) { + leapbits = 0; + setnexttimeout(leapnext - TWOHOURSBEFORE); + return; + } + + /* + * Here we're in the final 2 hours. If sys_leap is set, set + * leapbits to it. + */ + if (sys_leap == LEAP_ADDSECOND || sys_leap == LEAP_DELSECOND) + leapbits = sys_leap; + setnexttimeout((leapnext > FIVEMINUTES) ? FIVEMINUTES : leapnext); +} + + +/* + * setnexttimeout - set the next leap alarm + */ +static void +setnexttimeout(secs) + U_LONG secs; +{ + /* + * We try to aim the time out at between 1 and 1+(1< OKAYTOSETWARNING) + i = 1; + + if (indicator != ~0) + if (leapnext > DAYBEFORE) + i = 1; + + if (i) { + syslog(LOG_ERR, + "attempt to set leap bits at unlikely time of month"); + return 0; + } + + if (warning != ~0) + leap_warning = warning; + + if (indicator != ~0) { + if (indicator == LEAP_NOWARNING) { + leap_warning = LEAP_NOWARNING; + } + leap_indicator = indicator; + } + return 1; +} + +/* + * leap_actual + * + * calculate leap value - pass arg through of no local + * configuration. Otherwise ise local configuration + * (only used to cope with broken time servers and + * broken refclocks) + * + * Mapping of leap_indicator: + * LEAP_NOWARNING + * pass peer value to sys_leap - usual operation + * LEAP_ADD/DEL_SECOND + * pass LEAP_ADD/DEL_SECOND to sys_leap + * LEAP_NOTINSYNC + * pass LEAP_NOWARNING to sys_leap - effectively ignores leap + */ +/* there seems to be a bug in the IRIX 4 compiler which prevents + u_char from beeing used in prototyped functions + AIX also suffers from this. + So give up and define it terms of int. +*/ +int +leap_actual(l) + int l ; +{ + if (leap_indicator != LEAP_NOWARNING) { + if (leap_indicator == LEAP_NOTINSYNC) + return LEAP_NOWARNING; + else + return leap_indicator; + } else { + return l; + } +} + diff --git a/contrib/xntpd/xntpd/ntp_loopfilter.c b/contrib/xntpd/xntpd/ntp_loopfilter.c new file mode 100644 index 0000000000..d74da9956e --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_loopfilter.c @@ -0,0 +1,944 @@ +/* + * ntp_loopfilter.c - implements the NTP loop filter algorithm + */ + +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#if defined(KERNEL_PLL) +#include "ntp_timex.h" +#endif /* KERNEL_PLL */ +#include "ntp_unixtime.h" + +#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS) +#include +#include "ntp_refclock.h" +#endif /* PPS || PPSCLK || PPSPPS */ + +#if defined(PPSCLK) || defined(PPSPPS) +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(STREAM) +#include +#include +#if defined(PPSCLK) +#include +#endif /* PPSCLK */ +#endif /* STREAM */ + +#endif /* PPSCLK || PPSPPS */ + +#if defined(PPSPPS) +#include +#endif /* PPSPPS */ + +#include "ntp_stdlib.h" + +#ifdef KERNEL_PLL +#ifndef SYS_ntp_adjtime +#define SYS_ntp_adjtime NTP_SYSCALL_ADJ +#endif +#endif /* KERNEL_PLL */ + +/* + * The loop filter is implemented in slavish adherence to the + * specification (Section 5), except that for consistency we + * mostly carry the quantities in the same units as appendix G. + * + * Note that the long values below are the fractional portion of + * a long fixed-point value. This limits these values to +-0.5 + * seconds. When adjustments are capped inside this range (see + * CLOCK_MAX_{I,F}) both the clock_adjust and the compliance + * registers should be fine. (When the compliance is above 16, it + * will at most accumulate 2**CLOCK_MULT times the maximum offset, + * which means it fits in a s_fp.) + * + * The skew compensation is a special case. In version 2, it was + * kept in ms/4s (i.e., CLOCK_FREQ was 10). In version 3 (Section 5) + * it seems to be 2**-16ms/4s in a s_fp for a maximum of +-125ppm + * (stated maximum 100ppm). Since this seems about to change to a + * larger range, it will be kept in units of 2**-20 (CLOCK_DSCALE) + * in an s_fp (mainly because that's nearly the same as parts per + * million). Note that this is ``seconds per second'', whereas a + * clock adjustment is a 32-bit fraction of a second to be applied + * every 2**CLOCK_ADJ seconds; to find it, shift the drift right by + * (CLOCK_DSCALE-16-CLOCK_ADJ). When updating the drift, on the other + * hand, the CLOCK_FREQ factor from the spec assumes the value to be + * in ``seconds per 4 seconds''; to get our units, CLOCK_ADJ must be + * added to the shift. + */ + +/* + * Macro to compute log2(). We don't want to to this very often, but + * needs what must. + */ +#define LOG2(r, t) \ + do { \ + LONG x = t; \ + r = 0; \ + while(x >> 1) \ + r++; \ + } + +#define RSH_DRIFT_TO_FRAC (CLOCK_DSCALE - 16) +#define RSH_DRIFT_TO_ADJ (RSH_DRIFT_TO_FRAC - CLOCK_ADJ) +#define RSH_FRAC_TO_FREQ (CLOCK_FREQ + CLOCK_ADJ - RSH_DRIFT_TO_FRAC) + +/* + * Imported from the ntp_proto module + */ +extern u_char sys_stratum; +extern s_fp sys_rootdelay; +extern u_fp sys_rootdispersion; +extern s_char sys_precision; + + l_fp last_offset; /* last adjustment done */ +static LONG clock_adjust; /* clock adjust register (fraction only) */ + + s_fp drift_comp; /* drift compensation register */ +static s_fp max_comp; /* drift limit imposed by max host clock slew */ + + int time_constant; /* log2 of time constant (0 .. 4) */ +static U_LONG tcadj_time; /* last time-constant adjust time */ + + U_LONG watchdog_timer; /* watchdog timer, in seconds */ +static int first_adjustment; /* set to 1 if waiting for first adjustment */ +static int tc_counter; /* time-constant hold counter */ + + int pll_control; /* set nonzero if pll implemented in kernel */ + int pps_control; /* set nonzero if pps signal valid */ +static l_fp pps_delay; /* pps tuning offset */ + U_LONG pps_update; /* last pps update time */ + int fdpps = -1; /* pps file descriptor */ + +#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS) +/* + * This module has support for a 1-pps signal to fine-tune the local + * clock. The signal is optional; when present and operating within + * given tolerances in frequency and jitter, it is used to discipline + * the local clock. In order for this to work, the local clock must be + * set to within +-500 ms by another means, such as a radio clock or + * NTP itself. The 1-pps signal is connected via a serial port and + * gadget box consisting of a one-shot and EIA level-converter. When + * operated at 38.4 kbps with a SPARCstation IPC, this arrangement has a + * worst-case jitter less than 26 us. The pps delay configuration + * declaration can be used to compensate for miscellaneous uart and + * os delays. Allow about 247 us for uart delays at 38400 bps and + * -1 ms for SunOS streams nonsense. + */ + +/* + * A really messy way to map an integer baud rate to the system baud rate. + * There should be a better way. + */ +#define SYS_BAUD(i) \ + ( i == 38400 ? B38400 : \ + ( i == 19200 ? B19200 : \ + ( i == 9600 ? B9600 : \ + ( i == 4800 ? B4800 : \ + ( i == 2400 ? B2400 : \ + ( i == 1200 ? B1200 : \ + ( i == 600 ? B600 : \ + ( i == 300 ? B300 : 0 )))))))) + +#define PPS_BAUD B38400 /* default serial port speed */ +#define PPS_MAXAGE 120 /* seconds after which we disbelieve pps */ +#define PPS_MAXUPDATE 600 /* seconds after which we disbelieve timecode */ +#define PPS_DEV "/dev/pps" /* pps port */ +#define PPS_FAC 3 /* pps shift (log2 trimmed samples) */ +#define NPPS 12 /* pps filter size (1<> 1) + (tsf_maxslew >> 2)); + if ((max_comp >> RSH_DRIFT_TO_ADJ) > tsf_limit) + max_comp = tsf_limit << RSH_DRIFT_TO_ADJ; + + pps_control = 0; +#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS) +#if defined(PPSCLK) + pps_baud = PPS_BAUD; +#endif /* PPSCLK */ + pps_delay.l_i = 0; + pps_delay.l_f = 0; + pps_time = pps_update = 0; + nsamples = 0; +#if defined(PPSCLK) + + /* + * Open pps serial port. We don't care if the serial port comes + * up; if not, we just use the timecode. Therefore, if anything + * goes wrong, just reclaim the resources and continue. + */ + fd232 = open(PPS_DEV, O_RDONLY); + if (fd232 == -1) { + syslog(LOG_ERR, "loopfilter: open of %s: %m", PPS_DEV); + return; + } + +#if !defined(HPUXGADGET) /* dedicated to Ken Stone */ +#if defined(HAVE_SYSV_TTYS) + /* + * System V serial line parameters (termio interface) + */ + PPSCLK SUPPORT NOT AVAILABLE IN TERMIO INTERFACE +#endif /* HAVE_SYSV_TTYS */ +#if defined(STREAM) + /* + * POSIX/STREAMS serial line parameters (termios interface) + * + * The PPSCLK option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the tty_clk streams module and SunOS 4.1.1 or + * later. + */ + { struct termios ttyb, *ttyp; + + ttyp = &ttyb; + if (tcgetattr(fd232, ttyp) < 0) { + syslog(LOG_ERR, + "loopfilter: tcgetattr(%s): %m", PPS_DEV); + goto screwed; + } + ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL; + ttyp->c_oflag = 0; + ttyp->c_cflag = PPS_BAUD|CS8|CLOCAL|CREAD; + ttyp->c_lflag = ICANON; + ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; + if (tcsetattr(fd232, TCSANOW, ttyp) < 0) { + syslog(LOG_ERR, + "loopfilter: tcsetattr(%s): %m", PPS_DEV); + goto screwed; + } + if (tcflush(fd232, TCIOFLUSH) < 0) { + syslog(LOG_ERR, + "loopfilter: tcflush(%s): %m", PPS_DEV); + goto screwed; + } + while (ioctl(fd232, I_POP, 0 ) >= 0) ; + if (ioctl(fd232, I_PUSH, "clk") < 0) { + syslog(LOG_ERR, + "loopfilter: ioctl(%s, I_PUSH, clk): %m", PPS_DEV); + goto screwed; + } + if (ioctl(fd232, CLK_SETSTR, PPS_XCPT) < 0) { + syslog(LOG_ERR, + "loopfilter: ioctl(%s, CLK_SETSTR, PPS_XCPT): %m", PPS_DEV); + goto screwed; + } + } +#endif /* STREAM */ +#if defined(HAVE_BSD_TTYS) + /* + * 4.3bsd serial line parameters (sgttyb interface) + * + * The PPSCLK option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the tty_clk line discipline and 4.3bsd or later. + */ + { struct sgttyb ttyb; + int ldisc = CLKLDISC; + + if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { + syslog(LOG_ERR, + "loopfilter: ioctl(%s, TIOCGETP): %m", PPS_DEV); + goto screwed; + } + ttyb.sg_ispeed = ttyb.sg_ospeed = PPS_BAUD; + ttyb.sg_erase = ttyb.sg_kill = '\r'; + ttyb.sg_flags = RAW; + if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { + syslog(LOG_ERR, + "loopfilter: ioctl(%s, TIOCSETP): %m", PPS_DEV); + goto screwed; + } + if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { + syslog(LOG_ERR, + "loopfilter: ioctl(%s, TIOCSETD): %m", PPS_DEV); + goto screwed; + } + } +#endif /* HAVE_BSD_TTYS */ + fdpps = fd232; +#endif /* HPUXGADGET */ + + /* + * Insert in device list. + */ + io.clock_recv = pps_receive; + io.srcclock = (caddr_t)NULL; + io.datalen = 0; + io.fd = fdpps; +#if defined(HPUXGADGET) + if (!io_addclock_simple(&io)) +#else + if (!io_addclock(&io)) +#endif /* HPUXGADGET */ + goto screwed; + return; + + /* + * Something broke. Reclaim resources. + */ +screwed: + (void)close(fdpps); + return; +#endif /* PPSCLK */ +#endif /* PPS || PPSCLK || PPSPPS */ +} + +/* + * local_clock - the NTP logical clock loop filter. Returns 1 if the + * clock was stepped, 0 if it was slewed and -1 if it is + * hopeless. + */ +int +local_clock(fp_offset, peer) + l_fp *fp_offset; /* best offset estimate */ + struct peer *peer; /* from peer - for messages */ +{ + register LONG offset; + register U_LONG tmp_ui; + register U_LONG tmp_uf; + register LONG tmp; + int isneg; +#if defined(KERNEL_PLL) + struct timex ntv; +#endif /* KERNEL_PLL */ + +#ifdef DEBUG + if (debug > 1) + printf("local_clock(%s, %s)\n", lfptoa(fp_offset, 9), + ntoa(&peer->srcadr)); +#endif + + /* + * Take the absolute value of the offset + */ + tmp_ui = fp_offset->l_ui; + tmp_uf = fp_offset->l_uf; + if (M_ISNEG(tmp_ui, tmp_uf)) { + M_NEG(tmp_ui, tmp_uf); + isneg = 1; + } else + isneg = 0; + + /* + * If the clock is way off, don't tempt fate by correcting it. + */ + if (tmp_ui >= CLOCK_WAYTOOBIG) { + syslog(LOG_ERR, + "Clock appears to be %u seconds %s, something may be wrong", + tmp_ui, isneg>0?"fast":"slow"); +#ifndef BIGTIMESTEP + return (-1); +#endif /* BIGTIMESTEP */ + } + + /* + * Save this offset for later perusal + */ + last_offset = *fp_offset; + + /* + * If the magnitude of the offset is greater than CLOCK.MAX, step + * the time and reset the registers. + */ + if (tmp_ui > CLOCK_MAX_I || (tmp_ui == CLOCK_MAX_I + && (U_LONG)tmp_uf >= (U_LONG)CLOCK_MAX_F)) { + if (watchdog_timer < CLOCK_MINSTEP) { + /* Mustn't step yet, pretend we adjusted. */ +#ifdef SLEWALWAYS + syslog(LOG_INFO, + "adjust: SLEW dropped (%s offset %s)\n", + ntoa(&peer->srcadr), lfptoa(fp_offset, 9)); +#else + syslog(LOG_INFO, + "adjust: STEP dropped (%s offset %s)\n", + ntoa(&peer->srcadr), lfptoa(fp_offset, 9)); +#endif + return (0); + } +#ifdef SLEWALWAYS + syslog(LOG_NOTICE, " ** adjust: SLEW %s offset %s **\n", + ntoa(&peer->srcadr), lfptoa(fp_offset, 9)); +#else + syslog(LOG_NOTICE, " ** adjust: STEP %s offset %s **\n", + ntoa(&peer->srcadr), lfptoa(fp_offset, 9)); +#endif + step_systime(fp_offset); + + clock_adjust = 0; + watchdog_timer = 0; + first_adjustment = 1; + pps_update = 0; + return (1); + } + + /* + * Here we've got an offset small enough to slew. Note that + * since the offset is small we don't have to carry the damned + * high order longword in our calculations. + * + * The time constant and sample interval are approximated with + * shifts, as in Section 5 of the v3 spec. The spec procedure + * looks strange, as an interval of 64 to 127 seconds seems to + * cause multiplication with 128 (and so on). This code lowers + * the multiplier by one bit. + * + * The time constant update goes after adjust and skew updates, + * as in appendix G. + */ +#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS) + /* + * If pps samples are valid, update offset, root delay and + * root dispersion. This may be a dramatic surprise to high- + * stratum clients, since all of a sudden this server looks + * like a stratum-1 clock. + */ + if (pps_control) { + last_offset = pps_offset; + sys_stratum = 1; + sys_rootdelay = 0; + sys_rootdispersion = sys_maxd; + } +#endif /* PPS || PPSCLK || PPSPPS */ + + /* + * The pll_control is active when the phase-lock code is + * implemented in the kernel, which at present is only in the + * (modified) SunOS 4.1.x, Ultrix 4.3 and OSF/1 kernels. In the + * case of the DECstation 5000/240 and Alpha AXP, additional + * kernal modifications provide a true microsecond clock. We + * know the scaling of the frequency variable (s_fp) is the + * same as the kernel variable (1 << SHIFT_USEC = 16). + * + * In the case of stock kernels the phase-lock loop is + * implemented the hard way and the clock_adjust and drift_comp + * computed as required. + */ + offset = last_offset.l_f; + if (pll_control) { +#if defined(KERNEL_PLL) + ntv.mode = ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | + ADJ_ESTERROR; + if (offset >= 0) { + TSFTOTVU(offset, ntv.offset); + } else { + TSFTOTVU(-offset, ntv.offset); + ntv.offset = -ntv.offset; + } + ntv.maxerror = sys_rootdispersion + sys_rootdelay / 2; + ntv.esterror = sys_rootdispersion; + ntv.time_constant = time_constant; + (void)ntp_adjtime(&ntv); + drift_comp = ntv.frequency; +#endif /* KERNEL_PLL */ + } else { + if (offset < 0) { + clock_adjust = -((-offset) >> time_constant); + } else { + clock_adjust = offset >> time_constant; + } + + /* + * Calculate the new frequency error. The factor given in the + * spec gives the adjustment per 2**CLOCK_ADJ seconds, but we + * want it as a (scaled) pure ratio, so we include that factor + * now and remove it later. + */ + if (first_adjustment) { + first_adjustment = 0; + } else { + /* + * Clamp the integration interval to maxpoll. + * The bitcounting in Section 5 gives (n+1)-6 for 2**n, + * but has a factor 2**6 missing from CLOCK_FREQ. + * We make 2**n give n instead. If watchdog_timer is + * zero, pretend it's one. + */ + tmp = peer->maxpoll; + tmp_uf = watchdog_timer; + if (tmp_uf == 0) + tmp_uf = 1; + while (tmp_uf < (1 << peer->maxpoll)) { + tmp--; + tmp_uf <<= 1; + } + + /* + * We apply the frequency scaling at the same time as + * the sample interval; this ensures a safe right-shift. + * (as long as it keeps below 31 bits, which current + * parameters should ensure. + */ + tmp = (RSH_FRAC_TO_FREQ - tmp) + + time_constant + time_constant; + if (offset < 0) + tmp = -((-offset) >> tmp); + else + tmp = offset >> tmp; + drift_comp += tmp; + if (drift_comp > max_comp) + drift_comp = max_comp; + else if (drift_comp < -max_comp) + drift_comp = -max_comp; + } + } + watchdog_timer = 0; + + /* + * Determine when to adjust the time constant and poll interval. + */ + if (current_time - tcadj_time >= (1 << sys_poll)) { + tcadj_time = current_time; + tmp = offset; + if (tmp < 0) + tmp = -tmp; + tmp = tmp >> (16 + CLOCK_WEIGHTTC - time_constant); + if (tmp > sys_maxd) { + tc_counter = 0; + time_constant--; + } else { + tc_counter++; + if (tc_counter > CLOCK_HOLDTC) { + tc_counter = 0; + time_constant++; + } + } + if (time_constant < (int)(peer->minpoll - NTP_MINPOLL)) + time_constant = peer->minpoll - NTP_MINPOLL; + if (time_constant > (int)(peer->maxpoll - NTP_MINPOLL)) + time_constant = peer->maxpoll - NTP_MINPOLL; + } + sys_poll = (u_char)(NTP_MINPOLL + time_constant); + +#ifdef DEBUG + if (debug > 1) + printf("adj %s, drft %s, tau %3i\n", + mfptoa((clock_adjust<0?-1:0), clock_adjust, 9), + fptoa(drift_comp, 9), time_constant); +#endif /* DEBUG */ + + (void) record_loop_stats(&last_offset, &drift_comp, time_constant); + + /* + * Whew. I've had enough. + */ + return (0); +} + + +/* + * adj_host_clock - Called every 2**CLOCK_ADJ seconds to update host clock + */ +void +adj_host_clock() +{ + register LONG adjustment; +#if defined(PPSPPS) + struct ppsclockev ev; + l_fp ts; +#endif /* PPSPPS */ + + watchdog_timer += (1 << CLOCK_ADJ); + if (watchdog_timer >= NTP_MAXAGE) { + first_adjustment = 1; /* don't use next offset for freq */ + } + if (sys_refskew.l_i >= NTP_MAXSKEW) + sys_refskew.l_f = 0; /* clamp it */ + else + L_ADDUF(&sys_refskew, NTP_SKEWINC); + +#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS) +#if defined(PPSPPS) + /* + * Note that nothing ugly happens even if the CIOGETEV ioctl is + * not configured. Correct for signal delays (!) for ultimate + * finick. + */ + if (fdpps != -1 && ioctl(fdpps, CIOGETEV, (caddr_t)&ev) >= 0) { + static int last_serial = 0; /* avoid stale events */ + + if (last_serial != ev.serial) { + TVUTOTSF(ev.tv.tv_usec, ts.l_uf); + ts.l_ui = 0; /* seconds don't matter here */ + L_SUB(&ts, &pps_delay); + ts.l_uf = ~ts.l_uf; /* map [0.5..1[ into [-0.5..0[ */ + ts.l_ui = (ts.l_f < 0) ? ~0 : 0; /* sign extension */ + (void)pps_sample(&ts); + last_serial = ev.serial; + } + } +#endif /* PPSPPS */ + if (pps_time != 0 && current_time - pps_time > PPS_MAXAGE) + pps_time = 0; + if (pps_update != 0 && current_time - pps_update > PPS_MAXUPDATE) + pps_update = 0; + if (pps_time != 0 && pps_update != 0) { + if (!pps_control) + syslog(LOG_INFO, "pps synch"); + pps_control = 1; + } else { + if (pps_control) + syslog(LOG_INFO, "pps synch lost"); + pps_control = 0; + } +#endif /* PPS || PPSCLK || PPSPPS */ + + /* + * Resist the following code if the phase-lock loop has been + * implemented in the kernel. + */ + if (pll_control) + return; + adjustment = clock_adjust; + if (adjustment < 0) + adjustment = -((-adjustment) >> CLOCK_PHASE); + else + adjustment >>= CLOCK_PHASE; + + clock_adjust -= adjustment; + if (drift_comp < 0) + adjustment -= ((-drift_comp) >> RSH_DRIFT_TO_ADJ); + else + adjustment += drift_comp >> RSH_DRIFT_TO_ADJ; + + { l_fp offset; + offset.l_i = 0; + offset.l_f = adjustment; + adj_systime(&offset); + } +} + + +/* + * loop_config - configure the loop filter + */ +void +loop_config(item, lfp_value, int_value) + int item; + l_fp *lfp_value; + int int_value; +{ + s_fp tmp; +#if defined(KERNEL_PLL) + struct timex ntv; +#endif /* KERNEL_PLL */ + + switch (item) { + case LOOP_DRIFTCOMP: + tmp = LFPTOFP(lfp_value); + if (tmp >= max_comp || tmp <= -max_comp) { + syslog(LOG_ERR, + "loop_config: skew compensation %s too large", + fptoa(tmp, 5)); + } else { + drift_comp = tmp; + +#if defined(KERNEL_PLL) + /* + * If the phase-lock code is implemented in the kernel, + * give the time_constant and saved frequency offset + * to the kernel. If not, no harm is done. + */ + pll_control = 1; + ntv.mode = ADJ_FREQUENCY | ADJ_STATUS | ADJ_TIMECONST; + ntv.status = TIME_BAD; + ntv.time_constant = time_constant; + ntv.frequency = drift_comp; + newsigsys.sv_handler = pll_trap; + newsigsys.sv_mask = 0; + newsigsys.sv_flags = 0; + if ((sigvec(SIGSYS, &newsigsys, &sigsys))) + syslog(LOG_ERR, + "sigvec() fails to save SIGSYS trap: %m\n"); + (void)ntp_adjtime(&ntv); + if ((sigvec(SIGSYS, &sigsys, (struct sigvec *)NULL))) + syslog(LOG_ERR, + "sigvec() fails to restore SIGSYS trap: %m\n"); + syslog(LOG_NOTICE, + "%susing kernel phase-lock loop", + (pll_control) ? "" : "Not "); +#if DEBUG + if (debug) + printf("pll_control %d\n", pll_control); +#endif +#endif /* KERNEL_PLL */ + + } + break; + + case LOOP_PPSDELAY: + pps_delay = *lfp_value; + break; + +#if defined(PPSCLK) + case LOOP_PPSBAUD: +#if defined(STREAM) + /* + * System V STREAM serial line parameters + * (termios interface) + */ + { struct termios ttyb, *ttyp; + if (fdpps == -1) + return; + + ttyp = &ttyb; + if (tcgetattr(fdpps, ttyp) < 0) + return; + ttyp->c_cflag = CS8|CLOCAL|CREAD | int_value; + if (tcsetattr(fdpps, TCSANOW, ttyp) < 0) + return; + } +#endif /* STREAM */ +#if defined(HAVE_BSD_TTYS) + + /* + * 4.3bsd serial line parameters (sgttyb interface) + */ + { struct sgttyb ttyb; + + if (fdpps == -1 || ioctl(fdpps, TIOCGETP, &ttyb) < 0) + return; + ttyb.sg_ispeed = ttyb.sg_ospeed = SYS_BAUD(int_value); + if (ioctl(fdpps, TIOCSETP, &ttyb) < 0) + return; + } +#endif /* HAVE_BSD_TTYS */ + pps_baud = int_value; + break; +#endif /* PPSCLK */ + + default: + /* sigh */ + break; + } +} + +#if defined(KERNEL_PLL) +/* + * _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 int + * the kernel. In this case the phase-lock loop is emulated by + * the stock adjtime() syscall and a lot of indelicate abuse. + */ +RETSIGTYPE +pll_trap() +{ + pll_control = 0; +} +#endif /* KERNEL_PLL */ + +#if defined(PPSCLK) +/* + * pps_receive - compute and store 1-pps signal offset + * + * This routine is called once per second when the 1-pps signal is + * present. It calculates the offset of the local clock relative to the + * 1-pps signal and saves in a circular buffer for later use. If the + * clock line discipline is active, its timestamp is used; otherwise, + * the buffer timestamp is used. + */ +static void +pps_receive(rbufp) + struct recvbuf *rbufp; +{ + u_char *dpt; /* buffer pointer */ + l_fp ts; /* l_fp temps */ + int dpend; /* buffer length */ + + /* + * Set up pointers, check the buffer length, discard intercept + * character and convert unix timeval to timestamp format. + */ + dpt = (u_char *)&rbufp->recv_space; + dpend = rbufp->recv_length; +#if !defined(HPUXGADGET) + dpt++; + dpend--; +#endif /* HPUXGADGET */ + if (dpend != sizeof(struct timeval) || !buftvtots((char *)dpt, &ts)) + ts = rbufp->recv_time; + + /* + * Correct for uart and os delay and process sample offset. + */ + L_SUB(&ts, &pps_delay); + L_NEG(&ts); + (void)pps_sample(&ts); +} +#endif /* PPSCLK */ + +#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS) +/* + * pps_sample - process pps sample offset + */ +int pps_sample(tsr) + l_fp *tsr; +{ + int i, j; /* temp ints */ + LONG sort[NPPS]; /* temp array for sorting */ + l_fp lftemp, ts; /* l_fp temps */ + LONG ltemp; /* long temp */ + + /* + * Note the seconds offset is already in the low-order timestamp + * doubleword, so all we have to do is sign-extend and invert it. + * The resulting offset is believed only if within CLOCK_MAX. + */ + ts = *tsr; + lftemp.l_i = lftemp.l_f = 0; + M_ADDF(lftemp.l_i, lftemp.l_f, ts.l_f); + if (ts.l_f <= -CLOCK_MAX_F || ts.l_f >= CLOCK_MAX_F) { + pps_time = 0; + return (-1); + } + + /* + * Save the sample in a circular buffer for later processing. + */ + nsamples++; + i = ((int)(nsamples)) % NPPS; + samples[i] = lftemp.l_f; + if (i != NPPS-1) + return (0); + + /* + * When the buffer fills up, construct an array of sorted + * samples. + */ + pps_time = current_time; + for (i = 0; i < NPPS; i++) { + sort[i] = samples[i]; + for (j = 0; j < i; j++) { + if (sort[j] > sort[i]) { + ltemp = sort[j]; + sort[j] = sort[i]; + sort[i] = ltemp; + } + } + } + + /* + * Compute offset as the average of all samples in the filter + * less PPS_TRIM samples trimmed from the beginning and end, + * dispersion as the difference between max and min of samples + * retained. The system stratum, root delay and root dispersion + * are also set here. + */ + pps_offset.l_i = pps_offset.l_f = 0; + for (i = PPS_TRIM; i < NPPS - PPS_TRIM; i++) + M_ADDF(pps_offset.l_i, pps_offset.l_f, sort[i]); + if (L_ISNEG(&pps_offset)) { + L_NEG(&pps_offset); + for (i = 0; i < PPS_FAC; i++) + L_RSHIFT(&pps_offset); + L_NEG(&pps_offset); + } else { + for (i = 0; i < PPS_FAC; i++) + L_RSHIFT(&pps_offset); + } + lftemp.l_i = 0; + lftemp.l_f = sort[NPPS-1-PPS_TRIM] - sort[PPS_TRIM]; + sys_maxd = LFPTOFP(&lftemp); +#ifdef DEBUG + if (debug) + printf("pps_filter: %s %s %s\n", lfptoa(&pps_delay, 6), + lfptoa(&pps_offset, 6), lfptoa(&lftemp, 5)); +#endif /* DEBUG */ + record_peer_stats(&loopback_interface->sin, ctlsysstatus(), &pps_offset, + sys_rootdelay, sys_rootdispersion); + return (0); +} +#endif /* PPS || PPSCLK || PPSPPS */ + diff --git a/contrib/xntpd/xntpd/ntp_monitor.c b/contrib/xntpd/xntpd/ntp_monitor.c new file mode 100644 index 0000000000..5d589e8745 --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_monitor.c @@ -0,0 +1,305 @@ +/* ntp_monitor.c,v 3.1 1993/07/06 01:11:21 jbj Exp + * ntp_monitor.c - monitor who is using the xntpd server + */ +#include +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" + +/* + * 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. + */ + +/* + * 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. + */ +#define MAXMONMEM 400 /* we allocate up to 400 structures */ +#define MONMEMINC 40 /* allocate them 40 at a time */ + +/* + * Hashing stuff + */ +#define MON_HASH_SIZE 128 +#define MON_HASH_MASK (MON_HASH_SIZE-1) +#define MON_HASH(addr) ((int)(ntohl((addr)) & MON_HASH_MASK)) + +/* + * 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; /* Pointer to array of hash buckets */ +static int *mon_hash_count; /* Point to hash count stats keeper */ + 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; + +static int mon_free_mem; /* number of structures on free list */ +static int mon_total_mem; /* total number of structures allocated */ +static int mon_mem_increments; /* number of times we've 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; +static int mon_have_memory; + +/* + * Imported from the timer module + */ +extern U_LONG current_time; + +static void mon_getmoremem P((void)); + +/* + * init_mon - initialize monitoring global data + */ +void +init_mon() +{ + /* + * Don't do much of anything here. We don't allocate memory + * until someone explicitly starts us. + */ + mon_enabled = 0; + mon_have_memory = 0; + + mon_free_mem = 0; + mon_total_mem = 0; + mon_mem_increments = 0; + mon_free = 0; + mon_hash = 0; + mon_hash_count = 0; + bzero((char *)&mon_mru_list, sizeof mon_mru_list); +} + + +/* + * mon_start - start up the monitoring software + */ +void +mon_start() +{ + register struct mon_data *md; + register int i; + + if (mon_enabled) + return; + + if (!mon_have_memory) { + mon_hash = (struct mon_data *) + emalloc(MON_HASH_SIZE * sizeof(struct mon_data)); + bzero((char *)mon_hash, MON_HASH_SIZE*sizeof(struct mon_data)); + mon_hash_count = (int *)emalloc(MON_HASH_SIZE * sizeof(int)); + mon_free_mem = 0; + mon_total_mem = 0; + mon_mem_increments = 0; + mon_free = 0; + mon_getmoremem(); + mon_have_memory = 1; + } + + md = mon_hash; + for (i = 0; i < MON_HASH_SIZE; i++, md++) { + md->hash_next = md; + md->hash_prev = md; + *(mon_hash_count + i) = 0; + } + + mon_mru_list.mru_next = &mon_mru_list; + mon_mru_list.mru_prev = &mon_mru_list; + + mon_enabled = 1; +} + + +/* + * mon_stop - stop the monitoring software + */ +void +mon_stop() +{ + register struct mon_data *md; + register int i; + + if (!mon_enabled) + return; + + /* + * Put everything back on the free list + */ + md = mon_hash; + for (i = 0; i < MON_HASH_SIZE; i++, md++) { + if (md->hash_next != md) { + md->hash_prev->hash_next = mon_free; + mon_free = md->hash_next; + mon_free_mem += *(mon_hash_count + i); + md->hash_next = md; + md->hash_prev = md; + *(mon_hash_count + i) = 0; + } + } + + mon_mru_list.mru_next = &mon_mru_list; + mon_mru_list.mru_prev = &mon_mru_list; + + mon_enabled = 0; +} + + +/* + * monitor - record stats about this packet + */ +void +monitor(rbufp) + struct recvbuf *rbufp; +{ + register struct pkt *pkt; + register struct mon_data *md; + register U_LONG netnum; + register int hash; + register int mode; + register struct mon_data *mdhash; + + if (!mon_enabled) + return; + + pkt = &rbufp->recv_pkt; + netnum = NSRCADR(&rbufp->recv_srcadr); + hash = MON_HASH(netnum); + mode = PKT_MODE(pkt->li_vn_mode); + + md = (mon_hash + hash)->hash_next; + while (md != (mon_hash + hash)) { + if (md->rmtadr == netnum && md->mode == (u_char)mode) { + md->lasttime = current_time; + md->count++; + md->version = PKT_VERSION(pkt->li_vn_mode); + md->rmtport = NSRCPORT(&rbufp->recv_srcadr); + + /* + * Shuffle him to the head of the + * mru list. What a crock. + */ + 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_mem == 0 && mon_total_mem >= MAXMONMEM) { + /* + * Get it from MRU list + */ + md = mon_mru_list.mru_prev; + md->mru_prev->mru_next = &mon_mru_list; + mon_mru_list.mru_prev = md->mru_prev; + md->hash_next->hash_prev = md->hash_prev; + md->hash_prev->hash_next = md->hash_next; + *(mon_hash_count + MON_HASH(md->rmtadr)) -= 1; + } else { + if (mon_free_mem == 0) + mon_getmoremem(); + md = mon_free; + mon_free = md->hash_next; + mon_free_mem--; + } + + /* + * Got one, initialize it + */ + md->lasttime = md->firsttime = current_time; + md->count = 1; + md->rmtadr = netnum; + md->rmtport = NSRCPORT(&rbufp->recv_srcadr); + md->mode = (u_char) mode; + md->version = PKT_VERSION(pkt->li_vn_mode); + + /* + * Shuffle him into the hash table, inserting him at the + * end. Also put him on top of the MRU list. + */ + mdhash = mon_hash + MON_HASH(netnum); + md->hash_next = mdhash; + md->hash_prev = mdhash->hash_prev; + mdhash->hash_prev->hash_next = md; + mdhash->hash_prev = md; + *(mon_hash_count + MON_HASH(netnum)) += 1; + + 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() +{ + register struct mon_data *md; + register int i; + struct mon_data *freedata; + + 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_free_mem += MONMEMINC; + mon_total_mem += MONMEMINC; + mon_mem_increments++; +} diff --git a/contrib/xntpd/xntpd/ntp_peer.c b/contrib/xntpd/xntpd/ntp_peer.c new file mode 100644 index 0000000000..5e3b13455e --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_peer.c @@ -0,0 +1,639 @@ +/* ntp_peer.c,v 3.1 1993/07/06 01:11:22 jbj Exp + * ntp_peer.c - management of data maintained for peer associations + */ +#include +#include + +#include "ntpd.h" +#include "ntp_stdlib.h" + +/* + * These routines manage the allocation of memory to peer structures + * and the maintenance of the peer hash table. The two main entry + * points are findpeer(), which looks for corresponding peer data + * in the peer list, newpeer(), which allocates a new peer structure + * and adds it to the list, and unpeer(), which demobilizes the association + * and deallocates the structure. + */ + +/* + * The peer hash table (imported by the protocol module). + */ +struct peer *peer_hash[HASH_SIZE]; +int peer_hash_count[HASH_SIZE]; /* count of peers in each bucket */ + +/* + * The association ID hash table. Used for lookups by association ID + */ +struct peer *assoc_hash[HASH_SIZE]; +int assoc_hash_count[HASH_SIZE]; + +/* + * The free list. Clean structures only, please. + */ +struct peer *peer_free; +int peer_free_count; + +/* + * Association ID. We initialize this value randomly, the assign a new + * value every time the peer structure is incremented. + */ +u_short current_association_ID; + +/* + * Memory allocation watermarks. + */ +#define INIT_PEER_ALLOC 15 /* initialize space for 15 peers */ +#define INC_PEER_ALLOC 5 /* when we run out, add 5 more */ + +/* + * Miscellaneous statistic counters which may be queried. + */ +U_LONG peer_timereset; /* time stat counters were zeroed */ +U_LONG findpeer_calls; /* number of calls to findpeer */ +U_LONG assocpeer_calls; /* number of calls to findpeerbyassoc */ +U_LONG peer_allocations; /* number of allocations from the free list */ +U_LONG peer_demobilizations; /* number of structs freed to free list */ +int total_peer_structs; /* number of peer structs in circulation */ + +/* + * default interface. Imported from the io module. + */ +extern struct interface *any_interface; + +/* + * Timer queue and current time. Imported from the timer module. + */ +extern U_LONG current_time; +extern struct event timerqueue[]; + +/* + * Our initial allocation of peer space + */ +static struct peer init_peer_alloc[INIT_PEER_ALLOC]; + +/* + * Initialization data. When configuring peers at initialization time, + * we try to get their poll update timers initialized to different values + * to prevent us from sending big clumps of data all at once. + */ +U_LONG init_peer_starttime; +extern int initializing; +extern int debug; + +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() +{ + 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; + + /* + * Initialization counter. + */ + init_peer_starttime = 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 = (u_short)ranp2(16); + if (current_association_ID == 0) + current_association_ID = 1; +} + + + +/* + * getmorepeermem - add more peer structures to the free list + */ +static void +getmorepeermem() +{ + 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(addr, start_peer) + struct sockaddr_in *addr; + struct peer *start_peer; +{ + 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 (NSRCADR(addr) == NSRCADR(&peer->srcadr) + && NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) + return peer; + peer = peer->next; + } + + return (struct peer *)0; +} + + +/* + * findpeer - find and return a peer in the hash table. + */ +struct peer * +findpeer(srcadr, dstadr) + struct sockaddr_in *srcadr; + struct interface *dstadr; +{ + register struct peer *any_inter_peer; + register struct peer *peer; + int hash; + + findpeer_calls++; + + any_inter_peer = 0; + hash = HASH_ADDR(srcadr); + for (peer = peer_hash[hash]; peer != 0; peer = peer->next) { + if (NSRCADR(srcadr) == NSRCADR(&peer->srcadr) + && NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) { + if (peer->dstadr == dstadr) + return peer; /* got it! */ + if (peer->dstadr == any_interface) { + /* + * We shouldn't have more than one + * instance of the peer in the table, + * but I don't trust this. Save this + * one for later and continue search. + */ + if (any_inter_peer == 0) + any_inter_peer = peer; + else + syslog(LOG_ERR, + "two instances of default interface for %s in hash table", + ntoa(srcadr)); + } + } + } + + /* + * If we didn't find the specific peer but found a wild card, + * modify the interface and return him. + */ + if (any_inter_peer != 0) { + any_inter_peer->dstadr = dstadr; + return any_inter_peer; + } + + /* + * Out of luck. Return 0. + */ + return (struct peer *)0; +} + +/* + * findpeerbyassocid - find and return a peer using his association ID + */ +struct peer * +findpeerbyassoc(assoc) + 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 ((u_short)assoc == peer->associd) + return peer; /* got it! */ + } + + /* + * Out of luck. Return 0. + */ + return (struct peer *)0; +} + +/* + * unpeer - remove peer structure from hash table and free structure + */ +void +unpeer(peer_to_remove) + struct peer *peer_to_remove; +{ + int hash; + + 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 + + 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]++; + syslog(LOG_ERR, "peer struct for %s not in table!", + ntoa(&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]++; + syslog(LOG_ERR, + "peer struct for %s not in association table!", + ntoa(&peer->srcadr)); + } else { + peer->ass_next = peer_to_remove->ass_next; + } + } + + TIMER_DEQUEUE(&peer_to_remove->event_timer); + + peer_to_remove->next = peer_free; + peer_free = peer_to_remove; + peer_free_count++; +} + + +/* + * peer_config - configure a new peer + */ +struct peer * +peer_config(srcadr, dstadr, hmode, version, minpoll, maxpoll, key, flags) + struct sockaddr_in *srcadr; + struct interface *dstadr; + int hmode; + int version; + int minpoll; + int maxpoll; + U_LONG key; + int flags; +{ + register struct peer *peer; + +#ifdef DEBUG + if (debug) + printf("peer_config: addr %s mode %d version %d minpoll %d maxpoll %d key %u\n", + ntoa(srcadr), hmode, version, minpoll, maxpoll, key); +#endif + /* + * See if we have this guy in the tables already. If + * so just mark him configured. + */ + peer = findexistingpeer(srcadr, (struct peer *)0); + if (dstadr != 0) { + while (peer != 0) { + if (peer->dstadr == dstadr) + break; + peer = findexistingpeer(srcadr, peer); + } + } + + /* + * Torque the flags to make sure they're valid + */ + flags &= (FLAG_AUTHENABLE|FLAG_PREFER); + + /* + * If we found one, just change his mode and mark him configured. + */ + if (peer != 0) { + peer->hmode = (u_char)hmode; + peer->version = (u_char)version; + peer->minpoll = (u_char)minpoll; + peer->maxpoll = (u_char)maxpoll; + peer->hpoll = peer->minpoll; + peer->ppoll = peer->minpoll; + peer->flags = ((u_char)(flags|FLAG_CONFIG)) + |(peer->flags & (FLAG_REFCLOCK|FLAG_DEFBDELAY)); + peer->keyid = key; + return peer; + } + + /* + * If we're here this guy is unknown to us. Make a new peer + * structure for him. + */ + peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, key); + if (peer != 0) + peer->flags |= (u_char)(flags|FLAG_CONFIG); + return peer; +} + + +/* + * newpeer - initialize a new peer association + */ +struct peer * +newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, key) + struct sockaddr_in *srcadr; + struct interface *dstadr; + int hmode; + int version; + int minpoll; + int maxpoll; + U_LONG key; +{ + register struct peer *peer; + register int i; + + /* + * Some dirt here. Some of the initialization requires + * knowlege of our system state. + */ + extern U_LONG sys_bdelay; + extern LONG sys_clock; + + if (peer_free_count == 0) + getmorepeermem(); + + peer = peer_free; + peer_free = peer->next; + peer_free_count--; + + /* + * Initialize the structure. This stuff is sort of part of + * the receive procedure and part of the clear procedure rolled + * into one. + * + * Zero the whole thing for now. We might be pickier later. + */ + bzero((char *)peer, sizeof(struct peer)); + + peer->srcadr = *srcadr; + if (dstadr != 0) + peer->dstadr = dstadr; + else if (hmode == MODE_BROADCAST) + peer->dstadr = findbcastinter(srcadr); + else + peer->dstadr = any_interface; + peer->hmode = (u_char)hmode; + peer->version = (u_char)version; + peer->minpoll = (u_char)minpoll; + peer->maxpoll = (u_char)maxpoll; + peer->hpoll = peer->minpoll; + peer->ppoll = peer->minpoll; + peer->keyid = key; + + if (hmode == MODE_BCLIENT) { + peer->estbdelay = sys_bdelay; + peer->flags |= FLAG_DEFBDELAY; + } + + peer->leap = LEAP_NOTINSYNC; + peer->precision = DEFPRECISION; + peer->dispersion = NTP_MAXDISPERSE; + peer->stratum = STRATUM_UNSPEC; + peer->update = sys_clock; + + for (i = 0; i < NTP_SHIFT; i++) { + peer->filter_order[i] = i; + peer->filter_error[i] = NTP_MAXDISPERSE; + } + + /* + * Assign him an association ID and increment the system variable + */ + peer->associd = current_association_ID; + if (++current_association_ID == 0) + ++current_association_ID; + + /* + * Note time on statistics timers. + */ + peer->timereset = current_time; + 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 0; + } + } else { +#endif + /* + * Set up timer. If initializing, just make sure we start polling + * in different 4 second intervals. + */ + peer->event_timer.peer = peer; + peer->event_timer.event_handler = transmit; + + if (initializing) { + init_peer_starttime += (1 << EVENT_TIMEOUT); + if (init_peer_starttime >= (1 << peer->minpoll)) + init_peer_starttime = (1 << EVENT_TIMEOUT); + peer->event_timer.event_time = init_peer_starttime; + } else { + /* + * First expiry is set to eight seconds from now. + */ + peer->event_timer.event_time + = (1 << (peer->minpoll - 1)) + current_time; + } + TIMER_ENQUEUE(timerqueue, &peer->event_timer); +#ifdef REFCLOCK + } +#endif + + /* + * Put him 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]++; + + return peer; +} + + +/* + * peer_unconfig - remove the configuration bit from a peer + */ +int +peer_unconfig(srcadr, dstadr) + struct sockaddr_in *srcadr; + struct interface *dstadr; +{ + register struct peer *peer; + int num_found; + + num_found = 0; + peer = findexistingpeer(srcadr, (struct peer *)0); + 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); + } + return num_found; +} + + +/* + * peer_clr_stats - clear peer module stat counters + */ +void +peer_clr_stats() +{ + 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(peer) + struct peer *peer; +{ + if (peer == 0) + return; + peer->sent = 0; + peer->received = 0; + peer->processed = 0; + peer->badauth = 0; + peer->bogusorg = 0; + peer->bogusrec = 0; + peer->bogusdelay = 0; + peer->oldpkt = 0; + peer->seldisptoolarge = 0; + peer->selbroken = 0; + peer->seltooold = 0; + peer->timereset = current_time; +} + + +/* + * peer_all_reset - reset all peer stat counters + */ +void +peer_all_reset() +{ + 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); +} diff --git a/contrib/xntpd/xntpd/ntp_proto.c b/contrib/xntpd/xntpd/ntp_proto.c new file mode 100644 index 0000000000..a132624406 --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_proto.c @@ -0,0 +1,2168 @@ +/* ntp_proto.c,v 3.1 1993/07/06 01:11:23 jbj Exp + * ntp_proto.c - NTP version 3 protocol machinery + */ +#include +#include +#include + +#include "ntpd.h" +#include "ntp_stdlib.h" +#include "ntp_unixtime.h" + +/* + * 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 */ +s_fp sys_rootdelay; /* distance to current sync source */ +u_fp sys_rootdispersion; /* dispersion of system clock */ +U_LONG sys_refid; /* reference source for local clock */ +l_fp sys_offset; /* combined offset from clock_select */ +u_fp sys_maxd; /* dispersion of selected peer */ +l_fp sys_reftime; /* time we were last updated */ +l_fp sys_refskew; /* accumulated skew since last update */ +struct peer *sys_peer; /* our current peer */ +u_char sys_poll; /* log2 of desired system poll interval */ +LONG sys_clock; /* second part of current time */ +LONG sys_lastselect; /* sys_clock at last synch-dist update */ + +/* + * Non-specified system state variables. + */ +int sys_bclient; /* we set our time to broadcasts */ +U_LONG sys_bdelay; /* default delay to use for broadcasting */ +int sys_authenticate; /* authenticate time used for syncing */ + +U_LONG sys_authdelay; /* ts fraction, time it takes for encrypt() */ + +/* + * Statistics counters + */ +U_LONG sys_stattime; /* time when we started recording */ +U_LONG sys_badstratum; /* packets with invalid incoming stratum */ +U_LONG sys_oldversionpkt; /* old version packets received */ +U_LONG sys_newversionpkt; /* new version packets received */ +U_LONG sys_unknownversion; /* don't know version packets */ +U_LONG sys_badlength; /* packets with bad length */ +U_LONG sys_processed; /* packets processed */ +U_LONG sys_badauth; /* packets dropped because of authorization */ +U_LONG sys_wanderhold; /* sys_peer held to prevent wandering */ + +/* + * Imported from ntp_timer.c + */ +extern U_LONG current_time; +extern struct event timerqueue[]; + +/* + * Imported from ntp_io.c + */ +extern struct interface *any_interface; + +/* + * Imported from ntp_loopfilter.c + */ +extern int pps_control; +extern U_LONG pps_update; + +/* + * The peer hash table. Imported from ntp_peer.c + */ +extern struct peer *peer_hash[]; +extern int peer_hash_count[]; + +/* + * debug flag + */ +extern int debug; + +static void clear_all P((void)); + +/* + * transmit - Transmit Procedure. See Section 3.4.1 of the specification. + */ +void +transmit(peer) + register struct peer *peer; +{ + struct pkt xpkt; /* packet to send */ + U_LONG peer_timer; + + if (peer->hmode != MODE_BCLIENT) { + U_LONG xkeyid; + + /* + * Figure out which keyid to include in the packet + */ + if ((peer->flags & FLAG_AUTHENABLE) + && (peer->flags & (FLAG_CONFIG|FLAG_AUTHENTIC)) + && authhavekey(peer->keyid)) { + xkeyid = peer->keyid; + } else { + xkeyid = 0; + } + + /* + * Make up a packet to send. + */ + 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(sys_rootdelay); + xpkt.rootdispersion = + HTONS_FP(sys_rootdispersion + + (FP_SECOND >> (-(int)sys_precision)) + + LFPTOFP(&sys_refskew)); + xpkt.refid = sys_refid; + HTONL_FP(&sys_reftime, &xpkt.reftime); + HTONL_FP(&peer->org, &xpkt.org); + HTONL_FP(&peer->rec, &xpkt.rec); + + /* + * Decide whether to authenticate or not. If so, call encrypt() + * to fill in the rest of the frame. If not, just add in the + * xmt timestamp and send it quick. + */ + if (peer->flags & FLAG_AUTHENABLE) { + int sendlen; + + xpkt.keyid = htonl(xkeyid); + auth1crypt(xkeyid, (U_LONG *)&xpkt, LEN_PKT_NOMAC); + get_systime(&peer->xmt); + L_ADDUF(&peer->xmt, sys_authdelay); + HTONL_FP(&peer->xmt, &xpkt.xmt); + sendlen = auth2crypt(xkeyid, (U_LONG *)&xpkt, + LEN_PKT_NOMAC); + sendpkt(&(peer->srcadr), peer->dstadr, &xpkt, + sendlen + LEN_PKT_NOMAC); +#ifdef DEBUG + if (debug > 1) + printf("transmit auth to %s\n", + ntoa(&(peer->srcadr))); +#endif + peer->sent++; + } else { + /* + * Get xmt timestamp, then send it without mac field + */ + get_systime(&(peer->xmt)); + HTONL_FP(&peer->xmt, &xpkt.xmt); + sendpkt(&(peer->srcadr), peer->dstadr, &xpkt, + LEN_PKT_NOMAC); +#ifdef DEBUG + if (debug > 1) + printf("transmit to %s\n", ntoa(&(peer->srcadr))); +#endif + peer->sent++; + } + } + + if (peer->hmode != MODE_BROADCAST) { + u_char opeer_reach; + /* + * Determine reachability and diddle things if we + * haven't heard from the host for a while. + */ + opeer_reach = peer->reach; + peer->reach <<= 1; + if (peer->reach == 0) { + if (opeer_reach != 0) + report_event(EVNT_UNREACH, peer); + /* + * Clear this guy out. No need to redo clock + * selection since by now this guy won't be a player + */ + if (peer->flags & FLAG_CONFIG) { + if (opeer_reach != 0) { + peer_clear(peer); + peer->timereachable = current_time; + } + } else { + unpeer(peer); + return; + } + + /* + * While we have a chance, if our system peer + * is zero or his stratum is greater than the + * last known stratum of this guy, make sure + * hpoll is clamped to the minimum before + * resetting the timer. + * If the peer has been unreachable for a while + * and we have a system peer who is at least his + * equal, we may want to ramp his polling interval + * up to avoid the useless traffic. + */ + if (sys_peer == 0 + || sys_peer->stratum > peer->stratum) { + peer->hpoll = peer->minpoll; + peer->unreach = 0; + } else { + if (peer->unreach < 16) { + peer->unreach++; + peer->hpoll = peer->minpoll; + } else if (peer->hpoll < peer->maxpoll) { + peer->hpoll++; + peer->ppoll = peer->hpoll; + } + } + + /* + * Update reachability and poll variables + */ + } else if ((opeer_reach & 3) == 0) { + + l_fp off; + + if (peer->valid > 0) + peer->valid--; + if (peer->hpoll > peer->minpoll) + peer->hpoll--; + off.l_ui = off.l_uf = 0; + clock_filter(peer, &off, (s_fp)0, (u_fp)NTP_MAXDISPERSE); + if (peer->flags & FLAG_SYSPEER) + clock_select(); + } else { + if (peer->valid < NTP_SHIFT) { + peer->valid++; + } else { + if (peer->hpoll < peer->maxpoll) + peer->hpoll++; + } + } + } + + /* + * Finally, adjust the hpoll variable for special conditions. + */ + if (peer->flags & FLAG_SYSPEER && peer->hpoll > sys_poll) { + /* clamp it */ + peer->hpoll = max(peer->minpoll, sys_poll); + } + if (peer->hmode == MODE_BROADCAST || peer->hmode == MODE_BCLIENT) { + /* clamp it */ + peer->hpoll = peer->minpoll; + } + + /* + * Arrange for our next time out. hpoll will be less than + * maxpoll for sure. + */ + if (peer->event_timer.next != 0) + /* + * Oops, someone did already. + */ + TIMER_DEQUEUE(&peer->event_timer); + peer_timer = 1 << (int)max((u_char)min(peer->ppoll, peer->hpoll), peer->minpoll); + peer->event_timer.event_time = current_time + peer_timer; + TIMER_ENQUEUE(timerqueue, &peer->event_timer); +} + +#if 0 +static void +ct_die(after) +{ + syslog(LOG_ERR, "timers garbled (%s)", after?"after":"before"); + abort(); +} + +void +check_timers(after) +{ + register int i; + register struct event *p, *q; + + for (i = 0; i < TIMER_NSLOTS; i++) { + p = &timerqueue[i]; + if (p->event_time != 0) + ct_die(after); + do { + q = p; + if ((p = p->next) == 0) + ct_die(after); + if (p->prev != q) + ct_die(after); + } while (p->event_time != 0); + if (p != &timerqueue[i]) + ct_die(after); + } +} +#endif + +/* + * receive - Receive Procedure. See section 3.4.2 in the specification. + */ +void +receive(rbufp) + struct recvbuf *rbufp; +{ + register struct peer *peer; + register struct pkt *pkt; + register u_char hismode; + int restrict; + int has_mac; + int trustable; + int is_authentic; + U_LONG hiskeyid; + struct peer *peer2; + +#ifdef DEBUG + if (debug > 1) + printf("receive from %s\n", ntoa(&rbufp->recv_srcadr)); +#endif + + /* + * Let the monitoring software take a look at this first. + */ + monitor(rbufp); + + /* + * Get the restrictions on this guy. If we're to ignore him, + * go no further. + */ + restrict = restrictions(&rbufp->recv_srcadr); + if (restrict & RES_IGNORE) + return; + + /* + * Get a pointer to the packet. + */ + pkt = &rbufp->recv_pkt; + + /* + * Catch packets whose version number we can't deal with + */ + if (PKT_VERSION(pkt->li_vn_mode) >= NTP_VERSION) { + sys_newversionpkt++; + } else if (PKT_VERSION(pkt->li_vn_mode) >= NTP_OLDVERSION) { + sys_oldversionpkt++; + } else { + sys_unknownversion++; + return; + } + + /* + * Catch private mode packets. Dump it if queries not allowed. + */ + if (PKT_MODE(pkt->li_vn_mode) == MODE_PRIVATE) { + if (restrict & RES_NOQUERY) + return; + process_private(rbufp, ((restrict&RES_NOMODIFY) == 0)); + return; + } + + /* + * Same with control mode packets. + */ + if (PKT_MODE(pkt->li_vn_mode) == MODE_CONTROL) { + if (restrict & RES_NOQUERY) + return; + process_control(rbufp, restrict); + return; + } + + /* + * See if we're allowed to serve this guy time. If not, ignore + * him. + */ + if (restrict & RES_DONTSERVE) + return; + + /* + * Dump anything with a putrid stratum. These will most likely + * come from someone trying to poll us with ntpdc. + */ + if (pkt->stratum > NTP_MAXSTRATUM) { + sys_badstratum++; + return; + } + + /* + * Find the peer. This will return a null if this guy + * isn't in the database. + */ + peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr); + + /* + * Check the length for validity, drop the packet if it is + * not as expected. + * + * If this is a client mode poll, go no further. Send back + * his time and drop it. + * + * The scheme we use for authentication is this. If we are + * running in non-authenticated mode, we accept both frames + * which are authenticated and frames which aren't, but don't + * authenticate. We do record whether the frame had a mac field + * or not so we know what to do on output. + * + * If we are running in authenticated mode, we only trust frames + * which have authentication attached, which are validated and + * which are using one of our trusted keys. We respond to all + * other pollers without saving any state. If a host we are + * passively peering with changes his key from a trusted one to + * an untrusted one, we immediately unpeer with him, reselect + * the clock and treat him as an unmemorable client (this is + * a small denial-of-service hole I'll have to think about). + * If a similar event occurs with a configured peer we drop the + * frame and hope he'll revert to our key again. If we get a + * frame which can't be authenticated with the given key, we + * drop it. Either we disagree on the keys or someone is trying + * some funny stuff. + */ + + /* + * here we assume that any packet with an authenticator is at + * least LEN_PKT_MAC bytes long, which means at least 96 bits + */ + if (rbufp->recv_length >= LEN_PKT_MAC) { + has_mac = rbufp->recv_length - LEN_PKT_NOMAC; + hiskeyid = ntohl(pkt->keyid); +#ifdef DEBUG + if (debug > 3) + printf("receive: pkt is %d octets, mac %d octets long, keyid %d\n", + rbufp->recv_length, has_mac, hiskeyid); +#endif + } else if (rbufp->recv_length == LEN_PKT_NOMAC) { + hiskeyid = 0; + has_mac = 0; + } else { +#ifdef DEBUG + if (debug > 2) + printf("receive: bad length %d (not > %d or == %d)\n", + rbufp->recv_length, LEN_PKT_MAC, LEN_PKT_NOMAC); +#endif + sys_badlength++; + return; + } + + + + /* + * Figure out his mode and validate it. + */ + hismode = PKT_MODE(pkt->li_vn_mode); +#ifdef DEBUG + if (debug > 2) + printf("receive: his mode %d\n", hismode); +#endif + if (PKT_VERSION(pkt->li_vn_mode) == NTP_OLDVERSION && hismode == 0) { + /* + * Easy. If it is from the NTP port it is + * a sym act, else client. + */ + if (SRCPORT(&rbufp->recv_srcadr) == NTP_PORT) + hismode = MODE_ACTIVE; + else + hismode = MODE_CLIENT; + } else { + if (hismode != MODE_ACTIVE && hismode != MODE_PASSIVE && + hismode != MODE_SERVER && hismode != MODE_CLIENT && + hismode != MODE_BROADCAST) { + syslog(LOG_ERR, "bad mode %d received from %s", + PKT_MODE(pkt->li_vn_mode), + ntoa(&rbufp->recv_srcadr)); + return; + } + } + + + /* + * If he included a mac field, decrypt it to see if it is authentic. + */ + is_authentic = 0; + if (has_mac) { + if (authhavekey(hiskeyid)) { + if (authdecrypt(hiskeyid, (U_LONG *)pkt, LEN_PKT_NOMAC)) { + is_authentic = 1; +#ifdef DEBUG + if (debug > 3) + printf("receive: authdecrypt succeeds\n"); +#endif + } else { + sys_badauth++; +#ifdef DEBUG + if (debug > 3) + printf("receive: authdecrypt fails\n"); +#endif + } + } + } + + /* + * If this is someone we don't remember from a previous association, + * dispatch him now. Either we send something back quick, we + * ignore him, or we allocate some memory for him and let + * him continue. + */ + if (peer == 0) { + int mymode; + + mymode = MODE_PASSIVE; + switch(hismode) { + case MODE_ACTIVE: + /* + * See if this guy qualifies as being the least + * bit memorable. If so we keep him around for + * later. If not, send his time quick. + */ + if (restrict & RES_NOPEER) { + fast_xmit(rbufp, (int)hismode, is_authentic); + return; + } + break; + + case MODE_PASSIVE: + case MODE_SERVER: + /* + * These are obvious errors. Ignore. + */ + return; + + case MODE_CLIENT: + /* + * Send it back quick and go home. + */ + fast_xmit(rbufp, (int)hismode, is_authentic); + return; + + case MODE_BROADCAST: + /* + * Sort of a repeat of the above... + */ + if ((restrict & RES_NOPEER) || !sys_bclient) + return; + mymode = MODE_BCLIENT; + break; + } + + /* + * Okay, we're going to keep him around. Allocate him + * some memory. + */ + peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, mymode, + PKT_VERSION(pkt->li_vn_mode), NTP_MINDPOLL, + NTP_MAXPOLL, hiskeyid); + if (peer == 0) { + /* + * The only way this can happen is if the + * source address looks like a reference + * clock. Since this is an illegal address + * this is one of those "can't happen" things. + */ + syslog(LOG_ERR, + "receive() failed to peer with %s, mode %d", + ntoa(&rbufp->recv_srcadr), mymode); + return; + } + } + + /* + * Mark the time of reception + */ + peer->timereceived = current_time; + + /* + * If the peer isn't configured, set his keyid and authenable + * status based on the packet. + */ + if (!(peer->flags & FLAG_CONFIG)) { + if (has_mac) { + peer->keyid = hiskeyid; + peer->flags |= FLAG_AUTHENABLE; + } else { + peer->keyid = 0; + peer->flags &= ~FLAG_AUTHENABLE; + } + } + + + /* + * If this message was authenticated properly, note this + * in the flags. + */ + if (is_authentic) { + peer->flags |= FLAG_AUTHENTIC; + } else { + /* + * If this guy is authenable, and has been authenticated + * in the past, but just failed the authentic test, report + * the event. + */ + if (peer->flags & FLAG_AUTHENABLE + && peer->flags & FLAG_AUTHENTIC) + report_event(EVNT_PEERAUTH, peer); + peer->flags &= ~FLAG_AUTHENTIC; + } + + /* + * Determine if this guy is basically trustable. + */ + if (restrict & RES_DONTTRUST) + trustable = 0; + else + trustable = 1; + + if (sys_authenticate && trustable) { + if (!(peer->flags & FLAG_CONFIG) + || (peer->flags & FLAG_AUTHENABLE)) + trustable = 0; + + if (has_mac) { + if (authistrusted(hiskeyid)) { + if (is_authentic) { + trustable = 1; + } else { + trustable = 0; + peer->badauth++; + } + } + } + } + + /* + * Dispose of the packet based on our respective modes. We + * don't drive this with a table, though we probably could. + */ + switch (peer->hmode) { + case MODE_ACTIVE: + case MODE_CLIENT: + /* + * Active mode associations are configured. If the data + * isn't trustable, ignore it and hope this guy brightens + * up. Else accept any data we get and process it. + */ + switch (hismode) { + case MODE_ACTIVE: + case MODE_PASSIVE: + case MODE_SERVER: + process_packet(peer, pkt, &(rbufp->recv_time), + has_mac, trustable); + break; + + case MODE_CLIENT: + if (peer->hmode == MODE_ACTIVE) + fast_xmit(rbufp, hismode, is_authentic); + return; + + case MODE_BROADCAST: + /* + * No good for us, we want real time. + */ + break; + } + break; + + case MODE_PASSIVE: + /* + * Passive mode associations are (in the current + * implementation) always dynamic. If we get an + * invalid header, break the connection. I hate + * doing this since it seems like a waste. Oh, well. + */ + switch (hismode) { + case MODE_ACTIVE: + if (process_packet(peer, pkt, &(rbufp->recv_time), + has_mac, trustable) == 0) { + unpeer(peer); + clock_select(); + fast_xmit(rbufp, (int)hismode, is_authentic); + } + break; + + case MODE_PASSIVE: + case MODE_SERVER: + case MODE_BROADCAST: + /* + * These are errors. Just ignore the packet. + * If he doesn't straighten himself out this + * association will eventually be disolved. + */ + break; + + case MODE_CLIENT: + fast_xmit(rbufp, hismode, is_authentic); + return; + } + break; + + + case MODE_BCLIENT: + /* + * Broadcast client pseudo-mode. We accept both server + * and broadcast data. Passive mode data is an error. + */ + switch (hismode) { + case MODE_ACTIVE: + /* + * This guy wants to give us real time when we've + * been existing on lousy broadcasts! Create a + * passive mode association and do it that way, + * but keep the old one in case the packet turns + * out to be bad. + */ + peer2 = newpeer(&rbufp->recv_srcadr, + rbufp->dstadr, MODE_PASSIVE, + PKT_VERSION(pkt->li_vn_mode), + NTP_MINDPOLL, NTP_MAXPOLL, + hiskeyid); + if (process_packet(peer2, pkt, &rbufp->recv_time, + has_mac, trustable) == 0) { + /* + * Strange situation. We've been receiving + * broadcasts from him which we liked, but + * we don't like his active mode stuff. + * Keep his old peer structure and send + * him some time quickly, we'll figure it + * out later. + */ + unpeer(peer2); + fast_xmit(rbufp, (int)hismode, is_authentic); + } else + /* + * Drop the old association + */ + unpeer(peer); + break; + + case MODE_PASSIVE: + break; + + case MODE_SERVER: + case MODE_BROADCAST: + process_packet(peer, pkt, &rbufp->recv_time, + has_mac, trustable); + /* + * We don't test for invalid headers. + * Let him time out. + */ + break; + } + } +} + + +/* + * process_packet - Packet Procedure, a la Section 3.4.3 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. + */ +int +process_packet(peer, pkt, recv_ts, has_mac, trustable) + register struct peer *peer; + register struct pkt *pkt; + l_fp *recv_ts; + int has_mac; + int trustable; /* used as "valid header" */ +{ + U_LONG t23_ui = 0, t23_uf = 0; + U_LONG t10_ui, t10_uf; + s_fp di, ei, p_dist, p_disp; + l_fp ci, p_rec, p_xmt, p_org; + int randomize; + u_char ostratum, oreach; + + sys_processed++; + peer->processed++; + + peer->rec = *recv_ts; + p_dist = NTOHS_FP(pkt->rootdelay); + p_disp = NTOHS_FP(pkt->rootdispersion); + NTOHL_FP(&pkt->rec, &p_rec); + NTOHL_FP(&pkt->xmt, &p_xmt); + NTOHL_FP(&pkt->org, &p_org); + peer->flash = 0; + randomize = POLL_RANDOMCHANGE; + + /* + * Test for old or duplicate packets (tests 1 through 3). + */ + + if (L_ISHIS(&peer->org, &p_xmt)) /* count old packets */ + peer->oldpkt++; + if (L_ISEQU(&peer->org, &p_xmt)) /* test 1 */ + peer->flash |= TEST1; /* duplicate packet */ + if (PKT_MODE(pkt->li_vn_mode) != MODE_BROADCAST) { + if (!L_ISEQU(&peer->xmt, &p_org)) { /* test 2 */ + randomize = POLL_MAKERANDOM; + peer->bogusorg++; + peer->flash |= TEST2; /* bogus packet */ + } + if ((p_rec.l_ui == 0 && p_rec.l_uf == 0) || + (p_org.l_ui == 0 && p_org.l_uf == 0)) + peer->flash |= TEST3; /* unsynchronized */ + } + peer->org = p_xmt; /* reuse byte-swapped pkt->xmt */ + peer->ppoll = pkt->ppoll; + + /* + * Call poll_update(). This will either start us, if the + * association is new, or drop the polling interval if the + * association is existing and ppoll has been reduced. + */ + poll_update(peer, peer->hpoll, randomize); + + /* + * Test for valid header (tests 5 through 8) + */ + if (trustable == 0) /* test 5 */ + peer->flash |= TEST5; /* authentication failed */ + if (PKT_LEAP(pkt->li_vn_mode) == LEAP_NOTINSYNC || /* test 6 */ + p_xmt.l_ui < ntohl(pkt->reftime.l_ui) || + p_xmt.l_ui >= (ntohl(pkt->reftime.l_ui) + NTP_MAXAGE)) { + peer->seltooold++; /* test 6 */ + peer->flash |= TEST6; /* peer clock unsynchronized */ + } + if (!(peer->flags & FLAG_CONFIG) && /* test 7 */ + (PKT_TO_STRATUM(pkt->stratum) >= NTP_MAXSTRATUM || + PKT_TO_STRATUM(pkt->stratum) > sys_stratum)) + peer->flash |= TEST7; /* peer stratum out of bounds */ + if (p_dist >= NTP_MAXDISPERSE /* test 8 */ + || p_dist <= (-NTP_MAXDISPERSE) + || p_disp >= NTP_MAXDISPERSE) { + peer->disttoolarge++; + peer->flash |= TEST8; /* delay/dispersion too big */ + } + + /* + * If the packet header is invalid (tests 5 through 8), exit + */ + + if (peer->flash & (TEST5 | TEST6 | TEST7 | TEST8)) { + +#ifdef DEBUG + if (debug > 1) + printf("invalid packet header %s %02x\n", + ntoa(&peer->srcadr), peer->flash); +#endif + + return(0); + } + + /* + * Valid header; update our state. + */ + peer->leap = PKT_LEAP(pkt->li_vn_mode); + peer->pmode = PKT_MODE(pkt->li_vn_mode); + if (has_mac) + peer->pkeyid = ntohl(pkt->keyid); + else + peer->pkeyid = 0; + ostratum = peer->stratum; + peer->stratum = PKT_TO_STRATUM(pkt->stratum); + peer->precision = pkt->precision; + peer->rootdelay = p_dist; + peer->rootdispersion = p_disp; + peer->refid = pkt->refid; + NTOHL_FP(&pkt->reftime, &peer->reftime); + oreach = peer->reach; + if (peer->reach == 0) { + peer->timereachable = current_time; + /* + * If this guy was previously unreachable, set his + * polling interval to the minimum and reset the + * unreach counter. + */ + peer->unreach = 0; + peer->hpoll = peer->minpoll; + } + peer->reach |= 1; + + /* + * If running in a normal polled association, calculate the round + * trip delay (di) and the clock offset (ci). We use the equations + * (reordered from those in the spec): + * + * d = (t2 - t3) - (t1 - t0) + * c = ((t2 - t3) + (t1 - t0)) / 2 + * + * If running as a broadcast client, these change. di becomes + * equal to two times our broadcast delay, while the offset + * becomes equal to: + * + * c = (t1 - t0) + estbdelay + */ + t10_ui = p_xmt.l_ui; /* pkt->xmt == t1 */ + t10_uf = p_xmt.l_uf; + M_SUB(t10_ui, t10_uf, peer->rec.l_ui, peer->rec.l_uf); /*peer->rec==t0*/ + + if (PKT_MODE(pkt->li_vn_mode) != MODE_BROADCAST) { + t23_ui = p_rec.l_ui; /* pkt->rec == t2 */ + t23_uf = p_rec.l_uf; + M_SUB(t23_ui, t23_uf, p_org.l_ui, p_org.l_uf); /*pkt->org==t3*/ + } + + /* now have (t2 - t3) and (t0 - t1). Calculate (ci), (di) and (ei) */ + ci.l_ui = t10_ui; + ci.l_uf = t10_uf; + ei = (FP_SECOND >> (-(int)sys_precision)); + if (peer->hmode == MODE_BCLIENT) { +#ifdef notdef + if (PKT_MODE(pkt->li_vn_mode) == MODE_CLIENT) { + /* + * A client mode packet, used for delay computation. + * Give the data to the filter. + */ + bdelay_filter(peer, t23_ui, t23_uf, t10_ui, t10_uf); + } +#endif + M_ADDUF(ci.l_ui, ci.l_uf, peer->estbdelay>>1); + di = MFPTOFP(0, peer->estbdelay); + } else { + M_ADD(ci.l_ui, ci.l_uf, t23_ui, t23_uf); + M_RSHIFT(ci.l_i, ci.l_uf); + + /* + * Calculate di in t23 in full precision, then truncate + * to an s_fp. + */ + M_SUB(t23_ui, t23_uf, t10_ui, t10_uf); + di = MFPTOFP(t23_ui, t23_uf); + /* + * Calculate (t3 - t0) in t23 in full precision, convert + * to single, shift down by MAXSKEW and add to ei. + * We know NTP_SKEWFACTOR == 16 + */ +#if 0 + t23_ui = peer->rec.l_ui; /* peer->rec == t0 */ + t23_uf = peer->rec.l_uf; + M_SUB(t23_ui, t23_uf, p_org.l_ui, p_org.l_uf); /*pkt->org==t3*/ + ei += (MFPTOFP(t23_ui, t23_uf) >> NTP_SKEWFACTOR); +#endif + ei += peer->rec.l_ui - p_org.l_ui; + } +#ifdef DEBUG + if (debug > 3) + printf("offset: %s, delay %s, error %s\n", + lfptoa(&ci, 9), fptoa(di, 4), fptoa(ei, 4)); +#endif + if (di >= NTP_MAXDISPERSE || di <= (-NTP_MAXDISPERSE) + || ei >= NTP_MAXDISPERSE) { /* test 4 */ + peer->bogusdelay++; + peer->flash |= TEST4; /* delay/dispersion too big */ + } + + /* + * If the packet data is invalid (tests 1 through 4), exit + */ + if (peer->flash) { + +#ifdef DEBUG + if (debug) + printf("invalid packet data %s %02x\n", + ntoa(&peer->srcadr), peer->flash); +#endif + + /* + * If there was a reachability change report it even + * though the packet was bogus. + */ + if (oreach == 0) + report_event(EVNT_REACH, peer); + return(1); + } + + /* + * This one is valid. Mark it so, give it to clock_filter(), + */ + clock_filter(peer, &ci, di, (u_fp)ei); + + /* + * If this guy was previously unreachable, report him + * reachable. + * Note we do this here so that the peer values we return are + * the updated ones. + */ + if (oreach == 0) { + report_event(EVNT_REACH, peer); +#ifdef DEBUG + if (debug) + printf("proto: peer reach %d\n", peer->minpoll); +#endif /* DEBUG */ + } + + /* + * Now update the clock. + */ + clock_update(peer); + return(1); +} + + +/* + * clock_update - Clock-update procedure, see section 3.4.5. + */ +void +clock_update(peer) + struct peer *peer; +{ + u_char oleap; + u_char ostratum; + s_fp d; + extern u_char leap_mask; + +#ifdef DEBUG + if (debug) + printf("clock_update(%s)\n", ntoa(&peer->srcadr)); +#endif + + record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), &peer->offset, + peer->delay, peer->dispersion); + + /* + * Call the clock selection algorithm to see + * if this update causes the peer to change. + */ + clock_select(); + + /* + * Quit if this peer isn't the system peer. Other peers + * used in the combined offset are not allowed to set + * system variables or update the clock. + */ + if (peer != sys_peer) + return; + + /* + * Quit if the sys_peer is too far away. + */ + if (peer->synch >= NTP_MAXDISTANCE) + return; + + /* + * Update the system state + */ + oleap = sys_leap; + ostratum = sys_stratum; + /* + * get leap value (usually the peer leap unless overridden by local configuration) + */ + sys_leap = leap_actual(peer->leap & leap_mask); + /* + * N.B. peer->stratum was guaranteed to be less than + * NTP_MAXSTRATUM by the receive procedure. + * We assume peer->update == sys_clock because + * clock_filter was called right before this function. + * If the pps signal is in control, the system variables are + * set in the ntp_loopfilter.c module. + */ + if (!pps_control) { + sys_stratum = peer->stratum + 1; + d = peer->delay; + if (d < 0) + d = -d; + sys_rootdelay = peer->rootdelay + d; + sys_maxd = peer->dispersion; + if (peer->flags & FLAG_PREFER) + sys_maxd += peer->selectdisp; + d = peer->soffset; + if (d < 0) + d = -d; + d += sys_maxd; + if (!peer->flags & FLAG_REFCLOCK && d < NTP_MINDISPERSE) + d = NTP_MINDISPERSE; + sys_rootdispersion = peer->rootdispersion + d; + } + + /* + * Hack for reference clocks. Sigh. This is the + * only real silly part, though, so the analogy isn't + * bad. + */ + if (peer->flags & FLAG_REFCLOCK && peer->stratum == STRATUM_REFCLOCK) + sys_refid = peer->refid; + else { + if (pps_control) + bcopy(PPSREFID, (char *)&sys_refid, 4); + else + sys_refid = peer->srcadr.sin_addr.s_addr; + } + + /* + * Report changes. Note that we never sync to + * an unsynchronized host. + */ + if (oleap == LEAP_NOTINSYNC) + report_event(EVNT_SYNCCHG, (struct peer *)0); + else if (ostratum != sys_stratum) + report_event(EVNT_PEERSTCHG, (struct peer *)0); + + sys_reftime = peer->rec; + sys_refskew.l_i = 0; sys_refskew.l_f = NTP_SKEWINC; + + switch (local_clock(&sys_offset, peer)) { + case -1: + /* + * Clock is too screwed up. Just exit for now. + */ + report_event(EVNT_SYSFAULT, (struct peer *)0); + exit(1); + /*NOTREACHED*/ + case 0: + /* + * Clock was slewed. Continue on normally. + */ + break; + + case 1: + /* + * Clock was stepped. Clear filter registers + * of all peers. + */ + clear_all(); + leap_process(); /* reset the leap interrupt */ + sys_leap = LEAP_NOTINSYNC; + sys_refskew.l_i = NTP_MAXSKEW; sys_refskew.l_f = 0; + report_event(EVNT_CLOCKRESET, (struct peer *)0); + break; + } + if (sys_stratum > 1) + sys_refid = peer->srcadr.sin_addr.s_addr; + else { + if (peer->flags & FLAG_REFCLOCK) + sys_refid = peer->refid; + else + bcopy(PPSREFID, (char *)&sys_refid, 4); + } +} + + + +/* + * poll_update - update peer poll interval. See Section 3.4.8 of the spec. + */ +void +poll_update(peer, new_hpoll, randomize) + struct peer *peer; + unsigned int new_hpoll; + int randomize; +{ + register struct event *evp; + register U_LONG new_timer; + u_char newpoll, oldpoll; + +#ifdef DEBUG + if (debug > 1) + printf("poll_update(%s, %d, %d)\n", ntoa(&peer->srcadr), + new_hpoll, randomize); +#endif + /* + * Catch reference clocks here. The polling interval for a + * reference clock is fixed and needn't be maintained by us. + */ + if (peer->flags & FLAG_REFCLOCK) + return; + + /* + * This routine * will randomly perturb the new peer.timer if + * requested, to try to prevent synchronization with the remote + * peer from occuring. There are three options, based on the + * value of randomize: + * + * POLL_NOTRANDOM - essentially the spec algorithm. If + * peer.timer is greater than the new polling interval, + * drop it to the new interval. + * + * POLL_RANDOMCHANGE - make changes randomly. If peer.timer + * must be changed, based on the comparison about, randomly + * perturb the new value of peer.timer. + * + * POLL_MAKERANDOM - make next interval random. Calculate + * a randomly perturbed poll interval. If this value is + * less that peer.timer, update peer.timer. + */ + oldpoll = peer->hpoll; + if ((peer->flags & FLAG_SYSPEER) && new_hpoll > sys_poll) + peer->hpoll = max(peer->minpoll, sys_poll); + else { + if (new_hpoll > peer->maxpoll) + peer->hpoll = peer->maxpoll; + else if (new_hpoll < peer->minpoll) + peer->hpoll = peer->minpoll; + else + peer->hpoll = new_hpoll; + } + + /* hpoll <= maxpoll for sure */ + newpoll = max((u_char)min(peer->ppoll, peer->hpoll), peer->minpoll); + if (randomize == POLL_MAKERANDOM || + (randomize == POLL_RANDOMCHANGE && newpoll != oldpoll)) + new_timer = (1<<(newpoll - 1)) + + ranp2(newpoll - 1) + current_time; + else + new_timer = (1<event_timer); + if (evp->next == 0 || evp->event_time > new_timer) { + TIMER_DEQUEUE(evp); + evp->event_time = new_timer; + TIMER_ENQUEUE(timerqueue, evp); + } +} + +/* + * clear_all - clear all peer filter registers. This is done after + * a step change in the time. + */ +static void +clear_all() +{ + register int i; + register struct peer *peer; + + for (i = 0; i < HASH_SIZE; i++) + for (peer = peer_hash[i]; peer != 0; peer = peer->next) { + /* + * We used to drop all unconfigured pollers here. + * The problem with doing this is that if your best + * time source is unconfigured (there are reasons + * for doing this) and you drop him, he may not + * get around to polling you for a long time. Hang + * on to everyone, dropping their polling intervals + * to the minimum. + */ + peer_clear(peer); + } + + /* + * Clear sys_peer. We'll sync to one later. + */ + sys_peer = 0; + sys_stratum = STRATUM_UNSPEC; + +} + + +/* + * clear - clear peer filter registers. See Section 3.4.7 of the spec. + */ +void +peer_clear(peer) + register struct peer *peer; +{ + register int i; + +#ifdef DEBUG + if (debug) + printf("clear(%s)\n", ntoa(&peer->srcadr)); +#endif + bzero(CLEAR_TO_ZERO(peer), LEN_CLEAR_TO_ZERO); + peer->hpoll = peer->minpoll; + peer->dispersion = NTP_MAXDISPERSE; + for (i = 0; i < NTP_SHIFT; i++) + peer->filter_error[i] = NTP_MAXDISPERSE; + poll_update(peer, peer->minpoll, POLL_RANDOMCHANGE); + clock_select(); + + /* + * Clear out the selection counters + */ + peer->candidate = 0; + peer->select = 0; + peer->correct = 0; + peer->was_sane = 0; + + /* + * Since we have a chance to correct possible funniness in + * our selection of interfaces on a multihomed host, do so + * by setting us to no particular interface. + */ + peer->dstadr = any_interface; +} + + +/* + * clock_filter - add incoming clock sample to filter register and run + * the filter procedure to find the best sample. + */ +void +clock_filter(peer, sample_offset, sample_delay, sample_error) + register struct peer *peer; + l_fp *sample_offset; + s_fp sample_delay; + u_fp sample_error; +{ + register int i; + register u_char *ord; + register s_fp sample_distance, sample_soffset, skew; + s_fp distance[NTP_SHIFT]; + +#ifdef DEBUG + if (debug) + printf("clock_filter(%s, %s, %s, %s)\n", + ntoa(&peer->srcadr), lfptoa(sample_offset, 6), + fptoa(sample_delay, 5), ufptoa(sample_error, 5)); +#endif + + /* + * Update sample errors and calculate distances. + * We know NTP_SKEWFACTOR == 16 + */ + skew = sys_clock - peer->update; + peer->update = sys_clock; + for (i = 0; i < NTP_SHIFT; i++) { + distance[i] = peer->filter_error[i]; + if (peer->filter_error[i] < NTP_MAXDISPERSE) { + peer->filter_error[i] += skew; + distance[i] += (peer->filter_delay[i] >> 1); + } + } + + /* + * We keep a sort by distance of the current contents of the + * shift registers. We update this by (1) removing the + * register we are going to be replacing from the sort, and + * (2) reinserting it based on the new distance value. + */ + ord = peer->filter_order; + sample_distance = sample_error + (sample_delay >> 1); + sample_soffset = LFPTOFP(sample_offset); + + for (i = 0; i < NTP_SHIFT-1; i++) /* find old value */ + if (ord[i] == peer->filter_nextpt) + break; + for ( ; i < NTP_SHIFT-1; i++) /* i is current, move everything up */ + ord[i] = ord[i+1]; + /* Here, last slot in ord[] is empty */ + + if (sample_error >= NTP_MAXDISPERSE) + /* + * Last slot for this guy. + */ + i = NTP_SHIFT-1; + else { + register int j; + register u_fp *errorp; + + errorp = peer->filter_error; + /* + * Find where he goes in, then shift everyone else down + */ + if (peer->hmode == MODE_BCLIENT) { + register s_fp *soffsetp; + /* + * Sort by offset. The most positive offset + * should correspond to the minimum delay. + */ + soffsetp = peer->filter_soffset; + for (i = 0; i < NTP_SHIFT-1; i++) + if (errorp[ord[i]] >= NTP_MAXDISPERSE + || sample_soffset >= soffsetp[ord[i]]) + break; + } else { + /* + * Sort by distance. + */ + for (i = 0; i < NTP_SHIFT-1; i++) + if (errorp[ord[i]] >= NTP_MAXDISPERSE + || sample_distance <= distance[ord[i]]) + break; + } + + for (j = NTP_SHIFT-1; j > i; j--) + ord[j] = ord[j-1]; + } + ord[i] = peer->filter_nextpt; + + /* + * Got everything in order. Insert sample in current register + * and increment nextpt. + */ + peer->filter_delay[peer->filter_nextpt] = sample_delay; + peer->filter_offset[peer->filter_nextpt] = *sample_offset; + peer->filter_soffset[peer->filter_nextpt] = sample_soffset; + peer->filter_error[peer->filter_nextpt] = sample_error; + distance[peer->filter_nextpt] = sample_distance; + peer->filter_nextpt++; + if (peer->filter_nextpt >= NTP_SHIFT) + peer->filter_nextpt = 0; + + /* + * Now compute the dispersion, and assign values to delay and + * offset. If there are no samples in the register, delay and + * offset are not touched and dispersion is set to the maximum. + */ + if (peer->filter_error[ord[0]] >= NTP_MAXDISPERSE) { + peer->dispersion = NTP_MAXDISPERSE; + } else { + register s_fp d; + + peer->delay = peer->filter_delay[ord[0]]; + peer->offset = peer->filter_offset[ord[0]]; + peer->soffset = LFPTOFP(&peer->offset); + peer->dispersion = peer->filter_error[ord[0]]; + for (i = 1; i < NTP_SHIFT; i++) { + if (peer->filter_error[ord[i]] >= NTP_MAXDISPERSE) + d = NTP_MAXDISPERSE; + else { + d = peer->filter_soffset[ord[i]] + - peer->filter_soffset[ord[0]]; + if (d < 0) + d = -d; + if (d > NTP_MAXDISPERSE) + d = NTP_MAXDISPERSE; + } + /* + * XXX This *knows* NTP_FILTER is 1/2 + */ + peer->dispersion += (u_fp)(d) >> i; + } + /* + * Calculate synchronization distance backdated to + * sys_lastselect (clock_select will fix it). + * We know NTP_SKEWFACTOR == 16 + */ + d = peer->delay; + if (d < 0) + d = -d; + d += peer->rootdelay; + peer->synch = (d>>1) + + peer->rootdispersion + peer->dispersion + - (sys_clock - sys_lastselect); + } + /* + * We're done + */ +} + + +/* + * clock_select - find the pick-of-the-litter clock + */ +void +clock_select() +{ + register struct peer *peer; + register int i; + register int nlist, nl3; + register s_fp d, e; + register int j; + register int n; + register int allow, found, k; + /* XXX correct? */ + s_fp low = 0x7ffffff; + s_fp high = 0x00000000; + u_fp synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK]; + struct peer *osys_peer; + static int list_alloc = 0; + static struct endpoint *endpoint; + static int *index; + static struct peer **peer_list; + static int endpoint_size = 0, index_size = 0, peer_list_size = 0; + +#ifdef DEBUG + if (debug > 1) + printf("clock_select()\n"); +#endif + + 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(index); + free(peer_list); + } + while (list_alloc < nlist) { + list_alloc += 5; + endpoint_size += 5 * 3 * sizeof *endpoint; + index_size += 5 * 3 * sizeof *index; + peer_list_size += 5 * sizeof *peer_list; + } + endpoint = (struct endpoint *)emalloc(endpoint_size); + index = (int *)emalloc(index_size); + peer_list = (struct peer **)emalloc(peer_list_size); + } + + /* + * This first chunk of code is supposed to go through all + * peers we know about to find the NTP_MAXLIST peers which + * are most likely to succeed. We run through the list + * doing the sanity checks and trying to insert anyone who + * looks okay. We are at all times aware that we should + * only keep samples from the top two strata and we only need + * NTP_MAXLIST of them. + */ + nlist = nl3 = 0; /* none yet */ + for (n = 0; n < HASH_SIZE; n++) { + for (peer = peer_hash[n]; peer != 0; peer = peer->next) { + /* + * Clear peer selection stats + */ + peer->was_sane = 0; + peer->correct = 0; + peer->candidate = 0; + peer->select = 0; + + peer->flags &= ~FLAG_SYSPEER; + /* + * Update synch distance (NTP_SKEWFACTOR == 16) + */ + peer->synch += (sys_clock - sys_lastselect); + + if (peer->reach == 0) + continue; /* unreachable */ + if (peer->stratum > 1 && + peer->refid == peer->dstadr->sin.sin_addr.s_addr) + continue; /* sync loop */ + if (peer->stratum >= NTP_MAXSTRATUM || + peer->stratum > sys_stratum) + continue; /* bad stratum */ + + if (peer->dispersion >= NTP_MAXDISPERSE) { + peer->seldisptoolarge++; + continue; /* too noisy or broken */ + } + if (peer->org.l_ui < peer->reftime.l_ui) { + peer->selbroken++; + continue; /* very broken host */ + } + + /* + * This one seems sane. + */ + peer->was_sane = 1; + peer_list[nlist++] = peer; + + /* + * Insert each interval endpoint on the sorted list. + */ + e = peer->soffset + peer->synch; /* Upper end */ + for (i = nl3 - 1; i >= 0; i--) { + if (e >= endpoint[index[i]].val) + break; + index[i + 3] = index[i]; + } + index[i + 3] = nl3; + endpoint[nl3].type = 1; + endpoint[nl3++].val = e; + + e -= peer->synch; /* Center point */ + for ( ; i >= 0; i--) { + if (e >= endpoint[index[i]].val) + break; + index[i + 2] = index[i]; + } + index[i + 2] = nl3; + endpoint[nl3].type = 0; + endpoint[nl3++].val = e; + + e -= peer->synch; /* Lower end */ + for ( ; i >= 0; i--) { + if (e >= endpoint[index[i]].val) + break; + index[i + 1] = index[i]; + } + index[i + 1] = nl3; + endpoint[nl3].type = -1; + endpoint[nl3++].val = e; + } + } + sys_lastselect = sys_clock; + +#ifdef DEBUG + if (debug > 2) + for (i = 0; i < nl3; i++) + printf("select: endpoint %2d %s\n", + endpoint[index[i]].type, + fptoa(endpoint[index[i]].val, 6)); +#endif + + i = 0; + j = nl3 - 1; + allow = nlist; /* falsetickers assumed */ + found = 0; + while (allow > 0) { + allow--; + for (n = 0; i <= j; i++) { + n += endpoint[index[i]].type; + if (n < 0) + break; + if (endpoint[index[i]].type == 0) + found++; + } + for (n = 0; i <= j; j--) { + n += endpoint[index[j]].type; + if (n > 0) + break; + if (endpoint[index[j]].type == 0) + found++; + } + if (found > allow) + break; + low = endpoint[index[i++]].val; + high = endpoint[index[j--]].val; + } + if ((allow << 1) >= nlist) { + if (debug) + printf("clock_select: no intersection\n"); + if (sys_peer != 0) + report_event(EVNT_PEERSTCHG, (struct peer *)0); + sys_peer = 0; + sys_stratum = STRATUM_UNSPEC; + return; + } + +#ifdef DEBUG + if (debug > 2) + printf("select: low %s high %s\n", fptoa(low, 6), + fptoa(high, 6)); +#endif + + /* + * Clustering algorithm. Process intersection list to discard + * outlyers. First, construct candidate list in cluster order. + * Cluster order is determined by the sum of peer + * synchronization distance plus scaled stratum. + */ + + j = 0; + for (i = 0; i < nlist; i++) { + peer = peer_list[i]; + if (peer->soffset < low || high < peer->soffset) + continue; + peer->correct = 1; + d = peer->synch + ((U_LONG)peer->stratum << NTP_DISPFACTOR); + if (j >= NTP_MAXCLOCK) { + if (d >= synch[j - 1]) + continue; + else + j--; + } + for (k = j; k > 0; k--) { + if (d >= synch[k - 1]) + break; + synch[k] = synch[k - 1]; + peer_list[k] = peer_list[k - 1]; + } + peer_list[k] = peer; + synch[k] = d; + j++; + } + nlist = j; +#ifdef DEBUG + if (debug > 2) + for (i = 0; i < nlist; i++) + printf("select: candidate %s cdist %s\n", + ntoa(&peer_list[i]->srcadr), + fptoa(synch[i], 6)); +#endif + + /* + * Now, prune outlyers by root dispersion. + */ + + for (i = 0; i < nlist; i++) { + peer = peer_list[i]; + peer->candidate = i + 1; + error[i] = peer_list[i]->rootdispersion + + peer_list[i]->dispersion + + (sys_clock - peer_list[i]->update); + } + while (1) { + u_fp maxd = 0; + e = error[0]; + for (k = i = nlist - 1; i >= 0; i--) { + u_fp sdisp = 0; + + for (j = nlist - 1; j >= 0; j--) { + d = peer_list[i]->soffset + - peer_list[j]->soffset; + if (d < 0) + d = -d; + sdisp += d; + sdisp = ((sdisp>>1) + sdisp) >> 1; + } + peer_list[i]->selectdisp = sdisp; + if (sdisp > maxd) { + maxd = sdisp; + k = i; + } + if (error[i] < e) + e = error[i]; + } + if (nlist <= NTP_MINCLOCK || maxd <= e || + peer_list[k]->flags & FLAG_PREFER) + break; + for (j = k + 1; j < nlist; j++) { + peer_list[j - 1] = peer_list[j]; + error[j - 1] = error[j]; + } + nlist--; + } + +#ifdef DEBUG + if (debug > 1) { + for (i = 0; i < nlist; i++) + printf("select: survivor %s offset %s, cdist %s\n", + ntoa(&peer_list[i]->srcadr), + lfptoa(&peer_list[i]->offset, 6), + fptoa(synch[i], 5)); + } +#endif + + /* + * What remains is a list of less than NTP_MINCLOCK peers. + * First record their order, then choose a peer. If the + * head of the list has a lower stratum than sys_peer + * choose him right off. If not, see if sys_peer is in + * the list. If so, keep him. If not, take the top of + * the list anyway. Also, clamp the polling intervals. + */ + osys_peer = sys_peer; + for (i = nlist - 1; i >= 0; i--) { + if (peer_list[i]->flags & FLAG_PREFER) + sys_peer = peer_list[i]; + peer_list[i]->select = i + 1; + peer_list[i]->flags |= FLAG_SYSPEER; + poll_update(peer_list[i], peer_list[i]->hpoll, + POLL_RANDOMCHANGE); + } + if (sys_peer == 0 || sys_peer->stratum > peer_list[0]->stratum) { + sys_peer = peer_list[0]; + } else { + for (i = 1; i < nlist; i++) + if (peer_list[i] == sys_peer) + break; + if (i < nlist) + sys_wanderhold++; + else + sys_peer = peer_list[0]; + } + + /* + * If we got a new system peer from all of this, report the event. + */ + if (osys_peer != sys_peer) + report_event(EVNT_PEERSTCHG, (struct peer *)0); + + /* + * Combine the offsets of the survivors to form a weighted + * offset. + */ + clock_combine(peer_list, nlist); +} + +/* + * clock_combine - combine offsets from selected peers + * + * Note: this routine uses only those peers at the lowest stratum. + * Strictly speaking, this is at variance with the spec. + */ +void +clock_combine(peers, npeers) + struct peer **peers; + int npeers; +{ + register int i, j, k; + register u_fp a, b, d; + u_fp synch[NTP_MAXCLOCK]; + l_fp coffset[NTP_MAXCLOCK]; + l_fp diff; + + /* + * Sort peers by cluster distance as in the outlyer algorithm. If + * the preferred peer is found, use its offset only. + */ + k = 0; + for (i = 0; i < npeers; i++) { + if (peers[i]->stratum > sys_peer->stratum) continue; + if (peers[i]->flags & FLAG_PREFER) { + sys_offset = peers[i]->offset; + pps_update = current_time; +#ifdef DEBUG + printf("combine: prefer offset %s\n", + lfptoa(&sys_offset, 6)); +#endif + return; + } + d = peers[i]->synch; + for (j = k; j > 0; j--) { + if (synch[j - 1] <= d) + break; + synch[j] = synch[j - 1]; + coffset[j] = coffset[j - 1]; + } + synch[j] = d; + coffset[j] = peers[i]->offset; + k++; + } + /* + * Succesively combine the two offsets with the highest + * distance and enter the result into the sorted list. + */ + for (i = k - 2; i >= 0; i--) { + /* + * The possible weights for the most distant offset + * are 1/2, 1/4, 1/8 and zero. We combine the synch + * distances as if they were variances of the offsets; + * the given weights allow us to stay within 16/15 of + * the optimum combined variance at each step, and + * within 8/7 on any series. + * + * The breakeven points for the weigths are found + * where the smaller distance is 3/8, 3/16 and 1/16 + * of the sum, respectively. + */ + d = synch[i]; + a = (d + synch[i + 1]) >> 2; /* (d1+d2)/4 */ + b = a>>1; /* (d1+d2)/8 */ + if (d <= (b>>1)) /* d1 <= (d1+d2)/16 */ + /* + * Below 1/16, no combination is done, + * we just drop the distant offset. + */ + continue; + /* + * The offsets are combined by shifting their + * difference the appropriate number of times and + * adding it back in. + */ + diff = coffset[i + 1]; + L_SUB(&diff, &coffset[i]); + L_RSHIFT(&diff); + if (d >= a + b) { /* d1 >= 3(d1+d2)/8 */ + /* + * Above 3/8, the weight is 1/2, and the + * combined distance is (d1+d2)/4 + */ + d = a; + } else { + a >>= 2; /* (d1+d2)/16 */ + L_RSHIFT(&diff); + if (d >= a + b) { /* d1 >= 3(d1+d2)/16 */ + /* + * Between 3/16 and 3/8, the weight + * is 1/4, and the combined distance + * is (9d1+d2)/16 = d1/2 + (d1+d2)/16 + */ + d = (d>>1) + a; + } else { + /* + * Between 1/16 and 3/16, the weight + * is 1/8, and the combined distance + * is (49d1+d2)/64 = 3d1/4+(d1+d2)/64 + * (We know d > a, so the shift is safe). + */ + L_RSHIFT(&diff); + d -= (d - a)>>2; + } + } + /* + * Now we can make the combined offset and insert it + * in the list. + */ + L_ADD(&diff, &coffset[i]); + for (j = i; j > 0; j--) { + if (d >= synch[j - 1]) + break; + synch[j] = synch[j - 1]; + coffset[j] = coffset[j - 1]; + } + synch[j] = d; + coffset[j] = diff; + } + /* + * The result is put where clock_update() can find it. + */ + sys_offset = coffset[0]; + +#ifdef DEBUG + if (debug) { + printf("combine: offset %s\n", lfptoa(&sys_offset, 6)); + } +#endif + +} + + + +/* + * fast_xmit - fast path send for stateless (non-)associations + */ +void +fast_xmit(rbufp, rmode, authentic) + struct recvbuf *rbufp; + int rmode; + int authentic; +{ + struct pkt xpkt; + register struct pkt *rpkt; + u_char xmode; + u_short xkey = 0; + int docrypt = 0; + l_fp xmt_ts; + +#ifdef DEBUG + if (debug > 1) + printf("fast_xmit(%s, %d)\n", ntoa(&rbufp->recv_srcadr), rmode); +#endif + + /* + * Make up new packet and send it quick + */ + rpkt = &rbufp->recv_pkt; + if (rmode == MODE_ACTIVE) + xmode = MODE_PASSIVE; + else + xmode = MODE_SERVER; + + if (rbufp->recv_length >= LEN_PKT_MAC) { + docrypt = rbufp->recv_length - LEN_PKT_NOMAC; + if (authentic) + xkey = ntohl(rpkt->keyid); + } + + 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.ppoll = max(NTP_MINPOLL, rpkt->ppoll); + xpkt.precision = sys_precision; + xpkt.rootdelay = HTONS_FP(sys_rootdelay); + xpkt.rootdispersion = HTONS_FP(sys_rootdispersion + + (FP_SECOND >> (-(int)sys_precision)) + + LFPTOFP(&sys_refskew)); + xpkt.refid = sys_refid; + HTONL_FP(&sys_reftime, &xpkt.reftime); + xpkt.org = rpkt->xmt; + HTONL_FP(&rbufp->recv_time, &xpkt.rec); + + /* + * If we are encrypting, do it. Else don't. Easy. + */ + if (docrypt) { + int maclen; + + xpkt.keyid = htonl(xkey); + auth1crypt(xkey, (U_LONG *)&xpkt, LEN_PKT_NOMAC); + get_systime(&xmt_ts); + L_ADDUF(&xmt_ts, sys_authdelay); + HTONL_FP(&xmt_ts, &xpkt.xmt); + maclen = auth2crypt(xkey, (U_LONG *)&xpkt, LEN_PKT_NOMAC); + sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, &xpkt, + LEN_PKT_NOMAC + maclen); + } else { + /* + * Get xmt timestamp, then send it without mac field + */ + get_systime(&xmt_ts); + HTONL_FP(&xmt_ts, &xpkt.xmt); + sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, &xpkt, + LEN_PKT_NOMAC); + } +} + +/* Find the precision of the system clock by watching how the current time + * changes as we read it repeatedly. + * + * struct timeval is only good to 1us, which may cause problems as machines + * get faster, but until then the logic goes: + * + * If a machine has precision (i.e. accurate timing info) > 1us, then it will + * probably use the "unused" low order bits as a counter (to force time to be + * a strictly increaing variable), incrementing it each time any process + * requests the time [[ or maybe time will stand still ? ]]. + * + * SO: the logic goes: + * + * IF the difference from the last time is "small" (< MINSTEP) + * THEN this machine is "counting" with the low order bits + * ELIF this is not the first time round the loop + * THEN this machine *WAS* counting, and has now stepped + * ELSE this machine has precision < time to read clock + * + * SO: if it exits on the first loop, assume "full accuracy" (1us) + * otherwise, take the log2(observered difference, rounded UP) + * + * MINLOOPS > 1 ensures that even if there is a STEP between the initial call + * and the first loop, it doesn't stop too early. + * Making it even greater allows MINSTEP to be reduced, assuming that the + * chance of MINSTEP-1 other processes getting in and calling gettimeofday + * between this processes's calls. + * Reducing MINSTEP may be necessary as this sets an upper bound for the time + * to actually call gettimeofday. + */ + +#define DUSECS 1000000 /* us's as returned by gettime */ +#define HUSECS (1024*1024) /* Hex us's -- used when shifting etc */ +#define MINSTEP 5 /* some systems increment uS on each call */ + /* Don't use "1" as some *other* process may read too*/ + /*We assume no system actually *ANSWERS* in this time*/ +#define MAXLOOPS DUSECS /* if no STEP in a complete second, then FAST machine*/ +#define MINLOOPS 2 /* ensure at least this many loops */ + +int default_get_precision() +{ + struct timeval tp; + struct timezone tzp; + long last; + int i; + long diff; + long val; + int minsteps = 2; /* need at least this many steps */ + + GETTIMEOFDAY(&tp, &tzp); + last = tp.tv_usec; + for (i = - --minsteps; i< MAXLOOPS; i++) { + gettimeofday(&tp, &tzp); + diff = tp.tv_usec - last; + if (diff < 0) diff += DUSECS; + if (diff > MINSTEP) if (minsteps-- <= 0) break; + last = tp.tv_usec; + } + + syslog(LOG_INFO, "precision calculation given %dus after %d loop%s", + diff, i, (i==1) ? "" : "s"); + + diff = (diff*3) / 2; /* round it up 1.5 is approx sqrt(2) */ + if (i >= MAXLOOPS) diff = 1; /* No STEP, so FAST machine */ + if (i == 0) diff = 1; /* time to read clock >= precision */ + for (i=0, val=HUSECS; val>0; i--, val >>= 1) if (diff >= val) return i; + return DEFAULT_SYS_PRECISION /* Something's BUST, so lie ! */; +} + +/* + * init_proto - initialize the protocol module's data + */ +void +init_proto() +{ + l_fp dummy; + + /* + * Fill in the sys_* stuff. Default is don't listen + * to broadcasting, don't authenticate. + */ + sys_leap = LEAP_NOTINSYNC; + sys_stratum = STRATUM_UNSPEC; + sys_precision = (s_char)default_get_precision(); + sys_rootdelay = 0; + sys_rootdispersion = 0; + sys_refid = 0; + sys_reftime.l_ui = sys_reftime.l_uf = 0; + sys_refskew.l_i = NTP_MAXSKEW; sys_refskew.l_f = 0; + sys_peer = 0; + sys_poll = NTP_MINPOLL; + get_systime(&dummy); + sys_lastselect = sys_clock; + + sys_bclient = 0; + sys_bdelay = DEFBROADDELAY; + + sys_authenticate = 0; + + sys_stattime = 0; + sys_badstratum = 0; + sys_oldversionpkt = 0; + sys_newversionpkt = 0; + sys_badlength = 0; + sys_unknownversion = 0; + sys_processed = 0; + sys_badauth = 0; + sys_wanderhold = 0; + + syslog(LOG_NOTICE, "default precision is initialized to 2**%d", sys_precision); +} + + +/* + * proto_config - configure the protocol module + */ +void +proto_config(item, value) + int item; + LONG value; +{ + /* + * Figure out what he wants to change, then do it + */ + switch (item) { + case PROTO_BROADCLIENT: + /* + * Turn on/off facility to listen to broadcasts + */ + sys_bclient = (int)value; + if (sys_bclient) + io_setbclient(); + else + io_unsetbclient(); + break; + + case PROTO_PRECISION: + /* + * Set system precision + */ + sys_precision = (s_char)value; + break; + + case PROTO_BROADDELAY: + /* + * Set default broadcast delay + */ + sys_bdelay = (((U_LONG)value) + 0x00000800) & 0xfffff000; + break; + + case PROTO_AUTHENTICATE: + /* + * Specify the use of authenticated data + */ + sys_authenticate = (int)value; + break; + + + case PROTO_AUTHDELAY: + /* + * Provide an authentication delay value. Round it to + * the microsecond. This is crude. + */ + sys_authdelay = (((U_LONG)value) + 0x00000800) & 0xfffff000; + break; + + case PROTO_MAXSKEW: + /* + * Set the maximum skew value + */ + syslog(LOG_ERR, + "proto_config: attempt to set maxskew (obsolete)"); + break; + + case PROTO_SELECT: + /* + * Set the selection algorithm. + */ + syslog(LOG_ERR, + "proto_config: attempt to set selection algorithm (obsolete)"); + break; + + default: + /* + * Log this error + */ + syslog(LOG_ERR, "proto_config: illegal item %d, value %ld", + item, value); + break; + } +} + + +/* + * proto_clr_stats - clear protocol stat counters + */ +void +proto_clr_stats() +{ + sys_badstratum = 0; + sys_oldversionpkt = 0; + sys_newversionpkt = 0; + sys_unknownversion = 0; + sys_badlength = 0; + sys_processed = 0; + sys_badauth = 0; + sys_wanderhold = 0; + sys_stattime = current_time; +} diff --git a/contrib/xntpd/xntpd/ntp_refclock.c b/contrib/xntpd/xntpd/ntp_refclock.c new file mode 100644 index 0000000000..5199a1acbd --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_refclock.c @@ -0,0 +1,439 @@ +/* ntp_refclock.c,v 3.1 1993/07/06 01:11:25 jbj Exp + * ntp_refclock - processing support for reference clocks + */ +#include +#include + +#include "ntpd.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +#ifdef REFCLOCK +/* + * 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. 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. Refclock_peer and refclock_unpeer are called to + * initialize and terminate reference clock associations. + */ + +/* + * The refclock configuration table. Imported from refclock_conf.c + */ +extern struct refclock *refclock_conf[]; +extern u_char num_refclock_conf; + +/* + * Imported from the I/O module + */ +extern struct interface *any_interface; +extern struct interface *loopback_interface; + +/* + * Imported from the timer module + */ +extern U_LONG current_time; +extern struct event timerqueue[]; + +/* + * Imported from the main and peer modules. We use the same + * algorithm for spacing out timers at configuration time that + * the peer module does. + */ +extern U_LONG init_peer_starttime; +extern int initializing; +extern int debug; + +static void refclock_transmit P((struct peer *)); + +/* + * refclock_newpeer - initialize and start a reference clock + */ +int +refclock_newpeer(peer) + struct peer *peer; +{ + u_char clktype; + int unit; + + /* + * Sanity... + */ + if (!ISREFCLOCKADR(&peer->srcadr)) { + syslog(LOG_ERR, + "Internal error: attempting to initialize %s as reference clock", + ntoa(&peer->srcadr)); + return 0; + } + + clktype = REFCLOCKTYPE(&peer->srcadr); + unit = REFCLOCKUNIT(&peer->srcadr); + + /* + * If clktype is invalid, return + */ + if (clktype >= num_refclock_conf + || refclock_conf[clktype]->clock_start == noentry) { + syslog(LOG_ERR, + "Can't initialize %s, no support for clock type %d\n", + ntoa(&peer->srcadr), clktype); + return 0; + } + + /* + * Complete initialization of peer structure. + */ + peer->refclktype = clktype; + peer->refclkunit = unit; + peer->flags |= FLAG_REFCLOCK; + peer->stratum = STRATUM_REFCLOCK; + peer->ppoll = peer->minpoll; + peer->hpoll = peer->minpoll; + peer->maxpoll = peer->minpoll; + + /* + * Check the flags. If the peer is configured in client mode + * but prefers the broadcast client filter algorithm, change + * him over. + */ + if (peer->hmode == MODE_CLIENT + && refclock_conf[clktype]->clock_flags & REF_FLAG_BCLIENT) + peer->hmode = MODE_BCLIENT; + + peer->event_timer.peer = peer; + peer->event_timer.event_handler = refclock_transmit; + + /* + * Do driver dependent initialization + */ + if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { + syslog(LOG_ERR, "Clock dependent initialization of %s failed", + ntoa(&peer->srcadr)); + return 0; + } + + /* + * Set up the timeout for reachability determination. + */ + if (initializing) { + init_peer_starttime += (1 << EVENT_TIMEOUT); + if (init_peer_starttime >= (1 << peer->minpoll)) + init_peer_starttime = (1 << EVENT_TIMEOUT); + peer->event_timer.event_time = init_peer_starttime; + } else { + peer->event_timer.event_time = current_time + (1 << peer->hpoll); + } + TIMER_ENQUEUE(timerqueue, &peer->event_timer); + return 1; +} + + +/* + * refclock_unpeer - shut down a clock + */ +void +refclock_unpeer(peer) + struct peer *peer; +{ + /* + * Do sanity checks. I know who programmed the calling routine! + */ + if (peer->refclktype >= num_refclock_conf + || refclock_conf[peer->refclktype]->clock_shutdown == noentry) { + syslog(LOG_ERR, "Attempting to shutdown %s: no such clock!", + ntoa(&peer->srcadr)); + return; + } + + /* + * Tell the driver we're finished. + */ + (refclock_conf[peer->refclktype]->clock_shutdown)(peer->refclkunit); +} + + +/* + * refclock_transmit - replacement transmit procedure for reference clocks + */ +static void +refclock_transmit(peer) + struct peer *peer; +{ + u_char opeer_reach; + int clktype; + int unit; + + clktype = peer->refclktype; + unit = peer->refclkunit; + peer->sent++; + + /* + * The transmit procedure is supposed to freeze a time stamp. + * Get one just for fun, and to tell when we last were here. + */ + get_systime(&peer->xmt); + + /* + * Fiddle reachability. + */ + opeer_reach = peer->reach; + peer->reach <<= 1; + if (peer->reach == 0) { + /* + * Clear this one out. No need to redo + * selection since this fellow will definitely + * be suffering from dispersion madness. + */ + if (opeer_reach != 0) { + peer_clear(peer); + peer->timereachable = current_time; + report_event(EVNT_UNREACH, peer); + } + + /* + * Update reachability and poll variables + */ + } else if ((opeer_reach & 3) == 0) { + + l_fp off; + + if (peer->valid > 0) peer->valid--; + if (peer->hpoll > peer->minpoll) peer->hpoll--; + off.l_ui = off.l_uf = 0; + clock_filter(peer, &off, 0, NTP_MAXDISPERSE); + if (peer->flags & FLAG_SYSPEER) + clock_select(); + } else { + if (peer->valid < NTP_SHIFT) { + peer->valid++; + } else { + if (peer->hpoll < peer->maxpoll) + peer->hpoll++; + } + } + + /* + * If he wants to be polled, do it. + */ + if (refclock_conf[clktype]->clock_poll != noentry) + (refclock_conf[clktype]->clock_poll)(unit, peer); + + /* + * Finally, reset the timer + */ + peer->event_timer.event_time += (1 << peer->hpoll); + TIMER_ENQUEUE(timerqueue, &peer->event_timer); +} + + +/* + * refclock_receive - simulate the receive and packet procedures for clocks + */ +void +refclock_receive(peer, offset, delay, dispersion, reftime, rectime, leap) + struct peer *peer; + l_fp *offset; + s_fp delay; + u_fp dispersion; + l_fp *reftime; + l_fp *rectime; + int leap; +{ + int restrict; + int trustable; + extern u_char leap_indicator; + +#ifdef DEBUG + if (debug) + printf("refclock_receive: %s %s %s %s)\n", + ntoa(&peer->srcadr), lfptoa(offset, 6), + fptoa(delay, 5), ufptoa(dispersion, 5)); +#endif + + /* + * The name of this routine is actually a misnomer since + * we mostly simulate the variable setting of the packet + * procedure. We do check the flag values, though, and + * set the trust bits based on this. + */ + restrict = restrictions(&peer->srcadr); + if (restrict & (RES_IGNORE|RES_DONTSERVE)) { + /* + * Ours is not to reason why... + */ + return; + } + + peer->received++; + peer->processed++; + peer->timereceived = current_time; + if (restrict & RES_DONTTRUST) + trustable = 0; + else + trustable = 1; + + if (peer->flags & FLAG_AUTHENABLE) { + if (trustable) + peer->flags |= FLAG_AUTHENTIC; + else + peer->flags &= ~FLAG_AUTHENTIC; + } + if (leap == 0) + peer->leap = leap_indicator; + else + peer->leap = leap; + + /* + * Set the timestamps. rec and org are in local time, + * while ref is in timecode time. + */ + peer->rec = peer->org = *rectime; + peer->reftime = *reftime; + + /* + * If the interface has been set to any_interface, set it + * to the loop back address if we have one. This is so + * that peers which are unreachable are easy to see in + * peer display. + */ + if (peer->dstadr == any_interface && loopback_interface != 0) + peer->dstadr = loopback_interface; + + /* + * Set peer.pmode based on the hmode. For appearances only. + */ + switch (peer->hmode) { + case MODE_ACTIVE: + peer->pmode = MODE_PASSIVE; + break; + case MODE_CLIENT: + peer->pmode = MODE_SERVER; + break; + case MODE_BCLIENT: + peer->pmode = MODE_BROADCAST; + break; + default: + syslog(LOG_ERR, "refclock_receive: internal error, mode = %d", + peer->hmode); + } + + /* + * Abandon ship if the radio came bum. We only got this far + * in order to make pretty billboards, even if bum. + */ + if (leap == LEAP_NOTINSYNC) return; + /* + * If this guy was previously unreachable, report him + * reachable. + */ + if (peer->reach == 0) report_event(EVNT_REACH, peer); + peer->reach |= 1; + + /* + * Give the data to the clock filter and update the clock. + */ + clock_filter(peer, offset, delay, dispersion); + clock_update(peer); +} + + +/* + * refclock_control - set and/or return clock values + */ +void +refclock_control(srcadr, in, out) + struct sockaddr_in *srcadr; + struct refclockstat *in; + struct refclockstat *out; +{ + u_char clktype; + int unit; + + /* + * Sanity... + */ + if (!ISREFCLOCKADR(srcadr)) { + syslog(LOG_ERR, + "Internal error: refclock_control received %s as reference clock", + ntoa(srcadr)); + return; + } + + clktype = REFCLOCKTYPE(srcadr); + unit = REFCLOCKUNIT(srcadr); + + /* + * If clktype is invalid, return + */ + if (clktype >= num_refclock_conf + || refclock_conf[clktype]->clock_control == noentry) { + syslog(LOG_ERR, + "Internal error: refclock_control finds %s as not supported", + ntoa(srcadr)); + return; + } + + /* + * Give the stuff to the clock. + */ + (refclock_conf[clktype]->clock_control)(unit, in, out); +} + + + +/* + * refclock_buginfo - return debugging info + */ +void +refclock_buginfo(srcadr, bug) + struct sockaddr_in *srcadr; + struct refclockbug *bug; +{ + u_char clktype; + int unit; + + /* + * Sanity... + */ + if (!ISREFCLOCKADR(srcadr)) { + syslog(LOG_ERR, + "Internal error: refclock_buginfo received %s as reference clock", + ntoa(srcadr)); + return; + } + + clktype = REFCLOCKTYPE(srcadr); + unit = REFCLOCKUNIT(srcadr); + + /* + * If clktype is invalid or call is unsupported, return + */ + if (clktype >= num_refclock_conf || + refclock_conf[clktype]->clock_buginfo == noentry) { + return; + } + + /* + * Give the stuff to the clock. + */ + (refclock_conf[clktype]->clock_buginfo)(unit, bug); +} + +/* + * init_refclock - initialize the reference clock drivers + */ +void +init_refclock() +{ + register u_char i; + + for (i = 0; i < num_refclock_conf; i++) { + if (refclock_conf[i]->clock_init != noentry) + (refclock_conf[i]->clock_init)(); + } +} +#endif diff --git a/contrib/xntpd/xntpd/ntp_request.c b/contrib/xntpd/xntpd/ntp_request.c new file mode 100644 index 0000000000..96def3fa13 --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_request.c @@ -0,0 +1,2336 @@ +/* ntp_request.c,v 3.1 1993/07/06 01:11:26 jbj Exp + * ntp_request.c - respond to information requests + */ +#include +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "signal.h" +#include "ntp_request.h" +#include "ntp_control.h" +#include "ntp_refclock.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" + +/* + * Structure to hold request procedure information + */ +#define NOAUTH 0 +#define AUTH 1 + +#define NO_REQUEST (-1) + +struct req_proc { + short request_code; /* defined request code */ + short needs_auth; /* true when authentication needed */ + short sizeofitem; /* size of request data item */ + void (*handler)(); /* 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_in *, struct interface *, struct req_pkt *, int)); +static char * prepare_pkt P((struct sockaddr_in *, struct interface *, struct req_pkt *, u_int)); +static char * more_pkt P((void)); +static void flush_pkt P((void)); +static void peer_list P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void peer_list_sum P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void peer_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void peer_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void sys_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void sys_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void mem_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void io_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void timer_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void loop_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_conf P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_unconf P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void set_sys_flag P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void clr_sys_flag P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void setclr_flags P((struct sockaddr_in *, struct interface *, struct req_pkt *, int)); +static void do_monitor P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_nomonitor P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void list_restrict P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_resaddflags P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_ressubflags P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_unrestrict P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_restrict P((struct sockaddr_in *, struct interface *, struct req_pkt *, int)); +static void mon_getlist P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void reset_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void reset_peer P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_key_reread P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_dirty_hack P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void dont_dirty_hack P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void trust_key P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void untrust_key P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_trustkey P((struct sockaddr_in *, struct interface *, struct req_pkt *, int)); +static void get_auth_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void reset_auth_stats P((void)); +static void req_get_traps P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void req_set_trap P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void req_clr_trap P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void do_setclr_trap P((struct sockaddr_in *, struct interface *, struct req_pkt *, int)); +static void set_request_keyid P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void set_control_keyid P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void get_ctl_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void get_leap_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +#ifdef REFCLOCK +static void get_clock_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void set_clock_fudge P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +#endif /* REFCLOCK */ +static void set_maxskew P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void set_precision P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void set_select_code P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +#ifdef REFCLOCK +static void get_clkbug_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +#endif /* REFCLOCK */ + +/* + * Xntpd request codes + */ +static struct req_proc xntp_codes[] = { + { REQ_PEER_LIST, NOAUTH, 0, peer_list }, + { REQ_PEER_LIST_SUM, NOAUTH, 0, peer_list_sum }, + { REQ_PEER_INFO, NOAUTH, sizeof(struct info_peer_list), peer_info }, + { REQ_PEER_STATS, NOAUTH, sizeof(struct info_peer_list), peer_stats }, + { REQ_SYS_INFO, NOAUTH, 0, sys_info }, + { REQ_SYS_STATS, NOAUTH, 0, sys_stats }, + { REQ_IO_STATS, NOAUTH, 0, io_stats }, + { REQ_MEM_STATS, NOAUTH, 0, mem_stats }, + { REQ_LOOP_INFO, NOAUTH, 0, loop_info }, + { REQ_TIMER_STATS, NOAUTH, 0, timer_stats }, + { REQ_CONFIG, AUTH, sizeof(struct conf_peer), do_conf }, + { REQ_UNCONFIG, AUTH, sizeof(struct conf_unpeer), do_unconf }, + { REQ_SET_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), set_sys_flag }, + { REQ_CLR_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), clr_sys_flag }, + { REQ_MONITOR, AUTH, 0, do_monitor }, + { REQ_NOMONITOR, AUTH, 0, do_nomonitor }, + { REQ_GET_RESTRICT, NOAUTH, 0, list_restrict }, + { REQ_RESADDFLAGS, AUTH, sizeof(struct conf_restrict), do_resaddflags }, + { REQ_RESSUBFLAGS, AUTH, sizeof(struct conf_restrict), do_ressubflags }, + { REQ_UNRESTRICT, AUTH, sizeof(struct conf_restrict), do_unrestrict }, + { REQ_MON_GETLIST, NOAUTH, 0, mon_getlist }, + { REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), reset_stats }, + { REQ_RESET_PEER, AUTH, sizeof(struct conf_unpeer), reset_peer }, + { REQ_REREAD_KEYS, AUTH, 0, do_key_reread }, + { REQ_DO_DIRTY_HACK, AUTH, 0, do_dirty_hack }, + { REQ_DONT_DIRTY_HACK, AUTH, 0, dont_dirty_hack }, + { REQ_TRUSTKEY, AUTH, sizeof(U_LONG), trust_key }, + { REQ_UNTRUSTKEY, AUTH, sizeof(U_LONG), untrust_key }, + { REQ_AUTHINFO, NOAUTH, 0, get_auth_info }, + { REQ_TRAPS, NOAUTH, 0, req_get_traps }, + { REQ_ADD_TRAP, AUTH, sizeof(struct conf_trap), req_set_trap }, + { REQ_CLR_TRAP, AUTH, sizeof(struct conf_trap), req_clr_trap }, + { REQ_REQUEST_KEY, AUTH, sizeof(U_LONG), set_request_keyid }, + { REQ_CONTROL_KEY, AUTH, sizeof(U_LONG), set_control_keyid }, + { REQ_GET_CTLSTATS, NOAUTH, 0, get_ctl_stats }, + { REQ_GET_LEAPINFO, NOAUTH, 0, get_leap_info }, + { REQ_SET_MAXSKEW, AUTH, sizeof(u_fp), set_maxskew }, + { REQ_SET_PRECISION, AUTH, sizeof(LONG), set_precision }, + { REQ_SET_SELECT_CODE, AUTH, sizeof(U_LONG), set_select_code }, +#ifdef REFCLOCK + { REQ_GET_CLOCKINFO, NOAUTH, sizeof(U_LONG), get_clock_info }, + { REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge), set_clock_fudge }, + { REQ_GET_CLKBUGINFO, NOAUTH, sizeof(U_LONG), get_clkbug_info }, +#endif + { NO_REQUEST, NOAUTH, 0, 0 } +}; + + +/* + * Authentication keyid used to authenticate requests. Zero means we + * don't allow writing anything. + */ +U_LONG 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 */ + +/* + * Imported from the I/O module + */ +extern struct interface *any_interface; + +/* + * Imported from the main routines + */ +extern int debug; + +/* + * Imported from the timer module + */ +extern U_LONG current_time; + +/* + * A hack. To keep the authentication module clear of xntp-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 seqno; +static int nitems; +static int itemsize; +static int databytes; +static char exbuf[RESP_DATA_SIZE]; +static int usingexbuf; +static struct sockaddr_in *toaddr; +static struct interface *frominter; + +/* + * init_request - initialize request data + */ +void +init_request() +{ + 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(srcadr, inter, inpkt, errcode) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; + int errcode; +{ + /* + * fill in the fields + */ + rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0); + 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, (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(srcadr, inter, pkt, structsize) + struct sockaddr_in *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, reqest 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() +{ + /* + * 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); + rpkt.auth_seq = AUTH_SEQ(0, seqno); + rpkt.err_nitems = htons((u_short)nitems); + sendpkt(toaddr, frominter, (struct pkt *)&rpkt, + RESP_HEADER_SIZE+databytes); + numresppkts++; + + /* + * Copy data out of exbuf into the packet. + */ + bcopy(exbuf, &rpkt.data[0], 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() +{ +#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); + rpkt.auth_seq = AUTH_SEQ(0, seqno); + rpkt.err_nitems = htons((u_short)nitems); + sendpkt(toaddr, frominter, (struct pkt *)&rpkt, + RESP_HEADER_SIZE+databytes); + numresppkts++; + } +} + + + +/* + * process_private - process private mode (7) packets + */ +void +process_private(rbufp, mod_okay) + struct recvbuf *rbufp; + int mod_okay; +{ + struct req_pkt *inpkt; + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_proc *proc; + + /* + * Initialize pointers, for convenience + */ + inpkt = (struct req_pkt *)&rbufp->recv_pkt; + srcadr = &rbufp->recv_srcadr; + inter = rbufp->dstadr; + +#ifdef DEBUG + if (debug > 2) + printf("prepare_pkt: impl %d req %d\n", + inpkt->implementation, inpkt->request); +#endif + + /* + * Do some sanity checks on the packet. Return a format + * error if it fails. + */ + if (ISRESPONSE(inpkt->rm_vn_mode) + || ISMORE(inpkt->rm_vn_mode) + || INFO_VERSION(inpkt->rm_vn_mode) > NTP_VERSION + || INFO_VERSION(inpkt->rm_vn_mode) < NTP_OLDVERSION + || INFO_SEQ(inpkt->auth_seq) != 0 + || INFO_ERR(inpkt->err_nitems) != 0 + || INFO_MBZ(inpkt->mbz_itemsize) != 0 + || rbufp->recv_length > REQ_LEN_MAC + || rbufp->recv_length < REQ_LEN_NOMAC) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + + /* + * Get the appropriate procedure list to search. + */ + if (inpkt->implementation == IMPL_UNIV) + proc = univ_codes; + else if (inpkt->implementation == IMPL_XNTPD) + proc = xntp_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 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) { + register U_LONG tmp_ui; + register U_LONG tmp_uf; + + /* + * 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(inpkt->keyid) != info_auth_keyid) { +#ifdef DEBUG + if (debug > 4) + printf( + "failed auth %d info_auth_keyid %u pkt keyid %u\n", + INFO_IS_AUTH(inpkt->auth_seq), + info_auth_keyid, ntohl(inpkt->keyid)); +#endif + req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); + return; + } + if (rbufp->recv_length > REQ_LEN_MAC) { +#ifdef DEBUG + if (debug > 4) + printf("failed pkt length pkt %d req %d too long\n", + rbufp->recv_length, REQ_LEN_MAC); +#endif + 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); +#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. + */ + tmp_ui = ntohl(inpkt->tstamp.l_ui); + tmp_uf = ntohl(inpkt->tstamp.l_uf); + M_SUB(tmp_ui, tmp_uf, rbufp->recv_time.l_ui, + rbufp->recv_time.l_uf); + if (M_ISNEG(tmp_ui, tmp_uf)) + M_NEG(tmp_ui, tmp_uf); + + if (M_ISHIS(tmp_ui, tmp_uf, + INFO_TS_MAXSKEW_UI, INFO_TS_MAXSKEW_UF)) { + /* + * He's a loser. Tell him. + */ + 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_LONG *)inpkt, + REQ_LEN_NOMAC)) { + req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); + return; + } + } + + /* + * If we need data, check to see if we have some. If we + * don't, check to see that there is none (picky, picky). + */ + if (INFO_ITEMSIZE(inpkt->mbz_itemsize) != proc->sizeofitem) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + if (proc->sizeofitem != 0) + if (proc->sizeofitem*INFO_NITEMS(inpkt->err_nitems) + > sizeof(inpkt->data)) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + 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(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct info_peer_list *ip; + register struct peer *pp; + register int i; + extern struct peer *peer_hash[]; + extern struct peer *sys_peer; + + ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_peer_list)); + for (i = 0; i < HASH_SIZE && ip != 0; i++) { + pp = peer_hash[i]; + while (pp != 0 && ip != 0) { + ip->address = pp->srcadr.sin_addr.s_addr; + ip->port = pp->srcadr.sin_port; + ip->hmode = pp->hmode; + ip->flags = 0; + if (pp->flags & FLAG_CONFIG) + ip->flags |= INFO_FLAG_CONFIG; + if (pp == sys_peer) + ip->flags |= INFO_FLAG_SYSPEER; + if (pp->candidate != 0) + ip->flags |= INFO_FLAG_SEL_CANDIDATE; + if (pp->select != 0) + 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(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct info_peer_summary *ips; + register struct peer *pp; + register int i; + extern struct peer *peer_hash[]; + extern struct peer *sys_peer; + +#ifdef DEBUG + if (debug > 2) + printf("wants peer list summary\n"); +#endif + + ips = (struct info_peer_summary *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_peer_summary)); + 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 + if (pp->dstadr == any_interface) + ips->dstadr = 0; + else + ips->dstadr = pp->dstadr->sin.sin_addr.s_addr; + ips->srcadr = pp->srcadr.sin_addr.s_addr; + ips->srcport = pp->srcadr.sin_port; + ips->stratum = pp->stratum; + ips->hpoll = pp->hpoll; + ips->ppoll = pp->ppoll; + ips->reach = pp->reach; + ips->flags = 0; + if (pp == sys_peer) + ips->flags |= INFO_FLAG_SYSPEER; + if (pp->flags & FLAG_CONFIG) + ips->flags |= INFO_FLAG_CONFIG; + if (pp->flags & FLAG_REFCLOCK) + ips->flags |= INFO_FLAG_REFCLOCK; + if (pp->flags & FLAG_AUTHENABLE) + ips->flags |= INFO_FLAG_AUTHENABLE; + if (pp->flags & FLAG_PREFER) + ips->flags |= INFO_FLAG_PREFER; + if (pp->candidate != 0) + ips->flags |= INFO_FLAG_SEL_CANDIDATE; + if (pp->select != 0) + ips->flags |= INFO_FLAG_SHORTLIST; + ips->hmode = pp->hmode; + ips->delay = HTONS_FP(pp->delay); + HTONL_FP(&pp->offset, &ips->offset); + ips->dispersion = HTONS_FP(pp->dispersion); + 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 (srcadr, inter, inpkt) + struct sockaddr_in *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_in addr; + extern struct peer *sys_peer; + + bzero((char *)&addr, sizeof addr); + addr.sin_family = AF_INET; + items = INFO_NITEMS(inpkt->err_nitems); + ipl = (struct info_peer_list *) inpkt->data; + ip = (struct info_peer *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_peer)); + while (items-- > 0 && ip != 0) { + addr.sin_port = ipl->port; + addr.sin_addr.s_addr = ipl->address; + ipl++; + if ((pp = findexistingpeer(&addr, (struct peer *)0)) == 0) + continue; + ip->dstadr = NSRCADR(&pp->dstadr->sin); + ip->srcadr = NSRCADR(&pp->srcadr); + 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->candidate != 0) + ip->flags |= INFO_FLAG_SEL_CANDIDATE; + if (pp->select != 0) + ip->flags |= INFO_FLAG_SHORTLIST; + ip->leap = pp->leap; + ip->hmode = pp->hmode; + ip->keyid = pp->keyid; + ip->pkeyid = pp->pkeyid; + ip->stratum = pp->stratum; + ip->ppoll = pp->ppoll; + ip->hpoll = pp->hpoll; + ip->precision = pp->precision; + ip->version = pp->version; + ip->valid = pp->valid; + ip->reach = pp->reach; + ip->unreach = pp->unreach; + ip->trust = 0; + ip->associd = htons(pp->associd); + ip->rootdelay = HTONS_FP(pp->rootdelay); + ip->rootdispersion = HTONS_FP(pp->rootdispersion); + ip->refid = pp->refid; + ip->timer = htonl(pp->event_timer.event_time - current_time); + 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(pp->filter_delay[j]); + HTONL_FP(&pp->filter_offset[j], &ip->filtoffset[i]); + ip->order[i] = (pp->filter_nextpt+NTP_SHIFT-1) + - pp->filter_order[i]; + if (ip->order[i] >= NTP_SHIFT) + ip->order[i] -= NTP_SHIFT; + } + ip->delay = HTONS_FP(pp->delay); + HTONL_FP(&pp->offset, &ip->offset); + ip->dispersion = HTONS_FP(pp->dispersion); + for (i = 0; i < NTP_SHIFT; i++) + ip->bdelay[i] = 0; + ip->estbdelay = htonl(pp->estbdelay); + ip = (struct info_peer *)more_pkt(); + } + flush_pkt(); +} + + +/* + * peer_stats - send statistics for one or more peers + */ +static void +peer_stats (srcadr, inter, inpkt) + struct sockaddr_in *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_in addr; + extern struct peer *sys_peer; + + bzero((char *)&addr, sizeof addr); + addr.sin_family = AF_INET; + items = INFO_NITEMS(inpkt->err_nitems); + ipl = (struct info_peer_list *) inpkt->data; + ip = (struct info_peer_stats *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_peer_stats)); + while (items-- > 0 && ip != 0) { + addr.sin_port = ipl->port; + addr.sin_addr.s_addr = ipl->address; + ipl++; + if ((pp = findexistingpeer(&addr, (struct peer *)0)) == 0) + continue; + ip->dstadr = NSRCADR(&pp->dstadr->sin); + ip->srcadr = NSRCADR(&pp->srcadr); + 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->candidate != 0) + ip->flags |= INFO_FLAG_SEL_CANDIDATE; + if (pp->select != 0) + ip->flags |= INFO_FLAG_SHORTLIST; + ip->timereceived = htonl(current_time - pp->timereceived); + ip->timetosend + = htonl(pp->event_timer.event_time - current_time); + ip->timereachable = htonl(current_time - pp->timereachable); + ip->sent = htonl(pp->sent); + ip->received = htonl(pp->received); + ip->processed = htonl(pp->processed); + ip->badlength = 0; + ip->badauth = htonl(pp->badauth); + ip->bogusorg = htonl(pp->bogusorg); + ip->oldpkt = htonl(pp->oldpkt); + ip->baddelay = 0; + ip->seldelay = 0; + ip->seldisp = htonl(pp->seldisptoolarge); + ip->selbroken = htonl(pp->selbroken); + ip->selold = htonl(pp->seltooold); + ip->candidate = pp->candidate; + ip->falseticker = 0; + ip->select = pp->select; + ip->select_total = 0; + ip = (struct info_peer_stats *)more_pkt(); + } + flush_pkt(); +} + + +/* + * sys_info - return system info + */ +static void +sys_info(srcadr, inter, inpkt) + struct sockaddr_in *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 s_fp sys_rootdelay; + extern u_fp sys_rootdispersion; + extern U_LONG sys_refid; + extern l_fp sys_reftime; + extern u_char sys_poll; + extern struct peer *sys_peer; + extern int sys_bclient; + extern U_LONG sys_bdelay; + extern int sys_authenticate; + extern U_LONG sys_authdelay; + + is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_sys)); + + if (sys_peer != 0) { + is->peer = NSRCADR(&sys_peer->srcadr); + is->peer_mode = sys_peer->hmode; + } else { + is->peer = 0; + is->peer_mode = 0; + } + is->leap = sys_leap; + is->stratum = sys_stratum; + is->precision = sys_precision; + is->rootdelay = htonl(sys_rootdelay); + is->rootdispersion = htonl(sys_rootdispersion); + is->refid = sys_refid; + HTONL_FP(&sys_reftime, &is->reftime); + + is->poll = sys_poll; + + is->flags = 0; + if (sys_bclient) + is->flags |= INFO_FLAG_BCLIENT; + if (sys_authenticate) + is->flags |= INFO_FLAG_AUTHENABLE; + is->selection = 0; /* Obsolete */ + + HTONL_UF(sys_bdelay, &is->bdelay); + HTONL_UF(sys_authdelay, &is->authdelay); + is->maxskew = 0; + + (void) more_pkt(); + flush_pkt(); +} + + +/* + * sys_stats - return system statistics + */ +static void +sys_stats(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct info_sys_stats *ss; + + /* + * Importations from the protocol module + */ + extern U_LONG sys_stattime; + extern U_LONG sys_badstratum; + extern U_LONG sys_oldversionpkt; + extern U_LONG sys_newversionpkt; + extern U_LONG sys_unknownversion; + extern U_LONG sys_badlength; + extern U_LONG sys_processed; + extern U_LONG sys_badauth; + extern U_LONG sys_wanderhold; + + ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_sys_stats)); + + ss->timeup = htonl(current_time); + ss->timereset = htonl(current_time - sys_stattime); + ss->badstratum = htonl(sys_badstratum); + ss->oldversionpkt = htonl(sys_oldversionpkt); + ss->newversionpkt = htonl(sys_newversionpkt); + ss->unknownversion = htonl(sys_unknownversion); + ss->badlength = htonl(sys_badlength); + ss->processed = htonl(sys_processed); + ss->badauth = htonl(sys_badauth); + ss->wanderhold = htonl(sys_wanderhold); + + (void) more_pkt(); + flush_pkt(); +} + + +/* + * mem_stats - return memory statistics + */ +static void +mem_stats(srcadr, inter, inpkt) + struct sockaddr_in *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(current_time - peer_timereset); + ms->totalpeermem = htons((u_short)total_peer_structs); + ms->freepeermem = htons((u_short)peer_free_count); + ms->findpeer_calls = htonl(findpeer_calls); + ms->allocations = htonl(peer_allocations); + ms->demobilizations = htonl(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(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct info_io_stats *io; + + /* + * Importations from the io module + */ + extern U_LONG io_timereset; + extern U_LONG full_recvbufs; + extern U_LONG free_recvbufs; + extern U_LONG total_recvbufs; + extern U_LONG lowater_additions; + extern U_LONG packets_dropped; + extern U_LONG packets_ignored; + extern U_LONG packets_received; + extern U_LONG packets_sent; + extern U_LONG packets_notsent; + extern U_LONG handler_calls; + extern U_LONG handler_pkts; + + io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_io_stats)); + + io->timereset = htonl(current_time - io_timereset); + io->totalrecvbufs = htons((u_short) total_recvbufs); + io->freerecvbufs = htons((u_short) free_recvbufs); + io->fullrecvbufs = htons((u_short) full_recvbufs); + io->lowwater = htons((u_short) lowater_additions); + io->dropped = htonl(packets_dropped); + io->ignored = htonl(packets_ignored); + io->received = htonl(packets_received); + io->sent = htonl(packets_sent); + io->notsent = htonl(packets_notsent); + io->interrupts = htonl(handler_calls); + io->int_received = htonl(handler_pkts); + + (void) more_pkt(); + flush_pkt(); +} + + +/* + * timer_stats - return timer statistics + */ +static void +timer_stats(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct info_timer_stats *ts; + + /* + * Importations from the timer module + */ + extern U_LONG alarm_overflow; + 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(current_time - timer_timereset); + ts->alarms = htonl(alarm_overflow); + ts->overflows = htonl(timer_overflows); + ts->xmtcalls = htonl(timer_xmtcalls); + + (void) more_pkt(); + flush_pkt(); +} + + +/* + * loop_info - return the current state of the loop filter + */ +static void +loop_info(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct info_loop *li; + l_fp tmp; + + /* + * Importations from the loop filter module + */ + extern l_fp last_offset; + extern s_fp drift_comp; + extern int time_constant; + extern U_LONG watchdog_timer; + + li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_loop)); + + HTONL_FP(&last_offset, &li->last_offset); + FPTOLFP(drift_comp, &tmp); + HTONL_FP(&tmp, &li->drift_comp); + li->compliance = htonl(time_constant); + li->watchdog_timer = htonl(watchdog_timer); + + (void) more_pkt(); + flush_pkt(); +} + + +/* + * do_conf - add a peer to the configuration list + */ +static void +do_conf(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct conf_peer *cp; + register int items; + struct sockaddr_in peeraddr; + int fl; + + /* + * 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; + + fl = 0; + while (items-- > 0 && !fl) { + if (cp->version > NTP_VERSION + || cp->version < NTP_OLDVERSION) + fl = 1; + if (cp->hmode != MODE_ACTIVE + && cp->hmode != MODE_CLIENT + && cp->hmode != MODE_BROADCAST) + fl = 1; + if (cp->flags & ~(CONF_FLAG_AUTHENABLE|CONF_FLAG_PREFER)) + fl = 1; + cp++; + } + + 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; + bzero((char *)&peeraddr, sizeof(struct sockaddr_in)); + peeraddr.sin_family = AF_INET; + peeraddr.sin_port = htons(NTP_PORT); + + /* + * Make sure the address is valid + */ +#ifdef REFCLOCK + if (!ISREFCLOCKADR(&peeraddr) && ISBADADR(&peeraddr)) { +#else + if (ISBADADR(&peeraddr)) { +#endif + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + while (items-- > 0) { + fl = 0; + if (cp->flags & CONF_FLAG_AUTHENABLE) + fl |= FLAG_AUTHENABLE; + if (cp->flags & CONF_FLAG_PREFER) + fl |= FLAG_PREFER; + peeraddr.sin_addr.s_addr = cp->peeraddr; + /* XXX W2DO? minpoll/maxpoll arguments ??? */ + if (peer_config(&peeraddr, (struct interface *)0, + cp->hmode, cp->version, cp->minpoll, cp->maxpoll, + cp->keyid, fl) == 0) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + cp++; + } + + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * do_unconf - remove a peer from the configuration list + */ +static void +do_unconf(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct conf_unpeer *cp; + register int items; + register struct peer *peer; + struct sockaddr_in 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. + */ + peeraddr.sin_family = AF_INET; + peeraddr.sin_port = htons(NTP_PORT); + + items = INFO_NITEMS(inpkt->err_nitems); + cp = (struct conf_unpeer *)inpkt->data; + + bad = 0; + while (items-- > 0 && !bad) { + peeraddr.sin_addr.s_addr = cp->peeraddr; + found = 0; + peer = (struct peer *)0; + while (!found) { + peer = findexistingpeer(&peeraddr, peer); + if (peer == (struct peer *)0) + break; + if (peer->flags & FLAG_CONFIG) + found = 1; + } + if (!found) + bad = 1; + cp++; + } + + 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) { + peeraddr.sin_addr.s_addr = cp->peeraddr; + peer_unconfig(&peeraddr, (struct interface *)0); + cp++; + } + + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * set_sys_flag - set system flags + */ +static void +set_sys_flag(srcadr, inter, inpkt) + struct sockaddr_in *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(srcadr, inter, inpkt) + struct sockaddr_in *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(srcadr, inter, inpkt, set) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; + int set; +{ + register U_LONG flags; + + if (INFO_NITEMS(inpkt->err_nitems) > 1) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + flags = ((struct conf_sys_flags *)inpkt->data)->flags; + + if (flags + & ~(SYS_FLAG_BCLIENT|SYS_FLAG_AUTHENTICATE)) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + if (flags & SYS_FLAG_BCLIENT) + proto_config(PROTO_BROADCLIENT, (LONG)set); + if (flags & SYS_FLAG_AUTHENTICATE) + proto_config(PROTO_AUTHENTICATE, (LONG)set); + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * do_monitor - turn on monitoring + */ +static void +do_monitor(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + mon_start(); + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * do_nomonitor - turn off monitoring + */ +static void +do_nomonitor(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + mon_stop(); + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * list_restrict - return the restrict list + */ +static void +list_restrict(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct info_restrict *ir; + register struct restrictlist *rl; + extern struct restrictlist *restrictlist; + +#ifdef DEBUG + if (debug > 2) + printf("wants peer list summary\n"); +#endif + + ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_restrict)); + for (rl = restrictlist; rl != 0 && ir != 0; rl = rl->next) { + ir->addr = htonl(rl->addr); + ir->mask = htonl(rl->mask); + ir->count = htonl(rl->count); + ir->flags = htons(rl->flags); + ir->mflags = htons(rl->mflags); + ir = (struct info_restrict *)more_pkt(); + } + flush_pkt(); +} + + + +/* + * do_resaddflags - add flags to a restrict entry (or create one) + */ +static void +do_resaddflags(srcadr, inter, inpkt) + struct sockaddr_in *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(srcadr, inter, inpkt) + struct sockaddr_in *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(srcadr, inter, inpkt) + struct sockaddr_in *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(srcadr, inter, inpkt, op) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; + int op; +{ + register struct conf_restrict *cr; + register int items; + struct sockaddr_in matchaddr; + struct sockaddr_in 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 = 1; + if (cr->addr == INADDR_ANY && cr->mask != INADDR_ANY) + bad = 1; + cr++; + } + + if (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; + bzero((char *)&matchaddr, sizeof(struct sockaddr_in)); + bzero((char *)&matchmask, sizeof(struct sockaddr_in)); + matchaddr.sin_family = AF_INET; + matchmask.sin_family = AF_INET; + + while (items-- > 0) { + matchaddr.sin_addr.s_addr = cr->addr; + matchmask.sin_addr.s_addr = cr->mask; + 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(srcadr, inter, inpkt) + struct sockaddr_in *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 list\n"); +#endif + if (!mon_enabled) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + im = (struct info_monitor *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_monitor)); + for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0; + md = md->mru_next) { + im->lasttime = htonl(current_time - md->lasttime); + im->firsttime = htonl(current_time - md->firsttime); + im->count = htonl(md->count); + im->addr = md->rmtadr; + im->port = md->rmtport; + im->mode = md->mode; + im->version = md->version; + im = (struct info_monitor *)more_pkt(); + } + flush_pkt(); +} + +/* + * Module entry points and the flags they correspond with + */ +struct reset_entry { + int flag; /* flag this corresponds to */ + void (*handler)(); /* 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(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + U_LONG flags; + struct reset_entry *rent; + + if (INFO_NITEMS(inpkt->err_nitems) > 1) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + flags = ((struct reset_flags *)inpkt->data)->flags; + + if (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(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct conf_unpeer *cp; + register int items; + register struct peer *peer; + struct sockaddr_in peeraddr; + int bad; + + /* + * We check first to see that every peer exists. If not, + * we return an error. + */ + peeraddr.sin_family = AF_INET; + peeraddr.sin_port = htons(NTP_PORT); + + items = INFO_NITEMS(inpkt->err_nitems); + cp = (struct conf_unpeer *)inpkt->data; + + bad = 0; + while (items-- > 0 && !bad) { + peeraddr.sin_addr.s_addr = cp->peeraddr; + peer = findexistingpeer(&peeraddr, (struct peer *)0); + if (peer == (struct peer *)0) + bad++; + cp++; + } + + 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) { + peeraddr.sin_addr.s_addr = cp->peeraddr; + peer = findexistingpeer(&peeraddr, (struct peer *)0); + peer_reset(peer); + cp++; + } + + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * do_key_reread - reread the encryption key file + */ +static void +do_key_reread(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + rereadkeys(); + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * do_dirty_hack + */ +static void +do_dirty_hack(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + /* historical placeholder */ + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * dont_dirty_hack + */ +static void +dont_dirty_hack(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + /* historical placeholder */ + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * trust_key - make one or more keys trusted + */ +static void +trust_key(srcadr, inter, inpkt) + struct sockaddr_in *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(srcadr, inter, inpkt) + struct sockaddr_in *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(srcadr, inter, inpkt, trust) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; + int 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(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct info_auth *ia; + + /* + * Importations from the authentication module + */ + extern U_LONG authnumkeys; + extern U_LONG authnumfreekeys; + extern U_LONG authkeylookups; + extern U_LONG authkeynotfound; + extern U_LONG authencryptions; + extern U_LONG authdecryptions; + extern U_LONG authdecryptok; + extern U_LONG authkeyuncached; + + ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_auth)); + + ia->numkeys = htonl(authnumkeys); + ia->numfreekeys = htonl(authnumfreekeys); + ia->keylookups = htonl(authkeylookups); + ia->keynotfound = htonl(authkeynotfound); + ia->encryptions = htonl(authencryptions); + ia->decryptions = htonl(authdecryptions); + ia->decryptok = htonl(authdecryptok); + ia->keyuncached = htonl(authkeyuncached); + ia->timereset = htonl(current_time - auth_timereset); + + (void) more_pkt(); + flush_pkt(); +} + + + +/* + * reset_auth_stats - reset the authentication stat counters. Done here + * to keep xntp-isms out of the authentication module + */ +static void +reset_auth_stats() +{ + /* + * Importations from the authentication module + */ + extern U_LONG authkeylookups; + extern U_LONG authkeynotfound; + extern U_LONG authencryptions; + extern U_LONG authdecryptions; + extern U_LONG authdecryptok; + extern U_LONG authkeyuncached; + + authkeylookups = 0; + authkeynotfound = 0; + authencryptions = 0; + authdecryptions = 0; + authdecryptok = 0; + authkeyuncached = 0; + auth_timereset = current_time; +} + + +/* + * req_get_traps - return information about current trap holders + */ +static void +req_get_traps(srcadr, inter, inpkt) + struct sockaddr_in *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, + sizeof(struct info_trap)); + + for (i = 0, tr = ctl_trap; i < CTL_MAXTRAPS; i++, tr++) { + if (tr->tr_flags & TRAP_INUSE) { + if (tr->tr_localaddr == any_interface) + it->local_address = 0; + else + it->local_address + = NSRCADR(&tr->tr_localaddr->sin); + it->trap_address = NSRCADR(&tr->tr_addr); + it->trap_port = NSRCPORT(&tr->tr_addr); + it->sequence = htons(tr->tr_sequence); + it->settime = htonl(current_time - tr->tr_settime); + it->origtime = htonl(current_time - tr->tr_origtime); + it->resets = htonl(tr->tr_resets); + it->flags = htonl((U_LONG)tr->tr_flags); + it = (struct info_trap *)more_pkt(); + } + } + flush_pkt(); +} + + +/* + * req_set_trap - configure a trap + */ +static void +req_set_trap(srcadr, inter, inpkt) + struct sockaddr_in *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(srcadr, inter, inpkt) + struct sockaddr_in *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(srcadr, inter, inpkt, set) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; + int set; +{ + register struct conf_trap *ct; + register struct interface *linter; + int res; + struct sockaddr_in laddr; + + /* + * Prepare sockaddr_in structure + */ + bzero((char *)&laddr, sizeof laddr); + laddr.sin_family = AF_INET; + laddr.sin_port = ntohs(NTP_PORT); + + /* + * Restrict ourselves to one item only. This eliminates + * the error reporting problem. + */ + if (INFO_NITEMS(inpkt->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 { + laddr.sin_addr.s_addr = ct->local_address; + linter = findinterface(&laddr); + if (linter == NULL) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + } + + laddr.sin_addr.s_addr = ct->trap_address; + if (ct->trap_port != 0) + laddr.sin_port = ct->trap_port; + else + laddr.sin_port = 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(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + U_LONG keyid; + + /* + * Restrict ourselves to one item only. + */ + if (INFO_NITEMS(inpkt->err_nitems) > 1) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + keyid = ntohl(*((U_LONG *)(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(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + U_LONG keyid; + extern U_LONG ctl_auth_keyid; + + /* + * Restrict ourselves to one item only. + */ + if (INFO_NITEMS(inpkt->err_nitems) > 1) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + keyid = ntohl(*((U_LONG *)(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(srcadr, inter, inpkt) + struct sockaddr_in *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(current_time - ctltimereset); + ic->numctlreq = htonl(numctlreq); + ic->numctlbadpkts = htonl(numctlbadpkts); + ic->numctlresponses = htonl(numctlresponses); + ic->numctlfrags = htonl(numctlfrags); + ic->numctlerrors = htonl(numctlerrors); + ic->numctltooshort = htonl(numctltooshort); + ic->numctlinputresp = htonl(numctlinputresp); + ic->numctlinputfrag = htonl(numctlinputfrag); + ic->numctlinputerr = htonl(numctlinputerr); + ic->numctlbadoffset = htonl(numctlbadoffset); + ic->numctlbadversion = htonl(numctlbadversion); + ic->numctldatatooshort = htonl(numctldatatooshort); + ic->numctlbadop = htonl(numctlbadop); + ic->numasyncmsgs = htonl(numasyncmsgs); + + (void) more_pkt(); + flush_pkt(); +} + + + +/* + * get_leap_info - return some stats concerning the control message module + */ +static void +get_leap_info(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct info_leap *il; + + /* + * Imported from the protocol module + */ + extern u_char sys_leap; + + /* + * Importations from the leap module + */ + extern u_char leap_indicator; + extern u_char leap_warning; + extern u_char leapbits; + extern U_LONG leap_timer; + extern U_LONG leap_processcalls; + extern U_LONG leap_notclose; + extern U_LONG leap_monthofleap; + extern U_LONG leap_dayofleap; + extern U_LONG leap_hoursfromleap; + extern U_LONG leap_happened; + + il = (struct info_leap *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_leap)); + + il->sys_leap = sys_leap; + il->leap_indicator = leap_indicator; + il->leap_warning = leap_warning; + il->leap_bits = (leapbits & INFO_LEAP_MASK) + | ((leap_indicator != LEAP_NOWARNING) ? INFO_LEAP_OVERRIDE : 0); + il->leap_timer = htonl(leap_timer - current_time); + il->leap_processcalls = htonl(leap_processcalls); + il->leap_notclose = htonl(leap_notclose); + il->leap_monthofleap = htonl(leap_monthofleap); + il->leap_dayofleap = htonl(leap_dayofleap); + il->leap_hoursfromleap = htonl(leap_hoursfromleap); + il->leap_happened = htonl(leap_happened); + + (void) more_pkt(); + flush_pkt(); +} + + +#ifdef REFCLOCK +/* + * get_clock_info - get info about a clock + */ +static void +get_clock_info(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct info_clock *ic; + register U_LONG *clkaddr; + register int items; + struct refclockstat clock; + struct sockaddr_in addr; + + bzero((char *)&addr, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(NTP_PORT); + items = INFO_NITEMS(inpkt->err_nitems); + clkaddr = (U_LONG *) inpkt->data; + + ic = (struct info_clock *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_clock)); + + while (items-- > 0) { + addr.sin_addr.s_addr = *clkaddr++; + if (!ISREFCLOCKADR(&addr) || + findexistingpeer(&addr, (struct peer *)0) == 0) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + refclock_control(&addr, (struct refclockstat *)0, &clock); + + ic->clockadr = addr.sin_addr.s_addr; + ic->type = clock.type; + ic->flags = clock.flags; + ic->lastevent = clock.lastevent; + ic->currentstatus = clock.currentstatus; + ic->polls = htonl(clock.polls); + ic->noresponse = htonl(clock.noresponse); + ic->badformat = htonl(clock.badformat); + ic->baddata = htonl(clock.baddata); + ic->timestarted = clock.timereset; + HTONL_FP(&clock.fudgetime1, &ic->fudgetime1); + HTONL_FP(&clock.fudgetime2, &ic->fudgetime2); + ic->fudgeval1 = htonl(clock.fudgeval1); + ic->fudgeval2 = htonl(clock.fudgeval2); + + ic = (struct info_clock *)more_pkt(); + } + flush_pkt(); +} + + + +/* + * set_clock_fudge - get a clock's fudge factors + */ +static void +set_clock_fudge(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register struct conf_fudge *cf; + register int items; + struct refclockstat clock; + struct sockaddr_in addr; + + bzero((char *)&addr, sizeof addr); + bzero((char *)&clock, sizeof clock); + addr.sin_family = AF_INET; + addr.sin_port = htons(NTP_PORT); + items = INFO_NITEMS(inpkt->err_nitems); + cf = (struct conf_fudge *) inpkt->data; + + while (items-- > 0) { + addr.sin_addr.s_addr = cf->clockadr; + if (!ISREFCLOCKADR(&addr) || + findexistingpeer(&addr, (struct peer *)0) == 0) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + switch(ntohl(cf->which)) { + case FUDGE_TIME1: + NTOHL_FP(&cf->fudgetime, &clock.fudgetime1); + clock.haveflags = CLK_HAVETIME1; + break; + case FUDGE_TIME2: + NTOHL_FP(&cf->fudgetime, &clock.fudgetime2); + clock.haveflags = CLK_HAVETIME2; + break; + case FUDGE_VAL1: + clock.fudgeval1 = ntohl(cf->fudgeval_flags); + clock.haveflags = CLK_HAVEVAL1; + break; + case FUDGE_VAL2: + clock.fudgeval2 = ntohl(cf->fudgeval_flags); + clock.haveflags = CLK_HAVEVAL2; + break; + case FUDGE_FLAGS: + clock.flags = ntohl(cf->fudgeval_flags) & 0xf; + clock.haveflags = + (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4); + break; + default: + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + refclock_control(&addr, &clock, (struct refclockstat *)0); + } + + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} +#endif + +/* + * set_maxskew - set the system maxskew parameter + */ +static void +set_maxskew(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register u_fp maxskew; + + if (INFO_NITEMS(inpkt->err_nitems) > 1) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + maxskew = NTOHS_FP(*(u_fp *)(inpkt->data)); + + proto_config(PROTO_MAXSKEW, (LONG)maxskew); + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * set_precision - set the system precision + */ +static void +set_precision(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register LONG precision; + + precision = ntohl(*(LONG *)(inpkt->data)); + + if (INFO_NITEMS(inpkt->err_nitems) > 1 || + precision > -1 || precision < -20) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + proto_config(PROTO_PRECISION, precision); + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * set_select_code - set a select code to use + */ +static void +set_select_code(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register U_LONG select_code; + + select_code = ntohl(*(U_LONG *)(inpkt->data)); + + if (INFO_NITEMS(inpkt->err_nitems) > 1 || + select_code < SELECT_1 || select_code > SELECT_5) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + proto_config(PROTO_SELECT, (LONG)select_code); + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +#ifdef REFCLOCK +/* + * get_clkbug_info - get debugging info about a clock + */ +static void +get_clkbug_info(srcadr, inter, inpkt) + struct sockaddr_in *srcadr; + struct interface *inter; + struct req_pkt *inpkt; +{ + register int i; + register struct info_clkbug *ic; + register U_LONG *clkaddr; + register int items; + struct refclockbug bug; + struct sockaddr_in addr; + + bzero((char *)&addr, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(NTP_PORT); + items = INFO_NITEMS(inpkt->err_nitems); + clkaddr = (U_LONG *) inpkt->data; + + ic = (struct info_clkbug *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_clkbug)); + + while (items-- > 0) { + addr.sin_addr.s_addr = *clkaddr++; + if (!ISREFCLOCKADR(&addr) || + findexistingpeer(&addr, (struct peer *)0) == 0) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + bzero((char *)&bug, sizeof bug); + refclock_buginfo(&addr, &bug); + if (bug.nvalues == 0 && bug.ntimes == 0) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + ic->clockadr = addr.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<= 0) + ic->values[i] = htonl(bug.values[i]); + + i = bug.ntimes; + if (i > NUMCBUGTIMES) + i = NUMCBUGTIMES; + ic->ntimes = (u_char)i; + ic->stimes = htonl((U_LONG)bug.stimes & ((1<= 0) { + ic->times[i].l_ui = htonl(bug.times[i].l_ui); + ic->times[i].l_uf = htonl(bug.times[i].l_uf); + } + + ic = (struct info_clkbug *)more_pkt(); + } + flush_pkt(); +} +#endif diff --git a/contrib/xntpd/xntpd/ntp_restrict.c b/contrib/xntpd/xntpd/ntp_restrict.c new file mode 100644 index 0000000000..9bd9779589 --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_restrict.c @@ -0,0 +1,297 @@ +/* ntp_restrict.c,v 3.1 1993/07/06 01:11:28 jbj Exp + * ntp_restrict.c - find out what restrictions this host is running under + */ +#include +#include + +#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. + */ + +/* + * 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 + +/* + * The restriction list + */ + struct restrictlist *restrictlist; +static int restrictcount; /* count of entries in the restriction list */ + +/* + * The free list and associated counters. Also some uninteresting + * stat counters. + */ +static struct restrictlist *resfree; +static int numresfree; /* number of structures on free list */ + +U_LONG res_calls; +U_LONG res_found; +U_LONG res_not_found; +U_LONG res_timereset; + +/* + * Our initial allocation of list entries. + */ +static struct restrictlist resinit[INITRESLIST]; + +/* + * Imported from the timer module + */ +extern U_LONG current_time; + +/* + * init_restrict - initialize the restriction data structures + */ +void +init_restrict() +{ + register int i; + + /* + * Zero the list and put all but one on the free list + */ + resfree = 0; + bzero((char *)resinit, sizeof resinit); + + for (i = 1; i < INITRESLIST; i++) { + resinit[i].next = resfree; + resfree = &resinit[i]; + } + + numresfree = 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 = INADDR_ANY; + resinit[0].mask = 0; + restrictlist = &resinit[0]; + restrictcount = 1; + + + /* + * fix up stat counters + */ + res_calls = 0; + res_found = 0; + res_not_found = 0; + res_timereset = 0; +} + + +/* + * restrictions - return restrictions for this host + */ +int +restrictions(srcadr) + struct sockaddr_in *srcadr; +{ + register struct restrictlist *rl; + register struct restrictlist *match; + register U_LONG hostaddr; + register int isntpport; + + res_calls++; + /* + * We need the host address in host order. Also need to know + * whether this is from the ntp port or not. + */ + hostaddr = SRCADR(srcadr); + isntpport = (SRCPORT(srcadr) == NTP_PORT); + + /* + * 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++; + + return (int)match->flags; +} + + +/* + * restrict - add/subtract/manipulate entries on the restrict list + */ +void +restrict(op, resaddr, resmask, mflags, flags) + int op; + struct sockaddr_in *resaddr; + struct sockaddr_in *resmask; + int mflags; + int flags; +{ + register U_LONG addr; + register U_LONG mask; + register struct restrictlist *rl; + register struct restrictlist *rlprev; + int i; + + /* + * Get address and mask in host byte order + */ + addr = SRCADR(resaddr); + mask = SRCADR(resmask); + addr &= mask; /* make sure low bits are zero */ + + /* + * If this is the default address, point at first on list. Else + * go searching for it. + */ + if (addr == INADDR_ANY) { + rlprev = 0; + rl = restrictlist; + } else { + rlprev = restrictlist; + rl = rlprev->next; + while (rl != 0) { + if (rl->addr > addr) { + rl = 0; + break; + } else if (rl->addr == addr) { + if (rl->mask == mask) { + if ((mflags & RESM_NTPONLY) + == (rl->mflags & RESM_NTPONLY)) + break; /* exact match */ + if (!(mflags & RESM_NTPONLY)) { + /* + * No flag fits before flag + */ + rl = 0; + break; + } + /* continue on */ + } else if (rl->mask > mask) { + rl = 0; + break; + } + } + rlprev = rl; + rl = rl->next; + } + } + /* + * In case the above wasn't clear :-), either rl now points + * at the entry this call refers to, or rl is zero and rlprev + * points to the entry prior to where this one should go in + * the sort. + */ + + /* + * Switch based on operation + */ + switch (op) { + case RESTRICT_FLAGS: + /* + * Here we add bits to the flags. If this is a new + * restriction add it. + */ + if (rl == 0) { + if (numresfree == 0) { + rl = (struct restrictlist *) emalloc( + INCRESLIST*sizeof(struct restrictlist)); + bzero((char *)rl, + 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++; + } + 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) + 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 != INADDR_ANY + && !(rl->mflags & RESM_INTERFACE)) { + rlprev->next = rl->next; + restrictcount--; + bzero((char *)rl, sizeof(struct restrictlist)); + + rl->next = resfree; + resfree = rl; + numresfree++; + } + break; + + default: + /* Oh, well */ + break; + } + + /* done! */ +} diff --git a/contrib/xntpd/xntpd/ntp_timer.c b/contrib/xntpd/xntpd/ntp_timer.c new file mode 100644 index 0000000000..e3ba54cd39 --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_timer.c @@ -0,0 +1,187 @@ +/* ntp_timer.c,v 3.1 1993/07/06 01:11:29 jbj Exp + * ntp_event.c - event timer support routines + */ +#include +#include +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_stdlib.h" + +/* + * 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. + */ +int alarm_flag; + +/* + * adjust and hourly counters + */ +static U_LONG adjust_timer; +static U_LONG hourly_timer; + +/* + * Imported from the leap module. The leap timer. + */ +extern U_LONG leap_timer; + +/* + * Statistics counter for the interested. + */ +U_LONG alarm_overflow; + +#define HOUR (60*60) + +/* + * Current_time holds the number of seconds since we started, in + * increments of 2**EVENT_TIMEOUT seconds. The timer queue is the + * hash into which we sort timer entries. + */ +U_LONG current_time; +struct event timerqueue[TIMER_NSLOTS]; + +/* + * Stats. Number of overflows and number of calls to transmit(). + */ +U_LONG timer_timereset; +U_LONG timer_overflows; +U_LONG timer_xmtcalls; + +static RETSIGTYPE alarming P((int)); + +/* + * init_timer - initialize the timer data structures + */ +void +init_timer() +{ + register int i; + struct itimerval itimer; + + /* + * Initialize... + */ + alarm_flag = 0; + alarm_overflow = 0; + adjust_timer = (1<next; + while (ev->event_time != 0 + && ev->event_time < (current_time + (1<next = ev->next; + tq->next->prev = tq; + ev->prev = ev->next = 0; + timer_xmtcalls++; + ev->event_handler(ev->peer); + ev = tq->next; + } + + /* + * Finally, call the hourly routine + */ + if (hourly_timer <= current_time) { + hourly_timer += HOUR; + hourly_stats(); + } +} + + +/* + * alarming - tell the world we've been alarmed + */ +static RETSIGTYPE +alarming(sig) +int sig; +{ + extern int initializing; /* from main line code */ + + if (initializing) + return; + if (alarm_flag) + alarm_overflow++; + else + alarm_flag++; +} + + +/* + * timer_clr_stats - clear timer module stat counters + */ +void +timer_clr_stats() +{ + timer_overflows = 0; + timer_xmtcalls = 0; + timer_timereset = current_time; +} diff --git a/contrib/xntpd/xntpd/ntp_unixclock.c b/contrib/xntpd/xntpd/ntp_unixclock.c new file mode 100644 index 0000000000..4ac7cd223a --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_unixclock.c @@ -0,0 +1,564 @@ +/* ntp_unixclock.c,v 3.1 1993/07/06 01:11:30 jbj Exp + * ntp_unixclock.c - routines for reading and adjusting a 4BSD-style + * system clock + */ + +#include +#include +#include +#include +#include + +#if defined(SYS_HPUX) || defined(sgi) || defined(__bsdi__) +#include +#include +#endif + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +#if defined(HAVE_LIBKVM) +#ifdef __bsdi__ +#include +#endif /* __bsdi__ */ +#include +#include + +#ifndef _POSIX2_LINE_MAX +#define _POSIX2_LINE_MAX 2048 +#endif +#endif /* HAVE_LIBKVM */ + + +#ifdef RS6000 +#undef hz +#endif /* RS6000 */ + +extern int debug; +/* + * These routines (init_systime, get_systime, step_systime, adj_systime) + * implement an interface between the (more or less) system independent + * bits of NTP and the peculiarities of dealing with the Unix system + * clock. These routines will run with good precision fairly independently + * of your kernel's value of tickadj. I couldn't tell the difference + * between tickadj==40 and tickadj==5 on a microvax, though I prefer + * to set tickadj == 500/hz when in doubt. At your option you + * may compile this so that your system's clock is always slewed to the + * correct time even for large corrections. Of course, all of this takes + * a lot of code which wouldn't be needed with a reasonable tickadj and + * a willingness to let the clock be stepped occasionally. Oh well. + */ + +/* + * Clock variables. We round calls to adjtime() to adj_precision + * microseconds, and limit the adjustment to tvu_maxslew microseconds + * (tsf_maxslew fractional sec) in one adjustment interval. As we are + * thus limited in the speed and precision with which we can adjust the + * clock, we compensate by keeping the known "error" in the system time + * in sys_clock_offset. This is added to timestamps returned by get_systime(). + * We also remember the clock precision we computed from the kernel in + * case someone asks us. + */ +extern LONG adj_precision; /* adj precision in usec (tickadj) */ +extern LONG tvu_maxslew; /* maximum adjust doable in 1< 65535) { + syslog(LOG_ERR, "tick value of %lu is unreasonably large", + tick); + exit(3); + } + + /* + * Estimate hz from tick + */ + hz = 1000000L / tick; + + /* + * Set adj_precision and the maximum slew based on this. Note + * that maxslew is set slightly shorter than it needs to be as + * insurance that all slews requested will complete in 1< 999990) { + /* + * Don't let the maximum slew exceed 1 second in 4. This + * simplifies calculations a lot since we can then deal + * with less-than-one-second fractions. + */ + tvu_maxslew = (999990/adj_precision) * adj_precision; + } + TVUTOTSF(tvu_maxslew, tsf_maxslew); + syslog(LOG_NOTICE, "tickadj = %d, tick = %d, tvu_maxslew = %d", + tickadj, tick, tvu_maxslew); +#ifdef DEBUG + if (debug) + printf( + "adj_precision = %d, tvu_maxslew = %d, tsf_maxslew = 0.%08x\n", + adj_precision, tvu_maxslew, tsf_maxslew); +#endif + + /* + * Set the current offset to 0 + */ + sys_clock_offset.l_ui = sys_clock_offset.l_uf = 0; +} + +#ifdef HAVE_LIBKVM +/* + * clock_parms - return the local clock tickadj and tick parameters + * + * This version uses the SunOS libkvm (or the bsd compatability version). + */ +static void +clock_parms(tickadj, tick) + U_LONG *tickadj; + U_LONG *tick; +{ + static struct nlist nl[] = { +#define N_TICKADJ 0 + { "_tickadj" }, +#define N_TICK 1 + { "_tick" }, + { "" }, + }; +#if __convex__ /* { */ + if (K_open((char *)0,O_RDONLY,"/vmunix")!=0) { + syslog(LOG_ERR, "K_open failed"); + exit(3); + } + kusenlist(1); + if (knlist(nl)!=0 + || nl[N_TICKADJ].n_value==0 + || nl[N_TICK].n_value==0) { + syslog(LOG_ERR, "knlist failed"); + exit(3); + } + if (K_read(tickadj,sizeof(*tickadj),nl[N_TICKADJ].n_value) != + sizeof(*tickadj)) { + syslog(LOG_ERR, "K_read tickadj failed"); + exit(3); + } + if (K_read(tick,sizeof(*tick),nl[N_TICK].n_value) != + sizeof(*tick)) { + syslog(LOG_ERR, "K_read tick failed"); + exit(3); + } + (void)K_close(); +#else /* }__convex__{ */ + register kvm_t *kd; + if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL) { + syslog(LOG_ERR, "kvm_open failed"); + exit(3); + } + if (kvm_nlist(kd, nl) != 0) { + syslog(LOG_ERR, "kvm_nlist failed"); + exit(3); + } + if (kvm_read(kd, nl[N_TICKADJ].n_value, (char *)tickadj, sizeof(*tickadj)) != + sizeof(*tickadj)) { + syslog(LOG_ERR, "kvm_read tickadj failed"); + exit(3); + } + if (kvm_read(kd, nl[N_TICK].n_value, (char *)tick, sizeof(*tick)) != + sizeof(*tick)) { + syslog(LOG_ERR, "kvm_read tick failed"); + exit(3); + } + if (kvm_close(kd) < 0) { + syslog(LOG_ERR, "kvm_close failed"); + exit(3); + } +#endif /*}convex*/ +#undef N_TICKADJ +#undef N_TICK +} +#endif /* HAVE_LIBKVM */ + + +#ifdef HAVE_READKMEM +/* + * clock_parms - return the local clock tickadj and tick parameters + * + * Note that this version grovels about in /dev/kmem to determine + * these values. This probably should be elsewhere. + */ + +/* Define the following to be what the tick and tickadj variables are + * called in your kernel. + */ + +#if defined(SYS_AUX3) || defined(SYS_AUX2) || defined(SYS_SVR4) || defined(SYS_PTX) +#define K_TICKADJ_NAME "tickadj" +#define K_TICK_NAME "tick" +#endif + +#ifdef SYS_HPUX +#define K_TICKADJ_NAME "_tickadj" +#define K_TICK_NAME "_old_tick" +#endif + +/* The defaults if not defined previously */ +#if !defined(K_TICKADJ_NAME) +#define K_TICKADJ_NAME "_tickadj" +#endif +#if !defined(K_TICK_NAME) +#define K_TICK_NAME "_tick" +#endif + +static void +clock_parms(tickadj, tick) + U_LONG *tickadj; + U_LONG *tick; +{ + register int i; + int kmem; +#if defined(HAVE_N_UN) +#define N_NAME n_un.n_name + static struct nlist nl[] = + { {{K_TICKADJ_NAME}}, + {{K_TICK_NAME}}, + {{""}}, + }; +#else +#define N_NAME n_name + static struct nlist nl[] = + { {K_TICKADJ_NAME}, + {K_TICK_NAME}, + {""}, + }; +#endif + static char *kernelnames[] = { + "/vmunix", + "/unix", + "/mach", + "/hp-ux", + "/386bsd", + "/netbsd", +#ifdef KERNELFILE + KERNELFILE, +#endif + NULL + }; + struct stat stbuf; + int vars[2]; + +#define K_TICKADJ 0 +#define K_TICK 1 + + /* + * Check to see what to use for the object file for names and get + * the locations of the necessary kernel variables. + */ + for (i = 0; kernelnames[i] != NULL; i++) { + if (stat(kernelnames[i], &stbuf) == -1) + continue; + if (nlist(kernelnames[i], nl) >= 0) + break; + } + if (kernelnames[i] == NULL) { + syslog(LOG_ERR, + "Clock init couldn't find kernel object file"); + exit(3); + } + + /* + * Read clock parameters from kernel + */ + kmem = open("/dev/kmem", O_RDONLY); + if (kmem < 0) { + syslog(LOG_ERR, "Can't open /dev/kmem for reading: %m"); +#ifdef DEBUG + if (debug) + perror("/dev/kmem"); +#endif + exit(3); + } + + for (i = 0; i < (sizeof(vars)/sizeof(vars[0])); i++) { + off_t where; + + vars[i] = 0; + if ((where = nl[i].n_value) == 0) { + syslog(LOG_ERR, "Unknown kernal var %s", + nl[i].N_NAME); + continue; + } + if (lseek(kmem, where, SEEK_SET) == -1) { + syslog(LOG_ERR, "lseek for %s fails: %m", + nl[i].N_NAME); + continue; + } + if (read(kmem, &vars[i], sizeof(int)) != sizeof(int)) { + syslog(LOG_ERR, "read for %s fails: %m", + nl[i].N_NAME); + } + } + close(kmem); + + *tickadj = (U_LONG)vars[K_TICKADJ]; + *tick = (U_LONG)vars[K_TICK]; + +#undef K_TICKADJ +#undef K_TICK +#undef K_TICKADJ_NAME +#undef K_TICK_NAME +#undef N_NAME +} +#endif /* HAVE_READKMEM */ + +#if defined(SOLARIS)&&defined(ADJTIME_IS_ACCURATE) +/* + * clock_parms for Solaris 2.2 and later, with high-res timer kernel code. + * The clock code changed in Solaris 2.2, and tickadj went away. + * The good news is that ADJTIME_IS_ACCURATE and tick is available through + * sysconf(). + */ +static void +clock_parms(tickadj, tick) + U_LONG *tickadj; + U_LONG *tick; +{ + int hz; + + hz = (int) sysconf (_SC_CLK_TCK); + *tick = 1000000L/hz; + *tickadj = (*tick/16); /* There is no tickadj, and it is only set here + for tvu_maxslew calculation above. Really, + clock_parms should return adj_precision + and tvu_maxslew, instead of the very + BSD-centric tickadj */ + +#ifdef DEBUG + if (debug) printf ("Solaris tick = %d\n", *tick); +#endif +} +#endif /* SOLARIS_HRTIME */ + + +#if defined(sgi) +/* + * clock_parms - return the local clock tickadj and tick parameters + * + * The values set here were determined experimentally on a 4D/220 and + * an R4000-50 server under IRIX 4.0.5. + */ +static void +clock_parms(tickadj, tick) + U_LONG *tickadj; + U_LONG *tick; +{ + *tick = 10000; + *tickadj = 150; +} +#endif /* sgi */ + + +#ifdef NOKMEM + +#ifndef HZ +#define HZ 60 +#endif + +/* + * clock_parms - return the local clock tickadj and tick parameters + * + * Note that this version uses static values! + */ +static void +clock_parms(tickadj, tick) + U_LONG *tickadj; + U_LONG *tick; +{ +#ifdef RS6000 + *tickadj = 1000; +#else + *tickadj = 500 / HZ; +#endif /*RS6000*/ + *tick = 1000000L / HZ; + +#ifdef DEBUG + if (debug) + printf("NOTE: Using preset values for tick and tickadj !!\n"); +#endif +} +#endif /*NOKMEM*/ + +#if ((defined(SOLARIS)&&!defined(ADJTIME_IS_ACCURATE))|| (defined(RS6000)&&!defined(NOKMEM))||defined(SYS_SINIXM) ) +#ifndef _SC_CLK_TCK +#include +#endif +/* + * clock_parms - return the local clock tickadj and tick parameters + * + * Note that this version grovels about in /dev/kmem to determine + * these values. This probably should be elsewhere. + */ +static void +clock_parms(tickadj, tick) + U_LONG *tickadj; + U_LONG *tick; +{ + register int i; + int kmem; +#define N_NAME n_name + static struct nlist nl[] = + { {"tickadj"}, + {""}, + }; + static char *kernelnames[] = { + "/kernel/unix", + "/unix", + NULL + }; + struct stat stbuf; + int vars[1]; + +#define K_TICKADJ 0 + /* + * Read clock parameters from kernel + */ + kmem = open("/dev/kmem", O_RDONLY); + if (kmem < 0) { + syslog(LOG_ERR, "Can't open /dev/kmem for reading: %m"); +#ifdef DEBUG + if (debug) + perror("/dev/kmem"); +#endif + exit(3); + } + + for (i = 0; kernelnames[i] != NULL; i++) { + if (stat(kernelnames[i], &stbuf) == -1) + continue; + if (nlist(kernelnames[i], nl) >= 0) + break; + } + if (kernelnames[i] == NULL) { + syslog(LOG_ERR, + "Clock init couldn't find kernel as either /vmunix or /unix"); + exit(3); + } + + for (i = 0; i < (sizeof(vars)/sizeof(vars[0])); i++) { + off_t where; + + vars[i] = 0; + if ((where = nl[i].n_value) == 0) { + syslog(LOG_ERR, "Unknown kernal var %s", + nl[i].N_NAME); + continue; + } + if (lseek(kmem, where, SEEK_SET) == -1) { + syslog(LOG_ERR, "lseek for %s fails: %m", + nl[i].N_NAME); + continue; + } + if (read(kmem, &vars[i], sizeof(int)) != sizeof(int)) { + syslog(LOG_ERR, "read for %s fails: %m", + nl[i].N_NAME); + } +#if defined(RS6000) + /* + * Aix requires one more round of indirection. + */ + if (lseek(kmem, vars[i], SEEK_SET) == -1) { + syslog(LOG_ERR, "lseek for %s fails: %m", + nl[i].N_NAME); + continue; + } + if (read(kmem, &vars[i], sizeof(int)) != sizeof(int)) { + syslog(LOG_ERR, "read for %s fails: %m", + nl[i].N_NAME); + } +#endif + } + close(kmem); + + *tickadj = (U_LONG)vars[K_TICKADJ]; + *tick = (U_LONG)(1000000/sysconf(_SC_CLK_TCK)); + +#undef K_TICKADJ +#undef N_NAME +} +#endif /* SOLARIS */ + +#ifdef SYS_LINUX +/* XXX should look this up somewhere ! */ +static void +clock_parms(tickadj, tick) + U_LONG *tickadj; + U_LONG *tick; +{ + *tickadj = (U_LONG)1; + *tick = (U_LONG)10000; +} +#endif /* SYS_LINUX */ diff --git a/contrib/xntpd/xntpd/ntp_util.c b/contrib/xntpd/xntpd/ntp_util.c new file mode 100644 index 0000000000..394d6dfd29 --- /dev/null +++ b/contrib/xntpd/xntpd/ntp_util.c @@ -0,0 +1,466 @@ +/* ntp_util.c,v 3.1 1993/07/06 01:11:31 jbj Exp + * ntp_util.c - stuff I didn't have any other place for + */ +#include +#include +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_filegen.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" + +#ifdef DOSYNCTODR +#include +#endif + +/* + * 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 +#define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +static char statsdir[MAXPATHLEN] = NTP_VAR; + +static FILEGEN peerstats; +static FILEGEN loopstats; +static FILEGEN clockstats; +/* + * We query the errno to see what kind of error occured + * when opening the drift file. + */ +extern int errno; + +#ifdef DEBUG +extern int debug; +#endif + +/* + * init_util - initialize the utilities + */ +void +init_util() +{ + stats_drift_file = 0; + stats_temp_file = 0; + key_file_name = 0; + +#define PEERNAME "peerstats" +#define LOOPNAME "loopstats" +#define CLOCKNAME "clockstats" + peerstats.fp = NULL; + peerstats.prefix = &statsdir[0]; + peerstats.basename = 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 = 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 = 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); + +#undef PEERNAME +#undef LOOPNAME +#undef CLOCKNAME + +} + + +/* + * hourly_stats - print some interesting stats + */ +void +hourly_stats() +{ + int fd; + char *val; + int vallen; + extern l_fp last_offset; + extern s_fp drift_comp; + extern int time_constant; + +#ifdef DOSYNCTODR + struct timeval tv; + 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 xntpd 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 + */ + + o_prio=getpriority(PRIO_PROCESS,0); /* Save setting */ + if (setpriority(PRIO_PROCESS,0,-20) != 0) /* overdrive */ + { + syslog(LOG_ERR, "can't elevate priority: %m"); + goto skip; + } + GETTIMEOFDAY(&tv,(struct timezone *)NULL); + if (SETTIMEOFDAY(&tv,(struct timezone *)NULL) != 0) + { + syslog(LOG_ERR, "can't sync battery time: %m"); + } + setpriority(PRIO_PROCESS,0,o_prio); /* downshift */ + + skip: +#endif + + syslog(LOG_NOTICE, "offset %s freq %s comp %d", + lfptoa(&last_offset, 6), fptoa(drift_comp, 5), time_constant); + + if (stats_drift_file != 0) { + fd = open(stats_temp_file, O_WRONLY|O_TRUNC|O_CREAT, 0644); + if (fd == -1) { + syslog(LOG_ERR, "can't open %s: %m", stats_temp_file); + return; + } + + val = fptoa(drift_comp, 5); + vallen = strlen(val); + /* + * Hack here. Turn the trailing \0 into a \n and write it. + */ + val[vallen] = '\n'; + if (write(fd, val, vallen+1) == -1) { + syslog(LOG_ERR, "write to %s failed: %m", + stats_temp_file); + (void) close(fd); + (void) unlink(stats_temp_file); + } else { + (void) close(fd); + /* atomic */ + (void) rename(stats_temp_file, stats_drift_file); + } + } +} + + +/* + * stats_config - configure the stats operation + */ +void +stats_config(item, value) + int item; + char *value; /* only one type so far */ +{ + register char *cp; + FILE *fp; + int len; + char buf[128]; + l_fp old_drift; + + 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 = emalloc((u_int)(len + 1)); + stats_temp_file = emalloc((u_int)(len + sizeof(".TEMP"))); + bcopy(value, stats_drift_file, len+1); + bcopy(value, stats_temp_file, len); + bcopy(".TEMP", stats_temp_file + len, sizeof(".TEMP")); + L_CLR(&old_drift); + +#ifdef DEBUG + if (debug > 1) { + printf("stats drift file %s\n", stats_drift_file); + printf("stats temp file %s\n", stats_temp_file); + } +#endif + + if ((fp = fopen(stats_drift_file, "r")) == NULL) { + if (errno != ENOENT) + syslog(LOG_ERR, "can't open %s: %m", + stats_drift_file); + loop_config(LOOP_DRIFTCOMP, &old_drift, 0); + break; + } + + if (fgets(buf, sizeof buf, fp) == NULL) { + syslog(LOG_ERR, "can't read %s: %m", + stats_drift_file); + (void) fclose(fp); + loop_config(LOOP_DRIFTCOMP, &old_drift, 0); + break; + } + + (void) fclose(fp); + + /* + * We allow leading spaces, then the number. Terminate + * at any trailing space or string terminator. + */ + cp = buf; + while (isspace(*cp)) + cp++; + while (*cp != '\0' && !isspace(*cp)) + cp++; + *cp = '\0'; + + if (!atolfp(buf, &old_drift)) { + syslog(LOG_ERR, "drift value %s invalid", buf); + break; + } + + /* + * Finally! Give value to the loop filter. + */ +#ifdef DEBUG + if (debug > 1) { + printf("loop_config finds old drift of %s\n", + lfptoa(&old_drift, 9)); + } +#endif + loop_config(LOOP_DRIFTCOMP, &old_drift, 0); + break; + + case STATS_STATSDIR: + if (strlen(value) >= sizeof(statsdir)) { + syslog(LOG_ERR, + "value for statsdir too LONG (>%d, sigh)", + sizeof(statsdir)-1); + } else { + l_fp now; + strcpy(statsdir,value); + + gettstamp(&now); + 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); + } + } + break; + + case STATS_PID_FILE: + if ((fp = fopen(value, "w")) == NULL) { + syslog(LOG_ERR, "Can't open %s: %m", value); + break; + } + fprintf(fp, "%d", getpid()); + fclose(fp);; + break; + + default: + /* oh well */ + break; + } +} + +/* + * record_peer_stats - write peer statistics to file + * + * file format: + * day (mjd) + * time (s past midnight) + * peer (ip address) + * peer status word (hex) + * peer offset (s) + * peer delay (s) + * peer dispersion (s) + */ +void +record_peer_stats(addr, status, offset, delay, dispersion) + struct sockaddr_in *addr; + int status; + l_fp *offset; + s_fp delay; + u_fp dispersion; +{ + struct timeval tv; + U_LONG day, sec, msec; + + GETTIMEOFDAY(&tv, (struct timezone *)NULL); + day = (U_LONG)tv.tv_sec / 86400 + MJD_1970; + sec = (U_LONG)tv.tv_sec % 86400; + msec = (U_LONG)tv.tv_usec / 1000; + + filegen_setup(&peerstats, (U_LONG)(tv.tv_sec + JAN_1970)); + if (peerstats.fp != NULL) { + fprintf(peerstats.fp, "%lu %lu.%03lu %s %x %s %s %s\n", + day, sec, msec, ntoa(addr), status, lfptoa(offset, 6), + fptoa(delay, 5), ufptoa(dispersion, 5)); + 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(offset, drift_comp, time_constant) + l_fp *offset; + s_fp *drift_comp; + int time_constant; +{ + struct timeval tv; + U_LONG day, sec, msec; + + GETTIMEOFDAY(&tv, (struct timezone *)NULL); + day = (U_LONG)tv.tv_sec / 86400 + MJD_1970; + sec = (U_LONG)tv.tv_sec % 86400; + msec = (U_LONG)tv.tv_usec / 1000; + + filegen_setup(&loopstats, (U_LONG)(tv.tv_sec + JAN_1970)); + if (loopstats.fp != NULL) { + fprintf(loopstats.fp, "%lu %lu.%03lu %s %s %d\n", + day, sec, msec, lfptoa(offset, 6), + fptoa(*drift_comp, 4), time_constant); + 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(addr, text) + struct sockaddr_in *addr; + char *text; +{ + struct timeval tv; + U_LONG day, sec, msec; + + GETTIMEOFDAY(&tv, (struct timezone *)NULL); + day = (U_LONG)tv.tv_sec / 86400 + MJD_1970; + sec = (U_LONG)tv.tv_sec % 86400; + msec = (U_LONG)tv.tv_usec / 1000; + + filegen_setup(&clockstats, (U_LONG)(tv.tv_sec + JAN_1970)); + if (clockstats.fp != NULL) { + fprintf(clockstats.fp, "%lu %lu.%03lu %s %s\n", + day, sec, msec, ntoa(addr), text); + fflush(clockstats.fp); + } +} + +/* + * getauthkeys - read the authentication keys from the specified file + */ +void +getauthkeys(keyfile) + 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) + key_file_name = emalloc((u_int)(len + 1)); + + bcopy(keyfile, key_file_name, len+1); + + authreadkeys(key_file_name); +} + + +/* + * rereadkeys - read the authentication key file over again. + */ +void +rereadkeys() +{ + if (key_file_name != 0) + authreadkeys(key_file_name); +} diff --git a/contrib/xntpd/xntpd/ntpd.c b/contrib/xntpd/xntpd/ntpd.c new file mode 100644 index 0000000000..f29f741c9d --- /dev/null +++ b/contrib/xntpd/xntpd/ntpd.c @@ -0,0 +1,438 @@ +/* ntpd.c,v 3.1 1993/07/06 01:11:32 jbj Exp + * ntpd.c - main program for the fixed point NTP daemon + */ +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(SYS_HPUX) +#include +#include +#endif + +#if defined(SYS_SVR4) +#include +#endif + +#if (defined(SYS_SOLARIS)&&!defined(bsd)) || defined(__svr4__) +#include +#endif + +#include "ntpd.h" +#include "ntp_select.h" +#include "ntp_io.h" +#include "ntp_stdlib.h" + +#ifdef LOCK_PROCESS +#include +#endif + +/* + * Signals we catch for debugging. If not debugging we ignore them. + */ +#define MOREDEBUGSIG SIGUSR1 +#define LESSDEBUGSIG SIGUSR2 + +/* + * Signals which terminate us gracefully. + */ +#define SIGDIE1 SIGHUP +#define SIGDIE2 SIGINT +#define SIGDIE3 SIGQUIT +#define SIGDIE4 SIGTERM + +/* + * Scheduling priority we run at + */ +#define NTPD_PRIO (-12) + +/* + * Debugging flag + */ +int debug; + +/* + * Initializing flag. All async routines watch this and only do their + * thing when it is clear. + */ +int initializing; + +/* + * Version declaration + */ +extern char *Version; + +/* + * Alarm flag. Imported from timer module + */ +extern int alarm_flag; + +#if !defined(SYS_386BSD) && !defined(SYS_BSDI) +/* + * We put this here, since the argument profile is syscall-specific + */ +extern int syscall P((int, struct timeval *, struct timeval *)); +#endif /* !SYS_386BSD */ + +#ifdef SIGDIE1 +static RETSIGTYPE finish P((int)); +#endif /* SIGDIE1 */ + +#ifdef DEBUG +static RETSIGTYPE moredebug P((int)); +static RETSIGTYPE lessdebug P((int)); +#endif /* DEBUG */ + +/* + * Main program. Initialize us, disconnect us from the tty if necessary, + * and loop waiting for I/O and/or timer expiries. + */ +void +main(argc, argv) + int argc; + char *argv[]; +{ + char *cp; + int was_alarmed; + struct recvbuf *rbuflist; + struct recvbuf *rbuf; + + initializing = 1; /* mark that we are initializing */ + debug = 0; /* no debugging by default */ + + getstartup(argc, argv); /* startup configuration, may set debug */ + +#ifndef NODETACH + /* + * Detach us from the terminal. May need an #ifndef GIZMO. + */ +#ifdef DEBUG + if (!debug) { +#endif /* DEBUG */ +#undef BSD19906 +#if defined(BSD)&&!defined(sun)&&!defined(SYS_SINIXM) +#if (BSD >= 199006 && !defined(i386)) +#define BSD19906 +#endif /* BSD... */ +#endif /* BSD sun */ +#if defined(BSD19906) + daemon(0, 0); +#else /* BSD19906 */ + if (fork()) + exit(0); + + { + unsigned long s; + int max_fd; +#if defined(NTP_POSIX_SOURCE) && !defined(SYS_386BSD) + max_fd = sysconf(_SC_OPEN_MAX); +#else /* NTP_POSIX_SOURCE */ + max_fd = getdtablesize(); +#endif /* NTP_POSIX_SOURCE */ + for (s = 0; s < max_fd; s++) + (void) close(s); + (void) open("/", 0); + (void) dup2(0, 1); + (void) dup2(0, 2); +#ifdef NTP_POSIX_SOURCE +#if defined(SOLARIS) || defined(SYS_PTX) + (void) setsid(); +#else + (void) setpgid(0, 0); +#endif +#else /* NTP_POSIX_SOURCE */ +#ifdef HAVE_ATT_SETPGRP + (void) setpgrp(); +#else /* HAVE_ATT_SETPGRP */ + (void) setpgrp(0, getpid()); +#endif /* HAVE_ATT_SETPGRP */ +#if defined(SYS_HPUX) + if (fork()) + exit(0); +#else /* SYS_HPUX */ +#if defined(apollo) +/* + * This breaks... the program fails to listen to any packets coming + * in on the UDP socket. So how do you break terminal affiliation? + */ +#else /* apollo */ + { + int fid; + + fid = open("/dev/tty", 2); + if (fid >= 0) { + (void) ioctl(fid, (U_LONG) TIOCNOTTY, + (char *) 0); + (void) close(fid); + } + } +#endif /* apollo */ +#endif /* SYS_HPUX */ +#endif /* NTP_POSIX_SOURCE */ + } +#endif /* BSD19906 */ +#ifdef DEBUG + } +#endif /* DEBUG */ +#endif /* NODETACH */ + + /* + * 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++; + +#ifndef LOG_DAEMON + openlog(cp, LOG_PID); +#else + +#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 */ + + syslog(LOG_NOTICE, Version); + + +#if defined(SYS_HPUX) + /* + * Lock text into ram, set real time priority + */ + if (plock(TXTLOCK) < 0) + syslog(LOG_ERR, "plock() error: %m"); + if (rtprio(0, 120) < 0) + syslog(LOG_ERR, "rtprio() error: %m"); +#else +#if defined(PROCLOCK) && defined(LOCK_PROCESS) + /* + * lock the process into memory + */ + if (plock(PROCLOCK) < 0) + syslog(LOG_ERR, "plock(): %m"); +#endif +#if defined(NTPD_PRIO) && NTPD_PRIO != 0 + /* + * Set the priority. + */ +#ifdef HAVE_ATT_NICE + nice (NTPD_PRIO); +#endif /* HAVE_ATT_NICE */ +#ifdef HAVE_BSD_NICE + (void) setpriority(PRIO_PROCESS, 0, NTPD_PRIO); +#endif /* HAVE_BSD_NICE */ + +#endif /* !PROCLOCK || !LOCK_PROCESS */ +#endif /* SYS_HPUX */ + + /* + * 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 DEBUG + (void) signal_no_reset(MOREDEBUGSIG, moredebug); + (void) signal_no_reset(LESSDEBUGSIG, lessdebug); +#else + (void) signal_no_reset(MOREDEBUGSIG, SIG_IGN); + (void) signal_no_reset(LESSDEBUGSIG, SIG_IGN); +#endif /* DEBUG */ + + /* + * Call the init_ routines to initialize the data structures. + * Note that init_systime() may run a protocol to get a crude + * estimate of the time as an NTP client when running on the + * gizmo board. It is important that this be run before + * init_subs() since the latter uses the time of day to seed + * the random number generator. That is not the only + * dependency between these, either, be real careful about + * reordering. + */ + init_auth(); + init_util(); + init_restrict(); + init_mon(); + init_systime(); + init_timer(); + init_lib(); + init_random(); + init_request(); + init_control(); + init_leap(); + init_peer(); +#ifdef REFCLOCK + init_refclock(); +#endif + init_proto(); + init_io(); + init_loopfilter(); + + /* + * Get configuration. This (including argument list parsing) is + * done in a separate module since this will definitely be different + * for the gizmo board. + */ + getconfig(argc, argv); + initializing = 0; + + /* + * 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. + */ + was_alarmed = 0; + rbuflist = (struct recvbuf *)0; + for (;;) { +#ifndef HAVE_SIGNALED_IO + extern fd_set activefds; + extern int maxactivefd; + + fd_set rdfdes; + int nfound; +#else + 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; + nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, (struct timeval *)0); + if (nfound > 0) { + l_fp ts; + + get_systime(&ts); + (void)input_handler(&ts); + } + else if (nfound == -1 && errno != EINTR) { + syslog(LOG_ERR, "select() error: %m"); + } +#else + wait_for_signal(); +#endif + if (alarm_flag) { /* alarmed? */ + was_alarmed = 1; + alarm_flag = 0; + } + rbuflist = getrecvbufs(); /* get received buffers */ + } +#ifdef HAVE_SIGNALED_IO + unblock_io_and_alarm(); +#endif + + /* + * Out here, signals are unblocked. Call timer routine + * to process expiry. + */ + if (was_alarmed) { + timer(); + was_alarmed = 0; + } + + /* + * Call the data procedure to handle each received + * packet. + */ + while (rbuflist != (struct recvbuf *)0) { + rbuf = rbuflist; + rbuflist = rbuf->next; + (rbuf->receiver)(rbuf); + freerecvbuf(rbuf); + } + /* + * Go around again + */ + } +} + + +#ifdef SIGDIE1 +/* + * finish - exit gracefully + */ +static RETSIGTYPE +finish(sig) +int sig; +{ + + /* + * Log any useful info before exiting. + */ +#ifdef notdef + log_exit_stats(); +#endif + exit(0); +} +#endif /* SIGDIE1 */ + + +#ifdef DEBUG +/* + * moredebug - increase debugging verbosity + */ +static RETSIGTYPE +moredebug(sig) +int sig; +{ + if (debug < 255) { + debug++; + syslog(LOG_DEBUG, "debug raised to %d", debug); + } +} + +/* + * lessdebug - decrease debugging verbosity + */ +static RETSIGTYPE +lessdebug(sig) +int sig; +{ + if (debug > 0) { + debug--; + syslog(LOG_DEBUG, "debug lowered to %d", debug); + } +} +#endif /* DEBUG */ diff --git a/contrib/xntpd/xntpd/refclock_as2201.c b/contrib/xntpd/xntpd/refclock_as2201.c new file mode 100644 index 0000000000..f04d6d0659 --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_as2201.c @@ -0,0 +1,991 @@ +/* + * refclock_gps - clock driver for the Austron 2201A GPS Timing Receiver + */ +#if defined(REFCLOCK) && (defined(AS2201) || defined(AS2201CLK) || defined(AS2201PPS)) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(STREAM) +#include +#include +#if defined(AS2201CLK) +#include +#endif /* AS2201CLK */ +#endif /* STREAM */ + +#if defined (AS2201PPS) +#include +#endif /* AS2201PPS */ + +#include "ntp_stdlib.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. + * + * In order for this code to work, the radio must be placed in non- + * interactive mode using the "off" command and with a single + * resonse 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 + * undefined AS2201PPS 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 with AS2201PPS defined can be used for SunOS kernels + * that have been modified with the ppsclock streams module included in + * this distribution. In this mode a precise timestamp is available + * using a gadget box and 1-pps signal from the receiver; however, the + * sample rate is limited to the polling rate, normally about one poll + * every 16 seconds. 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 additional receivers. For the utmost accuracy, the + * sample rate can be increased to one per second using the PPSCD + * define. This improves the accuracy to the order of a few + * microseconds. + */ + +/* + * Definitions + */ +#define MAXUNITS 4 /* max number of GPS units */ +#define GPS232 "/dev/gps%d" /* name of radio device */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ + +/* + * Radio interface parameters + */ +#define GPSPRECISION (-15) /* precision assumed (about 30 us) */ +#define GPSREFID "GPS" /* reference id */ +#define GPSDESCRIPTION "Austron 2201A GPS Receiver" /* who we are */ +#define GPSHSREFID 0x7f7f040a /* 127.127.4.10 refid hi strata */ +#define GMT 0 /* hour offset from Greenwich */ +#define NCODES 3 /* stages of median filter */ +#define LENTOC 19 /* yy:ddd:hh:mm:ss.mmm datecode length */ +#define BMAX 100 /* timecode buffer length */ +#define SMAX 200 /* statistics buffer length */ +#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */ + +/* + * Hack to avoid excercising the multiplier. I have no pride. + */ +#define MULBY10(x) (((x)<<3) + ((x)<<1)) + +/* + * Imported from ntp_timer module + */ +extern U_LONG current_time; /* current time (s) */ + +/* + * Imported from ntp_loopfilter module + */ +extern int fdpps; /* pps file descriptor */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * GPS unit control structure. + */ +struct gpsunit { + struct peer *peer; /* associated peer structure */ + struct refclockio io; /* given to the I/O handler */ + l_fp lastrec; /* last data receive time */ + l_fp lastref; /* last timecode time */ + l_fp offset[NCODES]; /* recent sample offsets */ + char lastcode[BMAX]; /* last timecode received */ + char *lastptr; /* statistics buffer pointer */ + char stats[SMAX]; /* statistics buffer */ + u_char lencode; /* length of last received ASCII string */ + U_LONG lasttime; /* last time clock heard from */ +#ifdef AS2201PPS + U_LONG lastev; /* last ppsclock second */ +#endif /* AS2201PPS */ + 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 year; /* year of eternity */ + u_short day; /* day of year */ + u_char hour; /* hour of day */ + u_char minute; /* minute of hour */ + u_char second; /* seconds of minute */ + u_short msec; /* milliseconds of second */ + u_char leap; /* leap indicators */ + U_LONG yearstart; /* start of current year */ + int linect; /* count of lines remaining */ + int index; /* current statistics command */ + /* + * 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 */ +}; + +/* + * Radio commands to extract statitistics + * + * A command consists of an ASCII string terminated by a (\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 (\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 */ +}; + +/* + * Data space for the unit structures. Note that we allocate these on + * the fly, but never give them back. + */ +static struct gpsunit *gpsunits[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 as2201_init P(()); +static int as2201_start P((u_int, struct peer *)); +static void as2201_shutdown P((int)); +static void as2201_report_event P((struct gpsunit *, int)); +static void as2201_receive P((struct recvbuf *)); +static char as2201_process P((struct gpsunit *, l_fp *, u_fp *)); +static void as2201_poll P((int unit, struct peer *)); +static void as2201_control P((u_int, struct refclockstat *, struct refclockstat *)); +static void as2201_buginfo P((int, struct refclockbug *)); + +/* + * Transfer vector + */ +struct refclock refclock_as2201 = { + as2201_start, as2201_shutdown, as2201_poll, + as2201_control, as2201_init, as2201_buginfo, NOFLAGS +}; + +/* + * as2201_init - initialize internal gps driver data + */ +static void +as2201_init() +{ + register int i; + /* + * Just zero the data arrays + */ + bzero((char *)gpsunits, sizeof gpsunits); + 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; + } +} + + +/* + * as2201_start - open the GPS devices and initialize data for processing + */ +static int +as2201_start(unit, peer) + u_int unit; + struct peer *peer; +{ + register struct gpsunit *gps; + register int i; + int fd232; + char as2201dev[20]; +#ifdef AS2201PPS + struct ppsclockev ev; +#endif /* AS2201PPS */ + + /* + * Check configuration info + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "gps_start: unit %d invalid", unit); + return (0); + } + if (unitinuse[unit]) { + syslog(LOG_ERR, "gps_start: unit %d in use", unit); + return (0); + } + + /* + * Open serial port + */ + (void) sprintf(as2201dev, GPS232, unit); + fd232 = open(as2201dev, O_RDWR, 0777); + if (fd232 == -1) { + syslog(LOG_ERR, "gps_start: open of %s: %m", as2201dev); + return (0); + } + +#if defined(HAVE_SYSV_TTYS) + /* + * System V serial line parameters (termio interface) + * + */ + { struct termio ttyb; + if (ioctl(fd232, TCGETA, &ttyb) < 0) { + syslog(LOG_ERR, + "as2201_start: ioctl(%s, TCGETA): %m", as2201dev); + 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) { + syslog(LOG_ERR, + "as2201_start: ioctl(%s, TCSETA): %m", as2201dev); + goto screwed; + } + } +#endif /* HAVE_SYSV_TTYS */ +#if defined(STREAM) + /* + * POSIX/STREAMS serial line parameters (termios interface) + * + * The AS2201CLK option provides timestamping at the driver level. + * It requires the tty_clk streams module. + * + * The AS2201PPS option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the ppsclock streams module and SunOS 4.1.1 or + * later. + */ + { struct termios ttyb, *ttyp; + + ttyp = &ttyb; + if (tcgetattr(fd232, ttyp) < 0) { + syslog(LOG_ERR, + "as2201_start: tcgetattr(%s): %m", as2201dev); + 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) { + syslog(LOG_ERR, + "as2201_start: tcsetattr(%s): %m", as2201dev); + goto screwed; + } + if (tcflush(fd232, TCIOFLUSH) < 0) { + syslog(LOG_ERR, + "as2201_start: tcflush(%s): %m", as2201dev); + goto screwed; + } +#if defined(AS2201CLK) + if (ioctl(fd232, I_PUSH, "clk") < 0) + syslog(LOG_ERR, + "as2201_start: ioctl(%s, I_PUSH, clk): %m", as2201dev); + if (ioctl(fd232, CLK_SETSTR, "\n") < 0) + syslog(LOG_ERR, + "as2201_start: ioctl(%s, CLK_SETSTR): %m", as2201dev); +#endif /* AS2201CLK */ +#if defined(AS2201PPS) + if (ioctl(fd232, I_PUSH, "ppsclock") < 0) + syslog(LOG_ERR, + "as2201_start: ioctl(%s, I_PUSH, ppsclock): %m", as2201dev); + else + fdpps = fd232; +#endif /* AS2201PPS */ + } +#endif /* STREAM */ +#if defined(HAVE_BSD_TTYS) + /* + * 4.3bsd serial line parameters (sgttyb interface) + * + * The AS2201CLK option provides timestamping at the driver level. + * It requires the tty_clk line discipline and 4.3bsd or later. + */ + { struct sgttyb ttyb; +#if defined(AS2201CLK) + int ldisc = CLKLDISC; +#endif /* AS2201CLK */ + + if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { + syslog(LOG_ERR, + "as2201_start: ioctl(%s, TIOCGETP): %m", as2201dev); + goto screwed; + } + ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; +#if defined(AS2201CLK) + 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 /* AS2201CLK */ + if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { + syslog(LOG_ERR, + "as2201_start: ioctl(%s, TIOCSETP): %m", as2201dev); + goto screwed; + } +#if defined(AS2201CLK) + if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { + syslog(LOG_ERR, + "as2201_start: ioctl(%s, TIOCSETD): %m",as2201dev); + goto screwed; + } +#endif /* AS2201CLK */ + } +#endif /* HAVE_BSD_TTYS */ + + /* + * Allocate unit structure + */ + if (gpsunits[unit] != 0) { + gps = gpsunits[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && gpsunits[i] != 0) + break; + } + if (i < MAXUNITS) { + /* + * Reclaim this one + */ + gps = gpsunits[i]; + gpsunits[i] = 0; + } else { + gps = (struct gpsunit *) + emalloc(sizeof(struct gpsunit)); + } + } + bzero((char *)gps, sizeof(struct gpsunit)); + gpsunits[unit] = gps; + + /* + * Set up the structures + */ + gps->peer = peer; + gps->unit = (u_char)unit; + gps->timestarted = current_time; + gps->lastptr = gps->stats; + gps->index = 0; + + gps->io.clock_recv = as2201_receive; + gps->io.srcclock = (caddr_t)gps; + gps->io.datalen = 0; + gps->io.fd = fd232; +#ifdef AS2201PPS + if (ioctl(fd232, CIOGETEV, (caddr_t)&ev) < 0) { + syslog(LOG_ERR, + "gps_start: ioctl(%s, CIOGETEV): %m", as2201dev); + goto screwed; + } else + gps->lastev = ev.tv.tv_sec; +#endif /* AS2201PPS */ + if (!io_addclock(&gps->io)) { + goto screwed; + } + + /* + * 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 = GPSPRECISION; + peer->rootdelay = 0; + peer->rootdispersion = 0; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(GPSREFID, (char *)&peer->refid, 4); + else + peer->refid = htonl(GPSHSREFID); + unitinuse[unit] = 1; + return (1); + + /* + * Something broke; abandon ship. + */ +screwed: + (void) close(fd232); + return (0); +} + +/* + * as2201_shutdown - shut down a GPS clock + */ +static void +as2201_shutdown(unit) + int unit; +{ + register struct gpsunit *gps; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "gps_shutdown: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "gps_shutdown: unit %d not in use", unit); + return; + } + + /* + * Tell the I/O module to turn us off. We're history. + */ + gps = gpsunits[unit]; + io_closeclock(&gps->io); + unitinuse[unit] = 0; +} + + +/* + * as2201_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 +as2201_report_event(gps, code) + struct gpsunit *gps; + int code; +{ + struct peer *peer; + + peer = gps->peer; + if (gps->status != (u_char)code) { + gps->status = (u_char)code; + if (code != CEVNT_NOMINAL) + gps->lastevent = (u_char)code; + syslog(LOG_INFO, + "clock %s event %x\n", ntoa(&peer->srcadr), code); + } +} + + +/* + * as2201_receive - receive data from the serial interface + */ +static void +as2201_receive(rbufp) + struct recvbuf *rbufp; +{ + register int i; + register struct gpsunit *gps; + +#if defined(AS2201PPS) + struct ppsclockev ev; + l_fp trtmp; +#endif /* AS2201PPS */ + register u_char *dpt; + register char *cp, *dp; + int dpend; + l_fp tstmp; + u_fp dispersion; + + /* + * Get the clock this applies to and pointers to the data. + * Edit the timecode to remove control chars and trashbits. + */ + gps = (struct gpsunit *)rbufp->recv_srcclock; + dpt = (u_char *)&rbufp->recv_space; + dpend = rbufp->recv_length; + if (dpend > BMAX - 1) + dpend = BMAX - 1; + cp = dp = gps->lastcode; + for (i = 0; i < dpend; i++) + if ((*dp = 0x7f & *dpt++) >= ' ') dp++; + *dp = '\0'; + gps->lencode = dp - cp; +#ifdef DEBUG + if (debug) + printf("gps: timecode %d %d %s\n", + gps->linect, gps->lencode, gps->lastcode); +#endif + if (gps->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 (gps->linect > 0) { + gps->linect--; + if ((int)(gps->lastptr - gps->stats + gps->lencode) > SMAX - 2) + return; + *gps->lastptr++ = ' '; + (void)strcpy(gps->lastptr, gps->lastcode); + gps->lastptr += gps->lencode; + return; + } else { + if (gps->lencode == 1) { + gps->linect = atoi(gps->lastcode); + return; + } else { + record_clock_stats(&(gps->peer->srcadr), gps->stats); +#ifdef DEBUG + if (debug) + printf("gps: stat %s\n", gps->stats); +#endif + } + } + gps->lastptr = gps->stats; + *gps->lastptr = '\0'; + + /* + * We check the timecode format and decode its contents. The + * timecode has format yy:ddd:hh:mm:ss.mmm). If it has invalid + * length or is not in proper format, the driver declares bad + * format and exits. If the converted decimal values are out of + * range, the driver declares bad data and exits. + */ + if (gps->lencode != LENTOC || !isdigit(cp[0]) || + !isdigit(cp[1]) || !isdigit(cp[3]) || !isdigit(cp[4]) || + !isdigit(cp[5]) || !isdigit(cp[7]) || !isdigit(cp[8]) || + !isdigit(cp[10]) || !isdigit(cp[11]) || !isdigit(cp[13]) || + !isdigit(cp[14]) || !isdigit(cp[16]) || !isdigit(cp[17]) || + !isdigit(cp[18])) { + gps->badformat++; + as2201_report_event(gps, CEVNT_BADREPLY); + return; + } + + /* + * Convert date and check values. + */ + gps->day = cp[3] - '0'; + gps->day = MULBY10(gps->day) + cp[4] - '0'; + gps->day = MULBY10(gps->day) + cp[5] - '0'; + if (gps->day < 1 || gps->day > 366) { + gps->baddata++; + as2201_report_event(gps, CEVNT_BADDATE); + return; + } + + /* + * Convert time and check values. + */ + gps->hour = MULBY10(cp[7] - '0') + cp[8] - '0'; + gps->minute = MULBY10(cp[10] - '0') + cp[11] - '0'; + gps->second = MULBY10(cp[13] - '0') + cp[14] - '0'; + gps->msec = MULBY10(MULBY10(cp[16] - '0') + cp[17] - '0') + + cp[18] - '0'; + if (gps->hour > 23 || gps->minute > 59 || gps->second > 59) { + gps->baddata++; + as2201_report_event(gps, CEVNT_BADTIME); + return; + } + + /* + * Test for synchronization (this is a temporary crock). + */ + if (cp[2] != ':') + gps->leap = LEAP_NOTINSYNC; + else + gps->lasttime = current_time; + + /* + * Now, compute the reference time value. Use the heavy + * machinery for the second, which presumably is the one which + * occured at the last pps pulse and which was captured by the + * loop_filter module. All we have to do here is present a + * reasonable facsimile of the time at that pulse so the clock- + * filter and selection machinery declares us truechimer. The + * precision offset within the second is really tuned by the + * loop_filter module. Note that this code does not yet know how + * to do the years and relies on the clock-calendar chip for + * sanity. + */ + if (!clocktime(gps->day, gps->hour, gps->minute, + gps->second, GMT, gps->lastrec.l_ui, + &gps->yearstart, &gps->lastref.l_ui)) { + gps->baddata++; + as2201_report_event(gps, CEVNT_BADTIME); + + printf("gps: bad data\n"); + + return; + } + MSUTOTSF(gps->msec, gps->lastref.l_uf); +#if defined(AS2201PPS) + + /* + * If the pps signal is available and the local time is within + * +-0.5 second of the timecode, use the pps offset instead. + * Note that we believe the ppsclock timestamp only if the ioctl + * works and the new timestamp is greater than the previous one. + */ + gps->lastrec = rbufp->recv_time; + tstmp = gps->lastref; + L_SUB(&tstmp, &gps->lastrec); + L_ADD(&tstmp, &(fudgefactor[gps->unit])); + trtmp = tstmp; + if (L_ISNEG(&trtmp)) + L_NEG(&trtmp); + if (trtmp.l_i < CLOCK_MAX_I || (trtmp.l_i == CLOCK_MAX_I + && (U_LONG)trtmp.l_uf < (U_LONG)CLOCK_MAX_F)) { + if (ioctl(fdpps, CIOGETEV, (caddr_t)&ev) >= 0) { + if (gps->lastev < ev.tv.tv_sec) { + trtmp.l_ui = ev.tv.tv_sec + (U_LONG)JAN_1970; + TVUTOTSF(ev.tv.tv_usec, trtmp.l_uf); + L_NEG(&trtmp); + tstmp.l_i = tstmp.l_f = 0; + M_ADDF(tstmp.l_i, tstmp.l_f, trtmp.l_f); + } + gps->lastev = ev.tv.tv_sec; + } + } +#else + tstmp = gps->lastref; + L_SUB(&tstmp, &gps->lastrec); + L_ADD(&tstmp, &(fudgefactor[gps->unit])); +#endif /* AS2201PPS */ + i = ((int)(gps->coderecv)) % NCODES; + gps->offset[i] = tstmp; + gps->coderecv++; +#if DEBUG + if (debug) + printf("gps: times %s %s %s\n", + ulfptoa(&gps->lastref, 6), ulfptoa(&gps->lastrec, 6), + lfptoa(&tstmp, 6)); +#endif + + /* + * If the statistics-record switch (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(gps->lastptr, gps->lastcode); + gps->lastptr += gps->lencode; + if (sloppyclockflag[gps->unit] & CLK_FLAG4) { + *gps->lastptr++ = ' '; + (void)strcpy(gps->lastptr, stat_command[gps->index]); + gps->lastptr += strlen(stat_command[gps->index]); + gps->lastptr--; + *gps->lastptr = '\0'; + (void)write(gps->io.fd, stat_command[gps->index], + strlen(stat_command[gps->index])); + gps->index++; + if (*stat_command[gps->index] == '\0') + gps->index = 0; + } + + /* + * Process the samples in the median filter, add the fudge + * factor and pass the offset and dispersion along. We use + * lastref 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 (gps->coderecv < NCODES) + return; + if (!as2201_process(gps, &tstmp, &dispersion)) { + gps->baddata++; + as2201_report_event(gps, CEVNT_BADTIME); + return; + } + refclock_receive(gps->peer, &tstmp, GMT, dispersion, + &gps->lastrec, &gps->lastrec, gps->leap); +} + +/* + * as2201_process - process a pile of samples from the clock + * + * This routine uses a three-stage median filter to calculate offset and + * dispersion and reduce jitter. The dispersion is calculated as the + * span of the filter (max - min). + */ +static char +as2201_process(gps, offset, dispersion) + struct gpsunit *gps; + l_fp *offset; + u_fp *dispersion; +{ + register int i, j; + register U_LONG tmp_ui, tmp_uf; + int not_median1 = -1; /* XXX correct? */ + int not_median2 = -1; /* XXX correct? */ + int median; + u_fp disp_tmp, disp_tmp2; + + /* + * This code implements a three-stage median filter. First, we + * check if the samples are within 125 ms of each other. If not, + * dump the sample set. We take the median of the three offsets + * and use that as the sample offset. There probably is not much + * to be gained by a longer filter, since the clock filter in + * ntp_proto should do its thing. + */ + disp_tmp2 = 0; + for (i = 0; i < NCODES-1; i++) { + for (j = i+1; j < NCODES; j++) { + tmp_ui = gps->offset[i].l_ui; + tmp_uf = gps->offset[i].l_uf; + M_SUB(tmp_ui, tmp_uf, gps->offset[j].l_ui, + gps->offset[j].l_uf); + if (M_ISNEG(tmp_ui, tmp_uf)) { + M_NEG(tmp_ui, tmp_uf); + } + if (tmp_ui != 0 || tmp_uf > CODEDIFF) { + return (0); + } + disp_tmp = MFPTOFP(0, tmp_uf); + if (disp_tmp > disp_tmp2) { + disp_tmp2 = disp_tmp; + not_median1 = i; + not_median2 = j; + } + } + } + if (gps->lasttime == 0) + disp_tmp2 = NTP_MAXDISPERSE; + else + disp_tmp2 = current_time - gps->lasttime; + if (not_median1 == 0) { + if (not_median2 == 1) + median = 2; + else + median = 1; + } else { + median = 0; + } + *offset = gps->offset[median]; + *dispersion = disp_tmp2; + return (1); +} + +/* + * 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(unit, peer) + int unit; + struct peer *peer; +{ + struct gpsunit *gps; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "gps_poll: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "gps_poll: unit %d not in use", unit); + return; + } + gps = gpsunits[unit]; + if ((current_time - gps->lasttime) > 150) + as2201_report_event(gpsunits[unit], CEVNT_TIMEOUT); + gettstamp(&gps->lastrec); + if (write(gps->io.fd, "\r*toc\r", 6) != 6) { + syslog(LOG_ERR, "gps_poll: unit %d: %m", gps->unit); + as2201_report_event(gps, CEVNT_FAULT); + } else + gps->polls++; +} + +/* + * as2201_control - set fudge factors, return statistics + */ +static void +as2201_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct gpsunit *gps; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "gps_control: unit %d invalid", unit); + return; + } + + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + fudgefactor[unit] = in->fudgetime1; + 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 + */ + gps = gpsunits[unit]; + peer = gps->peer; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(GPSREFID, (char *)&peer->refid, + 4); + else + peer->refid = htonl(GPSHSREFID); + } + } + if (in->haveflags & CLK_HAVEFLAG4) { + sloppyclockflag[unit] = in->flags & CLK_FLAG4; + } + } + + if (out != 0) { + out->type = REFCLK_GPS_AS2201; + out->haveflags + = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG4; + out->clockdesc = GPSDESCRIPTION; + out->fudgetime1 = fudgefactor[unit]; + out->fudgetime2.l_ui = 0; + out->fudgetime2.l_uf = 0; + out->fudgeval1 = (LONG)stratumtouse[unit]; + out->fudgeval2 = 0; + out->flags = sloppyclockflag[unit]; + if (unitinuse[unit]) { + gps = gpsunits[unit]; + out->lencode = LENTOC; + out->lastcode = gps->stats; + out->timereset = current_time - gps->timestarted; + out->polls = gps->polls; + out->noresponse = gps->noreply; + out->badformat = gps->badformat; + out->baddata = gps->baddata; + out->lastevent = gps->lastevent; + out->currentstatus = gps->status; + } else { + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} + +/* + * as2201_buginfo - return clock dependent debugging info + */ +static void +as2201_buginfo(unit, bug) + int unit; + register struct refclockbug *bug; +{ + register struct gpsunit *gps; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "gps_buginfo: unit %d invalid", unit); + return; + } + + if (!unitinuse[unit]) + return; + gps = gpsunits[unit]; + + bug->nvalues = 10; + bug->ntimes = 5; + if (gps->lasttime != 0) + bug->values[0] = current_time - gps->lasttime; + else + bug->values[0] = 0; + bug->values[1] = (U_LONG)gps->reason; + bug->values[2] = (U_LONG)gps->year; + bug->values[3] = (U_LONG)gps->day; + bug->values[4] = (U_LONG)gps->hour; + bug->values[5] = (U_LONG)gps->minute; + bug->values[6] = (U_LONG)gps->second; + bug->values[7] = (U_LONG)gps->msec; + bug->values[8] = gps->noreply; + bug->values[9] = gps->yearstart; + bug->stimes = 0x1c; + bug->times[0] = gps->lastref; + bug->times[1] = gps->lastrec; + bug->times[2] = gps->offset[0]; + bug->times[3] = gps->offset[1]; + bug->times[4] = gps->offset[2]; +} +#endif diff --git a/contrib/xntpd/xntpd/refclock_chu.c b/contrib/xntpd/xntpd/refclock_chu.c new file mode 100644 index 0000000000..05379b6331 --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_chu.c @@ -0,0 +1,1135 @@ +/* + * refclock_chu - clock driver for the CHU time code + */ +#if defined(REFCLOCK) && (defined(CHU) || defined(CHUCLK) || defined(CHUPPS)) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(STREAM) +#include +#include +#endif /* STREAM */ + +#if defined (CHUPPS) +#include +#endif /* CHUPPS */ + +#include + +#include "ntp_stdlib.h" + +/* + * The CHU time signal includes a time code which is modulated at the + * standard Bell 103 frequencies (i.e. mark=2225Hz, space=2025Hz). + * and formatted into 8 bit characters with one start bit and two + * stop bits. The time code is composed of 10 8-bit characters. + * The second 5 bytes of the timecode are a redundancy check, and + * are a copy of the first 5 bytes. + * + * It is assumed that you have built or modified a Bell 103 standard + * modem, attached the input to the output of a radio and cabled the + * output to a serial port on your computer, i.e. what you are receiving + * is essentially the output of your radio. It is also assumed you have + * installed a special CHU line discipline to condition the output from + * the terminal driver and take accurate time stamps. + * + * There are two types of timecodes. One is sent in the 32nd + * through 39th second of the minute. + * + * 6dddhhmmss6dddhhmmss + * + * where ddd is the day of the year, hh is the hour (in UTC), mm is + * the minute and ss the second. The 6 is a constant. Note that + * the code is sent twice. + * + * The second sort of timecode is sent only during the 31st second + * past the minute. + * + * xdyyyyttabXDYYYYTTAB + * + * In this case, the second part of the code is the one's complement + * of the code. This differentiates it from the other timecode + * format. + * + * d is the absolute value of DUT (in tenths of a second). yyyy + * is the year. tt is the difference between UTC and TAI. a is + * a canadian daylight time flag and b is a serial number. + * x is a bitwise field. The least significant bit of x is + * one if DUT is negative. The 2nd bit is set if a leap second + * will be added at the next opportunity. The 3rd bit is set if + * a leap second will be deleted at the next opportunity. + * The 4th bit is an even parity bit for the other three bits + * in this nibble. + * + * The start bit in each character has a precise relationship to + * the on-time second. Most often UART's synchronize themselves to the + * start bit and will post an interrupt at the center of the first stop + * bit. Thus each character's interrupt should occur at a fixed offset + * from the on-time second. This means that a timestamp taken at the + * arrival of each character in the code will provide an independent + * estimate of the offset. Since there are 10 characters in the time + * code and the code is sent 9 times per minute, this means you potentially + * get 90 offset samples per minute. Much of the code in here is dedicated + * to producing a single offset estimate from these samples. + * + * A note about the line discipline. It is possible to receive the + * CHU time code in raw mode, but this has disadvantages. In particular, + * this puts a lot of code between the interrupt and the time you freeze + * a time stamp, decreasing precision. It is also expensive in terms of + * context switches, and made even more expensive by the way I do I/O. + * Worse, since you are listening directly to the output of your radio, + * CHU is noisy and will make you spend a lot of time receiving noise. + * + * The line discipline fixes a lot of this. It knows that the CHU time + * code consists of 10 bytes which arrive with an intercharacter + * spacing of about 37 ms, and that the data is BCD, and filters on this + * basis. It delivers block of ten characters plus their associated time + * stamps all at once. The time stamps are hence about as accurate as + * a Unix machine can get them, and much of the noise disappears in the + * kernel with no context switching cost. + * + * The kernel module also will insure that the packets that are + * delivered have the correct redundancy bytes, and will return + * a flag in chutype to differentiate one sort of packet from + * the other. + */ + +/* + * Definitions + */ +#define MAXUNITS 4 /* maximum number of CHU units permitted */ +#define CHUDEV "/dev/chu%d" /* device we open. %d is unit number */ +#define SPEED232 B300 /* uart speed (300 baud) */ +#define NCHUCODES 8 /* expect 8 CHU codes per minute */ +#define CHULDISC 10 /* XXX temp CHU line discipline */ + +/* + * To compute a quality for the estimate (a pseudo dispersion) we add a + * fixed 10 ms for each missing code in the minute and add to this + * the sum of the differences between the remaining offsets and the + * estimated sample offset. + */ +#define CHUDELAYPENALTY 0x0000028f + +/* + * Other constant stuff + */ +#define CHUPRECISION (-9) /* what the heck */ +#define CHUREFID "CHU\0" +#define CHUDESCRIPTION "Direct synchronized to CHU timecode" +#define CHUHSREFID 0x7f7f070a /* 127.127.7.10 refid for hi strata */ + +/* + * Default fudge factors + */ +#define DEFPROPDELAY 0x00624dd3 /* 0.0015 seconds, 1.5 ms */ +#define DEFFILTFUDGE 0x000d1b71 /* 0.0002 seconds, 200 us */ + +/* + * Hacks to avoid excercising the multiplier. I have no pride. + */ +#define MULBY10(x) (((x)<<3) + ((x)<<1)) +#define MULBY60(x) (((x)<<6) - ((x)<<2)) /* watch overflow */ +#define MULBY24(x) (((x)<<4) + ((x)<<3)) + +/* + * Constants for use when multiplying by 0.1. ZEROPTONE is 0.1 + * as an l_fp fraction, NZPOBITS is the number of significant bits + * in ZEROPTONE. + */ +#define ZEROPTONE 0x1999999a +#define NZPOBITS 29 + +static char hexstring[]="0123456789abcdef"; + +/* + * CHU unit control structure. + */ +struct chuunit { + struct peer *peer; /* associated peer structure */ + struct event chutimer; /* timeout timer structure */ + struct refclockio chuio; /* given to the I/O handler */ + l_fp offsets[NCHUCODES]; /* offsets computed from each code */ + l_fp rectimes[NCHUCODES]; /* times we received this stuff */ + U_LONG reftimes[NCHUCODES]; /* time of last code received */ + u_char lastcode[NCHUCHARS*4]; /* last code we received */ + u_char asciicode[NCHUCHARS*4+1]; /* last code translated to ascii */ + u_char expect; /* the next offset expected */ + u_char unit; /* unit number for this guy */ + u_short haveoffset; /* flag word indicating valid offsets */ + u_short flags; /* operational flags */ + u_char status; /* clock status */ + u_char lastevent; /* last clock event */ + u_char unused[2]; + U_LONG lastupdate; /* last time data received */ + U_LONG responses; /* number of responses */ + U_LONG badformat; /* number of bad format responses */ + U_LONG baddata; /* number of invalid time codes */ + U_LONG timestarted; /* time we started this */ + u_char leap; /* leap status */ +}; + +#define CHUTIMERSET 0x1 /* timer is set to fire */ + + +/* + * The CHU table. This gives the expected time of arrival of each + * character after the on-time second and is computed as follows: + * The CHU time code is sent at 300 bps. Your average UART will + * synchronize at the edge of the start bit and will consider the + * character complete at the middle of the first stop bit, i.e. + * 0.031667 ms later (some UARTS may complete the character at the + * end of the stop bit instead of the middle, but you can fudge this). + * Thus the expected time of each interrupt is the start bit time plus + * 0.031667 seconds. These times are in chutable[]. To this we add + * such things as propagation delay and delay fudge factor. + */ +#define CHARDELAY 0x081b4e82 + +static U_LONG chutable[NCHUCHARS] = { + 0x22222222 + CHARDELAY, /* 0.1333333333 */ + 0x2b851eb8 + CHARDELAY, /* 0.170 (exactly) */ + 0x34e81b4e + CHARDELAY, /* 0.2066666667 */ + 0x3f92c5f9 + CHARDELAY, /* 0.2483333333 */ + 0x47ae147b + CHARDELAY, /* 0.280 (exactly) */ + 0x51111111 + CHARDELAY, /* 0.3166666667 */ + 0x5a740da7 + CHARDELAY, /* 0.3533333333 */ + 0x63d70a3d + CHARDELAY, /* 0.390 (exactly) */ + 0x6d3a06d4 + CHARDELAY, /* 0.4266666667 */ + 0x769d0370 + CHARDELAY, /* 0.4633333333 */ +}; + +/* + * Data space for the unit structures. Note that we allocate these on + * the fly, but never give them back. + */ +static struct chuunit *chuunits[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 propagation_delay[MAXUNITS]; +static l_fp fudgefactor[MAXUNITS]; +static l_fp offset_fudge[MAXUNITS]; +static u_char stratumtouse[MAXUNITS]; +static u_char sloppyclockflag[MAXUNITS]; + +/* + * We keep track of the start of the year, watching for changes. + * We also keep track of whether the year is a leap year or not. + * All because stupid CHU doesn't include the year in the time code. + */ +static U_LONG yearstart; + +/* + * Imported from the timer module + */ +extern U_LONG current_time; +extern struct event timerqueue[]; + +/* + * Imported from ntp_loopfilter module + */ +extern int fdpps; /* pps file descriptor */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * Event reporting. This optimizes things a little. + */ +#define chu_event(chu, evcode) \ + do { \ + if ((chu)->status != (u_char)(evcode)) \ + chu_report_event((chu), (evcode)); \ + } while (0) + +static void chu_init P((void)); +static int chu_start P((u_int, struct peer *)); +static void chu_shutdown P((int)); +static void chu_report_event P((struct chuunit *, int)); +static void chu_receive P((struct recvbuf *)); +static void chu_process P((struct chuunit *)); +static void chu_poll P((int, struct peer *)); +static void chu_control P((u_int, struct refclockstat *, struct refclockstat *)); +static void chu_timeout P((struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_chu = { + chu_start, chu_shutdown, chu_poll, + chu_control, chu_init, noentry, NOFLAGS +}; + +/* + * chu_init - initialize internal chu driver data + */ +static void +chu_init() +{ + register int i; + /* + * Just zero the data arrays + */ + bzero((char *)chuunits, sizeof chuunits); + bzero((char *)unitinuse, sizeof unitinuse); + + /* + * Initialize fudge factors to default. + */ + for (i = 0; i < MAXUNITS; i++) { + propagation_delay[i].l_ui = 0; + propagation_delay[i].l_uf = DEFPROPDELAY; + fudgefactor[i].l_ui = 0; + fudgefactor[i].l_uf = DEFFILTFUDGE; + offset_fudge[i] = propagation_delay[i]; + L_ADD(&offset_fudge[i], &fudgefactor[i]); + stratumtouse[i] = 0; + sloppyclockflag[i] = 0; + } +} + + +/* + * chu_start - open the CHU device and initialize data for processing + */ +static int +chu_start(unit, peer) + u_int unit; + struct peer *peer; +{ + register struct chuunit *chu; + register int i; + int fd232; + char chudev[20]; + l_fp ts; + + /* + * Check configuration info + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "chu_start: unit %d invalid", unit); + return 0; + } + if (unitinuse[unit]) { + syslog(LOG_ERR, "chu_start: unit %d in use", unit); + return 0; + } + + /* + * Open serial port + */ + (void) sprintf(chudev, CHUDEV, unit); + fd232 = open(chudev, O_RDONLY, 0777); + if (fd232 == -1) { + syslog(LOG_ERR, "chu_start: open of %s: %m", chudev); + return 0; + } + +#if defined(HAVE_SYSV_TTYS) + /* + * System V serial line parameters (termio interface) + */ + CHU SUPPORT NOT AVAILABLE IN TERMIO INTERFACE +#endif /* HAVE_SYSV_TTYS */ +#if defined(STREAM) + /* + * POSIX/STREAMS serial line parameters (termios interface) + * + * The CHUCLK support uses a 300-baud modem and level converter + * (gadget box). It requires the chu_clk streams module and + * SunOS 4.1.1 or later. + * + * The CHUPPS option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the ppsclock streams module and SunOS 4.1.1 or + * later. + */ + { struct termios ttyb, *ttyp; + + ttyp = &ttyb; + if (tcgetattr(fd232, ttyp) < 0) { + syslog(LOG_ERR, + "chu_start: tcgetattr(%s): %m", chudev); + goto screwed; + } + ttyp->c_iflag = IGNBRK|IGNPAR; + ttyp->c_oflag = 0; + ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD; + ttyp->c_lflag = 0; + ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; + ttyp->c_cc[VMIN] = 1; + ttyp->c_cc[VTIME] = 0; + if (tcsetattr(fd232, TCSANOW, ttyp) < 0) { + syslog(LOG_ERR, + "chu_start: tcsetattr(%s): %m", chudev); + goto screwed; + } + if (tcflush(fd232, TCIOFLUSH) < 0) { + syslog(LOG_ERR, + "chu_start: tcflush(%s): %m", chudev); + goto screwed; + } + while (ioctl(fd232, I_POP, 0 ) >= 0) ; + if (ioctl(fd232, I_PUSH, "chu" ) < 0) { + syslog(LOG_ERR, + "chu_start: ioctl(%s, I_PUSH, chu): %m", chudev); + goto screwed; + } +#if defined(CHUPPS) + if (ioctl(fd232, I_PUSH, "ppsclock") < 0) + syslog(LOG_ERR, + "chu_start: ioctl(%s, I_PUSH, ppsclock): %m", chudev); + else + fdpps = fd232; +#endif /* CHUPPS */ + } +#endif /* STREAM */ +#if defined(HAVE_BSD_TTYS) + /* + * 4.3bsd serial line parameters (sgttyb interface) + * + * The CHUCLK support uses a 300-baud modem and level converter + * (gadget box). It requires the chu_clk streams module and + * 4.3bsd or later. + */ + { struct sgttyb ttyb; + int ldisc = CHULDISC; + + if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { + syslog(LOG_ERR, + "chu_start: ioctl(%s, TIOCGETP): %m", chudev); + goto screwed; + } + ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; + ttyb.sg_erase = ttyb.sg_kill = '\r'; + ttyb.sg_flags = RAW; + if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { + syslog(LOG_ERR, + "chu_start: ioctl(%s, TIOCSETP): %m", chudev); + goto screwed; + } + if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { + syslog(LOG_ERR, + "chu_start: ioctl(%s, TIOCSETD): %m",chudev); + goto screwed; + } + } +#endif /* HAVE_BSD_TTYS */ + + /* + * Allocate unit structure + */ + if (chuunits[unit] != 0) { + chu = chuunits[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && chuunits[i] != 0) + break; + } + if (i < MAXUNITS) { + /* + * Reclaim this one + */ + chu = chuunits[i]; + chuunits[i] = 0; + } else { + chu = (struct chuunit *)emalloc(sizeof(struct chuunit)); + } + } + bzero((char *)chu, sizeof(struct chuunit)); + chuunits[unit] = chu; + + /* + * Set up the structure + */ + chu->peer = peer; + chu->unit = (u_char)unit; + chu->timestarted = current_time; + + chu->chutimer.peer = (struct peer *)chu; + chu->chutimer.event_handler = chu_timeout; + + chu->chuio.clock_recv = chu_receive; + chu->chuio.srcclock = (caddr_t)chu; + chu->chuio.datalen = sizeof(struct chucode); + chu->chuio.fd = fd232; + + /* + * Initialize the year from the system time in case this is the + * first open. + */ + get_systime(&ts); + yearstart = calyearstart(ts.l_ui); + if (!io_addclock(&chu->chuio)) { + goto screwed; + } + + /* + * All done. Initialize a few random peer variables, then + * return success. + */ + peer->precision = CHUPRECISION; + peer->rootdelay = 0; + peer->rootdispersion = 0; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(CHUREFID, (char *)&peer->refid, 4); + else + peer->refid = htonl(CHUHSREFID); + unitinuse[unit] = 1; + return 1; + + /* + * Something broke; abandon ship. + */ +screwed: + (void) close(fd232); + return (0); +} + + +/* + * chu_shutdown - shut down a CHU clock + */ +static void +chu_shutdown(unit) + int unit; +{ + register struct chuunit *chu; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "chu_shutdown: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "chu_shutdown: unit %d not in use", unit); + return; + } + + /* + * Tell the I/O module to turn us off, and dequeue timer + * if any. We're history. + */ + chu = chuunits[unit]; + if (chu->flags & CHUTIMERSET) + TIMER_DEQUEUE(&chu->chutimer); + io_closeclock(&chu->chuio); + unitinuse[unit] = 0; +} + +/* + * chu_report_event - record an event and report it + */ +static void +chu_report_event(chu, code) + struct chuunit *chu; + int code; +{ + /* + * Trap support isn't up to handling this, so just + * record it. + */ + if (chu->status != (u_char)code) { + chu->status = (u_char)code; + if (code != CEVNT_NOMINAL) + chu->lastevent = (u_char)code; + } +} + + +/* + * chu_receive - receive data from a CHU clock, do format checks and compute + * an estimate from the sample data + */ +static void +chu_receive(rbufp) + struct recvbuf *rbufp; +{ + register int i; + register U_LONG date_ui; + register U_LONG tmp; + register u_char *code; + register struct chuunit *chu; + register struct chucode *chuc; + int isneg; + U_LONG reftime; + l_fp off[NCHUCHARS]; + int day, hour, minute, second; + + /* + * Do a length check on the data. Should be what we asked for. + */ + if (rbufp->recv_length != sizeof(struct chucode)) { + syslog(LOG_ERR, "chu_receive: received %d bytes, expected %d", + rbufp->recv_length, sizeof(struct chucode)); + return; + } + + /* + * Get the clock this applies to and a pointer to the data + */ + chu = (struct chuunit *)rbufp->recv_srcclock; + chuc = (struct chucode *)&rbufp->recv_space; + chu->responses++; + chu->lastupdate = current_time; + + /* + * At this point we're assured that both halves of the + * data match because of what the kernel has done. + * But there's more than one data format. We need to + * check chutype to see what to do now. If it's a + * year packet, then we fiddle with it specially. + */ + + if (chuc->chutype == CHU_YEAR) + { + u_char leapbits,parity; + + /* + * Break out the code into the BCD nibbles. + * Put it in the half of lastcode. + */ + code = chu->lastcode; + code += 2*NCHUCHARS; + for (i = 0; i < NCHUCHARS; i++) { + *code++ = chuc->codechars[i] & 0xf; + *code++ = (chuc->codechars[i] >> 4) & 0xf; + } + + leapbits = chuc->codechars[0]&0xf; + + /* + * Now make sure that the leap nibble + * is even parity. + */ + + parity = (leapbits ^ (leapbits >> 2))&0x3; + parity = (parity ^ (parity>>1))&0x1; + if (parity) + { + chu->badformat++; + chu_event(chu, CEVNT_BADREPLY); + return; + } + + /* + * This just happens to work. :-) + */ + + chu->leap = (leapbits >> 1) & 0x3; + + return; + } + + if (chuc->chutype != CHU_TIME) + { + chu->badformat++; + chu_event(chu, CEVNT_BADREPLY); + return; + } + + /* + * Break out the code into the BCD nibbles. Only need to fiddle + * with the first half since both are identical. Note the first + * BCD character is the low order nibble, the second the high order. + */ + code = chu->lastcode; + for (i = 0; i < NCHUCHARS; i++) { + *code++ = chuc->codechars[i] & 0xf; + *code++ = (chuc->codechars[i] >> 4) & 0xf; + } + + /* + * Format check. Make sure the two halves match. + * There's really no need for this, but it can't hurt. + */ + for (i = 0; i < NCHUCHARS/2; i++) + if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) { + chu->badformat++; + chu_event(chu, CEVNT_BADREPLY); + return; + } + + /* + * If the first nibble isn't a 6, we're up the creek + */ + code = chu->lastcode; + if (*code++ != 6) { + chu->badformat++; + chu_event(chu, CEVNT_BADREPLY); + return; + } + + /* + * Collect the day, the hour, the minute and the second. + */ + day = *code++; + day = MULBY10(day) + *code++; + day = MULBY10(day) + *code++; + hour = *code++; + hour = MULBY10(hour) + *code++; + minute = *code++; + minute = MULBY10(minute) + *code++; + second = *code++; + second = MULBY10(second) + *code++; + + /* + * Sanity check the day and time. Note that this + * only occurs on the 32st through the 39th second + * of the minute. + */ + if (day < 1 || day > 366 + || hour > 23 || minute > 59 + || second < 32 || second > 39) { + chu->baddata++; + if (day < 1 || day > 366) { + chu_event(chu, CEVNT_BADDATE); + } else { + chu_event(chu, CEVNT_BADTIME); + } + return; + } + + /* + * Compute the NTP date from the input data and the + * receive timestamp. If this doesn't work, mark the + * date as bad and forget it. + */ + if (!clocktime(day, hour, minute, second, 0, + rbufp->recv_time.l_ui, &yearstart, &reftime)) { + chu_event(chu, CEVNT_BADDATE); + return; + } + date_ui = reftime;; + + /* + * We've now got the integral seconds part of the time code (we hope). + * The fractional part comes from the table. We next compute + * the offsets for each character. + */ + for (i = 0; i < NCHUCHARS; i++) { + register U_LONG tmp2; + + off[i].l_ui = date_ui; + off[i].l_uf = chutable[i]; + tmp = chuc->codetimes[i].tv_sec + JAN_1970; + TVUTOTSF(chuc->codetimes[i].tv_usec, tmp2); + M_SUB(off[i].l_ui, off[i].l_uf, tmp, tmp2); + } + + if (!sloppyclockflag[chu->unit]) { + u_short ord[NCHUCHARS]; + /* + * In here we assume the clock has adequate bits + * to take timestamps with reasonable accuracy. + * Note that the time stamps may contain errors + * for a couple of reasons. Timing is actually + * referenced to the start bit in each character + * in the time code. If this is obscured by static + * you can still get a valid character but have the + * timestamp offset by +-1.5 ms. Also, we may suffer + * from interrupt delays if the interrupt is being + * held off when the character arrives. Note the + * latter error is always in the form of a delay. + * + * After fiddling I arrived at the following scheme. + * We sort the times into order by offset. We then + * drop the most positive 2 offset values (which may + * correspond to a character arriving early due to + * static) and the most negative 4 (which may correspond + * to delayed characters, either from static or from + * interrupt latency). We then take the mean of the + * remaining 4 offsets as our estimate. + */ + + /* + * Set up the order array. + */ + for (i = 0; i < NCHUCHARS; i++) + ord[i] = (u_short)i; + + /* + * Sort them into order. Reuse variables with abandon. + */ + for (tmp = 0; tmp < (NCHUCHARS-1); tmp++) { + for (i = (int)tmp+1; i < NCHUCHARS; i++) { + if (!L_ISGEQ(&off[ord[i]], &off[ord[tmp]])) { + date_ui = (U_LONG)ord[i]; + ord[i] = ord[tmp]; + ord[tmp] = (u_short)date_ui; + } + } + } + + /* + * Done the sort. We drop 0, 1, 2 and 3 at the negative + * end, and 8 and 9 at the positive. Take the sum of + * 4, 5, 6 and 7. + */ + date_ui = off[ord[4]].l_ui; + tmp = off[ord[4]].l_uf; + for (i = 5; i <= 7; i++) + M_ADD(date_ui, tmp, off[ord[i]].l_ui, off[ord[i]].l_uf); + + /* + * Round properly, then right shift two bits for the + * divide by four. + */ + if (tmp & 0x2) + M_ADDUF(date_ui, tmp, 0x4); + M_RSHIFT(date_ui, tmp); + M_RSHIFT(date_ui, tmp); + } else { + /* + * Here is a *big* problem. On a machine where the + * low order bit in the clock is on the order of half + * a millisecond or more we don't really have enough + * precision to make intelligent choices about which + * samples might be in error and which aren't. More + * than this, in the case of error free data we can + * pick up a few bits of precision by taking the mean + * of the whole bunch. This is what we do. The problem + * comes when it comes time to divide the 64 bit sum of + * the 10 samples by 10, a procedure which really sucks. + * Oh, well, grin and bear it. Compute the sum first. + */ + date_ui = 0; + tmp = 0; + for (i = 0; i < NCHUCHARS; i++) + M_ADD(date_ui, tmp, off[i].l_ui, off[i].l_uf); + if (M_ISNEG(date_ui, tmp)) + isneg = 1; + else + isneg = 0; + + /* + * Here is a multiply-by-0.1 optimization that should apply + * just about everywhere. If the magnitude of the sum + * is less than 9 we don't have to worry about overflow + * out of a 64 bit product, even after rounding. + */ + if (date_ui < 9 || date_ui > 0xfffffff7) { + register U_LONG prod_ui; + register U_LONG prod_uf; + + prod_ui = prod_uf = 0; + /* + * This code knows the low order bit in 0.1 is zero + */ + for (i = 1; i < NZPOBITS; i++) { + M_LSHIFT(date_ui, tmp); + if (ZEROPTONE & (1<expect) { + /* + * This shouldn't actually happen, but might if a single + * bit error occurred in the code which fooled us. + * Throw away all previous data. + */ + chu->expect = 0; + chu->haveoffset = 0; + if (chu->flags & CHUTIMERSET) { + TIMER_DEQUEUE(&chu->chutimer); + chu->flags &= ~CHUTIMERSET; + } + } + + /* + * Add in fudge factor. + */ + M_ADD(date_ui, tmp, offset_fudge[chu->unit].l_ui, + offset_fudge[chu->unit].l_uf); + + chu->offsets[i].l_ui = date_ui; + chu->offsets[i].l_uf = tmp; + chu->rectimes[i] = rbufp->recv_time; + chu->reftimes[i] = reftime; + + chu->expect = i + 1; + chu->haveoffset |= (1<expect >= NCHUCODES) { + /* + * Got a full second's worth. Dequeue timer and + * process this. + */ + if (chu->flags & CHUTIMERSET) { + TIMER_DEQUEUE(&chu->chutimer); + chu->flags &= ~CHUTIMERSET; + } + chu_process(chu); + } else if (!(chu->flags & CHUTIMERSET)) { + /* + * Try to take an interrupt sometime after the + * 42 second mark (leaves an extra 2 seconds for + * slop). Round it up to an even multiple of + * 4 seconds. + */ + chu->chutimer.event_time = + current_time + (U_LONG)(10 - i) + (1<chutimer.event_time &= ~((1<chutimer); + chu->flags |= CHUTIMERSET; + } +} + + +/* + * chu_timeout - process a timeout event + */ +static void +chu_timeout(fakepeer) + struct peer *fakepeer; +{ + /* + * If we got here it means we received some time codes + * but didn't get the one which should have arrived on + * the 39th second. Process what we have. + */ + ((struct chuunit *)fakepeer)->flags &= ~CHUTIMERSET; + chu_process((struct chuunit *)fakepeer); +} + + +/* + * chu_process - process the raw offset estimates we have and pass + * the results on to the NTP clock filters. + */ +static void +chu_process(chu) + register struct chuunit *chu; +{ + register int i; + register s_fp bestoff; + register s_fp tmpoff; + u_fp dispersion; + int imax; + l_fp ts; + + /* + * The most positive offset. + */ + imax = NCHUCODES; + for (i = 0; i < NCHUCODES; i++) + if (chu->haveoffset & (1<offsets[i], + &chu->offsets[imax])) + imax = i; + + /* + * The most positive estimate is our best bet. Go through + * the list again computing the dispersion. + */ + bestoff = LFPTOFP(&chu->offsets[imax]); + dispersion = 0; + for (i = 0; i < NCHUCODES; i++) { + if (chu->haveoffset & (1<offsets[i]); + dispersion += (bestoff - tmpoff); + } else { + dispersion += CHUDELAYPENALTY; + } + } + + /* + * Make up a reference time stamp, then give it to the + * reference clock support code for further processing. + */ + ts.l_ui = chu->reftimes[imax]; + ts.l_uf = chutable[NCHUCHARS-1]; + + for (i = 0; i < NCHUCHARS*4; i++) { + chu->asciicode[i] = hexstring[chu->lastcode[i]]; + } + chu->asciicode[i] = '\0'; + record_clock_stats(&(chu->peer->srcadr), chu->asciicode); + refclock_receive(chu->peer, &chu->offsets[imax], 0, + dispersion, &ts, &chu->rectimes[imax], chu->leap); + + /* + * Zero out unit for next code series + */ + chu->haveoffset = 0; + chu->expect = 0; + chu_event(chu, CEVNT_NOMINAL); +} + + +/* + * chu_poll - called by the transmit procedure + */ +static void +chu_poll(unit, peer) + int unit; + struct peer *peer; +{ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "chu_poll: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "chu_poll: unit %d not in use", unit); + return; + } + + if ((current_time - chuunits[unit]->lastupdate) > 150) { + chu_event(chuunits[unit], CEVNT_PROP); + } +} + + + +/* + * chu_control - set fudge factors, return statistics + */ +static void +chu_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct chuunit *chu; + U_LONG npolls; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "chu_control: unit %d invalid", unit); + return; + } + + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + propagation_delay[unit] = in->fudgetime1; + if (in->haveflags & CLK_HAVETIME2) + fudgefactor[unit] = in->fudgetime2; + offset_fudge[unit] = propagation_delay[unit]; + L_ADD(&offset_fudge[unit], &fudgefactor[unit]); + 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 + */ + peer = chuunits[unit]->peer; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(CHUREFID, (char *)&peer->refid,4); + else + peer->refid = htonl(CHUHSREFID); + } + } + if (in->haveflags & CLK_HAVEFLAG1) { + sloppyclockflag[unit] = in->flags & CLK_FLAG1; + } + } + + if (out != 0) { + out->type = REFCLK_CHU; + out->flags = 0; + out->haveflags + = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1| + CLK_HAVEVAL2|CLK_HAVEFLAG1; + out->clockdesc = CHUDESCRIPTION; + out->fudgetime1 = propagation_delay[unit]; + out->fudgetime2 = fudgefactor[unit]; + out->fudgeval1 = (long)stratumtouse[unit]; + out->flags = sloppyclockflag[unit]; + if (unitinuse[unit]) { + chu = chuunits[unit]; + out->lencode = NCHUCHARS*4; + out->fudgeval2 = chu->lastcode[2*NCHUCHARS+1]; + out->fudgeval2 *= (chu->lastcode[2*NCHUCHARS]&1)?-1:1; + out->lastcode = chu->asciicode; + out->timereset = current_time - chu->timestarted; + npolls = out->timereset / 6; /* **divide** */ + out->polls = npolls; + out->noresponse = (npolls - chu->responses); + out->badformat = chu->badformat; + out->baddata = chu->baddata; + out->lastevent = chu->lastevent; + out->currentstatus = chu->status; + } else { + out->fudgeval2 = 0; + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} +#endif diff --git a/contrib/xntpd/xntpd/refclock_conf.c b/contrib/xntpd/xntpd/refclock_conf.c new file mode 100644 index 0000000000..efe096647b --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_conf.c @@ -0,0 +1,121 @@ +/* + * refclock_conf.c - reference clock configuration + */ +#include +#include + +#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 LOCAL_CLOCK +extern struct refclock refclock_local; +#else +#define refclock_local refclock_none +#endif + +#if defined(PST) || defined(PSTCLK) || defined(PSTPPS) +extern struct refclock refclock_pst; +#else +#define refclock_pst refclock_none +#endif + +#if defined(CHU) || defined(CHUCLK) || defined(CHUPPS) +extern struct refclock refclock_chu; +#else +#define refclock_chu refclock_none +#endif + +#if defined(GOES) || defined(GOESCLK) || defined(GOESPPS) +extern struct refclock refclock_goes; +#else +#define refclock_goes refclock_none +#endif + +#if defined(WWVB) || defined(WWVBCLK) || defined(WWVBPPS) +extern struct refclock refclock_wwvb; +#else +#define refclock_wwvb refclock_none +#endif + +#if defined(PARSE) || defined(PARSEPPS) +extern struct refclock refclock_parse; +#else +#define refclock_parse refclock_none +#endif + +#if defined(MX4200) || defined(MX4200CLK) || defined(MX4200PPS) +extern struct refclock refclock_mx4200; +#else +#define refclock_mx4200 refclock_none +#endif + +#if defined(AS2201) || defined(AS2201CLK) || defined(AS2201PPS) +extern struct refclock refclock_as2201; +#else +#define refclock_as2201 refclock_none +#endif + +#if defined(OMEGA) || defined(OMEGACLK) || defined(OMEGAPPS) +extern struct refclock refclock_omega; +#else +#define refclock_omega refclock_none +#endif + +#ifdef TPRO +extern struct refclock refclock_tpro; +#else +#define refclock_tpro refclock_none +#endif + +#if defined(LEITCH) || defined(LEITCHCLK) || defined(LEITCHPPS) +extern struct refclock refclock_leitch; +#else +#define refclock_leitch refclock_none +#endif + +#ifdef IRIG +extern struct refclock refclock_irig; +#else +#define refclock_irig refclock_none +#endif + +#if defined(MSFEESPPS) +extern struct refclock refclock_msfees; +#else +#define refclock_msfees 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_none, /* 2 REFCLK_WWV_HEATH */ + &refclock_pst, /* 3 REFCLK_WWV_PST */ + &refclock_wwvb, /* 4 REFCLK_WWVB_SPECTRACOM */ + &refclock_goes, /* 5 REFCLK_GOES_TRUETIME */ + &refclock_irig, /* 6 REFCLK_IRIG_AUDIO */ + &refclock_chu, /* 7 REFCLK_CHU */ + &refclock_parse, /* 8 REFCLK_PARSE */ + &refclock_mx4200, /* 9 REFCLK_GPS_MX4200 */ + &refclock_as2201, /* 10 REFCLK_GPS_AS2201 */ + &refclock_omega, /* 11 REFCLK_OMEGA_TRUETIME */ + &refclock_tpro, /* 12 REFCLK_IRIG_TPRO */ + &refclock_leitch, /* 13 REFCLK_ATOM_LEITCH */ + &refclock_msfees, /* 14 REFCLK_MSF_EES */ +}; + +u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *); + +#endif diff --git a/contrib/xntpd/xntpd/refclock_goes.c b/contrib/xntpd/xntpd/refclock_goes.c new file mode 100644 index 0000000000..60b19f69ae --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_goes.c @@ -0,0 +1,1009 @@ +/* + * refclock_goes - clock driver for the Kinimetrics Truetime GOES receiver + * Version 2.0 + */ + +#if defined(REFCLOCK) && (defined(GOES) || defined(GOESCLK) || defined(GOESPPS)) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(STREAM) +#include +#include +#if defined(GOESCLK) +#include +#endif /* GOESCLK */ +#endif /* STREAM */ + +#if defined (GOESPPS) +#include +#endif /* GOESPPS */ + +#include "ntp_stdlib.h" + +/* + * Support for Kinemetrics Truetime 468-DC GOES Receiver + * + * Most of this code is copied from refclock_goes.c with thanks. + * + * the time code looks like follows; Send the clock a R or C and once per + * second a timestamp will appear that looks like this: + * ADDD:HH:MM:SSQCL + * A - control A + * Q Quality indication: indicates possible error of + * ? +/- 500 milliseconds # +/- 50 milliseconds + * * +/- 5 milliseconds . +/- 1 millisecond + * space less than 1 millisecond + * C - Carriage return + * L - Line feed + * The cariage return start bit begins on 0 seconds and extends to 1 bit time. + * + * Unless you live on 125 degrees west longitude, 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 5 milliseconds retard needed. + * The software will ask the clock which satellite it sees. + * + * Flag1 set to 1 will silence the clock side of xntpd, just reading the + * clock without trying to write to it. This is usefull if several + * xntpds listen to the same clock. This has not been tested yet... + */ + +/* + * Definitions + */ +#define MAXUNITS 4 /* max number of GOES units */ +#define GOES232 "/dev/goes%d" +#define SPEED232 B9600 /* 9600 baud */ + +/* + * Radio interface parameters + */ +#define GOESMAXDISPERSE (FP_SECOND>>1) /* max error for synchronized clock (0.5 s as an u_fp) */ +#define GOESSKEWFACTOR 17 /* skew factor (for about 32 ppm) */ +#define GOESPRECISION (-10) /* precision assumed (about 1 ms) */ +#define GOESREFID "GOES" /* reference id */ +#define GOESDESCRIPTION "Kinemetrics GOES Receiver" /* who we are */ +#define GOESHSREFID 0x7f7f050a /* 127.127.5.10 refid hi strata */ +#define GMT 0 /* hour offset from Greenwich */ +#define NCODES 3 /* stages of median filter */ +#define LENGOES0 13 /* format 0 timecode length */ +#define LENGOES2 21 /* format 2 timecode length */ +#define FMTGOESU 0 /* unknown format timecode id */ +#define FMTGOES0 1 /* format 0 timecode id */ +#define FMTGOES2 2 /* format 2 timecode id */ +#define DEFFUDGETIME 0 /* default fudge time (ms) */ +#define BMAX 50 /* timecode buffer length */ +#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */ + +/* + * Tag which satellite we see + */ +#define GOES_SAT_NONE 0 +#define GOES_SAT_WEST 1 +#define GOES_SAT_EAST 2 +#define GOES_SAT_STAND 3 + +/* + * Hack to avoid excercising the multiplier. I have no pride. + */ +#define MULBY10(x) (((x)<<3) + ((x)<<1)) + +/* + * Imported from the timer module + */ +extern U_LONG current_time; +extern struct event timerqueue[]; + +/* + * Imported from ntp_loopfilter module + */ +extern int fdpps; /* pps file descriptor */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * GOES unit control structure + */ +struct goesunit { + struct peer *peer; /* associated peer structure */ + struct refclockio io; /* given to the I/O handler */ + l_fp lastrec; /* last receive time */ + l_fp lastref; /* last timecode time */ + l_fp offset[NCODES]; /* recent sample offsets */ + char lastcode[BMAX]; /* last timecode received */ + u_short satellite; /* which satellite we saw */ + u_short polled; /* Hand in a time sample? */ + u_char format; /* timecode format */ + u_char lencode; /* length of last timecode */ + U_LONG lasttime; /* last time clock heard from */ + 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 year; /* year of eternity */ + u_short day; /* day of year */ + u_char hour; /* hour of day */ + u_char minute; /* minute of hour */ + u_char second; /* seconds of minute */ + u_char leap; /* leap indicators */ + u_short msec; /* millisecond of second */ + u_char quality; /* quality char from format 2 */ + U_LONG yearstart; /* start of current year */ + /* + * 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 goesunit *goesunits[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 fudgefactor1[MAXUNITS]; +static l_fp fudgefactor2[MAXUNITS]; +static u_char stratumtouse[MAXUNITS]; +static u_char readonlyclockflag[MAXUNITS]; + +/* + * Function prototypes + */ +static void goes_init P((void)); +static int goes_start P((u_int, struct peer *)); +static void goes_shutdown P((int)); +static void goes_report_event P((struct goesunit *, int)); +static void goes_receive P((struct recvbuf *)); +static char goes_process P((struct goesunit *, l_fp *, u_fp *)); +static void goes_poll P((int, struct peer *)); +static void goes_control P((u_int, struct refclockstat *, struct refclockstat *)); +static void goes_buginfo P((int, struct refclockbug *)); +static void goes_send P((struct goesunit *, char *)); + +struct refclock refclock_goes = { + goes_start, goes_shutdown, goes_poll, + goes_control, goes_init, goes_buginfo, NOFLAGS +}; + +/* + * goes_init - initialize internal goes driver data + */ +static void +goes_init() +{ + register int i; + /* + * Just zero the data arrays + */ + bzero((char *)goesunits, sizeof goesunits); + bzero((char *)unitinuse, sizeof unitinuse); + + /* + * Initialize fudge factors to default. + */ + for (i = 0; i < MAXUNITS; i++) { + fudgefactor1[i].l_ui = 0; + fudgefactor1[i].l_uf = DEFFUDGETIME; + fudgefactor2[i].l_ui = 0; + fudgefactor2[i].l_uf = DEFFUDGETIME; + stratumtouse[i] = 0; + readonlyclockflag[i] = 0; + } +} + + +/* + * goes_start - open the GOES devices and initialize data for processing + */ +static int +goes_start(unit, peer) + u_int unit; + struct peer *peer; +{ + register struct goesunit *goes; + register int i; + int fd232; + char goesdev[20]; + + /* + * Check configuration info + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "goes_start: unit %d invalid", unit); + return 0; + } + if (unitinuse[unit]) { + syslog(LOG_ERR, "goes_start: unit %d in use", unit); + return 0; + } + + /* + * Open serial port + */ + (void) sprintf(goesdev, GOES232, unit); + fd232 = open(goesdev, O_RDWR, 0777); + if (fd232 == -1) { + syslog(LOG_ERR, "goes_start: open of %s: %m", goesdev); + return 0; + } + +#if defined(HAVE_SYSV_TTYS) + /* + * System V serial line parameters (termio interface) + * + */ + { struct termio ttyb; + if (ioctl(fd232, TCGETA, &ttyb) < 0) { + syslog(LOG_ERR, + "goes_start: ioctl(%s, TCGETA): %m", goesdev); + 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) { + syslog(LOG_ERR, + "goes_start: ioctl(%s, TCSETA): %m", goesdev); + goto screwed; + } + } +#endif /* HAVE_SYSV_TTYS */ +#if defined(STREAM) + /* + * POSIX/STREAMS serial line parameters (termios interface) + * + * The GOESCLK option provides timestamping at the driver level. + * It requires the tty_clk streams module. + * + * The GOESPPS option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the ppsclock streams module and SunOS 4.1.1 or + * later. + */ + { struct termios ttyb, *ttyp; + ttyp = &ttyb; + + if (tcgetattr(fd232, ttyp) < 0) { + syslog(LOG_ERR, + "goes_start: tcgetattr(%s): %m", goesdev); + 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) { + syslog(LOG_ERR, + "goes_start: tcsetattr(%s): %m", goesdev); + goto screwed; + } + if (tcflush(fd232, TCIOFLUSH) < 0) { + syslog(LOG_ERR, + "goes_start: tcflush(%s): %m", goesdev); + goto screwed; + } +#if defined(GOESCLK) + if (ioctl(fd232, I_PUSH, "clk") < 0) + syslog(LOG_ERR, + "goes_start: ioctl(%s, I_PUSH, clk): %m", goesdev); + if (ioctl(fd232, CLK_SETSTR, "\n") < 0) + syslog(LOG_ERR, + "goes_start: ioctl(%s, CLK_SETSTR): %m", goesdev); +#endif /* GOESCLK */ +#if defined(GOESPPS) + if (ioctl(fd232, I_PUSH, "ppsclock") < 0) + syslog(LOG_ERR, + "goes_start: ioctl(%s, I_PUSH, ppsclock): %m", goesdev); + else + fdpps = fd232; +#endif /* GOESPPS */ + } +#endif /* STREAM */ +#if defined(HAVE_BSD_TTYS) + /* + * 4.3bsd serial line parameters (sgttyb interface) + * + * The GOESCLK option provides timestamping at the driver level. + * It requires the tty_clk line discipline and 4.3bsd or later. + */ + { struct sgttyb ttyb; +#if defined(GOESCLK) + int ldisc = CLKLDISC; +#endif /* GOESCLK */ + + if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { + syslog(LOG_ERR, + "goes_start: ioctl(%s, TIOCGETP): %m", goesdev); + goto screwed; + } + ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; +#if defined(GOESCLK) + 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 /* GOESCLK */ + if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { + syslog(LOG_ERR, + "goes_start: ioctl(%s, TIOCSETP): %m", goesdev); + goto screwed; + } +#if defined(GOESCLK) + if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { + syslog(LOG_ERR, + "goes_start: ioctl(%s, TIOCSETD): %m",goesdev); + goto screwed; + } +#endif /* GOESCLK */ + } +#endif /* HAVE_BSD_TTYS */ + + /* + * Allocate unit structure + */ + if (goesunits[unit] != 0) { + goes = goesunits[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && goesunits[i] != 0) + break; + } + if (i < MAXUNITS) { + /* + * Reclaim this one + */ + goes = goesunits[i]; + goesunits[i] = 0; + } else { + goes = (struct goesunit *) + emalloc(sizeof(struct goesunit)); + } + } + bzero((char *)goes, sizeof(struct goesunit)); + goesunits[unit] = goes; + + /* + * Set up the structures + */ + goes->peer = peer; + goes->unit = (u_char)unit; + goes->timestarted = current_time; + goes->satellite = GOES_SAT_NONE; + + goes->io.clock_recv = goes_receive; + goes->io.srcclock = (caddr_t)goes; + goes->io.datalen = 0; + goes->io.fd = fd232; + if (!io_addclock(&goes->io)) { + goto screwed; + } + + /* + * All done. Initialize a few random peer variables, then + * return success. + */ + peer->precision = GOESPRECISION; + peer->rootdelay = 0; + peer->rootdispersion = 0; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(GOESREFID, (char *)&peer->refid, 4); + else + peer->refid = htonl(GOESHSREFID); + unitinuse[unit] = 1; + return 1; + + /* + * Something broke; abandon ship + */ +screwed: + (void) close(fd232); + return 0; +} + +/* + * goes_shutdown - shut down a GOES clock + */ +static void +goes_shutdown(unit) + int unit; +{ + register struct goesunit *goes; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "goes_shutdown: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "goes_shutdown: unit %d not in use", unit); + return; + } + + /* + * Tell the I/O module to turn us off. We're history. + */ + goes = goesunits[unit]; + io_closeclock(&goes->io); + unitinuse[unit] = 0; +} + + +/* + * goes_report_event - note the occurance of an event + */ +static void +goes_report_event(goes, code) + struct goesunit *goes; + int code; +{ + struct peer *peer; + + peer = goes->peer; + if (goes->status != (u_char)code) { + goes->status = (u_char)code; + if (code != CEVNT_NOMINAL) + goes->lastevent = (u_char)code; + syslog(LOG_INFO, + "clock %s event %x\n", ntoa(&peer->srcadr), code); +#ifdef DEBUG + if (debug) { + printf("goes_report_event(goes%d, code %d)\n", + goes->unit, code); + } +#endif + } +} + + +/* + * goes_receive - receive data from the serial interface on a Kinimetrics + * clock + */ +static void +goes_receive(rbufp) + struct recvbuf *rbufp; +{ + register int i; + register struct goesunit *goes; + register u_char *dpt; + register char *cp; + register u_char *dpend; + l_fp tstmp; + u_fp dispersion; + + /* + * Get the clock this applies to and a pointers to the data + */ + goes = (struct goesunit *)rbufp->recv_srcclock; + dpt = (u_char *)&rbufp->recv_space; + + /* + * Edit timecode to remove control chars + */ + dpend = dpt + rbufp->recv_length; + cp = goes->lastcode; + while (dpt < dpend) { + if ((*cp = 0x7f & *dpt++) >= ' ') cp++; +#ifdef GOESCLK + else if (*cp == '\r') { + if (dpend - dpt < 8) { + /* short timestamp */ + return; + } + if (!buftvtots(dpt,&goes->lastrec)) { + /* screwy timestamp */ + return; + } + dpt += 8; + } +#endif + } + *cp = '\0'; + goes->lencode = cp - goes->lastcode; + if (goes->lencode == 0) return; +#ifndef GOESCLK + goes->lastrec = rbufp->recv_time; +#endif /* GOESCLK */ + tstmp = goes->lastrec; + +#ifdef DEBUG + if (debug) + printf("goes: timecode %d %s\n", + goes->lencode, goes->lastcode); +#endif + + /* + * We get down to business, check the timecode format and decode + * its contents. This code checks for and decodes both format 0 + * and format 2 and need not be told which in advance. + */ + cp = goes->lastcode; + goes->leap = 0; + goes->format = FMTGOESU; + if (goes->lencode == LENGOES0) { + + /* + * Check timecode format 0 + */ + if (!isdigit(cp[0]) || /* day of year */ + !isdigit(cp[1]) || + !isdigit(cp[2]) || + cp[3] != ':' || /* */ + !isdigit(cp[4]) || /* hours */ + !isdigit(cp[5]) || + cp[6] != ':' || /* : separator */ + !isdigit(cp[7]) || /* minutes */ + !isdigit(cp[8]) || + cp[9] != ':' || /* : separator */ + !isdigit(cp[10]) || /* seconds */ + !isdigit(cp[11])) { + goes->badformat++; + goes_report_event(goes, CEVNT_BADREPLY); + return; + } + else goes->format = FMTGOES0; + + /* + * Convert format 0 and check values + */ + goes->year = 0; /* fake */ + goes->day = cp[0] - '0'; + goes->day = MULBY10(goes->day) + cp[1] - '0'; + goes->day = MULBY10(goes->day) + cp[2] - '0'; + goes->hour = MULBY10(cp[4] - '0') + cp[5] - '0'; + goes->minute = MULBY10(cp[7] - '0') + cp[8] - '0'; + goes->second = MULBY10(cp[10] - '0') + cp[11] - '0'; + goes->msec = 0; + + if (cp[12] != ' ' && cp[12] != '.' && cp[12] != '*') + goes->leap = LEAP_NOTINSYNC; + else + goes->lasttime = current_time; + + if (goes->day < 1 || goes->day > 366) { + goes->baddata++; + goes_report_event(goes, CEVNT_BADDATE); + return; + } + if (goes->hour > 23 || goes->minute > 59 + || goes->second > 59) { + goes->baddata++; + goes_report_event(goes, CEVNT_BADTIME); + return; + } + + } else if (goes->lencode == LENGOES2) { + + /* + * Extended precision satelite location info + */ + if (!isdigit(cp[0]) || /* longitude */ + !isdigit(cp[1]) || + !isdigit(cp[2]) || + cp[3] != '.' || + !isdigit(cp[4]) || + !isdigit(cp[5]) || + !isdigit(cp[6]) || + !isdigit(cp[7]) || + (cp[8] != '+' && cp[8] != '-') || + !isdigit(cp[9]) || /*latitude */ + cp[10] != '.' || + !isdigit(cp[11]) || + !isdigit(cp[12]) || + !isdigit(cp[13]) || + !isdigit(cp[14]) || + (cp[15] != '+' && cp[15] != '-') || + !isdigit(cp[16]) || /* height */ + !isdigit(cp[17]) || + !isdigit(cp[18]) || + cp[19] != '.' || + !isdigit(cp[20])) { + goes->badformat++; + goes_report_event(goes, CEVNT_BADREPLY); + return; + } + else goes->format = FMTGOES2; + + /* + * Figure out which satellite this is. + * This allows +-5 degrees from nominal. + */ + if (cp[0] == '1' && (cp[1] == '3' || cp[1] == '2')) + goes->satellite = GOES_SAT_WEST; + else if (cp[0] == '1' && cp[1] == '0') + goes->satellite = GOES_SAT_STAND; + else if (cp[0] == '0' && cp[1] == '7') + goes->satellite = GOES_SAT_EAST; + else + goes->satellite = GOES_SAT_NONE; + +#ifdef DEBUG + if (debug) + printf("goes_receive: select satellite %d\n", + goes->satellite); +#endif + + /* + * Switch back to on-second time codes. + */ + goes_send(goes,"C"); + + /* + * Since this is not a time code, just return... + */ + return; + } else { + goes_report_event(goes, CEVNT_BADREPLY); + 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 (!goes->polled) + return; + + /* + * Now, compute the reference time value. Use the heavy + * machinery for the seconds and the millisecond field for the + * fraction when present. + * + * this code does not yet know how to do the years + */ + tstmp = goes->lastrec; + if (!clocktime(goes->day, goes->hour, goes->minute, + goes->second, GMT, tstmp.l_ui, + &goes->yearstart, &goes->lastref.l_ui)) { + goes->baddata++; + goes_report_event(goes, CEVNT_BADTIME); + return; + } + MSUTOTSF(goes->msec, goes->lastref.l_uf); + + + /* + * Slop the read value by fudgefactor1 or fudgefactor2 depending + * on which satellite we are viewing last time we checked. + */ + +#ifdef DEBUG + if (debug) + printf("GOES_RECEIVE: Slopping for satellite %d\n", + goes->satellite); +#endif + if (goes->satellite == GOES_SAT_WEST) + L_ADD(&goes->lastref, &fudgefactor1[goes->unit]); + else if (goes->satellite == GOES_SAT_EAST) + L_ADD(&goes->lastref, &fudgefactor2[goes->unit]); +/* else if (goes->satellite == GOES_SAT_STAND) + L_ADD(&goes->lastref, &((fudgefactor1[goes->unit] + + fudgefactor2[goes->unit]) / 2)); */ + + i = ((int)(goes->coderecv)) % NCODES; + goes->offset[i] = goes->lastref; + L_SUB(&goes->offset[i], &tstmp); + if (goes->coderecv == 0) + for (i = 1; i < NCODES; i++) + goes->offset[i] = goes->offset[0]; + + goes->coderecv++; + + /* + * Check the satellite position + */ + goes_send(goes,"E"); + + /* + * Process the median filter, add the fudge factor and pass the + * offset and dispersion along. 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 (!goes_process(goes, &tstmp, &dispersion)) { + goes->baddata++; + goes_report_event(goes, CEVNT_BADTIME); + return; + } + refclock_receive(goes->peer, &tstmp, GMT, dispersion, + &goes->lastrec, &goes->lastrec, goes->leap); + + /* + * We have succedded in answering the poll. Turn off the flag + */ + goes->polled = 0; +} + + +/* + * goes_send - time to send the clock a signal to cough up a time sample + */ +static void +goes_send(goes,cmd) + struct goesunit *goes; + char *cmd; +{ + if (!readonlyclockflag[goes->unit]) { + /* + * Send a command to the clock. C for on-second timecodes. + * E for extended resolution satelite postion information. + */ + if (write(goes->io.fd, cmd, 1) != 1) { + syslog(LOG_ERR, "goes_send: unit %d: %m", goes->unit); + goes_report_event(goes, CEVNT_FAULT); + } else { + goes->polls++; + } + } +} + +/* + * goes_process - process a pile of samples from the clock + */ +static char +goes_process(goes, offset, dispersion) + struct goesunit *goes; + l_fp *offset; + u_fp *dispersion; +{ + register int i, j; + register U_LONG tmp_ui, tmp_uf; + int not_median1 = -1; /* XXX correct? */ + int not_median2 = -1; /* XXX correct? */ + int median; + u_fp disp_tmp, disp_tmp2; + + /* + * This code implements a three-stage median filter. First, we + * check if the samples are within 125 ms of each other. If not, + * dump the sample set. We take the median of the three offsets + * and use that as the sample offset. We take the maximum + * difference and use that as the sample dispersion. There + * probably is not much to be gained by a longer filter, since + * the clock filter in ntp_proto should do its thing. + */ + disp_tmp2 = 0; + for (i = 0; i < NCODES-1; i++) { + for (j = i+1; j < NCODES; j++) { + tmp_ui = goes->offset[i].l_ui; + tmp_uf = goes->offset[i].l_uf; + M_SUB(tmp_ui, tmp_uf, goes->offset[j].l_ui, + goes->offset[j].l_uf); + if (M_ISNEG(tmp_ui, tmp_uf)) { + M_NEG(tmp_ui, tmp_uf); + } + if (tmp_ui != 0 || tmp_uf > CODEDIFF) { + return 0; + } + disp_tmp = MFPTOFP(0, tmp_uf); + if (disp_tmp > disp_tmp2) { + disp_tmp2 = disp_tmp; + not_median1 = i; + not_median2 = j; + } + } + } + + /* + * It seems as if all are within 125 ms of each other. + * Now to determine the median of the three. Whlie the + * 125 ms check was going on, we also subtly catch the + * dispersion and set-up for a very easy median calculation. + * The largest difference between any two samples constitutes + * the dispersion. The sample not involve in the dispersion is + * the median sample. EASY! + */ + if (goes->lasttime == 0 || disp_tmp2 > GOESMAXDISPERSE) + disp_tmp2 = GOESMAXDISPERSE; + if (not_median1 == 0) { + if (not_median2 == 1) + median = 2; + else + median = 1; + } else { + median = 0; + } + *offset = goes->offset[median]; + *dispersion = disp_tmp2; + return 1; +} + +/* + * goes_poll - called by the transmit procedure + */ +static void +goes_poll(unit, peer) + int unit; + struct peer *peer; +{ + struct goesunit *goes; + + /* + * 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 (unit >= MAXUNITS) { + syslog(LOG_ERR, "goes_poll: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "goes_poll: unit %d not in use", unit); + return; + } + goes = goesunits[unit]; + if ((current_time - goes->lasttime) > 150) { + goes->noreply++; + goes_report_event(goesunits[unit], CEVNT_TIMEOUT); + } + + /* + * polled every 64 seconds. Ask GOES_RECEIVE to hand in a timestamp. + */ + goes->polled = 1; + goes->polls++; + + goes_send(goes,"C"); +} + +/* + * goes_control - set fudge factors, return statistics + */ +static void +goes_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct goesunit *goes; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "goes_control: unit %d invalid", unit); + return; + } + goes = goesunits[unit]; + + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + fudgefactor1[unit] = in->fudgetime1; + if (in->haveflags & CLK_HAVETIME2) + fudgefactor2[unit] = in->fudgetime2; + 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 + */ + peer = goes->peer; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(GOESREFID, (char *)&peer->refid, + 4); + else + peer->refid = htonl(GOESHSREFID); + } + } + if (in->haveflags & CLK_HAVEFLAG1) { + readonlyclockflag[unit] = in->flags & CLK_FLAG1; + } + } + + if (out != 0) { + out->type = REFCLK_GOES_TRUETIME; + out->haveflags + = CLK_HAVETIME1|CLK_HAVETIME2| + CLK_HAVEVAL1|CLK_HAVEVAL2| + CLK_HAVEFLAG1|CLK_HAVEFLAG2; + out->clockdesc = GOESDESCRIPTION; + out->fudgetime1 = fudgefactor1[unit]; + out->fudgetime2 = fudgefactor2[unit]; + out->fudgeval1 = (LONG)stratumtouse[unit]; + out->fudgeval2 = 0; + out->flags = readonlyclockflag[unit] | + (goes->satellite << 1); + if (unitinuse[unit]) { + out->lencode = goes->lencode; + out->lastcode = goes->lastcode; + out->timereset = current_time - goes->timestarted; + out->polls = goes->polls; + out->noresponse = goes->noreply; + out->badformat = goes->badformat; + out->baddata = goes->baddata; + out->lastevent = goes->lastevent; + out->currentstatus = goes->status; + } else { + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} + +/* + * goes_buginfo - return clock dependent debugging info + */ +static void +goes_buginfo(unit, bug) + int unit; + register struct refclockbug *bug; +{ + register struct goesunit *goes; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "goes_buginfo: unit %d invalid", unit); + return; + } + + if (!unitinuse[unit]) + return; + goes = goesunits[unit]; + + bug->nvalues = 11; + bug->ntimes = 5; + if (goes->lasttime != 0) + bug->values[0] = current_time - goes->lasttime; + else + bug->values[0] = 0; + bug->values[1] = (U_LONG)goes->reason; + bug->values[2] = (U_LONG)goes->year; + bug->values[3] = (U_LONG)goes->day; + bug->values[4] = (U_LONG)goes->hour; + bug->values[5] = (U_LONG)goes->minute; + bug->values[6] = (U_LONG)goes->second; + bug->values[7] = (U_LONG)goes->msec; + bug->values[8] = goes->noreply; + bug->values[9] = goes->yearstart; + bug->values[10] = goes->quality; + bug->stimes = 0x1c; + bug->times[0] = goes->lastref; + bug->times[1] = goes->lastrec; + bug->times[2] = goes->offset[0]; + bug->times[3] = goes->offset[1]; + bug->times[4] = goes->offset[2]; +} +#endif diff --git a/contrib/xntpd/xntpd/refclock_irig.c b/contrib/xntpd/xntpd/refclock_irig.c new file mode 100644 index 0000000000..fb9424116e --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_irig.c @@ -0,0 +1,566 @@ +/* + * refclock_irig - clock driver for the IRIG audio decoder + */ + +#if defined(REFCLOCK) && defined(IRIG) +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include +#include "ntp_stdlib.h" + +/* + * This driver supports the IRIG audio decoder. This clever gadget uses + * a modified BSD audio driver for the Sun SPARCstation which provides + * a timestamp, raw binary timecode, status byte and decoded ASCII + # timecode. The data are represented in the structure: + * + * struct irig_time { + * struct timeval stamp; timestamp + * u_char bits[13]; 100 irig data bits + * u_char status; status byte + * char time[14]; time string (null terminated) + * + * where stamp represents a timestamp at the zero crossing of the index + * marker at the second's epoch, bits is a 13-octet, zero-padded binary- + * coded string representing code elements 1 through 100 in the IRIG-B + * code format and status is a status bute, The decoded timestamp is a + * 13-octet, null-terminated ASCII string "ddd hh:mm:ss*", where ddd is + * the day of year, hh:mm:ss the time of day and * is a status indicator, + * with " " indicating valid time and "?" indicating invalid time. The + * timestamp is in unix timeval format, consisting of two 32-bit + * longwords, the first of which is the seconds since 1970 and the second + * is the fraction of the second in microseconds. The status byte is zero + * if (a) the input signal is within amplitude tolerances, (b) the raw + * binary timecode contains only valid code elements, (c) 11 position + * identifiers have been found at the expected element positions, (d) the + * clock status byte contained in the timecode is valid, and (e) a time + * determination has been made since the last read() system call. + * + * The 100 elements of the IRIG-B timecode are numbered from 0 through + * 99. Position identifiers occur at elements 0, 9, 19 and every ten + * thereafter to 99. The control function elements begin at element 50, + * which is control-field element 1, and extend to element 78, which is + * control-field element 27. The control functions have different + * interpretations in various devices. The straight-binary-seconds(SBS) + * field begins at element 80 and is 17 bits long. + * + * Spectracom Netclock/2 WWVB Synchronized Clock + * 6 time sync status + * 10-13 bcd year units + * 15-18 bcd year tens + * + * Austron 2201A GPS Receiver (speculative) + */ + +/* + * Definitions + */ +#define MAXUNITS 1 /* max number of irig units */ +#define IRIGFD "/dev/irig" /* name of driver device */ + +/* + * IRIG interface parameters. + */ +#define IRIGPRECISION (-20) /* precision assumed (1 us) */ +#define IRIGREFID "IRIG" /* reference id */ +#define IRIGDESCRIPTION "IRIG audio decoder" /* who we are */ +#define IRIGHSREFID 0x7f7f0c0a /* 127.127.6.10 refid hi strata */ +#define GMT 0 /* hour offset from Greenwich */ +#define IRIG_FORMAT 1 /* IRIG timestamp format */ +#define BMAX 40 /* length of decoded timecode */ + +/* + * Hack to avoid excercising the multiplier. I have no pride. + */ +#define MULBY10(x) (((x)<<3) + ((x)<<1)) + +/* + * Imported from ntp_timer module + */ +extern U_LONG current_time; /* current time (s) */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * irig unit control structure. + */ +struct irigunit { + struct peer *peer; /* associated peer structure */ + struct refclockio io; /* given to the I/O handler */ + l_fp lastrec; /* last local time */ + l_fp lastref; /* last timecode time */ + char lastcode[BMAX]; /* decoded timecode */ + char bincode[BMAX]; /* raw irig message */ + int lencode; /* lengthof last timecode */ + U_LONG lasttime; /* last time clock heard from */ + u_char unit; /* unit number for this guy */ + u_char status; /* clock status */ + u_char lastevent; /* last clock event */ + u_char year; /* year of eternity */ + u_short day; /* day of year */ + u_char hour; /* hour of day */ + u_char minute; /* minute of hour */ + u_char second; /* seconds of minute */ + U_LONG yearstart; /* start of current year */ + u_char 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 irigunit *irigunits[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 irig_init P(()); +static int irig_start P((u_int, struct peer *)); +static void irig_shutdown P((int)); +static void irig_report_event P((struct irigunit *, int)); +static void irig_poll P((int, struct peer *)); +static void irig_control P((u_int, struct refclockstat *, struct refclockstat *)); +static void irig_buginfo P((int, struct refclockbug *)); + +/* + * Transfer vector + */ +struct refclock refclock_irig = { + irig_start, irig_shutdown, irig_poll, + irig_control, irig_init, irig_buginfo, NOFLAGS +}; + +/* + * irig_init - initialize internal irig driver data + */ +static void +irig_init() +{ + register int i; + + /* + * Just zero the data arrays + */ + bzero((char *) irigunits, sizeof irigunits); + 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; + } +} + + +/* + * irig_start - open the irig device and initialize data for processing + */ +static int +irig_start(unit, peer) + u_int unit; +struct peer *peer; +{ + register struct irigunit *irig; + register int i; + int fd_irig; + int format = IRIG_FORMAT; + + /* + * Check configuration info. + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "irig_start: unit %d invalid", unit); + return (0); + } + if (unitinuse[unit]) { + syslog(LOG_ERR, "irig_start: unit %d in use", unit); + return (0); + } + /* + * Open IRIG device and set format + */ + fd_irig = open(IRIGFD, O_RDONLY | O_NDELAY, 0777); + if (fd_irig == -1) { + syslog(LOG_ERR, "irig_start: open of %s: %m", IRIGFD); + return (0); + } + if (ioctl(fd_irig, AUDIO_IRIG_OPEN, 0) < 0) { + syslog(LOG_ERR, + "irig_start: ioctl(%s, AUDIO_IRIG_OPEN): %m", IRIGFD); + close(fd_irig); + return (0); + } + if (ioctl(fd_irig, AUDIO_IRIG_SETFORMAT, (char *) &format) < 0) { + syslog(LOG_ERR, + "irig_start: ioctl(%s, AUDIO_IRIG_SETFORMAT): %m", IRIGFD); + close(fd_irig); + return (0); + } + + /* + * Allocate unit structure + */ + if (irigunits[unit] != 0) { + irig = irigunits[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && irigunits[i] != 0) + break; + } + if (i < MAXUNITS) { + /* + * Reclaim this one + */ + irig = irigunits[i]; + irigunits[i] = 0; + } else { + irig = (struct irigunit *) + emalloc(sizeof(struct irigunit)); + } + } + bzero((char *) irig, sizeof(struct irigunit)); + + irigunits[unit] = irig; + + /* + * Set up the structures + */ + irig->peer = peer; + irig->unit = (u_char) unit; + irig->timestarted = current_time; + + irig->io.clock_recv = noentry; + irig->io.srcclock = (caddr_t) irig; + irig->io.datalen = 0; + irig->io.fd = fd_irig; + + /* + * 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 = IRIGPRECISION; + peer->rootdelay = 0; + peer->rootdispersion = 0; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(IRIGREFID, (char *) &peer->refid, 4); + else + peer->refid = htonl(IRIGHSREFID); + unitinuse[unit] = 1; + return (1); +} + +/* + * irig_shutdown - shut down a irig clock + */ +static void +irig_shutdown(unit) + int unit; +{ + register struct irigunit *irig; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "irig_shutdown: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "irig_shutdown: unit %d not in use", unit); + return; + } + /* + * Tell the I/O module to turn us off. We're history. + */ + irig = irigunits[unit]; + io_closeclock(&irig->io); + unitinuse[unit] = 0; +} + + +/* + * irig_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 +irig_report_event(irig, code) + struct irigunit *irig; +int code; +{ + struct peer *peer; + + peer = irig->peer; + if (irig->status != (u_char) code) { + irig->status = (u_char) code; + if (code != CEVNT_NOMINAL) + irig->lastevent = (u_char) code; + syslog(LOG_INFO, + "clock %s event %x", ntoa(&peer->srcadr), code); + } +} + +/* + * irig_poll - called by the transmit procedure + */ +static void +irig_poll(unit, peer) + int unit; +struct peer *peer; +{ + + struct irigunit *irig; + struct irig_time buf; + register u_char *dpt; + register char *cp, *dp; + l_fp tstmp; + int i; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "irig_poll: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "irig_poll: unit %d not in use", unit); + return; + } + irig = irigunits[unit]; + irig->polls++; + + if (read(irig->io.fd, (char *) &buf, sizeof(buf)) != sizeof(buf)) { + syslog(LOG_ERR, "irig_poll: unit %d: %m", irig->unit); + irig_report_event(irig, CEVNT_FAULT); + return; + } + +#ifdef DEBUG + if (debug) { + dpt = (u_char *) & buf; + printf("irig: "); + for (i = 0; i < sizeof(buf); i++) + printf("%02x", *dpt++); + printf("\n"); + } +#endif + + buf.stamp.tv_sec += (U_LONG) JAN_1970; + TVTOTS(&buf.stamp, &irig->lastrec); + dpt = buf.bits; + dp = irig->bincode; + for (i = 0; i < sizeof(buf.bits); i++) { + *dp++ = *dpt++; + } + cp = buf.time; + dp = irig->lastcode; + for (i = 0; i < sizeof(buf.time); i++) + *dp++ = *cp++; + dp--; + *dp = '\0'; + cp = irig->lastcode; + irig->lencode = dp - cp; + +#ifdef DEBUG + if (debug) + printf("irig: timecode %d %s %s\n", + irig->lencode, ulfptoa(&irig->lastrec, 6), irig->lastcode); +#endif + + irig->lasttime = current_time; + + /* + * Get irig time and convert to timestamp format. + */ + if (irig->lencode < 13 || !isdigit(cp[0]) || !isdigit(cp[1]) || + !isdigit(cp[2]) || + cp[3] != ' ' || !isdigit(cp[4]) || !isdigit(cp[5]) || + cp[6] != ':' || !isdigit(cp[7]) || !isdigit(cp[8]) || + cp[9] != ':' || !isdigit(cp[10]) || !isdigit(cp[11])) { + irig->badformat++; + irig_report_event(irig, CEVNT_BADREPLY); + return; + } + record_clock_stats(&(irig->peer->srcadr), irig->lastcode); + irig->day = cp[0] - '0'; + irig->day = MULBY10(irig->day) + cp[1] - '0'; + irig->day = MULBY10(irig->day) + cp[2] - '0'; + irig->hour = MULBY10(cp[4] - '0') + cp[5] - '0'; + irig->minute = MULBY10(cp[7] - '0') + cp[8] - '0'; + irig->second = MULBY10(cp[10] - '0') + cp[11] - '0'; + if (cp[12] != ' ') + irig->leap = LEAP_NOTINSYNC; + if (irig->day < 1 || irig->day > 366) { + irig->baddata++; + irig_report_event(irig, CEVNT_BADDATE); + return; + } + if (irig->hour > 23 || irig->minute > 59 || irig->second > 59) { + irig->baddata++; + irig_report_event(irig, CEVNT_BADTIME); + 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(irig->day, irig->hour, irig->minute, + irig->second, GMT, irig->lastrec.l_ui, + &irig->yearstart, &irig->lastref.l_ui)) { + irig->baddata++; + irig_report_event(irig, CEVNT_BADTIME); + return; + } + tstmp = irig->lastref; + L_SUB(&tstmp, &irig->lastrec); + irig->coderecv++; + L_ADD(&tstmp, &(fudgefactor[irig->unit])); + refclock_receive(irig->peer, &tstmp, GMT, 0, + &irig->lastrec, &irig->lastrec, irig->leap); +} + +/* + * irig_control - set fudge factors, return statistics + */ +static void +irig_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct irigunit *irig; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "irig_control: unit %d invalid", unit); + return; + } + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + fudgefactor[unit] = in->fudgetime1; + 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 + */ + irig = irigunits[unit]; + peer = irig->peer; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(IRIGREFID, (char *) &peer->refid, + 4); + else + peer->refid = htonl(IRIGHSREFID); + } + } + if (in->haveflags & CLK_HAVEFLAG1) { + sloppyclockflag[unit] = in->flags & CLK_FLAG1; + } + } + if (out != 0) { + out->type = REFCLK_IRIG_AUDIO; + out->haveflags + = CLK_HAVETIME1 | CLK_HAVEVAL1 | CLK_HAVEVAL2 | CLK_HAVEFLAG1; + out->clockdesc = IRIGDESCRIPTION; + out->fudgetime1 = fudgefactor[unit]; + out->fudgetime2.l_ui = 0; + out->fudgetime2.l_uf = 0; + out->fudgeval1 = (LONG) stratumtouse[unit]; + out->fudgeval2 = 0; + out->flags = sloppyclockflag[unit]; + if (unitinuse[unit]) { + irig = irigunits[unit]; + out->lencode = irig->lencode; + out->lastcode = irig->lastcode; + out->timereset = current_time - irig->timestarted; + out->polls = irig->polls; + out->noresponse = irig->noreply; + out->badformat = irig->badformat; + out->baddata = irig->baddata; + out->lastevent = irig->lastevent; + out->currentstatus = irig->status; + } else { + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} + +/* + * irig_buginfo - return clock dependent debugging info + */ +static void +irig_buginfo(unit, bug) + int unit; + register struct refclockbug *bug; +{ + register struct irigunit *irig; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "irig_buginfo: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) + return; + irig = irigunits[unit]; + + bug->nvalues = 8; + bug->ntimes = 2; + if (irig->lasttime != 0) + bug->values[0] = current_time - irig->lasttime; + else + bug->values[0] = 0; + bug->values[2] = (U_LONG) irig->year; + bug->values[3] = (U_LONG) irig->day; + bug->values[4] = (U_LONG) irig->hour; + bug->values[5] = (U_LONG) irig->minute; + bug->values[6] = (U_LONG) irig->second; + bug->values[7] = irig->yearstart; + bug->stimes = 0x1c; + bug->times[0] = irig->lastref; + bug->times[1] = irig->lastrec; +} + +#endif diff --git a/contrib/xntpd/xntpd/refclock_leitch.c b/contrib/xntpd/xntpd/refclock_leitch.c new file mode 100644 index 0000000000..0fa996c7c5 --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_leitch.c @@ -0,0 +1,700 @@ +/* + * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock + */ +#if defined(REFCLOCK) && (defined(LEITCH) || defined(LEITCHCLK) || defined(LEITCHPPS)) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(STREAM) +#include +#include +#if defined(LEITCHCLK) +#include +#endif /* LEITCHCLK */ +#endif /* STREAM */ + +#if defined (LEITCHPPS) +#include +#endif /* LEITCHPPS */ + +#include "ntp_stdlib.h" + +/* + * Driver for Leitch CSD-5300 Master Clock System + * + * COMMANDS: + * DATE: D + * TIME: T + * STATUS: S + * LOOP: L + * + * FORMAT: + * DATE: YYMMDD + * TIME: /HHMMSS /HHMMSS /HHMMSS / + * second bondaried on the stop bit of the + * 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 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 \ + syslog(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 + +extern struct event timerqueue[]; + +/* + * Imported from ntp_loopfilter module + */ +extern int fdpps; /* pps file descriptor */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * LEITCH unit control structure + */ +struct leitchunit { + struct peer *peer; + struct event leitchtimer; + 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((u_int, struct peer *)); +static void leitch_shutdown P((int)); +static void leitch_poll P((int, struct peer *)); +static void leitch_control P((u_int, struct refclockstat *, struct refclockstat *)); +#define leitch_buginfo noentry +static void leitch_receive P((struct recvbuf *)); +static void leitch_process P((struct leitchunit *)); +static void leitch_timeout P((struct peer *)); +static int leitch_get_date P((struct recvbuf *, struct leitchunit *)); +static int leitch_get_time P((struct recvbuf *, struct leitchunit *, int)); +static int dysize P((int)); + +static struct leitchunit leitchunits[MAXUNITS]; +static u_char unitinuse[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() +{ + bzero((char*)leitchunits,sizeof(leitchunits)); + bzero((char*)unitinuse,sizeof(unitinuse)); +} + +/* + * leitch_shutdown - shut down a LEITCH clock + */ +static void +leitch_shutdown(unit) +int unit; +{ +#ifdef DEBUG + if (debug) + fprintf(stderr, "leitch_shutdown()\n"); +#endif +} + +/* + * leitch_poll - called by the transmit procedure + */ +static void +leitch_poll(unit, peer) + 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(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ +#if debug + if (debug) + fprintf(stderr, "leitch_control()\n"); +#endif + if (unit >= MAXUNITS) { + syslog(LOG_ERR, + "leitch_control: unit %d invalid", unit); + return; + } + if (in) { + /* WE DONT SET ANY THING */ + } + if (out) { + out->type = REFCLK_ATOM_LEITCH; + out->flags = 0; + out->haveflags = 0; + out->lencode = 0; + out->lastcode = ""; + out->polls = 0; + out->noresponse = 0; + out->badformat = 0; + out->baddata = 0; + out->timereset = 0; + out->clockdesc = LEITCH_DESCRIPTION; + out->fudgetime1.l_uf = 0; + out->fudgetime1.l_ui = 0; + out->fudgetime2.l_uf = 0; + out->fudgetime2.l_ui = 0; + out->currentstatus = 0; + out->lastevent = 0; + } +} + +/* + * leitch_start - open the LEITCH devices and initialize data for processing + */ +static int +leitch_start(unit, peer) + u_int unit; + struct peer *peer; +{ + struct leitchunit *leitch; + int fd232; + char leitchdev[20]; + + /* + * Check configuration info. + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "leitch_start: unit %d invalid", unit); + return (0); + } + + if (unitinuse[unit]) { + syslog(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) { + syslog(LOG_ERR, + "leitch_start: open of %s: %m", leitchdev); + return (0); + } + + leitch = &leitchunits[unit]; + bzero((char*)leitch,sizeof(*leitch)); + +#if defined(HAVE_SYSV_TTYS) + /* + * System V serial line parameters (termio interface) + * + */ + { struct termio ttyb; + if (ioctl(fd232, TCGETA, &ttyb) < 0) { + syslog(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) { + syslog(LOG_ERR, + "leitch_start: ioctl(%s, TCSETA): %m", leitchdev); + goto screwed; + } + } +#endif /* HAVE_SYSV_TTYS */ +#if defined(STREAM) + /* + * POSIX/STREAMS serial line parameters (termios interface) + * + * The LEITCHCLK option provides timestamping at the driver level. + * It requires the tty_clk streams module. + * + * The LEITCHPPS option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the ppsclock streams module and SunOS 4.1.1 or + * later. + */ + { struct termios ttyb, *ttyp; + + ttyp = &ttyb; + if (tcgetattr(fd232, ttyp) < 0) { + syslog(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) { + syslog(LOG_ERR, + "leitch_start: tcsetattr(%s): %m", leitchdev); + goto screwed; + } + if (tcflush(fd232, TCIOFLUSH) < 0) { + syslog(LOG_ERR, + "leitch_start: tcflush(%s): %m", leitchdev); + goto screwed; + } +#if defined(LEITCHCLK) + if (ioctl(fd232, I_PUSH, "clk") < 0) + syslog(LOG_ERR, + "leitch_start: ioctl(%s, I_PUSH, clk): %m", leitchdev); + if (ioctl(fd232, CLK_SETSTR, "\n") < 0) + syslog(LOG_ERR, + "leitch_start: ioctl(%s, CLK_SETSTR): %m", leitchdev); +#endif /* LEITCHCLK */ +#if defined(LEITCHPPS) + if (ioctl(fd232, I_PUSH, "ppsclock") < 0) + syslog(LOG_ERR, + "leitch_start: ioctl(%s, I_PUSH, ppsclock): %m", leitchdev); + else + fdpps = fd232; +#endif /* LEITCHPPS */ + } +#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) { + syslog(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) { + syslog(LOG_ERR, + "leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev); + goto screwed; + } +#if defined(LEITCHCLK) + if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { + syslog(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. Note that root delay and root dispersion are + * always zero for this clock. + */ + peer->precision = 0; + peer->rootdelay = 0; + peer->rootdispersion = 0; + peer->stratum = 0; + peer->refid = htonl(0x41544f4d); /* ATOM */ + 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(rbufp) + 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, 0, rbufp->recv_time.l_ui, + &leitch->yearstart, &leitch->reftime1.l_ui)) { + leitch->state = STATE_IDLE; + break; + } +#ifdef DEBUG + if (debug) + fprintf(stderr, "%u\n", 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, 0, rbufp->recv_time.l_ui, + &leitch->yearstart, &leitch->reftime2.l_ui)) { + leitch->state = STATE_IDLE; + break; + } +#ifdef DEBUG + if (debug) + fprintf(stderr, "%u\n", 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, 0, rbufp->recv_time.l_ui, + &leitch->yearstart, &leitch->reftime3.l_ui)) { + leitch->state = STATE_IDLE; + break; + } +#ifdef DEBUG + if (debug) + fprintf(stderr, "%u\n", 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: + syslog(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(leitch) + struct leitchunit *leitch; +{ + l_fp off; + s_fp delay; + l_fp codetime; + l_fp tmp_fp; + int isinsync = 1; + u_fp dispersion = 10; + + delay = 20; + + codetime = leitch->codetime3; + + off = leitch->reftime1; + L_SUB(&off,&leitch->codetime1); + +#ifdef DEBUG + if (debug) + fprintf(stderr,"%u %u %u %u %d %d\n", + leitch->codetime1.l_ui, leitch->codetime1.l_uf, + leitch->reftime1.l_ui, leitch->reftime1.l_uf, + off.l_ui, off.l_uf); +#endif + tmp_fp = leitch->reftime2; + L_SUB(&tmp_fp,&leitch->codetime2); + if (L_ISGEQ(&off,&tmp_fp)) + off = tmp_fp; +#ifdef DEBUG + if (debug) + fprintf(stderr,"%u %u %u %u %d %d\n", + leitch->codetime2.l_ui, leitch->codetime2.l_uf, + leitch->reftime2.l_ui, leitch->reftime2.l_uf, + off.l_ui, off.l_uf); +#endif + tmp_fp = leitch->reftime3; + L_SUB(&tmp_fp,&leitch->codetime3); + + if (L_ISGEQ(&off,&tmp_fp)) + off = tmp_fp; + +#ifdef DEBUG + if (debug) + fprintf(stderr,"%u %u %u %u %d %d\n", + leitch->codetime3.l_ui, leitch->codetime3.l_uf, + leitch->reftime3.l_ui, leitch->reftime3.l_uf, + off.l_ui, off.l_uf); +#endif + refclock_receive(leitch->peer, &off, 0, dispersion, &codetime, + &codetime, isinsync); +} + +/* + * leitch_timeout + */ +static void +leitch_timeout(fp) + struct peer *fp; +{ + +#ifdef DEBUG + if (debug) + fprintf(stderr, "leitch_timeout()\n"); +#endif + +#ifdef NOTYET + { struct leitchunit *leitch = (struct leitchunit *)fp; + + switch(leitch->state) { + case STATE_IDLE: + leitch_send(leitch,"D\r"); + leitch->state = STATE_DATE; + break; + case STATE_DATE: + leitch_send(leitch,"T\r"); + leitch->state = STATE_TIME1; + break; + case STATE_TIME1: + case STATE_TIME2: + case STATE_TIME3: + default: + break; + } + + leitch->leitchtimer.event_time += 30; + TIMER_ENQUEUE(timerqueue, &leitch->leitchtimer); + } +#endif /* NOTYET */ +} + +/* + * dysize + */ +static int +dysize(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(rbufp,leitch) + struct recvbuf *rbufp; + struct leitchunit *leitch; +{ + int i; + + if (rbufp->recv_length < 6) + return(0); +#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 ((dysize((leitch->year>90?1900:2000)+leitch->year)==365) && + leitch->month > 2) + leitch->yearday--; + + return(1); +} + +/* + * leitch_get_time + */ +static int +leitch_get_time(rbufp,leitch,which) + 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); +} + +#endif diff --git a/contrib/xntpd/xntpd/refclock_local.c b/contrib/xntpd/xntpd/refclock_local.c new file mode 100644 index 0000000000..0925a7df5b --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_local.c @@ -0,0 +1,307 @@ +/* + * refclock_local - local pseudo-clock driver + */ +#if defined(REFCLOCK) && defined(LOCAL_CLOCK) +#include +#include +#include + +#include "ntpd.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +static void local_init P((void)); +static int local_start P((u_int, struct peer *)); +static void local_shutdown P((int)); +static void local_poll P((int, struct peer *)); +static void local_control P((u_int, struct refclockstat *, struct refclockstat *)); +#define local_buginfo noentry + +struct refclock refclock_local = { + local_start, local_shutdown, local_poll, + local_control, local_init, local_buginfo, NOFLAGS +}; + +/* + * This is a hack to allow a machine to use its own system clock as + * a "reference clock", i.e. to free run against its own clock at + * a non-infinity stratum. This is certainly useful if you want to + * use NTP in an isolated environment with no radio clock (not that + * this is a good idea) to synchronize the machines together. Pick + * a machine that you figure has a good clock and configure it with + * a local reference clock running at stratum 0 (i.e. 127.127.1.0). + * Then point all the other machines at the one you're using as the + * reference. + * + * The other thing this is good for is if you want to use a particular + * server's clock as the last resort, when all radio time has gone + * away. This is especially good if that server has an ovenized + * oscillator or something which will keep the time stable for extended + * periods, since then all the other machines can benefit from this. + * For this you would configure a local clock at a higher stratum (say + * 3 or 4) to prevent the server's stratum from falling below here. + */ + +/* + * Definitions + */ +#define NUMUNITS 16 /* 127.127.1.[0-15] */ + +/* + * Some constant values we stick in the peer structure + */ +#define LCLDISPERSION (FP_SECOND/5) /* 200 ms dispersion */ +#define LCLROOTDISPERSION (FP_SECOND/5) /* 200 ms root dispersion */ +#define LCLPRECISION (-5) /* what the heck */ +#define LCLREFID "LCL\0" +#define LCLREFOFFSET 20 /* reftime is 20s behind */ +#define LCLHSREFID 0x7f7f0101 /* 127.127.1.1 refid for hi stratum */ + +/* + * Description of clock + */ +#define LCLDESCRIPTION "Free running against local system clock" + +/* + * Local clock unit control structure. + */ +struct lclunit { + struct peer *peer; /* associated peer structure */ + u_char status; /* clock status */ + u_char lastevent; /* last clock event */ + u_char unit; /* unit number */ + u_char unused; + U_LONG lastupdate; /* last time data received */ + U_LONG polls; /* number of polls */ + 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 lclunit *lclunits[NUMUNITS]; +static u_char unitinuse[NUMUNITS]; + +/* + * Imported from the timer module + */ +extern U_LONG current_time; + +extern l_fp sys_clock_offset; + +/* + * local_init - initialize internal local clock driver data + */ +static void +local_init() +{ + /* + * Just zero the data arrays + */ + bzero((char *)lclunits, sizeof lclunits); + bzero((char *)unitinuse, sizeof unitinuse); +} + + +/* + * local_start - start up a local reference clock + */ +static int +local_start(unit, peer) + u_int unit; + struct peer *peer; +{ + register int i; + register struct lclunit *lcl; + + if (unit >= NUMUNITS) { + syslog(LOG_ERR, "local clock: unit number %d invalid (max 15)", + unit); + return 0; + } + if (unitinuse[unit]) { + syslog(LOG_ERR, "local clock: unit number %d in use", unit); + return 0; + } + + /* + * 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 (lclunits[unit] != 0) { + lcl = lclunits[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < NUMUNITS; i++) { + if (!unitinuse[i] && lclunits[i] != 0) + break; + } + if (i < NUMUNITS) { + /* + * Reclaim this one + */ + lcl = lclunits[i]; + lclunits[i] = 0; + } else { + lcl = (struct lclunit *)emalloc(sizeof(struct lclunit)); + } + } + bzero((char *)lcl, sizeof(struct lclunit)); + lclunits[unit] = lcl; + + /* + * Set up the structure + */ + lcl->peer = peer; + lcl->unit = (u_char)unit; + lcl->timestarted = lcl->lastupdate = current_time; + + /* + * That was easy. Diddle the peer variables and return success. + */ + peer->precision = LCLPRECISION; + peer->rootdelay = 0; + peer->rootdispersion = LCLROOTDISPERSION; + peer->stratum = (u_char)unit; + if (unit <= 1) + bcopy(LCLREFID, (char *)&peer->refid, 4); + else + peer->refid = htonl(LCLHSREFID); + unitinuse[unit] = 1; + return 1; +} + + +/* + * local_shutdown - shut down a local clock + */ +static void +local_shutdown(unit) + int unit; +{ + if (unit >= NUMUNITS) { + syslog(LOG_ERR, + "local clock: INTERNAL ERROR, unit number %d invalid (max 15)", + unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, + "local clock: INTERNAL ERROR, unit number %d not in use", unit); + return; + } + + unitinuse[unit] = 0; +} + + +/* + * local_poll - called by the transmit procedure + */ +static void +local_poll(unit, peer) + int unit; + struct peer *peer; +{ + l_fp off; + l_fp ts; + + if (unit >= NUMUNITS) { + syslog(LOG_ERR, "local clock poll: INTERNAL: unit %d invalid", + unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "local clock poll: INTERNAL: unit %d unused", + unit); + return; + } + if (peer != lclunits[unit]->peer) { + syslog(LOG_ERR, + "local clock poll: INTERNAL: peer incorrect for unit %d", + unit); + return; + } + + /* + * Update clock stat counters + */ + lclunits[unit]->polls++; + lclunits[unit]->lastupdate = current_time; + + /* + * This is pretty easy. Give the reference clock support + * a zero offset and our fixed dispersion. Use peer->xmt for + * our receive time. Use peer->xmt - 20 seconds for our + * reference time. + */ + off.l_ui = off.l_uf = 0; + ts = peer->xmt; + ts.l_ui -= LCLREFOFFSET; + refclock_receive(peer, &off, 0, LCLDISPERSION, + &ts, &peer->xmt, 0); +} + + + +/* + * local_control - set fudge factors, return statistics + */ +static void +local_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + extern s_fp drift_comp; + + if (unit >= NUMUNITS) { + syslog(LOG_ERR, "local clock: unit %d invalid (max %d)", + unit, NUMUNITS-1); + return; + } + + /* + * The time1 fudge factor is the drift compensation register. + * The time2 fudge factor is the offset of the system clock from + * what the protocol has set it to be. Most useful when SLEWALWAYS + * is defined. + */ + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + drift_comp = LFPTOFP(&in->fudgetime1); + if (in->haveflags & CLK_HAVETIME2) { + sys_clock_offset.l_ui = in->fudgetime2.l_ui; + sys_clock_offset.l_uf = in->fudgetime2.l_uf; + } + } + if (out != 0) { + out->type = REFCLK_LOCALCLOCK; + out->flags = 0; + out->haveflags = CLK_HAVETIME1; + out->clockdesc = LCLDESCRIPTION; + FPTOLFP(drift_comp, &out->fudgetime1); + out->fudgetime2.l_ui = sys_clock_offset.l_ui; + out->fudgetime2.l_uf = sys_clock_offset.l_uf; + out->fudgeval1 = out->fudgeval2 = 0; + out->lencode = 0; + out->lastcode = ""; + out->badformat = 0; + out->baddata = 0; + out->noresponse = 0; + if (unitinuse[unit]) { + out->polls = lclunits[unit]->polls; + out->timereset = + current_time - lclunits[unit]->timestarted; + out->lastevent = lclunits[unit]->lastevent; + out->currentstatus = lclunits[unit]->status; + } else { + out->polls = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} +#endif /* REFCLOCK */ diff --git a/contrib/xntpd/xntpd/refclock_msfees.c b/contrib/xntpd/xntpd/refclock_msfees.c new file mode 100644 index 0000000000..699ff0d202 --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_msfees.c @@ -0,0 +1,1570 @@ +/* refclock_ees - clock driver for the EES M201 receiver */ + +#if defined(REFCLOCK) && defined(MSFEESPPS) && defined(STREAM) + +/* 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 +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ +#include +#include +#include +#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 loose 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 "ppsclockd\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 }; */ + +/* Imported from the timer module */ +extern u_long current_time; + +#ifdef DEBUG +static int debug; +#endif + +#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) +static int ees_get_precision() +{ + struct timeval tp; + struct timezone tzp; + long last; + int i; + long diff; + long val; + gettimeofday(&tp, &tzp); + + last = tp.tv_usec; + for (i=0; i< 100000; i++) { + gettimeofday(&tp, &tzp); + diff = tp.tv_usec - last; + if (diff < 0) diff += USECS; + if (diff > MINSTEP) break; + last = tp.tv_usec; + } + syslog(LOG_INFO, + "I: ees: precision calculation given %duS after %d loop%s", + diff, i, (i==1) ? "" : "s"); + + if (i == 0) return -20 /* assume 1uS */; + if (i >= MAXLOOPS) return EESPRECISION /* Lies ! */; + for (i=0, val=USECS; val > 0; i--, val /= 2) if (diff > val) return i; + return EESPRECISION /* Lies ! */; +} + +static void dump_buf(coffs, from, to, text) +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 DUMP_BUF_SIZE) syslog(LOG_DEBUG, "D: %s", ptr=buff); + sprintf(ptr, " %06d", ((int)coffs[i].l_f) / 4295); + } + syslog(LOG_DEBUG, "D: %s", buff); +} + +/* msfees_init - initialize internal ees driver data */ +static void msfees_init() +{ + register int i; + /* Just zero the data arrays */ + bzero((char *)eesunits, sizeof eesunits); + bzero((char *)unitinuse, 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(unit, peer) + u_int unit; + struct peer *peer; +{ + register struct eesunit *ees; + register int i; + int fd232 = -1; + char eesdev[20]; + struct termios ttyb, *ttyp; + static void ees_receive(); + extern int io_addclock(); + extern void io_closeclock(); + extern char *emalloc(); + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)", + unit, MAXUNITS-1); + return 0; + } + if (unitinuse[unit]) { + syslog(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) { + syslog(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) { + syslog(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) { + syslog(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) { + syslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev); + goto screwed; + } + + if (tcflush(fd232, TCIOFLUSH) < 0) { + syslog(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)); + } + bzero((char *)ees, 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. + */ + + { + 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) { + syslog(LOG_ERR, + "ees clock: Push of `%s' and `%s' to %s failed %m", + STREAM_PP1, STREAM_PP2, eesdev); + goto screwed; + } + else { + syslog(LOG_INFO, "I: ees clock: PUSHed %s on %s", + (rc1 >= 0) ? STREAM_PP1 : STREAM_PP2, eesdev); + ees->ttytype |= T_PPS; + } + } + + /* Add the clock */ + if (!io_addclock(&ees->io)) { + /* Oh shit. Just close and return. */ + syslog(LOG_ERR, "ees clock: io_addclock(%s): %m", + eesdev); + goto screwed; + } + + + /* All done. Initialize a few random peer variables, then + * return success. */ + peer->precision = ees_get_precision(); + peer->stratum = stratumtouse[unit]; + peer->rootdelay = 0; /* ++++ */ + peer->rootdispersion = 0; /* ++++ */ + if (stratumtouse[unit] <= 1) + { bcopy(EESREFID, (char *)&peer->refid, 4); + if (unit>0 && unit<10) ((char *)&peer->refid)[3] = '0' + unit; + } + else peer->refid = htonl(EESHSREFID); + unitinuse[unit] = 1; + syslog(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(unit) + int unit; +{ + register struct eesunit *ees; + extern void io_closeclock(); + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, + "ees clock: INTERNAL ERROR, unit number %d invalid (max %d)", + unit, MAXUNITS); + return; + } + if (!unitinuse[unit]) { + syslog(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(ees, code) + 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(rbufp) + 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; + static void ees_process(); + 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; + extern errno; + int rc; + + /* 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) { + syslog(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) syslog(LOG_INFO, + "I: ees clock %d: %d == %d: await more", + ees->unit, dpt, dpend); + return; + } + + /* This shouldn't happen ... ! */ + if ((*dpt & 0x7f) != 0x7f) { + syslog(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: + syslog(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; + + bzero(&ppsclockev, sizeof ppsclockev); + + rc = ioctl(ees->io.fd, CIOGETEV, (char *) &ppsclockev); + if (debug & DB_PRINT_EV) fprintf(stderr, + "[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08x %08x %d\n", + DB_PRINT_EV, ees->unit, ees->io.fd, CIOGETEV, 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) syslog(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 %d (%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 %x.%08x and %x.%08x -> %x.%08x @ %s", + DB_PRINT_CDT, ees->arrvtime.l_ui, ees->arrvtime.l_uf, + pps_arrvstamp.l_ui, pps_arrvstamp.l_uf, + diff.l_ui, 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); +syslog(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, + 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] %08x %08x %d u%d (%d %d)\n", + DB_PRINT_CDTC, pps_arrvstamp.l_ui, + 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 *ptr=text; + int i; + for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) { + sprintf(ptr, " %d.%04d", + msec(deltas[i]), subms(deltas[i])); + while (*ptr) ptr++; + } + syslog(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 delta = (this_step - other_step); + if (delta < 0) delta = - delta; + if (third_step == 0 && ( + (delta == 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++; + } +syslog(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]) +syslog(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=%3d.%04d@%d :%d:%d:$%d:%d:%d\n", +ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs); +syslog(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) syslog(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), + msec(delta_f_abs), + 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 ees_step_notes = EES_STEP_NOTES; + if (ees_step_notes > 0) { + ees_step_notes--; +printf("MSF%d: D=%3d.%04d@%02d :%d%s\n", +ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !"); +syslog(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) syslog(LOG_ERR, + "[%x] MSF%d: %3d/%03d -> d=%11d (%d|%d)", + 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: %3d/%03d -> d=%11d (%d|%d)\n", + ees->unit, sec_of_ramp, ees->last_step_secs, fsecs, + 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) syslog(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); + (void) pps_sample(&pps_arrvstamp); + } + + /* Subtract off the local clock time stamp */ + L_SUB(&ees->codeoffsets[n_sample], &ees->arrvtime); + if (debug & DB_LOG_SAMPLES) syslog(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! */ +} + + +static void set_x(fp_offset) +l_fp *fp_offset; +{ + step_systime_real(fp_offset); +} + + +/* offcompare - auxiliary comparison routine for offset sort */ + +static int +offcompare(a, b) +l_fp *a, *b; +{ + return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1); +} + + +/* ees_process - process a pile of samples from the clock */ +static void ees_process(ees) + struct eesunit *ees; +{ + static last_samples = -1; + register int i, j; + register int noff; + register l_fp *coffs = ees->codeoffsets; + l_fp offset, tmp; + u_fp dispersion; /* ++++ */ + int lostsync, isinsync; + int samples = ees->nsamples; + int samplelog; + int samplereduce = (samples + 1) / 2; + + /* 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)) { + syslog(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, 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)) syslog( + (debug & DB_SYSLOG_SMPLE) ? LOG_ERR : LOG_INFO, + "I: [%x] Offset=%06d (%d), disp=%06d%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 & (1 << 31)) != + (((long) offset.l_uf) & ( 1 << 31))) + { syslog(LOG_INFO, "I: %x != %x (%x %x), so add %d", + new & (1 << 31), + ((long) offset.l_uf) & ( 1 << 31), + 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)) syslog( + (debug & DB_SYSLOG_SMTHE) ? LOG_ERR : LOG_INFO, + "I: [%x] Smooth data: %d -> %d, dispersion now %d", + 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)) syslog( + (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO, + "[%x] No smooth as delta not %d < %d < %d", + debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE), + - FRACT_SEC(100), diff, FRACT_SEC(100)); + } + else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) syslog( + (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) { + syslog(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; + set_x(&offset); + L_CLR(&offset); + } + refclock_receive(ees->peer, + &offset, + 0, /* delay */ + dispersion, + &ees->reftime, + &ees->lastsampletime, /* receive time */ + (isinsync) ? 0 : LEAP_NOTINSYNC); + ees_event(ees, lostsync ? CEVNT_PROP : CEVNT_NOMINAL); +} + +/* msfees_poll - called by the transmit procedure */ +static void msfees_poll(unit, peer) + int unit; + char *peer; +{ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d invalid", + unit); + return; + } + if (!unitinuse[unit]) { + syslog(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); +} + +/* msfees_leap - called when a leap second occurs */ +static void msfees_leap() +{ + register int i; + + /* This routine should be entered a few seconds after + * midnight UTC when a leap second occurs. To ensure we + * don't believe foolish time from the clock(s) we set a + * 40 minute hold on them. It shouldn't take anywhere + * near this amount of time to adjust if the clock is getTING + * data, but doing anything else is complicated. + */ + for (i = 0; i < MAXUNITS; i++) if (unitinuse[i]) + eesunits[i]->leaphold = current_time + EESLEAPHOLD; +} + +/* msfees_control - set fudge factors, return statistics */ +static void msfees_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct eesunit *ees = eesunits[unit]; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "ees clock: unit %d invalid (max %d)", + unit, MAXUNITS-1); + return; + } + + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + fudgefactor[unit] = in->fudgetime1; + if (in->haveflags & CLK_HAVETIME2) + os_delay[unit] = in->fudgetime2; + offset_fudge[unit] = os_delay[unit]; + L_ADD(&offset_fudge[unit], &fudgefactor[unit]); + L_ADD(&offset_fudge[unit], &inherent_delay[unit]); + if (in->haveflags & CLK_HAVEVAL1) { + stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf); + if (unitinuse[unit]) { + /* Should actually reselect clock, but + * will wait for the next timecode + */ + struct peer *peer = ees->peer; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) { + bcopy(EESREFID, (char *)&peer->refid, + 4); + if (unit>0 && unit<10) + ((char *)&peer->refid)[3] = + '0' + unit; + } + else peer->refid = htonl(EESHSREFID); + } + } + if (in->haveflags & CLK_HAVEVAL2) { + printf("Debug: %x -> %x\n", debug, in->fudgeval2); + syslog(LOG_ERR, "MSF%d: debug %x -> %x", + unit, debug, in->fudgeval2); + debug = in->fudgeval2; + } + if (in->haveflags & CLK_HAVEFLAG1) { + sloppyclockflag[unit] = in->flags & CLK_FLAG1; + } + if (in->haveflags & CLK_HAVEFLAG2) { + ees->fix_pending++; + /* if (in->flags & CLK_FLAG2 && unitinuse[unit]) + ees->leaphold = 0; */ + } + if (in->haveflags & CLK_HAVEFLAG3 && unitinuse[unit]) { + printf("dump_vals: %x -> %x\n", ees->dump_vals, in->flags & CLK_FLAG3); + ees->dump_vals = in->flags & CLK_FLAG3; + } + if (in->haveflags & CLK_HAVEFLAG4 && unitinuse[unit]) { + ees->usealldata = in->flags & CLK_FLAG4; + } + } + + if (out != 0) { + out->type = REFCLK_MSF_EES; + out->haveflags + = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1|CLK_HAVEFLAG3|CLK_HAVEFLAG4; + out->clockdesc = EESDESCRIPTION; + out->fudgetime1 = fudgefactor[unit]; + out->fudgetime2 = os_delay[unit]; + out->fudgeval1 = (long)stratumtouse[unit]; + out->fudgeval2 = debug; + out->flags = sloppyclockflag[unit]; + if (unitinuse[unit]) { + out->flags |= ees->dump_vals | ees->usealldata; + out->lencode = ees->lencode; + out->lastcode = ees->lastcode; + out->timereset = current_time - ees->timestarted; + out->polls = 0; /* we don't poll */ + out->noresponse = 0; /* ditto */ + out->badformat = ees->badformat; + out->baddata = ees->baddata; + out->lastevent = ees->lastevent; + out->currentstatus = ees->status; + } else { + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} + + +/* msfees_buginfo - return clock dependent debugging info */ +static void msfees_buginfo(unit, bug) + int unit; + register struct refclockbug *bug; +{ + register struct eesunit *ees; + + bug->nvalues = bug->ntimes = 0; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "ees clock: unit %d invalid (max %d)", + unit, MAXUNITS-1); + return; + } + + if (!unitinuse[unit]) + return; + ees = eesunits[unit]; + + bug->nvalues = 16; + bug->svalues = 0x0800; + 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->ntimes = 11; + bug->stimes = 0x3f8; + 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].l_ui = ees->yearstart; + bug->times[10].l_uf = 0; +} + +struct refclock refclock_msfees = { + msfees_start, msfees_shutdown, msfees_poll, + msfees_control, msfees_init, msfees_buginfo, NOFLAGS +}; +#endif /* defined(REFCLOCK) && defined(MSFEESPPS) && defined(STREAM) */ diff --git a/contrib/xntpd/xntpd/refclock_mx4200.c b/contrib/xntpd/xntpd/refclock_mx4200.c new file mode 100644 index 0000000000..3d98d10685 --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_mx4200.c @@ -0,0 +1,1357 @@ +/* + * 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. + */ + +#if defined(REFCLOCK) && (defined(MX4200) || defined(MX4200CLK) || defined(MX4200PPS)) + +#if !defined(lint) && !defined(__GNUC__) +static char rcsid[] = + "@(#) /src/master/xntp-930612/xntpd/refclock_mx4200.c,v 1.5 1993/06/18 21:19:54 jbj Exp (LBL) "; +#endif + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_calendar.h" +#include "ntp_unixtime.h" + +#if __STDC__ +#include +#else +#include +#endif + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(STREAM) +#include +#include +#if defined(MX4200CLK) +#include +#endif /* MX4200CLK */ +#endif /* STREAM */ + +#include + +#include "mx4200.h" +#include "ntp_stdlib.h" + +/* + * This driver supports the Magnavox Model MX4200 GPS Receiver. + */ + +/* + * Definitions + */ +#define MAXUNITS 2 /* max number of mx4200 units */ +#define MX4200232 "/dev/gps%d" +#define SPEED232 B4800 /* baud */ + +/* + * The number of raw samples which we acquire to derive a single estimate. + */ +#define NSTAMPS 64 + +/* + * Radio interface parameters + */ +#define MX4200PRECISION (-18) /* precision assumed (about 4 us) */ +#define MX4200REFID "GPS" /* reference id */ +#define MX4200DESCRIPTION "Magnavox MX4200 GPS Receiver" /* who we are */ +#define MX4200HSREFID 0x7f7f0a0a /* 127.127.10.10 refid for hi strata */ +#define DEFFUDGETIME 0 /* default fudge time (ms) */ + +/* Leap stuff */ +extern U_LONG leap_hoursfromleap; +extern U_LONG leap_happened; +static int leap_debug; + +/* + * mx4200_reset - reset the count back to zero + */ +#define mx4200_reset(mx4200) \ + do { \ + (mx4200)->nsamples = 0; \ + } while (0) + +/* + * mx4200_event - record and report an event + */ +#define mx4200_event(mx4200, evcode) \ + do { \ + if ((mx4200)->status != (u_char)(evcode)) \ + mx4200_report_event((mx4200), (evcode)); \ + } while (0) + +/* + * Imported from the timer module + */ +extern U_LONG current_time; +extern struct event timerqueue[]; + +/* + * Imported from ntp_loopfilter module + */ +extern int fdpps; /* pps file descriptor */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * MX4200 unit control structure. + */ +struct mx4200unit { + struct peer *peer; /* associated peer structure */ + struct refclockio io; /* given to the I/O handler */ + U_LONG gpssamples[NSTAMPS]; /* the GPS time samples */ + l_fp unixsamples[NSTAMPS]; /* the UNIX time samples */ + + + l_fp lastsampletime; /* time of last estimate */ + u_int lastserial; /* last pps serial number */ +#ifdef notdef + l_fp lastrec; /* last receive time */ + l_fp lastref; /* last timecode time */ +#endif + char lastcode[RX_BUFF_SIZE]; /* last timecode received */ + U_LONG lasttime; /* last time clock heard from */ + u_char nsamples; /* number of samples we've collected */ + 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 lencode; /* length of last timecode */ + u_char year; /* year of eternity */ + u_short monthday; /* day of month */ + u_char hour; /* hour of day */ + u_char minute; /* minute of hour */ + u_char second; /* seconds of minute */ + u_char leap; /* leap indicators */ + /* + * Status tallies + */ +#ifdef notdef + U_LONG polls; /* polls sent */ + U_LONG noresponse; /* number of nonresponses */ +#endif + U_LONG badformat; /* bad format */ + U_LONG baddata; /* bad data */ + U_LONG timestarted; /* time we started this */ +}; + +/* + * We demand that consecutive PPS samples are more than 0.995 seconds + * and less than 1.005 seconds apart. + */ +#define PPSLODIFF_UI 0 /* 0.900 as an l_fp */ +#define PPSLODIFF_UF 0xe6666610 + +#define PPSHIDIFF_UI 1 /* 1.100 as an l_fp */ +#define PPSHIDIFF_UF 0x19999990 + +/* + * reason codes + */ +#define PPSREASON 20 +#define CODEREASON 40 +#define PROCREASON 60 + +/* + * Data space for the unit structures. Note that we allocate these on + * the fly, but never give them back. + */ +static struct mx4200unit *mx4200units[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]; + +static const char pmvxg[] = "PMVXG"; + +/* + * Function prototypes + */ +static void mx4200_init P((void)); +static int mx4200_start P((u_int, struct peer *)); +static void mx4200_shutdown P((int)); +static void mx4200_receive P((struct recvbuf *)); +static void mx4200_process P((struct mx4200unit *)); +static void mx4200_report_event P((struct mx4200unit *, int)); +static void mx4200_poll P((int, struct peer *)); +static void mx4200_control P((u_int, struct refclockstat *, struct refclockstat *)); +static void mx4200_buginfo P((int, struct refclockbug *)); + +static char * mx4200_parse P((char *, struct calendar *, int *, int *)); +static int mx4200_needconf P((char *)); +static void mx4200_config P((struct mx4200unit *)); +static void mx4200_send P((int, const char *, ...)); +static int mx4200_cmpl_fp P((void *, void *)); +static u_char cksum P((char *, u_int)); + +#ifdef DEBUG +static void opendfile P((int)); +static void checkdfile P((void)); +#endif /* DEBUG */ + +/* + * Transfer vector + */ +struct refclock refclock_mx4200 = { + mx4200_start, mx4200_shutdown, mx4200_poll, + mx4200_control, mx4200_init, mx4200_buginfo, NOFLAGS +}; + +/* + * mx4200_init - initialize internal mx4200 driver data + */ +static void +mx4200_init() +{ + register int i; + /* + * Just zero the data arrays + */ + bzero((char *)mx4200units, sizeof mx4200units); + 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 = DEFFUDGETIME; + stratumtouse[i] = 0; + sloppyclockflag[i] = 0; + } +} + +#ifdef DEBUG +static char dfile[] = "/var/tmp/MX4200.debug"; +static FILE *df = NULL; + +static void +opendfile(create) + int create; +{ + if (!create && access(dfile, F_OK) < 0) { + syslog(LOG_ERR, "mx4200: open %s: %m", dfile); + return; + } + df = fopen(dfile, "a"); + if (df == NULL) + syslog(LOG_ERR, "mx4200: open %s: %m", dfile); + else if (setvbuf(df, NULL, _IOLBF, 0) < 0) + syslog(LOG_ERR, "mx4200: setvbuf %s: %m", dfile); +} + +static void +checkdfile() +{ + + if (df == NULL) + return; + + if (access(dfile, F_OK) < 0) { + fclose(df); + opendfile(1); + } +} + +#endif + + +/* + * mx4200_start - open the MX4200 devices and initialize data for processing + */ +static int +mx4200_start(unit, peer) + u_int unit; + struct peer *peer; +{ + register struct mx4200unit *mx4200; + register int i; + int fd232; + char mx4200dev[20]; + + /* + * Check configuration info + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "mx4200_start: unit %d invalid", unit); + return (0); + } + if (unitinuse[unit]) { + syslog(LOG_ERR, "mx4200_start: unit %d in use", unit); + return (0); + } + + /* + * Open serial port + */ + (void) sprintf(mx4200dev, MX4200232, unit); + fd232 = open(mx4200dev, O_RDWR, 0777); + if (fd232 == -1) { + syslog(LOG_ERR, + "mx4200_start: open of %s: %m", mx4200dev); + return (0); + } + +#if defined(HAVE_SYSV_TTYS) + /* + * System V serial line parameters (termio interface) + * + */ + { struct termio ttyb; + if (ioctl(fd232, TCGETA, &ttyb) < 0) { + syslog(LOG_ERR, + "mx4200_start: ioctl(%s, TCGETA): %m", mx4200dev); + 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) { + syslog(LOG_ERR, + "mx4200_start: ioctl(%s, TCSETA): %m", mx4200dev); + goto screwed; + } + } +#endif /* HAVE_SYSV_TTYS */ +#if defined(STREAM) + /* + * POSIX/STREAMS serial line parameters (termios interface) + * + * The MX4200CLK option provides timestamping at the driver level. + * It requires the tty_clk streams module. + * + * The MX4200PPS option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the ppsclock streams module and SunOS 4.1.1 or + * later. + */ + { struct termios ttyb, *ttyp; + + ttyp = &ttyb; + if (tcgetattr(fd232, ttyp) < 0) { + syslog(LOG_ERR, + "mx4200_start: tcgetattr(%s): %m", mx4200dev); + 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) { + syslog(LOG_ERR, + "mx4200_start: tcsetattr(%s): %m", mx4200dev); + goto screwed; + } + if (tcflush(fd232, TCIOFLUSH) < 0) { + syslog(LOG_ERR, + "mx4200_start: tcflush(%s): %m", mx4200dev); + goto screwed; + } +#if defined(MX4200CLK) + if (ioctl(fd232, I_PUSH, "clk") < 0) + syslog(LOG_ERR, + "mx4200_start: ioctl(%s, I_PUSH, clk): %m", mx4200dev); + if (ioctl(fd232, CLK_SETSTR, "\n") < 0) + syslog(LOG_ERR, + "mx4200_start: ioctl(%s, CLK_SETSTR): %m", mx4200dev); +#endif /* MX4200CLK */ +#if defined(MX4200PPS) + if (ioctl(fd232, I_PUSH, "ppsclock") < 0) + syslog(LOG_ERR, + "mx4200_start: ioctl(%s, I_PUSH, ppsclock): %m", mx4200dev); + else + fdpps = fd232; +#endif /* MX4200PPS */ + } +#endif /* STREAM */ +#if defined(HAVE_BSD_TTYS) + /* + * 4.3bsd serial line parameters (sgttyb interface) + * + * The MX4200CLK option provides timestamping at the driver level. + * It requires the tty_clk line discipline and 4.3bsd or later. + */ + { struct sgttyb ttyb; +#if defined(MX4200CLK) + int ldisc = CLKLDISC; +#endif /* MX4200CLK */ + + if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { + syslog(LOG_ERR, + "mx4200_start: ioctl(%s, TIOCGETP): %m", mx4200dev); + goto screwed; + } + ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; +#if defined(MX4200CLK) + 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 /* MX4200CLK */ + if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { + syslog(LOG_ERR, + "mx4200_start: ioctl(%s, TIOCSETP): %m", mx4200dev); + goto screwed; + } +#if defined(MX4200CLK) + if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { + syslog(LOG_ERR, + "mx4200_start: ioctl(%s, TIOCSETD): %m",mx4200dev); + goto screwed; + } +#endif /* MX4200CLK */ + } +#endif /* HAVE_BSD_TTYS */ + + /* + * Allocate unit structure + */ + if (mx4200units[unit] != 0) { + mx4200 = mx4200units[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && mx4200units[i] != 0) + break; + } + if (i < MAXUNITS) { + /* + * Reclaim this one + */ + mx4200 = mx4200units[i]; + mx4200units[i] = 0; + } else { + mx4200 = (struct mx4200unit *) + emalloc(sizeof(struct mx4200unit)); + } + } + + bzero((char *)mx4200, sizeof(struct mx4200unit)); + mx4200units[unit] = mx4200; + + /* + * Set up the structures + */ + mx4200->peer = peer; + mx4200->unit = (u_char)unit; + mx4200->timestarted = current_time; + + mx4200->io.clock_recv = mx4200_receive; + mx4200->io.srcclock = (caddr_t)mx4200; + mx4200->io.datalen = 0; + mx4200->io.fd = fd232; + if (!io_addclock(&mx4200->io)) + goto screwed; + + /* + * All done. Initialize a few random peer variables, then + * return success. + */ + peer->precision = MX4200PRECISION; + peer->rootdelay = 0; + peer->rootdispersion = 0; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(MX4200REFID, (char *)&peer->refid, 4); + else + peer->refid = htonl(MX4200HSREFID); + unitinuse[unit] = 1; + + /* Insure the receiver is properly configured */ + mx4200_config(mx4200); + +#ifdef DEBUG + opendfile(0); +#endif + return (1); + + /* + * Something broke; abandon ship + */ +screwed: + (void) close(fd232); + return (0); +} + +/* + * mx4200_shutdown - shut down a MX4200 clock + */ +static void +mx4200_shutdown(unit) + int unit; +{ + register struct mx4200unit *mx4200; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "mx4200_shutdown: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "mx4200_shutdown: unit %d not in use", unit); + return; + } + + /* + * Tell the I/O module to turn us off. We're history. + */ + mx4200 = mx4200units[unit]; + io_closeclock(&mx4200->io); + unitinuse[unit] = 0; +} + +static void +mx4200_config(mx4200) + register struct mx4200unit *mx4200; +{ + register int fd = mx4200->io.fd; + +syslog(LOG_DEBUG, "mx4200_config"); + + /* Zero the output list (do it twice to flush possible junk) */ + mx4200_send(fd, "%s,%03d,,%d,,,,,,", pmvxg, PMVXG_S_PORTCONF, 1); + mx4200_send(fd, "%s,%03d,,%d,,,,,,", pmvxg, PMVXG_S_PORTCONF, 1); + + /* Switch to 2d mode */ + mx4200_send(fd, "%s,%03d,%d,,%.1f,%.1f,,%d,%d,%c,%d", + pmvxg, PMVXG_S_INITMODEB, + 2, /* 2d mode */ + 0.1, /* hor accel fact as per Steve */ + 0.1, /* ver accel fact as per Steve */ + 10, /* hdop limit as per Steve */ + 5, /* elevation limit as per Steve */ + 'U', /* time output mode */ + 0); /* local time offset from gmt */ + + /* Configure time recovery */ + mx4200_send(fd, "%s,%03d,%c,%c,%c,%d,%d,%d,", + pmvxg, PMVXG_S_TRECOVCONF, +#ifdef notdef + 'K', /* known position */ + 'D', /* dynamic position */ +#else + 'S', /* static position */ +#endif + 'U', /* steer clock to gps time */ + 'A', /* always output time pulse */ + 500, /* max time error in ns */ + 0, /* user bias in ns */ + 1); /* output to control port */ +} + +/* + * mx4200_report_event - note the occurrence of an event + */ +static void +mx4200_report_event(mx4200, code) + struct mx4200unit *mx4200; + int code; +{ + struct peer *peer; + + peer = mx4200->peer; + if (mx4200->status != (u_char)code) { + mx4200->status = (u_char)code; + if (code != CEVNT_NOMINAL) + mx4200->lastevent = (u_char)code; + syslog(LOG_INFO, + "mx4200 clock %s event %x", ntoa(&peer->srcadr), code); + } +} + +/* + * mx4200_poll - mx4200 watchdog routine + */ +static void +mx4200_poll(unit, peer) + int unit; + struct peer *peer; +{ + register struct mx4200unit *mx4200; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "mx4200_poll: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "mx4200_poll: unit %d not used", unit); + return; + } + + mx4200 = mx4200units[unit]; + if ((current_time - mx4200->lasttime) > 150) { + mx4200_event(mx4200, CEVNT_FAULT); + + /* Request a status message which should trigger a reconfig */ + mx4200_send(mx4200->io.fd, "%s,%03d", "CDGPQ", PMVXG_D_STATUS); + syslog(LOG_DEBUG, "mx4200_poll: request status"); + } +} + +static const char char2hex[] = "0123456789ABCDEF"; + +/* + * mx4200_receive - receive gps data + */ +static void +mx4200_receive(rbufp) + struct recvbuf *rbufp; +{ + register struct mx4200unit *mx4200; + register char *dpt, *cp; + register U_LONG tmp_ui; + register U_LONG tmp_uf; + register U_LONG gpstime; + struct ppsclockev ev; + register struct calendar *jt; + struct calendar sjt; + register int n; + int valid, leapsec; + register u_char ck; + + mx4200 = (struct mx4200unit *)rbufp->recv_srcclock; + +#ifdef DEBUG + if (debug > 3) + printf("mx4200_receive: nsamples = %d\n", mx4200->nsamples); +#endif + + /* Record the time of this event */ + mx4200->lasttime = current_time; + + /* Get the pps value */ + if (ioctl(mx4200->io.fd, CIOGETEV, (char *)&ev) < 0) { + /* XXX Actually, if this fails, we're pretty much screwed */ +#ifdef DEBUG + if (debug) { + fprintf(stderr, "mx4200_receive: "); + perror("CIOGETEV"); + } +#endif + mx4200->reason = PPSREASON + 1; + mx4200_event(mx4200, CEVNT_FAULT); + mx4200_reset(mx4200); + return; + } + tmp_ui = ev.tv.tv_sec + (U_LONG)JAN_1970; + TVUTOTSF(ev.tv.tv_usec, tmp_uf); + + /* Get buffer and length; sock away last timecode */ + n = rbufp->recv_length; + dpt = rbufp->recv_buffer; + if (n <= 1) + return; + mx4200->lencode = n; + bcopy(dpt, mx4200->lastcode, n); + + /* + * We expect to see something like: + * + * $PMVXG,830,T,1992,07,09,04:18:34,U,S,-02154,00019,000000,00*1D\n + * + * Reject if any important landmarks are missing. + */ + cp = dpt + n - 4; + if (cp < dpt || *dpt != '$' || cp[0] != '*' || cp[3] != '\n') { +#ifdef DEBUG + if (debug) + printf("mx4200_receive: bad format\n"); +#endif + mx4200->badformat++; + mx4200->reason = PPSREASON + 2; + mx4200_event(mx4200, CEVNT_BADREPLY); + mx4200_reset(mx4200); + return; + } + + /* Check checksum */ + ck = cksum(&dpt[1], n - 5); + if (char2hex[ck >> 4] != cp[1] || char2hex[ck & 0xf] != cp[2]) { +#ifdef DEBUG + if (debug) + printf("mx4200_receive: bad checksum\n"); +#endif + mx4200->badformat++; + mx4200->reason = PPSREASON + 3; + mx4200_event(mx4200, CEVNT_BADREPLY); + mx4200_reset(mx4200); + return; + } + + /* Truncate checksum (and the buffer for that matter) */ + *cp = '\0'; + + /* Leap second debugging stuff */ + if ((leap_hoursfromleap && !leap_happened) || leap_debug > 0) { + /* generate reports for awhile after leap */ + if (leap_hoursfromleap && !leap_happened) + leap_debug = 3600; + else + --leap_debug; + syslog(LOG_INFO, "mx4200 leap: %s \"%s\"", + umfptoa(tmp_ui, tmp_uf, 6), dpt); + } + + /* Parse time recovery message */ + jt = &sjt; + if ((cp = mx4200_parse(dpt, jt, &valid, &leapsec)) != NULL) { + /* Configure the receiver if necessary */ + if (mx4200_needconf(dpt)) + mx4200_config(mx4200); +#ifdef DEBUG + if (debug) + printf("mx4200_receive: mx4200_parse: %s\n", cp); +#endif + mx4200->badformat++; + mx4200->reason = PPSREASON + 5; + mx4200_event(mx4200, CEVNT_BADREPLY); + mx4200_reset(mx4200); + return; + } + + /* Setup leap second indicator */ + if (leapsec == 0) + mx4200->leap = LEAP_NOWARNING; + else if (leapsec == 1) + mx4200->leap = LEAP_ADDSECOND; + else if (leapsec == -1) + mx4200->leap = LEAP_DELSECOND; + else + mx4200->leap = LEAP_NOTINSYNC; /* shouldn't happen */ + + /* Check parsed time (allow for possible leap seconds) */ + if (jt->second >= 61 || jt->minute >= 60 || jt->hour >= 24) { +#ifdef DEBUG + if (debug) { + printf("mx4200_receive: bad time %d:%02d:%02d", + jt->hour, jt->minute, jt->second); + if (leapsec != 0) + printf(" (leap %+d)", leapsec); + putchar('\n'); + } +#endif + mx4200->baddata++; + mx4200->reason = PPSREASON + 6; + mx4200_event(mx4200, CEVNT_BADTIME); + mx4200_reset(mx4200); + /* Eat the next pulse which the clock claims will be bad */ + mx4200->nsamples = -1; + return; + } + + /* Check parsed date */ + if (jt->monthday > 31 || jt->month > 12 || jt->year < 1900) { +#ifdef DEBUG + if (debug) + printf("mx4200_receive: bad date (%d/%d/%d)\n", + jt->monthday, jt->month, jt->year); +#endif + mx4200->baddata++; + mx4200->reason = PPSREASON + 7; + mx4200_event(mx4200, CEVNT_BADDATE); + mx4200_reset(mx4200); + return; + } + + /* Convert to ntp time */ + gpstime = caltontp(jt); + + /* The gps message describes the *next* pulse; pretend it's this one */ + --gpstime; + + /* Debugging */ +#ifdef DEBUG + checkdfile(); + if (df != NULL) { + l_fp t; + + t.l_ui = gpstime; + t.l_uf = 0; + M_SUB(t.l_ui, t.l_uf, tmp_ui, tmp_uf); + fprintf(df, "%s\t%s", + umfptoa(tmp_ui, tmp_uf, 6), mfptoa(t.l_ui, t.l_uf, 6)); + if (debug > 3) + fprintf(df, "\t(gps: %lu)", gpstime); + if (leapsec != 0) + fprintf(df, "\t(leap sec %+d)", leapsec); + if (!valid) + fprintf(df, "\t(pulse not valid)"); + fputc('\n', df); + } +#endif + + /* Check pps serial number against last one */ + if (mx4200->lastserial + 1 != ev.serial && mx4200->lastserial != 0) { +#ifdef DEBUG + if (debug) { + if (ev.serial == mx4200->lastserial) + printf("mx4200_receive: no new pps event\n"); + else + printf("mx4200_receive: missed %d pps events\n", + ev.serial - mx4200->lastserial - 1); + } +#endif + mx4200->reason = PPSREASON + 8; + mx4200_event(mx4200, CEVNT_FAULT); + mx4200_reset(mx4200); + /* fall through and this one collect as first sample */ + } + mx4200->lastserial = ev.serial; + +/* + * XXX + * Since this message is for the next pulse, it's really the next pulse + * that the clock might be telling us will be invalid. + */ + /* Toss if not designated "valid" by the gps */ + if (!valid) { +#ifdef DEBUG + if (debug) + printf("mx4200_receive: pps not valid\n"); +#endif + mx4200->reason = PPSREASON + 9; + mx4200_event(mx4200, CEVNT_BADTIME); + mx4200_reset(mx4200); + return; + } + + /* Copy time into mx4200unit struct */ + /* XXX (why?) */ + mx4200->year = jt->year; + mx4200->monthday = jt->monthday; + mx4200->hour = jt->hour; + mx4200->minute = jt->minute; + mx4200->second = jt->second; + + /* Sock away the GPS and UNIX timesamples */ + n = mx4200->nsamples++; + if (n < 0) + return; /* oops, this pulse is bad */ + mx4200->gpssamples[n] = gpstime; + mx4200->unixsamples[n].l_ui = mx4200->lastsampletime.l_ui = tmp_ui; + mx4200->unixsamples[n].l_uf = mx4200->lastsampletime.l_uf = tmp_uf; + if (mx4200->nsamples >= NSTAMPS) { + /* + * Here we've managed to complete an entire NSTAMPS + * second cycle without major mishap. Process what has + * been received. + */ + mx4200_process(mx4200); + mx4200_reset(mx4200); + } +} + +/* Compare two l_fp's, used with qsort() */ +static int +mx4200_cmpl_fp(p1, p2) + register void *p1, *p2; +{ + + if (!L_ISGEQ((l_fp *)p1, (l_fp *)p2)) + return (-1); + if (L_ISEQU((l_fp *)p1, (l_fp *)p2)) + return (0); + return (1); +} + +/* + * mx4200_process - process a pile of samples from the clock + */ +static void +mx4200_process(mx4200) + struct mx4200unit *mx4200; +{ + register int i, n; + register l_fp *fp, *op; + register U_LONG *lp; + l_fp off[NSTAMPS]; + register U_LONG tmp_ui, tmp_uf; + register U_LONG date_ui, date_uf; + u_fp dispersion; + + /* Compute offsets from the raw data. */ + fp = mx4200->unixsamples; + op = off; + lp = mx4200->gpssamples; + for (i = 0; i < NSTAMPS; ++i, ++lp, ++op, ++fp) { + op->l_ui = *lp; + op->l_uf = 0; + L_SUB(op, fp); + } + + /* Sort offsets into ascending order. */ + qsort((char *)off, NSTAMPS, sizeof(l_fp), mx4200_cmpl_fp); + + /* + * Reject the furthest from the median until 8 samples left + */ + i = 0; + n = NSTAMPS; + while ((n - i) > 8) { + tmp_ui = off[n-1].l_ui; + tmp_uf = off[n-1].l_uf; + date_ui = off[(n+i)/2].l_ui; + date_uf = off[(n+i)/2].l_uf; + M_SUB(tmp_ui, tmp_uf, date_ui, date_uf); + M_SUB(date_ui, date_uf, off[i].l_ui, off[i].l_uf); + if (M_ISHIS(date_ui, date_uf, tmp_ui, tmp_uf)) { + /* + * reject low end + */ + i++; + } else { + /* + * reject high end + */ + n--; + } + } + + /* + * Compute the dispersion based on the difference between the + * extremes of the remaining offsets. + */ + tmp_ui = off[n-1].l_ui; + tmp_uf = off[n-1].l_uf; + M_SUB(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf); + dispersion = MFPTOFP(tmp_ui, tmp_uf); + + /* + * Now compute the offset estimate. If the sloppy clock + * flag is set, average the remainder, otherwise pick the + * median. + */ + if (sloppyclockflag[mx4200->unit]) { + tmp_ui = tmp_uf = 0; + while (i < n) { + M_ADD(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf); + i++; + } + M_RSHIFT(tmp_ui, tmp_uf); + M_RSHIFT(tmp_ui, tmp_uf); + M_RSHIFT(tmp_ui, tmp_uf); + i = 0; + off[0].l_ui = tmp_ui; + off[0].l_uf = tmp_uf; + } else { + i = (n + i) / 2; + } + + /* + * Add the default MX4200 QT delay into this. + */ +#ifdef notdef + L_ADDUF(&off[i], MX4200QTFUDGE); +#endif + + /* + * Done. Use lastref as the reference time and lastrec + * as the receive time. ** note this can result in tossing + * out the peer in the protocol module if lastref > lastrec, + * so last rec is used for both values - dlm *** + */ + refclock_receive(mx4200->peer, &off[i], + (s_fp)0, /* delay */ + dispersion, + &mx4200->unixsamples[NSTAMPS-1], /* reftime */ + &mx4200->unixsamples[NSTAMPS-1], /* rectime */ + mx4200->leap); + + mx4200_event(mx4200, CEVNT_NOMINAL); +} + +/* + * mx4200_control - set fudge factors, return statistics + */ +static void +mx4200_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct mx4200unit *mx4200; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "mx4200_control: unit %d invalid", unit); + return; + } + + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + fudgefactor[unit] = in->fudgetime1; + 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 + */ + mx4200 = mx4200units[unit]; + peer = mx4200->peer; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(MX4200REFID, (char *)&peer->refid, + 4); + else + peer->refid = htonl(MX4200HSREFID); + } + } + if (in->haveflags & CLK_HAVEFLAG1) { + sloppyclockflag[unit] = in->flags & CLK_FLAG1; + } + } + + if (out != 0) { + out->type = REFCLK_GPS_MX4200; + out->haveflags + = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1; + out->clockdesc = MX4200DESCRIPTION; + out->fudgetime1 = fudgefactor[unit]; + out->fudgetime2.l_ui = 0; + out->fudgetime2.l_uf = 0; + out->fudgeval1 = (LONG)stratumtouse[unit]; + out->fudgeval2 = 0; + out->flags = sloppyclockflag[unit]; + if (unitinuse[unit]) { + mx4200 = mx4200units[unit]; + out->lencode = mx4200->lencode; + out->lastcode = mx4200->lastcode; + out->lastevent = mx4200->lastevent; + out->currentstatus = mx4200->status; + + out->polls = 0; /* mx4200->polls; */ + out->noresponse = 0; /* mx4200->noresponse; */ + out->badformat = mx4200->badformat; + out->baddata = mx4200->baddata; + out->timereset = current_time - mx4200->timestarted; + } else { + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} + +/* + * mx4200_buginfo - return clock dependent debugging info + */ +static void +mx4200_buginfo(unit, bug) + int unit; + register struct refclockbug *bug; +{ + register struct mx4200unit *mx4200; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "mx4200_buginfo: unit %d invalid", unit); + return; + } + + if (!unitinuse[unit]) + return; + mx4200 = mx4200units[unit]; + + bzero((char *)bug, sizeof(*bug)); + bug->nvalues = 10; + bug->ntimes = 2; + if (mx4200->lasttime != 0) + bug->values[0] = current_time - mx4200->lasttime; + else + bug->values[0] = 0; + bug->values[1] = (U_LONG)mx4200->reason; + bug->values[2] = (U_LONG)mx4200->year; + bug->values[3] = (U_LONG)mx4200->monthday; + bug->values[4] = (U_LONG)mx4200->hour; + bug->values[5] = (U_LONG)mx4200->minute; + bug->values[6] = (U_LONG)mx4200->second; +#ifdef notdef + bug->values[7] = mx4200->msec; + bug->values[8] = mx4200->noreply; + bug->values[9] = mx4200->yearstart; +#endif + bug->stimes = 0x1c; +#ifdef notdef + bug->times[0] = mx4200->lastref; + bug->times[1] = mx4200->lastrec; +#endif +} + +/* + * Returns true if the this is a status message. We use this as + * an indication that the receiver needs to be initialized. + */ +static int +mx4200_needconf(buf) + char *buf; +{ + register LONG v; + char *cp; + + cp = buf; + + if ((cp = strchr(cp, ',')) == NULL) + return (0); + ++cp; + + /* Record type */ + v = strtol(cp, &cp, 10); + if (v != PMVXG_D_STATUS) + return (0); + /* + * 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. + */ +#ifdef notdef + ++cp; + + /* Receiver status */ + if ((cp = strchr(cp, ',')) == NULL) + return (0); + ++cp; + + /* Number of satellites which should be visible */ + if ((cp = strchr(cp, ',')) == NULL) + return (0); + ++cp; + + /* Number of satellites being tracked */ + if ((cp = strchr(cp, ',')) == NULL) + return (0); + ++cp; + + /* Time since last NAV */ + if ((cp = strchr(cp, ',')) == NULL) + return (0); + ++cp; + + /* Initialization status */ + v = strtol(cp, &cp, 10); + if (v == 0) +#endif + return (1); +} + +/* Parse a mx4200 time recovery message. Returns a string if error */ +static char * +mx4200_parse(buf, jt, validp, leapsecp) + register char *buf; + register struct calendar *jt; + register int *validp, *leapsecp; +{ + register LONG v; + char *cp; + + cp = buf; + bzero((char *)jt, sizeof(*jt)); + + if ((cp = strchr(cp, ',')) == NULL) + return ("no rec-type"); + ++cp; + + /* Record type */ + v = strtol(cp, &cp, 10); + if (v != PMVXG_D_TRECOVOUT) + return ("wrong rec-type"); + + /* Pulse valid indicator */ + if (*cp++ != ',') + return ("no pulse-valid"); + if (*cp == 'T') + *validp = 1; + else if (*cp == 'F') + *validp = 0; + else + return ("bad pulse-valid"); + ++cp; + + /* Year */ + if (*cp++ != ',') + return ("no year"); + jt->year = strtol(cp, &cp, 10); + + /* Month of year */ + if (*cp++ != ',') + return ("no month"); + jt->month = strtol(cp, &cp, 10); + + /* Day of month */ + if (*cp++ != ',') + return ("no month day"); + jt->monthday = strtol(cp, &cp, 10); + + /* Hour */ + if (*cp++ != ',') + return ("no hour"); + jt->hour = strtol(cp, &cp, 10); + + /* Minute */ + if (*cp++ != ':') + return ("no minute"); + jt->minute = strtol(cp, &cp, 10); + + /* Second */ + if (*cp++ != ':') + return ("no second"); + jt->second = strtol(cp, &cp, 10); + + /* Time indicator */ + if (*cp++ != ',' || *cp++ == '\0') + return ("no time indicator"); + + /* Time recovery mode */ + if (*cp++ != ',' || *cp++ == '\0') + return ("no time mode"); + + /* Oscillator offset */ + if ((cp = strchr(cp, ',')) == NULL) + return ("no osc off"); + ++cp; + + /* Time mark error */ + if ((cp = strchr(cp, ',')) == NULL) + return ("no time mark err"); + ++cp; + + /* User time bias */ + if ((cp = strchr(cp, ',')) == NULL) + return ("no user bias"); + ++cp; + + /* Leap second flag */ + if ((cp = strchr(cp, ',')) == NULL) + return ("no leap"); + ++cp; + *leapsecp = strtol(cp, &cp, 10); + + return (NULL); +} + +/* Calculate the checksum */ +static u_char +cksum(cp, n) + register char *cp; + register u_int n; +{ + register u_char ck; + + for (ck = 0; n-- > 0; ++cp) + ck ^= *cp; + return (ck); +} + +static void +#if __STDC__ +mx4200_send(register int fd, const char *fmt, ...) +#else +mx4200_send(fd, fmt, va_alist) + register int fd; + const char *fmt; + va_dcl +#endif +{ + register char *cp; + register int n, m; + va_list ap; + char buf[1024]; + u_char ck; + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + cp = buf; + *cp++ = '$'; +#ifdef notdef + /* BSD is rational */ + n = vsnprintf(cp, sizeof(buf) - 1, fmt, ap); +#else + /* SunOS sucks */ + (void)vsprintf(cp, fmt, ap); + n = strlen(cp); +#endif + ck = cksum(cp, n); + cp += n; + ++n; +#ifdef notdef + /* BSD is rational */ + n += snprintf(cp, sizeof(buf) - n - 5, "*%02X\r\n", ck); +#else + /* SunOS sucks */ + sprintf(cp, "*%02X\r\n", ck); + n += strlen(cp); +#endif + + m = write(fd, buf, n); + if (m < 0) + syslog(LOG_ERR, "mx4200_send: write: %m (%s)", buf); + else if (m != n) + syslog(LOG_ERR, "mx4200_send: write: %d != %d (%s)", m, n, buf); + va_end(ap); +} +#endif diff --git a/contrib/xntpd/xntpd/refclock_omega.c b/contrib/xntpd/xntpd/refclock_omega.c new file mode 100644 index 0000000000..4dee7aa74a --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_omega.c @@ -0,0 +1,1015 @@ +/* + * refclock_omega - clock driver for the Kinemetrics Truetime OM-DC OMEGA + * receiver. + * + * Version 1.0 11-Dec-92 Steve Clift (clift@ml.csiro.au) + * Initial version, mostly lifted from refclock_goes.c. + * + * 1.1 03-May-93 Steve Clift + * Tarted up the sample filtering mechanism to give improved + * one-off measurements. Improved measurement dispersion code + * to account for accumulated drift when the clock loses lock. + * + */ + +#if defined(REFCLOCK) && (defined(OMEGA) || defined(OMEGACLK) || defined(OMEGAPPS)) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(STREAM) +#include +#include +#if defined(OMEGACLK) +#include +#endif /* OMEGACLK */ +#endif /* STREAM */ + +#if defined (OMEGAPPS) +#include +#endif /* OMEGAPPS */ + +#include "ntp_stdlib.h" + +/* + * Support for Kinemetrics Truetime OM-DC OMEGA Receiver + * + * Most of this code is copied from refclock_goes.c with thanks. + * + * the time code looks like follows; Send the clock a R or C and once per + * second a timestamp will appear that looks like this: + * ADDD:HH:MM:SSQCL + * A - control A + * Q Quality indication: indicates possible error of + * > >+- 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. + * C - Carriage return + * L - Line feed + * The carriage return start bit begins on 0 seconds and extends to 1 bit time. + */ + +/* + * Definitions + */ +#define MAXUNITS 4 /* max number of OMEGA units */ +#define OMEGA232 "/dev/omega%d" +#define SPEED232 B9600 /* 9600 baud */ + +/* + * Radio interface parameters + */ +#define OMEGADESCRIPTION "Kinemetrics OM-DC OMEGA Receiver" /* who we are */ +#define OMEGAMAXDISPERSE (FP_SECOND/32) /* max allowed sample dispersion */ +#define OMEGAPRECISION (-10) /* precision assumed (about 1 ms) */ +#define OMEGAREFID "VLF\0" /* reference id */ +#define OMEGAHSREFID 0x7f7f0b0a /* 127.127.11.10 refid hi strata */ +#define LENOMEGA 13 /* length of standard response */ +#define GMT 0 /* hour offset from Greenwich */ +#define NSTAMPS 9 /* samples collected when polled */ +#define NSKEEP 5 /* samples to keep after discards */ +#define BMAX 50 /* timecode buffer length */ + +/* + * The OM-DC puts out the start bit of the on the second, but + * we see the result after the is received, about 2ms later at + * 9600 baud. Use this as the default fudge time, and let the user + * fiddle it to account for driver latency etc. + */ +#define DEFFUDGETIME 0x00830000 /* default fudge time (~2ms) */ + +/* + * Clock drift errors as u_fp values. + */ +#define U_FP5000MS (5*FP_SECOND) /* 5 seconds */ +#define U_FP500MS (FP_SECOND/2) /* 500 msec */ +#define U_FP50MS (FP_SECOND/20) /* 50 msec */ +#define U_FP5MS (FP_SECOND/200) /* 5 msec */ + +/* + * Station codes + */ +#define STATION_NONE 0 +#define STATION_NORWAY 1 +#define STATION_LIBERIA 2 +#define STATION_HAWAII 3 +#define STATION_N_DAKOTA 4 +#define STATION_LA_REUNION 5 +#define STATION_ARGENTINA 6 +#define STATION_AUSTRALIA 7 +#define STATION_JAPAN 8 + +/* + * Hack to avoid excercising the multiplier. I have no pride. + */ +#define MULBY10(x) (((x)<<3) + ((x)<<1)) + +/* + * Imported from the timer module + */ +extern U_LONG current_time; +extern struct event timerqueue[]; + +/* + * Imported from ntp_loopfilter module + */ +extern int fdpps; /* pps file descriptor */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * OMEGA unit control structure + */ +struct omegaunit { + struct peer *peer; /* associated peer structure */ + struct refclockio io; /* given to the I/O handler */ + l_fp lastrec; /* last receive time */ + l_fp lastref; /* last timecode time */ + l_fp offset[NSTAMPS]; /* recent sample offsets */ + char lastcode[BMAX]; /* last timecode received */ + u_short station; /* which station we're locked to */ + u_short polled; /* Hand in a time sample? */ + U_LONG coderecv; /* timecodes received */ + u_char lencode; /* length of last timecode */ + U_LONG lasttime; /* last time clock heard from */ + 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 failure */ + u_char year; /* year of eternity */ + u_short day; /* day of year */ + u_char hour; /* hour of day */ + u_char minute; /* minute of hour */ + u_char second; /* seconds of minute */ + u_char leap; /* leap indicators */ + u_short msec; /* millisecond of second */ + u_char quality; /* quality char from last timecode */ + U_LONG yearstart; /* start of current year */ + /* + * Status tallies + */ + U_LONG polls; /* polls sent */ + U_LONG noreply; /* no replies to polls */ + 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 omegaunit *omegaunits[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 fudgefactor1[MAXUNITS]; +static l_fp fudgefactor2[MAXUNITS]; +static u_char stratumtouse[MAXUNITS]; +static u_char readonlyclockflag[MAXUNITS]; + +/* + * Function prototypes + */ +static void omega_init P((void)); +static int omega_start P((u_int, struct peer *)); +static void omega_shutdown P((int)); +static void omega_report_event P((struct omegaunit *, int)); +static void omega_receive P((struct recvbuf *)); +static char omega_process P((struct omegaunit *, l_fp *, u_fp *)); +static void omega_poll P((int, struct peer *)); +static void omega_control P((u_int, struct refclockstat *, struct refclockstat *)); +static void omega_buginfo P((int, struct refclockbug *)); +static void omega_send P((struct omegaunit *, char *)); + +/* + * Transfer vector + */ +struct refclock refclock_omega = { + omega_start, omega_shutdown, omega_poll, + omega_control, omega_init, omega_buginfo, NOFLAGS +}; + +/* + * omega_init - initialize internal omega driver data + */ +static void +omega_init() +{ + register int i; + /* + * Just zero the data arrays + */ + bzero((char *)omegaunits, sizeof omegaunits); + bzero((char *)unitinuse, sizeof unitinuse); + + /* + * Initialize fudge factors to default. + */ + for (i = 0; i < MAXUNITS; i++) { + fudgefactor1[i].l_ui = 0; + fudgefactor1[i].l_uf = DEFFUDGETIME; + fudgefactor2[i].l_ui = 0; + fudgefactor2[i].l_uf = 0; + stratumtouse[i] = 0; + readonlyclockflag[i] = 0; + } +} + + +/* + * omega_start - open the OMEGA devices and initialize data for processing + */ +static int +omega_start(unit, peer) + u_int unit; + struct peer *peer; +{ + register struct omegaunit *omega; + register int i; + int fd232; + char omegadev[20]; + + /* + * Check configuration info + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR,"omega_start: unit %d invalid", unit); + return 0; + } + if (unitinuse[unit]) { + syslog(LOG_ERR, "omega_start: unit %d in use", unit); + return 0; + } + + /* + * Open serial port + */ + (void) sprintf(omegadev, OMEGA232, unit); + fd232 = open(omegadev, O_RDWR, 0777); + if (fd232 == -1) { + syslog(LOG_ERR, "omega_start: open of %s: %m", omegadev); + return 0; + } + +#if defined(HAVE_SYSV_TTYS) + /* + * System V serial line parameters (termio interface) + * + */ + { struct termio ttyb; + if (ioctl(fd232, TCGETA, &ttyb) < 0) { + syslog(LOG_ERR, + "omega_start: ioctl(%s, TCGETA): %m", omegadev); + 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) { + syslog(LOG_ERR, + "omega_start: ioctl(%s, TCSETA): %m", omegadev); + goto screwed; + } + } +#endif /* HAVE_SYSV_TTYS */ +#if defined(STREAM) + /* + * POSIX/STREAMS serial line parameters (termios interface) + * + * The OMEGACLK option provides timestamping at the driver level. + * It requires the tty_clk streams module. + * + * The OMEGAPPS option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the ppsclock streams module and SunOS 4.1.1 or + * later. + */ + { struct termios ttyb, *ttyp; + + ttyp = &ttyb; + if (tcgetattr(fd232, ttyp) < 0) { + syslog(LOG_ERR, + "omega_start: tcgetattr(%s): %m", omegadev); + 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) { + syslog(LOG_ERR, + "omega_start: tcsetattr(%s): %m", omegadev); + goto screwed; + } + if (tcflush(fd232, TCIOFLUSH) < 0) { + syslog(LOG_ERR, + "omega_start: tcflush(%s): %m", omegadev); + goto screwed; + } +#if defined(OMEGACLK) + if (ioctl(fd232, I_PUSH, "clk") < 0) + syslog(LOG_ERR, + "omega_start: ioctl(%s, I_PUSH, clk): %m", omegadev); + if (ioctl(fd232, CLK_SETSTR, "\n") < 0) + syslog(LOG_ERR, + "omega_start: ioctl(%s, CLK_SETSTR): %m", omegadev); +#endif /* OMEGACLK */ +#if defined(OMEGAPPS) + if (ioctl(fd232, I_PUSH, "ppsclock") < 0) + syslog(LOG_ERR, + "omega_start: ioctl(%s, I_PUSH, ppsclock): %m", omegadev); + else + fdpps = fd232; +#endif /* OMEGAPPS */ + } +#endif /* STREAM */ +#if defined(HAVE_BSD_TTYS) + /* + * 4.3bsd serial line parameters (sgttyb interface) + * + * The OMEGACLK option provides timestamping at the driver level. + * It requires the tty_clk line discipline and 4.3bsd or later. + */ + { struct sgttyb ttyb; +#if defined(OMEGACLK) + int ldisc = CLKLDISC; +#endif /* OMEGACLK */ + + if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { + syslog(LOG_ERR, + "omega_start: ioctl(%s, TIOCGETP): %m", omegadev); + goto screwed; + } + ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; +#if defined(OMEGACLK) + 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 /* OMEGACLK */ + if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { + syslog(LOG_ERR, + "omega_start: ioctl(%s, TIOCSETP): %m", omegadev); + goto screwed; + } +#if defined(OMEGACLK) + if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { + syslog(LOG_ERR, + "omega_start: ioctl(%s, TIOCSETD): %m",omegadev); + goto screwed; + } +#endif /* OMEGACLK */ + } +#endif /* HAVE_BSD_TTYS */ + + /* + * Allocate unit structure + */ + if (omegaunits[unit] != 0) { + omega = omegaunits[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && omegaunits[i] != 0) + break; + } + if (i < MAXUNITS) { + /* + * Reclaim this one + */ + omega = omegaunits[i]; + omegaunits[i] = 0; + } else { + omega = (struct omegaunit *) + emalloc(sizeof(struct omegaunit)); + } + } + bzero((char *)omega, sizeof(struct omegaunit)); + omegaunits[unit] = omega; + + /* + * Set up the structures + */ + omega->peer = peer; + omega->unit = (u_char)unit; + omega->timestarted = current_time; + omega->station = STATION_NONE; + + omega->io.clock_recv = omega_receive; + omega->io.srcclock = (caddr_t)omega; + omega->io.datalen = 0; + omega->io.fd = fd232; + if (!io_addclock(&omega->io)) { + goto screwed; + } + + /* + * All done. Initialize a few random peer variables, then + * return success. + */ + peer->precision = OMEGAPRECISION; + peer->rootdelay = 0; + peer->rootdispersion = 0; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(OMEGAREFID, (char *)&peer->refid, 4); + else + peer->refid = htonl(OMEGAHSREFID); + unitinuse[unit] = 1; + return 1; + + /* + * Something broke; abandon ship + */ +screwed: + (void) close(fd232); + return 0; +} + + +/* + * omega_shutdown - shut down a OMEGA clock + */ +static void +omega_shutdown(unit) + int unit; +{ + register struct omegaunit *omega; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "omega_shutdown: unit %d invalid", + unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "omega_shutdown: unit %d not in use", unit); + return; + } + + /* + * Tell the I/O module to turn us off. We're history. + */ + omega = omegaunits[unit]; + io_closeclock(&omega->io); + unitinuse[unit] = 0; +} + + +/* + * omega_report_event - note the occurance of an event + */ +static void +omega_report_event(omega, code) + struct omegaunit *omega; + int code; +{ + struct peer *peer; + + peer = omega->peer; + if (omega->status != (u_char)code) { + omega->status = (u_char)code; + if (code != CEVNT_NOMINAL) + omega->lastevent = (u_char)code; + syslog(LOG_INFO, + "omega clock %s event %x\n", ntoa(&peer->srcadr), code); + } +} + + +/* + * omega_receive - receive data from the serial interface on a + * Kinemetrics OM-DC OMEGA clock. + */ +static void +omega_receive(rbufp) + struct recvbuf *rbufp; +{ + register int i; + register struct omegaunit *omega; + register u_char *dpt; + register char *cp, *cpend; + register u_char *dpend; + l_fp tstmp; + u_fp dispersion, drift; + + /* + * Get the clock this applies to and a pointers to the data + */ + omega = (struct omegaunit *)rbufp->recv_srcclock; + dpt = (u_char *)&rbufp->recv_space; + +#ifndef PEDANTIC + /* + * The OM-DC outputs a timecode every second, but we only want + * a set of NSTAMPS timecodes when polled (every 64 seconds). + * Setting PEDANTIC causes a sanity check on every timecode. + */ + if (!omega->polled) + return; +#endif + + /* + * Edit timecode to remove control chars + */ + dpend = dpt + rbufp->recv_length; + cp = omega->lastcode; + cpend = omega->lastcode + BMAX - 1; + while (dpt < dpend && cp < cpend) { + if ((*cp = 0x7f & *dpt++) >= ' ') cp++; +#ifdef OMEGACLK + else if (*cp == '\r') { + if (dpend - dpt < 8) { + /* short timestamp */ + return; + } + if (!buftvtots(dpt,&omega->lastrec)) { + /* screwy timestamp */ + return; + } + dpt += 8; + } +#endif + } + *cp = '\0'; + omega->lencode = cp - omega->lastcode; + + if (omega->lencode == 0) + return; + else if (omega->lencode != LENOMEGA) { + omega->badformat++; + /* Sometimes get a lot of these, filling the log with noise */ + /* omega_report_event(omega, CEVNT_BADREPLY); */ + return; + } + +#ifndef OMEGACLK + omega->lastrec = rbufp->recv_time; +#endif + +#ifdef DEBUG + if (debug) + printf("omega: timecode %d %s\n", + omega->lencode, omega->lastcode); +#endif + + /* + * We get down to business, check the timecode format + * and decode its contents. + */ + cp = omega->lastcode; + omega->leap = 0; + /* + * Check timecode format. + */ + if (!isdigit(cp[0]) || /* day of year */ + !isdigit(cp[1]) || + !isdigit(cp[2]) || + cp[3] != ':' || /* */ + !isdigit(cp[4]) || /* hours */ + !isdigit(cp[5]) || + cp[6] != ':' || /* : separator */ + !isdigit(cp[7]) || /* minutes */ + !isdigit(cp[8]) || + cp[9] != ':' || /* : separator */ + !isdigit(cp[10]) || /* seconds */ + !isdigit(cp[11])) { + omega->badformat++; + omega_report_event(omega, CEVNT_BADREPLY); + return; + } + + /* + * Convert and check values. + */ + omega->year = 0; /* fake */ + omega->day = cp[0] - '0'; + omega->day = MULBY10(omega->day) + cp[1] - '0'; + omega->day = MULBY10(omega->day) + cp[2] - '0'; + omega->hour = MULBY10(cp[4] - '0') + cp[5] - '0'; + omega->minute = MULBY10(cp[7] - '0') + cp[8] - '0'; + omega->second = MULBY10(cp[10] - '0') + cp[11] - '0'; + omega->msec = 0; + + if (omega->day < 1 || omega->day > 366) { + omega->baddata++; + omega_report_event(omega, CEVNT_BADDATE); + return; + } + if (omega->hour > 23 || omega->minute > 59 || omega->second > 59) { + omega->baddata++; + omega_report_event(omega, CEVNT_BADTIME); + return; + } + + /* + * Check quality/station-id flag. The OM-DC should normally stay + * permanently locked to a station, and its time error should be less + * than 1 msec. If it loses lock for any reason, it makes a worst + * case drift estimate based on the internally stored stability figure + * for its reference oscillator. The stability figure can be adjusted + * by the user based on experience. The default value is 1E05, which + * is pretty bad - 2E07 is about right for the unit I have. + * + * The following is arbitrary, change it if you're offended: + * For errors less than 50 msec, just clear the station indicator. + * For errors greater than 50 msec, flag loss of sync and report a + * propagation problem. If the error is greater than 500 msec, + * something is dreadfully wrong - report a clock fault. + * + * In each case, we set a drift estimate which is used below as an + * estimate of measurement accuracy. + */ + omega->quality = cp[12]; + if (cp[12] == '>' || cp[12] == '?') { + /* Error 500 to 5000 msec */ + omega_report_event(omega, CEVNT_FAULT); + omega->leap = LEAP_NOTINSYNC; + omega->station = STATION_NONE; + drift = U_FP5000MS; + } else if (cp[12] == '#') { + /* Error 50 to 500 msec */ + omega_report_event(omega, CEVNT_PROP); + omega->leap = LEAP_NOTINSYNC; + omega->station = STATION_NONE; + drift = U_FP500MS; + } else if (cp[12] == '*') { + /* Error 5 to 50 msec */ + omega->lasttime = current_time; + omega->station = STATION_NONE; + drift = U_FP50MS; + } else if (cp[12] == '.') { + /* Error 1 to 5 msec */ + omega->lasttime = current_time; + omega->station = STATION_NONE; + drift = U_FP5MS; + } else if ('A' <= cp[12] && cp[12] <= 'H') { + /* Error less than 1 msec */ + omega->lasttime = current_time; + omega->station = cp[12] - 'A' + 1; + drift = 0; + } else { + omega->badformat++; + omega_report_event(omega, CEVNT_BADREPLY); + return; + } + +#ifdef PEDANTIC + /* If we haven't been polled, bail out. */ + if (!omega->polled) + return; +#endif + + /* + * Now, compute the reference time value. Use the heavy + * machinery for the seconds and the millisecond field for the + * fraction when present. + * + * this code does not yet know how to do the years + */ + tstmp = omega->lastrec; + if (!clocktime(omega->day, omega->hour, omega->minute, + omega->second, GMT, tstmp.l_ui, + &omega->yearstart, &omega->lastref.l_ui)) { + omega->baddata++; + omega_report_event(omega, CEVNT_BADTIME); + return; + } + MSUTOTSF(omega->msec, omega->lastref.l_uf); + + /* + * Adjust the read value by fudgefactor1 to correct RS232 delays. + */ + L_ADD(&omega->lastref, &fudgefactor1[omega->unit]); + + /* Carousel of NSTAMPS offsets. */ + i = omega->coderecv % NSTAMPS; + omega->offset[i] = omega->lastref; + L_SUB(&omega->offset[i], &tstmp); + omega->coderecv++; + + /* If we don't yet have a full set, return. */ + if (omega->coderecv < NSTAMPS) + return; + + /* + * Filter the samples, add the fudge factor and pass the + * offset and dispersion along. We use lastrec as both the + * reference time and receive time in order to avoid being cute, + * like setting the reference time later than the receive time, + * which may cause a paranoid protocol module to chuck out the + * data. If the sample filter chokes because of excessive + * dispersion or whatever, get a new sample (omega->coderecv + * is still >= NSTAMPS) and try again. + */ + if (!omega_process(omega, &tstmp, &dispersion)) { + omega->baddata++; + omega_report_event(omega, CEVNT_BADTIME); + return; + } + + /* + * Add accumulated clock drift to the dispersion to get + * a (hopefully) meaningful measurement accuracy estimate. + */ + dispersion += drift; + refclock_receive(omega->peer, &tstmp, GMT, dispersion, + &omega->lastrec, &omega->lastrec, omega->leap); + + /* + * We have succeeded in answering the poll. If the clock + * is locked, we're nominal. + */ + omega->polled = 0; + omega->coderecv = 0; + if (omega->leap != LEAP_NOTINSYNC) + omega_report_event(omega, CEVNT_NOMINAL); +} + + +/* + * omega_send - time to send the clock a signal to cough up a time sample + */ +static void +omega_send(omega,cmd) + struct omegaunit *omega; + char *cmd; +{ + if (!readonlyclockflag[omega->unit]) { + /* + * Send a command to the clock. + */ + if (write(omega->io.fd, cmd, 1) != 1) { + syslog(LOG_ERR, "omega_send: unit %d: %m", omega->unit); + omega_report_event(omega, CEVNT_FAULT); + } + } +} + + +/* + * Compare two l_fp's, used with qsort() + */ +static int +omega_cmpl_fp(p1, p2) + register void *p1, *p2; +{ + + if (!L_ISGEQ((l_fp *)p1, (l_fp *)p2)) + return (-1); + if (L_ISEQU((l_fp *)p1, (l_fp *)p2)) + return (0); + return (1); +} + + +/* + * omega_process - process a pile of samples from the clock + */ +static char +omega_process(omega, offset, dispersion) + struct omegaunit *omega; + l_fp *offset; + u_fp *dispersion; +{ + register int i, n; + register U_LONG med_ui, med_uf, tmp_ui, tmp_uf; + l_fp off[NSTAMPS]; + u_fp disp; + + /* Copy in offsets and sort into ascending order */ + for (i = 0; i < NSTAMPS; i++) + off[i] = omega->offset[i]; + qsort((char *)off, NSTAMPS, sizeof(l_fp), omega_cmpl_fp); + /* + * Reject the furthest from the median until NSKEEP samples remain + */ + i = 0; + n = NSTAMPS; + while ((n - i) > NSKEEP) { + tmp_ui = off[n-1].l_ui; + tmp_uf = off[n-1].l_uf; + med_ui = off[(n+i)/2].l_ui; + med_uf = off[(n+i)/2].l_uf; + M_SUB(tmp_ui, tmp_uf, med_ui, med_uf); + M_SUB(med_ui, med_uf, off[i].l_ui, off[i].l_uf); + if (M_ISHIS(med_ui, med_uf, tmp_ui, tmp_uf)) { + /* reject low end */ + i++; + } else { + /* reject high end */ + n--; + } + } + + /* + * Compute the dispersion based on the difference between the + * extremes of the remaining offsets. If this is greater than + * the allowed sample set dispersion, bail out. Otherwise, + * return the median offset and the dispersion. + */ + tmp_ui = off[n-1].l_ui; + tmp_uf = off[n-1].l_uf; + M_SUB(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf); + disp = MFPTOFP(tmp_ui, tmp_uf); + if (disp > OMEGAMAXDISPERSE) + return 0; + *offset = off[(n+1)/2]; + *dispersion = disp; + return 1; +} + + +/* + * omega_poll - called by the transmit procedure + */ +static void +omega_poll(unit, peer) + int unit; + struct peer *peer; +{ + struct omegaunit *omega; + + /* + * 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 (unit >= MAXUNITS) { + syslog(LOG_ERR, "omega_poll: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "omega_poll: unit %d not in use", unit); + return; + } + omega = omegaunits[unit]; + if ((current_time - omega->lasttime) > 150) { + omega->noreply++; + omega_report_event(omegaunits[unit], CEVNT_TIMEOUT); + } + + /* + * polled every 64 seconds. Ask OMEGA_RECEIVE to hand in a timestamp. + */ + omega->polled = 1; + omega->polls++; + /* + * Ensure the clock is running in the correct mode - on-second + * timestamps. + */ + omega_send(omega,"C"); +} + + +/* + * omega_control - set fudge factors, return statistics + */ +static void +omega_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct omegaunit *omega; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "omega_control: unit %d invalid", unit); + return; + } + + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + fudgefactor1[unit] = in->fudgetime1; + if (in->haveflags & CLK_HAVETIME2) + fudgefactor2[unit] = in->fudgetime2; + 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 + */ + omega = omegaunits[unit]; + peer = omega->peer; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(OMEGAREFID, (char *)&peer->refid, + 4); + else + peer->refid = htonl(OMEGAHSREFID); + } + } + if (in->haveflags & CLK_HAVEFLAG1) { + readonlyclockflag[unit] = in->flags & CLK_FLAG1; + } + } + + if (out != 0) { + out->type = REFCLK_OMEGA_TRUETIME; + out->haveflags + = CLK_HAVETIME1|CLK_HAVETIME2| + CLK_HAVEVAL1|CLK_HAVEVAL2| + CLK_HAVEFLAG1|CLK_HAVEFLAG2; + out->clockdesc = OMEGADESCRIPTION; + out->fudgetime1 = fudgefactor1[unit]; + out->fudgetime2 = fudgefactor2[unit]; + out->fudgeval1 = (LONG)stratumtouse[unit]; + out->fudgeval2 = 0; + out->flags = readonlyclockflag[unit]; + if (unitinuse[unit]) { + omega = omegaunits[unit]; + out->flags |= omega->station << 1; + out->lencode = omega->lencode; + out->lastcode = omega->lastcode; + out->timereset = current_time - omega->timestarted; + out->polls = omega->polls; + out->noresponse = omega->noreply; + out->badformat = omega->badformat; + out->baddata = omega->baddata; + out->lastevent = omega->lastevent; + out->currentstatus = omega->status; + } else { + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} + + +/* + * omega_buginfo - return clock dependent debugging info + */ +static void +omega_buginfo(unit, bug) + int unit; + register struct refclockbug *bug; +{ + register struct omegaunit *omega; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "omega_buginfo: unit %d invalid", unit); + return; + } + + if (!unitinuse[unit]) + return; + omega = omegaunits[unit]; + + bug->nvalues = 11; + bug->ntimes = 5; + if (omega->lasttime != 0) + bug->values[0] = current_time - omega->lasttime; + else + bug->values[0] = 0; + bug->values[1] = (U_LONG)omega->reason; + bug->values[2] = (U_LONG)omega->year; + bug->values[3] = (U_LONG)omega->day; + bug->values[4] = (U_LONG)omega->hour; + bug->values[5] = (U_LONG)omega->minute; + bug->values[6] = (U_LONG)omega->second; + bug->values[7] = (U_LONG)omega->msec; + bug->values[8] = omega->noreply; + bug->values[9] = omega->yearstart; + bug->values[10] = omega->quality; + bug->stimes = 0x1c; + bug->times[0] = omega->lastref; + bug->times[1] = omega->lastrec; + bug->times[2] = omega->offset[0]; + bug->times[3] = omega->offset[1]; + bug->times[4] = omega->offset[2]; +} +#endif diff --git a/contrib/xntpd/xntpd/refclock_parse.c b/contrib/xntpd/xntpd/refclock_parse.c new file mode 100644 index 0000000000..9e34d6e159 --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_parse.c @@ -0,0 +1,3471 @@ +#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) +/* + * /src/NTP/REPOSITORY/v3/xntpd/refclock_parse.c,v 3.41 1993/11/27 18:44:37 kardel Exp + * + * refclock_parse.c,v 3.41 1993/11/27 18:44:37 kardel Exp + * + * generic reference clock driver for receivers + * + * 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 (new - careful!) + * + * Copyright (c) 1989,1990,1991,1992,1993 + * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg + * + * 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. + * + */ + +/* + * Defines: + * REFCLOCK && (PARSE||PARSEPPS) + * - enable this mess + * STREAM - allow for STREAMS modules + * ("parse", "ppsclocd", "ppsclock") + * PARSEPPS - provide PPS information to loopfilter (for + * backward compatibilty only) + * PPS - supply loopfilter with PPS samples (if configured) + * PPSPPS - notify loopfilter of PPS file descriptor + */ + +/* + * This driver currently provides the support for + * - Meinberg DCF77 receiver DCF77 PZF 535 (TCXO version) (DCF) + * - Meinberg DCF77 receiver DCF77 PZF 535 (OCXO version) (DCF) + * - Meinberg DCF77 receiver U/A 31 (DCF) + * - ELV DCF7000 (DCF) + * - Schmid clock (DCF) + * - Conrad DCF77 receiver module (DCF) + * - FAU DCF77 NTP receiver (TimeBrick) (DCF) + * - Meinberg GPS166 (GPS) + * - Trimble SV6 (GPS) + * + */ + +/* + * Meinberg receivers are connected via a 9600 baud serial line + * + * Receivers that do NOT support: + * - leap second indication + * DCF U/A 31 + * DCF PZF535 (stock version) + * + * so... + * - for PZF535 please ask for revision PZFUERL4.6 or higher + * (support for leap second and alternate antenna) + * + * The Meinberg GPS receiver also has a special NTP time stamp + * format. The firmware release is Uni-Erlangen. Only this + * firmware release is supported by xntp3. + * + * Meinberg generic receiver setup: + * output time code every second + * Baud rate 9600 7E2S + */ + +#include "ntpd.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_control.h" + +#include +#include +#include + +#include +extern int errno; + +#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) +/* #error NEED TO DEFINE ONE OF "STREAM" or "HAVE_SYSV_TTYS" */ +NEED TO DEFINE ONE OF "STREAM" or "HAVE_SYSV_TTYS" +#endif + +#ifdef STREAM +#include +#include +#include +#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 +#include +#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 */ +CURRENTLY NO BSD TTY SUPPORT +#endif + +#if !defined(O_RDWR) /* XXX SOLARIS */ +#include +#endif /* !def(O_RDWR) */ + +#ifdef PPSPPS +#include +#endif + +#include "ntp_select.h" +#include "ntp_stdlib.h" + +#include "parse.h" + +#if !defined(NO_SCCSID) && !defined(lint) && !defined(__GNUC__) +static char rcsid[]="refclock_parse.c,v 3.41 1993/11/27 18:44:37 kardel Exp"; +#endif + +/**=========================================================================== + ** external interface to xntp mechanism + **/ + +static void parse_init P((void)); +static int parse_start P((u_int, struct peer *)); +static void parse_shutdown P((int)); +static void parse_poll P((int, struct peer *)); +static void parse_control P((u_int, struct refclockstat *, struct refclockstat *)); + +#define parse_buginfo noentry + +struct refclock refclock_parse = { + parse_start, + parse_shutdown, + parse_poll, + parse_control, + parse_init, + parse_buginfo, + NOFLAGS +}; + +/* + * the unit field selects for one the prototype to be used (lower 4 bits) + * and for the other the clock type in case of different but similar + * receivers (bits 4-6) + * the most significant bit encodes PPS support + * when the most significant bit is set the pps telegrams will be used + * for controlling the local clock (ntp_loopfilter.c) + * receiver specific configration data is kept in the clockinfo field. + */ + +/* + * Definitions + */ +#define MAXUNITS 4 /* maximum number of "PARSE" units permitted */ +#define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */ + +/**=========================================================================== + ** function vector for dynamically binding io handling mechanism + **/ + +typedef struct bind +{ + char *bd_description; /* name of type of binding */ + int (*bd_init)(); /* initialize */ + void (*bd_end)(); /* end */ + int (*bd_setcs)(); /* set character size */ + int (*bd_disable)(); /* disable */ + int (*bd_enable)(); /* enable */ + int (*bd_getfmt)(); /* get format */ + int (*bd_setfmt)(); /* setfmt */ + int (*bd_getstat)(); /* getstat */ + int (*bd_setstat)(); /* setstat */ + int (*bd_timecode)(); /* get time code */ + void (*bd_receive)(); /* receive operation */ + void (*bd_poll)(); /* poll 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_GETSTAT(_X_, _DCT_) (*(_X_)->binding->bd_getstat)(_X_, _DCT_) +#define PARSE_SETSTAT(_X_, _DCT_) (*(_X_)->binding->bd_setstat)(_X_, _DCT_) +#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_) +#define PARSE_POLL(_X_) (*(_X_)->binding->bd_poll)(_X_) + +/* + * io modes + */ +#define PARSE_F_NOPOLLONLY 0x0001 /* always do async io (possible PPS support via PARSE) */ +#define PARSE_F_POLLONLY 0x0002 /* never do async io (no PPS support via PARSE) */ +#define PARSE_F_PPSPPS 0x0004 /* use loopfilter PPS code (CIOGETEV) */ +#define PARSE_F_PPSONSECOND 0x0008 /* PPS pulses are on second */ + +/**=========================================================================== + ** refclock instance data + **/ + +struct parseunit +{ + /* + * XNTP management + */ + struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */ + int fd; /* device file descriptor */ + u_char unit; /* encoded unit/type/PPS */ + + /* + * XNTP io + */ + struct refclockio io; /* io system structure (used in PPS mode) */ + bind_t *binding; /* io handling binding */ + + /* + * parse state + */ + parse_t parseio; /* io handling structure (user level parsing) */ + + /* + * type specific parameters + */ + struct clockinfo *parse_type; /* link to clock description */ + + /* + * clock specific configuration + */ + l_fp basedelay; /* clock local phase offset */ + + /* + * clock state handling/reporting + */ + u_char flags; /* flags (leap_control) */ + u_char status; /* current status */ + u_char lastevent; /* last not NORMAL status */ + U_LONG lastchange; /* time (xntp) when last state change accured */ + U_LONG statetime[CEVNT_MAX+1]; /* accumulated time of clock states */ + struct event stattimer; /* statistics timer */ + U_LONG polls; /* polls from NTP protocol machine */ + U_LONG noresponse; /* number of expected but not seen datagrams */ + U_LONG badformat; /* bad format (failed format conversions) */ + U_LONG baddata; /* usually bad receive length, bad format */ + + u_char pollonly; /* 1 for polling only (no PPS mode) */ + u_char pollneeddata; /* 1 for receive sample expected in PPS mode */ + U_LONG laststatus; /* last packet status (error indication) */ + u_short lastformat; /* last format used */ + U_LONG lastsync; /* time (xntp) when clock was last seen fully synchronized */ + U_LONG timestarted; /* time (xntp) when peer clock was instantiated */ + U_LONG nosynctime; /* time (xntp) when last nosync message was posted */ + U_LONG lastmissed; /* time (xntp) 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 data */ +}; + + +/**=========================================================================== + ** Clockinfo section all parameter for specific clock types + ** includes NTP paramaters, TTY parameters and IO handling parameters + **/ + +static void poll_dpoll P((struct parseunit *)); +static void poll_poll P((struct parseunit *)); +static int poll_init P((struct parseunit *)); +static void poll_end P((struct parseunit *)); + +typedef struct poll_info +{ + U_LONG rate; /* poll rate - once every "rate" seconds - 0 off */ + char * string; /* string to send for polling */ + U_LONG count; /* number of charcters in string */ +} poll_info_t; + +#define NO_FLAGS 0 +#define NO_POLL (void (*)())0 +#define NO_INIT (int (*)())0 +#define NO_END (void (*)())0 +#define NO_DATA (void *)0 +#define NO_FORMAT "" + +#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 0x00000000 +#define NOCLOCK_BASEDELAY 0x00000000 +#define NOCLOCK_DESCRIPTION ((char *)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 NO_FORMAT +#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC + +#define DCF_TYPE CTL_SST_TS_LF +#define GPS_TYPE CTL_SST_TS_UHF + +/* + * receiver specific constants + */ +#define MBG_CFLAG19200 (B19200|CS7|PARENB|CREAD|HUPCL) +#define MBG_CFLAG (B9600|CS7|PARENB|CREAD|HUPCL) +#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP) +#define MBG_OFLAG 0 +#define MBG_LFLAG 0 +/* + * Meinberg DCF U/A 31 (AM) receiver + */ +#define DCFUA31_ROOTDELAY 0x00000D00 /* 50.78125ms */ +#define DCFUA31_BASEDELAY 0x02C00000 /* 10.7421875ms: 10 ms (+/- 3 ms) */ +#define DCFUA31_DESCRIPTION "Meinberg DCF U/A 31" +#define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */ +#define DCFUA31_CFLAG MBG_CFLAG +#define DCFUA31_IFLAG MBG_IFLAG +#define DCFUA31_OFLAG MBG_OFLAG +#define DCFUA31_LFLAG MBG_LFLAG + +/* + * Meinberg DCF PZF535/TCXO (FM/PZF) receiver + */ +#define DCFPZF535_ROOTDELAY 0x00000034 /* 800us */ +#define DCFPZF535_BASEDELAY 0x00800000 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ +#define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/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_CFLAG MBG_CFLAG +#define DCFPZF535_IFLAG MBG_IFLAG +#define DCFPZF535_OFLAG MBG_OFLAG +#define DCFPZF535_LFLAG MBG_LFLAG + + +/* + * Meinberg DCF PZF535/OCXO receiver + */ +#define DCFPZF535OCXO_ROOTDELAY 0x00000034 /* 800us (max error * 10) */ +#define DCFPZF535OCXO_BASEDELAY 0x00800000 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ +#define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/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_CFLAG MBG_CFLAG +#define DCFPZF535OCXO_IFLAG MBG_IFLAG +#define DCFPZF535OCXO_OFLAG MBG_OFLAG +#define DCFPZF535OCXO_LFLAG MBG_LFLAG + +/* + * Meinberg GPS166 receiver + */ +#define GPS166_ROOTDELAY 0x00000000 /* nothing here */ +#define GPS166_BASEDELAY 0x00800000 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ +#define GPS166_DESCRIPTION "Meinberg GPS166 receiver" +#define GPS166_MAXUNSYNC 0 /* this clock is immediately lost */ +#define GPS166_CFLAG MBG_CFLAG +#define GPS166_IFLAG MBG_IFLAG +#define GPS166_OFLAG MBG_OFLAG +#define GPS166_LFLAG MBG_LFLAG +#define GPS166_POLL NO_POLL +#define GPS166_INIT NO_INIT +#define GPS166_END NO_END +#define GPS166_DATA NO_DATA +#define GPS166_ID GPS_ID +#define GPS166_FORMAT NO_FORMAT + +/* + * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit) + * + * This is really not the hottest clock - but before you have nothing ... + */ +#define DCF7000_ROOTDELAY 0x00000364 /* 13 ms */ +#define DCF7000_BASEDELAY 0x67AE0000 /* 405 ms - slow blow */ +#define DCF7000_DESCRIPTION "ELV DCF7000" +#define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */ +#define DCF7000_CFLAG (B9600|CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL) +#define DCF7000_IFLAG (IGNBRK) +#define DCF7000_OFLAG 0 +#define DCF7000_LFLAG 0 + +/* + * 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 poll_end +#define WSDCF_DATA ((void *)(&wsdcf_pollinfo)) +#define WSDCF_ROOTDELAY 0X00004A3D /* ~ 290ms */ +#define WSDCF_BASEDELAY 0x028F5C29 /* ~ 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_CFLAG (B1200|CS8|CREAD|CLOCAL) +#define WSDCF_IFLAG 0 +#define WSDCF_OFLAG 0 +#define WSDCF_LFLAG 0 + +/* + * RAW DCF77 - input of DCF marks via RS232 - many variants + */ +#define RAWDCF_FLAGS PARSE_F_NOPOLLONLY +#define RAWDCF_ROOTDELAY 0x00000364 /* 13 ms */ +#define RAWDCF_FORMAT "RAW DCF77 Timecode" +#define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */ +#define RAWDCF_CFLAG (B50|CS8|CREAD|CLOCAL) +#define RAWDCF_IFLAG 0 +#define RAWDCF_OFLAG 0 +#define RAWDCF_LFLAG 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 0x420C49B0 /* ~258 ms - Conrad receiver @ 50 Baud on a Sun */ +#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)" + +/* + * TimeBrick receiver + */ +#define TIMEBRICK_BASEDELAY 0x35C29000 /* ~210 ms - TimeBrick @ 50 Baud on a Sun */ +#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)" + +/* + * Trimble SV6 GPS receiver + */ +#define TRIM_POLLRATE 0 /* only true direct polling */ +#define TRIM_POLLCMD ">QTM<" +#define TRIM_CMDSIZE 5 + +static poll_info_t trimble_pollinfo = { TRIM_POLLRATE, TRIM_POLLCMD, TRIM_CMDSIZE }; +static int trimble_init P((struct parseunit *)); + +#define TRIMBLESV6_CFLAG (B4800|CS8|CREAD) +#define TRIMBLESV6_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON) +#define TRIMBLESV6_OFLAG (OPOST|ONLCR) +#define TRIMBLESV6_LFLAG (ICANON|ECHOK) +#define TRIMBLESV6_FLAGS (PARSE_F_PPSPPS|PARSE_F_PPSONSECOND) +#define TRIMBLESV6_POLL poll_dpoll +#define TRIMBLESV6_INIT trimble_init +#define TRIMBLESV6_END poll_end +#define TRIMBLESV6_DATA ((void *)(&trimble_pollinfo)) +#define TRIMBLESV6_ID GPS_ID +#define TRIMBLESV6_FORMAT NO_FORMAT +#define TRIMBLESV6_ROOTDELAY 0x0 +#define TRIMBLESV6_BASEDELAY 0x0 +#define TRIMBLESV6_DESCRIPTION "Trimble SV6 GPS receiver" +#define TRIMBLESV6_MAXUNSYNC 0 +#define TRIMBLESV6_EOL '<' + +static struct clockinfo +{ + U_LONG cl_flags; /* operation flags (io modes) */ + void (*cl_poll)(); /* active poll routine */ + int (*cl_init)(); /* active poll init routine */ + void (*cl_end)(); /* active poll end routine */ + void *cl_data; /* local data area for "poll" mechanism */ + u_fp cl_rootdelay; /* rootdelay */ + U_LONG cl_basedelay; /* current offset - unsigned l_fp fractional part */ + char *cl_id; /* ID code (usually "DCF") */ + char *cl_description; /* device name */ + char *cl_format; /* fixed format */ + u_char cl_type; /* clock type (ntp control) */ + U_LONG cl_maxunsync; /* time to trust oscillator after loosing synch */ + U_LONG cl_cflag; /* terminal io flags */ + U_LONG cl_iflag; /* terminal io flags */ + U_LONG cl_oflag; /* terminal io flags */ + U_LONG cl_lflag; /* terminal io flags */ +} clockinfo[] = +{ /* 0. 0.0.128 - base offset for PPS support */ + { /* 127.127.8. */ + NO_FLAGS, + NO_POLL, + NO_INIT, + NO_END, + NO_DATA, + DCFPZF535_ROOTDELAY, + DCFPZF535_BASEDELAY, + DCF_P_ID, + DCFPZF535_DESCRIPTION, + NO_FORMAT, + DCF_TYPE, + DCFPZF535_MAXUNSYNC, + DCFPZF535_CFLAG, + DCFPZF535_IFLAG, + DCFPZF535_OFLAG, + DCFPZF535_LFLAG + }, + { /* 127.127.8.4+ */ + NO_FLAGS, + NO_POLL, + NO_INIT, + NO_END, + NO_DATA, + DCFPZF535OCXO_ROOTDELAY, + DCFPZF535OCXO_BASEDELAY, + DCF_P_ID, + DCFPZF535OCXO_DESCRIPTION, + NO_FORMAT, + DCF_TYPE, + DCFPZF535OCXO_MAXUNSYNC, + DCFPZF535OCXO_CFLAG, + DCFPZF535OCXO_IFLAG, + DCFPZF535OCXO_OFLAG, + DCFPZF535OCXO_LFLAG + }, + { /* 127.127.8.8+ */ + NO_FLAGS, + NO_POLL, + NO_INIT, + NO_END, + NO_DATA, + DCFUA31_ROOTDELAY, + DCFUA31_BASEDELAY, + DCF_A_ID, + DCFUA31_DESCRIPTION, + NO_FORMAT, + DCF_TYPE, + DCFUA31_MAXUNSYNC, + DCFUA31_CFLAG, + DCFUA31_IFLAG, + DCFUA31_OFLAG, + DCFUA31_LFLAG + }, + { /* 127.127.8.12+ */ + NO_FLAGS, + NO_POLL, + NO_INIT, + NO_END, + NO_DATA, + DCF7000_ROOTDELAY, + DCF7000_BASEDELAY, + DCF_A_ID, + DCF7000_DESCRIPTION, + NO_FORMAT, + DCF_TYPE, + DCF7000_MAXUNSYNC, + DCF7000_CFLAG, + DCF7000_IFLAG, + DCF7000_OFLAG, + DCF7000_LFLAG + }, + { /* 127.127.8.16+ */ + NO_FLAGS, + WSDCF_POLL, + WSDCF_INIT, + WSDCF_END, + WSDCF_DATA, + WSDCF_ROOTDELAY, + WSDCF_BASEDELAY, + DCF_A_ID, + WSDCF_DESCRIPTION, + WSDCF_FORMAT, + DCF_TYPE, + WSDCF_MAXUNSYNC, + WSDCF_CFLAG, + WSDCF_IFLAG, + WSDCF_OFLAG, + WSDCF_LFLAG + }, + { /* 127.127.8.20+ */ + RAWDCF_FLAGS, + NO_POLL, + NO_INIT, + NO_END, + NO_DATA, + RAWDCF_ROOTDELAY, + CONRAD_BASEDELAY, + DCF_A_ID, + CONRAD_DESCRIPTION, + RAWDCF_FORMAT, + DCF_TYPE, + RAWDCF_MAXUNSYNC, + RAWDCF_CFLAG, + RAWDCF_IFLAG, + RAWDCF_OFLAG, + RAWDCF_LFLAG + }, + { /* 127.127.8.24+ */ + RAWDCF_FLAGS, + NO_POLL, + NO_INIT, + NO_END, + NO_DATA, + RAWDCF_ROOTDELAY, + TIMEBRICK_BASEDELAY, + DCF_A_ID, + TIMEBRICK_DESCRIPTION, + RAWDCF_FORMAT, + DCF_TYPE, + RAWDCF_MAXUNSYNC, + RAWDCF_CFLAG, + RAWDCF_IFLAG, + RAWDCF_OFLAG, + RAWDCF_LFLAG + }, + { /* 127.127.8.28+ */ + NO_FLAGS, + GPS166_POLL, + GPS166_INIT, + GPS166_END, + GPS166_DATA, + GPS166_ROOTDELAY, + GPS166_BASEDELAY, + GPS166_ID, + GPS166_DESCRIPTION, + GPS166_FORMAT, + GPS_TYPE, + GPS166_MAXUNSYNC, + GPS166_CFLAG, + GPS166_IFLAG, + GPS166_OFLAG, + GPS166_LFLAG + }, + { /* 127.127.8.32+ */ + TRIMBLESV6_FLAGS, + TRIMBLESV6_POLL, + TRIMBLESV6_INIT, + TRIMBLESV6_END, + TRIMBLESV6_DATA, + TRIMBLESV6_ROOTDELAY, + TRIMBLESV6_BASEDELAY, + TRIMBLESV6_ID, + TRIMBLESV6_DESCRIPTION, + TRIMBLESV6_FORMAT, + GPS_TYPE, + TRIMBLESV6_MAXUNSYNC, + TRIMBLESV6_CFLAG, + TRIMBLESV6_IFLAG, + TRIMBLESV6_OFLAG, + TRIMBLESV6_LFLAG + } +}; + +static int ncltypes = sizeof(clockinfo) / sizeof(struct clockinfo); + +#define CL_REALTYPE(x) (((x) >> 2) & 0x1F) +#define CL_TYPE(x) ((CL_REALTYPE(x) >= ncltypes) ? ~0 : CL_REALTYPE(x)) +#define CL_PPS(x) ((x) & 0x80) +#define CL_UNIT(x) ((x) & 0x3) + +/* + * Other constant stuff + */ +#define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */ + +#define PARSENOSYNCREPEAT (10*60) /* mention uninitialized clocks all 10 minutes */ +#define PARSESTATISTICS (60*60) /* output state statistics every hour */ + +static struct parseunit *parseunits[MAXUNITS]; + +extern U_LONG current_time; +extern s_char sys_precision; +extern struct event timerqueue[]; +#ifdef PPSPPS +extern int fdpps; +#endif + +static int notice = 0; + +#define PARSE_STATETIME(parse, i) ((parse->status == 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 *)); + +/**=========================================================================== + ** 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_nop 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_getstat P((struct parseunit *, parsectl_t *)); +static int stream_setstat P((struct parseunit *, parsectl_t *)); +static int stream_timecode P((struct parseunit *, parsectl_t *)); +static void stream_receive P((struct recvbuf *)); +static void stream_poll P((struct parseunit *)); +#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_getstat P((struct parseunit *, parsectl_t *)); +static int local_setstat P((struct parseunit *, parsectl_t *)); +static int local_timecode P((struct parseunit *, parsectl_t *)); +static void local_receive P((struct recvbuf *)); +static void local_poll P((struct parseunit *)); + +static bind_t io_bindings[] = +{ +#ifdef STREAM + { + "parse STREAM", + stream_init, + stream_nop, + stream_setcs, + stream_disable, + stream_enable, + stream_getfmt, + stream_setfmt, + stream_getstat, + stream_setstat, + stream_timecode, + stream_receive, + stream_poll + }, + { + "ppsclock STREAM", + ppsclock_init, + local_end, + local_setcs, + local_nop, + local_nop, + local_getfmt, + local_setfmt, + local_getstat, + local_setstat, + local_timecode, + local_receive, + local_poll + }, +#endif + { + "normal", + local_init, + local_end, + local_setcs, + local_nop, + local_nop, + local_getfmt, + local_setfmt, + local_getstat, + local_setstat, + local_timecode, + local_receive, + local_poll + }, + { + (char *)0, + } +}; + +#ifdef STREAM +/*-------------------------------------------------- + * ppsclock STREAM init + */ +static int +ppsclock_init(parse) + struct parseunit *parse; +{ + /* + * now push the parse streams module + * it will ensure exclusive access to the device + */ + if (ioctl(parse->fd, I_PUSH, (caddr_t)"ppsclocd") == -1 && + ioctl(parse->fd, I_PUSH, (caddr_t)"ppsclock") == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", + CL_UNIT(parse->unit)); + return 0; + } + if (!local_init(parse)) + { + (void)ioctl(parse->fd, I_POP, (caddr_t)0); + return 0; + } + + parse->flags |= PARSE_PPSCLOCK; + return 1; +} + +/*-------------------------------------------------- + * parse STREAM init + */ +static int +stream_init(parse) + struct parseunit *parse; +{ + /* + * now push the parse streams module + * to test whether it is there (Oh boy - neat kernel interface) + */ + if (ioctl(parse->fd, I_PUSH, (caddr_t)"parse") == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CL_UNIT(parse->unit)); + return 0; + } + else + { + while(ioctl(parse->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->fd, I_PUSH, (caddr_t)"parse") == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CL_UNIT(parse->unit)); + return 0; + } + else + { + return 1; + } + } +} + + /*-------------------------------------------------- + * STREAM setcs + */ +static int +stream_setcs(parse, tcl) + 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->fd, I_STR, (caddr_t)&strioc) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CL_UNIT(parse->unit)); + return 0; + } + return 1; +} + +/*-------------------------------------------------- + * STREAM nop + */ +static void +stream_nop(parse) + struct parseunit *parse; +{ +} + +/*-------------------------------------------------- + * STREAM enable + */ +static int +stream_enable(parse) + 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->fd, I_STR, (caddr_t)&strioc) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CL_UNIT(parse->unit)); + return 0; + } + return 1; +} + +/*-------------------------------------------------- + * STREAM disable + */ +static int +stream_disable(parse) + 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->fd, I_STR, (caddr_t)&strioc) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CL_UNIT(parse->unit)); + return 0; + } + return 1; +} + +/*-------------------------------------------------- + * STREAM getfmt + */ +static int +stream_getfmt(parse, tcl) + 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->fd, I_STR, (caddr_t)&strioc) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CL_UNIT(parse->unit)); + return 0; + } + return 1; +} + +/*-------------------------------------------------- + * STREAM setfmt + */ +static int +stream_setfmt(parse, tcl) + 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->fd, I_STR, (caddr_t)&strioc) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CL_UNIT(parse->unit)); + return 0; + } + return 1; +} + +/*-------------------------------------------------- + * STREAM getstat + */ +static int +stream_getstat(parse, tcl) + struct parseunit *parse; + parsectl_t *tcl; +{ + struct strioctl strioc; + + strioc.ic_cmd = PARSEIOC_GETSTAT; + strioc.ic_timout = 0; + strioc.ic_dp = (char *)tcl; + strioc.ic_len = sizeof (*tcl); + + if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: stream_getstat: ioctl(fd, I_STR, PARSEIOC_GETSTAT): %m", CL_UNIT(parse->unit)); + return 0; + } + return 1; +} + +/*-------------------------------------------------- + * STREAM setstat + */ +static int +stream_setstat(parse, tcl) + struct parseunit *parse; + parsectl_t *tcl; +{ + struct strioctl strioc; + + strioc.ic_cmd = PARSEIOC_SETSTAT; + strioc.ic_timout = 0; + strioc.ic_dp = (char *)tcl; + strioc.ic_len = sizeof (*tcl); + + if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: stream_setstat: ioctl(fd, I_STR, PARSEIOC_SETSTAT): %m", CL_UNIT(parse->unit)); + return 0; + } + return 1; +} + +/*-------------------------------------------------- + * STREAM timecode + */ +static int +stream_timecode(parse, tcl) + 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->fd, I_STR, (caddr_t)&strioc) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_process: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CL_UNIT(parse->unit), parse->fd); + return 0; + } + return 1; +} + +/*-------------------------------------------------- + * STREAM receive + */ +static void +stream_receive(rbufp) + struct recvbuf *rbufp; +{ + struct parseunit *parse = (struct parseunit *)rbufp->recv_srcclock; + parsetime_t parsetime; + + if (rbufp->recv_length != sizeof(parsetime_t)) + { + syslog(LOG_ERR,"PARSE receiver #%d: parse_receive: bad size (got %d expected %d)", + CL_UNIT(parse->unit), rbufp->recv_length, sizeof(parsetime_t)); + parse->baddata++; + parse_event(parse, CEVNT_BADREPLY); + return; + } + bcopy((caddr_t)&rbufp->recv_space, (caddr_t)&parsetime, sizeof(parsetime_t)); + + /* + * switch time stamp world - be sure to normalize small usec field + * errors. + */ + +#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)) \ + { \ + syslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%d.%06d) ", (_Y_), (&(_X_))->tv.tv_sec, (&(_X_))->tv.tv_usec);\ + return; \ + } \ + else \ + { \ + (&(_X_))->fp = ts; \ + } \ + } + + if (PARSE_TIMECODE(parsetime.parse_state)) + { + cvt_ts(parsetime.parse_time, "parse_time"); + cvt_ts(parsetime.parse_stime, "parse_stime"); + } + + if (PARSE_PPS(parsetime.parse_state)) + cvt_ts(parsetime.parse_ptime, "parse_ptime"); + + parse_process(parse, &parsetime); +} + +/*-------------------------------------------------- + * STREAM poll + */ +static void +stream_poll(parse) + struct parseunit *parse; +{ + register int fd, i, rtc; + fd_set fdmask; + struct timeval timeout, starttime, curtime, selecttime; + parsetime_t parsetime; + + /* + * now we do the following: + * - read the first packet from the parse module (OLD !!!) + * - read the second packet from the parse module (fresh) + * - compute values for xntp + */ + + FD_ZERO(&fdmask); + fd = parse->fd; + FD_SET(fd, &fdmask); + timeout.tv_sec = 0; + timeout.tv_usec = 500000; /* 0.5 sec */ + + if (parse->parse_type->cl_poll) + { + parse->parse_type->cl_poll(parse); + } + + if (GETTIMEOFDAY(&starttime, 0L) == -1) + { + syslog(LOG_ERR,"gettimeofday failed: %m"); + exit(1); + } + + selecttime = timeout; + + while ((rtc = select(fd + 1, &fdmask, 0, 0, &selecttime)) != 1) + { + /* no data from the radio clock */ + + if (rtc == -1) + { + if (errno == EINTR) + { + if (GETTIMEOFDAY(&curtime, 0L) == -1) + { + syslog(LOG_ERR,"gettimeofday failed: %m"); + exit(1); + } + selecttime.tv_sec = curtime.tv_sec - starttime.tv_sec; + if (curtime.tv_usec < starttime.tv_usec) + { + selecttime.tv_sec -= 1; + selecttime.tv_usec = 1000000 + curtime.tv_usec - starttime.tv_usec; + } + else + { + selecttime.tv_usec = curtime.tv_usec - starttime.tv_usec; + } + + + if (timercmp(&selecttime, &timeout, >)) + { + /* + * elapsed real time passed timeout value - consider it timed out + */ + break; + } + + /* + * calculate residual timeout value + */ + selecttime.tv_sec = timeout.tv_sec - selecttime.tv_sec; + + if (selecttime.tv_usec > timeout.tv_usec) + { + selecttime.tv_sec -= 1; + selecttime.tv_usec = 1000000 + timeout.tv_usec - selecttime.tv_usec; + } + else + { + selecttime.tv_usec = timeout.tv_usec - selecttime.tv_usec; + } + + FD_SET(fd, &fdmask); + continue; + } + else + { + syslog(LOG_WARNING, "PARSE receiver #%d: no data[old] from device (select() error: %m)", CL_UNIT(parse->unit)); + } + } + else + { + syslog(LOG_WARNING, "PARSE receiver #%d: no data[old] from device", CL_UNIT(parse->unit)); + } + parse->noresponse++; + parse->lastmissed = current_time; + parse_event(parse, CEVNT_TIMEOUT); + + return; + } + + while (((i = read(fd, (char *)&parsetime, sizeof(parsetime))) < sizeof(parsetime))) + { + /* bad packet */ + if ( i == -1) + { + if (errno == EINTR) + { + continue; + } + else + { + syslog(LOG_WARNING, "PARSE receiver #%d: bad read[old] from streams module (read() error: %m)", CL_UNIT(parse->unit), i, sizeof(parsetime)); + } + } + else + { + syslog(LOG_WARNING, "PARSE receiver #%d: bad read[old] from streams module (got %d bytes - expected %d bytes)", CL_UNIT(parse->unit), i, sizeof(parsetime)); + } + parse->baddata++; + parse_event(parse, CEVNT_BADREPLY); + + return; + } + + if (parse->parse_type->cl_poll) + { + parse->parse_type->cl_poll(parse); + } + + timeout.tv_sec = 1; + timeout.tv_usec = 500000; /* 1.500 sec */ + FD_ZERO(&fdmask); + FD_SET(fd, &fdmask); + + if (GETTIMEOFDAY(&starttime, 0L) == -1) + { + syslog(LOG_ERR,"gettimeofday failed: %m"); + exit(1); + } + + selecttime = timeout; + + while ((rtc = select(fd + 1, &fdmask, 0, 0, &selecttime)) != 1) + { + /* no data from the radio clock */ + + if (rtc == -1) + { + if (errno == EINTR) + { + if (GETTIMEOFDAY(&curtime, 0L) == -1) + { + syslog(LOG_ERR,"gettimeofday failed: %m"); + exit(1); + } + selecttime.tv_sec = curtime.tv_sec - starttime.tv_sec; + if (curtime.tv_usec < starttime.tv_usec) + { + selecttime.tv_sec -= 1; + selecttime.tv_usec = 1000000 + curtime.tv_usec - starttime.tv_usec; + } + else + { + selecttime.tv_usec = curtime.tv_usec - starttime.tv_usec; + } + + + if (timercmp(&selecttime, &timeout, >)) + { + /* + * elapsed real time passed timeout value - consider it timed out + */ + break; + } + + /* + * calculate residual timeout value + */ + selecttime.tv_sec = timeout.tv_sec - selecttime.tv_sec; + + if (selecttime.tv_usec > timeout.tv_usec) + { + selecttime.tv_sec -= 1; + selecttime.tv_usec = 1000000 + timeout.tv_usec - selecttime.tv_usec; + } + else + { + selecttime.tv_usec = timeout.tv_usec - selecttime.tv_usec; + } + + FD_SET(fd, &fdmask); + continue; + } + else + { + syslog(LOG_WARNING, "PARSE receiver #%d: no data[new] from device (select() error: %m)", CL_UNIT(parse->unit)); + } + } + else + { + syslog(LOG_WARNING, "PARSE receiver #%d: no data[new] from device", CL_UNIT(parse->unit)); + } + + /* + * we will return here iff we got a good old sample as this would + * be misinterpreted. bad samples are passed on to be logged into the + * state statistics + */ + if ((parsetime.parse_status & CVT_MASK) == CVT_OK) + { + parse->noresponse++; + parse->lastmissed = current_time; + parse_event(parse, CEVNT_TIMEOUT); + return; + } + } + + /* + * we get here either by a possible read() (rtc == 1 - while assertion) + * or by a timeout or a system call error. when a read() is possible we + * get the new data, otherwise we stick with the old + */ + if ((rtc == 1) && ((i = read(fd, (char *)&parsetime, sizeof(parsetime))) < sizeof(parsetime))) + { + /* bad packet */ + if ( i== -1) + { + syslog(LOG_WARNING, "PARSE receiver #%d: bad read[new] from streams module (read() error: %m)", CL_UNIT(parse->unit), i, sizeof(parsetime)); + } + else + { + syslog(LOG_WARNING, "PARSE receiver #%d: bad read[new] from streams module (got %d bytes - expected %d bytes)", CL_UNIT(parse->unit), i, sizeof(parsetime)); + } + parse->baddata++; + parse_event(parse, CEVNT_BADREPLY); + + return; + } + + /* + * process what we got + */ + parse_process(parse, &parsetime); +} +#endif + +/*-------------------------------------------------- + * local init + */ +static int +local_init(parse) + struct parseunit *parse; +{ + return parse_ioinit(&parse->parseio); +} + +/*-------------------------------------------------- + * local end + */ +static void +local_end(parse) + struct parseunit *parse; +{ + parse_ioend(&parse->parseio); +} + + +/*-------------------------------------------------- + * local nop + */ +static int +local_nop(parse) + struct parseunit *parse; +{ + return 1; +} + +/*-------------------------------------------------- + * local setcs + */ +static int +local_setcs(parse, tcl) + struct parseunit *parse; + parsectl_t *tcl; +{ + return parse_setcs(tcl, &parse->parseio); +} + +/*-------------------------------------------------- + * local getfmt + */ +static int +local_getfmt(parse, tcl) + struct parseunit *parse; + parsectl_t *tcl; +{ + return parse_getfmt(tcl, &parse->parseio); +} + +/*-------------------------------------------------- + * local setfmt + */ +static int +local_setfmt(parse, tcl) + struct parseunit *parse; + parsectl_t *tcl; +{ + return parse_setfmt(tcl, &parse->parseio); +} + +/*-------------------------------------------------- + * local getstat + */ +static int +local_getstat(parse, tcl) + struct parseunit *parse; + parsectl_t *tcl; +{ + return parse_getstat(tcl, &parse->parseio); +} + +/*-------------------------------------------------- + * local setstat + */ +static int +local_setstat(parse, tcl) + struct parseunit *parse; + parsectl_t *tcl; +{ + return parse_setstat(tcl, &parse->parseio); +} + +/*-------------------------------------------------- + * local timecode + */ +static int +local_timecode(parse, tcl) + struct parseunit *parse; + parsectl_t *tcl; +{ + return parse_timecode(tcl, &parse->parseio); +} + + +/*-------------------------------------------------- + * local receive + */ +static void +local_receive(rbufp) + struct recvbuf *rbufp; +{ + struct parseunit *parse = (struct parseunit *)rbufp->recv_srcclock; + register int count; + register char *s; + /* + * eat all characters, parsing then and feeding complete samples + */ + count = rbufp->recv_length; + s = rbufp->recv_buffer; + + while (count--) + { + if (parse_ioread(&parse->parseio, *s++, &rbufp->recv_time)) + { + /* + * got something good to eat + */ +#ifdef PPSPPS + if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state) && + (parse->flags & PARSE_PPSCLOCK)) + { + l_fp ts; + struct ppsclockev ev; + + if (ioctl(parse->fd, CIOGETEV, (caddr_t)&ev) == 0) + { + if (ev.serial != parse->ppsserial) + { + /* + * add PPS time stamp if available via ppsclock module + * and not supplied already. + */ + if (!buftvtots((const char *)&ev.tv, &ts)) + { + syslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); + } + else + { + parse->parseio.parse_dtime.parse_ptime.fp = ts; + parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; + } + } + parse->ppsserial = ev.serial; + } + } +#endif + parse_process(parse, &parse->parseio.parse_dtime); + parse_iodone(&parse->parseio); + } + } +} + +/*-------------------------------------------------- + * local poll + */ +static void +local_poll(parse) + struct parseunit *parse; +{ + register int fd, i, rtc; + fd_set fdmask; + struct timeval timeout, starttime, curtime, selecttime; + static struct timeval null_time = { 0, 0}; + timestamp_t ts; + + FD_ZERO(&fdmask); + fd = parse->fd; + FD_SET(fd, &fdmask); + timeout.tv_sec = 1; + timeout.tv_usec = 500000; /* 1.5 sec */ + + if (parse->parse_type->cl_poll) + { + parse->parse_type->cl_poll(parse); + } + + if (GETTIMEOFDAY(&starttime, 0L) == -1) + { + syslog(LOG_ERR,"gettimeofday failed: %m"); + exit(1); + } + + selecttime = timeout; + + do + { + while ((rtc = select(fd + 1, &fdmask, 0, 0, &selecttime)) != 1) + { + /* no data from the radio clock */ + + if (rtc == -1) + { + if (errno == EINTR) + { + if (GETTIMEOFDAY(&curtime, 0L) == -1) + { + syslog(LOG_ERR,"gettimeofday failed: %m"); + exit(1); + } + selecttime.tv_sec = curtime.tv_sec - starttime.tv_sec; + if (curtime.tv_usec < starttime.tv_usec) + { + selecttime.tv_sec -= 1; + selecttime.tv_usec = 1000000 + curtime.tv_usec - starttime.tv_usec; + } + else + { + selecttime.tv_usec = curtime.tv_usec - starttime.tv_usec; + } + + + if (!timercmp(&selecttime, &timeout, >)) + { + /* + * calculate residual timeout value + */ + selecttime.tv_sec = timeout.tv_sec - selecttime.tv_sec; + + if (selecttime.tv_usec > timeout.tv_usec) + { + selecttime.tv_sec -= 1; + selecttime.tv_usec = 1000000 + timeout.tv_usec - selecttime.tv_usec; + } + else + { + selecttime.tv_usec = timeout.tv_usec - selecttime.tv_usec; + } + + FD_SET(fd, &fdmask); + continue; + } + } + else + { + syslog(LOG_WARNING, "PARSE receiver #%d: no data from device (select() error: %m)", CL_UNIT(parse->unit)); + } + } + else + { + syslog(LOG_WARNING, "PARSE receiver #%d: no data from device", CL_UNIT(parse->unit)); + } + + parse->noresponse++; + parse->lastmissed = current_time; + parse_event(parse, CEVNT_TIMEOUT); + + return; + } + + /* + * at least 1 character is available - gobble everthing up that is available + */ + do + { + char inbuf[256]; + + register char *s = inbuf; + + rtc = i = read(fd, inbuf, sizeof(inbuf)); + + get_systime(&ts.fp); + + while (i-- > 0) + { + if (parse_ioread(&parse->parseio, *s++, ts)) + { + /* + * got something good to eat + */ + parse_process(parse, &parse->parseio.parse_dtime); + parse_iodone(&parse->parseio); + /* + * done if no more characters are available + */ + FD_SET(fd, &fdmask); + if (select(fd + 1, &fdmask, 0, 0, &null_time) == 0) + return; + } + } + FD_SET(fd, &fdmask); + } while ((rtc = select(fd + 1, &fdmask, 0, 0, &null_time)) == 1); + FD_SET(fd, &fdmask); + } while (1); +} + +/*-------------------------------------------------- + * init_iobinding - find and initialize lower layers + */ +static bind_t * +init_iobinding(parse) + struct parseunit *parse; +{ + register 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(state, buffer) + unsigned LONG state; + char *buffer; +{ + static struct bits + { + unsigned LONG bit; + 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_LEAP, "LEAP WARNING" }, + { PARSEB_LEAPSECOND, "LEAP SECOND" }, + { PARSEB_ALTERNATE,"ALTERNATE ANTENNA" }, + { PARSEB_TIMECODE, "TIME CODE" }, + { PARSEB_PPS, "PPS" }, + { PARSEB_POSITION, "POSITION" }, + { 0 } + }; + + static struct sbits + { + unsigned LONG bit; + 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 & state) + { + if (buffer[0]) + strcat(buffer, "; "); + strcat(buffer, flagstrings[i].name); + } + i++; + } + + if (state & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION)) + { + register 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 & state) + { + 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(state, buffer) + unsigned LONG state; + char *buffer; +{ + static struct bits + { + unsigned LONG bit; + 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" }, + { 0 } + }; + int i; + + *buffer = '\0'; + + i = 0; + while (flagstrings[i].bit) + { + if (flagstrings[i].bit & state) + { + if (buffer[0]) + strcat(buffer, "; "); + strcat(buffer, flagstrings[i].name); + } + i++; + } + + return buffer; +} + +/*-------------------------------------------------- + * convert a clock status flag field to a string + */ +static char * +clockstatus(state) + unsigned LONG state; +{ + static char buffer[20]; + static struct status + { + unsigned LONG value; + 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" }, + { ~0 } + }; + int i; + + i = 0; + while (flagstrings[i].value != ~0) + { + if (flagstrings[i].value == state) + { + return flagstrings[i].name; + } + i++; + } + + sprintf(buffer, "unknown #%d", state); + + return buffer; +} + +/*-------------------------------------------------- + * mkascii - make a printable ascii string + * assumes (unless defined better) 7-bit ASCII + */ +#ifndef isprint +#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F)) +#endif + +static char * +mkascii(buffer, blen, src, srclen) + register char *buffer; + register LONG blen; + register char *src; + register LONG srclen; +{ + register char *b = buffer; + register 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 ((*src != '\\') && isprint(*src)) + { /* printables 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; + } + 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; +} + + +/*-------------------------------------------------- + * l_mktime - make representation of a relative time + */ +static char * +l_mktime(delta) + unsigned LONG delta; +{ + unsigned LONG tmp, m, s; + static char buffer[40]; + + buffer[0] = '\0'; + + if ((tmp = delta / (60*60*24)) != 0) + { + sprintf(buffer, "%dd+", tmp); + delta -= tmp * 60*60*24; + } + + s = delta % 60; + delta /= 60; + m = delta % 60; + delta /= 60; + + sprintf(buffer+strlen(buffer), "%02d:%02d:%02d", + delta, m, s); + + return buffer; +} + + +/*-------------------------------------------------- + * parse_statistics - list summary of clock states + */ +static void +parse_statistics(parse) + register struct parseunit *parse; +{ + register int i; + + syslog(LOG_INFO, "PARSE receiver #%d: running time: %s", + CL_UNIT(parse->unit), + l_mktime(current_time - parse->timestarted)); + + syslog(LOG_INFO, "PARSE receiver #%d: current status: %s", + CL_UNIT(parse->unit), + clockstatus(parse->status)); + + for (i = 0; i <= CEVNT_MAX; i++) + { + register unsigned LONG stime; + register unsigned LONG percent, div = current_time - parse->timestarted; + + percent = stime = PARSE_STATETIME(parse, i); + + while (((unsigned LONG)(~0) / 10000) < percent) + { + percent /= 10; + div /= 10; + } + + if (div) + percent = (percent * 10000) / div; + else + percent = 10000; + + if (stime) + syslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3d.%02d%%)", + CL_UNIT(parse->unit), + clockstatus(i), + l_mktime(stime), + percent / 100, percent % 100); + } +} + +/*-------------------------------------------------- + * cparse_statistics - wrapper for statistics call + */ +static void +cparse_statistics(peer) + register struct peer *peer; +{ + register struct parseunit *parse = (struct parseunit *)peer; + + parse_statistics(parse); + parse->stattimer.event_time = current_time + PARSESTATISTICS; + TIMER_ENQUEUE(timerqueue, &parse->stattimer); +} + +/**=========================================================================== + ** xntp interface routines + **/ + +/*-------------------------------------------------- + * parse_init - initialize internal parse driver data + */ +static void +parse_init() +{ + bzero((caddr_t)parseunits, sizeof parseunits); +} + + +/*-------------------------------------------------- + * parse_shutdown - shut down a PARSE clock + */ +static void +parse_shutdown(unit) + int unit; +{ + register struct parseunit *parse; + + unit = CL_UNIT(unit); + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, + "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit invalid (max %d)", + unit,MAXUNITS); + return; + } + + parse = parseunits[unit]; + + if (parse && !parse->peer) { + syslog(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); + TIMER_DEQUEUE(&parse->stattimer); + +#if PPSPPS + { + /* + * kill possible PPS association + */ + if (fdpps == parse->fd) + fdpps = -1; + } +#endif + + 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. + */ + if (!parse->pollonly) + io_closeclock(&parse->io); + else + (void) close(parse->fd); + + syslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", + CL_UNIT(parse->unit), parse->parse_type->cl_description); + + parse->peer = (struct peer *)0; /* unused now */ +} + +/*-------------------------------------------------- + * parse_start - open the PARSE devices and initialize data for processing + */ +static int +parse_start(sysunit, peer) + u_int sysunit; + struct peer *peer; +{ + u_int unit; + int fd232, i; +#ifdef STREAM + struct termios tm; /* NEEDED FOR A LONG TIME ! */ +#endif +#ifdef HAVE_SYSV_TTYS + struct termio tm; /* NEEDED FOR A LONG TIME ! */ +#endif + struct parseunit * parse; + char parsedev[sizeof(PARSEDEVICE)+20]; + parsectl_t tmp_ctl; + u_int type; + + type = CL_TYPE(sysunit); + unit = CL_UNIT(sysunit); + + if (unit >= MAXUNITS) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: unit number invalid (max %d)", + unit, MAXUNITS-1); + return 0; + } + + if ((type == ~0) || (clockinfo[type].cl_description == (char *)0)) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", + unit, CL_REALTYPE(sysunit), ncltypes-1); + return 0; + } + + if (parseunits[unit] && parseunits[unit]->peer) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: unit in use", unit); + 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, 0777); + if (fd232 == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); + return 0; + } + + /* + * 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 (parseunits[unit]) + { + parse = parseunits[unit]; /* The one we want is okay - and free */ + } + else + { + for (i = 0; i < MAXUNITS; i++) + { + if (parseunits[i] && !parseunits[i]->peer) + break; + } + if (i < MAXUNITS) + { + /* + * Reclaim this one + */ + parse = parseunits[i]; + parseunits[i] = (struct parseunit *)0; + } + else + { + parse = (struct parseunit *) + emalloc(sizeof(struct parseunit)); + } + } + + bzero((char *)parse, sizeof(struct parseunit)); + parseunits[unit] = parse; + + /* + * Set up the structures + */ + parse->unit = (u_char)sysunit; + parse->timestarted = current_time; + parse->lastchange = current_time; + /* + * we want to filter input for the sake of + * getting an impression on dispersion + * also we like to average the median range + */ + parse->flags = PARSE_STAT_FILTER|PARSE_STAT_AVG; + parse->pollneeddata = 0; + parse->pollonly = 1; /* go for default polling mode */ + parse->lastformat = ~0; /* assume no format known */ + parse->status = CEVNT_TIMEOUT; /* expect the worst */ + parse->laststatus = ~0; /* be sure to mark initial status change */ + parse->nosynctime = 0; /* assume clock reasonable */ + parse->lastmissed = 0; /* assume got everything */ + parse->ppsserial = 0; + parse->localdata = (void *)0; + + parse->parse_type = &clockinfo[type]; + + parse->basedelay.l_ui = 0; /* we can only pre-configure delays less than 1 second */ + parse->basedelay.l_uf = parse->parse_type->cl_basedelay; + + 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) + bcopy(parse->parse_type->cl_id, (char *)&peer->refid, 4); + else + peer->refid = htonl(PARSEHSREFID); + + parse->fd = fd232; + + parse->peer = peer; /* marks it also as busy */ + + parse->binding = init_iobinding(parse); + + if (parse->binding == (bind_t *)0) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed."); + parse_shutdown(parse->unit); /* let our cleaning staff do the work */ + return 0; /* well, ok - special initialisation broke */ + } + + /* + * configure terminal line + */ + if (TTY_GETATTR(fd232, &tm) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tm): %m", unit, fd232); + parse_shutdown(parse->unit); /* let our cleaning staff do the work */ + return 0; + } + else + { +#ifndef _PC_VDISABLE + bzero((char *)tm.c_cc, sizeof(tm.c_cc)); +#else + int disablec; + errno = 0; /* pathconf can deliver -1 without changing errno ! */ + + disablec = fpathconf(parse->fd, _PC_VDISABLE); + if (disablec == -1 && errno) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CL_UNIT(parse->unit)); + memset((char *)tm.c_cc, 0, sizeof(tm.c_cc)); /* best guess */ + } + else + if (disablec != -1) + memset((char *)tm.c_cc, disablec, sizeof(tm.c_cc)); +#endif + + tm.c_cflag = clockinfo[type].cl_cflag; + tm.c_iflag = clockinfo[type].cl_iflag; + tm.c_oflag = clockinfo[type].cl_oflag; + tm.c_lflag = clockinfo[type].cl_lflag; + + if (TTY_SETATTR(fd232, &tm) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tm): %m", unit, fd232); + parse_shutdown(parse->unit); /* let our cleaning staff do the work */ + return 0; + } + } + + /* + * 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 (tm.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)) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); + parse_shutdown(parse->unit); /* 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)) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); + parse_shutdown(parse->unit); /* let our cleaning staff do the work */ + return 0; /* well, ok - special initialisation broke */ + } + +#ifdef TCFLSH + /* + * get rid of all IO accumulated so far + */ + { +#ifndef TCIOFLUSH +#define TCIOFLUSH 2 +#endif + int flshcmd = TCIOFLUSH; + + (void) ioctl(parse->fd, TCFLSH, (caddr_t)&flshcmd); + } +#endif + + tmp_ctl.parsestatus.flags = parse->flags & PARSE_STAT_FLAGS; + + if (!PARSE_SETSTAT(parse, &tmp_ctl)) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setstat() FAILED.", unit); + parse_shutdown(parse->unit); /* let our cleaning staff do the work */ + return 0; /* well, ok - special initialisation broke */ + } + + /* + * try to do any special initializations + */ + if (parse->parse_type->cl_init) + { + if (parse->parse_type->cl_init(parse)) + { + parse_shutdown(parse->unit); /* let our cleaning staff do the work */ + return 0; /* well, ok - special initialisation broke */ + } + } + + if (!(parse->parse_type->cl_flags & PARSE_F_POLLONLY) && + (CL_PPS(parse->unit) || (parse->parse_type->cl_flags & PARSE_F_NOPOLLONLY))) + { + /* + * Insert in async io device list. + */ + parse->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ + parse->io.srcclock = (caddr_t)parse; + parse->io.datalen = 0; + parse->io.fd = parse->fd; /* replicated, but what the heck */ + if (!io_addclock(&parse->io)) + { + if (parse->parse_type->cl_flags & PARSE_F_NOPOLLONLY) + { + syslog(LOG_ERR, + "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CL_UNIT(parse->unit), parsedev); + parse_shutdown(parse->unit); /* let our cleaning staff do the work */ + return 0; + } + else + { + syslog(LOG_ERR, + "PARSE receiver #%d: parse_start: addclock %s fails (switching to polling mode)", CL_UNIT(parse->unit), parsedev); + } + } + else + { + parse->pollonly = 0; /* + * update at receipt of time_stamp - also + * supports PPS processing + */ + } + } + +#ifdef PPSPPS + if (parse->pollonly || (parse->parse_type->cl_flags & PARSE_F_PPSPPS)) + { + if (fdpps == -1) + { + fdpps = parse->fd; + if (!PARSE_DISABLE(parse)) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_disable() FAILED", CL_UNIT(parse->unit)); + parse_shutdown(parse->unit); /* let our cleaning staff do the work */ + return 0; + } + } + else + { + syslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: loopfilter PPS already active - no PPS via CIOGETEV", CL_UNIT(parse->unit)); + } + } +#endif + + /* + * wind up statistics timer + */ + parse->stattimer.peer = (struct peer *)parse; /* we know better, but what the heck */ + parse->stattimer.event_handler = cparse_statistics; + parse->stattimer.event_time = current_time + PARSESTATISTICS; + TIMER_ENQUEUE(timerqueue, &parse->stattimer); + + /* + * get out Copyright information once + */ + if (!notice) + { + syslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1993, Frank Kardel"); + notice = 1; + } + + /* + * print out configuration + */ + syslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added", + CL_UNIT(parse->unit), + parse->parse_type->cl_description, parsedev); + + syslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, %sPPS support, trust time %s, precision %d", + CL_UNIT(parse->unit), + parse->peer->stratum, (parse->pollonly || !CL_PPS(parse->unit)) ? "no " : "", + l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision); + + syslog(LOG_INFO, "PARSE receiver #%d: rootdelay %s s, phaseadjust %s s, %s IO handling", + CL_UNIT(parse->unit), + ufptoa(parse->parse_type->cl_rootdelay, 6), + lfptoa(&parse->basedelay, 8), + parse->binding->bd_description); + + syslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CL_UNIT(parse->unit), + !(*parse->parse_type->cl_format) ? "" : parse->parse_type->cl_format); + +#ifdef PPSPPS + syslog(LOG_INFO, "PARSE receiver #%d: %sCD PPS support", + CL_UNIT(parse->unit), + (fdpps == parse->fd) ? "" : "NO "); +#endif + + return 1; +} + +/*-------------------------------------------------- + * parse_poll - called by the transmit procedure + */ +static void +parse_poll(unit, peer) + int unit; + struct peer *peer; +{ + register struct parseunit *parse; + + unit = CL_UNIT(unit); + + if (unit >= MAXUNITS) + { + syslog(LOG_ERR, "PARSE receiver #%d: poll: INTERNAL: unit invalid", + unit); + return; + } + + parse = parseunits[unit]; + + if (!parse->peer) + { + syslog(LOG_ERR, "PARSE receiver #%d: poll: INTERNAL: unit unused", + unit); + return; + } + + if (peer != parse->peer) + { + syslog(LOG_ERR, + "PARSE receiver #%d: poll: INTERNAL: peer incorrect", + unit); + return; + } + + /* + * Update clock stat counters + */ + parse->polls++; + + /* + * in PPS mode we just mark that we want the next sample + * for the clock filter + */ + if (!parse->pollonly) + { + if (parse->pollneeddata) + { + /* + * bad news - didn't get a response last time + */ + parse->noresponse++; + parse->lastmissed = current_time; + parse_event(parse, CEVNT_TIMEOUT); + + syslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval", CL_UNIT(parse->unit)); + } + parse->pollneeddata = 1; + if (parse->parse_type->cl_poll) + { + parse->parse_type->cl_poll(parse); + } + return; + } + + /* + * the following code is only executed only when polling is used + */ + + PARSE_POLL(parse); +} + +/*-------------------------------------------------- + * parse_leap - called when a leap second occurs + */ + +static void +parse_leap() +{ + /* + * PARSE does encode a leap warning... we are aware but not afraid of that + * as long as we get a little help for the direction from the operator until + * PARSE encodes the LEAP correction direction. + */ +} + + +/*-------------------------------------------------- + * parse_control - set fudge factors, return statistics + */ +static void +parse_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct parseunit *parse; + parsectl_t tmpctl; + unsigned LONG type; + static char outstatus[400]; /* status output buffer */ + + type = CL_TYPE(unit); + unit = CL_UNIT(unit); + + if (out) + { + out->lencode = 0; + out->lastcode = 0; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + + if (unit >= MAXUNITS) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (max %d)", + unit, MAXUNITS-1); + return; + } + + parse = parseunits[unit]; + + if (!parse || !parse->peer) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", + unit); + return; + } + + if (in) + { + if (in->haveflags & CLK_HAVETIME1) + parse->basedelay = in->fudgetime1; + + if (in->haveflags & CLK_HAVETIME2) + { + /* not USED */ + } + + if (in->haveflags & CLK_HAVEVAL1) + { + parse->peer->stratum = (u_char)(in->fudgeval1 & 0xf); + if (parse->peer->stratum <= 1) + bcopy(parse->parse_type->cl_id, (char *)&parse->peer->refid, 4); + else + parse->peer->refid = htonl(PARSEHSREFID); + } + + /* + * NOT USED - yet + * + if (in->haveflags & CLK_HAVEVAL2) + { + } + */ + if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) + { + parse->flags = (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) | + (parse->flags & ~PARSE_STAT_FLAGS); + } + + if (in->haveflags & (CLK_HAVEVAL2|CLK_HAVETIME2|CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) + { + parsectl_t tmpctl; + tmpctl.parsestatus.flags = parse->flags & PARSE_STAT_FLAGS; + + if (!PARSE_SETSTAT(parse, &tmpctl)) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_setstat() FAILED", unit); + } + } + } + + if (out) + { + register unsigned LONG sum = 0; + register char *t; + register struct tm *tm; + register short utcoff; + register char sign; + register int i; + time_t tim; + + out->haveflags = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3; + out->clockdesc = parse->parse_type->cl_description; + + out->fudgetime1 = parse->basedelay; + + L_CLR(&out->fudgetime2); + + out->fudgeval1 = (LONG)parse->peer->stratum; + + out->fudgeval2 = 0; + + out->flags = parse->flags & PARSE_STAT_FLAGS; + + out->type = REFCLK_PARSE; + + /* + * 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 */ + out->fudgetime2 = off; + out->haveflags |= CLK_HAVETIME2; + } + } + + /* + * all this for just finding out the +-xxxx part (there are always + * new and changing fields in the standards 8-(). + * + * but we do it for the human user... + */ + tim = parse->time.parse_time.fp.l_ui - JAN_1970; + tm = gmtime(&tim); + utcoff = tm->tm_hour * 60 + tm->tm_min; + tm = localtime(&tim); + utcoff = tm->tm_hour * 60 + tm->tm_min - utcoff + 12 * 60; + utcoff += 24 * 60; + utcoff %= 24 * 60; + utcoff -= 12 * 60; + if (utcoff < 0) + { + utcoff = -utcoff; + sign = '-'; + } + else + { + sign = '+'; + } + + tim = parse->time.parse_time.fp.l_ui - JAN_1970; + strcpy(outstatus, ctime(&tim)); + t = strrchr(outstatus, '\n'); + if (!t) + { + t = outstatus + strlen(outstatus); + } + else + { + sprintf(t, " %c%02d%02d", sign, utcoff / 60, utcoff % 60); + t += strlen(t); + } + + if (!PARSE_GETTIMECODE(parse, &tmpctl)) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); + } + else + { + /* + * copy PPS flags from last read transaction (informational only) + */ + tmpctl.parsegettc.parse_state |= parse->time.parse_state & + (PARSEB_PPS|PARSEB_S_PPS); + + if (t) + { + *t = ' '; + (void) parsestate(tmpctl.parsegettc.parse_state, t+1); + } + else + { + strcat(outstatus, " "); + (void) parsestate(tmpctl.parsegettc.parse_state, outstatus + strlen(outstatus)); + } + strcat(outstatus," <"); + if (tmpctl.parsegettc.parse_count) + mkascii(outstatus+strlen(outstatus), sizeof(outstatus) - strlen(outstatus) - 1, + tmpctl.parsegettc.parse_buffer, tmpctl.parsegettc.parse_count - 1); + strcat(outstatus,">"); + parse->badformat += tmpctl.parsegettc.parse_badformat; + } + + tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; + + if (!PARSE_GETFMT(parse, &tmpctl)) + { + syslog (LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); + } + else + { + strcat(outstatus," ("); + strncat(outstatus, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count); + strcat(outstatus,")"); + } + + /* + * gather state statistics + */ + + t = outstatus + strlen(outstatus); + + for (i = 0; i <= CEVNT_MAX; i++) + { + register unsigned LONG stime; + register unsigned LONG div = current_time - parse->timestarted; + register unsigned LONG percent; + + percent = stime = PARSE_STATETIME(parse, i); + + while (((unsigned LONG)(~0) / 10000) < percent) + { + percent /= 10; + div /= 10; + } + + if (div) + percent = (percent * 10000) / div; + else + percent = 10000; + + if (stime) + { + sprintf(t, "%s%s%s: %s (%d.%02d%%)", + sum ? "; " : " [", + (parse->status == i) ? "*" : "", + clockstatus(i), + l_mktime(stime), + percent / 100, percent % 100); + sum += stime; + t += strlen(t); + } + } + + sprintf(t, "; running time: %s]", l_mktime(sum)); + + out->lencode = strlen(outstatus); + out->lastcode = outstatus; + out->timereset = parse->timestarted; + out->polls = parse->polls; + out->noresponse = parse->noresponse; + out->badformat = parse->badformat; + out->baddata = parse->baddata; + out->lastevent = parse->lastevent; + out->currentstatus = parse->status; + } +} + +/**=========================================================================== + ** processing routines + **/ + +/*-------------------------------------------------- + * event handling - note that nominal events will also be posted + */ +static void +parse_event(parse, event) + struct parseunit *parse; + int event; +{ + if (parse->status != (u_char) event) + { + parse->statetime[parse->status] += current_time - parse->lastchange; + parse->lastchange = current_time; + + parse->status = (u_char)event; + if (event != CEVNT_NOMINAL) + parse->lastevent = parse->status; + + report_event(EVNT_PEERCLOCK, parse->peer); + } +} + +/*-------------------------------------------------- + * process a PARSE time sample + */ +static void +parse_process(parse, parsetime) + struct parseunit *parse; + parsetime_t *parsetime; +{ + unsigned char leap; + struct timeval usecdisp; + l_fp off, rectime, reftime, dispersion; + + /* + * check for changes in conversion status + * (only one for each new status !) + */ + if (parse->laststatus != parsetime->parse_status) + { + char buffer[200]; + + syslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", + CL_UNIT(parse->unit), 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)) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CL_UNIT(parse->unit)); + } + else + { + syslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\"", + CL_UNIT(parse->unit), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, tmpctl.parsegettc.parse_count - 1)); + parse->badformat += tmpctl.parsegettc.parse_badformat; + } + } + + parse->laststatus = parsetime->parse_status; + } + + /* + * 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: + break; /* well, still waiting - timeout is handled at higher levels */ + + case CVT_FAIL: + parse->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)) + { + syslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CL_UNIT(parse->unit)); + } + else + { + syslog(LOG_INFO, "PARSE receiver #%d: new packet format \"%s\"", + CL_UNIT(parse->unit), 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); + + syslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", + CL_UNIT(parse->unit), 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 U/A 31 the lost synchronisation ist 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); + if (parse->nosynctime) + { + /* + * repeated POWERUP/NOSYNC state - look whether + * the message should be repeated + */ + if (current_time - parse->nosynctime > PARSENOSYNCREPEAT) + { + syslog(LOG_ERR,"PARSE receiver #%d: *STILL* NOT SYNCHRONIZED (POWERUP or no PZF signal)", + CL_UNIT(parse->unit)); + parse->nosynctime = current_time; + } + } + else + { + syslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED", + CL_UNIT(parse->unit)); + parse->nosynctime = current_time; + } + } + 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 U/A 31 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 + */ + parse->nosynctime = 0; /* current state is better than worst state */ + + if (PARSE_SYNC(parsetime->parse_state)) + { + /* + * currently completely synchronized - best possible state + */ + parse->lastsync = current_time; + /* + * log OK status + */ + parse_event(parse, CEVNT_NOMINAL); + } + else + { + /* + * we have had some problems receiving the time code + */ + parse_event(parse, CEVNT_PROP); + } + } + + if (PARSE_TIMECODE(parsetime->parse_state)) + { + l_fp offset; + + /* + * calculate time offset including systematic delays + * off = PARSE-timestamp + propagation delay - kernel time stamp + */ + offset = parse->basedelay; + + off = parsetime->parse_time.fp; + + reftime = off; + + L_ADD(&off, &offset); + rectime = off; /* this makes org time and xmt time somewhat artificial */ + + if (parse->flags & PARSE_STAT_FILTER) + { + struct timeval usecerror; + /* + * offset is already calculated + */ + usecerror.tv_sec = parsetime->parse_usecerror / 1000000; + usecerror.tv_usec = parsetime->parse_usecerror % 1000000; + + sTVTOTS(&usecerror, &off); + L_ADD(&off, &offset); + } + else + { + L_SUB(&off, &parsetime->parse_stime.fp); + } + } + + if (PARSE_PPS(parsetime->parse_state) && CL_PPS(parse->unit)) + { + l_fp offset; + + /* + * we have a PPS signal - much better than the RS232 stuff (we hope) + */ + offset = parsetime->parse_ptime.fp; + + 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)) + { + /* + * RS232 offsets within [-0.5..0.5[ - take PPS offsets + */ + + if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) + { + reftime = off = offset; + rectime = offset; + /* + * 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 + */ + off = parsetime->parse_time.fp; + + rectime = reftime = off; /* take reference time - fake rectime */ + + L_SUB(&off, &offset); /* true offset */ + } + } + /* + * take RS232 offset when PPS when out of bounds + */ + } + else + { + /* + * Well, no time code to guide us - assume on second pulse + * and pray, that we are within [-0.5..0.5[ + */ + reftime = off = offset; + rectime = offset; + /* + * 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 ... + */ + return; + } + } + + +#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS) + if (CL_PPS(parse->unit) && !parse->pollonly && PARSE_SYNC(parsetime->parse_state)) + { + /* + * only provide PPS information when clock + * is in sync + * thus PHASE and EPOCH are correct and PPS is not + * done via the CIOGETEV loopfilter mechanism + */ +#ifdef PPSPPS + if (fdpps != parse->fd) +#endif + (void) pps_sample(&off); + } +#endif /* PPS || PPSCLK || PPSPPS */ + + /* + * ready, unless the machine wants a sample + */ + if (!parse->pollonly && !parse->pollneeddata) + return; + + parse->pollneeddata = 0; + + if (PARSE_PPS(parsetime->parse_state)) + { + L_CLR(&dispersion); + } + else + { + /* + * convert usec dispersion into NTP TS world + */ + + usecdisp.tv_sec = parsetime->parse_usecdisp / 1000000; + usecdisp.tv_usec = parsetime->parse_usecdisp % 1000000; + + TVTOTS(&usecdisp, &dispersion); + } + + /* + * 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)) + { + leap = LEAP_NOTINSYNC; + } + else + { + if (PARSE_LEAP(parsetime->parse_state)) + { + leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; + } + else + { + leap = LEAP_NOWARNING; + } + } + + refclock_receive(parse->peer, &off, 0, LFPTOFP(&dispersion), &reftime, &rectime, leap); +} + +/**=========================================================================== + ** clock polling support + **/ + +struct poll_timer +{ + struct event timer; /* we'd like to poll a a higher rate than 1/64s */ +}; + +typedef struct poll_timer poll_timer_t; + +/*-------------------------------------------------- + * direct poll routine + */ +static void +poll_dpoll(parse) + struct parseunit *parse; +{ + register int rtc; + register char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; + register int ct = ((poll_info_t *)parse->parse_type->cl_data)->count; + + rtc = write(parse->fd, ps, ct); + if (rtc < 0) + { + syslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CL_UNIT(parse->unit)); + } + else + if (rtc != ct) + { + syslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CL_UNIT(parse->unit), rtc, ct); + } +} + +/*-------------------------------------------------- + * periodic poll routine + */ +static void +poll_poll(parse) + struct parseunit *parse; +{ + register poll_timer_t *pt = (poll_timer_t *)parse->localdata; + + poll_dpoll(parse); + + if (pt != (poll_timer_t *)0) + { + pt->timer.event_time = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; + TIMER_ENQUEUE(timerqueue, &pt->timer); + } +} + +/*-------------------------------------------------- + * init routine - setup timer + */ +static int +poll_init(parse) + struct parseunit *parse; +{ + register poll_timer_t *pt; + + if (((poll_info_t *)parse->parse_type->cl_data)->rate) + { + parse->localdata = (void *)malloc(sizeof(poll_timer_t)); + bzero((char *)parse->localdata, sizeof(poll_timer_t)); + + pt = (poll_timer_t *)parse->localdata; + + pt->timer.peer = (struct peer *)parse; /* well, only we know what it is */ + pt->timer.event_handler = poll_poll; + poll_poll(parse); + } + else + { + parse->localdata = (void *)0; + } + + return 0; +} + +/*-------------------------------------------------- + * end routine - clean up timer + */ +static void +poll_end(parse) + struct parseunit *parse; +{ + if (parse->localdata != (void *)0) + { + TIMER_DEQUEUE(&((poll_timer_t *)parse->localdata)->timer); + free((char *)parse->localdata); + parse->localdata = (void *)0; + } +} + +/**=========================================================================== + ** special code for special clocks + **/ + +/*-------------------------------------------------- + * trimble init routine - setup EOL and then do poll_init. + */ +static int +trimble_init(parse) + struct parseunit *parse; +{ +#ifdef STREAM + struct termios tm; +#endif +#ifdef HAVE_SYSV_TTYS + struct termio tm; +#endif + /* + * configure terminal line for trimble receiver + */ + if (TTY_GETATTR(parse->fd, &tm) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: trimble_init: tcgetattr(fd, &tm): %m", CL_UNIT(parse->unit)); + return 0; + } + else + { + tm.c_cc[VEOL] = TRIMBLESV6_EOL; + + if (TTY_SETATTR(parse->fd, &tm) == -1) + { + syslog(LOG_ERR, "PARSE receiver #%d: trimble_init: tcsetattr(fd, &tm): %m", CL_UNIT(parse->unit)); + return 0; + } + } + return poll_init(parse); +} +#endif /* defined(REFCLOCK) && defined(PARSE) */ + +/* + * History: + * + * refclock_parse.c,v + * Revision 3.41 1993/11/27 18:44:37 kardel + * can't trust GPS166 on unsync + * + * Revision 3.40 1993/11/21 18:03:36 kardel + * useless declaration deleted + * + * Revision 3.39 1993/11/21 15:30:15 kardel + * static funcitions may be declared only at outer level + * + * Revision 3.38 1993/11/15 21:26:49 kardel + * conditional define comments fixed + * + * Revision 3.37 1993/11/11 11:20:49 kardel + * declaration fixes + * + * Revision 3.36 1993/11/10 12:17:14 kardel + * #ifdef glitch + * + * Revision 3.35 1993/11/01 21:15:06 kardel + * comments updated + * + * Revision 3.34 1993/11/01 20:01:08 kardel + * parse Solaris support (initial version) + * + * Revision 3.33 1993/10/30 09:44:58 kardel + * conditional compilation flag cleanup + * + * Revision 3.32 1993/10/22 14:28:43 kardel + * Oct. 22nd 1993 reconcilation + * + * Revision 3.31 1993/10/10 21:19:10 kardel + * compilation cleanup - (minimal porting tests) + * + * Revision 3.30 1993/10/09 21:44:35 kardel + * syslog strings fixed + * + * Revision 3.29 1993/10/09 14:40:15 kardel + * default precision setting fixed + * + * Revision 3.28 1993/10/08 14:48:22 kardel + * Changed offset determination logic: + * Take the PPS offset if it is available and the time + * code offset is within [-0.5..0.5[, otherwise stick + * to the time code offset + * + * Revision 3.27 1993/10/08 00:53:17 kardel + * announce also simulated PPS via CIOGETEV in ntpq cl + * + * Revision 3.26 1993/10/07 23:29:35 kardel + * trimble fixes + * + * Revision 3.25 1993/10/06 21:13:35 kardel + * test reversed (CIOGETEV support) + * + * Revision 3.24 1993/10/03 20:18:26 kardel + * Well, values > 999999 in the usec field from uniqtime() timestamps + * can prove harmful. + * + * Revision 3.23 1993/10/03 19:49:54 kardel + * buftvtots where failing on uninitialized time stamps + * + * Revision 3.22 1993/10/03 19:11:09 kardel + * restructured I/O handling + * + * Revision 3.21 1993/09/29 11:30:18 kardel + * special init for trimble to set EOL + * + * Revision 3.20 1993/09/27 22:46:28 kardel + * preserve module stack if I_PUSH parse fails + * + * Revision 3.19 1993/09/27 21:10:11 kardel + * wrong structure member + * + * Revision 3.18 1993/09/27 13:05:06 kardel + * Trimble is true polling only + * + * Revision 3.17 1993/09/27 12:47:10 kardel + * poll string support generalized + * + * Revision 3.16 1993/09/26 23:40:56 kardel + * new parse driver logic + * + * Revision 3.15 1993/09/24 15:00:51 kardel + * Sep 23rd distribution... + * + * Revision 3.14 1993/09/22 18:21:15 kardel + * support ppsclock streams module (-DSTREAM -DPPSPPS -DPARSEPPS -UPARSESTREAM) + * + * Revision 3.13 1993/09/05 15:38:33 kardel + * not every cpp understands #error... + * + * Revision 3.12 1993/09/02 20:04:19 kardel + * TTY cleanup + * + * Revision 3.11 1993/09/01 21:48:47 kardel + * conditional cleanup + * + * Revision 3.10 1993/09/01 11:32:45 kardel + * assuming HAVE_POSIX_TTYS when STREAM defined + * + * Revision 3.9 1993/08/31 22:31:46 kardel + * SINIX-M SysVR4 integration + * + * Revision 3.8 1993/08/27 00:29:50 kardel + * compilation cleanup + * + * Revision 3.7 1993/08/24 22:27:30 kardel + * cleaned up AUTOCONF DCF77 mess 8-) - wasn't too bad + * + * Revision 3.6 1993/08/24 21:36:23 kardel + * casting and ifdefs + * + * Revision 3.5 1993/07/09 23:36:59 kardel + * HAVE_POSIX_TTYS used to produce errors 8-( - BSD driver support still lacking + * + * Revision 3.4 1993/07/09 12:42:29 kardel + * RAW DCF now officially released + * + * Revision 3.3 1993/07/09 11:50:37 kardel + * running GPS also on 960 to be able to switch GPS/DCF77 + * + * Revision 3.2 1993/07/09 11:37:34 kardel + * Initial restructured version + GPS support + * + * Revision 3.1 1993/07/06 10:01:07 kardel + * DCF77 driver goes generic... + * + */ diff --git a/contrib/xntpd/xntpd/refclock_pst.c b/contrib/xntpd/xntpd/refclock_pst.c new file mode 100644 index 0000000000..e72ac8bf08 --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_pst.c @@ -0,0 +1,1800 @@ +/* + * refclock_pst - driver for the PSTI 1010/1020 WWV clock + */ +#if defined(REFCLOCK) && (defined(PST) || defined(PSTCLK) || defined(PSTPPS)) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(STREAM) +#include +#include +#if defined(PSTCLK) +#include +#endif /* PSTCLK */ +#endif /* STREAM */ + +#if defined (PSTPPS) +#include +#endif /* PSTPPS */ + +#include "ntp_stdlib.h" + +/* + * This driver is in good measure due to David Schachter, who wrote + * the firmware for the PST clock. Not that he is to blame for + * any of this, but he kindly loaned me a clock to allow me to + * debug this. + * + * Postscript: + * + * The strategy in here is actually pretty good, especially if + * you try to support the clock on something lacking low order + * clock bits like a Sun, since all the business which is done + * before taking a time stamp tends to randomize the taking of + * the stamp with respect to the timer interrupt. It is, however, + * a big cpu hog, and in some ways is a bit of a waste since, as + * it turns out, the PST clock can give you no better than a + * millisecond precision and it doesn't pay to try to push it + * harder. + * + * In any event, like the first waffle off the iron, this one + * should probably be tossed. My current preference would be + * to retain the 12-a-minute schedule, but to use the QU command + * instead of the QD and QT, and to only send a QM command with + * the 12th poll of the minute to get the minutes-since-sync + * and the station. Need to get a clock which supports QU, + * however. + * + * End postscript + * + * This driver polls the clock using the QM, QT and QD commands. + * Ntpd actually uses QU instead of the last two, something I would + * like to have done as well since it gives you the day and time + * atom, but the firmware in the clock I had (X04.01.999) didn't know + * about this command. + * + * The QM command produces output like: + * + * O6B532352823C00270322 + * b c deeee + * + * We use (b) for the time zone, (c) to see whether time is available, + * (d) to tell whether we are sync'd to WWV or WWVH, and (e) to determine + * the number of minutes since the last signal was received. We + * don't trust the clock for more than about 20 minutes on its own. + * After this, we keep taking the time but mark the clock unsynchronized. + * + * The QT command returns something that looks like this: + * + * 18:57:50.263D + * + * Note that this particular sample is in 24 hour format, local time + * (daylight savings time even). We allow just about anything for + * this (sigh) since this leaves the clock owner free to set the + * display mode in whatever way he finds convenient for setting + * his watch. + * + * The QD command returns: + * + * 89/10/19/292 + * + * We actually only use the day-of-the-year here. We use the year + * only to determine whether the PST clock thinks the current year + * has 365 or 366 days in it. + * + * At the current writing, this code expects to be using a BSD-style + * terminal driver. It will compile code which uses the CLKLDISC + * line discipline if it thinks this is available, but use cooked + * mode otherwise. The cooked mode stuff may not have been tested. + */ + +/* + * Definitions + */ +#define MAXUNITS 4 /* maximum number of PST units permitted */ +#define PSTDEV "/dev/pst%d" /* device we open. %d is unit number */ +#define NPSTSAMPS 12 /* take 12 PST samples per minute */ + +/* + * Other constant stuff + */ +#define PSTPRECISION (-9) /* what the heck */ +#define WWVREFID "WWV\0" +#define WWVHREFID "WWVH" +#define PSTHSREFID 0x7f7f030a /* 127.127.3.10 refid for hi strata */ + +/* + * Parameters for the clock + */ +#define SPEED232 B9600 +#define PSTMAGIC2 ('\r' | 0x80) /* HP-UX uses this also now */ +#ifdef CLKLDISC +#define PSTMAGIC1 '\r' +#define PSTEOL '\r' +#else +#define PSTEOL '\n' +#endif + +/* + * Description of clock. We fill in whether it is a 1010 or 1020, + * and the firmware revision, using the QV command. + */ +#define PSTDESCLEN 64 +#define PSTDESCRIPTION "%s %s (%s) WWV/H Receiver" +#define PSTDEFDESC "PSTI/Traconex 10?0 (V??.??) WWV/H Receiver" + +/* + * Length of the PST time code. This must be the length of the output + * of the QM command, plus QT, plus QD, plus two spaces. We make it + * big just on principle. + */ +#define PSTCODELEN (128) + +/* + * Minimum and maximum lengths + */ +#define PSTMINQVLEN (16) +#define PSTMAXQVLEN (24) + +#define PSTMINQMLEN (19) +#define PSTMAXQMLEN (32) + +#define PSTMINQDLEN (12) +#define PSTMAXQDLEN (12) + +#define PSTMINQTLEN (14) +#define PSTMAXQTLEN (14) + +/* + * It turns out that the QT command does *not* adjust for transmission + * delays. Since the QT command returns 15 characters at 9600 baud, + * the adjustment for this should be 15.6 ms. We'll default to this, + * but don't let this stop you from fiddling with the fudge factors + * to make things come out right + */ +#define PSTQTFUDGE 0x04000000 /* about 15.6 ms */ + +/* + * Default propagation delays. About right for Toronto + */ +#define DEFWWVPROP 0x01eb851f /* about 7.5 ms */ +#define DEFWWVHPROP 0x06c8b439 /* about 26.5 ms */ + +/* + * Maximum propagation delay we believe. 125 ms as an l_fp fraction + */ +#define PSTMAXPROP 0x20000000 + +/* + * Default minutes since an update. + */ +#define DEFMAXFREERUN (20) + +/* + * Hack to avoid excercising the multiplier. I have no pride. + */ +#define MULBY10(x) (((x)<<3) + ((x)<<1)) + +/* + * PST unit control structure. + */ +struct pstunit { + struct peer *peer; /* associated peer structure */ + struct event psttimer; /* timeout timer structure */ + struct refclockio pstio; /* given to the I/O handler */ + l_fp rectimes[NPSTSAMPS]; /* times we received this stuff */ + l_fp reftimes[NPSTSAMPS]; /* times of codes received */ + l_fp lastrec; /* last receive time */ + l_fp lastref; /* last reference time */ + char description[PSTDESCLEN]; /* description of clock */ + char lastcode[PSTCODELEN]; /* last code we received */ + u_char lencode; /* length of the last code */ + u_char nextsample; /* the next offset expected */ + u_char unit; /* unit number for this guy */ + u_char state; /* what we're waiting for */ + s_char station; /* WWV or WWVH? */ + u_char flags; /* flag byte */ + u_char status; /* clock status */ + u_char lastevent; /* last clock event */ + u_char timezone; /* hour offset to time zone */ + u_char errors; /* number of errors detected */ + u_char year; /* year reported by clock */ + u_char month; /* month, from clock */ + u_char monthday; /* day, from clock */ + u_char hour; /* hour of day */ + u_char minute; /* minute of day */ + u_char second; /* second of day */ + u_char leap; /* leap indicators */ + s_char tzoffset; /* time zone offset */ + u_char reason; /* reason for failure */ + u_short millisecond; /* millisecond of day */ + u_short yearday; /* day of the year */ + u_short timesincesync; /* time since radio got sample */ + U_LONG yearstart; /* NTP time at year start */ + U_LONG lastupdate; /* last time data received */ + U_LONG polls; /* number of polls */ + U_LONG noreply; /* number of time outs */ + U_LONG badformat; /* number of bad format responses */ + U_LONG baddata; /* number of invalid time codes */ + U_LONG timestarted; /* time we started this */ +}; + +/* + * States we might be in + */ +#define STATE_IDLE 0 /* not doing anything in particular */ +#define STATE_QV 1 /* trying to get version */ +#define STATE_QM 2 /* sent QM */ +#define STATE_QD 3 /* sent QD */ +#define STATE_QT 4 /* send QT */ + +/* + * Status flags + */ +#define PST_LEAPYEAR 0x1 /* pst clock thinks it is a leap year */ +#define PST_SIGFAULT 0x2 /* signal fault */ +#define PST_HARDERR 0x4 /* hardware error */ +#define PST_NOTIME 0x8 /* no time available */ +#define PST_WWVH 0x10 /* synchronized to WWVH */ +#define PST_DOQV 0x20 /* get version, reinit delays */ +#define PST_DORESET 0x40 /* reset the clock */ + +/* + * The PST often encodes stuff by adding an ASCII '0' to it. The + * largest range of values encoded this way is 0 through 31, or '0' + * through 'O'. These macroes manipulate these values. + */ +#define ISVALIDPST(c) ((c) >= '0' && (c) <= 'O') +#define PSTTOBIN(c) ((int)(c) - '0') +#define BINTOPST(c) ((char)((c) + '0')) + +/* + * Status bits. Look at the QM command + */ +#define SIGFAULT 0x1 +#define HARDFAULT 0x2 +#define OUTOFSPEC 0x4 +#define TIMEAVAILABLE 0x8 + +/* + * Module reason codes + */ +#define QVREASON 20 +#define QMREASON 40 +#define QDREASON 60 +#define QTREASON 80 + +/* + * Station i.d. characters in QM output + */ +#define WWV_CHAR 'C' +#define WWVH_CHAR 'H' + +/* + * We allow a few errors, but if we get more than 12 seconds behind + * the schedule we start from sample 0 again. 4 seconds is the minimum + * time between time out routine executions. + */ +#define PSTMAXDELAY 12 +#define PSTMINTIMEOUT 4 + +/* + * The PST polling schedule. We poll 12 times per 64 seconds (far too + * many, but what the heck). The polls are scheduled to finish in this + * time with the assumption that the timer is good for no better than + * 4 second resolution. If we get too far behind (due to bad samples + * or no responses) we start over. + */ +struct pstsched { + u_short nextinterval; + u_short tooold; +}; + +static struct pstsched psttab[NPSTSAMPS] = { + { 4, PSTMAXDELAY+1 }, + { 4, PSTMAXDELAY+1+4 }, + { 8, PSTMAXDELAY+1+4+4 }, + { 4, PSTMAXDELAY+1+4+4+8 }, + { 8, PSTMAXDELAY+1+4+4+8+4 }, + { 4, PSTMAXDELAY+1+4+4+8+4+8 }, + { 4, PSTMAXDELAY+1+4+4+8+4+8+4 }, + { 8, PSTMAXDELAY+1+4+4+8+4+8+4+4 }, + { 4, PSTMAXDELAY+1+4+4+8+4+8+4+4+8 }, + { 8, PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4 }, + { 4, PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4+8 }, + { 4, PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4+8+4 } +}; + + +/* + * Data space for the unit structures. Note that we allocate these on + * the fly, but never give them back. + */ +static struct pstunit *pstunits[MAXUNITS]; +static u_char unitinuse[MAXUNITS]; + +/* + * Structure to keep processed propagation data in. + */ +struct pst_propagate { + U_LONG remainder; /* left over submillisecond remainder */ + char msbchar; /* character for high order bits */ + char lsbchar; /* character for low order bits */ +}; + + +/* + * Keep the fudge factors separately so they can be set even + * when no clock is configured. + */ +static l_fp wwv_prop_delay[MAXUNITS]; +static l_fp wwvh_prop_delay[MAXUNITS]; +static struct pst_propagate wwv_prop_data[MAXUNITS]; +static struct pst_propagate wwvh_prop_data[MAXUNITS]; +static u_char stratumtouse[MAXUNITS]; +static u_char sloppyclock[MAXUNITS]; +static u_short freerun[MAXUNITS]; + +/* + * Pointer to the default description + */ +static char *pstdefdesc = PSTDEFDESC; + +/* + * macro for writing to the clock, printing an error if we fail + */ +#define pst_send(pst, str, len) \ + if (write((pst)->pstio.fd, (str), (len)) < 0) \ + pst_write_error((pst)) + +/* + * macro for resetting the clock structure to zero + */ +#define pst_reset(pst) \ + do { \ + pst->nextsample = 0; \ + pst->station = 0; \ + pst->leap = 0; \ + } while (0) + +/* + * macro for event reporting + */ +#define pst_event(pst, evnt_code) \ + do { \ + if ((pst)->status != (u_char)(evnt_code)) \ + pst_do_event((pst), (evnt_code)); \ + } while (0) + +/* + * Imported from the timer module + */ +extern U_LONG current_time; +extern struct event timerqueue[]; + +/* + * Imported from ntp_loopfilter module + */ +extern int fdpps; /* pps file descriptor */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * Function prototypes + */ +static void pst_init P((void)); +static int pst_start P((u_int, struct peer *)); +static void pst_shutdown P((int)); +static void pst_receive P((struct recvbuf *)); +static void pst_process P((struct pstunit *)); +static void pst_control P((u_int, struct refclockstat *, struct refclockstat *)); +static void pst_buginfo P((int, struct refclockbug *)); +static void pst_write_error P((struct pstunit *)); +static void pst_timeout P((struct peer *)); +static int pst_QV_process P((struct pstunit *, struct recvbuf *)); +static int pst_QM_process P((struct pstunit *, struct recvbuf *)); +static int pst_QD_process P((struct pstunit *, struct recvbuf *)); +static int pst_QT_process P((struct pstunit *, struct recvbuf *, l_fp *, l_fp *)); +static void pst_do_event P((struct pstunit *, int)); +static void pst_compute_delay P((U_LONG, struct pst_propagate *)); + +/* + * Transfer vector + */ +struct refclock refclock_pst = { + pst_start, pst_shutdown, noentry, + pst_control, pst_init, pst_buginfo, NOFLAGS +}; + +/* + * pst_init - initialize internal PST driver data + */ +static void +pst_init() +{ + register int i; + + /* + * Just zero the data arrays + */ + bzero((char *)pstunits, sizeof pstunits); + bzero((char *)unitinuse, sizeof unitinuse); + + /* + * Initialize fudge factors to default. + */ + for (i = 0; i < MAXUNITS; i++) { + wwv_prop_delay[i].l_ui = 0; + wwv_prop_delay[i].l_uf = DEFWWVPROP; + pst_compute_delay(DEFWWVPROP, &wwv_prop_data[i]); + wwvh_prop_delay[i].l_ui = 0; + wwvh_prop_delay[i].l_uf = DEFWWVHPROP; + pst_compute_delay(DEFWWVHPROP, &wwvh_prop_data[i]); + stratumtouse[i] = 0; + sloppyclock[i] = 0; + freerun[i] = DEFMAXFREERUN; + } +} + + +/* + * pst_start - open the PST device and initialize data for processing + */ +static int +pst_start(unit, peer) + u_int unit; + struct peer *peer; +{ + register struct pstunit *pst; + register int i; + int fd232; + char pstdev[20]; + + /* + * Check configuration info + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "pst_start: unit %d invalid", unit); + return 0; + } + if (unitinuse[unit]) { + syslog(LOG_ERR, "pst_start: unit %d in use", unit); + return 0; + } + + /* + * Open serial port + */ + (void) sprintf(pstdev, PSTDEV, unit); + fd232 = open(pstdev, O_RDWR, 0777); + if (fd232 == -1) { + syslog(LOG_ERR, "pst_start: open of %s: %m", pstdev); + return 0; + } + +#if defined(HAVE_SYSV_TTYS) + /* + * System V serial line parameters (termio interface) + * + */ + { struct termio ttyb; + if (ioctl(fd232, TCGETA, &ttyb) < 0) { + syslog(LOG_ERR, + "pst_start: ioctl(%s, TCGETA): %m", pstdev); + 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) { + syslog(LOG_ERR, + "pst_start: ioctl(%s, TCSETA): %m", pstdev); + goto screwed; + } + } +#endif /* HAVE_SYSV_TTYS */ +#if defined(STREAM) + /* + * POSIX/STREAMS serial line parameters (termios interface) + * + * The PSTCLK option provides timestamping at the driver level. + * It requires the tty_clk streams module. + * + * The PSTPPS option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the ppsclock streams module and SunOS 4.1.1 or + * later. + */ + { struct termios ttyb, *ttyp; + + ttyp = &ttyb; + if (tcgetattr(fd232, ttyp) < 0) { + syslog(LOG_ERR, + "pst_start: tcgetattr(%s): %m", pstdev); + 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) { + syslog(LOG_ERR, + "pst_start: tcsetattr(%s): %m", pstdev); + goto screwed; + } + if (tcflush(fd232, TCIOFLUSH) < 0) { + syslog(LOG_ERR, + "pst_start: tcflush(%s): %m", pstdev); + goto screwed; + } +#if defined(PSTCLK) + if (ioctl(fd232, I_PUSH, "clk") < 0) + syslog(LOG_ERR, + "pst_start: ioctl(%s, I_PUSH, clk): %m", pstdev); + if (ioctl(fd232, CLK_SETSTR, "\n") < 0) + syslog(LOG_ERR, + "pst_start: ioctl(%s, CLK_SETSTR): %m", pstdev); +#endif /* PSTCLK */ +#if defined(PSTPPS) + if (ioctl(fd232, I_PUSH, "ppsclock") < 0) + syslog(LOG_ERR, + "pst_start: ioctl(%s, I_PUSH, ppsclock): %m", pstdev); + else + fdpps = fd232; +#endif /* PSTPPS */ + } +#endif /* STREAM */ +#if defined(HAVE_BSD_TTYS) + /* + * 4.3bsd serial line parameters (sgttyb interface) + * + * The PSTCLK option provides timestamping at the driver level. + * It requires the tty_clk line discipline and 4.3bsd or later. + */ + { struct sgttyb ttyb; +#if defined(PSTCLK) + int ldisc = CLKLDISC; +#endif /* PSTCLK */ + + if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { + syslog(LOG_ERR, + "pst_start: ioctl(%s, TIOCGETP): %m", pstdev); + goto screwed; + } + ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; +#if defined(PSTCLK) + 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 /* PSTCLK */ + if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { + syslog(LOG_ERR, + "pst_start: ioctl(%s, TIOCSETP): %m", pstdev); + goto screwed; + } +#if defined(PSTCLK) + if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { + syslog(LOG_ERR, + "pst_start: ioctl(%s, TIOCSETD): %m",pstdev); + goto screwed; + } +#endif /* PSTCLK */ + } +#endif /* HAVE_BSD_TTYS */ + + /* + * Allocate unit structure + */ + if (pstunits[unit] != 0) { + pst = pstunits[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && pstunits[i] != 0) + break; + } + if (i < MAXUNITS) { + /* + * Reclaim this one + */ + pst = pstunits[i]; + pstunits[i] = 0; + } else { + pst = (struct pstunit *)emalloc(sizeof(struct pstunit)); + } + } + bzero((char *)pst, sizeof(struct pstunit)); + pstunits[unit] = pst; + + /* + * Set up the structure + */ + pst->peer = peer; + pst->unit = (u_char)unit; + pst->state = STATE_IDLE; + pst->flags |= PST_DOQV; + pst->timestarted = current_time; + (void) strcpy(pst->description, pstdefdesc); + + pst->psttimer.peer = (struct peer *)pst; + pst->psttimer.event_handler = pst_timeout; + + pst->pstio.clock_recv = pst_receive; + pst->pstio.srcclock = (caddr_t)pst; + pst->pstio.datalen = 0; + pst->pstio.fd = fd232; + if (!io_addclock(&pst->pstio)) { + goto screwed; + } + + /* + * All done. Initialize a few random peer variables, then + * start the timer and return success. + */ + peer->precision = PSTPRECISION; + peer->rootdelay = 0; + peer->rootdispersion = 0; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(WWVREFID, (char *)&peer->refid, 4); + else + peer->refid = htonl(PSTHSREFID); + pst->psttimer.event_time = current_time + PSTMINTIMEOUT; + TIMER_ENQUEUE(timerqueue, &pst->psttimer); + unitinuse[unit] = 1; + return 1; + + /* + * Something broke; abandon ship. + */ +screwed: + (void) close(fd232); + return (0); +} + +/* + * pst_shutdown - shut down a PST clock + */ +static void +pst_shutdown(unit) + int unit; +{ + register struct pstunit *pst; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "pst_shutdown: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "pst_shutdown: unit %d not in use", unit); + return; + } + + /* + * Tell the I/O module to turn us off, and dequeue timer + * if any. We're history. + */ + pst = pstunits[unit]; + TIMER_DEQUEUE(&pst->psttimer); + io_closeclock(&pst->pstio); + unitinuse[unit] = 0; +} + + +/* + * pst_write_error - complain about writes to the clock + */ +static void +pst_write_error(pst) + struct pstunit *pst; +{ + /* + * This will fill syslog is something is really wrong. Should + * throttle it back. + */ + syslog(LOG_ERR, "pst_write_error: unit %d: %m", pst->unit); +} + + +/* + * pst_timeout - process a timeout event + */ +static void +pst_timeout(fakepeer) + struct peer *fakepeer; +{ + register struct pstunit *pst; + U_LONG poll; + + /* + * The timeout routine always initiates a chain of + * query-responses from the clock, by sending either + * a QV command (if we need to (re)set the propagation + * delays into the clock), a QM command or an SRY + * command (after a leap second). The pst_receive() + * routine should complete the set of queries on its own + * LONG before the next time out is due, so if we see any + * state in here other than idle it means the clock hasn't + * responded. + */ + pst = (struct pstunit *)fakepeer; + switch(pst->state) { + case STATE_IDLE: + poll = (U_LONG)psttab[pst->nextsample].nextinterval; + break; /* all is well */ + + case STATE_QV: + pst->flags |= PST_DOQV; /* no response, do QV again */ + /*FALLSTHROUGH*/ + + case STATE_QM: + case STATE_QD: + case STATE_QT: + pst->noreply++; /* mark the lack of response */ + poll = PSTMINTIMEOUT; /* minimum time poll */ + break; + + default: + syslog(LOG_ERR, "pst_timeout: unit %d invalid state %d", + pst->unit, pst->state); + poll = PSTMINTIMEOUT; /* minimum time poll */ + break; + } + + if (pst->flags & PST_DORESET) { + /* + * Do a reset. At the next interrupt, start with + * a QV command to set in the delays. + */ + pst->flags &= ~PST_DORESET; + pst->flags |= PST_DOQV; + pst->state = STATE_IDLE; + pst_send(pst, "\003SRY", 4); + } else if (pst->flags & PST_DOQV) { + pst->polls++; + pst->flags &= ~PST_DOQV; + pst->state = STATE_QV; + pst_send(pst, "\003QV", 3); + } else { + pst->polls++; + pst->state = STATE_QM; + pst_send(pst, "\003QM", 3); + } + + pst->psttimer.event_time += poll; + TIMER_ENQUEUE(timerqueue, &pst->psttimer); +} + + +/* + * pst_QV_process - decode the results of a QV poll and insert fudge + * factors into the clock. + */ +static int +pst_QV_process(pst, rbufp) + register struct pstunit *pst; + struct recvbuf *rbufp; +{ + register char *cp; + register char *bp; + register int len; + char *model; + char *company; + char buf[20]; + static char wwvdelay[6] = { 'S', 'C', '\0', 'S', 'E', '\0' }; + static char wwvhdelay[6] = { 'S', 'H', '\0', 'S', 'G', '\0' }; + + /* + * The output of the QV command looks like: + * + * PSTI ITS V04.01.000\r + * + * or + * + * TRAC ITS V04.01.000\r + * + * or + * + * TRACONEX TS V05.02.001\r + * + * The minimum length of the string is about 16 characters. + * The maximum length is sort of unbounded, but we get suspicious + * if it is more than 34. + */ + len = rbufp->recv_length; + if (len > PSTMAXQVLEN + 10) + len = PSTMAXQVLEN + 10; + + bp = rbufp->recv_buffer; + cp = pst->lastcode; + while (len-- > 0) { + *cp = (*bp++) & 0x7f; /* strip parity */ + if (!isprint(*cp)) + break; + cp++; + } + pst->lencode = (u_char)(cp - pst->lastcode); + + /* + * Okay, got all printable characters from the string + * copied. We expect to have been terminated by the + * EOL character. If not, forget it. If the length + * is insane, forget it. + */ + + if (*cp != PSTEOL + || pst->lencode < PSTMINQVLEN || pst->lencode > PSTMAXQVLEN) { + pst->reason = QVREASON + 1; + return 0; + } + + /* + * Now, format check what we can. Dump it at the least + * sign of trouble. + */ + cp = pst->lastcode; + model = NULL; + if (*cp++ != 'P' || *cp++ != 'S' || *cp++ != 'T' + || *cp++ != 'I' || *cp++ != ' ') { + cp = pst->lastcode; + if (*cp++ != 'T' || *cp++ != 'R' || *cp++ != 'A' + || *cp++ != 'C' || *cp++ != ' ') { + cp = pst->lastcode; + if (*cp++ != 'T' || *cp++ != 'R' || *cp++ != 'A' + || *cp++ != 'C' || *cp++ != 'O' || *cp++ != 'N' + || *cp++ != 'E' || *cp++ != 'X' || *cp != ' ') { + pst->reason = QVREASON + 2; + return 0; + } + company = "Traconex"; + model = "1030"; + } + company = "Traconex"; + } else { + company = "Precision Standard Time"; + } + + if (*cp == 'M') + model = "1010"; + else if (*cp == 'I') + model = "1020"; + else if (model == NULL) { + pst->reason = QVREASON + 3; + return 0; + } + cp++; + + if (*cp++ != 'T' || *cp++ != 'S' || *cp++ != ' ') { + pst->reason = QVREASON + 4; + return 0; + } + if (*cp != 'X' && *cp != 'V') { + pst->reason = QVREASON + 5; + return 0; + } + + /* + * Next is the version. Copy it into the buffer. + */ + bp = buf; + *bp++ = *cp++; + while (isdigit(*cp) || *cp == '.') + *bp++ = *cp++; + *bp++ = '\0'; + + /* + * Final bit of fluff is to set the description + */ + (void) sprintf(pst->description, PSTDESCRIPTION, company, model, buf); + + /* + * Now the serious stuff. Since we are now sure that the + * clock is there, we can be fairly sure that the delay + * setting commands will take. Send them. + */ + wwvdelay[2] = wwv_prop_data[pst->unit].msbchar; + wwvdelay[5] = wwv_prop_data[pst->unit].lsbchar; + pst_send(pst, wwvdelay, 6); + + /* + * Same thing for WWVH + */ + wwvhdelay[2] = wwvh_prop_data[pst->unit].msbchar; + wwvhdelay[5] = wwvh_prop_data[pst->unit].lsbchar; + pst_send(pst, wwvhdelay, 6); + + /* + * Should be okay. Return positive response. + */ + return 1; +} + + +/* + * pst_QM_process - process the output of a QM command + */ +static int +pst_QM_process(pst, rbufp) + register struct pstunit *pst; + struct recvbuf *rbufp; +{ + register char *cp; + register char *bp; + register int n; + + /* + * The output of the QM command looks like: + * + * O6B532352823C00270322 + * + * The minimum length of the string is 19 characters. + * The maximum length is sort of unbounded, but we get suspicious + * if it is more than 42. + */ + n = rbufp->recv_length; + if (n > PSTMAXQMLEN + 10) + n = PSTMAXQMLEN + 10; + + bp = rbufp->recv_buffer; + cp = pst->lastcode; + while (n-- > 0) { + *cp = (*bp++) & 0x7f; /* strip parity */ + if (!isprint(*cp)) + break; + cp++; + } + pst->lencode = (u_char)(cp - pst->lastcode); + + /* + * Okay, got all printable characters from the string + * copied. We expect to have been terminated by the + * EOL character. If not, forget it. If the length + * is insane, forget it. + */ + if (*cp != PSTEOL + || pst->lencode < PSTMINQMLEN || pst->lencode > PSTMAXQMLEN) { + pst->reason = QMREASON + 1; + return 0; + } + + /* + * Ensure that the first PSTMINQMLEN characters are valid with + * respect to the way the clock encodes binary data. + */ + cp = pst->lastcode; + n = pst->lencode; + while (n-- > 0) { + if (!ISVALIDPST(*cp)) { + pst->reason = QMREASON + 2; + return 0; + } + cp++; + } + + /* + * Collect information we are interested in. + */ + cp = pst->lastcode; + pst->timezone = PSTTOBIN(cp[3]); + if (pst->timezone > 23) { + pst->reason = QMREASON + 3; + return 0; + } + + pst->flags &= + ~(PST_LEAPYEAR|PST_SIGFAULT|PST_HARDERR|PST_NOTIME|PST_WWVH); + n = PSTTOBIN(cp[4]); + if (n > 15) { + pst->reason = QMREASON + 4; + return 0; + } + if (((n + 2) & 0x3) == 0) + pst->flags |= PST_LEAPYEAR; + + n = PSTTOBIN(cp[9]); + if (n > 15) { + pst->reason = QMREASON + 5; + return 0; + } + if (n & SIGFAULT) + pst->flags |= PST_SIGFAULT; + if (n & HARDFAULT) + pst->flags |= PST_HARDERR; + if (!(n & TIMEAVAILABLE)) + pst->flags |= PST_NOTIME; + + if (cp[12] == 'H') { + pst->flags |= PST_WWVH; + } else if (cp[12] == 'C') { + pst->flags &= ~PST_WWVH; + } else { + pst->reason = QMREASON + 6; + return 0; + } + + if (wwv_prop_data[pst->unit].msbchar != cp[5] || + wwv_prop_data[pst->unit].lsbchar != cp[6] || + wwvh_prop_data[pst->unit].msbchar != cp[7] || + wwvh_prop_data[pst->unit].lsbchar != cp[8]) + pst->flags |= PST_DOQV; + + bp = cp + 13; + pst->timesincesync = 0; + while (bp < (cp + 17)) { + if (!isdigit(*bp)) { + pst->reason = QMREASON + 6; + return 0; + } + pst->timesincesync = MULBY10(pst->timesincesync) + + PSTTOBIN(*bp); + bp++; + } + + /* + * That's about all we can do. Return success. + */ + return 1; +} + + +/* + * pst_QD_process - process the output of a QD command + */ +static int +pst_QD_process(pst, rbufp) + register struct pstunit *pst; + struct recvbuf *rbufp; +{ + register char *cp; + register char *bp; + register int n; + char *cpstart; + int len; + + /* + * The output of the QM command looks like: + * + * 88/05/17/138\r + * + * The minimum length of the string is 12 characters as is + * the maximum length. + */ + n = rbufp->recv_length; + if (n > PSTMAXQDLEN + 10) + n = PSTMAXQDLEN + 10; + + bp = rbufp->recv_buffer; + cp = &pst->lastcode[pst->lencode]; + *cp++ = ' '; + cpstart = cp; + while (n-- > 0) { + *cp = (*bp++) & 0x7f; /* strip parity */ + if (!isprint(*cp)) + break; + cp++; + } + len = (cp - cpstart); + pst->lencode = (u_char)(cp - pst->lastcode); + + /* + * Okay, got all printable characters from the string + * copied. We expect to have been terminated by the + * EOL character. If not, forget it. If the length + * is insane, forget it. + */ + if (*cp != PSTEOL || + len < PSTMINQDLEN || len > PSTMAXQDLEN) { + pst->reason = QDREASON + 1; + return 0; + } + + /* + * Ensure that the characters are formatted validly. They + * are either digits or '/'s. + */ + cp = cpstart; + if (!isdigit(cp[0]) || !isdigit(cp[1]) || cp[2] != '/' || + !isdigit(cp[3]) || !isdigit(cp[4]) || cp[5] != '/' || + !isdigit(cp[6]) || !isdigit(cp[7]) || cp[8] != '/' || + !isdigit(cp[9]) || !isdigit(cp[10]) || !isdigit(cp[11])) { + pst->reason = QDREASON + 2; + return 0; + } + + /* + * Decode into year, month, day and year day + */ + pst->year = MULBY10(PSTTOBIN(cp[0])) + PSTTOBIN(cp[1]); + pst->month = MULBY10(PSTTOBIN(cp[3])) + PSTTOBIN(cp[4]); + pst->monthday = MULBY10(PSTTOBIN(cp[6])) + PSTTOBIN(cp[7]); + pst->yearday = MULBY10(PSTTOBIN(cp[9])) + PSTTOBIN(cp[10]); + pst->yearday = MULBY10(pst->yearday) + PSTTOBIN(cp[11]); + + /* + * Format check these. + */ + if (pst->month > 12 || pst->monthday > 31 || pst->yearday > 366) { + pst->reason = QDREASON + 3; + return 0; + } + if (!(pst->flags & PST_LEAPYEAR) && pst->yearday > 365) { + pst->reason = QDREASON + 4; + return 0; + } + + /* + * Done all we can. + */ + return 1; +} + + +/* + * pst_QT_process - process the output of a QT command, return the times + */ +static int +pst_QT_process(pst, rbufp, tsclk, tsrec) + register struct pstunit *pst; + struct recvbuf *rbufp; + l_fp *tsclk; + l_fp *tsrec; +{ + register char *cp; + register char *bp; + register int n; + char *cpstart; + int len; + int hour; + int minute; + int second; + int msec; + int tzoff; + + /* + * The output of the QT command looks like: + * + * A09:57:50.263D + * + * The minimum length of the string is 14 characters as is + * the maximum length. + */ + n = rbufp->recv_length; + if (n > PSTMAXQTLEN + 10) + n = PSTMAXQTLEN + 10; + + bp = rbufp->recv_buffer; + cp = &pst->lastcode[pst->lencode]; + *cp++ = ' '; + cpstart = cp; + while (n-- > 0) { + *cp = (*bp++) & 0x7f; /* strip parity */ + if (!isprint(*cp)) + break; + cp++; + } + len = (cp - cpstart); + pst->lencode = (u_char)(cp - pst->lastcode); + + /* + * Okay, got all printable characters from the string + * copied. We expect to have been terminated by the + * EOL character. If not, forget it. If the length + * is insane, forget it. + */ + if (*cp != PSTEOL || + len < PSTMINQTLEN || len > PSTMAXQTLEN) { + pst->reason = QTREASON + 1; + return 0; + } + *cp = '\0'; +#ifdef PSTCLK + /* + * Receive time stamp should be in buffer after the code. + * Make sure we have enough characters in there. + */ + if (&rbufp->recv_buffer[rbufp->recv_length] - bp < 8) { + pst->reason = QTREASON + 2; + return 0; + } + if (!buftvtots(bp, tsrec)) { + pst->reason = QTREASON + 3; + return 0; + } +#else + /* + * Use the timestamp collected with the input. + */ + *tsrec = rbufp->recv_time; +#endif + + /* + * Ensure that the characters are formatted validly. Mostly + * digits, but the occasional `:' and `.'. + */ + cp = cpstart; + if (!isdigit(cp[1]) || !isdigit(cp[2]) || cp[3] != ':' || + !isdigit(cp[4]) || !isdigit(cp[5]) || cp[6] != ':' || + !isdigit(cp[7]) || !isdigit(cp[8]) || cp[9] != '.' || + !isdigit(cp[10]) || !isdigit(cp[11]) || !isdigit(cp[12])) { + pst->reason = QTREASON + 4; + return 0; + } + + /* + * Extract the hour, minute, second and millisecond + */ + hour = MULBY10(PSTTOBIN(cp[1])) + PSTTOBIN(cp[2]); + minute = MULBY10(PSTTOBIN(cp[4])) + PSTTOBIN(cp[5]); + second = MULBY10(PSTTOBIN(cp[7])) + PSTTOBIN(cp[8]); + msec = MULBY10(PSTTOBIN(cp[10])) + PSTTOBIN(cp[11]); + msec = MULBY10(msec) + PSTTOBIN(cp[12]); + + if (minute > 59 || second > 59) { + pst->reason = QTREASON + 5; + return 0; + } + + /* + * Trouble here. Adjust the hours for AM/PM, if this is + * on, and for daylight saving time. + */ + if (*cp == 'A') { + if (hour > 12 || hour == 0) { + pst->reason = QTREASON + 5; + return 0; + } + if (hour == 12) + hour = 0; + } else if (*cp == 'P') { + if (hour > 12 || hour == 0) + return 0; + if (hour < 12) + hour += 12; + } else if (*cp != ' ') { + pst->reason = QTREASON + 6; + return 0; + } + + if (cp[13] == 'D') + tzoff = -1; + else if (cp[13] == ' ') + tzoff = 0; + else { + pst->reason = QTREASON + 7; + return 0; + } + + /* + * Adjust for the timezone. The PST manual is screwy here. + * it says the timezone is an integer in the range 0 to 23, + * but this doesn't allow us to tell the difference between + * +12 and -12. Assume the 12 hour timezone is west of + * GMT. + */ + if (pst->timezone <= 12) + tzoff += pst->timezone; + else + tzoff -= (24 - pst->timezone); + + + /* + * Record for posterity + */ + pst->hour = (u_char)hour; + pst->minute = (u_char)minute; + pst->second = (u_char)second; + pst->millisecond = (u_short)msec; + pst->tzoffset = (s_char)tzoff; + + /* + * All that to get the day-hour-minute-second. Turn this + * into the seconds part of a time stamp. Also use the + * milliseconds part directly as the fractional part. + */ + MSUTOTSF(msec, tsclk->l_uf); + if (!clocktime((int)pst->yearday, hour, minute, second, tzoff, + tsrec->l_ui, &pst->yearstart, &tsclk->l_ui)) { + pst->reason = QTREASON + 8; + return 0; + } + + /* + * Add in the fudge + */ + if (pst->flags & PST_WWVH) + L_ADDUF(tsclk, wwvh_prop_data[pst->unit].remainder); + else + L_ADDUF(tsclk, wwv_prop_data[pst->unit].remainder); + + /* + * Glad that's over with + */ + return 1; +} + + +/* + * pst_do_event - update our status and report any changes + */ +static void +pst_do_event(pst, evnt_code) + register struct pstunit *pst; + int evnt_code; +{ + if (pst->status != (u_char)evnt_code) { + pst->status = (u_char)evnt_code; + if (evnt_code != CEVNT_NOMINAL) + pst->lastevent = (u_char)evnt_code; + /* + * Should trap this, but the trap code isn't up to + * it yet. + */ + } +} + + + +/* + * pst_process - process the data collected to produce an offset estimate + */ +static void +pst_process(pst) + register struct pstunit *pst; +{ + register int i; + register int n; + register U_LONG tmp_ui; + register U_LONG tmp_uf; + register U_LONG date_ui; + register U_LONG date_uf; + u_fp dispersion; + l_fp off[NPSTSAMPS]; + + /* + * Compute offsets from the raw data. Sort them into + * ascending order. + */ + for (i = 0; i < NPSTSAMPS; i++) { + tmp_ui = pst->reftimes[i].l_ui; + tmp_uf = pst->reftimes[i].l_uf; + M_SUB(tmp_ui, tmp_uf, pst->rectimes[i].l_ui, + pst->rectimes[i].l_uf); + for (n = i; n > 0; n--) { + if (M_ISGEQ(tmp_ui, tmp_uf, off[n-1].l_ui, + off[n-1].l_uf)) + break; + off[n] = off[n-1]; + } + off[n].l_ui = tmp_ui; + off[n].l_uf = tmp_uf; + } + + /* + * Reject the furthest from the median until 8 samples left + */ + i = 0; + n = NPSTSAMPS; + while ((n - i) > 8) { + tmp_ui = off[n-1].l_ui; + tmp_uf = off[n-1].l_uf; + date_ui = off[(n+i)/2].l_ui; + date_uf = off[(n+i)/2].l_uf; + M_SUB(tmp_ui, tmp_uf, date_ui, date_uf); + M_SUB(date_ui, date_uf, off[i].l_ui, off[i].l_uf); + if (M_ISHIS(date_ui, date_uf, tmp_ui, tmp_uf)) { + /* + * reject low end + */ + i++; + } else { + /* + * reject high end + */ + n--; + } + } + + /* + * Compute the dispersion based on the difference between the + * extremes of the remaining offsets. + */ + tmp_ui = off[n-1].l_ui; + tmp_uf = off[n-1].l_uf; + M_SUB(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf); + dispersion = MFPTOFP(tmp_ui, tmp_uf); + + /* + * Now compute the offset estimate. If the sloppy clock + * flag is set, average the remainder, otherwise pick the + * median. + */ + if (sloppyclock[pst->unit]) { + tmp_ui = tmp_uf = 0; + while (i < n) { + M_ADD(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf); + i++; + } + M_RSHIFT(tmp_ui, tmp_uf); + M_RSHIFT(tmp_ui, tmp_uf); + M_RSHIFT(tmp_ui, tmp_uf); + i = 0; + off[0].l_ui = tmp_ui; + off[0].l_uf = tmp_uf; + } else { + i = (n+i)/2; + } + + /* + * Add the default PST QT delay into this. + */ + L_ADDUF(&off[i], PSTQTFUDGE); + + /* + * Set the reference ID to the appropriate station + */ + if (stratumtouse[pst->unit] <= 1) { + if (pst->station >= 0) + bcopy(WWVREFID, (char *)&pst->peer->refid, 4); + else + bcopy(WWVHREFID, (char *)&pst->peer->refid, 4); + } + + /* + * Give the data to the reference clock support code + */ + record_clock_stats(&(pst->peer->srcadr), pst->lastcode); + refclock_receive(pst->peer, &off[i], 0, dispersion, &pst->reftimes[NPSTSAMPS-1], + &pst->rectimes[NPSTSAMPS-1], pst->leap); + + /* + * If the don't-sync flag isn't on, we're nominal. + */ + if (pst->leap == 0) + pst_event(pst, CEVNT_NOMINAL); + pst_reset(pst); +} + + + +/* + * pst_receive - receive data from a PST clock, call the appropriate + * routine to process it, and advance the state. + */ +static void +pst_receive(rbufp) + struct recvbuf *rbufp; +{ + register struct pstunit *pst; + register U_LONG tmp; + + pst = (struct pstunit *)rbufp->recv_srcclock; + + /* + * Process based on the current state. + */ + switch(pst->state) { + case STATE_IDLE: + return; /* Ignore the input */ + + case STATE_QV: + if (!pst_QV_process(pst, rbufp)) { + /* + * Set the state to idle, but request another + * QV poll. + */ + pst->badformat++; + pst_event(pst, CEVNT_BADREPLY); + pst->state = STATE_IDLE; + pst->flags |= PST_DOQV; + } else { + /* + * This went okay. Advance the state to + * QM and send the request. + */ + pst->state = STATE_QM; + pst_send(pst, "QM", 2); + } + return; + + case STATE_QM: + if (!pst_QM_process(pst, rbufp)) { + /* + * Idle us and note the error + */ + pst->badformat++; + pst_event(pst, CEVNT_BADREPLY); + pst->state = STATE_IDLE; + return; + } + if (pst->flags & PST_NOTIME) { + /* + * Here we aren't getting any time because the + * clock is still searching. Don't bother + * looking for anything. Remove any leap + * second hold, however, since this should + * ensure the clock is sensible. + */ + pst_event(pst, CEVNT_FAULT); + pst->state = STATE_IDLE; + if (pst->nextsample > 0) + pst_reset(pst); /* Make sure rate low */ + return; + } + + /* + * Next is QD. Do it. + */ + pst->state = STATE_QD; + pst_send(pst, "QD", 2); + return; + + case STATE_QD: + if (!pst_QD_process(pst, rbufp)) { + /* + * Idle us and note the error + */ + pst->badformat++; + pst_event(pst, CEVNT_BADDATE); + pst->state = STATE_IDLE; + } else { + /* + * Last step is QT. + */ + pst->state = STATE_QT; + pst_send(pst, "QT", 2); + } + return; + + case STATE_QT: + pst->state = STATE_IDLE; + if (!pst_QT_process(pst, rbufp, &pst->lastref, &pst->lastrec)) { + /* + * Note the error + */ + pst->baddata++; + pst_event(pst, CEVNT_BADTIME); + return; + } + break; + + default: + syslog(LOG_ERR, + "pst_receive: unit %d invalid state %d", + pst->unit, pst->state); + return; + } + + + /* + * You may not have noticed this, but the only way we end up + * out here is if we've completed polling and have a couple of + * valid time stamps. First see if we should reset the + * structure. + */ + if (pst->nextsample > 0) { + tmp = pst->lastrec.l_ui - pst->rectimes[0].l_ui; + if (tmp > (U_LONG)psttab[pst->nextsample].tooold) + pst_reset(pst); + } + + pst->rectimes[pst->nextsample] = pst->lastrec; + pst->reftimes[pst->nextsample] = pst->lastref; + pst->nextsample++; + if (pst->flags & PST_WWVH) + pst->station--; + else + pst->station++; + + if (pst->flags & (PST_SIGFAULT|PST_HARDERR)) { + pst_event(pst, CEVNT_FAULT); + pst->leap = LEAP_NOTINSYNC; + } else if (pst->timesincesync > freerun[pst->unit]) { + pst_event(pst, CEVNT_PROP); + pst->leap = LEAP_NOTINSYNC; + } + + if (pst->nextsample >= NPSTSAMPS) + pst_process(pst); +} + + +/* + * pst_compute_delay - compute appropriate things to tell clock about delays + */ +static void +pst_compute_delay(prop_delay, prop_data) + U_LONG prop_delay; + struct pst_propagate *prop_data; +{ + register int code; + register U_LONG tsf; + + /* + * Convert (truncate) the delay to milliseconds. Save the + * characters needed to send this to the clock and compute + * the remainder to be added in later. + */ + code = tsftomsu(prop_delay, 0); + MSUTOTSF(code, tsf); + prop_data->remainder = prop_delay - tsf; + if (prop_data->remainder & 0x80000000) + prop_data->remainder = 0; + prop_data->msbchar = BINTOPST((code >> 2) & 0x1f); + prop_data->lsbchar = BINTOPST(code & 0x3); +} + + +/* + * pst_control - set fudge factors, return statistics + */ +static void +pst_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct pstunit *pst; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "pst_control: unit %d invalid", unit); + return; + } + + if (in != 0) { + int doqv = 0; + + if (in->haveflags & CLK_HAVETIME1) + if (in->fudgetime1.l_ui == 0 + && in->fudgetime1.l_uf <= PSTMAXPROP) { + wwv_prop_delay[unit] = in->fudgetime1; + doqv = 1; + pst_compute_delay(wwv_prop_delay[unit].l_uf, + &wwv_prop_data[unit]); + } + if (in->haveflags & CLK_HAVETIME2) + if (in->fudgetime2.l_ui == 0 + && in->fudgetime2.l_uf <= PSTMAXPROP) { + wwvh_prop_delay[unit] = in->fudgetime2; + doqv = 1; + pst_compute_delay(wwvh_prop_delay[unit].l_uf, + &wwvh_prop_data[unit]); + } + if (in->haveflags & CLK_HAVEVAL1) { + stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf); + } + if (in->haveflags & CLK_HAVEVAL2) { + if (in->fudgeval2 > 0 && in->fudgeval2 < 9990) + freerun[unit] = (u_short)in->fudgeval2; + } + if (in->haveflags & CLK_HAVEFLAG1) { + sloppyclock[unit] = in->flags & CLK_FLAG1; + } + if (unitinuse[unit]) { + /* + * Should actually reselect clock, but + * will wait for the next timecode + */ + if (in->haveflags & CLK_HAVEVAL1) { + pstunits[unit]->peer->stratum + = stratumtouse[unit]; + if (stratumtouse[unit] > 1) + pstunits[unit]->peer->refid + = htonl(PSTHSREFID); + } + + if ((in->haveflags & CLK_HAVEFLAG3) && + (in->flags & CLK_FLAG3)) { + pstunits[unit]->flags |= PST_DORESET; + } else if (doqv || ((in->haveflags & CLK_HAVEFLAG2) && + (in->flags & CLK_FLAG2))) { + pstunits[unit]->flags |= PST_DOQV; + } + } + } + + if (out != 0) { + out->type = REFCLK_WWV_PST; + out->flags = 0; + out->haveflags + = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1| + CLK_HAVEVAL2|CLK_HAVEFLAG1; + out->fudgetime1 = wwv_prop_delay[unit]; + out->fudgetime2 = wwvh_prop_delay[unit]; + out->fudgeval1 = (LONG)stratumtouse[unit]; + out->fudgeval2 = (LONG)freerun[unit]; + out->flags = sloppyclock[unit]; + if (unitinuse[unit]) { + pst = pstunits[unit]; + out->clockdesc = pst->description; + out->lencode = pst->lencode; + out->lastcode = pst->lastcode; + out->timereset = current_time - pst->timestarted; + out->polls = pst->polls; + out->noresponse = pst->noreply; + out->badformat = pst->badformat; + out->baddata = pst->baddata; + out->lastevent = pst->lastevent; + out->currentstatus = pst->status; + } else { + out->clockdesc = pstdefdesc; + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} + + +/* + * pst_buginfo - return clock dependent debugging info + */ +static void +pst_buginfo(unit, bug) + int unit; + register struct refclockbug *bug; +{ + register struct pstunit *pst; + register int i; + + bug->nvalues = bug->ntimes = 0; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "pst_buginfo: unit %d invalid", unit); + return; + } + + if (!unitinuse[unit]) + return; + pst = pstunits[unit]; + + bug->nvalues = 14; + bug->svalues = (1<<10); + bug->values[0] = (U_LONG)pst->nextsample; + bug->values[1] = (U_LONG)pst->state; + bug->values[2] = (U_LONG)pst->reason; + bug->values[3] = (U_LONG)pst->flags; + bug->values[4] = (U_LONG)pst->yearday; + bug->values[5] = (U_LONG)pst->hour; + bug->values[6] = (U_LONG)pst->minute; + bug->values[7] = (U_LONG)pst->second; + bug->values[8] = (U_LONG)pst->millisecond; + bug->values[9] = (U_LONG)pst->timezone; + bug->values[10] = (U_LONG)((LONG)pst->tzoffset); + bug->values[11] = (U_LONG)pst->timesincesync; + bug->values[12] = pst->yearstart; + bug->ntimes = ((NPSTSAMPS*2)+2) > NCLKBUGTIMES ? NCLKBUGTIMES : + ((NPSTSAMPS*2)+2); + bug->stimes = 0; + for (i = 0; i < (bug->ntimes-2)/2; i++) { + bug->times[2*i] = pst->rectimes[i]; + bug->times[(2*i) + 1] = pst->reftimes[i]; + } + bug->times[bug->ntimes - 2] = pst->lastrec; + bug->times[bug->ntimes - 1] = pst->lastref; +} +#endif diff --git a/contrib/xntpd/xntpd/refclock_tpro.c b/contrib/xntpd/xntpd/refclock_tpro.c new file mode 100644 index 0000000000..59881800bd --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_tpro.c @@ -0,0 +1,498 @@ +/* + * refclock_tpro - clock driver for the KSI/Odetics TPRO-S IRIG-B reader + */ +#if defined(REFCLOCK) && defined(TPRO) +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "sys/tpro.h" +#include "ntp_stdlib.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. + */ + +/* + * Definitions + */ +#define MAXUNITS 1 /* max number of TPRO units */ +#define TPROFD "/dev/tpro%d" /* name of driver device */ +#define BMAX 50 /* timecode buffer length */ + +/* + * TPRO interface parameters. The "IRIG" can be changed to "GPS" for the + * TPRO-GPS. + */ +#define TPROPRECISION (-20) /* precision assumed (1 us) */ +#define TPROREFID "IRIG" /* reference id */ +#define TPRODESCRIPTION "KSI/Odetics TPRO-S IRIG-B Reader" /* who we are */ +#define TPROHSREFID 0x7f7f0c0a /* 127.127.12.10 refid hi strata */ +#define GMT 0 /* hour offset from Greenwich */ + +/* + * Hack to avoid excercising the multiplier. I have no pride. + */ +#define MULBY10(x) (((x)<<3) + ((x)<<1)) + +/* + * Imported from ntp_timer module + */ +extern U_LONG current_time; /* current time (s) */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * TPRO unit control structure. + */ +struct tprounit { + struct peer *peer; /* associated peer structure */ + struct refclockio io; /* given to the I/O handler */ + struct tproval tprodata; /* data returned from tpro read */ + l_fp lastrec; /* last local time */ + l_fp lastref; /* last timecode time */ + char lastcode[BMAX]; /* last timecode received */ + u_char lencode; /* length of last timecode */ + U_LONG lasttime; /* last time clock heard from */ + u_char unit; /* unit number for this guy */ + u_char status; /* clock status */ + u_char lastevent; /* last clock event */ + u_char year; /* year of eternity */ + u_short day; /* day of year */ + u_char hour; /* hour of day */ + u_char minute; /* minute of hour */ + u_char second; /* seconds of minute */ + U_LONG usec; /* microsecond of second */ + U_LONG yearstart; /* start of current year */ + u_char 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 tprounit *tprounits[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 tpro_init P(()); +static int tpro_start P((u_int, struct peer *)); +static void tpro_shutdown P((int)); +static void tpro_report_event P((struct tprounit *, int)); +static void tpro_receive P((struct recvbuf *)); +static void tpro_poll P((int unit, struct peer *)); +static void tpro_control P((u_int, struct refclockstat *, struct refclockstat *)); +static void tpro_buginfo P((int, struct refclockbug *)); + +/* + * Transfer vector + */ +struct refclock refclock_tpro = { + tpro_start, tpro_shutdown, tpro_poll, + tpro_control, tpro_init, tpro_buginfo, NOFLAGS +}; + +/* + * tpro_init - initialize internal tpro driver data + */ +static void +tpro_init() +{ + register int i; + /* + * Just zero the data arrays + */ + bzero((char *)tprounits, sizeof tprounits); + 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; + } +} + +/* + * tpro_start - open the TPRO device and initialize data for processing + */ +static int +tpro_start(unit, peer) + u_int unit; + struct peer *peer; +{ + register struct tprounit *tpro; + register int i; + char tprodev[20]; + int fd_tpro; + + /* + * Check configuration info. + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "tpro_start: unit %d invalid", unit); + return (0); + } + if (unitinuse[unit]) { + syslog(LOG_ERR, "tpro_start: unit %d in use", unit); + return (0); + } + + /* + * Open TPRO device + */ + (void) sprintf(tprodev, TPROFD, unit); + fd_tpro = open(tprodev, O_RDWR, 0777); + if (fd_tpro == -1) { + syslog(LOG_ERR, "tpro_start: open of %s: %m", tprodev); + return (0); + } + + /* + * Allocate unit structure + */ + if (tprounits[unit] != 0) { + tpro = tprounits[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && tprounits[i] != 0) + break; + } + if (i < MAXUNITS) { + /* + * Reclaim this one + */ + tpro = tprounits[i]; + tprounits[i] = 0; + } else { + tpro = (struct tprounit *) + emalloc(sizeof(struct tprounit)); + } + } + bzero((char *)tpro, sizeof(struct tprounit)); + tprounits[unit] = tpro; + + /* + * Set up the structures + */ + tpro->peer = peer; + tpro->unit = (u_char)unit; + tpro->timestarted = current_time; + + tpro->io.clock_recv = tpro_receive; + tpro->io.srcclock = (caddr_t)tpro; + tpro->io.datalen = 0; + tpro->io.fd = fd_tpro; + + /* + * 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 = TPROPRECISION; + peer->rootdelay = 0; + peer->rootdispersion = 0; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(TPROREFID, (char *)&peer->refid, 4); + else + peer->refid = htonl(TPROHSREFID); + unitinuse[unit] = 1; + return (1); +} + + +/* + * tpro_shutdown - shut down a TPRO clock + */ +static void +tpro_shutdown(unit) + int unit; +{ + register struct tprounit *tpro; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "tpro_shutdown: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "tpro_shutdown: unit %d not in use", unit); + return; + } + + /* + * Tell the I/O module to turn us off. We're history. + */ + tpro = tprounits[unit]; + io_closeclock(&tpro->io); + unitinuse[unit] = 0; +} + +/* + * tpro_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 +tpro_report_event(tpro, code) + struct tprounit *tpro; + int code; +{ + struct peer *peer; + + peer = tpro->peer; + if (tpro->status != (u_char)code) { + tpro->status = (u_char)code; + if (code != CEVNT_NOMINAL) + tpro->lastevent = (u_char)code; + syslog(LOG_INFO, + "clock %s event %x", ntoa(&peer->srcadr), code); + } +} + + +/* + * tpro_receive - receive data from the TPRO 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 +tpro_receive(rbufp) + struct recvbuf *rbufp; +{ +} + +/* + * tpro_poll - called by the transmit procedure + */ +static void +tpro_poll(unit, peer) + int unit; + struct peer *peer; +{ + struct tprounit *tpro; + struct tproval *tptr; + l_fp tstmp; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "tpro_poll: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "tpro_poll: unit %d not in use", unit); + return; + } + tpro = tprounits[unit]; + tpro->polls++; + + tptr = &tpro->tprodata; + if (read(tpro->io.fd, (char *)tptr, sizeof(struct tproval)) < 0) { + tpro_report_event(tpro, CEVNT_BADREPLY); + return; + } + gettstamp(&tpro->lastrec); + tpro->lasttime = current_time; + + /* + * Get TPRO time and convert to timestamp format. Note: we + * can't use the sec/usec conversion produced by the driver, + * since the year may be suspect. + */ + sprintf(tpro->lastcode, + "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x", + tptr->day100, tptr->day10, tptr->day1, tptr->hour10, tptr->hour1, + tptr->min10, tptr->min1, tptr->sec10, tptr->sec1, + tptr->ms100, tptr->ms10, tptr->ms1, tptr->usec100, tptr->usec10, + tptr->usec1, tptr->status); + record_clock_stats(&(tpro->peer->srcadr), tpro->lastcode); + tpro->lencode = strlen(tpro->lastcode); + + tpro->day = MULBY10(MULBY10(tptr->day100) + tptr->day10) + tptr->day1; + tpro->hour = MULBY10(tptr->hour10) + tptr->hour1; + tpro->minute = MULBY10(tptr->min10) + tptr->min1; + tpro->second = MULBY10(tptr->sec10) + tptr->sec1; + tpro->usec = MULBY10(MULBY10(tptr->ms100) + tptr->ms10) + tptr->ms1; + tpro->usec = tpro->usec * 10 + tptr->usec100; + tpro->usec = tpro->usec * 10 + tptr->usec10; + tpro->usec = tpro->usec * 10 + tptr->usec1; +#ifdef DEBUG + if (debug) + printf("tpro: %3d %02d:%02d:%02d.%06ld %1x\n", + tpro->day, tpro->hour, tpro->minute, tpro->second, + tpro->usec, tptr->status); +#endif + if (tptr->status != 0xff) { + tpro_report_event(tpro, 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(tpro->day, tpro->hour, tpro->minute, + tpro->second, GMT, tpro->lastrec.l_ui, + &tpro->yearstart, &tpro->lastref.l_ui)) { + tpro->baddata++; + tpro_report_event(tpro, CEVNT_BADTIME); + return; + } + TVUTOTSF(tpro->usec, tpro->lastref.l_uf); + tstmp = tpro->lastref; + L_SUB(&tstmp, &tpro->lastrec); + tpro->coderecv++; + L_ADD(&tstmp, &(fudgefactor[tpro->unit])); + refclock_receive(tpro->peer, &tstmp, GMT, 0, + &tpro->lastrec, &tpro->lastrec, tpro->leap); +} + +/* + * tpro_control - set fudge factors, return statistics + */ +static void +tpro_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct tprounit *tpro; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "tpro_control: unit %d invalid)", unit); + return; + } + + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + fudgefactor[unit] = in->fudgetime1; + 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 + */ + tpro = tprounits[unit]; + peer = tpro->peer; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(TPROREFID, (char *)&peer->refid, + 4); + else + peer->refid = htonl(TPROHSREFID); + } + } + if (in->haveflags & CLK_HAVEFLAG1) { + sloppyclockflag[unit] = in->flags & CLK_FLAG1; + } + } + + if (out != 0) { + out->type = REFCLK_IRIG_TPRO; + out->haveflags + = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1; + out->clockdesc = TPRODESCRIPTION; + out->fudgetime1 = fudgefactor[unit]; + out->fudgetime2.l_ui = 0; + out->fudgetime2.l_uf = 0; + out->fudgeval1 = (LONG)stratumtouse[unit]; + out->fudgeval2 = 0; + out->flags = sloppyclockflag[unit]; + if (unitinuse[unit]) { + tpro = tprounits[unit]; + out->lencode = tpro->lencode; + out->lastcode = tpro->lastcode; + out->timereset = current_time - tpro->timestarted; + out->polls = tpro->polls; + out->noresponse = tpro->noreply; + out->badformat = tpro->badformat; + out->baddata = tpro->baddata; + out->lastevent = tpro->lastevent; + out->currentstatus = tpro->status; + } else { + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} + +/* + * tpro_buginfo - return clock dependent debugging info + */ +static void +tpro_buginfo(unit, bug) + int unit; + register struct refclockbug *bug; +{ + register struct tprounit *tpro; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "tpro_buginfo: unit %d invalid)", unit); + return; + } + + if (!unitinuse[unit]) + return; + tpro = tprounits[unit]; + + bug->nvalues = 11; + bug->ntimes = 5; + if (tpro->lasttime != 0) + bug->values[0] = current_time - tpro->lasttime; + else + bug->values[0] = 0; + bug->values[2] = (U_LONG)tpro->year; + bug->values[3] = (U_LONG)tpro->day; + bug->values[4] = (U_LONG)tpro->hour; + bug->values[5] = (U_LONG)tpro->minute; + bug->values[6] = (U_LONG)tpro->second; + bug->values[7] = (U_LONG)tpro->usec; + bug->values[9] = tpro->yearstart; + bug->stimes = 0x1c; + bug->times[0] = tpro->lastref; + bug->times[1] = tpro->lastrec; +} +#endif diff --git a/contrib/xntpd/xntpd/refclock_wwvb.c b/contrib/xntpd/xntpd/refclock_wwvb.c new file mode 100644 index 0000000000..602eee0ee4 --- /dev/null +++ b/contrib/xntpd/xntpd/refclock_wwvb.c @@ -0,0 +1,1041 @@ +/* + * refclock_wwvb - clock driver for the Spectracom WWVB receivers + */ +#if defined(REFCLOCK) && (defined(WWVB) || defined(WWVBCLK) || defined(WWVBPPS)) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(STREAM) +#include +#include +#if defined(WWVBCLK) +#include +#endif /* WWVBCLK */ +#endif /* STREAM */ + +#if defined (WWVBPPS) +#include +#endif /* WWVBPPS */ + +#include "ntp_stdlib.h" + +/* + * This driver supports the Spectracom Model 8170 and Netclock/2 WWVB + * Synchronized Clock under Unix and on a Gizmo board. There are two + * formats used by these clocks. Format 0 (zero), which is available + * with both the Netclock/2 and 8170, is in the following format: + * + * Idddhh:mm:ssTZ=nn + * + * The ddd, hh, mm and ss fields show the day of year, hours, minutes + * and seconds, respectively. The nn field shows the local hour offset + * relative to UTC and should always be set to 00. The I is normally + * when the clock is synchronized and '?' when it isn't (it could + * also be a '*' if we set the time manually, but this is forbidden. + * + * Format 2 (two), which is available only with the Netclock/2 and + * specially modified 8170, is in the following format: + * + * IQyydddhh:mm:ss.mmmLD + * + * The ddd, hh and ss fields and I are as in format 0. The yy field + * shows the year and mmm the milliseconds, respectively. The Q is + * normally when the time error is less than 1 ms and 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 is supposed to be synchronized to the on-time second. + * + * This driver does not need to be told which format is in use - it + * figures out which one from the length of the message. A three-stage + * median filter is used to reduce jitter and provide a dispersion + * measure. The driver makes no attempt to correct for the intrinsic + * jitter of the radio itself, which is a known problem with the older + * radios. + * + * This driver supports the 1-pps signal provided by the radio and + * connected via a level converted described in the gadget directory. + * The signal is captured using a separate, dedicated, serial port and + * the tty_clk line discipline/streams modules described in the kernel + * directory. For the highest precision, the signal is captured using + * the carrier-detect line of the same serial port using the ppsclock + * streams module described in the ppsclock directory. + * + * Bugs: + * + * The year indication so carefully provided in format 2 is not used. + */ + +/* + * Definitions + */ +#define MAXUNITS 4 /* max number of WWVB units */ +#define WWVB232 "/dev/wwvb%d" /* name of radio device */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ + +/* + * Radio interface parameters + */ +#define WWVBPRECISION (-13) /* precision assumed (about 100 us) */ +#define WWVBREFID "WWVB" /* reference id */ +#define WWVBDESCRIPTION "Spectracom WWVB Receiver" /* who we are */ +#define WWVBHSREFID 0x7f7f040a /* 127.127.4.10 refid hi strata */ +#define GMT 0 /* hour offset from Greenwich */ +#define NCODES 3 /* stages of median filter */ +#define LENWWVB0 22 /* format 0 timecode length */ +#define LENWWVB2 24 /* format 2 timecode length */ +#define FMTWWVBU 0 /* unknown format timecode id */ +#define FMTWWVB0 1 /* format 0 timecode id */ +#define FMTWWVB2 2 /* format 2 timecode id */ +#define BMAX 80 /* timecode buffer length */ +#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */ +#define MONLIN 15 /* number of monitoring lines */ +/* + * Hack to avoid excercising the multiplier. I have no pride. + */ +#define MULBY10(x) (((x)<<3) + ((x)<<1)) + +/* + * Imported from ntp_timer module + */ +extern U_LONG current_time; /* current time (s) */ + +/* + * Imported from ntp_loopfilter module + */ +extern int fdpps; /* pps file descriptor */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * WWVB unit control structure + */ +struct wwvbunit { + struct peer *peer; /* associated peer structure */ + struct refclockio io; /* given to the I/O handler */ + l_fp lastrec; /* last receive time */ + l_fp lastref; /* last timecode time */ + l_fp offset[NCODES]; /* recent sample offsets */ + char lastcode[BMAX]; /* last timecode received */ + u_char format; /* timecode format */ + u_char tcswitch; /* timecode switch */ + u_char pollcnt; /* poll message counter */ + u_char lencode; /* length of last timecode */ + U_LONG lasttime; /* last time clock heard from */ + 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 year; /* year of eternity */ + u_short day; /* day of year */ + u_char hour; /* hour of day */ + u_char minute; /* minute of hour */ + u_char second; /* seconds of minute */ + u_char leap; /* leap indicators */ + u_short msec; /* millisecond of second */ + u_char quality; /* quality char from format 2 */ + U_LONG yearstart; /* start of current year */ + u_char lasthour; /* last hour (for monitor) */ + u_char linect; /* count of ignored lines (for monitor */ + + /* + * 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 wwvbunit *wwvbunits[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 wwvb_init P((void)); +static int wwvb_start P((u_int, struct peer *)); +static void wwvb_shutdown P((int)); +static void wwvb_report_event P((struct wwvbunit *, int)); +static void wwvb_receive P((struct recvbuf *)); +static char wwvb_process P((struct wwvbunit *, l_fp *, u_fp *)); +static void wwvb_poll P((int, struct peer *)); +static void wwvb_control P((u_int, struct refclockstat *, struct refclockstat *)); +static void wwvb_buginfo P((int, struct refclockbug *)); + +/* + * Transfer vector + */ +struct refclock refclock_wwvb = { + wwvb_start, wwvb_shutdown, wwvb_poll, + wwvb_control, wwvb_init, wwvb_buginfo, NOFLAGS +}; + +/* + * wwvb_init - initialize internal wwvb driver data + */ +static void +wwvb_init() +{ + register int i; + /* + * Just zero the data arrays + */ + bzero((char *)wwvbunits, sizeof wwvbunits); + 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; + } +} + + +/* + * wwvb_start - open the WWVB devices and initialize data for processing + */ +static int +wwvb_start(unit, peer) + u_int unit; + struct peer *peer; +{ + register struct wwvbunit *wwvb; + register int i; + int fd232; + char wwvbdev[20]; + + /* + * Check configuration info + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "wwvb_start: unit %d invalid", unit); + return (0); + } + if (unitinuse[unit]) { + syslog(LOG_ERR, "wwvb_start: unit %d in use", unit); + return (0); + } + + /* + * Open serial port + */ + (void) sprintf(wwvbdev, WWVB232, unit); + fd232 = open(wwvbdev, O_RDWR, 0777); + if (fd232 == -1) { + syslog(LOG_ERR, "wwvb_start: open of %s: %m", wwvbdev); + return (0); + } + +#if defined(HAVE_SYSV_TTYS) + /* + * System V serial line parameters (termio interface) + * + */ + { struct termio ttyb; + if (ioctl(fd232, TCGETA, &ttyb) < 0) { + syslog(LOG_ERR, + "wwvb_start: ioctl(%s, TCGETA): %m", wwvbdev); + 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) { + syslog(LOG_ERR, + "wwvb_start: ioctl(%s, TCSETA): %m", wwvbdev); + goto screwed; + } + } +#endif /* HAVE_SYSV_TTYS */ +#if defined(STREAM) + /* + * POSIX/STREAMS serial line parameters (termios interface) + * + * The WWVBCLK option provides timestamping at the driver level. + * It requires the tty_clk streams module. + * + * The WWVBPPS option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the ppsclock streams module and SunOS 4.1.1 or + * later. + */ + { struct termios ttyb, *ttyp; + + ttyp = &ttyb; + if (tcgetattr(fd232, ttyp) < 0) { + syslog(LOG_ERR, + "wwvb_start: tcgetattr(%s): %m", wwvbdev); + 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) { + syslog(LOG_ERR, + "wwvb_start: tcsetattr(%s): %m", wwvbdev); + goto screwed; + } + if (tcflush(fd232, TCIOFLUSH) < 0) { + syslog(LOG_ERR, + "wwvb_start: tcflush(%s): %m", wwvbdev); + goto screwed; + } +#if defined(WWVBCLK) + if (ioctl(fd232, I_PUSH, "clk") < 0) + syslog(LOG_ERR, + "wwvb_start: ioctl(%s, I_PUSH, clk): %m", wwvbdev); + if (ioctl(fd232, CLK_SETSTR, "\n") < 0) + syslog(LOG_ERR, + "wwvb_start: ioctl(%s, CLK_SETSTR): %m", wwvbdev); +#endif /* WWVBCLK */ +#if defined(WWVBPPS) + if (ioctl(fd232, I_PUSH, "ppsclock") < 0) + syslog(LOG_ERR, + "wwvb_start: ioctl(%s, I_PUSH, ppsclock): %m", wwvbdev); + else + fdpps = fd232; +#endif /* WWVBPPS */ + } +#endif /* STREAM */ +#if defined(HAVE_BSD_TTYS) + /* + * 4.3bsd serial line parameters (sgttyb interface) + * + * The WWVBCLK option provides timestamping at the driver level. + * It requires the tty_clk line discipline and 4.3bsd or later. + */ + { struct sgttyb ttyb; +#if defined(WWVBCLK) + int ldisc = CLKLDISC; +#endif /* WWVBCLK */ + + if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { + syslog(LOG_ERR, + "wwvb_start: ioctl(%s, TIOCGETP): %m", wwvbdev); + goto screwed; + } + ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; +#if defined(WWVBCLK) + 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 /* WWVBCLK */ + if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { + syslog(LOG_ERR, + "wwvb_start: ioctl(%s, TIOCSETP): %m", wwvbdev); + goto screwed; + } +#if defined(WWVBCLK) + if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { + syslog(LOG_ERR, + "wwvb_start: ioctl(%s, TIOCSETD): %m",wwvbdev); + goto screwed; + } +#endif /* WWVBCLK */ + } +#endif /* HAVE_BSD_TTYS */ + + /* + * Allocate unit structure + */ + if (wwvbunits[unit] != 0) { + wwvb = wwvbunits[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && wwvbunits[i] != 0) + break; + } + if (i < MAXUNITS) { + /* + * Reclaim this one + */ + wwvb = wwvbunits[i]; + wwvbunits[i] = 0; + } else { + wwvb = (struct wwvbunit *) + emalloc(sizeof(struct wwvbunit)); + } + } + bzero((char *)wwvb, sizeof(struct wwvbunit)); + wwvbunits[unit] = wwvb; + + /* + * Set up the structures + */ + wwvb->peer = peer; + wwvb->unit = (u_char)unit; + wwvb->timestarted = current_time; + wwvb->pollcnt = 2; + + wwvb->io.clock_recv = wwvb_receive; + wwvb->io.srcclock = (caddr_t)wwvb; + wwvb->io.datalen = 0; + wwvb->io.fd = fd232; + if (!io_addclock(&wwvb->io)) + goto screwed; + + /* + * 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 = WWVBPRECISION; + peer->rootdelay = 0; + peer->rootdispersion = 0; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(WWVBREFID, (char *)&peer->refid, 4); + else + peer->refid = htonl(WWVBHSREFID); + unitinuse[unit] = 1; + return (1); + + /* + * Something broke; abandon ship. + */ +screwed: + (void) close(fd232); + return (0); +} + +/* + * wwvb_shutdown - shut down a WWVB clock + */ +static void +wwvb_shutdown(unit) + int unit; +{ + register struct wwvbunit *wwvb; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "wwvb_shutdown: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "wwvb_shutdown: unit %d not in use", unit); + return; + } + + /* + * Tell the I/O module to turn us off. We're history. + */ + wwvb = wwvbunits[unit]; + io_closeclock(&wwvb->io); + unitinuse[unit] = 0; +} + + +/* + * wwvb_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 +wwvb_report_event(wwvb, code) + struct wwvbunit *wwvb; + int code; +{ + struct peer *peer; + + peer = wwvb->peer; + if (wwvb->status != (u_char)code) { + wwvb->status = (u_char)code; + if (code != CEVNT_NOMINAL) + wwvb->lastevent = (u_char)code; + syslog(LOG_INFO, + "clock %s event %x", ntoa(&peer->srcadr), code); + } +} + + +/* + * wwvb_receive - receive data from the serial interface on a Spectracom + * clock + */ +static void +wwvb_receive(rbufp) + struct recvbuf *rbufp; +{ + register int i; + register struct wwvbunit *wwvb; + register char *dpt, *cp, *dp; + int dpend; + l_fp tstmp, trtmp; + u_fp dispersion; + + /* + * Get the clock this applies to and a pointers to the data. + * Check for the presence of a timestamp left by the tty_clock + * line discipline/streams module and, if present, use that + * instead of the timestamp captured by the i/o routines. + */ + wwvb = (struct wwvbunit *)rbufp->recv_srcclock; + dpt = (char *)&rbufp->recv_space; + dpend = rbufp->recv_length; + if (dpend > BMAX - 1) + dpend = BMAX - 1; + wwvb-> pollcnt = 2; + trtmp = rbufp->recv_time; + if (dpend >= 9) { + dp = dpt + dpend - 9; + if (*dp == '\n' || *dp == '\r') { + dpend -= 8; + if (!buftvtots(dp + 1, &tstmp)) { +#ifdef DEBUG + if (debug) + printf("wwvb_receive: invalid timestamp"); +#endif + } else { +#ifdef DEBUG + if (debug) { + L_SUB(&trtmp, &tstmp); + printf("wwvb: delta %s", + lfptoa(&trtmp, 6)); + gettstamp(&trtmp); + L_SUB(&trtmp, &tstmp); + printf(" SIGIO %s\n", + lfptoa(&trtmp, 6)); + } +#endif + trtmp = tstmp; + } + } + } + /* + * Note we get a buffer and timestamp for both a and , + * but only the 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 (dpend == 1) { + if (wwvb->tcswitch == 0) { + wwvb->tcswitch = 1; + wwvb->lastrec = trtmp; + } else + wwvb->tcswitch = 0; + return; + } + tstmp = wwvb->lastrec; + wwvb->lastrec = trtmp; + wwvb->tcswitch = 1; + + /* + * Edit timecode to remove control chars. Note the receive + * timestamp is determined at the first ; however, we don't + * get the timecode for that timestamp until the next . We + * assume that, if we happen to come up during a timestamp, or + * other awkward time, the format and data checks will cause the + * driver to resynchronize after maybe a few false starts. + */ + if (dpend <= 0) + return; + cp = dp = wwvb->lastcode; + for (i = 0; i < dpend; i++) + if ((*dp = 0x7f & *dpt++) >= ' ') dp++; + *dp = '\0'; + wwvb->lencode = dp - cp; + record_clock_stats(&(wwvb->peer->srcadr), wwvb->lastcode); +#ifdef DEBUG + if (debug) + printf("wwvb: timecode %d %d %s\n", + wwvb->linect, wwvb->lencode, wwvb->lastcode); +#endif + + /* + * We get down to business, check the timecode format and decode + * its contents. This code uses the timecode length to determine + * whether format 0 or format 2. If the timecode has invalid + * length or is not in proper format, we declare bad format and + * exit; if the converted decimal values are out of range, we + * declare bad data and exit. + */ + cp = wwvb->lastcode; + wwvb->leap = 0; + wwvb->format = FMTWWVBU; + if ((cp[0] == ' ' || cp[0] == '?') && wwvb->lencode == LENWWVB0) { + + /* + * Check timecode format 0 + */ + if (cp[1] != ' ' || /* separator */ + cp[2] != ' ' || /* separator */ + !isdigit(cp[3]) || /* day of year */ + !isdigit(cp[4]) || + !isdigit(cp[5]) || + cp[6] != ' ' || /* separator */ + !isdigit(cp[7]) || /* hours */ + !isdigit(cp[8]) || + cp[9] != ':' || /* : separator */ + !isdigit(cp[10]) || /* minutes */ + !isdigit(cp[11]) || + cp[12] != ':' || /* : separator */ + !isdigit(cp[13]) || /* seconds */ + !isdigit(cp[14])) { + wwvb->badformat++; + wwvb_report_event(wwvb, CEVNT_BADREPLY); + return; + } + else + wwvb->format = FMTWWVB0; + + /* + * Convert format 0 and check values + */ + wwvb->year = 0; /* fake */ + wwvb->day = cp[3] - '0'; + wwvb->day = MULBY10(wwvb->day) + cp[4] - '0'; + wwvb->day = MULBY10(wwvb->day) + cp[5] - '0'; + wwvb->hour = MULBY10(cp[7] - '0') + cp[8] - '0'; + wwvb->minute = MULBY10(cp[10] - '0') + cp[11] - '0'; + wwvb->second = MULBY10(cp[13] - '0') + cp[14] - '0'; + wwvb->msec = 0; + if (cp[0] != ' ') + wwvb->leap = LEAP_NOTINSYNC; + else + wwvb->lasttime = current_time; + if (wwvb->day < 1 || wwvb->day > 366) { + wwvb->baddata++; + wwvb_report_event(wwvb, CEVNT_BADDATE); + return; + } + if (wwvb->hour > 23 || wwvb->minute > 59 + || wwvb->second > 59) { + wwvb->baddata++; + wwvb_report_event(wwvb, CEVNT_BADTIME); + return; + } + } else if ((cp[0] == ' ' || cp[0] == '?') && wwvb->lencode == LENWWVB2) { + + /* + * Check timecode format 2 + */ + if (!isdigit(cp[2]) || /* year of century */ + !isdigit(cp[3]) || + cp[4] != ' ' || /* separator */ + !isdigit(cp[5]) || /* day of year */ + !isdigit(cp[6]) || + !isdigit(cp[7]) || + cp[8] != ' ' || /* separator */ + !isdigit(cp[9]) || /* hour */ + !isdigit(cp[10]) || + cp[11] != ':' || /* : separator */ + !isdigit(cp[12]) || /* minute */ + !isdigit(cp[13]) || + cp[14] != ':' || /* : separator */ + !isdigit(cp[15]) || /* second */ + !isdigit(cp[16]) || + cp[17] != '.' || /* . separator */ + !isdigit(cp[18]) || /* millisecond */ + !isdigit(cp[19]) || + !isdigit(cp[20]) || + cp[21] != ' ') { /* separator */ + wwvb->badformat++; + wwvb_report_event(wwvb, CEVNT_BADREPLY); + return; + } + else + wwvb->format = FMTWWVB2; + + /* + * Convert format 2 and check values + */ + wwvb->year = MULBY10(cp[2] - '0') + cp[3] - '0'; + wwvb->day = cp[5] - '0'; + wwvb->day = MULBY10(wwvb->day) + cp[6] - '0'; + wwvb->day = MULBY10(wwvb->day) + cp[7] - '0'; + wwvb->hour = MULBY10(cp[9] - '0') + cp[10] - '0'; + wwvb->minute = MULBY10(cp[12] - '0') + cp[13] - '0'; + wwvb->second = MULBY10(cp[15] - '0') + cp[16] - '0'; + wwvb->msec = cp[18] - '0'; + wwvb->msec = MULBY10(wwvb->msec) + cp[19] - '0'; + wwvb->msec = MULBY10(wwvb->msec) + cp[20] - '0'; + wwvb->quality = cp[1]; + if (cp[0] != ' ') + wwvb->leap = LEAP_NOTINSYNC; + + /* + * This nonsense adjusts the last time the clock was + * heard from depending on the quality indicator. Once + * the clock has been heard, the dispersion depends only + * on when the clock was last heard. The first time the + * clock is heard, the time last heard is faked based on + * the quality indicator. The magic numbers (in seconds) + * are from the clock specifications. + */ + if (wwvb->lasttime != 0) { + if (cp[1] == ' ') + wwvb->lasttime = current_time; + } else { + switch (cp[1]) { + case ' ': + wwvb->lasttime = current_time; + break; + case 'A': + wwvb->lasttime = current_time - 800; + break; + case 'B': + wwvb->lasttime = current_time - 5300; + break; + case 'C': + wwvb->lasttime = current_time - 25300; + break; + /* Don't believe anything else */ + } + } + if (cp[22] == 'L') + wwvb->leap = LEAP_ADDSECOND; + if (wwvb->day < 1 || wwvb->day > 366) { + wwvb->baddata++; + wwvb_report_event(wwvb, CEVNT_BADDATE); + return; + } + if (wwvb->hour > 23 || wwvb->minute > 59 + || wwvb->second > 59) { + wwvb->baddata++; + wwvb_report_event(wwvb, CEVNT_BADTIME); + return; + } + } else { + if (wwvb->linect > 0) + wwvb->linect--; + else { + wwvb->badformat++; + wwvb_report_event(wwvb, CEVNT_BADREPLY); + } + return; + } + if (sloppyclockflag[wwvb->unit] & CLK_FLAG4 && + wwvb->hour < wwvb->lasthour) + wwvb->linect = MONLIN; + wwvb->lasthour = wwvb->hour; + + /* + * 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(wwvb->day, wwvb->hour, wwvb->minute, + wwvb->second, GMT, tstmp.l_ui, + &wwvb->yearstart, &wwvb->lastref.l_ui)) { + wwvb->baddata++; + wwvb_report_event(wwvb, CEVNT_BADTIME); + return; + } + MSUTOTSF(wwvb->msec, wwvb->lastref.l_uf); + i = ((int)(wwvb->coderecv)) % NCODES; + wwvb->offset[i] = wwvb->lastref; + L_SUB(&wwvb->offset[i], &tstmp); + if (wwvb->coderecv == 0) + for (i = 1; i < NCODES; i++) + wwvb->offset[i] = wwvb->offset[0]; + wwvb->coderecv++; + + /* + * Process the samples in the median filter, add the fudge + * factor and pass the offset and dispersion along. 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 (!wwvb_process(wwvb, &tstmp, &dispersion)) { + wwvb->baddata++; + wwvb_report_event(wwvb, CEVNT_BADTIME); + return; + } + L_ADD(&tstmp, &(fudgefactor[wwvb->unit])); + refclock_receive(wwvb->peer, &tstmp, GMT, dispersion, + &wwvb->lastrec, &wwvb->lastrec, wwvb->leap); +} + +/* + * wwvb_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 char +wwvb_process(wwvb, offset, dispersion) + struct wwvbunit *wwvb; + l_fp *offset; + u_fp *dispersion; +{ + register int i, j; + register U_LONG tmp_ui, tmp_uf; + int not_median1 = -1; /* XXX correct? */ + int not_median2 = -1; /* XXX correct? */ + int median; + u_fp disp_tmp, disp_tmp2; + + /* + * This code implements a three-stage median filter. First, we + * check if the samples are within 125 ms of each other. If not, + * dump the sample set. We take the median of the three offsets + * and use that as the sample offset. There probably is not much + * to be gained by a longer filter, since the clock filter in + * ntp_proto should do its thing. + */ + disp_tmp2 = 0; + for (i = 0; i < NCODES-1; i++) { + for (j = i+1; j < NCODES; j++) { + tmp_ui = wwvb->offset[i].l_ui; + tmp_uf = wwvb->offset[i].l_uf; + M_SUB(tmp_ui, tmp_uf, wwvb->offset[j].l_ui, + wwvb->offset[j].l_uf); + if (M_ISNEG(tmp_ui, tmp_uf)) { + M_NEG(tmp_ui, tmp_uf); + } + if (tmp_ui != 0 || tmp_uf > CODEDIFF) { + return (0); + } + disp_tmp = MFPTOFP(0, tmp_uf); + if (disp_tmp > disp_tmp2) { + disp_tmp2 = disp_tmp; + not_median1 = i; + not_median2 = j; + } + } + } + if (wwvb->lasttime == 0) + disp_tmp2 = NTP_MAXDISPERSE; + else if (wwvb->quality != ' ') + disp_tmp2 = current_time - wwvb->lasttime; + if (not_median1 == 0) { + if (not_median2 == 1) + median = 2; + else + median = 1; + } else { + median = 0; + } + *offset = wwvb->offset[median]; + *dispersion = disp_tmp2; + return (1); +} + +/* + * wwvb_poll - called by the transmit procedure + */ +static void +wwvb_poll(unit, peer) + int unit; + struct peer *peer; +{ + struct wwvbunit *wwvb; + char poll; + + /* + * Time to request a time code. The Spectracom clock responds + * to a "T" sent to it by returning a time code as stated in the + * comments in the header. 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. + */ + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "wwvb_poll: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + syslog(LOG_ERR, "wwvb_poll: unit %d not in use", unit); + return; + } + wwvb = wwvbunits[unit]; + if (wwvb->pollcnt > 0) { + wwvb->pollcnt--; + if (wwvb->pollcnt == 0) + wwvb_report_event(wwvbunits[unit], CEVNT_TIMEOUT); + } + if (wwvb->pollcnt == 0) + wwvb->noreply++; + if (wwvb->linect > 0) + poll = 'R'; + else + poll = 'T'; + if (write(wwvb->io.fd, &poll, 1) != 1) { + syslog(LOG_ERR, "wwvb_poll: unit %d: %m", wwvb->unit); + wwvb_report_event(wwvb, CEVNT_FAULT); + } else { + wwvb->polls++; + } +} + +/* + * wwvb_control - set fudge factors, return statistics + */ +static void +wwvb_control(unit, in, out) + u_int unit; + struct refclockstat *in; + struct refclockstat *out; +{ + register struct wwvbunit *wwvb; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "wwvb_control: unit %d invalid", unit); + return; + } + + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + fudgefactor[unit] = in->fudgetime1; + 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 + */ + wwvb = wwvbunits[unit]; + peer = wwvb->peer; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + bcopy(WWVBREFID, (char *)&peer->refid, + 4); + else + peer->refid = htonl(WWVBHSREFID); + } + } + if (in->haveflags & CLK_HAVEFLAG4) { + sloppyclockflag[unit] = in->flags & CLK_FLAG4; + } + } + + if (out != 0) { + out->type = REFCLK_WWVB_SPECTRACOM; + out->haveflags + = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG4; + out->clockdesc = WWVBDESCRIPTION; + out->fudgetime1 = fudgefactor[unit]; + out->fudgetime2.l_ui = 0; + out->fudgetime2.l_uf = 0; + out->fudgeval1 = (LONG)stratumtouse[unit]; + out->fudgeval2 = 0; + out->flags = sloppyclockflag[unit]; + if (unitinuse[unit]) { + wwvb = wwvbunits[unit]; + out->lencode = wwvb->lencode; + out->lastcode = wwvb->lastcode; + out->timereset = current_time - wwvb->timestarted; + out->polls = wwvb->polls; + out->noresponse = wwvb->noreply; + out->badformat = wwvb->badformat; + out->baddata = wwvb->baddata; + out->lastevent = wwvb->lastevent; + out->currentstatus = wwvb->status; + } else { + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} + +/* + * wwvb_buginfo - return clock dependent debugging info + */ +static void +wwvb_buginfo(unit, bug) + int unit; + register struct refclockbug *bug; +{ + register struct wwvbunit *wwvb; + + if (unit >= MAXUNITS) { + syslog(LOG_ERR, "wwvb_buginfo: unit %d invalid", unit); + return; + } + + if (!unitinuse[unit]) + return; + wwvb = wwvbunits[unit]; + + bug->nvalues = 11; + bug->ntimes = 5; + if (wwvb->lasttime != 0) + bug->values[0] = current_time - wwvb->lasttime; + else + bug->values[0] = 0; + bug->values[1] = (U_LONG)wwvb->reason; + bug->values[2] = (U_LONG)wwvb->year; + bug->values[3] = (U_LONG)wwvb->day; + bug->values[4] = (U_LONG)wwvb->hour; + bug->values[5] = (U_LONG)wwvb->minute; + bug->values[6] = (U_LONG)wwvb->second; + bug->values[7] = (U_LONG)wwvb->msec; + bug->values[8] = wwvb->noreply; + bug->values[9] = wwvb->yearstart; + bug->values[10] = wwvb->quality; + bug->stimes = 0x1c; + bug->times[0] = wwvb->lastref; + bug->times[1] = wwvb->lastrec; + bug->times[2] = wwvb->offset[0]; + bug->times[3] = wwvb->offset[1]; + bug->times[4] = wwvb->offset[2]; +} +#endif diff --git a/contrib/xntpd/xntpdc/Makefile.tmpl b/contrib/xntpd/xntpdc/Makefile.tmpl new file mode 100644 index 0000000000..32ed024191 --- /dev/null +++ b/contrib/xntpd/xntpdc/Makefile.tmpl @@ -0,0 +1,68 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:11:58 jbj Exp +# +PROGRAM= xntpdc +# +# xntpdc - private mode query program for xntp +# +COMPILER= cc +COPTS= -O +BINDIR= /usr/local +INSTALL= install +DEFS= +DEFS_OPT= +DEFS_LOCAL= +RESLIB= +COMPAT= +# +INCL= -I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +LIB= ../lib/libntp.a +LINTLIB= ../lib/llib-llibntp.ln +MAKE= make +TOP=../ +# +OBJS= ntpdc.o ntpdc_ops.o +SOURCE= ntpdc.c ntpdc_ops.c + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) $(LIB) version.o + $(CC) $(COPTS) -o $@ $(OBJS) version.o $(LIB) $(RESLIB) $(COMPAT) + +install: $(BINDIR)/$(PROGRAM) + +$(BINDIR)/$(PROGRAM): $(PROGRAM) + $(INSTALL) -c -m 0755 $(PROGRAM) $(BINDIR) + +tags: + ctags *.c *.h + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(PROGRAM) *.o *.out tags make.log Makefile.bak lint.errs .version + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +lint: $(LINTLIB) + lint -x -u $(DEFS) $(DEFS_LOCAL) $(INCL) $(LINTLIB) $(SOURCE) >lint.errs + +../lib/llib-llibntp.ln: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" lintlib + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" + +# +# we want to build the current version string here +# +version.o: ../VERSION + ../scripts/mkversion $(PROGRAM) + $(CC) $(COPTS) $(INCL) -c version.c + +../VERSION: + -@rm -f .version diff --git a/contrib/xntpd/xntpdc/README b/contrib/xntpd/xntpdc/README new file mode 100644 index 0000000000..9d0b661e6c --- /dev/null +++ b/contrib/xntpd/xntpdc/README @@ -0,0 +1,6 @@ +README file for directory ./xntpdc of the NTP Version 3 distribution + +This directory contains the sources for the xntpdc utility program. See +the README and RELNOTES files in the parent directory for directions on +how to make and install this program. The current version number of this +program is in the version.c file. diff --git a/contrib/xntpd/xntpdc/ntpdc.c b/contrib/xntpd/xntpdc/ntpdc.c new file mode 100644 index 0000000000..c5fdf72eb7 --- /dev/null +++ b/contrib/xntpd/xntpdc/ntpdc.c @@ -0,0 +1,1536 @@ +/* ntpdc.c,v 3.1 1993/07/06 01:11:59 jbj Exp + * xntpdc - control and monitor your xntpd daemon + */ +#include +#include +#include +#include +#include +#include +#include + +#include "ntpdc.h" +#include "ntp_select.h" +#include "ntp_io.h" +#include "ntp_stdlib.h" + +/* + * Because we now potentially understand a lot of commands (and + * it requires a lot of commands to talk to xntpd) we will run + * interactive if connected to a terminal. + */ +static int interactive = 0; /* set to 1 when we should prompt */ +static char * prompt = "xntpdc> "; /* prompt to ask him about */ + + +/* + * Keyid used for authenticated requests. Obtained on the fly. + */ +static U_LONG info_auth_keyid; + +/* + * Type of key md5 or des + */ +#define KEY_TYPE_DES 3 +#define KEY_TYPE_MD5 4 + +static int info_auth_keytype = KEY_TYPE_DES; /* DES */ + + +/* + * Built in command handler declarations + */ +static int openhost P((char *)); +static int sendpkt P((char *, int)); +static void growpktdata P((void)); +static int getresponse P((int, int, int *, int *, char **)); +static int sendrequest P((int, int, int, int, int, char *)); +static void getcmds P((void)); +static RETSIGTYPE abortcmd P((int)); +static void docmd P((char *)); +static void tokenize P((char *, char **, int *)); +static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **)); +static int getarg P((char *, int, arg_v *)); +static int getnetnum P((char *, U_LONG *, char *)); +static void help P((struct parse *, FILE *)); +#if defined(sgi) +static int helpsort P((const void *, const void *)); +#else +static int helpsort P((char **, char **)); +#endif /* sgi */ +static void printusage P((struct xcmd *, FILE *)); +static void timeout P((struct parse *, FILE *)); +static void delay P((struct parse *, FILE *)); +static void host P((struct parse *, FILE *)); +static void ntp_poll P((struct parse *, FILE *)); +static void keyid P((struct parse *, FILE *)); +static void keytype P((struct parse *, FILE *)); +static void passwd P((struct parse *, FILE *)); +static void hostnames P((struct parse *, FILE *)); +static void setdebug P((struct parse *, FILE *)); +static void quit P((struct parse *, FILE *)); +static void version P((struct parse *, FILE *)); +static void warning P((char *, char *, char *)); +static void error P((char *, char *, char *)); +static U_LONG getkeyid P((char *)); + + +/* + * Built-in commands we understand + */ +static struct xcmd builtins[] = { + { "?", help, { OPT|STR, NO, NO, NO }, + { "command", "", "", "" }, + "tell the use and syntax of commands" }, + { "help", help, { OPT|STR, NO, NO, NO }, + { "command", "", "", "" }, + "tell the use and syntax of commands" }, + { "timeout", timeout, { OPT|UINT, NO, NO, NO }, + { "msec", "", "", "" }, + "set the primary receive time out" }, + { "delay", delay, { OPT|INT, NO, NO, NO }, + { "msec", "", "", "" }, + "set the delay added to encryption time stamps" }, + { "host", host, { OPT|STR, NO, NO, NO }, + { "hostname", "", "", "" }, + "specify the host whose NTP server we talk to" }, + { "poll", ntp_poll, { OPT|UINT, OPT|STR, NO, NO }, + { "n", "verbose", "", "" }, + "poll an NTP server in client mode `n' times" }, + { "passwd", passwd, { NO, NO, NO, NO }, + { "", "", "", "" }, + "specify a password to use for authenticated requests"}, + { "hostnames", hostnames, { OPT|STR, NO, NO, NO }, + { "yes|no", "", "", "" }, + "specify whether hostnames or net numbers are printed"}, + { "debug", setdebug, { OPT|STR, NO, NO, NO }, + { "no|more|less", "", "", "" }, + "set/change debugging level" }, + { "quit", quit, { NO, NO, NO, NO }, + { "", "", "", "" }, + "exit xntpdc" }, + { "keyid", keyid, { OPT|UINT, NO, NO, NO }, + { "key#", "", "", "" }, + "set keyid to use for authenticated requests" }, + { "keytype", keytype, { STR, NO, NO, NO }, + { "key type (md5|des)", "", "", "" }, + "set key type to use for authenticated requests (des|md5)" }, + { "version", version, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print version number" }, + { 0, 0, { NO, NO, NO, NO }, + { "", "", "", "" }, "" } +}; + + +/* + * Default values we use. + */ +#define DEFTIMEOUT (5) /* 5 second time out */ +#define DEFSTIMEOUT (2) /* 2 second time out after first */ +#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ +#define DEFHOST "localhost" /* default host name */ +#define LENHOSTNAME 256 /* host name is 256 characters LONG */ +#define MAXCMDS 100 /* maximum commands on cmd line */ +#define MAXHOSTS 100 /* maximum hosts on cmd line */ +#define MAXLINE 512 /* maximum line length */ +#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ + +/* + * Some variables used and manipulated locally + */ +static struct timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ +static struct timeval tvsout = { DEFSTIMEOUT, 0 }; /* secondary time out */ +static l_fp delay_time; /* delay time */ +static char currenthost[LENHOSTNAME]; /* current host name */ +static struct sockaddr_in hostaddr = { 0 }; /* host address */ +static int showhostnames = 1; /* show host names by default */ + +static int sockfd; /* fd socket is openned on */ +static int havehost = 0; /* set to 1 when host open */ + struct servent *server_entry = NULL; /* server entry for ntp */ + +/* + * Holds data returned from queries. We allocate INITDATASIZE + * octets to begin with, increasing this as we need to. + */ +#define INITDATASIZE (sizeof(struct resp_pkt) * 16) +#define INCDATASIZE (sizeof(struct resp_pkt) * 8) + +static char *pktdata; +static int pktdatasize; + +/* + * For commands typed on the command line (with the -c option) + */ +static int numcmds = 0; +static char *ccmds[MAXCMDS]; +#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) + +/* + * When multiple hosts are specified. + */ +static int numhosts = 0; +static char *chosts[MAXHOSTS]; +#define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp) + +/* + * Error codes for internal use + */ +#define ERR_INCOMPLETE 16 +#define ERR_TIMEOUT 17 + +/* + * Macro definitions we use + */ +#define ISSPACE(c) ((c) == ' ' || (c) == '\t') +#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +/* + * For converting time stamps to dates + */ +#define JAN_1970 2208988800 /* 1970 - 1900 in seconds */ + +/* + * Jump buffer for longjumping back to the command level + */ +static jmp_buf interrupt_buf; +static int jump = 0; + +/* + * Pointer to current output unit + */ +static FILE *current_output; + +/* + * Command table imported from ntpdc_ops.c + */ +extern struct xcmd opcmds[]; + +char *progname; +int debug; + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + + delay_time.l_ui = 0; + delay_time.l_uf = DEFDELAY; + + progname = argv[0]; + while ((c = getopt_l(argc, argv, "c:dilnps")) != EOF) + switch (c) { + case 'c': + ADDCMD(optarg); + break; + case 'd': + ++debug; + break; + case 'i': + interactive = 1; + break; + case 'l': + ADDCMD("listpeers"); + break; + case 'n': + showhostnames = 0; + break; + case 'p': + ADDCMD("peers"); + break; + case 's': + ADDCMD("dmpeers"); + break; + default: + errflg++; + break; + } + if (errflg) { + (void) fprintf(stderr, + "usage: %s [-dilnps] [-c cmd] host ...\n", + progname); + exit(2); + } + if (optind == argc) { + ADDHOST(DEFHOST); + } else { + for (; optind < argc; optind++) + ADDHOST(argv[optind]); + } + + if (numcmds == 0 && interactive == 0 + && isatty(fileno(stdin)) && isatty(fileno(stderr))) { + interactive = 1; + } + + if (interactive) + (void) signal_no_reset(SIGINT, abortcmd); + + /* + * Initialize the packet data buffer + */ + pktdata = (char *)malloc(INITDATASIZE); + if (pktdata == NULL) { + (void) fprintf(stderr, "%s: malloc() failed!\n", progname); + exit(1); + } + pktdatasize = INITDATASIZE; + + if (numcmds == 0) { + (void) openhost(chosts[0]); + getcmds(); + } else { + int ihost; + int icmd; + + for (ihost = 0; ihost < numhosts; ihost++) { + if (openhost(chosts[ihost])) + for (icmd = 0; icmd < numcmds; icmd++) { + if (numhosts > 1) + printf ("--- %s ---\n",chosts[ihost]); + docmd(ccmds[icmd]); + } + } + } + exit(0); +} + + +/* + * openhost - open a socket to a host + */ +static int +openhost(hname) + char *hname; +{ + U_LONG netnum; + char temphost[LENHOSTNAME]; + + if (server_entry == NULL) { + server_entry = getservbyname("ntp", "udp"); + if (server_entry == NULL) { + (void) fprintf(stderr, "%s: ntp/udp: unknown service\n", + progname); + exit(1); + } + if (debug > 2) + printf("Got ntp/udp service entry\n"); + } + + if (!getnetnum(hname, &netnum, temphost)) + return 0; + + if (debug > 2) + printf("Opening host %s\n", temphost); + + if (havehost == 1) { + if (debug > 2) + printf("Closing old host %s\n", currenthost); + (void) close(sockfd); + havehost = 0; + } + (void) strcpy(currenthost, temphost); + + hostaddr.sin_family = AF_INET; + hostaddr.sin_port = server_entry->s_port; + hostaddr.sin_addr.s_addr = netnum; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) + error("socket", "", ""); + +#if defined(SYS_HPUX) && (SYS_HPUX < 8) +#ifdef SO_RCVBUF + { int rbufsize = INITDATASIZE + 2048; /* 2K for slop */ + if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, + &rbufsize, sizeof(int)) == -1) + error("setsockopt", "", ""); + } +#endif +#endif + + if (connect(sockfd, (struct sockaddr *)&hostaddr, + sizeof(hostaddr)) == -1) + error("connect", "", ""); + + havehost = 1; + return 1; +} + + +/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ +/* + * sendpkt - send a packet to the remote host + */ +static int +sendpkt(xdata, xdatalen) + char *xdata; + int xdatalen; +{ + if (write(sockfd, xdata, xdatalen) == -1) { + warning("write to %s failed", currenthost, ""); + return -1; + } + + return 0; +} + + +/* + * growpktdata - grow the packet data area + */ +static void +growpktdata() +{ + pktdatasize += INCDATASIZE; + pktdata = (char *)realloc(pktdata, pktdatasize); + if (pktdata == 0) { + (void) fprintf(stderr, "%s: realloc() failed!\n", progname); + exit(1); + } +} + + +/* + * getresponse - get a (series of) response packet(s) and return the data + */ +static int +getresponse(implcode, reqcode, ritems, rsize, rdata) + int implcode; + int reqcode; + int *ritems; + int *rsize; + char **rdata; +{ + struct resp_pkt rpkt; + struct timeval tvo; + int items; + int size; + int datasize; + char *datap; + char haveseq[MAXSEQ+1]; + int firstpkt; + int lastseq; + int numrecv; + int seq; + fd_set fds; + int n; + + /* + * This is pretty tricky. We may get between 1 and many packets + * back in response to the request. We peel the data out of + * each packet and collect it in one LONG block. When the last + * packet in the sequence is received we'll know how many we + * should have had. Note we use one LONG time out, should reconsider. + */ + *ritems = 0; + *rsize = 0; + firstpkt = 1; + numrecv = 0; + *rdata = datap = pktdata; + lastseq = 999; /* too big to be a sequence number */ + bzero(haveseq, sizeof(haveseq)); + FD_ZERO(&fds); + +again: + if (firstpkt) + tvo = tvout; + else + tvo = tvsout; + + FD_SET(sockfd, &fds); + n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo); + + if (n == -1) { + warning("select fails", "", ""); + return -1; + } + if (n == 0) { + /* + * Timed out. Return what we have + */ + if (firstpkt) { + (void) fprintf(stderr, + "%s: timed out, nothing received\n", currenthost); + return ERR_TIMEOUT; + } else { + (void) fprintf(stderr, + "%s: timed out with incomplete data\n", + currenthost); + if (debug) { + printf("Received sequence numbers"); + for (n = 0; n <= MAXSEQ; n++) + if (haveseq[n]) + printf(" %d,", n); + if (lastseq != 999) + printf(" last frame received\n"); + else + printf(" last frame not received\n"); + } + return ERR_INCOMPLETE; + } + } + + n = read(sockfd, (char *)&rpkt, sizeof(rpkt)); + if (n == -1) { + warning("read", "", ""); + return -1; + } + + + /* + * Check for format errors. Bug proofing. + */ + if (n < RESP_HEADER_SIZE) { + if (debug) + printf("Short (%d byte) packet received\n", n); + goto again; + } + if (INFO_VERSION(rpkt.rm_vn_mode) != NTP_VERSION) { + if (debug) + printf("Packet received with version %d\n", + INFO_VERSION(rpkt.rm_vn_mode)); + goto again; + } + if (INFO_MODE(rpkt.rm_vn_mode) != MODE_PRIVATE) { + if (debug) + printf("Packet received with mode %d\n", + INFO_MODE(rpkt.rm_vn_mode)); + goto again; + } + if (INFO_IS_AUTH(rpkt.auth_seq)) { + if (debug) + printf("Encrypted packet received\n"); + goto again; + } + if (!ISRESPONSE(rpkt.rm_vn_mode)) { + if (debug) + printf("Received request packet, wanted response\n"); + goto again; + } + if (INFO_MBZ(rpkt.mbz_itemsize) != 0) { + if (debug) + printf("Received packet with nonzero MBZ field!\n"); + goto again; + } + + /* + * Check implementation/request. Could be old data getting to us. + */ + if (rpkt.implementation != implcode || rpkt.request != reqcode) { + if (debug) + printf( + "Received implementation/request of %d/%d, wanted %d/%d", + rpkt.implementation, rpkt.request, + implcode, reqcode); + goto again; + } + + /* + * Check the error code. If non-zero, return it. + */ + if (INFO_ERR(rpkt.err_nitems) != INFO_OKAY) { + if (debug && ISMORE(rpkt.rm_vn_mode)) { + printf("Error code %d received on not-final packet\n", + INFO_ERR(rpkt.err_nitems)); + } + return (int)INFO_ERR(rpkt.err_nitems); + } + + + /* + * Collect items and size. Make sure they make sense. + */ + items = INFO_NITEMS(rpkt.err_nitems); + size = INFO_ITEMSIZE(rpkt.mbz_itemsize); + + if ((datasize = items*size) > (n-RESP_HEADER_SIZE)) { + if (debug) + printf( + "Received items %d, size %d (total %d), data in packet is %d\n", + items, size, datasize, n-RESP_HEADER_SIZE); + goto again; + } + + /* + * If this isn't our first packet, make sure the size matches + * the other ones. + */ + if (!firstpkt && size != *rsize) { + if (debug) + printf("Received itemsize %d, previous %d\n", + size, *rsize); + goto again; + } + + /* + * If we've received this before, toss it + */ + seq = INFO_SEQ(rpkt.auth_seq); + if (haveseq[seq]) { + if (debug) + printf("Received duplicate sequence number %d\n", seq); + goto again; + } + haveseq[seq] = 1; + + /* + * If this is the last in the sequence, record that. + */ + if (!ISMORE(rpkt.rm_vn_mode)) { + if (lastseq != 999) { + printf("Received second end sequence packet\n"); + goto again; + } + lastseq = seq; + } + + /* + * So far, so good. Copy this data into the output array. + */ + if ((datap + datasize) > (pktdata + pktdatasize)) + growpktdata(); + bcopy((char *)rpkt.data, datap, datasize); + datap += datasize; + if (firstpkt) { + firstpkt = 0; + *rsize = size; + } + *ritems += items; + + /* + * Finally, check the count of received packets. If we've got them + * all, return + */ + ++numrecv; + if (numrecv <= lastseq) + goto again; + return INFO_OKAY; +} + + +/* + * sendrequest - format and send a request packet + */ +static int +sendrequest(implcode, reqcode, auth, qitems, qsize, qdata) + int implcode; + int reqcode; + int auth; + int qitems; + int qsize; + char *qdata; +{ + struct req_pkt qpkt; + int datasize; + + bzero((char *)&qpkt, sizeof qpkt); + + qpkt.rm_vn_mode = RM_VN_MODE(0, 0); + qpkt.implementation = (u_char)implcode; + qpkt.request = (u_char)reqcode; + + datasize = qitems * qsize; + if (datasize != 0 && qdata != NULL) { + bcopy(qdata, (char *)qpkt.data, datasize); + qpkt.err_nitems = ERR_NITEMS(0, qitems); + qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize); + } else { + qpkt.err_nitems = ERR_NITEMS(0, 0); + qpkt.mbz_itemsize = MBZ_ITEMSIZE(0); + } + + if (!auth) { + qpkt.auth_seq = AUTH_SEQ(0, 0); + return sendpkt((char *)&qpkt, REQ_LEN_NOMAC); + } else { + l_fp ts; + char *pass; + + if (info_auth_keyid == 0) { + info_auth_keyid = getkeyid("Keyid: "); + if (info_auth_keyid == 0) { + (void) fprintf(stderr, + "Keyid must be defined, request not sent\n"); + return 1; + } + } + if (!auth_havekey(info_auth_keyid)) { + pass = getpass("Password: "); + if (*pass != '\0') + authusekey(info_auth_keyid, info_auth_keytype, + pass); + } + if (auth_havekey(info_auth_keyid)) { + int maclen; + + qpkt.auth_seq = AUTH_SEQ(1, 0); + qpkt.keyid = htonl(info_auth_keyid); + auth1crypt(info_auth_keyid, (U_LONG *)&qpkt, + REQ_LEN_NOMAC); + gettstamp(&ts); + L_ADD(&ts, &delay_time); + HTONL_FP(&ts, &qpkt.tstamp); + maclen = auth2crypt(info_auth_keyid, (U_LONG *)&qpkt, + REQ_LEN_NOMAC); + return sendpkt((char *)&qpkt, REQ_LEN_NOMAC+maclen); + } else { + (void) fprintf(stderr, + "No password, request not sent\n"); + return 1; + } + } + /*NOTREACHED*/ +} + + +/* + * doquery - send a request and process the response + */ +int +doquery(implcode, reqcode, auth, qitems, qsize, qdata, ritems, rsize, rdata) + int implcode; + int reqcode; + int auth; + int qitems; + int qsize; + char *qdata; + int *ritems; + int *rsize; + char **rdata; +{ + int res; + char junk[512]; + fd_set fds; + struct timeval tvzero; + + /* + * Check to make sure host is open + */ + if (!havehost) { + (void) fprintf(stderr, "***No host open, use `host' command\n"); + return -1; + } + + /* + * Poll the socket and clear out any pending data + */ + do { + tvzero.tv_sec = tvzero.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(sockfd, &fds); + res = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero); + + if (res == -1) { + warning("polling select", "", ""); + return -1; + } else if (res > 0) + (void) read(sockfd, junk, sizeof junk); + } while (res > 0); + + + /* + * send a request + */ + res = sendrequest(implcode, reqcode, auth, qitems, qsize, qdata); + if (res != 0) + return res; + + /* + * Get the response. If we got a standard error, print a message + */ + res = getresponse(implcode, reqcode, ritems, rsize, rdata); + + if (res > 0) { + switch(res) { + case INFO_ERR_IMPL: + (void) fprintf(stderr, + "***Server implementation incompatable with our own\n"); + break; + case INFO_ERR_REQ: + (void) fprintf(stderr, + "***Server doesn't implement this request\n"); + case INFO_ERR_FMT: + (void) fprintf(stderr, +"***Server reports a format error in the received packet (shouldn't happen)\n"); + break; + case INFO_ERR_NODATA: + (void) fprintf(stderr, + "***Server reports data not found\n"); + break; + case INFO_ERR_AUTH: + (void) fprintf(stderr, "***Permission denied\n"); + break; + case ERR_TIMEOUT: + (void) fprintf(stderr, "***Request timed out\n"); + break; + case ERR_INCOMPLETE: + (void) fprintf(stderr, + "***Response from server was incomplete\n"); + break; + default: + (void) fprintf(stderr, + "***Server returns unknown error code %d\n", res); + break; + } + } + return res; +} + + +/* + * getcmds - read commands from the standard input and execute them + */ +static void +getcmds() +{ + char line[MAXLINE]; + + for (;;) { + if (interactive) { + (void) fputs(prompt, stderr); + (void) fflush(stderr); + } + + if (fgets(line, sizeof line, stdin) == NULL) + return; + + docmd(line); + } +} + + +/* + * abortcmd - catch interrupts and abort the current command + */ +static RETSIGTYPE +abortcmd(sig) +int sig; +{ + if (current_output == stdout) + (void) fflush(stdout); + putc('\n', stderr); + (void) fflush(stderr); + if (jump) longjmp(interrupt_buf, 1); +} + + +/* + * docmd - decode the command line and execute a command + */ +static void +docmd(cmdline) + char *cmdline; +{ + char *tokens[1+MAXARGS+2]; + struct parse pcmd; + int ntok; + static int i; + struct xcmd *xcmd; + + /* + * Tokenize the command line. If nothing on it, return. + */ + tokenize(cmdline, tokens, &ntok); + if (ntok == 0) + return; + + /* + * Find the appropriate command description. + */ + i = findcmd(tokens[0], builtins, opcmds, &xcmd); + if (i == 0) { + (void) fprintf(stderr, "***Command `%s' unknown\n", + tokens[0]); + return; + } else if (i >= 2) { + (void) fprintf(stderr, "***Command `%s' ambiguous\n", + tokens[0]); + return; + } + + /* + * Save the keyword, then walk through the arguments, interpreting + * as we go. + */ + pcmd.keyword = tokens[0]; + pcmd.nargs = 0; + for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { + if ((i+1) >= ntok) { + if (!(xcmd->arg[i] & OPT)) { + printusage(xcmd, stderr); + return; + } + break; + } + if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) + break; + if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) + return; + pcmd.nargs++; + } + + i++; + if (i < ntok && *tokens[i] == '>') { + char *fname; + + if (*(tokens[i]+1) != '\0') + fname = tokens[i]+1; + else if ((i+1) < ntok) + fname = tokens[i+1]; + else { + (void) fprintf(stderr, "***No file for redirect\n"); + return; + } + + current_output = fopen(fname, "w"); + if (current_output == NULL) { + (void) fprintf(stderr, "***Error opening %s: ", fname); + perror(""); + return; + } + i = 1; /* flag we need a close */ + } else { + current_output = stdout; + i = 0; /* flag no close */ + } + + if (interactive && setjmp(interrupt_buf)) { + return; + } else { + jump = 1; + (xcmd->handler)(&pcmd, current_output); + if (i) (void) fclose(current_output); + } +} + + +/* + * tokenize - turn a command line into tokens + */ +static void +tokenize(line, tokens, ntok) + char *line; + char **tokens; + int *ntok; +{ + register char *cp; + register char *sp; + static char tspace[MAXLINE]; + + sp = tspace; + cp = line; + for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { + tokens[*ntok] = sp; + while (ISSPACE(*cp)) + cp++; + if (ISEOL(*cp)) + break; + do { + *sp++ = *cp++; + } while (!ISSPACE(*cp) && !ISEOL(*cp)); + + *sp++ = '\0'; + } +} + + + +/* + * findcmd - find a command in a command description table + */ +static int +findcmd(str, clist1, clist2, cmd) + register char *str; + struct xcmd *clist1; + struct xcmd *clist2; + struct xcmd **cmd; +{ + register struct xcmd *cl; + register int clen; + int nmatch; + struct xcmd *nearmatch = NULL; + struct xcmd *clist; + + clen = strlen(str); + nmatch = 0; + if (clist1 != 0) + clist = clist1; + else if (clist2 != 0) + clist = clist2; + else + return 0; + +again: + for (cl = clist; cl->keyword != 0; cl++) { + /* do a first character check, for efficiency */ + if (*str != *(cl->keyword)) + continue; + if (strncmp(str, cl->keyword, clen) == 0) { + /* + * Could be extact match, could be approximate. + * Is exact if the length of the keyword is the + * same as the str. + */ + if (*((cl->keyword) + clen) == '\0') { + *cmd = cl; + return 1; + } + nmatch++; + nearmatch = cl; + } + } + + /* + * See if there is more to do. If so, go again. Sorry about the + * goto, too much looking at BSD sources... + */ + if (clist == clist1 && clist2 != 0) { + clist = clist2; + goto again; + } + + /* + * If we got extactly 1 near match, use it, else return number + * of matches. + */ + if (nmatch == 1) { + *cmd = nearmatch; + return 1; + } + return nmatch; +} + + +/* + * getarg - interpret an argument token + */ +static int +getarg(str, code, argp) + char *str; + int code; + arg_v *argp; +{ + int isneg; + char *cp, *np; + static char *digits = "0123456789"; + + switch (code & ~OPT) { + case STR: + argp->string = str; + break; + case ADD: + if (!getnetnum(str, &(argp->netnum), (char *)0)) { + return 0; + } + break; + case INT: + case UINT: + isneg = 0; + np = str; + if (*np == '-') { + np++; + isneg = 1; + } + + argp->uval = 0; + do { + cp = strchr(digits, *np); + if (cp == NULL) { + (void) fprintf(stderr, + "***Illegal integer value %s\n", str); + return 0; + } + argp->uval *= 10; + argp->uval += (cp - digits); + } while (*(++np) != '\0'); + + if (isneg) { + if ((code & ~OPT) == UINT) { + (void) fprintf(stderr, + "***Value %s should be unsigned\n", str); + return 0; + } + argp->ival = -argp->ival; + } + break; + } + + return 1; +} + + +/* + * getnetnum - given a host name, return its net number + * and (optional) full name + */ +static int +getnetnum(host, num, fullhost) + char *host; + U_LONG *num; + char *fullhost; +{ + struct hostent *hp; + + if (decodenetnum(host, num)) { + if (fullhost != 0) { + (void) sprintf(fullhost, + "%d.%d.%d.%d", ((htonl(*num)>>24)&0xff), + ((htonl(*num)>>16)&0xff), ((htonl(*num)>>8)&0xff), + (htonl(*num)&0xff)); + } + return 1; + } else if ((hp = gethostbyname(host)) != 0) { + bcopy(hp->h_addr, (char *)num, sizeof(U_LONG)); + if (fullhost != 0) + (void) strcpy(fullhost, hp->h_name); + return 1; + } else { + (void) fprintf(stderr, "***Can't find host %s\n", host); + return 0; + } + /*NOTREACHED*/ +} + +/* + * nntohost - convert network number to host name. This routine enforces + * the showhostnames setting. + */ +char * +nntohost(netnum) + U_LONG netnum; +{ + if (!showhostnames) + return numtoa(netnum); + if ((ntohl(netnum) & REFCLOCK_MASK) == REFCLOCK_ADDR) + return refnumtoa(netnum); + return numtohost(netnum); +} + + +/* + * Finally, the built in command handlers + */ + +/* + * help - tell about commands, or details of a particular command + */ +static void +help(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int i; + int n; + struct xcmd *xcp; + char *cmd; + char *cmdsort[100]; + int length[100]; + int maxlength; + int numperline; + static char *spaces = " "; /* 20 spaces */ + + if (pcmd->nargs == 0) { + n = 0; + for (xcp = builtins; xcp->keyword != 0; xcp++) { + if (*(xcp->keyword) != '?') + cmdsort[n++] = xcp->keyword; + } + for (xcp = opcmds; xcp->keyword != 0; xcp++) + cmdsort[n++] = xcp->keyword; + +#if defined(sgi) + qsort((void *)cmdsort, n, sizeof(char *), helpsort); +#else + qsort((char *)cmdsort, n, sizeof(char *), helpsort); +#endif /* sgi */ + + maxlength = 0; + for (i = 0; i < n; i++) { + length[i] = strlen(cmdsort[i]); + if (length[i] > maxlength) + maxlength = length[i]; + } + maxlength++; + numperline = 76 / maxlength; + + (void) fprintf(fp, "Commands available:\n"); + for (i = 0; i < n; i++) { + if ((i % numperline) == (numperline-1) + || i == (n-1)) + (void) fprintf(fp, "%s\n", cmdsort[i]); + else + (void) fprintf(fp, "%s%s", cmdsort[i], + spaces+20-maxlength+length[i]); + } + } else { + cmd = pcmd->argval[0].string; + n = findcmd(cmd, builtins, opcmds, &xcp); + if (n == 0) { + (void) fprintf(stderr, + "Command `%s' is unknown\n", cmd); + return; + } else if (n >= 2) { + (void) fprintf(stderr, + "Command `%s' is ambiguous\n", cmd); + return; + } + (void) fprintf(fp, "function: %s\n", xcp->comment); + printusage(xcp, fp); + } +} + + +/* + * helpsort - do hostname qsort comparisons + */ +static int +#if defined(sgi) +helpsort(t1, t2) + const void *t1; + const void *t2; +{ + const char **name1 = (const char **)t1; + const char **name2 = (const char **)t2; +#else +helpsort(name1, name2) + char **name1; + char **name2; +{ +#endif /* sgi */ + return strcmp(*name1, *name2); +} + + +/* + * printusage - print usage information for a command + */ +static void +printusage(xcp, fp) + struct xcmd *xcp; + FILE *fp; +{ + register int i; + + (void) fprintf(fp, "usage: %s", xcp->keyword); + for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { + if (xcp->arg[i] & OPT) + (void) fprintf(fp, " [ %s ]", xcp->desc[i]); + else + (void) fprintf(fp, " %s", xcp->desc[i]); + } + (void) fprintf(fp, "\n"); +} + + +/* + * timeout - set time out time + */ +static void +timeout(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int val; + + if (pcmd->nargs == 0) { + val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000; + (void) fprintf(fp, "primary timeout %d ms\n", val); + } else { + tvout.tv_sec = pcmd->argval[0].uval / 1000; + tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000)) + * 1000; + } +} + + +/* + * delay - set delay for auth requests + */ +static void +delay(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int isneg; + U_LONG val; + + if (pcmd->nargs == 0) { + val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; + (void) fprintf(fp, "delay %d ms\n", val); + } else { + if (pcmd->argval[0].ival < 0) { + isneg = 1; + val = (U_LONG)(-pcmd->argval[0].ival); + } else { + isneg = 0; + val = (U_LONG)pcmd->argval[0].ival; + } + + delay_time.l_ui = val / 1000; + val %= 1000; + delay_time.l_uf = val * 4294967; /* 2**32/1000 */ + + if (isneg) + L_NEG(&delay_time); + } +} + + +/* + * host - set the host we are dealing with. + */ +static void +host(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) { + if (havehost) + (void) fprintf(fp, "current host is %s\n", currenthost); + else + (void) fprintf(fp, "no current host\n"); + } else if (openhost(pcmd->argval[0].string)) { + (void) fprintf(fp, "current host set to %s\n", currenthost); + } else { + if (havehost) + (void) fprintf(fp, + "current host remains %s\n", currenthost); + else + (void) fprintf(fp, "still no current host\n"); + } +} + + +/* + * poll - do one (or more) polls of the host via NTP + */ +/*ARGSUSED*/ +static void +ntp_poll(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + (void) fprintf(fp, "poll not implemented yet\n"); +} + + +/* + * keyid - get a keyid to use for authenticating requests + */ +static void +keyid(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) { + if (info_auth_keyid == 0) + (void) fprintf(fp, "no keyid defined\n"); + else + (void) fprintf(fp, "keyid is %u\n", info_auth_keyid); + } else { + info_auth_keyid = pcmd->argval[0].uval; + } +} + + +/* + * keytype - get type of key to use for authenticating requests + */ +static void +keytype(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) + fprintf(fp, "keytype is %s", + (info_auth_keytype == KEY_TYPE_MD5) ? "md5" : "des"); + else + switch (*(pcmd->argval[0].string)) { + case 'm': + case 'M': + info_auth_keytype = KEY_TYPE_MD5; + break; + + case 'd': + case 'D': + info_auth_keytype = KEY_TYPE_DES; + break; + + default: + fprintf(fp, "keytype must be 'md5' or 'des'\n"); + } +} + + + +/* + * passwd - get an authentication key + */ +/*ARGSUSED*/ +static void +passwd(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + char *pass; + + if (info_auth_keyid == 0) { + info_auth_keyid = getkeyid("Keyid: "); + if (info_auth_keyid == 0) { + (void)fprintf(fp, "Keyid must be defined\n"); + return; + } + } + pass = getpass("Password: "); + if (*pass == '\0') + (void) fprintf(fp, "Password unchanged\n"); + else + authusekey(info_auth_keyid, info_auth_keytype, pass); +} + + +/* + * hostnames - set the showhostnames flag + */ +static void +hostnames(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) { + if (showhostnames) + (void) fprintf(fp, "hostnames being shown\n"); + else + (void) fprintf(fp, "hostnames not being shown\n"); + } else { + if (STREQ(pcmd->argval[0].string, "yes")) + showhostnames = 1; + else if (STREQ(pcmd->argval[0].string, "no")) + showhostnames = 0; + else + (void)fprintf(stderr, "What?\n"); + } +} + + +/* + * setdebug - set/change debugging level + */ +static void +setdebug(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (pcmd->nargs == 0) { + (void) fprintf(fp, "debug level is %d\n", debug); + return; + } else if (STREQ(pcmd->argval[0].string, "no")) { + debug = 0; + } else if (STREQ(pcmd->argval[0].string, "more")) { + debug++; + } else if (STREQ(pcmd->argval[0].string, "less")) { + debug--; + } else { + (void) fprintf(fp, "What?\n"); + return; + } + (void) fprintf(fp, "debug level set to %d\n", debug); +} + + +/* + * quit - stop this nonsense + */ +/*ARGSUSED*/ +static void +quit(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + if (havehost) + (void) close(sockfd); /* cleanliness next to godliness */ + exit(0); +} + + +/* + * version - print the current version number + */ +/*ARGSUSED*/ +static void +version(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + extern char *Version; + + (void) fprintf(fp, "%s\n", Version); +} + + +/* + * warning - print a warning message + */ +static void +warning(fmt, st1, st2) + char *fmt; + char *st1; + char *st2; +{ + (void) fprintf(stderr, "%s: ", progname); + (void) fprintf(stderr, fmt, st1, st2); + (void) fprintf(stderr, ": "); + perror(""); +} + + +/* + * error - print a message and exit + */ +static void +error(fmt, st1, st2) + char *fmt; + char *st1; + char *st2; +{ + warning(fmt, st1, st2); + exit(1); +} + +/* + * getkeyid - prompt the user for a keyid to use + */ +static U_LONG +getkeyid(prompt) +char *prompt; +{ + register char *p; + register c; + FILE *fi; + char pbuf[20]; + + if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) + fi = stdin; + else + setbuf(fi, (char *)NULL); + fprintf(stderr, "%s", prompt); fflush(stderr); + for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) { + if (p < &pbuf[18]) + *p++ = c; + } + *p = '\0'; + if (fi != stdin) + fclose(fi); + return (U_LONG)atoi(pbuf); +} diff --git a/contrib/xntpd/xntpdc/ntpdc.h b/contrib/xntpd/xntpdc/ntpdc.h new file mode 100644 index 0000000000..7784ebc5a6 --- /dev/null +++ b/contrib/xntpd/xntpdc/ntpdc.h @@ -0,0 +1,59 @@ +/* ntpdc.h,v 3.1 1993/07/06 01:12:01 jbj Exp + * ntpdc.h - definitions of interest to xntpdc + */ +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_request.h" +#include "ntp_string.h" +#include "ntp_malloc.h" + +/* + * Maximum number of arguments + */ +#define MAXARGS 4 + +/* + * Flags for forming descriptors. + */ +#define OPT 0x80 /* this argument is optional, or'd with type */ + +#define NO 0x0 +#define STR 0x1 /* string argument */ +#define UINT 0x2 /* unsigned integer */ +#define INT 0x3 /* signed integer */ +#define ADD 0x4 /* IP network address */ + +/* + * Arguments are returned in a union + */ +typedef union { + char *string; + LONG ival; + U_LONG uval; + U_LONG netnum; +} arg_v; + +/* + * Structure for passing parsed command line + */ +struct parse { + char *keyword; + arg_v argval[MAXARGS]; + int nargs; +}; + +/* + * xntpdc includes a command parser which could charitably be called + * crude. The following structure is used to define the command + * syntax. + */ +struct xcmd { + char *keyword; /* command key word */ + void (*handler) P((struct parse *, FILE *)); /* command handler */ + u_char arg[MAXARGS]; /* descriptors for arguments */ + char *desc[MAXARGS]; /* descriptions for arguments */ + char *comment; +}; + +extern int doquery P((int, int, int, int, int, char *, int *, int *, char **)); +extern char * nntohost P((U_LONG)); diff --git a/contrib/xntpd/xntpdc/ntpdc_ops.c b/contrib/xntpd/xntpdc/ntpdc_ops.c new file mode 100644 index 0000000000..26f7e91d8f --- /dev/null +++ b/contrib/xntpd/xntpdc/ntpdc_ops.c @@ -0,0 +1,2421 @@ +/* ntpdc_ops.c,v 3.1 1993/07/06 01:12:02 jbj Exp + * ntpdc_ops.c - subroutines which are called to perform operations by xntpdc + */ +#include +#include +#include +#include +#include + +#include "ntpdc.h" +#include "ntp_control.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +/* + * Declarations for command handlers in here + */ +static int checkitems P((int, FILE *)); +static int checkitemsize P((int, int)); +static int check1item P((int, FILE *)); +static void peerlist P((struct parse *, FILE *)); +static void peers P((struct parse *, FILE *)); +static void dmpeers P((struct parse *, FILE *)); +static void dopeers P((struct parse *, FILE *, int)); +static void printpeer P((struct info_peer *, FILE *)); +static void showpeer P((struct parse *, FILE *)); +static void peerstats P((struct parse *, FILE *)); +static void loopinfo P((struct parse *, FILE *)); +static void sysinfo P((struct parse *, FILE *)); +static void sysstats P((struct parse *, FILE *)); +static void iostats P((struct parse *, FILE *)); +static void memstats P((struct parse *, FILE *)); +static void timerstats P((struct parse *, FILE *)); +static void addpeer P((struct parse *, FILE *)); +static void addserver P((struct parse *, FILE *)); +static void broadcast P((struct parse *, FILE *)); +static void doconfig P((struct parse *, FILE *, int)); +static void unconfig P((struct parse *, FILE *)); +static void set P((struct parse *, FILE *)); +static void sys_clear P((struct parse *, FILE *)); +static void doset P((struct parse *, FILE *, int)); +static void reslist P((struct parse *, FILE *)); +static void restrict P((struct parse *, FILE *)); +static void unrestrict P((struct parse *, FILE *)); +static void delrestrict P((struct parse *, FILE *)); +static void do_restrict P((struct parse *, FILE *, int)); +static void monlist P((struct parse *, FILE *)); +static void monitor P((struct parse *, FILE *)); +static void reset P((struct parse *, FILE *)); +static void preset P((struct parse *, FILE *)); +static void readkeys P((struct parse *, FILE *)); +static void dodirty P((struct parse *, FILE *)); +static void dontdirty P((struct parse *, FILE *)); +static void trustkey P((struct parse *, FILE *)); +static void untrustkey P((struct parse *, FILE *)); +static void do_trustkey P((struct parse *, FILE *, int)); +static void authinfo P((struct parse *, FILE *)); +static void traps P((struct parse *, FILE *)); +static void addtrap P((struct parse *, FILE *)); +static void clrtrap P((struct parse *, FILE *)); +static void do_addclr_trap P((struct parse *, FILE *, int)); +static void requestkey P((struct parse *, FILE *)); +static void controlkey P((struct parse *, FILE *)); +static void do_changekey P((struct parse *, FILE *, int)); +static void ctlstats P((struct parse *, FILE *)); +static void leapinfo P((struct parse *, FILE *)); +static void clockstat P((struct parse *, FILE *)); +static void fudge P((struct parse *, FILE *)); +static void maxskew P((struct parse *, FILE *)); +static void clkbug P((struct parse *, FILE *)); +static void setprecision P((struct parse *, FILE *)); +static void setselect P((struct parse *, FILE *)); + +/* + * Commands we understand. Ntpdc imports this. + */ +struct xcmd opcmds[] = { + { "listpeers", peerlist, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print list of peers the server knows about" }, + { "peers", peers, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print peer summary information" }, + { "dmpeers", dmpeers, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print peer summary info the way Dave Mills likes it" }, + { "showpeer", showpeer, { ADD, OPT|ADD, OPT|ADD, OPT|ADD }, + { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" }, + "print detailed information for one or more peers" }, + { "pstats", peerstats, { ADD, OPT|ADD, OPT|ADD, OPT|ADD }, + { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" }, + "print statistical information for one or more peers" }, + { "loopinfo", loopinfo, { OPT|STR, NO, NO, NO }, + { "oneline|multiline", "", "", "" }, + "print loop filter information" }, + { "sysinfo", sysinfo, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print local server information" }, + { "sysstats", sysstats, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print local server statistics" }, + { "memstats", memstats, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print peer memory usage statistics" }, + { "iostats", iostats, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print I/O subsystem statistics" }, + { "timerstats", timerstats, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print event timer subsystem statistics" }, + { "addpeer", addpeer, { ADD, OPT|UINT, OPT|UINT, OPT|STR }, + { "addr", "keyid", "version", "minpoll|prefer" }, + "configure a new peer association" }, + { "addserver", addserver, { ADD, OPT|UINT, OPT|UINT, OPT|STR }, + { "addr", "keyid", "version", "minpoll|prefer" }, + "configure a new server" }, + { "broadcast", broadcast, { ADD, OPT|UINT, OPT|UINT, OPT|STR }, + { "addr", "keyid", "version", "minpoll" }, + "configure broadcasting time service" }, + { "unconfig", unconfig, { ADD, OPT|ADD, OPT|ADD, OPT|ADD }, + { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" }, + "unconfigure existing peer assocations" }, + { "set", set, { STR, OPT|STR, OPT|STR, OPT|STR }, + { "bclient|auth", "...", "...", "..." }, + "set a system flag (bclient, authenticate)" }, + { "clear", sys_clear, { STR, OPT|STR, OPT|STR, OPT|STR }, + { "bclient|auth", "...", "...", "..." }, + "clear a system flag (bclient, authenticate)" }, + { "reslist", reslist, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print the server's restrict list" }, + { "restrict", restrict, { ADD, ADD, STR, OPT|STR }, + { "address", "mask", + "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer", + "..." }, + "create restrict entry/add flags to entry" }, + { "unrestrict", unrestrict, { ADD, ADD, STR, OPT|STR }, + { "address", "mask", + "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer", + "..." }, + "remove flags from a restrict entry" }, + { "delrestrict", delrestrict, { ADD, ADD, OPT|STR, NO }, + { "address", "mask", "ntpport", "" }, + "delete a restrict entry" }, + { "monlist", monlist, { NO, NO, NO, NO }, + { "", "", "", "" }, + "print data the server's monitor routines have collected" }, + { "monitor", monitor, { STR, NO, NO, NO }, + { "on|off", "", "", "" }, + "turn the server's monitoring facility on or off" }, + { "reset", reset, { STR, OPT|STR, OPT|STR, OPT|STR }, + { "io|sys|mem|timer|auth|allpeers", "...", "...", "..." }, + "reset various subsystem statistics counters" }, + { "preset", preset, { ADD, OPT|ADD, OPT|ADD, OPT|ADD }, + { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" }, + "reset stat counters associated with particular peer(s)" }, + { "readkeys", readkeys, { NO, NO, NO, NO }, + { "", "", "", "" }, + "request a reread of the `keys' file and re-init of system keys" }, + { "dodirty", dodirty, { NO, NO, NO, NO }, + { "", "", "", "" }, + "placeholder, historical interest only" }, + { "dontdirty", dontdirty, { NO, NO, NO, NO }, + { "", "", "", "" }, + "placeholder, historical interest only" }, + { "trustkey", trustkey, { UINT, OPT|UINT, OPT|UINT, OPT|UINT }, + { "keyid", "keyid", "keyid", "keyid" }, + "add one or more key ID's to the trusted list" }, + { "untrustkey", untrustkey, { UINT, OPT|UINT, OPT|UINT, OPT|UINT }, + { "keyid", "keyid", "keyid", "keyid" }, + "remove one or more key ID's from the trusted list" }, + { "authinfo", authinfo, { NO, NO, NO, NO }, + { "", "", "", "" }, + "obtain information concerning the state of the authentication code" }, + { "traps", traps, { NO, NO, NO, NO }, + { "", "", "", "" }, + "obtain information about traps set in server" }, + { "addtrap", addtrap, { ADD, OPT|UINT, OPT|ADD, NO }, + { "address", "port", "interface", "" }, + "configure a trap in the server" }, + { "clrtrap", clrtrap, { ADD, OPT|UINT, OPT|ADD, NO }, + { "address", "port", "interface", "" }, + "remove a trap (configured or otherwise) from the server" }, + { "requestkey", requestkey, { UINT, NO, NO, NO }, + { "keyid", "", "", "" }, + "change the keyid the server uses to authenticate requests" }, + { "controlkey", controlkey, { UINT, NO, NO, NO }, + { "keyid", "", "", "" }, + "change the keyid the server uses to authenticate control messages" }, + { "ctlstats", ctlstats, { NO, NO, NO, NO }, + { "", "", "", "" }, + "obtain packet count statistics from the control module" }, + { "leapinfo", leapinfo, { NO, NO, NO, NO }, + { "", "", "", "" }, + "obtain information about the current leap second state" }, + { "clockstat", clockstat, { ADD, OPT|ADD, OPT|ADD, OPT|ADD }, + { "address", "address", "address", "address" }, + "obtain status information about the specified clock" }, + { "fudge", fudge, { ADD, STR, STR, NO }, + { "address", "time1|time2|val1|val2|flags", "value", "" }, + "set/change one of a clock's fudge factors" }, + { "maxskew", maxskew, { STR, NO, NO, NO }, + { "maximum_skew", "", "", "" }, + "set the server's maximum skew parameter" }, + { "clkbug", clkbug, { ADD, OPT|ADD, OPT|ADD, OPT|ADD }, + { "address", "address", "address", "address" }, + "obtain debugging information from the specified clock" }, + { "setprecision", setprecision, { INT, NO, NO, NO }, + { "sys_precision", "", "", "" }, + "set the server's advertised precision" }, + { "setselect", setselect, { UINT, NO, NO, NO }, + { "select_algorithm_number", "", "", "" }, + "change the selection weighting algorithm used by the server" }, + { 0, 0, { NO, NO, NO, NO }, + { "", "", "", "" }, "" } +}; + + +/* + * Imported from ntpdc.c + */ +extern int showhostnames; +extern int debug; +extern struct servent *server_entry; + +/* + * For quick string comparisons + */ +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + + +/* + * checkitems - utility to print a message if no items were returned + */ +static int +checkitems(items, fp) + int items; + FILE *fp; +{ + if (items == 0) { + (void) fprintf(fp, "No data returned in response to query\n"); + return 0; + } + return 1; +} + + +/* + * checkitemsize - utility to print a message if the item size is wrong + */ +static int +checkitemsize(itemsize, expected) + int itemsize; + int expected; +{ + if (itemsize != expected) { + (void) fprintf(stderr, + "***Incorrect item size returned by remote host (%d should be %d)\n", + itemsize, expected); + return 0; + } + return 1; +} + + +/* + * check1item - check to make sure we have exactly one item + */ +static int +check1item(items, fp) + int items; + FILE *fp; +{ + if (items == 0) { + (void) fprintf(fp, "No data returned in response to query\n"); + return 0; + } + if (items > 1) { + (void) fprintf(fp, "Expected one item in response, got %d\n", + items); + return 0; + } + return 1; +} + + + +/* + * peerlist - get a short list of peers + */ +/*ARGSUSED*/ +static void +peerlist(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_peer_list *plist; + int items; + int itemsize; + int res; + + res = doquery(IMPL_XNTPD, REQ_PEER_LIST, 0, 0, 0, (char *)NULL, &items, + &itemsize, (char **)&plist); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_peer_list))) + return; + + while (items > 0) { + (void) fprintf(fp, "%-9s %s\n", modetoa(plist->hmode), + nntohost(plist->address)); + plist++; + items--; + } +} + + +/* + * peers - show peer summary + */ +static void +peers(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + dopeers(pcmd, fp, 0); +} + +/* + * dmpeers - show peer summary, Dave Mills style + */ +static void +dmpeers(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + dopeers(pcmd, fp, 1); +} + + +/* + * peers - show peer summary + */ +/*ARGSUSED*/ +static void +dopeers(pcmd, fp, dmstyle) + struct parse *pcmd; + FILE *fp; + int dmstyle; +{ + struct info_peer_summary *plist; + int items; + int itemsize; + int ntp_poll; + int res; + int c; + l_fp tempts; + + res = doquery(IMPL_XNTPD, REQ_PEER_LIST_SUM, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&plist); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_peer_summary))) + return; + + (void) fprintf(fp, + " remote local st poll reach delay offset disp\n"); + (void) fprintf(fp, + "======================================================================\n"); + while (items > 0) { + if (!dmstyle) { + if (plist->flags & INFO_FLAG_SYSPEER) + c = '*'; + else if (plist->hmode == MODE_ACTIVE) + c = '+'; + else if (plist->hmode == MODE_PASSIVE) + c = '-'; + else if (plist->hmode == MODE_CLIENT) + c = '='; + else if (plist->hmode == MODE_BROADCAST) + c = '^'; + else if (plist->hmode == MODE_BCLIENT) + c = '~'; + else + c = ' '; + } else { + if (plist->flags & INFO_FLAG_SYSPEER) + c = '*'; + else if (plist->flags & INFO_FLAG_SHORTLIST) + c = '+'; + else if (plist->flags & INFO_FLAG_SEL_CANDIDATE) + c = '.'; + else + c = ' '; + } + NTOHL_FP(&(plist->offset), &tempts); + ntp_poll = 1<ppoll, plist->hpoll, NTP_MAXPOLL), + NTP_MINPOLL); + (void) fprintf(fp, + "%c%-15.15s %-15.15s %2d %4d %3o %7.7s %9.9s %6.6s\n", + c, nntohost(plist->srcadr), + numtoa(plist->dstadr), + plist->stratum, ntp_poll, plist->reach, + fptoa(NTOHS_FP(plist->delay), 4), + lfptoa(&tempts, 6), + ufptoa(NTOHS_FP(plist->dispersion), 4)); + plist++; + items--; + } +} + + +/* + * printpeer - print detail information for a peer + */ +static void +printpeer(pp, fp) + register struct info_peer *pp; + FILE *fp; +{ + register int i; + char junk[5]; + char *str; + l_fp tempts; + + (void) fprintf(fp, "remote %s, local %s\n", + numtoa(pp->srcadr), numtoa(pp->dstadr)); + + (void) fprintf(fp, "hmode %s, pmode %s, stratum %d, precision %d\n", + modetoa(pp->hmode), modetoa(pp->pmode), + pp->stratum, pp->precision); + + if (pp->stratum <= 1) { + junk[4] = 0; + bcopy((char *)&pp->refid, junk, 4); + str = junk; + } else { + str = numtoa(pp->refid); + } + (void) fprintf(fp, + "leap %c%c, refid [%s], rootdistance %s, rootdispersion %s\n", + pp->leap & 0x2 ? '1' : '0', + pp->leap & 0x1 ? '1' : '0', + str, ufptoa(HTONS_FP(pp->rootdelay), 4), + ufptoa(HTONS_FP(pp->rootdispersion), 4)); + + (void) fprintf(fp, + "ppoll %d, hpoll %d, keyid %u, version %d, association %u\n", + pp->ppoll, pp->hpoll, pp->keyid, pp->version, ntohs(pp->associd)); + + (void) fprintf(fp, + "valid %d, reach %03o, unreach %d, trust %03o\n", + pp->valid, pp->reach, pp->unreach, pp->trust); + + (void) fprintf(fp, "timer %ds, flags", ntohl(pp->timer)); + if (pp->flags == 0) { + (void) fprintf(fp, " none\n"); + } else { + str = ""; + if (pp->flags & INFO_FLAG_SYSPEER) { + (void) fprintf(fp, " system_peer"); + str = ","; + } + if (pp->flags & INFO_FLAG_CONFIG) { + (void) fprintf(fp, "%s configured", str); + str = ","; + } + if (pp->flags & INFO_FLAG_MINPOLL) { + (void) fprintf(fp, "%s minpoll", str); + str = ","; + } + if (pp->flags & INFO_FLAG_AUTHENABLE) { + (void) fprintf(fp, "%s authenable", str); + str = ","; + } + if (pp->flags & INFO_FLAG_REFCLOCK) { + (void) fprintf(fp, "%s reference_clock", str); + str = ","; + } + if (pp->flags & INFO_FLAG_PREFER) { + (void) fprintf(fp, "%s preferred_peer", str); + } + (void) fprintf(fp, "\n"); + } + + HTONL_FP(&pp->reftime, &tempts); + (void) fprintf(fp, "reference time: %s\n", + prettydate(&tempts)); + HTONL_FP(&pp->org, &tempts); + (void) fprintf(fp, "originate timestamp: %s\n", + prettydate(&tempts)); + HTONL_FP(&pp->rec, &tempts); + (void) fprintf(fp, "receive timestamp: %s\n", + prettydate(&tempts)); + HTONL_FP(&pp->xmt, &tempts); + (void) fprintf(fp, "transmit timestamp: %s\n", + prettydate(&tempts)); + + (void) fprintf(fp, "filter delay: "); + for (i = 0; i < NTP_SHIFT; i++) { + (void) fprintf(fp, " %-8.8s", fptoa(HTONS_FP(pp->filtdelay[i]),4)); + if (i == (NTP_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "filter offset:"); + for (i = 0; i < NTP_SHIFT; i++) { + HTONL_FP(&pp->filtoffset[i], &tempts); + (void) fprintf(fp, " %-8.8s", lfptoa(&tempts, 5)); + if (i == (NTP_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "filter order: "); + for (i = 0; i < NTP_SHIFT; i++) { + (void) fprintf(fp, " %-8d", pp->order[i]); + if (i == (NTP_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "bdelay filter:"); + for (i = 0; i < NTP_SHIFT; i++) { + (void) fprintf(fp, " %-8.8s", + mfptoa(0, ntohl(pp->bdelay[i]), 5)); + if (i == (NTP_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "delay %s, estbdelay %s\n", + fptoa(HTONS_FP(pp->delay), 4), + mfptoa(0, ntohl(pp->estbdelay), 4)); + + HTONL_FP(&pp->offset, &tempts); + (void) fprintf(fp, "offset %s, dispersion %s\n", + lfptoa(&tempts, 6), + ufptoa(HTONS_FP(pp->dispersion), 4)); +} + + +/* + * showpeer - show detailed information for a peer + */ +static void +showpeer(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_peer *pp; + /* 4 is the maximum number of peers which will fit in a packet */ + struct info_peer_list plist[min(MAXARGS, 4)]; + int qitems; + int items; + int itemsize; + int res; + + for (qitems = 0; qitems < min(pcmd->nargs, 4); qitems++) { + plist[qitems].address = pcmd->argval[qitems].netnum; + plist[qitems].port = server_entry->s_port; + plist[qitems].hmode = plist[qitems].flags = 0; + } + + res = doquery(IMPL_XNTPD, REQ_PEER_INFO, 0, qitems, + sizeof(struct info_peer_list), (char *)plist, &items, + &itemsize, (char **)&pp); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_peer))) + return; + + while (items-- > 0) { + printpeer(pp, fp); + if (items > 0) + (void) fprintf(fp, "\n"); + pp++; + } +} + + +/* + * peerstats - return statistics for a peer + */ +static void +peerstats(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_peer_stats *pp; + /* 4 is the maximum number of peers which will fit in a packet */ + struct info_peer_list plist[min(MAXARGS, 4)]; + int qitems; + int items; + int itemsize; + int res; + + for (qitems = 0; qitems < min(pcmd->nargs, 4); qitems++) { + plist[qitems].address = pcmd->argval[qitems].netnum; + plist[qitems].port = server_entry->s_port; + plist[qitems].hmode = plist[qitems].flags = 0; + } + + res = doquery(IMPL_XNTPD, REQ_PEER_STATS, 0, qitems, + sizeof(struct info_peer_list), (char *)plist, &items, + &itemsize, (char **)&pp); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_peer_stats))) + return; + + while (items-- > 0) { + (void) fprintf(fp, "remote host: %s\n", + nntohost(pp->srcadr)); + (void) fprintf(fp, "local interface: %s\n", + numtoa(pp->dstadr)); + (void) fprintf(fp, "time last received: %ds\n", + ntohl(pp->timereceived)); + (void) fprintf(fp, "time until next send: %ds\n", + ntohl(pp->timetosend)); + (void) fprintf(fp, "reachability change: %ds\n", + ntohl(pp->timereachable)); + (void) fprintf(fp, "packets sent: %d\n", + ntohl(pp->sent)); + (void) fprintf(fp, "packets received: %d\n", + ntohl(pp->received)); + (void) fprintf(fp, "packets processed: %d\n", + ntohl(pp->processed)); + (void) fprintf(fp, "bad length packets: %d\n", + ntohl(pp->badlength)); + (void) fprintf(fp, "bad auth packets: %d\n", + ntohl(pp->badauth)); + (void) fprintf(fp, "bogus origin packets: %d\n", + ntohl(pp->bogusorg)); + (void) fprintf(fp, "duplicate packets: %d\n", + ntohl(pp->oldpkt)); + (void) fprintf(fp, "bad delay rejections: %d\n", + ntohl(pp->baddelay)); + (void) fprintf(fp, "select delay rejects: %d\n", + ntohl(pp->seldelay)); + (void) fprintf(fp, "select disp rejects: %d\n", + ntohl(pp->seldisp)); + (void) fprintf(fp, "select finds broken: %d\n", + ntohl(pp->selbroken)); + (void) fprintf(fp, "too old for select: %d\n", + ntohl(pp->selold)); + (void) fprintf(fp, "sel candidate order: %d\n", + (int)pp->candidate); + (void) fprintf(fp, "falseticker order: %d\n", + (int)pp->falseticker); + (void) fprintf(fp, "select order: %d\n", + (int)pp->select); + (void) fprintf(fp, "select total: %d\n", + (int)pp->select_total); + if (items > 0) + (void) fprintf(fp, "\n"); + pp++; + } +} + + +/* + * loopinfo - show loop filter information + */ +static void +loopinfo(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_loop *il; + int items; + int itemsize; + int oneline = 0; + int res; + l_fp tempts; + + if (pcmd->nargs > 0) { + if (STREQ(pcmd->argval[0].string, "oneline")) + oneline = 1; + else if (STREQ(pcmd->argval[0].string, "multiline")) + oneline = 0; + else { + (void) fprintf(stderr, "How many lines?\n"); + return; + } + } + + res = doquery(IMPL_XNTPD, REQ_LOOP_INFO, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&il); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_loop))) + return; + + if (oneline) { + l_fp temp2ts; + + HTONL_FP(&il->last_offset, &tempts); + HTONL_FP(&il->drift_comp, &temp2ts); + + (void) fprintf(fp, + "offset %s, drift %s, compliance %d, timer %d seconds\n", + lfptoa(&tempts, 7), + lfptoa(&temp2ts, 7), + ntohl(il->compliance), + ntohl(il->watchdog_timer)); + } else { + HTONL_FP(&il->last_offset, &tempts); + (void) fprintf(fp, "offset: %s seconds\n", + lfptoa(&tempts, 7)); + HTONL_FP(&il->drift_comp, &tempts); + (void) fprintf(fp, "frequency: %s seconds\n", + lfptoa(&tempts, 7)); + (void) fprintf(fp, "compliance: %d seconds\n", + ntohl(il->compliance)); + (void) fprintf(fp, "timer: %d seconds\n", + ntohl(il->watchdog_timer)); + } +} + + +/* + * sysinfo - show current system state + */ +/*ARGSUSED*/ +static void +sysinfo(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_sys *is; + int items; + int itemsize; + int res; + char junk[5]; + char *str; + l_fp tempts; + + res = doquery(IMPL_XNTPD, REQ_SYS_INFO, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&is); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_sys))) + return; + + (void) fprintf(fp, "system peer: %s\n", nntohost(is->peer)); + (void) fprintf(fp, "system peer mode: %s\n", modetoa(is->peer_mode)); + (void) fprintf(fp, "leap indicator: %c%c\n", + is->leap & 0x2 ? '1' : '0', + is->leap & 0x1 ? '1' : '0'); + (void) fprintf(fp, "stratum: %d\n", (int)is->stratum); + (void) fprintf(fp, "precision: %d\n", (int)is->precision); + (void) fprintf(fp, "select algorithm: %d\n", (int)is->selection); + (void) fprintf(fp, "sync distance: %s\n", + fptoa(NTOHS_FP(is->rootdelay), 4)); + (void) fprintf(fp, "sync dispersion: %s\n", + ufptoa(NTOHS_FP(is->rootdispersion), 4)); + if (is->stratum <= 1) { + junk[4] = 0; + bcopy((char *)&is->refid, junk, 4); + str = junk; + } else { + str = numtoa(is->refid); + } + (void) fprintf(fp, "reference ID: [%s]\n", str); + + HTONL_FP(&is->reftime, &tempts); + (void) fprintf(fp, "reference time: %s\n", prettydate(&tempts)); + + (void) fprintf(fp, "system flags: "); + if ((is->flags & (INFO_FLAG_BCLIENT|INFO_FLAG_AUTHENABLE)) == 0) { + (void) fprintf(fp, "none\n"); + } else { + res = 0; + if (is->flags & INFO_FLAG_BCLIENT) { + (void) fprintf(fp, "bclient"); + res = 1; + } + if (is->flags & INFO_FLAG_AUTHENABLE) + (void) fprintf(fp, "%sauthenticate", + res ? ", " : ""); + (void) fprintf(fp, "\n"); + } + + HTONL_FP(&is->bdelay, &tempts); + (void) fprintf(fp, "broadcast delay: %s\n", lfptoa(&tempts, 7)); + + HTONL_FP(&is->authdelay, &tempts); + (void) fprintf(fp, "encryption delay: %s\n", lfptoa(&tempts, 7)); + (void) fprintf(fp, "maximum skew: %s\n", + ufptoa(NTOHS_FP(is->maxskew), 4)); +} + + +/* + * sysstats - print system statistics + */ +/*ARGSUSED*/ +static void +sysstats(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_sys_stats *ss; + int items; + int itemsize; + int res; + + res = doquery(IMPL_XNTPD, REQ_SYS_STATS, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&ss); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_sys_stats))) + return; + + (void) fprintf(fp, "system uptime: %d\n", + ntohl(ss->timeup)); + (void) fprintf(fp, "time since reset: %d\n", + ntohl(ss->timereset)); + (void) fprintf(fp, "bad stratum in packet: %d\n", + ntohl(ss->badstratum)); + (void) fprintf(fp, "old version packets: %d\n", + ntohl(ss->oldversionpkt)); + (void) fprintf(fp, "new version packets: %d\n", + ntohl(ss->newversionpkt)); + (void) fprintf(fp, "unknown version number: %d\n", + ntohl(ss->unknownversion)); + (void) fprintf(fp, "bad packet length: %d\n", + ntohl(ss->badlength)); + (void) fprintf(fp, "packets processed: %d\n", + ntohl(ss->processed)); + (void) fprintf(fp, "bad authentication: %d\n", + ntohl(ss->badauth)); + (void) fprintf(fp, "wander hold downs: %d\n", + ntohl(ss->wanderhold)); +} + + + +/* + * iostats - print I/O statistics + */ +/*ARGSUSED*/ +static void +iostats(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_io_stats *io; + int items; + int itemsize; + int res; + + res = doquery(IMPL_XNTPD, REQ_IO_STATS, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&io); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_io_stats))) + return; + + (void) fprintf(fp, "time since reset: %d\n", + ntohl(io->timereset)); + (void) fprintf(fp, "total receive buffers: %d\n", + (int)ntohs(io->totalrecvbufs)); + (void) fprintf(fp, "free receive buffers: %d\n", + (int)ntohs(io->freerecvbufs)); + (void) fprintf(fp, "used receive buffers: %d\n", + (int)ntohs(io->fullrecvbufs)); + (void) fprintf(fp, "low water refills: %d\n", + (int)ntohs(io->lowwater)); + (void) fprintf(fp, "dropped packets: %d\n", + ntohl(io->dropped)); + (void) fprintf(fp, "ignored packets: %d\n", + ntohl(io->ignored)); + (void) fprintf(fp, "received packets: %d\n", + ntohl(io->received)); + (void) fprintf(fp, "packets sent: %d\n", + ntohl(io->sent)); + (void) fprintf(fp, "packets not sent: %d\n", + ntohl(io->notsent)); + (void) fprintf(fp, "interrupts handled: %d\n", + ntohl(io->interrupts)); + (void) fprintf(fp, "received by interrupt: %d\n", + ntohl(io->int_received)); +} + + + +/* + * memstats - print peer memory statistics + */ +/*ARGSUSED*/ +static void +memstats(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_mem_stats *mem; + int i; + int items; + int itemsize; + int res; + + res = doquery(IMPL_XNTPD, REQ_MEM_STATS, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&mem); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_mem_stats))) + return; + + (void) fprintf(fp, "time since reset: %d\n", + ntohl(mem->timereset)); + (void) fprintf(fp, "total peer memory: %d\n", + (int)ntohs(mem->totalpeermem)); + (void) fprintf(fp, "free peer memory: %d\n", + (int)ntohs(mem->freepeermem)); + (void) fprintf(fp, "calls to findpeer: %d\n", + ntohl(mem->findpeer_calls)); + (void) fprintf(fp, "new peer allocations: %d\n", + ntohl(mem->allocations)); + (void) fprintf(fp, "peer demobilizations: %d\n", + ntohl(mem->demobilizations)); + + (void) fprintf(fp, "hash table counts: "); + for (i = 0; i < HASH_SIZE; i++) { + (void) fprintf(fp, "%4d", (int)mem->hashcount[i]); + if ((i % 8) == 7 && i != (HASH_SIZE-1)) { + (void) fprintf(fp, "\n "); + } + } + (void) fprintf(fp, "\n"); +} + + + +/* + * timerstats - print timer statistics + */ +/*ARGSUSED*/ +static void +timerstats(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_timer_stats *tim; + int items; + int itemsize; + int res; + + res = doquery(IMPL_XNTPD, REQ_TIMER_STATS, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&tim); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_timer_stats))) + return; + + (void) fprintf(fp, "time since reset: %d\n", + ntohl(tim->timereset)); + (void) fprintf(fp, "alarms handled: %d\n", + ntohl(tim->alarms)); + (void) fprintf(fp, "alarm overruns: %d\n", + ntohl(tim->overflows)); + (void) fprintf(fp, "calls to transmit: %d\n", + ntohl(tim->xmtcalls)); +} + + +/* + * addpeer - configure an active mode association + */ +static void +addpeer(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + doconfig(pcmd, fp, MODE_ACTIVE); +} + + +/* + * addserver - configure a client mode association + */ +static void +addserver(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + doconfig(pcmd, fp, MODE_CLIENT); +} + +/* + * broadcast - configure a broadcast mode association + */ +static void +broadcast(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + doconfig(pcmd, fp, MODE_BROADCAST); +} + + +/* + * config - configure a new peer association + */ +static void +doconfig(pcmd, fp, mode) + struct parse *pcmd; + FILE *fp; + int mode; +{ + struct conf_peer cpeer; + int items; + int itemsize; + char *dummy; + U_LONG keyid; + u_int version; + u_int flags; + int res; + + keyid = 0; + version = NTP_VERSION; + flags = 0; + res = 0; + if (pcmd->nargs > 1) { + keyid = pcmd->argval[1].uval; + if (keyid > 0) { + flags |= CONF_FLAG_AUTHENABLE; + } + if (pcmd->nargs > 2) { + version = (u_int)pcmd->argval[2].uval; + if (version > NTP_VERSION + || version < NTP_OLDVERSION) { + (void) fprintf(fp, + "funny version number %u specified\n", + version); + res++; + } + + items = 3; + while (pcmd->nargs > items) { + if (STREQ(pcmd->argval[items].string, + "minpoll")) { + flags |= CONF_FLAG_MINPOLL; + } else { + if (STREQ(pcmd->argval[items].string, + "prefer")) { + flags |= CONF_FLAG_PREFER; + } else { + (void) fprintf(fp, + "`%s' not understood\n", + pcmd->argval[3].string); + res++; + break; + } + } + items++; + } + } + } + + if (res) + return; + + cpeer.peeraddr = pcmd->argval[0].netnum; + cpeer.hmode = (u_char) mode; + cpeer.keyid = keyid; + cpeer.version = (u_char) version; + cpeer.minpoll = NTP_MINDPOLL; + cpeer.maxpoll = NTP_MAXPOLL; + cpeer.flags = (u_char)flags; + + res = doquery(IMPL_XNTPD, REQ_CONFIG, 1, 1, + sizeof(struct conf_peer), (char *)&cpeer, &items, + &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + +/* + * unconfig - unconfigure some associations + */ +static void +unconfig(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + /* 8 is the maximum number of peers which will fit in a packet */ + struct conf_unpeer plist[min(MAXARGS, 8)]; + int qitems; + int items; + int itemsize; + char *dummy; + int res; + + for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++) { + plist[qitems].peeraddr = pcmd->argval[qitems].netnum; + } + + res = doquery(IMPL_XNTPD, REQ_UNCONFIG, 1, qitems, + sizeof(struct conf_unpeer), (char *)plist, &items, + &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); +} + + +/* + * set - set some system flags + */ +static void +set(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + doset(pcmd, fp, REQ_SET_SYS_FLAG); +} + + +/* + * clear - clear some system flags + */ +static void +sys_clear(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + doset(pcmd, fp, REQ_CLR_SYS_FLAG); +} + + +/* + * doset - set/clear system flags + */ +static void +doset(pcmd, fp, req) + struct parse *pcmd; + FILE *fp; + int req; +{ + /* 8 is the maximum number of peers which will fit in a packet */ + struct conf_sys_flags sys; + int items; + int itemsize; + char *dummy; + int res; + + sys.flags = 0; + res = 0; + for (items = 0; items < pcmd->nargs; items++) { + if (STREQ(pcmd->argval[items].string, "bclient")) + sys.flags |= SYS_FLAG_BCLIENT; + else if (STREQ(pcmd->argval[items].string, "auth")) + sys.flags |= SYS_FLAG_AUTHENTICATE; + else { + (void) fprintf(fp, "unknown flag %s\n", + pcmd->argval[items].string); + res = 1; + } + } + + if (res || sys.flags == 0) + return; + + res = doquery(IMPL_XNTPD, req, 1, 1, + sizeof(struct conf_sys_flags), (char *)&sys, &items, + &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); +} + + +/* + * data for printing/interrpreting the restrict flags + */ +struct resflags { + char *str; + int bit; +}; + +static struct resflags resflags[] = { + { "ignore", RES_IGNORE }, + { "noserve", RES_DONTSERVE }, + { "notrust", RES_DONTTRUST }, + { "noquery", RES_NOQUERY }, + { "nomodify", RES_NOMODIFY }, + { "nopeer", RES_NOPEER }, + { "notrap", RES_NOTRAP }, + { "lptrap", RES_LPTRAP }, + { "", 0 } +}; + +static struct resflags resmflags[] = { + { "ntpport", RESM_NTPONLY }, + { "interface", RESM_INTERFACE }, + { "", 0 } +}; + + +/* + * reslist - obtain and print the server's restrict list + */ +/*ARGSUSED*/ +static void +reslist(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_restrict *rl; + int items; + int itemsize; + int res; + char *addr; + char *mask; + struct resflags *rf; + U_LONG count; + u_short flags; + u_short mflags; + char flagstr[300]; + static char *comma = ", "; + + res = doquery(IMPL_XNTPD, REQ_GET_RESTRICT, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&rl); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_restrict))) + return; + + (void) fprintf(fp, + " address mask count flags\n"); + (void) fprintf(fp, + "=====================================================================\n"); + while (items > 0) { + addr = numtoa(rl->addr); + mask = numtoa(rl->mask); + count = ntohl(rl->count); + flags = ntohs(rl->flags); + mflags = ntohs(rl->mflags); + flagstr[0] = '\0'; + + res = 1; + rf = &resmflags[0]; + while (rf->bit != 0) { + if (mflags & rf->bit) { + if (!res) + (void) strcat(flagstr, comma); + res = 0; + (void) strcat(flagstr, rf->str); + } + rf++; + } + + rf = &resflags[0]; + while (rf->bit != 0) { + if (flags & rf->bit) { + if (!res) + (void) strcat(flagstr, comma); + res = 0; + (void) strcat(flagstr, rf->str); + } + rf++; + } + + if (flagstr[0] == '\0') + (void) strcpy(flagstr, "none"); + + (void) fprintf(fp, "%-15.15s %-15.15s %9d %s\n", + addr, mask, count, flagstr); + rl++; + items--; + } +} + + + +/* + * restrict - create/add a set of restrictions + */ +static void +restrict(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + do_restrict(pcmd, fp, REQ_RESADDFLAGS); +} + + +/* + * unrestrict - remove restriction flags from existing entry + */ +static void +unrestrict(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + do_restrict(pcmd, fp, REQ_RESSUBFLAGS); +} + + +/* + * delrestrict - delete an existing restriction + */ +static void +delrestrict(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + do_restrict(pcmd, fp, REQ_UNRESTRICT); +} + + +/* + * do_restrict - decode commandline restrictions and make the request + */ +static void +do_restrict(pcmd, fp, req_code) + struct parse *pcmd; + FILE *fp; + int req_code; +{ + struct conf_restrict cres; + int items; + int itemsize; + char *dummy; + U_LONG num; + U_LONG bit; + int i; + int res; + int err; + + cres.addr = pcmd->argval[0].netnum; + cres.mask = pcmd->argval[1].netnum; + cres.flags = 0; + cres.mflags = 0; + err = 0; + for (res = 2; res < pcmd->nargs; res++) { + if (STREQ(pcmd->argval[res].string, "ntpport")) { + cres.mflags |= RESM_NTPONLY; + } else { + for (i = 0; resflags[i].bit != 0; i++) { + if (STREQ(pcmd->argval[res].string, + resflags[i].str)) + break; + } + if (resflags[i].bit != 0) { + cres.flags |= resflags[i].bit; + if (req_code == REQ_UNRESTRICT) { + (void) fprintf(fp, + "Flag `%s' inappropriate\n", + resflags[i].str); + err++; + } + } else { + (void) fprintf(fp, "Unknown flag %s\n", + pcmd->argval[res].string); + err++; + } + } + } + + /* + * Make sure mask for default address is zero. Otherwise, + * make sure mask bits are contiguous. + */ + if (cres.addr == 0) { + cres.mask = 0; + } else { + num = ntohl(cres.mask); + for (bit = 0x80000000; bit != 0; bit >>= 1) + if ((num & bit) == 0) + break; + for ( ; bit != 0; bit >>= 1) + if ((num & bit) != 0) + break; + if (bit != 0) { + (void) fprintf(fp, "Invalid mask %s\n", + numtoa(cres.mask)); + err++; + } + } + + if (err) + return; + + res = doquery(IMPL_XNTPD, req_code, 1, 1, + sizeof(struct conf_restrict), (char *)&cres, &items, + &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + +/* + * monlist - obtain and print the server's monitor data + */ +/*ARGSUSED*/ +static void +monlist(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_monitor *ml; + int items; + int itemsize; + int res; + + res = doquery(IMPL_XNTPD, REQ_MON_GETLIST, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&ml); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_monitor))) + return; + + (void) fprintf(fp, + " address port count mode version lasttime firsttime\n"); + (void) fprintf(fp, + "=====================================================================\n"); + while (items > 0) { + (void) fprintf(fp, "%-20.20s %5d %9d %4d %3d %9u %9u\n", + nntohost(ml->addr), + ntohs(ml->port), + ntohl(ml->count), + ml->mode, ml->version, + ntohl(ml->lasttime), + ntohl(ml->firsttime)); + ml++; + items--; + } +} + + +/* + * monitor - turn the server's monitor facility on or off + */ +static void +monitor(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int items; + int itemsize; + char *dummy; + int req_code; + int res; + + if (STREQ(pcmd->argval[0].string, "on")) + req_code = REQ_MONITOR; + else if (STREQ(pcmd->argval[0].string, "off")) + req_code = REQ_NOMONITOR; + else { + (void) fprintf(fp, "monitor what?\n"); + return; + } + + res = doquery(IMPL_XNTPD, req_code, 1, 0, 0, (char *)0, + &items, &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * Mapping between command line strings and stat reset flags + */ +struct statreset { + char *str; + int flag; +} sreset[] = { + { "io", RESET_FLAG_IO }, + { "sys", RESET_FLAG_SYS }, + { "mem", RESET_FLAG_MEM }, + { "timer", RESET_FLAG_TIMER }, + { "auth", RESET_FLAG_AUTH }, + { "allpeers", RESET_FLAG_ALLPEERS }, + { "", 0 } +}; + +/* + * reset - reset statistic counters + */ +static void +reset(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct reset_flags rflags; + int items; + int itemsize; + char *dummy; + int i; + int res; + int err; + + err = 0; + rflags.flags = 0; + for (res = 0; res < pcmd->nargs; res++) { + for (i = 0; sreset[i].flag != 0; i++) { + if (STREQ(pcmd->argval[res].string, sreset[i].str)) + break; + } + if (sreset[i].flag == 0) { + (void) fprintf(fp, "Flag `%s' unknown\n", + pcmd->argval[res].string); + err++; + } else { + rflags.flags |= sreset[i].flag; + } + } + + if (err) { + (void) fprintf(fp, "Not done due to errors\n"); + return; + } + + res = doquery(IMPL_XNTPD, REQ_RESET_STATS, 1, 1, + sizeof(struct reset_flags), (char *)&rflags, &items, + &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * preset - reset stat counters for particular peers + */ +static void +preset(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + /* 8 is the maximum number of peers which will fit in a packet */ + struct conf_unpeer plist[min(MAXARGS, 8)]; + int qitems; + int items; + int itemsize; + char *dummy; + int res; + + for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++) { + plist[qitems].peeraddr = pcmd->argval[qitems].netnum; + } + + res = doquery(IMPL_XNTPD, REQ_RESET_PEER, 1, qitems, + sizeof(struct conf_unpeer), (char *)plist, &items, + &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); +} + + +/* + * readkeys - request the server to reread the keys file + */ +/*ARGSUSED*/ +static void +readkeys(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int items; + int itemsize; + char *dummy; + int res; + + res = doquery(IMPL_XNTPD, REQ_REREAD_KEYS, 1, 0, 0, (char *)0, + &items, &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + +/* + * dodirty - request the server to do something dirty + */ +/*ARGSUSED*/ +static void +dodirty(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int items; + int itemsize; + char *dummy; + int res; + + res = doquery(IMPL_XNTPD, REQ_DO_DIRTY_HACK, 1, 0, 0, (char *)0, + &items, &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + +/* + * dontdirty - request the server to not do something dirty + */ +/*ARGSUSED*/ +static void +dontdirty(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int items; + int itemsize; + char *dummy; + int res; + + res = doquery(IMPL_XNTPD, REQ_DONT_DIRTY_HACK, 1, 0, 0, (char *)0, + &items, &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + +/* + * trustkey - add some keys to the trusted key list + */ +static void +trustkey(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + do_trustkey(pcmd, fp, REQ_TRUSTKEY); +} + + +/* + * untrustkey - remove some keys from the trusted key list + */ +static void +untrustkey(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + do_trustkey(pcmd, fp, REQ_UNTRUSTKEY); +} + + +/* + * do_trustkey - do grunge work of adding/deleting keys + */ +static void +do_trustkey(pcmd, fp, req) + struct parse *pcmd; + FILE *fp; + int req; +{ + U_LONG keyids[MAXARGS]; + int i; + int items; + int itemsize; + char *dummy; + int ritems; + int res; + + ritems = 0; + for (i = 0; i < pcmd->nargs; i++) { + keyids[ritems++] = pcmd->argval[i].uval; + } + + res = doquery(IMPL_XNTPD, req, 1, ritems, sizeof(U_LONG), + (char *)keyids, &items, &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * authinfo - obtain and print info about authentication + */ +/*ARGSUSED*/ +static void +authinfo(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_auth *ia; + int items; + int itemsize; + int res; + + res = doquery(IMPL_XNTPD, REQ_AUTHINFO, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&ia); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_auth))) + return; + + (void) fprintf(fp, "time since reset: %d\n", + ntohl(ia->timereset)); + (void) fprintf(fp, "key lookups: %d\n", + ntohl(ia->keylookups)); + (void) fprintf(fp, "keys not found: %d\n", + ntohl(ia->keynotfound)); + (void) fprintf(fp, "encryptions: %d\n", + ntohl(ia->encryptions)); + (void) fprintf(fp, "decryptions: %d\n", + ntohl(ia->decryptions)); + (void) fprintf(fp, "successful decryptions: %d\n", + ntohl(ia->decryptions)); + (void) fprintf(fp, "uncached keys: %d\n", + ntohl(ia->keyuncached)); +} + + + +/* + * traps - obtain and print a list of traps + */ +/*ARGSUSED*/ +static void +traps(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + int i; + struct info_trap *it; + int items; + int itemsize; + int res; + + res = doquery(IMPL_XNTPD, REQ_TRAPS, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&it); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_trap))) + return; + + for (i = 0; i < items; i++ ) { + if (i != 0) + (void) fprintf(fp, "\n"); + (void) fprintf(fp, "address %s, port %d\n", + numtoa(it->trap_address), ntohs(it->trap_port)); + (void) fprintf(fp, "interface: %s, ", + it->local_address==0?"wildcard":numtoa(it->local_address)); + + if (htonl(it->flags) & TRAP_CONFIGURED) + (void) fprintf(fp, "configured\n"); + else if (it->flags & TRAP_NONPRIO) + (void) fprintf(fp, "low priority\n"); + else + (void) fprintf(fp, "normal priority\n"); + + (void) fprintf(fp, "set for %d secs, last set %d secs ago\n", + it->origtime, it->settime); + (void) fprintf(fp, "sequence %d, number of resets %d\n", + it->sequence, it->resets); + } +} + + +/* + * addtrap - configure a trap + */ +static void +addtrap(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + do_addclr_trap(pcmd, fp, REQ_ADD_TRAP); +} + + +/* + * clrtrap - clear a trap from the server + */ +static void +clrtrap(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + do_addclr_trap(pcmd, fp, REQ_CLR_TRAP); +} + + +/* + * do_addclr_trap - do grunge work of adding/deleting traps + */ +static void +do_addclr_trap(pcmd, fp, req) + struct parse *pcmd; + FILE *fp; + int req; +{ + struct conf_trap ctrap; + int items; + int itemsize; + char *dummy; + int res; + + ctrap.trap_address = pcmd->argval[0].netnum; + ctrap.local_address = 0; + ctrap.trap_port = htons(TRAPPORT); + ctrap.unused = 0; + + if (pcmd->nargs > 1) { + ctrap.trap_port + = htons((u_short)(pcmd->argval[1].uval & 0xffff)); + if (pcmd->nargs > 2) + ctrap.local_address = pcmd->argval[2].netnum; + } + + res = doquery(IMPL_XNTPD, req, 1, 1, sizeof(struct conf_trap), + (char *)&ctrap, &items, &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * requestkey - change the server's request key (a dangerous request) + */ +static void +requestkey(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + do_changekey(pcmd, fp, REQ_REQUEST_KEY); +} + + +/* + * controlkey - change the server's control key + */ +static void +controlkey(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + do_changekey(pcmd, fp, REQ_CONTROL_KEY); +} + + + +/* + * do_changekey - do grunge work of changing keys + */ +static void +do_changekey(pcmd, fp, req) + struct parse *pcmd; + FILE *fp; + int req; +{ + U_LONG key; + int items; + int itemsize; + char *dummy; + int res; + + + key = htonl(pcmd->argval[0].uval); + + res = doquery(IMPL_XNTPD, req, 1, 1, sizeof(U_LONG), + (char *)&key, &items, &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * ctlstats - obtain and print info about authentication + */ +/*ARGSUSED*/ +static void +ctlstats(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_control *ic; + int items; + int itemsize; + int res; + + res = doquery(IMPL_XNTPD, REQ_GET_CTLSTATS, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&ic); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_control))) + return; + + (void) fprintf(fp, "time since reset: %d\n", + ntohl(ic->ctltimereset)); + (void) fprintf(fp, "requests received: %d\n", + ntohl(ic->numctlreq)); + (void) fprintf(fp, "responses sent: %d\n", + ntohl(ic->numctlresponses)); + (void) fprintf(fp, "fragments sent: %d\n", + ntohl(ic->numctlfrags)); + (void) fprintf(fp, "async messages sent: %d\n", + ntohl(ic->numasyncmsgs)); + (void) fprintf(fp, "error msgs sent: %d\n", + ntohl(ic->numctlerrors)); + (void) fprintf(fp, "total bad pkts: %d\n", + ntohl(ic->numctlbadpkts)); + (void) fprintf(fp, "packet too short: %d\n", + ntohl(ic->numctltooshort)); + (void) fprintf(fp, "response on input: %d\n", + ntohl(ic->numctlinputresp)); + (void) fprintf(fp, "fragment on input: %d\n", + ntohl(ic->numctlinputfrag)); + (void) fprintf(fp, "error set on input: %d\n", + ntohl(ic->numctlinputerr)); + (void) fprintf(fp, "bad offset on input: %d\n", + ntohl(ic->numctlbadoffset)); + (void) fprintf(fp, "bad version packets: %d\n", + ntohl(ic->numctlbadversion)); + (void) fprintf(fp, "data in pkt too short: %d\n", + ntohl(ic->numctldatatooshort)); + (void) fprintf(fp, "unknown op codes: %d\n", + ntohl(ic->numctlbadop)); +} + + + +/* + * Table for human printing leap bits + */ +char *leapbittab[] = { + "00 (no leap second scheduled)", + "01 (second to be added at end of month)", + "10 (second to be deleted at end of month)", + "11 (clock out of sync)" +}; + +char *controlleapbittab[] = { + "00 (leap controlled by lower stratum)", + "01 (second to be added at end of month)", + "10 (second to be deleted at end of month)", + "11 (lower stratum leap information ignored - no leap)" +}; + +/* + * leapinfo - obtain information about the state of the leap second support + */ +/*ARGSUSED*/ +static void +leapinfo(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct info_leap *il; + int items; + int itemsize; + int res; + l_fp ts; + + res = doquery(IMPL_XNTPD, REQ_GET_LEAPINFO, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&il); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_leap))) + return; + + (void) fprintf(fp, "sys.leap: %s\n", + leapbittab[il->sys_leap & INFO_LEAP_MASK]); + (void) fprintf(fp, "leap.indicator: %s\n", + controlleapbittab[il->leap_indicator & INFO_LEAP_MASK]); + (void) fprintf(fp, "leap.warning: %s\n", + controlleapbittab[il->leap_warning & INFO_LEAP_MASK]); + (void) fprintf(fp, "leap.bits: %s\n", + leapbittab[il->leap_bits & INFO_LEAP_MASK]); + if (il->leap_bits & INFO_LEAP_OVERRIDE) + (void) fprintf(fp, "Leap overide option in effect\n"); + if (il->leap_bits & INFO_LEAP_SEENSTRATUM1) + (void) fprintf(fp, "Stratum 1 restrictions in effect\n"); + (void) fprintf(fp, "time to next leap interrupt: %d seconds\n", + ntohl(il->leap_timer)); + gettstamp(&ts); + (void) fprintf(fp, "date of next leap interrupt: %s\n", + humandate(ts.l_ui + ntohl(il->leap_timer))); + (void) fprintf(fp, "calls to leap process: %u\n", + ntohl(il->leap_processcalls)); + (void) fprintf(fp, "leap more than month away: %u\n", + ntohl(il->leap_notclose)); + (void) fprintf(fp, "leap less than month away: %u\n", + ntohl(il->leap_monthofleap)); + (void) fprintf(fp, "leap less than day away: %u\n", + ntohl(il->leap_dayofleap)); + (void) fprintf(fp, "leap in less than 2 hours: %u\n", + ntohl(il->leap_hoursfromleap)); + (void) fprintf(fp, "leap happened: %u\n", + ntohl(il->leap_happened)); +} + + +/* + * clockstat - get and print clock status information + */ +static void +clockstat(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + extern struct clktype clktypes[]; + struct info_clock *cl; + /* 8 is the maximum number of clocks which will fit in a packet */ + U_LONG clist[min(MAXARGS, 8)]; + int qitems; + int items; + int itemsize; + int res; + l_fp ts; + struct clktype *clk; + + for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++) + clist[qitems] = pcmd->argval[qitems].netnum; + + res = doquery(IMPL_XNTPD, REQ_GET_CLOCKINFO, 0, qitems, + sizeof(U_LONG), (char *)clist, &items, + &itemsize, (char **)&cl); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_clock))) + return; + + while (items-- > 0) { + (void) fprintf(fp, "clock address: %s\n", + numtoa(cl->clockadr)); + for (clk = clktypes; clk->code >= 0; clk++) + if (clk->code == cl->type) + break; + if (clk->code >= 0) + (void) fprintf(fp, "clock type: %s\n", + clk->clocktype); + else + (void) fprintf(fp, "clock type: unknown type (%d)\n", + cl->type); + (void) fprintf(fp, "last event: %d\n", + cl->lastevent); + (void) fprintf(fp, "current status: %d\n", + cl->currentstatus); + (void) fprintf(fp, "number of polls: %u\n", + ntohl(cl->polls)); + (void) fprintf(fp, "no response to poll: %u\n", + ntohl(cl->noresponse)); + (void) fprintf(fp, "bad format responses: %u\n", + ntohl(cl->badformat)); + (void) fprintf(fp, "bad data responses: %u\n", + ntohl(cl->baddata)); + (void) fprintf(fp, "running time: %u\n", + ntohl(cl->timestarted)); + NTOHL_FP(&cl->fudgetime1, &ts); + (void) fprintf(fp, "fudge time 1: %s\n", + lfptoa(&ts, 7)); + NTOHL_FP(&cl->fudgetime2, &ts); + (void) fprintf(fp, "fudge time 2: %s\n", + lfptoa(&ts, 7)); + (void) fprintf(fp, "fudge value 1: %ld\n", + ntohl(cl->fudgeval1)); + (void) fprintf(fp, "fudge value 2: %ld\n", + ntohl(cl->fudgeval2)); + (void) fprintf(fp, "fudge flags: 0x%x\n", + cl->flags); + + if (items > 0) + (void) fprintf(fp, "\n"); + cl++; + } +} + + +/* + * fudge - set clock fudge factors + */ +static void +fudge(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + struct conf_fudge fudgedata; + int items; + int itemsize; + char *dummy; + l_fp ts; + int res; + LONG val; + int err; + + + err = 0; + bzero((char *)&fudgedata, sizeof fudgedata); + fudgedata.clockadr = pcmd->argval[0].netnum; + + if (STREQ(pcmd->argval[1].string, "time1")) { + fudgedata.which = htonl(FUDGE_TIME1); + if (!atolfp(pcmd->argval[2].string, &ts)) + err = 1; + else + HTONL_FP(&ts, &fudgedata.fudgetime); + } else if (STREQ(pcmd->argval[1].string, "time2")) { + fudgedata.which = htonl(FUDGE_TIME2); + if (!atolfp(pcmd->argval[2].string, &ts)) + err = 1; + else + HTONL_FP(&ts, &fudgedata.fudgetime); + } else if (STREQ(pcmd->argval[1].string, "val1")) { + fudgedata.which = htonl(FUDGE_VAL1); + if (!atoint(pcmd->argval[2].string, &val)) + err = 1; + else + fudgedata.fudgeval_flags = htonl(val); + } else if (STREQ(pcmd->argval[1].string, "val2")) { + fudgedata.which = htonl(FUDGE_VAL2); + if (!atoint(pcmd->argval[2].string, &val)) + err = 1; + else + fudgedata.fudgeval_flags = htonl(val); + } else if (STREQ(pcmd->argval[1].string, "flags")) { + fudgedata.which = htonl(FUDGE_FLAGS); + if (!atoint(pcmd->argval[2].string, &val)) + err = 1; + else + fudgedata.fudgeval_flags = htonl(val & 0xf); + } else { + (void) fprintf(stderr, "What fudge is `%s'?\n", + pcmd->argval[1].string); + return; + } + + if (err) { + (void) fprintf(stderr, "Can't decode the value `%s'\n", + pcmd->argval[2].string); + return; + } + + + res = doquery(IMPL_XNTPD, REQ_SET_CLKFUDGE, 1, 1, + sizeof(struct conf_fudge), (char *)&fudgedata, &items, + &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * maxskew - set the server's maximum skew parameter + */ +static void +maxskew(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + u_fp Xmaxskew; + l_fp tmp; + int items; + int itemsize; + char *dummy; + int res; + + if (!atolfp(pcmd->argval[0].string, &tmp)) { + (void) fprintf(stderr, "What the heck does %s mean?\n", + pcmd->argval[0].string); + return; + } + Xmaxskew = HTONS_FP(LFPTOFP(&tmp)); + + res = doquery(IMPL_XNTPD, REQ_SET_MAXSKEW, 1, 1, sizeof(u_fp), + (char *)&Xmaxskew, &items, &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); +} + + + +/* + * clkbug - get and print clock debugging information + */ +static void +clkbug(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + register int i; + register int n; + register U_LONG s; + struct info_clkbug *cl; + /* 8 is the maximum number of clocks which will fit in a packet */ + U_LONG clist[min(MAXARGS, 8)]; + int qitems; + int items; + int itemsize; + int res; + l_fp ts; + + for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++) + clist[qitems] = pcmd->argval[qitems].netnum; + + res = doquery(IMPL_XNTPD, REQ_GET_CLKBUGINFO, 0, qitems, + sizeof(U_LONG), (char *)clist, &items, + &itemsize, (char **)&cl); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_clkbug))) + return; + + while (items-- > 0) { + (void) fprintf(fp, "clock address: %s\n", + numtoa(cl->clockadr)); + n = (int)cl->nvalues; + (void) fprintf(fp, "values: %d", n); + s = (U_LONG)ntohs(cl->svalues); + if (n > NUMCBUGVALUES) + n = NUMCBUGVALUES; + for (i = 0; i < n; i++) { + if ((i & 0x3) == 0) + (void) fprintf(fp, "\n"); + if (s & (1<values[i])); + } else { + (void) fprintf(fp, "%12lu", + ntohl(cl->values[i])); + } + } + (void) fprintf(fp, "\n"); + + n = (int)cl->ntimes; + (void) fprintf(fp, "times: %d", n); + s = ntohl(cl->stimes); + if (n > NUMCBUGTIMES) + n = NUMCBUGTIMES; + for (i = 0; i < n; i++) { + int needsp = 0; + if ((i & 0x1) == 0) + (void) fprintf(fp, "\n"); + else { + for (;needsp > 0; needsp--) + putc(' ', fp); + } + HTONL_FP(&cl->times[i], &ts); + if (s & (1< 0) { + cl++; + (void) fprintf(fp, "\n"); + } + } +} + + +/* + * setprecision - set the server's value of sys.precision + */ +static void +setprecision(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + LONG precision; + int items; + int itemsize; + char *dummy; + int res; + + precision = htonl(pcmd->argval[0].ival); + + res = doquery(IMPL_XNTPD, REQ_SET_PRECISION, 1, 1, sizeof(LONG), + (char *)&precision, &items, &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * setselect - change the server's selection algorithm + */ +static void +setselect(pcmd, fp) + struct parse *pcmd; + FILE *fp; +{ + U_LONG select_code; + int items; + int itemsize; + char *dummy; + int res; + + select_code = htonl(pcmd->argval[0].uval); + + res = doquery(IMPL_XNTPD, REQ_SET_SELECT_CODE, 1, 1, sizeof(U_LONG), + (char *)&select_code, &items, &itemsize, &dummy); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} diff --git a/contrib/xntpd/xntpres/Makefile.tmpl b/contrib/xntpd/xntpres/Makefile.tmpl new file mode 100644 index 0000000000..8f0742bd3b --- /dev/null +++ b/contrib/xntpd/xntpres/Makefile.tmpl @@ -0,0 +1,68 @@ +# +# Makefile.tmpl,v 3.1 1993/07/06 01:12:07 jbj Exp +# +PROGRAM= xntpres +# +# xntpres - name resolver support for xntpd +# +COMPILER= cc +COPTS= -O +BINDIR= /usr/local +INSTALL= install +DEFS= +DEFS_OPT= +DEFS_LOCAL= +RESLIB= +COMPAT= +# +INCL= -I../include +CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) +CC= $(COMPILER) +LIB= ../lib/libntp.a +LINTLIB= ../lib/llib-llibntp.ln +MAKE= make +TOP=../ +# +OBJS= xntpres.o +SOURCE= xntpres.c + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) $(LIB) version.o + $(CC) $(COPTS) -o $@ $(OBJS) version.o $(LIB) $(RESLIB) $(COMPAT) + +install: $(BINDIR)/$(PROGRAM) + +$(BINDIR)/$(PROGRAM): $(PROGRAM) + $(INSTALL) -c -m 0755 $(PROGRAM) $(BINDIR) + +tags: + ctags *.c *.h + +depend: + mkdep $(CFLAGS) $(SOURCE) + +clean: + -@rm -f $(PROGRAM) *.o *.out tags make.log Makefile.bak lint.errs .version + +distclean: clean + -@rm -f *.orig *.rej .version Makefile + +lint: $(LINTLIB) + lint -x -u $(DEFS) $(DEFS_LOCAL) $(INCL) $(LINTLIB) $(SOURCE) >lint.errs + +../lib/llib-llibntp.ln: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" lintlib + +../lib/libntp.a: + cd ../lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" + +# +# we want to build the current version string here +# +version.o: ../VERSION + ../scripts/mkversion $(PROGRAM) + $(CC) $(COPTS) $(INCL) -c version.c + +../VERSION: + -@rm -f .version diff --git a/contrib/xntpd/xntpres/README b/contrib/xntpd/xntpres/README new file mode 100644 index 0000000000..06d7266b4f --- /dev/null +++ b/contrib/xntpd/xntpres/README @@ -0,0 +1,6 @@ +README file for directory ./xntpres of the NTP Version 3 distribution + +This directory contains the sources for the xntpres utility program. See +the README and RELNOTES files in the parent directory for directions on +how to make and install this program. The current version number of this +program is in the version.c file. diff --git a/contrib/xntpd/xntpres/xntpres.c b/contrib/xntpd/xntpres/xntpres.c new file mode 100644 index 0000000000..cf0d850bd8 --- /dev/null +++ b/contrib/xntpd/xntpres/xntpres.c @@ -0,0 +1,845 @@ +/* xntpres.c,v 3.1 1993/07/06 01:12:09 jbj Exp + * xntpres - process configuration entries which require use of the resolver + * + * This is meant to be run by xntpd 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. + * + * Usage is: + * xntpres [-d] [-r] keyid keyfile configuration_data + */ +#include +#include +#include +#include +#include +#include +#include + +#include "ntp_select.h" +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "ntp_malloc.h" +#include "ntp_request.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" +#include "ntp_syslog.h" + +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +/* + * Each item we are to resolve and configure gets one of these + * structures defined for it. + */ +struct conf_entry { + struct conf_entry *ce_next; + char *ce_name; /* name we are trying to resolve */ + struct conf_peer ce_config; /* configuration info for peer */ +}; +#define ce_peeraddr ce_config.peeraddr +#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_keyid ce_config.keyid + +/* + * confentries is a pointer to the list of configuration entries + * we have left to do. + */ +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 + +int config_timer = 0; +int resolve_timer = 0; + +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_KEYID 6 +#define NUMTOK 7 + +#define MAXLINESIZE 512 + + +/* + * File descriptor for ntp request code. + */ +int sockfd = -1; + +/* + * Misc. data from argument processing + */ +int removefile = 0; /* remove configuration file when done */ + +U_LONG req_keyid; /* request keyid */ +char *keyfile; /* file where keys are kept */ +char *conffile; /* name of the file with configuration info */ + +char *progname; +int debug = 0; +extern char *Version; +extern int errno; + +static RETSIGTYPE bong P((int)); +static void checkparent P((void)); +static void removeentry P((struct conf_entry *)); +static void addentry P((char *, int, int, int, int, int, U_LONG)); +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)); + +/* + * main - parse arguments and handle options + */ +void +main(argc, argv) + int argc; + char *argv[]; +{ + int c; + int errflg = 0; + char *cp; + FILE *in; + extern int optind; + + progname = argv[0]; + + /* + * Better get syslog open early since stderr messages are likely + * ending up in the twilight zone + */ + cp = strrchr(argv[0], '/'); + if (cp == 0) + cp = argv[0]; + else + cp++; + +#ifndef LOG_DAEMON + openlog(cp, LOG_PID); +#else + +#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_INFO)); +#endif /* LOG_DAEMON */ + + syslog(LOG_NOTICE, Version); + + while ((c = getopt_l(argc, argv, "dr")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + case 'r': + ++removefile; + break; + default: + errflg++; + break; + } + if (errflg || (optind + 3) != argc) { + (void) fprintf(stderr, + "usage: %s [-d] [-r] keyid keyfile conffile\n", progname); + syslog(LOG_ERR, "exiting due to usage error"); + exit(2); + } + + if (!atouint(argv[optind], &req_keyid)) { + syslog(LOG_ERR, "undecodeable keyid %s", argv[optind]); + exit(1); + } + + keyfile = argv[optind+1]; + conffile = argv[optind+2]; + + /* + * Make sure we have the key we need + */ + if (!authreadkeys(keyfile)) + exit(1); + if (!authhavekey(req_keyid)) { + syslog(LOG_ERR, "request keyid %lu not found in %s", + req_keyid, keyfile); + exit(1); + } + + /* + * Read the configuration info + */ + if ((in = fopen(conffile, "r")) == NULL) { + syslog(LOG_ERR, "can't open configuration file %s: %m", + conffile); + exit(1); + } + readconf(in, conffile); + (void) fclose(in); + if (removefile) + (void) unlink(conffile); + + /* + * 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) + exit(0); /* done that quick */ + + /* + * Here we've got some problem children. Set up the timer + * and wait for it. + */ + resolve_value = resolve_timer = MINRESOLVE; + config_timer = CONFIG_TIME; + (void) signal(SIGALRM, bong); + alarm(ALARM_TIME); + + for (;;) { + if (confentries == NULL) + exit(0); + checkparent(); + if (resolve_timer == 0) { + if (resolve_value < MAXRESOLVE) + resolve_value <<= 1; + resolve_timer = resolve_value; + config_timer = CONFIG_TIME; + doconfigure(1); + continue; + } else if (config_timer == 0) { + config_timer = CONFIG_TIME; + doconfigure(0); + continue; + } + /* + * There is a race in here. Is okay, though, since + * all it does is delay things by 30 seconds. + */ + (void) pause(); + } +} + + +/* + * bong - service and reschedule an alarm() interrupt + */ +static RETSIGTYPE +bong(sig) +int sig; +{ + if (config_timer > 0) + config_timer--; + if (resolve_timer > 0) + resolve_timer--; + alarm(ALARM_TIME); +} + + +/* + * checkparent - see if our parent process is still running + */ +static void +checkparent() +{ + /* + * If our parent (the server) has died we will have been + * inherited by init. If so, exit. + */ + if (getppid() == 1) { + syslog(LOG_INFO, "parent died before we finished, exiting"); + exit(0); + } +} + + +/* + * removeentry - we are done with an entry, remove it from the list + */ +static void +removeentry(entry) + 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(name, mode, version, minpoll, maxpoll, flags, keyid) + char *name; + int mode; + int version; + int minpoll; + int maxpoll; + int flags; + U_LONG keyid; +{ + register char *cp; + register struct conf_entry *ce; + int len; + + len = strlen(name) + 1; + cp = emalloc((unsigned)len); + bcopy(name, cp, len); + + ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry)); + ce->ce_name = cp; + ce->ce_peeraddr = 0; + 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_keyid = htonl(keyid); + 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 + * + * The routine sticks the address into the entry's ce_peeraddr if it + * gets one. It returns 1 for "success" and 0 for an uncorrectable + * failure. Note that "success" includes try again errors. You can + * tell that you got a try again since ce_peeraddr will still be zero. + */ +static int +findhostaddr(entry) + struct conf_entry *entry; +{ + struct hostent *hp; + + checkparent(); /* make sure our guy is still running */ + + hp = gethostbyname(entry->ce_name); + + if (hp == NULL) { +#ifndef NODNS + /* + * If the resolver is in use, see if the failure is + * temporary. If so, return success. + */ + extern int h_errno; + + if (h_errno == TRY_AGAIN) + return 1; +#endif + return 0; + } + + /* + * Use the first address. We don't have any way to + * tell preferences and older gethostbyname() implementations + * only return one. + */ + (void) bcopy(hp->h_addr, (char *)&(entry->ce_peeraddr), + sizeof(struct in_addr)); + return 1; +} + + +/* + * openntp - open a socket to the ntp server + */ +static void +openntp() +{ + struct sockaddr_in saddr; + + if (sockfd >= 0) + return; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) { + syslog(LOG_ERR, "socket() failed: %m"); + exit(1); + } + + bzero((char *)&saddr, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(NTP_PORT); /* trash */ + saddr.sin_addr.s_addr = htonl(LOCALHOST); /* garbage */ + + + /* + * Make the socket non-blocking. We'll wait with select() + */ +#if defined(O_NONBLOCK) + if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) { + syslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m"); + exit(1); + } +#else +#if defined(FNDELAY) + if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) { + syslog(LOG_ERR, "fcntl(FNDELAY) failed: %m"); + exit(1); + } +#else +NEED NON BLOCKING IO +#endif +#endif + + if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { + syslog(LOG_ERR, "connect() failed: %m"); + exit(1); + } +} + + +/* + * request - send a configuration request to the server, wait for a response + */ +static int +request(conf) + struct conf_peer *conf; +{ + fd_set fdset; + struct timeval tvout; + struct req_pkt reqpkt; + l_fp ts; + int n; + + checkparent(); /* make sure our guy is still running */ + + if (sockfd < 0) + openntp(); + + /* + * Try to clear out any previously received traffic so it + * doesn't fool us. Note the socket is nonblocking. + */ + while (read(sockfd, (char *)&reqpkt, REQ_LEN_MAC) > 0) + /* nothing */; + + /* + * Make up a request packet with the configuration info + */ + bzero((char *)&reqpkt, sizeof(reqpkt)); + + reqpkt.rm_vn_mode = RM_VN_MODE(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)); + bcopy((char *)conf, reqpkt.data, sizeof(struct conf_peer)); + reqpkt.keyid = htonl(req_keyid); + + auth1crypt(req_keyid, (U_LONG *)&reqpkt, REQ_LEN_NOMAC); + gettstamp(&ts); + M_ADDUF(ts.l_ui, ts.l_uf, SKEWTIME); + HTONL_FP(&ts, &reqpkt.tstamp); + n = auth2crypt(req_keyid, (U_LONG *)&reqpkt, REQ_LEN_NOMAC); + + /* + * Done. Send it. + */ + n = write(sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n); + if (n < 0) { + syslog(LOG_ERR, "send to NTP server failed: %m"); + return 0; /* maybe should exit */ + } + + /* + * 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 (n < 0) + syslog(LOG_ERR, "select() fails: %m"); + return 0; + } + + n = read(sockfd, (char *)&reqpkt, REQ_LEN_MAC); + if (n <= 0) { + if (n < 0) { + syslog(LOG_ERR, "read() fails: %m"); + return 0; + } + continue; + } + + /* + * Got one. Check through to make sure it is what + * we expect. + */ + if (n < RESP_HEADER_SIZE) { + syslog(LOG_ERR, "received runt response (%d octets)", + n); + continue; + } + + if (!ISRESPONSE(reqpkt.rm_vn_mode)) { +#ifdef DEBUG + if (debug > 1) + printf("received non-response packet\n"); +#endif + continue; + } + + if (ISMORE(reqpkt.rm_vn_mode)) { +#ifdef DEBUG + if (debug > 1) + printf("received fragmented packet\n"); +#endif + continue; + } + + if (INFO_VERSION(reqpkt.rm_vn_mode) != NTP_VERSION + || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) { +#ifdef DEBUG + if (debug > 1) + printf("version (%d) or mode (%d) incorrect\n", + INFO_VERSION(reqpkt.rm_vn_mode), + INFO_MODE(reqpkt.rm_vn_mode)); +#endif + continue; + } + + if (INFO_SEQ(reqpkt.auth_seq) != 0) { +#ifdef DEBUG + if (debug > 1) + printf("nonzero sequence number (%d)\n", + INFO_SEQ(reqpkt.auth_seq)); +#endif + continue; + } + + if (reqpkt.implementation != IMPL_XNTPD || + reqpkt.request != REQ_CONFIG) { +#ifdef DEBUG + if (debug > 1) + printf( + "implementation (%d) or request (%d) incorrect\n", + 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) + printf( + "nitems (%d) mbz (%d) or itemsize (%d) nonzero\n", + 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: + syslog(LOG_ERR, + "server reports implementation mismatch!!"); + return 0; + + case INFO_ERR_REQ: + syslog(LOG_ERR, + "server claims configuration request is unknown"); + return 0; + + case INFO_ERR_FMT: + syslog(LOG_ERR, + "server indicates a format error occured(!!)"); + return 0; + + case INFO_ERR_NODATA: + syslog(LOG_ERR, + "server indicates no data available (shouldn't happen)"); + return 0; + + case INFO_ERR_AUTH: + syslog(LOG_ERR, + "server returns a permission denied error"); + return 0; + + default: + syslog(LOG_ERR, + "server returns unknown error code %d", n); + return 0; + } + } +} + + +/* + * nexttoken - return the next token from a line + */ +static char * +nexttoken(lptr) + 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(fp, name) + FILE *fp; + char *name; +{ + register int i; + char *token[NUMTOK]; + U_LONG intval[NUMTOK]; + 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) { + syslog(LOG_ERR, + "tokenizing error in file `%s', quitting", + name); + exit(1); + } + } + + for (i = 1; i < NUMTOK; i++) { + if (!atouint(token[i], &intval[i])) { + syslog(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) { + syslog(LOG_ERR, "invalid mode (%d) in file %s", + intval[TOK_HMODE], name); + exit(1); + } + + if (intval[TOK_VERSION] > NTP_VERSION || + intval[TOK_VERSION] < NTP_OLDVERSION) { + syslog(LOG_ERR, "invalid version (%d) in file %s", + intval[TOK_VERSION], name); + exit(1); + } + + if (intval[TOK_MINPOLL] < NTP_MINPOLL || + intval[TOK_MINPOLL] > NTP_MAXPOLL) { + syslog(LOG_ERR, "invalid MINPOLL value (%d) in file %s", + intval[TOK_MINPOLL], name); + exit(1); + } + + if (intval[TOK_MAXPOLL] < NTP_MINPOLL || + intval[TOK_MAXPOLL] > NTP_MAXPOLL) { + syslog(LOG_ERR, "invalid MAXPOLL value (%d) in file %s", + intval[TOK_MAXPOLL], name); + exit(1); + } + + if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE|FLAG_PREFER)) + != 0) { + syslog(LOG_ERR, "invalid flags (%d) 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; + + /* + * 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, intval[TOK_KEYID]); + } +} + + +/* + * doconfigure - attempt to resolve names and configure the server + */ +static void +doconfigure(dores) + int dores; +{ + register struct conf_entry *ce; + register struct conf_entry *ceremove; + + ce = confentries; + while (ce != NULL) { + if (dores && ce->ce_peeraddr == 0) { + if (!findhostaddr(ce)) { + syslog(LOG_ERR, + "couldn't resolve `%s', giving up on it", + ce->ce_name); + ceremove = ce; + ce = ceremove->ce_next; + removeentry(ceremove); + continue; + } + } + + if (ce->ce_peeraddr != 0) { + if (request(&ce->ce_config)) { + ceremove = ce; + ce = ceremove->ce_next; + removeentry(ceremove); + continue; + } + } + ce = ce->ce_next; + } +} -- 2.20.1