aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/xntpd
diff options
context:
space:
mode:
authorGarrett Wollman <wollman@FreeBSD.org>1993-12-21 18:36:48 +0000
committerGarrett Wollman <wollman@FreeBSD.org>1993-12-21 18:36:48 +0000
commite7c996d95e438eb882cfb523ba6e047f12adb01f (patch)
tree726a343c62286ac7f6753b0f898e58cdcf285af6 /usr.sbin/xntpd
downloadsrc-e7c996d95e438eb882cfb523ba6e047f12adb01f.tar.gz
src-e7c996d95e438eb882cfb523ba6e047f12adb01f.zip
xntpd 3.3b from UDelvendor/ntpd/udel_33B
Notes
Notes: svn path=/cvs2svn/branches/UDEL/; revision=893 svn path=/vendor/ntpd/udel_33B/; revision=895; tag=vendor/ntpd/udel_33B
Diffstat (limited to 'usr.sbin/xntpd')
-rw-r--r--usr.sbin/xntpd/COPYRIGHT56
-rw-r--r--usr.sbin/xntpd/Config200
-rw-r--r--usr.sbin/xntpd/Config.local190
-rw-r--r--usr.sbin/xntpd/Config.local.dist190
-rw-r--r--usr.sbin/xntpd/Config.sed14
-rw-r--r--usr.sbin/xntpd/Makefile359
-rw-r--r--usr.sbin/xntpd/PORTING37
-rw-r--r--usr.sbin/xntpd/README163
-rw-r--r--usr.sbin/xntpd/RELNOTES195
-rw-r--r--usr.sbin/xntpd/TODO37
-rw-r--r--usr.sbin/xntpd/VERSION1
-rw-r--r--usr.sbin/xntpd/adjtime/Makefile.tmpl53
-rw-r--r--usr.sbin/xntpd/adjtime/README23
-rw-r--r--usr.sbin/xntpd/adjtime/adjtime.c101
-rw-r--r--usr.sbin/xntpd/adjtime/adjtime.h63
-rw-r--r--usr.sbin/xntpd/adjtime/adjtimed.c485
-rw-r--r--usr.sbin/xntpd/authstuff/Makefile.tmpl92
-rw-r--r--usr.sbin/xntpd/authstuff/README13
-rw-r--r--usr.sbin/xntpd/authstuff/auth.samplekeys45
-rw-r--r--usr.sbin/xntpd/authstuff/auth.speed20
-rw-r--r--usr.sbin/xntpd/authstuff/authcert.c96
-rw-r--r--usr.sbin/xntpd/authstuff/authspeed.c315
-rw-r--r--usr.sbin/xntpd/authstuff/certdata34
-rw-r--r--usr.sbin/xntpd/authstuff/keyparity.c279
-rw-r--r--usr.sbin/xntpd/authstuff/makeIPFP.c345
-rw-r--r--usr.sbin/xntpd/authstuff/makePC1.c286
-rw-r--r--usr.sbin/xntpd/authstuff/makePC2.c238
-rw-r--r--usr.sbin/xntpd/authstuff/makeSP.c183
-rw-r--r--usr.sbin/xntpd/authstuff/md5_sample_output8
-rw-r--r--usr.sbin/xntpd/authstuff/md5driver.c209
-rw-r--r--usr.sbin/xntpd/authstuff/mkrandkeys.c167
-rw-r--r--usr.sbin/xntpd/authstuff/omakeIPFP.c361
-rw-r--r--usr.sbin/xntpd/authstuff/results2
-rw-r--r--usr.sbin/xntpd/authstuff/unixcert.c156
-rw-r--r--usr.sbin/xntpd/clockstuff/Makefile.tmpl60
-rw-r--r--usr.sbin/xntpd/clockstuff/README31
-rw-r--r--usr.sbin/xntpd/clockstuff/chutest.c798
-rw-r--r--usr.sbin/xntpd/clockstuff/clktest.c511
-rw-r--r--usr.sbin/xntpd/clockstuff/propdelay.c536
-rw-r--r--usr.sbin/xntpd/compilers/README5
-rw-r--r--usr.sbin/xntpd/compilers/aux2.gcc1
-rw-r--r--usr.sbin/xntpd/compilers/aux3.gcc1
-rw-r--r--usr.sbin/xntpd/compilers/decosf1.gcc1
-rw-r--r--usr.sbin/xntpd/compilers/hpux.cc2
-rw-r--r--usr.sbin/xntpd/compilers/hpux.gcc2
-rw-r--r--usr.sbin/xntpd/compilers/hpux10+.cc1
-rw-r--r--usr.sbin/xntpd/compilers/linux.gcc2
-rw-r--r--usr.sbin/xntpd/compilers/mips.cc1
-rw-r--r--usr.sbin/xntpd/compilers/sinix-m.cc1
-rw-r--r--usr.sbin/xntpd/compilers/sinix-m.gcc2
-rw-r--r--usr.sbin/xntpd/compilers/sunos4.bsd.cc1
-rw-r--r--usr.sbin/xntpd/compilers/sunos4.bsd.gcc1
-rw-r--r--usr.sbin/xntpd/compilers/sunos4.posix.gcc1
-rw-r--r--usr.sbin/xntpd/compilers/sunos5.1.gcc2
-rw-r--r--usr.sbin/xntpd/compilers/sunos5.2.gcc2
-rw-r--r--usr.sbin/xntpd/compilers/ultrix.bsd.cc2
-rw-r--r--usr.sbin/xntpd/compilers/ultrix.bsd.gcc1
-rw-r--r--usr.sbin/xntpd/compilers/ultrix.posix.cc2
-rw-r--r--usr.sbin/xntpd/compilers/ultrix.posix.gcc1
-rw-r--r--usr.sbin/xntpd/conf/Config.CHATHAM214
-rw-r--r--usr.sbin/xntpd/conf/Config.MONOMOY189
-rw-r--r--usr.sbin/xntpd/conf/Config.TIGER185
-rw-r--r--usr.sbin/xntpd/conf/Config.TRURO205
-rw-r--r--usr.sbin/xntpd/conf/Config.dartnet187
-rw-r--r--usr.sbin/xntpd/conf/Config.local190
-rw-r--r--usr.sbin/xntpd/conf/Config.svr4167
-rw-r--r--usr.sbin/xntpd/conf/README8
-rw-r--r--usr.sbin/xntpd/conf/dewey.conf38
-rw-r--r--usr.sbin/xntpd/conf/grundoon.conf58
-rw-r--r--usr.sbin/xntpd/conf/malarky.conf40
-rw-r--r--usr.sbin/xntpd/conf/ntp.conf.gw34
-rw-r--r--usr.sbin/xntpd/conf/ntp.conf.ipl32
-rw-r--r--usr.sbin/xntpd/conf/ntp.conf.nsf156
-rw-r--r--usr.sbin/xntpd/conf/ntp.conf.shiningtree32
-rw-r--r--usr.sbin/xntpd/conf/ntp.conf.suzuki43
-rw-r--r--usr.sbin/xntpd/conf/pogo.conf50
-rw-r--r--usr.sbin/xntpd/conf/rackety.conf75
-rw-r--r--usr.sbin/xntpd/conf/snow-white.conf33
-rw-r--r--usr.sbin/xntpd/doc/README.irig306
-rw-r--r--usr.sbin/xntpd/doc/README.kern775
-rw-r--r--usr.sbin/xntpd/doc/README.magic346
-rw-r--r--usr.sbin/xntpd/doc/UofT146
-rw-r--r--usr.sbin/xntpd/doc/notes.txt1258
-rw-r--r--usr.sbin/xntpd/doc/ntpdate.8185
-rw-r--r--usr.sbin/xntpd/doc/ntpq.8566
-rw-r--r--usr.sbin/xntpd/doc/ntptrace.8104
-rw-r--r--usr.sbin/xntpd/doc/tickadj.8143
-rw-r--r--usr.sbin/xntpd/doc/xntpd.81352
-rw-r--r--usr.sbin/xntpd/doc/xntpdc.8659
-rw-r--r--usr.sbin/xntpd/gadget/README84
-rw-r--r--usr.sbin/xntpd/gadget/adt0127.lpr1427
-rw-r--r--usr.sbin/xntpd/gadget/art01.lpr890
-rw-r--r--usr.sbin/xntpd/gadget/art02.lpr893
-rw-r--r--usr.sbin/xntpd/gadget/dd0124.lpr813
-rw-r--r--usr.sbin/xntpd/gadget/gadget.lst332
-rw-r--r--usr.sbin/xntpd/gadget/gadget.s012277
-rw-r--r--usr.sbin/xntpd/gadget/gadget.s02288
-rw-r--r--usr.sbin/xntpd/gadget/gen0102.lpr1973
-rw-r--r--usr.sbin/xntpd/gadget/sm0228.lpr744
-rw-r--r--usr.sbin/xntpd/gadget/sst0126.lpr1118
-rw-r--r--usr.sbin/xntpd/hints/README12
-rw-r--r--usr.sbin/xntpd/hints/aux159
-rw-r--r--usr.sbin/xntpd/hints/bsdi61
-rw-r--r--usr.sbin/xntpd/hints/decosf140
-rw-r--r--usr.sbin/xntpd/hints/hpux76
-rw-r--r--usr.sbin/xntpd/hints/notes-xntp-v3119
-rw-r--r--usr.sbin/xntpd/hints/parse105
-rw-r--r--usr.sbin/xntpd/hints/refclocks32
-rw-r--r--usr.sbin/xntpd/hints/rs600056
-rw-r--r--usr.sbin/xntpd/hints/sgi74
-rw-r--r--usr.sbin/xntpd/hints/solaris88
-rw-r--r--usr.sbin/xntpd/hints/svr4-dell6
-rw-r--r--usr.sbin/xntpd/include/README6
-rw-r--r--usr.sbin/xntpd/include/l_stdlib.h228
-rw-r--r--usr.sbin/xntpd/include/md5.h56
-rw-r--r--usr.sbin/xntpd/include/mx4200.h42
-rw-r--r--usr.sbin/xntpd/include/ntp.h681
-rw-r--r--usr.sbin/xntpd/include/ntp_calendar.h80
-rw-r--r--usr.sbin/xntpd/include/ntp_control.h249
-rw-r--r--usr.sbin/xntpd/include/ntp_filegen.h51
-rw-r--r--usr.sbin/xntpd/include/ntp_fp.h315
-rw-r--r--usr.sbin/xntpd/include/ntp_if.h43
-rw-r--r--usr.sbin/xntpd/include/ntp_io.h24
-rw-r--r--usr.sbin/xntpd/include/ntp_machine.h457
-rw-r--r--usr.sbin/xntpd/include/ntp_malloc.h15
-rw-r--r--usr.sbin/xntpd/include/ntp_refclock.h142
-rw-r--r--usr.sbin/xntpd/include/ntp_request.h713
-rw-r--r--usr.sbin/xntpd/include/ntp_select.h20
-rw-r--r--usr.sbin/xntpd/include/ntp_stdlib.h92
-rw-r--r--usr.sbin/xntpd/include/ntp_string.h29
-rw-r--r--usr.sbin/xntpd/include/ntp_syslog.h15
-rw-r--r--usr.sbin/xntpd/include/ntp_timex.h158
-rw-r--r--usr.sbin/xntpd/include/ntp_types.h60
-rw-r--r--usr.sbin/xntpd/include/ntp_unixtime.h119
-rw-r--r--usr.sbin/xntpd/include/ntpd.h142
-rw-r--r--usr.sbin/xntpd/include/parse.h401
-rw-r--r--usr.sbin/xntpd/include/parse_conf.h54
-rw-r--r--usr.sbin/xntpd/include/sys/bsd_audioirig.h101
-rw-r--r--usr.sbin/xntpd/include/sys/chudefs.h22
-rw-r--r--usr.sbin/xntpd/include/sys/clkdefs.h31
-rw-r--r--usr.sbin/xntpd/include/sys/parsestreams.h66
-rw-r--r--usr.sbin/xntpd/include/sys/ppsclock.h59
-rw-r--r--usr.sbin/xntpd/include/sys/tpro.h34
-rw-r--r--usr.sbin/xntpd/kernel/Makefile.tmpl39
-rw-r--r--usr.sbin/xntpd/kernel/README90
-rw-r--r--usr.sbin/xntpd/kernel/README.kern596
-rw-r--r--usr.sbin/xntpd/kernel/README.streams86
-rw-r--r--usr.sbin/xntpd/kernel/tty_chu.c276
-rw-r--r--usr.sbin/xntpd/kernel/tty_chu_STREAMS.c444
-rw-r--r--usr.sbin/xntpd/kernel/tty_clk.c303
-rw-r--r--usr.sbin/xntpd/kernel/tty_clk_STREAMS.c265
-rw-r--r--usr.sbin/xntpd/lib/Makefile.tmpl75
-rw-r--r--usr.sbin/xntpd/lib/README5
-rw-r--r--usr.sbin/xntpd/lib/a_md512crypt.c86
-rw-r--r--usr.sbin/xntpd/lib/a_md5decrypt.c58
-rw-r--r--usr.sbin/xntpd/lib/a_md5encrypt.c68
-rw-r--r--usr.sbin/xntpd/lib/adjtimex.c15
-rw-r--r--usr.sbin/xntpd/lib/atoint.c48
-rw-r--r--usr.sbin/xntpd/lib/atolfp.c117
-rw-r--r--usr.sbin/xntpd/lib/atouint.c33
-rw-r--r--usr.sbin/xntpd/lib/auth12crypt.c125
-rw-r--r--usr.sbin/xntpd/lib/authdecrypt.c85
-rw-r--r--usr.sbin/xntpd/lib/authdes.c891
-rw-r--r--usr.sbin/xntpd/lib/authdes.c.export40
-rw-r--r--usr.sbin/xntpd/lib/authencrypt.c88
-rw-r--r--usr.sbin/xntpd/lib/authkeys.c602
-rw-r--r--usr.sbin/xntpd/lib/authparity.c58
-rw-r--r--usr.sbin/xntpd/lib/authreadkeys.c191
-rw-r--r--usr.sbin/xntpd/lib/authusekey.c132
-rw-r--r--usr.sbin/xntpd/lib/buftvtots.c61
-rw-r--r--usr.sbin/xntpd/lib/caljulian.c105
-rw-r--r--usr.sbin/xntpd/lib/calleapwhen.c61
-rw-r--r--usr.sbin/xntpd/lib/caltontp.c90
-rw-r--r--usr.sbin/xntpd/lib/calyearstart.c62
-rw-r--r--usr.sbin/xntpd/lib/clocktime.c131
-rw-r--r--usr.sbin/xntpd/lib/clocktypes.c45
-rw-r--r--usr.sbin/xntpd/lib/decodenetnum.c58
-rw-r--r--usr.sbin/xntpd/lib/dofptoa.c117
-rw-r--r--usr.sbin/xntpd/lib/dolfptoa.c162
-rw-r--r--usr.sbin/xntpd/lib/emalloc.c20
-rwxr-xr-xusr.sbin/xntpd/lib/findconfig.c62
-rw-r--r--usr.sbin/xntpd/lib/fptoa.c24
-rw-r--r--usr.sbin/xntpd/lib/fptoms.c23
-rw-r--r--usr.sbin/xntpd/lib/getopt.c106
-rw-r--r--usr.sbin/xntpd/lib/gettstamp.c29
-rw-r--r--usr.sbin/xntpd/lib/hextoint.c38
-rw-r--r--usr.sbin/xntpd/lib/hextolfp.c66
-rw-r--r--usr.sbin/xntpd/lib/humandate.c61
-rw-r--r--usr.sbin/xntpd/lib/inttoa.c19
-rw-r--r--usr.sbin/xntpd/lib/lib_strbuf.c21
-rw-r--r--usr.sbin/xntpd/lib/lib_strbuf.h22
-rw-r--r--usr.sbin/xntpd/lib/machines.c118
-rw-r--r--usr.sbin/xntpd/lib/md5.c322
-rw-r--r--usr.sbin/xntpd/lib/mfptoa.c22
-rw-r--r--usr.sbin/xntpd/lib/mfptoms.c22
-rw-r--r--usr.sbin/xntpd/lib/modetoa.c33
-rw-r--r--usr.sbin/xntpd/lib/mstolfp.c99
-rw-r--r--usr.sbin/xntpd/lib/msutotsf.c35
-rw-r--r--usr.sbin/xntpd/lib/msyslog.c107
-rw-r--r--usr.sbin/xntpd/lib/numtoa.c24
-rw-r--r--usr.sbin/xntpd/lib/numtohost.c39
-rw-r--r--usr.sbin/xntpd/lib/octtoint.c34
-rw-r--r--usr.sbin/xntpd/lib/prettydate.c44
-rw-r--r--usr.sbin/xntpd/lib/ranny.c97
-rw-r--r--usr.sbin/xntpd/lib/refnumtoa.c34
-rw-r--r--usr.sbin/xntpd/lib/syssignal.c45
-rw-r--r--usr.sbin/xntpd/lib/systime.c371
-rw-r--r--usr.sbin/xntpd/lib/tsftomsu.c37
-rw-r--r--usr.sbin/xntpd/lib/tstotod.c21
-rw-r--r--usr.sbin/xntpd/lib/tstotv.c135
-rw-r--r--usr.sbin/xntpd/lib/tvtoa.c33
-rw-r--r--usr.sbin/xntpd/lib/tvtots.c159
-rw-r--r--usr.sbin/xntpd/lib/uglydate.c53
-rw-r--r--usr.sbin/xntpd/lib/uinttoa.c19
-rw-r--r--usr.sbin/xntpd/lib/utvtoa.c21
-rw-r--r--usr.sbin/xntpd/machines/README5
-rw-r--r--usr.sbin/xntpd/machines/aix3.210
-rw-r--r--usr.sbin/xntpd/machines/aux29
-rw-r--r--usr.sbin/xntpd/machines/aux39
-rw-r--r--usr.sbin/xntpd/machines/bsdi9
-rw-r--r--usr.sbin/xntpd/machines/convexos1010
-rw-r--r--usr.sbin/xntpd/machines/convexos99
-rw-r--r--usr.sbin/xntpd/machines/decosf19
-rw-r--r--usr.sbin/xntpd/machines/freebsd8
-rw-r--r--usr.sbin/xntpd/machines/hpux8
-rw-r--r--usr.sbin/xntpd/machines/hpux10+8
-rw-r--r--usr.sbin/xntpd/machines/i3867
-rw-r--r--usr.sbin/xntpd/machines/i386svr49
-rw-r--r--usr.sbin/xntpd/machines/irix49
-rw-r--r--usr.sbin/xntpd/machines/irix59
-rw-r--r--usr.sbin/xntpd/machines/linux8
-rw-r--r--usr.sbin/xntpd/machines/mips9
-rw-r--r--usr.sbin/xntpd/machines/netbsd8
-rw-r--r--usr.sbin/xntpd/machines/next9
-rw-r--r--usr.sbin/xntpd/machines/ptx8
-rw-r--r--usr.sbin/xntpd/machines/sequent8
-rw-r--r--usr.sbin/xntpd/machines/sinix-m11
-rw-r--r--usr.sbin/xntpd/machines/sony6
-rw-r--r--usr.sbin/xntpd/machines/sunos4.bsd11
-rw-r--r--usr.sbin/xntpd/machines/sunos4.posix11
-rw-r--r--usr.sbin/xntpd/machines/sunos5.111
-rw-r--r--usr.sbin/xntpd/machines/sunos5.211
-rw-r--r--usr.sbin/xntpd/machines/svr410
-rw-r--r--usr.sbin/xntpd/machines/ultrix.bsd7
-rw-r--r--usr.sbin/xntpd/machines/ultrix.posix7
-rw-r--r--usr.sbin/xntpd/machines/vax6
-rw-r--r--usr.sbin/xntpd/ntpdate/Makefile.tmpl70
-rw-r--r--usr.sbin/xntpd/ntpdate/README7
-rw-r--r--usr.sbin/xntpd/ntpdate/ntpdate.c1598
-rw-r--r--usr.sbin/xntpd/ntpdate/ntpdate.h86
-rw-r--r--usr.sbin/xntpd/ntpq/Makefile.tmpl68
-rw-r--r--usr.sbin/xntpd/ntpq/README6
-rw-r--r--usr.sbin/xntpd/ntpq/ntpq.c3059
-rw-r--r--usr.sbin/xntpd/ntpq/ntpq.h97
-rw-r--r--usr.sbin/xntpd/ntpq/ntpq_ops.c1600
-rw-r--r--usr.sbin/xntpd/ntptrace/Makefile.tmpl70
-rw-r--r--usr.sbin/xntpd/ntptrace/README7
-rw-r--r--usr.sbin/xntpd/ntptrace/ntptrace.c777
-rw-r--r--usr.sbin/xntpd/ntptrace/ntptrace.h36
-rw-r--r--usr.sbin/xntpd/parse/Makefile.kernel71
-rw-r--r--usr.sbin/xntpd/parse/Makefile.tmpl111
-rw-r--r--usr.sbin/xntpd/parse/README100
-rw-r--r--usr.sbin/xntpd/parse/README.parse142
-rw-r--r--usr.sbin/xntpd/parse/clk_dcf7000.c142
-rw-r--r--usr.sbin/xntpd/parse/clk_meinberg.c444
-rw-r--r--usr.sbin/xntpd/parse/clk_rawdcf.c553
-rw-r--r--usr.sbin/xntpd/parse/clk_schmid.c195
-rw-r--r--usr.sbin/xntpd/parse/clk_trimble.c131
-rw-r--r--usr.sbin/xntpd/parse/empty.c7
-rw-r--r--usr.sbin/xntpd/parse/parse.c1193
-rw-r--r--usr.sbin/xntpd/parse/parse_conf.c117
-rw-r--r--usr.sbin/xntpd/parse/parsesolaris.c1170
-rw-r--r--usr.sbin/xntpd/parse/parsestreams.c1277
-rw-r--r--usr.sbin/xntpd/parse/util/Makefile49
-rw-r--r--usr.sbin/xntpd/parse/util/Makefile.tmpl49
-rw-r--r--usr.sbin/xntpd/parse/util/README12
-rw-r--r--usr.sbin/xntpd/parse/util/dcfd.c1206
-rw-r--r--usr.sbin/xntpd/parse/util/parsetest.c268
-rw-r--r--usr.sbin/xntpd/parse/util/testdcf.c485
-rw-r--r--usr.sbin/xntpd/refclocks/Dependencies28
-rw-r--r--usr.sbin/xntpd/refclocks/README4
-rwxr-xr-xusr.sbin/xntpd/refclocks/check2
-rwxr-xr-xusr.sbin/xntpd/refclocks/echon2
-rwxr-xr-xusr.sbin/xntpd/refclocks/query11
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.AS220129
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.CHU24
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.GOES32
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.IRIG24
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.LEITCH29
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.LOCAL_CLOCK22
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.MSFEES26
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.MX420027
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.OMEGA29
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.PARSE51
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.PST37
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.TPRO24
-rw-r--r--usr.sbin/xntpd/refclocks/rclk.WWVB38
-rw-r--r--usr.sbin/xntpd/refclocks/rconfig119
-rw-r--r--usr.sbin/xntpd/refclocks/setup16
-rw-r--r--usr.sbin/xntpd/refclocks/setupfn27
-rwxr-xr-xusr.sbin/xntpd/scripts/Guess.sh116
-rw-r--r--usr.sbin/xntpd/scripts/README41
-rwxr-xr-xusr.sbin/xntpd/scripts/autoconf885
-rwxr-xr-xusr.sbin/xntpd/scripts/install.sh100
-rwxr-xr-xusr.sbin/xntpd/scripts/makeconfig.sh85
-rwxr-xr-xusr.sbin/xntpd/scripts/mklinks9
-rwxr-xr-xusr.sbin/xntpd/scripts/mkversion33
-rw-r--r--usr.sbin/xntpd/scripts/monitoring/README154
-rw-r--r--usr.sbin/xntpd/scripts/monitoring/loopwatch.config.SAMPLE89
-rwxr-xr-xusr.sbin/xntpd/scripts/monitoring/lr.pl145
-rwxr-xr-xusr.sbin/xntpd/scripts/monitoring/ntp.pl477
-rwxr-xr-xusr.sbin/xntpd/scripts/monitoring/ntploopstat457
-rwxr-xr-xusr.sbin/xntpd/scripts/monitoring/ntploopwatch1631
-rwxr-xr-xusr.sbin/xntpd/scripts/monitoring/ntptrap453
-rwxr-xr-xusr.sbin/xntpd/scripts/monitoring/timelocal.pl77
-rwxr-xr-xusr.sbin/xntpd/scripts/ntp-groper95
-rwxr-xr-xusr.sbin/xntpd/scripts/ntp-restart9
-rw-r--r--usr.sbin/xntpd/scripts/stats/README32
-rw-r--r--usr.sbin/xntpd/scripts/stats/README.stats246
-rw-r--r--usr.sbin/xntpd/scripts/stats/README.timecodes149
-rw-r--r--usr.sbin/xntpd/scripts/stats/clock.awk341
-rwxr-xr-xusr.sbin/xntpd/scripts/stats/clock.sh17
-rw-r--r--usr.sbin/xntpd/scripts/stats/dupe.awk7
-rw-r--r--usr.sbin/xntpd/scripts/stats/ensemble.awk17
-rw-r--r--usr.sbin/xntpd/scripts/stats/etf.awk19
-rw-r--r--usr.sbin/xntpd/scripts/stats/itf.awk19
-rw-r--r--usr.sbin/xntpd/scripts/stats/loop.awk49
-rwxr-xr-xusr.sbin/xntpd/scripts/stats/loop.sh13
-rw-r--r--usr.sbin/xntpd/scripts/stats/peer.awk57
-rwxr-xr-xusr.sbin/xntpd/scripts/stats/peer.sh13
-rw-r--r--usr.sbin/xntpd/scripts/stats/psummary.awk41
-rwxr-xr-xusr.sbin/xntpd/scripts/stats/summary.sh12
-rw-r--r--usr.sbin/xntpd/scripts/stats/tdata.awk45
-rw-r--r--usr.sbin/xntpd/scripts/support/README73
-rwxr-xr-xusr.sbin/xntpd/scripts/support/bin/monl212
-rwxr-xr-xusr.sbin/xntpd/scripts/support/bin/mvstats23
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/hp300.hp30070
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/hp700.hp70067
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/hp700.hp700.faui4771
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/hp800.hp80070
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/ntp.conf36
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/ntp.keys0
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/ntp.keys.dumb0
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/sun3.sun336
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/sun4.sun4.faui0183
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/sun4.sun4.faui10176
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/sun4.sun4.faui45228
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/sun4.sun4c63
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/sun4.sun4c.Lucifer174
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/sun4.sun4m69
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/sun4.sun4m.faui42152
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/sun4.sun4m.faui45m165
-rw-r--r--usr.sbin/xntpd/scripts/support/conf/tickconf19
-rwxr-xr-xusr.sbin/xntpd/scripts/support/etc/cron18
-rw-r--r--usr.sbin/xntpd/scripts/support/etc/crontab8
-rwxr-xr-xusr.sbin/xntpd/scripts/support/etc/install67
-rwxr-xr-xusr.sbin/xntpd/scripts/support/etc/rc198
-rwxr-xr-xusr.sbin/xntpd/scripts/support/etc/setup72
-rw-r--r--usr.sbin/xntpd/util/Makefile.tmpl62
-rw-r--r--usr.sbin/xntpd/util/README67
-rw-r--r--usr.sbin/xntpd/util/byteorder.c52
-rw-r--r--usr.sbin/xntpd/util/jitter.c73
-rw-r--r--usr.sbin/xntpd/util/kern.c210
-rw-r--r--usr.sbin/xntpd/util/longsize.c11
-rw-r--r--usr.sbin/xntpd/util/ntptime.c220
-rw-r--r--usr.sbin/xntpd/util/precision.c81
-rw-r--r--usr.sbin/xntpd/util/testrs6000.c44
-rw-r--r--usr.sbin/xntpd/util/tickadj.c518
-rw-r--r--usr.sbin/xntpd/util/timetrim.c85
-rw-r--r--usr.sbin/xntpd/xntpd/Makefile.tmpl138
-rw-r--r--usr.sbin/xntpd/xntpd/README6
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_config.c1849
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_control.c2305
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_filegen.c536
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_intres.c792
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_io.c1621
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_leap.c315
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_loopfilter.c944
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_monitor.c305
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_peer.c639
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_proto.c2168
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_refclock.c439
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_request.c2336
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_restrict.c297
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_timer.c187
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_unixclock.c564
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_util.c466
-rw-r--r--usr.sbin/xntpd/xntpd/ntpd.c438
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_as2201.c991
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_chu.c1135
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_conf.c121
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_goes.c1009
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_irig.c566
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_leitch.c700
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_local.c307
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_msfees.c1570
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_mx4200.c1357
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_omega.c1015
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_parse.c3471
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_pst.c1800
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_tpro.c498
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_wwvb.c1041
-rw-r--r--usr.sbin/xntpd/xntpdc/Makefile.tmpl68
-rw-r--r--usr.sbin/xntpd/xntpdc/README6
-rw-r--r--usr.sbin/xntpd/xntpdc/ntpdc.c1536
-rw-r--r--usr.sbin/xntpd/xntpdc/ntpdc.h59
-rw-r--r--usr.sbin/xntpd/xntpdc/ntpdc_ops.c2421
-rw-r--r--usr.sbin/xntpd/xntpres/Makefile.tmpl68
-rw-r--r--usr.sbin/xntpd/xntpres/README6
-rw-r--r--usr.sbin/xntpd/xntpres/xntpres.c845
410 files changed, 101569 insertions, 0 deletions
diff --git a/usr.sbin/xntpd/COPYRIGHT b/usr.sbin/xntpd/COPYRIGHT
new file mode 100644
index 000000000000..be272fe18063
--- /dev/null
+++ b/usr.sbin/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 <dennis@mrbill.canet.ca> (foundation code for NTP
+ * Version 2 as specified in RFC-1119)
+ * Lars H. Mathiesen <thorinn@diku.dk> (adaptation of foundation code for
+ * Version 3 as specified in RFC-1305)
+ * Louis A. Mamakos <louie@ni.umd.edu> (support for md5-based
+ * authentication)
+ * Craig Leres <leres@ee.lbl.gov> (port to 4.4BSD operating system,
+ * ppsclock, Maganavox GPS clock driver)
+ * Nick Sayer <mrapple@quack.kfu.com> (SunOS streams modules)
+ * Frank Kardel <Frank.Kardel@informatik.uni-erlangen.de>
+ * (PARSE (GENERIC) driver, STREAMS module for PARSE, support scripts,
+ * reference clock configuration scripts, Makefile cleanup)
+ * Rainer Pruy <Rainer.Pruy@informatik.uni-erlangen.de> (monitoring/trap
+ * scripts, statistics file handling)
+ * Glenn Hollinger <glenn@herald.usask.ca> (GOES clock driver)
+ * Kenneth Stone <ken@sdd.hp.com> (port to HPUX operating system)
+ * Dave Katz <dkatz@cisco.com> (port to RS/6000 AIX operating system)
+ * William L. Jones <jones@hermes.chpc.utexas.edu> (RS/6000 AIX
+ * modifications, HPUX modifications)
+ * John A. Dundas III <dundas@salt.jpl.nasa.gov> (Apple A/UX port)
+ * David L. Mills <mills@udel.edu> (Spectractom WWVB, Austron GPS,
+ * and KSI/Odetics IRIG-B clock drivers; pps support)
+ * Jeffrey Mogul <mogul@pa.dec.com> (ntptrace utility)
+ * Steve Clift (clift@ml.csiro.au) OMEGA clock driver)
+ * Mike Iglesias (iglesias@uci.edu) (DEC Alpha changes)
+ * Mark Andrews <marka@syd.dms.csiro.au> (Leitch atomic clock controller)
+ * George Lindholm <lindholm@ucs.ubc.ca> (port to SunOS 5.1 operating system)
+ * Jeff Johnson <jbj@chatham.usdesign.com> (massive prototyping overhaul)
+ * Tom Moore <tmoore@fievel.daytonoh.ncr.com> (port to i386 svr4)
+ * Piete Brooks <Piete.Brooks@cl.cam.ac.uk> (MSF clock driver, Trimble PARSE
+ * support)
+ * Karl Berry <karl@owl.HQ.ileaf.com> (syslog to file option)
+ * Torsten Duwe <duwe@immd4.informatik.uni-erlangen.de> (Linux Port)
+ */
diff --git a/usr.sbin/xntpd/Config b/usr.sbin/xntpd/Config
new file mode 100644
index 000000000000..c15ec053a520
--- /dev/null
+++ b/usr.sbin/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 <filename>" 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/usr.sbin/xntpd/Config.local b/usr.sbin/xntpd/Config.local
new file mode 100644
index 000000000000..4c5095c164da
--- /dev/null
+++ b/usr.sbin/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 <filename>" 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/usr.sbin/xntpd/Config.local.dist b/usr.sbin/xntpd/Config.local.dist
new file mode 100644
index 000000000000..4c5c24672700
--- /dev/null
+++ b/usr.sbin/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 <filename>" 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/usr.sbin/xntpd/Config.sed b/usr.sbin/xntpd/Config.sed
new file mode 100644
index 000000000000..fe5a9b7927bd
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/Makefile b/usr.sbin/xntpd/Makefile
new file mode 100644
index 000000000000..30e59bbb5ce0
--- /dev/null
+++ b/usr.sbin/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 <VERSION>.tar.<comperssorsuffix>)
+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/usr.sbin/xntpd/PORTING b/usr.sbin/xntpd/PORTING
new file mode 100644
index 000000000000..7f236424ec4f
--- /dev/null
+++ b/usr.sbin/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 <string.h>.
+ 3) Always include "ntp_malloc.h" if you use malloc.
+ 4) Always include "ntp_io.h" instead of <sys/file.h> or <fnctl.h> to
+ get O_* flags.
+ 5) Always include "ntp_if.h" instead of <net/if.h>.
+ 6) Always include "ntp_stdlib.h" instead of <stdlib.h>.
+ 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/usr.sbin/xntpd/README b/usr.sbin/xntpd/README
new file mode 100644
index 000000000000..76414a2a52d5
--- /dev/null
+++ b/usr.sbin/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-<version>.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/usr.sbin/xntpd/RELNOTES b/usr.sbin/xntpd/RELNOTES
new file mode 100644
index 000000000000..277b8921de82
--- /dev/null
+++ b/usr.sbin/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=<machine>", where <machine> 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=<compiler>", where <compiler> 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: <prefix><version>.tar.<compression suffix> - 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 <jones@chpc.utexas.edu>
+Dennis Ferguson (Advanced Network Systems) <dennis@ans.net>
+Lars Mathiesen (University of Copenhagen) <thorinn@diku.dk>
+David Mills <mills@udel.edu>
+Frank Kardel <Frank.Kardel@informatik.uni-erlangen.de>
+Piete Brooks <Piete.Brooks@cl.cam.ac.uk>
+
+-- and a cast of thousands -- see the COPYRIGHT file
+16 November 1993
diff --git a/usr.sbin/xntpd/TODO b/usr.sbin/xntpd/TODO
new file mode 100644
index 000000000000..9b803722efc9
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/VERSION b/usr.sbin/xntpd/VERSION
new file mode 100644
index 000000000000..80868e3ba5fb
--- /dev/null
+++ b/usr.sbin/xntpd/VERSION
@@ -0,0 +1 @@
+version=3.3b (beta)
diff --git a/usr.sbin/xntpd/adjtime/Makefile.tmpl b/usr.sbin/xntpd/adjtime/Makefile.tmpl
new file mode 100644
index 000000000000..c2e8381165b8
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/adjtime/README b/usr.sbin/xntpd/adjtime/README
new file mode 100644
index 000000000000..fe8b7e51e78a
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/adjtime/adjtime.c b/usr.sbin/xntpd/adjtime/adjtime.c
new file mode 100644
index 000000000000..5b0475e1d31b
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <time.h>
+#include <signal.h>
+#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/usr.sbin/xntpd/adjtime/adjtime.h b/usr.sbin/xntpd/adjtime/adjtime.h
new file mode 100644
index 000000000000..f063a4777bf1
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/adjtime/adjtimed.c b/usr.sbin/xntpd/adjtime/adjtimed.c
new file mode 100644
index 000000000000..f2de6921cf34
--- /dev/null
+++ b/usr.sbin/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 <sys/param.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <time.h>
+#include <signal.h>
+#include <nlist.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#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/usr.sbin/xntpd/authstuff/Makefile.tmpl b/usr.sbin/xntpd/authstuff/Makefile.tmpl
new file mode 100644
index 000000000000..e5f0310eb330
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/authstuff/README b/usr.sbin/xntpd/authstuff/README
new file mode 100644
index 000000000000..2985751cc0c0
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/authstuff/auth.samplekeys b/usr.sbin/xntpd/authstuff/auth.samplekeys
new file mode 100644
index 000000000000..c46d283405f2
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/authstuff/auth.speed b/usr.sbin/xntpd/authstuff/auth.speed
new file mode 100644
index 000000000000..b55f20cbd821
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/authstuff/authcert.c b/usr.sbin/xntpd/authstuff/authcert.c
new file mode 100644
index 000000000000..6f6e42c220c8
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#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/usr.sbin/xntpd/authstuff/authspeed.c b/usr.sbin/xntpd/authstuff/authspeed.c
new file mode 100644
index 000000000000..05af1326d8ed
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#ifdef FAKE_RUSAGE
+#include <sys/param.h>
+#include <sys/times.h>
+#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/usr.sbin/xntpd/authstuff/certdata b/usr.sbin/xntpd/authstuff/certdata
new file mode 100644
index 000000000000..f9a818efecb8
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/authstuff/keyparity.c b/usr.sbin/xntpd/authstuff/keyparity.c
new file mode 100644
index 000000000000..45a706173b43
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+#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/usr.sbin/xntpd/authstuff/makeIPFP.c b/usr.sbin/xntpd/authstuff/makeIPFP.c
new file mode 100644
index 000000000000..51f8a55e7240
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+
+#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/usr.sbin/xntpd/authstuff/makePC1.c b/usr.sbin/xntpd/authstuff/makePC1.c
new file mode 100644
index 000000000000..c0109892fa10
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+
+#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/usr.sbin/xntpd/authstuff/makePC2.c b/usr.sbin/xntpd/authstuff/makePC2.c
new file mode 100644
index 000000000000..d92d2b2a9eaf
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+
+#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/usr.sbin/xntpd/authstuff/makeSP.c b/usr.sbin/xntpd/authstuff/makeSP.c
new file mode 100644
index 000000000000..bfeb82c1304e
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+
+#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/usr.sbin/xntpd/authstuff/md5_sample_output b/usr.sbin/xntpd/authstuff/md5_sample_output
new file mode 100644
index 000000000000..a7d4282d2edb
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/authstuff/md5driver.c b/usr.sbin/xntpd/authstuff/md5driver.c
new file mode 100644
index 000000000000..73db940598fd
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+#include <time.h>
+#ifdef __bsdi__
+#include <sys/time.h>
+#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/usr.sbin/xntpd/authstuff/mkrandkeys.c b/usr.sbin/xntpd/authstuff/mkrandkeys.c
new file mode 100644
index 000000000000..3bb987af8f2d
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#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/usr.sbin/xntpd/authstuff/omakeIPFP.c b/usr.sbin/xntpd/authstuff/omakeIPFP.c
new file mode 100644
index 000000000000..887cc58c287b
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+
+#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/usr.sbin/xntpd/authstuff/results b/usr.sbin/xntpd/authstuff/results
new file mode 100644
index 000000000000..305a179d0a2c
--- /dev/null
+++ b/usr.sbin/xntpd/authstuff/results
@@ -0,0 +1,2 @@
+odin/1000000: 0.000145
+idavolde/1000000: 0.000451
diff --git a/usr.sbin/xntpd/authstuff/unixcert.c b/usr.sbin/xntpd/authstuff/unixcert.c
new file mode 100644
index 000000000000..36234b13f55f
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+
+#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/usr.sbin/xntpd/clockstuff/Makefile.tmpl b/usr.sbin/xntpd/clockstuff/Makefile.tmpl
new file mode 100644
index 000000000000..9a0f9c184b43
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/clockstuff/README b/usr.sbin/xntpd/clockstuff/README
new file mode 100644
index 000000000000..3714ab3b4767
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/clockstuff/chutest.c b/usr.sbin/xntpd/clockstuff/chutest.c
new file mode 100644
index 000000000000..f65686c3b3ca
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sgtty.h>
+
+#include "../include/ntp_fp.h"
+#include "../include/ntp.h"
+#include "../include/ntp_unixtime.h"
+
+#ifdef STREAM
+#include <sys/chudefs.h>
+#include <stropts.h>
+#endif
+
+#ifdef CHULDISC
+#include <sys/chudefs.h>
+#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<<i))
+ M_ADD(prod_ui, prod_uf, date_ui, tmp);
+ }
+
+ /*
+ * Done, round it correctly. Prod_ui contains the
+ * fraction.
+ */
+ if (prod_uf & 0x80000000)
+ prod_ui++;
+ if (isneg)
+ date_ui = 0xffffffff;
+ else
+ date_ui = 0;
+ tmp = prod_ui;
+ /*
+ * date_ui is integral part, tmp is fraction.
+ */
+ } else {
+ register u_long prod_ovr;
+ register u_long prod_ui;
+ register u_long prod_uf;
+ register u_long highbits;
+
+ prod_ovr = prod_ui = prod_uf = 0;
+ if (isneg)
+ highbits = 0xffffffff; /* sign extend */
+ else
+ highbits = 0;
+ /*
+ * This code knows the low order bit in 0.1 is zero
+ */
+ for (i = 1; i < NZPOBITS; i++) {
+ M_LSHIFT3(highbits, date_ui, tmp);
+ if (ZEROPTONE & (1<<i))
+ M_ADD3(prod_ovr, prod_uf, prod_ui,
+ highbits, date_ui, tmp);
+ }
+
+ if (prod_uf & 0x80000000)
+ M_ADDUF(prod_ovr, prod_ui, (u_long)1);
+ date_ui = prod_ovr;
+ tmp = prod_ui;
+ }
+
+ /*
+ * At this point we have the mean offset, with the integral
+ * part in date_ui and the fractional part in tmp. Store
+ * it in the structure.
+ */
+ /*
+ * Add in fudge factor.
+ */
+ M_ADD(date_ui, tmp, offset_fudge.l_ui, offset_fudge.l_uf);
+
+ /*
+ * Find the minimun and maximum offset
+ */
+ imin = imax = 0;
+ for (i = 1; i < NCHUCHARS; i++) {
+ if (L_ISGEQ(&off[i], &off[imax])) {
+ imax = i;
+ } else if (L_ISGEQ(&off[imin], &off[i])) {
+ imin = i;
+ }
+ }
+
+ L_ADD(&off[imin], &offset_fudge);
+ if (imin != imax)
+ L_ADD(&off[imax], &offset_fudge);
+ (void) printf("mean %s, min %s, max %s\n",
+ mfptoa(date_ui, tmp, 8), lfptoa(&off[imin], 8),
+ lfptoa(&off[imax], 8));
+}
diff --git a/usr.sbin/xntpd/clockstuff/clktest.c b/usr.sbin/xntpd/clockstuff/clktest.c
new file mode 100644
index 000000000000..7ed13b3aa33c
--- /dev/null
+++ b/usr.sbin/xntpd/clockstuff/clktest.c
@@ -0,0 +1,511 @@
+/* clktest.c,v 3.1 1993/07/06 01:05:23 jbj Exp
+ * clktest - test the clock line discipline
+ *
+ * usage: clktest -b bps -f -t timeo -s cmd -c char1 -a char2 /dev/whatever
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sgtty.h>
+
+#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 <stropts.h>
+#include <sys/clkdefs.h>
+#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/usr.sbin/xntpd/clockstuff/propdelay.c b/usr.sbin/xntpd/clockstuff/propdelay.c
new file mode 100644
index 000000000000..5ba1789eee67
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <string.h>
+
+#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/usr.sbin/xntpd/compilers/README b/usr.sbin/xntpd/compilers/README
new file mode 100644
index 000000000000..46794dc5399c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/compilers/aux2.gcc b/usr.sbin/xntpd/compilers/aux2.gcc
new file mode 100644
index 000000000000..53672c45366e
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/aux2.gcc
@@ -0,0 +1 @@
+COMPILER=gcc -O -pipe -finline-functions -fomit-frame-pointer -D_POSIX_SOURCE
diff --git a/usr.sbin/xntpd/compilers/aux3.gcc b/usr.sbin/xntpd/compilers/aux3.gcc
new file mode 100644
index 000000000000..53672c45366e
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/aux3.gcc
@@ -0,0 +1 @@
+COMPILER=gcc -O -pipe -finline-functions -fomit-frame-pointer -D_POSIX_SOURCE
diff --git a/usr.sbin/xntpd/compilers/decosf1.gcc b/usr.sbin/xntpd/compilers/decosf1.gcc
new file mode 100644
index 000000000000..d071385d7a79
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/decosf1.gcc
@@ -0,0 +1 @@
+COMPILER= gcc -Wall -O2 -finline-functions
diff --git a/usr.sbin/xntpd/compilers/hpux.cc b/usr.sbin/xntpd/compilers/hpux.cc
new file mode 100644
index 000000000000..e3c27af87bd8
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/hpux.cc
@@ -0,0 +1,2 @@
+COMPILER=cc
+COPTS=+O1
diff --git a/usr.sbin/xntpd/compilers/hpux.gcc b/usr.sbin/xntpd/compilers/hpux.gcc
new file mode 100644
index 000000000000..ecd037212eda
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/hpux.gcc
@@ -0,0 +1,2 @@
+COMPILER=gcc
+COPTS=-O2
diff --git a/usr.sbin/xntpd/compilers/hpux10+.cc b/usr.sbin/xntpd/compilers/hpux10+.cc
new file mode 100644
index 000000000000..cf058ef46b5c
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/hpux10+.cc
@@ -0,0 +1 @@
+COMPILER=cc +O1
diff --git a/usr.sbin/xntpd/compilers/linux.gcc b/usr.sbin/xntpd/compilers/linux.gcc
new file mode 100644
index 000000000000..501568c714e3
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/linux.gcc
@@ -0,0 +1,2 @@
+COMPILER= gcc -DUSE_PROTOTYPES -Wall
+COPTS= -O6 -finline-functions -fomit-frame-pointer
diff --git a/usr.sbin/xntpd/compilers/mips.cc b/usr.sbin/xntpd/compilers/mips.cc
new file mode 100644
index 000000000000..dcd8697077ab
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/mips.cc
@@ -0,0 +1 @@
+COMPILER= cc -systype bsd43
diff --git a/usr.sbin/xntpd/compilers/sinix-m.cc b/usr.sbin/xntpd/compilers/sinix-m.cc
new file mode 100644
index 000000000000..e4712dc89ed6
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/sinix-m.cc
@@ -0,0 +1 @@
+COMPILER= /usr/ucb/cc
diff --git a/usr.sbin/xntpd/compilers/sinix-m.gcc b/usr.sbin/xntpd/compilers/sinix-m.gcc
new file mode 100644
index 000000000000..fe6af589c439
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/sinix-m.gcc
@@ -0,0 +1,2 @@
+COMPILER= gcc -traditional
+
diff --git a/usr.sbin/xntpd/compilers/sunos4.bsd.cc b/usr.sbin/xntpd/compilers/sunos4.bsd.cc
new file mode 100644
index 000000000000..eb4dd629860a
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/sunos4.bsd.cc
@@ -0,0 +1 @@
+COMPILER= cc
diff --git a/usr.sbin/xntpd/compilers/sunos4.bsd.gcc b/usr.sbin/xntpd/compilers/sunos4.bsd.gcc
new file mode 100644
index 000000000000..09e841a2b4de
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/sunos4.bsd.gcc
@@ -0,0 +1 @@
+COMPILER= gcc -DUSE_PROTOTYPES -Wall -O2 -finline-functions -fdelayed-branch -fomit-frame-pointer
diff --git a/usr.sbin/xntpd/compilers/sunos4.posix.gcc b/usr.sbin/xntpd/compilers/sunos4.posix.gcc
new file mode 100644
index 000000000000..09e841a2b4de
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/sunos4.posix.gcc
@@ -0,0 +1 @@
+COMPILER= gcc -DUSE_PROTOTYPES -Wall -O2 -finline-functions -fdelayed-branch -fomit-frame-pointer
diff --git a/usr.sbin/xntpd/compilers/sunos5.1.gcc b/usr.sbin/xntpd/compilers/sunos5.1.gcc
new file mode 100644
index 000000000000..fe6af589c439
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/sunos5.1.gcc
@@ -0,0 +1,2 @@
+COMPILER= gcc -traditional
+
diff --git a/usr.sbin/xntpd/compilers/sunos5.2.gcc b/usr.sbin/xntpd/compilers/sunos5.2.gcc
new file mode 100644
index 000000000000..fe6af589c439
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/sunos5.2.gcc
@@ -0,0 +1,2 @@
+COMPILER= gcc -traditional
+
diff --git a/usr.sbin/xntpd/compilers/ultrix.bsd.cc b/usr.sbin/xntpd/compilers/ultrix.bsd.cc
new file mode 100644
index 000000000000..06f68830e503
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/ultrix.bsd.cc
@@ -0,0 +1,2 @@
+COMPILER= cc -Olimit 800
+
diff --git a/usr.sbin/xntpd/compilers/ultrix.bsd.gcc b/usr.sbin/xntpd/compilers/ultrix.bsd.gcc
new file mode 100644
index 000000000000..5ed9d554abc8
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/ultrix.bsd.gcc
@@ -0,0 +1 @@
+COMPILER= gcc -Wall -O2 -finline-functions -fdelayed-branch
diff --git a/usr.sbin/xntpd/compilers/ultrix.posix.cc b/usr.sbin/xntpd/compilers/ultrix.posix.cc
new file mode 100644
index 000000000000..06f68830e503
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/ultrix.posix.cc
@@ -0,0 +1,2 @@
+COMPILER= cc -Olimit 800
+
diff --git a/usr.sbin/xntpd/compilers/ultrix.posix.gcc b/usr.sbin/xntpd/compilers/ultrix.posix.gcc
new file mode 100644
index 000000000000..5ed9d554abc8
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/ultrix.posix.gcc
@@ -0,0 +1 @@
+COMPILER= gcc -Wall -O2 -finline-functions -fdelayed-branch
diff --git a/usr.sbin/xntpd/conf/Config.CHATHAM b/usr.sbin/xntpd/conf/Config.CHATHAM
new file mode 100644
index 000000000000..41e6fc2aa340
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/Config.MONOMOY b/usr.sbin/xntpd/conf/Config.MONOMOY
new file mode 100644
index 000000000000..b9e075fbfce6
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/Config.TIGER b/usr.sbin/xntpd/conf/Config.TIGER
new file mode 100644
index 000000000000..c757ad90e186
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/Config.TRURO b/usr.sbin/xntpd/conf/Config.TRURO
new file mode 100644
index 000000000000..6caa2b82d62e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/Config.dartnet b/usr.sbin/xntpd/conf/Config.dartnet
new file mode 100644
index 000000000000..b591db341655
--- /dev/null
+++ b/usr.sbin/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 <filename>" 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/usr.sbin/xntpd/conf/Config.local b/usr.sbin/xntpd/conf/Config.local
new file mode 100644
index 000000000000..4c5095c164da
--- /dev/null
+++ b/usr.sbin/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 <filename>" 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/usr.sbin/xntpd/conf/Config.svr4 b/usr.sbin/xntpd/conf/Config.svr4
new file mode 100644
index 000000000000..d6d0661539f1
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/README b/usr.sbin/xntpd/conf/README
new file mode 100644
index 000000000000..19dcb795f80c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/dewey.conf b/usr.sbin/xntpd/conf/dewey.conf
new file mode 100644
index 000000000000..523008fcdc82
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/grundoon.conf b/usr.sbin/xntpd/conf/grundoon.conf
new file mode 100644
index 000000000000..c5aef6eb88e3
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/malarky.conf b/usr.sbin/xntpd/conf/malarky.conf
new file mode 100644
index 000000000000..f887f839d1bb
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/ntp.conf.gw b/usr.sbin/xntpd/conf/ntp.conf.gw
new file mode 100644
index 000000000000..bd5687874f53
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/ntp.conf.ipl b/usr.sbin/xntpd/conf/ntp.conf.ipl
new file mode 100644
index 000000000000..1fd5b7d62145
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/ntp.conf.nsf b/usr.sbin/xntpd/conf/ntp.conf.nsf
new file mode 100644
index 000000000000..298bb7a6905e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/ntp.conf.shiningtree b/usr.sbin/xntpd/conf/ntp.conf.shiningtree
new file mode 100644
index 000000000000..1576ebbd072c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/ntp.conf.suzuki b/usr.sbin/xntpd/conf/ntp.conf.suzuki
new file mode 100644
index 000000000000..ee32e7ad87a1
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/pogo.conf b/usr.sbin/xntpd/conf/pogo.conf
new file mode 100644
index 000000000000..94ac6c84ea28
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/rackety.conf b/usr.sbin/xntpd/conf/rackety.conf
new file mode 100644
index 000000000000..1a5181cd4b5c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/conf/snow-white.conf b/usr.sbin/xntpd/conf/snow-white.conf
new file mode 100644
index 000000000000..a86cb4bc5b45
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/doc/README.irig b/usr.sbin/xntpd/doc/README.irig
new file mode 100644
index 000000000000..f293f4cde160
--- /dev/null
+++ b/usr.sbin/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 <lecates@udel.edu> and David Mills <mills@udel.edu>
+Electrical Engineering Department
+University of Delaware
+Newark, DE 19716
+302 831 8247 fax 302 831 4316
+
+24 August 1993
diff --git a/usr.sbin/xntpd/doc/README.kern b/usr.sbin/xntpd/doc/README.kern
new file mode 100644
index 000000000000..1b791c325ccf
--- /dev/null
+++ b/usr.sbin/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 <sys/timex.h>
+ *
+ * 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 <sys/timex.h>
+ *
+ * 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 <mills@udel.edu>
+Electrical Engineering Department
+University of Delaware
+Newark, DE 19716
+302 831 8247 fax 302 831 4316
+
+1 April 1992
diff --git a/usr.sbin/xntpd/doc/README.magic b/usr.sbin/xntpd/doc/README.magic
new file mode 100644
index 000000000000..f473a9220c44
--- /dev/null
+++ b/usr.sbin/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 <CR>, 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 <CR>, 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 <mills@udel.edu>
+Electrical Engineering Department
+University of Delaware
+Newark, DE 19716
+302 831 8247 fax 302 831 4316
+
+25 August 1993
diff --git a/usr.sbin/xntpd/doc/UofT b/usr.sbin/xntpd/doc/UofT
new file mode 100644
index 000000000000..54420d5f5252
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/doc/notes.txt b/usr.sbin/xntpd/doc/notes.txt
new file mode 100644
index 000000000000..5ea2b3318bb3
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/doc/ntpdate.8 b/usr.sbin/xntpd/doc/ntpdate.8
new file mode 100644
index 000000000000..05be737fd88c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/doc/ntpq.8 b/usr.sbin/xntpd/doc/ntpq.8
new file mode 100644
index 000000000000..81aca09ac183
--- /dev/null
+++ b/usr.sbin/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 <variable_name>[=<value>] [,...]
+.B rmvars
+.IR <variable_name> [,...]
+.B clearvars
+.PP
+The data carried by NTP mode 6 messages consists of a list of items
+of the form
+.IP "" 8
+<variable_name>=<value>
+.PP
+where the \*(L"=<value>\*(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 <variable_name>[=<value>] [,...]
+]
+.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 <variable_name>[=<value>] [,...]
+]
+.PP
+An easy\-to\-type short form for the
+.B readvar
+command.
+.PP
+.B writevar
+.I assocID
+.IR <variable_name>=<value> [,...]
+.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 <variable_name>[=<value>] [,...]
+]
+.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 <variable_name>[=<value>] [,...]
+]
+.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 <variable_name>[=<value>] [,...]
+]
+.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 <variable_name>[=<value>] [,...]
+]
+.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: <sp> 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(<implementation number>, <parameter>)\*(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/usr.sbin/xntpd/doc/ntptrace.8 b/usr.sbin/xntpd/doc/ntptrace.8
new file mode 100644
index 000000000000..fb93ebb4df72
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/doc/tickadj.8 b/usr.sbin/xntpd/doc/tickadj.8
new file mode 100644
index 000000000000..5fce0884f892
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/doc/xntpd.8 b/usr.sbin/xntpd/doc/xntpd.8
new file mode 100644
index 000000000000..b02101980d97
--- /dev/null
+++ b/usr.sbin/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"<prefix><filename>.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 <u> 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 <u>
+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 <u>.
+.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/usr.sbin/xntpd/doc/xntpdc.8 b/usr.sbin/xntpd/doc/xntpdc.8
new file mode 100644
index 000000000000..20209b553bf0
--- /dev/null
+++ b/usr.sbin/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(<implementation number>, <parameter>)\*(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/usr.sbin/xntpd/gadget/README b/usr.sbin/xntpd/gadget/README
new file mode 100644
index 000000000000..35bbc18ad2b8
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/gadget/adt0127.lpr b/usr.sbin/xntpd/gadget/adt0127.lpr
new file mode 100644
index 000000000000..f0359e897d5a
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/gadget/art01.lpr b/usr.sbin/xntpd/gadget/art01.lpr
new file mode 100644
index 000000000000..d770fed357b2
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/gadget/art02.lpr b/usr.sbin/xntpd/gadget/art02.lpr
new file mode 100644
index 000000000000..1b336f378254
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/gadget/dd0124.lpr b/usr.sbin/xntpd/gadget/dd0124.lpr
new file mode 100644
index 000000000000..f6474d43864d
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/gadget/gadget.lst b/usr.sbin/xntpd/gadget/gadget.lst
new file mode 100644
index 000000000000..a10aff3054a8
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/gadget/gadget.s01 b/usr.sbin/xntpd/gadget/gadget.s01
new file mode 100644
index 000000000000..314f7ba18a62
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/gadget/gadget.s02 b/usr.sbin/xntpd/gadget/gadget.s02
new file mode 100644
index 000000000000..6af4a6ec77e6
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/gadget/gen0102.lpr b/usr.sbin/xntpd/gadget/gen0102.lpr
new file mode 100644
index 000000000000..cc4fd8e5a38d
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/gadget/sm0228.lpr b/usr.sbin/xntpd/gadget/sm0228.lpr
new file mode 100644
index 000000000000..cd39c9ca9291
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/gadget/sst0126.lpr b/usr.sbin/xntpd/gadget/sst0126.lpr
new file mode 100644
index 000000000000..c3f19867cde1
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/hints/README b/usr.sbin/xntpd/hints/README
new file mode 100644
index 000000000000..f7fdb72aaa6b
--- /dev/null
+++ b/usr.sbin/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.<machine> 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/usr.sbin/xntpd/hints/aux b/usr.sbin/xntpd/hints/aux
new file mode 100644
index 000000000000..aa7ccbb2c420
--- /dev/null
+++ b/usr.sbin/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 <host.domain>
+ 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 <host.domain> (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 <<!
+ init_time_fix_timeout?4i
+ init_time_fix_timeout?w 0x4e75
+ init_time_fix_timeout?4i
+ $q
+ !
+
+This must be done _every_ time you create a new kernel (via newconfig or
+newunix) or else 'xntpd' will go crazy.
+
+John Dundas was the original porter of xntpd and a lot of the additions
+and A/UX-ports are from him. I got involved when I wanted to run 'xntpd'
+on jagubox. It was also around this time that the base-patchlevel of
+'xntpd' changed relatively significantly so John may not be up on this
+version (called the "jones" version).
+
+The original kernel patch (which patched 'time_fix_timeout') was from
+Richard Todd. I suggest patching 'init_time_fix_timeout' which prevents
+'time_fix_timeout' from even being called.
+
+TECHNICAL NOTES:
+
+ o As configured (see machines/aux3), 'xntpd' will log messages via syslogd
+ using the LOC_LOCAL1 facility. I would suggest the following in
+ /etc/syslog.conf:
+
+ local1.notice /usr/adm/ntpd-syslog
+
+ o As mentioned above, the clocks on A/UX and Macs are kinda bad. Not
+ only that, but logging in and out of the MacOS mode as well as
+ extensive floppy use causes A/UX to drop and lose clock interupts
+ (these are sent every 1/60th of a second). So, if you do these
+ activities a lot, you find out that you lose about 300ms of time
+ (i.e., you become 300ms slow). 'xntpd' default way of handling this
+ is to called 'settimeofday()' and step the clock to the correct
+ time. I prefer having 'xntpd' slew the clock back into line by
+ making gradual adjustments to the clock over a coupla minutes
+ or so. It's for this reason that SLEWALWAYS is defined in
+ include/ntp_machine.h for SYS_AUX3.
+
+Good luck! If you have problems under A/UX feel free to contact me (e-mail
+is preferred).
+--
+ Jim Jagielski | "That is no ordinary rabbit... 'tis the
+ jim@jagubox.gsfc.nasa.gov | most foul, cruel and bad-tempered
+ NASA/GSFC, Code 734.4 | rodent you ever set eyes on"
+ Greenbelt, MD 20771 | Tim the Enchanter
diff --git a/usr.sbin/xntpd/hints/bsdi b/usr.sbin/xntpd/hints/bsdi
new file mode 100644
index 000000000000..3ab518b0b63d
--- /dev/null
+++ b/usr.sbin/xntpd/hints/bsdi
@@ -0,0 +1,61 @@
+README.bsdi
+
+Author: Bdale Garbee, bdale@gag.com
+Last revision: 16 July 1993
+
+Included in this distribution of XNTP is a configuration file suitable
+for use with the BSDI BSD/386 operation system. It has been tested against
+the version 1.0 "production release", but should work with any 0.9.X "gamma
+release" version if anyone still cares. I'm using the stock gcc provided
+with the OS.
+
+[ As the pmake is badly broken on these systems at the time of this writing
+ the only way to compile is to call make like this "make -e MAKE=make [target]"
+ - Frank Kardel - 93/12/3 ]
+
+To date, I haven't used this with any hardware clocks, but I will probably
+get around to trying a Spectracom WWVB receiver at some point, and I'm hacking
+on an interface for the Rockwell Navcore 5 GPS widget in my "copious spare
+time".
+
+The config file is Config.bsdi, and the following steps should be all that
+are required to install and use the bits.
+
+To build the software:
+
+ rm -f Config.local
+ make refconf
+ make
+
+To install the software:
+
+ make install
+
+ This will place all of the executables in /usr/local/etc. The config
+ file is expected to be /usr/local/etc/xntp.conf and the key file for
+ the optional authentication is /etc/ntp.keys.
+
+ Craft a config file and a key file, and put them in the right places.
+ There is information on how to do this elsewhere in the documentation,
+ the only thing I'll mention is that I put the drift file in
+ /var/log/ntp.drift, and the authdelay on my 486DX/50 system is
+ 0.000064. Your mileage will vary, learn to use the authspeed tools
+ if you're going to authenticate.
+
+ In the file /etc/rc.local, make sure that the invocation of ntpd is
+ commented out, and add an invocation of xntpd. Here's what I'm using:
+
+ echo -n 'starting local daemons:'
+
+ if [ -f /etc/ntp.keys -a -f /usr/local/etc/xntp.conf ]; then
+ echo -n ' xntpd'; /usr/local/etc/xntpd
+ fi
+
+ #XXX# echo -n ' ntpd'; /usr/libexec/ntpd -t
+
+At this point, you should be good to go. Try running /usr/local/etc/xntpd and
+using ntpq or xntpdc to see if things are working, then pay attention the next
+time you reboot to make sure that xntpd is being invoked, and use ntpq or
+xntpdc again to make sure all is well.
+
+Enjoy!
diff --git a/usr.sbin/xntpd/hints/decosf1 b/usr.sbin/xntpd/hints/decosf1
new file mode 100644
index 000000000000..bc4ce0bb294d
--- /dev/null
+++ b/usr.sbin/xntpd/hints/decosf1
@@ -0,0 +1,40 @@
+Some major changes were necessary to make xntp v3 run on the DEC Alpha
+hardware running DEC OSF/1. All "long" and "u_long" declarations and
+casts in the code were changed to "LONG" and "U_LONG" and a new header
+file (include/ntp_types.h) was added. The new header file defines
+LONG as int and U_LONG as u_int for the Alpha hardware and as long
+and u_long for anything else. A couple of #ifs where changed in
+ntpq and xntpdc to get the result of a signal defined correctly. The
+Config.decosf1 file built the programs here with no problems.
+
+I don't have a radio clock here, so none of that code has been tested.
+I have run xntpd, xntpdc, xntpres, ntpq, ntpdate, and tickadj under
+DEC OSF/1 v1.2-2 (BL10).
+
+Mike Iglesias Internet: iglesias@draco.acs.uci.edu
+University of California, Irvine BITNET: iglesias@uci
+Office of Academic Computing uucp: ...!ucbvax!ucivax!iglesias
+Distributed Computing Support phone: (714) 856-6926
+
+Support for NTP Version 2 is included with the current OSF/1 release. If
+you are upgrading to NTP Version 3 with this distribution, you should not
+use the xntpd or ntpq programs that come with the OSF/1 release. The
+older programs should be replaced by the newer programs of the same name,
+either in situ or via a link to a tranquil spot like /usr/local/bin. The
+make install script in the this distribution don't work due to a silly
+install program incompatibility, so you will need to copy the programs by
+hand.
+
+Don't use the setup utility to install or configure the xntpd installation,
+as it will cheerfully clobber your painstakingly crafted ntp.conf program.
+However, assuming you put this file in /etc/ntp.conf, you can use the
+/sbin/init.d/xntpd script to start and stop the daemon.
+
+This distribution compiles with nominal mumur with the stock cc compiler
+that comes with OSF/1.
+
+Dave Mills
+Electrical Engineering Department
+Unibergisty of Delabunch
+mills@udel.edu
+
diff --git a/usr.sbin/xntpd/hints/hpux b/usr.sbin/xntpd/hints/hpux
new file mode 100644
index 000000000000..f0b3271febe9
--- /dev/null
+++ b/usr.sbin/xntpd/hints/hpux
@@ -0,0 +1,76 @@
+This file hopefully describes the whatever and however of how to get xntp
+running on hpux 8.0 and later s300, s700, and s800.
+
+First off, all the standard disclaimers hold here ... HP doesn't have anthing
+to do with this stuff. I fool with it in my spare time because we use it and
+because I like to. We just happen to have a lot of HP machines around here :-)
+Xntp has been in use here for several months and has a fair amount of mileage
+on various HP platforms within the company. I can't really guarantee bug fixes
+but I'd certainly like to hear about bugs and I won't hestitate to look at
+any fixes sent to me.
+
+Now lets talk OS. If you don't have 8.0 or later, pretty much hang it up now.
+This stuff has run here on 8.0 s300, s700, and s800. Its possible that it
+runs on 7.0 but I have not tried v3 code on 7.0 at all.
+
+[Note that recent reports state that this release does in fact run on HP
+300 and 400 boxes, which run 7.0 - Ed.]
+
+Next, let me explain a bit about how this stuff works on HP-UX since we don't
+have adjtime(2). The directory adjtime contains libadjtime.a and the adjtimed
+daemon. Instead of the adjtime(2) system call, we use a library routine to
+talk to adjtimed thru message queues. Adjtimed munges into /dev/kmem and
+causes the clock to skew properly as needed. PLEASE NOTE that the adjtime
+code provided here is NOT a general replacement for adjtime(2) ... use of
+this adjtime(3)/adjtimed(8) other than here may yield very odd results.
+
+What to do to get this stuff running ?
+
+ * cd ..
+ * Say "make makeconfig"
+
+ * cd ..
+ * Say "make", sit back for a few minutes.
+
+ * cd authstuff
+ * Say "./authcert < certdata" and check the output. Every line should
+ end with "OK" ... if not, we got trouble.
+ * Now try "./authspeed auth.samplekeys". What we want to
+ remember here is the "authentication delay in CPU time"
+
+ * cd ..
+ * Now we need to install this stuff ... make install will not work
+ unless you have replaced the SYSV install command with a BSD
+ compatible version. So ... the simplest thing to do is run
+ make -n install and do manually what it would have done.
+
+ * I'd suggest reading the xntp docs about now :-) ... seriously !!
+
+ * Check out the docs and the stuff in xntp/conf and build a config
+ file ... put it in /usr/local/etc/xntp.conf (or where ever you
+ defined the config file to be in Config). One thing we have
+ added to this version of xntpd is a way to select config files
+ if you are sharing /usr/local thru NFS or whatever. If the
+ file /usr/local/etc/xntp.conf happens to be a directory, the files
+ in that directory are searched until a match is found. The rules
+ for a match are:
+
+ 1. Our hostname
+ 2. default.<machine id> (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/usr.sbin/xntpd/hints/notes-xntp-v3 b/usr.sbin/xntpd/hints/notes-xntp-v3
new file mode 100644
index 000000000000..ba027f2105fe
--- /dev/null
+++ b/usr.sbin/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 <file>, where
+ <file> is the name of a statistics file." When present, each clock
+ update generates an entry of the form:
+
+ <day> <sec>.<frac> <addr> <status> <offset> <delay> <disp>
+
+ where <day> is the modified Julian day, <sec>.<frac> is the time of
+ day, <addr> is the peer address and <status> is the peer status.
+ The <offset>, <delay> and <disp> 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 <file>.<gen>, where <gen> 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/usr.sbin/xntpd/hints/parse b/usr.sbin/xntpd/hints/parse
new file mode 100644
index 000000000000..d2523515e839
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/hints/refclocks b/usr.sbin/xntpd/hints/refclocks
new file mode 100644
index 000000000000..34b2ea934446
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/hints/rs6000 b/usr.sbin/xntpd/hints/rs6000
new file mode 100644
index 000000000000..8561ac29b1b0
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/hints/sgi b/usr.sbin/xntpd/hints/sgi
new file mode 100644
index 000000000000..5e4f7de6d597
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/hints/solaris b/usr.sbin/xntpd/hints/solaris
new file mode 100644
index 000000000000..038d65f99634
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/hints/svr4-dell b/usr.sbin/xntpd/hints/svr4-dell
new file mode 100644
index 000000000000..b6d015752dd7
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/README b/usr.sbin/xntpd/include/README
new file mode 100644
index 000000000000..5127b70a1b3a
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/l_stdlib.h b/usr.sbin/xntpd/include/l_stdlib.h
new file mode 100644
index 000000000000..7a4383dcd2a3
--- /dev/null
+++ b/usr.sbin/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 <stdlib.h>
+#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/usr.sbin/xntpd/include/md5.h b/usr.sbin/xntpd/include/md5.h
new file mode 100644
index 000000000000..c13f63905ebc
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/mx4200.h b/usr.sbin/xntpd/include/mx4200.h
new file mode 100644
index 000000000000..5a9e49651ca4
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/ntp.h b/usr.sbin/xntpd/include/ntp.h
new file mode 100644
index 000000000000..98a083aa17b8
--- /dev/null
+++ b/usr.sbin/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<<n)-1. This
+ * is shifted by EVENT_TIMEOUT and added to the base value.
+ */
+#define RANDOM_SPREAD(poll) ((poll) - (EVENT_TIMEOUT+1))
+#define RANDOM_POLL(poll, rval) ((((rval)+1)<<EVENT_TIMEOUT) + (1<<((poll)-2)))
+
+/*
+ * min, min3 and max. Makes it easier to transliterate the spec without
+ * thinking about it.
+ */
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) > (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/usr.sbin/xntpd/include/ntp_calendar.h b/usr.sbin/xntpd/include/ntp_calendar.h
new file mode 100644
index 000000000000..fc12f0b2945c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/ntp_control.h b/usr.sbin/xntpd/include/ntp_control.h
new file mode 100644
index 000000000000..89f62298d437
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/ntp_filegen.h b/usr.sbin/xntpd/include/ntp_filegen.h
new file mode 100644
index 000000000000..263f56118f64
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/ntp_fp.h b/usr.sbin/xntpd/include/ntp_fp.h
new file mode 100644
index 000000000000..327306054b44
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#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/usr.sbin/xntpd/include/ntp_if.h b/usr.sbin/xntpd/include/ntp_if.h
new file mode 100644
index 000000000000..1a76ca02da4b
--- /dev/null
+++ b/usr.sbin/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 <sys/time.h>
+#include <time.h>
+#endif
+
+#if defined(SOLARIS)&&!defined(bsd)
+#include <sys/sockio.h>
+#endif
+
+#if defined(SYS_PTX) || defined(SYS_SINIXM)
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#endif
+
+#if defined(SYS_SVR4)
+#if !defined(USE_STREAMS_DEVICE_FOR_IF_CONFIG)
+#include <sys/sockio.h>
+#else /* USE_STREAMS_DEVICE_FOR_IF_CONFIG */
+#include <netinet/ip.h>
+#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 <net/if.h>
diff --git a/usr.sbin/xntpd/include/ntp_io.h b/usr.sbin/xntpd/include/ntp_io.h
new file mode 100644
index 000000000000..c3b79be0616c
--- /dev/null
+++ b/usr.sbin/xntpd/include/ntp_io.h
@@ -0,0 +1,24 @@
+/*
+ * POSIX says use <fnct.h> to get O_* symbols and
+ * SEEK_SET symbol form <untisd.h>.
+ */
+#if defined(NTP_POSIX_SOURCE)
+/*
+ * POSIX way
+ */
+#include <stdio.h>
+#if defined(HAVE_SIGNALED_IO) && (defined(SYS_AUX2) || defined(SYS_AUX3) || defined(SYS_PTX))
+#include <sys/file.h>
+#endif
+#include <unistd.h>
+#include <fcntl.h>
+#else
+/*
+ * BSD way
+ */
+#include <sys/file.h>
+#include <fcntl.h>
+#if !defined(SEEK_SET) && defined(L_SET)
+#define SEEK_SET L_SET
+#endif
+#endif
diff --git a/usr.sbin/xntpd/include/ntp_machine.h b/usr.sbin/xntpd/include/ntp_machine.h
new file mode 100644
index 000000000000..97f5729f4240
--- /dev/null
+++ b/usr.sbin/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/<os> 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/usr.sbin/xntpd/include/ntp_malloc.h b/usr.sbin/xntpd/include/ntp_malloc.h
new file mode 100644
index 000000000000..0079cb700ed1
--- /dev/null
+++ b/usr.sbin/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 <stdlib.h>
+#else /* NTP_POSIX_SOURCE */
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#endif /* NTP_POSIX_SOURCE */
+
+#endif /* _ntp_malloc_h */
diff --git a/usr.sbin/xntpd/include/ntp_refclock.h b/usr.sbin/xntpd/include/ntp_refclock.h
new file mode 100644
index 000000000000..96e63ac8bba8
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/ntp_request.h b/usr.sbin/xntpd/include/ntp_request.h
new file mode 100644
index 000000000000..e94cb452aac7
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/ntp_select.h b/usr.sbin/xntpd/include/ntp_select.h
new file mode 100644
index 000000000000..5dd18682104d
--- /dev/null
+++ b/usr.sbin/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 <sys/select.h>
+#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/usr.sbin/xntpd/include/ntp_stdlib.h b/usr.sbin/xntpd/include/ntp_stdlib.h
new file mode 100644
index 000000000000..fcccd6e7e7d0
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+
+#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/usr.sbin/xntpd/include/ntp_string.h b/usr.sbin/xntpd/include/ntp_string.h
new file mode 100644
index 000000000000..f17905ea8f71
--- /dev/null
+++ b/usr.sbin/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 <memory.h>
+#endif
+
+#include <string.h>
+
+#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 <strings.h>
+
+#define strrchr rindex
+#define strchr index
+
+#endif /* NTP_POSIX_SOURCE */
+
+#endif /* _ntp_string_h */
diff --git a/usr.sbin/xntpd/include/ntp_syslog.h b/usr.sbin/xntpd/include/ntp_syslog.h
new file mode 100644
index 000000000000..0d5dff8cc45a
--- /dev/null
+++ b/usr.sbin/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 <syslog.h>
+#ifdef SYSLOG_FILE
+#include <stdio.h>
+#endif
+#endif /* GIZMO */
+#ifdef SYSLOG_FILE
+extern FILE *syslog_file;
+#define syslog msyslog
+#endif
diff --git a/usr.sbin/xntpd/include/ntp_timex.h b/usr.sbin/xntpd/include/ntp_timex.h
new file mode 100644
index 000000000000..1756e2e07f21
--- /dev/null
+++ b/usr.sbin/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 <sys/timex.h>
+ *
+ * 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 <sys/timex.h>
+ *
+ * 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 <sys/timex.h>
+#else /* provide definitions */
+#include <sys/syscall.h>
+
+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/usr.sbin/xntpd/include/ntp_types.h b/usr.sbin/xntpd/include/ntp_types.h
new file mode 100644
index 000000000000..7a2a3474bdf3
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/ntp_unixtime.h b/usr.sbin/xntpd/include/ntp_unixtime.h
new file mode 100644
index 000000000000..c1ab573f4d4c
--- /dev/null
+++ b/usr.sbin/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 <sys/time.h>
+
+/* 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/usr.sbin/xntpd/include/ntpd.h b/usr.sbin/xntpd/include/ntpd.h
new file mode 100644
index 000000000000..85a812520f52
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/parse.h b/usr.sbin/xntpd/include/parse.h
new file mode 100644
index 000000000000..9c8befee7b57
--- /dev/null
+++ b/usr.sbin/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 <sys/kmem.h>
+#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 <stdio.h>
+#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/usr.sbin/xntpd/include/parse_conf.h b/usr.sbin/xntpd/include/parse_conf.h
new file mode 100644
index 000000000000..3cc634891e40
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/sys/bsd_audioirig.h b/usr.sbin/xntpd/include/sys/bsd_audioirig.h
new file mode 100644
index 000000000000..1daeec700b42
--- /dev/null
+++ b/usr.sbin/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 <sys/time.h>
+
+/********************************************************************/
+/* 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/usr.sbin/xntpd/include/sys/chudefs.h b/usr.sbin/xntpd/include/sys/chudefs.h
new file mode 100644
index 000000000000..50f82527f468
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/sys/clkdefs.h b/usr.sbin/xntpd/include/sys/clkdefs.h
new file mode 100644
index 000000000000..b2596e110514
--- /dev/null
+++ b/usr.sbin/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 <sys/ioccom.h>
+
+/*
+ * 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/usr.sbin/xntpd/include/sys/parsestreams.h b/usr.sbin/xntpd/include/sys/parsestreams.h
new file mode 100644
index 000000000000..91786c163f85
--- /dev/null
+++ b/usr.sbin/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 <sys/ppsclock.h>
+
+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/usr.sbin/xntpd/include/sys/ppsclock.h b/usr.sbin/xntpd/include/sys/ppsclock.h
new file mode 100644
index 000000000000..952a57bff1e1
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/include/sys/tpro.h b/usr.sbin/xntpd/include/sys/tpro.h
new file mode 100644
index 000000000000..1cdaf9c8e610
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/kernel/Makefile.tmpl b/usr.sbin/xntpd/kernel/Makefile.tmpl
new file mode 100644
index 000000000000..700efa6925c8
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/kernel/README b/usr.sbin/xntpd/kernel/README
new file mode 100644
index 000000000000..cf69b137286b
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/kernel/README.kern b/usr.sbin/xntpd/kernel/README.kern
new file mode 100644
index 000000000000..64ba9c5bf379
--- /dev/null
+++ b/usr.sbin/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 <sys/timex.h>
+
+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 <sys/timex.h>
+
+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 <sys/timex.h>
+
+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 <sys/timex.h>
+
+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/usr.sbin/xntpd/kernel/README.streams b/usr.sbin/xntpd/kernel/README.streams
new file mode 100644
index 000000000000..26c2825b50df
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/kernel/tty_chu.c b/usr.sbin/xntpd/kernel/tty_chu.c
new file mode 100644
index 000000000000..4615875e77e0
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/kernel/tty_chu_STREAMS.c b/usr.sbin/xntpd/kernel/tty_chu_STREAMS.c
new file mode 100644
index 000000000000..eea792d91c6b
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+#include <sys/stream.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/user.h>
+
+#include <sys/chudefs.h>
+
+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 <sys/conf.h>
+#include <sys/buf.h>
+#include <sundev/mbvar.h>
+#include <sun/autoconf.h>
+#include <sun/vddrv.h>
+
+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; i<NCHU; i++)
+ our_priv_data[i].in_use=0;
+ }
+
+ return 0;
+ case VDUNLOAD:
+ {
+ int dev;
+
+ for (dev = 0; dev < NCHU; dev++)
+ if (our_priv_data[dev].in_use) {
+ /* One of the modules is still open */
+ return (EBUSY);
+ }
+ }
+ chu_fmod->f_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;i<NCHU;i++)
+ our_priv_data[i].in_use=0;
+ }
+#endif
+
+ for(i=0;i<NCHU;i++)
+ if (!our_priv_data[i].in_use)
+ {
+ ((struct priv_data *) (q->q_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;j<sizeof(struct chucode); j++)
+ *mp->b_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/usr.sbin/xntpd/kernel/tty_clk.c b/usr.sbin/xntpd/kernel/tty_clk.c
new file mode 100644
index 000000000000..d1b4bbef64b4
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/kernel/tty_clk_STREAMS.c b/usr.sbin/xntpd/kernel/tty_clk_STREAMS.c
new file mode 100644
index 000000000000..f41af285dc3b
--- /dev/null
+++ b/usr.sbin/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 <string.h>
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/user.h>
+#include <sys/errno.h>
+
+#include <sys/clkdefs.h>
+
+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;i<NCLK;i++)
+ priv_data[i].in_use=0;
+ }
+
+ for(i=0;i<NCLK;i++)
+ if(!priv_data[i].in_use)
+ {
+ priv_data[i].in_use++;
+ ((struct priv_data_type *) (q->q_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;i<sizeof(struct timeval);i++)
+ *mp->b_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/usr.sbin/xntpd/lib/Makefile.tmpl b/usr.sbin/xntpd/lib/Makefile.tmpl
new file mode 100644
index 000000000000..697edcfe609a
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/README b/usr.sbin/xntpd/lib/README
new file mode 100644
index 000000000000..c2b65d94cd81
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/a_md512crypt.c b/usr.sbin/xntpd/lib/a_md512crypt.c
new file mode 100644
index 000000000000..a3714a24085e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/a_md5decrypt.c b/usr.sbin/xntpd/lib/a_md5decrypt.c
new file mode 100644
index 000000000000..892e52e60624
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/a_md5encrypt.c b/usr.sbin/xntpd/lib/a_md5encrypt.c
new file mode 100644
index 000000000000..a26e8f0d2afc
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/adjtimex.c b/usr.sbin/xntpd/lib/adjtimex.c
new file mode 100644
index 000000000000..03e9d79e359e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/atoint.c b/usr.sbin/xntpd/lib/atoint.c
new file mode 100644
index 000000000000..0e8ea8f6fc18
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+#include <ctype.h>
+
+#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/usr.sbin/xntpd/lib/atolfp.c b/usr.sbin/xntpd/lib/atolfp.c
new file mode 100644
index 000000000000..9e2d88301471
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+
+#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/usr.sbin/xntpd/lib/atouint.c b/usr.sbin/xntpd/lib/atouint.c
new file mode 100644
index 000000000000..b27653f60a21
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+#include <ctype.h>
+
+#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/usr.sbin/xntpd/lib/auth12crypt.c b/usr.sbin/xntpd/lib/auth12crypt.c
new file mode 100644
index 000000000000..a5d988972757
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/authdecrypt.c b/usr.sbin/xntpd/lib/authdecrypt.c
new file mode 100644
index 000000000000..7ff1129a479e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/authdes.c b/usr.sbin/xntpd/lib/authdes.c
new file mode 100644
index 000000000000..36077fc0adaf
--- /dev/null
+++ b/usr.sbin/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 <netinet/in.h>
+
+#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/usr.sbin/xntpd/lib/authdes.c.export b/usr.sbin/xntpd/lib/authdes.c.export
new file mode 100644
index 000000000000..b0323a0a6be1
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+
+/*
+ * 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/usr.sbin/xntpd/lib/authencrypt.c b/usr.sbin/xntpd/lib/authencrypt.c
new file mode 100644
index 000000000000..66b5281b7ae5
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/authkeys.c b/usr.sbin/xntpd/lib/authkeys.c
new file mode 100644
index 000000000000..2d46eee3931e
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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/usr.sbin/xntpd/lib/authparity.c b/usr.sbin/xntpd/lib/authparity.c
new file mode 100644
index 000000000000..33562cb4b12a
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/authreadkeys.c b/usr.sbin/xntpd/lib/authreadkeys.c
new file mode 100644
index 000000000000..5800186dc812
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+
+#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/usr.sbin/xntpd/lib/authusekey.c b/usr.sbin/xntpd/lib/authusekey.c
new file mode 100644
index 000000000000..0452031fb05e
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+
+#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/usr.sbin/xntpd/lib/buftvtots.c b/usr.sbin/xntpd/lib/buftvtots.c
new file mode 100644
index 000000000000..d9b484db2df0
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/caljulian.c b/usr.sbin/xntpd/lib/caljulian.c
new file mode 100644
index 000000000000..92d6d742a63a
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+
+#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/usr.sbin/xntpd/lib/calleapwhen.c b/usr.sbin/xntpd/lib/calleapwhen.c
new file mode 100644
index 000000000000..379643f09566
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+
+#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/usr.sbin/xntpd/lib/caltontp.c b/usr.sbin/xntpd/lib/caltontp.c
new file mode 100644
index 000000000000..f5da0ab761e8
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+
+#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/usr.sbin/xntpd/lib/calyearstart.c b/usr.sbin/xntpd/lib/calyearstart.c
new file mode 100644
index 000000000000..1bb3321f7252
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+
+#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/usr.sbin/xntpd/lib/clocktime.c b/usr.sbin/xntpd/lib/clocktime.c
new file mode 100644
index 000000000000..36b967e9a16c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/clocktypes.c b/usr.sbin/xntpd/lib/clocktypes.c
new file mode 100644
index 000000000000..f6fc003699ce
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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/usr.sbin/xntpd/lib/decodenetnum.c b/usr.sbin/xntpd/lib/decodenetnum.c
new file mode 100644
index 000000000000..32320a24b881
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#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/usr.sbin/xntpd/lib/dofptoa.c b/usr.sbin/xntpd/lib/dofptoa.c
new file mode 100644
index 000000000000..c6e317f69d43
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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/usr.sbin/xntpd/lib/dolfptoa.c b/usr.sbin/xntpd/lib/dolfptoa.c
new file mode 100644
index 000000000000..ff341536ee68
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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/usr.sbin/xntpd/lib/emalloc.c b/usr.sbin/xntpd/lib/emalloc.c
new file mode 100644
index 000000000000..d2a8e789f012
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/findconfig.c b/usr.sbin/xntpd/lib/findconfig.c
new file mode 100755
index 000000000000..83126686b40c
--- /dev/null
+++ b/usr.sbin/xntpd/lib/findconfig.c
@@ -0,0 +1,62 @@
+#ifdef SYS_HPUX
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+
+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/usr.sbin/xntpd/lib/fptoa.c b/usr.sbin/xntpd/lib/fptoa.c
new file mode 100644
index 000000000000..d245e9fa6917
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/fptoms.c b/usr.sbin/xntpd/lib/fptoms.c
new file mode 100644
index 000000000000..fb850c5362c2
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/getopt.c b/usr.sbin/xntpd/lib/getopt.c
new file mode 100644
index 000000000000..0ab3c2917fc3
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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/usr.sbin/xntpd/lib/gettstamp.c b/usr.sbin/xntpd/lib/gettstamp.c
new file mode 100644
index 000000000000..19bcb0c638ff
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/time.h>
+
+#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/usr.sbin/xntpd/lib/hextoint.c b/usr.sbin/xntpd/lib/hextoint.c
new file mode 100644
index 000000000000..90329c4136f4
--- /dev/null
+++ b/usr.sbin/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 <ctype.h>
+
+#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/usr.sbin/xntpd/lib/hextolfp.c b/usr.sbin/xntpd/lib/hextolfp.c
new file mode 100644
index 000000000000..6473c7c3dbca
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+
+#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/usr.sbin/xntpd/lib/humandate.c b/usr.sbin/xntpd/lib/humandate.c
new file mode 100644
index 000000000000..464ed6ba4de4
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#include "ntp_fp.h"
+#include "ntp_unixtime.h"
+#include "lib_strbuf.h"
+#include "ntp_stdlib.h"
+
+#ifdef NTP_POSIX_SOURCE
+#include <time.h>
+#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/usr.sbin/xntpd/lib/inttoa.c b/usr.sbin/xntpd/lib/inttoa.c
new file mode 100644
index 000000000000..25ce26cb8144
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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/usr.sbin/xntpd/lib/lib_strbuf.c b/usr.sbin/xntpd/lib/lib_strbuf.c
new file mode 100644
index 000000000000..15661ab980ad
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/lib_strbuf.h b/usr.sbin/xntpd/lib/lib_strbuf.h
new file mode 100644
index 000000000000..20720fd5892b
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/machines.c b/usr.sbin/xntpd/lib/machines.c
new file mode 100644
index 000000000000..f7a400c1d5db
--- /dev/null
+++ b/usr.sbin/xntpd/lib/machines.c
@@ -0,0 +1,118 @@
+/*
+ * provide special support for peculiar architectures
+ *
+ * Real bummers unite !
+ */
+
+#ifdef SYS_PTX
+#include <sys/types.h>
+#include <sys/procstats.h>
+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 <unistd.h>
+#endif
+#include <stdio.h>
+
+#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/usr.sbin/xntpd/lib/md5.c b/usr.sbin/xntpd/lib/md5.c
new file mode 100644
index 000000000000..77644cb32aa6
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/mfptoa.c b/usr.sbin/xntpd/lib/mfptoa.c
new file mode 100644
index 000000000000..4e513d24f8b0
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/mfptoms.c b/usr.sbin/xntpd/lib/mfptoms.c
new file mode 100644
index 000000000000..f686d413edba
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/modetoa.c b/usr.sbin/xntpd/lib/modetoa.c
new file mode 100644
index 000000000000..483327186a11
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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/usr.sbin/xntpd/lib/mstolfp.c b/usr.sbin/xntpd/lib/mstolfp.c
new file mode 100644
index 000000000000..8a642cf0a55b
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+
+#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/usr.sbin/xntpd/lib/msutotsf.c b/usr.sbin/xntpd/lib/msutotsf.c
new file mode 100644
index 000000000000..412cfbd1ed96
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+
+#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/usr.sbin/xntpd/lib/msyslog.c b/usr.sbin/xntpd/lib/msyslog.c
new file mode 100644
index 000000000000..a8df27d3b9fc
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <errno.h>
+
+/* alternative, as Solaris 2.x defines __STDC__ as 0 in a largely standard
+ conforming environment
+ #if __STDC__ || (defined(SOLARIS) && defined(__STDC__))
+*/
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#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/usr.sbin/xntpd/lib/numtoa.c b/usr.sbin/xntpd/lib/numtoa.c
new file mode 100644
index 000000000000..c36885d19e68
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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/usr.sbin/xntpd/lib/numtohost.c b/usr.sbin/xntpd/lib/numtohost.c
new file mode 100644
index 000000000000..c8b532f1fd7c
--- /dev/null
+++ b/usr.sbin/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 <string.h>
+#include <netdb.h>
+
+#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/usr.sbin/xntpd/lib/octtoint.c b/usr.sbin/xntpd/lib/octtoint.c
new file mode 100644
index 000000000000..1f25b1d57693
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+
+#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/usr.sbin/xntpd/lib/prettydate.c b/usr.sbin/xntpd/lib/prettydate.c
new file mode 100644
index 000000000000..ad679bd872ce
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#include "ntp_fp.h"
+#include "ntp_unixtime.h"
+#include "lib_strbuf.h"
+#include "ntp_stdlib.h"
+
+#ifdef NTP_POSIX_SOURCE
+#include <time.h>
+#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/usr.sbin/xntpd/lib/ranny.c b/usr.sbin/xntpd/lib/ranny.c
new file mode 100644
index 000000000000..2a47e03f59ac
--- /dev/null
+++ b/usr.sbin/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<<m)-1
+ */
+U_LONG
+ranp2(m)
+ int m;
+{
+ U_LONG r;
+
+ ran_y[ran_k] += ran_y[ran_j]; /* overflow does a mod */
+ r = ran_y[ran_k];
+ if (ran_k-- == 0) ran_k = 54;
+ if (ran_j-- == 0) ran_j = 54;
+ return (r & ((1<<m)-1));
+}
+
+#ifdef notdef
+/*
+ * ranny - return a random integer in the range 0 .. m-1
+ */
+U_LONG
+ranny(m)
+ u_int m;
+{
+ unsigned LONG r;
+
+ ran_y[ran_k] += ran_y[ran_j]; /* overflow does a mod */
+ r = ran_y[ran_k];
+ if (ran_k-- == 0) ran_k = 54;
+ if (ran_j-- == 0) ran_j = 54;
+ return (r % m);
+}
+#endif /* notdef */
+
+/*
+ * init_random - do initialization of random number routine
+ */
+void
+init_random()
+{
+ register int i;
+ register time_t now;
+
+ ran_j = 23;
+ ran_k = 54;
+
+ /*
+ * Randomize the seed array some more. The time of day
+ * should be initialized by now.
+ */
+ now = (time_t)(time((time_t *)0))|01;
+
+ for (i = 0; i < 55; ++i)
+ ran_y[i] = now * init_ran_y[i]; /* overflow does a mod */
+}
diff --git a/usr.sbin/xntpd/lib/refnumtoa.c b/usr.sbin/xntpd/lib/refnumtoa.c
new file mode 100644
index 000000000000..31175d9f877b
--- /dev/null
+++ b/usr.sbin/xntpd/lib/refnumtoa.c
@@ -0,0 +1,34 @@
+/* refnumtoa.c,v 3.1 1993/07/06 01:08:44 jbj Exp
+ * refnumtoa - return asciized refclock addresses stored in local array space
+ */
+#include <stdio.h>
+
+#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/usr.sbin/xntpd/lib/syssignal.c b/usr.sbin/xntpd/lib/syssignal.c
new file mode 100644
index 000000000000..f8abfddfe4fd
--- /dev/null
+++ b/usr.sbin/xntpd/lib/syssignal.c
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include "ntp_stdlib.h"
+
+#if defined(NTP_POSIX_SOURCE)
+#include <errno.h>
+
+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/usr.sbin/xntpd/lib/systime.c b/usr.sbin/xntpd/lib/systime.c
new file mode 100644
index 000000000000..99e715a54a02
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+#include <sys/time.h>
+#if defined(SYS_HPUX) || defined(sgi) || defined(__bsdi__)
+#include <sys/param.h>
+#include <utmp.h>
+#endif
+
+#ifdef SYS_LINUX
+#include <sys/timex.h>
+#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<<CLOCK_ADJ sec (usec) */
+
+ U_LONG tsf_maxslew; /* same as above, as LONG format */
+
+ LONG sys_clock;
+ l_fp sys_clock_offset; /* correction for current system time */
+
+/*
+ * get_systime - return the system time in timestamp format
+ * As a side effect, update sys_clock.
+ */
+void
+get_systime(ts)
+ l_fp *ts;
+{
+ struct timeval tv;
+
+#if !defined(SLEWALWAYS)
+ /*
+ * Quickly get the time of day and convert it
+ */
+ (void) GETTIMEOFDAY(&tv, (struct timezone *)0);
+ TVTOTS(&tv, ts);
+ ts->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<<CLOCK_ADJ seconds to make system time
+ * adjustments.
+ */
+int
+adj_systime(ts)
+ l_fp *ts;
+{
+ register unsigned LONG offset_i, offset_f;
+ register LONG temp;
+ register unsigned LONG residual;
+ register int isneg = 0;
+ struct timeval adjtv, oadjtv;
+ l_fp oadjts;
+ LONG adj = ts->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/usr.sbin/xntpd/lib/tsftomsu.c b/usr.sbin/xntpd/lib/tsftomsu.c
new file mode 100644
index 000000000000..b9161141d359
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/tstotod.c b/usr.sbin/xntpd/lib/tstotod.c
new file mode 100644
index 000000000000..a78aea1c2ed9
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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/usr.sbin/xntpd/lib/tstotv.c b/usr.sbin/xntpd/lib/tstotv.c
new file mode 100644
index 000000000000..c9b0d1c036ad
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/lib/tvtoa.c b/usr.sbin/xntpd/lib/tvtoa.c
new file mode 100644
index 000000000000..778caa1cee26
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/time.h>
+
+#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/usr.sbin/xntpd/lib/tvtots.c b/usr.sbin/xntpd/lib/tvtots.c
new file mode 100644
index 000000000000..befc48055933
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+
+#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/usr.sbin/xntpd/lib/uglydate.c b/usr.sbin/xntpd/lib/uglydate.c
new file mode 100644
index 000000000000..308c70336232
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#include "ntp_fp.h"
+#include "ntp_unixtime.h"
+#include "lib_strbuf.h"
+#include "ntp_stdlib.h"
+#ifdef NTP_POSIX_SOURCE
+#include <time.h>
+#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/usr.sbin/xntpd/lib/uinttoa.c b/usr.sbin/xntpd/lib/uinttoa.c
new file mode 100644
index 000000000000..ce29390342b0
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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/usr.sbin/xntpd/lib/utvtoa.c b/usr.sbin/xntpd/lib/utvtoa.c
new file mode 100644
index 000000000000..b573f187a38f
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/time.h>
+
+#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/usr.sbin/xntpd/machines/README b/usr.sbin/xntpd/machines/README
new file mode 100644
index 000000000000..d40d8cb0f652
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/aix3.2 b/usr.sbin/xntpd/machines/aix3.2
new file mode 100644
index 000000000000..70607d81a6bc
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/aux2 b/usr.sbin/xntpd/machines/aux2
new file mode 100644
index 000000000000..c31c80d35cb5
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/aux3 b/usr.sbin/xntpd/machines/aux3
new file mode 100644
index 000000000000..98dc65531452
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/bsdi b/usr.sbin/xntpd/machines/bsdi
new file mode 100644
index 000000000000..040bab4fe155
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/convexos10 b/usr.sbin/xntpd/machines/convexos10
new file mode 100644
index 000000000000..ba6afed6882a
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/convexos9 b/usr.sbin/xntpd/machines/convexos9
new file mode 100644
index 000000000000..c742c2aff797
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/decosf1 b/usr.sbin/xntpd/machines/decosf1
new file mode 100644
index 000000000000..c404d6a52588
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/freebsd b/usr.sbin/xntpd/machines/freebsd
new file mode 100644
index 000000000000..1914de0de4a6
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/hpux b/usr.sbin/xntpd/machines/hpux
new file mode 100644
index 000000000000..60ec6780d361
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/hpux10+ b/usr.sbin/xntpd/machines/hpux10+
new file mode 100644
index 000000000000..f4b420c149d2
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/i386 b/usr.sbin/xntpd/machines/i386
new file mode 100644
index 000000000000..8fb6f94f815b
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/i386svr4 b/usr.sbin/xntpd/machines/i386svr4
new file mode 100644
index 000000000000..b33e3c3b8b00
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/irix4 b/usr.sbin/xntpd/machines/irix4
new file mode 100644
index 000000000000..ae2bbf8ba8d8
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/irix5 b/usr.sbin/xntpd/machines/irix5
new file mode 100644
index 000000000000..a808b9767c49
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/linux b/usr.sbin/xntpd/machines/linux
new file mode 100644
index 000000000000..853654acebab
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/mips b/usr.sbin/xntpd/machines/mips
new file mode 100644
index 000000000000..283c1c096504
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/netbsd b/usr.sbin/xntpd/machines/netbsd
new file mode 100644
index 000000000000..c1995eabb6b4
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/next b/usr.sbin/xntpd/machines/next
new file mode 100644
index 000000000000..e0e86cebeaac
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/ptx b/usr.sbin/xntpd/machines/ptx
new file mode 100644
index 000000000000..c1d9da2e5d05
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/sequent b/usr.sbin/xntpd/machines/sequent
new file mode 100644
index 000000000000..309b11bf91a8
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/sinix-m b/usr.sbin/xntpd/machines/sinix-m
new file mode 100644
index 000000000000..e26a81299b28
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/sony b/usr.sbin/xntpd/machines/sony
new file mode 100644
index 000000000000..cfeef7486711
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/sunos4.bsd b/usr.sbin/xntpd/machines/sunos4.bsd
new file mode 100644
index 000000000000..82be85d3421e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/sunos4.posix b/usr.sbin/xntpd/machines/sunos4.posix
new file mode 100644
index 000000000000..86716e18c2ae
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/sunos5.1 b/usr.sbin/xntpd/machines/sunos5.1
new file mode 100644
index 000000000000..55cccad59edd
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/sunos5.2 b/usr.sbin/xntpd/machines/sunos5.2
new file mode 100644
index 000000000000..3e09c15714e0
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/svr4 b/usr.sbin/xntpd/machines/svr4
new file mode 100644
index 000000000000..1cf90f58ca9d
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/ultrix.bsd b/usr.sbin/xntpd/machines/ultrix.bsd
new file mode 100644
index 000000000000..22d405996e90
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/ultrix.posix b/usr.sbin/xntpd/machines/ultrix.posix
new file mode 100644
index 000000000000..c55e555ddf74
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/machines/vax b/usr.sbin/xntpd/machines/vax
new file mode 100644
index 000000000000..86030467bc48
--- /dev/null
+++ b/usr.sbin/xntpd/machines/vax
@@ -0,0 +1,6 @@
+RANLIB= ranlib
+DEFS_LOCAL= -DREFCLOCK
+DEFS= -DSYS_VAX
+CLOCKDEFS= -DLOCAL_CLOCK
+DAEMONLIBS=
+RESLIB=
diff --git a/usr.sbin/xntpd/ntpdate/Makefile.tmpl b/usr.sbin/xntpd/ntpdate/Makefile.tmpl
new file mode 100644
index 000000000000..170625f0e35b
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/ntpdate/README b/usr.sbin/xntpd/ntpdate/README
new file mode 100644
index 000000000000..fd2dbe2e2c49
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/ntpdate/ntpdate.c b/usr.sbin/xntpd/ntpdate/ntpdate.c
new file mode 100644
index 000000000000..e144d8c1eb06
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#if defined(SYS_HPUX)
+#include <utmp.h>
+#endif
+
+#ifdef SYS_LINUX
+#include <sys/timex.h>
+#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/usr.sbin/xntpd/ntpdate/ntpdate.h b/usr.sbin/xntpd/ntpdate/ntpdate.h
new file mode 100644
index 000000000000..4a8ff746e772
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/ntpq/Makefile.tmpl b/usr.sbin/xntpd/ntpq/Makefile.tmpl
new file mode 100644
index 000000000000..e80286123cf0
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/ntpq/README b/usr.sbin/xntpd/ntpq/README
new file mode 100644
index 000000000000..117c66ce978b
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/ntpq/ntpq.c b/usr.sbin/xntpd/ntpq/ntpq.c
new file mode 100644
index 000000000000..e9db0086c0f9
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+
+#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/usr.sbin/xntpd/ntpq/ntpq.h b/usr.sbin/xntpd/ntpq/ntpq.h
new file mode 100644
index 000000000000..edfc9b599028
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/ntpq/ntpq_ops.c b/usr.sbin/xntpd/ntpq/ntpq_ops.c
new file mode 100644
index 000000000000..17929ac2f1a4
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+
+#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<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL);
+ if (pktversion == NTP_VERSION)
+ c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
+ else
+ c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
+ if (numhosts > 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/usr.sbin/xntpd/ntptrace/Makefile.tmpl b/usr.sbin/xntpd/ntptrace/Makefile.tmpl
new file mode 100644
index 000000000000..c98482da06ec
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/ntptrace/README b/usr.sbin/xntpd/ntptrace/README
new file mode 100644
index 000000000000..b976cfdf22ce
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/ntptrace/ntptrace.c b/usr.sbin/xntpd/ntptrace/ntptrace.c
new file mode 100644
index 000000000000..57d86ba5ab57
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#if defined(SYS_HPUX)
+#include <utmp.h>
+#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/usr.sbin/xntpd/ntptrace/ntptrace.h b/usr.sbin/xntpd/ntptrace/ntptrace.h
new file mode 100644
index 000000000000..3367c226a89d
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/Makefile.kernel b/usr.sbin/xntpd/parse/Makefile.kernel
new file mode 100644
index 000000000000..36dcf86e7239
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/Makefile.tmpl b/usr.sbin/xntpd/parse/Makefile.tmpl
new file mode 100644
index 000000000000..173c91b3d89b
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/README b/usr.sbin/xntpd/parse/README
new file mode 100644
index 000000000000..aa83aa7ae009
--- /dev/null
+++ b/usr.sbin/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 <modulename>.
+
+ 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/usr.sbin/xntpd/parse/README.parse b/usr.sbin/xntpd/parse/README.parse
new file mode 100644
index 000000000000..660973af319a
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/clk_dcf7000.c b/usr.sbin/xntpd/parse/clk_dcf7000.c
new file mode 100644
index 000000000000..c1c01d2480a7
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/clk_meinberg.c b/usr.sbin/xntpd/parse/clk_meinberg.c
new file mode 100644
index 000000000000..363120b1eb1e
--- /dev/null
+++ b/usr.sbin/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)
+ *
+ * <STX>D:<dd>.<mm>.<yy>;T:<w>;U:<hh>:<mm>:<ss>;<S><F><D><A><ETX>
+ * 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
+ * <STX> = '\002' ASCII start of text
+ * <ETX> = '\003' ASCII end of text
+ * <dd>,<mm>,<yy> = day, month, year(2 digits!!)
+ * <w> = day of week (sunday= 0)
+ * <hh>,<mm>,<ss> = hour, minute, second
+ * <S> = '#' if never synced since powerup else ' ' for DCF U/A 31
+ * '#' if not PZF sychronisation available else ' ' for PZF 535
+ * <F> = '*' if time comes from internal quartz else ' '
+ * <D> = 'S' if daylight saving time is active else ' '
+ * <A> = '!' 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 !!!
+ *
+ * <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <U><S><F><D><A><L><R><ETX>
+ * 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
+ * <STX> = '\002' ASCII start of text
+ * <ETX> = '\003' ASCII end of text
+ * <dd>,<mm>,<yy> = day, month, year(2 digits!!)
+ * <w> = day of week (sunday= 0)
+ * <hh>,<mm>,<ss> = hour, minute, second
+ * <U> = 'U' UTC time display
+ * <S> = '#' if never synced since powerup else ' ' for DCF U/A 31
+ * '#' if not PZF sychronisation available else ' ' for PZF 535
+ * <F> = '*' if time comes from internal quartz else ' '
+ * <D> = 'S' if daylight saving time is active else ' '
+ * <A> = '!' during the hour preceeding an daylight saving time
+ * start/end change
+ * <L> = 'A' LEAP second announcement
+ * <R> = 'R' alternate antenna
+ *
+ * Meinberg GPS166 receiver
+ *
+ * You must get the Uni-Erlangen firmware for the GPS receiver support
+ * to work to full satisfaction !
+ *
+ * <STX><dd>.<mm>.<yy>; <w>; <hh>:<mm>:<ss>; <+/-><00:00>; <U><S><F><D><A><L><R><L>; <position...><ETX>
+ *
+ * 000000000111111111122222222223333333333444444444455555555556666666
+ * 123456789012345678901234567890123456789012345678901234567890123456
+ * \x0209.07.93; 5; 08:48:26; +00:00; ; 49.5736N 11.0280E 373m\x03
+ *
+ *
+ * <STX> = '\002' ASCII start of text
+ * <ETX> = '\003' ASCII end of text
+ * <dd>,<mm>,<yy> = day, month, year(2 digits!!)
+ * <w> = day of week (sunday= 0)
+ * <hh>,<mm>,<ss> = hour, minute, second
+ * <+/->,<00:00> = offset to UTC
+ * <S> = '#' if never synced since powerup else ' ' for DCF U/A 31
+ * '#' if not PZF sychronisation available else ' ' for PZF 535
+ * <U> = 'U' UTC time display
+ * <F> = '*' if time comes from internal quartz else ' '
+ * <D> = 'S' if daylight saving time is active else ' '
+ * <A> = '!' during the hour preceeding an daylight saving time
+ * start/end change
+ * <L> = 'A' LEAP second announcement
+ * <R> = 'R' alternate antenna (reminiscent of PZF535) usually ' '
+ * <L> = '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/usr.sbin/xntpd/parse/clk_rawdcf.c b/usr.sbin/xntpd/parse/clk_rawdcf.c
new file mode 100644
index 000000000000..4a5ad5608a4e
--- /dev/null
+++ b/usr.sbin/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, (" <M>"));
+
+ 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/usr.sbin/xntpd/parse/clk_schmid.c b/usr.sbin/xntpd/parse/clk_schmid.c
new file mode 100644
index 000000000000..12b06fdcc304
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/clk_trimble.c b/usr.sbin/xntpd/parse/clk_trimble.c
new file mode 100644
index 000000000000..c9c124ea4dee
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/empty.c b/usr.sbin/xntpd/parse/empty.c
new file mode 100644
index 000000000000..91b777afe709
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/parse.c b/usr.sbin/xntpd/parse/parse.c
new file mode 100644
index 000000000000..7a360021e167
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/parse_conf.c b/usr.sbin/xntpd/parse/parse_conf.c
new file mode 100644
index 000000000000..78ddb3a1c9dd
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/parsesolaris.c b/usr.sbin/xntpd/parse/parsesolaris.c
new file mode 100644
index 000000000000..0da27e7a087a
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+/*
+ * the Solaris 2.2 include list
+ */
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/termios.h>
+#include <sys/stream.h>
+#include <sys/strtty.h>
+#include <sys/stropts.h>
+#include <sys/modctl.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cpu.h>
+
+#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 <sun4c/cpu.h>
+#include <sun4c/auxio.h>
+#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 <sys/tty.h>
+#include <sys/zsdev.h>
+#include <sys/ser_async.h>
+#include <sys/ser_zscc.h>
+
+/*
+ * 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/usr.sbin/xntpd/parse/parsestreams.c b/usr.sbin/xntpd/parse/parsestreams.c
new file mode 100644
index 000000000000..56ce07c93e6a
--- /dev/null
+++ b/usr.sbin/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 <sun4c/cpu.h>
+#include <sun4c/auxio.h>
+#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 <sundev/zsreg.h>
+#include <sundev/zscom.h>
+#include <sundev/zsvar.h>
+
+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/usr.sbin/xntpd/parse/util/Makefile b/usr.sbin/xntpd/parse/util/Makefile
new file mode 100644
index 000000000000..99caacffa6df
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/util/Makefile.tmpl b/usr.sbin/xntpd/parse/util/Makefile.tmpl
new file mode 100644
index 000000000000..a72100f9ec75
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/util/README b/usr.sbin/xntpd/parse/util/README
new file mode 100644
index 000000000000..4f6dab08e940
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/parse/util/dcfd.c b/usr.sbin/xntpd/parse/util/dcfd.c
new file mode 100644
index 000000000000..723e2c8e8cad
--- /dev/null
+++ b/usr.sbin/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 <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <sys/errno.h>
+#include <syslog.h>
+
+#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 <termios.h>
+#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 <termio.h>
+#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((" <M>"));
+
+ 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<<USECSCALE);
+ /*XXX*/ if (loop_filter_debug)
+ printf("read_drift: drift_comp %d ", drift_comp);
+ }
+}
+
+static void update_drift(drift_file, offset, reftime)
+ char *drift_file;
+ long offset;
+ time_t reftime;
+{
+ FILE *df;
+
+ df = fopen(drift_file, "w");
+ if (df != NULL)
+ {
+ int idrift = R_SHIFT(drift_comp, USECSCALE);
+ int fdrift = drift_comp & ((1<<USECSCALE)-1);
+
+ /*XXX*/ if (loop_filter_debug)
+ printf("update_drift: drift_comp %d ", drift_comp);
+ fdrift = (fdrift * 1000) / (1<<USECSCALE);
+ fprintf(df, "%4d.%03d %c%d.%06d %.24s\n", idrift, fdrift,
+ (offset < 0) ? '-' : '+', abs(offset) / 1000000, abs(offset) % 1000000,
+ asctime(localtime(&reftime)));
+ fclose(df);
+ /*XXX*/ if (loop_filter_debug)
+ printf("update_drift: %d.%03d ppm ", idrift, fdrift);
+ }
+}
+
+static void adjust_clock(offset, drift_file, reftime)
+ struct timeval *offset;
+ char *drift_file;
+ time_t reftime;
+{
+ struct timeval toffset;
+ register long usecoffset;
+ int tmp;
+
+ if (skip_adjust)
+ {
+ skip_adjust = 0;
+ return;
+ }
+
+ toffset = *offset;
+ toffset.tv_sec = abs(toffset.tv_sec);
+ toffset.tv_usec = abs(toffset.tv_usec);
+ if (timercmp(&toffset, &max_adj_offset, >))
+ {
+ /*
+ * 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<<ADJINTERVAL;
+
+ if ((sync_state == NO_SYNC) && ((ticks - last_sync) > 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<<ADJINTERVAL);
+#endif
+}
+
+static void detach()
+{
+ int s;
+
+ if (fork())
+ exit(0);
+
+ for (s = 0; s < 3; s++)
+ (void) close(s);
+ (void) open("/", 0);
+ (void) dup2(0, 1);
+ (void) dup2(0, 2);
+
+#if defined(NTP_POSIX_SOURCE) || defined(_POSIX_)
+ (void) setsid();
+#else /* _POSIX_ */
+#ifndef BSD
+ (void) setpgrp();
+#else /* BSD */
+ (void) setpgrp(0, getpid());
+#endif /* BSD */
+#endif /* _POSIX_ */
+#if defined(hpux)
+ if (fork())
+ exit(0);
+#endif /* hpux */
+}
+
+static void usage(program)
+ char *program;
+{
+ fprintf(stderr, "usage: %s [-f] [-l] [-t] [-i] [-o] [-d <drift_file>] <device>\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 <drift_file> 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<<ADJINTERVAL;
+ it.it_interval.tv_usec = 0;
+ it.it_value.tv_sec = 1<<ADJINTERVAL;
+ it.it_value.tv_usec = 0;
+
+ if (setitimer(ITIMER_REAL, &it, (struct itimerval *)0) == -1)
+ {
+ syslog(LOG_ERR, "setitimer: %m");
+ exit(1);
+ }
+ }
+#else
+ (void) alarm(1<<ADJINTERVAL);
+#endif
+
+ PRINTF(" DCF77 monitor - Copyright 1993, Frank Kardel\n\n");
+
+ pbuf[60] = '\0';
+ for ( i = 0; i < 60; i++)
+ pbuf[i] = '.';
+
+ read_drift(drift_file);
+
+ gettimeofday(&tlast, 0L);
+ i = 0;
+ do
+ {
+ while ((rrc = read(fd, &c, 1)) == 1)
+ {
+ gettimeofday(&t, 0L);
+ tt = t;
+ timersub(&t, &tlast);
+
+ if (errs > 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/usr.sbin/xntpd/parse/util/parsetest.c b/usr.sbin/xntpd/parse/util/parsetest.c
new file mode 100644
index 000000000000..4f26a0a6a98a
--- /dev/null
+++ b/usr.sbin/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 <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/errno.h>
+#include <fcntl.h>
+
+#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 <parse-device>\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/usr.sbin/xntpd/parse/util/testdcf.c b/usr.sbin/xntpd/parse/util/testdcf.c
new file mode 100644
index 000000000000..e07bc0c1cc01
--- /dev/null
+++ b/usr.sbin/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 <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/types.h>
+#ifdef STREAM
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#endif
+#include <sys/time.h>
+
+#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] <device>\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/usr.sbin/xntpd/refclocks/Dependencies b/usr.sbin/xntpd/refclocks/Dependencies
new file mode 100644
index 000000000000..d5e68d3da939
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/README b/usr.sbin/xntpd/refclocks/README
new file mode 100644
index 000000000000..b27b0064bdf3
--- /dev/null
+++ b/usr.sbin/xntpd/refclocks/README
@@ -0,0 +1,4 @@
+This directory contains shell scripts that should allow an interactive
+refclock configuration.
+
+Frank Kardel
diff --git a/usr.sbin/xntpd/refclocks/check b/usr.sbin/xntpd/refclocks/check
new file mode 100755
index 000000000000..d1e8b19cd558
--- /dev/null
+++ b/usr.sbin/xntpd/refclocks/check
@@ -0,0 +1,2 @@
+#!/bin/sh
+`echo "$1" | awk '{ if ( '"$2"' ) { print ":"; } else { print "false"; } exit; }'`;
diff --git a/usr.sbin/xntpd/refclocks/echon b/usr.sbin/xntpd/refclocks/echon
new file mode 100755
index 000000000000..8750ae86c2d4
--- /dev/null
+++ b/usr.sbin/xntpd/refclocks/echon
@@ -0,0 +1,2 @@
+#!/bin/sh
+echo -n "$@";
diff --git a/usr.sbin/xntpd/refclocks/query b/usr.sbin/xntpd/refclocks/query
new file mode 100755
index 000000000000..07e11ccf2f7a
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.AS2201 b/usr.sbin/xntpd/refclocks/rclk.AS2201
new file mode 100644
index 000000000000..9af89af40965
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.CHU b/usr.sbin/xntpd/refclocks/rclk.CHU
new file mode 100644
index 000000000000..fedd55c33dea
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.GOES b/usr.sbin/xntpd/refclocks/rclk.GOES
new file mode 100644
index 000000000000..cb87c638987e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.IRIG b/usr.sbin/xntpd/refclocks/rclk.IRIG
new file mode 100644
index 000000000000..b480e90391c4
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.LEITCH b/usr.sbin/xntpd/refclocks/rclk.LEITCH
new file mode 100644
index 000000000000..1bd5fb8011bd
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.LOCAL_CLOCK b/usr.sbin/xntpd/refclocks/rclk.LOCAL_CLOCK
new file mode 100644
index 000000000000..e2f9e1afe753
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.MSFEES b/usr.sbin/xntpd/refclocks/rclk.MSFEES
new file mode 100644
index 000000000000..aeb988af8d80
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.MX4200 b/usr.sbin/xntpd/refclocks/rclk.MX4200
new file mode 100644
index 000000000000..5d107126192f
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.OMEGA b/usr.sbin/xntpd/refclocks/rclk.OMEGA
new file mode 100644
index 000000000000..62094e46130d
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.PARSE b/usr.sbin/xntpd/refclocks/rclk.PARSE
new file mode 100644
index 000000000000..0bcf6972eb4c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.PST b/usr.sbin/xntpd/refclocks/rclk.PST
new file mode 100644
index 000000000000..4f93c8e8f24f
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.TPRO b/usr.sbin/xntpd/refclocks/rclk.TPRO
new file mode 100644
index 000000000000..74e5545211fc
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rclk.WWVB b/usr.sbin/xntpd/refclocks/rclk.WWVB
new file mode 100644
index 000000000000..2801ac70b18b
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/rconfig b/usr.sbin/xntpd/refclocks/rconfig
new file mode 100644
index 000000000000..727f0a8707da
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/setup b/usr.sbin/xntpd/refclocks/setup
new file mode 100644
index 000000000000..461117841c35
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/refclocks/setupfn b/usr.sbin/xntpd/refclocks/setupfn
new file mode 100644
index 000000000000..5724dcb52da6
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/Guess.sh b/usr.sbin/xntpd/scripts/Guess.sh
new file mode 100755
index 000000000000..97fd4c7cb24e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/README b/usr.sbin/xntpd/scripts/README
new file mode 100644
index 000000000000..79f1792a43d4
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/autoconf b/usr.sbin/xntpd/scripts/autoconf
new file mode 100755
index 000000000000..d1dc4c0bae71
--- /dev/null
+++ b/usr.sbin/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 <<EOF
+#ifdef __GNUC__
+ yes
+#endif
+EOF
+${CC-cc} -E 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
+#include <stdio.h>
+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 <sgtty.h>
+Autoconf TIOCGETP'
+ cat > conftest.c <<EOF
+$prog
+EOF
+eval "$CPP \$DEFS 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 <termio.h>
+Autoconf TCGETA'
+ cat > conftest.c <<EOF
+$prog
+EOF
+eval "$CPP \$DEFS 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 <<EOF
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+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 <string.h>' > 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 <<EOF
+#include <ctype.h>
+#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
+#include <${hdr}>
+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
+#include <unistd.h>
+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 <sys/types.h>' > 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 <sys/types.h>' > 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 <<EOF
+#include <sys/types.h>
+#include <signal.h>
+#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 <sys/types.h>' > 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 <<EOF
+main() { signed char c; }
+EOF
+eval $compile
+if test -s conftest && (./conftest; exit) 2>/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 <sys/types.h>' > 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 <<EOF
+
+int main() { exit(0); }
+int t() { $prog }
+EOF
+if eval $compile; then
+ :
+else
+ {
+test -n "$verbose" && \
+echo ' defining' const to be 'empty'
+DEFS="$DEFS -Dconst="
+}
+
+fi
+rm -f conftest*
+
+if test -n "$GCC"; then
+echo checking for inline
+cat > conftest.c <<EOF
+
+int main() { exit(0); }
+int t() { } inline foo() { }
+EOF
+if eval $compile; then
+ :
+else
+ {
+test -n "$verbose" && \
+echo ' defining' inline to be '__inline'
+DEFS="$DEFS -Dinline=__inline"
+}
+
+fi
+rm -f conftest*
+
+fi
+
+
+# aC_INT_16_BITS
+# DEC Alpha running OSF/1
+echo checking integer size
+cat > conftest.c <<EOF
+main() { exit(!(sizeof(long) > 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 <<EOF
+
+int main() { exit(0); }
+int t() { } long double foo() { }
+EOF
+if eval $compile; then
+ {
+test -n "$verbose" && \
+echo ' defining' HAVE_LONG_DOUBLE
+DEFS="$DEFS -DHAVE_LONG_DOUBLE=1"
+}
+
+fi
+rm -f conftest*
+
+fi
+
+echo checking byte ordering
+cat > conftest.c <<EOF
+main () {
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+EOF
+eval $compile
+if test -s conftest && (./conftest; exit) 2>/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 <<EOF
+/* Exit 0 (true) if wait returns something other than -1,
+ i.e. the pid of the child, which means that wait was restarted
+ after getting the signal. */
+#include <sys/types.h>
+#include <signal.h>
+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
+#include <sys/stream.h>
+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 <<EOF
+
+int main() { exit(0); }
+int t() { main(); }
+EOF
+if eval $compile; then
+ have_lib="1"
+fi
+rm -f conftest*
+LIBS="${LIBS_save}"
+if test -n "${have_lib}"; then
+ :; RESLIB="$RESLIB -lresolv"
+else
+ :;
+fi
+
+}
+test -n "$isSOLARIS" && {
+ {
+test -n "$verbose" && \
+echo ' defining' SOLARIS
+DEFS="$DEFS -DSOLARIS=1"
+}
+
+ {
+test -n "$verbose" && \
+echo ' defining' SLEWALWAYS
+DEFS="$DEFS -DSLEWALWAYS=1"
+}
+
+ {
+test -n "$verbose" && \
+echo ' defining' STUPID_SIGNAL
+DEFS="$DEFS -DSTUPID_SIGNAL=1"
+}
+
+ LIBS_save="${LIBS}"
+LIBS="${LIBS} -lsocket"
+have_lib=""
+echo checking for -lsocket
+cat > conftest.c <<EOF
+
+int main() { exit(0); }
+int t() { main(); }
+EOF
+if eval $compile; then
+ have_lib="1"
+fi
+rm -f conftest*
+LIBS="${LIBS_save}"
+if test -n "${have_lib}"; then
+ :; RESLIB="$RESLIB -lsocket"
+else
+ :;
+fi
+
+ LIBS_save="${LIBS}"
+LIBS="${LIBS} -lnsl"
+have_lib=""
+echo checking for -lnsl
+cat > conftest.c <<EOF
+
+int main() { exit(0); }
+int t() { main(); }
+EOF
+if eval $compile; then
+ have_lib="1"
+fi
+rm -f conftest*
+LIBS="${LIBS_save}"
+if test -n "${have_lib}"; then
+ :; RESLIB="$RESLIB -lnsl"
+else
+ :;
+fi
+
+ LIBS_save="${LIBS}"
+LIBS="${LIBS} -lelf"
+have_lib=""
+echo checking for -lelf
+cat > conftest.c <<EOF
+
+int main() { exit(0); }
+int t() { main(); }
+EOF
+if eval $compile; then
+ have_lib="1"
+fi
+rm -f conftest*
+LIBS="${LIBS_save}"
+if test -n "${have_lib}"; then
+ :; RESLIB="$RESLIB -lelf"
+else
+ :;
+fi
+
+}
+
+LIBS_save="${LIBS}"
+LIBS="${LIBS} -lBSD"
+have_lib=""
+echo checking for -lBSD
+cat > conftest.c <<EOF
+
+int main() { exit(0); }
+int t() { main(); }
+EOF
+if eval $compile; then
+ have_lib="1"
+fi
+rm -f conftest*
+LIBS="${LIBS_save}"
+if test -n "${have_lib}"; then
+ :; LIBS="$LIBS -lBSD"
+else
+ :;
+fi
+
+test -n "$have_lib" && {
+test -n "$verbose" && \
+echo ' defining' COMPAT to be '"-lBSD"'
+DEFS="$DEFS -DCOMPAT=\"-lBSD\""
+}
+
+
+test -z "$isSOLARIS" && {
+ LIBS_save="${LIBS}"
+LIBS="${LIBS} -lkvm"
+have_lib=""
+echo checking for -lkvm
+cat > conftest.c <<EOF
+
+int main() { exit(0); }
+int t() { main(); }
+EOF
+if eval $compile; then
+ have_lib="1"
+fi
+rm -f conftest*
+LIBS="${LIBS_save}"
+if test -n "${have_lib}"; then
+ :; RESLIB="$RESLIB -lkvm"
+else
+ :;
+fi
+
+ test -n "$have_lib" && {
+test -n "$verbose" && \
+echo ' defining' USELIBKVM
+DEFS="$DEFS -DUSELIBKVM=1"
+}
+
+}
+
+LIBS_save="${LIBS}"
+LIBS="${LIBS} -lmld"
+have_lib=""
+echo checking for -lmld
+cat > conftest.c <<EOF
+
+int main() { exit(0); }
+int t() { main(); }
+EOF
+if eval $compile; then
+ have_lib="1"
+fi
+rm -f conftest*
+LIBS="${LIBS_save}"
+if test -n "${have_lib}"; then
+ :; RESLIB="$RESLIB -lmld"
+else
+ :;
+fi
+
+
+prefix=/usr/local
+bindir=/usr/local/bin
+
+if test -n "$prefix"; then
+ test -z "$exec_prefix" && exec_prefix='${prefix}'
+ prsub="s%^prefix\\([ ]*\\)=\\([ ]*\\).*$%prefix\\1=\\2$prefix%"
+fi
+if test -n "$exec_prefix"; then
+ prsub="$prsub
+s%^exec_prefix\\([ ]*\\)=\\([ ]*\\).*$%\
+exec_prefix\\1=\\2$exec_prefix%"
+fi
+DEFS="`echo \"$DEFS\" | sed 's%[&\\\]%\\\&%g'`"
+
+trap 'rm -f config.status; exit 1' 1 3 15
+echo creating config.status
+rm -f config.status
+cat > config.status <<EOF
+#!/bin/sh
+# Generated automatically by autoconf.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/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/usr.sbin/xntpd/scripts/install.sh b/usr.sbin/xntpd/scripts/install.sh
new file mode 100755
index 000000000000..5dd98315d82c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/makeconfig.sh b/usr.sbin/xntpd/scripts/makeconfig.sh
new file mode 100755
index 000000000000..8842a86c6c51
--- /dev/null
+++ b/usr.sbin/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=<system>\""
+ 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/usr.sbin/xntpd/scripts/mklinks b/usr.sbin/xntpd/scripts/mklinks
new file mode 100755
index 000000000000..8565d1ca3580
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/mkversion b/usr.sbin/xntpd/scripts/mkversion
new file mode 100755
index 000000000000..07dbb775e162
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/monitoring/README b/usr.sbin/xntpd/scripts/monitoring/README
new file mode 100644
index 000000000000..fa8ad8bb9585
--- /dev/null
+++ b/usr.sbin/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 <port>] [-l <debug-output>] 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<delay>] [-t<timeout>] [-l <logfile>] [-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:<ntpserver>:
+ (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 <seconds since midnight UTC> 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[<level>]] [-c <config-file>] [-d <working-dir>]
+
+ to get a single print out specify also
+ -P<printer> [-s<samples>]
+ [-S <start-time>] [-E <end-time>]
+ [-O <MaxOffs>] [-o <MinOffs>]
+
+ 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/usr.sbin/xntpd/scripts/monitoring/loopwatch.config.SAMPLE b/usr.sbin/xntpd/scripts/monitoring/loopwatch.config.SAMPLE
new file mode 100644
index 000000000000..8cefea395db0
--- /dev/null
+++ b/usr.sbin/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/<baseval>
+# 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/<scaling>
+# 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/<number>
+# limit display (y-axis) to values not larger than <number>
+MaxOffset=none
+#
+# MinOffs: none/<number>
+# limit display (y-axis) to values not smaller than <number>
+MinOffset=none
+
+#
+# verbose: <number>
+# 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: <seconds>
+# mark `holes' in the sample data grater than <seconds>
+# by a break in the plot
+# default: 512 seconds
+deltaT=512
diff --git a/usr.sbin/xntpd/scripts/monitoring/lr.pl b/usr.sbin/xntpd/scripts/monitoring/lr.pl
new file mode 100755
index 000000000000..02c7550ec3ad
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/monitoring/ntp.pl b/usr.sbin/xntpd/scripts/monitoring/ntp.pl
new file mode 100755
index 000000000000..f3bfd2bfe0b9
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/monitoring/ntploopstat b/usr.sbin/xntpd/scripts/monitoring/ntploopstat
new file mode 100755
index 000000000000..75cdff227b27
--- /dev/null
+++ b/usr.sbin/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<delay>] [-t<timeout>] [-l <logfile>] [-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/usr.sbin/xntpd/scripts/monitoring/ntploopwatch b/usr.sbin/xntpd/scripts/monitoring/ntploopwatch
new file mode 100755
index 000000000000..655ed7188cea
--- /dev/null
+++ b/usr.sbin/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[<level>]] [-c <config-file>] [-d <working-dir>]
+ $F [-h <hostname>]
+
+ to get a single print out specify also
+ $F -P[<printer>] [-s<samples>]
+ $F [-S <start-time>] [-E <end-time>]
+ $F [-Y <MaxOffs>] [-y <MinOffs>]
+
+If You like long option names, You can use:
+ -help
+ -c +config
+ -d +directory
+ -h +host
+ -v +verbose[=<level>]
+ -P +printer[=<printer>]
+ -s +samples[=<samples>]
+ -S +starttime
+ -E +endtime
+ -Y +maxy
+ -y +miny
+
+If <printer> 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(<CF>)
+ {
+ 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];
+ </X{> 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(<IN>)
+ {
+ @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(<IN>)
+ {
+ @F = split;
+ next if @F < 5;
+ next if $F[$[] eq "";
+ $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60;
+ $t += $F[$[+1];
+ $F_last{$key} = $t;
+ $_ = <IN>;
+ print "\tfound last entry: $t ", &ctime($t)
+ if $verbose > 4 && ! defined($_);
+ last unless defined($_);
+ redo;
+ ;# Ok, calm down...
+ ;# using $_ = <IN> 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(<IN>)
+ {
+ $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/usr.sbin/xntpd/scripts/monitoring/ntptrap b/usr.sbin/xntpd/scripts/monitoring/ntptrap
new file mode 100755
index 000000000000..69c66608af97
--- /dev/null
+++ b/usr.sbin/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 <port>] [-l <logfile>] [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/usr.sbin/xntpd/scripts/monitoring/timelocal.pl b/usr.sbin/xntpd/scripts/monitoring/timelocal.pl
new file mode 100755
index 000000000000..d0f73a236676
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/ntp-groper b/usr.sbin/xntpd/scripts/ntp-groper
new file mode 100755
index 000000000000..1fd0cfe4c2d6
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/ntp-restart b/usr.sbin/xntpd/scripts/ntp-restart
new file mode 100755
index 000000000000..d2023f0b67b2
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/README b/usr.sbin/xntpd/scripts/stats/README
new file mode 100644
index 000000000000..5aa64d4c1db9
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/README.stats b/usr.sbin/xntpd/scripts/stats/README.stats
new file mode 100644
index 000000000000..aa8e77fb1bbe
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/README.timecodes b/usr.sbin/xntpd/scripts/stats/README.timecodes
new file mode 100644
index 000000000000..00b5ba54584f
--- /dev/null
+++ b/usr.sbin/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)
+<LF> ASCII line feed (hex 0a)
+<CR> ASCII carriage return (hex 0d)
+<SP> 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 <SP>
+stand for themselves; lowercase letters stand for fields as described.
+Special characters other than <LF>, <CR> and <SP> are preceded by ^.
+
+Spectracom 8170 and Netclock/2 WWV Synchonized Clock (format 0)
+
+"<CR><LF>i ddd hh:mm:ss TZ=zz<CR><LF>"
+ C A D T
+
+ poll: ?; offsets: Y = none, D = 3, T = 7, A = 0, Q = none
+ i = synchronization flag (<SP> = 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 <SP> 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)
+
+"<CR><LF>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 (<SP> = in synch, ? = out synch)
+ q = quality indicator (<SP> < 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 (<SP> standard, D daylight)
+
+ Note: alarm condition is indicated by other than <SP> 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 <SP> 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)
+
+"<CR><LF><^A>ddd:hh:mm:ssq<CR>"
+ 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 (<SP> = 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 <SP>
+ at Q
+
+ example: "216:15:36:43 "
+ D T Q
+
+Heath GC-1000 Most Accurate Clock (WWV/H)
+
+"<CR>hh:mm:ss.f dd/mm/yy<CR>"
+ 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<CR>" "ahh:mm:ss.fffs<CR>" "yy/dd/mm/ddd<CR>"
+ 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, <SP> - 24-hour format)
+ hh:mm:ss.fff = hours, minutes, seconds, milliseconds of day
+ s = daylight-saving indicator (<SP> 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/usr.sbin/xntpd/scripts/stats/clock.awk b/usr.sbin/xntpd/scripts/stats/clock.awk
new file mode 100644
index 000000000000..f6afc994fd83
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/clock.sh b/usr.sbin/xntpd/scripts/stats/clock.sh
new file mode 100755
index 000000000000..1866d556403d
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/dupe.awk b/usr.sbin/xntpd/scripts/stats/dupe.awk
new file mode 100644
index 000000000000..3ddc1b6f9754
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/ensemble.awk b/usr.sbin/xntpd/scripts/stats/ensemble.awk
new file mode 100644
index 000000000000..136b33da37cb
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/etf.awk b/usr.sbin/xntpd/scripts/stats/etf.awk
new file mode 100644
index 000000000000..8e6e334c1e01
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/itf.awk b/usr.sbin/xntpd/scripts/stats/itf.awk
new file mode 100644
index 000000000000..2b21c5b9b97c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/loop.awk b/usr.sbin/xntpd/scripts/stats/loop.awk
new file mode 100644
index 000000000000..25d0bdb97d53
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/loop.sh b/usr.sbin/xntpd/scripts/stats/loop.sh
new file mode 100755
index 000000000000..619eeb8c66af
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/peer.awk b/usr.sbin/xntpd/scripts/stats/peer.awk
new file mode 100644
index 000000000000..4cb48cddb68e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/peer.sh b/usr.sbin/xntpd/scripts/stats/peer.sh
new file mode 100755
index 000000000000..b5d8d29186db
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/psummary.awk b/usr.sbin/xntpd/scripts/stats/psummary.awk
new file mode 100644
index 000000000000..b7f0e922a7d6
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/summary.sh b/usr.sbin/xntpd/scripts/stats/summary.sh
new file mode 100755
index 000000000000..e27ecfa94650
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/stats/tdata.awk b/usr.sbin/xntpd/scripts/stats/tdata.awk
new file mode 100644
index 000000000000..04d7e6ad3242
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/README b/usr.sbin/xntpd/scripts/support/README
new file mode 100644
index 000000000000..812965bd0955
--- /dev/null
+++ b/usr.sbin/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 <regexp> (regular expression matchin IP addres to be ignored
+ -d <directory> where the current state is kept (default /tmp)
+ -v debug output
+ -n do not translate IP addresses into hostnames
+ <host> 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 <hostname> <hostid>
+<tickadj parameters>. 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
+<NTPROOT>/etc/rc for daemon startup.
+
+For more information: time@informatik.uni-erlangen.de
diff --git a/usr.sbin/xntpd/scripts/support/bin/monl b/usr.sbin/xntpd/scripts/support/bin/monl
new file mode 100755
index 000000000000..44201d0d0f99
--- /dev/null
+++ b/usr.sbin/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 = <MONL>;
+ 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/usr.sbin/xntpd/scripts/support/bin/mvstats b/usr.sbin/xntpd/scripts/support/bin/mvstats
new file mode 100755
index 000000000000..e33dc792e805
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/conf/hp300.hp300 b/usr.sbin/xntpd/scripts/support/conf/hp300.hp300
new file mode 100644
index 000000000000..7b1875842219
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/conf/hp700.hp700 b/usr.sbin/xntpd/scripts/support/conf/hp700.hp700
new file mode 100644
index 000000000000..911ff10a5005
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/conf/hp700.hp700.faui47 b/usr.sbin/xntpd/scripts/support/conf/hp700.hp700.faui47
new file mode 100644
index 000000000000..80c72a6c2d6d
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/conf/hp800.hp800 b/usr.sbin/xntpd/scripts/support/conf/hp800.hp800
new file mode 100644
index 000000000000..58f47062a6fd
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/conf/ntp.conf b/usr.sbin/xntpd/scripts/support/conf/ntp.conf
new file mode 100644
index 000000000000..06f5482c431e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/conf/ntp.keys b/usr.sbin/xntpd/scripts/support/conf/ntp.keys
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/usr.sbin/xntpd/scripts/support/conf/ntp.keys
diff --git a/usr.sbin/xntpd/scripts/support/conf/ntp.keys.dumb b/usr.sbin/xntpd/scripts/support/conf/ntp.keys.dumb
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/usr.sbin/xntpd/scripts/support/conf/ntp.keys.dumb
diff --git a/usr.sbin/xntpd/scripts/support/conf/sun3.sun3 b/usr.sbin/xntpd/scripts/support/conf/sun3.sun3
new file mode 100644
index 000000000000..06f5482c431e
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/conf/sun4.sun4.faui01 b/usr.sbin/xntpd/scripts/support/conf/sun4.sun4.faui01
new file mode 100644
index 000000000000..8927535ef80a
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/conf/sun4.sun4.faui10 b/usr.sbin/xntpd/scripts/support/conf/sun4.sun4.faui10
new file mode 100644
index 000000000000..3be93a920f9a
--- /dev/null
+++ b/usr.sbin/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/
+#
+# <stat type> file <file name> type <modifier> enable|disable|link|nolink
+filegen peerstats file peerstats type day link # generate <statsdir><file>.<YYYYMMDD> 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/usr.sbin/xntpd/scripts/support/conf/sun4.sun4.faui45 b/usr.sbin/xntpd/scripts/support/conf/sun4.sun4.faui45
new file mode 100644
index 000000000000..57e77f274980
--- /dev/null
+++ b/usr.sbin/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/
+#
+# <stat type> file <file name> type <modifier> enable|disable|link|nolink
+filegen peerstats file peerstats type day link # generate <statsdir><file>.<YYYYMMDD> 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/usr.sbin/xntpd/scripts/support/conf/sun4.sun4c b/usr.sbin/xntpd/scripts/support/conf/sun4.sun4c
new file mode 100644
index 000000000000..e1ff90259077
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/conf/sun4.sun4c.Lucifer b/usr.sbin/xntpd/scripts/support/conf/sun4.sun4c.Lucifer
new file mode 100644
index 000000000000..78d3ea887958
--- /dev/null
+++ b/usr.sbin/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/
+#
+# <stat type> file <file name> type <modifier> enable|disable|link|nolink
+filegen peerstats file peerstats type day link # generate <statsdir><file>.<YYYYMMDD> 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/usr.sbin/xntpd/scripts/support/conf/sun4.sun4m b/usr.sbin/xntpd/scripts/support/conf/sun4.sun4m
new file mode 100644
index 000000000000..cf1e283cb1fd
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/conf/sun4.sun4m.faui42 b/usr.sbin/xntpd/scripts/support/conf/sun4.sun4m.faui42
new file mode 100644
index 000000000000..acc919c85f2c
--- /dev/null
+++ b/usr.sbin/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/
+#
+# <stat type> file <file name> type <modifier> enable|disable|link|nolink
+filegen peerstats file peerstats type day link # generate <statsdir><file>.<YYYYMMDD> 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/usr.sbin/xntpd/scripts/support/conf/sun4.sun4m.faui45m b/usr.sbin/xntpd/scripts/support/conf/sun4.sun4m.faui45m
new file mode 100644
index 000000000000..2c75f67545f0
--- /dev/null
+++ b/usr.sbin/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/
+#
+# <stat type> file <file name> type <modifier> enable|disable|link|nolink
+filegen peerstats file peerstats type day link # generate <statsdir><file>.<YYYYMMDD> 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/usr.sbin/xntpd/scripts/support/conf/tickconf b/usr.sbin/xntpd/scripts/support/conf/tickconf
new file mode 100644
index 000000000000..b17dbe834743
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/etc/cron b/usr.sbin/xntpd/scripts/support/etc/cron
new file mode 100755
index 000000000000..07ed18949835
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/etc/crontab b/usr.sbin/xntpd/scripts/support/etc/crontab
new file mode 100644
index 000000000000..2b2d19ced76c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/etc/install b/usr.sbin/xntpd/scripts/support/etc/install
new file mode 100755
index 000000000000..169a7e5a06d7
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/scripts/support/etc/rc b/usr.sbin/xntpd/scripts/support/etc/rc
new file mode 100755
index 000000000000..ef8834a69f7b
--- /dev/null
+++ b/usr.sbin/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/<ARCH>.<KARCH>
+#
+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/usr.sbin/xntpd/scripts/support/etc/setup b/usr.sbin/xntpd/scripts/support/etc/setup
new file mode 100755
index 000000000000..d4ea75ecfaa9
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/util/Makefile.tmpl b/usr.sbin/xntpd/util/Makefile.tmpl
new file mode 100644
index 000000000000..1115ef83a7d4
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/util/README b/usr.sbin/xntpd/util/README
new file mode 100644
index 000000000000..2aedb006834c
--- /dev/null
+++ b/usr.sbin/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 <jones@chpc.utexas.edu> 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/usr.sbin/xntpd/util/byteorder.c b/usr.sbin/xntpd/util/byteorder.c
new file mode 100644
index 000000000000..665c146153ad
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+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/usr.sbin/xntpd/util/jitter.c b/usr.sbin/xntpd/util/jitter.c
new file mode 100644
index 000000000000..7201e87eba2e
--- /dev/null
+++ b/usr.sbin/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 <sys/time.h>
+#include <stdio.h>
+
+#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/usr.sbin/xntpd/util/kern.c b/usr.sbin/xntpd/util/kern.c
new file mode 100644
index 000000000000..a2a667203a72
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include <sys/time.h>
+
+#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/usr.sbin/xntpd/util/longsize.c b/usr.sbin/xntpd/util/longsize.c
new file mode 100644
index 000000000000..6bdbdfeff5f1
--- /dev/null
+++ b/usr.sbin/xntpd/util/longsize.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+main()
+{
+ if (sizeof(long) == 8) {
+ printf("-DLONG8\n");
+ } else if (sizeof(long) == 4) {
+ printf("-DLONG4\n");
+ }
+ exit(0);
+}
diff --git a/usr.sbin/xntpd/util/ntptime.c b/usr.sbin/xntpd/util/ntptime.c
new file mode 100644
index 000000000000..e528802f7298
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <sys/syscall.h>
+
+#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/usr.sbin/xntpd/util/precision.c b/usr.sbin/xntpd/util/precision.c
new file mode 100644
index 000000000000..69af19fb92ec
--- /dev/null
+++ b/usr.sbin/xntpd/util/precision.c
@@ -0,0 +1,81 @@
+#include <sys/types.h>
+#include <sys/time.h>
+
+#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/usr.sbin/xntpd/util/testrs6000.c b/usr.sbin/xntpd/util/testrs6000.c
new file mode 100644
index 000000000000..9a5e0cd77634
--- /dev/null
+++ b/usr.sbin/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 <signal.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdio.h>
+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/usr.sbin/xntpd/util/tickadj.c b/usr.sbin/xntpd/util/tickadj.c
new file mode 100644
index 000000000000..da18e0660318
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#if defined(SYS_AUX3) || defined(SYS_AUX2)
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/file.h>
+#include <a.out.h>
+#include <sys/var.h>
+#else
+#include <nlist.h>
+#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 <unistd.h>
+#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/usr.sbin/xntpd/util/timetrim.c b/usr.sbin/xntpd/util/timetrim.c
new file mode 100644
index 000000000000..052a587a7dff
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/syssgi.h>
+
+#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/usr.sbin/xntpd/xntpd/Makefile.tmpl b/usr.sbin/xntpd/xntpd/Makefile.tmpl
new file mode 100644
index 000000000000..a51dbd7becea
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/xntpd/README b/usr.sbin/xntpd/xntpd/README
new file mode 100644
index 000000000000..45512762d187
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/xntpd/ntp_config.c b/usr.sbin/xntpd/xntpd/ntp_config.c
new file mode 100644
index 000000000000..1a0e9ef4bf24
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#ifdef RESOLVE_INTERNAL
+#include <sys/time.h>
+#endif
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
+#include "ntp_refclock.h"
+#include "ntp_filegen.h"
+#include "ntp_stdlib.h"
+
+/*
+ * 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/usr.sbin/xntpd/xntpd/ntp_control.c b/usr.sbin/xntpd/xntpd/ntp_control.c
new file mode 100644
index 000000000000..5e71196e4e16
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#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/usr.sbin/xntpd/xntpd/ntp_filegen.c b/usr.sbin/xntpd/xntpd/ntp_filegen.c
new file mode 100644
index 000000000000..bbbd24270d7d
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_string.h"
+#include "ntp_calendar.h"
+#include "ntp_filegen.h"
+#include "ntp_stdlib.h"
+
+/*
+ * NTP is intended to run LONG periods of time without restart.
+ * Thus log and statistic files generated by NTP will grow large.
+ *
+ * this set of routines provides a central interface
+ * to generating files using file generations
+ *
+ * the generation of a file is changed according to file generation type
+ */
+
+
+/*
+ * 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/usr.sbin/xntpd/xntpd/ntp_intres.c b/usr.sbin/xntpd/xntpd/ntp_intres.c
new file mode 100644
index 000000000000..ebd3d52d0511
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <signal.h>
+#include <errno.h>
+
+#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/usr.sbin/xntpd/xntpd/ntp_io.c b/usr.sbin/xntpd/xntpd/ntp_io.c
new file mode 100644
index 000000000000..e765b03f31a2
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#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 <stropts.h>
+#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/usr.sbin/xntpd/xntpd/ntp_leap.c b/usr.sbin/xntpd/xntpd/ntp_leap.c
new file mode 100644
index 000000000000..aadbb09dc346
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+
+#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<<EVENT_TIMEOUT;
+ leapbits = 0;
+
+ leap_processcalls = leap_notclose = 0;
+ leap_monthofleap = leap_dayofleap = 0;
+ leap_hoursfromleap = leap_happened = 0;
+}
+
+
+/*
+ * leap_process - process a leap event expiry and/or a system time step
+ */
+void
+leap_process()
+{
+ U_LONG leapnext;
+ U_LONG leaplast;
+ l_fp ts;
+ u_char bits;
+ extern u_char sys_leap;
+
+ leap_processcalls++;
+ get_systime(&ts);
+ calleapwhen(ts.l_ui, &leaplast, &leapnext);
+
+ /*
+ * Figure out what to do based on how LONG to the next leap.
+ */
+ if (leapnext > 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<<EVENT_TIMEOUT)
+ * seconds after the desired time.
+ */
+ leap_timer = (secs + 1 + (1<<EVENT_TIMEOUT) + current_time)
+ & ~((1<<EVENT_TIMEOUT)-1);
+}
+
+
+/*
+ * leap_setleap - set leap_indicator and/or leap_warning. Return failure
+ * if we don't want to do it.
+ */
+int
+leap_setleap(indicator, warning)
+ int indicator;
+ int warning;
+{
+ U_LONG leapnext;
+ U_LONG leaplast;
+ l_fp ts;
+ int i;
+
+ get_systime(&ts);
+ calleapwhen(ts.l_ui, &leaplast, &leapnext);
+
+ i = 0;
+ if (warning != ~0)
+ if (leapnext > 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/usr.sbin/xntpd/xntpd/ntp_loopfilter.c b/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
new file mode 100644
index 000000000000..d74da9956e16
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
@@ -0,0 +1,944 @@
+/*
+ * ntp_loopfilter.c - implements the NTP loop filter algorithm
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <signal.h>
+
+#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 <sys/stat.h>
+#include "ntp_refclock.h"
+#endif /* PPS || PPSCLK || PPSPPS */
+
+#if defined(PPSCLK) || defined(PPSPPS)
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#if defined(PPSCLK)
+#include <sys/clkdefs.h>
+#endif /* PPSCLK */
+#endif /* STREAM */
+
+#endif /* PPSCLK || PPSPPS */
+
+#if defined(PPSPPS)
+#include <sys/ppsclock.h>
+#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<<PPS_FAC+2*PPS_TRIM) */
+#define PPS_TRIM 2 /* samples trimmed from median filter */
+#define PPS_XCPT "\377" /* intercept character */
+
+#if defined(PPSCLK)
+static struct refclockio io; /* given to the I/O handler */
+static int pps_baud; /* baud rate of PPS line */
+#endif /* PPSCLK */
+static l_fp pps_offset; /* filtered pps offset */
+static U_LONG pps_time; /* last pps sample time */
+static U_LONG nsamples; /* number of pps samples collected */
+static LONG samples[NPPS]; /* median filter for pps samples */
+/*
+ * Imported from ntp_io.c
+ */
+extern struct interface *loopback_interface;
+
+#endif /* PPS || PPSCLK || PPSPPS */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * Imported from timer module
+ */
+extern U_LONG current_time; /* like it says, in seconds */
+
+/*
+ * sys_poll and sys_refskew are set here
+ */
+extern u_char sys_poll; /* log2 of system poll interval */
+extern l_fp sys_refskew; /* accumulated skew since last update */
+extern u_fp sys_maxd; /* max dispersion of survivor list */
+
+/*
+ * Function prototypes
+ */
+#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
+int pps_sample P((l_fp *));
+#if defined(PPSCLK)
+static void pps_receive P((struct recvbuf *));
+#endif /* PPSCLK */
+#endif /* PPS || PPSCLK || PPSPPS */
+
+#if defined(KERNEL_PLL)
+extern int sigvec P((int, struct sigvec *, struct sigvec *));
+void pll_trap P((void));
+
+static struct sigvec sigsys; /* current sigvec status */
+static struct sigvec newsigsys; /* new sigvec status */
+#endif /* KERNEL_PLL */
+
+/*
+ * init_loopfilter - initialize loop filter data
+ */
+void
+init_loopfilter()
+{
+ extern U_LONG tsf_maxslew;
+ U_LONG tsf_limit;
+#if defined(PPSCLK)
+ int fd232;
+#endif /* PPSCLK */
+ clock_adjust = 0;
+ drift_comp = 0;
+ time_constant = 0;
+ tcadj_time = 0;
+ watchdog_timer = 0;
+ tc_counter = 0;
+ last_offset.l_i = 0;
+ last_offset.l_f = 0;
+ first_adjustment = 1;
+
+/*
+ * Limit for drift_comp, minimum of two values. The first is to avoid
+ * signed overflow, the second to keep within 75% of the maximum
+ * adjustment possible in adj_systime().
+ */
+ max_comp = 0x7fff0000;
+ tsf_limit = ((tsf_maxslew >> 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/usr.sbin/xntpd/xntpd/ntp_monitor.c b/usr.sbin/xntpd/xntpd/ntp_monitor.c
new file mode 100644
index 000000000000..5d589e87454c
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#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/usr.sbin/xntpd/xntpd/ntp_peer.c b/usr.sbin/xntpd/xntpd/ntp_peer.c
new file mode 100644
index 000000000000..5e3b13455e42
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+
+#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/usr.sbin/xntpd/xntpd/ntp_proto.c b/usr.sbin/xntpd/xntpd/ntp_proto.c
new file mode 100644
index 000000000000..a13262440653
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#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<<newpoll) + current_time;
+ evp = &(peer->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/usr.sbin/xntpd/xntpd/ntp_refclock.c b/usr.sbin/xntpd/xntpd/ntp_refclock.c
new file mode 100644
index 000000000000..5199a1acbd26
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+
+#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/usr.sbin/xntpd/xntpd/ntp_request.c b/usr.sbin/xntpd/xntpd/ntp_request.c
new file mode 100644
index 000000000000..96def3fa13cf
--- /dev/null
+++ b/usr.sbin/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 <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#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<<i)-1));
+ while (--i >= 0)
+ ic->values[i] = htonl(bug.values[i]);
+
+ i = bug.ntimes;
+ if (i > NUMCBUGTIMES)
+ i = NUMCBUGTIMES;
+ ic->ntimes = (u_char)i;
+ ic->stimes = htonl((U_LONG)bug.stimes & ((1<<i)-1));
+ while (--i >= 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/usr.sbin/xntpd/xntpd/ntp_restrict.c b/usr.sbin/xntpd/xntpd/ntp_restrict.c
new file mode 100644
index 000000000000..9bd977958967
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <sys/types.h>
+
+#include "ntpd.h"
+#include "ntp_if.h"
+#include "ntp_stdlib.h"
+
+/*
+ * This code keeps a simple address-and-mask list of hosts we want
+ * to place restrictions on (or remove them from). The restrictions
+ * are implemented as a set of flags which tell you what the host
+ * can't do. There is a subroutine entry to return the flags. The
+ * list is kept sorted to reduce the average number of comparisons
+ * and make sure you get the set of restrictions most specific to
+ * the address.
+ *
+ * The algorithm is that, when looking up a host, it is first assumed
+ * that the default set of restrictions will apply. It then searches
+ * down through the list. Whenever it finds a match it adopts the match's
+ * flags instead. When you hit the point where the sorted address is
+ * greater than the target, you return with the last set of flags you
+ * found. Because of the ordering of the list, the most specific match
+ * will provide the final set of flags.
+ *
+ * This was originally intended to restrict you from sync'ing to your
+ * own broadcasts when you are doing that, by restricting yourself
+ * from your own interfaces. It was also thought it would sometimes
+ * be useful to keep a misbehaving host or two from abusing your primary
+ * clock. It has been expanded, however, to suit the needs of those
+ * with more restrictive access policies.
+ */
+
+/*
+ * 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/usr.sbin/xntpd/xntpd/ntp_timer.c b/usr.sbin/xntpd/xntpd/ntp_timer.c
new file mode 100644
index 000000000000..e3ba54cd39bc
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <sys/signal.h>
+
+#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<<CLOCK_ADJ);
+ hourly_timer = HOUR;
+ current_time = 0;
+ timer_overflows = 0;
+ timer_xmtcalls = 0;
+ timer_timereset = 0;
+
+ for (i = 0; i < TIMER_NSLOTS; i++) {
+ /*
+ * Queue pointers should point at themselves. Event
+ * times must be set to 0 since this is used to
+ * detect the queue end.
+ */
+ timerqueue[i].next = &timerqueue[i];
+ timerqueue[i].prev = &timerqueue[i];
+ timerqueue[i].event_time = 0;
+ }
+
+ /*
+ * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
+ * seconds from now and they continue on every 2**EVENT_TIMEOUT
+ * seconds.
+ */
+ (void) signal_no_reset(SIGALRM, alarming);
+ itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
+ itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
+ setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+}
+
+
+
+/*
+ * timer - dispatch anyone who needs to be
+ */
+void
+timer()
+{
+ register struct event *ev;
+ register struct event *tq;
+
+ current_time += (1<<EVENT_TIMEOUT);
+
+ /*
+ * Adjustment timeout first
+ */
+ if (adjust_timer <= current_time) {
+ adjust_timer += (1<<CLOCK_ADJ);
+ adj_host_clock();
+ }
+
+ /*
+ * Leap timer next.
+ */
+ if (leap_timer != 0 && leap_timer <= current_time)
+ leap_process();
+
+ /*
+ * Now dispatch any peers whose event timer has expired.
+ */
+ tq = &timerqueue[TIMER_SLOT(current_time)];
+ ev = tq->next;
+ while (ev->event_time != 0
+ && ev->event_time < (current_time + (1<<EVENT_TIMEOUT))) {
+ tq->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/usr.sbin/xntpd/xntpd/ntp_unixclock.c b/usr.sbin/xntpd/xntpd/ntp_unixclock.c
new file mode 100644
index 000000000000..4ac7cd223afd
--- /dev/null
+++ b/usr.sbin/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 <nlist.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#if defined(SYS_HPUX) || defined(sgi) || defined(__bsdi__)
+#include <sys/param.h>
+#include <utmp.h>
+#endif
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
+#include "ntp_stdlib.h"
+
+#if defined(HAVE_LIBKVM)
+#ifdef __bsdi__
+#include <sys/proc.h>
+#endif /* __bsdi__ */
+#include <kvm.h>
+#include <limits.h>
+
+#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<<CLOCK_ADJ sec (usec) */
+
+extern U_LONG tsf_maxslew; /* same as above, as LONG format */
+
+extern l_fp sys_clock_offset; /* correction for current system time */
+
+/*
+ * Import sys_clock (it is updated in get_systime)
+ */
+extern LONG sys_clock;
+
+static void clock_parms P((U_LONG *, U_LONG *));
+
+/*
+ * init_systime - initialize the system clock support code, return
+ * clock precision.
+ *
+ * Note that this code obtains to kernel variables related to the local
+ * clock, tickadj and tick. The code knows how the Berkeley adjtime
+ * call works, and assumes these two variables are obtainable and are
+ * used in the same manner. Tick is supposed to be the number of
+ * microseconds which are added to the system clock at clock interrupt
+ * time when the time isn't being slewed. Tickadj is supposed to be
+ * the number of microseconds which are added or subtracted from tick when
+ * the time is being slewed.
+ *
+ * If either of these two variables is missing, or is there but is used
+ * for a purpose different than that described, you are SOL and may have
+ * to do some custom kludging.
+ *
+ * This really shouldn't be in here.
+ */
+void
+init_systime()
+{
+ U_LONG tickadj;
+ U_LONG tick;
+ U_LONG hz;
+
+ /*
+ * Obtain the values
+ */
+ clock_parms(&tickadj, &tick);
+#ifdef DEBUG
+ if (debug)
+ printf("kernel vars: tickadj = %d, tick = %d\n", tickadj, tick);
+#endif
+
+ /*
+ * If tickadj or hz wasn't found, we're doomed. If hz is
+ * unreasonably small, forget it.
+ */
+ if (tickadj == 0 || tick == 0) {
+ syslog(LOG_ERR, "tickadj or tick unknown, exiting");
+ exit(3);
+ }
+ if (tick > 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<<CLOCK_ADJ
+ * seconds.
+ */
+#ifdef ADJTIME_IS_ACCURATE
+ adj_precision = 1;
+#else
+ adj_precision = tickadj;
+#endif /* ADJTIME_IS_ACCURATE */
+#if defined(SLEWALWAYS) && !defined(ADJTIME_IS_ACCURATE)
+ /*
+ * give us more time if we are always slewing... just in case
+ */
+ tvu_maxslew = tickadj * (hz-3) * (1<<CLOCK_ADJ);
+#else
+ tvu_maxslew = tickadj * (hz-1) * (1<<CLOCK_ADJ);
+#endif /* SLEWALWAYS */
+ if (tvu_maxslew > 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 <unistd.h>
+#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/usr.sbin/xntpd/xntpd/ntp_util.c b/usr.sbin/xntpd/xntpd/ntp_util.c
new file mode 100644
index 000000000000..394d6dfd2938
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#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 <sys/resource.h>
+#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/usr.sbin/xntpd/xntpd/ntpd.c b/usr.sbin/xntpd/xntpd/ntpd.c
new file mode 100644
index 000000000000..f29f741c9d21
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#if defined(SYS_HPUX)
+#include <sys/lock.h>
+#include <sys/rtprio.h>
+#endif
+
+#if defined(SYS_SVR4)
+#include <sys/termios.h>
+#endif
+
+#if (defined(SYS_SOLARIS)&&!defined(bsd)) || defined(__svr4__)
+#include <sys/termios.h>
+#endif
+
+#include "ntpd.h"
+#include "ntp_select.h"
+#include "ntp_io.h"
+#include "ntp_stdlib.h"
+
+#ifdef LOCK_PROCESS
+#include <sys/lock.h>
+#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/usr.sbin/xntpd/xntpd/refclock_as2201.c b/usr.sbin/xntpd/xntpd/refclock_as2201.c
new file mode 100644
index 000000000000..f04d6d0659ca
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#if defined(AS2201CLK)
+#include <sys/clkdefs.h>
+#endif /* AS2201CLK */
+#endif /* STREAM */
+
+#if defined (AS2201PPS)
+#include <sys/ppsclock.h>
+#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 <cr>
+ * 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 <cr> (\r). The
+ * command list consist of a sequence of commands terminated by a null
+ * string ("\0"). One command from the list is sent immediately
+ * following each received timecode (*toc\r command) and the ASCII
+ * strings received from the radio are saved along with the timecode in
+ * the clockstats file. Subsequent commands are sent at each timecode,
+ * with the last one in the list followed by the first one. The data
+ * received from the radio consist of ASCII strings, each terminated by
+ * a <cr> (\r) character. The number of strings for each command is
+ * specified as the first line of output as an ASCII-encode number. Note
+ * that the ETF command requires the Input Buffer Module and the LORAN
+ * commands require the LORAN Assist Module. However, if these modules
+ * are not installed, the radio and this driver will continue to operate
+ * successfuly, but no data will be captured for these commands.
+ */
+static char stat_command[][30] = {
+ "ITF\r", /* internal time/frequency */
+ "ETF\r", /* external time/frequency */
+ "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */
+ "LORAN TDATA\r", /* LORAN signal data */
+ "ID;OPT;VER\r", /* model; options; software version */
+
+ "ITF\r", /* internal time/frequency */
+ "ETF\r", /* external time/frequency */
+ "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */
+ "TRSTAT\r", /* satellite tracking status */
+ "POS;PPS;PPSOFF\r", /* position, pps source, offsets */
+
+ "ITF\r", /* internal time/frequency */
+ "ETF\r", /* external time/frequency */
+ "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */
+ "LORAN TDATA\r", /* LORAN signal data */
+ "UTC\r", /* UTC leap info */
+
+ "ITF\r", /* internal time/frequency */
+ "ETF\r", /* external time/frequency */
+ "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */
+ "TRSTAT\r", /* satellite tracking status */
+ "OSC;ET;TEMP\r", /* osc type; tune volts; oven temp */
+ "\0" /* end of table */
+};
+
+/*
+ * 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/usr.sbin/xntpd/xntpd/refclock_chu.c b/usr.sbin/xntpd/xntpd/refclock_chu.c
new file mode 100644
index 000000000000..05379b6331f2
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#endif /* STREAM */
+
+#if defined (CHUPPS)
+#include <sys/ppsclock.h>
+#endif /* CHUPPS */
+
+#include <sys/chudefs.h>
+
+#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<<i))
+ M_ADD(prod_ui, prod_uf, date_ui, tmp);
+ }
+
+ /*
+ * Done, round it correctly. Prod_ui contains the
+ * fraction.
+ */
+ if (prod_uf & 0x80000000)
+ prod_ui++;
+ if (isneg)
+ date_ui = 0xffffffff;
+ else
+ date_ui = 0;
+ tmp = prod_ui;
+ /*
+ * date_ui is integral part, tmp is fraction.
+ */
+ } else {
+ register U_LONG prod_ovr;
+ register U_LONG prod_ui;
+ register U_LONG prod_uf;
+ register U_LONG highbits;
+
+ prod_ovr = prod_ui = prod_uf = 0;
+ if (isneg)
+ highbits = 0xffffffff; /* sign extend */
+ else
+ highbits = 0;
+ /*
+ * This code knows the low order bit in 0.1 is zero
+ */
+ for (i = 1; i < NZPOBITS; i++) {
+ M_LSHIFT3(highbits, date_ui, tmp);
+ if (ZEROPTONE & (1<<i))
+ M_ADD3(prod_ovr, prod_uf, prod_ui,
+ highbits, date_ui, tmp);
+ }
+
+ if (prod_uf & 0x80000000)
+ M_ADDUF(prod_ovr, prod_ui, (U_LONG)1);
+ date_ui = prod_ovr;
+ tmp = prod_ui;
+ }
+ }
+
+ /*
+ * At this point we have the mean offset, with the integral
+ * part in date_ui and the fractional part in tmp. Store
+ * it in the structure.
+ */
+ i = second - 32; /* gives a value 0 through 8 */
+ if (i < (int)chu->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<<i);
+
+ if (chu->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<<EVENT_TIMEOUT);
+ chu->chutimer.event_time &= ~((1<<EVENT_TIMEOUT) - 1);
+ TIMER_INSERT(timerqueue, &chu->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<<i))
+ if (i < imax || L_ISGEQ(&chu->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<<i)) {
+ tmpoff = LFPTOFP(&chu->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/usr.sbin/xntpd/xntpd/refclock_conf.c b/usr.sbin/xntpd/xntpd/refclock_conf.c
new file mode 100644
index 000000000000..efe096647bd8
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_conf.c
@@ -0,0 +1,121 @@
+/*
+ * refclock_conf.c - reference clock configuration
+ */
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "ntpd.h"
+#include "ntp_refclock.h"
+#include "ntp_stdlib.h"
+
+#ifdef REFCLOCK
+
+static struct refclock refclock_none = {
+ noentry, noentry, noentry, noentry, noentry, noentry, NOFLAGS
+};
+
+#ifdef 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/usr.sbin/xntpd/xntpd/refclock_goes.c b/usr.sbin/xntpd/xntpd/refclock_goes.c
new file mode 100644
index 000000000000..60b19f69aecf
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#if defined(GOESCLK)
+#include <clkdefs.h>
+#endif /* GOESCLK */
+#endif /* STREAM */
+
+#if defined (GOESPPS)
+#include <sys/ppsclock.h>
+#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] != ':' || /* <sp> */
+ !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/usr.sbin/xntpd/xntpd/refclock_irig.c b/usr.sbin/xntpd/xntpd/refclock_irig.c
new file mode 100644
index 000000000000..fb9424116eb6
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_irig.c
@@ -0,0 +1,566 @@
+/*
+ * refclock_irig - clock driver for the IRIG audio decoder
+ */
+
+#if defined(REFCLOCK) && defined(IRIG)
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/ioccom.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include <sys/bsd_audioirig.h>
+#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/usr.sbin/xntpd/xntpd/refclock_leitch.c b/usr.sbin/xntpd/xntpd/refclock_leitch.c
new file mode 100644
index 000000000000..0fa996c7c5c6
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#if defined(LEITCHCLK)
+#include <sys/clkdefs.h>
+#endif /* LEITCHCLK */
+#endif /* STREAM */
+
+#if defined (LEITCHPPS)
+#include <sys/ppsclock.h>
+#endif /* LEITCHPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+ * Driver for Leitch CSD-5300 Master Clock System
+ *
+ * COMMANDS:
+ * DATE: D <CR>
+ * TIME: T <CR>
+ * STATUS: S <CR>
+ * LOOP: L <CR>
+ *
+ * FORMAT:
+ * DATE: YYMMDD<CR>
+ * TIME: <CR>/HHMMSS <CR>/HHMMSS <CR>/HHMMSS <CR>/
+ * second bondaried on the stop bit of the <CR>
+ * second boundaries at '/' above.
+ * STATUS: G (good), D (diag fail), T (time not provided) or
+ * P (last phone update failed)
+ */
+#define MAXUNITS 1 /* max number of LEITCH units */
+#define 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/usr.sbin/xntpd/xntpd/refclock_local.c b/usr.sbin/xntpd/xntpd/refclock_local.c
new file mode 100644
index 000000000000..0925a7df5b5e
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_local.c
@@ -0,0 +1,307 @@
+/*
+ * refclock_local - local pseudo-clock driver
+ */
+#if defined(REFCLOCK) && defined(LOCAL_CLOCK)
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#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/usr.sbin/xntpd/xntpd/refclock_msfees.c b/usr.sbin/xntpd/xntpd/refclock_msfees.c
new file mode 100644
index 000000000000..699ff0d202cd
--- /dev/null
+++ b/usr.sbin/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 <ctype.h>
+#include <sys/time.h>
+
+#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 <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+#include <termios.h>
+#include <stropts.h>
+#include <sys/ppsclock.h>
+#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<to; i++)
+ { while (*ptr) ptr++;
+ if ((ptr-buff) > 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/usr.sbin/xntpd/xntpd/refclock_mx4200.c b/usr.sbin/xntpd/xntpd/refclock_mx4200.c
new file mode 100644
index 000000000000..3d98d106857c
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_calendar.h"
+#include "ntp_unixtime.h"
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#if defined(MX4200CLK)
+#include <sys/clkdefs.h>
+#endif /* MX4200CLK */
+#endif /* STREAM */
+
+#include <sys/ppsclock.h>
+
+#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/usr.sbin/xntpd/xntpd/refclock_omega.c b/usr.sbin/xntpd/xntpd/refclock_omega.c
new file mode 100644
index 000000000000..4dee7aa74aa7
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#if defined(OMEGACLK)
+#include <sys/clkdefs.h>
+#endif /* OMEGACLK */
+#endif /* STREAM */
+
+#if defined (OMEGAPPS)
+#include <sys/ppsclock.h>
+#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 <CR> on the second, but
+ * we see the result after the <LF> 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] != ':' || /* <sp> */
+ !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/usr.sbin/xntpd/xntpd/refclock_parse.c b/usr.sbin/xntpd/xntpd/refclock_parse.c
new file mode 100644
index 000000000000..9e34d6e1595c
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <time.h>
+
+#include <sys/errno.h>
+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 <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/termios.h>
+#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 <sys/termio.h>
+#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 <fcntl.h>
+#endif /* !def(O_RDWR) */
+
+#ifdef PPSPPS
+#include <sys/ppsclock.h>
+#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.<device> */
+ 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+<device> */
+ 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+<device> */
+ 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+<device> */
+ 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+<device> */
+ 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+<device> */
+ 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+<device> */
+ 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+<device> */
+ 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+<device> */
+ 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) ? "<AUTOMATIC>" : 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/usr.sbin/xntpd/xntpd/refclock_pst.c b/usr.sbin/xntpd/xntpd/refclock_pst.c
new file mode 100644
index 000000000000..e72ac8bf082a
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#if defined(PSTCLK)
+#include <sys/clkdefs.h>
+#endif /* PSTCLK */
+#endif /* STREAM */
+
+#if defined (PSTPPS)
+#include <sys/ppsclock.h>
+#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/usr.sbin/xntpd/xntpd/refclock_tpro.c b/usr.sbin/xntpd/xntpd/refclock_tpro.c
new file mode 100644
index 000000000000..59881800bd63
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "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/usr.sbin/xntpd/xntpd/refclock_wwvb.c b/usr.sbin/xntpd/xntpd/refclock_wwvb.c
new file mode 100644
index 000000000000..602eee0ee424
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#if defined(WWVBCLK)
+#include <sys/clkdefs.h>
+#endif /* WWVBCLK */
+#endif /* STREAM */
+
+#if defined (WWVBPPS)
+#include <sys/ppsclock.h>
+#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:
+ *
+ * <cr><lf>I<sp><sp>ddd<sp>hh:mm:ss<sp><sp>TZ=nn<cr><lf>
+ *
+ * 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
+ * <sp> 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:
+ *
+ * <cr><lf>IQyy<sp>ddd<sp>hh:mm:ss.mmm<sp>LD
+ *
+ * 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 <sp> 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
+ * <sp>, but is set to 'L' early in the month of an upcoming UTC
+ * leap second and reset to <sp> on the first day of the following
+ * month. The D is set to 'S' for standard time 'I' on the day
+ * preceding a switch to daylight time, 'D' for daylight time and 'O'
+ * on the day preceding a switch to standard time. The start bit of the
+ * first <cr> is 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 <cr> and <lf>,
+ * but only the <cr> timestamp is retained. Note: in format 0 on
+ * a Netclock/2 or upgraded 8170 the start bit is delayed 100
+ * +-50 us relative to the pps; however, on an unmodified 8170
+ * the start bit can be delayed up to 10 ms. In format 2 the
+ * reading precision is only to the millisecond. Thus, unless
+ * you have a pps gadget and don't have to have the year, format
+ * 0 provides the lowest jitter.
+ */
+ if (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 <cr>; however, we don't
+ * get the timecode for that timestamp until the next <cr>. 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] != ' ' || /* <sp> separator */
+ cp[2] != ' ' || /* <sp> separator */
+ !isdigit(cp[3]) || /* day of year */
+ !isdigit(cp[4]) ||
+ !isdigit(cp[5]) ||
+ cp[6] != ' ' || /* <sp> 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] != ' ' || /* <sp> separator */
+ !isdigit(cp[5]) || /* day of year */
+ !isdigit(cp[6]) ||
+ !isdigit(cp[7]) ||
+ cp[8] != ' ' || /* <sp> 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] != ' ') { /* <sp> 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/usr.sbin/xntpd/xntpdc/Makefile.tmpl b/usr.sbin/xntpd/xntpdc/Makefile.tmpl
new file mode 100644
index 000000000000..32ed02419146
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/xntpdc/README b/usr.sbin/xntpd/xntpdc/README
new file mode 100644
index 000000000000..9d0b661e6c09
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/xntpdc/ntpdc.c b/usr.sbin/xntpd/xntpdc/ntpdc.c
new file mode 100644
index 000000000000..c5fdf72eb7cb
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+
+#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/usr.sbin/xntpd/xntpdc/ntpdc.h b/usr.sbin/xntpd/xntpdc/ntpdc.h
new file mode 100644
index 000000000000..7784ebc5a672
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/xntpdc/ntpdc_ops.c b/usr.sbin/xntpd/xntpdc/ntpdc_ops.c
new file mode 100644
index 000000000000..26f7e91d8fa3
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+
+#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<<max(min3(plist->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<<i)) {
+ (void) fprintf(fp, "%12ld",
+ (LONG)ntohl(cl->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<<i)) {
+ (void) fprintf(fp, "%17s",
+ lfptoa(&ts, 6));
+ needsp = 22;
+ } else {
+ (void) fprintf(fp, "%37s",
+ uglydate(&ts));
+ needsp = 2;
+ }
+ }
+ (void) fprintf(fp, "\n");
+ if (items > 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/usr.sbin/xntpd/xntpres/Makefile.tmpl b/usr.sbin/xntpd/xntpres/Makefile.tmpl
new file mode 100644
index 000000000000..8f0742bd3bbc
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/xntpres/README b/usr.sbin/xntpd/xntpres/README
new file mode 100644
index 000000000000..06d7266b4f2c
--- /dev/null
+++ b/usr.sbin/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/usr.sbin/xntpd/xntpres/xntpres.c b/usr.sbin/xntpd/xntpres/xntpres.c
new file mode 100644
index 000000000000..cf0d850bd888
--- /dev/null
+++ b/usr.sbin/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 <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <signal.h>
+#include <errno.h>
+
+#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;
+ }
+}