aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorsvn2git <svn2git@FreeBSD.org>1994-05-01 08:00:00 +0000
committersvn2git <svn2git@FreeBSD.org>1994-05-01 08:00:00 +0000
commita16f65c7d117419bd266c28a1901ef129a337569 (patch)
tree2626602f66dc3551e7a7c7bc9ad763c3bc7ab40a /contrib
parent8503f4f13f77abf7adc8f7e329c6f9c1d52b6a20 (diff)
This commit was manufactured to restore the state of the 1.1-RELEASE image. Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
Diffstat (limited to 'contrib')
-rw-r--r--contrib/Makefile4
-rw-r--r--contrib/tcpdump/tcpdump/addrtoname.c2
-rw-r--r--contrib/tcpdump/tcpdump/addrtoname.h2
-rw-r--r--contrib/tcpdump/tcpdump/appletalk.h2
-rw-r--r--contrib/tcpdump/tcpdump/bootp.h2
-rw-r--r--contrib/tcpdump/tcpdump/bpf_dump.c2
-rw-r--r--contrib/tcpdump/tcpdump/bpf_image.c2
-rw-r--r--contrib/tcpdump/tcpdump/etherent.c2
-rw-r--r--contrib/tcpdump/tcpdump/etherent.h2
-rw-r--r--contrib/tcpdump/tcpdump/etherproto.h2
-rw-r--r--contrib/tcpdump/tcpdump/extract.h2
-rw-r--r--contrib/tcpdump/tcpdump/gencode.c2
-rw-r--r--contrib/tcpdump/tcpdump/gencode.h2
-rw-r--r--contrib/tcpdump/tcpdump/inet.c2
-rw-r--r--contrib/tcpdump/tcpdump/interface.h2
-rw-r--r--contrib/tcpdump/tcpdump/md.c2
-rw-r--r--contrib/tcpdump/tcpdump/md.h2
-rw-r--r--contrib/tcpdump/tcpdump/nametoaddr.c2
-rw-r--r--contrib/tcpdump/tcpdump/nametoaddr.h2
-rw-r--r--contrib/tcpdump/tcpdump/ntp.h2
-rw-r--r--contrib/tcpdump/tcpdump/optimize.c2
-rw-r--r--contrib/tcpdump/tcpdump/os.c2
-rw-r--r--contrib/tcpdump/tcpdump/os.h2
-rw-r--r--contrib/tcpdump/tcpdump/pcap.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-arp.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-atalk.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-bootp.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-domain.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-ether.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-fddi.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-icmp.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-ip.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-nfs.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-ntp.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-null.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-ospf.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-ppp.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-rip.c34
-rw-r--r--contrib/tcpdump/tcpdump/print-sl.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-sunrpc.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-tcp.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-tftp.c2
-rw-r--r--contrib/tcpdump/tcpdump/print-udp.c2
-rw-r--r--contrib/tcpdump/tcpdump/savefile.c2
-rw-r--r--contrib/tcpdump/tcpdump/savefile.h2
-rw-r--r--contrib/tcpdump/tcpdump/tcpdump.14
-rw-r--r--contrib/tcpdump/tcpdump/tcpdump.c2
-rw-r--r--contrib/tcpdump/tcpdump/tcpgram.y2
-rw-r--r--contrib/tcpdump/tcpdump/tcplex.l2
-rw-r--r--contrib/tcpdump/tcpdump/util.c2
-rw-r--r--contrib/tcpdump/tcpslice/gwtm2secs.c2
-rw-r--r--contrib/tcpdump/tcpslice/search.c2
-rw-r--r--contrib/tcpdump/tcpslice/tcpslice.12
-rw-r--r--contrib/tcpdump/tcpslice/tcpslice.c2
-rw-r--r--contrib/xntpd/COPYRIGHT58
-rw-r--r--contrib/xntpd/Makefile8
-rw-r--r--contrib/xntpd/Makefile.inc7
-rw-r--r--contrib/xntpd/PORTING37
-rw-r--r--contrib/xntpd/README154
-rw-r--r--contrib/xntpd/README.FreeBSD10
-rw-r--r--contrib/xntpd/RELNOTES208
-rw-r--r--contrib/xntpd/TODO26
-rw-r--r--contrib/xntpd/VERSION1
-rw-r--r--contrib/xntpd/adjtime/.keep_me0
-rw-r--r--contrib/xntpd/authstuff/Makefile27
-rw-r--r--contrib/xntpd/authstuff/README13
-rw-r--r--contrib/xntpd/authstuff/auth.samplekeys45
-rw-r--r--contrib/xntpd/authstuff/auth.speed20
-rw-r--r--contrib/xntpd/authstuff/authcert.c96
-rw-r--r--contrib/xntpd/authstuff/authspeed.c315
-rw-r--r--contrib/xntpd/authstuff/certdata34
-rw-r--r--contrib/xntpd/authstuff/keyparity.c279
-rw-r--r--contrib/xntpd/authstuff/makeIPFP.c345
-rw-r--r--contrib/xntpd/authstuff/makePC1.c286
-rw-r--r--contrib/xntpd/authstuff/makePC2.c238
-rw-r--r--contrib/xntpd/authstuff/makeSP.c183
-rw-r--r--contrib/xntpd/authstuff/md5_sample_output8
-rw-r--r--contrib/xntpd/authstuff/md5driver.c211
-rw-r--r--contrib/xntpd/authstuff/mkrandkeys.c167
-rw-r--r--contrib/xntpd/authstuff/omakeIPFP.c361
-rw-r--r--contrib/xntpd/authstuff/results2
-rw-r--r--contrib/xntpd/authstuff/unixcert.c156
-rw-r--r--contrib/xntpd/clockstuff/Makefile16
-rw-r--r--contrib/xntpd/clockstuff/README31
-rw-r--r--contrib/xntpd/clockstuff/chutest.c798
-rw-r--r--contrib/xntpd/clockstuff/clktest.c511
-rw-r--r--contrib/xntpd/clockstuff/propdelay.c536
-rw-r--r--contrib/xntpd/compilers/.keep_me0
-rw-r--r--contrib/xntpd/conf/Config.CHATHAM211
-rw-r--r--contrib/xntpd/conf/Config.MONOMOY186
-rw-r--r--contrib/xntpd/conf/Config.TIGER182
-rw-r--r--contrib/xntpd/conf/Config.TRURO202
-rw-r--r--contrib/xntpd/conf/Config.dartnet187
-rw-r--r--contrib/xntpd/conf/Config.local190
-rw-r--r--contrib/xntpd/conf/Config.svr4167
-rw-r--r--contrib/xntpd/conf/README8
-rw-r--r--contrib/xntpd/conf/dewey.conf38
-rw-r--r--contrib/xntpd/conf/grundoon.conf58
-rw-r--r--contrib/xntpd/conf/malarky.conf40
-rw-r--r--contrib/xntpd/conf/ntp.conf.gw34
-rw-r--r--contrib/xntpd/conf/ntp.conf.ipl32
-rw-r--r--contrib/xntpd/conf/ntp.conf.nsf156
-rw-r--r--contrib/xntpd/conf/ntp.conf.shiningtree32
-rw-r--r--contrib/xntpd/conf/ntp.conf.suzuki43
-rw-r--r--contrib/xntpd/conf/pogo.conf50
-rw-r--r--contrib/xntpd/conf/rackety.conf75
-rw-r--r--contrib/xntpd/conf/snow-white.conf33
-rw-r--r--contrib/xntpd/doc/README.irig306
-rw-r--r--contrib/xntpd/doc/README.kern775
-rw-r--r--contrib/xntpd/doc/README.magic346
-rw-r--r--contrib/xntpd/doc/UofT146
-rw-r--r--contrib/xntpd/doc/notes.txt1258
-rw-r--r--contrib/xntpd/doc/ntpdate.8185
-rw-r--r--contrib/xntpd/doc/ntpq.8566
-rw-r--r--contrib/xntpd/doc/ntptrace.8104
-rw-r--r--contrib/xntpd/doc/tickadj.8143
-rw-r--r--contrib/xntpd/doc/xntpd.81479
-rw-r--r--contrib/xntpd/doc/xntpdc.8686
-rw-r--r--contrib/xntpd/gadget/.keep_me0
-rw-r--r--contrib/xntpd/hints/.keep_me0
-rw-r--r--contrib/xntpd/include/README6
-rw-r--r--contrib/xntpd/include/l_stdlib.h234
-rw-r--r--contrib/xntpd/include/md5.h56
-rw-r--r--contrib/xntpd/include/mx4200.h42
-rw-r--r--contrib/xntpd/include/ntp.h682
-rw-r--r--contrib/xntpd/include/ntp_calendar.h80
-rw-r--r--contrib/xntpd/include/ntp_control.h252
-rw-r--r--contrib/xntpd/include/ntp_filegen.h51
-rw-r--r--contrib/xntpd/include/ntp_fp.h315
-rw-r--r--contrib/xntpd/include/ntp_if.h43
-rw-r--r--contrib/xntpd/include/ntp_io.h24
-rw-r--r--contrib/xntpd/include/ntp_machine.h622
-rw-r--r--contrib/xntpd/include/ntp_malloc.h15
-rw-r--r--contrib/xntpd/include/ntp_refclock.h142
-rw-r--r--contrib/xntpd/include/ntp_request.h713
-rw-r--r--contrib/xntpd/include/ntp_select.h20
-rw-r--r--contrib/xntpd/include/ntp_stdlib.h92
-rw-r--r--contrib/xntpd/include/ntp_string.h35
-rw-r--r--contrib/xntpd/include/ntp_syslog.h15
-rw-r--r--contrib/xntpd/include/ntp_timex.h158
-rw-r--r--contrib/xntpd/include/ntp_types.h60
-rw-r--r--contrib/xntpd/include/ntp_unixtime.h119
-rw-r--r--contrib/xntpd/include/ntpd.h171
-rw-r--r--contrib/xntpd/include/parse.h407
-rw-r--r--contrib/xntpd/include/parse_conf.h54
-rw-r--r--contrib/xntpd/include/sys/bsd_audioirig.h101
-rw-r--r--contrib/xntpd/include/sys/chudefs.h22
-rw-r--r--contrib/xntpd/include/sys/clkdefs.h31
-rw-r--r--contrib/xntpd/include/sys/parsestreams.h66
-rw-r--r--contrib/xntpd/include/sys/ppsclock.h59
-rw-r--r--contrib/xntpd/include/sys/tpro.h34
-rw-r--r--contrib/xntpd/kernel/.keep_me0
-rw-r--r--contrib/xntpd/kernel/README.kern596
-rw-r--r--contrib/xntpd/lib/Makefile30
-rw-r--r--contrib/xntpd/lib/README5
-rw-r--r--contrib/xntpd/lib/a_md512crypt.c87
-rw-r--r--contrib/xntpd/lib/a_md5decrypt.c60
-rw-r--r--contrib/xntpd/lib/a_md5encrypt.c70
-rw-r--r--contrib/xntpd/lib/adjtimex.c15
-rw-r--r--contrib/xntpd/lib/atoint.c48
-rw-r--r--contrib/xntpd/lib/atolfp.c117
-rw-r--r--contrib/xntpd/lib/atouint.c33
-rw-r--r--contrib/xntpd/lib/auth12crypt.c125
-rw-r--r--contrib/xntpd/lib/authdecrypt.c85
-rw-r--r--contrib/xntpd/lib/authdes.c.desbin0 -> 35168 bytes
-rw-r--r--contrib/xntpd/lib/authdes.c.export41
-rw-r--r--contrib/xntpd/lib/authencrypt.c88
-rw-r--r--contrib/xntpd/lib/authkeys.c602
-rw-r--r--contrib/xntpd/lib/authparity.c58
-rw-r--r--contrib/xntpd/lib/authreadkeys.c191
-rw-r--r--contrib/xntpd/lib/authusekey.c132
-rw-r--r--contrib/xntpd/lib/buftvtots.c61
-rw-r--r--contrib/xntpd/lib/caljulian.c105
-rw-r--r--contrib/xntpd/lib/calleapwhen.c61
-rw-r--r--contrib/xntpd/lib/caltontp.c90
-rw-r--r--contrib/xntpd/lib/calyearstart.c62
-rw-r--r--contrib/xntpd/lib/clocktime.c131
-rw-r--r--contrib/xntpd/lib/clocktypes.c46
-rw-r--r--contrib/xntpd/lib/decodenetnum.c58
-rw-r--r--contrib/xntpd/lib/dofptoa.c117
-rw-r--r--contrib/xntpd/lib/dolfptoa.c162
-rw-r--r--contrib/xntpd/lib/emalloc.c20
-rwxr-xr-xcontrib/xntpd/lib/findconfig.c62
-rw-r--r--contrib/xntpd/lib/fptoa.c24
-rw-r--r--contrib/xntpd/lib/fptoms.c23
-rw-r--r--contrib/xntpd/lib/getopt.c105
-rw-r--r--contrib/xntpd/lib/gettstamp.c29
-rw-r--r--contrib/xntpd/lib/hextoint.c38
-rw-r--r--contrib/xntpd/lib/hextolfp.c66
-rw-r--r--contrib/xntpd/lib/humandate.c61
-rw-r--r--contrib/xntpd/lib/inttoa.c19
-rw-r--r--contrib/xntpd/lib/lib_strbuf.c21
-rw-r--r--contrib/xntpd/lib/lib_strbuf.h22
-rw-r--r--contrib/xntpd/lib/machines.c43
-rw-r--r--contrib/xntpd/lib/md5.c322
-rw-r--r--contrib/xntpd/lib/mfptoa.c22
-rw-r--r--contrib/xntpd/lib/mfptoms.c22
-rw-r--r--contrib/xntpd/lib/modetoa.c33
-rw-r--r--contrib/xntpd/lib/mstolfp.c99
-rw-r--r--contrib/xntpd/lib/msutotsf.c35
-rw-r--r--contrib/xntpd/lib/msyslog.c108
-rw-r--r--contrib/xntpd/lib/numtoa.c24
-rw-r--r--contrib/xntpd/lib/numtohost.c39
-rw-r--r--contrib/xntpd/lib/octtoint.c34
-rw-r--r--contrib/xntpd/lib/prettydate.c44
-rw-r--r--contrib/xntpd/lib/ranny.c97
-rw-r--r--contrib/xntpd/lib/refnumtoa.c34
-rw-r--r--contrib/xntpd/lib/syssignal.c45
-rw-r--r--contrib/xntpd/lib/systime.c375
-rw-r--r--contrib/xntpd/lib/tsftomsu.c37
-rw-r--r--contrib/xntpd/lib/tstotod.c21
-rw-r--r--contrib/xntpd/lib/tstotv.c135
-rw-r--r--contrib/xntpd/lib/tvtoa.c33
-rw-r--r--contrib/xntpd/lib/tvtots.c159
-rw-r--r--contrib/xntpd/lib/uglydate.c53
-rw-r--r--contrib/xntpd/lib/uinttoa.c19
-rw-r--r--contrib/xntpd/lib/utvtoa.c21
-rw-r--r--contrib/xntpd/machines/.keep_me0
-rw-r--r--contrib/xntpd/ntpdate/Makefile28
-rw-r--r--contrib/xntpd/ntpdate/README7
-rw-r--r--contrib/xntpd/ntpdate/ntpdate.c1590
-rw-r--r--contrib/xntpd/ntpdate/ntpdate.h86
-rw-r--r--contrib/xntpd/ntpq/Makefile29
-rw-r--r--contrib/xntpd/ntpq/README6
-rw-r--r--contrib/xntpd/ntpq/ntpq.c3063
-rw-r--r--contrib/xntpd/ntpq/ntpq.h97
-rw-r--r--contrib/xntpd/ntpq/ntpq_ops.c1601
-rw-r--r--contrib/xntpd/ntptrace/Makefile28
-rw-r--r--contrib/xntpd/ntptrace/README7
-rw-r--r--contrib/xntpd/ntptrace/ntptrace.c777
-rw-r--r--contrib/xntpd/ntptrace/ntptrace.h36
-rw-r--r--contrib/xntpd/parse/Makefile19
-rw-r--r--contrib/xntpd/parse/README100
-rw-r--r--contrib/xntpd/parse/README.parse142
-rw-r--r--contrib/xntpd/parse/clk_dcf7000.c142
-rw-r--r--contrib/xntpd/parse/clk_meinberg.c450
-rw-r--r--contrib/xntpd/parse/clk_rawdcf.c559
-rw-r--r--contrib/xntpd/parse/clk_schmid.c201
-rw-r--r--contrib/xntpd/parse/clk_trimble.c134
-rw-r--r--contrib/xntpd/parse/empty.c7
-rw-r--r--contrib/xntpd/parse/parse.c1208
-rw-r--r--contrib/xntpd/parse/parse_conf.c123
-rw-r--r--contrib/xntpd/parse/parsesolaris.c1209
-rw-r--r--contrib/xntpd/parse/parsestreams.c1294
-rw-r--r--contrib/xntpd/parse/util/Makefile.tmpl49
-rw-r--r--contrib/xntpd/parse/util/README12
-rw-r--r--contrib/xntpd/parse/util/dcfd.c1583
-rw-r--r--contrib/xntpd/parse/util/parsetest.c268
-rw-r--r--contrib/xntpd/parse/util/testdcf.c485
-rw-r--r--contrib/xntpd/ppsclock/ppstest/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/genassym/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/os/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sun/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sun4c/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sun4c/conf/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sun4m/conf/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sundev/.keep_me0
-rw-r--r--contrib/xntpd/ppsclock/sys/sys/.keep_me0
-rw-r--r--contrib/xntpd/refclocks/Dependencies30
-rw-r--r--contrib/xntpd/refclocks/README4
-rwxr-xr-xcontrib/xntpd/refclocks/check2
-rwxr-xr-xcontrib/xntpd/refclocks/echon2
-rwxr-xr-xcontrib/xntpd/refclocks/query11
-rw-r--r--contrib/xntpd/refclocks/rclk.AS220129
-rw-r--r--contrib/xntpd/refclocks/rclk.CHU24
-rw-r--r--contrib/xntpd/refclocks/rclk.GOES32
-rw-r--r--contrib/xntpd/refclocks/rclk.GPSTM33
-rw-r--r--contrib/xntpd/refclocks/rclk.IRIG24
-rw-r--r--contrib/xntpd/refclocks/rclk.LEITCH29
-rw-r--r--contrib/xntpd/refclocks/rclk.LOCAL_CLOCK22
-rw-r--r--contrib/xntpd/refclocks/rclk.MSFEES26
-rw-r--r--contrib/xntpd/refclocks/rclk.MX420027
-rw-r--r--contrib/xntpd/refclocks/rclk.OMEGA29
-rw-r--r--contrib/xntpd/refclocks/rclk.PARSE51
-rw-r--r--contrib/xntpd/refclocks/rclk.PST37
-rw-r--r--contrib/xntpd/refclocks/rclk.TPRO24
-rw-r--r--contrib/xntpd/refclocks/rclk.WWVB38
-rw-r--r--contrib/xntpd/refclocks/rconfig119
-rw-r--r--contrib/xntpd/refclocks/setup16
-rw-r--r--contrib/xntpd/refclocks/setupfn27
-rwxr-xr-xcontrib/xntpd/scripts/Guess.sh122
-rw-r--r--contrib/xntpd/scripts/README41
-rwxr-xr-xcontrib/xntpd/scripts/autoconf885
-rwxr-xr-xcontrib/xntpd/scripts/install.sh100
-rwxr-xr-xcontrib/xntpd/scripts/makeconfig.sh85
-rwxr-xr-xcontrib/xntpd/scripts/mklinks9
-rwxr-xr-xcontrib/xntpd/scripts/mkversion36
-rw-r--r--contrib/xntpd/scripts/monitoring/README154
-rw-r--r--contrib/xntpd/scripts/monitoring/loopwatch.config.SAMPLE89
-rwxr-xr-xcontrib/xntpd/scripts/monitoring/lr.pl145
-rwxr-xr-xcontrib/xntpd/scripts/monitoring/ntp.pl477
-rwxr-xr-xcontrib/xntpd/scripts/monitoring/ntploopstat457
-rwxr-xr-xcontrib/xntpd/scripts/monitoring/ntploopwatch1631
-rwxr-xr-xcontrib/xntpd/scripts/monitoring/ntptrap453
-rwxr-xr-xcontrib/xntpd/scripts/monitoring/timelocal.pl77
-rwxr-xr-xcontrib/xntpd/scripts/ntp-groper95
-rwxr-xr-xcontrib/xntpd/scripts/ntp-restart9
-rw-r--r--contrib/xntpd/scripts/stats/README32
-rw-r--r--contrib/xntpd/scripts/stats/README.stats246
-rw-r--r--contrib/xntpd/scripts/stats/README.timecodes149
-rw-r--r--contrib/xntpd/scripts/stats/clock.awk341
-rwxr-xr-xcontrib/xntpd/scripts/stats/clock.sh17
-rw-r--r--contrib/xntpd/scripts/stats/dupe.awk7
-rw-r--r--contrib/xntpd/scripts/stats/ensemble.awk17
-rw-r--r--contrib/xntpd/scripts/stats/etf.awk19
-rw-r--r--contrib/xntpd/scripts/stats/itf.awk19
-rw-r--r--contrib/xntpd/scripts/stats/loop.awk49
-rwxr-xr-xcontrib/xntpd/scripts/stats/loop.sh13
-rw-r--r--contrib/xntpd/scripts/stats/peer.awk57
-rwxr-xr-xcontrib/xntpd/scripts/stats/peer.sh13
-rw-r--r--contrib/xntpd/scripts/stats/psummary.awk41
-rwxr-xr-xcontrib/xntpd/scripts/stats/summary.sh17
-rw-r--r--contrib/xntpd/scripts/stats/tdata.awk45
-rw-r--r--contrib/xntpd/scripts/support/README73
-rwxr-xr-xcontrib/xntpd/scripts/support/bin/monl212
-rwxr-xr-xcontrib/xntpd/scripts/support/bin/mvstats23
-rw-r--r--contrib/xntpd/scripts/support/conf/hp300.hp30070
-rw-r--r--contrib/xntpd/scripts/support/conf/hp700.hp70067
-rw-r--r--contrib/xntpd/scripts/support/conf/hp700.hp700.faui4771
-rw-r--r--contrib/xntpd/scripts/support/conf/hp800.hp80070
-rw-r--r--contrib/xntpd/scripts/support/conf/ntp.conf36
-rw-r--r--contrib/xntpd/scripts/support/conf/ntp.keys0
-rw-r--r--contrib/xntpd/scripts/support/conf/ntp.keys.dumb0
-rw-r--r--contrib/xntpd/scripts/support/conf/sun3.sun336
-rw-r--r--contrib/xntpd/scripts/support/conf/sun4.sun4.faui0183
-rw-r--r--contrib/xntpd/scripts/support/conf/sun4.sun4.faui10176
-rw-r--r--contrib/xntpd/scripts/support/conf/sun4.sun4.faui45228
-rw-r--r--contrib/xntpd/scripts/support/conf/sun4.sun4c63
-rw-r--r--contrib/xntpd/scripts/support/conf/sun4.sun4c.Lucifer174
-rw-r--r--contrib/xntpd/scripts/support/conf/sun4.sun4m69
-rw-r--r--contrib/xntpd/scripts/support/conf/sun4.sun4m.faui42152
-rw-r--r--contrib/xntpd/scripts/support/conf/sun4.sun4m.faui45m165
-rw-r--r--contrib/xntpd/scripts/support/conf/tickconf19
-rwxr-xr-xcontrib/xntpd/scripts/support/etc/cron18
-rw-r--r--contrib/xntpd/scripts/support/etc/crontab8
-rwxr-xr-xcontrib/xntpd/scripts/support/etc/install67
-rwxr-xr-xcontrib/xntpd/scripts/support/etc/rc198
-rwxr-xr-xcontrib/xntpd/scripts/support/etc/setup72
-rw-r--r--contrib/xntpd/util/Makefile28
-rw-r--r--contrib/xntpd/util/README67
-rw-r--r--contrib/xntpd/util/byteorder.c52
-rw-r--r--contrib/xntpd/util/jitter.c73
-rw-r--r--contrib/xntpd/util/kern.c210
-rw-r--r--contrib/xntpd/util/longsize.c11
-rw-r--r--contrib/xntpd/util/ntptime.c220
-rw-r--r--contrib/xntpd/util/precision.c81
-rw-r--r--contrib/xntpd/util/testrs6000.c44
-rw-r--r--contrib/xntpd/util/tickadj.c515
-rw-r--r--contrib/xntpd/util/timetrim.c85
-rw-r--r--contrib/xntpd/xntpd/Makefile45
-rw-r--r--contrib/xntpd/xntpd/README6
-rw-r--r--contrib/xntpd/xntpd/ntp_config.c1878
-rw-r--r--contrib/xntpd/xntpd/ntp_control.c2658
-rw-r--r--contrib/xntpd/xntpd/ntp_filegen.c536
-rw-r--r--contrib/xntpd/xntpd/ntp_intres.c793
-rw-r--r--contrib/xntpd/xntpd/ntp_io.c1616
-rw-r--r--contrib/xntpd/xntpd/ntp_leap.c315
-rw-r--r--contrib/xntpd/xntpd/ntp_loopfilter.c948
-rw-r--r--contrib/xntpd/xntpd/ntp_monitor.c306
-rw-r--r--contrib/xntpd/xntpd/ntp_peer.c639
-rw-r--r--contrib/xntpd/xntpd/ntp_proto.c2168
-rw-r--r--contrib/xntpd/xntpd/ntp_refclock.c439
-rw-r--r--contrib/xntpd/xntpd/ntp_request.c2341
-rw-r--r--contrib/xntpd/xntpd/ntp_restrict.c297
-rw-r--r--contrib/xntpd/xntpd/ntp_timer.c187
-rw-r--r--contrib/xntpd/xntpd/ntp_unixclock.c568
-rw-r--r--contrib/xntpd/xntpd/ntp_util.c466
-rw-r--r--contrib/xntpd/xntpd/ntpd.c439
-rw-r--r--contrib/xntpd/xntpd/refclock_as2201.c995
-rw-r--r--contrib/xntpd/xntpd/refclock_chu.c1140
-rw-r--r--contrib/xntpd/xntpd/refclock_conf.c128
-rw-r--r--contrib/xntpd/xntpd/refclock_goes.c1013
-rw-r--r--contrib/xntpd/xntpd/refclock_gpstm.c1015
-rw-r--r--contrib/xntpd/xntpd/refclock_irig.c566
-rw-r--r--contrib/xntpd/xntpd/refclock_leitch.c704
-rw-r--r--contrib/xntpd/xntpd/refclock_local.c307
-rw-r--r--contrib/xntpd/xntpd/refclock_msfees.c1572
-rw-r--r--contrib/xntpd/xntpd/refclock_mx4200.c1361
-rw-r--r--contrib/xntpd/xntpd/refclock_omega.c1019
-rw-r--r--contrib/xntpd/xntpd/refclock_parse.c3538
-rw-r--r--contrib/xntpd/xntpd/refclock_pst.c1804
-rw-r--r--contrib/xntpd/xntpd/refclock_tpro.c498
-rw-r--r--contrib/xntpd/xntpd/refclock_wwvb.c1045
-rw-r--r--contrib/xntpd/xntpdc/Makefile28
-rw-r--r--contrib/xntpd/xntpdc/README6
-rw-r--r--contrib/xntpd/xntpdc/ntpdc.c1536
-rw-r--r--contrib/xntpd/xntpdc/ntpdc.h59
-rw-r--r--contrib/xntpd/xntpdc/ntpdc_ops.c2421
-rw-r--r--contrib/xntpd/xntpres/Makefile28
-rw-r--r--contrib/xntpd/xntpres/README6
-rw-r--r--contrib/xntpd/xntpres/xntpres.c846
391 files changed, 87270 insertions, 59 deletions
diff --git a/contrib/Makefile b/contrib/Makefile
index c272cb933a41..c1625896c8f4 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -1,6 +1,6 @@
-# @(#)Makefile 0.1 (RGrimes) 4/7/93
+# $Id: Makefile,v 1.3 1993/12/21 21:18:14 wollman Exp $
-SUBDIR= tcpdump
+SUBDIR= tcpdump xntpd
# Not ported: isode
diff --git a/contrib/tcpdump/tcpdump/addrtoname.c b/contrib/tcpdump/tcpdump/addrtoname.c
index 435eb0d2e751..29974a5452e4 100644
--- a/contrib/tcpdump/tcpdump/addrtoname.c
+++ b/contrib/tcpdump/tcpdump/addrtoname.c
@@ -23,7 +23,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/addrtoname.c,v 1.1.1.1 1993/06/12 14:42:14 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/addrtoname.c,v 1.1.1.1 1993/06/12 14:42:14 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/addrtoname.h b/contrib/tcpdump/tcpdump/addrtoname.h
index 9eee4f369ab1..723134a7c877 100644
--- a/contrib/tcpdump/tcpdump/addrtoname.h
+++ b/contrib/tcpdump/tcpdump/addrtoname.h
@@ -18,7 +18,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/addrtoname.h,v 1.1.1.1 1993/06/12 14:42:14 rgrimes Exp $ (LBL)
+ * @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/addrtoname.h,v 1.1.1.1 1993/06/12 14:42:14 rgrimes Exp $ (LBL)
*/
/* Name to address translation routines. */
diff --git a/contrib/tcpdump/tcpdump/appletalk.h b/contrib/tcpdump/tcpdump/appletalk.h
index 48777662f129..2b3c23e44809 100644
--- a/contrib/tcpdump/tcpdump/appletalk.h
+++ b/contrib/tcpdump/tcpdump/appletalk.h
@@ -20,7 +20,7 @@
*
* AppleTalk protocol formats (courtesy Bill Croft of Stanford/SUMEX).
*
- * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/appletalk.h,v 1.1.1.1 1993/06/12 14:42:14 rgrimes Exp $ (LBL)
+ * @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/appletalk.h,v 1.1.1.1 1993/06/12 14:42:14 rgrimes Exp $ (LBL)
*/
/* Datagram Delivery Protocol */
diff --git a/contrib/tcpdump/tcpdump/bootp.h b/contrib/tcpdump/tcpdump/bootp.h
index 45bc1a30bdd1..61111ebbfd3e 100644
--- a/contrib/tcpdump/tcpdump/bootp.h
+++ b/contrib/tcpdump/tcpdump/bootp.h
@@ -1,4 +1,4 @@
-/* @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/bootp.h,v 1.1.1.1 1993/06/12 14:42:14 rgrimes Exp $ (LBL) */
+/* @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/bootp.h,v 1.1.1.1 1993/06/12 14:42:14 rgrimes Exp $ (LBL) */
/*
* Bootstrap Protocol (BOOTP). RFC951 and RFC1048.
*
diff --git a/contrib/tcpdump/tcpdump/bpf_dump.c b/contrib/tcpdump/tcpdump/bpf_dump.c
index 18089605d4ec..b5b1cecbb95d 100644
--- a/contrib/tcpdump/tcpdump/bpf_dump.c
+++ b/contrib/tcpdump/tcpdump/bpf_dump.c
@@ -20,7 +20,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/bpf_dump.c,v 1.1.1.1 1993/06/12 14:42:14 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/bpf_dump.c,v 1.1.1.1 1993/06/12 14:42:14 rgrimes Exp $ (LBL)";
#endif
#include <sys/types.h>
diff --git a/contrib/tcpdump/tcpdump/bpf_image.c b/contrib/tcpdump/tcpdump/bpf_image.c
index 25b9511e7d3d..c49636d17950 100644
--- a/contrib/tcpdump/tcpdump/bpf_image.c
+++ b/contrib/tcpdump/tcpdump/bpf_image.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/bpf_image.c,v 1.1.1.1 1993/06/12 14:42:13 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/bpf_image.c,v 1.1.1.1 1993/06/12 14:42:13 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/etherent.c b/contrib/tcpdump/tcpdump/etherent.c
index f1d0f0bd26c0..55b70d29d4df 100644
--- a/contrib/tcpdump/tcpdump/etherent.c
+++ b/contrib/tcpdump/tcpdump/etherent.c
@@ -20,7 +20,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/etherent.c,v 1.1.1.1 1993/06/12 14:42:13 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/etherent.c,v 1.1.1.1 1993/06/12 14:42:13 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/etherent.h b/contrib/tcpdump/tcpdump/etherent.h
index 352ff5e4a2ae..540a6ee14d78 100644
--- a/contrib/tcpdump/tcpdump/etherent.h
+++ b/contrib/tcpdump/tcpdump/etherent.h
@@ -18,7 +18,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/etherent.h,v 1.1.1.1 1993/06/12 14:42:13 rgrimes Exp $ (LBL)
+ * @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/etherent.h,v 1.1.1.1 1993/06/12 14:42:13 rgrimes Exp $ (LBL)
*/
/* File name of ethernet address data base. */
diff --git a/contrib/tcpdump/tcpdump/etherproto.h b/contrib/tcpdump/tcpdump/etherproto.h
index 2b57e8278927..840548306ddf 100644
--- a/contrib/tcpdump/tcpdump/etherproto.h
+++ b/contrib/tcpdump/tcpdump/etherproto.h
@@ -18,7 +18,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/etherproto.h,v 1.1.1.1 1993/06/12 14:42:13 rgrimes Exp $ (LBL)
+ * @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/etherproto.h,v 1.1.1.1 1993/06/12 14:42:13 rgrimes Exp $ (LBL)
*/
/* Map between Ethernet protocol types and names */
diff --git a/contrib/tcpdump/tcpdump/extract.h b/contrib/tcpdump/tcpdump/extract.h
index d8e88bb86eff..090d696190ec 100644
--- a/contrib/tcpdump/tcpdump/extract.h
+++ b/contrib/tcpdump/tcpdump/extract.h
@@ -18,7 +18,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/extract.h,v 1.1.1.1 1993/06/12 14:42:13 rgrimes Exp $ (LBL)
+ * @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/extract.h,v 1.1.1.1 1993/06/12 14:42:13 rgrimes Exp $ (LBL)
*/
#ifdef TCPDUMP_ALIGN
diff --git a/contrib/tcpdump/tcpdump/gencode.c b/contrib/tcpdump/tcpdump/gencode.c
index 74bbc8340e35..6bfd09d42f7e 100644
--- a/contrib/tcpdump/tcpdump/gencode.c
+++ b/contrib/tcpdump/tcpdump/gencode.c
@@ -20,7 +20,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/gencode.c,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/gencode.c,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)";
#endif
#ifdef __STDC__
diff --git a/contrib/tcpdump/tcpdump/gencode.h b/contrib/tcpdump/tcpdump/gencode.h
index 7444f48a63c9..190eacdc614f 100644
--- a/contrib/tcpdump/tcpdump/gencode.h
+++ b/contrib/tcpdump/tcpdump/gencode.h
@@ -18,7 +18,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/gencode.h,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)
+ * @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/gencode.h,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)
*/
/*
diff --git a/contrib/tcpdump/tcpdump/inet.c b/contrib/tcpdump/tcpdump/inet.c
index 99e12f0bea08..dc0ec267b124 100644
--- a/contrib/tcpdump/tcpdump/inet.c
+++ b/contrib/tcpdump/tcpdump/inet.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/inet.c,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/inet.c,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/interface.h b/contrib/tcpdump/tcpdump/interface.h
index 88a5bafbb9c3..c3ef7046caf5 100644
--- a/contrib/tcpdump/tcpdump/interface.h
+++ b/contrib/tcpdump/tcpdump/interface.h
@@ -18,7 +18,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/interface.h,v 1.2 1993/08/29 01:59:05 rgrimes Exp $ (LBL)
+ * @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/interface.h,v 1.2 1993/08/29 01:59:05 rgrimes Exp $ (LBL)
*/
#ifdef __GNUC__
diff --git a/contrib/tcpdump/tcpdump/md.c b/contrib/tcpdump/tcpdump/md.c
index 7a823bb73fc7..0e88001dd34d 100644
--- a/contrib/tcpdump/tcpdump/md.c
+++ b/contrib/tcpdump/tcpdump/md.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/md.c,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/md.c,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)";
#endif
/* Vaxen appear to have clocks accurate to 1 us,
diff --git a/contrib/tcpdump/tcpdump/md.h b/contrib/tcpdump/tcpdump/md.h
index d77644b032b8..2b7b959e888e 100644
--- a/contrib/tcpdump/tcpdump/md.h
+++ b/contrib/tcpdump/tcpdump/md.h
@@ -18,7 +18,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/md.h,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)
+ * @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/md.h,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)
*/
#ifndef BYTE_ORDER
diff --git a/contrib/tcpdump/tcpdump/nametoaddr.c b/contrib/tcpdump/tcpdump/nametoaddr.c
index 3cbd7190daf6..5b0372af6b7a 100644
--- a/contrib/tcpdump/tcpdump/nametoaddr.c
+++ b/contrib/tcpdump/tcpdump/nametoaddr.c
@@ -24,7 +24,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/nametoaddr.c,v 1.1.1.1 1993/06/12 14:42:11 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/nametoaddr.c,v 1.1.1.1 1993/06/12 14:42:11 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/nametoaddr.h b/contrib/tcpdump/tcpdump/nametoaddr.h
index 1902c9197d71..af771d97e474 100644
--- a/contrib/tcpdump/tcpdump/nametoaddr.h
+++ b/contrib/tcpdump/tcpdump/nametoaddr.h
@@ -18,7 +18,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/nametoaddr.h,v 1.1.1.1 1993/06/12 14:42:11 rgrimes Exp $ (LBL)
+ * @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/nametoaddr.h,v 1.1.1.1 1993/06/12 14:42:11 rgrimes Exp $ (LBL)
*
* Address to name translation routines.
*/
diff --git a/contrib/tcpdump/tcpdump/ntp.h b/contrib/tcpdump/tcpdump/ntp.h
index 5a7d58b7a8b9..2459efdbe3fb 100644
--- a/contrib/tcpdump/tcpdump/ntp.h
+++ b/contrib/tcpdump/tcpdump/ntp.h
@@ -1,4 +1,4 @@
-/* $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/ntp.h,v 1.1.1.1 1993/06/12 14:42:11 rgrimes Exp $ */
+/* $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/ntp.h,v 1.1.1.1 1993/06/12 14:42:11 rgrimes Exp $ */
/*
* Based on ntp.h from the U of MD implementation
diff --git a/contrib/tcpdump/tcpdump/optimize.c b/contrib/tcpdump/tcpdump/optimize.c
index 37e7525a052a..ede6cd19e96b 100644
--- a/contrib/tcpdump/tcpdump/optimize.c
+++ b/contrib/tcpdump/tcpdump/optimize.c
@@ -22,7 +22,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/optimize.c,v 1.1.1.1 1993/06/12 14:42:10 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/optimize.c,v 1.1.1.1 1993/06/12 14:42:10 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/os.c b/contrib/tcpdump/tcpdump/os.c
index c805149f2bd3..d8f41764a326 100644
--- a/contrib/tcpdump/tcpdump/os.c
+++ b/contrib/tcpdump/tcpdump/os.c
@@ -21,6 +21,6 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/os.c,v 1.1.1.1 1993/06/12 14:42:10 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/os.c,v 1.1.1.1 1993/06/12 14:42:10 rgrimes Exp $ (LBL)";
#endif
diff --git a/contrib/tcpdump/tcpdump/os.h b/contrib/tcpdump/tcpdump/os.h
index ae6d7b0c3242..5ca2bc1e5dd0 100644
--- a/contrib/tcpdump/tcpdump/os.h
+++ b/contrib/tcpdump/tcpdump/os.h
@@ -18,7 +18,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/os.h,v 1.1.1.1 1993/06/12 14:42:10 rgrimes Exp $ (LBL)
+ * @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/os.h,v 1.1.1.1 1993/06/12 14:42:10 rgrimes Exp $ (LBL)
*/
#include <sys/param.h>
diff --git a/contrib/tcpdump/tcpdump/pcap.c b/contrib/tcpdump/tcpdump/pcap.c
index 3a4bc79aac62..8ad78667f184 100644
--- a/contrib/tcpdump/tcpdump/pcap.c
+++ b/contrib/tcpdump/tcpdump/pcap.c
@@ -20,7 +20,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/pcap.c,v 1.1.1.1 1993/06/12 14:42:10 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/pcap.c,v 1.1.1.1 1993/06/12 14:42:10 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/print-arp.c b/contrib/tcpdump/tcpdump/print-arp.c
index d5a3d26d934f..30ed0851cc33 100644
--- a/contrib/tcpdump/tcpdump/print-arp.c
+++ b/contrib/tcpdump/tcpdump/print-arp.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-arp.c,v 1.1.1.1 1993/06/12 14:42:10 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-arp.c,v 1.1.1.1 1993/06/12 14:42:10 rgrimes Exp $ (LBL)";
#endif
#include <sys/param.h>
diff --git a/contrib/tcpdump/tcpdump/print-atalk.c b/contrib/tcpdump/tcpdump/print-atalk.c
index 150e774372fc..e55e7652d8b1 100644
--- a/contrib/tcpdump/tcpdump/print-atalk.c
+++ b/contrib/tcpdump/tcpdump/print-atalk.c
@@ -22,7 +22,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-atalk.c,v 1.1.1.1 1993/06/12 14:42:09 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-atalk.c,v 1.1.1.1 1993/06/12 14:42:09 rgrimes Exp $ (LBL)";
#endif
#ifdef __STDC__
diff --git a/contrib/tcpdump/tcpdump/print-bootp.c b/contrib/tcpdump/tcpdump/print-bootp.c
index 215b2c699ab2..162c1bb81857 100644
--- a/contrib/tcpdump/tcpdump/print-bootp.c
+++ b/contrib/tcpdump/tcpdump/print-bootp.c
@@ -22,7 +22,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-bootp.c,v 1.1.1.1 1993/06/12 14:42:09 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-bootp.c,v 1.1.1.1 1993/06/12 14:42:09 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/print-domain.c b/contrib/tcpdump/tcpdump/print-domain.c
index 4d4e8c3cd777..a95e1b324da7 100644
--- a/contrib/tcpdump/tcpdump/print-domain.c
+++ b/contrib/tcpdump/tcpdump/print-domain.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-domain.c,v 1.1.1.1 1993/06/12 14:42:09 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-domain.c,v 1.1.1.1 1993/06/12 14:42:09 rgrimes Exp $ (LBL)";
#endif
#include <sys/param.h>
diff --git a/contrib/tcpdump/tcpdump/print-ether.c b/contrib/tcpdump/tcpdump/print-ether.c
index 00696cbdbf43..7d587ccdfd42 100644
--- a/contrib/tcpdump/tcpdump/print-ether.c
+++ b/contrib/tcpdump/tcpdump/print-ether.c
@@ -20,7 +20,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-ether.c,v 1.1.1.1 1993/06/12 14:42:09 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-ether.c,v 1.1.1.1 1993/06/12 14:42:09 rgrimes Exp $ (LBL)";
#endif
#include <sys/param.h>
diff --git a/contrib/tcpdump/tcpdump/print-fddi.c b/contrib/tcpdump/tcpdump/print-fddi.c
index c630729ac54d..7e2fc1925acc 100644
--- a/contrib/tcpdump/tcpdump/print-fddi.c
+++ b/contrib/tcpdump/tcpdump/print-fddi.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-fddi.c,v 1.1.1.1 1993/06/12 14:42:09 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-fddi.c,v 1.1.1.1 1993/06/12 14:42:09 rgrimes Exp $ (LBL)";
#endif
#ifdef FDDI
diff --git a/contrib/tcpdump/tcpdump/print-icmp.c b/contrib/tcpdump/tcpdump/print-icmp.c
index 9da444ab237e..4c799090476e 100644
--- a/contrib/tcpdump/tcpdump/print-icmp.c
+++ b/contrib/tcpdump/tcpdump/print-icmp.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-icmp.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-icmp.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/print-ip.c b/contrib/tcpdump/tcpdump/print-ip.c
index 4fd2a344c2bc..ec2989a970ae 100644
--- a/contrib/tcpdump/tcpdump/print-ip.c
+++ b/contrib/tcpdump/tcpdump/print-ip.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-ip.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-ip.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
#endif
#include <sys/param.h>
diff --git a/contrib/tcpdump/tcpdump/print-nfs.c b/contrib/tcpdump/tcpdump/print-nfs.c
index 406e696a1ad4..9a288166e11c 100644
--- a/contrib/tcpdump/tcpdump/print-nfs.c
+++ b/contrib/tcpdump/tcpdump/print-nfs.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-nfs.c,v 1.2 1993/09/15 20:27:23 jtc Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-nfs.c,v 1.2 1993/09/15 20:27:23 jtc Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/print-ntp.c b/contrib/tcpdump/tcpdump/print-ntp.c
index 29944802766c..9f39200015f1 100644
--- a/contrib/tcpdump/tcpdump/print-ntp.c
+++ b/contrib/tcpdump/tcpdump/print-ntp.c
@@ -25,7 +25,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-ntp.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-ntp.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/print-null.c b/contrib/tcpdump/tcpdump/print-null.c
index 26cab7d921ba..413e1fb8d46b 100644
--- a/contrib/tcpdump/tcpdump/print-null.c
+++ b/contrib/tcpdump/tcpdump/print-null.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-null.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-null.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/print-ospf.c b/contrib/tcpdump/tcpdump/print-ospf.c
index bb8425e455c1..ab4ddecd4c23 100644
--- a/contrib/tcpdump/tcpdump/print-ospf.c
+++ b/contrib/tcpdump/tcpdump/print-ospf.c
@@ -22,7 +22,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-ospf.c,v 1.1.1.1 1993/06/12 14:42:07 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-ospf.c,v 1.1.1.1 1993/06/12 14:42:07 rgrimes Exp $ (LBL)";
#endif
#include <sys/param.h>
diff --git a/contrib/tcpdump/tcpdump/print-ppp.c b/contrib/tcpdump/tcpdump/print-ppp.c
index 7ba3ed4902b9..dd45d75d324c 100644
--- a/contrib/tcpdump/tcpdump/print-ppp.c
+++ b/contrib/tcpdump/tcpdump/print-ppp.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-ppp.c,v 1.1.1.1 1993/06/12 14:42:07 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-ppp.c,v 1.1.1.1 1993/06/12 14:42:07 rgrimes Exp $ (LBL)";
#endif
#ifdef PPP
diff --git a/contrib/tcpdump/tcpdump/print-rip.c b/contrib/tcpdump/tcpdump/print-rip.c
index 26244500679c..60ed146a7c49 100644
--- a/contrib/tcpdump/tcpdump/print-rip.c
+++ b/contrib/tcpdump/tcpdump/print-rip.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-rip.c,v 1.1.1.1 1993/06/12 14:42:07 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-rip.c,v 1.3 1994/02/10 11:24:32 davidg Exp $ (LBL)";
#endif
#include <sys/param.h>
@@ -33,13 +33,39 @@ static char rcsid[] =
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
-#include <protocols/routed.h>
#include <errno.h>
#include "interface.h"
#include "addrtoname.h"
+#define RIPVERSION 1
+
+struct netinfo {
+ struct osockaddr rip_dst; /* destination net/host */
+ int rip_metric; /* cost of route */
+};
+
+struct rip {
+ u_char rip_cmd; /* request/response */
+ u_char rip_vers; /* protocol version # */
+ u_char rip_res1[2]; /* pad to 32-bit boundary */
+ union {
+ struct netinfo ru_nets[1]; /* variable length... */
+ char ru_tracefile[1]; /* ditto ... */
+ } ripun;
+#define rip_nets ripun.ru_nets
+#define rip_tracefile ripun.ru_tracefile
+};
+
+/*
+ * Packet types.
+ */
+#define RIPCMD_REQUEST 1 /* want info */
+#define RIPCMD_RESPONSE 2 /* responding to request */
+#define RIPCMD_TRACEON 3 /* turn tracing on */
+#define RIPCMD_TRACEOFF 4 /* turn it off */
+
static void
rip_entry_print(ni)
register struct netinfo *ni;
@@ -49,8 +75,8 @@ rip_entry_print(ni)
printf(" [family %d:", ntohs(ni->rip_dst.sa_family));
for (i = 0; i < 14; i += 2)
- printf(" %02x%02x", ni->rip_dst.sa_data[i],
- ni->rip_dst.sa_data[i+1]);
+ printf(" %02x%02x", (u_char)ni->rip_dst.sa_data[i],
+ (u_char)ni->rip_dst.sa_data[i+1]);
printf("]");
} else {
register struct sockaddr_in *sin =
diff --git a/contrib/tcpdump/tcpdump/print-sl.c b/contrib/tcpdump/tcpdump/print-sl.c
index 7e767009519a..ca4c14e3f218 100644
--- a/contrib/tcpdump/tcpdump/print-sl.c
+++ b/contrib/tcpdump/tcpdump/print-sl.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-sl.c,v 1.1.1.1 1993/06/12 14:42:07 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-sl.c,v 1.1.1.1 1993/06/12 14:42:07 rgrimes Exp $ (LBL)";
#endif
#ifdef CSLIP
diff --git a/contrib/tcpdump/tcpdump/print-sunrpc.c b/contrib/tcpdump/tcpdump/print-sunrpc.c
index a613b5ab89a3..18bcc5baed03 100644
--- a/contrib/tcpdump/tcpdump/print-sunrpc.c
+++ b/contrib/tcpdump/tcpdump/print-sunrpc.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-sunrpc.c,v 1.2 1993/09/15 20:27:24 jtc Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-sunrpc.c,v 1.2 1993/09/15 20:27:24 jtc Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/print-tcp.c b/contrib/tcpdump/tcpdump/print-tcp.c
index ec22110aa7c0..7dbf16373299 100644
--- a/contrib/tcpdump/tcpdump/print-tcp.c
+++ b/contrib/tcpdump/tcpdump/print-tcp.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-tcp.c,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-tcp.c,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $ (LBL)";
#endif
#include <sys/param.h>
diff --git a/contrib/tcpdump/tcpdump/print-tftp.c b/contrib/tcpdump/tcpdump/print-tftp.c
index b5f48b901c60..43b7e8d47d4d 100644
--- a/contrib/tcpdump/tcpdump/print-tftp.c
+++ b/contrib/tcpdump/tcpdump/print-tftp.c
@@ -22,7 +22,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-tftp.c,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-tftp.c,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/print-udp.c b/contrib/tcpdump/tcpdump/print-udp.c
index 2d97ca57fa08..9a61381b72a5 100644
--- a/contrib/tcpdump/tcpdump/print-udp.c
+++ b/contrib/tcpdump/tcpdump/print-udp.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-udp.c,v 1.2 1993/09/15 20:27:25 jtc Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-udp.c,v 1.2 1993/09/15 20:27:25 jtc Exp $ (LBL)";
#endif
#include <sys/param.h>
diff --git a/contrib/tcpdump/tcpdump/savefile.c b/contrib/tcpdump/tcpdump/savefile.c
index c46bedc19fdc..5df0a1d9535a 100644
--- a/contrib/tcpdump/tcpdump/savefile.c
+++ b/contrib/tcpdump/tcpdump/savefile.c
@@ -20,7 +20,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/savefile.c,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/savefile.c,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $ (LBL)";
#endif
/*
diff --git a/contrib/tcpdump/tcpdump/savefile.h b/contrib/tcpdump/tcpdump/savefile.h
index ea7e08dd767d..9f6811da2cfc 100644
--- a/contrib/tcpdump/tcpdump/savefile.h
+++ b/contrib/tcpdump/tcpdump/savefile.h
@@ -18,7 +18,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/savefile.h,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $
+ * $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/savefile.h,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $
*
* Header for offline storage info.
* Extraction/creation by Jeffrey Mogul, DECWRL.
diff --git a/contrib/tcpdump/tcpdump/tcpdump.1 b/contrib/tcpdump/tcpdump/tcpdump.1
index f1e7c13892ce..61148f494014 100644
--- a/contrib/tcpdump/tcpdump/tcpdump.1
+++ b/contrib/tcpdump/tcpdump/tcpdump.1
@@ -1,4 +1,4 @@
-.\" @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcpdump.1,v 1.1.1.1 1993/06/12 14:42:05 rgrimes Exp $ (LBL)
+.\" @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcpdump.1,v 1.1.1.1.2.1 1994/05/01 16:00:56 jkh Exp $ (LBL)
.\"
.\" Copyright (c) 1988, 1989, 1990, 1991, 1992
.\" The Regents of the University of California.
@@ -139,7 +139,7 @@ default of 68 (with NIT, the minimum is actually 96).
and UDP but may truncate protocol information from name server and NFS
packets (see below). Packets truncated because of a limited snapshot
are indicated in the output with ``[|\fIproto\fP]'', where \fIproto\fP
-is the name of the protocol level at which the truncation has occured.
+is the name of the protocol level at which the truncation has occurred.
Note that taking larger snapshots both increases
the amount of time it takes to process packets and, effectively,
decreases the amount of packet buffering. This may cause packets to be
diff --git a/contrib/tcpdump/tcpdump/tcpdump.c b/contrib/tcpdump/tcpdump/tcpdump.c
index 4360e655de16..70c60f0767d8 100644
--- a/contrib/tcpdump/tcpdump/tcpdump.c
+++ b/contrib/tcpdump/tcpdump/tcpdump.c
@@ -22,7 +22,7 @@
char copyright[] =
"@(#) Copyright (c) 1987-1990 The Regents of the University of California.\nAll rights reserved.\n";
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcpdump.c,v 1.1.1.1 1993/06/12 14:42:05 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcpdump.c,v 1.1.1.1 1993/06/12 14:42:05 rgrimes Exp $ (LBL)";
#endif
/*
diff --git a/contrib/tcpdump/tcpdump/tcpgram.y b/contrib/tcpdump/tcpdump/tcpgram.y
index 36577154ebc6..ea084540fcb6 100644
--- a/contrib/tcpdump/tcpdump/tcpgram.y
+++ b/contrib/tcpdump/tcpdump/tcpgram.y
@@ -23,7 +23,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcpgram.y,v 1.1.1.1 1993/06/12 14:42:05 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcpgram.y,v 1.1.1.1 1993/06/12 14:42:05 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpdump/tcplex.l b/contrib/tcpdump/tcpdump/tcplex.l
index 626180ecc38f..2e84a1585901 100644
--- a/contrib/tcpdump/tcpdump/tcplex.l
+++ b/contrib/tcpdump/tcpdump/tcplex.l
@@ -22,7 +22,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcplex.l,v 1.1.1.1 1993/06/12 14:42:05 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcplex.l,v 1.1.1.1 1993/06/12 14:42:05 rgrimes Exp $ (LBL)";
#endif
/*
diff --git a/contrib/tcpdump/tcpdump/util.c b/contrib/tcpdump/tcpdump/util.c
index a9313fab4f2f..7e005dad861e 100644
--- a/contrib/tcpdump/tcpdump/util.c
+++ b/contrib/tcpdump/tcpdump/util.c
@@ -21,7 +21,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/util.c,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $ (LBL)";
+ "@(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/util.c,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $ (LBL)";
#endif
#include <stdio.h>
diff --git a/contrib/tcpdump/tcpslice/gwtm2secs.c b/contrib/tcpdump/tcpslice/gwtm2secs.c
index ecae63f514e4..a7ca86ca5f98 100644
--- a/contrib/tcpdump/tcpslice/gwtm2secs.c
+++ b/contrib/tcpdump/tcpslice/gwtm2secs.c
@@ -20,7 +20,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpslice/gwtm2secs.c,v 1.1.1.1 1993/06/12 14:42:17 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpslice/gwtm2secs.c,v 1.1.1.1 1993/06/12 14:42:17 rgrimes Exp $ (LBL)";
#endif
/*
diff --git a/contrib/tcpdump/tcpslice/search.c b/contrib/tcpdump/tcpslice/search.c
index 9365dd13cbfc..0dc933d28ae5 100644
--- a/contrib/tcpdump/tcpslice/search.c
+++ b/contrib/tcpdump/tcpslice/search.c
@@ -20,7 +20,7 @@
*/
#ifndef lint
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpslice/search.c,v 1.1.1.1 1993/06/12 14:42:16 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpslice/search.c,v 1.1.1.1 1993/06/12 14:42:16 rgrimes Exp $ (LBL)";
#endif
/*
diff --git a/contrib/tcpdump/tcpslice/tcpslice.1 b/contrib/tcpdump/tcpslice/tcpslice.1
index 30ac6cbe4a17..92af935f2897 100644
--- a/contrib/tcpdump/tcpslice/tcpslice.1
+++ b/contrib/tcpdump/tcpslice/tcpslice.1
@@ -1,4 +1,4 @@
-.\" @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpslice/tcpslice.1,v 1.1.1.1 1993/06/12 14:42:16 rgrimes Exp $ (LBL)
+.\" @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpslice/tcpslice.1,v 1.1.1.1.2.1 1994/05/01 16:01:05 jkh Exp $ (LBL)
.\"
.\" Copyright (c) 1988-1990 The Regents of the University of California.
.\" All rights reserved.
diff --git a/contrib/tcpdump/tcpslice/tcpslice.c b/contrib/tcpdump/tcpslice/tcpslice.c
index fe6bfe35c1d5..5a9ba01bbbe6 100644
--- a/contrib/tcpdump/tcpslice/tcpslice.c
+++ b/contrib/tcpdump/tcpslice/tcpslice.c
@@ -22,7 +22,7 @@
char copyright[] =
"@(#) Copyright (c) 1987-1990 The Regents of the University of California.\nAll rights reserved.\n";
static char rcsid[] =
- "@(#)$Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpslice/tcpslice.c,v 1.1.1.1 1993/06/12 14:42:16 rgrimes Exp $ (LBL)";
+ "@(#)$Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpslice/tcpslice.c,v 1.1.1.1 1993/06/12 14:42:16 rgrimes Exp $ (LBL)";
#endif
/*
diff --git a/contrib/xntpd/COPYRIGHT b/contrib/xntpd/COPYRIGHT
new file mode 100644
index 000000000000..711a8f1efcb4
--- /dev/null
+++ b/contrib/xntpd/COPYRIGHT
@@ -0,0 +1,58 @@
+/******************************************************************************
+ * *
+ * Copyright (c) David L. Mills 1992, 1993, 1994 *
+ * *
+ * 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)
+ * Paul A Vixie <vixie@vix.com> (TrueTime GPS driver)
+ * Jim Jagielski <jim@jagubox.gsfc.nasa.gov> (A/UX port)
+*/
diff --git a/contrib/xntpd/Makefile b/contrib/xntpd/Makefile
new file mode 100644
index 000000000000..a51b83e67ed0
--- /dev/null
+++ b/contrib/xntpd/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for xntpd.
+# $Id: Makefile,v 1.3 1994/02/03 22:30:30 wollman Exp $
+#
+
+SUBDIR= lib parse xntpd xntpdc ntpq ntpdate ntptrace xntpres authstuff util
+
+.include <bsd.subdir.mk>
diff --git a/contrib/xntpd/Makefile.inc b/contrib/xntpd/Makefile.inc
new file mode 100644
index 000000000000..0983df967f72
--- /dev/null
+++ b/contrib/xntpd/Makefile.inc
@@ -0,0 +1,7 @@
+DEFS_LOCAL=-DREFCLOCK -DPARSE
+NTPDEFS= -DSYS_FREEBSD -DSYS_386BSD -DHAVE_TERMIOS
+AUTHDEFS= -DMD5
+CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DAS2201 -DGOES -DGPSTM -DOMEGA \
+ -DLEITCH
+CFLAGS+= ${NTPDEFS} ${DEFS_LOCAL} ${AUTHDEFS} ${CLOCKDEFS} ${COPTS}
+BINDIR?= /usr/sbin
diff --git a/contrib/xntpd/PORTING b/contrib/xntpd/PORTING
new file mode 100644
index 000000000000..7f236424ec4f
--- /dev/null
+++ b/contrib/xntpd/PORTING
@@ -0,0 +1,37 @@
+These are the rules so that older bsd systems and the POSIX standard
+system can coexist togather.
+
+ 1) If you use select then include "ntp_select.h"
+ select is not standard, since it is very system depenedent as to where
+ select is defined. The logic to include the right system dependent
+ include file is in "ntp_select.h".
+ 2) Always use POSIX defintion of strings. Inlcude "ntp_string.h" instaed
+ of <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/contrib/xntpd/README b/contrib/xntpd/README
new file mode 100644
index 000000000000..83d38a8fe5f6
--- /dev/null
+++ b/contrib/xntpd/README
@@ -0,0 +1,154 @@
+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 build 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 installation
+ 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.
+
+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 reasonably 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
+
+scripts directory containing scripts to build the configuration
+ file "config" in this directory and then the makefiles
+ used in various dependent directories.
+ the subdirectories monitoring and support hold various
+ perl and shell scripts for visualising synchronisation
+ and daemon startup.
+
+util directory containing sources for various utility and
+ testing programs.
+
+xntpd directory containing sources for the NTP Version 3 daemon.
+
+xntpdc directory containing sources for a utility program to
+ query local and remote NTP peers for state variables and
+ related timekeeping information. This program is
+ specific to this implmentation of NTP Version 3 and does
+ not conform to Appendix A of the NTP Version 3
+ Specification RFC 1305.
+
+xntpres directory containing sources for a name-resolution
+ program used in some configurations of NTP Version 3.
diff --git a/contrib/xntpd/README.FreeBSD b/contrib/xntpd/README.FreeBSD
new file mode 100644
index 000000000000..437d4783d1ed
--- /dev/null
+++ b/contrib/xntpd/README.FreeBSD
@@ -0,0 +1,10 @@
+This version of NTP was converted to the BSD-style Makefile system by
+Garrett Wollman (wollman@freefall.cdrom.com); it is based on version
+3.3z (late beta) from the University of Delaware.
+
+Besides the Makefile changes, the DES code has been completely removed
+in order to make this code exportable. If you have a legal copy of
+`authdes.c', you can just add it to the lib/ directory and add `-DDES'
+to the AUTHDEFS in Makefile.inc.
+
+You can change CLOCKDEFS in the same file to add other reference clocks.
diff --git a/contrib/xntpd/RELNOTES b/contrib/xntpd/RELNOTES
new file mode 100644
index 000000000000..1b9d9c02c3b3
--- /dev/null
+++ b/contrib/xntpd/RELNOTES
@@ -0,0 +1,208 @@
+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.x.x gcc LOCAL_CLOCK (jmj (94/01/26 see hints)
+ 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 BSD/386 1.0 gcc LOCAL_CLOCK possibly see "build problems"
+ PC Linux (pl14) gcc LOCAL_CLOCK (dw 93/10/30)
+ PC Dell SVR4 v2.2 gcc ? (tl 93/12/30)
+ NCR3445 NCR SVR4 cc LOCAL_CLOCK (tm 93/11/29)
+
+ pb: Piete Brooks
+ kd: Frank Kardel
+ dw: Torsten Duwe (duwe@informatik.uni-erlangen.de)
+ dm: David Mills (mills@udel.edu)
+ tl: Tony Lill <ajlill@tlill.hookup.net>
+ tm: Tom Moore <Tom.Moore@DaytonOH.NCR.COM>
+ jmj: Jim Jagielski <jim@jagubox.gsfc.nasa.gov>
+
+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 are 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".
+
+ On BSD/386 the solution is to get GNU make and run build as:
+ % gnumake MAKE=gnumake
+ Note that BSD/386 1.0's "sed" goes into an infinite loop if
+ you try to make the "refconf" target -- so edit Config.local
+ by hand if you have a reference clock. (BSD/386 1.1 will fix
+ this "sed" bug.)
+
+ The NetBSD people claim that this problem goes away
+ when you compile make with POSIX compilation options.
+
+The known sh and some make pecularities have already been taken care of.
+
+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/contrib/xntpd/TODO b/contrib/xntpd/TODO
new file mode 100644
index 000000000000..e4bbe4713c94
--- /dev/null
+++ b/contrib/xntpd/TODO
@@ -0,0 +1,26 @@
+#
+# TODO,v 3.5 1994/01/25 19:03:55 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:
+
+Apollo:
+ - terminal affiliation
+ Check whether thing are still correct in respect to breaking
+ terminal affiliation - horrible stories are told in the code.
+ File affected: xntpd/ntpd.c
diff --git a/contrib/xntpd/VERSION b/contrib/xntpd/VERSION
new file mode 100644
index 000000000000..85051bd4db45
--- /dev/null
+++ b/contrib/xntpd/VERSION
@@ -0,0 +1 @@
+version=3.3c (beta)
diff --git a/contrib/xntpd/adjtime/.keep_me b/contrib/xntpd/adjtime/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/adjtime/.keep_me
diff --git a/contrib/xntpd/authstuff/Makefile b/contrib/xntpd/authstuff/Makefile
new file mode 100644
index 000000000000..d2e79971f872
--- /dev/null
+++ b/contrib/xntpd/authstuff/Makefile
@@ -0,0 +1,27 @@
+#
+# $Id: Makefile,v 1.2 1993/12/22 11:32:10 rgrimes Exp $
+#
+# Most of the programs in this directory are completely useless for the
+# NTP configuration that we provide by default.
+# We provide the `md5' program as a public service.
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= ${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= ${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= md5
+
+SRCS= md5driver.c
+NOMAN=
+
+install:
+
+.include <bsd.prog.mk>
diff --git a/contrib/xntpd/authstuff/README b/contrib/xntpd/authstuff/README
new file mode 100644
index 000000000000..2985751cc0c0
--- /dev/null
+++ b/contrib/xntpd/authstuff/README
@@ -0,0 +1,13 @@
+README file for directory ./authstuff of the NTP Version 3 distribution
+
+This directory contains the sources for miscellaneous programs to test,
+validate and calibreate cryptographic routines used by NTP. These include
+
+authcert.c used to certify the DES and MD5 message digest algorithms
+ work properly. See the source for directions for use.
+
+authspeed.c used to determing the running time for DES and MD5
+ messge digest algorithms. See the source for directions
+ for use.
+
+For other programs, see the source files.
diff --git a/contrib/xntpd/authstuff/auth.samplekeys b/contrib/xntpd/authstuff/auth.samplekeys
new file mode 100644
index 000000000000..c46d283405f2
--- /dev/null
+++ b/contrib/xntpd/authstuff/auth.samplekeys
@@ -0,0 +1,45 @@
+# auth.samplekeys,v 3.1 1993/07/06 01:04:49 jbj Exp
+#
+# Sample key file, also used for testing.
+#
+# Note that there are three formats for keys. Standard format is a
+# hex format with the low order bit of each byte being a parity
+# bit, a la the NBS standard. NTP format is also hex, but uses the
+# high order bit of each byte for parity. Ascii format simply encodes
+# a 1-8 character ascii string as a key. Note that because of the
+# simple tokenizing routine, the characters ' ', '#', '\t', '\n' and
+# '\0' can't be used in an ascii key. Everything else is fair game, though.
+#
+
+1 S 0101010101010101 # odd parity 0 key
+2 N 8080808080808080 # and again
+3 A ugosnod
+4 A BigbOObs
+5 S f1f1f1f1f1f1f1f1
+6 N f8f8f8f8f8f8f8f8 # same as key 5
+7 S f8f8f8f8f8f8f8f8 # not same as key 6
+8 A a # short ascii keys are zero padded
+9 A &^%$@!*(
+10 S 01020407080bf1f1
+11 N 4040404040404040
+12 A more
+13 A random
+14 A keys
+15 A password # 15 used as password by runtime configuration
+#
+16 M password # MD5 key
+17 M secret
+18 M key1
+19 M key2
+20 M foobar
+21 M tick
+22 M tock
+23 M key23
+24 M key24
+25 M key25
+26 M a
+27 M few
+28 M more
+29 M random
+30 M md5
+31 M keys!
diff --git a/contrib/xntpd/authstuff/auth.speed b/contrib/xntpd/authstuff/auth.speed
new file mode 100644
index 000000000000..b55f20cbd821
--- /dev/null
+++ b/contrib/xntpd/authstuff/auth.speed
@@ -0,0 +1,20 @@
+Authentication delays (us) DES MD5
+DEC 3000/400 OSF/1 bunnylou 14 35
+HP9000/735 hpux9.0 na 30
+HP9000/730 hpux8.07(+OV) 16 55
+SGI Indigo R4000 19 48
+HP9000/720 hpux8.07 21 66
+SGI 4/35 38 110
+DECstation 5000/240 cowbird 39 81
+Sun4c/75 SS2 43 96
+Sun4c/50 IPX malarky 47 94
+DECstation 5000/33 sundeck 49 106
+SGI Indigo 54 115
+DECstation 5000/125 herald 63 136
+Sun4c/65 SS1+ pogo 72 159
+Sun4c/40 IPC grundoon 73 163
+Sun4c/60 SS1 albert 95 199
+Sun4c/20 SLC 95 203
+DECstation 3100 sheol 98 214
+DECstation 2100 circus 126 278
+VAX 780 985 ?
diff --git a/contrib/xntpd/authstuff/authcert.c b/contrib/xntpd/authstuff/authcert.c
new file mode 100644
index 000000000000..6f6e42c220c8
--- /dev/null
+++ b/contrib/xntpd/authstuff/authcert.c
@@ -0,0 +1,96 @@
+/* authcert.c,v 3.1 1993/07/06 01:04:52 jbj Exp
+ * This file, and the certdata file, shamelessly stolen
+ * from Phil Karn's DES implementation.
+ */
+
+#include <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/contrib/xntpd/authstuff/authspeed.c b/contrib/xntpd/authstuff/authspeed.c
new file mode 100644
index 000000000000..c83d5b24497e
--- /dev/null
+++ b/contrib/xntpd/authstuff/authspeed.c
@@ -0,0 +1,315 @@
+/* authspeed.c,v 3.1 1993/07/06 01:04:54 jbj Exp
+ * authspeed - figure out how LONG it takes to do an NTP encryption
+ */
+
+#if defined(SYS_HPUX) || defined(SYS_AUX3) || defined(SYS_AUX2) || defined(SOLARIS) || defined(SYS_SVR4) || defined(SYS_PTX)
+#define FAKE_RUSAGE
+#endif
+
+#include <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 ntp_optind;
+ extern char *ntp_optarg;
+
+ progname = argv[0];
+ loops = DEFLOOPS;
+ while ((c = ntp_getopt(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(ntp_optarg);
+ if (loops <= 0) {
+ (void) fprintf(stderr,
+ "%s: %s is unlikely to be a useful number of loops\n",
+ progname, ntp_optarg);
+ errflg++;
+ }
+ break;
+ default:
+ errflg++;
+ break;
+ }
+ if (errflg || ntp_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[ntp_optind]);
+ for (i = 0; i < 16; i++) {
+ if (!auth_havekey(i + domd5)) {
+ errflg++;
+ (void) fprintf(stderr, "%s: key %d missing\n",
+ progname, i + domd5);
+ }
+ }
+
+ if (errflg) {
+ (void) fprintf(stderr,
+ "%s: check syslog for errors, or use file with complete set of keys\n",
+ progname);
+ exit(1);
+ }
+
+ if (loops == DEFLOOPS) {
+ if (totalcost)
+ loops = DEFCOSTLOOPS;
+ else
+ loops = DEFDELAYLOOPS;
+ }
+
+ dummy1.l_ui = 0x80808080;
+ dummy1.l_uf = 0xffffff00;
+ dummy3 = 0x0aaaaaaa;
+
+ for (i = 0; i < 12; i++)
+ pkt[i] = i * 0x22222;
+
+ if (totalcost) {
+ if (totalcost > 1)
+ docheap(loops);
+ else
+ docost(loops);
+ } else {
+ dodelay(loops);
+ }
+
+ printf("total real time: %.3f\n", rtime);
+ printf("total CPU time: %.3f\n", vtime);
+ if (totalcost) {
+ printf("real cost (in seconds): %.6f\n",
+ rtime/(double)loops);
+ printf("CPU cost (in seconds): %.6f\n",
+ vtime/(double)loops);
+ printf("\nThis includes the cost of a decryption plus the\n");
+ printf("the cost of an encryption, i.e. the cost to process\n");
+ printf("a single authenticated packet.\n");
+ } else {
+ printf("authdelay in the configuration file\n");
+ printf("real authentication delay: %.6f\n",
+ rtime/(double)loops);
+ printf("authentication delay in CPU time: %.6f\n",
+ vtime/(double)loops);
+ printf("\nThe CPU delay is probably the best bet for\n");
+ printf("authdelay in the configuration file\n");
+ }
+ exit(0);
+}
+
+
+/*
+ * dodelay - do the delay measurement
+ */
+static void
+dodelay(loops)
+ int loops;
+{
+ double vtime1, rtime1, vtime2, rtime2;
+ register int loopcount;
+ /*
+ * If we're attempting to compute the cost of an auth2crypt()
+ * for first compute the total cost, then compute the
+ * cost of only doing the first step, auth1crypt(). What
+ * remains is the cost of auth2crypt.
+ */
+ loopcount = loops;
+ (void) gettimeofday(&tstart, (struct timezone *)0);
+ (void) getrusage(RUSAGE_SELF, &rstart);
+
+ while (loopcount-- > 0) {
+ auth1crypt((loops & 0xf) + domd5, pkt, 48);
+ L_ADDUF(&dummy1, dummy3);
+ auth2crypt((loops & 0xf) + domd5, pkt, 48);
+ }
+
+ (void) getrusage(RUSAGE_SELF, &rend);
+ (void) gettimeofday(&tend, (struct timezone *)0);
+
+ subtime(&tstart, &tend, &rtime1);
+#ifdef FAKE_RUSAGE
+ vtime1 = (rend.tms_utime - rstart.tms_utime) * 1.0 / HZ;
+#else
+ subtime(&rstart.ru_utime, &rend.ru_utime, &vtime1);
+#endif
+printf("Time for full encryptions is %f rusage %f real\n", vtime1, rtime1);
+ loopcount = loops;
+ (void) gettimeofday(&tstart, (struct timezone *)0);
+ (void) getrusage(RUSAGE_SELF, &rstart);
+
+ while (loopcount-- > 0) {
+ auth1crypt((loops & 0xf) + domd5, pkt, 48);
+ }
+
+ (void) getrusage(RUSAGE_SELF, &rend);
+ (void) gettimeofday(&tend, (struct timezone *)0);
+
+ subtime(&tstart, &tend, &rtime2);
+#ifdef FAKE_RUSAGE
+ vtime2 = (rend.tms_utime - rstart.tms_utime) * 1.0 / HZ;
+#else
+ subtime(&rstart.ru_utime, &rend.ru_utime, &vtime2);
+#endif
+
+printf("Time for auth1crypt is %f rusage %f real\n", vtime2, rtime2);
+ vtime = vtime1 - vtime2;
+ rtime = rtime1 - rtime2;
+}
+
+
+/*
+ * docheap - do the cost measurement the cheap way
+ */
+static void
+docheap(loops)
+ register int loops;
+{
+
+ (void) authhavekey(3 + domd5);
+
+ (void) gettimeofday(&tstart, (struct timezone *)0);
+ (void) getrusage(RUSAGE_SELF, &rstart);
+
+ while (loops-- > 0) {
+ auth1crypt(3 + domd5, pkt, 48);
+ L_ADDUF(&dummy1, dummy3);
+ auth2crypt(3 + domd5, pkt, 48);
+ (void) authdecrypt(3 + domd5, pkt, 48);
+ }
+
+ (void) getrusage(RUSAGE_SELF, &rend);
+ (void) gettimeofday(&tend, (struct timezone *)0);
+
+ subtime(&tstart, &tend, &rtime);
+#ifdef FAKE_RUSAGE
+ vtime = (rend.tms_utime - rstart.tms_utime) * 1.0 / HZ;
+#else
+ subtime(&rstart.ru_utime, &rend.ru_utime, &vtime);
+#endif
+}
+
+
+/*
+ * docost - do the cost measurement
+ */
+static void
+docost(loops)
+ register int loops;
+{
+
+ (void) gettimeofday(&tstart, (struct timezone *)0);
+ (void) getrusage(RUSAGE_SELF, &rstart);
+
+ while (loops-- > 0) {
+ auth1crypt((loops & 0xf) + domd5, pkt, 48);
+ L_ADDUF(&dummy1, dummy3);
+ auth2crypt((loops & 0xf) + domd5, pkt, 48);
+ (void) authdecrypt(((loops+1) & 0xf) + domd5, pkt, 48);
+ }
+
+ (void) getrusage(RUSAGE_SELF, &rend);
+ (void) gettimeofday(&tend, (struct timezone *)0);
+
+ subtime(&tstart, &tend, &rtime);
+#ifdef FAKE_RUSAGE
+ vtime = (rend.tms_utime - rstart.tms_utime) * 1.0 / HZ;
+#else
+ subtime(&rstart.ru_utime, &rend.ru_utime, &vtime);
+#endif
+}
+
+
+/*
+ * subtime - subtract two struct timevals, return double result
+ */
+static void
+subtime(tvs, tve, res)
+ struct timeval *tvs, *tve;
+ double *res;
+{
+ LONG sec;
+ LONG usec;
+
+ sec = tve->tv_sec - tvs->tv_sec;
+ usec = tve->tv_usec - tvs->tv_usec;
+
+ if (usec < 0) {
+ usec += 1000000;
+ sec--;
+ }
+
+ *res = (double)sec + (double)usec/1000000.;
+ return;
+}
diff --git a/contrib/xntpd/authstuff/certdata b/contrib/xntpd/authstuff/certdata
new file mode 100644
index 000000000000..f9a818efecb8
--- /dev/null
+++ b/contrib/xntpd/authstuff/certdata
@@ -0,0 +1,34 @@
+0000000000000000 0000000000000000 8CA64DE9C1B123A7
+FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7359B2163E4EDC58
+3000000000000000 1000000000000001 958E6E627A05557B
+1111111111111111 1111111111111111 F40379AB9E0EC533
+0123456789ABCDEF 1111111111111111 17668DFC7292532D
+1111111111111111 0123456789ABCDEF 8A5AE1F81AB8F2DD
+0000000000000000 0000000000000000 8CA64DE9C1B123A7
+FEDCBA9876543210 0123456789ABCDEF ED39D950FA74BCC4
+7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B
+0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271
+07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A
+3849674C2602319E 51454B582DDF440A 7178876E01F19B2A
+04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095
+0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B
+0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09
+43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A
+07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F
+04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088
+37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77
+1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A
+584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56
+025816164629B007 480D39006EE762F2 A1F9915541020B56
+49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556
+4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC
+49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A
+018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41
+1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793
+0101010101010101 0123456789ABCDEF 617B3A0CE8F07100
+1F1F1F1F0E0E0E0E 0123456789ABCDEF DB958605F8C8C606
+E0FEE0FEF1FEF1FE 0123456789ABCDEF EDBFD1C66C29CCC7
+0000000000000000 FFFFFFFFFFFFFFFF 355550B2150E2451
+FFFFFFFFFFFFFFFF 0000000000000000 CAAAAF4DEAF1DBAE
+0123456789ABCDEF 0000000000000000 D5D44FF720683D0D
+FEDCBA9876543210 FFFFFFFFFFFFFFFF 2A2BB008DF97C2F2
diff --git a/contrib/xntpd/authstuff/keyparity.c b/contrib/xntpd/authstuff/keyparity.c
new file mode 100644
index 000000000000..424fade71745
--- /dev/null
+++ b/contrib/xntpd/authstuff/keyparity.c
@@ -0,0 +1,279 @@
+/* keyparity.c,v 3.1 1993/07/06 01:04:57 jbj Exp
+ * keyparity - add parity bits to key and/or change an ascii key to binary
+ */
+
+#include <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 ntp_optind;
+ extern char *ntp_optarg;
+
+ progname = argv[0];
+ while ((c = ntp_getopt(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 (*ntp_optarg == 'n') {
+ ntpoutflag = 1;
+ gotoopt = 1;
+ } else if (*ntp_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 || ntp_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 (; ntp_optind < argc; ntp_optind++) {
+ if (!decodekey(keytype, argv[ntp_optind], key)) {
+ (void) fprintf(stderr,
+ "%s: format of key %s invalid\n",
+ progname, argv[ntp_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
+ */
+ memset(keybytes, 0, sizeof(keybytes));
+ for (i = 0; i < 8 && i < len; i++)
+ keybytes[i] = *cp++ << 1;
+ key[0] = keybytes[0] << 24 | keybytes[1] << 16
+ | keybytes[2] << 8 | keybytes[3];
+ key[1] = keybytes[4] << 24 | keybytes[5] << 16
+ | keybytes[6] << 8 | keybytes[7];
+ break;
+
+ default:
+ /* Oh, well */
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * output - print a hex key on the standard output
+ */
+static void
+output(key, ntpformat)
+ U_LONG *key;
+ int ntpformat;
+{
+ int i;
+
+ if (ntpformat) {
+ for (i = 0; i < 2; i++)
+ key[i] = ((key[i] & ~STD_PARITY_BITS) >> 1)
+ | ((key[i] & STD_PARITY_BITS) << 7);
+ }
+ (void) printf("%08x%08x\n", key[0], key[1]);
+}
diff --git a/contrib/xntpd/authstuff/makeIPFP.c b/contrib/xntpd/authstuff/makeIPFP.c
new file mode 100644
index 000000000000..50b31f4f2513
--- /dev/null
+++ b/contrib/xntpd/authstuff/makeIPFP.c
@@ -0,0 +1,345 @@
+/* makeIPFP.c,v 3.1 1993/07/06 01:04:58 jbj Exp
+ * makeIPFP - make fast DES IP and FP tables
+ */
+
+#include <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 ntp_optind;
+ extern char *ntp_optarg;
+
+ progname = argv[0];
+ while ((c = ntp_getopt(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;
+
+ memset((char *)bits, 0, sizeof bits);
+
+ /*
+ * Do the rounds for the IP table. We save the results of
+ * this as well as printing them. Note that this is the
+ * left-half table, the right half table will be identical.
+ */
+ printf("static U_LONG IP[256] = {");
+ for (tabno = 0; tabno < 4; tabno++) {
+ i = tabno * 8;
+ ind7 = IPLbits[i] - 1;
+ ind6 = IPLbits[i+1] - 1;
+ ind5 = IPLbits[i+2] - 1;
+ ind4 = IPLbits[i+3] - 1;
+ ind3 = IPLbits[i+4] - 1;
+ ind2 = IPLbits[i+5] - 1;
+ ind1 = IPLbits[i+6] - 1;
+ ind0 = IPLbits[i+7] - 1;
+ for (octbits = 0; octbits < 256; octbits++) {
+ if (octbits & (1 << 7))
+ bits[ind7] = 1;
+ if (octbits & (1 << 6))
+ bits[ind6] = 1;
+ if (octbits & (1 << 5))
+ bits[ind5] = 1;
+ if (octbits & (1 << 4))
+ bits[ind4] = 1;
+ if (octbits & (1 << 3))
+ bits[ind3] = 1;
+ if (octbits & (1 << 2))
+ bits[ind2] = 1;
+ if (octbits & (1 << 1))
+ bits[ind1] = 1;
+ if (octbits & 1)
+ bits[ind0] = 1;
+ perm(bits, IP, &left, &right);
+ bits[ind7] = 0;
+ bits[ind6] = 0;
+ bits[ind5] = 0;
+ bits[ind4] = 0;
+ bits[ind3] = 0;
+ bits[ind2] = 0;
+ bits[ind1] = 0;
+ bits[ind0] = 0;
+ if (right != 0) {
+ fprintf(stderr,
+ "IP tabno %d oct %d right not zero\n",
+ tabno, octbits);
+ exit(1);
+ }
+ if (tabno > 0) {
+ if ((IPL[octbits] << tabno) != left) {
+ fprintf(stderr,
+ "IP tabno %d oct %d IP %d left %d, IP != left\n",
+ tabno, octbits, IPL[octbits], left);
+ exit (1);
+ }
+ } else {
+ IPL[octbits] = left;
+ if (octbits == 255) {
+ printf(" 0x%08x", left);
+ } else if (octbits & 0x3) {
+ printf(" 0x%08x,", left);
+ } else {
+ printf("\n\t0x%08x,", left);
+ }
+ }
+ }
+ if (tabno == 0)
+ printf("\n};\n\n");
+ }
+
+ /*
+ * Next is the FP table, in big endian order
+ */
+ printf("#if BYTE_ORDER == LITTLE_ENDIAN\nstatic U_LONG FP[256] = {");
+ for (tabno = 3; tabno >= 0; tabno--) {
+ i = tabno * 8;
+ ind7 = FPLbits[i] - 1;
+ ind6 = FPLbits[i+1] - 1;
+ ind5 = FPLbits[i+2] - 1;
+ ind4 = FPLbits[i+3] - 1;
+ ind3 = FPLbits[i+4] - 1;
+ ind2 = FPLbits[i+5] - 1;
+ ind1 = FPLbits[i+6] - 1;
+ ind0 = FPLbits[i+7] - 1;
+ for (octbits = 0; octbits < 256; octbits++) {
+ if (octbits & (1 << 7))
+ bits[ind7] = 1;
+ if (octbits & (1 << 6))
+ bits[ind6] = 1;
+ if (octbits & (1 << 5))
+ bits[ind5] = 1;
+ if (octbits & (1 << 4))
+ bits[ind4] = 1;
+ if (octbits & (1 << 3))
+ bits[ind3] = 1;
+ if (octbits & (1 << 2))
+ bits[ind2] = 1;
+ if (octbits & (1 << 1))
+ bits[ind1] = 1;
+ if (octbits & 1)
+ bits[ind0] = 1;
+ perm(bits, FP, &left, &right);
+ bits[ind7] = 0;
+ bits[ind6] = 0;
+ bits[ind5] = 0;
+ bits[ind4] = 0;
+ bits[ind3] = 0;
+ bits[ind2] = 0;
+ bits[ind1] = 0;
+ bits[ind0] = 0;
+ if (right != 0) {
+ fprintf(stderr,
+ "FP tabno %d oct %d right not zero\n",
+ tabno, octbits);
+ exit(1);
+ }
+ if (tabno != 3) {
+ if ((FPL[octbits] << ((3-tabno)<<1)) != left) {
+ fprintf(stderr,
+ "FP tabno %d oct %d FP %x left %x, FP != left\n",
+ tabno, octbits, FPL[octbits], left);
+ exit (1);
+ }
+ } else {
+ FPL[octbits] = left;
+ if (octbits == 255) {
+ printf(" 0x%08x", left);
+ } else if (octbits & 0x3) {
+ printf(" 0x%08x,", left);
+ } else {
+ printf("\n\t0x%08x,", left);
+ }
+ }
+ }
+ if (tabno == 3)
+ printf("\n};\n");
+ }
+
+ /*
+ * Now reouput the FP table in order appropriate for little
+ * endian machines
+ */
+ printf("#else\nstatic U_LONG FP[256] = {");
+ for (octbits = 0; octbits < 256; octbits++) {
+ left = ((FPL[octbits] >> 24) & 0x000000ff)
+ | ((FPL[octbits] >> 8) & 0x0000ff00)
+ | ((FPL[octbits] << 8) & 0x00ff0000)
+ | ((FPL[octbits] << 24) & 0xff000000);
+ if (octbits == 255) {
+ printf(" 0x%08x", left);
+ } else if (octbits & 0x3) {
+ printf(" 0x%08x,", left);
+ } else {
+ printf("\n\t0x%08x,", left);
+ }
+ }
+ printf("\n};\n#endif\n");
+}
diff --git a/contrib/xntpd/authstuff/makePC1.c b/contrib/xntpd/authstuff/makePC1.c
new file mode 100644
index 000000000000..337353c1516b
--- /dev/null
+++ b/contrib/xntpd/authstuff/makePC1.c
@@ -0,0 +1,286 @@
+/* makePC1.c,v 3.1 1993/07/06 01:04:59 jbj Exp
+ * makePC1 - build custom permutted choice 1 tables
+ */
+
+#include <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 ntp_optind;
+ extern char *ntp_optarg;
+
+ progname = argv[0];
+ while ((c = ntp_getopt(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];
+
+ memset((char *)c, 0, sizeof c);
+ memset((char *)d, 0, 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];
+
+ memset((char *)bits, 0, sizeof bits);
+
+ printf("static U_LONG PC1_CL[8] = {");
+ for (i = 0; i < 4; i++) {
+ for (comb = 0; comb < 8; comb++) {
+ if (comb & 0x4)
+ bits[lc3[i]] = 1;
+ if (comb & 0x2)
+ bits[lc3[i]+1] = 1;
+ if (comb & 0x1)
+ bits[lc3[i]+2] = 1;
+ permute(bits, &c, &d);
+ bits[lc3[i]] = 0;
+ bits[lc3[i]+1] = 0;
+ bits[lc3[i]+2] = 0;
+ if (d != 0) {
+ (void) fprintf(stderr,
+ "Error PC_CL i %d comb %d\n", i, comb);
+ }
+ if (i == 0) {
+ PC_CL[comb] = c;
+ if ((comb & 0x3) == 0)
+ printf("\n\t0x%08x,", c);
+ else if (comb == 7)
+ printf(" 0x%08x\n};\n\n", c);
+ else
+ printf(" 0x%08x,", c);
+ } else {
+ if (c != PC_CL[comb] << i)
+ (void) fprintf(stderr,
+ "Error PC_CL 0x%08x c 0x%08x\n",
+ PC_CL[comb], c);
+ }
+ }
+ }
+
+ printf("static U_LONG PC1_DL[16] = {");
+ for (i = 0; i < 4; i++) {
+ for (comb = 0; comb < 16; comb++) {
+ if (comb & 0x8)
+ bits[ld4[i]] = 1;
+ if (comb & 0x4)
+ bits[ld4[i]+1] = 1;
+ if (comb & 0x2)
+ bits[ld4[i]+2] = 1;
+ if (comb & 0x1)
+ bits[ld4[i]+3] = 1;
+ permute(bits, &c, &d);
+ bits[ld4[i]] = 0;
+ bits[ld4[i]+1] = 0;
+ bits[ld4[i]+2] = 0;
+ bits[ld4[i]+3] = 0;
+ if (c != 0) {
+ (void) fprintf(stderr,
+ "Error PC_DL i %d comb %d\n", i, comb);
+ }
+ if (i == 0) {
+ PC_DL[comb] = d;
+ if ((comb & 0x3) == 0)
+ printf("\n\t0x%08x,", d);
+ else if (comb == 15)
+ printf(" 0x%08x\n};\n\n", d);
+ else
+ printf(" 0x%08x,", d);
+ } else {
+ if (d != PC_DL[comb] << i)
+ (void) fprintf(stderr,
+ "Error PC_DL 0x%08x c 0x%08x\n",
+ PC_DL[comb], d);
+ }
+ }
+ }
+
+ printf("static U_LONG PC1_CR[16] = {");
+ for (i = 0; i < 4; i++) {
+ for (comb = 0; comb < 16; comb++) {
+ if (comb & 0x8)
+ bits[rc4[i]] = 1;
+ if (comb & 0x4)
+ bits[rc4[i]+1] = 1;
+ if (comb & 0x2)
+ bits[rc4[i]+2] = 1;
+ if (comb & 0x1)
+ bits[rc4[i]+3] = 1;
+ permute(bits, &c, &d);
+ bits[rc4[i]] = 0;
+ bits[rc4[i]+1] = 0;
+ bits[rc4[i]+2] = 0;
+ bits[rc4[i]+3] = 0;
+ if (d != 0) {
+ (void) fprintf(stderr,
+ "Error PC_CR i %d comb %d\n", i, comb);
+ }
+ if (i == 0) {
+ PC_CR[comb] = c;
+ if ((comb & 0x3) == 0)
+ printf("\n\t0x%08x,", c);
+ else if (comb == 15)
+ printf(" 0x%08x\n};\n\n", c);
+ else
+ printf(" 0x%08x,", c);
+ } else {
+ if (c != PC_CR[comb] << i)
+ (void) fprintf(stderr,
+ "Error PC_CR 0x%08x c 0x%08x\n",
+ PC_CR[comb], c);
+ }
+ }
+ }
+
+ printf("static U_LONG PC1_DR[8] = {");
+ for (i = 0; i < 4; i++) {
+ for (comb = 0; comb < 8; comb++) {
+ if (comb & 0x4)
+ bits[rd3[i]] = 1;
+ if (comb & 0x2)
+ bits[rd3[i]+1] = 1;
+ if (comb & 0x1)
+ bits[rd3[i]+2] = 1;
+ permute(bits, &c, &d);
+ bits[rd3[i]] = 0;
+ bits[rd3[i]+1] = 0;
+ bits[rd3[i]+2] = 0;
+ if (c != 0) {
+ (void) fprintf(stderr,
+ "Error PC_DR i %d comb %d\n", i, comb);
+ }
+ if (i == 0) {
+ PC_DR[comb] = d;
+ if ((comb & 0x3) == 0)
+ printf("\n\t0x%08x,", d);
+ else if (comb == 7)
+ printf(" 0x%08x\n};\n\n", d);
+ else
+ printf(" 0x%08x,", d);
+ } else {
+ if (d != PC_DR[comb] << i)
+ (void) fprintf(stderr,
+ "Error PC_DR 0x%08x c 0x%08x\n",
+ PC_DR[comb], d);
+ }
+ }
+ }
+}
diff --git a/contrib/xntpd/authstuff/makePC2.c b/contrib/xntpd/authstuff/makePC2.c
new file mode 100644
index 000000000000..9795b6215a20
--- /dev/null
+++ b/contrib/xntpd/authstuff/makePC2.c
@@ -0,0 +1,238 @@
+/* makePC2.c,v 3.1 1993/07/06 01:05:01 jbj Exp
+ * makePC2 - build custom permutted choice 2 tables
+ */
+
+#include <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 ntp_optind;
+ extern char *ntp_optarg;
+
+ progname = argv[0];
+ while ((c = ntp_getopt(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];
+
+ memset((char *)res, 0, 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];
+
+ memset((char *)res, 0, 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];
+
+ memset((char *)bits, 0, sizeof bits);
+
+ printf("static U_LONG PC2_C[4][64] = {");
+ for (i = 0; i < 4; i++) {
+ for (comb = 0; comb < 64; comb++) {
+ if (comb & 0x20)
+ bits[cbits[i][0]] = 1;
+ if (comb & 0x10)
+ bits[cbits[i][1]] = 1;
+ if (comb & 0x8)
+ bits[cbits[i][2]] = 1;
+ if (comb & 0x4)
+ bits[cbits[i][3]] = 1;
+ if (comb & 0x2)
+ bits[cbits[i][4]] = 1;
+ if (comb & 0x1)
+ bits[cbits[i][5]] = 1;
+ permc(bits, &res);
+ bits[cbits[i][0]] = 0;
+ bits[cbits[i][1]] = 0;
+ bits[cbits[i][2]] = 0;
+ bits[cbits[i][3]] = 0;
+ bits[cbits[i][4]] = 0;
+ bits[cbits[i][5]] = 0;
+ if ((comb & 0x3) == 0)
+ printf("\n\t0x%08x,", res);
+ else if (comb == 63 && i == 3)
+ printf(" 0x%08x\n};\n\n", res);
+ else if (comb == 63)
+ printf(" 0x%08x,\n", res);
+ else
+ printf(" 0x%08x,", res);
+ }
+ }
+
+ printf("static U_LONG PC2_D[4][64] = {");
+ for (i = 0; i < 4; i++) {
+ for (comb = 0; comb < 64; comb++) {
+ if (comb & 0x20)
+ bits[dbits[i][0]] = 1;
+ if (comb & 0x10)
+ bits[dbits[i][1]] = 1;
+ if (comb & 0x8)
+ bits[dbits[i][2]] = 1;
+ if (comb & 0x4)
+ bits[dbits[i][3]] = 1;
+ if (comb & 0x2)
+ bits[dbits[i][4]] = 1;
+ if (comb & 0x1)
+ bits[dbits[i][5]] = 1;
+ permd(bits, &res);
+ bits[dbits[i][0]] = 0;
+ bits[dbits[i][1]] = 0;
+ bits[dbits[i][2]] = 0;
+ bits[dbits[i][3]] = 0;
+ bits[dbits[i][4]] = 0;
+ bits[dbits[i][5]] = 0;
+ if ((comb & 0x3) == 0)
+ printf("\n\t0x%08x,", res);
+ else if (comb == 63 && i == 3)
+ printf(" 0x%08x\n};\n\n", res);
+ else if (comb == 63)
+ printf(" 0x%08x,\n", res);
+ else
+ printf(" 0x%08x,", res);
+ }
+ }
+}
diff --git a/contrib/xntpd/authstuff/makeSP.c b/contrib/xntpd/authstuff/makeSP.c
new file mode 100644
index 000000000000..7bfd93e2cbd6
--- /dev/null
+++ b/contrib/xntpd/authstuff/makeSP.c
@@ -0,0 +1,183 @@
+/* makeSP.c,v 3.1 1993/07/06 01:05:02 jbj Exp
+ * makeSP - build combination S and P tables for quick DES computation
+ */
+
+#include <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 ntp_optind;
+ extern char *ntp_optarg;
+
+ progname = argv[0];
+ while ((c = ntp_getopt(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;
+
+ memset((char *)bits, 0, sizeof bits);
+ printf("static U_LONG SP[8][64] = {");
+ for (selno = 0; selno < 8; selno++) {
+ for (sixbits = 0; sixbits < 64; sixbits++) {
+ selperm(selno, sixbits, &result);
+ if ((sixbits & 0x3) == 0)
+ printf("\n\t0x%08x,", result);
+ else if (sixbits == 63 && selno == 7)
+ printf(" 0x%08x\n};\n", result);
+ else if (sixbits == 63)
+ printf(" 0x%08x,\n", result);
+ else
+ printf(" 0x%08x,", result);
+ }
+ }
+}
diff --git a/contrib/xntpd/authstuff/md5_sample_output b/contrib/xntpd/authstuff/md5_sample_output
new file mode 100644
index 000000000000..a7d4282d2edb
--- /dev/null
+++ b/contrib/xntpd/authstuff/md5_sample_output
@@ -0,0 +1,8 @@
+MD5 test suite results:
+d41d8cd98f00b204e9800998ecf8427e ""
+0cc175b9c0f1b6a831c399e269772661 "a"
+900150983cd24fb0d6963f7d28e17f72 "abc"
+f96b697d7cb7938d525a2f31aaf161d0 "message digest"
+c3fcd3d76192e4007dfb496cca67e13b "abcdefghijklmnopqrstuvwxyz"
+d174ab98d277d9f5a5611c2c9f419d9f "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+57edf4a22be3c955ac49da2e2107b67a "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
diff --git a/contrib/xntpd/authstuff/md5driver.c b/contrib/xntpd/authstuff/md5driver.c
new file mode 100644
index 000000000000..a608add35f4a
--- /dev/null
+++ b/contrib/xntpd/authstuff/md5driver.c
@@ -0,0 +1,211 @@
+/* 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 SYS_BSDI
+#include <sys/time.h>
+#endif /* SYS_BSDI */
+#include "md5.h"
+
+#ifndef MD5
+#define MD5
+#endif
+#include "ntp_string.h"
+#include "ntp_stdlib.h"
+
+/* Prints message digest buffer in mdContext as 32 hexadecimal digits.
+ Order is from low-order byte to high-order byte of digest.
+ Each byte is printed with high-order hexadecimal digit first.
+ */
+static void
+MDPrint (mdContext)
+MD5_CTX *mdContext;
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ printf ("%02x", mdContext->digest[i]);
+}
+
+/* size of test block */
+#define TEST_BLOCK_SIZE 1000
+
+/* number of blocks to process */
+#define TEST_BLOCKS 10000
+
+/* number of test bytes = TEST_BLOCK_SIZE * TEST_BLOCKS */
+static LONG TEST_BYTES = (LONG)TEST_BLOCK_SIZE * (LONG)TEST_BLOCKS;
+
+/* A time trial routine, to measure the speed of MD5.
+ Measures wall time required to digest TEST_BLOCKS * TEST_BLOCK_SIZE
+ characters.
+ */
+static void
+MDTimeTrial ()
+{
+ MD5_CTX mdContext;
+ time_t endTime, startTime;
+ unsigned char data[TEST_BLOCK_SIZE];
+ unsigned int i;
+
+ /* initialize test data */
+ for (i = 0; i < TEST_BLOCK_SIZE; i++)
+ data[i] = (unsigned char)(i & 0xFF);
+
+ /* start timer */
+ printf ("MD5 time trial. Processing %ld characters...\n", TEST_BYTES);
+ time (&startTime);
+
+ /* digest data in TEST_BLOCK_SIZE byte blocks */
+ MD5Init (&mdContext);
+ for (i = TEST_BLOCKS; i > 0; i--)
+ MD5Update (&mdContext, data, TEST_BLOCK_SIZE);
+ MD5Final (&mdContext);
+
+ /* stop timer, get time difference */
+ time (&endTime);
+ MDPrint (&mdContext);
+ printf (" is digest of test input.\n");
+ printf
+ ("Seconds to process test input: %ld\n", (LONG)(endTime-startTime));
+ printf
+ ("Characters processed per second: %ld\n",
+ TEST_BYTES/(endTime-startTime));
+}
+
+/* Computes the message digest for string inString.
+ Prints out message digest, a space, the string (in quotes) and a
+ carriage return.
+ */
+static void
+MDString (inString)
+char *inString;
+{
+ MD5_CTX mdContext;
+ unsigned int len = strlen (inString);
+
+ MD5Init (&mdContext);
+ MD5Update (&mdContext, inString, len);
+ MD5Final (&mdContext);
+ MDPrint (&mdContext);
+ printf (" \"%s\"\n", inString);
+}
+
+/* Computes the message digest for a specified file.
+ Prints out message digest, a space, the file name, and a carriage
+ return.
+ */
+static void
+MDFile (filename)
+char *filename;
+{
+ FILE *inFile = fopen (filename, "rb");
+ MD5_CTX mdContext;
+ int bytes;
+ unsigned char data[1024];
+
+ if (inFile == NULL) {
+ printf ("%s can't be opened.\n", filename);
+ return;
+ }
+
+ MD5Init (&mdContext);
+ while ((bytes = fread (data, 1, 1024, inFile)) != 0)
+ MD5Update (&mdContext, data, bytes);
+ MD5Final (&mdContext);
+ MDPrint (&mdContext);
+ printf (" %s\n", filename);
+ fclose (inFile);
+}
+
+/* Writes the message digest of the data from stdin onto stdout,
+ followed by a carriage return.
+ */
+static void
+MDFilter ()
+{
+ MD5_CTX mdContext;
+ int bytes;
+ unsigned char data[16];
+
+ MD5Init (&mdContext);
+ while ((bytes = fread (data, 1, 16, stdin)) != 0)
+ MD5Update (&mdContext, data, bytes);
+ MD5Final (&mdContext);
+ MDPrint (&mdContext);
+ printf ("\n");
+}
+
+/* Runs a standard suite of test data.
+ */
+static void
+MDTestSuite ()
+{
+ printf ("MD5 test suite results:\n");
+ MDString ("");
+ MDString ("a");
+ MDString ("abc");
+ MDString ("message digest");
+ MDString ("abcdefghijklmnopqrstuvwxyz");
+ MDString
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ MDString
+ ("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
+}
+
+void
+main (argc, argv)
+int argc;
+char *argv[];
+{
+ int i;
+
+ /* For each command line argument in turn:
+ ** filename -- prints message digest and name of file
+ ** -sstring -- prints message digest and contents of string
+ ** -t -- prints time trial statistics for 10M
+ characters
+ ** -x -- execute a standard suite of test data
+ ** (no args) -- writes messages digest of stdin onto stdout
+ */
+ if (argc == 1)
+ MDFilter ();
+ else
+ for (i = 1; i < argc; i++)
+ if (argv[i][0] == '-' && argv[i][1] == 's')
+ MDString (argv[i] + 2);
+ else if (strcmp (argv[i], "-t") == 0)
+ MDTimeTrial ();
+ else if (strcmp (argv[i], "-x") == 0)
+ MDTestSuite ();
+ else MDFile (argv[i]);
+}
+
+/*
+ ***********************************************************************
+ ** End of md5driver.c **
+ ******************************** (cut) ********************************
+ */
diff --git a/contrib/xntpd/authstuff/mkrandkeys.c b/contrib/xntpd/authstuff/mkrandkeys.c
new file mode 100644
index 000000000000..454b3418bbb1
--- /dev/null
+++ b/contrib/xntpd/authstuff/mkrandkeys.c
@@ -0,0 +1,167 @@
+/* mkrandkeys.c,v 3.1 1993/07/06 01:05:08 jbj Exp
+ * mkrandkeys - make a key file for xntpd with some quite random keys
+ */
+#include <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 ntp_optind;
+ extern char *ntp_optarg;
+ extern char *getpass();
+
+ numkeys = 0;
+ progname = argv[0];
+ passwd = NULL;
+ while ((c = ntp_getopt(argc, argv, "dnp:s")) != EOF)
+ switch (c) {
+ case 'd':
+ ++debug;
+ break;
+ case 'n':
+ std = 0;
+ break;
+ case 'p':
+ passwd = ntp_optarg;
+ break;
+ case 's':
+ std = 1;
+ break;
+ default:
+ errflg++;
+ break;
+ }
+
+ numkeys = 0;
+ for (; !errflg && ntp_optind < argc; ntp_optind++) {
+ c = atoi(argv[ntp_optind]);
+ if (c <= 0 || c > 15) {
+ (void) fprintf(stderr, "%s: invalid key number `%s'\n",
+ progname, argv[ntp_optind]);
+ exit(2);
+ }
+ dokey[c] = 1;
+ numkeys++;
+ }
+
+ if (errflg || numkeys == 0) {
+ (void) fprintf(stderr,
+ "usage: %s [-ns] [-p seed] key# [key# ...]\n",
+ progname);
+ exit(2);
+ }
+
+ while (passwd == 0 || *passwd == '\0') {
+ passwd = getpass("Seed: ");
+ if (*passwd == '\0') {
+ (void) fprintf(stderr,
+ "better use a better seed than that\n");
+ }
+ }
+
+ keydata[0] = keydata[1] = 0;
+ for (i = 0; i < 8 && *passwd != '\0'; i++) {
+ keydata[i/4] |= ((((U_LONG)(*passwd))&0xff)<<(1+((3-(i%4))*8)));
+ passwd++;
+ }
+
+ for (i = 1; i <= 15; i++) {
+ if (dokey[i]) {
+ for (c = 0, tmp = 0; c < 32; c += 4)
+ tmp |= (i << c);
+ keydata[0] ^= tmp;
+ keydata[1] ^= tmp;
+ rand_data(keydata);
+ DESauth_parity(keydata);
+
+ if (std) {
+ (void)printf("%-2d S\t%08x%08x\n",
+ i, keydata[0], keydata[1]);
+ } else {
+ for (j = 0; j < 2; j++) {
+ keydata[j]
+ = ((keydata[j] & 0xfefefefe) >> 1)
+ | ((keydata[j] & 0x01010101) << 7);
+ }
+ (void)printf("%-2d N\t%08x%08x\n",
+ i, keydata[0], keydata[1]);
+ }
+ }
+ }
+ exit(0);
+}
+
+char *volatile_file[] = {
+ "/bin/echo",
+ "/bin/sh",
+ "/bin/cat",
+ "/bin/ls",
+ "/bin/stty",
+ "/bin/date",
+ "/bin/cat",
+ "/bin/cc",
+ "/etc/motd",
+ "/etc/utmp",
+ "/dev/kmem",
+ "/dev/null",
+ "",
+};
+
+#define NEXT(X) (0x1e1f2f2d*(X) + 0x361962e9)
+
+static void
+rand_data(data)
+ U_LONG *data;
+{
+ register i;
+ struct stat buf;
+ extern LONG time();
+ char ekeys[128], dkeys[128];
+
+ *data ^= 0x9662f394;
+ *(data+1) ^= 0x9f17c55f;
+ DESauth_subkeys(data, ekeys, dkeys);
+ *data ^= NEXT(getpid() + (getuid() << 16));
+ *(data+1) ^= NEXT(time((LONG *)0));
+ DESauth_des(data, ekeys);
+ for (i = 0; strlen(volatile_file[i]); i++) {
+ if (stat(volatile_file[i], &buf) == -1)
+ continue;
+ if (i & 1) {
+ *data ^= NEXT(buf.st_atime);
+ *(data+1) ^= NEXT(buf.st_mtime);
+ } else {
+ *data ^= NEXT(buf.st_mtime);
+ *(data+1) ^= NEXT(buf.st_atime);
+ }
+ DESauth_des(data, ekeys);
+ }
+}
diff --git a/contrib/xntpd/authstuff/omakeIPFP.c b/contrib/xntpd/authstuff/omakeIPFP.c
new file mode 100644
index 000000000000..0751a5d96b9c
--- /dev/null
+++ b/contrib/xntpd/authstuff/omakeIPFP.c
@@ -0,0 +1,361 @@
+/* omakeIPFP.c,v 3.1 1993/07/06 01:05:10 jbj Exp
+ * makeIPFP - make fast DES IP and FP tables
+ *
+ * This is an older version which generated tables half the size of
+ * the current version, but which took about double the CPU time to
+ * compute permutations from these tables. Since the CPU spent on the
+ * permutations is small compared to the CPU spent in the cipher code,
+ * I may go back to the smaller tables to save the space some day.
+ */
+
+#include <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 ntp_optind;
+ extern char *ntp_optarg;
+
+ progname = argv[0];
+ while ((c = ntp_getopt(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;
+
+ memset((char *)bits, 0, sizeof bits);
+
+ /*
+ * Do the rounds for the IPL table. We save the results of
+ * this as well as printing them. Note that this is the
+ * left-half table.
+ */
+ printf("static U_LONG IP[8][16] = {");
+ for (tabno = 0; tabno < 8; tabno++) {
+ i = tabno * 4;
+ ind3 = IPLbits[i] - 1;
+ ind2 = IPLbits[i+1] - 1;
+ ind1 = IPLbits[i+2] - 1;
+ ind0 = IPLbits[i+3] - 1;
+ for (quadbits = 0; quadbits < 16; quadbits++) {
+ if (quadbits & (1 << 3))
+ bits[ind3] = 1;
+ if (quadbits & (1 << 2))
+ bits[ind2] = 1;
+ if (quadbits & (1 << 1))
+ bits[ind1] = 1;
+ if (quadbits & 1)
+ bits[ind0] = 1;
+ perm(bits, IP, &left, &right);
+ bits[ind3] = 0;
+ bits[ind2] = 0;
+ bits[ind1] = 0;
+ bits[ind0] = 0;
+ if (right != 0) {
+ fprintf(stderr,
+ "IPL tabno %d quad %d right not zero\n",
+ tabno, quadbits);
+ exit(1);
+ }
+ IPL[tabno][quadbits] = left;
+ if (quadbits == 15 && tabno == 7) {
+ printf(" 0x%08x", left);
+ } else if (quadbits & 0x3) {
+ printf(" 0x%08x,", left);
+ } else {
+ printf("\n\t0x%08x,", left);
+ }
+ }
+ if (tabno == 7)
+ printf("\n};\n");
+ printf("\n");
+ }
+
+ /*
+ * Compute the right half of the same table. I noticed this table
+ * was the same as the previous one, just by luck, so we don't
+ * actually have to do this. Do it anyway just for a check.
+ */
+ for (tabno = 0; tabno < 8; tabno++) {
+ i = tabno * 4;
+ ind3 = IPRbits[i] - 1;
+ ind2 = IPRbits[i+1] - 1;
+ ind1 = IPRbits[i+2] - 1;
+ ind0 = IPRbits[i+3] - 1;
+ for (quadbits = 0; quadbits < 16; quadbits++) {
+ if (quadbits & (1 << 3))
+ bits[ind3] = 1;
+ if (quadbits & (1 << 2))
+ bits[ind2] = 1;
+ if (quadbits & (1 << 1))
+ bits[ind1] = 1;
+ if (quadbits & 1)
+ bits[ind0] = 1;
+ perm(bits, IP, &left, &right);
+ bits[ind3] = 0;
+ bits[ind2] = 0;
+ bits[ind1] = 0;
+ bits[ind0] = 0;
+ if (left != 0) {
+ fprintf(stderr,
+ "IPR tabno %d quad %d left not zero\n",
+ tabno, quadbits);
+ exit(1);
+ }
+ if (right != IPL[tabno][quadbits]) {
+ fprintf(stderr,
+ "IPR tabno %d quad %d: 0x%08x not same as 0x%08x\n",
+ tabno, quadbits, right,IPL[tabno][quadbits]);
+ exit(1);
+ }
+ }
+ }
+
+ /*
+ * Next are the FP tables
+ */
+ printf("static U_LONG FP[8][16] = {");
+ for (tabno = 0; tabno < 8; tabno++) {
+ i = tabno * 4;
+ ind3 = FPLbits[i] - 1;
+ ind2 = FPLbits[i+1] - 1;
+ ind1 = FPLbits[i+2] - 1;
+ ind0 = FPLbits[i+3] - 1;
+ for (quadbits = 0; quadbits < 16; quadbits++) {
+ if (quadbits & (1 << 3))
+ bits[ind3] = 1;
+ if (quadbits & (1 << 2))
+ bits[ind2] = 1;
+ if (quadbits & (1 << 1))
+ bits[ind1] = 1;
+ if (quadbits & 1)
+ bits[ind0] = 1;
+ perm(bits, FP, &left, &right);
+ bits[ind3] = 0;
+ bits[ind2] = 0;
+ bits[ind1] = 0;
+ bits[ind0] = 0;
+ if (right != 0) {
+ fprintf(stderr,
+ "FPL tabno %d quad %d right not zero\n",
+ tabno, quadbits);
+ exit(1);
+ }
+ FPL[tabno][quadbits] = left;
+ if (quadbits == 15 && tabno == 7) {
+ printf(" 0x%08x", left);
+ } else if (quadbits & 0x3) {
+ printf(" 0x%08x,", left);
+ } else {
+ printf("\n\t0x%08x,", left);
+ }
+ }
+ if (tabno == 7)
+ printf("\n};");
+ printf("\n");
+ }
+
+ /*
+ * Right half of same set of tables. This was symmetric too.
+ * Amazing!
+ */
+ for (tabno = 0; tabno < 8; tabno++) {
+ i = tabno * 4;
+ ind3 = FPRbits[i] - 1;
+ ind2 = FPRbits[i+1] - 1;
+ ind1 = FPRbits[i+2] - 1;
+ ind0 = FPRbits[i+3] - 1;
+ for (quadbits = 0; quadbits < 16; quadbits++) {
+ if (quadbits & (1 << 3))
+ bits[ind3] = 1;
+ if (quadbits & (1 << 2))
+ bits[ind2] = 1;
+ if (quadbits & (1 << 1))
+ bits[ind1] = 1;
+ if (quadbits & 1)
+ bits[ind0] = 1;
+ perm(bits, FP, &left, &right);
+ bits[ind3] = 0;
+ bits[ind2] = 0;
+ bits[ind1] = 0;
+ bits[ind0] = 0;
+ if (left != 0) {
+ fprintf(stderr,
+ "FPR tabno %d quad %d left not zero\n",
+ tabno, quadbits);
+ exit(1);
+ }
+ if (right != FPL[tabno][quadbits]) {
+ fprintf(stderr,
+ "FPR tabno %d quad %d: 0x%08x not same as 0x%08x\n",
+ tabno, quadbits, right,FPL[tabno][quadbits]);
+ exit(1);
+ }
+ }
+ }
+}
diff --git a/contrib/xntpd/authstuff/results b/contrib/xntpd/authstuff/results
new file mode 100644
index 000000000000..305a179d0a2c
--- /dev/null
+++ b/contrib/xntpd/authstuff/results
@@ -0,0 +1,2 @@
+odin/1000000: 0.000145
+idavolde/1000000: 0.000451
diff --git a/contrib/xntpd/authstuff/unixcert.c b/contrib/xntpd/authstuff/unixcert.c
new file mode 100644
index 000000000000..36234b13f55f
--- /dev/null
+++ b/contrib/xntpd/authstuff/unixcert.c
@@ -0,0 +1,156 @@
+/* unixcert.c,v 3.1 1993/07/06 01:05:14 jbj Exp
+ * This file, and the certdata file, shamelessly stolen
+ * from Phil Karn's DES implementation.
+ *
+ * This version uses the standard Unix setkey() and encrypt()
+ * routines to do the encryption.
+ */
+
+#include <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/contrib/xntpd/clockstuff/Makefile b/contrib/xntpd/clockstuff/Makefile
new file mode 100644
index 000000000000..0dd3493f7181
--- /dev/null
+++ b/contrib/xntpd/clockstuff/Makefile
@@ -0,0 +1,16 @@
+#
+# $Id: Makefile,v 1.1 1993/12/21 21:06:24 wollman Exp $
+#
+
+PROG= propdelay
+LIBADD= -L${.CURDIR}/../lib -lntp -lm
+DPADD= ${.CURDIR}/../lib/libntp.a
+
+SRCS= propdelay.c
+NOMAN=
+
+install:
+
+CLEANFILES+= chutest clktest chutest.o clktest.o
+
+.include <bsd.prog.mk>
diff --git a/contrib/xntpd/clockstuff/README b/contrib/xntpd/clockstuff/README
new file mode 100644
index 000000000000..3714ab3b4767
--- /dev/null
+++ b/contrib/xntpd/clockstuff/README
@@ -0,0 +1,31 @@
+README file for directory ./clockstuff of the NTP Version 3 distribution
+
+This directory contains the sources for utility programs designed to
+support radio clocks. The chutest.c and clktest.c are desgined to
+test the chu_clk and tty_clk line disciplines and STREAMS modules in
+the ../kernel directory.
+
+These files have been modified to work with either the line disciplines
+or the STREAMS modules. Be sure to define -DSTREAM if appropriate.
+
+These are random bits of things written to help with clocks. You can
+make things in here by typing one or more of:
+
+ make propdelay (or `make')
+ make chutest
+ make clktest
+
+Propdelay computes high frequency propagation delays, given the
+longitude and latitude of the transmitter and receiver. Use
+this for WWV/H and CHU. Don't use it for WWVB (the computation
+is easier for that).
+
+Chutest can be used to input and process data from a CHU modem
+attached to a serial port. It will use the CHU line discipline
+(if installed), or raw mode otherwise. This was used to test
+out the initial reduction algorithms, and may not be up to date.
+
+Clktest can be used to test the clock line discipline (CLKLDISC,
+it must be available), and to take a look at radio clocks attached to a
+serial port.
+
diff --git a/contrib/xntpd/clockstuff/chutest.c b/contrib/xntpd/clockstuff/chutest.c
new file mode 100644
index 000000000000..2bf058c3b012
--- /dev/null
+++ b/contrib/xntpd/clockstuff/chutest.c
@@ -0,0 +1,798 @@
+/* chutest.c,v 3.1 1993/07/06 01:05:21 jbj Exp
+ * chutest - test the CHU clock
+ */
+
+#include <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 ntp_optind;
+ extern char *ntp_optarg;
+ void init_chu();
+
+ progname = argv[0];
+ while ((c = ntp_getopt(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 || ntp_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[ntp_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/contrib/xntpd/clockstuff/clktest.c b/contrib/xntpd/clockstuff/clktest.c
new file mode 100644
index 000000000000..b54048576c41
--- /dev/null
+++ b/contrib/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 ntp_optind;
+ extern char *ntp_optarg;
+ int alarming();
+ int ioready();
+
+ progname = argv[0];
+#ifdef STREAM
+ magic[0] = 0;
+#endif
+ while ((c = ntp_getopt(argc, argv, "a:b:c:dfs:t:")) != EOF)
+ switch (c) {
+#ifdef CLKLDISC
+ case 'a':
+#endif
+ case 'c':
+ if (!atouint(ntp_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(ntp_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(ntp_optarg);
+ if (cmdlen == 0)
+ errflg++;
+ else
+ cmd = ntp_optarg;
+ break;
+ case 't':
+ if (!atouint(ntp_optarg, &tmp))
+ errflg++;
+ else {
+ timeout.tv_sec = (long)tmp;
+ docmd = 1;
+ }
+ break;
+ default:
+ errflg++;
+ break;
+ }
+ if (errflg || ntp_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[ntp_optind], O_RDWR, 0777);
+ else
+ fd = open(argv[ntp_optind], O_RDONLY, 0777);
+ if (fd == -1) {
+ (void) fprintf(stderr, "%s: open(%s): ", progname,
+ argv[ntp_optind]);
+ perror("");
+ exit(1);
+ }
+
+ if (ioctl(fd, TIOCEXCL, (char *)0) < 0) {
+ (void) fprintf(stderr, "%s: ioctl(TIOCEXCL): ", progname);
+ perror("");
+ exit(1);
+ }
+
+ /*
+ * If we have the clock discipline, set the port to raw. Otherwise
+ * we run cooked.
+ */
+ ttyb.sg_ispeed = ttyb.sg_ospeed = speed;
+#ifdef CLKLDISC
+ ttyb.sg_erase = (char)magic1;
+ ttyb.sg_kill = (char)magic2;
+#endif
+ ttyb.sg_flags = (short)ttflags;
+ if (ioctl(fd, TIOCSETP, (char *)&ttyb) < 0) {
+ (void) fprintf(stderr, "%s: ioctl(TIOCSETP): ", progname);
+ perror("");
+ exit(1);
+ }
+
+ if (fcntl(fd, F_SETOWN, getpid()) == -1) {
+ (void) fprintf(stderr, "%s: fcntl(F_SETOWN): ", progname);
+ perror("");
+ exit(1);
+ }
+
+#ifdef CLKLDISC
+ {
+ int ldisc;
+ ldisc = CLKLDISC;
+ if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) {
+ (void) fprintf(stderr, "%s: ioctl(TIOCSETD): ", progname);
+ perror("");
+ exit(1);
+ }
+ }
+#endif
+#ifdef STREAM
+ if (ioctl(fd, I_POP, 0) >=0 ) ;
+ if (ioctl(fd, I_PUSH, "clk") < 0) {
+ (void) fprintf(stderr, "%s: ioctl(I_PUSH): ", progname);
+ perror("");
+ exit(1);
+ }
+ if (ioctl(fd, CLK_SETSTR, magic) < 0) {
+ (void) fprintf(stderr, "%s: ioctl(CLK_SETSTR): ", progname);
+ perror("");
+ exit(1);
+ }
+#endif
+
+
+ (void) gettimeofday(&lasttv, (struct timezone *)0);
+ if (docmd) {
+ /*
+ * set non-blocking, async I/O on the descriptor
+ */
+ iosig = 0;
+ (void) signal(SIGIO, ioready);
+ if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) {
+ (void) fprintf(stderr, "%s: fcntl(F_SETFL): ",
+ progname);
+ perror("");
+ exit(1);
+ }
+
+ /*
+ * Set up the alarm interrupt.
+ */
+ wasalarmed = 0;
+ (void) signal(SIGALRM, alarming);
+ itimer.it_interval = itimer.it_value = timeout;
+ setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+ doboth(fd);
+ }
+ doioonly(fd);
+}
+
+
+/*
+ * doboth - handle both I/O and alarms via SIGIO
+ */
+doboth(fd)
+ int fd;
+{
+ int n;
+ int sawalarm;
+ int sawiosig;
+ int omask;
+ fd_set fds;
+ struct timeval tvzero;
+
+ sawalarm = 0;
+ sawiosig = 0;
+ FD_ZERO(&fds);
+ for (;;) {
+ omask = sigblock(BLOCKSIGMASK);
+ if (wasalarmed) { /* alarmed? */
+ sawalarm = 1;
+ wasalarmed = 0;
+ }
+ if (iosig) {
+ sawiosig = 1;
+ iosig = 0;
+ }
+
+ if (!sawalarm && !sawiosig) {
+ /*
+ * Nothing to do. Wait for something.
+ */
+ sigpause(omask);
+ if (wasalarmed) { /* alarmed? */
+ sawalarm = 1;
+ wasalarmed = 0;
+ }
+ if (iosig) {
+ sawiosig = 1;
+ iosig = 0;
+ }
+ }
+ (void)sigsetmask(omask);
+
+ if (sawiosig) {
+
+ do {
+ tvzero.tv_sec = tvzero.tv_usec = 0;
+ FD_SET(fd, &fds);
+ n = select(fd+1, &fds, (fd_set *)0,
+ (fd_set *)0, &tvzero);
+ if (n > 0)
+ doio(fd);
+ } while (n > 0);
+
+ if (n == -1) {
+ (void) fprintf(stderr, "%s: select: ",
+ progname);
+ perror("");
+ exit(1);
+ }
+ sawiosig = 0;
+ }
+ if (sawalarm) {
+ doalarm(fd);
+ sawalarm = 0;
+ }
+ }
+}
+
+
+/*
+ * doioonly - do I/O. This avoids the use of signals
+ */
+doioonly(fd)
+ int fd;
+{
+ int n;
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ for (;;) {
+ FD_SET(fd, &fds);
+ n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0,
+ (struct timeval *)0);
+ if (n > 0)
+ doio(fd);
+ }
+}
+
+
+/*
+ * doio - read a buffer full of stuff and print it out
+ */
+doio(fd)
+ int fd;
+{
+ register char *rp, *rpend;
+ register char *cp;
+ register int i;
+ char raw[512];
+ struct timeval tv, tvd;
+ int rlen;
+ int ind;
+ char cooked[2049];
+ static char *digits = "0123456789abcdef";
+
+ rlen = read(fd, raw, sizeof(raw));
+ if (rlen < 0) {
+ (void) fprintf(stderr, "%s: read(): ", progname);
+ perror("");
+ return;
+ }
+ if (rlen == 0) {
+ (void) printf("Zero length read\n");
+ return;
+ }
+
+ cp = cooked;
+ rp = raw;
+ rpend = &raw[rlen];
+ ind = 0;
+
+ while (rp < rpend) {
+ ind = 1;
+ if (isprint(*rp))
+ *cp++ = *rp;
+ else {
+ *cp++ = '<';
+ *cp++ = digits[((*rp)>>4) & 0xf];
+ *cp++ = digits[*rp & 0xf];
+ *cp++ = '>';
+ }
+#ifdef CLKLDISC
+ if (*rp == (char)magic1 || *rp == (char)magic2) {
+#else
+ if ( strchr( magic, *rp) != NULL ) {
+#endif
+ rp++;
+ ind = 0;
+ *cp = '\0';
+ if ((rpend - rp) < sizeof(struct timeval)) {
+ (void)printf(
+ "Too little data (%d): %s\n",
+ rpend-rp, cooked);
+ return;
+ }
+
+ tv.tv_sec = 0;
+ for (i = 0; i < 4; i++) {
+ tv.tv_sec <<= 8;
+ tv.tv_sec |= ((long)*rp++) & 0xff;
+ }
+ tv.tv_usec = 0;
+ for (i = 0; i < 4; i++) {
+ tv.tv_usec <<= 8;
+ tv.tv_usec |= ((long)*rp++) & 0xff;
+ }
+
+ tvd.tv_sec = tv.tv_sec - lasttv.tv_sec;
+ tvd.tv_usec = tv.tv_usec - lasttv.tv_usec;
+ if (tvd.tv_usec < 0) {
+ tvd.tv_usec += 1000000;
+ tvd.tv_sec--;
+ }
+
+ (void)printf("%lu.%06lu %lu.%06lu %s\n",
+ tv.tv_sec, tv.tv_usec, tvd.tv_sec, tvd.tv_usec,
+ cooked);
+ lasttv = tv;
+ } else {
+ rp++;
+ }
+ }
+
+ if (ind) {
+ *cp = '\0';
+ (void)printf("Incomplete data: %s\n", cooked);
+ }
+}
+
+
+/*
+ * doalarm - send a string out the port, if we have one.
+ */
+doalarm(fd)
+ int fd;
+{
+ int n;
+
+ if (cmd == NULL || cmdlen <= 0)
+ return;
+
+ n = write(fd, cmd, cmdlen);
+
+ if (n < 0) {
+ (void) fprintf(stderr, "%s: write(): ", progname);
+ perror("");
+ } else if (n < cmdlen) {
+ (void) printf("Short write (%d bytes, should be %d)\n",
+ n, cmdlen);
+ }
+}
+
+
+/*
+ * alarming - receive alarm interupt
+ */
+alarming()
+{
+ wasalarmed = 1;
+}
+
+/*
+ * ioready - handle SIGIO interrupt
+ */
+ioready()
+{
+ iosig = 1;
+}
diff --git a/contrib/xntpd/clockstuff/propdelay.c b/contrib/xntpd/clockstuff/propdelay.c
new file mode 100644
index 000000000000..0c1f1bb3e38c
--- /dev/null
+++ b/contrib/xntpd/clockstuff/propdelay.c
@@ -0,0 +1,536 @@
+/* propdelay.c,v 3.1 1993/07/06 01:05:24 jbj Exp
+ * propdelay - compute propagation delays
+ *
+ * cc -o propdelay propdelay.c -lm
+ *
+ * "Time and Frequency Users' Manual", NBS Technical Note 695 (1977).
+ */
+
+/*
+ * This can be used to get a rough idea of the HF propagation delay
+ * between two points (usually between you and the radio station).
+ * The usage is
+ *
+ * propdelay latitudeA longitudeA latitudeB longitudeB
+ *
+ * where points A and B are the locations in question. You obviously
+ * need to know the latitude and longitude of each of the places.
+ * The program expects the latitude to be preceded by an 'n' or 's'
+ * and the longitude to be preceded by an 'e' or 'w'. It understands
+ * either decimal degrees or degrees:minutes:seconds. Thus to compute
+ * the delay between the WWVH (21:59:26N, 159:46:00W) and WWV (40:40:49N,
+ * 105:02:27W) you could use:
+ *
+ * propdelay n21:59:26 w159:46 n40:40:49 w105:02:27
+ *
+ * By default it prints out a summer (F2 average virtual height 350 km) and
+ * winter (F2 average virtual height 250 km) number. The results will be
+ * quite approximate but are about as good as you can do with HF time anyway.
+ * You might pick a number between the values to use, or use the summer
+ * value in the summer and switch to the winter value when the static
+ * above 10 MHz starts to drop off in the fall. You can also use the
+ * -h switch if you want to specify your own virtual height.
+ *
+ * You can also do a
+ *
+ * propdelay -W n45:17:47 w75:45:22
+ *
+ * to find the propagation delays to WWV and WWVH (from CHU in this
+ * case), a
+ *
+ * propdelay -C n40:40:49 w105:02:27
+ *
+ * to find the delays to CHU, and a
+ *
+ * propdelay -G n52:03:17 w98:34:18
+ *
+ * to find delays to GOES via each of the three satellites.
+ */
+
+#include <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 ntp_optind;
+ extern char *ntp_optarg;
+
+ progname = argv[0];
+ while ((c = ntp_getopt(argc, argv, "dh:CWG")) != EOF)
+ switch (c) {
+ case 'd':
+ ++debug;
+ break;
+ case 'h':
+ hflag++;
+ height = atof(ntp_optarg);
+ if (height <= 0.0) {
+ (void) fprintf(stderr, "height %s unlikely\n",
+ ntp_optarg);
+ errflg++;
+ }
+ break;
+ case 'C':
+ Cflag++;
+ break;
+ case 'W':
+ Wflag++;
+ break;
+ case 'G':
+ Gflag++;
+ break;
+ default:
+ errflg++;
+ break;
+ }
+ if (errflg || (!(Cflag || Wflag || Gflag) && ntp_optind+4 != argc) ||
+ ((Cflag || Wflag || Gflag) && ntp_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[ntp_optind], 1);
+ long1 = latlong(argv[ntp_optind + 1], 0);
+ lat2 = latlong(argv[ntp_optind + 2], 1);
+ long2 = latlong(argv[ntp_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[ntp_optind], 1);
+ long1 = latlong(argv[ntp_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[ntp_optind], 1);
+ long1 = latlong(argv[ntp_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[ntp_optind], 1);
+ long3 = latlong(argv[ntp_optind + 1], 0);
+
+ lat2 = latlong(goes_sat_lat, 1);
+
+ long2 = latlong(goes_west_long, 0);
+ satdoit(lat1, long1, lat2, long2, lat3, long3,
+ "GOES Delay via WEST");
+
+ long2 = latlong(goes_stby_long, 0);
+ satdoit(lat1, long1, lat2, long2, lat3, long3,
+ "GOES Delay via STBY");
+
+ long2 = latlong(goes_east_long, 0);
+ satdoit(lat1, long1, lat2, long2, lat3, long3,
+ "GOES Delay via EAST");
+
+ }
+ exit(0);
+}
+
+
+/*
+ * doit - compute a delay and print it
+ */
+static void
+doit(lat1, long1, lat2, long2, h, str)
+ double lat1;
+ double long1;
+ double lat2;
+ double long2;
+ double h;
+ char *str;
+{
+ int hops;
+ double delay;
+
+ hops = finddelay(lat1, long1, lat2, long2, h, &delay);
+ printf("%sheight %g km, hops %d, delay %g seconds\n",
+ str, h, hops, delay);
+}
+
+
+/*
+ * latlong - decode a latitude/longitude value
+ */
+static double
+latlong(str, islat)
+ char *str;
+ int islat;
+{
+ register char *cp;
+ register char *bp;
+ double arg;
+ double div;
+ int isneg;
+ char buf[32];
+ char *colon;
+
+ if (islat) {
+ /*
+ * Must be north or south
+ */
+ if (*str == 'N' || *str == 'n')
+ isneg = 0;
+ else if (*str == 'S' || *str == 's')
+ isneg = 1;
+ else
+ isneg = -1;
+ } else {
+ /*
+ * East is positive, west is negative
+ */
+ if (*str == 'E' || *str == 'e')
+ isneg = 0;
+ else if (*str == 'W' || *str == 'w')
+ isneg = 1;
+ else
+ isneg = -1;
+ }
+
+ if (isneg >= 0)
+ str++;
+
+ colon = strchr(str, ':');
+ if (colon != NULL) {
+ /*
+ * in hhh:mm:ss form
+ */
+ cp = str;
+ bp = buf;
+ while (cp < colon)
+ *bp++ = *cp++;
+ *bp = '\0';
+ cp++;
+ arg = atof(buf);
+ div = 60.0;
+ colon = strchr(cp, ':');
+ if (colon != NULL) {
+ bp = buf;
+ while (cp < colon)
+ *bp++ = *cp++;
+ *bp = '\0';
+ cp++;
+ arg += atof(buf) / div;
+ div = 3600.0;
+ }
+ if (*cp != '\0')
+ arg += atof(cp) / div;
+ } else {
+ arg = atof(str);
+ }
+
+ if (isneg == 1)
+ arg = -arg;
+
+ if (debug > 2)
+ (void) printf("latitude/longitude %s = %g\n", str, arg);
+
+ return arg;
+}
+
+
+/*
+ * greatcircle - compute the great circle distance in kilometers
+ */
+static double
+greatcircle(lat1, long1, lat2, long2)
+ double lat1;
+ double long1;
+ double lat2;
+ double long2;
+{
+ double dg;
+ double l1r, l2r;
+
+ l1r = lat1 * RADPERDEG;
+ l2r = lat2 * RADPERDEG;
+ dg = EARTHRADIUS * acos(
+ (cos(l1r) * cos(l2r) * cos((long2-long1)*RADPERDEG))
+ + (sin(l1r) * sin(l2r)));
+ if (debug >= 2)
+ printf(
+ "greatcircle lat1 %g long1 %g lat2 %g long2 %g dist %g\n",
+ lat1, long1, lat2, long2, dg);
+ return dg;
+}
+
+
+/*
+ * waveangle - compute the wave angle for the given distance, virtual
+ * height and number of hops.
+ */
+static double
+waveangle(dg, h, n)
+ double dg;
+ double h;
+ int n;
+{
+ double theta;
+ double delta;
+
+ theta = dg / (EARTHRADIUS * (double)(2 * n));
+ delta = atan((h / (EARTHRADIUS * sin(theta))) + tan(theta/2)) - theta;
+ if (debug >= 2)
+ printf("waveangle dist %g height %g hops %d angle %g\n",
+ dg, h, n, delta / RADPERDEG);
+ return delta;
+}
+
+
+/*
+ * propdelay - compute the propagation delay
+ */
+static double
+propdelay(dg, h, n)
+ double dg;
+ double h;
+ int n;
+{
+ double phi;
+ double theta;
+ double td;
+
+ theta = dg / (EARTHRADIUS * (double)(2 * n));
+ phi = (PI/2.0) - atan((h / (EARTHRADIUS * sin(theta))) + tan(theta/2));
+ td = dg / (LIGHTSPEED * sin(phi));
+ if (debug >= 2)
+ printf("propdelay dist %g height %g hops %d time %g\n",
+ dg, h, n, td);
+ return td;
+}
+
+
+/*
+ * finddelay - find the propagation delay
+ */
+static int
+finddelay(lat1, long1, lat2, long2, h, delay)
+ double lat1;
+ double long1;
+ double lat2;
+ double long2;
+ double h;
+ double *delay;
+{
+ double dg; /* great circle distance */
+ double delta; /* wave angle */
+ int n; /* number of hops */
+
+ dg = greatcircle(lat1, long1, lat2, long2);
+ if (debug)
+ printf("great circle distance %g km %g miles\n", dg, dg/MILE);
+
+ n = 1;
+ while ((delta = waveangle(dg, h, n)) < 0.0) {
+ if (debug)
+ printf("tried %d hop%s, no good\n", n, n>1?"s":"");
+ n++;
+ }
+ if (debug)
+ printf("%d hop%s okay, wave angle is %g\n", n, n>1?"s":"",
+ delta / RADPERDEG);
+
+ *delay = propdelay(dg, h, n);
+ return n;
+}
+
+/*
+ * satdoit - compute a delay and print it
+ */
+static void
+satdoit(lat1, long1, lat2, long2, lat3, long3, str)
+ double lat1;
+ double long1;
+ double lat2;
+ double long2;
+ double lat3;
+ double long3;
+ char *str;
+{
+ double up_delay,down_delay;
+
+ satfinddelay(lat1, long1, lat2, long2, &up_delay);
+ satfinddelay(lat3, long3, lat2, long2, &down_delay);
+
+ printf("%s, delay %g seconds\n", str, up_delay + down_delay);
+}
+
+/*
+ * satfinddelay - calculate the one-way delay time between a ground station
+ * and a satellite
+ */
+static void
+satfinddelay(lat1, long1, lat2, long2, delay)
+ double lat1;
+ double long1;
+ double lat2;
+ double long2;
+ double *delay;
+{
+ double dg; /* great circle distance */
+
+ dg = greatcircle(lat1, long1, lat2, long2);
+
+ *delay = satpropdelay(dg);
+}
+
+/*
+ * satpropdelay - calculate the one-way delay time between a ground station
+ * and a satellite
+ */
+static double
+satpropdelay(dg)
+ double dg;
+{
+ double k1, k2, dist;
+ double theta;
+ double td;
+
+ theta = dg / (EARTHRADIUS);
+ k1 = EARTHRADIUS * sin(theta);
+ k2 = SATHEIGHT - (EARTHRADIUS * cos(theta));
+ if (debug >= 2)
+ printf("Theta %g k1 %g k2 %g\n", theta, k1, k2);
+ dist = sqrt(k1*k1 + k2*k2);
+ td = dist / LIGHTSPEED;
+ if (debug >= 2)
+ printf("propdelay dist %g height %g time %g\n", dg, dist, td);
+ return td;
+}
diff --git a/contrib/xntpd/compilers/.keep_me b/contrib/xntpd/compilers/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/compilers/.keep_me
diff --git a/contrib/xntpd/conf/Config.CHATHAM b/contrib/xntpd/conf/Config.CHATHAM
new file mode 100644
index 000000000000..b1f980be477b
--- /dev/null
+++ b/contrib/xntpd/conf/Config.CHATHAM
@@ -0,0 +1,211 @@
+# 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.
+#
+# 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 -DNTP_POSIX_SOURCE
+
+#
+# Authentication types supported. Choose from DES and MD5. If you
+# have a 680x0 type CPU and GNU-C, also choose -DFASTMD5
+#
+AUTHDEFS=-DDES -DMD5
+
+#
+# Clock support definitions (these only make sense if -DREFCLOCK used):
+#
+# Define -DLOCAL_CLOCK to include local pseudo-clock support
+#
+# Define -DPST to include support for the PST 1020 WWV/H receiver.
+#
+# Define -DWWVB to include support for the Spectracom 8170 WWVB receiver.
+# Define -DWWVBPPS for PPS support via the WWVB receiver; also,
+# define -DPPSCD in the DEFS above. This requires the ppsclock
+# streams module under SunOS 4.2.
+#
+# Define -DCHU to include support for a driver to receive the CHU
+# timecode. Note that to compile in CHU support you must
+# previously have installed the CHU serial line discipline in
+# the kernel of the machine you are doing the compile on.
+#
+# Define -DDCF to include support for the DCF77 receiver. This code
+# requires a special STREAMS module found in the kernel directory.
+# Define -DDCFPPS for PPS support via the DCF77 receiver; also,
+# devine -DPPS in the DEFS above.
+#
+# Define -DMX4200 to support a Magnavox 4200 GPS receiver. Define -DPPSCD
+# in the DEFS above for PPS support via this receiver. This requires
+# the ppsclock streams module under SunOS 4.2.
+#
+# Define -DAS2201 to include support for the Austron 2201 GPS Timing
+# Receiver. Define -DPPSCD in the DEFS above for PPS support via this
+# receiver. This requires the ppsclock streams module under SunOS 4.2.
+#
+# Define -DGOES to support a Kinemetrics TrueTime 468-DC GOES receiver. This
+# driver may work with other True-Time products as well.
+#
+# Define -DOMEGA to support a Kinemetrics TrueTime OM-DC OMEGA receiver.
+#
+# Define -DTPRO to support a KSI/Odetics TPRO-S IRIG-B timecode reader. This
+# requires the Sun interface driver available from KSI.
+#
+# Define -DLEITCH to support a Leitch CSD 5300 Master Clock System Driver
+# for the HP 5061B Cesium Clock.
+#
+CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DWWVBPPS -DCHU -DDCF -DMX4200 -DAS2201 -DGOES -DOMEGA -DTPRO -DLEITCH -DIRIG
+
+#
+# For MIPS 4.3BSD or RISCos 4.0, include a -lmld to get the nlist() routine.
+# If USELIBKVM is defined above, include a -lkvm to get the kernel
+# routines.
+#
+#DAEMONLIBS= -lmld
+DAEMONLIBS= -lkvm
+#DAEMONLIBS=
+
+#
+# Name resolver library. Included when loading xntpres, which calls
+# gethostbyname(). Define this if you would rather use a different
+# version of the routine than the one in libc.a
+#
+#RESLIB= -lresolv
+RESLIB=
+
+#
+# Option flags for the C compiler. A -g if you are uncomfortable
+#
+COPTS= -O
+
+#
+# C compiler to use. gcc will work, but avoid the -fstrength-reduce option
+# if the version is 1.35 or earlier (using this option caused incorrect
+# code to be generated in the DES key permutation code, and perhaps
+# elsewhere).
+#
+COMPILER= gcc -pipe -Wall -g -O2 -finline-functions -fdelayed-branch -fomit-frame-pointer
+#COMPILER= cc -pipe
+
+#
+# Directory into which binaries should be installed
+#
+BINDIR= /usr/local/bin
+
+#
+# Special library for adjtime emulation. Used under HP-UX
+# (remember to run make in the adjtime directory)
+#
+#ADJLIB= ../adjtime/libadjtime.a
+ADJLIB=
+
+#
+# BSD emulation library. In theory, this fixes signal semantics under
+# HP-UX, but it doesn't work with 8.0 on a 9000s340, so there is now
+# a work-around in the code (compiled when hpux80 is defined). In other
+# words, use this for HP-UX prior to 8.0.
+#
+#COMPAT= -lBSD
+COMPAT=
+
diff --git a/contrib/xntpd/conf/Config.MONOMOY b/contrib/xntpd/conf/Config.MONOMOY
new file mode 100644
index 000000000000..18dddffe6ff1
--- /dev/null
+++ b/contrib/xntpd/conf/Config.MONOMOY
@@ -0,0 +1,186 @@
+# 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.
+#
+# 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\\" -DNTP_POSIX_SOURCE
+
+#
+# Authentication types supported. Choose from DES and MD5. If you
+# have a 680x0 type CPU and GNU-C, also choose -DFASTMD5
+#
+AUTHDEFS=-DDES -DMD5
+
+#
+# Clock support definitions (these only make sense if -DREFCLOCK used):
+#
+# Define -DLOCAL_CLOCK to include local pseudo-clock support
+#
+# Define -DPST to include support for the PST 1020 WWV/H receiver.
+#
+# Define -DWWVB to include support for the Spectracom 8170 WWVB receiver.
+#
+# Define -DCHU to include support for a driver to receive the CHU
+# timecode. Note that to compile in CHU support you must
+# previously have installed the CHU serial line discipline in
+# the kernel of the machine you are doing the compile on.
+#
+# Define -DDCF to include support for the DCF77 receiver. This code
+# requires a special STREAMS module found in the kernel directory.
+# Define -DDCFPPS for PPS support via the DCF77 receiver
+# (see also: -DPPS)
+#
+# Define -DGOES to support a Kinemetrics TrueTime 468-DC GOES receiver.
+#
+CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DCHU -DGOES # -DMX4200 -DAS2201
+
+#
+# For MIPS 4.3BSD or RISCos 4.0, include a -lmld to get the nlist() routine.
+# If USELIBKVM is defined above, include a -lkvm to get the kernel
+# routines.
+#
+#DAEMONLIBS= -lmld
+DAEMONLIBS= -lkvm
+#DAEMONLIBS=
+
+#
+# Name resolver library. Included when loading xntpres, which calls
+# gethostbyname(). Define this if you would rather use a different
+# version of the routine than the one in libc.a
+#
+#RESLIB= -lresolv
+RESLIB=
+
+#
+# Option flags for the C compiler. A -g if you are uncomfortable
+#
+COPTS= -O
+
+#
+# C compiler to use. gcc will work, but avoid the -fstrength-reduce option
+# if the version is 1.35 or earlier (using this option caused incorrect
+# code to be generated in the DES key permutation code, and perhaps
+# elsewhere).
+#
+COMPILER= gcc -pipe -Wall -g -O -finline-functions -fdelayed-branch -fomit-frame-pointer
+#COMPILER= cc -pipe -g
+
+#
+# Directory into which binaries should be installed
+#
+BINDIR= /usr/local/bin
+
+#
+# Special library for adjtime emulation. Used under HP-UX
+# (remember to run make in the adjtime directory)
+#
+#ADJLIB= ../adjtime/libadjtime.a
+ADJLIB=
+
+#
+# BSD emulation library. In theory, this fixes signal semantics under
+# HP-UX, but it doesn't work with 8.0 on a 9000s340, so there is now
+# a work-around in the code (compiled when hpux80 is defined). In other
+# words, use this for HP-UX prior to 8.0.
+#
+#COMPAT= -lBSD
+COMPAT=
+
diff --git a/contrib/xntpd/conf/Config.TIGER b/contrib/xntpd/conf/Config.TIGER
new file mode 100644
index 000000000000..29c6cbd28cbe
--- /dev/null
+++ b/contrib/xntpd/conf/Config.TIGER
@@ -0,0 +1,182 @@
+# 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.
+#
+# 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 -DNTP_POSIX_SOURCE
+
+#
+# Authentication types supported. Choose from DES and MD5. If you
+# have a 680x0 type CPU and GNU-C, also choose -DFASTMD5
+#
+AUTHDEFS=-DDES -DMD5
+
+#
+# Clock support definitions (these only make sense if -DREFCLOCK used):
+#
+# Define -DLOCAL_CLOCK to include local pseudo-clock support
+#
+# Define -DPST to include support for the PST 1020 WWV/H receiver.
+#
+# Define -DWWVB to include support for the Spectracom 8170 WWVB receiver.
+#
+# Define -DCHU to include support for a driver to receive the CHU
+# timecode. Note that to compile in CHU support you must
+# previously have installed the CHU serial line discipline in
+# the kernel of the machine you are doing the compile on.
+#
+# Define -DDCF to include support for the DCF77 receiver. This code
+# requires a special STREAMS module found in the kernel directory.
+# Define -DDCFPPS for PPS support via the DCF77 receiver
+# (see also: -DPPS)
+#
+# Define -DGOES to support a Kinemetrics TrueTime 468-DC GOES receiver.
+#
+CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DGOES -DCHU
+
+#
+# For MIPS 4.3BSD or RISCos 4.0, include a -lmld to get the nlist() routine.
+# If USELIBKVM is defined above, include a -lkvm to get the kernel
+# routines.
+#
+#DAEMONLIBS= -lmld
+#DAEMONLIBS= -lkvm
+DAEMONLIBS=
+
+#
+# Name resolver library. Included when loading xntpres, which calls
+# gethostbyname(). Define this if you would rather use a different
+# version of the routine than the one in libc.a
+#
+#RESLIB= -lresolv
+RESLIB=
+
+#
+# Option flags for the C compiler. A -g if you are uncomfortable
+#
+COPTS= -O
+
+#
+# C compiler to use. gcc will work, but avoid the -fstrength-reduce option
+# if the version is 1.35 or earlier (using this option caused incorrect
+# code to be generated in the DES key permutation code, and perhaps
+# elsewhere).
+#
+COMPILER= gcc -Wall -g -O2 -finline-functions -fdelayed-branch -fomit-frame-pointer
+#COMPILER= cc
+
+#
+# Directory into which binaries should be installed
+#
+BINDIR= /usr/local/bin
+
+#
+# Special library for adjtime emulation. Used under HP-UX
+# (remember to run make in the adjtime directory)
+#
+#ADJLIB= ../adjtime/libadjtime.a
+ADJLIB=
+
+#
+# BSD emulation library. In theory, this fixes signal semantics under
+# HP-UX, but it doesn't work with 8.0 on a 9000s340, so there is now
+# a work-around in the code (compiled when hpux80 is defined). In other
+# words, use this for HP-UX prior to 8.0.
+#
+#COMPAT= -lBSD
+COMPAT=
+
diff --git a/contrib/xntpd/conf/Config.TRURO b/contrib/xntpd/conf/Config.TRURO
new file mode 100644
index 000000000000..2fc258002096
--- /dev/null
+++ b/contrib/xntpd/conf/Config.TRURO
@@ -0,0 +1,202 @@
+# 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.
+#
+# 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 -DNTP_POSIX_SOURCE
+
+#
+# Authentication types supported. Choose from DES and MD5. If you
+# have a 680x0 type CPU and GNU-C, also choose -DFASTMD5
+#
+AUTHDEFS=-DDES -DMD5
+
+#
+# Clock support definitions (these only make sense if -DREFCLOCK used):
+#
+# Define -DLOCAL_CLOCK to include local pseudo-clock support
+#
+# Define -DPST to include support for the PST 1020 WWV/H receiver.
+#
+# Define -DWWVB to include support for the Spectracom 8170 WWVB receiver.
+# Define -DWWVBPPS for PPS support via the WWVB receiver; also,
+# define -DPPSCD in the DEFS above. This requires the ppsclock
+# streams module under SunOS 4.2.
+#
+# Define -DCHU to include support for a driver to receive the CHU
+# timecode. Note that to compile in CHU support you must
+# previously have installed the CHU serial line discipline in
+# the kernel of the machine you are doing the compile on.
+#
+# Define -DDCF to include support for the DCF77 receiver. This code
+# requires a special STREAMS module found in the kernel directory.
+# Define -DDCFPPS for PPS support via the DCF77 receiver; also,
+# devine -DPPS in the DEFS above.
+#
+# Define -DMX4200 to support a Magnavox 4200 GPS receiver. Define -DPPSCD
+# in the DEFS above for PPS support via this receiver. This requires
+# the ppsclock streams module under SunOS 4.2.
+#
+# Define -DAS2201 to include support for the Austron 2201 GPS Timing
+# Receiver. Define -DPPSCD in the DEFS above for PPS support via this
+# receiver. This requires the ppsclock streams module under SunOS 4.2.
+#
+# Define -DGOES to support a Kinemetrics TrueTime 468-DC GOES receiver. This
+# driver may work with other True-Time products as well.
+#
+CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DWWVBPPS -DGOES -DCHU -DMX4200 -DAS2201 -DOMEGA -DTPRO -DLEITCH -DIRIG
+
+#
+# For MIPS 4.3BSD or RISCos 4.0, include a -lmld to get the nlist() routine.
+# If USELIBKVM is defined above, include a -lkvm to get the kernel
+# routines.
+#
+#DAEMONLIBS= -lmld
+DAEMONLIBS=
+
+#
+# Name resolver library. Included when loading xntpres, which calls
+# gethostbyname(). Define this if you would rather use a different
+# version of the routine than the one in libc.a
+#
+#RESLIB= -lresolv
+RESLIB= -lsocket -lnsl -lelf
+
+#
+# Option flags for the C compiler. A -g if you are uncomfortable
+#
+COPTS= -O
+
+#
+# C compiler to use. gcc will work, but avoid the -fstrength-reduce option
+# if the version is 1.35 or earlier (using this option caused incorrect
+# code to be generated in the DES key permutation code, and perhaps
+# elsewhere).
+#
+#COMPILER= gcc -traditional
+COMPILER= gcc -pipe -Wall -g -O2 -finline-functions -fdelayed-branch -fomit-frame-pointer
+
+#
+# Directory into which binaries should be installed
+#
+BINDIR= /usr/local/bin
+
+#
+# Special library for adjtime emulation. Used under HP-UX
+# (remember to run make in the adjtime directory)
+#
+#ADJLIB= ../adjtime/libadjtime.a
+ADJLIB=
+
+#
+# BSD emulation library. In theory, this fixes signal semantics under
+# HP-UX, but it doesn't work with 8.0 on a 9000s340, so there is now
+# a work-around in the code (compiled when hpux80 is defined). In other
+# words, use this for HP-UX prior to 8.0.
+#
+#COMPAT= -lBSD
+COMPAT=
+
diff --git a/contrib/xntpd/conf/Config.dartnet b/contrib/xntpd/conf/Config.dartnet
new file mode 100644
index 000000000000..b591db341655
--- /dev/null
+++ b/contrib/xntpd/conf/Config.dartnet
@@ -0,0 +1,187 @@
+# This is the local configure file (distribution version).
+# You must modify it to fit your particular configuration
+# and name it Config.local
+# The following configuratiions can be auto-generated:
+#
+# make Config.local.green
+# make a Config.local that supports a local clock
+# (i.e. allow fallback to use of the CPU's own clock)
+# make Config.local.NO.clock
+# make a Config.local that supports no clocks
+#
+#
+# NOTE TO GREENHORNS
+#
+# For plug-'n-play and no radios or other complicated gadgetry,
+# use "make Config.local.green" or "make Config.local.local" as above.
+#
+# Following defines can be set in the DEFS_OPT= define:
+#
+# The flag -DDEBUG includes some debugging code. To use this, include
+# the define and start the daemon with one or more -d flags, depending
+# on your calibration of pearannoya. The daemon will not detach your
+# terminal in this case. Judicious use of grep will reduce the speaker
+# volume to bearable levels.
+#
+# To change the location of the configuration file, use a
+# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar.
+#
+# The -DSYSLOG_FILE defines allows logging messages that are normally
+# reported via syslof() in a file. The file name can be configured using
+# the configuration line "logfile <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/contrib/xntpd/conf/Config.local b/contrib/xntpd/conf/Config.local
new file mode 100644
index 000000000000..12a6dfece755
--- /dev/null
+++ b/contrib/xntpd/conf/Config.local
@@ -0,0 +1,190 @@
+# This is the local configure file (distribution version).
+# You must modify it to fit your particular configuration
+# and name it Config.local
+# The following configuratiions can be auto-generated:
+#
+# make Config.local.green
+# make a Config.local that supports a local clock
+# (i.e. allow fallback to use of the CPU's own clock)
+# make Config.local.NO.clock
+# make a Config.local that supports no clocks
+#
+#
+# NOTE TO GREENHORNS
+#
+# For plug-'n-play and no radios or other complicated gadgetry,
+# use "make Config.local.green" as above.
+#
+# Following defines can be set in the DEFS_OPT= define:
+#
+# The flag -DDEBUG includes some debugging code. To use this, include
+# the define and start the daemon with one or more -d flags, depending
+# on your calibration of pearannoya. The daemon will not detach your
+# terminal in this case. Judicious use of grep will reduce the speaker
+# volume to bearable levels.
+#
+# To change the location of the configuration file, use a
+# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar.
+#
+# The -DSYSLOG_FILE defines allows logging messages that are normally
+# reported via syslof() in a file. The file name can be configured using
+# the configuration line "logfile <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 -DCHUPPS -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH
+
+#
+# Directory into which binaries should be installed (default /usr/local)
+#
+BINDIR= /usr/local/bin
diff --git a/contrib/xntpd/conf/Config.svr4 b/contrib/xntpd/conf/Config.svr4
new file mode 100644
index 000000000000..d6d0661539f1
--- /dev/null
+++ b/contrib/xntpd/conf/Config.svr4
@@ -0,0 +1,167 @@
+#
+# This is the local configure file. Modify it to fit your particular
+# configuration.
+#
+# NOTE TO GREENHORNS
+#
+# For plug-'n-play and no radios or other complicated gadgetry, set the
+# alternate defines as shown.
+#
+# The flag -DDEBUG includes some debugging code. To use this, include
+# the define and start the daemon with one or more -d flags, depending
+# on your calibration of pearannoya. The daemon will not detach your
+# terminal in this case. Judicious use of grep will reduce the speaker
+# volume to bearable levels.
+#
+# To change the location of the configuration file, use a
+# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar.
+#
+# The flag -DREFCLOCK causes the basic reference clock support to be
+# compiled into the daemon. If you set this you may also want to
+# configure the particular clock drivers you want in the CLOCKDEFS= line
+# below. This flag affects xntpd only. This define is included by
+# default when using the "make makeconfig" script.
+#
+# The next two sets of defines are meaningful only when radio clock
+# drivers or special 1-pps signals are to be used. For systems without
+# these features, these delicious complexities can be avoided. Ordinarily,
+# the "make makeconfig" script figures out which ones to use, but your
+# mileage may vary.
+#
+# There are three ways to utilize external 1-pps signals. Define
+# -DPPS to include just the pps routine, such as used by the DCF77
+# clock driver. Define -DPPSCLK to include a serial device driver
+# which avoids much of the jitter due to upper level port
+# processing. This requires a dedicated serial port and either the
+# tty_clock line discipline or tty_clk_streams module, both of
+# which are in the ./kernel directory. Define -DPPSCD to include a
+# special driver which intercepts carrier-detect transitions
+# generated by the pps signal. This requires a nondedicated serial
+# port and the ppsclock streams module in the ./kernel directory.
+# Only one of these three flags should be defined.
+#
+# There are three serial port system software interfaces, each of
+# which is peculiar to one or more Unix versions. Define
+# -DHAVE_SYSV_TTYS for basic System V compatibility; define -DSTREAM
+# for POSIX compatibility including System V Streams, and
+# HAVE_BSD_TTYS for 4.3bsd compatibility. Only one of these three
+# should be defined. If none are defined, HAVE_BSD_TTYS is assumed.
+# Ordinarily, the correct define is sniffed by the "make makeconfig"
+# script and automatically included.
+#
+# The flag KERNEL_PLL is a temporary hack to use when the phase-lock loop
+# is implmented in the kernel. Do not use unless you have modified
+# kernel routines (see doc/README.kern).
+#
+#DEFS_LOCAL= -DDEBUG -DPPSPPS -DKERNEL_PLL
+DEFS_LOCAL= -DDEBUG
+#DEFS_LOCAL= # for greenhorns
+#
+# Radio clock support definitions (these only make sense if -DREFCLOCK
+# used), which is normally the case. Note that a configuration can include
+# no clocks, more than one type of clock and even multiple clocks of the
+# same type.
+#
+# For most radio clocks operating with serial ports, accuracy can
+# be considerably improved through use of the tty_clk line
+# discipline or tty_clk_STREAMS streams module found in the
+# ./kernel directory. These gizmos capture a timestamp upon
+# occurrence of an intercept character and stuff it in the data
+# stream for the clock driver to munch. To select this mode,
+# postfix the driver name with the string CLK; that is, WWVB
+# becomes WWVBCLK. If more than one clock is in use, the CLK
+# postfix can be used with any or all of them.
+#
+# Alternatively, for the best accuracy, use the ppsclock streams
+# module in the ./ppsclock directory to steal the carrier-detect
+# transition and capture a precision timestamp. At present this
+# works only with SunOS 4.1.1 or later. To select this mode,
+# postfix the driver name with the string PPS; that is, AS2201
+# becomes AS2201PPS. If more than one clock is in use, the PPS
+# postfix should be used with only one of them. If any PPS
+# postfix is defined, the -DPPSPPS define should be used on the
+# DEFS above.
+#
+# Define -DLOCAL_CLOCK for a local pseudo-clock to masquerade as a
+# reference clock for those subnets without access to the real thing.
+# Works in all systems and requires no hardware support. This is defined
+# by default when using the "make makeconfig" script.
+#
+# Define -DPST for a PST/Traconex 1020 WWV/H receiver. The driver
+# supports both the CLK and PPS modes. It should work in all systems
+# with a serial port.
+#
+# Define -DWWVB for a Spectracom 8170 or Netclock/2 WWVB receiver. It
+# should work in all systems with a serial port. The driver supports
+# both the CLK and PPS modes if the requisite kernel support is installed.
+#
+# Define -DCHU for a special CHU receiver using an ordinary shortwave
+# radio. This requires the chu_clk line discipline or chu_clk_STREAMS
+# module in the ./kernel directory. At present, this driver works only
+# on SunOS4.1.x; operation in other systems has not been confirmed.
+# Construction details for a suitable modem can be found in the ./gadget
+# directory. The driver supports # neither the CLK nor PPS modes.
+#
+# Define -DPARSE for a DCF77/GPS(GENERIC) receiver. For best performance
+# this requires a special parsestreams STREAMS (SunOS 4.x) module in the
+# ./kernel directory. Define -DPARSEPPS for PPS support via the
+# DCF77/GPS (GENERIC) receiver; also, define -DPPS in the DEFS above.
+# Define PARSESTREAM for utilising the STREAMS module for improved
+# precision (currently only SunOS4.x)
+#
+# Define: -DCLOCK_MEINBERG for Meinberg clocks
+# -DCLOCK_SCHMID for Schmid receivers
+# -DCLOCK_DCF7000 for ELV DCF7000
+# -DCLOCK_RAWDCF for simple receivers (100/200ms pulses on Rx)
+#
+# Define -DMX4200PPS for a Magnavox 4200 GPS receiver. At present, this
+# driver works only on SunOS4.1.x with CPU serial ports only. The PPS
+# mode is required.
+#
+# Define -DAS2201 for an Austron 2200A or 2201A GPS receiver. It should
+# work in all systems with a serial port. The driver does not support the
+# CLK mode, but does support the PPS mode. If the radio is connected to
+# more than one machine, the PPS mode is required.
+#
+# Define -DGOES for a Kinemetrics/TrueTime 468-DC GOES receiver. This
+# driver is known to work with some other TrueTime products as well,
+# including the GPS-DC GPS receiver. It should work in all systems with
+# a serial port. The driver does not support the CLK mode, but does
+# support the PPS mode.
+#
+# Define -DOMEGA for a Kinemetrics/TrueTime OM-DC OMEGA receiver. It
+# should work in all systems with a serial port. The driver does not
+# support the CLK mode, but does support the PPS mode.
+#
+# Define -DTPRO for a KSI/Odetics TPRO-S IRIG-B timecode reader. This
+# requires the SunOS interface driver available from KSI. The driver
+# supports neither the CLK nor PPS modes.
+#
+# Define -DLEITCH for a Leitch CSD 5300 Master Clock System Driver for
+# the HP 5061B Cesium Clock. It should work in all systems with a serial
+# port. The driver does not support the CLK mode, but does support the
+# PPS mode.
+#
+# Define -DMSF for a EES M201 MSF receiver. It should work in all systems
+# with a serial port. The driver does not support the CLK mode, but does
+# support the # PPS mode.
+#
+# Define -DIRIG for a IRIG-B timecode timecode using the audio codec of
+# the Sun SPARCstations. This requires a modified BSD audio driver and
+# exclusive access to the audio port. A memo describing how it works and
+# how to install the driver is in the README.irig file in the ./doc
+# directory.
+#
+# Note: The following defines result in compilation of all the above radio
+# clocks. This works on a Sun 4.1.x system which has tty_clk, chu_clk and
+# ppsclock STREAMS modules installed. If the trailing CLK and PPS suffixes
+# are removed and the IRIG deleted, all of the rest compile under
+# Ultrix 4.2a/3. If the MX4200 is removed, all the rest compile on a DEC
+# OSF/1 Alpha.
+#
+#CLOCKDEFS= -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPST -DPSTCLK -DTPRO -DWWVBCLK
+CLOCKDEFS= # for greenhorns
+#
+# Directory into which binaries should be installed
+#
+BINDIR= /usr/etc
diff --git a/contrib/xntpd/conf/README b/contrib/xntpd/conf/README
new file mode 100644
index 000000000000..19dcb795f80c
--- /dev/null
+++ b/contrib/xntpd/conf/README
@@ -0,0 +1,8 @@
+README file for directory ./conf of the NTP Version 3 distribution
+
+This directory contains example run-time configuration files for the
+NTP Version 3 daemon xntpd. These files illustrate some of the more
+obtuse configurations you may run into. They are not likely to do
+anything good if run on machines other than their native spot, so don't
+just blindly copy something and put it up. Additional information can
+be found in the ./doc directory of the base directory.
diff --git a/contrib/xntpd/conf/dewey.conf b/contrib/xntpd/conf/dewey.conf
new file mode 100644
index 000000000000..523008fcdc82
--- /dev/null
+++ b/contrib/xntpd/conf/dewey.conf
@@ -0,0 +1,38 @@
+#
+# NTP configuration file (ntp.conf)
+# dewey.udel.edu (128.175.1.2)
+#
+# Stratum-1 peers
+#
+#peer 128.4.1.5 # dcn5.udel.edu
+#peer 128.8.10.1 # umd1.umd.edu
+#peer 18.72.0.3 version 2 # bitsy.mit.edu
+peer 192.43.244.9 # ncar-fuzz.nsf.net
+peer 132.249.16.1 # sdsc-fuzz.nsf.net
+peer 128.118.46.3 version 2 # otc1.psu.edu
+#peer 130.126.174.40 # truechimer.cso.uiuc.edu
+#peer 128.9.2.129 # wwvb.isi.edu
+#peer 130.43.2.2 version 2 # apple.com
+#
+# Stratum-2 peers
+#
+peer 128.175.1.1 # huey.udel.edu
+#peer 128.175.1.2 # dewey.udel.edu
+peer 128.175.1.3 # louie.udel.edu
+#peer 128.175.2.33 # louie.udel.edu
+#peer 128.175.7.39 # louie.udel.edu
+#
+# Miscellaneous stuff
+#
+monitor yes # enable monitoring
+precision -7 # clock reading precision (10 msec)
+driftfile /etc/ntp.drift # path for drift file
+#
+# Authentication stuff
+#
+authenticate yes # enable authentication
+keys /etc/ntp.keys # path for key file
+trustedkey 1 2 15 # define trusted keys
+requestkey 15 # key (7) for accessing server variables
+controlkey 15 # key (6) for accessing server variables
+authdelay 0.001501 # authentication delay (VAX 11/780)
diff --git a/contrib/xntpd/conf/grundoon.conf b/contrib/xntpd/conf/grundoon.conf
new file mode 100644
index 000000000000..c5aef6eb88e3
--- /dev/null
+++ b/contrib/xntpd/conf/grundoon.conf
@@ -0,0 +1,58 @@
+#
+# NTP configuration file (ntp.conf)
+# grundoon.udel.edu (128.4.2.7)
+#
+server 127.127.6.0 prefer # irig audio decoder
+fudge 127.127.6.0 time1 0.0005
+#pps delay -0.0004 # pps correction for CLK streams module
+server 127.127.4.1 # spectracom 8170/netclock-2 wwvb receiver
+# propagation delay: wwvb 0.0088; receiver delay 0.0173 os delay .0035
+fudge 127.127.4.1 time1 0.0035 flag4 1
+server 127.127.3.1 # pst/traconex 1020 wwv/h receiver
+# propagation delay: wwv 0.0088 wwvh 0.0281; receiver+os delay 0.0035
+fudge 127.127.3.1 time1 0.0123 time2 0.0316
+server 127.127.7.1 # scratchbuilt chu receiver/demodulator
+# propagtion delay: chu 0.0030; receiver+os delay 0.0060
+fudge 127.127.7.1 time1 0.0030 time2 0.0060
+#server 127.127.10.1 # austron 2201 gps receiver
+
+server 127.127.1.2 # local clock
+#server 127.127.12.2 # ksi/odetics tpr0-s irig-b reader
+
+#broadcast 128.4.2.255
+
+peer 128.4.1.1 key 3 # rackety.udel.edu (Sun4c/40 IPC)
+peer 128.4.1.4 # barnstable.udel.edu (Sun4c/65 SS1+)
+#peer 128.4.1.5 # churchy.udel.edu (Bancomm bc700LAN)
+#peer 128.4.2.7 key 3 # grundoon.udel.edu (Sun4c/40 IPC)
+peer 128.4.1.8 # bridgeport.udel.edu (Sun4c/40 IPC)
+peer 128.4.1.20 key 3 # pogo.udel.edu (Sun4c/65 SS1+)
+peer 128.4.1.22 # malarky.udel.edu (Sun4c/50 IPX)
+peer 128.4.1.23 # beauregard.udel.edu (Sun4/40 IPC)
+peer 128.4.1.24 # baldwin.udel.edu (Sun4/40 IPC)
+peer 128.4.1.25 # albert.udel.edu (Sun4c/60 SS1)
+peer 128.4.1.27 # bunnylou.udel.edu (Sun4c/40 IPC)
+peer 128.4.1.28 # cowbird.udel.edu (DEC 5000/240)
+peer 128.4.1.29 # porkypine.udel.edu (DEC 5000/240)
+#
+# Miscellaneous stuff
+#
+monitor yes # enable monitoring
+precision -18 # clock reading precision (usec)
+driftfile /etc/ntp.drift # path for drift file
+statsdir /grundoon/ntpstats/ # directory for statistics files
+filegen peerstats file peerstats type day enable
+filegen loopstats file loopstats type day enable
+filegen clockstats file clockstats type day enable
+
+#
+# Authentication stuff
+#
+authenticate yes # enable authentication
+keys /usr/local/ntp.keys # path for keys file
+trustedkey 1 2 3 4 14 15 # define trusted keys
+requestkey 15 # key (7) for accessing server variables
+controlkey 15 # key (6) for accessing server variables
+#authdelay 0.000073 # authentication delay (SPARC4c/40 IPC DES)
+authdelay 0.000163 # authentication delay (SPARC4c/40 IPC MD5)
+
diff --git a/contrib/xntpd/conf/malarky.conf b/contrib/xntpd/conf/malarky.conf
new file mode 100644
index 000000000000..f887f839d1bb
--- /dev/null
+++ b/contrib/xntpd/conf/malarky.conf
@@ -0,0 +1,40 @@
+#
+# NTP configuration file (ntp.conf)
+# malarky.udel.edu (128.4.1.22)
+#
+peer 128.4.1.1 # rackety.udel.edu
+peer 128.4.1.4 # barnstable.udel.edu
+#peer 128.4.1.5 #churchy.udel.edu
+peer 128.4.2.7 # grundoon.udel.edu
+peer 128.4.1.8 # bridgeport.udel.edu
+peer 128.4.1.20 prefer # pogo.udel.edu
+#peer 128.4.1.22 # malarky.udel.edu
+peer 128.4.1.23 # beauregard.udel.edu
+peer 128.4.1.24 # baldwin.udel.edu
+peer 128.4.1.25 # albert.udel.edu
+peer 128.4.1.27 # bunnylou.udel.edu
+peer 128.4.1.28 # cowbird.udel.edu
+peer 128.4.1.29 # porkypine.udel.edu
+
+#
+# Miscellaneous stuff
+#
+monitor yes # enable monitoring
+precision -18 # clock reading precision (usec)
+driftfile /etc/ntp.drift # path for drift file
+statsdir /malarky/ntpstats/ # directory for statistics files
+filegen peerstats file peerstats type day enable
+filegen loopstats file loopstats type day enable
+filegen clockstats file clockstats type day enable
+
+#
+# Authentication stuff
+#
+authenticate yes # enable authentication
+keys /usr/local/bin/ntp.keys # path for key file
+trustedkey 1 2 3 4 14 15 # define trusted keys
+requestkey 15 # key (7) for accessing server variables
+controlkey 15 # key (6) for accessing server variables
+#authdelay 0.000047 # authentication delay (Sun4c/50 IPX DES)
+authdelay 0.000094 # authentication delay (Sun4c/50 IPX MD5)
+
diff --git a/contrib/xntpd/conf/ntp.conf.gw b/contrib/xntpd/conf/ntp.conf.gw
new file mode 100644
index 000000000000..bd5687874f53
--- /dev/null
+++ b/contrib/xntpd/conf/ntp.conf.gw
@@ -0,0 +1,34 @@
+#
+# peers for gw.ccie.utoronto.ca (128.100.63.2, 128.100.49.104, 128.100.224.224)
+#
+peer 128.4.0.1 key 1 # dcn1.udel.edu
+peer 128.8.10.1 key 2 # umd1.umd.edu
+peer 128.116.64.3 key 3 # ncarfuzz.ucar.edu
+peer 128.9.2.129 key 4 # wwvb.isi.edu
+#peer 128.4.0.6 key 1 # dcn6.udel.edu
+#
+# Don't configure associations with the other secondaries. This is
+# the only one in a machine room and will hold itself pretty stable
+# when all else fails
+#
+monitor yes # keep track of traffic
+
+#
+# drift file
+#
+driftfile /etc/ntp.drift
+
+#
+# authentication stuff. We're running authenticated, tell it
+# where the keys are and which to trust.
+#
+authenticate yes
+authdelay 0.000323 # seconds, about right for an RT model 125
+trustedkey 1 2 3 4 21 22 23 24
+keys /etc/ntp.keys
+
+#
+# allow run time reconfiguration using key 65535
+#
+requestkey 65535
+controlkey 65535
diff --git a/contrib/xntpd/conf/ntp.conf.ipl b/contrib/xntpd/conf/ntp.conf.ipl
new file mode 100644
index 000000000000..1fd5b7d62145
--- /dev/null
+++ b/contrib/xntpd/conf/ntp.conf.ipl
@@ -0,0 +1,32 @@
+#
+# peers for ipl.utcs.utoronto.ca (128.100.102.7)
+#
+peer 128.4.0.5 key 1 # dcn5.udel.edu
+peer 128.8.10.1 key 2 # umd1.umd.edu
+peer 192.12.207.1 key 3 # fuzz.sdsc.edu
+peer 128.9.2.129 key 4 # wwvb.isi.edu
+peer 128.100.63.2 key 21 # gw.ccie
+peer 128.100.49.105 key 22 # suzuki.ccie
+peer 128.100.102.4 key 23 # shiningtree.utcs
+#
+monitor yes # keep track of traffic
+
+#
+# drift file
+#
+driftfile /etc/ntp.drift
+
+#
+# authentication stuff. We're running authenticated, tell it
+# where the keys are and which to trust.
+#
+authenticate yes
+authdelay 0.000323 # seconds, about right for an RT model 125
+trustedkey 1 2 3 4 21 22 23
+keys /etc/ntp.keys
+
+#
+# allow run time reconfiguration using key 65535
+#
+requestkey 65535
+controlkey 65535
diff --git a/contrib/xntpd/conf/ntp.conf.nsf b/contrib/xntpd/conf/ntp.conf.nsf
new file mode 100644
index 000000000000..298bb7a6905e
--- /dev/null
+++ b/contrib/xntpd/conf/ntp.conf.nsf
@@ -0,0 +1,156 @@
+#
+# Maybe an alternate xntpd configuration for NSS#17
+#
+
+#
+# precision is supported, but you don't really need it. The code
+# will determine a precision from the kernel's value of _hz which
+# is fine. Note you shouldn't claim too good a precision on a
+# Unix machine even if the clock carries a lot of bits, since
+# precision also depends on things like I/O delays and scheduling
+# latencies, which Unix machines control poorly. If you claim better
+# than -6 or -7 it will make the anti-hop aperture tighter than is
+# reasonable for a Unix machine.
+#
+#precision -7
+
+#
+# peers are ncarfuzz.ucar.edu umd1.umd.edu dcn5.udel.edu fuzz.sdsc.edu
+# syntax is peer addr [ key 1-15 ] [ version 1_or_2 ]
+#
+
+peer 128.116.64.3 # ncarfuzz.ucar.edu
+peer 128.8.10.1 # umd1.umd.edu
+peer 128.4.0.5 # dcn5.udel.edu
+peer 192.12.207.1 # fuzz.sdsc.edu
+
+#
+# Drift file. Put this in a directory which the daemon can write to.
+# No symbolic links allowed, either, since the daemon updates the file
+# by creating a temporary in the same directory and then rename()'ing
+# it to the file.
+#
+# This is a nice feature. Once you've got the drift computed it hardly
+# ever takes more than an hour or so to resync after a restart.
+#
+driftfile /etc/ntp.drift
+
+#
+# The server statement causes polling to be done in client mode rather
+# than symmetric active. It is an alternative to the peer command
+# above. Which you use depends on what you want to achieve. Usually
+# it doesn't matter. Syntax is:
+#
+#server 128.100.49.1 key 4 version 1
+
+#
+# The broadcast statement tells it to start broadcasting time out one
+# of its interfaces. Syntax is
+#
+#broadcast 128.100.49.255 # [ key n ] [ version n ]
+
+#
+# broadcastclient tells the daemon whether it should attempt to sync
+# to broadcasts or not. Defaults to `no'.
+#
+#broadcastclient yes # or no
+
+#
+# broadcastdelay configures in a default round-trip delay to use for
+# broadcast time. It may poll to improve this estimate.
+#
+#broadcastdelay 0.0095 # in seconds
+
+#
+# authenticate configures us into strict authentication mode (or not).
+#
+#authenticate yes # or no. Default is no
+
+#
+# authdelay is the time it takes to do an NTP encryption on this host.
+# The current routine is pretty fast.
+#
+#authdelay 0.000340 # in seconds
+
+#
+# trustedkey are used when authenticate is on. We only trust (and sync to)
+# peers who know these keys.
+#
+#trustedkey 1 3 4 8
+
+#
+# monitor turns on the monitoring facility. See xntpdc's monlist command.
+# This shows a lot of neat stuff, but I'm not fussy about the implementation.
+# Uses up to 20Kb of memory at run time. You could try this.
+#
+#monitor yes # or no. Default is no
+
+#
+# keys points at the file which holds the authentication keys.
+#
+#keys /etc/ntp.keys
+
+#
+# requestkey indicates which key is to be used for validating
+# runtime reconfiguration requests. If this isn't defined, or the
+# key isn't in the keys file, you can't do runtime reconfiguration.
+# controlkey indicates which key is to be used for validating
+# mode 6 write variables commands. If this isn't defined you can't
+# do it. The only thing the latter is used for is to set leap second
+# warnings on machines with radio clocks.
+#
+#requestkey 65535
+#controlkey 65534
+
+#
+# restrict places restrictions on the punters. This is implemented as
+# a sorted address-and-mask list, with each entry including a set of
+# flags which define what a host matching the entry *can't* do (the sort
+# also saves CPU time searching the table since it needn't be searched
+# to the end). The last match in the table defines what the host does.
+# The default entry, which everyone matches, is first, most specific
+# matches are later in the table. The flags are:
+#
+# ignore - ignore all traffic from host
+# noserve - don't give host any time (but let him make queries?)
+# notrust - give host time, let him make queries, but don't sync to him
+# noquery - host can have time, but not make queries
+# nomodify - allow the host to make queries except those which are
+# actually run-time configuration commands.
+# notrap - don't allow matching hosts to set traps. If noquery is
+# set this isn't needed
+# lowpriotrap - if this guy sets a trap make it easy to delete
+# ntpport - a different kind of flag. Makes matches for this entry
+# possible only if the source port is 123.
+#
+# To understand this better, take a look at xntpdc's reslist command when the
+# server is running. This usually prints in the sorted order.
+#
+# This should match the NSS 17 stuff. Default mask is all ones.
+
+restrict default ignore # ignore almost everyone
+
+#
+# These guys can be served time and make non-modifying queries
+#
+restrict 129.140.0.0 mask 255.255.0.0 notrust nomodify
+restrict 35.1.1.42 notrust nomodify
+
+#
+# Rest of 35.1.1 gets to look but not touch
+#
+restrict 35.1.1.0 mask 255.255.255.0 noserve nomodify
+
+#
+# modifications can be made from local NSS only
+#
+restrict 129.140.17.0 mask 255.255.255.0 notrust
+restrict 127.0.0.1 notrust
+
+#
+# take time from the following peers, but don't let them peek or modify
+#
+restrict 128.116.64.3 noquery
+restrict 128.8.10.1 noquery
+restrict 128.4.0.5 noquery
+restrict 192.12.207.1 noquery
diff --git a/contrib/xntpd/conf/ntp.conf.shiningtree b/contrib/xntpd/conf/ntp.conf.shiningtree
new file mode 100644
index 000000000000..1576ebbd072c
--- /dev/null
+++ b/contrib/xntpd/conf/ntp.conf.shiningtree
@@ -0,0 +1,32 @@
+#
+# peers for shiningtree.utcs.utoronto.ca (128.100.102.4)
+#
+peer 128.4.0.1 key 1 # dcn1.udel.edu
+peer 130.126.174.40 key 2 # truechimer.cso.uiuc.edu
+peer 192.12.207.1 key 3 # fuzz.sdsc.edu
+peer 128.116.64.3 key 4 # ncarfuzz.ucar.edu
+peer 128.100.63.2 key 21 # gw.ccie
+peer 128.100.49.105 key 22 # suzuki.ccie
+peer 128.100.102.7 key 23 # ipl.utcs
+#
+monitor yes # keep track of traffic
+
+#
+# drift file
+#
+driftfile /etc/ntp.drift
+
+#
+# authentication stuff. We're running authenticated, tell it
+# where the keys are and which to trust.
+#
+authenticate yes
+authdelay 0.000323 # seconds, about right for an RT model 125
+trustedkey 1 2 3 4 21 22 23
+keys /etc/ntp.keys
+
+#
+# allow run time reconfiguration using key 65535
+#
+requestkey 65535
+controlkey 65535
diff --git a/contrib/xntpd/conf/ntp.conf.suzuki b/contrib/xntpd/conf/ntp.conf.suzuki
new file mode 100644
index 000000000000..ee32e7ad87a1
--- /dev/null
+++ b/contrib/xntpd/conf/ntp.conf.suzuki
@@ -0,0 +1,43 @@
+#
+# peers for suzuki.ccie.utoronto.ca (128.100.49.105, 128.100.224.225)
+#
+
+#
+# the reference clock, /dev/chu1
+#
+server 127.127.7.1 key 4
+# Propagation delay 2.5 ms, sloppy clock flag on
+fudge 127.127.7.1 time1 0.0025 flag1 1
+
+peer 128.4.0.5 key 1 # dcn5.udel.edu
+peer 128.8.10.1 key 2 # umd1.umd.edu
+peer 128.116.64.34 key 3 # ncarfuzz.ucar.edu
+peer 130.126.174.40 key 4 # truechimer.cso.uiuc.edu
+peer 128.100.49.104 key 24 # gw.ccie
+peer 128.100.102.4 key 22 # shiningtree.utcs
+peer 128.100.102.7 key 22 # ipl.utcs
+
+peer 128.4.0.6 key 1 # dcn6.udel.edu
+
+#
+monitor yes # keep track of traffic
+
+#
+# drift file
+#
+driftfile /etc/ntp.drift
+
+#
+# authentication stuff. We're running authenticated, tell it
+# where the keys are and which to trust.
+#
+authenticate yes
+authdelay 0.000323 # seconds, about right for an RT model 125
+trustedkey 1 2 3 4 21 22 23 24
+keys /etc/ntp.keys
+
+#
+# allow run time reconfiguration using key 65535
+#
+requestkey 65535
+controlkey 65535
diff --git a/contrib/xntpd/conf/pogo.conf b/contrib/xntpd/conf/pogo.conf
new file mode 100644
index 000000000000..94ac6c84ea28
--- /dev/null
+++ b/contrib/xntpd/conf/pogo.conf
@@ -0,0 +1,50 @@
+#
+# NTP configuration file (ntp.conf)
+# pogo.udel.edu (128.4.1.20)
+#
+server 127.127.10.1 prefer # austron 2201 gps receiver
+#server 127.127.4.1 # spectracom 8170/netclock-2 wwvb receiver
+# propagation delay: wwvb 0.0088; receiver delay 0.0017
+#fudge 127.127.4.1 time1 0.0017
+
+peer 128.4.1.1 key 3 # rackety.udel.edu (Sun4c/40 IPC)
+peer 128.4.1.2 # mizbeaver.udel.edu
+peer 128.4.1.4 # barnstable.udel.edu (Sun4c/65 SS1+)
+#peer 128.4.1.5 # churchy.udel.edu (Bancomm bc700LAN)
+peer 128.4.2.7 key 3 # grundoon.udel.edu (Sun4c/40 IPC)
+peer 128.4.1.5 maxpoll 8 # churchy.udel.edu (cisco IGS router)
+#peer 128.4.1.8 # bridgeport.udel.edu (Sun4c/40 IPC)
+#peer 128.4.1.20 key 3 # pogo.udel.edu (Sun4c/65 SS1+)
+#peer 128.4.1.22 # malarky.udel.edu (Sun4c/50 IPX)
+#peer 128.4.1.23 # beauregard.udel.edu (Sun4/40 IPC)
+peer 128.4.1.24 # baldwin.udel.edu (Sun4/40 IPC)
+#peer 128.4.1.25 # albert.udel.edu (Sun4c/60 SS1)
+#peer 128.4.1.27 # maccarony.udel.edu (Sun4c/40 IPC)
+peer 128.4.1.29 # porkypine.udel.edu
+peer 132.163.135.130 maxpoll 8 # time_A.timefreq.bldrdoc.gov (ACTS)
+peer 131.188.1.40 maxpoll 8 # ntps1-0.uni-erlangen.de (DCF77)
+peer 129.132.2.21 maxpoll 8 # swisstime.ethz.ch (DCF77)
+peer 130.155.98.13 maxpoll 8 # terss.ml.csiro.au (OMEGA)
+
+#
+# Miscellaneous stuff
+#
+monitor yes # enable monitoring
+precision -18 # clock reading precision (usec)
+driftfile /etc/ntp.drift # path for drift file
+statsdir /pogo/ntpstats/ # directory for statistics files
+filegen peerstats file peerstats type day enable
+filegen loopstats file loopstats type day enable
+filegen clockstats file clockstats type day enable
+
+#
+# Authentication stuff
+#
+authenticate yes # enable authentication
+keys /usr/local/bin/ntp.keys # path for keys file
+trustedkey 1 2 3 4 14 15 # define trusted keys
+requestkey 15 # key (7) for accessing server variables
+controlkey 15 # key (6) for accessing server variables
+#authdelay 0.000072 # authentication delay (SPARC4c/65 SS1+ DES)
+authdelay 0.000159 # authentication delay (SPARC4c/65 SS1+ MD5)
+
diff --git a/contrib/xntpd/conf/rackety.conf b/contrib/xntpd/conf/rackety.conf
new file mode 100644
index 000000000000..1a5181cd4b5c
--- /dev/null
+++ b/contrib/xntpd/conf/rackety.conf
@@ -0,0 +1,75 @@
+#
+# NTP configuration file (ntp.conf)
+# rackety (128.4.1.1)
+#
+server 127.127.10.1 prefer # austron 2201 gps receiver
+fudge 127.127.10.1 flag4 1 # enable statistics
+server 127.127.4.1 # spectracom 8170/netclock-2 wwvb receiver
+#propagation delay: wwvb 0.0088; receiver delay 0.0017
+fudge 127.127.4.1 time1 0.0017 value1 2
+
+#
+# ee vaxen
+#
+peer 128.175.1.1 # huey.udel.edu
+peer 128.175.1.2 # louie.udel.edu
+peer 128.175.1.3 # dewey.udel.edu
+
+#
+# munchkins (stratum-1 only)
+#
+peer 128.4.1.2 # mizbeaver.udel.edu
+#peer 128.4.1.5 # churchy.udel.edu
+peer 128.4.2.7 key 3 # grundoon.udel.edu
+peer 128.4.1.20 key 3 # pogo.udel.edu
+
+#
+# dartnet
+#
+peer 140.173.112.2 # ames.dart.net
+peer 140.173.128.1 # la.dart.net
+peer 140.173.64.1 # dc.dart.net
+peer 140.173.144.2 # parc.dart.net
+peer 140.173.80.1 # sri.dart.net
+peer 140.173.96.1 # lbl.dart.net
+peer 140.173.128.2 # isi.dart.net
+peer 140.173.16.1 # udel.dart.net
+peer 140.173.32.1 # bbn.dart.net
+peer 140.173.48.2 # mit.dart.net
+
+#
+# nsfnet t3 backbone
+#
+server 140.222.134.1 version 2 # enss134 (cambridge - mit)
+server 140.222.135.1 version 2 # enss135 (san diego - sdsc)
+peer 140.222.136.1 version 2 # enss136 (college park - sura)
+server 140.222.141.1 version 2 # enss141 (boulder - ncar)
+server 140.222.144.1 version 2 # enss144 (sunnyvale - nasa ames)
+
+#
+# famous players
+#
+#peer 132.163.135.130 # time_A.timefreq.bldrdoc.gov
+
+#
+# Miscellaneous stuff
+#
+monitor yes # enable monitoring
+precision -18 # clock reading precision (usec)
+driftfile /etc/ntp.drift # path for drift file
+statsdir /rackety/ntpstats/ # directory for statistics files
+filegen peerstats file peerstats type day enable
+filegen loopstats file loopstats type day enable
+filegen clockstats file clockstats type day enable
+
+#
+# Authentication stuff
+#
+authenticate yes # enable authentication
+keys /usr/local/bin/ntp.keys # path for keys file
+trustedkey 1 2 3 4 14 15 # define trusted keys
+requestkey 15 # key (7) for accessing server variables
+controlkey 15 # key (6) for accessing server variables
+#authdelay 0.000073 # authentication delay (SPARC4c/40 IPC DES)
+authdelay 0.000163 # authentication delay (SPARC4c/40 IPC MD5)
+
diff --git a/contrib/xntpd/conf/snow-white.conf b/contrib/xntpd/conf/snow-white.conf
new file mode 100644
index 000000000000..a86cb4bc5b45
--- /dev/null
+++ b/contrib/xntpd/conf/snow-white.conf
@@ -0,0 +1,33 @@
+#
+# NTP configuration file (ntp.conf)
+# snow-white.udel.edu (128.175.2.15)
+#
+# Stratum-2 peers
+#
+peer 128.175.1.1 # huey.udel.edu
+peer 128.175.1.2 # dewey.udel.edu
+#peer 128.175.1.3 # louie.udel.edu
+peer 128.175.2.33 # louie.udel.edu
+#peer 128.175.7.39 # louie.udel.edu
+#
+# Stratum-3 peers
+#
+peer 128.175.7.4 # sol.cis.udel.edu
+peer 128.175.7.18 # ra.cis.udel.edu
+#peer 128.175.2.15 # snow-white.ee.udel.edu
+peer 128.175.2.21 # opus.ee.udel.edu
+#
+# Miscellaneous stuff
+#
+monitor yes # enable monitoring
+precision -18 # clock reading precision (1 usec)
+driftfile /etc/ntp.drift # path for drift file
+#
+# Authentication stuff
+#
+authenticate yes # enable authentication
+keys /etc/ntp.keys # path for key file
+trustedkey 1 2 15 # define trusted keys
+requestkey 15 # key (7) for accessing server variables
+controlkey 15 # key (6) for accessing server variables
+authdelay 0.000077 # authentication delay (SPARC IPC)
diff --git a/contrib/xntpd/doc/README.irig b/contrib/xntpd/doc/README.irig
new file mode 100644
index 000000000000..f293f4cde160
--- /dev/null
+++ b/contrib/xntpd/doc/README.irig
@@ -0,0 +1,306 @@
+ Audio IRIG Receiver for Precision Timekeeping
+
+ Revised 20 September 1993
+
+Note: This information file is included in both the BSD audio driver
+distribution (bsd_audio.tar.Z) and NTP Version 3 distribution
+(xntp3.tar.Z) as the file README.irig. Both distributions can be
+obtained via anonymous ftp from louie.udel.edu in the directory pub/ntp.
+
+1. Introduction
+
+This software distribution includes modifications to the BSD audio
+driver for the Sun SPARCstation written by Van Jacobson and
+collaborators at Lawrence Berkeley National Laboratory. The
+modifications provide for the connection of a standard Inter-Range
+Instrumentation Group (IRIG) timecode signal generator and the decoding
+of the signal to produce data sufficient to synchronize a host clock to
+the IRIG signal. There are several timing receivers now on the market
+that can produce IRIG signals, including those made by Austron,
+TrueTime, Odetics and Spectracom, among others. These data can be used
+to precisely synchronize the host computer clock to within a few
+microseconds without requiring level converters or pulse generators
+necessary with the one-pulse-per-second signals also produced by these
+receivers. The current implementation of the Network Time Protocol
+Version 3 supports the modified BSD driver when installed in the SunOS
+4.1.x kernel.
+
+The specific IRIG signal format supported by the driver is designated
+IRIG-B. It consists of an amplitude-modulated 1000-Hz sinewave, where
+each symbol is encoded as ten full carrier cycles, or 10 ms in duration.
+The symbols are distinguished using a pulse-width code, where 2 ms
+corresponds to logic zero, 5 ms to logic one and 8 ms to a position
+identifier used for symbol synchronization. The complete IRIG-B message
+consists of a frame of ten fields, each field consisting of a nine
+information symbols followed by a position identifier for a total frame
+duration of one second. The first symbol in the frame is also a position
+identifier to facilitate frame synchronization.
+
+The IRIG-B signal encodes the day of year and time of day in binary-
+coded decimal (BCD) format, together with a set of control functions,
+which are not used by the driver, but included in the raw binary
+timecode. Either the BCD timecode or the combined raw timecode and BCD
+timecode can be returned in response to a read() system call. The BCD
+timecode is in handy ASCII format: "ddd hh:mm:ss*" for convenience in
+client programs. In this format the "*" status character is " " when the
+driver is operating normally and "?" when errors may be present (see
+below). In order to reduce residual errors to the greatest extent
+possible, the driver computes a timestamp based on the value of the
+kernel clock at the on-time epoch of the IRIG-B signal. In addition, the
+driver automatically adjusts for slowly varying amplitude levels of the
+IRIG-B signal and suppresses noise transients.
+
+In operation the IRIG driver interprets the IRIG-B signal in real time,
+synchronizes to the signal, demodulates the data bits and prepares the
+data to be read later. At the on-time epoch a timestamp is captured from
+the kernel clock and adjusted for the phase of the IRIG carrier signal
+relative to the 8-kHz codec sample clock. When a client program issues a
+read() request, the most recent timecode data, including a status byte
+and the corrected timestamp, are stored in a structure and returned to
+the caller. Depending on the frequency with which the driver is called,
+this may result in old data or duplicate data or even invalid data,
+should the driver be called before it has computed its first timestamp.
+
+In practice, the resulting ambiguity causes few problems. The caller
+converts the ASCII timecode returned by a read() system call to Unix
+timeval format and subtracts it from the kernel timestamp provided by
+the driver. The result is an adjustment that can be subtracted from the
+kernel time, as returned in a gettimeofday() call, for example, to
+correct for the deviation between IRIG time and kernel time. The result
+can always be relied on to within plus/minus 128 microseconds, the audio
+codec sampling interval, and ordinarily to within a few microseconds, as
+determined by the interpolation algorithm.
+
+2. Programming Interface
+
+The IRIG driver modifications are integrated in the BSD audio driver
+bsd_audio.c without affecting its usual functions in transmitting and
+receiving ordinary speech, except when enabled by specific ioctl()
+system calls. However, the driver cannot be used for both speech and
+IRIG signals at the same time. Once activated by a designated ioctl()
+call, the driver remains active until it is explicitly deactivated by
+another ioctl() call. This allows applications to configure the audio
+device and pass the pre-configured driver to other applications. Since
+the driver is currently only a receiver, it does not affect the
+operation of the BSD audio output driver.
+
+Data are read using the standard read() system call. Since the output
+formats have constant lengths, the application receives the data into a
+fixed-length buffer or structure. The read() call never blocks; it
+simply returns the most recent IRIG data received during the last
+second. It may happen that, due to unavoidable race conditions in the
+kernel, data for other than the most recent second are returned. The
+driver's internal data structure is updated as an atomic unit; thus, the
+entire structure is valid, even if it contains old data. This should
+cause no problems, since in the intended application the driver is
+called at regular intervals by a time-synchronization daemon such as
+NTP. The daemon can determine the validity of the time indication by
+checking the timecode or status byte returned with the data.
+
+The header file bsd_audioirig.h defines the irig_time structure and
+ioctl() codes used by the driver. Following are those codes specific to
+the IRIG function of the driver. Unless indicated otherwise, the (third)
+argument of the ioctl() system call points to an integer or string.
+
+AUDIO_IRIG_OPEN
+
+ This command activates the IRIG receiver. The audio driver must be
+ opened with this command before other commands can be issued. The
+ argument is ignored. When the IRIG receiver is initialized, all
+ internal data are purged and any buffered data are lost.
+
+AUDIO_IRIG_CLOSE
+
+ This command deactivates the IRIG receiver. The argument is
+ ignored. The buffers are purged and any buffered time data are
+ lost. The original BSD audio driver functions are enabled and it
+ resumes operating normally.
+
+AUDIO_IRIG_SETFORMAT
+
+ The argument is a pointer to an integer designating the output
+ format for the IRIG data. There are currently two formats defined,
+ 0 (default) and 1. If an invalid format is selected, the default
+ format is used.
+
+The data returned by a read() system call in format 0 is a character
+string in the format "ddd hh:mm:ss*\n", which consists of 13 ASCII
+characters followed by a newline terminator for a total of 14
+characters. The "*" status character is an ASCII space " " if the status
+byte determined by the driver is zero and "?" if not. This format is
+intended to be used with simple user programs that care only about the
+time to the nearest second.
+The data returned by a read() system call in format 1 is a structure
+defined in the bsd_audioirig.h header file:
+
+ struct irig_time {
+ struct timeval stamp; /* timestamp */
+ u_char bits[13]; /* 100 irig data bits */
+ u_char status; /* status byte */
+ char time[14]; /* time string */
+ };
+
+The irig-time.stamp is a pair of 32-bit longwords in Unix timeval
+format, as defined in the sys/time.h header file. The first word is the
+number of seconds since 1 January 1970, while the second is the number
+of microseconds in the current second. The timestamp is captured at the
+most recent on-time instant of the IRIG timecode and applies to all
+other values returned in the irig_time structure.
+
+The irig_time.bits[13] is a vector of 13 bytes to hold the 100-bit,
+zero-padded raw binary timecode, packed 8 symbols per byte. The symbol
+encoding maps IRIG one to 1 and both IRIG zero and IRIG position
+identifier to 0. The order of encoding is illustrated by the following
+diagram (the padding bits are represented by xxxx, which are set to
+zero):
+
+IRIG symbol number 00000000001111111111 . . . 8888889999999999xxxx
+ 01234567890123456789 . . . 4567890123456789xxxx
+ -----------------------------------------------
+bits byte number <--00--><--01--><---- ----><--11--><--12-->
+bits bit in byte 01234567012345670123 . . . 45670123456701234567
+
+The irig_time.status is a single byte with bits defined in the
+bsd_audioirig.h header file. In ordinary operation all bits of the
+status byte are zero and the " " status character is set in the ASCII
+timecode. If any of these bits are nonzero, the "?" status character is
+set in the ASCII timecode.
+
+AUDIO_IRIG_BADSIGNAL
+
+ The signal amplitude is outside tolerance limits, either in
+ amplitude or modulation depth. The indicated time may or may not be
+ in error. If the signal is too high, it may be clipped by the
+ codec, so that the pulse width cannot be reliably determined. If
+ too low, it may be obscured by noise. The nominal expectation is
+ that the peak amplitude of the signal be maintained by the codec
+ AGC at about 10 dB below the clipping level and that the modulation
+ index be at least 0.5 (6 dB).
+
+AUDIO_IRIG_BADDATA
+
+ An invalid hex code (A through F) has been found where BCD data is
+ expected. The ASCII representation of the invalid code is set to
+ "?". Errors of this type are most likely due to noise on the IRIG
+ signal due to ground loops, coupling to other noise sources, etc.
+
+AUDIO_IRIG_BADSYNC
+
+ A code element has been found where a position identifier should be
+ or a position identifier has been found where a code element should
+ be. The time is meaningless and should be disregarded. Errors of
+ this type can be due to severe noise on the IRIG signal due to
+ ground loops, coupling to other noise sources, etc., or during
+ initial acquisition of the signal.
+
+AUDIO_IRIG_BADCLOCK
+
+ Some IRIG timecode generators can indicate whether or not the
+ generator is operating correctly or synchronized to its source of
+ standard time using a designated field in the raw binary timecode.
+ Where such information is available and the IRIG decoder can detect
+ it, this bit is set when the generator reports anything except
+ normal operating conditions.
+
+AUDIO_IRIG_OLDDATA
+
+ The IRIG time has not changed since the last time it was returned
+ in a read() call. This is not normally considered an error, unless
+ it persists for longer than a few seconds, in which case it
+ probably indicates a hardware problem.
+
+The irig_time.time[14] vector is a character string in the format "ddd
+hh:mm:ss*\0", which consists of 13 ASCII characters followed by a zero
+terminator. The "*" status character is an ASCII space " " if the status
+byte is zero and "?" if not. This format is identical to format 0,
+except that in format 1 the time string is null-terminated.
+
+2.1. Programming Example
+
+The following pseudo-code demonstrates how the IRIG receiver may be used
+by a simple user program. Of course, real code should include error
+checking after each call to ensure the driver is communicating properly.
+It should also verify that the correct fields in the structure are being
+filled by the read() call.
+
+ include "bsd_audioirig.h"
+
+ int format = 1;
+ struct irig_time it;
+
+ Audio_fd = open("/dev/audio", O_RDONLY);
+ ioctl(Audio_fd, AUDIO_IRIG_OPEN, NULL);
+ ioctl(Audio_fd, AUDIO_IRIG_SETFORMAT,&format);
+ while (condition)
+ read(Audio_fd, &it, sizeof(it);
+ printf("%s\n", it.time);
+ ioctl(Audio_fd, AUDIO_IRIG_CLOSE, NULL);
+ close(Audio_fd);
+
+3. Implementation and Configuration Notes
+
+The signal level produced by most IRIG-equipped radios is on the order
+of a few volts peak-peak, which is far larger than the audio codec can
+accept; therefore, an attenuator in the form of a voltage divider is
+needed. The codec can handle IRIG signals at the microphone input from
+4.2mV to 230mV peak-peak. A suitable attenuator conists of a series-
+connected 100K-Ohm resistor at the input and a parallel-connected 1K-Ohm
+resistor at the output, both contained along with suitable connectors in
+a small aluminum box. The exact values of these resistors are not
+critical, since the IRIG driver includes an automatic level-adjustment
+capability.
+
+For the most accurate time using the IRIG signal and a particular radio,
+it may be necessary to adjust the time1 parameter of the fudge command
+to compensate for the codec delay and any additional delay due to IRIG
+processing in the radio itself. Since the codec samples at an 8-kHz
+rate, the average delay is about 62 usec; however, the delays due to the
+radios and IRIG signals themselves can vary. For instance, in the
+Austron recievers the IRIG delay is essentially zero, while in the
+Spectracom receivers the delay is about 240 usec relative to the 1-pps
+signal. In addition, the poll interval can be reduced from the usual 64
+seconds to 16 seconds to reduce wander of the local hardware clock.
+Finally, the prefer parameter can be used to bias the clock-selection
+algorithm to favor the IRIG time, which is ordinarily the best time
+available. For example, the following two lines in the NTP configuration
+file ntp.conf are appropriate for the Spectracom Netclock/1 WWVB
+Synchronized Clock with IRIG Option:
+
+server 127.127.6.0 prefer minpoll 4 maxpoll 4 # irig audio decoder
+fudge 127.127.6.0 time1 0.0005
+
+The time1 value of .0005 s (500 usec) was determined by actual
+measurement. Since the IRIG delay in Austron receivers is essentially
+zero, the fudge command is not necessary with these receivers. The
+correct value in case of other radios may have to be determined by
+actual measurement. A convenient way of doing this is to configure the
+PPSPPS feature in the NTP Version 3 distribution and adjust time1 until
+the 1-pps signal and IRIG signal both show the same offset.
+
+The modified BSD driver includes both the modified driver itself
+bsd_audio.c and the IRIG header file bsd_audioirig.h, as well as
+modified header files bsd_audiovar.h and bsd_audioio.h. The driver is
+installed in the same way as described in the BSD driver documentation,
+with the addition of the following define in the kernel configuration
+file:
+
+options AUDIO_IRIG # IRIG driver
+
+This causes the IRIG code to be included in the BSD driver, as well as a
+C-coded codec interrupt routine which replaces the assembly-coded
+routine and provides the IRIG functionality. While the C-coded routine
+is somewhat slower than the assembly-coded routine, the extra overhead
+is not expected to be significant. Note that the IRIG driver calls the
+kernel routine microtime() as included in the ppsclock directory of the
+NTP Version 3 distribution xntp3. It is highly recommended that this
+routine be installed in the kernel configuration as well. The
+instructions for doing this are contained in the ppsclock directory of
+the xntp3 distribution.
+
+Roy LeCates <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/contrib/xntpd/doc/README.kern b/contrib/xntpd/doc/README.kern
new file mode 100644
index 000000000000..1b791c325ccf
--- /dev/null
+++ b/contrib/xntpd/doc/README.kern
@@ -0,0 +1,775 @@
+ Unix Kernel Modifications for Precision Timekeeping
+
+ Revised 3 December 1993
+
+Note: This information file is included in the distributions for the
+SunOS, Ultrix and OSF/1 kernels and in the NTP Version 3 distribution
+(xntp3.tar.Z) as the file README.kern. Availability of the kernel
+distributions, which involve licensed code, will be announced
+separately. The NTP Version 3 distribution can be obtained via anonymous
+ftp from louie.udel.edu in the directory pub/ntp. In order to utilize
+all features of this distribution, the NTP version number should be 3.3
+or later.
+
+1. Introduction
+
+This memo describes modifications to certain SunOS, Ultrix and OSF/1
+kernel software that manage the system clock and timer functions. They
+provide improved accuracy and stability through the use of a disciplined
+clock interface for use with the Network Time Protocol (NTP) or similar
+time-synchronization protocol. In addition, for the DEC 3000 AXP (Alpha)
+and DECstation 5000/240 machines, the modifications provide improved
+precision within one microsecond (us) (SunOS 4.1.x already does provide
+precision to this order). The NTP Version 3 daemon xntpd operates with
+these kernel modifications to provide synchronization in principle to
+within this order, but in practice this is limited by the short-term
+stability of the timer oscillator to within the order of 100 usec.
+
+This memo describes the principles behind the design and operation of
+the new software. There are three versions: one that operates with the
+SunOS 4.1.x kernels, a second that operates with the Ultrix 4.x kernels
+and a third that operates with the OSF/1 V1.x kernels. A detailed
+description of the variables and algorithms is given in the hope that
+similar functionality can be incorporated in Unix kernels for other
+machines. The algorithms involve only minor changes to the system clock
+and interval timer routines and include interfaces for application
+programs to learn the system clock status and certain statistics of the
+time-synchronization process. Detailed installation instructions are
+given in a companion README.install file included in the kernel
+distributions. The kernel software itself is not provided for public
+distribution, since it involves licensed code. Detailed instructions on
+how to obtain it for either SunOS, Ultrix or OSF/1 will be given
+separately.
+
+The principal feature added to the Unix kernels is to change the way the
+system clock is controlled, in order to provide precision time and
+frequency adjustments. Another feature utilizes an undocumented bus-
+cycle counter in the DEC 3000 AXP and DECstation 5000/240 to provide
+precise time to the microsecond. This feature can in principle be used
+with any DEC machine that has this counter, although this has not been
+verified. The addition of these features does not affect the operation
+of existing Unix system calls such as gettimeofday(), settimeofday() and
+adjtime(); however, if the new features are in use, the operations of
+adjtime() are controlled instead by a new system call ntp_adjtime().
+
+Most Unix programs read the system clock using the gettimeofday() system
+call, which returns only the system time and timezone data. For some
+applications it is useful to know the maximum error of the reported time
+due to all causes, including clock reading errors, oscillator frequency
+errors and accumulated latencies on the path to a primary reference
+source. However, the new software can adjust the system clock to
+compensate for its intrinsic frequency error, so that the timing errors
+expected in normal operation will usually be much less than the maximum
+error. The user application interface includes a new system call
+ntp_gettime(), which returns the system time, as well as the maximum
+error and estimated error. This interface is intended to support
+applications that need such things, including distributed file systems,
+multimedia teleconferencing and other real-time applications. The
+protocol daemon application interface includes a new system call
+ntp_adjtime(), which can be used to read and write kernel variables used
+for precision timekeeping, including time and frequency adjustments,
+controlling time constant, leap-second warning and related data.
+
+In this memo, NTP Version 3 and the Unix implementation xntpd are used
+as an example application of the new system calls for use by a protocol
+daemon. In principle, the new system calls can be used by other
+protocols and daemon implementations as well. Even in cases where the
+local time is maintained by periodic exchanges of messages at relatively
+long intervals, such as using the NIST Automated Computer Time Service,
+the ability to precisely adjust the local clock frequency simplifies the
+synchronization procedures and allows the call frequency to be
+considerably reduced.
+
+2. Design Principles
+
+In order to understand how the new software works, it is useful to
+consider how most Unix systems maintain the system time. In the original
+design a hardware timer interrupts the kernel at a fixed rate: 100 Hz in
+the SunOS kernel, 256 Hz in the Ultrix kernel and 1024 Hz in the OSF/1
+kernel. Since the Ultrix kernel rate does not evenly divide one second
+in microseconds, the kernel adds 64 microseconds once each second, so
+the timescale consists of 255 advances of 3906 usec plus one of 3970
+usec. Similarly, the OSF/1 kernel adds 576 usec once each second, so its
+timescale consists of 1023 advances of 976 usec plus one of 1552 usec.
+
+In all Unix kernels considered in this memo, it is possible to slew the
+system clock to a new offset using the standard Unix adjtime() system
+call. To do this the clock frequency is changed by adding or subtracting
+a fixed amount (tickadj) at each timer interrupt (tick) for a calculated
+number of ticks. Since this calculation involves dividing the requested
+offset by tickadj, it is possible to slew to a new offset with a
+precision only of tickadj, which is usually in the neighborhood of 5 us,
+but sometimes much higher. This results in an amortization error which
+can accumulate to unacceptable levels, so that special provisions must
+be made in the clock adjustment procedures of the protocol daemon.
+
+In order to maintain the system clock within specified bounds with this
+scheme, it is necessary to call adjtime() on a regular basis. For
+instance, let the bound be set at 100 usec, which is a reasonable value
+for NTP-synchronized hosts on a local network, and let the onboard
+oscillator tolerance be 100 parts-per-million (ppm), which is a
+reasonably conservative assumption. This requires that adjtime() be
+called at intervals not exceeding 1 second (s), which is in fact what
+the unmodified NTP software daemon does.
+
+In the new software this scheme is replaced by another that extends the
+low-order bits of the system clock to provide very precise clock
+adjustments. At each timer interrupt a precisely calibrated quantity is
+added to the composite time value and overflows handled as required. The
+quantity is computed from the measured clock offset and in addition a
+frequency adjustment, which is automatically calculated from previous
+time adjustments. This implementation operates as an adaptive-parameter
+first-order, type-II, phase-lock loop (PLL), which in principle provides
+precision control of the system clock phase to within +-1 us and
+frequency to within +-5 nanoseconds (ns) per day.
+
+This PLL model is identical to the one implemented in NTP, except that
+in NTP the software daemon has to simulate the PLL using only the
+original adjtime() system call. The daemon is considerably complicated
+by the need to parcel time adjustments at frequent intervals in order to
+maintain the accuracy to specified bounds. The modified kernel routines
+do this directly, allowing vast gobs of ugly daemon code to be avoided
+at the expense of only a small amount of new code in the kernel. In
+fact, the amount of code added to the kernel for the new scheme is about
+the amount needed to implement the old scheme. A new system call
+ntp_adjtime(), which operates in a way similar to the original
+adjtime(), is called only as each new time update is determined, which
+in NTP occurs at intervals of from 16 s to 1024 s. In addition, doing
+the frequency correction in the kernel means that the system time runs
+true even if the daemon were to cease operation or the network paths to
+the primary reference source fail. The addition of the new ntp_adjtime()
+system call does not affect the original adjtime() system call, which
+continues to operate in its traditional fashion. However, the two system
+calls canot be used at the same time; only one of the two should be used
+on any given system.
+
+It is the intent in the design that settimeofday() be used for changes
+in system time greater than +-128 ms. It has been the Internet
+experience that the need to change the system time in increments greater
+than +-128 milliseconds is extremely rare and is usually associated with
+a hardware or software malfunction or system reboot. Once the system
+clock has been set in this way, the ntp_adjtime() system call is used to
+provide periodic updates including the time offset, maximum error,
+estimated error and PLL time constant. With NTP the update interval
+depends on the measured error and time constant; however, the scheme is
+quite forgiving and neither moderate loss of updates nor variations in
+the length of the polling interval are serious.
+
+In addition, the kernel adjusts the maximum error to grow by an amount
+equal to the oscillator frequency tolerance times the elapsed time since
+the last update. The default engineering parameters have been optimized
+for intervals not greater than about 16 s. For longer intervals the PLL
+time constant can be adjusted to optimize the dynamic response up to
+intervals of 1024 s. Normally, this is automatically done by NTP. In any
+case, if updates are suspended, the PLL coasts at the frequency last
+determined, which usually results in errors increasing only to a few
+tens of milliseconds over a day.
+
+The new code needs to know the initial frequency offset and time
+constant for the PLL, and the daemon needs to know the current frequency
+offset computed by the kernel for monitoring purposes. These data are
+exchanged between the kernel and protocol daemon using ntp_adjtime() as
+documented later in this memo. Provisions are made to exchange related
+timing information, such as the maximum error and estimated error,
+between the kernel and daemon and between the kernel and application
+programs.
+
+In the DEC 3000 AXP, DECstation 5000/240 and possibly other DEC
+machines there is an undocumented hardware register that counts system
+bus cycles at a rate of 25 MHz. The new kernel microtime() routine tests
+for the CPU type and, in the case of these machines, use this register
+to interpolate system time between hardware timer interrupts. This
+results in a precision of +-1 us for all time values obtained via the
+gettimeofday() and ntp_gettime() system calls. These routines call the
+microtime() routine, which returns the actual interpolated value but
+does not change the kernel time variable. Therefore, other kernel
+routines that access the kernel time variable directly and do not call
+either gettimeofday(), ntp_gettime() or microtime() will continue their
+present behavior. The microtime() feature is independent of other
+features described here and is operative even if the kernel PLL or new
+system calls have not been implemented.
+
+While any protocol daemon can in principle be modified to use the new
+system calls, the most likely will be users of the NTP Version 3 daemon
+xntpd. The xntpd code determines whether the new system calls are
+implemented and automatically reconfigures as required. When
+implemented, the daemon reads the frequency offset from a file and
+provides it and the initial time constant via ntp_adjtime(). In
+subsequent calls to ntp_adjtime(), only the time adjustment and time
+constant are affected. The daemon reads the frequency from the kernel
+using ntp_adjtime() at intervals of about one hour and writes it to the
+system log file. This information is recovered when the daemon is
+restarted after reboot, for example, so the sometimes extensive training
+period to learn the frequency separately for each system can be avoided.
+
+3. Kernel Interfaces
+
+This section describes the kernel interfaces to the protocol daemon and
+user applications. The ideas are based on suggestions from Jeff Mogul
+and Philip Gladstone and a similar interface designed by the latter. It
+is important to point out that the functionality of the original Unix
+adjtime() system call is preserved, so that the modified kernel will
+work as the unmodified one should the kernel PLL not be in use. In this
+case the ntp_adjtime() system call can still be used to read and write
+kernel variables that might be used by a protocol daemon other than NTP,
+for example.
+
+3.1. The ntp_gettime() System Call
+
+The syntax and semantics of the ntp_gettime() call are given in the
+following fragment of the timex.h header file. This file is identical in
+the SunOS, Ultrix and OSF/1 kernel distributions. Note that the timex.h
+file calls the syscall.h system header file, which must be modified to
+define the SYS_ntp_gettime system call specific to each system type. The
+kernel distributions include directions on how to do this.
+
+/*
+ * This header file defines the Network Time Protocol (NTP) interfaces
+ * for user and daemon application programs. These are implemented using
+ * private system calls and data structures and require specific kernel
+ * support.
+ *
+ * NAME
+ * ntp_gettime - NTP user application interface
+ *
+ * SYNOPSIS
+ * #include <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/contrib/xntpd/doc/README.magic b/contrib/xntpd/doc/README.magic
new file mode 100644
index 000000000000..f473a9220c44
--- /dev/null
+++ b/contrib/xntpd/doc/README.magic
@@ -0,0 +1,346 @@
+ Magic Tricks for Precision Timekeeping
+
+ Revised 19 September 1993
+
+Note: This information file is included in the NTP Version 3
+distribution (xntp3.tar.Z) as the file README.magic. This distribution
+can be obtained via anonymous ftp from louie.udel.edu in the directory
+pub/ntp.
+
+1. Introduction
+
+It most cases it is possible using NTP to synchronize a number of hosts
+on an Ethernet or moderately loaded T1 network to a radio clock within a
+few tens of milliseconds with no particular care in selecting the radio
+clock or configuring the servers on the network. This may be adequate
+for the majority of applications; however, modern workstations and high
+speed networks can do much better than that, generally to within some
+fraction of a millisecond, by using special care in the design of the
+hardware and software interfaces.
+
+The timekeeping accuracy of a NTP-synchronized host depends on two
+quantities: the delay due to hardware and software processing and the
+accumulated jitter due to such things as clock reading precision and
+varying latencies in hardware and software queuing. Processing delays
+directly affect the timekeeping accuracy, unless minimized by systematic
+analysis and adjustment. Jitter, on the other hand, can be essentially
+removed, as long as the statistical properties are unbiased, by the low-
+pass filtering of the phase-lock loop incorporated in the NTP local
+clock model.
+
+This note discusses issues in the connection of external time sources
+such as radio clocks and related timing signals to a primary (stratum-1)
+NTP time server. Of principal concern are various techniques that can be
+utilized to improve the accuracy and precision of the time accuracy and
+frequency stability. Radio clocks are most often connected to a time
+server using a serial asynchronous port. Much of the discussion in this
+memorandum has to do with ways in which the delay incurred in this type
+of connection can be controlled and ways in which the jitter due to
+various causes can be minimized.
+
+However, there are ways other than serial ports to connect a radio
+clock, including special purpose hardware devices for some
+architectures, and even unusual applications of existing interface
+devices, such as the audio codec provided in some systems. Many of these
+methods can yield accuracies as good as any attainable with a serial
+port. For those radio clocks equipped with an IRIG-B signal output, for
+example, a hardware device is available for the Sun SPARCstation; see
+the xntpd.8 manual page in the doc directory of the NTP Version 3
+distribution for further information. In addition, it is possible to
+decode the IRIG-B signal using the audio codec included in the Sun
+SPARCstation and a special kernel driver described in the irig.txt file
+in the doc directory of the NTP Version 3 distribution. These devices
+will not be discussed further in this memorandum.
+
+2. Connection via Serial Port
+
+Most radio clocks produce an ASCII timecode with a precision only to the
+millisecond. This results in a maximum peak-to-peak (p-p) jitter in the
+clock readings of one millisecond. However, assuming the read requests
+are statistically independent of the clock update times, the reading
+error is uniformly distributed over the millisecond, so that the average
+over a large number of readings will make the clock appear 0.5 ms late.
+To compensate for this, it is only necessary to add 0.5 ms to its
+reading before further processing by the NTP algorithms.
+
+Radio clocks are usually connected to the host computer using a serial
+port operating at a typical speed of 9600 baud. The on-time reference
+epoch for the timecode is usually the start bit of a designated
+character, usually <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/contrib/xntpd/doc/UofT b/contrib/xntpd/doc/UofT
new file mode 100644
index 000000000000..54420d5f5252
--- /dev/null
+++ b/contrib/xntpd/doc/UofT
@@ -0,0 +1,146 @@
+This file is the original README, and is a little out of date. It
+is also very specific to UofT, since there was a time when the daemon
+was only run here.
+
+To run this:
+
+(1) Fix your kernel's value of tickadj. Tickadj sets both the
+ precision with which time slews can be performed and the amount
+ of slew you can do in a given interval. Xntpd operates by making
+ a bunch of little adjustments. Make tickadj too large (the default
+ value almost always is) and xntpd will perform poorly since the
+ slews will disappear in the roundoff. Make tickadj too small
+ and large slews won't complete before the next adjustment is
+ ready.
+
+ To determine a good value of tickadj to use, first determine your
+ kernel's value of hz (50 on a Sun 3, 100 on Sun 4's and vaxes).
+ Divide that number into 500 (i.e. compute 500/hz) and use an
+ integer near there as tickadj (say, 10 on Sun 3's, 5 on Sun 4's
+ and vaxes). Then adb your kernel and write the new value. You
+ should probably do both the running kernel and the disk image.
+
+ If your machine doesn't come with adb, or if the kernel is of a
+ non-Berkeley flavour, take a look at the util directory, particularly
+ util/tickadj.
+
+(2) Edit the Config file in this directory. You *must* tell it whether
+ your machine uses big endian or little endian byte order. Also,
+ Suns running SunOS 3.x require special consideration, as well as Vaxes
+ running Ultrix 2.0 and compilers which don't understand `signed char'
+ declarations. When you've got all this worked out, type `make makefiles'
+ to distribute configuration information to Makefiles for individual
+ programs, followed by `make' to compile everything.
+
+(2a) Note that, among other things, two programs were made in the authstuff
+ directory, authcert and authspeed. The last two are utilities for
+ checking the authentication code. Type `authcert < certdata'. If
+ this provokes a massive failure you probably got the byte order wrong
+ in the Config file. Type `authspeed -n 10000 auth.samplekeys', or
+ something, a couple of times to get a value of authdelay to stick in
+ the configuration file. The numbers for machines I've tried look like:
+
+ uVax II 0.001450
+ Sun 3/180 0.000620
+ uVax III 0.000515
+ Sun 3/60 0.000455
+ IBM RT Mdl 125 0.000323
+ Sun 3/280 0.000302
+ Sun 4/280 0.000110
+ MIPS M/1000 0.000100
+
+(3) Typing `make install' will nstall xntpd, xntpdc, ntpdate and ntpq. Watch
+ the install location in the Config file.
+
+(4) If you will be running xntpd (see 4a below for the alternative),
+ configure it (configuration is necessary for all machines now, though
+ this restriction will go away when I get broadcast time fully tested).
+ xntpd reads its configuration from /etc/ntp.conf (by default) and
+ you must tell it which machines it is to get its time from in
+ here.
+
+ Note that NTP operates in a hierarchy. Machines with radio clocks
+ (which are stratum 1 servers) are at the top of the heap, in that
+ all time originates with them. The situation with servers locally
+ is in a state of flux. We currently have one semi-reliable stratum 1
+ server on campus (suzuki.ccie), and maintain three other stratum 2
+ servers which (gently) access other people's off-campus stratum 1
+ servers. All of these machines are lightly loaded and have good
+ quality clocks, and so will probably do until we get some more stratum 1
+ weight.
+
+ Thus you are probably faced with choosing whether your hosts should
+ be stratum 2 or stratum 3 (or stratum 3 or 4 when suzuki's clock is down).
+ The rule of thumb is to make your best clocks and/or your file servers
+ stratum 2 (or 3) by peering them with the four campus servers, and make
+ lesser clocks and clients stratum 3 (or 4) by peering them with near
+ by servers which are synchonized to the campus servers. The second rule
+ of thumb is that more servers are better. It is quite possible to
+ synchronize with just a single server, but if you do your xtnpd daemon
+ won't have any cross checks to tell it when the server has gone
+ wonky. 3 or 4 lower stratum peers is about right. Note that while
+ you can also peer with same-stratum peers, you shouldn't do this
+ unless the same-stratum peer is exchanging time with a lower stratum
+ peer you don't talk to directly.
+
+ Anyway, for your stratum 2 servers you can probably use ntp.conf
+ from the conf directory directly. You will have to handcraft the
+ peer assocations for your stratum 3 servers.
+
+ Oh, and a note about the drift file (see ntp.conf). One of the
+ things xntpd does is accumulate a correction for the frequency of
+ the crystal in your computer. It usually takes a day or so of
+ running to figure this out, after which the value will usually remain
+ pretty stable, especially if the computer is in a machine room. The
+ value is printed in your syslog file (once a minute, currently, though
+ this will change), and can be obtained from the daemon using xntpdc.
+
+ To avoid having to wait a day after restarts before the computer
+ synchronizes really well, xntpd will optionally write its current
+ value of the frequency correction into a file, once an hour. When
+ it is killed and restarted, xntpd reinitializes itself to this
+ value on start up. This is an advantageous feature, so a driftfile
+ line should always be included in the configuration file.
+
+(4a) Xntpd is a daemon. It will keep your time exquisitely precise under
+ normal conditions (it is quite capable of keeping a good clock within
+ a millisecond of a good server. Our servers aren't normally this
+ good, yet, but may become so when we get a few more stable local
+ stratum 1 peers). Even when cut off entirely from its servers xntpd
+ will prevent your clock from drifting seriously by continuing to apply
+ its accumulated frequency correction. The cost of this is that xntpd
+ will permanently consume memory while it is running, and real memory
+ at that since xntpd is unlikely to ever swap out. This cost is
+ currently over 100 kb.
+
+ If you aren't too worried about millisecond timing and feel religious
+ about keeping memory consumption at a minimum (perhaps on memory-poor
+ workstations), a passable alternative might be to run ntpdate instead.
+ Ntpdate is the NTP equivalent of rdate, a one shot date setting
+ program, and implements the same multiple sample/multiple server
+ filter algorithms as xntpd. Ntpdate was explicitly designed to be
+ run repeatly from cron, though it also makes a good boot time date
+ setter. Running ntpdate from cron on an hourly basis will keep all
+ but seriously broken clocks within 100 ms of on-time, and for most
+ clocks will probably do better than 50 ms. If this is an attractive
+ alternative see the manual page. You should choose ntpdate's servers
+ as you would the peer associations for a stratum 3 xntpd server.
+
+(5) Once everything is configured, start the daemon(s). ntpq can be
+ used to see what xntpd is doing. It runs both interactive and from
+ the command line, type ? to see the interactive commands and ? command
+ to see what a command does. The `peers' command is a good one. ntpq
+ can also be used to see what other peoples' servers are doing, in
+ particular the fuzzball primary servers.
+
+(6) If you want to use the authentication facility (this might be useful
+ if, for example, you were running Kerberos since this prevents people
+ from setting your time back and doing replay attacks on the server),
+ you might find a couple of useful programs in the auth_stuff directory.
+ mkrandkeys will generate some very random keys to use. keyparity
+ generates odd parity bits for keys (needed for the key file) and will
+ convert between key formats.
+
+All bug reports gratefully received.
+
+Dennis
diff --git a/contrib/xntpd/doc/notes.txt b/contrib/xntpd/doc/notes.txt
new file mode 100644
index 000000000000..5ea2b3318bb3
--- /dev/null
+++ b/contrib/xntpd/doc/notes.txt
@@ -0,0 +1,1258 @@
+ Notes on Xntpd Configuration
+
+ David L. Mills (mills@udel.edu)
+ University of Delaware
+ 14 January 1993
+
+Introduction
+
+This document is a collection of notes concerning the use of xntpd and
+related programs, and on coping with the Network Time Protocol (NTP) in
+general. It is a major rewrite and update of an earlier document written
+by Dennis Ferguson of the University of Toronto dated 5 November 1989.
+It includes many changes and additions resulting from the NTP Version 3
+specification and new implementation features. It supersedes the earlier
+document, which should no longer be used for new configurations.
+
+Xntpd is a complete implementation of the NTP Version 3 specification as
+defined in RFC 1305. It also retains compatibility with both NTP Version
+2, as defined in RFC 1119, and NTP Version 1, as defined in RFC 1059,
+although this compatibility is sometimes strained and only
+semiautomatic. In order to support in principle the ultimate precision
+of about 232 picoseconds in the NTP specification, xntpd does no
+floating-point arithmetic and instead manipulates the 64-bit NTP
+timestamps as unsigned 64-bit integers. Xntpd fully implements NTP
+Versions 2 and 3 authentication and a mode-6 control-message facility.
+As extensions to the specification, a flexible address-and-mask
+restriction facility has been included, along with a private mode-7
+control-message facility used to remotely reconfigure the system and
+monitor a considerable amount of internal detail.
+
+The code is biased towards the needs of a busy time server with
+numerous, possibly hundreds, of clients and other servers. Tables are
+hashed to allow efficient handling of many associations, though at the
+expense of additional overhead when the number of associations is small.
+Many fancy features have been included to permit efficient management
+and monitoring of a busy primary server, features which are simply
+excess baggage for a server on a high stratum client. The code was
+written with near demonic attention to details which can affect
+precision and as a consequence should be able to make good use of high
+performance, special purpose hardware such as precision oscillators and
+radio clocks. The present code supports a number of radio clocks,
+including those for the WWV, CHU, WWVB, DCF77, GOES and GPS radio and
+satellite services. The server methodically avoids the use of Unix-
+specific library routines where possible by implementing local versions,
+in order to aid in porting the code to perverse Unix and non-Unix
+platforms.
+
+While this implementation slavishly obeys the NTP specification RFC
+1305, it has been specifically tuned to achieve the highest accuracy
+possible on whatever hardware and operating-system platform is
+available. In general, its precision is limited only by that of the
+onboard time-of-day clock maintained by the hardware and operating
+system, while its stability is limited only by that of the onboard
+frequency source, usually an uncompensated crystal oscillator. On modern
+RISC-based processors connected directly to radio clocks via serial-
+asynchronous interfaces, the accuracy is usually limited by that of the
+radio clock and interface to the order of a few milliseconds. The code
+includes special features to support a one-pulse-per-second (1-pps)
+signal generated by some radio clocks. When used in conjunction with a
+suitable hardware level converter, the accuracy can be improved to the
+order of 100 microseconds. Further improvement is possible using an
+outboard, stabilized frequency source, in which the accuracy and
+stability are limited only by the characteristics of that source.
+
+The xntp3 distribution includes, in addition to the daemon itself
+(xntpd), several utility programs, including two remote-monitoring
+programs (ntpq, xntpdc), a remote clock-setting program similar to the
+Unix rdate program (ntpdate), a traceback utility useful to discover
+suitable synchronization sources (ntptrace), and various programs used
+to configure the local platform and calibrate the intrinsic errors. NTP
+has been ported to a large number of platforms, including most RISC and
+CISC workstations and mainframes manufactured today. Example
+configuration files for many models of these machines are included in
+the xntp3 distribution. While in most cases the standard version of the
+implementation runs with no hardware or operating-system modifications,
+not all features of the distribution are available on all platforms. For
+instance, a special feature allowing Sun 4s to achieve accuracies in the
+order of 100 microseconds requires some minor changes and additions to
+the kernel and input/output support.
+
+There are, however, several drawbacks to all of this. Xntpd is very,
+very fat. This is rotten if your intended platform for the daemon is
+memory-limited. Xntpd uses SIGIO for all input, a facility which appears
+to not enjoy universal support and whose use seems to exercise the parts
+of your vendors' kernels which are most likely to have been done poorly.
+The code is unforgiving in the face of kernel problems which affect
+performance, and generally requires that you repair the problems in
+order to achieve acceptable performance. The code has a distinctly
+experimental flavour and contains features which could charitably be
+termed failed experiments, but which have not been hacked out yet. There
+is code which has not been thoroughly tested (e.g. leap-second support)
+due to the inconvenience of setting up tests. Much was learned from the
+addition of support for a variety of radio clocks, with the result that
+this support could use some rewriting.
+
+How NTP Works
+
+The approach used by NTP to achieve reliable time synchronization from a
+set of possibly unreliable remote time servers is somewhat different
+than other such protocols. In particular, NTP does not attempt to
+synchronize clocks to each other. Rather, each server attempts to
+synchronize to UTC (i.e., Universal Coordinated Time) using the best
+available source and available transmission paths to that source. This
+is a fine point which is worth understanding. A group of NTP-
+synchronized clocks may be close to each other in time, but this is not
+a consequence of the clocks in the group having synchronized to each
+other, but rather because each clock has synchronized closely to UTC via
+the best source it has access to. As such, trying to synchronize a set
+of clocks to a set of servers whose time is not in mutual agreement may
+not result in any sort of useful synchronization of the clocks, even if
+you don't care about UTC. NTP operates on the premise that there is one
+true standard time, and that if several servers which claim
+synchronization to standard time disagree about what that time is, then
+one or more of them must be broken. There is no attempt to resolve
+differences more gracefully since the premise is that substantial
+differences cannot exist. In essence, NTP expects that the time being
+distributed from the root of the synchronization subnet will be derived
+from some external source of UTC (e.g. a radio clock). This makes it
+somewhat inconvenient (though not impossible) to synchronize hosts
+together without a reliable source of UTC to synchronize them to. If
+your network is isolated and you cannot access other people's servers
+across the Internet, a radio clock may make a good investment.
+
+Time is distributed through a hierarchy of NTP servers, with each server
+adopting a "stratum" which indicates how far away from an external
+source of UTC it is operating at. Stratum-1 servers, which are at the
+top of the pile (or bottom, depending on your point of view), have
+access to some external time source, usually a radio clock synchronized
+to time signal broadcasts from radio stations which explicitly provide a
+standard time service. A stratum-2 server is one which is currently
+obtaining time from a stratum-1 server, a stratum-3 server gets its time
+from a stratum-2 server, and so on. To avoid long lived synchronization
+loops the number of strata is limited to 15.
+
+Each client in the synchronization subnet (which may also be a server
+for other, higher stratum clients) chooses exactly one of the available
+servers to synchronize to, usually from among the lowest stratum servers
+it has access to. It is thus possible to construct a synchronization
+subnet where each server has exactly one source of lower stratum time to
+synchronize to. This is, however, not an optimal configuration, for
+indeed NTP operates under another premise as well, that each server's
+time should be viewed with a certain amount of distrust. NTP really
+prefers to have access to several sources of lower stratum time (at
+least three) since it can then apply an agreement algorithm to detect
+insanity on the part of any one of these. Normally, when all servers are
+in agreement, NTP will choose the best of these, where "best" is defined
+in terms of lowest stratum, closest (in terms of network delay) and
+claimed precision, along with several other considerations. The
+implication is that, while one should aim to provide each client with
+three or more sources of lower stratum time, several of these will only
+be providing backup service and may be of lesser quality in terms of
+network delay and stratum (i.e. a same-stratum peer which receives time
+from lower stratum sources the local server doesn't access directly can
+also provide good backup service).
+
+Finally, there is the issue of association modes. There are a number of
+modes in which NTP servers can associate with each other, with the mode
+of each server in the pair indicating the behaviour the other server can
+expect from it. In particular, when configuring a server to obtain time
+from other servers, there is a choice of two modes which may be
+alternatively used. Configuring an association in symmetric-active mode
+(usually indicated by a "peer" declaration in configuration files)
+indicates to the remote server that one wishes to obtain time from the
+remote server and that one is also willing to supply time to the remote
+server if need be. This mode is appropriate in configurations involving
+a number of redundant time servers interconnected via diverse network
+paths, which is presently the case for most stratum-1 and stratum-2
+servers on the Internet today. Configuring an association in client mode
+(usually indicated by a "server" declaration in configuration files)
+indicates that one wishes to obtain time from the remote server, but that
+one is not willing to provide time to the remote server. This mode is
+appropriate for file-server and workstation clients that do not provide
+synchronization to other local clients. Client mode is also useful for
+boot-date-setting programs and the like, which really have no time to
+provide and which don't retain state about associations over the longer
+term.
+
+Configuring Your Subnet
+
+At startup time the xntpd daemon running on a host reads the initial
+configuration information from a file, usually /etc/ntp.conf, unless a
+different name has been specified at compile time. Putting something in
+this file which will enable the host to obtain time from somewhere else
+is usually the first big hurdle after installation of the software
+itself, which is described in other documents included in the xntp3
+distribution. At its simplest, what you need to do in the configuration
+file is declare the servers that the daemon should poll for time
+synchronization. In principle, no such list is needed if some other time
+server explicitly mentions the host and is willing to provide
+synchronization; however, this is considered dangerous, unless the
+access control or authentication features (described later) are in use.
+
+In the case of a workstation operating in an enterprise network for a
+public or private organization, there is often an administrative
+department that coordinates network services, including NTP. Where
+available, the addresses of appropriate servers can be provided by that
+department. However, if this infrastructure is not available, it is
+necessary to explore some portion of the existing NTP subnet now running
+in the Internet. There are at present many thousands of time servers
+running NTP in the Internet, a significant number of which are willing
+to provide a public time-synchronization service. Some of these are
+listed in a file maintained on the Internet host louie.udel.edu
+(128.175.1.3) on the path pub/ntp/doc/clock.txt. This file is updated on
+a regular basis using information provided voluntarily by various site
+administrators. There are other ways to explore the nearby subnet using
+the ntptrace and ntpq programs. See the man pages for further
+information on these programs.
+
+It is vital to carefully consider the issues of robustness and
+reliability when selecting the sources of synchronization. Normally, not
+less than three sources should be available, preferably selected to
+avoid common points of failure. It is usually better to choose sources
+which are likely to be "close" to you in terms of network topology,
+though you shouldn't worry overly about this if you are unable to
+determine who is close and who isn't. Normally, it is much more serious
+when a server becomes faulty and delivers incorrect time than when it
+simply stops operating, since an NTP-synchronized host normally can
+coast for hours or even days without its clock accumulating serious
+error over one second, for instance. Selecting at least three sources
+from different operating administrations, where possible, is the minimum
+recommended, although a lesser number could provide acceptable service
+with a degraded degree of robustness.
+
+Normally, it is not considered good practice for a single workstation to
+request synchronization from a primary (stratum-1) time server. At
+present, these servers provide synchronization for hundreds of clients
+in many cases and could, along with the network access paths, become
+seriously overloaded if large numbers of workstation clients requested
+synchronization directly. Therefore, workstations located in sparsely
+populated administrative domains with no local synchronization
+infrastructure should request synchronization from nearby stratum-2
+servers instead. In most cases the keepers of those servers listed in
+the clock.txt file provide unrestricted access without prior permission;
+however, in all cases it is considered polite to notify the
+administrator listed in the file upon commencement of regular service.
+In all cases the access mode and notification requirements listed in the
+file must be respected.
+
+In the case of a gateway or file server providing service to a
+significant number of workstations or file servers in an enterprise
+network it is even more important to provide multiple, redundant sources
+of synchronization and multiple, diversity-routed, network access paths.
+The preferred configuration is at least three administratively
+coordinated time servers providing service throughout the administrative
+domain including campus networks and subnetworks. Each of these should
+obtain service from at least two different outside sources of
+synchronization, preferably via different gateways and access paths.
+These sources should all operate at the same stratum level, which is one
+less than the stratum level to be used by the local time servers
+themselves. In addition, each of these time servers should peer with all
+of the other time servers in the local administrative domain at the
+stratum level used by the local time servers, as well as at least one
+(different) outside source at this level. This configuration results in
+the use of six outside sources at a lower stratum level (toward the
+primary source of synchronization, usually a radio clock), plus three
+outside sources at the same stratum level, for a total of nine outside
+sources of synchronization. While this may seem excessive, the actual
+load on network resources is minimal, since the interval between polling
+messages exchanged between peers usually ratchets back to no more than
+one message every 17 minutes.
+
+The stratum level to be used by the local time servers is an engineering
+choice. As a matter of policy, and in order to reduce the load on the
+primary servers, it is desirable to use the highest stratum consistent
+with reliable, accurate time synchronization throughout the
+administrative domain. In the case of enterprise networks serving
+hundreds or thousands of client file servers and workstations,
+conventional practice is to obtain service from stratum-1 primary
+servers such as listed in the clock.txt file. When choosing sources away
+from the primary sources, the particular synchronization path in use at
+any time can be verified using the ntptrace program included in the
+xntp3 distribution. It is important to avoid loops and possible common
+points of failure when selecting these sources. Note that, while NTP
+detects and rejects loops involving neighboring servers, it does not
+detect loops involving intervening servers. In the unlikely case that
+all primary sources of synchronization are lost throughout the subnet,
+the remaining servers on that subnet can form temporary loops and, if
+the loss continues for an interval of many hours, the servers will drop
+off the subnet and free-run with respect to their internal (disciplined)
+timing sources.
+
+In many cases the purchase of one or more radio clocks is justified, in
+which cases good engineering practice is to use the configurations
+described above and connect the radio clock to one of the local servers.
+This server is then encouraged to participate in a special primary-
+server subnetwork in which each radio-equipped server peers with several
+other similarly equipped servers. In this way the radio-equipped server
+may provide synchronization, as well as receive synchronization, should
+the local or remote radio clock(s) fail or become faulty. Xntpd treats
+attached radio clock(s) in the same way as other servers and applies the
+same criteria and algorithms to the time indications, so can detect when
+the radio fails or becomes faulty and switch to alternate sources of
+synchronization. It is strongly advised, and in practice for most
+primary servers today, to employ the authentication or access-control
+features of the xntp3 distribution in order to protect against hostile
+penetration and possible destabilization of the time service.
+
+Using this or similar strategies, the remaining hosts in the same
+administrative domain can be synchronized to the three (or more)
+selected time servers. Assuming these servers are synchronized directly
+to stratum-1 sources and operate normally as stratum-2, the next level
+away from the primary source of synchronization, for instance various
+campus file servers, will operate at stratum 3 and dependent
+workstations at stratum 4. Engineered correctly, such a subnet will
+survive all but the most exotic failures or even hostile penetrations of
+the various, distributed timekeeping resources.
+
+The above arrangement should provide very good, robust time service with
+a minimum of traffic to distant servers and with manageable loads on the
+local servers. While it is theoretically possible to extend the
+synchronization subnet to even higher strata, this is seldom justified
+and can make the maintenance of configuration files unmanageable.
+Serving time to a higher stratum peer is very inexpensive in terms of
+the load on the lower stratum server if the latter is located on the
+same concatenated LAN. When justified by the accuracy expectations, NTP
+can be operated in broadcast mode, so that clients need only listen for
+periodic broadcasts and do not need to send anything.
+
+When planning your network you might, beyond this, keep in mind a few
+generic don'ts, in particular:
+
+1. Don't synchronize a local time server to another peer at the same
+ stratum, unless the latter is receiving time from lower stratum
+ sources the former doesn't talk to directly. This minimizes the
+ occurance of common points of failure, but does not eliminate them
+ in cases where the usual chain of associations to the primary
+ sources of synchronization are disrupted due to failures.
+2. Don't configure peer associations with higher stratum servers. Let
+ the higher strata configure lower stratum servers, but not the
+ reverse. This greatly simplifies configuration file maintenance,
+ since there is usually much greater configuration churn in the high
+ stratum clients such as personal workstations.
+
+3. Don't synchronize more than one time server in a particular
+ administrative domain to the same time server outside that domain.
+ Such a practice invites common points of failure, as well as raises
+ the possibility of massive abuse, should the configuration file be
+ automatically distributed do a large number of clients.
+
+There are many useful exceptions to these rules. When in doubt, however,
+follow them.
+
+Dennis Ferguson writes: Note that mention was made of machines with
+"good" clocks versus machines with "bad" ones. There are two things that
+make a clock good, the precision of the clock (e.g. how many low order
+bits in a time value are actually significant) and the frequency of
+occurance (or lack thereof) of such things as lost clock interrupts.
+Among the most common computers I have observed there to be a fairly
+simple algorithm for determining the goodness of its clock. If the
+machine is a Vax, it probably has a good clock (the low order bit in the
+time is in the microseconds and most of these seem to manage to get
+along without losing clock interrupts). If the machine is a Sun 3 it
+probably doesn't (the low order clock bit is at the 10 or 20 millisecond
+mark and Sun 3s like to lose clock interrupts, particularly if they have
+a screen and particularly if they run SunOS 4.0.x). If you have IBM RTs
+running AOS 4.3, they have fair clocks (low order clock bit at about a
+millisecond and they don't lose clock interrupts, though they do have
+trouble with clock rollovers while reading the low order clock bits) but
+I recommend them as low stratum NTP servers anyway since they aren't
+much use as anything else. Sun 4s running SunOS 4.1.1 make very good
+time servers, once some native foolishness mentioned below is
+surmounted. [However, it is very important to avoid using the keyboard
+firmware, which can cause severe interrupt latencies, in favor of the
+software drivers ordinarily used in conjunction with a windowing system.
+- DLM] For other machines you are on your own since I don't have enough
+data points to venture an opinion. In any event, if at all possible you
+should try to use machines with good clocks for the lower strata.
+
+Configuring Your Server or Client
+
+As mentioned previously, the configuration file is usually called
+/etc/ntp.conf. This is an ASCII file conforming to the usual comment and
+whitespace conventions. A working configuration file might look like (In
+this and other examples, do not copy this directly.):
+
+ # peer configuration for 128.100.100.7
+ # (expected to operate at stratum 2)
+
+ server 128.4.1.1 # rackety.udel.edu
+ server 128.8.10.1 # umd1.umd.edu
+ server 192.35.82.50 # lilben.tn.cornell.edu
+ driftfile /etc/ntp.drift
+
+This particular host is expected to operate as a client at stratum 2 by
+virtue of the "server" keyward and the fact that two of the three
+servers declared (the first two, actually) have radio clocks and usually
+run at stratum 1. The third server in the list has no radio clock, but
+is known to maintain associations with a number of stratum 1 peers and
+usually operates at stratum 2. Of particular importance with the last
+host is that it maintains associations with peers besides the two
+stratum 1 peers mentioned. This can be verified using the ntpq program
+included in the xntp3 distribution. When configured using the "server"
+keyword, this host can receive synchronization from any of the listed
+servers, but can never provide synchronization to them.
+
+Unless restricted using facilities described later, this host can
+provide synchronization to dependent clients, which do not have to be
+listed in the configuration file. Associations maintained for these
+clients are transitory and result in no persistent state in the host.
+These clients are normally not visible using the ntpq program included
+in the xntp3 distribution; however, xntpd includes a monitoring feature
+(described later) which caches a minimal amount of client information
+useful for debugging administrative purposes.
+
+A time server expected to both receive synchronization from another
+server, as well as to provide synchronization to it, is delared using
+the "peer" keyword instead of the "server" keyword. In all other aspects
+the server operates the same in either mode and can provide
+synchronization to dependent clients or other peers. It is considered
+good engineering practice to declare time servers outside the
+administrative domain as "peer" and those inside as "server" in order to
+provide redundancy in the global Internet, while minimizing the
+possibility of instability within the domain itself. A time server in
+one domain can in principle heal another domain temporarily isolated
+from all other sources of synchronization. However, it is probably
+unwise for a casual workstation to bridge fragments of the local domain
+which have become temporarily isolated.
+
+Note the inclusion of a "driftfile" declaration. One of the things the
+NTP daemon does when it is first started is to compute the error in the
+intrinsic frequency of the clock on the computer it is running on. It
+usually takes about a day or so after the daemon is started to compute a
+good estimate of this (and it needs a good estimate to synchronize
+closely to its server). Once the initial value is computed, it will
+change only by relatively small amounts during the course of continued
+operation. The "driftfile" declaration indicates to the daemon the name
+of a file where it may store the current value of the frequency error so
+that, if the daemon is stopped and restarted, it can reinitialize itself
+to the previous estimate and avoid the day's worth of time it will take
+to recompute the frequency estimate. Since this is a desireable feature,
+a "driftfile" declaration should always be included in the configuration
+file.
+
+An implication in the above is that, should xntpd be stopped for some
+reason, the local platform time will diverge from UTC by an amount that
+depends on the intrinsic error of the clock oscillator and the time
+since last synchronized. In view of the length of time necessary to
+refine the frequency estimate, every effort should be made to operate
+the daemon on a continuous basis and minimize the intervals when for
+some reason it is not running.
+
+Xntpd3 Versus Previous Versions
+
+There are several items of note when dealing with a mixture of xntp3 and
+and previous distributions of xntp (NTP Version 2 xntpd) and ntp3.4 (NTP
+Version 1 ntpd). The xntp3 implementation of xntpd is an NTP Version 3
+implementation. As such, by default when no additional information is
+available concerning the preferences of the peer, xntpd claims to be
+version 3 in the packets that it sends.
+
+An NTP implementation conforming to a previous version specification
+ordinarily discards packets from a later version. However, in most
+respects documented in RFC 1305, the previous version is compatible with
+the version-3 algorithms and protocol. Ntpd, while implementing most of
+the version-2 algorithms, still believes itself to be a version-1
+implementation. The sticky part here is that, when either xntpd version
+2 or ntpd version 1 receives a packet claiming to be from a version-3
+server, it discards it without further processing. Hence there is a
+danger that in some situations synchronization with previous versions
+will fail.
+
+Xntpd is aware of this problem. In particular, when xntpd is polled
+first by a host claiming to be a previous version 1 or version 2
+implementation, xntpd claims to be a version 1 or 2 implementation,
+respectively, in packets returned to the poller. This allows xntpd to
+serve previous version clients transparently. The trouble occurs when an
+previous version is to be included in an xntpd configuration file. With
+no further indication, xntpd will send packets claiming to be version 3
+when it polls. To get around this, xntpd allows a qualifier to be added
+to configuration entries to indicate which version to use when polling.
+Hence the entry
+
+ # specify NTP version 1
+
+ peer 130.43.2.2 version 1 # apple.com (running ntpd version 1)
+ peer 130.43.2.2 version 2 # apple.com (running xntpd version 2)
+
+will cause version 1 packets to be sent to the host address 130.43.2.2.
+If you are testing xntpd against previous version servers you will need
+to be careful about this. Note that, as indicated in the RFC 1305
+specification, there is no longer support for the original NTP
+specification, popularly called NTP Version 0.
+
+There are a few other items to watch when converting an ntpd
+configuration file for use with xntpd. The first is to reconsider the
+precision entry from the configuration file, if there is one. There was
+a time when the precision claimed by a server was mostly commentary,
+with no particularly useful purpose. This is no longer the case,
+however, and so changing the precision a server claims should only be
+done with some consideration as to how this alters the performance of
+the server. The default precision claimed by xntpd will be right for
+most situations. A section later on will deal with when and how it is
+appropriate to change a server's precision without doing things you
+don't intend.
+
+Second, note that in the example configuration file above numeric
+addresses are used in the peer and server declarations. It is also
+possible to use names requiring resolution instead, but only if some
+additional configuration is done (xntpd doesn't include the resolver
+routines itself, and requires that a second program be used to do name
+resolution). If you find numeric addresses offensive, see below.
+
+Finally, "passive" and "client" entries in an ntpd configuration file
+have no useful equivalent semantics for xntpd and should be deleted.
+Xntpd won't reset the kernel variable tickadj when it starts, so you can
+remove anything dealing with this in the configuration file. The
+configuration of radio clock peers is done using different language in
+xntpd configuration files, so you will need to delete these entries from
+your ntpd configuration file and see below for the equivalent language.
+
+Traffic Monitoring
+
+Xntpd handles peers whose stratum is higher than the stratum of the
+local server and pollers using client mode by a fast path which
+minimizes the work done in responding to their polls, and normally
+retains no memory of these pollers. Sometimes, however, it is
+interesting to be able to determine who is polling the server, and how
+often, as well as who has been sending other types of queries to the
+server.
+
+To allow this, xntpd implements a traffic monitoring facility which
+records the source address and a minimal amount of other information
+from each packet which is received by the server. This can be enabled by
+adding the following line to the server's configuration file:
+
+ # enable monitoring feature
+
+ monitor yes
+
+The recorded information can be displayed using the xntpdc query
+program, described briefly below.
+
+Address-and-Mask Restrictions
+
+The address-and-mask configuration facility supported by xntpd is quite
+flexible and general, but is not an integral part of the NTP Version 3
+specification. The major drawback is that, while the internal
+implementation is very nice, the user interface sucks. For this reason
+it is probably worth doing an example here. Briefly, the facility works
+as follows. There is an internal list, each entry of which holds an
+address, a mask and a set of flags. On receipt of a packet, the source
+address of the packet is compared to each entry in the list, with a
+match being posted when the following is true:
+
+ (source_addr & mask) == (address & mask)
+
+A particular source address may match several list entries. In this case
+the entry with the most one bits in the mask is chosen. The flags
+associated with this entry are used to control the access.
+
+In the current implementation the flags always add restrictions. In
+effect, an entry with no flags set leaves matching hosts unrestricted.
+An entry can be added to the internal list using a "restrict"
+declaration. The flags associated with the entry are specified
+textually. For example, the "notrust" flag indicates that hosts matching
+this entry, while treated normally in other respects, shouldn't be
+trusted to provide synchronization even if otherwise so enabled. The
+"nomodify" flag indicates that hosts matching this entry should not be
+allowed to do run time configuration. There are many more flags, see the
+xntpd.8 man page.
+
+Now the example. Suppose you are running the server on a host whose
+address is 128.100.100.7. You would like to ensure that run time
+reconfiguration requests can only be made from the local host and that
+the server only ever synchronizes to one of a pair of off-campus servers
+or, failing that, a time source on net 128.100. The following entries in
+the configuration file would implement this policy:
+
+ # by default, don't trust and don't allow modifications
+
+ restrict default notrust nomodify
+
+ # these guys are trusted for time, but no modifications allowed
+
+ restrict 128.100.0.0 mask 255.255.0.0 nomodify
+ restrict 128.8.10.1 nomodify
+ restrict 192.35.82.50 nomodify
+
+ # the local addresses are unrestricted
+
+ restrict 128.100.100.7
+ restrict 127.0.0.1
+
+The first entry is the default entry, which all hosts match and hence
+which provides the default set of flags. The next three entries indicate
+that matching hosts will only have the nomodify flag set and hence will
+be trusted for time. If the mask isn't specified in the restrict
+keyward, it defaults to 255.255.255.255. Note that the address
+128.100.100.7 matches three entries in the table, the default entry
+(mask 0.0.0.0), the entry for net 128.100 (mask 255.255.0.0) and the
+entry for the host itself (mask 255.255.255.255). As expected, the flags
+for the host are derived from the last entry since the mask has the most
+bits set.
+
+The only other thing worth mentioning is that the restrict declarations
+apply to packets from all hosts, including those that are configured
+elsewhere in the configuration file and even including your clock
+pseudopeer(s), in any. Hence, if you specify a default set of
+restrictions which you don't wish to be applied to your configured
+peers, you must remove those restrictions for the configured peers with
+additional restrict declarations mentioning each peer separately.
+
+Authentication
+
+Xntpd supports the optional authentication procedure specified in the
+NTP Version 2 and 3 specifications. Briefly, when an association runs in
+authenticated mode, each packet transmitted has appended to it a 32-bit
+key ID and a 64-bit crypto checksum of the contents of the packet
+computed using either the Data Encryption Standard (DES) or Message
+Digest (MD5) algorithms. Note that while either of these algorithms
+provide sufficient protection from message-modification attacks,
+distribution of the former algorithm implementation is restricted to the
+U.S. and Canada, while the latter presently is free from such
+restrictions. With either algorithm the receiving peer recomputes the
+checksum and compares it with the one included in the packet. For this
+to work, the peers must share at least one encryption key and,
+furthermore, must associate the shared key with the same key ID.
+
+This facility requires some minor modifications to the basic packet
+processing procedures, as required by the specification. These
+modifications are enabled by the "authenticate" configuration
+declaration. In particular, in authenticated mode, peers which send
+unauthenticated packets, peers which send authenticated packets which
+the local server is unable to decrypt and peers which send authenticated
+packets encrypted using a key we don't trust are all marked
+untrustworthy and unsuitable for synchronization. Note that, while the
+server may know many keys (identified by many key IDs), it is possible
+to declare only a subset of these as trusted. This allows the server to
+share keys with a client which requires authenticated time and which
+trusts the server but which is not trusted by the server. Also, some
+additional configuration language is required to specify the key ID to
+be used to authenticate each configured peer association. Hence, for a
+server running in authenticated mode, the configuration file might look
+similar to the following:
+
+ # peer configuration for 128.100.100.7
+ # (expected to operate at stratum 2)
+ # fully authenticated this time
+
+ peer 128.100.49.105 key 22 # suzuki.ccie.utoronto.ca
+ peer 128.8.10.1 key 4 # umd1.umd.edu
+ peer 192.35.82.50 key 6 # lilben.tn.cornell.edu
+ authenticate yes # enable authentication
+ keys /usr/local/bin/ntp.keys # path for key file
+ trustedkey 1 2 14 15 # define trusted keys
+ requestkey 15 # key (7) for accessing server variables
+ controlkey 15 # key (6) for accessing server variables
+
+ #authdelay 0.000047 # authentication delay (Sun4c/50 IPX DES)
+ authdelay 0.000094 # authentication delay (Sun4c/50 IPX MD5)
+
+There are a couple of previously unmentioned things in here. The
+"authenticate yes" line enables authentication processing, while the
+"keys /usr/local/bin/ntp.keys" specifies the path to the keys file (see
+below and the xntpd.8 man page for detaiils of the file format). The
+"trustedkey" declaration identifies those keys that are known to be
+uncompromised; the remainder presumably represent the expired or
+possibly compromised keys. Both sets of keys must be declared by key
+identifier in the ntp.keys file described below. This provides a way to
+retire old keys while minimrequestkey 15izing the frequency of delicate
+key-distribution procedures. The "requestkey 15" line establishes the
+key to be used for mode-6 control messages as specified in RFC 1305 and
+used by the ntpq utility program, while the "controlkey 15" establishes
+the key to be used for mode-7 private control messages used by the
+xntpdc utility program these keys are used to prevent unauthorized
+modification of daemon variables.
+
+The "authdelay" declaration is an estimate of the amount of processing
+time taken between the freezing of a transmit timestamp and the actual
+transmission of the packet when authentication is enabled (i.e. more or
+less the time it takes for the DES or MD5 routine to encrypt a single
+block), and is used as a correction for the transmit timestamp. This can
+be computed for your CPU by the authspeed program included in the
+authstuff directory in the xntp3 distribution. The usage is illustrated
+to the following:
+
+ # for DES keys
+
+ authspeed -n 30000 auth.samplekeys
+
+ # for MD5 keys
+
+ authspeed -nd 30000 auth.samplekeys
+
+Additional utility programs included in the authstuff directory can be
+used to generate random keys, certify implementation correctness and
+display sample keys. As a general rule, keys should be chosen randomly,
+except possibly the request and control keys, which must be entered by
+the user as a password.
+
+The ntp.keys file contains the list of keys and associated key IDs the
+server knows about (for obvious reasons this file is better left
+unreadable by anyone except the server). The contents of this file might
+look like:
+
+ # ntp keys file (ntp.keys)
+
+ 1 N 29233E0461ECD6AE # des key in NTP format
+ 2 M RIrop8KPPvQvYotM # md5 key as an ASCII random string
+ 14 M sundial # md5 key as an ASCII string
+ 15 A sundial # des key as an ASCII string
+
+ # the following 3 keys are identical
+
+ 10 A SeCReT
+ 10 N d3e54352e5548080
+ 10 S a7cb86a4cba80101
+
+In the keys file the first token on each line indicates the key ID, the
+second token the format of the key and the third the key itself. There
+are four key formats. An "A" indicates a DES key written as a 1-to-8
+character string in 7-bit ASCII representation, with each character
+standing for a key octet (like a Unix password). An "S" indicates a DES
+key written as a hex number in the DES standard format, with the low
+order bit (LSB) of each octet being the (odd) parity bit. An "N"
+indicates a DES key again written as a hex number, but in NTP standard
+format with the high order bit of each octet being the (odd) parity bit
+(confusing enough?). An "M" indicates an MD5 key written as a 1-to-31
+character ASCII string in the "A" format. Note that, because of the
+simple tokenizing routine, the characters ' ', '#', '\t', '\n' and '\0'
+can't be used in either a DES or MD5 ASCII key. Everything else is fair
+game, though. Key 0 (zero) is used for special purposes and should not
+appear in this file.
+
+The big trouble with the authentication facility is the keys file. It is
+a maintenance headache and a security problem. This should be fixed some
+day. Presumably, this whole bag of worms goes away if/when a generic
+security regime for the Internet is established.
+
+Query Programs
+
+Three utility query programs are included with the xntp3 distribution,
+ntpq, ntptrace and xntpdc. Ntpq is a rather handy program which sends
+queries and receives responses using NTP standard mode-6 control
+messages. Since it uses the standard control protocol specified in RFC
+1305, it may be used with NTP Version 2 and Version 3 implementations
+for both Unix and Fuzzball, but not Version 1 implementations. It is
+most useful to query remote NTP implementations to assess timekeeping
+accuracy and expose bugs in configuration or operation.
+
+Ntptrace can be used to display the current synchronization path from a
+selected host through possibly intervening servers to the primary source
+of synchronization, usually a radio clock. It works with both version 2
+and version 3 servers, but not version 1.
+
+Xnptdc is a horrid program which uses NTP private mode-7 control
+messages to query local or remote servers. The format and and contents
+of these messages are specific to xntpd. The program does allow
+inspection of a wide variety of internal counters and other state data,
+and hence does make a pretty good debugging tool, even if it is
+frustrating to use. The other thing of note about xntpdc is that it
+provides a user interface to the run time reconfiguration facility.
+
+See the respective man pages for details on the use of these programs.
+The primary reason for mentioning them here is to point out an
+inconsistancy which can be awfully annoying if it catches you, and which
+is worth keeping firmly in mind. Both xntpdc and xntpd demand that
+anything which has dimensions of time be specified in units of seconds,
+both in the configuration file and when doing run time reconfiguration.
+Both programs also print the values in seconds. Ntpq on the other hand,
+obeys the standard by printing all time values in milliseconds. This
+makes the process of looking at values with ntpq and then changing them
+in the configuration file or with xntpdc very prone to errors (by three
+orders of magnitude). I wish this problem didn't exist, but xntpd and
+its love of seconds predate the mode-6 protocol and the latter's
+(Fuzzball-inspired) millisecond orientation, making the inconsistancy
+irresolvable without considerable work.
+
+Run Time Reconfiguration
+
+Xntpd was written specifically to allow its configuration to be fully
+modifiable at run time. Indeed, the only way to configure the server is
+at run time. The configuration file is read only after the rest of the
+server has been initialized into a running, but default unconfigured,
+state. This facility was included not so much for the benefit of Unix,
+where it is handy but not strictly essential, but rather for dedicated
+platforms where the feature is more important for maintenance.
+Nevertheless, run time configuration works very nicely for Unix servers
+as well.
+
+Nearly all of the things it is possible to configure in the
+configuration file may be altered via NTP mode-7 messages using the
+xntpdc program. Mode-6 messages may also provide some limited
+configuration functionality (though the only thing you can currently do
+with mode-6 messages is set the leap-second warning bits) and the ntpq
+program provides generic support for the latter. The leap bits that can be
+set in the leap_warning variable (up to one month ahead) and in the
+leap_indication variable have a slighly different encoding than the
+usual interpretation:
+
+ Value Action
+ 00 The daemon passes the leap bits of its
+ synchronisation source (usual mode of operation)
+ 01/10 A leap second is added/deleted
+ 11 Leap information from the sychronisation source
+ is ignored (thus LEAP_NOWARNING is passed on)
+
+Mode-6 and mode-7 messages which would modify the configuration of the
+server are required to be authenticated using standard NTP
+authentication. To enable the facilities one must, in addition to
+specifying the location of a keys file, indicate in the configuration
+file the key IDs to be used for authenticating reconfiguration commands.
+Hence the following fragment might be added to a configuration file to
+enable the mode-6 (ntpq) and mode-7 (xntpdc) facilities in the daemon:
+
+ # specify mode-6 and mode-7 trusted keys
+
+ requestkey 65535 # for mode-7 requests
+ controlkey 65534 # for mode-6 requests
+
+If the "requestkey" and/or the "controlkey" configuration declarations
+are omitted from the configuration file, the corresponding run time
+reconfiguration facility is disabled.
+
+The query programs require the user to specify a key ID and a key to use
+for authenticating requests to be sent. The key ID provided should be
+the same as the one mentioned in the configuration file, while the key
+should match that corresponding to the key ID in the keys file. As the
+query programs prompt for the key as a password, it is useful to make
+the request and control authentication keys typable (in ASCII format)
+from the keyboard.
+
+Name Resolution
+
+Xntpd includes the cability to specify host names requiring resolution
+in "peer" and "server" declarations in the configuration file. There are
+several reasons why this was not permitted in the past. Chief among
+these is the fact that name service is unreliable and the interface to
+the Unix resolver routines is synchronous. The hangups and delays
+resulting from name-resolver clanking can be unacceptable once the NTP
+server is running (and remember it is up and running before the
+configuration file is read). However, it is advantageous to resolve time
+server names, since their addresses are occasionally changed.
+
+Instead of running the resolver itself the daemon can defer this task to
+a separate program, xntpres. When the daemon comes across a "peer" or
+"server" entry with a non-numeric host address it records the relevant
+information in a temporary file and continues on. When the end of the
+configuration file has been reached and one or more entries requiring
+name resolution have been found, the server runs an instance of xntpres
+with the temporary file as an argument. The server then continues on
+normally but with the offending peers/servers omitted from its
+configuration.
+
+When xntpres successfully resolves a name from this file, it configures
+the associated entry into the server using the same mode-7 run time
+reconfiguration facility that xntpdc uses. If temporary resolver
+failures occur, xntpres will periodically retry the offending requests
+until a definite response is received. The program will continue to run
+until all entries have been resolved.
+There are several configuration requirements if xntpres is to be used.
+The path to the xntpres program must be made known to the daemon via a
+"resolver" configuration entry, and mode-7 run time reconfiguration must
+be enabled. The following fragment might be used to accomplish this:
+
+ # specify host name resolver data
+
+ resolver /local/etc/xntpres
+ keys /etc/ntp.keys
+ requestkey 65535
+
+Note that xntpres sends packets to the server with a source address of
+127.0.0.1. You should obviously avoid "restrict" modification requests
+from this address or xntpres will fail.
+
+Dealing with Frequency Tolerance Violations (Tickadj and Friends)
+
+The NTP Version 3 specification RFC 1305 calls for a maximum oscillator
+frequency tolerance of +-100 parts-per-million (ppm), which is
+representative of those components suitable for use in relatively
+inexpensive workstation platforms. For those platforms meeting this
+tolerance, NTP will automatically compensate for the frequency errors of
+the individual oscillator and no further adjustments are required,
+either to the configuration file or to various kernel variables.
+
+However, in the case of certain notorious platforms, in particular Sun
+4s, the 100-ppm tolerance is routinely violated. In such cases it may be
+necessary to adjust the values of certain kernel variables; in
+particular, "tick" and "tickadj". The variable tick is the increment in
+microseconds added to the system time on each interval-timer interrupt,
+while the variable tickadj is used by the time adjustment code as a slew
+rate. When the time is being adjusted via a call to the system routine
+adjtime(), the kernel increases or reduces tick by tickadj microseconds
+until the specified adjustment has been completed. Unfortunately, in
+most Unix implementations the tick increment must be either zero or
+plus/minus exactly tickadj microseconds, meaning that adjustments are
+truncated to be an integral multiple of tickadj (this latter behaviour
+is a misfeature, and is the only reason the xntpd code needs to concern
+itself with the internal implementation of adjtime() at all). In
+addition, the stock Unix implementation considers it an error to request
+another adjustment before a prior one has completed.
+
+Thus, to make very sure it avoids problems related to the roundoff, the
+xntpd daemon reads the values of tick and tickadj from /dev/kmem when it
+starts. It then ensures that all adjustments given to adjtime() are an
+even multiple of tickadj microseconds and computes the largest
+adjustment that can be completed in the adjustment interval (using both
+the value of tickadj and the value of tick) so it can avoid exceeding
+this limit.
+
+Unfortunately, the value of tickadj set by default is almost always too
+large for xntpd. NTP operates by continuously making small adjustments
+to the clock, usually at one-second intervals. If tickadj is set too
+large, the adjustments will disappear in the roundoff; while, if tickadj
+is too small, NTP will have difficulty if it needs to make an occasional
+large adjustment. While the daemon itself will read the kernel's values
+of tick and tickadj, it will not change the values, even if they are
+unsuitable. You must do this yourself before the daemon is started,
+either with adb or, in the running kernel only, with the tickadj program
+included in the util directory of the xntp3 distribution. Note that the
+latter program will also computes an optimal value of tickadj for NTP
+use based on the kernel's value of tick.
+
+The tickadj program can reset several other kernel variables if asked.
+It can also change the value of tick if asked, this being necessary on a
+few machines with very broken clocks, like Sun 4s. With these machines
+it should also set the value of the kernel dosynctodr variable to zero.
+This variable controls whether to synchronize the system clock to the
+time-of-day clock, something you really don't want to be happen when
+xntpd is trying to keep it under control.
+
+In order to maintain reasonable correctness bounds, as well as
+reasonably good accuracy with acceptable polling intervals, xntpd will
+complain if the frequency error is greater than 100 ppm. For machines
+with a value of tick in the 10-ms range, a change of one in the value of
+tick will change the frequency by about 100 ppm. In order to determine
+the value of tick for a particular CPU, disconnect the machine from all
+sources of time (dosynctodr = 0) and record its actual time compared to
+an outside source (eyeball-and-wristwatch will do) over a day or more.
+Multiply the time change over the day by 0.116 and add or subtract the
+result to tick, depending on whether the CPU is fast or slow. An example
+call to tickadj useful on Sun 4s is:
+
+ tickadj -t 9999 -a 5 -s
+
+which sets tick 100 ppm fast, tickadj to 5 microseconds and turns off
+the clock/calendar chip fiddle. This line can be added to the rc.local
+configuration file to automatically set the kernel variables at boot
+time.
+
+All this stuff about diddling kernel variables so the NTP daemon will
+work is really silly. If vendors would ship machines with clocks that
+kept reasonable time and would make their adjtime() system call apply
+the slew it is given exactly, independent of the value of tickadj, all
+this could go away.
+
+Tuning Your Subnet
+
+There are several parameters available for tuning the NTP subnet for
+maximum accuracy and minimum jitter. Two important parameters are the
+the "precision" and "prefer" configuration declarations. The precision
+declaration specifies the number of significant bits of the system clock
+representation relative to one second. For instance, the default value
+of -6 corresponds to 1/64 second or about 16 milliseconds.
+
+The NTP protocol makes use of the precision parameter in several places.
+It is included in packets sent to peers and is used by them to calculate
+the maximum absolute error and maximum statistical error. When faced
+with selecting one of several servers of the same stratum and about the
+same network path delay for synchronization purposes, clients will
+usually prefer to synchronize to those servers claiming the smallest
+(most negative) precision, since this maximizes the accuracy and
+minimizes the jitter apparent to application programs running on the
+client platform. Therefore, when the maximum attainable accuracy is
+required, it is important that every platform configure an accurate
+value for the precision variable. This can be done using the optional
+"precision" declaration in the configuration file:
+
+ # precision declaration
+
+ precision -18 # for microsecond clocks (Sun 4s, DEC 5000/240)
+
+When more than one eligible server exists, the NTP clock-selection and
+combining algorithms act to winnow out all except the "best" set of
+servers using several criteria based on differences between the readings
+of different servers and between successive readings of the same server.
+The result is usually a set of surviving servers that are apparently
+statistically equivalent in accuracy, jitter and stability. The
+population of survivors remaining in this set depends on the individual
+server characteristics measured during the selection process and may
+vary from time to time as the result of normal statistical variations.
+In LANs with high speed RISC-based time servers, the population can
+become somewhat unstable, with individual servers popping in and out of
+the surviving population, generally resulting in a regime called
+clockhopping.
+
+When only the smallest residual jitter can be tolerated, it may be
+convenient to elect one of the servers at each stratum level as the
+preferred one using the keyword "prefer" on the configuration
+declaration for the selected server:
+
+ # prefered server declaration
+
+ peer 128.4.1.1 prefer # preferred server
+
+The preferred server will always be included in the surviving
+population, regardless of its characteristics and as long as it survives
+preliminary sanity checks and validation procedures.
+
+The most useful application of the prefer keyword is in high speed LANs
+equipped with precision radio clocks, such as a GPS receiver. In order
+to insure robustness, the hosts need to include outside peers as well as
+the GPS-equipped server; however, as long as that server is running, the
+synchronization preference should be that server. The keyword should
+normally be used in all cases in order to prefer an attached radio
+clock. It is probably inadvisable to use this keyword for peers outside
+the LAN, since it interferes with the carefully crafted judgement of the
+selection and combining algorithms.
+
+Provisions for Leap Seconds and Accuracy Metrics
+
+Xntpd understands leap seconds and will attempt to take appropriate
+action when one occurs. In principle, every host running xntpd will
+insert a leap second in the local timescale in precise synchronization
+with UTC. This requires that the leap-warning bits be manually activated
+some time prior to the occurance of a leap second at the primary
+(stratum 1) servers. Subsequently, these bits are propagated throughout
+the subnet depending on these servers by the NTP protocol itself and
+automatically implemented by xntpd and the time-conversion routines of
+each host. The implementation is independent of the idiosyncracies of
+the particular radio clock, which vary widely among the various devices,
+as long as the idiosyncratic behavior does not last for more than about
+20 minutes following the leap. Provisions are included to modify the
+behavior in cases where this cannot be guaranteed.
+
+While provisions for leap seconds have been carefully crafted so that
+correct timekeeping immediately before, during and after the occurance
+of a leap second is scrupulously correct, stock Unix systems are mostly
+inept in responding to the available information. This caveat goes also
+for the maximum-error and statistical-error bounds carefully calculated
+for all clients and servers, which could be very useful for application
+programs needing to calibrate the delays and offsets to achieve a near-
+simulataneous commit procedure, for example. While this information is
+maintained in the xntpd data structures, there is at present no way for
+application programs to access it. This may be a topic for further
+development.
+
+Clock Support Overview
+
+Xntpd was designed to support radio (and other external) clocks and does
+some parts of this function with utmost care. Clocks are treated by the
+protocol as ordinary NTP peers, even to the point of referring to them
+with an (invalid) IP host address. Clock addresses are of the form
+127.127.t.u, where t specifies the particular type of clock (i.e. refers
+to a particular clock driver) and u is a unit number whose
+interpretation is clock-driver dependent. This is analogous to the use
+of major and minor device numbers by Unix and permits multiple
+instantiations of clocks of the same type on the same server, should
+such magnificant redundancy be required.
+
+Because clocks look much like peers, both configuration file syntax and
+run time reconfiguration commands can be be used to control clocks in
+the same way as ordinary peers. Clocks are configured via "server"
+declarations in the configuration file, can be started and stopped using
+xntpdc and are subject to address-and-mask restrictions much like a
+normal peer, should this stretch of imagination ever be useful. As a
+concession to the need to sometimes transmit additional information to
+clock drivers, an additional configuration file is available: the
+"fudge" statement. This enables one to specify the values two time
+quantities, two integral values and two flags, the use of which is
+dependent on the particular clock driver. For example, to configure a
+PST radio clock which can be accessed through the serial device
+/dev/pst1, with propagation delays to WWV and WWVH of 7.5 and 26.5
+milliseconds, respectively, on a machine with an imprecise system clock
+and with the driver set to disbelieve the radio clock once it has gone
+30 minutes without an update, one might use the following configuration
+file entries:
+
+ # radio clock fudge fiddles
+
+ server 127.127.3.1
+ fudge 127.127.3.1 time1 0.0075 time2 0.0265
+ fudge 127.127.3.1 value2 30 flag1 1
+
+Additional information on the interpretation of these data with respect
+to various radio clock drivers is given in the xntpd.8 man page.
+
+Towards the Ultimate Tick
+
+This section consideres issues in providing precision time
+synchronization in NTP subnets which need the highest quality time
+available in the present technology. These issues are important in
+subnets supporting real-time services such as distributed multimedia
+conferencing and wide-are experiment control and monitoring.
+
+In the Internet of today synchronization paths often span continents and
+oceans with moderate to high variations in delay due to traffic spasms.
+NTP is specifically designed to minimize timekeeping jitter due to delay
+variations using intricately crafted filtering and selection algorithms;
+however, in cases where these variations are as much as a second or
+more, the residual jitter following these algorithms may still be
+excessive. Sometimes, as in the case of some isolated NTP subnets where
+a local source of precision time is available, such as a 1-pps signal
+produced by a calibrated cesium clock, it is possible to remove the
+jitter and retime the local clock oscillator of the NTP server. This has
+turned out to be a useful feature to improve the synchronization quality
+of time distributed in remote places where radio clocks are not
+available. In these cases special features of the xntp3 distribution are
+used together with the 1-pps signal to provide a jitter-free timing
+signal, while NTP itself is used to provide the coarse timing and
+resolve the seconds numbering.
+
+Most available radio clocks can provide time to an accuracy in the order
+of milliseconds, depending on propagation conditions, local noise levels
+and so forth. However, as a practical matter, all clocks can
+occasionally display errors significantly exceeding nominal
+specifications. Usually, the algorithms used by NTP for ordinary network
+peers, as well as radio clock "peers" will detect and discard these
+errors as discrepancies between the disciplined local clock oscillator
+and the decoded time message produced by the radio clock. Some radio
+clocks can produce a special 1-pps signal which can be interfaced to the
+server platform in a number of ways and used to substantially improve
+the (disciplined) clock oscillator jitter and wander characteristics by
+at least an order of magnitude. Using these features it is possible to
+achieve accuracies in the order of 100 microseconds with a fast RISC-
+based platform.
+
+There are three ways to implement 1-pps support, depending on the radio
+clock model, platform model and serial line interface. Each of these
+requires circuitry to convert the TTL signal produced by most clocks to
+the the EIA levels used by most serial interfaces. An example of a
+device designed to do this is presented in the gadget subdirectory
+included in the xntp3 distribtuion. Besides being useful for this
+purpose, this device includes an inexpensive modem designed for use with
+the Canadian CHU time/frequency radio station.
+
+In order to select the appropriate implementation, it is important to
+understand the underlying 1-pps mechanism used by xntpd. The 1-pps
+suport depends on a continuous source of 1-pps pulses used to calculate
+an offset within +-500 milliseconds relative to the local clock. The
+serial timecode produced by the radio or the time determined by NTP in
+absence of the radio is used to adjust the local clock within +-128
+milliseconds of the actual time. As long as the local clock is within
+this interval the 1-pps support is used to discipline the local clock
+and the timecode used only to verify that the local clock is in fact
+within the interval. Outside this interval the 1-pps support is disabled
+and the timecode used directly to control the local clock.
+
+The first method of implementation uses a dedicated serial port and
+either the bsd line discipline or System V streams module, which can be
+found in the kernel directory of the xntp3 distribution. This method can
+be used with any radio clock or in the absence of any clock. The line
+discipline and streams modules take receive timestamps in the kernel,
+specifically the interrupt routine of the serial port hardware driver.
+Using this method the port is dedicated to serve the 1-pps signal and
+cannot be used for other purposes. Instructions for implementing the
+feature, which requires rebuilding the kernel, are included in the
+modules themselves. Note that xndpd must be compiled with the -DPPSDEV
+compiler switch in this case. There is an inherent error in this method
+due to the latency of the interrupt system and remaining serial-line
+protocol modules in the order of a millisecond with Sun 4s. While the
+jitter in this latency is unavoidable, the systematic component can be
+calibrated out using a special configuration declaration:
+
+ # pps delay and baud rate
+
+ pps delay .0017 baud 19200 # pps delay (ms) and baud rate
+
+Note that the delay defaults to zero and the baud to 38400.
+
+The second method uses mechanisms embedded in the radio clock driver,
+which call the 1-pps support directly and do not require a dedicated
+serial port. Currently, only the DCF77 (German radio time service)
+driver uses this method. Instructions for implementing this are given in
+README files in the xntp3 distribution.
+
+The third method and the most accurate and intrusive of all uses the
+carrier-detect modem-control lead monitored by the serial port driver.
+This method can be used with any radio clock and 1-pps interface
+mentioned above. It requires in addition to a special streams module,
+replacement of the kernel high resolution time-of-day clock routine.
+This method is applicable only to Sun 4 platforms running SunOS 4.1.1
+and then only with either of the two onboard serial ports. It does not
+work with other platforms, operating systems or external (SBus) serial
+multiplexors.
+
+Swatting Bugs
+
+Let's say you have compiled and installed the code and put up an
+apparently relevant configuration file. In many Unix systems the xntpd
+daemon and utility programs (ntpq, ntptrace and xntpdc) are usually
+installed in the /usr/local directory along with the key file
+(ntp.keys), while the configuration file (ntp.conf) and drift file
+(ntp.drift) are installed in the /etc directory. The daemon can is
+usually started from the rc.local shell script at system boot time, but
+could be started (and stopped) at other times for debugging, etc. How do
+you verify that the daemon can form associations with remote peers and
+verify correct synchronization? For this you need the ntpq utility
+described in the ntpq.8 man page.
+
+After starting the daemon, run the ntpq program using the -n switch,
+which will avoid possible distractions due to name resolutions. Use the
+peer command to display a billboard showing the status of configured
+peers and possibly other clients poking the daemon. After operating for
+a few minutes, the display should be something like:
+
+ remote refid st when poll reach delay offset disp
+========================================================================
++128.4.2.6 132.249.16.1 2 131 256 373 9.89 16.28 23.25
+*128.4.1.20 .WWVB. 1 137 256 377 280.62 21.74 20.23
+-128.8.2.88 128.8.10.1 2 49 128 376 294.14 5.94 17.47
++128.4.2.17 .WWVB. 1 173 256 377 279.95 20.56 16.40
+
+The hosts shown in the "remote" column should agree with the entries in
+the configuration file, plus any peers not mentioned in the file at the
+same or lower than your stratum that happen to be configured to peer
+with you. The "refid" entry shows the current source of synchronization
+for that peer, while the "st" reveals its stratum and the "poll" entry
+the polling interval, in seconds. The "when" entry shows the time since
+the peer was last heard, in seconds, while the "reach" entry shows the
+status of the reachability register (see specification), which is in
+octal format. The remaining entries show the latest delay, offset and
+dispersion computed for the peer, in milliseconds.
+
+*** This section incomplete. Soon.
+
+status=0664 leap_none, sync_ntp, 6 events, event_peer/strat_chg
+system="UNIX", leap=00, stratum=2, rootdelay=280.62,
+rootdispersion=45.26, peer=11673, refid=128.4.1.20,
+reftime=af00bb42.56111000 Fri, Jan 15 1993 4:25:38.336, poll=8,
+clock=af00bbcd.8a5de000 Fri, Jan 15 1993 4:27:57.540, phase=21.147,
+freq=13319.46, compliance=2
+
+status=7414 reach, auth, sel_sync, 1 event, event_reach
+srcadr=128.4.2.6, srcport=123, dstadr=128.4.2.7, dstport=123, keyid=1,
+stratum=2, precision=-10, rootdelay=362.00, rootdispersion=21.99,
+refid=132.249.16.1,
+reftime=af00bb44.849b0000 Fri, Jan 15 1993 4:25:40.517,
+delay= 9.89, offset= 16.28, dispersion=23.25, reach=373, valid=8,
+hmode=2, pmode=1, hpoll=8, ppoll=10, leap=00, flash=0x0,
+org=af00bb48.31a90000 Fri, Jan 15 1993 4:25:44.193,
+rec=af00bb48.305e3000 Fri, Jan 15 1993 4:25:44.188,
+xmt=af00bb1e.16689000 Fri, Jan 15 1993 4:25:02.087,
+filtdelay= 16.40 9.89 140.08 9.63 9.72 9.22 10.79 122.99,
+filtoffset= 13.24 16.28 -49.19 16.04 16.83 16.49 16.95 -39.43,
+filterror= 16.27 20.17 27.98 31.89 35.80 39.70 43.61 47.52
+
+ind assID status conf reach auth condition last_event cnt
+===========================================================
+ 1 11670 7414 no yes ok synchr. reachable 1
+ 2 11673 7614 no yes ok sys.peer reachable 1
+ 3 11833 7314 no yes ok outlyer reachable 1
+ 4 11868 7414 no yes ok synchr. reachable 1
+
+Parting Shots
+
+There are several undocumented programs which are useful if you are
+trying to set up a clock. They can be found in the clockstuff directory
+of the xntp3 distribution. The most useful of these is the propdelay
+program, which can compute high frequency radio propagation delays
+between any two points whose latitude and longitude are known. The
+program understands something about the phenomena which allow high
+frequency radio propagation to occur, and will generally provide a
+better estimate than a calculation based on the great circle distance.
+The other two programs in the directory are clktest, which allows one to
+exercise the generic clock line discipline, and chutest, which runs the
+basic reduction algorithms used by the daemon on data received from a
+serial port.
diff --git a/contrib/xntpd/doc/ntpdate.8 b/contrib/xntpd/doc/ntpdate.8
new file mode 100644
index 000000000000..e738cabdf9b7
--- /dev/null
+++ b/contrib/xntpd/doc/ntpdate.8
@@ -0,0 +1,185 @@
+''' $Header
+'''
+.de Sh
+.br
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+.de Ip
+.br
+.ie \\n.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+'''
+''' Set up \*(-- to give an unbreakable dash;
+''' string Tr holds user defined translation string.
+''' Greek uppercase omega is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+.ds L" ""
+.ds R" ""
+.ds L' '
+.ds R' '
+'br\}
+.el\{\
+.ds -- \(em\|
+.tr \*(Tr
+.ds L" ``
+.ds R" ''
+.ds L' `
+.ds R' '
+'br\}
+.TH NTPDATE 8 LOCAL
+.SH NAME
+ntpdate - set the date and time via NTP
+.SH SYNOPSIS
+.B ntpdate
+[
+.B -bdos
+] [
+.B -a
+.I key#
+] [
+.B -e
+.I authdelay
+] [
+.B -k
+.I keyfile
+] [
+.B -p
+.I samples
+] [
+.B -t
+.I timeout
+]
+server ...
+.SH DESCRIPTION
+.I Ntpdate
+sets the local date and time by polling the Network Time Protocol
+server(s) on the host(s) given as arguments to determine
+the correct time. It must be run as root on the local host. A number
+of samples are obtained from each of the servers specified and the
+standard NTP clock filter and selection algorithms are applied to select
+the best of these. Typically,
+.I ntpdate
+can be inserted in the
+.I /etc/rc.local
+startup up script to set the time of day at boot time and/or can be run
+from time\-to\-time via
+.IR cron (8).
+Note that
+.IR ntpdate 's
+reliability and precision will improve dramatically with greater numbers
+of servers. While a single server may be used, better performance and
+greater resistance to insanity on the part of any one server
+will be obtained by providing at least three or four servers, if not more.
+.PP
+Time adjustments are made by
+.I ntpdate
+in one of two ways. If
+.I ntpdate
+determines your clock is off by more than 0.5 seconds it will simply
+step the time by calling
+.IR settimeofday (2).
+If the error is less than 0.5 seconds, however, it will by default slew
+the clock's time via a call to
+.IR adjtime (2)
+with the offset. The latter technique is less disruptive and more
+accurate when the offset is small, and works quite well when
+.I ntpdate
+is run by
+.I cron (8)
+every hour or two. The adjustment made in the latter
+case is actually 50% larger than the measured offset since this will
+tend to keep a badly drifting clock more accurate (at some expense to
+stability, though this tradeoff is usually advantageous). At boot time,
+however, it is usually better to always step the time. This can be forced
+in all cases by specifying the
+.B -b
+switch on the command line. The
+.B -s
+switch tells
+.I ntpdate
+to log its actions via the
+.IR syslog (3)
+facility rather than to the standard output, a useful option when
+running the program from
+.IR cron (8).
+.PP
+The
+.B -d
+flag may be used to determine what
+.I ntpdate
+will do without it actually doing it. Information useful for general
+debugging will also be printed. By default
+.I ntpdate
+claims to be an NTP version 2 implementation in its outgoing packets. As
+some older software will decline to respond to version 2 queries, the
+.B -o
+switch can be used to force the program to poll as a version 1 implementation
+instead.
+.PP
+The number of samples
+.I ntpdate
+acquires from each server can be set to between 1 and 8 inclusive
+using the
+.B -p
+switch. The default is 4. The time it will spend waiting for a
+response can be set using the
+.B -t
+switch, and will be rounded to a multiple of 0.2 seconds. The default
+is 1 second, a value suitable for polling across a LAN.
+.PP
+.I Ntpdate
+will authenticate its transactions if need be. The
+.B -a
+switch specifies that all packets should be authenticated using the
+key number indicated. The
+.B -k
+switch allows the name of the file from which the keys may be read
+to be modified from the default of
+.I /etc/ntp.keys.
+This file should be in the format described in
+.IR xntpd (8).
+The
+.B -e
+option allows the specification of an authentication processing delay,
+in seconds (see
+.IR xntpd (8)
+for details). This number is usually small enough to be negligible for
+.IR ntpdate 's
+purposes, though specifying a value may improve timekeeping on very slow
+CPU's.
+.PP
+.I Ntpdate
+will decline to set the date if an NTP server daemon (e.g.
+.IR xntpd (8))
+is running on the same host. When running
+.I ntpdate
+on a regular basis from
+.IR cron (8)
+as an alternative to running a daemon, doing so once every hour or two
+will result in precise enough timekeeping to avoid stepping the clock.
+.SH FILES
+.nf
+/etc/ntp.keys\0\0contains the encription keys used by \fIntpdate\fP.
+.fi
+.SH SEE ALSO
+xntpd(8)
+.SH HISTORY
+Written by Dennis Ferguson at the University of Toronto
+.SH BUGS
+The technique used for improving accuracy by compensating for clock
+oscillator errors sucks, but doing better would require the program
+to save state from previous runs.
diff --git a/contrib/xntpd/doc/ntpq.8 b/contrib/xntpd/doc/ntpq.8
new file mode 100644
index 000000000000..ad374768f6c7
--- /dev/null
+++ b/contrib/xntpd/doc/ntpq.8
@@ -0,0 +1,566 @@
+''' $Header
+'''
+.de Sh
+.br
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+.de Ip
+.br
+.ie \\n.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+'''
+''' Set up \*(-- to give an unbreakable dash;
+''' string Tr holds user defined translation string.
+''' Greek uppercase omega is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\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 occurring and terminating the
+command.
+.PP
+The timeout time is a fixed constant, which means you wait a long time
+for time outs since it assumes sort of a worst case. The program
+should improve the time out estimate as it sends queries to a particular
+host, but doesn't.
diff --git a/contrib/xntpd/doc/ntptrace.8 b/contrib/xntpd/doc/ntptrace.8
new file mode 100644
index 000000000000..a79a679f47b1
--- /dev/null
+++ b/contrib/xntpd/doc/ntptrace.8
@@ -0,0 +1,104 @@
+''' $Header
+'''
+.de Sh
+.br
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+.de Ip
+.br
+.ie \\n.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+'''
+''' Set up \*(-- to give an unbreakable dash;
+''' string Tr holds user defined translation string.
+''' Greek uppercase omega is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+.ds L" ""
+.ds R" ""
+.ds L' '
+.ds R' '
+'br\}
+.el\{\
+.ds -- \(em\|
+.tr \*(Tr
+.ds L" ``
+.ds R" ''
+.ds L' `
+.ds R' '
+'br\}
+.TH NTPTRACE 8 LOCAL
+.SH NAME
+ntptrace - trace a chain of NTP hosts back to their master time source
+.SH SYNOPSIS
+.B ntptrace
+[
+.B -vdn
+] [
+.B -r
+.I retries
+] [
+.B -t
+.I timeout
+] [
+.I server
+]
+.SH DESCRIPTION
+.I Ntptrace
+determines where a given Network Time Protocol (NTP) server gets
+its time from, and follows the chain of NTP servers back to their
+master time source.
+If given no arguments, it starts with ``localhost.''
+.PP
+Here is an example of the output from
+.IR ntptrace :
+.RS 2
+.nf
+
+% ntptrace
+localhost: stratum 4, offset 0.0019529, synch distance 0.144135
+server2.bozo.com: stratum 2, offset 0.0124263, synch distance 0.115784
+usndh.edu: stratum 1, offset 0.0019298, synch distance 0.011993, refid 'WWVB'
+
+.fi
+.RE
+On each line, the fields are (left to right): the host name, the
+host's stratum,
+the time offset between that host and the local host
+(as measured by
+.IR ntptrace ;
+this is why it is not always zero for ``localhost''),
+the host's ``synchronization distance,''
+and (only for stratum-1 servers) the reference clock ID. All times
+are given in seconds. (Synchronization distance is a measure of the
+goodness of the clock's time.)
+.SH OPTIONS
+.IP "\-d" 5
+Turns on some debugging output.
+.IP "\-n" 5
+Turns off the printing of host names; instead, host IP addresses
+are given. This may be necessary if a nameserver is down.
+.IP "\-r retries" 5
+Sets the number of retransmission attempts for each host; default = 5.
+.IP "\-t timeout" 5
+Sets the retransmission timeout (in seconds); default = 2.
+.IP "\-v" 5
+Prints verbose information about the NTP servers.
+.SH SEE ALSO
+xntpd(8), xntpdc(8)
+.SH BUGS
+This program makes no attempt to improve accuracy by doing multiple
+samples.
diff --git a/contrib/xntpd/doc/tickadj.8 b/contrib/xntpd/doc/tickadj.8
new file mode 100644
index 000000000000..8726288f837d
--- /dev/null
+++ b/contrib/xntpd/doc/tickadj.8
@@ -0,0 +1,143 @@
+''' $Header
+'''
+.de Sh
+.br
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+.de Ip
+.br
+.ie \\n.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+'''
+''' Set up \*(-- to give an unbreakable dash;
+''' string Tr holds user defined translation string.
+''' Greek uppercase omega is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+.ds L" ""
+.ds R" ""
+.ds L' '
+.ds R' '
+'br\}
+.el\{\
+.ds -- \(em\|
+.tr \*(Tr
+.ds L" ``
+.ds R" ''
+.ds L' `
+.ds R' '
+'br\}
+.TH TICKADJ 8 LOCAL
+.SH NAME
+tickadj - fiddle time\-related variables in the kernel
+.SH SYNOPSIS
+.B tickadj
+[
+.B -Aqs
+] [
+.B -a
+.I new_tickadj
+] [
+.B -t
+.I new_tick
+]
+.SH DESCRIPTION
+The
+.I tickadj
+program reads, and optionally modifies, several time\-keeping\-related
+variables in the running kernel, via
+.IR /dev/kmem .
+The particular variables it is concerned with are
+.IR tick ,
+which is the number of microseconds added to the system time during a
+clock interrupt,
+.IR tickadj ,
+which sets the slew rate and resolution used by the
+.IR adjtime (2)
+system call, and
+.IR dosynctodr ,
+which indicates to the kernels on some machines whether they should internally
+adjust the system clock to keep it in line with with time\-of\-day clock
+or not.
+.PP
+By default, with no arguments,
+.I tickadj
+reads the variables of interest in the kernel and prints them. At the
+same time it determines an \*(L"optimal\*(R" value for the value of the
+.I tickadj
+variable if the intent is to run the
+.IR xntpd (8)
+Network Time Protocol daemon, and prints this as well. Since the operation
+of
+.I tickadj
+when reading the kernel mimics the operation of similar parts of the
+.IR xntpd (8)
+program fairly closely, this is useful for doing debugging of problems
+with
+.IR xntpd (8).
+.PP
+Various flags may be specified to change the variables of interest in
+the running kernel. The
+.B -a
+flag allows one to set the the variable
+.I tickadj
+to the value specified as an argument. The
+.B -A
+flag will also cause
+.I tickadj
+to be modified, but instead will set it to the internally computed
+\*(L"optimal\*(R" value. The
+.B -t
+flag may be used to reset the kernel's value of
+.IR tick ,
+a capability which is useful on machines with very broken clocks. The
+.B -s
+flag tells the program to set the value of the variable
+.I dosynctodr
+to zero, a prerequisite for running the
+.IR xntpd (8)
+daemon under SunOS 4.0. Normally
+.I tickadj
+is quite verbose about what it is doing. The
+.B -q
+flag tells it to shut up about everything except errors.
+.PP
+Note that
+.I tickadj
+should be run with some caution when being used for the first time on
+different types of machines. The operations which
+.I tickadj
+trys to perform are not guaranteed to work on all Unix machines.
+.SH FILES
+.nf
+/vmunix
+/unix
+/dev/kmem
+.fi
+.SH SEE ALSO
+xntpd(8)
+.SH HISTORY
+Written by Dennis Ferguson at the University of Toronto
+.SH BUGS
+Fiddling with kernel variables at run time as a part of ordinary
+operations is a hideous practice which is only necessary to make
+up for deficiencies in the implementation of
+.IR adjtime (8)
+in many kernels and/or brokenness of the system clock in some
+vendors' kernels. It would be much better if the kernels were fixed
+and the
+.I tickadj
+program went away.
diff --git a/contrib/xntpd/doc/xntpd.8 b/contrib/xntpd/doc/xntpd.8
new file mode 100644
index 000000000000..ed92e62dec42
--- /dev/null
+++ b/contrib/xntpd/doc/xntpd.8
@@ -0,0 +1,1479 @@
+''' $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.
+''' Greek uppercase omega is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\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
+] [
+.B -v
+.I variable
+] [
+.B -V
+.I variable
+]
+.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
+compatibility 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 -m 8
+listen for multicast NTP and sync to this if available (requires multicast
+kernel)
+.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
+.Ip -v 8
+add a system variable
+.Ip -V 8
+add a system variable listed by default
+.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] or a multicast address assigned to
+NTP. The Numbers Czar has assigned the address 224.0.1.1 to NTP; this
+is presently the only number that should be used. Note that the use
+of multicast requires a multicast kernel.
+.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
+.PP
+This directs the local server should listen for, and attempt to
+synchonize to, broadcast NTP. Note that authentication is required in
+this mode.
+.PP
+.B multicastclient
+[
+.I IP address ...
+]
+.PP
+This directs the local server should listen for, and attempt to
+synchonize to, multicast NTP. This function requires a multicast kernel
+and the use of authentication.
+If one or more IP addresses are given, the server joins the respective
+multicast group. If none are given, the default address assigned to
+NTP (224.0.1.1) is assumed.
+.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 limited 10
+These hosts are subject to limitation of number of clients from the
+same net. Net in this context refers to the IP notion of net (class A,
+class B, class C, etc.). Only the first \*(L"client_limit\*(R" hosts
+that have shown up at the server and that have been active during the
+last \*(L"client_limit_period\*(R" seconds are accepted. Requests from
+other clients from the same net are rejected. Only time request
+packets are taken into account. \*(L"Private\*(R", \*(L"control\*(R",
+and \*(L"broadcast\*(R" packets are not subject to client limitation
+and therefore are not contributing to client count. History of clients
+is kept using the monitoring capability of
+.IR xntpd .
+Thus, monitoring is active as long as there is a restriction entry
+with the \*(L"limited\*(R" flag. The default value for
+\*(L"client_limit\*(R" is 3. The default value for
+\*(L"client_limit_period\*(R" is 3600 seconds.
+.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 clientlimit
+.I limit
+.PP
+Sets \*(L"client_limit\*(R" to \*(L"limit\*(R", allows configuration
+of client limitation policy. This variable defines the number of
+clients from the same network that are allowed to use the server.
+.PP
+.B clientperiod
+.I period
+.PP
+Sets \*(L"client_limit_period\*(R", allows configuration of client
+limitation policy. This variable specifies the number
+of seconds after which a client is considered inactive and thus no
+longer is counted for client limit restriction.
+.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 setvar
+.I variable
+.I [default]
+.PP
+This command adds an additional system variable. These variables can be
+used to distribute additional information such as the access policy. If
+the variable of the from <name>=<value> is followed by the
+.I default
+keyword the variable will be listed as part of the default system
+variables (ntpq rv command). These additional variables serve informational
+purposes only. They are not related to the protocol other that they can be
+listed. The known protocol variables will always overide any variables defined
+via the
+.I setvar
+mechanism.
+.PP
+There are three special variables that contain the names of all variable of
+the same group. The
+.I sys_var_list
+holds the names of all system variables. The
+.I peer_var_list
+holds the names of all peer variables and the
+.I clock_var_list
+hold the names of the reference clock variables.
+.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 initial 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 occurring 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 defines the skew between the PPS time stamp and the reception
+time stamp of the PPS signal. This parameter is usually 0 as usually
+the PPS signal is believed in time and OS delays should be corrected
+in the machine specific section of the kernel driver.
+.I time2
+needs only be set when the actial PPS signal is delayed for some
+reason.
+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 ntpq read clock variables command list several variables. These
+hold followinf information:
+.I refclock_time
+is the local time with the offset to UTC (format HHMM).
+The currently active receiver flags are listed in
+.I refclock_status.
+Additional feature flags of the receiver are optionally listed in paranthesis.
+The actual time code is listed in
+.I timecode.
+A qualification of the decoded time code format is following in
+.I refclock_format.
+The last piece of information is the overall running time and the accumulated
+times for the clock event states in
+.I refclock_states.
+When PPS information is present additional variable are available.
+.I refclock_ppstime
+lists then the PPS timestamp and
+.I refclock_ppsskew
+lists the difference between RS232 derived timestamp and the PPS timestamp.
+.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.
+.PP
+.SH VARIABLES
+Most variables used by the NTP protocol can be examined with the xntpdc
+(mode 7 messages) and the ntpq (mode 6 messages). Currently very few variables
+can be modified via mode 6 messages. These variables are either created with the
+.I setvar
+directive or the leap warning variables. The leap warning bits that can be
+set in the
+.B leapwarning
+variable (up to one month ahead). Both, the
+.B leapwarning and in the
+.B leapindication
+variable, have a slightly different encoding than the usual
+.B leap
+bits interpretation:
+.P
+.Ip 00 8
+The daemon passes the leap bits of its synchronisation source (usual mode of
+operation).
+.Ip 01/10 8
+A leap second is added/deleted (operator forced leap second).
+.Ip 11 8
+Leap information from the sychronisation source is ignored (thus LEAP_NOWARNING
+is passed on).
+.PP
+.SH FILES
+.Ip /etc/ntp.conf 20
+the default name of the configuration file
+.Ip /etc/ntp.drift 20
+the conventional name of the drift file
+.Ip /etc/ntp.keys 20
+the conventional name of the key file
+.SH SEE ALSO
+.PP
+.IR xntpdc (8),
+.IR ntpq (8),
+.IR ntpdate (8)
+.SH HISTORY
+.PP
+Written by Dennis Ferguson at the University of Toronto.
+Text amended by David Mills at the University of Delaware.
+.SH BUGS
+.PP
+.I Xntpd
+has gotten rather fat. While not huge, it has gotten larger
+than might be desireable for an elevated\-priority daemon running on a
+workstation, particularly since many of the fancy features which
+consume the space were designed more with a busy primary server, rather
+than a high stratum workstation, in mind. This will eventually be corrected
+either by adopting the
+.I ntpd
+daemon as an alternative when it becomes able to match
+.IR xntpd 's
+performance, or if not than by producing a stripped down version of
+.I xntpd
+specifically for workstation use.
diff --git a/contrib/xntpd/doc/xntpdc.8 b/contrib/xntpd/doc/xntpdc.8
new file mode 100644
index 000000000000..80979e2675b4
--- /dev/null
+++ b/contrib/xntpd/doc/xntpdc.8
@@ -0,0 +1,686 @@
+''' $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.
+''' Greek uppercase omega is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\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.
+.PP
+.B kerninfo
+.PP
+Obtain and print kernel phase-lock loop operating parameters. This
+information is available only if the kernel has been specially modified
+for a precision timekeeping function.
+.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|mclient|auth
+[
+.I ...
+]
+.PP
+Allows the setting of the broadcast/multicast client and/or authenticate
+system flags. Setting bclient causes the server to listen for broadcast
+NTP to to synchronize to broadcasts when appropriate. Setting mclient
+causes the same thing, but using multicast facilities, when available.
+Setting auth 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/multicast client and/or authenticate system flags to be
+cleared. Clearing bclient causes incoming broadcast and multicast NTP packets
+to be ignored. Clearing auth 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 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 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 limited 10
+These hosts are subject to limitation of number of clients from the
+same net. Net in this context refers to the IP notion of net (class A,
+class B, class C, etc.). Only the first \*(L"client_limit\*(R" hosts
+that have shown up at the server and that have been active during the
+last \*(L"client_limit_period\*(R" seconds are accepted. Requests from
+other clients from the same net are rejected. Only time request
+packets are taken into account. \*(L"Private\*(R", \*(L"control\*(R",
+and \*(L"broadcast\*(R" packets are not subject to client limitation
+and therefore are not contributing to client count. History of clients
+is kept using the monitoring capability of
+.IR xntpd.
+Thus, monitoring is active as long as there is a restriction entry
+with the \*(L"limited\*(R" flag. The default value for
+\*(L"client_limit\*(R" is 3. The default value for
+\*(L"client_limit_period\*(R" is 3600 seconds. Currently both
+variables are not runtime configurable.
+.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.
+.SH SEE ALSO
+.PP
+.IR xntpd (8)
+.SH HISTORY
+.PP
+Written by Dennis Ferguson at the University of Toronto.
+.SH BUGS
+.PP
+.I Xntpdc
+is a crude hack. Much of the information it shows is deadly boring
+and could only be loved by its implementer. The program was designed
+so that new (and temporary) features were easy to hack in, at great
+expense to the program's ease of use. Despite this, the program
+is occasionally useful.
diff --git a/contrib/xntpd/gadget/.keep_me b/contrib/xntpd/gadget/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/gadget/.keep_me
diff --git a/contrib/xntpd/hints/.keep_me b/contrib/xntpd/hints/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/hints/.keep_me
diff --git a/contrib/xntpd/include/README b/contrib/xntpd/include/README
new file mode 100644
index 000000000000..5127b70a1b3a
--- /dev/null
+++ b/contrib/xntpd/include/README
@@ -0,0 +1,6 @@
+README file for directory ./include of the NTP Version 3 distribution
+
+This directory contains the include files used by most programs in this
+distribution. The ./sys directory in this directory contains system
+header files used by the clock discipline and STREAMS modules in the
+../kernel directory.
diff --git a/contrib/xntpd/include/l_stdlib.h b/contrib/xntpd/include/l_stdlib.h
new file mode 100644
index 000000000000..89a8092853b5
--- /dev/null
+++ b/contrib/xntpd/include/l_stdlib.h
@@ -0,0 +1,234 @@
+/*
+ * 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 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));
+extern void bcopy P((char *, char *, int));
+#endif
+
+#ifndef bzero /* XXX macro prototyping clash */
+extern void bzero P((char *, int));
+extern int bcmp P((char *, char *, int));
+extern void bcopy 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 */
+#ifndef NTP_NEED_BOPS /* but may be emulated by bops */
+extern char *memcpy();
+extern char *memset();
+extern int memcmp();
+#endif
+#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 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 */
+
+#ifdef SYS_DOMAINOS
+extern char * getpass P((char *));
+#endif /* SYS_DOMAINOS */
+
+#endif /* l_stdlib_h */
+
diff --git a/contrib/xntpd/include/md5.h b/contrib/xntpd/include/md5.h
new file mode 100644
index 000000000000..c13f63905ebc
--- /dev/null
+++ b/contrib/xntpd/include/md5.h
@@ -0,0 +1,56 @@
+/* md5.h,v 3.1 1993/07/06 01:06:44 jbj Exp
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5 **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#include "ntp_types.h"
+
+/* typedef a 32-bit type */
+typedef unsigned LONG UINT4;
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+ UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
+ UINT4 buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5Init ();
+void MD5Update ();
+void MD5Final ();
+
+/*
+ ***********************************************************************
+ ** End of md5.h **
+ ******************************** (cut) ********************************
+ */
diff --git a/contrib/xntpd/include/mx4200.h b/contrib/xntpd/include/mx4200.h
new file mode 100644
index 000000000000..5a9e49651ca4
--- /dev/null
+++ b/contrib/xntpd/include/mx4200.h
@@ -0,0 +1,42 @@
+/* @(#) mx4200.h,v 3.1 1993/07/06 01:06:46 jbj Exp */
+
+
+/* records transmitted from extern CDU to MX 4200 */
+#define PMVXG_S_INITMODEA 0 /* initialization/mode part A */
+#define PMVXG_S_INITMODEB 1 /* initialization/mode part B*/
+#define PMVXG_S_SATHEALTH 2 /* satellite health control */
+#define PMVXG_S_DIFFNAV 3 /* differential navigation control */
+#define PMVXG_S_PORTCONF 7 /* control port configuration */
+#define PMVXG_S_GETSELFTEST 3 /* self test (request results) */
+#define PMVXG_S_RTCMCONF 16 /* RTCM port configuration */
+#define PMVXG_S_PASSTHRU 17 /* equipment port pass-thru config */
+#define PMVXG_S_RESTART 18 /* restart control */
+#define PMVXG_S_OSCPARAM 19 /* oscillator parameter */
+#define PMVXG_S_DOSELFTEST 20 /* self test (activate a test) */
+#define PMVXG_S_TRECOVCONF 23 /* time recovery configuration */
+#define PMVXG_S_RAWDATASEL 24 /* raw data port data selection */
+#define PMVXG_S_EQUIPCONF 26 /* equipment port configuration */
+#define PMVXG_S_RAWDATACONF 27 /* raw data port configuration */
+
+/* records transmitted from MX 4200 to external CDU */
+#define PMVXG_D_STATUS 0 /* status */
+#define PMVXG_D_POSITION 1 /* position */
+#define PMVXG_D_OPDOPS 3 /* (optimum) DOPs */
+#define PMVXG_D_MODEDATA 4 /* mode data */
+#define PMVXG_D_SATPRED 5 /* satellite predictions */
+#define PMVXG_D_SATHEALTH 6 /* satellite health status */
+#define PMVXG_D_UNRECOG 7 /* unrecognized request response */
+#define PMVXG_D_SIGSTRLOC 8 /* sig strength & location (sats 1-4) */
+#define PMVXG_D_SPEEDHEAD 11 /* speed/heading data */
+#define PMVXG_D_OSELFTEST 12 /* (old) self-test results */
+#define PMVXG_D_SIGSTRLOC2 18 /* sig strength & location (sats 5-8) */
+#define PMVXG_D_OSCPARAM 19 /* oscillator parameter */
+#define PMVXG_D_SELFTEST 20 /* self test results */
+#define PMVXG_D_PHV 21 /* position, height & velocity */
+#define PMVXG_D_DOPS 22 /* DOPs */
+#define PMVXG_D_SOFTCONF 30 /* software configuration */
+#define PMVXG_D_DIFFGPSMODE 503 /* differential gps moding */
+#define PMVXG_D_TRECOVUSEAGE 523 /* time recovery usage */
+#define PMVXG_D_RAWDATAOUT 524 /* raw data port data output */
+#define PMVXG_D_TRECOVRESULT 828 /* time recovery results */
+#define PMVXG_D_TRECOVOUT 830 /* time recovery output message */
diff --git a/contrib/xntpd/include/ntp.h b/contrib/xntpd/include/ntp.h
new file mode 100644
index 000000000000..310353f1cda2
--- /dev/null
+++ b/contrib/xntpd/include/ntp.h
@@ -0,0 +1,682 @@
+/* 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 memset() 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 /* MSF EES M201, UK */
+#define REFCLK_GPSTM_TRUETIME 15 /* TrueTime GPS/TM-TMD */
+
+/*
+ * 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/contrib/xntpd/include/ntp_calendar.h b/contrib/xntpd/include/ntp_calendar.h
new file mode 100644
index 000000000000..fc12f0b2945c
--- /dev/null
+++ b/contrib/xntpd/include/ntp_calendar.h
@@ -0,0 +1,80 @@
+/* ntp_calendar.h,v 3.1 1993/07/06 01:06:48 jbj Exp
+ * ntp_calendar.h - definitions for the calendar time-of-day routine
+ */
+
+#include "ntp_types.h"
+
+struct calendar {
+ u_short year; /* year (A.D.) */
+ u_short yearday; /* day of year, 1 = January 1 */
+ u_char month; /* month, 1 = January */
+ u_char monthday; /* day of month */
+ u_char hour; /* hour of day, midnight = 0 */
+ u_char minute; /* minute of hour */
+ u_char second; /* second of minute */
+};
+
+/*
+ * Days in each month. 30 days hath September...
+ */
+#define JAN 31
+#define FEB 28
+#define FEBLEAP 29
+#define MAR 31
+#define APR 30
+#define MAY 31
+#define JUN 30
+#define JUL 31
+#define AUG 31
+#define SEP 30
+#define OCT 31
+#define NOV 30
+#define DEC 31
+
+/*
+ * We deal in a 4 year cycle starting at March 1, 1900. We assume
+ * we will only want to deal with dates since then, and not to exceed
+ * the rollover day in 2036.
+ */
+#define SECSPERMIN (60) /* seconds per minute */
+#define MINSPERHR (60) /* minutes per hour */
+#define HRSPERDAY (24) /* hours per day */
+#define DAYSPERYEAR (365) /* days per year */
+
+#define SECSPERDAY (SECSPERMIN*MINSPERHR*HRSPERDAY)
+#define SECSPERYEAR (365 * SECSPERDAY) /* regular year */
+#define SECSPERLEAPYEAR (366 * SECSPERDAY) /* leap year */
+
+#define MAR1900 ((JAN+FEB) * SECSPERDAY) /* no leap year in 1900 */
+#define DAYSPERCYCLE (365+365+365+366) /* 3 normal years plus leap */
+#define SECSPERCYCLE (DAYSPERCYCLE*SECSPERDAY)
+#define YEARSPERCYCLE 4
+
+/*
+ * Gross hacks. I have illicit knowlege that there won't be overflows
+ * here, the compiler often can't tell this.
+ */
+#define TIMES60(val) ((((val)<<4) - (val))<<2) /* *(16 - 1) * 4 */
+#define TIMES24(val) (((val)<<4) + ((val)<<3)) /* *16 + *8 */
+#define TIMES7(val) (((val)<<3) - (val)) /* *8 - *1 */
+#define TIMESDPERC(val) (((val)<<10) + ((val)<<8) \
+ + ((val)<<7) + ((val)<<5) \
+ + ((val)<<4) + ((val)<<2) + (val)) /* *big* hack */
+
+/*
+ * Another big hack. Cycle 22 started on March 1, 1988. This is
+ * STARTCYCLE22 seconds after the start of cycle 0.
+ */
+#define CYCLE22 (22)
+#define STARTCYCLE22 (U_LONG)(0xa586b500) /* 2777068800 */
+#define MAR1988 (U_LONG)(STARTCYCLE22 + (U_LONG)MAR1900)
+
+/*
+ * The length of January + February in leap and non-leap years.
+ */
+#define JANFEBNOLEAP ((JAN+FEB) * SECSPERDAY)
+#define JANFEBLEAP ((JAN+FEBLEAP) * SECSPERDAY)
+
+extern void caljulian P((U_LONG, struct calendar *));
+extern U_LONG caltontp P((const struct calendar *));
+
diff --git a/contrib/xntpd/include/ntp_control.h b/contrib/xntpd/include/ntp_control.h
new file mode 100644
index 000000000000..74f75f17f51a
--- /dev/null
+++ b/contrib/xntpd/include/ntp_control.h
@@ -0,0 +1,252 @@
+/* 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_VARLIST 20
+
+#define CS_MAXCODE CS_VARLIST
+
+/*
+ * 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_VARLIST 36
+
+#define CP_MAXCODE CP_VARLIST
+
+/*
+ * 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_VARLIST 13
+
+#define CC_MAXCODE CC_VARLIST
+
+/*
+ * Definition of the structure used internally to hold trap information.
+ * ntp_request.c wants to see this.
+ */
+struct ctl_trap {
+ struct sockaddr_in tr_addr; /* address of trap recipient */
+ struct interface *tr_localaddr; /* interface to send this through */
+ U_LONG tr_settime; /* time trap was set */
+ U_LONG tr_count; /* async messages sent to this guy */
+ U_LONG tr_origtime; /* time trap was originally set */
+ U_LONG tr_resets; /* count of resets for this trap */
+ u_short tr_sequence; /* trap sequence id */
+ u_char tr_flags; /* trap flags */
+ u_char tr_version; /* version number of trapper */
+};
+
+/*
+ * Flag bits
+ */
+#define TRAP_INUSE 0x1 /* this trap is active */
+#define TRAP_NONPRIO 0x2 /* this trap is non-priority */
+#define TRAP_CONFIGURED 0x4 /* this trap was configured */
diff --git a/contrib/xntpd/include/ntp_filegen.h b/contrib/xntpd/include/ntp_filegen.h
new file mode 100644
index 000000000000..7281d597aaeb
--- /dev/null
+++ b/contrib/xntpd/include/ntp_filegen.h
@@ -0,0 +1,51 @@
+/*
+ * ntp_filegen.h,v 3.7 1994/01/25 19:04:16 kardel Exp
+ *
+ * definitions for NTP file generations support
+ *
+ *
+ * Copyright (c) 1992
+ * Rainer Pruy Friedrich-Alexander Unuiversitaet Erlangen-Nuernberg
+ *
+ * This code may be modified and used freely
+ * provided the credits remain intact.
+ */
+
+#include "ntp_types.h"
+
+/*
+ * supported file generation types
+ */
+
+#define FILEGEN_NONE 255 /* no generations - use plain file name */
+#define FILEGEN_PID 1 /* one filegen per process incarnation */
+#define FILEGEN_DAY 2 /* one filegen per day */
+#define FILEGEN_WEEK 3 /* one filegen per week */
+#define FILEGEN_MONTH 4 /* one filegen per month */
+#define FILEGEN_YEAR 5 /* one filegen per year */
+#define FILEGEN_AGE 6 /* change filegen each FG_AGE_SECS */
+
+/*
+ * supported file generation flags
+ */
+
+#define FGEN_FLAG_LINK 0x01 /* make a link to base name */
+
+#define FGEN_FLAG_ENABLED 0x80 /* set this to really create files */
+ /* without this, open is suppressed */
+
+typedef struct FILEGEN
+ {
+ FILE *fp; /* file referring to current generation */
+ char *prefix; /* filename prefix and basename to be used*/
+ char *basename; /* for constructing filename of generation file */
+ /* WARNING: must be malloced !!! will be fed to free()*/
+ U_LONG id; /* id of current generation */
+ u_char type; /* type of file generation */
+ u_char flag; /* flags modifying processing of file generation */
+ } FILEGEN;
+
+extern void filegen_setup P((FILEGEN *, U_LONG));
+extern void filegen_config P((FILEGEN *, char *, u_int, u_int));
+extern FILEGEN *filegen_get P((char *));
+extern void filegen_register P((char *, FILEGEN *));
diff --git a/contrib/xntpd/include/ntp_fp.h b/contrib/xntpd/include/ntp_fp.h
new file mode 100644
index 000000000000..327306054b44
--- /dev/null
+++ b/contrib/xntpd/include/ntp_fp.h
@@ -0,0 +1,315 @@
+/* ntp_fp.h,v 3.1 1993/07/06 01:06:54 jbj Exp
+ * ntp_fp.h - definitions for NTP fixed point arithmetic
+ */
+
+#include <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/contrib/xntpd/include/ntp_if.h b/contrib/xntpd/include/ntp_if.h
new file mode 100644
index 000000000000..1a76ca02da4b
--- /dev/null
+++ b/contrib/xntpd/include/ntp_if.h
@@ -0,0 +1,43 @@
+/*
+ * Sockets are not standard.
+ * So hide uglyness in include file.
+ */
+#if defined(SYS_CONVEXOS9)
+#include "/sys/sync/queue.h"
+#include "/sys/sync/sema.h"
+#endif
+
+#if defined(SYS_AIX)
+#include <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/contrib/xntpd/include/ntp_io.h b/contrib/xntpd/include/ntp_io.h
new file mode 100644
index 000000000000..c3b79be0616c
--- /dev/null
+++ b/contrib/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/contrib/xntpd/include/ntp_machine.h b/contrib/xntpd/include/ntp_machine.h
new file mode 100644
index 000000000000..1c3983e4a9ef
--- /dev/null
+++ b/contrib/xntpd/include/ntp_machine.h
@@ -0,0 +1,622 @@
+/* ntp_machine.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_TERMIOS if
+ NTP_POSIX_SOURCE was set but can'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_TERMIOS - Use POSIX termios.h
+
+THIS MAKES PORTS TO NEW SYSTEMS EASY - You only have to wory about
+ kernel mucking.
+
+ NTP_POSIX_SOURCE - Use POSIX functions over bsd functions and att functions.
+ This is NOT the same as _POSIX_SOURCE.
+ It is much weaker!
+
+
+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
+
+HOW TO GET IP INTERFACE INFORMATION
+
+ Some UNIX V.4 machines implement a sockets library on top of
+ streams. For these systems, you must use send the SIOCGIFCONF down
+ the stream in an I_STR ioctl. This ususally also implies
+ USE_STREAMS_DEVICE FOR IF_CONFIG. Dell UNIX is a notable exception.
+
+ STREAMS_TLI - use ioctl(I_STR) to implement ioctl(SIOCGIFCONF)
+
+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 array 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 packets 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 ?
+
+DEFINITIONS FOR SYSTEM && PROCESSOR
+ STR_SYSTEM - value of system variable
+ STR_PROCESSOR - value of processor variable
+
+You could just put the defines on the DEFS line in machines/<os> file.
+I don't since there are lots of different types of compilers that a system might
+have, some that can do proto typing and others that cannot on the same system.
+I get a chance to twiddle some of the configuration parameters at compile
+time based on compiler/machine combinations by using this include file.
+See convex, aix and sun configurations see how complex it get.
+
+Note that it _is_ considered reasonable to add some system-specific defines
+to the machine/<os> file if it would be too inconvenient to puzzle them out
+in this file.
+
+*/
+
+
+/*
+ * 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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/AIX"
+#endif
+#endif /* RS6000 */
+
+/*
+ * SunOS 4.X.X
+ * Note: posix version has NTP_POSIX_SOURCE and HAVE_SIGNALED_IO
+ */
+#if defined(SYS_SUNOS4)
+#define NTP_NEED_BOPS
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/SunOS 4.x"
+#endif
+#endif
+
+/*
+ * Sinix-M
+ */
+#if defined(SYS_SINIXM)
+#undef HAVE_SIGNALED_IO
+#undef USE_TTY_SIGPOLL
+#undef USE_UDP_SIGPOLL
+#define STREAMS_TLI
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/SINIX-M"
+#endif
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/Solaris 2.x"
+#endif
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/ConvexOS"
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/IRIX"
+#endif
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/Ultrix"
+#endif
+#define HAVE_TERMIOS
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/AUX"
+#endif
+#endif
+
+/*
+ * Next
+ */
+#if defined(SYS_NEXT)
+#define DOSYNCTODR
+#define HAVE_READKMEM
+#define HAVE_BSD_NICE
+#define HAVE_N_UN
+#undef NTP_POSIX_SOURCE
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/Next"
+#endif
+#endif
+
+/*
+ * HPUX
+ */
+#if defined(SYS_HPUX)
+#define NTP_POSIX_SOURCE
+#define HAVE_SIGNALED_IO
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+#define setlinebuf(f) setvbuf(f, NULL, _IOLBF, 0)
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/HPUX"
+#endif
+#endif
+
+/*
+ * bsdi
+ */
+#if defined(SYS_BSDI)
+#define HAVE_SIGNALED_IO
+#define HAVE_LIBKVM
+#define NTP_POSIX_SOURCE
+#define HAVE_BSD_NICE
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/BSDI"
+#endif
+#define HAVE_BSD_TTYS
+#define HAVE_TERMIOS
+#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
+/* hope there will be a standard interface
+ * along with a standard name one day ! */
+#define ntp_adjtime __adjtimex
+#define HAVE_BSD_NICE
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/Linux"
+#endif
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/*BSD"
+#endif
+#endif
+
+/*
+ * DEC AXP OSF/1
+ */
+#if defined(SYS_DECOSF1)
+#define HAVE_SIGNALED_IO
+#define HAVE_READKMEM
+#define NTP_POSIX_SOURCE
+#define NTP_SYSCALLS_STD
+#define HAVE_BSD_NICE
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/DECOSF1"
+#endif
+#endif
+
+/*
+ * I386
+ * XXX - what OS?
+ */
+#if defined(SYS_I386)
+#define HAVE_READKMEM
+#define S_CHAR_DEFINED
+#define HAVE_BSD_NICE
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/I386"
+#endif
+#endif
+
+/*
+ * Mips
+ */
+#if defined(SYS_MIPS)
+#define NOKMEM
+#define HAVE_BSD_NICE
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/Mips"
+#endif
+#endif
+
+/*
+ * SEQUENT
+ */
+#if defined(SYS_SEQUENT)
+#define HAVE_BSD_NICE
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/Sequent Dynix 3"
+#endif
+#endif
+
+/*
+ * PTX
+ */
+#if defined(SYS_PTX)
+#define NO_SIGNED_CHAR_DECL
+#ifndef HAVE_SYSV_TTYS
+#define HAVE_SYSV_TTYS
+#endif
+#define STREAMS_TLI
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/Sequent PTX"
+#endif
+#endif
+
+
+/*
+ * Sony NEWS
+ */
+#if defined(SYS_SONY)
+#define NO_SIGNED_CHAR_DECL
+#define HAVE_READKMEM
+#define HAVE_BSD_NICE
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/Sony"
+#endif
+#endif
+
+/*
+ * VAX
+ * XXX - VMS?
+ */
+#if defined(SYS_VAX)
+#define NO_SIGNED_CHAR_DECL
+#define HAVE_READKMEM
+#define HAVE_BSD_NICE
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/VAX"
+#endif
+#endif
+
+/*
+ * UNIX V.4 on and NCR 3000
+ */
+#if defined(SYS_SVR4)
+#define HAVE_ATT_SETPGRP
+#define USE_PROTOTYPES
+#define NTP_POSIX_SOURCE
+#define HAVE_ATT_NICE
+#define HAVE_READKMEM
+#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
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/SysVR4"
+#endif
+#endif
+
+/*
+ * DomainOS
+ */
+#if defined(SYS_DOMAINOS)
+#define HAVE_BSD_NICE
+#define NOKMEM
+#define HAVE_SIGNALED_IO
+#define HAVE_BSD_TTYS
+#define NTP_SYSCALLS_STD
+#define USE_PROTOTYPES
+#define UDP_WILDCARD_DELIVERY
+#ifndef STR_SYSTEM
+#define STR_SYSTEM "UNIX/DOMAINOS"
+#endif
+#endif
+
+#ifdef STREAM /* STREAM implies TERMIOS */
+#ifndef HAVE_TERMIOS
+#define HAVE_TERMIOS
+#endif
+#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
+
+#if !defined(HAVE_SYSV_TTYS) \
+ && !defined(HAVE_BSD_TTYS) \
+ && !defined(HAVE_TERMIOS)
+ ERROR no_tty_type_defined
+#endif
+
+
+#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 */
+
+/*
+ * 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
+
+
+#endif /* __ntp_machine */
diff --git a/contrib/xntpd/include/ntp_malloc.h b/contrib/xntpd/include/ntp_malloc.h
new file mode 100644
index 000000000000..0079cb700ed1
--- /dev/null
+++ b/contrib/xntpd/include/ntp_malloc.h
@@ -0,0 +1,15 @@
+/*
+ * Define malloc and friends.
+ */
+#ifndef _ntp_malloc_h
+
+#define _ntp_malloc_h
+#ifdef NTP_POSIX_SOURCE
+#include <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/contrib/xntpd/include/ntp_refclock.h b/contrib/xntpd/include/ntp_refclock.h
new file mode 100644
index 000000000000..cc026f5c742f
--- /dev/null
+++ b/contrib/xntpd/include/ntp_refclock.h
@@ -0,0 +1,142 @@
+/*
+ * ntp_refclock.h - definitions for reference clock support
+ */
+
+#include "ntp_types.h"
+
+#if !defined(SYSV_TTYS) && !defined(STREAM) & !defined(BSD_TTYS)
+#define BSD_TTYS
+#endif /* SYSV_TTYS STREAM BSD_TTYS */
+
+/*
+ * Macros to determine the clock type and unit numbers from a
+ * 127.127.t.u address.
+ */
+#define REFCLOCKTYPE(srcadr) ((SRCADR(srcadr) >> 8) & 0xff)
+#define REFCLOCKUNIT(srcadr) (SRCADR(srcadr) & 0xff)
+
+/*
+ * list of reference clock names
+ * see lib/clocktypes.c (must also agree with xntpd/refclock_conf.c)
+ */
+struct clktype {
+ int code; /* driver "major" number */
+ char *clocktype; /* LONG description */
+ char *abbrev; /* short description */
+};
+
+/*
+ * Definitions for default values
+ */
+#define noentry 0 /* flag for null routine */
+
+/*
+ * Definitions for flags
+ */
+#define NOFLAGS 0
+#define REF_FLAG_BCLIENT 0x1 /* clock prefers to run as a bclient */
+
+/*
+ * Flag values
+ */
+#define CLK_HAVETIME1 0x1
+#define CLK_HAVETIME2 0x2
+#define CLK_HAVEVAL1 0x4
+#define CLK_HAVEVAL2 0x8
+
+#define CLK_FLAG1 0x1
+#define CLK_FLAG2 0x2
+#define CLK_FLAG3 0x4
+#define CLK_FLAG4 0x8
+
+#define CLK_HAVEFLAG1 0x10
+#define CLK_HAVEFLAG2 0x20
+#define CLK_HAVEFLAG3 0x40
+#define CLK_HAVEFLAG4 0x80
+
+/*
+ * Structure for returning clock status
+ */
+struct refclockstat {
+ u_char type;
+ u_char flags;
+ u_char haveflags;
+ u_short lencode; /* ahem, we do have some longer "time-codes" */
+ char *lastcode;
+ U_LONG polls;
+ U_LONG noresponse;
+ U_LONG badformat;
+ U_LONG baddata;
+ U_LONG timereset;
+ char *clockdesc; /* description of clock, in ASCII */
+ l_fp fudgetime1;
+ l_fp fudgetime2;
+ LONG fudgeval1;
+ LONG fudgeval2;
+ u_char currentstatus;
+ u_char lastevent;
+ u_char unused;
+ struct ctl_var *kv_list; /* additional variables */
+};
+
+/*
+ * Reference clock I/O structure. Used to provide an interface between
+ * the reference clock drivers and the I/O module.
+ */
+struct refclockio {
+ struct refclockio *next;
+ void (*clock_recv)();
+ caddr_t srcclock; /* pointer to clock structure */
+ int datalen;
+ int fd;
+ U_LONG recvcount;
+};
+
+
+/*
+ * Sizes of things we return for debugging
+ */
+#define NCLKBUGVALUES 16
+#define NCLKBUGTIMES 32
+
+/*
+ * Structure for returning debugging info
+ */
+struct refclockbug {
+ u_char nvalues;
+ u_char ntimes;
+ u_short svalues;
+ U_LONG stimes;
+ U_LONG values[NCLKBUGVALUES];
+ l_fp times[NCLKBUGTIMES];
+};
+
+/*
+ * Struct refclock provides the interface between the reference
+ * clock support and particular clock drivers. There are entries
+ * to open and close a unit, optional values to specify the
+ * timer interval for calls to the transmit procedure and to
+ * specify a polling routine to be called when the transmit
+ * procedure executes. There is an entry which is called when
+ * the transmit routine is about to shift zeroes into the
+ * filter register, and entries for stuffing fudge factors into
+ * the driver and getting statistics from it.
+ */
+struct refclock {
+ int (*clock_start) P((u_int, struct peer *)); /* start a clock unit */
+ void (*clock_shutdown) P((int)); /* shut a clock down */
+ void (*clock_poll) P((int, struct peer *)); /* called from the xmit routine */
+ void (*clock_control) P((u_int, struct refclockstat *, struct refclockstat *)); /* set fudge values, return stats */
+ void (*clock_init) P((void)); /* initialize driver data at startup */
+ void (*clock_buginfo) P((int, struct refclockbug *)); /* get clock dependent bug info */
+ U_LONG clock_flags; /* flag values */
+};
+
+extern int io_addclock_simple P((struct refclockio *));
+extern int io_addclock P((struct refclockio *));
+extern void io_closeclock P((struct refclockio *));
+
+#ifdef REFCLOCK
+extern void refclock_buginfo P((struct sockaddr_in *, struct refclockbug *));
+extern void refclock_control P((struct sockaddr_in *, struct refclockstat *, struct refclockstat *));
+#endif /* REFCLOCK */
diff --git a/contrib/xntpd/include/ntp_request.h b/contrib/xntpd/include/ntp_request.h
new file mode 100644
index 000000000000..e94cb452aac7
--- /dev/null
+++ b/contrib/xntpd/include/ntp_request.h
@@ -0,0 +1,713 @@
+/* ntp_request.h,v 3.1 1993/07/06 01:06:57 jbj Exp
+ * ntp_request.h - definitions for the xntpd remote query facility
+ */
+
+#include "ntp_types.h"
+
+/*
+ * A mode 7 packet is used exchanging data between an NTP server
+ * and a client for purposes other than time synchronization, e.g.
+ * monitoring, statistics gathering and configuration. A mode 7
+ * packet has the following format:
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |R|M| VN | Mode|A| Sequence | Implementation| Req Code |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Err | Number of data items | MBZ | Size of data item |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * | Data (Minimum 0 octets, maximum 500 octets) |
+ * | |
+ * [...]
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Encryption Keyid (when A bit set) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * | Message Authentication Code (when A bit set) |
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * where the fields are (note that the client sends requests, the server
+ * responses):
+ *
+ * Response Bit: This packet is a response (if clear, packet is a request).
+ *
+ * More Bit: Set for all packets but the last in a response which
+ * requires more than one packet.
+ *
+ * Version Number: 2 for current version
+ *
+ * Mode: Always 7
+ *
+ * Authenticated bit: If set, this packet is authenticated.
+ *
+ * Sequence number: For a multipacket response, contains the sequence
+ * number of this packet. 0 is the first in the sequence,
+ * 127 (or less) is the last. The More Bit must be set in
+ * all packets but the last.
+ *
+ * Implementation number: The number of the implementation this request code
+ * is defined by. An implementation number of zero is used
+ * for requst codes/data formats which all implementations
+ * agree on. Implementation number 255 is reserved (for
+ * extensions, in case we run out).
+ *
+ * Request code: An implementation-specific code which specifies the
+ * operation to be (which has been) performed and/or the
+ * format and semantics of the data included in the packet.
+ *
+ * Err: Must be 0 for a request. For a response, holds an error
+ * code relating to the request. If nonzero, the operation
+ * requested wasn't performed.
+ *
+ * 0 - no error
+ * 1 - incompatable implementation number
+ * 2 - unimplemented request code
+ * 3 - format error (wrong data items, data size, packet size etc.)
+ * 4 - no data available (e.g. request for details on unknown peer)
+ * 5-6 I don't know
+ * 7 - authentication failure (i.e. permission denied)
+ *
+ * Number of data items: number of data items in packet. 0 to 500
+ *
+ * MBZ: A reserved data field, must be zero in requests and responses.
+ *
+ * Size of data item: size of each data item in packet. 0 to 500
+ *
+ * Data: Variable sized area containing request/response data. For
+ * requests and responses the size in octets must be greater
+ * than or equal to the product of the number of data items
+ * and the size of a data item. For requests the data area
+ * must be exactly 40 octets in length. For responses the
+ * data area may be any length between 0 and 500 octets
+ * inclusive.
+ *
+ * Message Authentication Code: Same as NTP spec, in definition and function.
+ * May optionally be included in requests which require
+ * authentication, is never included in responses.
+ *
+ * The version number, mode and keyid have the same function and are
+ * in the same location as a standard NTP packet. The request packet
+ * is the same size as a standard NTP packet to ease receive buffer
+ * management, and to allow the same encryption procedure to be used
+ * both on mode 7 and standard NTP packets. The mac is included when
+ * it is required that a request be authenticated, the keyid should be
+ * zero in requests in which the mac is not included.
+ *
+ * The data format depends on the implementation number/request code pair
+ * and whether the packet is a request or a response. The only requirement
+ * is that data items start in the octet immediately following the size
+ * word and that data items be concatenated without padding between (i.e.
+ * if the data area is larger than data_items*size, all padding is at
+ * the end). Padding is ignored, other than for encryption purposes.
+ * Implementations using encryption might want to include a time stamp
+ * or other data in the request packet padding. The key used for requests
+ * is implementation defined, but key 15 is suggested as a default.
+ */
+
+/*
+ * A request packet. These are almost a fixed length.
+ */
+struct req_pkt {
+ u_char rm_vn_mode; /* response, more, version, mode */
+ u_char auth_seq; /* key, sequence number */
+ u_char implementation; /* implementation number */
+ u_char request; /* request number */
+ u_short err_nitems; /* error code/number of data items */
+ u_short mbz_itemsize; /* item size */
+ char data[32]; /* data area */
+ l_fp tstamp; /* time stamp, for authentication */
+ U_LONG keyid; /* encryption key */
+ char mac[MAX_MAC_LEN-sizeof(U_LONG)]; /* (optional) 8 byte auth code */
+};
+
+/*
+ * Input packet lengths. One with the mac, one without.
+ */
+#define REQ_LEN_MAC (sizeof(struct req_pkt))
+#define REQ_LEN_NOMAC (sizeof(struct req_pkt) - MAX_MAC_LEN)
+
+/*
+ * A response packet. The length here is variable, this is a
+ * maximally sized one. Note that this implementation doesn't
+ * authenticate responses.
+ */
+#define RESP_HEADER_SIZE (8)
+#define RESP_DATA_SIZE (500)
+
+struct resp_pkt {
+ u_char rm_vn_mode; /* response, more, version, mode */
+ u_char auth_seq; /* key, sequence number */
+ u_char implementation; /* implementation number */
+ u_char request; /* request number */
+ u_short err_nitems; /* error code/number of data items */
+ u_short mbz_itemsize; /* item size */
+ char data[RESP_DATA_SIZE]; /* data area */
+};
+
+
+/*
+ * Information error codes
+ */
+#define INFO_OKAY 0
+#define INFO_ERR_IMPL 1 /* incompatable implementation */
+#define INFO_ERR_REQ 2 /* unknown request code */
+#define INFO_ERR_FMT 3 /* format error */
+#define INFO_ERR_NODATA 4 /* no data for this request */
+#define INFO_ERR_AUTH 7 /* authentication failure */
+
+/*
+ * Maximum sequence number.
+ */
+#define MAXSEQ 127
+
+
+/*
+ * Bit setting macros for multifield items.
+ */
+#define RESP_BIT 0x80
+#define MORE_BIT 0x40
+
+#define ISRESPONSE(rm_vn_mode) (((rm_vn_mode)&RESP_BIT)!=0)
+#define ISMORE(rm_vn_mode) (((rm_vn_mode)&MORE_BIT)!=0)
+#define INFO_VERSION(rm_vn_mode) ((u_char)(((rm_vn_mode)>>3)&0x7))
+#define INFO_MODE(rm_vn_mode) ((rm_vn_mode)&0x7)
+
+#define RM_VN_MODE(resp, more) ((u_char)(((resp)?RESP_BIT:0)\
+ |((more)?MORE_BIT:0)\
+ |((NTP_VERSION)<<3)\
+ |(MODE_PRIVATE)))
+
+#define INFO_IS_AUTH(auth_seq) (((auth_seq) & 0x80) != 0)
+#define INFO_SEQ(auth_seq) ((auth_seq)&0x7f)
+#define AUTH_SEQ(auth, seq) ((u_char)((((auth)!=0)?0x80:0)|((seq)&0x7f)))
+
+#define INFO_ERR(err_nitems) ((u_short)((ntohs(err_nitems)>>12)&0xf))
+#define INFO_NITEMS(err_nitems) ((u_short)(ntohs(err_nitems)&0xfff))
+#define ERR_NITEMS(err, nitems) (htons((((u_short)(err)<<12)&0xf000)\
+ |((u_short)(nitems)&0xfff)))
+
+#define INFO_MBZ(mbz_itemsize) ((ntohs(mbz_itemsize)>>12)&0xf)
+#define INFO_ITEMSIZE(mbz_itemsize) (ntohs(mbz_itemsize)&0xfff)
+#define MBZ_ITEMSIZE(itemsize) (htons((u_short)(itemsize)))
+
+
+/*
+ * Implementation numbers. One for universal use and one for xntpd.
+ */
+#define IMPL_UNIV 0
+#define IMPL_XNTPD 2
+
+/*
+ * Some limits related to authentication. Frames which are
+ * authenticated must include a time stamp which differs from
+ * the receive time stamp by no more than 10 seconds.
+ */
+#define INFO_TS_MAXSKEW_UI 10
+#define INFO_TS_MAXSKEW_UF 0
+
+/*
+ * Universal request codes go here. There aren't any.
+ */
+
+/*
+ * XNTPD request codes go here.
+ */
+#define REQ_PEER_LIST 0 /* return list of peers */
+#define REQ_PEER_LIST_SUM 1 /* return summary info for all peers */
+#define REQ_PEER_INFO 2 /* get standard information on peer */
+#define REQ_PEER_STATS 3 /* get statistics for peer */
+#define REQ_SYS_INFO 4 /* get system information */
+#define REQ_SYS_STATS 5 /* get system stats */
+#define REQ_IO_STATS 6 /* get I/O stats */
+#define REQ_MEM_STATS 7 /* stats related to peer list maint */
+#define REQ_LOOP_INFO 8 /* info from the loop filter */
+#define REQ_TIMER_STATS 9 /* get timer stats */
+#define REQ_CONFIG 10 /* configure a new peer */
+#define REQ_UNCONFIG 11 /* unconfigure an existing peer */
+#define REQ_SET_SYS_FLAG 12 /* set system flags */
+#define REQ_CLR_SYS_FLAG 13 /* clear system flags */
+#define REQ_MONITOR 14 /* monitor clients */
+#define REQ_NOMONITOR 15 /* stop monitoring clients */
+#define REQ_GET_RESTRICT 16 /* return restrict list */
+#define REQ_RESADDFLAGS 17 /* add flags to restrict list */
+#define REQ_RESSUBFLAGS 18 /* remove flags from restrict list */
+#define REQ_UNRESTRICT 19 /* remove entry from restrict list */
+#define REQ_MON_GETLIST 20 /* return data collected by monitor */
+#define REQ_RESET_STATS 21 /* reset stat counters */
+#define REQ_RESET_PEER 22 /* reset peer stat counters */
+#define REQ_REREAD_KEYS 23 /* reread the encryption key file */
+#define REQ_DO_DIRTY_HACK 24 /* historical interest */
+#define REQ_DONT_DIRTY_HACK 25 /* Ibid. */
+#define REQ_TRUSTKEY 26 /* add a trusted key */
+#define REQ_UNTRUSTKEY 27 /* remove a trusted key */
+#define REQ_AUTHINFO 28 /* return authentication info */
+#define REQ_TRAPS 29 /* return currently set traps */
+#define REQ_ADD_TRAP 30 /* add a trap */
+#define REQ_CLR_TRAP 31 /* clear a trap */
+#define REQ_REQUEST_KEY 32 /* define a new request keyid */
+#define REQ_CONTROL_KEY 33 /* define a new control keyid */
+#define REQ_GET_CTLSTATS 34 /* get stats from the control module */
+#define REQ_GET_LEAPINFO 35 /* get leap information */
+#define REQ_GET_CLOCKINFO 36 /* get clock information */
+#define REQ_SET_CLKFUDGE 37 /* set clock fudge factors */
+#define REQ_SET_MAXSKEW 38 /* set the maximum skew factor */
+#define REQ_GET_CLKBUGINFO 39 /* get clock debugging info */
+#define REQ_SET_SELECT_CODE 40 /* set selection algorithm */
+#define REQ_SET_PRECISION 41 /* set clock precision */
+
+
+/*
+ * Flags in the information returns
+ */
+#define INFO_FLAG_CONFIG 0x1
+#define INFO_FLAG_SYSPEER 0x2
+#define INFO_FLAG_MINPOLL 0x4
+#define INFO_FLAG_REFCLOCK 0x8
+#define INFO_FLAG_BCLIENT 0x10
+#define INFO_FLAG_PREFER 0x10 /* SHARES BCLIENT bit - ok since mutually exclusive - Oh why ist flags a u_char ? */
+#define INFO_FLAG_AUTHENABLE 0x20
+#define INFO_FLAG_SEL_CANDIDATE 0x40
+#define INFO_FLAG_SHORTLIST 0x80
+
+/*
+ * Peer list structure. Used to return raw lists of peers. It goes
+ * without saying that everything returned is in network byte order.
+ */
+struct info_peer_list {
+ U_LONG address; /* address of peer */
+ u_short port; /* port number of peer */
+ u_char hmode; /* mode for this peer */
+ u_char flags; /* flags (from above) */
+};
+
+
+/*
+ * Peer summary structure. Sort of the info that ntpdc returns by default.
+ */
+struct info_peer_summary {
+ U_LONG dstadr; /* local address (zero for undetermined) */
+ U_LONG srcadr; /* source address */
+ u_short srcport; /* source port */
+ u_char stratum; /* stratum of peer */
+ s_char hpoll; /* host polling interval */
+ s_char ppoll; /* peer polling interval */
+ u_char reach; /* reachability register */
+ u_char flags; /* flags, from above */
+ u_char hmode; /* peer mode */
+ s_fp delay; /* peer.estdelay */
+ l_fp offset; /* peer.estoffset */
+ u_fp dispersion; /* peer.estdisp */
+};
+
+
+/*
+ * Peer information structure.
+ */
+struct info_peer {
+ U_LONG dstadr; /* local address */
+ U_LONG srcadr; /* remote address */
+ u_short srcport; /* remote port */
+ u_char flags; /* peer flags */
+ u_char leap; /* peer.leap */
+ u_char hmode; /* peer.hmode */
+ u_char pmode; /* peer.pmode */
+ u_char stratum; /* peer.stratum */
+ u_char ppoll; /* peer.ppoll */
+ u_char hpoll; /* peer.hpoll */
+ s_char precision; /* peer.precision */
+ u_char version; /* peer.version */
+ u_char valid; /* peer.valid */
+ u_char reach; /* peer.reach */
+ u_char unreach; /* peer.unreach */
+ u_char trust; /* peer.trust */
+ u_char unused1;
+ u_char unused2;
+ u_char unused3;
+ u_short associd; /* association ID */
+ U_LONG keyid; /* auth key in use */
+ U_LONG pkeyid; /* peer.pkeyid */
+ U_LONG refid; /* peer.refid */
+ U_LONG timer; /* peer.timer */
+ s_fp rootdelay; /* peer.distance */
+ u_fp rootdispersion; /* peer.dispersion */
+ l_fp reftime; /* peer.reftime */
+ l_fp org; /* peer.org */
+ l_fp rec; /* peer.rec */
+ l_fp xmt; /* peer.xmt */
+ s_fp filtdelay[NTP_SHIFT]; /* delay shift register */
+ l_fp filtoffset[NTP_SHIFT]; /* offset shift register */
+ u_char order[NTP_SHIFT]; /* order of peers from last filter */
+ s_fp delay; /* peer.estdelay */
+ u_fp dispersion; /* peer.estdisp */
+ l_fp offset; /* peer.estoffset */
+ U_LONG bdelay[NTP_SHIFT]; /* broadcast delay filters */
+ U_LONG estbdelay; /* broadcast delay */
+};
+
+
+/*
+ * Peer statistics structure
+ */
+struct info_peer_stats {
+ U_LONG dstadr; /* local address */
+ U_LONG srcadr; /* remote address */
+ u_short srcport; /* remote port */
+ u_short flags; /* peer flags */
+ U_LONG timereset; /* time counters were reset */
+ U_LONG timereceived; /* time since a packet received */
+ U_LONG timetosend; /* time until a packet sent */
+ U_LONG timereachable; /* time peer has been reachable */
+ U_LONG sent; /* number sent */
+ U_LONG received; /* number received */
+ U_LONG processed; /* number processed */
+ U_LONG badlength; /* rejected due to bad length */
+ U_LONG badauth; /* rejected due to bad auth */
+ U_LONG bogusorg; /* funny org time stamps */
+ U_LONG oldpkt; /* duplicate packets */
+ U_LONG baddelay; /* dropped due to bad delays */
+ U_LONG seldelay; /* not selected due to delay */
+ U_LONG seldisp; /* not selected due to dispersion */
+ U_LONG selbroken; /* not selected because of brokenness */
+ U_LONG selold; /* not selected because too old */
+ u_char candidate; /* order after falseticker candidate select */
+ u_char falseticker; /* order after resort for falseticker */
+ u_char select; /* order after select */
+ u_char select_total; /* number who made it to selection */
+};
+
+
+/*
+ * Loop filter variables
+ */
+struct info_loop {
+ l_fp last_offset;
+ l_fp drift_comp;
+ U_LONG compliance;
+ U_LONG watchdog_timer;
+};
+
+
+/*
+ * System info. Mostly the sys.* variables, plus a few unique to
+ * the implementation.
+ */
+struct info_sys {
+ U_LONG peer; /* system peer address */
+ u_char peer_mode; /* mode we are syncing to peer in */
+ u_char leap; /* system leap bits */
+ u_char stratum; /* our stratum */
+ s_char precision; /* local clock precision */
+ s_fp rootdelay; /* distance from sync source */
+ u_fp rootdispersion; /* dispersion from sync source */
+ U_LONG refid; /* reference ID of sync source */
+ l_fp reftime; /* system reference time */
+ U_LONG poll; /* system poll interval */
+ u_short flags; /* system flags */
+ u_char selection; /* selection algorithm code */
+ u_char unused;
+ l_fp bdelay; /* default broadcast delay, a ts fraction */
+ l_fp authdelay; /* default authentication delay */
+ u_fp maxskew; /* maximum skew parameter (obsolete) */
+};
+
+
+/*
+ * System stats. These are collected in the protocol module
+ */
+struct info_sys_stats {
+ U_LONG timeup; /* time we have been up and running */
+ U_LONG timereset; /* time since these were last cleared */
+ U_LONG badstratum; /* packets claiming an invalid stratum */
+ U_LONG oldversionpkt; /* old version packets received */
+ U_LONG newversionpkt; /* new version packets received */
+ U_LONG unknownversion; /* don't know version packets */
+ U_LONG badlength; /* packets with bad length */
+ U_LONG processed; /* packets processed */
+ U_LONG badauth; /* packets dropped because of authorization */
+ U_LONG wanderhold;
+};
+
+
+/*
+ * Peer memory statistics. Collected in the peer module.
+ */
+struct info_mem_stats {
+ U_LONG timereset; /* time since reset */
+ u_short totalpeermem;
+ u_short freepeermem;
+ U_LONG findpeer_calls;
+ U_LONG allocations;
+ U_LONG demobilizations;
+ u_char hashcount[HASH_SIZE];
+};
+
+
+/*
+ * I/O statistics. Collected in the I/O module
+ */
+struct info_io_stats {
+ U_LONG timereset; /* time since reset */
+ u_short totalrecvbufs; /* total receive bufs */
+ u_short freerecvbufs; /* free buffers */
+ u_short fullrecvbufs; /* full buffers */
+ u_short lowwater; /* number of times we've added buffers */
+ U_LONG dropped; /* dropped packets */
+ U_LONG ignored; /* ignored packets */
+ U_LONG received; /* received packets */
+ U_LONG sent; /* packets sent */
+ U_LONG notsent; /* packets not sent */
+ U_LONG interrupts; /* interrupts we've handled */
+ U_LONG int_received; /* received by interrupt handler */
+};
+
+
+/*
+ * Timer stats. Guess where from.
+ */
+struct info_timer_stats {
+ U_LONG timereset; /* time since reset */
+ U_LONG alarms; /* alarms we've handled */
+ U_LONG overflows; /* timer overflows */
+ U_LONG xmtcalls; /* calls to xmit */
+};
+
+
+/*
+ * Structure for passing peer configuration information
+ */
+struct conf_peer {
+ U_LONG peeraddr; /* address to poll */
+ u_char hmode; /* mode, either broadcast, active or client */
+ u_char version; /* version number to poll with */
+ u_char minpoll; /* min host poll interval */
+ u_char maxpoll; /* max host poll interval */
+ u_char flags; /* flags for this request */
+ u_char unused;
+ U_LONG keyid; /* key to use for this association */
+};
+
+#define CONF_FLAG_AUTHENABLE 0x1
+#define CONF_FLAG_MINPOLL 0x2
+#define CONF_FLAG_PREFER 0x4
+
+/*
+ * Structure for passing peer deletion information. Currently
+ * we only pass the address and delete all configured peers with
+ * this addess.
+ */
+struct conf_unpeer {
+ U_LONG peeraddr; /* address of peer */
+};
+
+
+/*
+ * Structure for carrying system flags.
+ */
+struct conf_sys_flags {
+ U_LONG flags;
+};
+
+/*
+ * System flags we can set/clear
+ */
+#define SYS_FLAG_BCLIENT 0x1
+#define SYS_FLAG_AUTHENTICATE 0x2
+
+/*
+ * Structure used for returning restrict entries
+ */
+struct info_restrict {
+ U_LONG addr; /* match address */
+ U_LONG mask; /* match mask */
+ U_LONG count; /* number of packets matched */
+ u_short flags; /* restrict flags */
+ u_short mflags; /* match flags */
+};
+
+
+/*
+ * Structure used for specifying restrict entries
+ */
+struct conf_restrict {
+ U_LONG addr; /* match address */
+ U_LONG mask; /* match mask */
+ u_short flags; /* restrict flags */
+ u_short mflags; /* match flags */
+};
+
+
+/*
+ * Structure used for returning monitor data
+ */
+struct info_monitor {
+ U_LONG lasttime; /* last packet from this host */
+ U_LONG firsttime; /* first time we received a packet */
+ U_LONG count; /* count of packets received */
+ U_LONG addr; /* host address */
+ u_short port; /* port number of last reception */
+ u_char mode; /* mode of last packet */
+ u_char version; /* version number of last packet */
+};
+
+
+/*
+ * Structure used for passing indication of flags to clear
+ */
+struct reset_flags {
+ U_LONG flags;
+};
+
+#define RESET_FLAG_ALLPEERS 0x01
+#define RESET_FLAG_IO 0x02
+#define RESET_FLAG_SYS 0x04
+#define RESET_FLAG_MEM 0x08
+#define RESET_FLAG_TIMER 0x10
+#define RESET_FLAG_AUTH 0x20
+#define RESET_FLAG_CTL 0x40
+
+#define RESET_ALLFLAGS \
+ (RESET_FLAG_ALLPEERS|RESET_FLAG_IO|RESET_FLAG_SYS \
+ |RESET_FLAG_MEM|RESET_FLAG_TIMER|RESET_FLAG_AUTH|RESET_FLAG_CTL)
+
+/*
+ * Structure used to return information concerning the authentication
+ * module.
+ */
+struct info_auth {
+ U_LONG timereset; /* time counters were reset */
+ U_LONG numkeys; /* number of keys we know */
+ U_LONG numfreekeys; /* number of free keys */
+ U_LONG keylookups; /* calls to authhavekey() */
+ U_LONG keynotfound; /* requested key unknown */
+ U_LONG encryptions; /* number of encryptions */
+ U_LONG decryptions; /* number of decryptions */
+ U_LONG decryptok; /* number of successful decryptions */
+ U_LONG keyuncached; /* calls to encrypt/decrypt with uncached key */
+};
+
+
+/*
+ * Structure used to pass trap information to the client
+ */
+struct info_trap {
+ U_LONG local_address; /* local interface address */
+ U_LONG trap_address; /* remote client's address */
+ u_short trap_port; /* remote port number */
+ u_short sequence; /* sequence number */
+ U_LONG settime; /* time trap last set */
+ U_LONG origtime; /* time trap originally set */
+ U_LONG resets; /* number of resets on this trap */
+ U_LONG flags; /* trap flags, as defined in ntp_control.h */
+};
+
+/*
+ * Structure used to pass add/clear trap information to the client
+ */
+struct conf_trap {
+ U_LONG local_address; /* local interface address */
+ U_LONG trap_address; /* remote client's address */
+ u_short trap_port; /* remote client's port */
+ u_short unused;
+};
+
+
+/*
+ * Structure used to return statistics from the control module
+ */
+struct info_control {
+ U_LONG ctltimereset;
+ U_LONG numctlreq; /* number of requests we've received */
+ U_LONG numctlbadpkts; /* number of bad control packets */
+ U_LONG numctlresponses; /* # resp packets sent */
+ U_LONG numctlfrags; /* # of fragments sent */
+ U_LONG numctlerrors; /* number of error responses sent */
+ U_LONG numctltooshort; /* number of too short input packets */
+ U_LONG numctlinputresp; /* number of responses on input */
+ U_LONG numctlinputfrag; /* number of fragments on input */
+ U_LONG numctlinputerr; /* # input pkts with err bit set */
+ U_LONG numctlbadoffset; /* # input pkts with nonzero offset */
+ U_LONG numctlbadversion; /* # input pkts with unknown version */
+ U_LONG numctldatatooshort; /* data too short for count */
+ U_LONG numctlbadop; /* bad op code found in packet */
+ U_LONG numasyncmsgs; /* # async messages we've sent */
+};
+
+
+/*
+ * Structure used to return leap information.
+ */
+struct info_leap {
+ u_char sys_leap; /* current sys_leap */
+ u_char leap_indicator; /* current leap indicator */
+ u_char leap_warning; /* current leap warning */
+ u_char leap_bits; /* leap flags */
+ U_LONG leap_timer; /* seconds to next interrupt */
+ U_LONG leap_processcalls; /* calls to the leap process */
+ U_LONG leap_notclose; /* found leap was not close */
+ U_LONG leap_monthofleap; /* in month of leap */
+ U_LONG leap_dayofleap; /* in day of leap */
+ U_LONG leap_hoursfromleap; /* leap within two hours */
+ U_LONG leap_happened; /* leap second happened */
+};
+
+#define INFO_LEAP_MASK 0x3 /* flag for leap_bits */
+#define INFO_LEAP_SEENSTRATUM1 0x4 /* server has seen stratum 1 */
+#define INFO_LEAP_OVERRIDE 0x8 /* server will override the leap information */
+
+/*
+ * Structure used to return clock information
+ */
+struct info_clock {
+ U_LONG clockadr;
+ u_char type;
+ u_char flags;
+ u_char lastevent;
+ u_char currentstatus;
+ U_LONG polls;
+ U_LONG noresponse;
+ U_LONG badformat;
+ U_LONG baddata;
+ U_LONG timestarted;
+ l_fp fudgetime1;
+ l_fp fudgetime2;
+ LONG fudgeval1;
+ LONG fudgeval2;
+};
+
+
+/*
+ * Structure used for setting clock fudge factors
+ */
+struct conf_fudge {
+ U_LONG clockadr;
+ U_LONG which;
+ l_fp fudgetime;
+ LONG fudgeval_flags;
+};
+
+#define FUDGE_TIME1 1
+#define FUDGE_TIME2 2
+#define FUDGE_VAL1 3
+#define FUDGE_VAL2 4
+#define FUDGE_FLAGS 5
+
+
+/*
+ * Structure used for returning clock debugging info
+ */
+#define NUMCBUGVALUES 16
+#define NUMCBUGTIMES 32
+
+struct info_clkbug {
+ U_LONG clockadr;
+ u_char nvalues;
+ u_char ntimes;
+ u_short svalues;
+ U_LONG stimes;
+ U_LONG values[NUMCBUGVALUES];
+ l_fp times[NUMCBUGTIMES];
+};
diff --git a/contrib/xntpd/include/ntp_select.h b/contrib/xntpd/include/ntp_select.h
new file mode 100644
index 000000000000..e3ce0e7e41bb
--- /dev/null
+++ b/contrib/xntpd/include/ntp_select.h
@@ -0,0 +1,20 @@
+/*
+ * Not all machines define FD_SET in sys/types.h
+ */
+#ifndef _ntp_select_h
+#define _ntp_select_h
+
+#if (defined(RS6000)||defined(SYS_PTX))&&!defined(_BSD)
+#include <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) memset((char *)(p), 0, sizeof(*(p)))
+#endif
+
+#endif /* _ntp_select_h */
diff --git a/contrib/xntpd/include/ntp_stdlib.h b/contrib/xntpd/include/ntp_stdlib.h
new file mode 100644
index 000000000000..0ec062581616
--- /dev/null
+++ b/contrib/xntpd/include/ntp_stdlib.h
@@ -0,0 +1,92 @@
+/* ntp_stdlib.h,v 3.1 1993/07/06 01:06:58 jbj Exp
+ * ntp_stdlib.h - Prototypes for XNTP lib.
+ */
+#include <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 ntp_getopt P((int, char **, char *));
+extern void init_auth P((void));
+extern void init_lib P((void));
+extern void init_random P((void));
+
+#ifdef DES
+extern void DESauth1crypt P((U_LONG, U_LONG *, int));
+extern int DESauth2crypt P((U_LONG, U_LONG *, int));
+extern int DESauthdecrypt P((U_LONG, const U_LONG *, int));
+extern int DESauthencrypt P((U_LONG, U_LONG *, int));
+extern void DESauth_setkey P((U_LONG, const U_LONG *));
+extern void DESauth_subkeys P((const U_LONG *, u_char *, u_char *));
+extern void DESauth_des P((U_LONG *, u_char *));
+extern int DESauth_parity P((U_LONG *));
+#endif /* DES */
+
+#ifdef MD5
+extern void MD5auth1crypt P((U_LONG, U_LONG *, int));
+extern int MD5auth2crypt P((U_LONG, U_LONG *, int));
+extern int MD5authdecrypt P((U_LONG, const U_LONG *, int));
+extern int MD5authencrypt P((U_LONG, U_LONG *, int));
+extern void MD5auth_setkey P((U_LONG, const U_LONG *));
+#endif /* MD5 */
+
+extern int atoint P((const char *, LONG *));
+extern int atouint P((const char *, U_LONG *));
+extern int hextoint P((const char *, U_LONG *));
+extern char * humandate P((U_LONG));
+extern char * inttoa P((LONG));
+extern char * mfptoa P((U_LONG, U_LONG, int));
+extern char * mfptoms P((U_LONG, U_LONG, int));
+extern char * modetoa P((int));
+extern char * numtoa P((U_LONG));
+extern char * numtohost P((U_LONG));
+extern int octtoint P((const char *, U_LONG *));
+extern U_LONG ranp2 P((int));
+extern char * refnumtoa P((U_LONG));
+extern int tsftomsu P((U_LONG, int));
+extern char * uinttoa P((U_LONG));
+
+extern int decodenetnum P((const char *, U_LONG *));
+
+extern RETSIGTYPE signal_no_reset P((int, RETSIGTYPE (*func)()));
diff --git a/contrib/xntpd/include/ntp_string.h b/contrib/xntpd/include/ntp_string.h
new file mode 100644
index 000000000000..cc2eec858069
--- /dev/null
+++ b/contrib/xntpd/include/ntp_string.h
@@ -0,0 +1,35 @@
+/*
+ * Define string ops: strchr strrchr memcmp memmove memset
+ */
+
+#ifndef _ntp_string_h
+#define _ntp_string_h
+
+#if defined(NTP_POSIX_SOURCE)
+
+# if defined(HAVE_MEMORY_H)
+# include <memory.h>
+# endif
+
+# include <string.h>
+
+#else
+
+# include <strings.h>
+# define strchr(s,c) index(s,c)
+# define strrchr(s,c) rindex(s,c)
+# ifndef NTP_NEED_BOPS
+# define NTP_NEED_BOPS
+# endif
+#endif /* NTP_POSIX_SOURCE */
+
+#ifdef NTP_NEED_BOPS
+
+# define memcmp(a,b,c) bcmp(a,b,c)
+# define memmove(t,f,c) bcopy(f,t,c)
+# define memset(a,x,c) if (x == 0x00) bzero(a,c); else ntp_memset((char*)a,x,c)
+void ntp_memset P((char *, int, int));
+
+#endif /* NTP_NEED_BOPS */
+
+#endif /* _ntp_string_h */
diff --git a/contrib/xntpd/include/ntp_syslog.h b/contrib/xntpd/include/ntp_syslog.h
new file mode 100644
index 000000000000..0d5dff8cc45a
--- /dev/null
+++ b/contrib/xntpd/include/ntp_syslog.h
@@ -0,0 +1,15 @@
+/* ntp_syslog.h,v 3.1 1993/07/06 01:06:59 jbj Exp
+ * A hack for platforms which require specially built syslog facilities
+ */
+#ifdef GIZMO
+#include "gizmo_syslog.h"
+#else /* !GIZMO */
+#include <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/contrib/xntpd/include/ntp_timex.h b/contrib/xntpd/include/ntp_timex.h
new file mode 100644
index 000000000000..1756e2e07f21
--- /dev/null
+++ b/contrib/xntpd/include/ntp_timex.h
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * *
+ * Copyright (c) David L. Mills 1993 *
+ * *
+ * Permission to use, copy, modify, and distribute this software and its *
+ * documentation for any purpose and without fee is hereby granted, provided *
+ * that the above copyright notice appears in all copies and that both the *
+ * copyright notice and this permission notice appear in supporting *
+ * documentation, and that the name University of Delaware not be used in *
+ * advertising or publicity pertaining to distribution of the software *
+ * without specific, written prior permission. The University of Delaware *
+ * makes no representations about the suitability this software for any *
+ * purpose. It is provided "as is" without express or implied warranty. *
+ * *
+ ******************************************************************************/
+
+/*
+ * Modification history timex.h
+ *
+ * 28 Nov 93 David L. Mills
+ * Adjusted parameters to improve stability and increase poll interval
+ *
+ * 10 Oct 93 Torsten Duwe
+ * Changed to ntp_timex.h (#ifdef'd HAVE_SYS_TIMEX_H)
+ *
+ * 17 Sep 93 David L. Mills
+ * Created file
+ */
+/*
+ * This header file defines the Network Time Protocol (NTP) interfaces
+ * for user and daemon application programs. These are implemented using
+ * private syscalls and data structures and require specific kernel
+ * support.
+ *
+ * NAME
+ * ntp_gettime - NTP user application interface
+ *
+ * SYNOPSIS
+ * #include <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/contrib/xntpd/include/ntp_types.h b/contrib/xntpd/include/ntp_types.h
new file mode 100644
index 000000000000..7a2a3474bdf3
--- /dev/null
+++ b/contrib/xntpd/include/ntp_types.h
@@ -0,0 +1,60 @@
+/* ntp_types.h,v 3.1 1993/07/06 01:07:00 jbj Exp
+ * ntp_types.h - defines how LONG and U_LONG are treated. For 64 bit systems
+ * like the DEC Alpha, they has to be defined as int and u_int. for 32 bit
+ * systems, define them as long and u_long
+ */
+#include "ntp_machine.h"
+
+#ifndef _NTP_TYPES_
+#define _NTP_TYPES_
+
+/*
+ * This is another naming conflict.
+ * On NetBSD for MAC the macro "mac" is defined as 1
+ * this is fun for a as a paket structure contains an
+ * optional "mac" member - severe confusion results 8-)
+ * As we hopefully do not have to rely on that macro we
+ * just undefine that.
+ */
+#ifdef mac
+#undef mac
+#endif
+
+/*
+ * Set up for prototyping
+ */
+#ifndef P
+#if defined(__STDC__) || defined(USE_PROTOTYPES)
+#define P(x) x
+#else /* __STDC__ USE_PROTOTYPES */
+#define P(x) ()
+#if !defined(const)
+#define const
+#endif /* const */
+#endif /* __STDC__ USE_PROTOTYPES */
+#endif /* P */
+
+/*
+ * DEC Alpha systems need LONG and U_LONG defined as int and u_int
+ */
+#ifdef __alpha
+#ifndef LONG
+#define LONG int
+#endif /* LONG */
+#ifndef U_LONG
+#define U_LONG u_int
+#endif /* U_LONG */
+/*
+ * All other systems fall into this part
+ */
+#else /* __alpha */
+#ifndef LONG
+#define LONG long
+#endif /* LONG */
+#ifndef U_LONG
+#define U_LONG u_long
+#endif /* U_LONG */
+#endif /* __ alplha */
+
+#endif /* _NTP_TYPES_ */
+
diff --git a/contrib/xntpd/include/ntp_unixtime.h b/contrib/xntpd/include/ntp_unixtime.h
new file mode 100644
index 000000000000..c1ab573f4d4c
--- /dev/null
+++ b/contrib/xntpd/include/ntp_unixtime.h
@@ -0,0 +1,119 @@
+/* ntp_unixtime.h,v 3.1 1993/07/06 01:07:02 jbj Exp
+ * ntp_unixtime.h - contains constants and macros for converting between
+ * NTP time stamps (l_fp) and Unix times (struct timeval)
+ */
+
+#include "ntp_types.h"
+#include <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/contrib/xntpd/include/ntpd.h b/contrib/xntpd/include/ntpd.h
new file mode 100644
index 000000000000..f2c56af20b90
--- /dev/null
+++ b/contrib/xntpd/include/ntpd.h
@@ -0,0 +1,171 @@
+/*
+ * 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_control.c */
+/*
+ * 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 0x01
+#define CAN_WRITE 0x02
+
+#define DEF 0x20
+#define PADDING 0x40
+#define EOV 0x80
+
+#define RO (CAN_READ)
+#define WO (CAN_WRITE)
+#define RW (CAN_READ|CAN_WRITE)
+
+extern char * add_var P((struct ctl_var **, unsigned long, int));
+extern void free_varlist P((struct ctl_var *));
+extern void set_var P((struct ctl_var **, char *, unsigned long, int));
+extern void set_sys_var P((char *, unsigned long, int));
+
+/* ntp_intres.c */
+extern void ntp_intres P((void));
+
+/* ntp_io.c */
+extern struct interface *findbcastinter P((struct sockaddr_in *));
+extern struct interface *findinterface P((struct sockaddr_in *));
+extern void freerecvbuf P((struct recvbuf *));
+extern struct recvbuf *getrecvbufs P((void));
+extern void init_io P((void));
+extern void input_handler P((l_fp *));
+extern void io_clr_stats P((void));
+extern void io_setbclient P((void));
+extern void io_unsetbclient P((void));
+extern void sendpkt P((struct sockaddr_in *, struct interface *, struct pkt *, int));
+#ifdef HAVE_SIGNALED_IO
+extern void wait_for_signal P((void));
+extern void unblock_io_and_alarm P((void));
+extern void block_io_and_alarm P((void));
+#endif
+
+/* ntp_leap.c */
+extern void init_leap P((void));
+extern void leap_process P((void));
+extern int leap_setleap P((int, int));
+/*
+ * there seems to be a bug in the IRIX 4 compiler which prevents
+ * u_char from beeing used in prototyped functions.
+ * This is also true AIX compiler.
+ * So give up and define it to be int. WLJ
+ */
+extern int leap_actual P((int));
+
+/* ntp_loopfilter.c */
+extern void init_loopfilter P((void));
+extern int local_clock P((l_fp *, struct peer *));
+extern void adj_host_clock P((void));
+extern void loop_config P((int, l_fp *, int));
+#if defined(PPS) || defined(PPSPPS) || defined(PPSCD)
+extern int pps_sample P((l_fp *));
+#endif /* PPS || PPSDEV || PPSCD */
+
+/* ntp_monitor.c */
+extern void init_mon P((void));
+extern void mon_start P((void));
+extern void mon_stop P((void));
+extern void monitor P((struct recvbuf *));
+
+/* ntp_peer.c */
+extern void init_peer P((void));
+extern struct peer *findexistingpeer P((struct sockaddr_in *, struct peer *));
+extern struct peer *findpeer P((struct sockaddr_in *, struct interface *));
+extern struct peer *findpeerbyassoc P((int));
+extern struct peer *newpeer P((struct sockaddr_in *, struct interface *, int, int, int, int, U_LONG));
+extern void peer_all_reset P((void));
+extern void peer_clr_stats P((void));
+extern struct peer *peer_config P((struct sockaddr_in *, struct interface *, int, int, int, int, U_LONG, int));
+extern void peer_reset P((struct peer *));
+extern int peer_unconfig P((struct sockaddr_in *, struct interface *));
+extern void unpeer P((struct peer *));
+
+/* ntp_proto.c */
+extern void transmit P((struct peer *));
+extern void receive P((struct recvbuf *));
+extern void peer_clear P((struct peer *));
+extern int process_packet P((struct peer *, struct pkt *, l_fp *, int, int));
+extern void clock_update P((struct peer *));
+
+/*
+ * there seems to be a bug in the IRIX 4 compiler which prevents
+ * u_char from beeing used in prototyped functions.
+ * This is also true AIX compiler.
+ * So give up and define it to be int. WLJ
+ */
+extern void poll_update P((struct peer *, unsigned int, int));
+
+extern void clear P((struct peer *));
+extern void clock_filter P((struct peer *, l_fp *, s_fp, u_fp));
+extern void clock_select P((void));
+extern void clock_combine P((struct peer **, int));
+extern void fast_xmit P((struct recvbuf *, int, int));
+extern void init_proto P((void));
+extern void proto_config P((int, LONG));
+extern void proto_clr_stats P((void));
+
+#ifdef REFCLOCK
+/* ntp_refclock.c */
+extern int refclock_newpeer P((struct peer *));
+extern void refclock_unpeer P((struct peer *));
+extern void refclock_receive P((struct peer *, l_fp *, s_fp, u_fp, l_fp *, l_fp *, int));
+extern void refclock_leap P((void));
+extern void init_refclock P((void));
+#endif /* REFCLOCK */
+
+/* ntp_request.c */
+extern void init_request P((void));
+extern void process_private P((struct recvbuf *, int));
+
+/* ntp_restrict.c */
+extern void init_restrict P((void));
+extern int restrictions P((struct sockaddr_in *));
+extern void restrict P((int, struct sockaddr_in *, struct sockaddr_in *, int, int));
+
+/* ntp_timer.c */
+extern void init_timer P((void));
+extern void timer P((void));
+extern void timer_clr_stats P((void));
+
+/* ntp_unixclock.c */
+extern void init_systime P((void));
+
+/* ntp_util.c */
+extern void init_util P((void));
+extern void hourly_stats P((void));
+extern void stats_config P((int, char *));
+extern void record_peer_stats P((struct sockaddr_in *, int, l_fp *, s_fp, u_fp));
+extern void record_loop_stats P((l_fp *, s_fp *, int));
+extern void record_clock_stats P((struct sockaddr_in *, char *));
+extern void getauthkeys P((char *));
+extern void rereadkeys P((void));
diff --git a/contrib/xntpd/include/parse.h b/contrib/xntpd/include/parse.h
new file mode 100644
index 000000000000..31041afe292f
--- /dev/null
+++ b/contrib/xntpd/include/parse.h
@@ -0,0 +1,407 @@
+/*
+ * /src/NTP/REPOSITORY/v3/include/parse.h,v 3.13 1994/01/25 19:04:21 kardel Exp
+ *
+ * parse.h,v 3.13 1994/01/25 19:04:21 kardel Exp
+ *
+ * Copyright (c) 1989,1990,1991,1992,1993,1994
+ * 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.13 1994/01/25 19:04:21 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.13 1994/01/25 19:04:21 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.12 1994/01/23 17:23:05 kardel
+ * 1994 reconcilation
+ *
+ * Revision 3.11 1993/11/11 11:20:18 kardel
+ * declaration fixes
+ *
+ * Revision 3.10 1993/11/01 19:59:48 kardel
+ * parse Solaris support (initial version)
+ *
+ * Revision 3.9 1993/10/06 00:14:57 kardel
+ * include fixes
+ *
+ * Revision 3.8 1993/10/05 23:15:41 kardel
+ * more STREAM protection
+ *
+ * Revision 3.7 1993/10/05 22:56:10 kardel
+ * STREAM must be defined for PARSESTREAMS
+ *
+ * Revision 3.6 1993/10/03 19:10:28 kardel
+ * restructured I/O handling
+ *
+ * Revision 3.5 1993/09/26 23:41:13 kardel
+ * new parse driver logic
+ *
+ * Revision 3.4 1993/09/01 21:46:31 kardel
+ * conditional cleanup
+ *
+ * Revision 3.3 1993/08/27 00:29:29 kardel
+ * compilation cleanup
+ *
+ * Revision 3.2 1993/07/09 11:37:05 kardel
+ * Initial restructured version + GPS support
+ *
+ * Revision 3.1 1993/07/06 09:59:12 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/contrib/xntpd/include/parse_conf.h b/contrib/xntpd/include/parse_conf.h
new file mode 100644
index 000000000000..13cec551db34
--- /dev/null
+++ b/contrib/xntpd/include/parse_conf.h
@@ -0,0 +1,54 @@
+/*
+ * /src/NTP/REPOSITORY/v3/include/parse_conf.h,v 3.5 1994/01/25 19:04:23 kardel Exp
+ *
+ * parse_conf.h,v 3.5 1994/01/25 19:04:23 kardel Exp
+ *
+ * Copyright (c) 1993,1994
+ * 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.5 1994/01/25 19:04:23 kardel Exp FAU";
+#endif
+
+/*
+ * field location structure (Meinberg clocks/simple format)
+ */
+#define O_DAY 0
+#define O_MONTH 1
+#define O_YEAR 2
+#define O_HOUR 3
+#define O_MIN 4
+#define O_SEC 5
+#define O_WDAY 6
+#define O_FLAGS 7
+#define O_ZONE 8
+#define O_UTCHOFFSET 9
+#define O_UTCMOFFSET 10
+#define O_UTCSOFFSET 11
+#define O_COUNT (O_UTCSOFFSET+1)
+
+#define MBG_EXTENDED 0x00000001
+
+/*
+ * see below for field offsets
+ */
+
+struct format
+{
+ struct foff
+ {
+ char offset; /* offset into buffer */
+ char length; /* length of field */
+ } field_offsets[O_COUNT];
+ char *fixed_string; /* string with must be chars (blanks = wildcards) */
+ unsigned LONG flags;
+};
+#endif
diff --git a/contrib/xntpd/include/sys/bsd_audioirig.h b/contrib/xntpd/include/sys/bsd_audioirig.h
new file mode 100644
index 000000000000..1daeec700b42
--- /dev/null
+++ b/contrib/xntpd/include/sys/bsd_audioirig.h
@@ -0,0 +1,101 @@
+/*
+ * $Header: bsd_audioirig.h,v 1.0 93/08/02 12:42:00
+ */
+
+#ifndef _BSD_AUDIOIRIG_H_
+#define _BSD_AUDIOIRIG_H_
+
+#include <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/contrib/xntpd/include/sys/chudefs.h b/contrib/xntpd/include/sys/chudefs.h
new file mode 100644
index 000000000000..50f82527f468
--- /dev/null
+++ b/contrib/xntpd/include/sys/chudefs.h
@@ -0,0 +1,22 @@
+/* chudefs.h,v 3.1 1993/07/06 01:07:11 jbj Exp
+ * Definitions for the CHU line discipline v2.0
+ */
+
+/*
+ * The CHU time code consists of 10 BCD digits and is repeated
+ * twice for a total of 10 characters. A time is taken after
+ * the arrival of each character. The following structure is
+ * used to return this stuff.
+ */
+#define NCHUCHARS (10)
+
+struct chucode {
+ u_char codechars[NCHUCHARS]; /* code characters */
+ u_char ncodechars; /* number of code characters */
+ u_char chutype; /* packet type */
+ struct timeval codetimes[NCHUCHARS]; /* arrival times */
+};
+
+#define CHU_TIME 0 /* second half is equal to first half */
+#define CHU_YEAR 1 /* second half is one's complement */
+
diff --git a/contrib/xntpd/include/sys/clkdefs.h b/contrib/xntpd/include/sys/clkdefs.h
new file mode 100644
index 000000000000..b2596e110514
--- /dev/null
+++ b/contrib/xntpd/include/sys/clkdefs.h
@@ -0,0 +1,31 @@
+/* clkdefs.h,v 3.1 1993/07/06 01:07:12 jbj Exp
+ * Defines for the "clk" timestamping STREAMS module
+ */
+
+#include <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/contrib/xntpd/include/sys/parsestreams.h b/contrib/xntpd/include/sys/parsestreams.h
new file mode 100644
index 000000000000..d07e75cbf26f
--- /dev/null
+++ b/contrib/xntpd/include/sys/parsestreams.h
@@ -0,0 +1,66 @@
+/*
+ * /src/NTP/REPOSITORY/v3/include/sys/parsestreams.h,v 3.11 1994/01/25 19:04:30 kardel Exp
+ *
+ * parsestreams.h,v 3.11 1994/01/25 19:04:30 kardel Exp
+ *
+ * Copyright (c) 1989,1990,1991,1992,1993,1994
+ * 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.11 1994/01/25 19:04:30 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/contrib/xntpd/include/sys/ppsclock.h b/contrib/xntpd/include/sys/ppsclock.h
new file mode 100644
index 000000000000..952a57bff1e1
--- /dev/null
+++ b/contrib/xntpd/include/sys/ppsclock.h
@@ -0,0 +1,59 @@
+/* ppsclock.h,v 3.1 1993/07/06 01:07:14 jbj Exp */
+/*
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66.
+ *
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ * 4. The name of the University may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define PPSCLOCKSTR "ppsclock"
+
+struct ppsclockev {
+ struct timeval tv;
+ u_int serial;
+};
+
+#if defined(__STDC__) || defined(SYS_HPUX)
+#ifdef _IOR
+#define CIOGETEV _IOR('C', 0, struct ppsclockev) /* get last pps event */
+#else /* XXX SOLARIS is different */
+#define CIO ('C'<<8)
+#define CIOGETEV (CIO|0) /* get last pps event */
+#endif /* _IOR */
+#else /* __STDC__ */
+#ifdef _IOR
+#define CIOGETEV _IOR(C, 0, struct ppsclockev) /* get last pps event */
+#else /* XXX SOLARIS is different */
+#define CIO ('C'<<8)
+#define CIOGETEV (CIO|0) /* get last pps event */
+#endif /* _IOR */
+#endif /* __STDC__ */
diff --git a/contrib/xntpd/include/sys/tpro.h b/contrib/xntpd/include/sys/tpro.h
new file mode 100644
index 000000000000..1cdaf9c8e610
--- /dev/null
+++ b/contrib/xntpd/include/sys/tpro.h
@@ -0,0 +1,34 @@
+/* tpro.h,v 3.1 1993/07/06 01:07:07 jbj Exp
+ * Structure for the KSI/Odetics TPRO-S data returned in reponse to a
+ * read() call. Note that these are driver-specific and not dependent on
+ * 32/64-bit architecture.
+ */
+struct tproval {
+ u_short day100; /* days * 100 */
+ u_short day10; /* days * 10 */
+ u_short day1; /* days * 1 */
+ u_short hour10; /* hours * 10 */
+ u_short hour1; /* hours * 1 */
+ u_short min10; /* minutes * 10 */
+ u_short min1; /* minutes * 1 */
+ u_short sec10; /* seconds * 10 */
+ u_short sec1; /* seconds * 1*/
+ u_short ms100; /* milliseconds * 100 */
+ u_short ms10; /* milliseconds * 10 */
+ u_short ms1; /* milliseconds * 1 */
+ u_short usec100; /* microseconds * 100 */
+ u_short usec10; /* microseconds * 10 */
+ u_short usec1; /* microseconds * 1 */
+ long tv_sec; /* seconds */
+ long tv_usec; /* microseconds */
+ u_short status; /* status register */
+};
+
+/*
+ * Status register bits
+ */
+#define TIMEAVAIL 0x0001 /* time available */
+#define NOSIGNAL 0x0002 /* insufficient IRIG-B signal */
+#define NOSYNC 0x0004 /* local oscillator not synchronized */
+
+/* end of tpro.h */
diff --git a/contrib/xntpd/kernel/.keep_me b/contrib/xntpd/kernel/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/kernel/.keep_me
diff --git a/contrib/xntpd/kernel/README.kern b/contrib/xntpd/kernel/README.kern
new file mode 100644
index 000000000000..64ba9c5bf379
--- /dev/null
+++ b/contrib/xntpd/kernel/README.kern
@@ -0,0 +1,596 @@
+Precision Time and Frequency Synchronization Using Modified Kernels
+
+1. Introduction
+
+This memo describes replacements for certain SunOS and Ultrix kernel
+routines that manage the system clock and timer functions. They provide
+improved accuracy and stability through the use of a disciplined clock
+interface for use with the Network Time Protocol (NTP) or similar time-
+synchronization protocol. In addition, for certain models of the
+DECstation 5000 product line, the new routines provide improved
+precision to +-1 microsecond (us) (SunOS 4.1.1 already does provide
+precision to +-1 us). The current public NTP distribution cooperates
+with these kernel routines to provide synchronization in principle to
+within a microsecond, but in practice this is limited by the short-term
+stability of the oscillator that drives the timer interrupt.
+
+This memo describes the principles behind the design and operation of
+the software. There are two versions of the software, one that operates
+with the SunOS 4.1.1 kernel and the other that operates with the Ultrix
+4.2a kernel (and probably the 4.3 kernel, although this has not been
+tested). A detailed description of the variables and algorithms is given
+in the hope that similar improvements can be incorporated in Unix
+kernels for other machines. The software itself is not included in this
+memo, since it involves licensed code. Detailed instructions on where to
+obtain it for either SunOS or Ultrix will be given separately.
+
+The principle function added to the SunOS and Ultrix kernels is to
+change the way the system clock is controlled, in order to provide
+precision time and frequency adjustments. Another function utilizes an
+undocumented counter in the DECstation hardware to provide precise time
+to the microsecond. This function can be used only with the DECstation
+5000/240 and possibly others that use the same input/output chipset.
+
+2. Design Principles
+
+In order to understand how these routines work, it is useful to consider
+how most Unix systems maintain the system clock. In the original design
+a hardware timer interrupts the kernel at some fixed rate, such as 100
+Hz in the SunOS kernel and 256 Hz in the Ultrix kernel. Since 256 does
+not evenly divide the second in microseconds, the kernel inserts 64 us
+once each second so that the system clock stays in step with real time.
+The time returned by the gettimeofday() routine is thus characterized by
+255 advances of 3906 us plus one of 3970 us.
+
+Also in the original design it is possible to slew the system clock to a
+new offset using the adjtime() system call. To do this the clock
+frequency is changed by adding or subtracting a fixed amount (tickadj)
+at each timer interrupt (tick) for a calculated number of ticks. Since
+this calculation involves dividing the requested offset by tickadj, it
+is possible to slew to a new offset with a precision only of tickadj,
+which is usually in the neighborhood of 5 us, but sometimes much higher.
+
+In order to maintain the system clock within specified bounds with this
+scheme, it is necessary to call adjtime() on a regular basis. For
+instance, let the bound be set at 100 us, which is a reasonable value
+for NTP-synchronized hosts on a local network, and let the onboard
+oscillator tolerance be 100 ppm, which is a reasonably conservative
+assumption. This requires that adjtime() be called at intervals not
+exceeding 1 second (s), which is in fact what the unmodified NTP
+software daemon does.
+
+In the modified kernel routines this scheme is replaced by another that
+extends the low-order bits of the system clock to provide very precise
+clock adjustments. At each timer interrupt a precisely calibrated time
+adjustment is added to the composite time value and overflows handled as
+required. The quantity to add is computed from the adjtime() call and,
+in addition a frequency adjustment, which is automatically calculated
+from previous time adjustments. This implementation operates as an
+adaptive-parameter, first-order, type-II, phase-lock loop (PLL), which
+in principle provides precision control of the system clock phase to
+within +-1 us and frequency to within +-5 nanoseconds (ns) per day.
+
+This PLL model is identical to the one implemented in NTP, except that
+in NTP the software daemon has to simulate the PLL using only the
+original adjtime() system call. The daemon is considerably complicated
+by the need to parcel time adjustments at frequent intervals in order to
+maintain the accuracy to specified bounds. The kernel routines do this
+directly, allowing vast gobs of ugly daemon code to be avoided at the
+expense of only a small amount of new code in the kernel. In fact, the
+amount of code added to the kernel for the new scheme is about the
+amount removed for the old scheme. The new adjtime() routine needs to be
+called only as each new time update is determined, which in NTP occurs
+at intervals of from 64 s to 1024 s. In addition, doing the frequency
+correction in the kernel means that the system time runs true even if
+the daemon were to cease operation or the network paths to the primary
+reference source fail.
+
+Note that the degree to which the adjtime() adjustment can be made is
+limited to a specific maximum value, presently +-128 milliseconds (ms),
+in order to achieve microsecond resolution. It is the intent in the
+design that settimeofday() be used for changes in system time greater
+than +-128 ms. It has been the Internet experience that the need to
+change the system time in increments greater than +-128 milliseconds is
+extremely rare and is usually associated with a hardware or software
+malfunction. Nevertheless, the limit applies to each adjtime() call and
+it is possible, but not recommended, that this routine is called at
+intervals smaller than 64 seconds, which is the NTP lower limit.
+
+For the most accurate and stable operation, adjtime() should be called
+at specified intervals; however, the PLL is quite forgiving and neither
+moderate loss of updates nor variations in the length of the interval is
+serious. The current engineering parameters have been optimized for
+intervals not greater than about 64 s. For larger intervals the PLL time
+constant can be adjusted to optimize the dynamic response up to
+intervals of 1024 s. Normally, this is automatically done by NTP. In any
+case, if updates are suspended, the PLL coasts at the frequency last
+determinated, which usually results in errors increasing only to a few
+tens of milliseconds over a day.
+
+The new code needs to know the initial frequency offset and time
+constant for the PLL, and the daemon needs to know the current frequency
+offset computed by the kernel for monitoring purposes. This is provided
+by a small change in the second argument of the kernel adjtime() calling
+sequence, which is documented later in this memo. Ordinarily, only the
+daemon will call the adjtime() routine, so the modified calling sequence
+is easily accommodated. Other than this change, the operation of
+adjtime() is transparent to the original.
+
+In the DECstation 5000/240 and possibly other models there happens to be
+an undocumented hardware register that counts system bus cycles at a
+rate of 25 MHz. The new kernel routines test for the CPU type and, in
+the case of the '240, use this register to interpolate system time
+between hardware timer interrupts. This results in a precision of +-1 us
+for all time values obtained via the gettimeofday() system call. This
+routine calls the kernel routine microtime(), which returns the actual
+interpolated value, but does not change the kernel time variable.
+Therefore, other kernel routines that access the kernel time variable
+directly and do not call either gettimeofday() or microtime() will
+continue their present behavior.
+
+The new kernel routines include provisions for error statistics (maximum
+error and estimated error), leap seconds and system clock status. These
+are intended to support applications that need such things; however,
+there are no applications other than the time-synchronization daemon
+itself that presently use them. At issue is the manner in which these
+data can be provided to application clients, such as new system calls
+and data interfaces. While a proposed interface is described later in
+this memo, it has not yet been implemented. This is an area for further
+study.
+
+While any time-synchronization daemon can in principle be modified to
+use the new code, the most likely will be users of the xntp3
+distribution of NTP. The code in the xntp3 distribution determines
+whether the new kernel code is in use and automatically reconfigures as
+required. When the new code is in use, the daemon reads the frequency
+offset from a file and provides it and the initial time constant via
+adjtime(). In subsequent calls to adjtime(), only the time adjustment
+and time constant are affected. The daemon reads the frequency from the
+kernel (returned as the second argument of adjtime()) at intervals of
+one hour and writes it to the file.
+
+3. Technical Description
+
+Following is a technical description of how the new scheme works in
+terms of the variables and algorithms involved. These components are
+discussed as a distinct entity and do not involve coding details
+specific to the Ultrix kernel. The algorithms involve only minor changes
+to the system clock and interval timer routines, but do not in
+themselves provide a conduit for application programs to learn the
+system clock status or statistics of the time-synchronization process.
+In a later section a number of new system calls are proposed to do this,
+along with an interface specification.
+
+The new scheme works like the companion simulator called kern.c and
+included in this directory. This stand-alone simulator includes code
+fragments identical to those in the modified kernel routines and
+operates in the same way. The system clock is implemented in the kernel
+using a set of variables and algorithms defined below and in the
+simulator. The algorithms are driven by explicit calls from the
+synchronization protocol as each time update is computed. The clock is
+read and set using the gettimeofday() and settimeofday() system calls,
+which operate in the same way as the originals, but return a status word
+describing the state of the system clock.
+
+Once the system clock has been set, the adjtime() system call is used to
+provide periodic updates including the time offset and possibly
+frequency offset and time constant. With NTP this occurs at intervals of
+from 64 s to 1024 s, deending on the time constant value. The kernel
+implements an adaptive-parameter, first-order, type-II, phase-lock loop
+(PLL) in order to integrate this offset into the phase and frequency of
+the system clock. The kernel keeps track of the time of the last update
+and adjusts the maximum error to grow by an amount equal to the
+oscillator frequency tolerance times the elapsed time since the last
+update.
+
+Occasionally, it is necessary to adjust the PLL parameters in response
+to environmental conditions, such as leap-second warning and oscillator
+stability observations. While the interface to do this has not yet been
+implemented, proposals to to that are included in a later section. A
+system call (setloop()) is used on such occasions to communicate these
+data. In addition, a system call (getloop())) is used to extract these
+data from the kernel for monitoring purposes.
+
+All programs utilize the system clock status variable time_status, which
+records whether the clock is synchronized, waiting for a leap second,
+etc. The value of this variable is returned by each system call. It can
+be set explicitly by the setloop() system call and implicitly by the
+settimeofday() system call and in the timer-interrupt routine. Values
+presently defined in the header file timex.h are as follows:
+
+int time_status = TIME_BAD; /* clock synchronization status */
+
+#define TIME_UNS 0 /* unspecified or unknown */
+#define TIME_OK 1 /* operation succeeded */
+#define TIME_INS 1 /* insert leap second at end of current day */
+#define TIME_DEL 2 /* delete leap second at end of current day */
+#define TIME_OOP 3 /* leap second in progress */
+#define TIME_BAD 4 /* system clock is not synchronized */
+#define TIME_ADR -1 /* operation failed: invalid address */
+#define TIME_VAL -2 /* operation failed: invalid argument */
+#define TIME_PRV -3 /* operation failed: priviledged operation */
+
+In case of a negative result code, the operation has failed; however,
+some variables may have been modified before the error was detected.
+Note that the new system calls never return a value of zero, so it is
+possible to determine whether the old routines or the new ones are in
+use. The syntax of the modified adjtime() is as follows:
+
+/*
+ * adjtime - adjuts system time
+ */
+#include <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/contrib/xntpd/lib/Makefile b/contrib/xntpd/lib/Makefile
new file mode 100644
index 000000000000..dcb4f091f82c
--- /dev/null
+++ b/contrib/xntpd/lib/Makefile
@@ -0,0 +1,30 @@
+#
+# $Id: Makefile,v 1.4 1993/12/22 11:32:23 rgrimes Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+SRCS= 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 \
+ 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 clocktypes.c \
+ md5.c a_md5encrypt.c a_md5decrypt.c \
+ a_md512crypt.c decodenetnum.c systime.c msyslog.c syssignal.c \
+ findconfig.c getopt.c
+
+NOMAN=
+NOPROFILE=
+LIB= ntp
+CLEANFILES+=authdes.c
+
+install:
+
+authdes.c: authdes.c.export
+ cp ${.CURDIR}/authdes.c.export authdes.c
+
+.include <bsd.lib.mk>
diff --git a/contrib/xntpd/lib/README b/contrib/xntpd/lib/README
new file mode 100644
index 000000000000..c2b65d94cd81
--- /dev/null
+++ b/contrib/xntpd/lib/README
@@ -0,0 +1,5 @@
+README file for directory ./lib of the NTP Version 3 distribution
+
+This directory contains the sources for the NTP library used by most
+programs in this distribution. See the README and RELNOTES files in the
+parent directory for directions on how to make this library.
diff --git a/contrib/xntpd/lib/a_md512crypt.c b/contrib/xntpd/lib/a_md512crypt.c
new file mode 100644
index 000000000000..6033dedcff44
--- /dev/null
+++ b/contrib/xntpd/lib/a_md512crypt.c
@@ -0,0 +1,87 @@
+/* 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);
+
+ memmove((char *) &pkt[NOCRYPT_LONGS + length/sizeof(U_LONG)],
+ (char *) ctx.digest,
+ BLOCK_OCTETS);
+ return (4 + BLOCK_OCTETS);
+}
diff --git a/contrib/xntpd/lib/a_md5decrypt.c b/contrib/xntpd/lib/a_md5decrypt.c
new file mode 100644
index 000000000000..dc7acf6e44bb
--- /dev/null
+++ b/contrib/xntpd/lib/a_md5decrypt.c
@@ -0,0 +1,60 @@
+/* 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 (!memcmp((char *)ctx.digest,
+ (char *)pkt + length + 4,
+ BLOCK_OCTETS));
+}
diff --git a/contrib/xntpd/lib/a_md5encrypt.c b/contrib/xntpd/lib/a_md5encrypt.c
new file mode 100644
index 000000000000..2ae625810339
--- /dev/null
+++ b/contrib/xntpd/lib/a_md5encrypt.c
@@ -0,0 +1,70 @@
+/* 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);
+
+ memmove((char *)&pkt[NOCRYPT_LONGS + len],
+ (char *)ctx.digest,
+ BLOCK_OCTETS);
+ return (4 + BLOCK_OCTETS); /* return size of key and MAC */
+}
diff --git a/contrib/xntpd/lib/adjtimex.c b/contrib/xntpd/lib/adjtimex.c
new file mode 100644
index 000000000000..03e9d79e359e
--- /dev/null
+++ b/contrib/xntpd/lib/adjtimex.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+_sccsid:.asciz "11/19/91 ULTRIX @(#)adjtime.c 6.1"
+#endif not lint
+
+#include "SYS.h"
+
+SYSCALL(adjtimex)
+ ret
+
diff --git a/contrib/xntpd/lib/atoint.c b/contrib/xntpd/lib/atoint.c
new file mode 100644
index 000000000000..0e8ea8f6fc18
--- /dev/null
+++ b/contrib/xntpd/lib/atoint.c
@@ -0,0 +1,48 @@
+/* atoint.c,v 3.1 1993/07/06 01:07:39 jbj Exp
+ * atoint - convert an ascii string to a signed long, with error checking
+ */
+#include <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/contrib/xntpd/lib/atolfp.c b/contrib/xntpd/lib/atolfp.c
new file mode 100644
index 000000000000..9e2d88301471
--- /dev/null
+++ b/contrib/xntpd/lib/atolfp.c
@@ -0,0 +1,117 @@
+/* atolfp.c,v 3.1 1993/07/06 01:07:40 jbj Exp
+ * atolfp - convert an ascii string to an l_fp number
+ */
+#include <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/contrib/xntpd/lib/atouint.c b/contrib/xntpd/lib/atouint.c
new file mode 100644
index 000000000000..b27653f60a21
--- /dev/null
+++ b/contrib/xntpd/lib/atouint.c
@@ -0,0 +1,33 @@
+/* atouint.c,v 3.1 1993/07/06 01:07:42 jbj Exp
+ * atouint - convert an ascii string to an unsigned long, with error checking
+ */
+#include <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/contrib/xntpd/lib/auth12crypt.c b/contrib/xntpd/lib/auth12crypt.c
new file mode 100644
index 000000000000..a5d988972757
--- /dev/null
+++ b/contrib/xntpd/lib/auth12crypt.c
@@ -0,0 +1,125 @@
+/* auth12crypt.c,v 3.1 1993/07/06 01:07:43 jbj Exp
+ * auth12crypt.c - routines to support two stage NTP encryption
+ */
+#include "ntp_stdlib.h"
+
+/*
+ * For our purposes an NTP packet looks like:
+ *
+ * a variable amount of encrypted data, multiple of 8 bytes, which
+ * is encrypted in pass 1, followed by:
+ * an 8 byte chunk of data which is encrypted in pass 2
+ * NOCRYPT_OCTETS worth of unencrypted data, followed by:
+ * BLOCK_OCTETS worth of ciphered checksum.
+ */
+#define NOCRYPT_OCTETS 4
+#define BLOCK_OCTETS 8
+
+#define NOCRYPT_LONGS ((NOCRYPT_OCTETS)/sizeof(U_LONG))
+#define BLOCK_LONGS ((BLOCK_OCTETS)/sizeof(U_LONG))
+
+/*
+ * Imported from the key data base module
+ */
+extern U_LONG cache_keyid; /* cached key ID */
+extern u_char DEScache_ekeys[]; /* cached decryption keys */
+extern u_char DESzeroekeys[]; /* zero key decryption keys */
+
+/*
+ * Stat counters, from the database module
+ */
+extern U_LONG authencryptions;
+extern U_LONG authkeyuncached;
+extern U_LONG authnokey;
+
+
+/*
+ * auth1crypt - do the first stage of a two stage encryption
+ */
+void
+DESauth1crypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* length of all encrypted data */
+{
+ register U_LONG *pd;
+ register int i;
+ register u_char *keys;
+ U_LONG work[2];
+
+ authencryptions++;
+
+ if (keyno == 0) {
+ keys = DESzeroekeys;
+ } else {
+ if (keyno != cache_keyid) {
+ authkeyuncached++;
+ if (!authhavekey(keyno)) {
+ authnokey++;
+ return;
+ }
+ }
+ keys = DEScache_ekeys;
+ }
+
+ /*
+ * Do the first five encryptions. Stick the intermediate result
+ * in the mac field. The sixth encryption must wait until the
+ * caller freezes a transmit time stamp, and will be done in stage 2.
+ */
+ pd = pkt;
+ work[0] = work[1] = 0;
+
+ for (i = (length/BLOCK_OCTETS - 1); i > 0; i--) {
+ work[0] ^= *pd++;
+ work[1] ^= *pd++;
+ DESauth_des(work, keys);
+ }
+
+ /*
+ * Space to the end of the packet and stick the intermediate
+ * result in the mac field.
+ */
+ pd += BLOCK_LONGS + NOCRYPT_LONGS;
+ *pd++ = work[0];
+ *pd = work[1];
+}
+
+
+/*
+ * auth2crypt - do the second stage of a two stage encryption
+ */
+int
+DESauth2crypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* total length of encrypted area */
+{
+ register U_LONG *pd;
+ register u_char *keys;
+
+ /*
+ * Skip the key check. The call to the first stage should
+ * have got it.
+ */
+ if (keyno == 0)
+ keys = DESzeroekeys;
+ else
+ keys = DEScache_ekeys;
+
+ /*
+ * The mac currently should hold the results of the first `n'
+ * encryptions. We xor in the last block in data section and
+ * do the final encryption in place.
+ *
+ * Get a pointer to the MAC block. XOR in the last two words of
+ * the data area. Call the encryption routine.
+ */
+ pd = pkt + (length/sizeof(U_LONG)) + NOCRYPT_LONGS;
+
+ *pd ^= *(pd - NOCRYPT_LONGS - 2);
+ *(pd + 1) ^= *(pd - NOCRYPT_LONGS - 1);
+ DESauth_des(pd, keys);
+
+ return 4 + 8; /* return size of key number and MAC */
+}
diff --git a/contrib/xntpd/lib/authdecrypt.c b/contrib/xntpd/lib/authdecrypt.c
new file mode 100644
index 000000000000..7ff1129a479e
--- /dev/null
+++ b/contrib/xntpd/lib/authdecrypt.c
@@ -0,0 +1,85 @@
+/* authdecrypt.c,v 3.1 1993/07/06 01:07:44 jbj Exp
+ * authdecrypt - routine to decrypt a packet to see if this guy knows our key.
+ */
+#include "ntp_stdlib.h"
+
+/*
+ * For our purposes an NTP packet looks like:
+ *
+ * a variable amount of unencrypted data, multiple of 8 bytes, followed by:
+ * NOCRYPT_OCTETS worth of unencrypted data, followed by:
+ * BLOCK_OCTETS worth of ciphered checksum.
+ */
+#define NOCRYPT_OCTETS 4
+#define BLOCK_OCTETS 8
+
+#define NOCRYPT_LONGS ((NOCRYPT_OCTETS)/sizeof(U_LONG))
+#define BLOCK_LONGS ((BLOCK_OCTETS)/sizeof(U_LONG))
+
+/*
+ * Imported from the key data base module
+ */
+extern U_LONG cache_keyid; /* cached key ID */
+extern u_char DEScache_dkeys[]; /* cached decryption keys */
+extern u_char DESzerodkeys[]; /* zero key decryption keys */
+
+/*
+ * Stat counters, imported from data base module
+ */
+extern U_LONG authdecryptions;
+extern U_LONG authkeyuncached;
+extern U_LONG authdecryptok;
+
+int
+DESauthdecrypt(keyno, pkt, length)
+ U_LONG keyno;
+ const U_LONG *pkt;
+ int length; /* length of variable data in octets */
+{
+ register const U_LONG *pd;
+ register int i;
+ register u_char *keys;
+ register int longlen;
+ U_LONG work[2];
+
+ authdecryptions++;
+
+ if (keyno == 0)
+ keys = DESzerodkeys;
+ else {
+ if (keyno != cache_keyid) {
+ authkeyuncached++;
+ if (!authhavekey(keyno))
+ return 0;
+ }
+ keys = DEScache_dkeys;
+ }
+
+ /*
+ * Get encryption block data in host byte order and decrypt it.
+ */
+ longlen = length / sizeof(U_LONG);
+ pd = pkt + longlen; /* points at NOCRYPT area */
+ work[0] = *(pd + NOCRYPT_LONGS);
+ work[1] = *(pd + NOCRYPT_LONGS + 1);
+
+ if (longlen & 0x1) {
+ DESauth_des(work, keys);
+ work[0] ^= *(--pd);
+ }
+
+ for (i = longlen/2; i > 0; i--) {
+ DESauth_des(work, keys);
+ work[1] ^= *(--pd);
+ work[0] ^= *(--pd);
+ }
+
+ /*
+ * Success if the encryption data is zero
+ */
+ if ((work[0] == 0) && (work[1] == 0)) {
+ authdecryptok++;
+ return 1;
+ }
+ return 0;
+}
diff --git a/contrib/xntpd/lib/authdes.c.des b/contrib/xntpd/lib/authdes.c.des
new file mode 100644
index 000000000000..93058c745d59
--- /dev/null
+++ b/contrib/xntpd/lib/authdes.c.des
Binary files differ
diff --git a/contrib/xntpd/lib/authdes.c.export b/contrib/xntpd/lib/authdes.c.export
new file mode 100644
index 000000000000..a63c6d3839c5
--- /dev/null
+++ b/contrib/xntpd/lib/authdes.c.export
@@ -0,0 +1,41 @@
+/* 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>
+#include "ntp_stdlib.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/contrib/xntpd/lib/authencrypt.c b/contrib/xntpd/lib/authencrypt.c
new file mode 100644
index 000000000000..66b5281b7ae5
--- /dev/null
+++ b/contrib/xntpd/lib/authencrypt.c
@@ -0,0 +1,88 @@
+/* authencrypt.c,v 3.1 1993/07/06 01:07:50 jbj Exp
+ * authencrypt - compute and encrypt the mac field in an NTP packet
+ */
+#include "ntp_stdlib.h"
+
+/*
+ * For our purposes an NTP packet looks like:
+ *
+ * a variable amount of encrypted data, multiple of 8 bytes, followed by:
+ * NOCRYPT_OCTETS worth of unencrypted data, followed by:
+ * BLOCK_OCTETS worth of ciphered checksum.
+ */
+#define NOCRYPT_OCTETS 4
+#define BLOCK_OCTETS 8
+
+#define NOCRYPT_LONGS ((NOCRYPT_OCTETS)/sizeof(U_LONG))
+#define BLOCK_LONGS ((BLOCK_OCTETS)/sizeof(U_LONG))
+
+/*
+ * Imported from the key data base module
+ */
+extern U_LONG cache_keyid; /* cached key ID */
+extern u_char DEScache_ekeys[]; /* cached decryption keys */
+extern u_char DESzeroekeys[]; /* zero key decryption keys */
+
+/*
+ * Stat counters from the database module
+ */
+extern U_LONG authencryptions;
+extern U_LONG authkeyuncached;
+extern U_LONG authnokey;
+
+int
+DESauthencrypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* length of encrypted portion of packet */
+{
+ register U_LONG *pd;
+ register int i;
+ register u_char *keys;
+ register int len;
+ U_LONG work[2];
+
+ authencryptions++;
+
+ if (keyno == 0) {
+ keys = DESzeroekeys;
+ } else {
+ if (keyno != cache_keyid) {
+ authkeyuncached++;
+ if (!authhavekey(keyno)) {
+ authnokey++;
+ return 0;
+ }
+ }
+ keys = DEScache_ekeys;
+ }
+
+ /*
+ * Do the encryption. Work our way forward in the packet, eight
+ * bytes at a time, encrypting as we go. Note that the byte order
+ * issues are handled by the DES routine itself
+ */
+ pd = pkt;
+ work[0] = work[1] = 0;
+ len = length / sizeof(U_LONG);
+
+ for (i = (len/2); i > 0; i--) {
+ work[0] ^= *pd++;
+ work[1] ^= *pd++;
+ DESauth_des(work, keys);
+ }
+
+ if (len & 0x1) {
+ work[0] ^= *pd++;
+ DESauth_des(work, keys);
+ }
+
+ /*
+ * Space past the keyid and stick the result back in the mac field
+ */
+ pd += NOCRYPT_LONGS;
+ *pd++ = work[0];
+ *pd = work[1];
+
+ return 4 + BLOCK_OCTETS; /* return size of key and MAC */
+}
diff --git a/contrib/xntpd/lib/authkeys.c b/contrib/xntpd/lib/authkeys.c
new file mode 100644
index 000000000000..743af83ba6e1
--- /dev/null
+++ b/contrib/xntpd/lib/authkeys.c
@@ -0,0 +1,602 @@
+/* authkeys.c,v 3.1 1993/07/06 01:07:51 jbj Exp
+ * authkeys.c - routines to manage the storage of authentication keys
+ */
+#include <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
+ */
+ memset((char *)key_hash, 0, sizeof key_hash);
+ cache_flags = cache_keyid = 0;
+
+ authnumfreekeys = authkeynotfound = authkeylookups = 0;
+ authnumkeys = authuncached = authkeyuncached = authnokey = 0;
+ authencryptions = authdecryptions = authdecryptok = 0;
+
+#ifdef DES
+ /*
+ * Initialize the zero key
+ */
+ zerokey[0] = ZEROKEY_L;
+ zerokey[1] = ZEROKEY_R;
+ /* could just zero all */
+ DESauth_subkeys(zerokey, DESzeroekeys, DESzerodkeys);
+#endif
+}
+
+
+/*
+ * auth_findkey - find a key in the hash table
+ */
+struct savekey *
+auth_findkey(keyno)
+ U_LONG keyno;
+{
+ register struct savekey *sk;
+
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid)
+ return sk;
+ sk = sk->next;
+ }
+ return 0;
+}
+
+
+/*
+ * auth_havekey - return whether a key is known
+ */
+int
+auth_havekey(keyno)
+ U_LONG keyno;
+{
+ register struct savekey *sk;
+
+ if (keyno == 0 || (keyno == cache_keyid))
+ return 1;
+
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid) {
+ if (sk->flags & KEY_KNOWN)
+ return 1;
+ else {
+ authkeynotfound++;
+ return 0;
+ }
+ }
+ sk = sk->next;
+ }
+ authkeynotfound++;
+ return 0;
+}
+
+
+/*
+ * authhavekey - return whether a key is known. Permute and cache
+ * the key as a side effect.
+ */
+int
+authhavekey(keyno)
+ U_LONG keyno;
+{
+ register struct savekey *sk;
+
+ authkeylookups++;
+ if (keyno == 0 || keyno == cache_keyid)
+ return 1;
+
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid)
+ break;
+ sk = sk->next;
+ }
+
+ if (sk == 0 || !(sk->flags & KEY_KNOWN)) {
+ authkeynotfound++;
+ return 0;
+ }
+
+ cache_keyid = sk->keyid;
+ cache_flags = sk->flags;
+#ifdef MD5
+ if (sk->flags & KEY_MD5) {
+ cache_keylen = sk->keylen;
+ cache_key = (char *) sk->k.MD5_key; /* XXX */
+ return 1;
+ }
+#endif
+
+#ifdef DES
+ if (sk->flags & KEY_DES) {
+ DESauth_subkeys(sk->k.DES_key, DEScache_ekeys, DEScache_dkeys);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+
+/*
+ * auth_moremem - get some more free key structures
+ */
+int
+auth_moremem()
+{
+ register struct savekey *sk;
+ register int i;
+
+ sk = (struct savekey *)malloc(MEMINC * sizeof(struct savekey));
+ if (sk == 0)
+ return 0;
+
+ for (i = MEMINC; i > 0; i--) {
+ sk->next = authfreekeys;
+ authfreekeys = sk++;
+ }
+ authnumfreekeys += MEMINC;
+ return authnumfreekeys;
+}
+
+
+/*
+ * authtrust - declare a key to be trusted/untrusted
+ */
+void
+authtrust(keyno, trust)
+ U_LONG keyno;
+ int trust;
+{
+ register struct savekey *sk;
+
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid)
+ break;
+ sk = sk->next;
+ }
+
+ if (sk == 0 && !trust)
+ return;
+
+ if (sk != 0) {
+ if (cache_keyid == keyno)
+ cache_flags = cache_keyid = 0;
+
+ if (trust) {
+ sk->flags |= KEY_TRUSTED;
+ return;
+ }
+
+ sk->flags &= ~KEY_TRUSTED;
+ if (!(sk->flags & KEY_KNOWN)) {
+ register struct savekey *skp;
+
+ skp = key_hash[KEYHASH(keyno)];
+ if (skp == sk) {
+ key_hash[KEYHASH(keyno)] = sk->next;
+ } else {
+ while (skp->next != sk)
+ skp = skp->next;
+ skp->next = sk->next;
+ }
+ authnumkeys--;
+
+ sk->next = authfreekeys;
+ authfreekeys = sk;
+ authnumfreekeys++;
+ }
+ return;
+ }
+
+ if (authnumfreekeys == 0)
+ if (auth_moremem() == 0)
+ return;
+
+ sk = authfreekeys;
+ authfreekeys = sk->next;
+ authnumfreekeys--;
+
+ sk->keyid = keyno;
+ sk->flags = KEY_TRUSTED;
+ sk->next = key_hash[KEYHASH(keyno)];
+ key_hash[KEYHASH(keyno)] = sk;
+ authnumkeys++;
+ return;
+}
+
+
+/*
+ * authistrusted - determine whether a key is trusted
+ */
+int
+authistrusted(keyno)
+ U_LONG keyno;
+{
+ register struct savekey *sk;
+
+ if (keyno == cache_keyid)
+ return ((cache_flags & KEY_TRUSTED) != 0);
+
+ authkeyuncached++;
+
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid)
+ break;
+ sk = sk->next;
+ }
+
+ if (sk == 0 || !(sk->flags & KEY_TRUSTED))
+ return 0;
+ return 1;
+}
+
+
+
+#ifdef DES
+/*
+ * DESauth_setkey - set a key into the key array
+ */
+void
+DESauth_setkey(keyno, key)
+ U_LONG keyno;
+ const U_LONG *key;
+{
+ register struct savekey *sk;
+
+ /*
+ * See if we already have the key. If so just stick in the
+ * new value.
+ */
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid) {
+ sk->k.DES_key[0] = key[0];
+ sk->k.DES_key[1] = key[1];
+ sk->flags |= KEY_KNOWN | KEY_DES;
+ if (cache_keyid == keyno)
+ cache_flags = cache_keyid = 0;
+ return;
+ }
+ sk = sk->next;
+ }
+
+ /*
+ * Need to allocate new structure. Do it.
+ */
+ if (authnumfreekeys == 0) {
+ if (auth_moremem() == 0)
+ return;
+ }
+
+ sk = authfreekeys;
+ authfreekeys = sk->next;
+ authnumfreekeys--;
+
+ sk->k.DES_key[0] = key[0];
+ sk->k.DES_key[1] = key[1];
+ sk->keyid = keyno;
+ sk->flags = KEY_KNOWN | KEY_DES;
+ sk->next = key_hash[KEYHASH(keyno)];
+ key_hash[KEYHASH(keyno)] = sk;
+ authnumkeys++;
+ return;
+}
+#endif
+
+#ifdef MD5
+void
+MD5auth_setkey(keyno, key)
+ U_LONG keyno;
+ const U_LONG *key;
+{
+ register struct savekey *sk;
+
+ /*
+ * See if we already have the key. If so just stick in the
+ * new value.
+ */
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid) {
+ strncpy(sk->k.MD5_key, (char *)key, sizeof(sk->k.MD5_key));
+ if ((sk->keylen = strlen((char *)key)) >
+ sizeof(sk->k.MD5_key))
+ sk->keylen = sizeof(sk->k.MD5_key);
+
+ sk->flags |= KEY_KNOWN | KEY_MD5;
+ if (cache_keyid == keyno)
+ cache_flags = cache_keyid = 0;
+ return;
+ }
+ sk = sk->next;
+ }
+
+ /*
+ * Need to allocate new structure. Do it.
+ */
+ if (authnumfreekeys == 0) {
+ if (auth_moremem() == 0)
+ return;
+ }
+
+ sk = authfreekeys;
+ authfreekeys = sk->next;
+ authnumfreekeys--;
+
+ strncpy(sk->k.MD5_key, (char *)key, sizeof(sk->k.MD5_key));
+ if ((sk->keylen = strlen((char *)key)) > sizeof(sk->k.MD5_key))
+ sk->keylen = sizeof(sk->k.MD5_key);
+
+ sk->keyid = keyno;
+ sk->flags = KEY_KNOWN | KEY_MD5;
+ sk->next = key_hash[KEYHASH(keyno)];
+ key_hash[KEYHASH(keyno)] = sk;
+ authnumkeys++;
+ return;
+}
+#endif
+
+/*
+ * auth_delkeys - delete all known keys, in preparation for rereading
+ * the keys file (presumably)
+ */
+void
+auth_delkeys()
+{
+ register struct savekey *sk;
+ register struct savekey **skp;
+ register int i;
+
+ for (i = 0; i < HASHSIZE; i++) {
+ skp = &(key_hash[i]);
+ sk = key_hash[i];
+ while (sk != 0) {
+ sk->flags &= ~(KEY_KNOWN
+#ifdef MD5
+ | KEY_MD5
+#endif
+#ifdef DES
+ | KEY_DES
+#endif
+ );
+ if (sk->flags == 0) {
+ *skp = sk->next;
+ authnumkeys--;
+ sk->next = authfreekeys;
+ authfreekeys = sk;
+ authnumfreekeys++;
+ sk = *skp;
+ } else {
+ skp = &(sk->next);
+ sk = sk->next;
+ }
+ }
+ }
+}
+
+
+/*
+ * auth1crypt - support for two stage encryption, part 1.
+ */
+void
+auth1crypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* length of all encrypted data */
+{
+ if (keyno && keyno != cache_keyid) {
+ authkeyuncached++;
+ if (!authhavekey(keyno)) {
+ authnokey++;
+ return;
+ }
+ }
+
+#ifdef DES
+ if (!keyno || (cache_flags & KEY_DES)) {
+ DESauth1crypt(keyno, pkt, length);
+ return;
+ }
+#endif
+
+#ifdef MD5
+ if (cache_flags & KEY_MD5) {
+ MD5auth1crypt(keyno, pkt, length);
+ return;
+ }
+#endif
+}
+
+
+/*
+ * auth1crypt - support for two stage encryption, part 1.
+ */
+int
+auth2crypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* total length of encrypted area */
+{
+ if (keyno && keyno != cache_keyid) {
+ authkeyuncached++;
+ if (!authhavekey(keyno)) {
+ authnokey++;
+ return 0;
+ }
+ }
+
+#ifdef DES
+ if (!keyno || (cache_flags & KEY_DES))
+ return DESauth2crypt(keyno, pkt, length);
+#endif
+
+#ifdef MD5
+ if (cache_flags & KEY_MD5)
+ return MD5auth2crypt(keyno, pkt, length);
+#endif
+
+ return 0;
+}
+
+int
+authencrypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* length of encrypted portion of packet */
+{
+ int sendlength = 0;
+
+ if (keyno && keyno != cache_keyid) {
+ authkeyuncached++;
+ if (!authhavekey(keyno)) {
+ authnokey++;
+ return 0;
+ }
+ }
+
+#ifdef DES
+ if (!keyno || (cache_flags & KEY_DES))
+ return sendlength = DESauthencrypt(keyno, pkt, length);
+#endif
+
+#ifdef MD5
+ if (cache_flags & KEY_MD5)
+ return MD5authencrypt(keyno, pkt, length);
+#endif
+ return 0;
+}
+
+
+int
+authdecrypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* length of variable data in octets */
+{
+ if (keyno && (keyno != cache_keyid)) {
+ authkeyuncached++;
+ if (!authhavekey(keyno)) {
+ authnokey++;
+ return 0;
+ }
+ }
+
+#ifdef DES
+ if (!keyno || (cache_flags & KEY_DES))
+ return DESauthdecrypt(keyno, pkt, length);
+#endif
+
+#ifdef MD5
+ if (cache_flags & KEY_MD5)
+ return MD5authdecrypt(keyno, pkt, length);
+#endif
+
+ return 0;
+}
diff --git a/contrib/xntpd/lib/authparity.c b/contrib/xntpd/lib/authparity.c
new file mode 100644
index 000000000000..33562cb4b12a
--- /dev/null
+++ b/contrib/xntpd/lib/authparity.c
@@ -0,0 +1,58 @@
+/* authparity.c,v 3.1 1993/07/06 01:07:55 jbj Exp
+ * auth_parity - set parity on a key/check for odd parity
+ */
+#include "ntp_stdlib.h"
+
+int
+DESauth_parity(key)
+ U_LONG *key;
+{
+ U_LONG mask;
+ int parity_err;
+ int bitcount;
+ int half;
+ int byte;
+ int i;
+
+ /*
+ * Go through counting bits in each byte. Check to see if
+ * each parity bit was set correctly. If not, note the error
+ * and set it right.
+ */
+ parity_err = 0;
+ for (half = 0; half < 2; half++) { /* two halves of key */
+ mask = 0x80000000;
+ for (byte = 0; byte < 4; byte++) { /* 4 bytes per half */
+ bitcount = 0;
+ for (i = 0; i < 7; i++) { /* 7 data bits / byte */
+ if (key[half] & mask)
+ bitcount++;
+ mask >>= 1;
+ }
+
+ /*
+ * If bitcount is even, parity must be set. If
+ * bitcount is odd, parity must be clear.
+ */
+ if ((bitcount & 0x1) == 0) {
+ if (!(key[half] & mask)) {
+ parity_err++;
+ key[half] |= mask;
+ }
+ } else {
+ if (key[half] & mask) {
+ parity_err++;
+ key[half] &= ~mask;
+ }
+ }
+ mask >>= 1;
+ }
+ }
+
+ /*
+ * Return the result of the parity check.
+ */
+ return (parity_err == 0);
+}
+
+
diff --git a/contrib/xntpd/lib/authreadkeys.c b/contrib/xntpd/lib/authreadkeys.c
new file mode 100644
index 000000000000..5800186dc812
--- /dev/null
+++ b/contrib/xntpd/lib/authreadkeys.c
@@ -0,0 +1,191 @@
+/* authreadkeys.c,v 3.1 1993/07/06 01:07:57 jbj Exp
+ * authreadkeys.c - routines to support the reading of the key file
+ */
+#include <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/contrib/xntpd/lib/authusekey.c b/contrib/xntpd/lib/authusekey.c
new file mode 100644
index 000000000000..c268c4d2455c
--- /dev/null
+++ b/contrib/xntpd/lib/authusekey.c
@@ -0,0 +1,132 @@
+/* authusekey.c,v 3.1 1993/07/06 01:07:58 jbj Exp
+ * authusekey - decode a key from ascii and use it
+ */
+#include <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
+ */
+ memset((char *) keybytes, 0, sizeof(keybytes));
+ for (i = 0; i < 8 && i < len; i++)
+ keybytes[i] = *cp++ << 1;
+ key[0] = (U_LONG)keybytes[0] << 24 | (U_LONG)keybytes[1] << 16
+ | (U_LONG)keybytes[2] << 8 | (U_LONG)keybytes[3];
+ key[1] = (U_LONG)keybytes[4] << 24 | (U_LONG)keybytes[5] << 16
+ | (U_LONG)keybytes[6] << 8 | (U_LONG)keybytes[7];
+
+ /*
+ * Set parity on key
+ */
+ (void)DESauth_parity(key);
+
+ /*
+ * Now set key in.
+ */
+ DESauth_setkey(keyno, key);
+ break;
+#endif
+
+#ifdef MD5
+ case KEY_TYPE_MD5:
+ /* XXX FIXME: MD5auth_setkey() casts arg2 back to (char *) */
+ MD5auth_setkey(keyno, (U_LONG *)str);
+ break;
+#endif
+
+ default:
+ /* Oh, well */
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/contrib/xntpd/lib/buftvtots.c b/contrib/xntpd/lib/buftvtots.c
new file mode 100644
index 000000000000..d9b484db2df0
--- /dev/null
+++ b/contrib/xntpd/lib/buftvtots.c
@@ -0,0 +1,61 @@
+/* buftvtots.c,v 3.1 1993/07/06 01:07:59 jbj Exp
+ * buftvtots - pull a Unix-format (struct timeval) time stamp out of
+ * an octet stream and convert it to a l_fp time stamp.
+ * This is useful when using the clock line discipline.
+ */
+#include "ntp_fp.h"
+#include "ntp_unixtime.h"
+
+int
+buftvtots(bufp, ts)
+ const char *bufp;
+ l_fp *ts;
+{
+ register const u_char *bp;
+ register U_LONG sec;
+ register U_LONG usec;
+
+#ifdef XNTP_BIG_ENDIAN
+ bp = (u_char *)bufp;
+
+ sec = (U_LONG)*bp++ & 0xff;
+ sec <<= 8;
+ sec += (U_LONG)*bp++ & 0xff;
+ sec <<= 8;
+ sec += (U_LONG)*bp++ & 0xff;
+ sec <<= 8;
+ sec += (U_LONG)*bp++ & 0xff;
+
+ usec = (U_LONG)*bp++ & 0xff;
+ usec <<= 8;
+ usec += (U_LONG)*bp++ & 0xff;
+ usec <<= 8;
+ usec += (U_LONG)*bp++ & 0xff;
+ usec <<= 8;
+ usec += (U_LONG)*bp & 0xff;
+#else
+ bp = (u_char *)bufp + 7;
+
+ usec = (U_LONG)*bp-- & 0xff;
+ usec <<= 8;
+ usec += (U_LONG)*bp-- & 0xff;
+ usec <<= 8;
+ usec += (U_LONG)*bp-- & 0xff;
+ usec <<= 8;
+ usec += (U_LONG)*bp-- & 0xff;
+
+ sec = (U_LONG)*bp-- & 0xff;
+ sec <<= 8;
+ sec += (U_LONG)*bp-- & 0xff;
+ sec <<= 8;
+ sec += (U_LONG)*bp-- & 0xff;
+ sec <<= 8;
+ sec += (U_LONG)*bp & 0xff;
+#endif
+ if (usec > 999999)
+ return 0;
+
+ ts->l_ui = sec + (U_LONG)JAN_1970;
+ TVUTOTSF(usec, ts->l_uf);
+ return 1;
+}
diff --git a/contrib/xntpd/lib/caljulian.c b/contrib/xntpd/lib/caljulian.c
new file mode 100644
index 000000000000..92d6d742a63a
--- /dev/null
+++ b/contrib/xntpd/lib/caljulian.c
@@ -0,0 +1,105 @@
+/* caljulian.c,v 3.1 1993/07/06 01:08:00 jbj Exp
+ * caljulian - determine the Julian date from an NTP time.
+ */
+#include <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/contrib/xntpd/lib/calleapwhen.c b/contrib/xntpd/lib/calleapwhen.c
new file mode 100644
index 000000000000..379643f09566
--- /dev/null
+++ b/contrib/xntpd/lib/calleapwhen.c
@@ -0,0 +1,61 @@
+/* calleapwhen.c,v 3.1 1993/07/06 01:08:02 jbj Exp
+ * calleapwhen - determine the number of seconds to the next possible
+ * leap occurance and the last one.
+ */
+#include <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/contrib/xntpd/lib/caltontp.c b/contrib/xntpd/lib/caltontp.c
new file mode 100644
index 000000000000..f5da0ab761e8
--- /dev/null
+++ b/contrib/xntpd/lib/caltontp.c
@@ -0,0 +1,90 @@
+/* caltontp.c,v 3.1 1993/07/06 01:08:04 jbj Exp
+ * caltontp - convert a julian date to an NTP time
+ */
+#include <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/contrib/xntpd/lib/calyearstart.c b/contrib/xntpd/lib/calyearstart.c
new file mode 100644
index 000000000000..1bb3321f7252
--- /dev/null
+++ b/contrib/xntpd/lib/calyearstart.c
@@ -0,0 +1,62 @@
+/* calyearstart.c,v 3.1 1993/07/06 01:08:06 jbj Exp
+ * calyearstart - determine the NTP time at midnight of January 1 in
+ * the year of the given date.
+ */
+#include <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/contrib/xntpd/lib/clocktime.c b/contrib/xntpd/lib/clocktime.c
new file mode 100644
index 000000000000..36b967e9a16c
--- /dev/null
+++ b/contrib/xntpd/lib/clocktime.c
@@ -0,0 +1,131 @@
+/* clocktime.c,v 3.1 1993/07/06 01:08:07 jbj Exp
+ * clocktime - compute the NTP date from a day of year, hour, minute
+ * and second.
+ */
+#include "ntp_fp.h"
+#include "ntp_unixtime.h"
+#include "ntp_stdlib.h"
+
+/*
+ * Hacks to avoid excercising the multiplier. I have no pride.
+ */
+#define MULBY10(x) (((x)<<3) + ((x)<<1))
+#define MULBY60(x) (((x)<<6) - ((x)<<2)) /* watch overflow */
+#define MULBY24(x) (((x)<<4) + ((x)<<3))
+
+/*
+ * Two days, in seconds.
+ */
+#define TWODAYS (2*24*60*60)
+
+/*
+ * We demand that the time be within CLOSETIME seconds of the receive
+ * time stamp. This is about 4 hours, which hopefully should be
+ * wide enough to collect most data, while close enough to keep things
+ * from getting confused.
+ */
+#define CLOSETIME (4*60*60)
+
+
+int
+clocktime(yday, hour, minute, second, tzoff, rec_ui, yearstart, ts_ui)
+ int yday;
+ int hour;
+ int minute;
+ int second;
+ int tzoff;
+ U_LONG rec_ui;
+ U_LONG *yearstart;
+ U_LONG *ts_ui;
+{
+ register LONG tmp;
+ register U_LONG date;
+ register U_LONG yst;
+
+ /*
+ * Compute the offset into the year in seconds. Note that
+ * this could come out to be a negative number.
+ */
+ tmp = (LONG)(MULBY24((yday-1)) + hour + tzoff);
+ tmp = MULBY60(tmp) + (LONG)minute;
+ tmp = MULBY60(tmp) + (LONG)second;
+
+ /*
+ * Initialize yearstart, if necessary.
+ */
+ yst = *yearstart;
+ if (yst == 0) {
+ yst = calyearstart(rec_ui);
+ *yearstart = yst;
+ }
+
+ /*
+ * Now the fun begins. We demand that the received clock time
+ * be within CLOSETIME of the receive timestamp, but
+ * there is uncertainty about the year the timestamp is in.
+ * Use the current year start for the first check, this should
+ * work most of the time.
+ */
+ date = (U_LONG)(tmp + (LONG)yst);
+ if (date < (rec_ui + CLOSETIME) &&
+ date > (rec_ui - CLOSETIME)) {
+ *ts_ui = date;
+ return 1;
+ }
+
+ /*
+ * Trouble. Next check is to see if the year rolled over and, if
+ * so, try again with the new year's start.
+ */
+ yst = calyearstart(rec_ui);
+ if (yst != *yearstart) {
+ date = (U_LONG)((LONG)yst + tmp);
+ *ts_ui = date;
+ if (date < (rec_ui + CLOSETIME) &&
+ date > (rec_ui - CLOSETIME)) {
+ *yearstart = yst;
+ return 1;
+ }
+ }
+
+ /*
+ * Here we know the year start matches the current system
+ * time. One remaining possibility is that the time code
+ * is in the year previous to that of the system time. This
+ * is only worth checking if the receive timestamp is less
+ * than a couple of days into the new year.
+ */
+ if ((rec_ui - yst) < TWODAYS) {
+ yst = calyearstart(yst - TWODAYS);
+ if (yst != *yearstart) {
+ date = (U_LONG)(tmp + (LONG)yst);
+ if (date < (rec_ui + CLOSETIME) &&
+ date > (rec_ui - CLOSETIME)) {
+ *yearstart = yst;
+ *ts_ui = date;
+ return 1;
+ }
+ }
+ }
+
+ /*
+ * One last possibility is that the time stamp is in the year
+ * following the year the system is in. Try this one before
+ * giving up.
+ */
+ yst = calyearstart(rec_ui + TWODAYS);
+ if (yst != *yearstart) {
+ date = (U_LONG)((LONG)yst + tmp);
+ if (date < (rec_ui + CLOSETIME) &&
+ date > (rec_ui - CLOSETIME)) {
+ *yearstart = yst;
+ *ts_ui = date;
+ return 1;
+ }
+ }
+
+ /*
+ * Give it up.
+ */
+ return 0;
+}
diff --git a/contrib/xntpd/lib/clocktypes.c b/contrib/xntpd/lib/clocktypes.c
new file mode 100644
index 000000000000..2701e3f1d0ef
--- /dev/null
+++ b/contrib/xntpd/lib/clocktypes.c
@@ -0,0 +1,46 @@
+/* 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" },
+ { REFCLK_GPSTM_TRUETIME, "TrueTime GPS/TM-TMD clock (15)", "GPS_TRUE" },
+ { -1, "", "" }
+};
+
+const char *
+clockname(num)
+ int num;
+{
+ register struct clktype *clk;
+
+ for (clk = clktypes; clk->code != -1; clk++)
+ {
+ if (num == clk->code)
+ {
+ return clk->abbrev;
+ }
+ }
+
+ return NULL;
+}
diff --git a/contrib/xntpd/lib/decodenetnum.c b/contrib/xntpd/lib/decodenetnum.c
new file mode 100644
index 000000000000..32320a24b881
--- /dev/null
+++ b/contrib/xntpd/lib/decodenetnum.c
@@ -0,0 +1,58 @@
+/* decodenetnum.c,v 3.1 1993/07/06 01:08:11 jbj Exp
+ * decodenetnum - return a net number (this is crude, but careful)
+ */
+#include <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/contrib/xntpd/lib/dofptoa.c b/contrib/xntpd/lib/dofptoa.c
new file mode 100644
index 000000000000..a496df85dd5b
--- /dev/null
+++ b/contrib/xntpd/lib/dofptoa.c
@@ -0,0 +1,117 @@
+/* dofptoa.c,v 3.1 1993/07/06 01:08:12 jbj Exp
+ * dofptoa - do the grunge work to convert an fp number to ascii
+ */
+#include <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
+ */
+ memset((char *)cbuf, 0, sizeof cbuf);
+
+ /*
+ * Set the pointers to point at the first
+ * decimal place. Get a local copy of the value.
+ */
+ cp = cpend = &cbuf[5];
+ val = fpv;
+
+ /*
+ * If we have to, decode the integral part
+ */
+ if (!(val & 0xffff0000))
+ cp--;
+ else {
+ register u_short sv = (u_short)(val >> 16);
+ register u_short tmp;
+ register u_short ten = 10;
+
+ do {
+ tmp = sv;
+ sv /= ten;
+ *(--cp) = tmp - ((sv<<3) + (sv<<1));
+ } while (sv != 0);
+ }
+
+ /*
+ * Figure out how much of the fraction to do
+ */
+ if (msec) {
+ dec = ndec + 3;
+ if (dec < 3)
+ dec = 3;
+ cpdec = &cbuf[8];
+ } else {
+ dec = ndec;
+ cpdec = cpend;
+ }
+
+ if (dec > 6)
+ dec = 6;
+
+ if (dec > 0) {
+ do {
+ val &= 0xffff;
+ val = (val << 3) + (val << 1);
+ *cpend++ = (u_char)(val >> 16);
+ } while (--dec > 0);
+ }
+
+ if (val & 0x8000) {
+ register u_char *tp;
+ /*
+ * Round it. Ick.
+ */
+ tp = cpend;
+ *(--tp) += 1;
+ while (*tp >= 10) {
+ *tp = 0;
+ *(--tp) += 1;
+ }
+ }
+
+ /*
+ * Remove leading zeroes if necessary
+ */
+ while (cp < (cpdec -1) && *cp == 0)
+ cp++;
+
+ /*
+ * Copy it into the buffer, asciizing as we go.
+ */
+ bp = buf;
+ if (neg)
+ *bp++ = '-';
+
+ while (cp < cpend) {
+ if (cp == cpdec)
+ *bp++ = '.';
+ *bp++ = (char)(*cp++ + '0');
+ }
+ *bp = '\0';
+ return buf;
+}
diff --git a/contrib/xntpd/lib/dolfptoa.c b/contrib/xntpd/lib/dolfptoa.c
new file mode 100644
index 000000000000..ff37c9f1e1e6
--- /dev/null
+++ b/contrib/xntpd/lib/dolfptoa.c
@@ -0,0 +1,162 @@
+/* dolfptoa.c,v 3.1 1993/07/06 01:08:14 jbj Exp
+ * dolfptoa - do the grunge work of converting an l_fp number to decimal
+ */
+#include <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
+ */
+ memset((char *) cbuf, 0, sizeof(cbuf));
+
+ /*
+ * Work on the integral part. This is biased by what I know
+ * compiles fairly well for a 68000.
+ */
+ cp = cpend = &cbuf[10];
+ work_i = fpi;
+ if (work_i & 0xffff0000) {
+ register U_LONG lten = 10;
+ register U_LONG ltmp;
+
+ do {
+ ltmp = work_i;
+ work_i /= lten;
+ ltmp -= (work_i<<3) + (work_i<<1);
+ *--cp = (u_char)ltmp;
+ } while (work_i & 0xffff0000);
+ }
+ if (work_i != 0) {
+ register u_short sten = 10;
+ register u_short stmp;
+ register u_short swork = (u_short)work_i;
+
+ do {
+ stmp = swork;
+ swork /= sten;
+ stmp -= (swork<<3) + (swork<<1);
+ *--cp = (u_char)stmp;
+ } while (swork != 0);
+ }
+
+ /*
+ * Done that, now deal with the problem of the fraction. First
+ * determine the number of decimal places.
+ */
+ if (msec) {
+ dec = ndec + 3;
+ if (dec < 3)
+ dec = 3;
+ cpdec = &cbuf[13];
+ } else {
+ dec = ndec;
+ if (dec < 0)
+ dec = 0;
+ cpdec = &cbuf[10];
+ }
+ if (dec > 12)
+ dec = 12;
+
+ /*
+ * If there's a fraction to deal with, do so.
+ */
+ if (fpv != 0) {
+ register U_LONG work_f;
+
+ work_f = fpv;
+ while (dec > 0) {
+ register U_LONG tmp_i;
+ register U_LONG tmp_f;
+
+ dec--;
+ /*
+ * The scheme here is to multiply the
+ * fraction (0.1234...) by ten. This moves
+ * a junk of BCD into the units part.
+ * record that and iterate.
+ */
+ work_i = 0;
+ M_LSHIFT(work_i, work_f);
+ tmp_i = work_i;
+ tmp_f = work_f;
+ M_LSHIFT(work_i, work_f);
+ M_LSHIFT(work_i, work_f);
+ M_ADD(work_i, work_f, tmp_i, tmp_f);
+ *cpend++ = (u_char)work_i;
+ if (work_f == 0)
+ break;
+ }
+
+ /*
+ * Rounding is rotten
+ */
+ if (work_f & 0x80000000) {
+ register u_char *tp = cpend;
+
+ *(--tp) += 1;
+ while (*tp >= 10) {
+ *tp = 0;
+ *(--tp) += 1;
+ };
+ if (tp < cp)
+ cp = tp;
+ }
+ }
+ cpend += dec;
+
+
+ /*
+ * We've now got the fraction in cbuf[], with cp pointing at
+ * the first character, cpend pointing past the last, and
+ * cpdec pointing at the first character past the decimal.
+ * Remove leading zeros, then format the number into the
+ * buffer.
+ */
+ while (cp < cpdec) {
+ if (*cp != 0)
+ break;
+ cp++;
+ }
+ if (cp == cpdec)
+ --cp;
+
+ bp = buf;
+ if (neg)
+ *bp++ = '-';
+ while (cp < cpend) {
+ if (cp == cpdec)
+ *bp++ = '.';
+ *bp++ = (char)(*cp++ + '0'); /* ascii dependent? */
+ }
+ *bp = '\0';
+
+ /*
+ * Done!
+ */
+ return buf;
+}
diff --git a/contrib/xntpd/lib/emalloc.c b/contrib/xntpd/lib/emalloc.c
new file mode 100644
index 000000000000..d2a8e789f012
--- /dev/null
+++ b/contrib/xntpd/lib/emalloc.c
@@ -0,0 +1,20 @@
+/* emalloc.c,v 3.1 1993/07/06 01:08:15 jbj Exp
+ * emalloc - return new memory obtained from the system. Belch if none.
+ */
+#include "ntp_types.h"
+#include "ntp_malloc.h"
+#include "ntp_stdlib.h"
+#include "ntp_syslog.h"
+
+char *
+emalloc(size)
+ unsigned int size;
+{
+ char *mem;
+
+ if ((mem = (char *)malloc(size)) == 0) {
+ syslog(LOG_ERR, "No more memory!");
+ exit(1);
+ }
+ return mem;
+}
diff --git a/contrib/xntpd/lib/findconfig.c b/contrib/xntpd/lib/findconfig.c
new file mode 100755
index 000000000000..83126686b40c
--- /dev/null
+++ b/contrib/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/contrib/xntpd/lib/fptoa.c b/contrib/xntpd/lib/fptoa.c
new file mode 100644
index 000000000000..d245e9fa6917
--- /dev/null
+++ b/contrib/xntpd/lib/fptoa.c
@@ -0,0 +1,24 @@
+/* fptoa.c,v 3.1 1993/07/06 01:08:16 jbj Exp
+ * fptoa - return an asciized representation of an s_fp number
+ */
+#include "ntp_fp.h"
+#include "ntp_stdlib.h"
+
+char *
+fptoa(fpv, ndec)
+ s_fp fpv;
+ int ndec;
+{
+ u_fp plusfp;
+ int neg;
+
+ if (fpv < 0) {
+ plusfp = (u_fp)(-fpv);
+ neg = 1;
+ } else {
+ plusfp = (u_fp)fpv;
+ neg = 0;
+ }
+
+ return dofptoa(plusfp, neg, ndec, 0);
+}
diff --git a/contrib/xntpd/lib/fptoms.c b/contrib/xntpd/lib/fptoms.c
new file mode 100644
index 000000000000..fb850c5362c2
--- /dev/null
+++ b/contrib/xntpd/lib/fptoms.c
@@ -0,0 +1,23 @@
+/* fptoms.c,v 3.1 1993/07/06 01:08:17 jbj Exp
+ * fptoms - return an asciized s_fp number in milliseconds
+ */
+#include "ntp_fp.h"
+
+char *
+fptoms(fpv, ndec)
+ s_fp fpv;
+ int ndec;
+{
+ u_fp plusfp;
+ int neg;
+
+ if (fpv < 0) {
+ plusfp = (u_fp)(-fpv);
+ neg = 1;
+ } else {
+ plusfp = (u_fp)fpv;
+ neg = 0;
+ }
+
+ return dofptoa(plusfp, neg, ndec, 1);
+}
diff --git a/contrib/xntpd/lib/getopt.c b/contrib/xntpd/lib/getopt.c
new file mode 100644
index 000000000000..5519235180fa
--- /dev/null
+++ b/contrib/xntpd/lib/getopt.c
@@ -0,0 +1,105 @@
+/* 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, which is why we use it even if the system has its own (in fact,
+ * this one has a unique name so as not to conflict with the system's).
+ * 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 *ntp_optarg; /* Global argument pointer. */
+int ntp_optind = 0; /* Global argv index. */
+int ntp_opterr = 1; /* for compatibility, should error be printed? */
+int ntp_optopt; /* for compatibility, option character checked */
+
+static char *scan = NULL; /* Private scan pointer. */
+static char *prog = "amnesia";
+
+/*
+ * Print message about a bad option.
+ */
+static int
+badopt(mess, ch)
+ char *mess;
+ int ch;
+{
+ if (ntp_opterr) {
+ fputs(prog, stderr);
+ fputs(mess, stderr);
+ (void) putc(ch, stderr);
+ (void) putc('\n', stderr);
+ }
+ return ('?');
+}
+
+int
+ntp_getopt(argc, argv, optstring)
+ int argc;
+ char *argv[];
+ char *optstring;
+{
+ register char c;
+ register char *place;
+
+ prog = argv[0];
+ ntp_optarg = NULL;
+
+ if (ntp_optind == 0) {
+ scan = NULL;
+ ntp_optind++;
+ }
+
+ if (scan == NULL || *scan == '\0') {
+ if (ntp_optind >= argc
+ || argv[ntp_optind][0] != '-'
+ || argv[ntp_optind][1] == '\0') {
+ return (EOF);
+ }
+ if (argv[ntp_optind][1] == '-'
+ && argv[ntp_optind][2] == '\0') {
+ ntp_optind++;
+ return (EOF);
+ }
+
+ scan = argv[ntp_optind++]+1;
+ }
+
+ c = *scan++;
+ ntp_optopt = c & 0377;
+ for (place = optstring; place != NULL && *place != '\0'; ++place)
+ if (*place == c)
+ break;
+
+ if (place == NULL || *place == '\0' || c == ':' || c == '?') {
+ return (badopt(": unknown option -", c));
+ }
+
+ place++;
+ if (*place == ':') {
+ if (*scan != '\0') {
+ ntp_optarg = scan;
+ scan = NULL;
+ } else if (ntp_optind >= argc) {
+ return (badopt(": option requires argument -", c));
+ } else {
+ ntp_optarg = argv[ntp_optind++];
+ }
+ }
+
+ return (c & 0377);
+}
diff --git a/contrib/xntpd/lib/gettstamp.c b/contrib/xntpd/lib/gettstamp.c
new file mode 100644
index 000000000000..19bcb0c638ff
--- /dev/null
+++ b/contrib/xntpd/lib/gettstamp.c
@@ -0,0 +1,29 @@
+/* gettstamp.c,v 3.1 1993/07/06 01:08:20 jbj Exp
+ * gettstamp - return the system time in timestamp format
+ */
+#include <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/contrib/xntpd/lib/hextoint.c b/contrib/xntpd/lib/hextoint.c
new file mode 100644
index 000000000000..90329c4136f4
--- /dev/null
+++ b/contrib/xntpd/lib/hextoint.c
@@ -0,0 +1,38 @@
+/* hextoint.c,v 3.1 1993/07/06 01:08:21 jbj Exp
+ * hextoint - convert an ascii string in hex to an unsigned
+ * long, with error checking
+ */
+#include <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/contrib/xntpd/lib/hextolfp.c b/contrib/xntpd/lib/hextolfp.c
new file mode 100644
index 000000000000..6473c7c3dbca
--- /dev/null
+++ b/contrib/xntpd/lib/hextolfp.c
@@ -0,0 +1,66 @@
+/* hextolfp.c,v 3.1 1993/07/06 01:08:22 jbj Exp
+ * hextolfp - convert an ascii hex string to an l_fp number
+ */
+#include <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/contrib/xntpd/lib/humandate.c b/contrib/xntpd/lib/humandate.c
new file mode 100644
index 000000000000..464ed6ba4de4
--- /dev/null
+++ b/contrib/xntpd/lib/humandate.c
@@ -0,0 +1,61 @@
+/* humandate.c,v 3.1 1993/07/06 01:08:24 jbj Exp
+ * humandate - convert an NTP (or the current) time to something readable
+ */
+#include <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/contrib/xntpd/lib/inttoa.c b/contrib/xntpd/lib/inttoa.c
new file mode 100644
index 000000000000..25ce26cb8144
--- /dev/null
+++ b/contrib/xntpd/lib/inttoa.c
@@ -0,0 +1,19 @@
+/* inttoa.c,v 3.1 1993/07/06 01:08:25 jbj Exp
+ * inttoa - return an asciized signed integer
+ */
+#include <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/contrib/xntpd/lib/lib_strbuf.c b/contrib/xntpd/lib/lib_strbuf.c
new file mode 100644
index 000000000000..15661ab980ad
--- /dev/null
+++ b/contrib/xntpd/lib/lib_strbuf.c
@@ -0,0 +1,21 @@
+/* lib_strbuf.c,v 3.1 1993/07/06 01:08:27 jbj Exp
+ * lib_strbuf - library string storage
+ */
+
+#include "lib_strbuf.h"
+
+/*
+ * Storage declarations
+ */
+char lib_stringbuf[LIB_NUMBUFS][LIB_BUFLENGTH];
+int lib_nextbuf;
+
+
+/*
+ * initialization routine. Might be needed if the code is ROMized.
+ */
+void
+init_lib()
+{
+ lib_nextbuf = 0;
+}
diff --git a/contrib/xntpd/lib/lib_strbuf.h b/contrib/xntpd/lib/lib_strbuf.h
new file mode 100644
index 000000000000..20720fd5892b
--- /dev/null
+++ b/contrib/xntpd/lib/lib_strbuf.h
@@ -0,0 +1,22 @@
+/* lib_strbuf.h,v 3.1 1993/07/06 01:08:28 jbj Exp
+ * lib_strbuf.h - definitions for routines which use the common string buffers
+ */
+
+/*
+ * Sizes of things
+ */
+#define LIB_NUMBUFS 20
+#define LIB_BUFLENGTH 80
+
+/*
+ * Macro to get a pointer to the next buffer
+ */
+#define LIB_GETBUF(buf) \
+ do { \
+ buf = &lib_stringbuf[lib_nextbuf][0]; \
+ if (++lib_nextbuf >= LIB_NUMBUFS) \
+ lib_nextbuf = 0; \
+ } while (0)
+
+extern char lib_stringbuf[LIB_NUMBUFS][LIB_BUFLENGTH];
+extern int lib_nextbuf;
diff --git a/contrib/xntpd/lib/machines.c b/contrib/xntpd/lib/machines.c
new file mode 100644
index 000000000000..63eb5ccd67a7
--- /dev/null
+++ b/contrib/xntpd/lib/machines.c
@@ -0,0 +1,43 @@
+/* machines.c - provide special support for peculiar architectures
+ *
+ * Real bummers unite !
+ *
+ * $Id: machines.c,v 1.1.1.2 1994/02/03 22:04:12 wollman Exp $
+ */
+
+#include "ntp_stdlib.h"
+
+#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
+
+#if !defined(NTP_POSIX_SOURCE) || defined(NTP_NEED_BOPS)
+void
+ntp_memset(a, x, c)
+ char *a;
+ int x, c;
+{
+ while (c-- > 0)
+ *a++ = x;
+}
+#endif /*POSIX*/
diff --git a/contrib/xntpd/lib/md5.c b/contrib/xntpd/lib/md5.c
new file mode 100644
index 000000000000..77644cb32aa6
--- /dev/null
+++ b/contrib/xntpd/lib/md5.c
@@ -0,0 +1,322 @@
+/* md5.c,v 3.1 1993/07/06 01:08:29 jbj Exp
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ** -- G modified to have y&~z instead of y&z **
+ ** -- FF, GG, HH modified to add in last register done **
+ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
+ ** -- distinct additive constant for each step **
+ ** -- round 4 added, working mod 7 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ ** Message-digest routines: **
+ ** To form the message digest for a message M **
+ ** (1) Initialize a context buffer mdContext using MD5Init **
+ ** (2) Call MD5Update on mdContext and M **
+ ** (3) Call MD5Final on mdContext **
+ ** The message digest is now in mdContext->digest[0...15] **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform ();
+
+#ifdef __STDC__
+static const
+#else
+static
+#endif
+unsigned char PADDING[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#if defined(FAST_MD5) && defined(__GNUC__) && defined(mc68000)
+/*
+ * If we're on a 68000 based CPU and using a GNU C compiler with
+ * inline assembly code, we can speed this up a bit.
+ */
+inline UINT4 ROTATE_LEFT(UINT4 x, int n)
+{
+ asm("roll %2,%0" : "=d" (x) : "0" (x), "Ir" (n));
+ return x;
+}
+#else
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+#endif
+
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+ {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) \
+ {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) \
+ {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) \
+ {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* The routine MD5Init initializes the message-digest context
+ mdContext. All fields are set to zero.
+ */
+void MD5Init (mdContext)
+MD5_CTX *mdContext;
+{
+ mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+ /* Load magic initialization constants.
+ */
+ mdContext->buf[0] = (UINT4)0x67452301;
+ mdContext->buf[1] = (UINT4)0xefcdab89;
+ mdContext->buf[2] = (UINT4)0x98badcfe;
+ mdContext->buf[3] = (UINT4)0x10325476;
+}
+
+/* The routine MD5Update updates the message-digest context to
+ account for the presence of each of the characters inBuf[0..inLen-1]
+ in the message whose digest is being computed.
+ */
+void MD5Update (mdContext, inBuf, inLen)
+MD5_CTX *mdContext;
+unsigned char *inBuf;
+unsigned int inLen;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* update number of bits */
+ if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+ mdContext->i[1]++;
+ mdContext->i[0] += ((UINT4)inLen << 3);
+ mdContext->i[1] += ((UINT4)inLen >> 29);
+
+ while (inLen--) {
+ /* add new character to buffer, increment mdi */
+ mdContext->in[mdi++] = *inBuf++;
+
+ /* transform if necessary */
+ if (mdi == 0x40) {
+ for (i = 0, ii = 0; i < 16; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+ mdi = 0;
+ }
+ }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+ ends with the desired message digest in mdContext->digest[0...15].
+ */
+
+void MD5Final (mdContext)
+MD5_CTX *mdContext;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+ unsigned int padLen;
+
+ /* save number of bits */
+ in[14] = mdContext->i[0];
+ in[15] = mdContext->i[1];
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* pad out to 56 mod 64 */
+ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+ MD5Update (mdContext, PADDING, padLen);
+
+ /* append length in bits and transform */
+ for (i = 0, ii = 0; i < 14; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+
+ /* store buffer in digest */
+ for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+ mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+ mdContext->digest[ii+1] =
+ (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+ mdContext->digest[ii+2] =
+ (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+ mdContext->digest[ii+3] =
+ (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+ }
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+ UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+ FF ( a, b, c, d, in[ 0], S11, 0xd76aa478); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, 0xe8c7b756); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, 0x242070db); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, 0xc1bdceee); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, 0xf57c0faf); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, 0x4787c62a); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, 0xa8304613); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, 0xfd469501); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, 0x698098d8); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, 0x8b44f7af); /* 10 */
+ FF ( c, d, a, b, in[10], S13, 0xffff5bb1); /* 11 */
+ FF ( b, c, d, a, in[11], S14, 0x895cd7be); /* 12 */
+ FF ( a, b, c, d, in[12], S11, 0x6b901122); /* 13 */
+ FF ( d, a, b, c, in[13], S12, 0xfd987193); /* 14 */
+ FF ( c, d, a, b, in[14], S13, 0xa679438e); /* 15 */
+ FF ( b, c, d, a, in[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG ( a, b, c, d, in[ 1], S21, 0xf61e2562); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, 0xc040b340); /* 18 */
+ GG ( c, d, a, b, in[11], S23, 0x265e5a51); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, 0xd62f105d); /* 21 */
+ GG ( d, a, b, c, in[10], S22, 0x2441453); /* 22 */
+ GG ( c, d, a, b, in[15], S23, 0xd8a1e681); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, 0x21e1cde6); /* 25 */
+ GG ( d, a, b, c, in[14], S22, 0xc33707d6); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, 0xf4d50d87); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, 0x455a14ed); /* 28 */
+ GG ( a, b, c, d, in[13], S21, 0xa9e3e905); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, 0x676f02d9); /* 31 */
+ GG ( b, c, d, a, in[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH ( a, b, c, d, in[ 5], S31, 0xfffa3942); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, 0x8771f681); /* 34 */
+ HH ( c, d, a, b, in[11], S33, 0x6d9d6122); /* 35 */
+ HH ( b, c, d, a, in[14], S34, 0xfde5380c); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, 0xa4beea44); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH ( b, c, d, a, in[10], S34, 0xbebfbc70); /* 40 */
+ HH ( a, b, c, d, in[13], S31, 0x289b7ec6); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, 0xeaa127fa); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, 0xd4ef3085); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, 0x4881d05); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, 0xd9d4d039); /* 45 */
+ HH ( d, a, b, c, in[12], S32, 0xe6db99e5); /* 46 */
+ HH ( c, d, a, b, in[15], S33, 0x1fa27cf8); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II ( a, b, c, d, in[ 0], S41, 0xf4292244); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, 0x432aff97); /* 50 */
+ II ( c, d, a, b, in[14], S43, 0xab9423a7); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, 0xfc93a039); /* 52 */
+ II ( a, b, c, d, in[12], S41, 0x655b59c3); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, 0x8f0ccc92); /* 54 */
+ II ( c, d, a, b, in[10], S43, 0xffeff47d); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, 0x85845dd1); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, 0x6fa87e4f); /* 57 */
+ II ( d, a, b, c, in[15], S42, 0xfe2ce6e0); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, 0xa3014314); /* 59 */
+ II ( b, c, d, a, in[13], S44, 0x4e0811a1); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, 0xf7537e82); /* 61 */
+ II ( d, a, b, c, in[11], S42, 0xbd3af235); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, 0xeb86d391); /* 64 */
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ ***********************************************************************
+ ** End of md5.c **
+ ******************************** (cut) ********************************
+ */
diff --git a/contrib/xntpd/lib/mfptoa.c b/contrib/xntpd/lib/mfptoa.c
new file mode 100644
index 000000000000..4e513d24f8b0
--- /dev/null
+++ b/contrib/xntpd/lib/mfptoa.c
@@ -0,0 +1,22 @@
+/* mfptoa.c,v 3.1 1993/07/06 01:08:30 jbj Exp
+ * mfptoa - Return an asciized representation of a signed LONG fp number
+ */
+#include "ntp_fp.h"
+#include "ntp_stdlib.h"
+
+char *
+mfptoa(fpi, fpf, ndec)
+ U_LONG fpi;
+ U_LONG fpf;
+ int ndec;
+{
+ int isneg;
+
+ if (M_ISNEG(fpi, fpf)) {
+ isneg = 1;
+ M_NEG(fpi, fpf);
+ } else
+ isneg = 0;
+
+ return dolfptoa(fpi, fpf, isneg, ndec, 0);
+}
diff --git a/contrib/xntpd/lib/mfptoms.c b/contrib/xntpd/lib/mfptoms.c
new file mode 100644
index 000000000000..f686d413edba
--- /dev/null
+++ b/contrib/xntpd/lib/mfptoms.c
@@ -0,0 +1,22 @@
+/* mfptoms.c,v 3.1 1993/07/06 01:08:31 jbj Exp
+ * mfptoms - Return an asciized signed LONG fp number in milliseconds
+ */
+#include "ntp_fp.h"
+#include "ntp_stdlib.h"
+
+char *
+mfptoms(fpi, fpf, ndec)
+ U_LONG fpi;
+ U_LONG fpf;
+ int ndec;
+{
+ int isneg;
+
+ if (M_ISNEG(fpi, fpf)) {
+ isneg = 1;
+ M_NEG(fpi, fpf);
+ } else
+ isneg = 0;
+
+ return dolfptoa(fpi, fpf, isneg, ndec, 1);
+}
diff --git a/contrib/xntpd/lib/modetoa.c b/contrib/xntpd/lib/modetoa.c
new file mode 100644
index 000000000000..483327186a11
--- /dev/null
+++ b/contrib/xntpd/lib/modetoa.c
@@ -0,0 +1,33 @@
+/* modetoa.c,v 3.1 1993/07/06 01:08:33 jbj Exp
+ * modetoa - return an asciized mode
+ */
+#include <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/contrib/xntpd/lib/mstolfp.c b/contrib/xntpd/lib/mstolfp.c
new file mode 100644
index 000000000000..8a642cf0a55b
--- /dev/null
+++ b/contrib/xntpd/lib/mstolfp.c
@@ -0,0 +1,99 @@
+/* mstolfp.c,v 3.1 1993/07/06 01:08:34 jbj Exp
+ * mstolfp - convert an ascii string in milliseconds to an l_fp number
+ */
+#include <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/contrib/xntpd/lib/msutotsf.c b/contrib/xntpd/lib/msutotsf.c
new file mode 100644
index 000000000000..412cfbd1ed96
--- /dev/null
+++ b/contrib/xntpd/lib/msutotsf.c
@@ -0,0 +1,35 @@
+/* msutotsf.c,v 3.1 1993/07/06 01:08:35 jbj Exp
+ * msutotsf - tables for converting from a subsecond millisecond value
+ * to a time stamp fraction.
+ */
+#include <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/contrib/xntpd/lib/msyslog.c b/contrib/xntpd/lib/msyslog.c
new file mode 100644
index 000000000000..a6186b72ef34
--- /dev/null
+++ b/contrib/xntpd/lib/msyslog.c
@@ -0,0 +1,108 @@
+/* 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);
+ }
+ }
+ if (!syslogit)
+ *n++ = '\n';
+ *n = '\0';
+
+ vsprintf(buf, nfmt, ap);
+ if (syslogit)
+ syslog(level, buf);
+ else {
+ extern char * humanlogtime P((void));
+
+ FILE *out_file = syslog_file ? syslog_file
+ : level <= LOG_ERR ? stderr : stdout;
+ /* syslog() provides the timestamp, so if we're not using
+ syslog, we must provide it. */
+ prog = strrchr(progname, '/');
+ if (prog == NULL)
+ prog = progname;
+ else
+ prog++;
+ (void) fprintf(out_file, "%s ", humanlogtime ());
+ (void) fprintf(out_file, "%s: %s", prog, buf);
+ fflush (out_file);
+ }
+ va_end(ap);
+}
diff --git a/contrib/xntpd/lib/numtoa.c b/contrib/xntpd/lib/numtoa.c
new file mode 100644
index 000000000000..c36885d19e68
--- /dev/null
+++ b/contrib/xntpd/lib/numtoa.c
@@ -0,0 +1,24 @@
+/* numtoa.c,v 3.1 1993/07/06 01:08:38 jbj Exp
+ * numtoa - return asciized network numbers store in local array space
+ */
+#include <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/contrib/xntpd/lib/numtohost.c b/contrib/xntpd/lib/numtohost.c
new file mode 100644
index 000000000000..e22b6231790a
--- /dev/null
+++ b/contrib/xntpd/lib/numtohost.c
@@ -0,0 +1,39 @@
+/* numtohost.c,v 3.1 1993/07/06 01:08:40 jbj Exp
+ * numtohost - convert network number to host name.
+ */
+#include "ntp_types.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/contrib/xntpd/lib/octtoint.c b/contrib/xntpd/lib/octtoint.c
new file mode 100644
index 000000000000..1f25b1d57693
--- /dev/null
+++ b/contrib/xntpd/lib/octtoint.c
@@ -0,0 +1,34 @@
+/* octtoint.c,v 3.1 1993/07/06 01:08:41 jbj Exp
+ * octtoint - convert an ascii string in octal to an unsigned
+ * long, with error checking
+ */
+#include <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/contrib/xntpd/lib/prettydate.c b/contrib/xntpd/lib/prettydate.c
new file mode 100644
index 000000000000..ad679bd872ce
--- /dev/null
+++ b/contrib/xntpd/lib/prettydate.c
@@ -0,0 +1,44 @@
+/* prettydate.c,v 3.1 1993/07/06 01:08:42 jbj Exp
+ * prettydate - convert a time stamp to something readable
+ */
+#include <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/contrib/xntpd/lib/ranny.c b/contrib/xntpd/lib/ranny.c
new file mode 100644
index 000000000000..2a47e03f59ac
--- /dev/null
+++ b/contrib/xntpd/lib/ranny.c
@@ -0,0 +1,97 @@
+/* ranny.c,v 3.1 1993/07/06 01:08:43 jbj Exp
+ * Random number generator is:
+ *
+ * Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
+ * This will be free software, but only when it is finished.
+ *
+ * Used in xntp by permission of the author. If copyright is
+ * annoying to you, read no further. Instead, look up the reference,
+ * write me an equivalent to this and send it back to me.
+ */
+
+/*
+ * Random number generator; see Knuth Vol 2. 2nd ed. p.27 (section 3.2.2)
+ */
+#include "ntp_stdlib.h"
+
+extern time_t time P((time_t *loc));
+
+/*
+ * 55 random numbers, not all even. Note we don't initialize ran_y
+ * directly since I have had thoughts of putting this in an EPROM
+ */
+static U_LONG ran_y[55];
+
+static U_LONG init_ran_y[55] = {
+ 1860909544, 231033423, 437666411, 1349655137, 2014584962,
+ 504613712, 656256107, 1246027206, 573713775, 643466871,
+ 540235388, 1630565153, 443649364, 729302839, 1933991552,
+ 944681982, 949111118, 406212522, 1065063137, 1712954727,
+ 73280612, 787623973, 1874130997, 801658492, 73395958,
+ 739165367, 596047144, 490055249, 1131094323, 662727104,
+ 483614097, 844520219, 893760527, 921280508, 46691708,
+ 760861842, 1425894220, 702947816, 2006889048, 1999607995,
+ 1346414687, 399640789, 1482689501, 1790064052, 1128943628,
+ 1269197405, 587262386, 2078054746, 1675409928, 1652325524,
+ 1643525825, 1748690540, 292465849, 1370173174, 402865384
+};
+
+static int ran_j;
+static int ran_k;
+
+
+/*
+ * ranp2 - return a random integer in the range 0 .. (1<<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/contrib/xntpd/lib/refnumtoa.c b/contrib/xntpd/lib/refnumtoa.c
new file mode 100644
index 000000000000..31175d9f877b
--- /dev/null
+++ b/contrib/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/contrib/xntpd/lib/syssignal.c b/contrib/xntpd/lib/syssignal.c
new file mode 100644
index 000000000000..f8abfddfe4fd
--- /dev/null
+++ b/contrib/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/contrib/xntpd/lib/systime.c b/contrib/xntpd/lib/systime.c
new file mode 100644
index 000000000000..ea15734f1abb
--- /dev/null
+++ b/contrib/xntpd/lib/systime.c
@@ -0,0 +1,375 @@
+/* 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(SYS_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
+ }
+
+ if (adjtime(&adjtv, &oadjtv) < 0) {
+ syslog(LOG_ERR, "Can't do time adjustment: %m");
+ rval = 0;
+ } else {
+ sys_clock_offset.l_ui = offset_i;
+ sys_clock_offset.l_uf = offset_f;
+ 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) {
+ sTVTOTS(&oadjtv, &oadjts);
+ L_ADD(&sys_clock_offset, &oadjts);
+ if (max_no_complete > 0) {
+ 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) {
+ memset((char *)&ut, 0, sizeof(ut));
+ ut.ut_type = OLD_TIME;
+ ut.ut_time = oldtime;
+ (void)strcpy(ut.ut_line, OTIME_MSG);
+ pututline(&ut);
+ setutent();
+ ut.ut_type = NEW_TIME;
+ ut.ut_time = timetv.tv_sec;
+ (void)strcpy(ut.ut_line, NTIME_MSG);
+ pututline(&ut);
+ utmpname(WTMP_FILE);
+ ut.ut_type = OLD_TIME;
+ ut.ut_time = oldtime;
+ (void)strcpy(ut.ut_line, OTIME_MSG);
+ pututline(&ut);
+ ut.ut_type = NEW_TIME;
+ ut.ut_time = timetv.tv_sec;
+ (void)strcpy(ut.ut_line, NTIME_MSG);
+ pututline(&ut);
+ endutent();
+ }
+#endif
+ return 1;
+}
diff --git a/contrib/xntpd/lib/tsftomsu.c b/contrib/xntpd/lib/tsftomsu.c
new file mode 100644
index 000000000000..b9161141d359
--- /dev/null
+++ b/contrib/xntpd/lib/tsftomsu.c
@@ -0,0 +1,37 @@
+/* tsftomsu.c,v 3.1 1993/07/06 01:08:47 jbj Exp
+ * tsftomsu - convert from a time stamp fraction to milliseconds
+ */
+#include "ntp_fp.h"
+#include "ntp_stdlib.h"
+
+int
+tsftomsu(tsf, round)
+ U_LONG tsf;
+ int round;
+{
+ register U_LONG val_ui, val_uf;
+ register U_LONG tmp_ui, tmp_uf;
+ register int i;
+
+ /*
+ * Essentially, multiply by 10 three times in l_fp form.
+ * The integral part is the milliseconds.
+ */
+ val_ui = 0;
+ val_uf = tsf;
+ for (i = 3; i > 0; i--) {
+ M_LSHIFT(val_ui, val_uf);
+ tmp_ui = val_ui;
+ tmp_uf = val_uf;
+ M_LSHIFT(val_ui, val_uf);
+ M_LSHIFT(val_ui, val_uf);
+ M_ADD(val_ui, val_uf, tmp_ui, tmp_uf);
+ }
+
+ /*
+ * Round the value if need be, then return it.
+ */
+ if (round && (val_uf & 0x80000000))
+ val_ui++;
+ return (int)val_ui;
+}
diff --git a/contrib/xntpd/lib/tstotod.c b/contrib/xntpd/lib/tstotod.c
new file mode 100644
index 000000000000..a78aea1c2ed9
--- /dev/null
+++ b/contrib/xntpd/lib/tstotod.c
@@ -0,0 +1,21 @@
+#ifdef ELIMINATE
+/* tstotod.c,v 3.1 1993/07/06 01:08:48 jbj Exp
+ * tstotod - compute calendar time given an NTP timestamp
+ */
+#include <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/contrib/xntpd/lib/tstotv.c b/contrib/xntpd/lib/tstotv.c
new file mode 100644
index 000000000000..c9b0d1c036ad
--- /dev/null
+++ b/contrib/xntpd/lib/tstotv.c
@@ -0,0 +1,135 @@
+/* tstotv.c,v 3.1 1993/07/06 01:08:49 jbj Exp
+ * tstotv - tables for converting from NTP time stamps to struct timeval
+ */
+
+#include "ntp_types.h"
+
+/*
+ * Tables to convert from a time stamp fraction to usecs. Note that
+ * the units of these tables are actually (usec<<3). We carry three
+ * guard bits so that the result can be properly truncated (or rounded)
+ * to be correct to the least significant bit.
+ *
+ * These tables are rounded.
+ */
+
+LONG tstoushi[256] = {
+ 0x000000, 0x007a12, 0x00f424, 0x016e36,
+ 0x01e848, 0x02625a, 0x02dc6c, 0x03567e,
+ 0x03d090, 0x044aa2, 0x04c4b4, 0x053ec6,
+ 0x05b8d8, 0x0632ea, 0x06acfc, 0x07270e,
+ 0x07a120, 0x081b32, 0x089544, 0x090f56,
+ 0x098968, 0x0a037a, 0x0a7d8c, 0x0af79e,
+ 0x0b71b0, 0x0bebc2, 0x0c65d4, 0x0cdfe6,
+ 0x0d59f8, 0x0dd40a, 0x0e4e1c, 0x0ec82e,
+ 0x0f4240, 0x0fbc52, 0x103664, 0x10b076,
+ 0x112a88, 0x11a49a, 0x121eac, 0x1298be,
+ 0x1312d0, 0x138ce2, 0x1406f4, 0x148106,
+ 0x14fb18, 0x15752a, 0x15ef3c, 0x16694e,
+ 0x16e360, 0x175d72, 0x17d784, 0x185196,
+ 0x18cba8, 0x1945ba, 0x19bfcc, 0x1a39de,
+ 0x1ab3f0, 0x1b2e02, 0x1ba814, 0x1c2226,
+ 0x1c9c38, 0x1d164a, 0x1d905c, 0x1e0a6e,
+ 0x1e8480, 0x1efe92, 0x1f78a4, 0x1ff2b6,
+ 0x206cc8, 0x20e6da, 0x2160ec, 0x21dafe,
+ 0x225510, 0x22cf22, 0x234934, 0x23c346,
+ 0x243d58, 0x24b76a, 0x25317c, 0x25ab8e,
+ 0x2625a0, 0x269fb2, 0x2719c4, 0x2793d6,
+ 0x280de8, 0x2887fa, 0x29020c, 0x297c1e,
+ 0x29f630, 0x2a7042, 0x2aea54, 0x2b6466,
+ 0x2bde78, 0x2c588a, 0x2cd29c, 0x2d4cae,
+ 0x2dc6c0, 0x2e40d2, 0x2ebae4, 0x2f34f6,
+ 0x2faf08, 0x30291a, 0x30a32c, 0x311d3e,
+ 0x319750, 0x321162, 0x328b74, 0x330586,
+ 0x337f98, 0x33f9aa, 0x3473bc, 0x34edce,
+ 0x3567e0, 0x35e1f2, 0x365c04, 0x36d616,
+ 0x375028, 0x37ca3a, 0x38444c, 0x38be5e,
+ 0x393870, 0x39b282, 0x3a2c94, 0x3aa6a6,
+ 0x3b20b8, 0x3b9aca, 0x3c14dc, 0x3c8eee,
+ 0x3d0900, 0x3d8312, 0x3dfd24, 0x3e7736,
+ 0x3ef148, 0x3f6b5a, 0x3fe56c, 0x405f7e,
+ 0x40d990, 0x4153a2, 0x41cdb4, 0x4247c6,
+ 0x42c1d8, 0x433bea, 0x43b5fc, 0x44300e,
+ 0x44aa20, 0x452432, 0x459e44, 0x461856,
+ 0x469268, 0x470c7a, 0x47868c, 0x48009e,
+ 0x487ab0, 0x48f4c2, 0x496ed4, 0x49e8e6,
+ 0x4a62f8, 0x4add0a, 0x4b571c, 0x4bd12e,
+ 0x4c4b40, 0x4cc552, 0x4d3f64, 0x4db976,
+ 0x4e3388, 0x4ead9a, 0x4f27ac, 0x4fa1be,
+ 0x501bd0, 0x5095e2, 0x510ff4, 0x518a06,
+ 0x520418, 0x527e2a, 0x52f83c, 0x53724e,
+ 0x53ec60, 0x546672, 0x54e084, 0x555a96,
+ 0x55d4a8, 0x564eba, 0x56c8cc, 0x5742de,
+ 0x57bcf0, 0x583702, 0x58b114, 0x592b26,
+ 0x59a538, 0x5a1f4a, 0x5a995c, 0x5b136e,
+ 0x5b8d80, 0x5c0792, 0x5c81a4, 0x5cfbb6,
+ 0x5d75c8, 0x5defda, 0x5e69ec, 0x5ee3fe,
+ 0x5f5e10, 0x5fd822, 0x605234, 0x60cc46,
+ 0x614658, 0x61c06a, 0x623a7c, 0x62b48e,
+ 0x632ea0, 0x63a8b2, 0x6422c4, 0x649cd6,
+ 0x6516e8, 0x6590fa, 0x660b0c, 0x66851e,
+ 0x66ff30, 0x677942, 0x67f354, 0x686d66,
+ 0x68e778, 0x69618a, 0x69db9c, 0x6a55ae,
+ 0x6acfc0, 0x6b49d2, 0x6bc3e4, 0x6c3df6,
+ 0x6cb808, 0x6d321a, 0x6dac2c, 0x6e263e,
+ 0x6ea050, 0x6f1a62, 0x6f9474, 0x700e86,
+ 0x708898, 0x7102aa, 0x717cbc, 0x71f6ce,
+ 0x7270e0, 0x72eaf2, 0x736504, 0x73df16,
+ 0x745928, 0x74d33a, 0x754d4c, 0x75c75e,
+ 0x764170, 0x76bb82, 0x773594, 0x77afa6,
+ 0x7829b8, 0x78a3ca, 0x791ddc, 0x7997ee
+};
+
+LONG tstousmid[256] = {
+ 0x0000, 0x007a, 0x00f4, 0x016e, 0x01e8, 0x0262, 0x02dc, 0x0356,
+ 0x03d1, 0x044b, 0x04c5, 0x053f, 0x05b9, 0x0633, 0x06ad, 0x0727,
+ 0x07a1, 0x081b, 0x0895, 0x090f, 0x0989, 0x0a03, 0x0a7e, 0x0af8,
+ 0x0b72, 0x0bec, 0x0c66, 0x0ce0, 0x0d5a, 0x0dd4, 0x0e4e, 0x0ec8,
+ 0x0f42, 0x0fbc, 0x1036, 0x10b0, 0x112b, 0x11a5, 0x121f, 0x1299,
+ 0x1313, 0x138d, 0x1407, 0x1481, 0x14fb, 0x1575, 0x15ef, 0x1669,
+ 0x16e3, 0x175d, 0x17d8, 0x1852, 0x18cc, 0x1946, 0x19c0, 0x1a3a,
+ 0x1ab4, 0x1b2e, 0x1ba8, 0x1c22, 0x1c9c, 0x1d16, 0x1d90, 0x1e0a,
+ 0x1e84, 0x1eff, 0x1f79, 0x1ff3, 0x206d, 0x20e7, 0x2161, 0x21db,
+ 0x2255, 0x22cf, 0x2349, 0x23c3, 0x243d, 0x24b7, 0x2531, 0x25ac,
+ 0x2626, 0x26a0, 0x271a, 0x2794, 0x280e, 0x2888, 0x2902, 0x297c,
+ 0x29f6, 0x2a70, 0x2aea, 0x2b64, 0x2bde, 0x2c59, 0x2cd3, 0x2d4d,
+ 0x2dc7, 0x2e41, 0x2ebb, 0x2f35, 0x2faf, 0x3029, 0x30a3, 0x311d,
+ 0x3197, 0x3211, 0x328b, 0x3306, 0x3380, 0x33fa, 0x3474, 0x34ee,
+ 0x3568, 0x35e2, 0x365c, 0x36d6, 0x3750, 0x37ca, 0x3844, 0x38be,
+ 0x3938, 0x39b3, 0x3a2d, 0x3aa7, 0x3b21, 0x3b9b, 0x3c15, 0x3c8f,
+ 0x3d09, 0x3d83, 0x3dfd, 0x3e77, 0x3ef1, 0x3f6b, 0x3fe5, 0x405f,
+ 0x40da, 0x4154, 0x41ce, 0x4248, 0x42c2, 0x433c, 0x43b6, 0x4430,
+ 0x44aa, 0x4524, 0x459e, 0x4618, 0x4692, 0x470c, 0x4787, 0x4801,
+ 0x487b, 0x48f5, 0x496f, 0x49e9, 0x4a63, 0x4add, 0x4b57, 0x4bd1,
+ 0x4c4b, 0x4cc5, 0x4d3f, 0x4db9, 0x4e34, 0x4eae, 0x4f28, 0x4fa2,
+ 0x501c, 0x5096, 0x5110, 0x518a, 0x5204, 0x527e, 0x52f8, 0x5372,
+ 0x53ec, 0x5466, 0x54e1, 0x555b, 0x55d5, 0x564f, 0x56c9, 0x5743,
+ 0x57bd, 0x5837, 0x58b1, 0x592b, 0x59a5, 0x5a1f, 0x5a99, 0x5b13,
+ 0x5b8d, 0x5c08, 0x5c82, 0x5cfc, 0x5d76, 0x5df0, 0x5e6a, 0x5ee4,
+ 0x5f5e, 0x5fd8, 0x6052, 0x60cc, 0x6146, 0x61c0, 0x623a, 0x62b5,
+ 0x632f, 0x63a9, 0x6423, 0x649d, 0x6517, 0x6591, 0x660b, 0x6685,
+ 0x66ff, 0x6779, 0x67f3, 0x686d, 0x68e7, 0x6962, 0x69dc, 0x6a56,
+ 0x6ad0, 0x6b4a, 0x6bc4, 0x6c3e, 0x6cb8, 0x6d32, 0x6dac, 0x6e26,
+ 0x6ea0, 0x6f1a, 0x6f94, 0x700f, 0x7089, 0x7103, 0x717d, 0x71f7,
+ 0x7271, 0x72eb, 0x7365, 0x73df, 0x7459, 0x74d3, 0x754d, 0x75c7,
+ 0x7641, 0x76bc, 0x7736, 0x77b0, 0x782a, 0x78a4, 0x791e, 0x7998
+};
+
+LONG tstouslo[128] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+ 0x1f, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+ 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x33, 0x34,
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
+ 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
+ 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b,
+ 0x5c, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
+ 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+ 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x71,
+ 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79
+};
diff --git a/contrib/xntpd/lib/tvtoa.c b/contrib/xntpd/lib/tvtoa.c
new file mode 100644
index 000000000000..778caa1cee26
--- /dev/null
+++ b/contrib/xntpd/lib/tvtoa.c
@@ -0,0 +1,33 @@
+/* tvtoa.c,v 3.1 1993/07/06 01:08:50 jbj Exp
+ * tvtoa - return an asciized representation of a struct timeval
+ */
+#include <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/contrib/xntpd/lib/tvtots.c b/contrib/xntpd/lib/tvtots.c
new file mode 100644
index 000000000000..befc48055933
--- /dev/null
+++ b/contrib/xntpd/lib/tvtots.c
@@ -0,0 +1,159 @@
+/* tvtots.c,v 3.1 1993/07/06 01:08:51 jbj Exp
+ * tvtots - tables for converting from Unix struct timeval's to
+ * NTP time stamp format.
+ */
+#include <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/contrib/xntpd/lib/uglydate.c b/contrib/xntpd/lib/uglydate.c
new file mode 100644
index 000000000000..308c70336232
--- /dev/null
+++ b/contrib/xntpd/lib/uglydate.c
@@ -0,0 +1,53 @@
+/* uglydate.c,v 3.1 1993/07/06 01:08:53 jbj Exp
+ * uglydate - convert a time stamp to something barely readable
+ * The string returned is 37 characters long.
+ */
+#include <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/contrib/xntpd/lib/uinttoa.c b/contrib/xntpd/lib/uinttoa.c
new file mode 100644
index 000000000000..ce29390342b0
--- /dev/null
+++ b/contrib/xntpd/lib/uinttoa.c
@@ -0,0 +1,19 @@
+/* uinttoa.c,v 3.1 1993/07/06 01:08:54 jbj Exp
+ * uinttoa - return an asciized unsigned integer
+ */
+#include <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/contrib/xntpd/lib/utvtoa.c b/contrib/xntpd/lib/utvtoa.c
new file mode 100644
index 000000000000..b573f187a38f
--- /dev/null
+++ b/contrib/xntpd/lib/utvtoa.c
@@ -0,0 +1,21 @@
+/* utvtoa.c,v 3.1 1993/07/06 01:08:55 jbj Exp
+ * utvtoa - return an asciized representation of an unsigned struct timeval
+ */
+#include <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/contrib/xntpd/machines/.keep_me b/contrib/xntpd/machines/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/machines/.keep_me
diff --git a/contrib/xntpd/ntpdate/Makefile b/contrib/xntpd/ntpdate/Makefile
new file mode 100644
index 000000000000..7f97eb51e05b
--- /dev/null
+++ b/contrib/xntpd/ntpdate/Makefile
@@ -0,0 +1,28 @@
+#
+# $Id: Makefile,v 1.3 1993/12/22 11:32:56 rgrimes Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= ntpdate
+MAN8= ${.CURDIR}/../doc/ntpdate.8
+CLEANFILES+= .version version.c
+
+SRCS= ntpdate.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion ntpdate
+
+.include <bsd.prog.mk>
diff --git a/contrib/xntpd/ntpdate/README b/contrib/xntpd/ntpdate/README
new file mode 100644
index 000000000000..fd2dbe2e2c49
--- /dev/null
+++ b/contrib/xntpd/ntpdate/README
@@ -0,0 +1,7 @@
+README file for directory ./ntpdate of the NTP Version 3 distribution
+
+This directory contains the sources for the ntpdate utility program. See
+the README and RELNOTES files in the parent directory for directions on
+how to make and install this program. The current version number of this
+program is in the version.c file.
+
diff --git a/contrib/xntpd/ntpdate/ntpdate.c b/contrib/xntpd/ntpdate/ntpdate.c
new file mode 100644
index 000000000000..b5ad05dc9baa
--- /dev/null
+++ b/contrib/xntpd/ntpdate/ntpdate.c
@@ -0,0 +1,1590 @@
+/* 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 *ntp_optarg;
+ extern int ntp_optind;
+ extern char *Version;
+
+ errflg = 0;
+ progname = argv[0];
+ syslogit = 0;
+
+ /*
+ * Decode argument list
+ */
+ while ((c = ntp_getopt(argc, argv, "a:bde:k:o:p:qst:v")) != EOF)
+ switch (c) {
+ case 'a':
+ c = atoi(ntp_optarg);
+ sys_authenticate = 1;
+ sys_authkey = (U_LONG)c;
+ break;
+ case 'b':
+ always_step++;
+ break;
+ case 'd':
+ ++debug;
+ break;
+ case 'e':
+ if (!atolfp(ntp_optarg, &tmp)
+ || tmp.l_ui != 0) {
+ (void) fprintf(stderr,
+ "%s: encryption delay %s is unlikely\n",
+ progname, ntp_optarg);
+ errflg++;
+ } else {
+ sys_authdelay = tmp.l_uf;
+ }
+ break;
+ case 'k':
+ key_file = ntp_optarg;
+ break;
+ case 'o':
+ sys_version = atoi(ntp_optarg);
+ break;
+ case 'p':
+ c = atoi(ntp_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(ntp_optarg, &tmp)) {
+ (void) fprintf(stderr,
+ "%s: timeout %s is undecodeable\n",
+ progname, ntp_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 - ntp_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 ( ; ntp_optind < argc; ntp_optind++)
+ addserver(argv[ntp_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 ||
+ 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));
+ memset((char *)server, 0, 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;
+
+ memset((char *)&addr, 0, 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) {
+ memmove((char *)num, hp->h_addr, 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;
+ memmove(junk, (char *)&pp->refid, 4);
+ str = junk;
+ } else {
+ str = numtoa(pp->refid);
+ }
+ (void) fprintf(fp,
+ "refid [%s], delay %s, dispersion %s\n",
+ str, fptoa(pp->delay, 4),
+ ufptoa(pp->dispersion, 4));
+
+ (void) fprintf(fp, "transmitted %d, in filter %d\n",
+ pp->xmtcnt, pp->filter_nextpt);
+
+ (void) fprintf(fp, "reference time: %s\n",
+ prettydate(&pp->reftime));
+ (void) fprintf(fp, "originate timestamp: %s\n",
+ prettydate(&pp->org));
+ (void) fprintf(fp, "transmit timestamp: %s\n",
+ prettydate(&pp->xmt));
+
+ (void) fprintf(fp, "filter delay: ");
+ for (i = 0; i < NTP_SHIFT; i++) {
+ (void) fprintf(fp, " %-8.8s", ufptoa(pp->filter_delay[i],4));
+ if (i == (NTP_SHIFT>>1)-1)
+ (void) fprintf(fp, "\n ");
+ }
+ (void) fprintf(fp, "\n");
+
+ (void) fprintf(fp, "filter offset:");
+ for (i = 0; i < PEER_SHIFT; i++) {
+ (void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 5));
+ if (i == (PEER_SHIFT>>1)-1)
+ (void) fprintf(fp, "\n ");
+ }
+ (void) fprintf(fp, "\n");
+
+ (void) fprintf(fp, "delay %s, dispersion %s\n",
+ ufptoa(pp->delay, 4), ufptoa(pp->dispersion, 4));
+
+ (void) fprintf(fp, "offset %s\n\n",
+ lfptoa(&pp->offset, 7));
+}
+
+#if defined(NEED_VSPRINTF)
+/*
+ * This nugget for pre-tahoe 4.3bsd systems
+ */
+#if !defined(__STDC__) || !__STDC__
+#define const
+#endif
+
+int
+vsprintf(str, fmt, ap)
+ char *str;
+ const char *fmt;
+ va_list ap;
+{
+ FILE f;
+ int len;
+
+ f._flag = _IOWRT+_IOSTRG;
+ f._ptr = str;
+ f._cnt = 32767;
+ len = _doprnt(fmt, ap, &f);
+ *f._ptr = 0;
+ return (len);
+}
+#endif
+
diff --git a/contrib/xntpd/ntpdate/ntpdate.h b/contrib/xntpd/ntpdate/ntpdate.h
new file mode 100644
index 000000000000..4a8ff746e772
--- /dev/null
+++ b/contrib/xntpd/ntpdate/ntpdate.h
@@ -0,0 +1,86 @@
+/* ntpdate.h,v 3.1 1993/07/06 01:09:23 jbj Exp
+ * ntpdate.h - declarations for the ntpdate program
+ */
+
+#include "ntp_malloc.h"
+
+/*
+ * The server structure is a much simplified version of the
+ * peer structure, for ntpdate's use. Since we always send
+ * in client mode and expect to receive in server mode, this
+ * leaves only a very limited number of things we need to
+ * remember about the server.
+ */
+struct server {
+ struct sockaddr_in srcadr; /* address of remote host */
+ u_char leap; /* leap indicator */
+ u_char stratum; /* stratum of remote server */
+ s_char precision; /* server's clock precision */
+ u_char trust; /* trustability of the filtered data */
+ u_fp rootdelay; /* distance from primary clock */
+ u_fp rootdispersion; /* peer clock dispersion */
+ U_LONG refid; /* peer reference ID */
+ l_fp reftime; /* time of peer's last update */
+ U_LONG event_time; /* time for next timeout */
+ u_short xmtcnt; /* number of packets transmitted */
+ u_short filter_nextpt; /* index into filter shift register */
+ s_fp filter_delay[NTP_SHIFT]; /* delay part of shift register */
+ l_fp filter_offset[NTP_SHIFT]; /* offset part of shift register */
+ s_fp filter_soffset[NTP_SHIFT]; /* offset in s_fp format, for disp */
+ u_fp filter_error[NTP_SHIFT]; /* error part of shift register */
+ l_fp org; /* peer's originate time stamp */
+ l_fp xmt; /* transmit time stamp */
+ u_fp delay; /* filter estimated delay */
+ u_fp dispersion; /* filter estimated dispersion */
+ l_fp offset; /* filter estimated clock offset */
+ s_fp soffset; /* fp version of above */
+};
+
+
+/*
+ * ntpdate runs everything on a simple, short timeout. It sends a
+ * packet and sets the timeout (by default, to a small value suitable
+ * for a LAN). If it receives a response it sends another request.
+ * If it times out it shifts zeroes into the filter and sends another
+ * request.
+ *
+ * The timer routine is run often (once every 1/5 second currently)
+ * so that time outs are done with reasonable precision.
+ */
+#define TIMER_HZ (5) /* 5 per second */
+
+/*
+ * ntpdate will make a LONG adjustment using adjtime() if the times
+ * are close, or step the time if the times are farther apart. The
+ * following defines what is "close".
+ */
+#define NTPDATE_THRESHOLD (FP_SECOND >> 1) /* 1/2 second */
+
+/*
+ * When doing adjustments, ntpdate actually overadjusts (currently
+ * by 50%, though this may change). While this will make it take longer
+ * to reach a steady state condition, it will typically result in
+ * the clock keeping more accurate time, on average. The amount of
+ * overshoot is limited.
+ */
+#ifdef NOTNOW
+#define ADJ_OVERSHOOT 1/2 /* this is hard coded */
+#endif /* NOTNOW */
+#define ADJ_MAXOVERSHOOT 0x10000000 /* 50 ms as a ts fraction */
+
+/*
+ * Since ntpdate isn't aware of some of the things that normally get
+ * put in an NTP packet, we fix some values.
+ */
+#define NTPDATE_PRECISION (-6) /* use this precision */
+#define NTPDATE_DISTANCE FP_SECOND /* distance is 1 sec */
+#define NTPDATE_DISP FP_SECOND /* so is the dispersion */
+#define NTPDATE_REFID (0) /* reference ID to use */
+
+
+/*
+ * Some defaults
+ */
+#define DEFTIMEOUT 5 /* 5 timer increments */
+#define DEFSAMPLES 4 /* get 4 samples per server */
+#define DEFPRECISION (-5) /* the precision we claim */
diff --git a/contrib/xntpd/ntpq/Makefile b/contrib/xntpd/ntpq/Makefile
new file mode 100644
index 000000000000..ea09b314a0b3
--- /dev/null
+++ b/contrib/xntpd/ntpq/Makefile
@@ -0,0 +1,29 @@
+#
+# $Id: Makefile,v 1.3 1993/12/22 11:33:07 rgrimes Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= ntpq
+MAN8= ${.CURDIR}/../doc/ntpq.8
+CLEANFILES+= .version version.c
+BINDIR= /usr/bin
+
+SRCS= ntpq.c ntpq_ops.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion ntpq
+
+.include <bsd.prog.mk>
diff --git a/contrib/xntpd/ntpq/README b/contrib/xntpd/ntpq/README
new file mode 100644
index 000000000000..117c66ce978b
--- /dev/null
+++ b/contrib/xntpd/ntpq/README
@@ -0,0 +1,6 @@
+README file for directory ./ntpq of the NTP Version 3 distribution
+
+This directory contains the sources for the ntpq utility program. See
+the README and RELNOTES files in the parent directory for directions on
+how to make and install this program. The current version number of this
+program is in the version.c file.
diff --git a/contrib/xntpd/ntpq/ntpq.c b/contrib/xntpd/ntpq/ntpq.c
new file mode 100644
index 000000000000..5cfc3daff820
--- /dev/null
+++ b/contrib/xntpd/ntpq/ntpq.c
@@ -0,0 +1,3063 @@
+/* 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) || defined(SYS_BSDI)
+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) || defined(SYS_BSDI)
+static int assoccmp P((const void *, const void *));
+#else
+static int assoccmp P((struct association *, struct association *));
+#endif /* sgi || bsdi */
+
+
+/*
+ * 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 ntp_optind;
+ extern char *ntp_optarg;
+
+ delay_time.l_ui = 0;
+ delay_time.l_uf = DEFDELAY;
+
+ progname = argv[0];
+ while ((c = ntp_getopt(argc, argv, "c:dinp")) != EOF)
+ switch (c) {
+ case 'c':
+ ADDCMD(ntp_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 (ntp_optind == argc) {
+ ADDHOST(DEFHOST);
+ } else {
+ for (; ntp_optind < argc; ntp_optind++)
+ ADDHOST(argv[ntp_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.
+ */
+ memmove((char *)pktdata + offset, (char *)rpkt.data, 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) {
+ memmove((char *)qpkt.data, qdata, 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) {
+ memmove((char *)num, hp->h_addr, 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) || defined(SYS_BSDI)
+ qsort((void *)cmdsort, n, sizeof(char *), helpsort);
+#else
+ qsort((char *)cmdsort, n, sizeof(char *), helpsort);
+#endif /* sgi || bsdi */
+
+ 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) || defined(SYS_BSDI)
+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 || bsdi */
+ 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;
+ int quoted = 0;
+ 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 != ',') || quoted))
+ {
+ quoted ^= ((*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) || defined(SYS_BSDI)
+ qsort((void *)assoc_cache, numassoc,
+ sizeof(struct association), assoccmp);
+#else
+ qsort((char *)assoc_cache, numassoc,
+ sizeof(struct association), assoccmp);
+#endif /* sgi || bsdi */
+}
+
+
+/*
+ * assoccmp - compare two associations
+ */
+static int
+#if defined(sgi) || defined(SYS_BSDI)
+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 || bsdi */
+ if (ass1->assid < ass2->assid)
+ return -1;
+ if (ass1->assid > ass2->assid)
+ return 1;
+ return 0;
+}
diff --git a/contrib/xntpd/ntpq/ntpq.h b/contrib/xntpd/ntpq/ntpq.h
new file mode 100644
index 000000000000..edfc9b599028
--- /dev/null
+++ b/contrib/xntpd/ntpq/ntpq.h
@@ -0,0 +1,97 @@
+/* ntpq.h,v 3.1 1993/07/06 01:09:30 jbj Exp
+ * ntpq.h - definitions of interest to ntpq
+ */
+#include "ntp_fp.h"
+#include "ntp.h"
+#include "ntp_control.h"
+#include "ntp_string.h"
+#include "ntp_malloc.h"
+
+/*
+ * Maximum number of arguments
+ */
+#define MAXARGS 4
+
+/*
+ * Flags for forming descriptors.
+ */
+#define OPT 0x80 /* this argument is optional, or'd with type */
+
+#define NO 0x0
+#define STR 0x1 /* string argument */
+#define UINT 0x2 /* unsigned integer */
+#define INT 0x3 /* signed integer */
+#define ADD 0x4 /* IP network address */
+
+/*
+ * Arguments are returned in a union
+ */
+typedef union {
+ char *string;
+ LONG ival;
+ U_LONG uval;
+ U_LONG netnum;
+} arg_v;
+
+/*
+ * Structure for passing parsed command line
+ */
+struct parse {
+ char *keyword;
+ arg_v argval[MAXARGS];
+ int nargs;
+};
+
+/*
+ * xntpdc includes a command parser which could charitably be called
+ * crude. The following structure is used to define the command
+ * syntax.
+ */
+struct xcmd {
+ char *keyword; /* command key word */
+ void (*handler) P((struct parse *, FILE *)); /* command handler */
+ u_char arg[MAXARGS]; /* descriptors for arguments */
+ char *desc[MAXARGS]; /* descriptions for arguments */
+ char *comment;
+};
+
+/*
+ * Types of things we may deal with
+ */
+#define TYPE_SYS 1
+#define TYPE_PEER 2
+#define TYPE_CLOCK 3
+
+
+/*
+ * Structure to hold association data
+ */
+struct association {
+ u_short assid;
+ u_short status;
+};
+
+#define MAXASSOC 1024
+
+/*
+ * Structure for translation tables between text format
+ * variable indices and text format.
+ */
+struct ctl_var {
+ u_short code;
+ u_short fmt;
+ char *text;
+};
+
+extern void asciize P((int, char *, FILE *));
+extern int getnetnum P((char *, U_LONG *, char *));
+extern void sortassoc P((void));
+extern int doquery P((int, int, int, int, char *, u_short *, int *, char **));
+extern char * nntohost P((U_LONG));
+extern int decodets P((char *, l_fp *));
+extern int decodeuint P((char *, U_LONG *));
+extern int nextvar P((int *, char **, char **, char **));
+extern int decodetime P((char *, l_fp *));
+extern void printvars P((int, char *, int, int, FILE *));
+extern int decodeint P((char *, LONG *));
+extern int findvar P((char *, struct ctl_var *));
diff --git a/contrib/xntpd/ntpq/ntpq_ops.c b/contrib/xntpd/ntpq/ntpq_ops.c
new file mode 100644
index 000000000000..395a9ecfd914
--- /dev/null
+++ b/contrib/xntpd/ntpq/ntpq_ops.c
@@ -0,0 +1,1601 @@
+/* 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
+ * XXX - should be in libntp.a
+ */
+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);
+ }
+
+ memmove(cp, str, 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++ = ',';
+ memmove(cp, vl->name, namelen);
+ cp += namelen;
+ if (valuelen != 0) {
+ *cp++ = '=';
+ memmove(cp, vl->value, 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;
+
+ memset((char *)tmplist, 0, 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;
+
+ memset((char *)tmplist, 0, 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;
+
+ memset((char *)tmplist, 0, 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;
+
+ memset((char *)tmplist, 0, 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[];
+
+ memset((char *)havevar, 0, 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/contrib/xntpd/ntptrace/Makefile b/contrib/xntpd/ntptrace/Makefile
new file mode 100644
index 000000000000..823f9e483012
--- /dev/null
+++ b/contrib/xntpd/ntptrace/Makefile
@@ -0,0 +1,28 @@
+#
+# $Id: Makefile,v 1.2 1993/12/22 11:33:14 rgrimes Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= ntptrace
+MAN8= ${.CURDIR}/../doc/ntptrace.8
+CLEANFILES+= .version version.c
+
+SRCS= ntptrace.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion ntptrace
+
+.include <bsd.prog.mk>
diff --git a/contrib/xntpd/ntptrace/README b/contrib/xntpd/ntptrace/README
new file mode 100644
index 000000000000..b976cfdf22ce
--- /dev/null
+++ b/contrib/xntpd/ntptrace/README
@@ -0,0 +1,7 @@
+README file for directory ./ntptrace of the NTP Version 3 distribution
+
+This directory contains the sources for the ntptrace utility program. See
+the README and RELNOTES files in the parent directory for directions on
+how to make and install this program. The current version number of this
+program is in the version.c file.
+
diff --git a/contrib/xntpd/ntptrace/ntptrace.c b/contrib/xntpd/ntptrace/ntptrace.c
new file mode 100644
index 000000000000..6454ec1df1f4
--- /dev/null
+++ b/contrib/xntpd/ntptrace/ntptrace.c
@@ -0,0 +1,777 @@
+/* ntptrace.c,v 3.1 1993/07/06 01:09:38 jbj Exp
+ * ntptrace - show the chain from an NTP host leading back to
+ * its source of time
+ *
+ * Jeffrey Mogul DECWRL 13 January 1993
+ *
+ * Inspired by a script written by Glenn Trewitt
+ *
+ * Large portions stolen from ntpdate.c
+ */
+#include <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 *ntp_optarg;
+ extern int ntp_optind;
+ extern char *Version;
+
+ errflg = 0;
+ progname = argv[0];
+
+ /*
+ * Decode argument list
+ */
+ while ((c = ntp_getopt(argc, argv, "do:nr:t:v")) != EOF)
+ switch (c) {
+ case 'd':
+ ++debug;
+ break;
+ case 'n':
+ nonames = 1;
+ break;
+ case 'o':
+ sys_version = atoi(ntp_optarg);
+ break;
+ case 'r':
+ sys_retries = atoi(ntp_optarg);
+ if (sys_retries < 1) {
+ (void)fprintf(stderr,
+ "%s: retries (%d) too small\n",
+ progname, sys_retries);
+ errflg++;
+ }
+ break;
+ case 't':
+ sys_timeout = atoi(ntp_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 - ntp_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 - ntp_optind) == 1)
+ firstserver = addservbyname(argv[ntp_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));
+ memset((char *)server, 0, 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) {
+ memmove((char *)num, hp->h_addr, 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;
+ memmove(junk, (char *)&pp->refid, 4);
+ str = junk;
+ (void) fprintf(fp, "'%s'", str);
+ } else {
+ if (nonames) {
+ str = numtoa(pp->refid);
+ (void) fprintf(fp, "[%s]", str);
+ }
+ else {
+ str = numtohost(pp->refid);
+ (void) fprintf(fp, "%s", str);
+ }
+ }
+}
+
+#if defined(NEED_VSPRINTF)
+/*
+ * This nugget for pre-tahoe 4.3bsd systems
+ */
+#if !defined(__STDC__) || !__STDC__
+#define const
+#endif
+
+int
+vsprintf(str, fmt, ap)
+ char *str;
+ const char *fmt;
+ va_list ap;
+{
+ FILE f;
+ int len;
+
+ f._flag = _IOWRT+_IOSTRG;
+ f._ptr = str;
+ f._cnt = 32767;
+ len = _doprnt(fmt, ap, &f);
+ *f._ptr = 0;
+ return (len);
+}
+#endif
diff --git a/contrib/xntpd/ntptrace/ntptrace.h b/contrib/xntpd/ntptrace/ntptrace.h
new file mode 100644
index 000000000000..3367c226a89d
--- /dev/null
+++ b/contrib/xntpd/ntptrace/ntptrace.h
@@ -0,0 +1,36 @@
+/* ntptrace.h,v 3.1 1993/07/06 01:09:39 jbj Exp
+ * ntptrace.h - declarations for the ntptrace program
+ */
+
+/*
+ * The server structure is a much simplified version of the
+ * peer structure, for ntptrace's use. Since we always send
+ * in client mode and expect to receive in server mode, this
+ * leaves only a very limited number of things we need to
+ * remember about the server.
+ */
+struct server {
+ struct sockaddr_in srcadr; /* address of remote host */
+ u_char leap; /* leap indicator */
+ u_char stratum; /* stratum of remote server */
+ s_char precision; /* server's clock precision */
+ u_fp rootdelay; /* distance from primary clock */
+ u_fp rootdispersion; /* peer clock dispersion */
+ U_LONG refid; /* peer reference ID */
+ l_fp reftime; /* time of peer's last update */
+ l_fp org; /* peer's originate time stamp */
+ l_fp xmt; /* transmit time stamp */
+ u_fp delay; /* filter estimated delay */
+ u_fp dispersion; /* filter estimated dispersion */
+ l_fp offset; /* filter estimated clock offset */
+};
+
+
+/*
+ * Since ntptrace isn't aware of some of the things that normally get
+ * put in an NTP packet, we fix some values.
+ */
+#define NTPTRACE_PRECISION (-6) /* use this precision */
+#define NTPTRACE_DISTANCE FP_SECOND /* distance is 1 sec */
+#define NTPTRACE_DISP FP_SECOND /* so is the dispersion */
+#define NTPTRACE_REFID (0) /* reference ID to use */
diff --git a/contrib/xntpd/parse/Makefile b/contrib/xntpd/parse/Makefile
new file mode 100644
index 000000000000..69983c7cfff0
--- /dev/null
+++ b/contrib/xntpd/parse/Makefile
@@ -0,0 +1,19 @@
+#
+# $Id: Makefile,v 1.1 1993/12/21 20:04:14 wollman Exp $
+#
+
+PARSEFLAGS= -DCLOCK_SCHMID -DCLOCK_DCF7000 -DCLOCK_MEINBERG \
+ -DCLOCK_RAWDCF -DCLOCK_TRIMSV6
+
+CFLAGS+= -I${.CURDIR}/../include ${PARSEFLAGS}
+
+SRCS= parse.c parse_conf.c clk_meinberg.c clk_schmid.c clk_rawdcf.c \
+ clk_dcf7000.c clk_trimble.c
+
+NOMAN=
+NOPROFILE=
+LIB= parse
+
+install:
+
+.include <bsd.lib.mk>
diff --git a/contrib/xntpd/parse/README b/contrib/xntpd/parse/README
new file mode 100644
index 000000000000..aa83aa7ae009
--- /dev/null
+++ b/contrib/xntpd/parse/README
@@ -0,0 +1,100 @@
+PARSE reference clock driver:
+
+This directory contains the files making up the parser for
+the parse refclock driver. For reasonably sane clocks this refclock
+drivers allows a refclock implementation by just providing a
+conversion routine and the appropriate NTP parameters. Refclock
+support can run as low a 3k code with the parse refclock driver.
+
+The modules in here are designed to live in two worlds. In userlevel
+as part of the xntp daemon and in kernel land as part of a STREAMS module
+or, if someone gets to it, as part of a line discipline. Currently only
+SunOS4.x/SunOS5.x STREAMS are supported (volunteers for other vendors like HP?).
+This structure means, that refclock_parse can work with or without kernel
+support. Kernelsupport increases accuracy tremendingly. The current restriction
+of the parse driver is that it only supports SYSV type ttys and that kernel
+support is only available for Suns right now.
+
+Three kernel modules are part of this directory. These work only on
+SunOS (SunOS4 and SunOS5 (not fully tested!)).
+
+ SunOS4 (aka Solaris 1.x):
+ parsestreams.o - standard parse module for SunOS 4
+ mparsestreams.o - parse module for SunOS 4 with better
+ clock reading code (assembler)
+
+ Both modules can be loaded via modload <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/contrib/xntpd/parse/README.parse b/contrib/xntpd/parse/README.parse
new file mode 100644
index 000000000000..660973af319a
--- /dev/null
+++ b/contrib/xntpd/parse/README.parse
@@ -0,0 +1,142 @@
+MINI INFO:
+The following info pertains mainly to SunOS4.x in respect to installation.
+Installation for SunOS5.x (Solaris 2.x) is very simple - just drop the parse
+module into /kernel/strmod.
+All others notes about the software structure refer to both environments.
+
+#ifdef ENGLISH
+Installation of a Streams module requires knowledge in kernel generation
+and possession of "superuser" rights.
+
+This directory contains the STREAMS module code for the supported DCF/GPS
+receivers of the "parse" driver.
+The dataformat should be easy to adept for other clocks.
+
+A suitable kernel module can be generated in two ways:
+ 1) loadable driver
+ 2) linking into the kernel
+
+Solution 1 has the advantage that the kernel module is present right at system startup,
+while solution 2 avoids reconfigurating the kernel (except for VDDRV).
+
+Loadable Driver: (Kernel must be configured with VDDRV option like e.g. GENERIC)
+ make -f Makefile.kernel
+
+# make one module for each kernel architecture you intend to use this module for
+
+ make -f Makefile.kernel mparsestreams.o
+# use the above command for a version with increased time stamp precision
+# (available only for sun4c and sun4m architectures (thanks Craig Leres)
+
+Integration into kernel (refer to the Manual for complete instructions)
+ Still possible, but not recommended
+
+if you run into trouble: time@informatik.uni-erlangen.de
+
+Porting to different clock formats:
+The streams module is designed to be able to parse different time code
+packets. The parser is very simple and expects at least a start or end of packet
+character. In order to be able to distinguish time code packets a list
+of several start/end pairs and conversion routines can be defined in the
+clockformats structure. Whenever a packet delimited by any start/end pair is
+detected the conversion routines are called in a RR fashion for converting the
+time code into a clocktime structure. A return code of CVT_OK indicates a
+correct conversion.
+(This routine will be called first on the next conversion attempt). CVT_FAIL
+indicates the the packet format was detected, but the actual conversion failed
+(e.g. illegal time codes). A CVT_NONE indicates that this conversion routine
+did not recognize the packet format.
+See the simpleformat conversion routines for Meinberg clocks for examples.
+It might be possible to parse other periodically sent time codes with a fixed
+format with these simple conversion routines.
+The parser can be found in parse/*.c
+
+The actual STREAMS module is parsestreams.c. It contains some fudge factors.
+These are needed if a PPS hardware signal is sampled via the serial CD input.
+There are some emperically determined valued for sun4c type machine in there.
+Measurements have shown, that for full precision these values have to be
+determined in the actual environment, as line lengths and capacities DO matter.
+So for absolute precision you need a good oscilloscope and the license for
+hardware work.
+WARNING: DO NOT ATTEMPT TO MEASURE IF YOU ARE NOT ABSOLUTELY CERTAIN WHAT YOU
+ARE DOING.
+
+This instructions are distributed in the hope that they will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+I will not be in any case responsible for any damage cause by this
+Software/Instruction.
+
+USE AT YOUR OWN RISK.
+
+#else
+
+Die folgenden Hinweise zur Uebersetzung und Installation besiehen sich auf
+SunOS 4.x (Solaris1.x). Die Installation auf SunOS5.x (Solaris 2.x) gestaltet
+sich erheblich einfacher. Man muss nur die Daten "parse" in dem Verzeichnis
+/kernel/strmod ablegen.
+Alle anderen Hinweise zur Softwarestruktur sind fuer beide Umgebungen gueltig.
+
+Installation eines STREAMS Moduls setzt Kenntnisse in der Kerngenerierung
+und "Superuser"-Rechte vorraus.
+
+Dieses Inhaltsverzeichnis enthaelt das aktuelle Streams Modul fuer Sun.
+
+Man kann dieses Modul auf zwei Weisen in den Kern integrieren:
+ 1) direkt durch Einbinden (neuer Kern)
+ 2) als ladbarer Treiber
+
+Loesung 1 hat den Vorteil, dass das Modul gleich nach Systemstart zur
+Verfuegung steht.
+Loesung 2 besticht dadurch, das man das Modul nachtraeglich laden und
+auch debuggen kann, ohne einen neuen Kern zu booten.
+
+Fuer ein ladbares Modul muss der Kern mit der VDDRV option konfiguriert sein und das
+parsestreams.c muss mit -DVDDRV uebersetzt werden.
+
+Uebersetzung fuer ladbaren Treiber (Kern muss mit VDDRV konfiguriert sein):
+ make -f Makefile.kernel
+ bitte einmal fuer jede Kernelarchitektur, fuer die dieses Modul
+ benoetigt wird durchfuehren.
+
+ make -f Makefile.kernel mparsestreams.o
+ Das obige make erstellt eine Version, die die Rechneruhr besser
+ als SunOS abliest. Nur fur sun4c und sun4m Architekturen verfuegbar
+
+Uebersetzung als .o Modul oder vorherige Einbindung in die Kernbauumgebung:
+ Immer noch moeglich, wird aber nicht mehr empfohlen.
+
+Anpassung an andere Datenformate:
+Das Streamsmodul ist in der Lage verschiedene Datenformate zu erkennen und
+umzusetzen. Der Parser ist einfach gehalten und kann Datenpakete anhand von
+Start und Endekennzeichen unterscheiden. Jedes so erkannte Paket wird einer
+Liste von Konvertierroutinen vorgelegt (clockformats Struktur). Die
+Konvertierroutinen koennen mit drei verschiedenen Rueckgabewerten angeben,
+wie die Konvertierung verlaufen ist. CVT_OK heisst, dass die Konvertierung
+in die clocktime Struktur erfolgreich verlaufen ist. Beim naechsten
+Umsetzungsversuch wird diese Routine als erstes wieder befragt werden
+(Optimierung). CVT_FAIL bedeutet, dass zwar das Format erkannt wurde, aber
+die eigentliche Konvertierung fehlgeschlagen ist (z. B. illegale Feldwerte).
+CVT_NONE heisst, dass das Format dieser Konvertierroutine nicht erkannt wurde.
+Die simpleformat Routinen fuer Meinberg Uhren koennen als Vorlage fuer eigene
+Anpassungen an Uhren mit periodischem Zeittelegramm und festem Format genommen werden.
+Der Parser ist in parse/*.c zu finden.
+
+Das eigentliche STREAMSmodul ist parsestreams.c. Es enthaelt einige
+Korrekturfaktoren, die beim Einsatz von Hardware-PPS Signalen benoetigt werden.
+Einige empirische Werte fuer sun4c Maschinen sind schon vorgegeben. Bei exterm
+hohen Genauigkeitsanforderungen muessen diese Werte aber in der aktuellen
+Installation NEU ermittelt werden, weil die Zeiten unter anderem von
+Leitunglaengen der PPS Leitung abhaengen. Wenn Sie diese Abstimmung
+durchfuehren, benoetigen Sie ein gutes Oszilloskop und die Lizenz fuer
+Hardwarearbeiten.
+
+ACHTUNG: VERSUCHEN SIE NICHT DIESE MESSUNGEN ZU MACHEN, WENN IHNEN DIE
+VORAUSSETZUNGEN DAFUER FEHLEN !
+
+WIR GEBEN KEINE GARANTIEN
+
+Bei Schwierigkeiten email an: time@informatik.uni-erlangen.de
+
+#endif
diff --git a/contrib/xntpd/parse/clk_dcf7000.c b/contrib/xntpd/parse/clk_dcf7000.c
new file mode 100644
index 000000000000..5655d0a017f0
--- /dev/null
+++ b/contrib/xntpd/parse/clk_dcf7000.c
@@ -0,0 +1,142 @@
+#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_DCF7000)
+/*
+ * /src/NTP/REPOSITORY/v3/parse/clk_dcf7000.c,v 3.10 1994/01/25 19:05:07 kardel Exp
+ *
+ * clk_dcf7000.c,v 3.10 1994/01/25 19:05:07 kardel Exp
+ *
+ * ELV DCF7000 module
+ *
+ * Copyright (c) 1992,1993,1994
+ * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include "sys/types.h"
+#include "sys/time.h"
+#include "sys/errno.h"
+#include "ntp_fp.h"
+#include "ntp_unixtime.h"
+#include "ntp_calendar.h"
+
+#include "parse.h"
+
+static struct format dcf7000_fmt =
+{ /* ELV DCF7000 */
+ {
+ { 6, 2}, { 3, 2}, { 0, 2},
+ { 12, 2}, { 15, 2}, { 18, 2},
+ { 9, 2}, { 21, 2},
+ },
+ " - - - - - - - \r",
+ 0
+};
+
+static unsigned LONG cvt_dcf7000();
+
+clockformat_t clock_dcf7000 =
+{
+ cvt_dcf7000, /* ELV DCF77 conversion */
+ syn_simple, /* easy time stamps */
+ (unsigned LONG (*)())0, /* no direct PPS monitoring */
+ (unsigned LONG (*)())0, /* no time code synthesizer monitoring */
+ (void *)&dcf7000_fmt, /* conversion configuration */
+ "ELV DCF7000", /* ELV clock */
+ 24, /* string buffer */
+ F_END|SYNC_END, /* END packet delimiter / synchronisation */
+ { 0, 0},
+ '\0',
+ '\r',
+ '\0'
+};
+
+/*
+ * cvt_dcf7000
+ *
+ * convert dcf7000 type format
+ */
+static unsigned LONG
+cvt_dcf7000(buffer, size, format, clock)
+ register char *buffer;
+ register int size;
+ register struct format *format;
+ register clocktime_t *clock;
+{
+ if (!Strok(buffer, format->fixed_string))
+ {
+ return CVT_NONE;
+ }
+ else
+ {
+ if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock->day,
+ format->field_offsets[O_DAY].length) ||
+ Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock->month,
+ format->field_offsets[O_MONTH].length) ||
+ Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock->year,
+ format->field_offsets[O_YEAR].length) ||
+ Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock->hour,
+ format->field_offsets[O_HOUR].length) ||
+ Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock->minute,
+ format->field_offsets[O_MIN].length) ||
+ Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock->second,
+ format->field_offsets[O_SEC].length))
+ {
+ return CVT_FAIL|CVT_BADFMT;
+ }
+ else
+ {
+ char *f = &buffer[format->field_offsets[O_FLAGS].offset];
+ LONG flags;
+
+ clock->flags = 0;
+ clock->usecond = 0;
+
+ if (Stoi(f, &flags, format->field_offsets[O_FLAGS].length))
+ {
+ return CVT_FAIL|CVT_BADFMT;
+ }
+ else
+ {
+ if (flags & 0x1)
+ clock->utcoffset = -2*60*60;
+ else
+ clock->utcoffset = -1*60*60;
+
+ if (flags & 0x2)
+ clock->flags |= PARSEB_ANNOUNCE;
+
+ if (flags & 0x4)
+ clock->flags |= PARSEB_NOSYNC;
+ }
+ return CVT_OK;
+ }
+ }
+}
+#endif /* defined(PARSE) && defined(CLOCK_DCF7000) */
+
+/*
+ * History:
+ *
+ * clk_dcf7000.c,v
+ * Revision 3.6 1993/10/09 15:01:27 kardel
+ * file structure unified
+ *
+ * Revision 3.5 1993/10/03 19:10:41 kardel
+ * restructured I/O handling
+ *
+ * Revision 3.4 1993/09/27 21:08:02 kardel
+ * utcoffset now in seconds
+ *
+ * Revision 3.3 1993/09/26 23:40:20 kardel
+ * new parse driver logic
+ *
+ * Revision 3.2 1993/07/09 11:37:15 kardel
+ * Initial restructured version + GPS support
+ *
+ * Revision 3.1 1993/07/06 10:00:14 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/contrib/xntpd/parse/clk_meinberg.c b/contrib/xntpd/parse/clk_meinberg.c
new file mode 100644
index 000000000000..b08dfec91152
--- /dev/null
+++ b/contrib/xntpd/parse/clk_meinberg.c
@@ -0,0 +1,450 @@
+#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_MEINBERG)
+/*
+ * /src/NTP/REPOSITORY/v3/parse/clk_meinberg.c,v 3.11 1994/01/25 19:05:10 kardel Exp
+ *
+ * clk_meinberg.c,v 3.11 1994/01/25 19:05:10 kardel Exp
+ *
+ * Meinberg clock support
+ *
+ * Copyright (c) 1992,1993,1994
+ * 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.11 1994/01/25 19:05:10 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.10 1994/01/23 17:21:54 kardel
+ * 1994 reconcilation
+ *
+ * Revision 3.9 1993/10/30 09:44:38 kardel
+ * conditional compilation flag cleanup
+ *
+ * Revision 3.8 1993/10/22 14:27:48 kardel
+ * Oct. 22nd 1993 reconcilation
+ *
+ * Revision 3.7 1993/10/09 15:01:30 kardel
+ * file structure unified
+ *
+ * Revision 3.6 1993/10/03 19:10:43 kardel
+ * restructured I/O handling
+ *
+ * Revision 3.5 1993/09/27 21:08:04 kardel
+ * utcoffset now in seconds
+ *
+ * Revision 3.4 1993/09/26 23:40:22 kardel
+ * new parse driver logic
+ *
+ * Revision 3.3 1993/08/18 09:29:32 kardel
+ * GPS format is somewhat variable length - variable length part holds position
+ *
+ * Revision 3.2 1993/07/09 11:37:16 kardel
+ * Initial restructured version + GPS support
+ *
+ * Revision 3.1 1993/07/06 10:00:17 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/contrib/xntpd/parse/clk_rawdcf.c b/contrib/xntpd/parse/clk_rawdcf.c
new file mode 100644
index 000000000000..2fd3cae20b89
--- /dev/null
+++ b/contrib/xntpd/parse/clk_rawdcf.c
@@ -0,0 +1,559 @@
+#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_RAWDCF)
+/*
+ * /src/NTP/REPOSITORY/v3/parse/clk_rawdcf.c,v 3.9 1994/01/25 19:05:12 kardel Exp
+ *
+ * clk_rawdcf.c,v 3.9 1994/01/25 19:05:12 kardel Exp
+ *
+ * Raw DCF77 pulse clock support
+ *
+ * Copyright (c) 1992,1993,1994
+ * 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)
+ {
+ 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.9 1994/01/25 19:05:12 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.8 1994/01/22 11:24:11 kardel
+ * fixed PPS handling
+ *
+ * Revision 3.7 1993/10/30 09:44:41 kardel
+ * conditional compilation flag cleanup
+ *
+ * Revision 3.6 1993/10/03 19:10:45 kardel
+ * restructured I/O handling
+ *
+ * Revision 3.5 1993/09/27 21:08:07 kardel
+ * utcoffset now in seconds
+ *
+ * Revision 3.4 1993/09/26 23:40:25 kardel
+ * new parse driver logic
+ *
+ * Revision 3.3 1993/09/01 21:44:54 kardel
+ * conditional cleanup
+ *
+ * Revision 3.2 1993/07/09 11:37:18 kardel
+ * Initial restructured version + GPS support
+ *
+ * Revision 3.1 1993/07/06 10:00:19 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/contrib/xntpd/parse/clk_schmid.c b/contrib/xntpd/parse/clk_schmid.c
new file mode 100644
index 000000000000..a8ec8a64b546
--- /dev/null
+++ b/contrib/xntpd/parse/clk_schmid.c
@@ -0,0 +1,201 @@
+#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_SCHMID)
+/*
+ * /src/NTP/REPOSITORY/v3/parse/clk_schmid.c,v 3.10 1994/01/25 19:05:15 kardel Exp
+ *
+ * clk_schmid.c,v 3.10 1994/01/25 19:05:15 kardel Exp
+ *
+ * Schmid clock support
+ *
+ * Copyright (c) 1992,1993,1994
+ * 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.10 1994/01/25 19:05:15 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.9 1994/01/23 17:21:56 kardel
+ * 1994 reconcilation
+ *
+ * Revision 3.8 1993/11/01 20:00:18 kardel
+ * parse Solaris support (initial version)
+ *
+ * Revision 3.7 1993/10/30 09:44:43 kardel
+ * conditional compilation flag cleanup
+ *
+ * Revision 3.6 1993/10/09 15:01:32 kardel
+ * file structure unified
+ *
+ * Revision 3.5 1993/10/03 19:10:47 kardel
+ * restructured I/O handling
+ *
+ * Revision 3.4 1993/09/27 21:08:09 kardel
+ * utcoffset now in seconds
+ *
+ * Revision 3.3 1993/09/26 23:40:27 kardel
+ * new parse driver logic
+ *
+ * Revision 3.2 1993/07/09 11:37:19 kardel
+ * Initial restructured version + GPS support
+ *
+ * Revision 3.1 1993/07/06 10:00:22 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/contrib/xntpd/parse/clk_trimble.c b/contrib/xntpd/parse/clk_trimble.c
new file mode 100644
index 000000000000..bfbf1e6bc796
--- /dev/null
+++ b/contrib/xntpd/parse/clk_trimble.c
@@ -0,0 +1,134 @@
+#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS)) && defined(CLOCK_TRIMSV6)
+/*
+ * /src/NTP/REPOSITORY/v3/parse/clk_trimble.c,v 3.7 1994/01/25 19:05:17 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.7 1994/01/25 19:05:17 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.6 1993/10/30 09:44:45 kardel
+ * conditional compilation flag cleanup
+ *
+ * Revision 3.5 1993/10/09 15:01:35 kardel
+ * file structure unified
+ *
+ * revision 3.4
+ * date: 1993/10/08 14:44:51; author: kardel;
+ * trimble - initial working version
+ *
+ * revision 3.3
+ * date: 1993/10/03 19:10:50; author: kardel;
+ * restructured I/O handling
+ *
+ * revision 3.2
+ * date: 1993/09/27 21:07:17; author: kardel;
+ * Trimble alpha integration
+ *
+ * revision 3.1
+ * date: 1993/09/26 23:40:29; author: kardel;
+ * new parse driver logic
+ *
+ */
diff --git a/contrib/xntpd/parse/empty.c b/contrib/xntpd/parse/empty.c
new file mode 100644
index 000000000000..91b777afe709
--- /dev/null
+++ b/contrib/xntpd/parse/empty.c
@@ -0,0 +1,7 @@
+/*
+ * Well, some ranlibs, ar's or compilers react funny
+ * if asked to do nothing but build empty valid files
+ * I would have preferred to a no or at least a static
+ * symbol here...
+ */
+char * _____empty__ = "empty .o file";
diff --git a/contrib/xntpd/parse/parse.c b/contrib/xntpd/parse/parse.c
new file mode 100644
index 000000000000..ed5fd9a8fad7
--- /dev/null
+++ b/contrib/xntpd/parse/parse.c
@@ -0,0 +1,1208 @@
+#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS))
+/*
+ * /src/NTP/REPOSITORY/v3/parse/parse.c,v 3.19 1994/01/25 19:05:20 kardel Exp
+ *
+ * parse.c,v 3.19 1994/01/25 19:05:20 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,1994
+ * 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.19 1994/01/25 19:05:20 kardel Exp";
+#endif
+
+#include "sys/types.h"
+#include "sys/time.h"
+#include "sys/errno.h"
+
+#include "ntp_machine.h"
+
+#if defined(PARSESTREAM) && (defined(SYS_SUNOS4) || defined(SYS_SOLARIS)) && defined(STREAM)
+/*
+ * Sorry, but in SunOS 4.x AND Solaris 2.x kernels there are no
+ * mem* operations. I don't want them - bcopy, bzero
+ * are fine in the kernel
+ */
+#ifndef NTP_NEED_BOPS
+#define NTP_NEED_BOPS
+#endif
+#else
+#ifndef NTP_NEED_BOPS
+#ifndef bzero
+#define bzero(_X_, _Y_) memset(_X_, 0, _Y_)
+#define bcopy(_X_, _Y_, _Z_) memmove(_Y_, _X_, _Z_)
+#endif
+#endif
+#endif
+
+#include "ntp_fp.h"
+#include "ntp_unixtime.h"
+#include "ntp_calendar.h"
+
+#include "parse.h"
+
+#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.19 1994/01/25 19:05:20 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.18 1994/01/23 17:21:59 kardel
+ * 1994 reconcilation
+ *
+ * Revision 3.17 1993/11/11 11:20:29 kardel
+ * declaration fixes
+ *
+ * Revision 3.16 1993/11/06 22:26:07 duwe
+ * Linux cleanup after config change
+ *
+ * Revision 3.15 1993/11/04 11:14:18 kardel
+ * ansi/K&R traps
+ *
+ * Revision 3.14 1993/11/04 10:03:28 kardel
+ * disarmed ansiism
+ *
+ * Revision 3.13 1993/11/01 20:14:13 kardel
+ * useless comparision removed
+ *
+ * Revision 3.12 1993/11/01 20:00:22 kardel
+ * parse Solaris support (initial version)
+ *
+ * Revision 3.11 1993/10/30 09:41:25 kardel
+ * minor optimizations
+ *
+ * Revision 3.10 1993/10/22 14:27:51 kardel
+ * Oct. 22nd 1993 reconcilation
+ *
+ * Revision 3.9 1993/10/05 23:15:09 kardel
+ * more STREAM protection
+ *
+ * Revision 3.8 1993/09/27 21:08:00 kardel
+ * utcoffset now in seconds
+ *
+ * Revision 3.7 1993/09/26 23:40:16 kardel
+ * new parse driver logic
+ *
+ * Revision 3.6 1993/09/07 10:12:46 kardel
+ * September 7th reconcilation - 3.2 (alpha)
+ *
+ * Revision 3.5 1993/09/01 21:44:48 kardel
+ * conditional cleanup
+ *
+ * Revision 3.4 1993/08/27 00:29:39 kardel
+ * compilation cleanup
+ *
+ * Revision 3.3 1993/08/24 22:27:13 kardel
+ * cleaned up AUTOCONF DCF77 mess 8-) - wasn't too bad
+ *
+ * Revision 3.2 1993/07/09 11:37:11 kardel
+ * Initial restructured version + GPS support
+ *
+ * Revision 3.1 1993/07/06 10:00:08 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/contrib/xntpd/parse/parse_conf.c b/contrib/xntpd/parse/parse_conf.c
new file mode 100644
index 000000000000..0281c9dd1071
--- /dev/null
+++ b/contrib/xntpd/parse/parse_conf.c
@@ -0,0 +1,123 @@
+#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS))
+/*
+ * /src/NTP/REPOSITORY/v3/parse/parse_conf.c,v 3.13 1994/01/25 19:05:23 kardel Exp
+ *
+ * parse_conf.c,v 3.13 1994/01/25 19:05:23 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,1994
+ * 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.13 1994/01/25 19:05:23 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.12 1994/01/23 17:22:02 kardel
+ * 1994 reconcilation
+ *
+ * Revision 3.11 1993/11/01 20:00:24 kardel
+ * parse Solaris support (initial version)
+ *
+ * Revision 3.10 1993/10/09 15:01:37 kardel
+ * file structure unified
+ *
+ * Revision 3.9 1993/09/26 23:40:19 kardel
+ * new parse driver logic
+ *
+ * Revision 3.8 1993/09/02 23:20:57 kardel
+ * dragon extiction
+ *
+ * Revision 3.7 1993/09/01 21:44:52 kardel
+ * conditional cleanup
+ *
+ * Revision 3.6 1993/09/01 11:25:09 kardel
+ * patch accident 8-(
+ *
+ * Revision 3.5 1993/08/31 22:31:14 kardel
+ * SINIX-M SysVR4 integration
+ *
+ * Revision 3.4 1993/08/27 00:29:42 kardel
+ * compilation cleanup
+ *
+ * Revision 3.3 1993/07/14 09:04:45 kardel
+ * only when REFCLOCK && PARSE is defined
+ *
+ * Revision 3.2 1993/07/09 11:37:13 kardel
+ * Initial restructured version + GPS support
+ *
+ * Revision 3.1 1993/07/06 10:00:11 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/contrib/xntpd/parse/parsesolaris.c b/contrib/xntpd/parse/parsesolaris.c
new file mode 100644
index 000000000000..09fac2861f0c
--- /dev/null
+++ b/contrib/xntpd/parse/parsesolaris.c
@@ -0,0 +1,1209 @@
+/*
+ * /src/NTP/REPOSITORY/v3/parse/parsesolaris.c,v 3.9 1994/01/25 19:05:26 kardel Exp
+ *
+ * parsesolaris.c,v 3.9 1994/01/25 19:05:26 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,1994
+ * 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.9 1994/01/25 19:05:26 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.9";
+ 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
+ {
+#if 0
+ parseprintf(DD_RPUT,("parse: parserput - M_%s\n", (type == M_DATA) ? "DATA" : "BREAK"));
+#endif
+ 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);
+ freemsg(mp);
+ }
+ else
+ if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
+ {
+ putnext(q, mp);
+ }
+ else
+ putq(q, mp);
+
+ 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 */
+ /*
+ * XXX: this is usually done via zsopinit()
+ * - have yet to find a way to call that routine
+ */
+ zs->zs_xsint = (void (*)())zs_xsisr;
+
+ 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 */
+ /*
+ * XXX: revert xsint (usually done via zsopinit() - have still to find
+ * a way to call that bugger
+ */
+ zs->zs_xsint = zs->zs_ops->zsop_xsint;
+
+ 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 ZSRR0_IGNORE (ZSRR0_CD|ZSRR0_SYNC|ZSRR0_CTS)
+
+#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 and ignored transistion (SYNC,CTS)
+ * have been handled
+ */
+ za->za_rr0 = (za->za_rr0 & ~ZSRR0_IGNORE) | (zsstatus & ZSRR0_IGNORE);
+
+ if (((za->za_rr0 ^ zsstatus) & ~ZSRR0_IGNORE) == 0)
+ {
+ /*
+ * all done - kill status indication and return
+ */
+ SCC_WRITE0(ZSWR0_RESET_STATUS); /* might kill other conditions here */
+ return;
+ }
+ }
+
+ parseprintf(DD_ISR, ("zs_xsisr: non CD event 0x%x for \"%s\"\n",
+ (za->za_rr0 ^ zsstatus) & ~ZSRR0_CD,dname));
+ /*
+ * 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.9 1994/01/25 19:05:26 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.8 1994/01/23 17:22:04 kardel
+ * 1994 reconcilation
+ *
+ * Revision 3.7 1993/12/15 18:24:41 kardel
+ * Now also ignoring state changes on ZSRR0_{SYNC,CTS} to avoid zs driver bugs (Solaris 2.3)
+ *
+ * Revision 3.6 1993/12/15 12:48:53 kardel
+ * fixed message loss on M_*HANHUP messages
+ *
+ * Revision 3.5 1993/12/14 21:05:12 kardel
+ * PPS working now for SunOS 5.x zs external status hook
+ *
+ * Revision 3.4 1993/11/13 11:13:17 kardel
+ * Solaris 2.3 additional includes
+ *
+ * Revision 3.3 1993/11/11 11:20:33 kardel
+ * declaration fixes
+ *
+ * Revision 3.2 1993/11/05 15:40:25 kardel
+ * shut up nice feature detection
+ *
+ * Revision 3.1 1993/11/01 20:00:29 kardel
+ * parse Solaris support (initial version)
+ *
+ */
diff --git a/contrib/xntpd/parse/parsestreams.c b/contrib/xntpd/parse/parsestreams.c
new file mode 100644
index 000000000000..b371aedafcee
--- /dev/null
+++ b/contrib/xntpd/parse/parsestreams.c
@@ -0,0 +1,1294 @@
+/*
+ * /src/NTP/REPOSITORY/v3/parse/parsestreams.c,v 3.12 1994/01/25 19:05:30 kardel Exp
+ *
+ * parsestreams.c,v 3.12 1994/01/25 19:05:30 kardel Exp
+ *
+ * STREAMS module for reference clocks
+ * (SunOS4.x)
+ *
+ * Copyright (c) 1989,1990,1991,1992,1993,1994
+ * 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.12 1994/01/25 19:05:30 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.12";
+ 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);
+ freemsg(mp);
+ }
+ else
+ if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
+ {
+ putnext(q, mp);
+ }
+ else
+ putq(q, mp);
+
+ 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.12 1994/01/25 19:05:30 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.11 1994/01/23 17:22:07 kardel
+ * 1994 reconcilation
+ *
+ * Revision 3.10 1993/12/15 12:48:58 kardel
+ * fixed message loss on M_*HANHUP messages
+ *
+ * Revision 3.9 1993/11/05 15:34:55 kardel
+ * shut up nice feature detection
+ *
+ * Revision 3.8 1993/10/22 14:27:56 kardel
+ * Oct. 22nd 1993 reconcilation
+ *
+ * Revision 3.7 1993/10/10 18:13:53 kardel
+ * Makefile reorganisation, file relocation
+ *
+ * Revision 3.6 1993/10/09 15:01:18 kardel
+ * file structure unified
+ *
+ * Revision 3.5 1993/10/04 07:59:31 kardel
+ * Well, at least we should know that a the tv_usec field should be in the range 0..999999
+ *
+ * Revision 3.4 1993/09/26 23:41:33 kardel
+ * new parse driver logic
+ *
+ * Revision 3.3 1993/09/11 00:38:34 kardel
+ * LINEMON must also cover M_[UN]HANGUP handling
+ *
+ * Revision 3.2 1993/07/06 10:02:56 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/contrib/xntpd/parse/util/Makefile.tmpl b/contrib/xntpd/parse/util/Makefile.tmpl
new file mode 100644
index 000000000000..aa0b26225952
--- /dev/null
+++ b/contrib/xntpd/parse/util/Makefile.tmpl
@@ -0,0 +1,49 @@
+#
+# /src/NTP/REPOSITORY/v3/parse/util/Makefile.tmpl,v 3.12 1994/01/25 19:05:39 kardel Exp
+#
+COMPILER= cc
+DEFS=
+DEFS_OPT=
+DEFS_LOCAL=
+CLOCKDEFS=
+INCL=
+COPTS= -O
+INSTALL= install
+BINDIR=
+#
+CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) -I../../include
+CC= $(COMPILER)
+TOP=../../
+#
+EXECS=parsetest testdcf dcfd
+
+all:
+ @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \
+ awk '/-DSTREAM/ && /-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \
+ END { if (makeit) \
+ { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" parsetest"; } \
+ }' | \
+ sh
+ @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \
+ awk '/-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \
+ END { if (makeit) \
+ { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" testdcf"; } \
+ }' | \
+ sh
+ @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \
+ awk '/-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \
+ END { if (makeit) \
+ { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" dcfd"; } \
+ }' | \
+ sh
+
+clean:
+ -@rm -f $(EXECS) *.o
+
+distclean: clean
+ -@rm -f *.orig *.rej .version Makefile
+
+install:
+ @echo "--- DCF77 utilities should be installed manually"
+ @#[ -f testdcf ] && $(INSTALL) -c -m 0755 testdcf $(BINDIR) || true
+ @#[ -f dcfd ] && $(INSTALL) -c -m 0755 dcfd $(BINDIR) || true
diff --git a/contrib/xntpd/parse/util/README b/contrib/xntpd/parse/util/README
new file mode 100644
index 000000000000..4f6dab08e940
--- /dev/null
+++ b/contrib/xntpd/parse/util/README
@@ -0,0 +1,12 @@
+This directory contains some DCF77 related programs.
+They have not yet fully been ported to other architectures then Sun with
+SunOS 4.x. So if you want to try them you are on your own - a little
+porting may be necessary.
+
+parsetest: simple parse streams module test
+testdcf: simple DCF77 raw impulse test program via 50Baud RS232
+dcfd: simple DCF77 raw impulse receiver with NTP loopfilter
+ mechanics for synchronisation (allows DCF77 synchronisation
+ without network code in a nutshell)
+
+Frank Kardel
diff --git a/contrib/xntpd/parse/util/dcfd.c b/contrib/xntpd/parse/util/dcfd.c
new file mode 100644
index 000000000000..23934a8e104e
--- /dev/null
+++ b/contrib/xntpd/parse/util/dcfd.c
@@ -0,0 +1,1583 @@
+/*
+ * /src/NTP/REPOSITORY/v3/parse/util/dcfd.c,v 3.15 1994/01/25 19:05:42 kardel Exp
+ *
+ * dcfd.c,v 3.15 1994/01/25 19:05:42 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,1994
+ * 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>
+
+/*
+ * NTP compilation environment
+ */
+#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
+
+/*
+ * select which terminal handling to use (currently only SysV variants)
+ */
+#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_) \
+ if ((_a_)->tv_usec >= 1000000) \
+ { \
+ (_a_)->tv_sec += (_a_)->tv_usec / 1000000; \
+ (_a_)->tv_usec = (_a_)->tv_usec % 1000000; \
+ } \
+ if ((_a_)->tv_usec < 0) \
+ { \
+ (_a_)->tv_sec -= 1 + -(_a_)->tv_usec / 1000000; \
+ (_a_)->tv_usec = 1000000 - (-(_a_)->tv_usec % 1000000); \
+ }
+
+#define timeradd(_a_, _b_) \
+ (_a_)->tv_sec += (_b_)->tv_sec; \
+ (_a_)->tv_usec += (_b_)->tv_usec; \
+ timernormalize((_a_))
+
+#define timersub(_a_, _b_) \
+ (_a_)->tv_sec -= (_b_)->tv_sec; \
+ (_a_)->tv_usec -= (_b_)->tv_usec; \
+ timernormalize((_a_))
+
+/*
+ * debug macros
+ */
+#define PRINTF if (interactive) printf
+#define LPRINTF if (interactive && loop_filter_debug) printf
+
+#ifdef DEBUG
+#define dprintf(_x_) PRINTF _x_
+#else
+#define dprintf(_x_)
+#endif
+
+extern int errno;
+
+/*
+ * display received data (avoids also detaching from tty)
+ */
+static int interactive = 0;
+
+/*
+ * display loopfilter (clock control) variables
+ */
+static int loop_filter_debug = 0;
+
+/*
+ * do not set/adjust system time
+ */
+static int no_set = 0;
+
+/*
+ * time that passes between start of DCF impulse and time stamping (fine
+ * adjustment) in microseconds (receiver/OS dependent)
+ */
+#define DEFAULT_DELAY 230000 /* rough estimate */
+
+/*
+ * The two states we can be in - eithe we receive nothing
+ * usable or we have the correct time
+ */
+#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 (10*60) /* allow synchronisation loss for 10 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 2
+#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) */
+
+/*
+ * DCF77 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; /* Day of week: 1: Monday - 7: Sunday */
+ long day;
+ long month;
+ long year;
+ long hour;
+ long minute;
+ long second;
+ long usecond;
+ long utcoffset; /* in minutes */
+ long flags; /* current clock status (DCF77 state flags) */
+};
+
+typedef struct clocktime clocktime_t;
+
+/*
+ * (usually) quick constant multiplications
+ */
+#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 */
+/*
+ * generic abs() function
+ */
+#define abs(_x_) (((_x_) < 0) ? -(_x_) : (_x_))
+
+/*
+ * conversion 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
+ */
+
+/*-----------------------------------------------------------------------
+ * conversion table to map DCF77 bit stream into data fields.
+ * Encoding:
+ * Each field of the DCF77 code is described with two adjacent entries in
+ * this table. The first entry specifies the offset into the DCF77 data stream
+ * while the length is given as the difference between the start index and
+ * the start index of the following field.
+ */
+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 }
+};
+
+/*-----------------------------------------------------------------------
+ * symbolic names for the fields of DCF77 describes in "rawdcfcode".
+ * see comment above for the structure of the DCF77 data
+ */
+#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
+
+/*-----------------------------------------------------------------------
+ * parity field table (same encoding as rawdcfcode)
+ * This table describes the sections of the DCF77 code that are
+ * parity protected
+ */
+static struct partab
+{
+ char offset; /* start bit of parity field */
+} partab[] =
+{
+ { 21 }, { 29 }, { 36 }, { 59 }
+};
+
+/*-----------------------------------------------------------------------
+ * offsets for parity field descriptions
+ */
+#define DCF_P_P1 0
+#define DCF_P_P2 1
+#define DCF_P_P3 2
+
+/*-----------------------------------------------------------------------
+ * legal values for time zone information
+ */
+#define DCF_Z_MET 0x2
+#define DCF_Z_MED 0x1
+
+/*-----------------------------------------------------------------------
+ * symbolic representation if the DCF77 data stream
+ */
+static struct dcfparam
+{
+ unsigned char onebits[60];
+ unsigned char zerobits[60];
+} dcfparam =
+{
+ "###############RADMLS1248124P124812P1248121241248112481248P", /* 'ONE' representation */
+ "--------------------s-------p------p----------------------p" /* 'ZERO' representation */
+};
+
+/*-----------------------------------------------------------------------
+ * extract a bitfield from DCF77 datastream
+ * All numeric field are LSB first.
+ * buf holds a pointer to a DCF77 data buffer in symbolic
+ * representation
+ * idx holds the index to the field description in rawdcfcode
+ */
+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;
+}
+
+/*-----------------------------------------------------------------------
+ * check even parity integrity for a bitfield
+ *
+ * buf holds a pointer to a DCF77 data buffer in symbolic
+ * representation
+ * idx holds the index to the field description in partab
+ */
+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;
+}
+
+/*-----------------------------------------------------------------------
+ * convert a DCF77 data buffer into wall clock time + flags
+ *
+ * buffer holds a pointer to a DCF77 data buffer in symbolic
+ * representation
+ * size describes the length of DCF77 information in bits (represented
+ * as chars in symbolic notation
+ * clock points to a wall clock time description of the DCF77 data (result)
+ */
+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 - extract all fields and build wall clock time from them
+ */
+
+ 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);
+
+ /*
+ * determine offset to UTC by examining the time zone
+ */
+ 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;
+ }
+
+ /*
+ * extract various warnings from DCF77
+ */
+ 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)
+ *
+ * The basic idea is that on corret reception we must have two
+ * maxima in the pulse length distribution histogram. (one for
+ * the zero representing pulses and one for the one representing
+ * pulses)
+ * There will always be ones in the datastream, thus we have to see
+ * two maxima.
+ * The best point to cut for a 1/0 decision is the minimum between those
+ * between the maxima. The following code tries to find this cutoff point.
+ */
+
+ /*
+ * clear histogram buffer
+ */
+ for (i = 0; i < BITS; i++)
+ {
+ histbuf[i] = 0;
+ }
+
+ cutoff = 0;
+ lowmax = 0;
+
+ /*
+ * convert sequences of set bits into bits counts updating
+ * the histogram alongway
+ */
+ while (s < e)
+ {
+ register unsigned int ch = *s ^ 0xFF;
+ /*
+ * check integrity and update histogramm
+ */
+ if (!((ch+1) & ch) || !*s)
+ {
+ /*
+ * character ok
+ */
+ for (i = 0; ch; i++)
+ {
+ ch >>= 1;
+ }
+
+ *s = i;
+ histbuf[i]++;
+ cutoff += i;
+ lowmax++;
+ }
+ else
+ {
+ /*
+ * invalid character (no consecutive bit sequence)
+ */
+ dprintf(("parse: cvt_rawdcf: character check for 0x%x@%d FAILED\n", *s, s - buffer));
+ *s = ~0;
+ rtc = CVT_FAIL|CVT_BADFMT;
+ }
+ s++;
+ }
+
+ /*
+ * first cutoff estimate (average bit count - must be between both
+ * maxima)
+ */
+ 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; /* weighted sum */
+ highmax = 0; /* bitcount */
+
+ /*
+ * collect weighted sum of lower bits (left of initial guess)
+ */
+ dprintf(("parse: cvt_rawdcf: histogram:"));
+ for (i = 0; i <= cutoff; i++)
+ {
+ lowmax += histbuf[i] * i;
+ highmax += histbuf[i];
+ dprintf((" %d", histbuf[i]));
+ }
+ dprintf((" <M>"));
+
+ /*
+ * round up
+ */
+ lowmax += highmax / 2;
+
+ /*
+ * calculate lower bit maximum (weighted sum / bit count)
+ *
+ * avoid divide by zero
+ */
+ if (highmax)
+ {
+ lowmax /= highmax;
+ }
+ else
+ {
+ lowmax = 0;
+ }
+
+ highmax = 0; /* weighted sum of upper bits counts */
+ cutoff = 0; /* bitcount */
+
+ /*
+ * collect weighted sum of lower bits (right of initial guess)
+ */
+ for (; i < BITS; i++)
+ {
+ highmax+=histbuf[i] * i;
+ cutoff +=histbuf[i];
+ dprintf((" %d", histbuf[i]));
+ }
+ dprintf(("\n"));
+
+ /*
+ * determine upper maximum (weighted sum / bit count)
+ */
+ if (cutoff)
+ {
+ highmax /= cutoff;
+ }
+ else
+ {
+ highmax = BITS-1;
+ }
+
+ /*
+ * following now holds:
+ * lowmax <= cutoff(initial guess) <= highmax
+ * best cutoff is the minimum nearest to higher bits
+ */
+
+ /*
+ * find the minimum between lowmax and highmax (detecting
+ * possibly a minimum span)
+ */
+ span = cutoff = lowmax;
+ for (i = lowmax; i <= highmax; i++)
+ {
+ if (histbuf[cutoff] > histbuf[i])
+ {
+ /*
+ * got a new minimum move beginning of minimum (cutoff) and
+ * end of minimum (span) there
+ */
+ cutoff = span = i;
+ }
+ else
+ if (histbuf[cutoff] == histbuf[i])
+ {
+ /*
+ * minimum not better yet - but it spans more than
+ * one bit value - follow it
+ */
+ span = i;
+ }
+ }
+
+ /*
+ * cutoff point for 1/0 decision is the middle of the minimum section
+ * in the histogram
+ */
+ cutoff = (cutoff + span) / 2;
+
+ dprintf(("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff));
+
+ /*
+ * convert the bit counts to symbolic 1/0 information for data conversion
+ */
+ s = buffer;
+ while ((s < e) && *c && *b)
+ {
+ if (*s == (unsigned char)~0)
+ {
+ /*
+ * invalid character
+ */
+ *s = '?';
+ }
+ else
+ {
+ /*
+ * symbolic 1/0 representation
+ */
+ *s = (*s >= cutoff) ? *b : *c;
+ }
+ s++;
+ b++;
+ c++;
+ }
+
+ /*
+ * if everything went well so far return the result of the symbolic
+ * conversion routine else just the accumulated errors
+ */
+ return (rtc == CVT_NONE) ? convert_rawdcf(buffer, size, clock) : rtc;
+}
+
+/*-----------------------------------------------------------------------
+ * convert a wall clock time description of DCF77 to a Unix time (seconds
+ * since 1.1. 1970 UTC)
+ */
+time_t
+dcf_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;
+
+ /*
+ * map 2 digit years to 19xx (DCF77 is a 20th century item)
+ */
+ if (clock->year < 100)
+ clock->year += 1900;
+
+ /*
+ * assume that we convert timecode within the unix/UTC epoch -
+ * prolonges validity of 2 digit years
+ */
+ if (clock->year < 1994)
+ clock->year += 100; /* XXX this will do it till <2094 */
+
+ /*
+ * must have been a really negative year code - drop it
+ */
+ if (clock->year < 0)
+ {
+ SETRTC(CVT_FAIL|CVT_BADDATE);
+ return -1;
+ }
+
+ /*
+ * sorry, slow section here - but it's not time critical anyway
+ */
+
+ /*
+ * calculate days since 1970 (watching leap years)
+ */
+ 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 current leap year */
+ if (clock->month >= 3 && dysize(clock->year) == 366)
+ t++;
+
+ /*
+ * collect days from months excluding the current one
+ */
+ 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 */
+ }
+
+ /*
+ * collect days from date excluding the current one
+ */
+ t += clock->day - 1;
+
+ /* hour */
+ if (clock->hour < 0 || clock->hour >= 24)
+ {
+ SETRTC(CVT_FAIL|CVT_BADTIME);
+ return -1; /* bad hour */
+ }
+
+ /*
+ * calculate hours from 1. 1. 1970
+ */
+ t = TIMES24(t) + clock->hour;
+
+ /* min */
+ if (clock->minute < 0 || clock->minute > 59)
+ {
+ SETRTC(CVT_FAIL|CVT_BADTIME);
+ return -1; /* bad min */
+ }
+
+ /*
+ * calculate minutes from 1. 1. 1970
+ */
+ t = TIMES60(t) + clock->minute;
+ /* sec */
+
+ /*
+ * calculate UTC in minutes
+ */
+ t += clock->utcoffset;
+
+ if (clock->second < 0 || clock->second > 60) /* allow for LEAPs */
+ {
+ SETRTC(CVT_FAIL|CVT_BADTIME);
+ return -1; /* bad sec */
+ }
+
+ /*
+ * calculate UTC in seconds - phew !
+ */
+ 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);
+}
+
+/*-----------------------------------------------------------------------
+ * week day representation
+ */
+static char *wday[8] =
+{
+ "??",
+ "Mo",
+ "Tu",
+ "We",
+ "Th",
+ "Fr",
+ "Sa",
+ "Su"
+};
+
+/*-----------------------------------------------------------------------
+ * generate a string representation for a timeval
+ */
+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;
+}
+
+/*-----------------------------------------------------------------------
+ * correct the current time by an offset by setting the time rigorously
+ */
+static void set_time(offset)
+ struct timeval *offset;
+{
+ struct timeval the_time;
+
+ if (no_set)
+ return;
+
+ LPRINTF("set_time: %s ", pr_timeval(offset));
+ syslog(LOG_NOTICE, "setting time (offset %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()");
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ * slew the time by a given offset
+ */
+static void adj_time(offset)
+ register long offset;
+{
+ struct timeval time_offset;
+
+ if (no_set)
+ return;
+
+ time_offset.tv_sec = offset / 1000000;
+ time_offset.tv_usec = offset % 1000000;
+
+ LPRINTF("adj_time: %d us ", offset);
+ if (adjtime(&time_offset, 0L) == -1)
+ perror("adjtime()");
+}
+
+/*-----------------------------------------------------------------------
+ * read in a possibly previously written drift value
+ */
+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);
+ LPRINTF("read_drift: %d.%03d ppm ", idrift, fdrift);
+
+ drift_comp = idrift << USECSCALE;
+ fdrift = (fdrift << USECSCALE) / 1000;
+ drift_comp += fdrift & (1<<USECSCALE);
+ LPRINTF("read_drift: drift_comp %d ", drift_comp);
+ }
+}
+
+/*-----------------------------------------------------------------------
+ * write out the current drift value
+ */
+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);
+
+ LPRINTF("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);
+ LPRINTF("update_drift: %d.%03d ppm ", idrift, fdrift);
+ }
+}
+
+/*-----------------------------------------------------------------------
+ * process adjustments derived from the DCF77 observation
+ * (controls clock PLL)
+ */
+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 (no_set)
+ return;
+
+ 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);
+ LPRINTF("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);
+}
+
+/*-----------------------------------------------------------------------
+ * adjust the clock by a small mount to simulate frequency correction
+ */
+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);
+}
+
+/*-----------------------------------------------------------------------
+ * control synchronisation status (warnings) and do periodic adjusts
+ * (frequency control simulation)
+ */
+static void tick()
+{
+ static unsigned long last_notice = 0;
+
+#ifndef SV_ONSTACK
+ (void)signal(SIGALRM, tick);
+#endif
+
+ periodic_adjust();
+
+ ticks += 1<<ADJINTERVAL;
+
+ if ((ticks - last_sync) > MAX_UNSYNC)
+ {
+ /*
+ * not getting time for a while
+ */
+ if (sync_state == SYNC)
+ {
+ /*
+ * completely lost information
+ */
+ sync_state = NO_SYNC;
+ syslog(LOG_INFO, "DCF77 reception lost (timeout)");
+ last_notice = ticks;
+ }
+ else
+ /*
+ * in NO_SYNC state - look whether its time to speak up again
+ */
+ if ((ticks - last_notice) > NOTICE_INTERVAL)
+ {
+ syslog(LOG_NOTICE, "still not synchronized to DCF77 - check receiver/signal");
+ last_notice = ticks;
+ }
+ }
+
+#ifndef ITIMER_REAL
+ (void) alarm(1<<ADJINTERVAL);
+#endif
+}
+
+/*-----------------------------------------------------------------------
+ * break association from terminal to avaoid catching terminal
+ * or process group related signals (-> daemon operation)
+ */
+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 */
+}
+
+/*-----------------------------------------------------------------------
+ * list possible arguments and options
+ */
+static void usage(program)
+ char *program;
+{
+ fprintf(stderr, "usage: %s [-f] [-l] [-t] [-i] [-o] [-d <drift_file>] <device>\n", program);
+ fprintf(stderr, "\t-n do not change time\n");
+ 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");
+ fprintf(stderr, "\t-D <input delay>specify delay from input edge to processing in micro seconds\n");
+}
+
+/*-----------------------------------------------------------------------
+ * main loop - argument interpreter / setup / main loop
+ */
+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 delay = DEFAULT_DELAY; /* average delay from input edge to time stamping */
+ int trace = 0;
+ int errs = 0;
+
+ /*
+ * process arguments
+ */
+ 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 'n':
+ no_set = 1;
+ break;
+
+ case 'o':
+ offsets = 1;
+ interactive = 1;
+ break;
+
+ case 'i':
+ interactive = 1;
+ break;
+
+ case 'D':
+ if (ac > 1)
+ {
+ delay = atoi(*++a);
+ ac--;
+ }
+ else
+ {
+ fprintf(stderr, "%s: -D requires integer argument\n", argv[0]);
+ errs=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;
+
+ /*
+ * get access to DCF77 tty port
+ */
+ 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;
+ time_t last_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 = delay;
+
+ /*
+ * setup TTY (50 Baud, Read, 8Bit, No Hangup, 1 character IO)
+ */
+ 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);
+ }
+
+ /*
+ * loose terminal if in daemon operation
+ */
+ if (!interactive)
+ detach();
+
+ /*
+ * get syslog() initialized
+ */
+#ifdef LOG_DAEMON
+ openlog("dcfd", LOG_PID, LOG_DAEMON);
+#else
+ openlog("dcfd", LOG_PID);
+#endif
+
+ /*
+ * setup periodic operations (state control / frequency control)
+ */
+#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);
+
+ /*
+ * what time is it now (for interval measurement)
+ */
+ gettimeofday(&tlast, 0L);
+ i = 0;
+ /*
+ * loop until input trouble ...
+ */
+ do
+ {
+ /*
+ * get an impulse
+ */
+ 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;
+ }
+
+ /*
+ * timeout -> possible minute mark -> interpretation
+ */
+ 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)
+ {
+ /*
+ * this data was bad - well - forget synchronisation for now
+ */
+ PRINTF("\n");
+ if (sync_state == SYNC)
+ {
+ sync_state = NO_SYNC;
+ syslog(LOG_INFO, "DCF77 reception lost (bad data)");
+ }
+ errs++;
+ }
+
+ buf[0] = c;
+
+ /*
+ * collect first character
+ */
+ if (((c^0xFF)+1) & (c^0xFF))
+ pbuf[0] = '?';
+ else
+ pbuf[0] = type(c) ? '#' : '-';
+
+ for ( i = 1; i < 60; i++)
+ pbuf[i] = '.';
+
+ i = 0;
+ }
+ else
+ {
+ /*
+ * collect character
+ */
+ 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)
+ {
+ /*
+ * we got a good time code here - try to convert it to
+ * UTC
+ */
+ if ((utc_time = dcf_to_unixtime(&clock, &rtc)) == -1)
+ {
+ PRINTF("*** BAD CONVERSION\n");
+ }
+
+ if (utc_time != (last_utc_time + 60))
+ {
+ /*
+ * well, two successive sucessful telegrams are not 60 seconds
+ * apart
+ */
+ PRINTF("*** NO MINUTE INC\n");
+ if (sync_state == SYNC)
+ {
+ sync_state = NO_SYNC;
+ syslog(LOG_INFO, "DCF77 reception lost (data mismatch)");
+ }
+ errs++;
+ rtc = CVT_FAIL|CVT_BADTIME|CVT_BADDATE;
+ }
+ else
+ usecerror = 0;
+
+ last_utc_time = utc_time;
+ }
+
+ if (rtc == CVT_OK)
+ {
+ if (trace && (i == 0))
+ {
+ PRINTF("\r %.*s ", 59 - offset, &buf[offset]);
+ }
+
+ if (i == 0)
+ {
+ /*
+ * valid time code - determine offset and
+ * note regained reception
+ */
+ last_sync = ticks;
+ if (sync_state == NO_SYNC)
+ {
+ syslog(LOG_INFO, "receiving DCF77");
+ }
+ else
+ {
+ /*
+ * we had at least one minute SYNC - thus
+ * last error is valid
+ */
+ time_offset.tv_sec = lasterror / 1000000;
+ time_offset.tv_usec = lasterror % 1000000;
+ adjust_clock(&time_offset, drift_file, utc_time);
+ }
+ 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;
+
+ /*
+ * output interpreted DCF77 data
+ */
+ 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);
+ }
+ else
+ {
+ lasterror = 0; /* we cannot calculate phase errors on bad reception */
+ }
+
+ PRINTF("\r");
+
+ if (i < 60)
+ {
+ i++;
+ }
+
+ tlast = tt;
+
+ if (interactive)
+ fflush(stdout);
+ }
+ } while ((rrc == -1) && (errno == EINTR));
+
+ /*
+ * lost IO - sorry guys
+ */
+ syslog(LOG_ERR, "TERMINATING - cannot read from device %s (%m)", file);
+
+ (void)close(fd);
+ }
+
+ closelog();
+
+ return 0;
+}
diff --git a/contrib/xntpd/parse/util/parsetest.c b/contrib/xntpd/parse/util/parsetest.c
new file mode 100644
index 000000000000..9028b4cf4cf4
--- /dev/null
+++ b/contrib/xntpd/parse/util/parsetest.c
@@ -0,0 +1,268 @@
+/*
+ * /src/NTP/REPOSITORY/v3/kernel/parsetest.c,v 3.4 1993/03/17 17:16:57 kardel Exp
+ *
+ * parsetest.c,v 3.10 1994/01/23 17:22:18 kardel Exp
+ *
+ * Copyright (c) 1989,1990,1991,1992,1993,1994
+ * 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.10 1994/01/23 17:22:18 kardel Exp\n");
+
+ while (ioctl(fd, I_POP, 0) == 0)
+ ;
+
+ if (ioctl(fd, I_PUSH, "parse") == -1)
+ {
+ perror("ioctl(I_PUSH,\"parse\")");
+ exit(1);
+ }
+
+ strioc.ic_cmd = PARSEIOC_GETSTAT;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)&dct;
+ strioc.ic_len = sizeof(parsectl_t);
+
+ if (ioctl(fd, I_STR, &strioc) == -1)
+ {
+ perror("ioctl(fd, I_STR(PARSEIOC_GETSTAT))");
+ exit(1);
+ }
+ printf("parse status: %04x\n", dct.parsestatus.flags);
+
+ dct.parsestatus.flags |= PARSE_STAT_FILTER;
+ strioc.ic_cmd = PARSEIOC_SETSTAT;
+
+ if (ioctl(fd, I_STR, &strioc) == -1)
+ {
+ perror("ioctl(fd, I_STR(PARSEIOC_SETSTAT))");
+ exit(1);
+ }
+ printf("PARSE clock FILTERMODE\n");
+
+ if (ioctl(fd, I_STR, &strioc) == -1)
+ {
+ perror("ioctl(fd, I_STR(PARSEIOC_GETSTAT))");
+ exit(1);
+ }
+ printf("parse status: %04x\n", dct.parsestatus.flags);
+
+ while (read(fd, &parsetime, sizeof(parsetime)) == sizeof(parsetime))
+ {
+ char tmp[200], tmp1[200], tmp2[60];
+
+ strncpy(tmp, asctime(localtime(&parsetime.parse_time.tv.tv_sec)), 30);
+ strncpy(tmp1,asctime(localtime(&parsetime.parse_stime.tv.tv_sec)), 30);
+ strncpy(tmp2,asctime(localtime(&parsetime.parse_ptime.tv.tv_sec)), 30);
+ tmp[24] = '\0';
+ tmp1[24] = '\0';
+ tmp2[24] = '\0';
+
+ printf("%s (+%06dus) %s PPS: %s (+%06dus), ", tmp1, parsetime.parse_stime.tv.tv_usec, tmp, tmp2, parsetime.parse_ptime.tv.tv_usec);
+
+ strstatus(tmp, parsetime.parse_state);
+ printf("state: 0x%x (%s) error: %dus, dispersion: %dus, Status: 0x%x (%s)\n",
+ parsetime.parse_state,
+ tmp,
+ parsetime.parse_usecerror,
+ parsetime.parse_usecdisp,
+ parsetime.parse_status,
+ parsestatus(parsetime.parse_status, tmp1));
+ }
+
+ close(fd);
+ }
+ }
+ return 0;
+}
diff --git a/contrib/xntpd/parse/util/testdcf.c b/contrib/xntpd/parse/util/testdcf.c
new file mode 100644
index 000000000000..ebdfd2fded07
--- /dev/null
+++ b/contrib/xntpd/parse/util/testdcf.c
@@ -0,0 +1,485 @@
+/*
+ * /src/NTP/REPOSITORY/v3/parse/util/testdcf.c,v 3.9 1994/01/25 19:05:45 kardel Exp
+ *
+ * testdcf.c,v 3.9 1994/01/25 19:05:45 kardel Exp
+ *
+ * simple DCF77 100/200ms pulse test program (via 50Baud serial line)
+ *
+ * Copyright (c) 1993,1994
+ * 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);
+ }
+
+ 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 (tcsetattr(fd, TCSANOW, &term) == -1)
+ {
+ perror("tcsetattr");
+ exit(1);
+ }
+
+#ifdef I_POP
+ while (ioctl(fd, I_POP, 0) == 0)
+ ;
+#endif
+#if defined(TIOCMBIC) && defined(TIOCM_RTS)
+ if (ioctl(fd, TIOCMBIC, (caddr_t)&on) == -1)
+ {
+ perror("TIOCM_RTS");
+ }
+#endif
+
+ printf(" DCF77 monitor - Copyright 1993, Frank Kardel\n\n");
+
+ clock.hour = 0;
+ clock.minute = 0;
+ clock.day = 0;
+ clock.wday = 0;
+ clock.month = 0;
+ clock.year = 0;
+ clock.flags = 0;
+ buf[60] = '\0';
+ for ( i = 0; i < 60; i++)
+ buf[i] = '.';
+
+ gettimeofday(&tlast, 0L);
+ i = 0;
+ while (read(fd, &c, 1) == 1)
+ {
+ gettimeofday(&t, 0L);
+ tt = t;
+ t.tv_sec -= tlast.tv_sec;
+ t.tv_usec -= tlast.tv_usec;
+ if (t.tv_usec < 0)
+ {
+ t.tv_usec += 1000000;
+ t.tv_sec -= 1;
+ }
+
+ if (errs > LINES)
+ {
+ printf(" %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]);
+ printf(" %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]);
+ errs = 0;
+ }
+
+ if (t.tv_sec > 1 ||
+ t.tv_sec == 1 &&
+ t.tv_usec > 500000)
+ {
+ printf("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &buf[offset]);
+
+ if ((rtc = convert_rawdcf(buf, i, &clock)) != CVT_OK)
+ {
+ printf("\n");
+ clock.hour = 0;
+ clock.minute = 0;
+ clock.day = 0;
+ clock.wday = 0;
+ clock.month = 0;
+ clock.year = 0;
+ clock.flags = 0;
+ errs++;
+ }
+
+ if (((c^0xFF)+1) & (c^0xFF))
+ buf[0] = '?';
+ else
+ buf[0] = type(c) ? '#' : '-';
+
+ for ( i = 1; i < 60; i++)
+ buf[i] = '.';
+
+ i = 0;
+ }
+ else
+ {
+ if (((c^0xFF)+1) & (c^0xFF))
+ buf[i] = '?';
+ else
+ buf[i] = type(c) ? '#' : '-';
+
+ printf("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &buf[offset]);
+ }
+
+ if (rtc == CVT_OK)
+ {
+ printf("%s, %2d:%02d:%02d, %d.%02d.%02d, <%s%s%s%s>",
+ wday[clock.wday],
+ clock.hour, clock.minute, i, clock.day, clock.month,
+ clock.year,
+ (clock.flags & DCFB_ALTERNATE) ? "R" : "_",
+ (clock.flags & DCFB_ANNOUNCE) ? "A" : "_",
+ (clock.flags & DCFB_DST) ? "D" : "_",
+ (clock.flags & DCFB_LEAP) ? "L" : "_"
+ );
+ if (trace && (i == 0))
+ {
+ printf("\n");
+ errs++;
+ }
+ }
+
+ printf("\r");
+
+ if (i < 60)
+ {
+ i++;
+ }
+
+ tlast = tt;
+
+ fflush(stdout);
+ }
+ close(fd);
+ }
+ }
+ return 0;
+}
diff --git a/contrib/xntpd/ppsclock/ppstest/.keep_me b/contrib/xntpd/ppsclock/ppstest/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/ppsclock/ppstest/.keep_me
diff --git a/contrib/xntpd/ppsclock/sys/genassym/.keep_me b/contrib/xntpd/ppsclock/sys/genassym/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/ppsclock/sys/genassym/.keep_me
diff --git a/contrib/xntpd/ppsclock/sys/os/.keep_me b/contrib/xntpd/ppsclock/sys/os/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/ppsclock/sys/os/.keep_me
diff --git a/contrib/xntpd/ppsclock/sys/sun/.keep_me b/contrib/xntpd/ppsclock/sys/sun/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/ppsclock/sys/sun/.keep_me
diff --git a/contrib/xntpd/ppsclock/sys/sun4c/.keep_me b/contrib/xntpd/ppsclock/sys/sun4c/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/ppsclock/sys/sun4c/.keep_me
diff --git a/contrib/xntpd/ppsclock/sys/sun4c/conf/.keep_me b/contrib/xntpd/ppsclock/sys/sun4c/conf/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/ppsclock/sys/sun4c/conf/.keep_me
diff --git a/contrib/xntpd/ppsclock/sys/sun4m/conf/.keep_me b/contrib/xntpd/ppsclock/sys/sun4m/conf/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/ppsclock/sys/sun4m/conf/.keep_me
diff --git a/contrib/xntpd/ppsclock/sys/sundev/.keep_me b/contrib/xntpd/ppsclock/sys/sundev/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/ppsclock/sys/sundev/.keep_me
diff --git a/contrib/xntpd/ppsclock/sys/sys/.keep_me b/contrib/xntpd/ppsclock/sys/sys/.keep_me
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/ppsclock/sys/sys/.keep_me
diff --git a/contrib/xntpd/refclocks/Dependencies b/contrib/xntpd/refclocks/Dependencies
new file mode 100644
index 000000000000..28294765f79e
--- /dev/null
+++ b/contrib/xntpd/refclocks/Dependencies
@@ -0,0 +1,30 @@
+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 /SYSV_TTYS/||/STREAM/||/TERMIOS/ PPS any||STREAM(parse||ppsclock||ppsclocd)
+ PARSEPPS /SYSV_TTYS/||/STREAM/||/TERMIOS/ PPS any||STREAM(parse||ppsclock||ppsclocd)
+ CLOCK_*
+MX4200 MX4200PPS /PPSPPS/
+AS2201 AS2201
+ AS2201PPS /PPSPPS/
+GOES GOES
+ GOESPPS /PPSPPS/
+GPSTM GPSTM
+ GPSTTMPPS /PPSPPS/
+OMEGA OMEGA
+ OMEGAPPS /PPSPPS/
+TPRO TPRO /SUNOS/
+LEITCH LEITCH
+ LEITCHPPS /PPSPPS/
+MSFEES MSFEESPPS /PPSPPS/
+IRIG IRIG /SUNOS/ BSDAUDIO
diff --git a/contrib/xntpd/refclocks/README b/contrib/xntpd/refclocks/README
new file mode 100644
index 000000000000..b27b0064bdf3
--- /dev/null
+++ b/contrib/xntpd/refclocks/README
@@ -0,0 +1,4 @@
+This directory contains shell scripts that should allow an interactive
+refclock configuration.
+
+Frank Kardel
diff --git a/contrib/xntpd/refclocks/check b/contrib/xntpd/refclocks/check
new file mode 100755
index 000000000000..d1e8b19cd558
--- /dev/null
+++ b/contrib/xntpd/refclocks/check
@@ -0,0 +1,2 @@
+#!/bin/sh
+`echo "$1" | awk '{ if ( '"$2"' ) { print ":"; } else { print "false"; } exit; }'`;
diff --git a/contrib/xntpd/refclocks/echon b/contrib/xntpd/refclocks/echon
new file mode 100755
index 000000000000..8750ae86c2d4
--- /dev/null
+++ b/contrib/xntpd/refclocks/echon
@@ -0,0 +1,2 @@
+#!/bin/sh
+echo -n "$@";
diff --git a/contrib/xntpd/refclocks/query b/contrib/xntpd/refclocks/query
new file mode 100755
index 000000000000..07e11ccf2f7a
--- /dev/null
+++ b/contrib/xntpd/refclocks/query
@@ -0,0 +1,11 @@
+#!/bin/sh
+echon "$1 (y/n) [$2] ? "
+X=""
+read X
+if [ "$X" = "" ]; then
+ X="$2"
+fi
+case "$X" in
+ [yY]*) exit 0;;
+ *) exit 1;;
+esac
diff --git a/contrib/xntpd/refclocks/rclk.AS2201 b/contrib/xntpd/refclocks/rclk.AS2201
new file mode 100644
index 000000000000..9af89af40965
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.AS2201
@@ -0,0 +1,29 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ echo " AS2201 - Austron 2200A or 2201A GPS receiver"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /AS2201/'; then
+ echo "AS2201 - Austron 2200A or 2201A GPS receiver"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /AS2201/' ||
+ ( [ ! "$REFCONF" ] && query "Include Austron 2200A or 2201A GPS receiver (AS2201)" n); then
+ if check "$PPSFEATURES" '$0 ~ /CD/' &&
+ [ "$PPSOK" -eq 1 ] &&
+ (check "$REFCONF" '$0 ~ /AS2201PPS/' ||
+ ( [ ! "$REFCONF" ] && query " Use AS2201 for PPS" n)); then
+ echo "-DAS2201PPS" >> $RCONFIG
+ else
+ echo "-DAS2201" >> $RCONFIG
+ fi
+ fi
+ ;;
+esac
diff --git a/contrib/xntpd/refclocks/rclk.CHU b/contrib/xntpd/refclocks/rclk.CHU
new file mode 100644
index 000000000000..fedd55c33dea
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.CHU
@@ -0,0 +1,24 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+if check "$DEFS" '$0 ~ /SYS_SUNOS4/'; then
+ case "$CMD" in
+ info)
+ echo " CHU - CHU via shortwave radio"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /CHU/'; then
+ echo "CHU - CHU via shortwave radio"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /CHU/' ||
+ ( [ ! "$REFCONF" ] && query "Include CHU via shortwave radio (CHU)" n); then
+ echo "-DCHU" >> $RCONFIG
+ fi
+ ;;
+esac
+fi
diff --git a/contrib/xntpd/refclocks/rclk.GOES b/contrib/xntpd/refclocks/rclk.GOES
new file mode 100644
index 000000000000..cb87c638987e
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.GOES
@@ -0,0 +1,32 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ echo " GOES - Kinemetrics/TrueTime 468-DC GOES receiver"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /GOES/'; then
+ echo "GOES - Kinemetrics/TrueTime 468-DC GOES receiver"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /GOES/' ||
+ ( [ ! "$REFCONF" ] && query "Include Kinemetrics/TrueTime 468-DC GOES receiver (GOES)" n); then
+ if check "$PPSFEATURES" '$0 ~ /CD/'; then
+ if [ "$PPSOK" -eq 1 ] &&
+ (check "$REFCONF" '$0 ~ /GOESPPS/' ||
+ ( [ ! "$REFCONF" ] && query " Use GOES for PPS" n)); then
+ echo "-DGOESPPS" >> $RCONFIG
+ else
+ echo "-DGOES" >> $RCONFIG
+ fi
+ else
+ echo "-DGOES" >> $RCONFIG
+ fi
+ fi
+ ;;
+esac
diff --git a/contrib/xntpd/refclocks/rclk.GPSTM b/contrib/xntpd/refclocks/rclk.GPSTM
new file mode 100644
index 000000000000..552747a57afd
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.GPSTM
@@ -0,0 +1,33 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ echo " GPSTM - Kinemetrics/TrueTime GPS-TM/TMD receiver"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /GPSTM/'; then
+ echo "GPSTM - Kinemetrics/TrueTime GPS-TM/TMD receiver"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /GPSTM/' ||
+ ( [ ! "$REFCONF" ] &&
+ query "Include Kinemetrics/TrueTime GPS-TM/TMD receiver (GPSTM)" n); then
+ if check "$PPSFEATURES" '$0 ~ /CD/'; then
+ if [ "$PPSOK" -eq 1 ] &&
+ (check "$REFCONF" '$0 ~ /GPSTMPPS/' ||
+ ( [ ! "$REFCONF" ] && query " Use GPSTM for PPS" n)); then
+ echo "-DGPSTMPPS" >> $RCONFIG
+ else
+ echo "-DGPSTM" >> $RCONFIG
+ fi
+ else
+ echo "-DGPSTM" >> $RCONFIG
+ fi
+ fi
+ ;;
+esac
diff --git a/contrib/xntpd/refclocks/rclk.IRIG b/contrib/xntpd/refclocks/rclk.IRIG
new file mode 100644
index 000000000000..b480e90391c4
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.IRIG
@@ -0,0 +1,24 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+if check "$DEFS" '$0 ~ /SYS_SUNOS4/'; then
+ case "$CMD" in
+ info)
+ echo " IRIG - IRIG-B timecode timecode using the audio codec"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /IRIG/'; then
+ echo "IRIG - IRIG-B timecode timecode using the audio codec"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /IRIG/' ||
+ ( [ ! "$REFCONF" ] && query "Include IRIG-B timecode timecode using the audio codec (IRIG)" n); then
+ echo "-DIRIG" >> $RCONFIG
+ fi
+ ;;
+ esac
+fi
diff --git a/contrib/xntpd/refclocks/rclk.LEITCH b/contrib/xntpd/refclocks/rclk.LEITCH
new file mode 100644
index 000000000000..1bd5fb8011bd
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.LEITCH
@@ -0,0 +1,29 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ echo " LEITCH - Leitch CSD 5300 Master Clock System Driver"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /LEITCH/'; then
+ echo "LEITCH - Leitch CSD 5300 Master Clock System Driver"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /LEITCH/' ||
+ ( [ ! "$REFCONF" ] && query "Include Leitch CSD 5300 Master Clock System Driver (LEITCH)" n); then
+ if check "$PPSFEATURES" '$0 ~ /CD/' &&
+ [ "$PPSOK" -eq 1 ] &&
+ (check "$REFCONF" '$0 ~ /LEITCHPPS/' ||
+ ( [ ! "$REFCONF" ] && query " Use LEITCH for PPS" n)); then
+ echo "-DLEITCHPPS" >> $RCONFIG
+ else
+ echo "-DLEITCH" >> $RCONFIG
+ fi
+ fi
+ ;;
+esac
diff --git a/contrib/xntpd/refclocks/rclk.LOCAL_CLOCK b/contrib/xntpd/refclocks/rclk.LOCAL_CLOCK
new file mode 100644
index 000000000000..e2f9e1afe753
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.LOCAL_CLOCK
@@ -0,0 +1,22 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ echo " LOCAL_CLOCK - use local clock as reference"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /LOCAL_CLOCK/'; then
+ echo "LOCAL_CLOCK - local clock"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /LOCAL_CLOCK/' ||
+ ( [ ! "$REFCONF" ] && query "Include local clock reference support (LOCAL_CLOCK)" y); then
+ echo "-DLOCAL_CLOCK" >> $RCONFIG
+ fi
+ ;;
+esac
diff --git a/contrib/xntpd/refclocks/rclk.MSFEES b/contrib/xntpd/refclocks/rclk.MSFEES
new file mode 100644
index 000000000000..aeb988af8d80
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.MSFEES
@@ -0,0 +1,26 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ if check "$DEFS" '$0 ~ /STREAM/'; then
+ echo " MSFEESPPS - EES M201 MSF receiver"
+ fi
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /MSFEESPPS/'; then
+ echo "MSFEESPPS - EES M201 MSF receiver"
+ fi
+ ;;
+ config)
+ if check "$PPSFEATURES" '$0 ~ /CD/' &&
+ [ "$PPSOK" -eq 1 ] &&
+ (check "$REFCONF" '$0 ~ /MSFEESPPS/' ||
+ ( [ ! "$REFCONF" ] && query "Include EES M201 MSF receiver (MSFEESPPS)" n)); then
+ echo "-DMSFEESPPS" >> $RCONFIG
+ fi
+ ;;
+esac
diff --git a/contrib/xntpd/refclocks/rclk.MX4200 b/contrib/xntpd/refclocks/rclk.MX4200
new file mode 100644
index 000000000000..5d107126192f
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.MX4200
@@ -0,0 +1,27 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ if check "$DEFS" '$0 ~ /STREAM/'; then
+ echo " MX4200 - Magnavox 4200 GPS receiver"
+ fi
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /MX4200PPS/'; then
+ echo "MX4200 - Magnavox 4200 GPS receiver"
+ fi
+ ;;
+ config)
+ if check "$PPSFEATURES" '$0 ~ /CD/' &&
+ [ "$PPSOK" -eq 1 ] &&
+ (check "$REFCONF" '$0 ~ /MX4200PPS/' ||
+ ( [ ! "$REFCONF" ] && query "Include Magnavox 4200 GPS receiver (MX4200PPS)" n)); then
+ echo "-DMX4200PPS" >> $RCONFIG
+ fi
+ ;;
+esac
+
diff --git a/contrib/xntpd/refclocks/rclk.OMEGA b/contrib/xntpd/refclocks/rclk.OMEGA
new file mode 100644
index 000000000000..62094e46130d
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.OMEGA
@@ -0,0 +1,29 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ echo " OMEGA - Kinemetrics/TrueTime OM-DC OMEGA receiver"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /OMEGA/'; then
+ echo "OMEGA - Kinemetrics/TrueTime OM-DC OMEGA receiver"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /OMEGA/' ||
+ ( [ ! "$REFCONF" ] && query "Include Kinemetrics/TrueTime OM-DC OMEGA receiver (OMEGA)" n); then
+ if check "$PPSFEATURES" '$0 ~ /CD/' &&
+ [ "$PPSOK" -eq 1 ] &&
+ (check "$REFCONF" '$0 ~ /OMEGAPPS/' ||
+ ( [ ! "$REFCONF" ] && query " Use OMEGA for PPS" n)); then
+ echo "-DOMEGAPPS" >> $RCONFIG
+ else
+ echo "-DOMEGA" >> $RCONFIG
+ fi
+ fi
+ ;;
+esac
diff --git a/contrib/xntpd/refclocks/rclk.PARSE b/contrib/xntpd/refclocks/rclk.PARSE
new file mode 100644
index 000000000000..b91ed8bf8153
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.PARSE
@@ -0,0 +1,51 @@
+#!/bin/sh
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+if check "$DEFS" '$0 ~ /HAVE_SYSV_TTYS|STREAM|HAVE_TERMIOS/'; then
+ case "$CMD" in
+ info)
+ echo " PARSE - GENERIC refence clock driver"
+ echo " DCF77:"
+ echo " Meinberg DCF U/A 31, PZF 535"
+ echo " Schmid DCF77 receiver"
+ echo " ELV DCF7000"
+ echo " Raw DCF77 signal (100/200ms pulses)"
+ echo " GPS:"
+ echo " Meinberg GPS 166"
+ echo " Trimble GPS SV6"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /PARSE/ && $0 ~ /CLOCK/'; then
+ echon "PARSE - GENERIC"
+ if check "$RCONFIG" '$0 ~ /PARSEPPS/'; then echon "/PPS"; fi
+ if check "$RCONFIG" '$0 ~ /CLOCK_MEINBERG/'; then echon ",MEINBERG"; fi
+ if check "$RCONFIG" '$0 ~ /CLOCK_SCHMID/'; then echon ",SCHMID"; fi
+ if check "$RCONFIG" '$0 ~ /CLOCK_DCF7000/'; then echon ",DCF7000"; fi
+ if check "$RCONFIG" '$0 ~ /CLOCK_TRIMSV6/'; then echon ",Trimble SV6"; fi
+ if check "$RCONFIG" '$0 ~ /CLOCK_RAWDCF/'; then echon ",Raw DCF77 pulses"; fi
+ echo
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /PARSE/' ||
+ ( [ ! "$REFCONF" ] && query "Include PARSE generic driver support" n); then
+ if check "$REFCONF" '$0 ~ /PARSEPPS/' ||
+ ( [ ! "$REFCONF" ] && query " Include support for PPS simulation" y); then echo "-DPARSEPPS" >> $RCONFIG; else echo "-DPARSE" >> $RCONFIG; fi
+ if check "$REFCONF" '$0 ~ /MEINBERG/' ||
+ ( [ ! "$REFCONF" ] && query " Include support for Meinberg clocks" y); then echo "-DCLOCK_MEINBERG" >> $RCONFIG; fi
+ if check "$REFCONF" '$0 ~ /SCHMID/' ||
+ ( [ ! "$REFCONF" ] && query " Include support for Schmid DCF77 clock" y); then echo "-DCLOCK_SCHMID" >> $RCONFIG; fi
+ if check "$REFCONF" '$0 ~ /DCF7000|ELV/' ||
+ ( [ ! "$REFCONF" ] && query " Include support for ELV/DCF7000 clock" y); then echo "-DCLOCK_DCF7000" >> $RCONFIG; fi
+ if check "$REFCONF" '$0 ~ /TRIMBLE/' ||
+ ( [ ! "$REFCONF" ] && query " Include support for Trimble SV6 GPS receiver" y); then echo "-DCLOCK_TRIMSV6" >> $RCONFIG; fi
+ if check "$REFCONF" '$0 ~ /RAWDCF/' ||
+ ( [ ! "$REFCONF" ] && query " Include support for raw DCF77 time code" y); then echo "-DCLOCK_RAWDCF" >> $RCONFIG; fi
+ fi
+ ;;
+ esac
+fi
+
diff --git a/contrib/xntpd/refclocks/rclk.PST b/contrib/xntpd/refclocks/rclk.PST
new file mode 100644
index 000000000000..4f93c8e8f24f
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.PST
@@ -0,0 +1,37 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ echo " PST - PST/Traconex 1020 WWV/H receiver"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /PST/'; then
+ echo "PST - PST/Traconex 1020 WWV/H receiver"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /PST/' ||
+ ( [ ! "$REFCONF" ] && query "Include PST/Traconex 1020 WWV/H receiver (PST)" n); then
+ _PST=0
+ if check "$PPSFEATURES" '$0 ~ /CLK/'; then
+ if (check "$REFCONF" '$0 ~ /PSTCLK/' ||
+ ( [ ! "$REFCONF" ] && query " Support PPS via clk" y)); then
+ echo " -DPSTCLK" >> $RCONFIG
+ _PST=1
+ fi
+ fi
+ if check "$PPSFEATURES" '$0 ~ /CD/' &&
+ [ "$PPSOK" -eq 1 ] &&
+ (check "$REFCONF" '$0 ~ /PSTPPS/' ||
+ ( [ ! "$REFCONF" ] && query " Use PST for PPS" n)); then
+ echo " -DPSTPPS" >> $RCONFIG
+ else
+ [ "$_PST" -eq 0 ] && echo "-DPST" >> $RCONFIG
+ fi
+ fi
+ ;;
+esac
diff --git a/contrib/xntpd/refclocks/rclk.TPRO b/contrib/xntpd/refclocks/rclk.TPRO
new file mode 100644
index 000000000000..74e5545211fc
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.TPRO
@@ -0,0 +1,24 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+if check "$DEFS" '$0 ~ /SYS_SUNOS/'; then
+ case "$CMD" in
+ info)
+ echo " TPRO - KSI/Odetics TPRO-S IRIG-B timecode reader"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /TPRO/'; then
+ echo "TPRO - KSI/Odetics TPRO-S IRIG-B timecode reader"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /TPRO/' ||
+ ( [ ! "$REFCONF" ] && query "Include KSI/Odetics TPRO-S IRIG-B timecode reader (TPRO)" n); then
+ echo "-DTPRO" >> $RCONFIG
+ fi
+ ;;
+ esac
+fi
diff --git a/contrib/xntpd/refclocks/rclk.WWVB b/contrib/xntpd/refclocks/rclk.WWVB
new file mode 100644
index 000000000000..2801ac70b18b
--- /dev/null
+++ b/contrib/xntpd/refclocks/rclk.WWVB
@@ -0,0 +1,38 @@
+#!/bin/sh -
+CMD="$1"
+shift;
+
+. refclocks/setup
+
+case "$CMD" in
+ info)
+ echo " WWVB - Spectracom 8170 or Netclock/2 WWVB receiver"
+ ;;
+ check)
+ if check "$RCONFIG" '$0 ~ /WWVB/'; then
+ echo "WWVB - Spectracom 8170 or Netclock/2 WWVB receiver"
+ fi
+ ;;
+ config)
+ if check "$REFCONF" '$0 ~ /WWVB/' ||
+ ( [ ! "$REFCONF" ] && query "Include Spectracom 8170 or Netclock/2 WWVB receiver (WWVB)" n); then
+ _WWV=0
+ if check "$PPSFEATURES" '$0 ~ /CLK/'; then
+ if check "$REFCONF" '$0 ~ /WWVBCLK/' ||
+ ( [ ! "$REFCONF" ] && query " Support PPS via clk" y); then
+ echo " -DWWVBCLK" >> $RCONFIG
+ _WWV=1
+ fi
+ fi
+ if check "$PPSFEATURES" '$0 ~ /CD/'; then
+ if [ "$PPSOK" -eq 1 ] &&
+ (check "$REFCONF" '$0 ~ /WWVBPPS/' ||
+ ( [ ! "$REFCONF" ] && query " Use WWVB for PPS" n)); then
+ echo " -DWWVBPPS" >> $RCONFIG
+ fi
+ else
+ [ "$_WWV" -eq 0 ] && echo "-DWWVB" >> $RCONFIG
+ fi
+ fi
+ ;;
+esac
diff --git a/contrib/xntpd/refclocks/rconfig b/contrib/xntpd/refclocks/rconfig
new file mode 100644
index 000000000000..75f43fad2087
--- /dev/null
+++ b/contrib/xntpd/refclocks/rconfig
@@ -0,0 +1,119 @@
+#!/bin/sh -
+#
+# Refclock configuration script
+#
+# batch configuration options (optional arg 1)
+# pps related
+# PPS - general PPS support
+# CLK - CLK line discipline or streams module
+# CD - ppsclock or ppsclockd streams module
+# LINE - dedicated line
+PATH=refclocks:${PATH}
+export PATH
+RCONFIG=rconf
+DLOCAL=dlocal
+REFCONF=${1-""}
+
+. refclocks/setup
+
+rcfg="`echo refclocks/rclk.*`"
+
+if [ "$rcfg" = "refclocks/rclk.*" ]; then
+ echo "no reference clock configuration information available"
+else
+ config="`egrep '^[ ]*CLOCKDEFS[ ]*=' Config.local | sed 's/\([^#]*\)#.*$/\1/g; s/[ ]*CLOCKDEFS[ ]*=//g; s/-D//g; s/[ ][ ]*/ /g; s/^ *//g; s/ *$//g;'`"
+ DEFS="`egrep '^[ ]*DEFS[ ]*=' Config | sed 's/\([^#]*\)#.*$/\1/g; s/[ ]*DEFS[ ]*=//g; s/-D//g; s/[ ][ ]*/ /g; s/^ *//g; s/ *$//g;'`"
+ if [ ! "$REFCONF" ]; then
+ echo
+ echo "Current configuration"
+ echo
+ for i in $rcfg
+ do
+ sh $i check "$config" "" "" "$DEFS" "$REFCONF"
+ done
+ echo
+ fi
+ if [ "$REFCONF" ] || query "Change Configuration" n; then
+ if [ ! "$REFCONF" ]; then
+ echo
+ echo 'Available reference clock drivers'
+ for i in $rcfg
+ do
+ sh $i info "" "" "" "$DEFS" "$REFCONF"
+ done
+ echo
+ fi
+ :>"$RCONFIG"
+ PPS=""
+ PPSFEATURES=""
+ PPSOK=0
+ if check "$REFCONF" '$0 ~ /PLL/' ||
+ ( [ ! "$REFCONF" ] && query "Include support for Kernel PLL" n); then
+ PPS="-DKERNEL_PLL $PPS"
+ fi
+ if check "$REFCONF" '$0 ~ /[^A-Za-z]PPS/' ||
+ ( [ ! "$REFCONF" ] && query "Do you have a PPS (pulse per second) signal" n); then
+ if check "$DEFS" '$0 ~ /HAVE_BSD_TTYS|STREAM/' &&
+ (check "$REFCONF" '$0 ~ /CLK/' ||
+ ( [ ! "$REFCONF" ] && query "Is the clk line discipline available" n)); then
+ PPSFEATURES="CLK"
+ else
+ if check "$DEFS" '$0 ~ /STREAM/' &&
+ (check "$REFCONF" '$0 ~ /CD/' ||
+ ( [ ! "$REFCONF" ] && query "Is the ppsclock or ppsclocd STREAMS module available" n)); then
+ PPSFEATURES="CD $PPSFEATURES"
+ fi
+ fi
+ if check "$PPSFEATURES" '$0 ~ /CLK|CD/' &&
+ (check "$REFCONF" '$0 ~ /LINE/' ||
+ ( [ ! "$REFCONF" ] && query "Do you want to use a dedicated serial port for PPS signal" n)); then
+ if check "$PPSFEATURES" '$0 ~ /CLK/'; then
+ PPS="-DPPSCLK $PPS"
+ fi
+ if check "$PPSFEATURES" '$0 ~ /CD/'; then
+ PPS="-DPPSCD $PPS"
+ fi
+ else
+ PPSOK=1
+ PPS="-DPPS $PPS"
+ fi
+ fi
+ for i in $rcfg
+ do
+ sh $i config "$RCONFIG" "$PPSFEATURES" "$PPSOK" "$DEFS" "$REFCONF"
+ if [ "$PPSOK" -eq 1 ] && egrep -e '-D..*PPS' "$RCONFIG" >/dev/null 2>&1; then
+ PPSOK=0
+ fi
+ done
+ if egrep -e '-D..*PPS' "$RCONFIG" >/dev/null 2>&1; then
+ PPS="-DPPSPPS $PPS"
+ fi
+ CLOCKDEFS="`tr '\012' ' ' < $RCONFIG`"
+ if check "$CLOCKDEFS" '$0 !~ /^[ ]*$/'; then
+ PPS="-DREFCLOCK $PPS"
+ if [ ! "$REFCONF" ]; then
+ echo
+ echo "Do not forget to set up the appropriate device links in the /dev directory"
+ echo
+ fi
+ fi
+ if sed -e 's/^[ ]*CLOCKDEFS[ ]*=.*$/CLOCKDEFS='"$CLOCKDEFS"'/;' \
+ -e 's/^[ ]*DEFS_LOCAL[ ]*=.*$/DEFS_LOCAL= $(DEFS_OPT) '"$PPS"'/;' \
+ Config.local > Config.local.new; then
+ mv Config.local Config.local.old &&
+ mv Config.local.new Config.local &&
+ rm -f Config.local.old
+ echo
+ echo "New configuration defines:"
+ echo " CLOCKDEFS=$CLOCKDEFS"
+ echo " DEFS_LOCAL="'$(DEFS_OPT)'" $PPS"
+ echo
+ echo "Configuration updated"
+ else
+ echo "Configuration update FAILED"
+ fi
+ rm -f "$RCONFIG"
+ else
+ :;
+ fi
+fi
diff --git a/contrib/xntpd/refclocks/setup b/contrib/xntpd/refclocks/setup
new file mode 100644
index 000000000000..461117841c35
--- /dev/null
+++ b/contrib/xntpd/refclocks/setup
@@ -0,0 +1,16 @@
+#
+# gobble possible parameters
+#
+if [ $# -eq 5 ]; then
+ RCONFIG="$1"
+ PPSFEATURES="$2"
+ PPSOK="$3"
+ DEFS="$4"
+ REFCONF="$5"
+fi
+#
+# shell dumbness detection
+#
+if (eval "_x () { :; }") >/dev/null 2>&1 ; then
+ . refclocks/setupfn
+fi
diff --git a/contrib/xntpd/refclocks/setupfn b/contrib/xntpd/refclocks/setupfn
new file mode 100644
index 000000000000..5724dcb52da6
--- /dev/null
+++ b/contrib/xntpd/refclocks/setupfn
@@ -0,0 +1,27 @@
+#
+# sh io functions
+#
+if [ "`echo -n`" = "-n" ]; then
+ echon () { echo "$@\\c"; }
+else
+ echon () { echo -n "$@"; }
+fi
+
+query() {
+ _Q="$1"
+ _A="$2"
+ echon "$_Q (y/n) [$_A] ? "
+ X=""
+ read X
+ if [ "$X" = "" ]; then
+ X="$_A"
+ fi
+ case "$X" in
+ [yY]*) return 0;;
+ *) return 1;;
+ esac
+}
+
+check () {
+ `echo "$1" | awk '{ if ( '"$2"' ) { print ":"; } else { print "false"; } exit; }'`;
+}
diff --git a/contrib/xntpd/scripts/Guess.sh b/contrib/xntpd/scripts/Guess.sh
new file mode 100755
index 000000000000..c2be5697eab7
--- /dev/null
+++ b/contrib/xntpd/scripts/Guess.sh
@@ -0,0 +1,122 @@
+#! /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|solaris)
+ 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 in 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
+
+if [ -f /lib/clib -a -f /lib/libc ]; then
+ echo domainos
+ exit 0
+fi
+
+case "$guess" in
+ '') guess="none"
+esac
+
+echo $guess
diff --git a/contrib/xntpd/scripts/README b/contrib/xntpd/scripts/README
new file mode 100644
index 000000000000..79f1792a43d4
--- /dev/null
+++ b/contrib/xntpd/scripts/README
@@ -0,0 +1,41 @@
+README file for directory ./scripts of the NTP Version 3 distribution
+
+This directory contains shell and perl script files for the configuration,
+monitoring and support of NTP installations. See the README and RELNOTES
+files in the parent directory for directions on how to use these files.
+
+Guess.sh script to figure out what machine and operating system
+ is running this thing. Prizes awarded for new machines
+ added to the list.
+
+autoconf awesome script swiped from Jeff Johnson (who may have
+ swiped it from GNU) which delves deep into the system
+ files to reveal dark secrets necessary to port NTP to
+ everything exceptt sewing machines. Unfinished work.
+
+makeconfig.sh shell script that calles Guess.sh and then figures out
+ what compiler is available, then builds the
+ configuration file in the base directory. Finally, it
+ launches the sed script Config.sed in the base directory
+ to make the makefiles used by most programs.
+
+mklinks script useful to create directories for multiple
+ architecture maintenance
+
+mkversion script useful to create new version numbers for all
+ sources
+
+monitoring directory containing perl scripts useful for monitoring
+ operations
+
+ntp-groper script useful for reaching out and rattling the cages of
+ NTP peers to see if animals are inside the bars
+
+ntp-restart script useful for killing and restarting the NTP daemon
+
+stats directory containing awk ans shell scripts useful for
+ maintaining statistics summaries of clockstats, loopstats
+ and peerstats files
+
+support directory containing shell and perl scripts useful for
+ configuration and monitoring of NTP subnets
diff --git a/contrib/xntpd/scripts/autoconf b/contrib/xntpd/scripts/autoconf
new file mode 100755
index 000000000000..b661910b5e23
--- /dev/null
+++ b/contrib/xntpd/scripts/autoconf
@@ -0,0 +1,885 @@
+#!/bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf.
+# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp] [--no-create]
+# [--prefix=PREFIX] [--exec-prefix=PREFIX] [--with-PACKAGE] [TARGET]
+# Ignores all args except --srcdir, --prefix, --exec-prefix, --no-create, and
+# --with-PACKAGE unless this script has special code to handle it.
+
+
+for arg
+do
+ # Handle --exec-prefix with a space before the argument.
+ if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix=
+ # Handle --host with a space before the argument.
+ elif test x$next_host = xyes; then next_host=
+ # Handle --prefix with a space before the argument.
+ elif test x$next_prefix = xyes; then prefix=$arg; next_prefix=
+ # Handle --srcdir with a space before the argument.
+ elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir=
+ else
+ case $arg in
+ # For backward compatibility, also recognize exact --exec_prefix.
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* | --exe=* | --ex=* | --e=*)
+ exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;;
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e)
+ next_exec_prefix=yes ;;
+
+ -gas | --gas | --ga | --g) ;;
+
+ -host=* | --host=* | --hos=* | --ho=* | --h=*) ;;
+ -host | --host | --hos | --ho | --h)
+ next_host=yes ;;
+
+ -nfp | --nfp | --nf) ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre | --no-cr | --no-c | --no- | --no)
+ no_create=1 ;;
+
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;;
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ next_prefix=yes ;;
+
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=* | --s=*)
+ srcdir=`echo $arg | sed 's/[-a-z_]*=//'` ;;
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s)
+ next_srcdir=yes ;;
+
+ -with-* | --with-*)
+ package=`echo $arg|sed 's/-*with-//'`
+ # Delete all the valid chars; see if any are left.
+ if test -n "`echo $package|sed 's/[-a-zA-Z0-9_]*//g'`"; then
+ echo "configure: $package: invalid package name" >&2; exit 1
+ fi
+ eval "with_`echo $package|sed s/-/_/g`=1" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb | --ver | --ve | --v)
+ verbose=yes ;;
+
+ *) ;;
+ esac
+ fi
+done
+
+trap 'rm -f conftest* core; exit 1' 1 3 15
+
+# Needed for some versions of `tr' so that character classes in `[]' work.
+if test "${LANG+set}" = "set" ; then
+ LANG=C
+fi
+
+rm -f conftest*
+compile='${CC-cc} $CFLAGS $DEFS conftest.c -o conftest $LIBS >/dev/null 2>&1'
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+unique_file=lib/msyslog.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ srcdirdefaulted=yes
+ # Try the directory containing this script, then `..'.
+ prog=$0
+ confdir=`echo $prog|sed 's%/[^/][^/]*$%%'`
+ test "X$confdir" = "X$prog" && confdir=.
+ srcdir=$confdir
+ if test ! -r $srcdir/$unique_file; then
+ srcdir=..
+ fi
+fi
+if test ! -r $srcdir/$unique_file; then
+ if test x$srcdirdefaulted = xyes; then
+ echo "configure: Can not find sources in \`${confdir}' or \`..'." 1>&2
+ else
+ echo "configure: Can not find sources in \`${srcdir}'." 1>&2
+ fi
+ exit 1
+fi
+# Preserve a srcdir of `.' to avoid automounter screwups with pwd.
+# But we can't avoid them for `..', to make subdirectories work.
+case $srcdir in
+ .|/*|~*) ;;
+ *) srcdir=`cd $srcdir; pwd` ;; # Make relative path absolute.
+esac
+
+
+useresolv=""
+
+echo CONFIGURE -- initializing DEFS
+test -z "$DEFS" && DEFS="-DDEBUG -DREFCLOCK"
+echo CONFIGURE -- initializing AUTHDEFS
+test -z "$AUTHDEFS" && AUTHDEFS="-DDES -DMD5"
+echo CONFIGURE -- initializing CLOCKDEFS
+test -z "$CLOCKDEFS" && CLOCKDEFS="-DAS2201 -DCHU -DGOES -DLEITCH -DLOCAL_CLOCK -DOMEGA -DPST -DWWVB"
+echo CONFIGURE -- initializing COPTS
+test -z "$COPTS" && COPTS="-O"
+
+test -z "$INCLUDE" && INCLUDE="-I../include"
+test -z "$LIB" && LIB="../lib/libntp.a"
+
+test "`uname`" = "SunOS" && {
+ DEFS="$DEFS -DXNTP_RETROFIT_STDLIB"
+}
+test "`uname`" = "ULTRIX" && {
+ DEFS="$DEFS -DXNTP_RETROFIT_STDLIB -DPLL -DREADKMEM"
+}
+test "`uname`" = "BSD/386" && {
+ DEFS="$DEFS -D__bsdi__"
+}
+test -d /usr/lib/NextStep && {
+ DEFS="$DEFS -DREADKMEM -DSYNCTODR_SUCKS"
+}
+
+SOLARIS=""
+test -d /kernel && test -d /opt && isSOLARIS="1"
+
+echo TODO -- checking for HPUX
+
+# We want these before the checks, so the checks can modify their values.
+test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1
+test -z "$LDFLAGS" && LDFLAGS=-g
+
+#==========================================================================
+if test -z "$CC"; then
+ # Extract the first word of `gcc', so it can be a program name with args.
+ set dummy gcc; word=$2
+ echo checking for $word
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ CC="gcc"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+test -z "$CC" && CC="cc"
+test -n "$CC" -a -n "$verbose" && echo " setting CC to $CC"
+
+# Find out if we are using GNU C, under whatever name.
+cat > conftest.c <<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' NTP_POSIX_SOURCE
+DEFS="$DEFS -DNTP_POSIX_SOURCE=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/contrib/xntpd/scripts/install.sh b/contrib/xntpd/scripts/install.sh
new file mode 100755
index 000000000000..5dd98315d82c
--- /dev/null
+++ b/contrib/xntpd/scripts/install.sh
@@ -0,0 +1,100 @@
+#!/bin/sh
+#
+# Emulate the BSD install command with cpset for System V
+# Tom Moore - NCR Corporation
+#
+PATH=/bin:/etc:/usr/bin:/usr/ucb
+export PATH
+
+# Default values
+mode=0755
+owner=bin
+group=bin
+strip=FALSE
+remove=TRUE
+
+USAGE="install [-s] [-c] [-m mode] [-o owner] [-g group] source file|directory"
+set -- `getopt scm:o:g: $*` || {
+ echo $USAGE >&2
+ exit 2
+}
+for option in $*
+do
+ case $option in
+ -s) # Strip the installed file
+ strip=TRUE
+ shift
+ ;;
+ -c) # Copy the source file rather than move it
+ remove=FALSE
+ shift
+ ;;
+ -m) # File mode
+ mode=$2
+ shift 2
+ ;;
+ -o) # File owner
+ owner=$2
+ shift 2
+ ;;
+ -g) # File group
+ group=$2
+ shift 2
+ ;;
+ --) # End of options
+ shift
+ break
+ ;;
+ esac
+done
+
+case $# in
+0) echo "install: no file or destination specified" >&2
+ exit 2
+ ;;
+1) echo "install: no destination specified" >&2
+ exit 2
+ ;;
+2) source=$1
+ destination=$2
+ ;;
+*) echo "install: too many files specified" >&2
+ exit 2
+ ;;
+esac
+
+[ $source = $destination -o $destination = . ] && {
+ echo "install: can't move $source onto itself" >&2
+ exit 1
+}
+
+[ -f $source ] || {
+ echo "install: can't open $source" >&2
+ exit 1
+}
+
+if [ -d $destination ]
+then
+ file=`basename $source`
+ OLDdestination=$destination/OLD$file
+ destination=$destination/$file
+else
+ dir=`dirname $destination`
+ file=`basename $destination`
+ OLDdestination=$dir/OLD$file
+fi
+
+(cp $source $destination &&
+ chmod $mode $destination &&
+ chown $owner $destination &&
+ chgrp $group $destination) || exit 1
+
+# /bin/rm -f $OLDdestination
+
+[ $strip = TRUE ] &&
+ strip $destination
+
+[ $remove = TRUE ] &&
+ rm -f $source
+
+exit 0
diff --git a/contrib/xntpd/scripts/makeconfig.sh b/contrib/xntpd/scripts/makeconfig.sh
new file mode 100755
index 000000000000..8842a86c6c51
--- /dev/null
+++ b/contrib/xntpd/scripts/makeconfig.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+MACHINE=${1-${OS}}
+COMPILER=${2-${CC}}
+
+#
+# Figure out which compiler to use. Stolen from Jeff Johnson.
+#
+if [ "0$COMPILER" = "0" ]; then
+ COMPILER="cc"
+ set dummy gcc; word=$2
+ IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:"
+ for dir in $PATH; do
+ test -z "$dir" && dir=.
+ if test -f $dir/$word; then
+ COMPILER="gcc"
+ break
+ fi
+ done
+ IFS="$saveifs"
+fi
+
+#
+# Figure out the byte order and word size.
+#
+if (cd util && rm -f longsize && $COMPILER -o longsize longsize.c ); then
+ if util/longsize >/dev/null 2>&1; then
+ LONG=`util/longsize`
+ else
+ echo "TROUBLE: executables built by your compiler don't work - bug your vendor"
+ exit 1
+ fi
+else
+ echo "TROUBLE: could not compile !"
+ echo "TROUBLE: either your compiler does not work / is not present"
+ echo "TROUBLE: or you have mangled the file tree"
+ exit 1
+fi
+(cd util && rm -f byteorder && $COMPILER -o byteorder byteorder.c $LONG )
+BYTE=`util/byteorder `
+if [ "0$BYTE" = "0" ]; then
+ BYTE="XNTP_BIG_ENDIAN"
+fi
+(cd util && rm -f byteorder longsize)
+
+#
+# Figure out which machine we have.
+#
+if [ "0$MACHINE" = "0" ]; then
+ GUESS=`scripts/Guess.sh`
+ if [ "0$GUESS" = "0none" ]; then
+ echo ' '
+ echo "I don't know your system!"
+ echo "I do know about the following systems:"
+ (cd machines && ls -C *)
+ echo "Choose a system and type \"make OS=<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/contrib/xntpd/scripts/mklinks b/contrib/xntpd/scripts/mklinks
new file mode 100755
index 000000000000..8565d1ca3580
--- /dev/null
+++ b/contrib/xntpd/scripts/mklinks
@@ -0,0 +1,9 @@
+#!/bin/sh
+# call from the source root as 'mklinks ../sun4 ../src'
+find . -type d -print | sort | sed "s-^\.-mkdir $1-" | sh
+root=`echo $2 | sed "s-^\.\./--"`
+find . ! -type d -a ! -name Config -print | sed "s-^\./--" | while read file
+ do
+ down=`echo $file | sed -e "s-[^/]*-..-g"`
+ ln -s $down/$root/$file $1/$file
+ done
diff --git a/contrib/xntpd/scripts/mkversion b/contrib/xntpd/scripts/mkversion
new file mode 100755
index 000000000000..740454f5c2d7
--- /dev/null
+++ b/contrib/xntpd/scripts/mkversion
@@ -0,0 +1,36 @@
+#!/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`"
+TOPDIR=`echo $0 | sed -e 's;mkversion;..;'`
+
+if [ -r VERSION ]; then
+ VERSION=VERSION
+else if [ -r ${TOPDIR}/VERSION ]; then
+ VERSION=${TOPDIR}/VERSION
+else
+ VERSION=../VERSION
+fi; fi
+
+if [ -f "$VERSION" ]; then
+ FLAGS="`egrep '^[0-9a-zA-Z_]+=' "$VERSION" | tr '\012' ';'` "
+else
+ FLAGS=""
+fi
+
+echo "Version $PROG ${FLAGS}${DATE} (${RUN})";
+
+rm -f version.c
+cat > version.c << -EoF-
+/*
+ * version file for $PROG
+ */
+char * Version = "$PROG ${FLAGS}${DATE} (${RUN})";
+-EoF-
diff --git a/contrib/xntpd/scripts/monitoring/README b/contrib/xntpd/scripts/monitoring/README
new file mode 100644
index 000000000000..fa8ad8bb9585
--- /dev/null
+++ b/contrib/xntpd/scripts/monitoring/README
@@ -0,0 +1,154 @@
+This directory contains support for monitoring the local clock of xntp daemons.
+
+WARNING: The scripts and routines contained in this directory are bete realease!
+ Do not depend on their correct operation. They are, however, in regular
+ use at University of Erlangen-Nuernberg. No severe problems are known
+ for this code.
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+PLEASE THINK TWICE BEFORE STARTING MONITORING REMOTE XNTP DEAMONS !!!!
+MONITORING MAY INCREASE THE LOAD OF THE DEAMON MONITORED AND MAY
+INCREASE THE NETWORK LOAD SIGNIFICANTLY
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+Files are:
+
+README:
+ This file
+
+ntptrap:
+ perl script to log ntp mode 6 trap messages.
+
+ It sends a set_trap request to each server given and dumps the
+ trap messages received. It handles refresh of set_trap.
+ Currently it handles only NTP V2, however the NTP V3 servers
+ also accept v2 requests. It will not interpret v3 system and peer
+ stati correctly.
+
+ usage:
+ ntptrap [-n] [-p <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/contrib/xntpd/scripts/monitoring/loopwatch.config.SAMPLE b/contrib/xntpd/scripts/monitoring/loopwatch.config.SAMPLE
new file mode 100644
index 000000000000..8cefea395db0
--- /dev/null
+++ b/contrib/xntpd/scripts/monitoring/loopwatch.config.SAMPLE
@@ -0,0 +1,89 @@
+# sample configuration and control file for ntploowatch
+#
+# delay: sampling interval in seconds
+delay=60
+# samples: use only last # samples
+samples=600
+# DO NOT USE srcprefix in shared config files
+# srcprefix: name of file to read samples from
+# current time suffix (month name) is appended
+# defaults to "./var@$STATHOST/loopstats."
+# The string "$STATHOST"is replaced by the name of the host
+# being monitored
+#srcprefix=./var@$STATHOST/loopstats.
+#
+# showoffs: yes/no control display of offset values
+showoffs=yes
+#
+# showfreq: yes/no control display of frequency values
+showfreq=yes
+#
+# showcmpl: yes/no control display of compliance values
+showcmpl=no
+#
+# showoreg: yes/no control display of linear regression of offset values
+showoreg=no
+#
+# showfreg: yes/no control display of linear regression of frequency values
+showfreg=no
+#
+# timebase: dynamic/ISO_DATE_TIME point of zero for linear regression
+# ISO_DATE_TIME: yyyy-mm-dd_hh:mm:ss.ms
+# values are interpreted using local time zone
+# parts omitted from front default to current date/time
+# parts omitted from end default to lowest permitted values
+# to get aa:bb being interpreted as minutes:seconds use aa:bb.0
+# for dynamic '00:00:00.0 of current day' is used
+timebase=dynamic
+#
+# freqbase: dynamic/<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/contrib/xntpd/scripts/monitoring/lr.pl b/contrib/xntpd/scripts/monitoring/lr.pl
new file mode 100755
index 000000000000..02c7550ec3ad
--- /dev/null
+++ b/contrib/xntpd/scripts/monitoring/lr.pl
@@ -0,0 +1,145 @@
+;#
+;# lr.pl,v 3.1 1993/07/06 01:09:08 jbj Exp
+;#
+;#
+;# Linear Regression Package for perl
+;# to be 'required' from perl
+;#
+;# Copyright (c) 1992
+;# Frank Kardel, Rainer Pruy
+;# Friedrich-Alexander Universitaet Erlangen-Nuernberg
+;#
+;#
+;#############################################################
+
+##
+## y = A + Bx
+##
+## B = (n * Sum(xy) - Sum(x) * Sum(y)) / (n * Sum(x^2) - Sum(x)^2)
+##
+## A = (Sum(y) - B * Sum(x)) / n
+##
+
+##
+## interface
+##
+*lr_init = *lr'lr_init; #';# &lr_init(tag); initialize data set for tag
+*lr_sample = *lr'lr_sample; #';# &lr_sample(x,y,tag); enter sample
+*lr_Y = *lr'lr_Y; #';# &lr_Y(x,tag); compute y for given x
+*lr_X = *lr'lr_X; #';# &lr_X(y,tag); compute x for given y
+*lr_r = *lr'lr_r; #';# &lr_r(tag); regression coeffizient
+*lr_cov = *lr'lr_cov; #';# &lr_cov(tag); covariance
+*lr_A = *lr'lr_A; #';# &lr_A(tag);
+*lr_B = *lr'lr_B; #';# &lr_B(tag);
+*lr_sigma = *lr'lr_sigma; #';# &lr_sigma(tag); standard deviation
+*lr_mean = *lr'lr_mean; #';# &lr_mean(tag);
+#########################
+
+package lr;
+
+sub tagify
+{
+ local($tag) = @_;
+ if (defined($tag))
+ {
+ *lr_n = eval "*${tag}_n";
+ *lr_sx = eval "*${tag}_sx";
+ *lr_sx2 = eval "*${tag}_sx2";
+ *lr_sxy = eval "*${tag}_sxy";
+ *lr_sy = eval "*${tag}_sy";
+ *lr_sy2 = eval "*${tag}_sy2";
+ }
+}
+
+sub lr_init
+{
+ &tagify($_[$[]) if defined($_[$[]);
+
+ $lr_n = 0;
+ $lr_sx = 0.0;
+ $lr_sx2 = 0.0;
+ $lr_sxy = 0.0;
+ $lr_sy = 0.0;
+ $lr_sy2 = 0.0;
+}
+
+sub lr_sample
+{
+ local($_x, $_y) = @_;
+
+ &tagify($_[$[+2]) if defined($_[$[+2]);
+
+ $lr_n++;
+ $lr_sx += $_x;
+ $lr_sy += $_y;
+ $lr_sxy += $_x * $_y;
+ $lr_sx2 += $_x**2;
+ $lr_sy2 += $_y**2;
+}
+
+sub lr_B
+{
+ &tagify($_[$[]) if defined($_[$[]);
+
+ return 1 unless ($lr_n * $lr_sx2 - $lr_sx**2);
+ return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / ($lr_n * $lr_sx2 - $lr_sx**2);
+}
+
+sub lr_A
+{
+ &tagify($_[$[]) if defined($_[$[]);
+
+ return ($lr_sy - &lr_B * $lr_sx) / $lr_n;
+}
+
+sub lr_Y
+{
+ &tagify($_[$[]) if defined($_[$[]);
+
+ return &lr_A + &lr_B * $_[$[];
+}
+
+sub lr_X
+{
+ &tagify($_[$[]) if defined($_[$[]);
+
+ return ($_[$[] - &lr_A) / &lr_B;
+}
+
+sub lr_r
+{
+ &tagify($_[$[]) if defined($_[$[]);
+
+ local($s) = ($lr_n * $lr_sx2 - $lr_sx**2) * ($lr_n * $lr_sy2 - $lr_sy**2);
+
+ return 1 unless $s;
+
+ return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / sqrt($s);
+}
+
+sub lr_cov
+{
+ &tagify($_[$[]) if defined($_[$[]);
+
+ return ($lr_sxy - $lr_sx * $lr_sy / $lr_n) / ($lr_n - 1);
+}
+
+sub lr_sigma
+{
+ &tagify($_[$[]) if defined($_[$[]);
+
+ return 0 if $lr_n <= 1;
+ return sqrt(($lr_sy2 - ($lr_sy * $lr_sy) / $lr_n) / ($lr_n));
+}
+
+sub lr_mean
+{
+ &tagify($_[$[]) if defined($_[$[]);
+
+ return 0 if $lr_n <= 0;
+ return $lr_sy / $lr_n;
+}
+
+&lr_init();
+
+1;
diff --git a/contrib/xntpd/scripts/monitoring/ntp.pl b/contrib/xntpd/scripts/monitoring/ntp.pl
new file mode 100755
index 000000000000..f3bfd2bfe0b9
--- /dev/null
+++ b/contrib/xntpd/scripts/monitoring/ntp.pl
@@ -0,0 +1,477 @@
+#!/local/bin/perl
+;#
+;# ntp.pl,v 3.1 1993/07/06 01:09:09 jbj Exp
+;#
+;# process loop filter statistics file and either
+;# - show statistics periodically using gnuplot
+;# - or print a single plot
+;#
+;# Copyright (c) 1992
+;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg
+;#
+;#
+;#############################################################
+
+package ntp;
+
+$NTP_version = 2;
+$ctrl_mode=6;
+
+$byte1 = (($NTP_version & 0x7)<< 3) & 0x34 | ($ctrl_mode & 0x7);
+$MAX_DATA = 468;
+
+$sequence = 0; # initial sequence number incred before used
+$pad=4;
+$do_auth=0; # no possibility today
+$keyid=0;
+;#list if known keys (passwords)
+%KEYS = ( 0, "\200\200\200\200\200\200\200\200",
+ );
+
+;#-----------------------------------------------------------------------------
+;# access routines for ntp control packet
+ ;# NTP control message format
+ ;# C LI|VN|MODE LI 2bit=00 VN 3bit=2(3) MODE 3bit=6 : $byte1
+ ;# C R|E|M|Op R response E error M more Op opcode
+ ;# n sequence
+ ;# n status
+ ;# n associd
+ ;# n offset
+ ;# n count
+ ;# a+ data (+ padding)
+ ;# optional authentication data
+ ;# N key
+ ;# N2 checksum
+
+;# first bye of packet
+sub pkt_LI { return ($_[$[] >> 6) & 0x3; }
+sub pkt_VN { return ($_[$[] >> 3) & 0x7; }
+sub pkt_MODE { return ($_[$[] ) & 0x7; }
+
+;# second byte of packet
+sub pkt_R { return ($_[$[] & 0x80) == 0x80; }
+sub pkt_E { return ($_[$[] & 0x40) == 0x40; }
+sub pkt_M { return ($_[$[] & 0x20) == 0x20; }
+sub pkt_OP { return $_[$[] & 0x1f; }
+
+;#-----------------------------------------------------------------------------
+
+sub setkey
+{
+ local($id,$key) = @_;
+
+ $KEYS{$id} = $key if (defined($key));
+ if (! defined($KEYS{$id}))
+ {
+ warn "Key $id not yet specified - key not changed\n";
+ return undef;
+ }
+ return ($keyid,$keyid = $id)[$[];
+}
+
+;#-----------------------------------------------------------------------------
+sub numerical { $a <=> $b; }
+
+;#-----------------------------------------------------------------------------
+
+sub send #'
+{
+ local($fh,$opcode, $associd, $data,$address) = @_;
+ $fh = caller(0)."'$fh";
+
+ local($junksize,$junk,$packet,$offset,$ret);
+ $offset = 0;
+
+ $sequence++;
+ while(1)
+ {
+ $junksize = length($data);
+ $junksize = $MAX_DATA if $junksize > $MAX_DATA;
+
+ ($junk,$data) = $data =~ /^(.{$junksize})(.*)$/;
+ $packet
+ = pack("C2n5a".(($junk eq "") ? 0 : &pad($junksize+12,$pad)-12),
+ $byte1,
+ ($opcode & 0x1f) | ($data ? 0x20 : 0),
+ $sequence,
+ 0, $associd,
+ $offset, $junksize, $junk);
+ if ($do_auth)
+ {
+ ;# not yet
+ }
+ $offset += $junksize;
+
+ if (defined($address))
+ {
+ $ret = send($fh, $packet, 0, $address);
+ }
+ else
+ {
+ $ret = send($fh, $packet, 0);
+ }
+
+ if (! defined($ret))
+ {
+ warn "send failed: $!\n";
+ return undef;
+ }
+ elsif ($ret != length($packet))
+ {
+ warn "send failed: sent only $ret from ".length($packet). "bytes\n";
+ return undef;
+ }
+ return $sequence unless $data;
+ }
+}
+
+;#-----------------------------------------------------------------------------
+;# status interpretation
+;#
+sub getval
+{
+ local($val,*list) = @_;
+
+ return $list{$val} if defined($list{$val});
+ return sprintf("%s#%d",$list{"-"},$val) if defined($list{"-"});
+ return "unknown-$val";
+}
+
+;#---------------------------------
+;# system status
+;#
+;# format: |LI|CS|SECnt|SECode| LI=2bit CS=6bit SECnt=4bit SECode=4bit
+sub ssw_LI { return ($_[$[] >> 14) & 0x3; }
+sub ssw_CS { return ($_[$[] >> 8) & 0x3f; }
+sub ssw_SECnt { return ($_[$[] >> 4) & 0xf; }
+sub ssw_SECode { return $_[$[] & 0xf; }
+
+%LI = ( 0, "leap_none", 1, "leap_add_sec", 2, "leap_del_sec", 3, "sync_alarm", "-", "leap");
+%ClockSource = (0, "sync_unspec",
+ 1, "sync_lf_clock",
+ 2, "sync_uhf_clock",
+ 3, "sync_hf_clock",
+ 4, "sync_local_proto",
+ 5, "sync_ntp",
+ 6, "sync_udp/time",
+ 7, "sync_wristwatch",
+ "-", "ClockSource",
+ );
+
+%SystemEvent = (0, "event_unspec",
+ 1, "event_restart",
+ 2, "event_fault",
+ 3, "event_sync_chg",
+ 4, "event_sync/strat_chg",
+ 5, "event_clock_reset",
+ 6, "event_bad_date",
+ 7, "event_clock_excptn",
+ "-", "event",
+ );
+sub LI
+{
+ &getval(&ssw_LI($_[$[]),*LI);
+}
+sub ClockSource
+{
+ &getval(&ssw_CS($_[$[]),*ClockSource);
+}
+
+sub SystemEvent
+{
+ &getval(&ssw_SECode($_[$[]),*SystemEvent);
+}
+
+sub system_status
+{
+ return sprintf("%s, %s, %d event%s, %s", &LI($_[$[]), &ClockSource($_[$[]),
+ &ssw_SECnt($_[$[]), ((&ssw_SECnt($_[$[])==1) ? "" : "s"),
+ &SystemEvent($_[$[]));
+}
+;#---------------------------------
+;# peer status
+;#
+;# format: |PStat|PSel|PCnt|PCode| Pstat=6bit PSel=2bit PCnt=4bit PCode=4bit
+sub psw_PStat_config { return ($_[$[] & 0x8000) == 0x8000; }
+sub psw_PStat_authenable { return ($_[$[] & 0x4000) == 0x4000; }
+sub psw_PStat_authentic { return ($_[$[] & 0x2000) == 0x2000; }
+sub psw_PStat_reach { return ($_[$[] & 0x1000) == 0x1000; }
+sub psw_PStat_sane { return ($_[$[] & 0x0800) == 0x0800; }
+sub psw_PStat_dispok { return ($_[$[] & 0x0400) == 0x0400; }
+sub psw_PStat { return ($_[$[] >> 10) & 0x3f; }
+sub psw_PSel { return ($_[$[] >> 8) & 0x3; }
+sub psw_PCnt { return ($_[$[] >> 4) & 0xf; }
+sub psw_PCode { return $_[$[] & 0xf; }
+
+%PeerSelection = (0, "sel_reject",
+ 1, "sel_candidate",
+ 2, "sel_selcand",
+ 3, "sel_sys.peer",
+ "-", "PeerSel",
+ );
+%PeerEvent = (0, "event_unspec",
+ 1, "event_ip_err",
+ 2, "event_authen",
+ 3, "event_unreach",
+ 4, "event_reach",
+ 5, "event_clock_excptn",
+ 6, "event_stratum_chg",
+ "-", "event",
+ );
+
+sub PeerSelection
+{
+ &getval(&psw_PSel($_[$[]),*PeerSelection);
+}
+sub PeerEvent
+{
+ &getval(&psw_PCode($_[$[]),*PeerEvent);
+}
+
+sub peer_status
+{
+ local($x) = ("");
+ $x .= "config," if &psw_PStat_config($_[$[]);
+ $x .= "authenable," if &psw_PStat_authenable($_[$[]);
+ $x .= "authentic," if &psw_PStat_authentic($_[$[]);
+ $x .= "reach," if &psw_PStat_reach($_[$[]);
+ $x .= &psw_PStat_sane($_[$[]) ? "sane," : "insane,";
+ $x .= "hi_disp," unless &psw_PStat_dispok($_[$[]);
+
+ $x .= sprintf(" %s, %d event%s, %s", &PeerSelection($_[$[]),
+ &psw_PCnt($_[$[]), ((&psw_PCnt($_[$[]) == 1) ? "" : "s"),
+ &PeerEvent($_[$[]));
+ return $x;
+}
+
+;#---------------------------------
+;# clock status
+;#
+;# format: |CStat|CEvnt| CStat=8bit CEvnt=8bit
+sub csw_CStat { return ($_[$[] >> 8) & 0xff; }
+sub csw_CEvnt { return $_[$[] & 0xff; }
+
+%ClockStatus = (0, "clk_nominal",
+ 1, "clk_timeout",
+ 2, "clk_badreply",
+ 3, "clk_fault",
+ 4, "clk_prop",
+ 5, "clk_baddate",
+ 6, "clk_badtime",
+ "-", "clk",
+ );
+
+sub clock_status
+{
+ return sprintf("%s, last %s",
+ &getval(&csw_CStat($_[$[]),*ClockStatus),
+ &getval(&csw_CEvnt($_[$[]),*ClockStatus));
+}
+
+;#---------------------------------
+;# error status
+;#
+;# format: |Err|reserved| Err=8bit
+;#
+sub esw_Err { return ($_[$[] >> 8) & 0xff; }
+
+%ErrorStatus = (0, "err_unspec",
+ 1, "err_auth_fail",
+ 2, "err_invalid_fmt",
+ 3, "err_invalid_opcode",
+ 4, "err_unknown_assoc",
+ 5, "err_unknown_var",
+ 6, "err_invalid_value",
+ 7, "err_adm_prohibit",
+ );
+
+sub error_status
+{
+ return sprintf("%s", &getval(&esw_Err($_[$[]),*ErrorStatus));
+}
+
+;#-----------------------------------------------------------------------------
+;#
+;# cntrl op name translation
+
+%CntrlOpName = (1, "read_status",
+ 2, "read_variables",
+ 3, "write_variables",
+ 4, "read_clock_variables",
+ 5, "write_clock_variables",
+ 6, "set_trap",
+ 7, "trap_response",
+ 31, "unset_trap", # !!! unofficial !!!
+ "-", "cntrlop",
+ );
+
+sub cntrlop_name
+{
+ return &getval($_[$[],*CntrlOpName);
+}
+
+;#-----------------------------------------------------------------------------
+
+$STAT_short_pkt = 0;
+$STAT_pkt = 0;
+
+;# process a NTP control message (response) packet
+;# returns a list ($ret,$data,$status,$associd,$op,$seq,$auth_keyid)
+;# $ret: undef --> not yet complete
+;# "" --> complete packet received
+;# "ERROR" --> error during receive, bad packet, ...
+;# else --> error packet - list may contain useful info
+
+
+sub handle_packet
+{
+ local($pkt,$from) = @_; # parameters
+ local($len_pkt) = (length($pkt));
+;# local(*FRAGS,*lastseen);
+ local($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data);
+ local($autch_keyid,$auth_cksum);
+
+ $STAT_pkt++;
+ if ($len_pkt < 12)
+ {
+ $STAT_short_pkt++;
+ return ("ERROR","short packet received");
+ }
+
+ ;# now break packet apart
+ ($li_vn_mode,$r_e_m_op,$seq,$status,$associd,$offset,$count,$data) =
+ unpack("C2n5a".($len_pkt-12),$pkt);
+ $data=substr($data,$[,$count);
+ if ((($len_pkt - 12) - &pad($count,4)) >= 12)
+ {
+ ;# looks like an authenticator
+ ($auth_keyid,$auth_cksum) =
+ unpack("Na8",substr($pkt,$len_pkt-12+$[,12));
+ $STAT_auth++;
+ ;# no checking of auth_cksum (yet ?)
+ }
+
+ if (&pkt_VN($li_vn_mode) != $NTP_version)
+ {
+ $STAT_bad_version++;
+ return ("ERROR","version ".&pkt_VN($li_vn_mode)."packet ignored");
+ }
+
+ if (&pkt_MODE($li_vn_mode) != $ctrl_mode)
+ {
+ $STAT_bad_mode++;
+ return ("ERROR", "mode ".&pkt_MODE($li_vn_mode)." packet ignored");
+ }
+
+ ;# handle single fragment fast
+ if ($offset == 0 && &pkt_M($r_e_m_op) == 0)
+ {
+ $STAT_single_frag++;
+ if (&pkt_E($r_e_m_op))
+ {
+ $STAT_err_pkt++;
+ return (&error_status($status),
+ $data,$status,$associd,&pkt_OP($r_e_m_op),$seq,
+ $auth_keyid);
+ }
+ else
+ {
+ return ("",
+ $data,$status,$associd,&pkt_OP($r_e_m_op),$seq,
+ $auth_keyid);
+ }
+ }
+ else
+ {
+ ;# fragment - set up local name space
+ $id = "$from$seq".&pkt_OP($r_e_m_op);
+ $ID{$id} = 1;
+ *FRAGS = "$id FRAGS";
+ *lastseen = "$id lastseen";
+
+ $STAT_frag++;
+
+ $lastseen = 1 if !&pkt_M($r_e_m_op);
+ if (!defined(%FRAGS))
+ {
+ (&pkt_M($r_e_m_op) ? " more" : "")."\n";
+ $FRAGS{$offset} = $data;
+ ;# save other info
+ @FRAGS = ($status,$associd,&pkt_OP($r_e_m_op),$seq,$auth_keyid,$r_e_m_op);
+ }
+ else
+ {
+ (&pkt_M($r_e_m_op) ? " more" : "")."\n";
+ ;# add frag to previous - combine on the fly
+ if (defined($FRAGS{$offset}))
+ {
+ $STAT_dup_frag++;
+ return ("ERROR","duplicate fragment at $offset seq=$seq");
+ }
+
+ $FRAGS{$offset} = $data;
+
+ undef($loff);
+ foreach $off (sort numerical keys(%FRAGS))
+ {
+ next unless defined($FRAGS{$off});
+ if (defined($loff) &&
+ ($loff + length($FRAGS{$loff})) == $off)
+ {
+ $FRAGS{$loff} .= $FRAGS{$off};
+ delete $FRAGS{$off};
+ last;
+ }
+ $loff = $off;
+ }
+
+ ;# return packet if all frags arrived
+ ;# at most two frags with possible padding ???
+ if ($lastseen && defined($FRAGS{0}) &&
+ scalar(@x=sort numerical keys(%FRAGS)) <= 2 &&
+ (length($FRAGS{0}) + 8) > $x[$[+1])
+ {
+ @x=((&pkt_E($r_e_m_op) ? &error_status($status) : ""),
+ $FRAGS{0},@FRAGS);
+ &pkt_E($r_e_m_op) ? $STAT_err_frag++ : $STAT_frag_all++;
+ undef(%FRAGS);
+ undef(@FRAGS);
+ undef($lastseen);
+ delete $ID{$id};
+ &main'clear_timeout($id);
+ return @x;
+ }
+ else
+ {
+ &main'set_timeout($id,time+$timeout,"&ntp'handle_packet_timeout(\"".unpack("H*",$id)."\");"); #'";
+ }
+ }
+ return (undef);
+ }
+}
+
+sub handle_packet_timeout
+{
+ local($id) = @_;
+ local($r_e_m_op,*FRAGS,*lastseen,@x) = (@FRAGS[$[+5]);
+
+ *FRAGS = "$id FRAGS";
+ *lastseen = "$id lastseen";
+
+ @x=((&pkt_E($r_e_m_op) ? &error_status($status) : "TIMEOUT"),
+ $FRAGS{0},@FRAGS[$[ .. $[+4]);
+ $STAT_frag_timeout++;
+ undef(%FRAGS);
+ undef(@FRAGS);
+ undef($lastseen);
+ delete $ID{$id};
+ return @x;
+}
+
+
+sub pad
+{
+ return $_[$[+1] * int(($_[$[] + $_[$[+1] - 1) / $_[$[+1]);
+}
+
+1;
diff --git a/contrib/xntpd/scripts/monitoring/ntploopstat b/contrib/xntpd/scripts/monitoring/ntploopstat
new file mode 100755
index 000000000000..75cdff227b27
--- /dev/null
+++ b/contrib/xntpd/scripts/monitoring/ntploopstat
@@ -0,0 +1,457 @@
+#!/local/bin/perl -w--*-perl-*-
+;#
+;# ntploopstat,v 3.1 1993/07/06 01:09:11 jbj Exp
+;#
+;# Poll NTP server using NTP mode 7 loopinfo request.
+;# Log info and timestamp to file for processing by ntploopwatch.
+;#
+;#
+;# Copyright (c) 1992
+;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg
+;#
+;#################################################################
+;#
+;# The format written to the logfile is the same as used by xntpd
+;# for the loopstats file.
+;# This script however allows to gather loop filter statistics from
+;# remote servers where you do not have access to the loopstats logfile.
+;#
+;# Please note: Communication delays affect the accuracy of the
+;# timestamps recorded. Effects from these delays will probably
+;# not show up, as timestamps are recorded to the second only.
+;# (Should have implemented &gettimeofday()..)
+;#
+
+$0 =~ s!^.*/([^/]+)$!\1!; # beautify script name
+
+$ntpserver = 'localhost'; # default host to poll
+$delay = 60; # default sampling rate
+ ;# keep it shorter than minpoll (=64)
+ ;# to get all values
+
+require "ctime.pl";
+;# handle bug in early ctime distributions
+$ENV{'TZ'} = 'MET' unless defined($ENV{'TZ'}) || $] > 4.010;
+
+if (defined(@ctime'MoY))
+{
+ *MonthName = *ctime'MoY;
+}
+else
+{
+ @MonthName = ('Jan','Feb','Mar','Apr','May','Jun',
+ 'Jul','Aug','Sep','Oct','Nov','Dec');
+}
+
+;# this routine can be redefined to point to syslog if necessary
+sub msg
+{
+ return unless $verbose;
+
+ print STDERR "$0: ";
+ printf STDERR @_;
+}
+
+;#############################################################
+;#
+;# process command line
+$usage = <<"E-O-S";
+
+usage:
+ $0 [-d<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/contrib/xntpd/scripts/monitoring/ntploopwatch b/contrib/xntpd/scripts/monitoring/ntploopwatch
new file mode 100755
index 000000000000..655ed7188cea
--- /dev/null
+++ b/contrib/xntpd/scripts/monitoring/ntploopwatch
@@ -0,0 +1,1631 @@
+#!/local/bin/perl -w--*-perl-*-
+;#
+;# ntploopwatch,v 3.1 1993/07/06 01:09:13 jbj Exp
+;#
+;# process loop filter statistics file and either
+;# - show statistics periodically using gnuplot
+;# - or print a single plot
+;#
+;# Copyright (c) 1992
+;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg
+;#
+;#
+;#############################################################
+$0 =~ s!^.*/([^/]+)$!\1!;
+$F = ' ' x length($0);
+$|=1;
+
+$ENV{'SHELL'} = '/bin/sh'; # use bourne shell
+
+undef($config);
+undef($workdir);
+undef($PrintIt);
+undef($samples);
+undef($StartTime);
+undef($EndTime);
+($a,$b) if 0; # keep -w happy
+$usage = <<"E-O-P";
+usage:
+ to watch statistics permanently:
+ $0 [-v[<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/contrib/xntpd/scripts/monitoring/ntptrap b/contrib/xntpd/scripts/monitoring/ntptrap
new file mode 100755
index 000000000000..69c66608af97
--- /dev/null
+++ b/contrib/xntpd/scripts/monitoring/ntptrap
@@ -0,0 +1,453 @@
+#!/local/bin/perl --*-perl-*-
+;#
+;# ntptrap,v 3.1 1993/07/06 01:09:15 jbj Exp
+;#
+;# a client for the xntp mode 6 trap mechanism
+;#
+;# Copyright (c) 1992
+;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg
+;#
+;#
+;#############################################################
+$0 =~ s!^.*/([^/]+)$!\1!; # strip to filename
+;# enforce STDOUT and STDERR to be line buffered
+$| = 1;
+select((select(STDERR),$|=1)[$[]);
+
+;#######################################
+;# load utility routines and definitions
+;#
+require('ntp.pl'); # implementation of the NTP protocol
+eval { require('sys/socket.ph'); require('netinet/in.ph') unless defined(&INADDR_ANY); } ||
+do {
+ die("$0: $@") unless $[ == index($@, "Can't locate ");
+ warn "$0: $@";
+ warn "$0: supplying some default definitions\n";
+ eval 'sub INADDR_ANY { 0; } sub AF_INET {2;} sub SOCK_DGRAM {2;} 1;' || die "$0: $@";
+};
+require('getopts.pl'); # option parsing
+require('ctime.pl'); # date/time formatting
+
+;######################################
+;# define some global constants
+;#
+$BASE_TIMEOUT=10;
+$FRAG_TIMEOUT=10;
+$MAX_TRY = 5;
+$REFRESH_TIME=60*15; # 15 minutes (server uses 1 hour)
+$ntp'timeout = $FRAG_TIMEOUT; #';
+
+;######################################
+;# now process options
+;#
+sub usage
+{
+ die("usage: $0 [-n] [-p <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/contrib/xntpd/scripts/monitoring/timelocal.pl b/contrib/xntpd/scripts/monitoring/timelocal.pl
new file mode 100755
index 000000000000..d0f73a236676
--- /dev/null
+++ b/contrib/xntpd/scripts/monitoring/timelocal.pl
@@ -0,0 +1,77 @@
+;# timelocal.pl
+;#
+;# Usage:
+;# $time = timelocal($sec,$min,$hours,$mday,$mon,$year,$junk,$junk,$isdst);
+;# $time = timegm($sec,$min,$hours,$mday,$mon,$year);
+
+;# These routines are quite efficient and yet are always guaranteed to agree
+;# with localtime() and gmtime(). We manage this by caching the start times
+;# of any months we've seen before. If we know the start time of the month,
+;# we can always calculate any time within the month. The start times
+;# themselves are guessed by successive approximation starting at the
+;# current time, since most dates seen in practice are close to the
+;# current date. Unlike algorithms that do a binary search (calling gmtime
+;# once for each bit of the time value, resulting in 32 calls), this algorithm
+;# calls it at most 6 times, and usually only once or twice. If you hit
+;# the month cache, of course, it doesn't call it at all.
+
+;# timelocal is implemented using the same cache. We just assume that we're
+;# translating a GMT time, and then fudge it when we're done for the timezone
+;# and daylight savings arguments. The timezone is determined by examining
+;# the result of localtime(0) when the package is initialized. The daylight
+;# savings offset is currently assumed to be one hour.
+
+CONFIG: {
+ package timelocal;
+
+ @epoch = localtime(0);
+ $tzmin = $epoch[2] * 60 + $epoch[1]; # minutes east of GMT
+ if ($tzmin > 0) {
+ $tzmin = 24 * 60 - $tzmin; # minutes west of GMT
+ $tzmin -= 24 * 60 if $epoch[5] == 70; # account for the date line
+ }
+
+ $SEC = 1;
+ $MIN = 60 * $SEC;
+ $HR = 60 * $MIN;
+ $DAYS = 24 * $HR;
+ $YearFix = ((gmtime(946684800))[5] == 100) ? 100 : 0;
+}
+
+sub timegm {
+ package timelocal;
+
+ $ym = pack(C2, @_[5,4]);
+ $cheat = $cheat{$ym} || &cheat;
+ $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS;
+}
+
+sub timelocal {
+ package timelocal;
+
+ $ym = pack(C2, @_[5,4]);
+ $cheat = $cheat{$ym} || &cheat;
+ $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS
+ + $tzmin * $MIN - 60 * 60 * ($_[8] != 0);
+}
+
+package timelocal;
+
+sub cheat {
+ $year = $_[5];
+ $month = $_[4];
+ $guess = $^T;
+ @g = gmtime($guess);
+ $year += $YearFix if $year < $epoch[5];
+ while ($diff = $year - $g[5]) {
+ $guess += $diff * (364 * $DAYS);
+ @g = gmtime($guess);
+ }
+ while ($diff = $month - $g[4]) {
+ $guess += $diff * (28 * $DAYS);
+ @g = gmtime($guess);
+ }
+ $g[3]--;
+ $guess -= $g[0] * $SEC + $g[1] * $MIN + $g[2] * $HR + $g[3] * $DAYS;
+ $cheat{$ym} = $guess;
+}
diff --git a/contrib/xntpd/scripts/ntp-groper b/contrib/xntpd/scripts/ntp-groper
new file mode 100755
index 000000000000..1fd0cfe4c2d6
--- /dev/null
+++ b/contrib/xntpd/scripts/ntp-groper
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# ntpgroper host ...
+#
+# This script checks each hostname given as an argument to see if
+# it is running NTP. It reports one of the following messages (assume
+# the host is named "dumbo.hp.com":
+#
+# dumbo.hp.com not registered in DNS
+# dumbo.hp.com not responding to ping
+# dumbo.hp.com refused ntpq connection
+# dumbo.hp.com not responding to NTP
+# dumbo.hp.com answers NTP version 2, stratum: 3, ref: telford.nsa.hp.com
+# dumbo.hp.com answers NTP version 3, stratum: 3, ref: telford.nsa.hp.com
+#
+# It ain't pretty, but it is kinda useful.
+#
+# Walter Underwood, 11 Feb 1993, wunder@hpl.hp.com
+#
+# converted to /bin/sh from /bin/ksh by scott@ee.udel.edu 24 Mar 1993
+
+PATH="/usr/local/etc:$PATH" export PATH
+
+verbose=1
+logfile=/tmp/cntp-log$$
+ntpqlog=/tmp/cntp-ntpq$$
+
+# I wrap the whole thing in parens so that it is possible to redirect
+# all the output somewhere, if desired.
+(
+for host in $*
+do
+ # echo "Trying $host."
+
+ gethost $host > /dev/null 2>&1
+ if [ $? -ne 0 ]
+ then
+ echo "$host not registered in DNS"
+ continue
+ fi
+
+ ping $host 64 1 > /dev/null 2>&1
+ if [ $? -ne 0 ]
+ then
+ echo "$host not responding to ping"
+ continue
+ fi
+
+ # Attempt to contact with version 3 ntp, then try version 2.
+ for version in 3 2
+ do
+
+ ntpq -c "ntpversion $version" -p $host > $ntpqlog 2>&1
+
+ if fgrep -s 'Connection refused' $ntpqlog
+ then
+ echo "$host refused ntpq connection"
+ break
+ fi
+
+ responding=1
+ fgrep -s 'timed out, nothing received' $ntpqlog > /dev/null && responding=0
+
+ if [ $responding -eq 1 ]
+ then
+ ntpq -c "ntpversion $version" -c rl $host > $ntpqlog
+
+ # First we extract the reference ID (usually a host or a clock)
+ synchost=`fgrep "refid=" $ntpqlog`
+ #synchost=${synchost##*refid=} # strip off the beginning of the line
+ #synchost=${synchost%%,*} # strip off the end
+ synchost=`expr "$synchost" : '.*refid=\([^,]*\),.*'`
+
+ # Next, we get the stratum
+ stratum=`fgrep "stratum=" $ntpqlog`
+ #stratum=${stratum##*stratum=}
+ #stratum=${stratum%%,*}
+ stratum=`expr "$stratum" : '.*stratum=\([^,]*\),.*'`
+
+ echo "$host answers NTP version $version, stratum: $stratum, ref: $synchost"
+ break;
+ fi
+
+ if [ $version -eq 2 -a $responding -eq 0 ]
+ then
+ echo "$host not responding to NTP"
+ fi
+ done
+done
+)
+# ) >> $logfile
+
+if [ -f $ntpqlog ]; then
+ rm $ntpqlog
+fi
diff --git a/contrib/xntpd/scripts/ntp-restart b/contrib/xntpd/scripts/ntp-restart
new file mode 100755
index 000000000000..d2023f0b67b2
--- /dev/null
+++ b/contrib/xntpd/scripts/ntp-restart
@@ -0,0 +1,9 @@
+#!/bin/sh
+#
+# This script can be used to kill and restart the NTP daemon. Edit the
+# /usr/local/bin/xntpd line to fit.
+#
+kill -INT `ps -ax | egrep "xntpd" | egrep -v "egrep" | sed 's/^\([ 0-9]*\) .*/\1'/`
+sleep 10
+/usr/local/bin/xntpd
+exit 0
diff --git a/contrib/xntpd/scripts/stats/README b/contrib/xntpd/scripts/stats/README
new file mode 100644
index 000000000000..5aa64d4c1db9
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/README
@@ -0,0 +1,32 @@
+Statistics processing scripts (README)
+
+This directory contains a number of scripts for use with the filegen
+facility. Those files ending in .awk are for the Unix awk utility, while
+those ending in .sh are for the csh utility. Normally, the summary.sh
+script is called from a cron job once per day. This script calls the
+peer.sh script to process the peerstats file and append the summary
+statistics to the peer_summary file. Then, it callse the loop.sh script
+to process the loopstats file and append the summary statistics to the
+loop_summary file. Finally, it calls the clock.sh script to process the
+clockstats file and append the summary statistics to the clock_summary
+file.
+
+Each of the three shell scripts peer.sh, loop.sh and clock.sh invoke
+one or more awk scripts to actually produce the data. This may result
+in multiple scans of the same input file. The input file is deleted after
+processing. In fact, the shell scripts will process all input files
+found of the correct type in chronological order, deleting each one as
+it is scanned, except the current day file.
+
+The psummary.awk script can be used to scan the peer_summary file and
+construct an historical reprise of the daily summaries.
+
+The file formats are documented in the README.stats file and in the
+scripts themselves. Further detail on the radio clock ASCII timecode
+formats and related data are in the README.timecode file.
+
+David L. Mills
+University of Delaware
+mills@udel.edu
+1 November 1993
+
diff --git a/contrib/xntpd/scripts/stats/README.stats b/contrib/xntpd/scripts/stats/README.stats
new file mode 100644
index 000000000000..aa8e77fb1bbe
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/README.stats
@@ -0,0 +1,246 @@
+Statistics file formats (README.stats)
+
+The xntp3 daemon can produce a variety of statistics files which are
+useful for maintenance, evaluation and retrospective calibration
+purposes. See the xntpd.8 man page for instructions on how to configure
+this feature. Since these files can become rather large and cumbersome,
+they are ordinarily reduced to summary form by running the summary.sh
+shell script once per day, week or month, as appropriate. There are
+three file collections presently defined: peerstats, loopstats and
+clockstats, each of which is described in this note.
+
+peerstats
+
+The following data are collected in the peerstats files. The files are
+reduced to summary data using the peer.sh shell script. See the peer.awk
+script for further information. A line in the file is produced upon
+reception of each valid update from a configured peer.
+
+ 49236 30.756 140.173.96.1 9474 0.000603 0.37532
+
+ 49236 modified Julian day number
+ 30.756 time of day (s) past midnight UTC
+ 140.173.96.1 peer identifier (IP address or receiver identifier)
+ 9474 peer status word (hex) (see NTP specification)
+ 0.000603 offset (s)
+ 0.08929 delay (s)
+ 0.37532 dispersion (s)
+
+loopstats
+
+The following data are collected in the loopstats files. The files are
+reduced to summary data using the loop.sh shell script. See the loop.awk
+script for further information. A line in the file is produced at each
+valid update of the local clock.
+
+ 49236 11.897 -0.000004 -35.9384 0
+
+ 49236 modified Julian day number
+ 11.897 time of day (s) past midnight UTC
+ -0.000004 time offset (s)
+ -35.9384 frequency offset (ppm)
+ 0 phase-lock loop time constant
+
+clockstats
+
+The following data are collected in the clockstats files. The files are
+reduced to summary data using the clock.sh shell script, which also
+updates the ensemble, etf, itf and tdata data files as well. See the
+clock.awk, ensemble.awk, etf.awk, itf.awk and tdta.awk scripts for
+further information. A line in the file is produced at each valid update
+received from a configured radio clock. Data are at present recorded for
+several radios. The first part of each data line is similar for all
+radios, e.g.:
+
+ 49234 60517.826 127.127.4.1 93 247 16:48:21.814
+
+ 49234 modified Julian day number
+ 60517.826 time of day (s) past midnight UTC
+ 127.127.4.1 receiver identifier (Spectracom 8170/Netclock-2)
+ 93 247 16:48:21.814 timecode (format varies)
+
+In the case of the Austron GPS receiver, a good deal of additional
+information is extracted from the radio, as described below. The formats
+shown consist of one line with all the fields shown in order. The
+timecode formats specific to each radio follow. See the file
+README.timecodes for detailed information on the timecode formats used
+by these radios.
+
+Spectracom 8170/Netclock-2 WWVB receiver
+
+ 49234 60517.826 127.127.4.1 ?A93 247 16:48:21.814
+
+ The '?' and 'A' characters are present only when the receiver is
+ unsynchronized; otherwise, they are replaced by space ' ' characters.
+
+IRIG audio decoder
+
+ 49234 60517.826 127.127.6.0 247 16:48:21?
+
+ The '?' character is present only when the receiver is unsynchronized.
+
+Austron 2200A/2201A GPS receiver
+
+ 49234 60580.843 127.127.10.1 93:247:16:49:24.814?
+
+ The '?' character is present only when the receiver is unsynchronized.
+
+Depending on the installed options, the Austron 2200A/2201A recognizes a
+number of special commands that report various data items. See the
+refclock_as2201.c source module for a list of the commands used. These
+data are collected only if the following line is included in the
+configuration file ntp.conf:
+
+ fudge 127.127.10.1 flag4 1 # enable extended statistics collection
+
+The format of each data line returned is summarized in the following
+list.
+
+External time/frequency data (requires input buffer option IN)
+
+These data determine the deviations of external time/frequency inputs
+relative to receiver oscillator time. The following data are typical
+using an external cesium oscillator PPS and 5-MHz outputs.
+
+ 49234 60580.843 127.127.10.1 93:247:16:49:24.814 ETF
+
+ -85.9 time interval (ns)
+ -89.0 average time interval (ns)
+ 4.0 time interval sigma (ns)
+ +1.510E-11 time interval rate
+ -4.500E-11 deltaf/f
+ +1.592E-11 average deltaf/f
+ 5.297E-13 sigma deltaf/f
+ 500 number of samples
+
+Model and option identifiers
+
+These data show the receiver model number and option configuration.
+
+ 49234 60708.848 127.127.10.1 93:247:16:51:32.817 ID;OPT;VER
+
+ GPS 2201A model ident (must be "GPS 2200A" or "GPS 2201A")
+ TTY1 rs232 option present (required)
+ TC1 IRIG option present (optional)
+ LORAN LORAN assist option present (optional)
+ IN input buffer option present (optional)
+ OUT1 output buffer option present (required)
+ B.00 data processor software version ("B.00" or later)
+ B.00 signal processor software version ("B.00" or later)
+ 28-Apr-93 software version date ("28-Apr-93" or later)
+
+Internal time/frequency data
+
+These data determine the deviations of the receiver oscillator with
+respect to satellite time.
+
+ 49234 60564.846 127.127.10.1 93:247:16:49:08.816 ITF
+
+ COCO current mode (must be "COCO")
+ 0 code coast mode (must be zero)
+ +6.6152E-08 code sigma (s)
+ -3.5053E-08 code delta t (s)
+ -4.0361E-11 deltat/t
+ -6.4746E-11 oscillator ageing rate
+ 500.00 loop time constant
+ 4.984072 electrical tuning (V)
+
+GPS/LORAN ensemble data (requires LORAN assist option LORAN)
+
+These data determine the deviations and weights to calculate ensemble
+time from GPS and LORAN data.
+
+ 49234 60596.852 127.127.10.1 93:247:16:49:40.812 LORAN ENSEMBLE
+
+ +9.06E-08 GPS t (s)
+ +3.53E-08 GPS sigma (s)
+ .532 GPS weight
+ +3.71E-08 LORAN t (s)
+ +3.76E-08 LORAN sigma (s)
+ .468 LORAN weight
+ +6.56E-08 ensemble t
+ +6.94E-08 ensemble sigma (s)
+
+LORAN stationkeeping data (requires LORAN assist option LORAN)
+
+These data determine which stations of the LORAN chain are being
+tracked, together with individual signal/noise ratios, deviations and
+weights.
+
+ 49234 60532.850 127.127.10.1 93:247:16:48:36.820 LORAN TDATA
+
+ M station identifier; data follows
+ OK status (must be "OK" for tracking)
+ 0 cw flag
+ 0 sw flag
+ 1162.17 time of arrival
+ -4.6 snr (-30.0 if not "OK" status)
+ 1.67E-07 2-sample phase-time deviation
+ .507 weight (included only if "OK" status)
+ W AQ 0 0 3387.80 -31.0 station identifier and data
+ X OK 0 0 1740.27 -11.2 2.20E-07 .294 station identifier and data
+ Y OK 0 0 2180.71 -4.6 2.68E-07 .198 station identifier and data
+ Z CV 0 0 3392.94 -30.0 station identifier and data
+
+Oscillator status and environment
+
+These data determine the receiver oscillator type, mode, status and
+environment. Nominal operating conditions are shown below.
+
+ 49234 60628.847 127.127.10.1 93:247:16:50:12.817 OSC;ET;TEMP
+
+ 1121 Software Control oscillator model and mode (must be
+ "Software Control")
+ Locked status (must be "Locked")
+ 4.979905 electrical tuning (V)
+ 44.81 oscillator cavity temperature
+
+Receiver position, status and offsets
+
+These data determine the receiver position and elevation, together with
+programmable delay corrections for the antenna cable and receiver.
+
+ 49234 60788.847 127.127.10.1 93:247:16:52:52.817 POS;PPS;PPSOFF
+
+ +39:40:48.425 receiver latitude (N)
+ -075:45:02.392 receiver longitude (E)
+ +74.09 receiver elevation (m)
+ Stored position status (must be "Stored")
+ UTC PPS/PPM alignment (must be "UTC")
+ 0 receiver delay (ns) (should be zero for calibrated
+ receiver)
+ 200 cable delay (ns)
+ 0 user time bias (ns) (must be zero)
+
+Satellite tracking status
+
+These data determine how many satellites are being tracked. At the
+present state of constellation development, there should be at least
+three visible satellites in view. Much of the time the maximum of
+seven are being tracked; rarely this number drops to two.
+
+ 49234 60612.850 127.127.10.1 93:247:16:49:56.820 TRSTAT
+
+ 24 T satellite prn and status (T = track, A = acquire)
+ 16 A 13 T 20 T 18 T 07 T 12 T list continued
+
+UTC leap-second information
+
+These data determine when the next leap second is to occur. The exact
+method to use is obscure.
+
+ 49234 60548.847 127.127.10.1 93:247:16:48:52.818 UTC
+
+ -1.2107E-08 A0 term (s)
+ -1.2790E-13 A1 term (s)
+ +9.0000E+00 current leap seconds (s)
+ +2.0480E+05 time for leap seconds (s)
+ +2.0100E+02 week number for delta leap (weeks)
+ +1.9100E+02 week number for future leap (weeks)
+ +4.0000E+00 day number for future leap (days)
+ +9.0000E+00 future leap seconds (s)
+
+David L. Mills
+University of Delaware
+mills@udel.edu
+23 October 1993
diff --git a/contrib/xntpd/scripts/stats/README.timecodes b/contrib/xntpd/scripts/stats/README.timecodes
new file mode 100644
index 000000000000..00b5ba54584f
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/README.timecodes
@@ -0,0 +1,149 @@
+Radio Timecode Formats (README.timecodes)
+
+Following are examples of the serial timecode formats used by various
+timecode receivers as given in the instruction manuals. These examples
+are intended only for illustration and not as the basis of system
+design. The following symbols are used to identify the timecode
+character that begins a subfield. The values given after this symbol
+represent the character offset from the beginning of the timecode string
+as edited to remove control characters.
+
+C on-time character (start bit)
+Y year of century
+T time of day
+D day of year or month/day
+A alarm indicator (format specific)
+Q quality indicator (format specific)
+<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/contrib/xntpd/scripts/stats/clock.awk b/contrib/xntpd/scripts/stats/clock.awk
new file mode 100644
index 000000000000..c9d1455b6fef
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/clock.awk
@@ -0,0 +1,341 @@
+# awk program to scan clockstat files and report errors/statistics
+#
+# usage: awk -f check.awk clockstats
+#
+# This program works for Spectracom 8170/Netclock-2 receiver, Austron
+# 2200A/2201A receiver and IRIG audio decoder. It is easily adapted to
+# other receivers as required. See README.austron file for additional
+# information on Austron receiver.
+#
+BEGIN {
+ etf_min = osc_vmin = osc_tmin = 1e9
+ etf_max = osc_vmax = osc_tmax = -1e9
+}
+#
+# scan all records in file
+#
+{
+ #
+ # select WWVB records
+ # see summary for decode
+ #
+ if (NF >= 4 && $3 == "127.127.4.1") {
+ if ($4 == "SIGNAL" || NF > 7)
+ printf "%s\n", $0
+ else {
+ wwvb_count++
+ if ($4 ~ /\?/)
+ wwvb_x++
+ else if ($4 ~ /A/)
+ wwvb_a++
+ else if ($4 ~ /B/)
+ wwvb_b++
+ else if ($4 ~ /C/)
+ wwvb_c++
+ else if ($4 ~ /D/)
+ wwvb_d++
+ }
+ continue
+ }
+ #
+ # select IRIG records
+ # see summary for decode
+ #
+ if (NF >= 4 && $3 == "127.127.6.0") {
+ irig_count++
+ if ($5 ~ /\?/)
+ irig_error++
+ continue
+ }
+ #
+ # select LORAN ENSEMBLE records
+ # see summary for decode
+ #
+ else if (NF >= 13 && $6 == "ENSEMBLE") {
+ ensemble_count++
+ if ($9 <= 0)
+ ensemble_badgps++
+ else if ($12 <= 0)
+ ensemble_badloran++
+ else {
+ if ($13 > 200e-9 || $13 < -200e-9)
+ ensemble_200++
+ else if ($13 > 100e-9 || $13 < -100e-9)
+ ensemble_100++
+ ensemble_mean += $13
+ ensemble_rms += $13 * $13
+ }
+ continue
+ }
+ #
+ # select LORAN TDATA records
+ # see summary for decode; note that signal quality log is simply
+ # copied to output
+ #
+ else if (NF >= 7 && $6 == "TDATA") {
+ tdata_count++
+ for (i = 7; i < NF; i++) {
+ if ($i == "M" && $(i+1) == "OK") {
+ i += 5
+ m += $i
+ tdata_m++
+ }
+ else if ($i == "W" && $(i+1) == "OK") {
+ i += 5
+ w += $i
+ tdata_w++
+ }
+ else if ($i == "X" && $(i+1) == "OK") {
+ i += 5
+ x += $i
+ tdata_x++
+ }
+ else if ($i == "Y" && $(i+1) == "OK") {
+ i += 5
+ y += $i
+ tdata_y++
+ }
+ else if ($i == "Z" && $(i+1) == "OK") {
+ i += 5
+ z += $i
+ tdata_z++
+ }
+ }
+ continue
+ }
+ #
+ # select ITF records
+ # see summary for decode
+ #
+ else if (NF >= 13 && $5 == "ITF" && $12 >= 100) {
+ 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 >= 100) {
+ etf_count++
+ if ($6 > etf_max)
+ etf_max = $6
+ else if ($6 < etf_min)
+ etf_min = $6
+ etf_mean += $6
+ etf_rms += $6 * $6
+ etf_var += $9 * $9
+ continue
+ }
+ #
+ # select TRSTAT records
+ # see summary for decode
+ #
+ else if (NF >= 5 && $5 == "TRSTAT") {
+ trstat_count++
+ j = 0
+ for (i = 6; i <= NF; i++)
+ if ($i == "T")
+ j++
+ trstat_sat[j]++
+ continue
+ }
+ #
+ # select ID;OPT;VER records
+ #
+ # config GPS 2201A TTY1 TC1 LORAN IN OUT1 B.00 B.00 28-Apr-93
+ #
+ # GPS 2201A receiver model
+ # TTY1 rs232 moduel
+ # TC1 IRIG module
+ # LORAN LORAN assist module
+ # IN input module
+ # OUT1 output module
+ # B.00 B.00 firmware revision
+ # 28-Apr-9 firmware date3
+ #
+ else if (NF >= 5 && $5 == "ID;OPT;VER") {
+ id_count++
+ id_temp = ""
+ for (i = 6; i <= NF; i++)
+ id_temp = id_temp " " $i
+ if (id_string != id_temp)
+ printf "config%s\n", id_temp
+ id_string = id_temp
+ continue
+ }
+ #
+ # select POS;PPS;PPSOFF records
+ #
+ # position +39:40:48.425 -075:45:02.392 +74.09 Stored UTC 0 200 0
+ #
+ # +39:40:48.425 position north latitude
+ # -075:45:02.392 position east longitude
+ # +74.09 elevation (meters)
+ # Stored position is stored
+ # UTC time is relative to UTC
+ # 0 200 0 PPS offsets
+ #
+ else if (NF >= 5 && $5 == "POS;PPS;PPSOFF") {
+ pos_count++
+ pos_temp = ""
+ for (i = 6; i <= NF; i++)
+ pos_temp = pos_temp " " $i
+ if (pos_string != pos_temp)
+ printf "position%s\n", pos_temp
+ pos_string = pos_temp
+ continue
+ }
+ #
+ # select OSC;ET;TEMP records
+ #
+ # loop 1121 Software Control Locked
+ #
+ # 1121 oscillator type
+ # Software Control loop is under software control
+ # Locked loop is locked
+ #
+ else if (NF >= 5 && $5 == "OSC;ET;TEMP") {
+ osc_count++
+ osc_temp = $6 " " $7 " " $8 " " $9
+ if (osc_status != osc_temp)
+ printf "loop %s\n", osc_temp
+ osc_status = osc_temp
+ if ($10 > osc_vmax)
+ osc_vmax = $10
+ if ($10 < osc_vmin)
+ osc_vmin = $10
+ if ($11 > osc_tmax)
+ osc_tmax = $11
+ if ($11 < osc_tmin)
+ osc_tmin = $11
+ continue
+ }
+ #
+ # select UTC records
+ # these ain't ready yet
+ #
+ else if (NF >= 5 && $5 == "UTC") {
+ utc_count++
+ utc_temp = ""
+ for (i = 6; i <= NF; i++)
+ utc_temp = utc_temp " " $i
+ if (utc_string != utc_temp)
+# printf "utc%s\n", utc_temp
+ utc_string = utc_temp
+ continue
+ }
+} END {
+#
+# ensemble summary data
+#
+# ensemble record count
+# badgps gps data unavailable
+# badloran loran data unavailable
+# rms ensemble rms error (ns)
+# >200 ensemble error >200 ns
+# >100 100 ns < ensemble error < 200 ns
+#
+ if (ensemble_count > 0) {
+ ensemble_mean /= ensemble_count
+ ensemble_rms = sqrt(ensemble_rms / ensemble_count - ensemble_mean * ensemble_mean) * 1e9
+ printf "ensemble %d, badgps %d, badloran %d, rms %.1f, >200 %d, >100 %d\n", ensemble_count, ensemble_badgps, ensemble_badloran, ensemble_rms, ensemble_200, ensemble_100
+ }
+#
+# wwvb summary data
+#
+# wwvb record count
+# ? unsynchronized
+# >1 error > 1 ms
+# >10 error > 10 ms
+# >100 error > 100 ms
+# >500 error > 500 ms
+#
+ if (wwvb_count > 0)
+ printf "wwvb %d, ? %d, >1 %d, >10 %d, >100 %d, >500 %d\n", wwvb_count, wwvb_x, wwvb_a, wwvb_b, wwvb_c, wwvb_d
+#
+# irig summary data
+#
+# irig record count
+# err error count
+#
+ if (irig_count > 0)
+ printf "irig %d, err %d\n", irig_count, irig_error
+#
+# tdata summary data
+#
+# tdata record count
+# m M master OK-count, mean level (dB)
+# w W slave OK-count, mean level (dB)
+# x X slave OK-count, mean level (dB)
+# y Y slave OK-count, mean level (dB)
+# z Z slave OK-count, mean level (dB)
+#
+ if (tdata_count > 0 ) {
+ if (tdata_m > 0)
+ m /= tdata_count
+ if (tdata_x > 0)
+ w /= tdata_count
+ if (tdata_x > 0)
+ x /= tdata_count
+ if (tdata_y > 0)
+ y /= tdata_count
+ if (tdata_z > 0)
+ z /= tdata_count
+ printf "tdata %d, m %d %.1f, w %d %.1f, x %d %.1f, y %d %.1f, z %d %.1f\n", tdata_count, tdata_m, m, tdata_w, w, tdata_x, x, tdata_y, y, tdata_z, z
+ }
+#
+# itf summary data
+#
+# itf record count
+# rms itf rms error (ns)
+# >200 itf error > 200 ns
+# >100 itf error > 100 ns
+# var Allan variance
+#
+ if (itf_count > 1) {
+ itf_mean /= itf_count
+ itf_rms = sqrt(itf_rms / itf_count - itf_mean * itf_mean) * 1e9
+ itf_var = sqrt(itf_var / (2 * (itf_count - 1)))
+ printf "itf %d, rms %.1f, >200 %d, >100 %d, var %.2e\n", itf_count, itf_rms, itf_200, itf_100, itf_var
+ }
+#
+# etf summary data
+#
+# etf record count
+# mean etf mean (ns)
+# rms etf rms error (ns)
+# max etf maximum (ns)
+# min etf minimum (ns)
+# var Allan variance
+#
+ if (etf_count > 0) {
+ etf_mean /= etf_count
+ etf_rms = sqrt(etf_rms / etf_count - etf_mean * etf_mean)
+ etf_var = sqrt(etf_var / (2 * (etf_count - 1)))
+ printf "etf %d, mean %.1f, rms %.1f, max %d, min %d, var %.2e\n", etf_count, etf_mean, etf_rms, etf_max, etf_min, etf_var
+ }
+#
+# trstat summary data
+#
+# trstat record count
+# sat histogram of tracked satellites (0 - 7)
+#
+ if (trstat_count > 0)
+ printf "trstat %d, sat %d %d %d %d %d %d %d %d\n", trstat_count, trstat_sat[0], trstat_sat[1], trstat_sat[2], trstat_sat[2], trstat_sat[3], trstat_sat[4], trstat_sat[5], trstat_sat[6], trstat_sat[7]
+#
+# osc summary data
+#
+# osc record count
+# control control midrange (V) +/- deviation (mV)
+# temp oven temperature midrange +/- deviation (deg C)
+#
+ if (osc_count > 0)
+ printf "osc %d, control %.3f+/-%.3f, temp %.1f+/-%.2f\n", osc_count, (osc_vmax + osc_vmin) / 2, (osc_vmax - osc_vmin) / 2 * 1e3, (osc_tmax + osc_tmin) / 2, (osc_tmax - osc_tmin) / 2
+}
diff --git a/contrib/xntpd/scripts/stats/clock.sh b/contrib/xntpd/scripts/stats/clock.sh
new file mode 100755
index 000000000000..1866d556403d
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/clock.sh
@@ -0,0 +1,17 @@
+#!/bin/csh
+#
+# Script to summarize clockstats files
+#
+set x = `ls clockstats.*`
+foreach dayfile ( $x )
+ if ($dayfile == $x[$#x]) continue
+ echo " "
+ echo $dayfile
+ awk -f clock.awk $dayfile
+ awk -f itf.awk $dayfile >>itf
+ awk -f etf.awk $dayfile >>etf
+ awk -f ensemble.awk $dayfile >>ensemble
+ awk -f tdata.awk $dayfile >>tdata
+ rm -f $dayfile
+end
+
diff --git a/contrib/xntpd/scripts/stats/dupe.awk b/contrib/xntpd/scripts/stats/dupe.awk
new file mode 100644
index 000000000000..3ddc1b6f9754
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/dupe.awk
@@ -0,0 +1,7 @@
+# program to delete duplicate lines in a file
+#
+{
+ if (old != $0)
+ printf "%s\n", $0
+ old = $0
+}
diff --git a/contrib/xntpd/scripts/stats/ensemble.awk b/contrib/xntpd/scripts/stats/ensemble.awk
new file mode 100644
index 000000000000..136b33da37cb
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/ensemble.awk
@@ -0,0 +1,17 @@
+# program to produce loran ensemble statistics from clockstats files
+#
+# usage: awk -f ensemble.awk clockstats
+#
+# format of input record (time values in seconds)
+# 49165 8.628 127.127.10.1 93:178:00:00:07.241 LORAN ENSEMBLE
+# -6.43E-08 +5.02E-08 .091 +5.98E-08 +1.59E-08 .909 +4.85E-08 +3.52E-08
+#
+# format of output record (time values in nanoseconds)
+# MJD sec GPS wgt LORAN wgt avg sigma
+# 49165 8.628 -64.3 0.091 59.8 0.909 48.5 35.2
+#
+# select LORAN ENSEMBLE records with valid format and weights
+{
+ if (NF >= 14 && $6 == "ENSEMBLE" && $9 > 0 && $12 > 0)
+ printf "%5s %9.3f %7.1f %6.3f %7.1f %6.3f %7.1f %7.1f\n", $1, $2, $7*1e9, $9, $10*1e9, $12, $13*1e9, $14*1e9
+}
diff --git a/contrib/xntpd/scripts/stats/etf.awk b/contrib/xntpd/scripts/stats/etf.awk
new file mode 100644
index 000000000000..8e6e334c1e01
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/etf.awk
@@ -0,0 +1,19 @@
+# program to produce external time/frequence statistics from clockstats files
+#
+# usage: awk -f etf.awk clockstats
+#
+# format of input record
+# 49165 40.473 127.127.10.1 93:178:00:00:39.238 ETF
+# +175.0 +176.8 2.0 +3.729E-11 +1.000E-10 +3.511E-11 4.005E-13 500
+#
+# format of output record (time values in nanoseconds)
+# MJD sec time freq
+# 49165 40.473 175.0 3.729e-11
+#
+# select ETF records with valid format
+{
+ if (NF >= 9 && $5 == "ETF") {
+ printf "%5s %9.3f %7.1f %10.3e\n", $1, $2, $6, $9
+ }
+}
+
diff --git a/contrib/xntpd/scripts/stats/itf.awk b/contrib/xntpd/scripts/stats/itf.awk
new file mode 100644
index 000000000000..2b21c5b9b97c
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/itf.awk
@@ -0,0 +1,19 @@
+# program to produce intewrnal time/frequence statistics from clockstats files
+#
+# usage: awk -f itf.awk clockstats
+#
+# format of input record
+# 49227 67.846 127.127.10.1 93:240:00:00:51.816 ITF
+# COCO 0 +2.0579E-07 -3.1037E-08 -7.7723E-11 +6.5455E-10 500.00 4.962819
+#
+# format of output record (time values in nanoseconds)
+# MJD sec time freq
+# 49227 67.846 +2.0579E-07 -7.7723E-11
+#
+# select ITF records with valid format
+{
+ if (NF >= 10 && $5 == "ITF") {
+ printf "%5s %9.3f %7.1f %10.3e\n", $1, $2, $8 * 1e9, $10
+ }
+}
+
diff --git a/contrib/xntpd/scripts/stats/loop.awk b/contrib/xntpd/scripts/stats/loop.awk
new file mode 100644
index 000000000000..25d0bdb97d53
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/loop.awk
@@ -0,0 +1,49 @@
+# awk program to scan loopstats files and report errors/statistics
+#
+# usage: awk -f loop.awk loopstats
+#
+# format of loopstats record
+# MJD sec time (s) freq (ppm) tc
+# 49235 3.943 0.000016 22.4716 0
+#
+BEGIN {
+ loop_tmax = loop_fmax = -1e9
+ loop_tmin = loop_fmin = 1e9
+}
+#
+# scan all records in file
+#
+{
+ if (NF >= 5) {
+ loop_count++
+ if ($3 > loop_tmax)
+ loop_tmax = $3
+ if ($3 < loop_tmin)
+ loop_tmin = $3
+ if ($4 > loop_fmax)
+ loop_fmax = $4
+ if ($4 < loop_fmin)
+ loop_fmin = $4
+ loop_time += $3
+ loop_time_rms += $3 * $3
+ loop_freq += $4
+ loop_freq_rms += $4 * $4
+ }
+} END {
+ if (loop_count > 0) {
+ loop_time /= loop_count
+ loop_time_rms = sqrt(loop_time_rms / loop_count - loop_time * loop_time)
+ loop_freq /= loop_count
+ loop_freq_rms = sqrt(loop_freq_rms / loop_count - loop_freq * loop_freq)
+ loop_tmax = loop_tmax - loop_time
+ loop_tmin = loop_time - loop_tmin
+ if (loop_tmin > loop_tmax)
+ loop_tmax = loop_tmin
+ loop_fmax = loop_fmax - loop_freq
+ loop_fmin = loop_time - loop_fmin
+ if (loop_fmin > loop_fmax)
+ loop_fmax = loop_fmin
+ printf "loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, rms %.3f\n", loop_count, loop_time * 1e6, loop_tmax * 1e6, loop_time_rms * 1e6, loop_freq, loop_fmax, loop_freq_rms
+ }
+}
+
diff --git a/contrib/xntpd/scripts/stats/loop.sh b/contrib/xntpd/scripts/stats/loop.sh
new file mode 100755
index 000000000000..619eeb8c66af
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/loop.sh
@@ -0,0 +1,13 @@
+#!/bin/csh
+#
+# Script to summarize loopstats files
+#
+set x = `ls loopstats.*`
+foreach dayfile ( $x )
+ if ($dayfile == $x[$#x]) continue
+ echo " "
+ echo $dayfile
+ awk -f loop.awk $dayfile
+ rm -f $dayfile
+end
+
diff --git a/contrib/xntpd/scripts/stats/peer.awk b/contrib/xntpd/scripts/stats/peer.awk
new file mode 100644
index 000000000000..4cb48cddb68e
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/peer.awk
@@ -0,0 +1,57 @@
+# awk program to scan peerstats files and report errors/statistics
+#
+# usage: awk -f peer.awk peerstats
+#
+# format of peerstats record
+# MJD sec ident stat offset (s) delay (s) disp (s)
+# 49235 11.632 128.4.2.7 f414 -0.000041 0.21910 0.00084
+#
+BEGIN {
+ n = 0
+ MAXDISTANCE = 1.0
+}
+#
+# scan all records in file
+#
+{
+ if (NF >= 7 && ($7 + $6 / 2) < MAXDISTANCE) {
+ i = n
+ for (j = 0; j < n; j++) {
+ if ($3 == peer_ident[j])
+ i = j
+ }
+ if (i == n) {
+ peer_ident[i] = $3
+ peer_tmax[i] = peer_dist[i] = -1e9
+ peer_tmin[i] = 1e9
+ n++
+ }
+ peer_count[i]++
+ if ($5 > peer_tmax[i])
+ peer_tmax[i] = $5
+ if ($5 < peer_tmin[i])
+ peer_tmin[i] = $5
+ dist = $7 + $6 / 2
+ if (dist > peer_dist[i])
+ peer_dist[i] = dist
+ peer_time[i] += $5
+ peer_time_rms[i] += $5 * $5
+ peer_delay[i] += $6
+ peer_disp[i] += $7
+ }
+} END {
+ printf " ident cnt mean rms max delay dist disp\n"
+ printf "==========================================================================\n"
+ for (i = 0; i < n; i++) {
+ peer_time[i] /= peer_count[i]
+ peer_time_rms[i] = sqrt(peer_time_rms[i] / peer_count[i] - peer_time[i] * peer_time[i])
+ peer_delay[i] /= peer_count[i]
+ peer_disp[i] /= peer_count[i]
+ peer_tmax[i] = peer_tmax[i] - peer_time[i]
+ peer_tmin[i] = peer_time[i] - peer_tmin[i]
+ if (peer_tmin[i] > peer_tmax[i])
+ peer_tmax[i] = peer_tmin[i]
+ printf "%15s%5d%9.3f%9.3f%9.3f%9.3f%9.3f%9.3f\n", peer_ident[i], peer_count[i], peer_time[i] * 1e3, peer_time_rms[i] * 1e3, peer_tmax[i] * 1e3, peer_delay[i] * 1e3, peer_dist[i] * 1e3, peer_disp[i] * 1e3
+ }
+}
+
diff --git a/contrib/xntpd/scripts/stats/peer.sh b/contrib/xntpd/scripts/stats/peer.sh
new file mode 100755
index 000000000000..b5d8d29186db
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/peer.sh
@@ -0,0 +1,13 @@
+#!/bin/csh
+#
+# Script to summarize peerstats files
+#
+set x = `ls peerstats.*`
+foreach dayfile ( $x )
+ if ($dayfile == $x[$#x]) continue
+ echo " "
+ echo $dayfile
+ awk -f peer.awk $dayfile
+ rm -f $dayfile
+end
+
diff --git a/contrib/xntpd/scripts/stats/psummary.awk b/contrib/xntpd/scripts/stats/psummary.awk
new file mode 100644
index 000000000000..b7f0e922a7d6
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/psummary.awk
@@ -0,0 +1,41 @@
+# program to scan peer_summary file and produce summary of daily summaries
+#
+{
+ if (NF < 8 || $1 == "ident")
+ continue
+ i = n
+ for (j = 0; j < n; j++) {
+ if ($1 == peer_ident[j])
+ i = j
+ }
+ if (i == n) {
+ peer_ident[i] = $1
+ n++
+ }
+ peer_count[i]++
+ if (($7 - $6 / 2) < 400) {
+ peer_count[i]++
+ peer_mean[i] += $3
+ peer_var[i] += $4 * $4
+ if ($5 > peer_max[i])
+ peer_max[i] = $5
+ if ($5 > 1)
+ peer_1[i]++
+ if ($5 > 5)
+ peer_2[i]++
+ if ($5 > 10)
+ peer_3[i]++
+ if ($5 > 50)
+ peer_4[i]++
+ }
+} END {
+ printf " host cnt mean rms max >1 >5 >10 >50\n"
+ printf "=================================================================\n"
+ for (i = 0; i < n; i++) {
+ if (peer_count[i] <= 0)
+ continue
+ peer_mean[i] /= peer_count[i]
+ peer_var[i] = sqrt(peer_var[i] / peer_count[i])
+ printf "%15s%4d%10.3f%10.3f%10.3f%4d%4d%4d%4d\n", peer_ident[i], peer_count[i], peer_mean[i], peer_var[i], peer_max[i], peer_1[i], peer_2[i], peer_3[i], peer_4[i]
+ }
+}
diff --git a/contrib/xntpd/scripts/stats/summary.sh b/contrib/xntpd/scripts/stats/summary.sh
new file mode 100755
index 000000000000..ab99f4d8e8d5
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/summary.sh
@@ -0,0 +1,17 @@
+#!/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, which must be created first.
+#
+if ( -e peer_summary ) then
+ peer.sh >>peer_summary
+endif
+if ( -e loop_summary ) then
+ loop.sh >>loop_summary
+endif
+if ( -e clock_summary ) then
+ clock.sh >>clock_summary
+endif
diff --git a/contrib/xntpd/scripts/stats/tdata.awk b/contrib/xntpd/scripts/stats/tdata.awk
new file mode 100644
index 000000000000..04d7e6ad3242
--- /dev/null
+++ b/contrib/xntpd/scripts/stats/tdata.awk
@@ -0,0 +1,45 @@
+# program to produce loran tdata statistics from clockstats files
+#
+# usage: awk -f tdata.awk clockstats
+#
+# format of input record (missing replaced by -40.0)
+# 49228 36.852 127.127.10.1 93:241:00:00:20.812 LORAN TDATA
+# M OK 0 0 1169.14 -7.4 3.16E-07 .424
+# W CV 0 0 3329.30 -16.4 1.81E-06
+# X OK 0 0 1737.19 -10.5 3.44E-07 .358
+# Y OK 0 0 2182.07 -9.0 4.41E-07 .218
+#
+# format of output record (signal values are in dB)
+# MJD sec time M W X Y Z
+# 49228 36.852 175.0 -7.4 -16.4 -10.5 -9.0
+#
+# select LORAN TDATA records with valid format
+{
+ if (NF >= 7 && $6 == "TDATA") {
+ m = w = x = y = z = -40.0
+ for (i = 7; i < NF - 5; i++) {
+ if ($i == "M" && $(i+1) == "OK") {
+ i += 5
+ m = $i
+ }
+ else if ($i == "W" && $(i+1) == "OK") {
+ i += 5
+ w = $i
+ }
+ else if ($i == "X" && $(i+1) == "OK") {
+ i += 5
+ x = $i
+ }
+ else if ($i == "Y" && $(i+1) == "OK") {
+ i += 5
+ y = $i
+ }
+ else if ($i == "Z" && $(i+1) == "OK") {
+ i += 5
+ z = $i
+ }
+ }
+ printf "%5s %9.3f %6.1f %6.1f %6.1f %6.1f %6.1f\n", $1, $2, m, w, x, y, z
+ }
+}
+
diff --git a/contrib/xntpd/scripts/support/README b/contrib/xntpd/scripts/support/README
new file mode 100644
index 000000000000..812965bd0955
--- /dev/null
+++ b/contrib/xntpd/scripts/support/README
@@ -0,0 +1,73 @@
+The bin and etc directories contain several scripts (sh and perl) that
+should ease startup and configuration of NTP sites.
+
+ bin/monl is a monitoring script that prints out new, current and
+ old customers of an NTP timeserver when monitoring is
+ in effect.
+ monl has following options:
+ -i <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/contrib/xntpd/scripts/support/bin/monl b/contrib/xntpd/scripts/support/bin/monl
new file mode 100755
index 000000000000..44201d0d0f99
--- /dev/null
+++ b/contrib/xntpd/scripts/support/bin/monl
@@ -0,0 +1,212 @@
+#!/local/bin/perl
+
+%service = ( 0, "unspec",
+ 1, "Active",
+ 2, "Passive",
+ 3, "Client",
+ 4, "Server",
+ 5, "Broadcast",
+ 6, "Control",
+ 7, "Private" );
+%nc = ();
+@ignpat = ();
+$noname = 0;
+$verbose = 0;
+$retries = 5;
+$lastkey = 0;
+
+sub timedelta {
+ local($tm, $days, $h, $m, $s);
+
+ $tm = @_[$[];
+ $days = 0;
+ $days = sprintf("%dd+", $days) if $days = int($tm / (60*60*24));
+ $days = "" unless $days;
+ $tm = $tm % (60*60*24);
+ $h = int($tm / (60*60));
+ $tm = $tm % (60*60);
+ $m = int($tm / 60);
+ $s = $tm % 60;
+
+ return sprintf("%s%02d:%02d:%02d", $days, $h, $m, $s);
+}
+
+sub listentry {
+ local($host, $mode) = split("$;" , @_[$[]);
+ local($count, $version, $firsttime) = split("$;" , $_[$[+1]);
+ local($name);
+
+ if (grep($host =~ m/$_/, @ignpat))
+ {
+ print "ignored $host ...\n" if $verbose;
+ return;
+ }
+
+ return if ! $count;
+
+ if (defined($nc{$host}))
+ {
+ $name = $nc{$host};
+ }
+ else
+ {
+ if ($noname)
+ {
+ $nc{$host} = $name = $host;
+ }
+ else
+ {
+ $name = (gethostbyaddr(pack("C4", split(/\./, $host)), 2))[$[];
+ $nc{$host} = $name = $host if ! defined($name);
+ }
+ }
+
+ printf ($fmt, ($lastkey eq $host) ? "" : $name, $service{$mode}, $count, $version, &timedelta($firsttime), $firsttime / $count);
+
+ if (@_[$[+2])
+ {
+ $hostcnt++ if $lastkey ne $host;
+ $packcnt += $count;
+ $maxtime = $firsttime if $firsttime > $maxtime;
+ }
+
+ $lastkey = $host;
+}
+
+while ($ARGV[$[] =~ /^-[nvid]$/)
+ {
+ if ($ARGV[$[] eq "-i")
+ {
+ shift;
+ push(@ignpat, shift) unless ! defined($ARGV[$[]);
+ }
+ elsif ($ARGV[$[] eq "-d")
+ {
+ shift;
+ $dir = shift unless ! defined($ARGV[$[]);
+ }
+ elsif ($ARGV[$[] eq "-n")
+ {
+ shift;
+ $noname = 1;
+ }
+ elsif ($ARGV[$[] eq "-v")
+ {
+ shift;
+ $verbose = 1;
+ }
+ }
+
+$dir = "/tmp" unless defined($dir);
+$gone = 60*60*48;
+$fmt = "%48s %10s %7d %7d %13s %14.3f\n";
+$sfmt = "%48s %10s %7s %7s %13s %14s\n";
+@lbl = ("Host", "Mode", "Count", "Version", "Time active", "Packetinterval");
+
+if (!defined($ARGV[$[]))
+ {
+ $hostname = `hostname`;
+ chop($hostname);
+ unshift(@ARGV, $hostname);
+ }
+
+foreach $hostname (@ARGV)
+ {
+ $dbmfile = $dir . "/monlstats-" . $hostname;
+ $monl = "xntpdc -c 'hostnames no' -c monl $hostname | tail +3 |";
+ $hostcnt = 0;
+ $packcnt = 0;
+ $maxtime = 0;
+ %Seen = ();
+ %New = ();
+ %Old = ();
+
+ print "Monitor Status of $hostname\n\n";
+
+ $cnt = $retries;
+ do
+ {
+ open(MONL, $monl) || die("$monl failed $!");
+ @monlout = <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/contrib/xntpd/scripts/support/bin/mvstats b/contrib/xntpd/scripts/support/bin/mvstats
new file mode 100755
index 000000000000..e33dc792e805
--- /dev/null
+++ b/contrib/xntpd/scripts/support/bin/mvstats
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# mvstats,v 3.1 1993/07/06 01:10:24 jbj Exp
+#
+# mvstats is called by cron for keeping the log files together
+# usually only used on reference hosts
+#
+# Files reside in /var/NTP
+# Files older than 2 days will be compressed,
+# Files older than 64 days will be removed.
+#
+# mvstats,v
+# Revision 3.1 1993/07/06 01:10:24 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:58:24 kardel
+# Prerelease NTP V3 / DCF
+#
+#
+cd /var/NTP
+find . ! -name '*.Z' -mtime +2 -exec compress -f {} \;
+find . -mtime +64 -exec rm -f {} \;
diff --git a/contrib/xntpd/scripts/support/conf/hp300.hp300 b/contrib/xntpd/scripts/support/conf/hp300.hp300
new file mode 100644
index 000000000000..7b1875842219
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/hp300.hp300
@@ -0,0 +1,70 @@
+#
+# FAU NTP client configuration file
+#
+# hp300.hp300,v 3.1 1993/07/06 01:10:27 jbj Exp
+#
+# hp300.hp300,v
+# Revision 3.1 1993/07/06 01:10:27 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:58:29 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.2 1992/09/24 06:10:46 kardel
+# authdelay adjust
+#
+# Revision 1.1 1992/09/24 06:09:23 kardel
+# Initial revision
+#
+# Revision 1.2 1992/01/14 14:01:35 kardel
+# update for joined INF4/INF1 nets
+#
+#
+# Local fall back clock
+#
+precision -7
+#
+# Local clock
+#
+peer 127.127.1.13
+#
+broadcastclient yes
+# broadcastdelay must be figured out
+
+#
+# peers - local synch setup
+#
+#server ntps1-0 version 3
+#server ntps1-1 version 2
+#server ntps2-0 version 3
+#
+# files
+#
+driftfile /+private/local/NTP/xntp.drift
+#
+# authentication stuff
+#
+authdelay 0.000436 # hp300
+controlkey 1006
+requestkey 1007
+#
+# restrictions
+#
+# provide cheap services to the world/ prevent modifications from there
+#
+restrict default notrust lowpriotrap nomodify
+#
+# hosts on the local networks are allowed unrestricted access
+#
+restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts
+restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.60.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.54.0 mask 255.255.255.0 # allow local hosts
+#
+restrict 127.0.0.1 mask 255.255.255.255 # local config
+restrict 127.127.0.0 mask 255.255.0.0 # local clocks
diff --git a/contrib/xntpd/scripts/support/conf/hp700.hp700 b/contrib/xntpd/scripts/support/conf/hp700.hp700
new file mode 100644
index 000000000000..911ff10a5005
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/hp700.hp700
@@ -0,0 +1,67 @@
+#
+# FAU NTP client configuration file
+#
+# hp700.hp700,v 3.1 1993/07/06 01:10:29 jbj Exp
+#
+# hp700.hp700,v
+# Revision 3.1 1993/07/06 01:10:29 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:58:31 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.1 1992/09/24 06:09:02 kardel
+# Initial revision
+#
+# Revision 1.2 1992/01/14 14:01:35 kardel
+# update for joined INF4/INF1 nets
+#
+#
+# Local fall back clock
+#
+precision -7
+#
+# Local clock
+#
+peer 127.127.1.13
+#
+broadcastclient yes
+# broadcastdelay must be figured out
+
+#
+# peers - local synch setup
+#
+#server ntps1-0 version 3
+#server ntps1-1 version 2
+#server ntps2-0 version 3
+#
+# files
+#
+driftfile /+private/local/NTP/xntp.drift
+#
+# authentication stuff
+#
+authdelay 0.000016 # hp700
+controlkey 1006
+requestkey 1007
+#
+# restrictions
+#
+# provide cheap services to the world/ prevent modifications from there
+#
+restrict default notrust lowpriotrap nomodify
+#
+# hosts on the local networks are allowed unrestricted access
+#
+restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts
+restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.60.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.54.0 mask 255.255.255.0 # allow local hosts
+#
+restrict 127.0.0.1 mask 255.255.255.255 # local config
+restrict 127.127.0.0 mask 255.255.0.0 # local clocks
diff --git a/contrib/xntpd/scripts/support/conf/hp700.hp700.faui47 b/contrib/xntpd/scripts/support/conf/hp700.hp700.faui47
new file mode 100644
index 000000000000..80c72a6c2d6d
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/hp700.hp700.faui47
@@ -0,0 +1,71 @@
+#
+# FAU NTP client configuration file
+#
+# hp700.hp700.faui47,v 3.1 1993/07/06 01:10:30 jbj Exp
+#
+# hp700.hp700.faui47,v
+# Revision 3.1 1993/07/06 01:10:30 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:58:33 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.1 1992/09/24 14:53:10 kirschni
+# Initial revision
+#
+# Revision 1.1 1992/09/24 06:09:02 kardel
+# Initial revision
+#
+# Revision 1.2 1992/01/14 14:01:35 kardel
+# update for joined INF4/INF1 nets
+#
+#
+# Local fall back clock
+#
+precision -7
+#
+# Local clock
+#
+peer 127.127.1.13
+#
+broadcastclient yes
+# broadcastdelay must be figured out
+broadcast 131.188.54.255
+
+#
+# peers - local synch setup
+#
+#server ntps1-0 version 3
+#server ntps1-1 version 2
+#server ntps2-0 version 3
+#
+# files
+#
+driftfile /+private/local/NTP/xntp.drift
+#
+# authentication stuff
+#
+authdelay 0.000016 # hp700
+controlkey 1006
+requestkey 1007
+#
+# restrictions
+#
+# provide cheap services to the world/ prevent modifications from there
+#
+restrict default notrust lowpriotrap nomodify
+#
+# hosts on the local networks are allowed unrestricted access
+#
+restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts
+restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.60.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.54.0 mask 255.255.255.0 # allow local hosts
+#
+restrict 127.0.0.1 mask 255.255.255.255 # local config
+restrict 127.127.0.0 mask 255.255.0.0 # local clocks
diff --git a/contrib/xntpd/scripts/support/conf/hp800.hp800 b/contrib/xntpd/scripts/support/conf/hp800.hp800
new file mode 100644
index 000000000000..58f47062a6fd
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/hp800.hp800
@@ -0,0 +1,70 @@
+#
+# FAU NTP client configuration file
+#
+# hp800.hp800,v 3.1 1993/07/06 01:10:31 jbj Exp
+#
+# hp800.hp800,v
+# Revision 3.1 1993/07/06 01:10:31 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:58:35 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.2 1992/09/24 06:10:46 kardel
+# authdelay adjust
+#
+# Revision 1.1 1992/09/24 06:09:23 kardel
+# Initial revision
+#
+# Revision 1.2 1992/01/14 14:01:35 kardel
+# update for joined INF4/INF1 nets
+#
+#
+# Local fall back clock
+#
+precision -7
+#
+# Local clock
+#
+peer 127.127.1.13
+#
+broadcastclient yes
+# broadcastdelay must be figured out
+
+#
+# peers - local synch setup
+#
+#server ntps1-0 version 3
+#server ntps1-1 version 2
+#server ntps2-0 version 3
+#
+# files
+#
+driftfile /+private/local/NTP/xntp.drift
+#
+# authentication stuff
+#
+authdelay 0.000088 # hp800
+controlkey 1006
+requestkey 1007
+#
+# restrictions
+#
+# provide cheap services to the world/ prevent modifications from there
+#
+restrict default notrust lowpriotrap nomodify
+#
+# hosts on the local networks are allowed unrestricted access
+#
+restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts
+restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.60.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.54.0 mask 255.255.255.0 # allow local hosts
+#
+restrict 127.0.0.1 mask 255.255.255.255 # local config
+restrict 127.127.0.0 mask 255.255.0.0 # local clocks
diff --git a/contrib/xntpd/scripts/support/conf/ntp.conf b/contrib/xntpd/scripts/support/conf/ntp.conf
new file mode 100644
index 000000000000..06f5482c431e
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/ntp.conf
@@ -0,0 +1,36 @@
+#
+# peers - local synch setup
+#
+#server ntps1-0 key 0 version 2
+#server ntps1-1 key 0 version 2
+#server ntps2-0 key 0 version 2
+#server ntps2-1 key 0 version 2
+broadcastclient yes
+#broadcastdelay # use default, until we measure something
+#
+# files
+#
+driftfile /+private/local/NTP/xntp.drift
+resolver /local/NTP/bin/xntpres
+#
+# authentication stuff
+#
+authdelay 0.000629
+requestkey 65634
+controlkey 65635
+#
+# restrictions
+#
+# provide cheap services to the world/ prevent modifications from there
+restrict default notrust lowpriotrap nopeer nomodify
+#
+# hosts on the local networks are allowed unrestricted access
+#
+restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts
+#
+restrict 127.127.0.0 mask 255.255.0.0 # allow refclocks
+restrict 127.0.0.1 mask 255.255.255.255 # allow local config
+#
+restrict 131.188.0.0 mask 255.255.0.0 nomodify# allow local hosts
diff --git a/contrib/xntpd/scripts/support/conf/ntp.keys b/contrib/xntpd/scripts/support/conf/ntp.keys
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/ntp.keys
diff --git a/contrib/xntpd/scripts/support/conf/ntp.keys.dumb b/contrib/xntpd/scripts/support/conf/ntp.keys.dumb
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/ntp.keys.dumb
diff --git a/contrib/xntpd/scripts/support/conf/sun3.sun3 b/contrib/xntpd/scripts/support/conf/sun3.sun3
new file mode 100644
index 000000000000..06f5482c431e
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/sun3.sun3
@@ -0,0 +1,36 @@
+#
+# peers - local synch setup
+#
+#server ntps1-0 key 0 version 2
+#server ntps1-1 key 0 version 2
+#server ntps2-0 key 0 version 2
+#server ntps2-1 key 0 version 2
+broadcastclient yes
+#broadcastdelay # use default, until we measure something
+#
+# files
+#
+driftfile /+private/local/NTP/xntp.drift
+resolver /local/NTP/bin/xntpres
+#
+# authentication stuff
+#
+authdelay 0.000629
+requestkey 65634
+controlkey 65635
+#
+# restrictions
+#
+# provide cheap services to the world/ prevent modifications from there
+restrict default notrust lowpriotrap nopeer nomodify
+#
+# hosts on the local networks are allowed unrestricted access
+#
+restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts
+#
+restrict 127.127.0.0 mask 255.255.0.0 # allow refclocks
+restrict 127.0.0.1 mask 255.255.255.255 # allow local config
+#
+restrict 131.188.0.0 mask 255.255.0.0 nomodify# allow local hosts
diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4.faui01 b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui01
new file mode 100644
index 000000000000..8927535ef80a
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui01
@@ -0,0 +1,83 @@
+#
+# NTP v3 configuration file for faui01
+#
+# sun4.sun4.faui01,v 3.1 1993/07/06 01:10:37 jbj Exp
+#
+# sun4.sun4.faui01,v
+# Revision 3.1 1993/07/06 01:10:37 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:58:44 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.3 1992/10/15 10:56:01 kardel
+# -60 has 0 broadcasts now
+#
+# Revision 1.2 1992/09/17 12:46:53 kardel
+# CIP network broadcasts
+#
+# Revision 1.1 1992/06/09 13:40:44 kardel
+# Initial revision
+#
+#
+
+#
+# Local clock definitions
+#
+precision -14 # kernel fix - HIREZ timer
+
+#
+# Local clock
+#
+peer 127.127.1.6 # Fall back stratum 6
+
+#
+# get time from local network - hope this is reasonably stable
+#
+broadcastclient yes
+
+#
+# files / programs
+#
+driftfile /+private/local/NTP/xntp.drift
+
+#
+# authentication stuff
+#
+authdelay 0.000076
+requestkey 1007
+controlkey 1006
+
+#
+# service
+#
+broadcast 131.188.54.255 key 0 version 3
+broadcast 131.188.60.0 key 0 version 3
+broadcast 131.188.61.0 version 3 # inf1-net.revue (still on 2)
+broadcast 131.188.62.0 version 3 # inf4-net1.revue (still on 2)
+
+#
+# Statistics
+#
+monitor yes
+#statfile /var/NTP/statistics
+
+#
+# restrictions
+#
+# provide cheap services to the world/ prevent modifications from there
+restrict default notrust lowpriotrap nomodify
+
+#
+# hosts on the local networks are allowed unrestricted access
+#
+restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts
+restrict 131.188.1.0 mask 255.255.255.0 notrust # allow local hosts
+#
+restrict 127.127.0.0 mask 255.255.0.0 # local clocks
+restrict 127.0.0.1 # localhost does it too
+#
+restrict 131.188.1.45 mask 255.255.255.255 # ntps1-0
+restrict 131.188.34.45 mask 255.255.255.255 # ntps1-0
+restrict 131.188.44.45 mask 255.255.255.255 # ntps1-0
diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4.faui10 b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui10
new file mode 100644
index 000000000000..3be93a920f9a
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui10
@@ -0,0 +1,176 @@
+#
+# NTP v3 configuration file for faui45
+#
+# sun4.sun4.faui10,v 3.1 1993/07/06 01:10:38 jbj Exp
+#
+# sun4.sun4.faui10,v
+# Revision 3.1 1993/07/06 01:10:38 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.2 1993/01/19 09:32:31 kardel
+# Release 1993/01/19 DCF77/PPS
+#
+# Revision 1.1 1992/12/10 12:58:46 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.11 1992/10/28 07:38:09 kardel
+# bear.zoo.bt.co.uk now also peer
+#
+# Revision 1.10 1992/09/17 12:56:22 kardel
+# 61 and 62 have ZEROBROADCASTS
+#
+# Revision 1.9 1992/09/17 12:46:53 kardel
+# CIP network broadcasts
+#
+# Revision 1.8 1992/08/14 21:51:04 kardel
+# local clock is now preferred peer
+#
+# Revision 1.7 1992/07/19 14:19:26 kardel
+# fixed broadcasts
+#
+# Revision 1.6 1992/07/17 17:12:43 kardel
+# new statistics support
+#
+# Revision 1.5 1992/07/10 07:46:03 kardel
+# added loopstats statistic file
+#
+# Revision 1.4 1992/06/26 07:30:32 kardel
+# update for reference clock support
+#
+# Revision 1.3 1992/05/18 13:51:04 kardel
+# precision fix
+#
+# Revision 1.2 1992/03/30 11:16:07 kardel
+# ntps1-1 version 3
+#
+# Revision 1.1 1992/01/14 12:30:21 kardel
+# Initial revision
+#
+#
+
+#
+# Local clock definitions
+#
+precision -18 # us resolution
+
+# DCF77 - 0 - REFERENCE CLOCK / Meinberg PZF 535/OCXO
+#
+# Supported clock types Base
+# Meinberg DCF PZF535 TCXO 0
+# Meinberg DCF PZF535 OCXO 16
+# Meinberg DCF U/A 31 32
+#
+# Option PPS support (CLOCKDEFS=-DDCF -DDCFPPS)
+# PPS 128
+#
+# The device to be used is added to the base (16 devices possible
+# /dev/dcf77-0 - /dev/dcf77-15)
+#
+# If PPS support is to be used 128 has to be added to the base
+# thus a DCF77 U/A 31 without PPS would be 127.127.8.32 (device 0 - /dev/dcf77-0)
+# a DCF77 PZF535/TCXO with PPS would be 127.127.8.129 (device 1 - /dev/dcf77-1)
+# a DCF77 PZF535/OCXO with PPS would be 127.127.8.146 (device 2 - /dev/dcf77-2)
+#
+peer 127.127.8.144 prefer # PZF 535/OCXO / PPS support
+#
+# We want to provide timed service too, thus (startup script magic)
+# TIMED
+
+#
+# Local clock
+#
+peer 127.127.1.6 # Fall back stratum 6
+
+#
+# peers - local synch setup
+#
+peer ntps1-0 key 0 version 3
+peer ntps2-0 key 0 version 3
+
+#
+# European servers
+#
+peer sunmanager.lrz-muenchen.de key 0 version 2
+peer rustime01.rus.uni-stuttgart.de version 2
+peer mailszrz.zrz.tu-berlin.de version 2
+
+#
+# UK servers
+#
+peer bear.zoo.bt.co.uk version 3
+
+# US Servers
+#
+server truechimer.cso.uiuc.edu version 2
+
+#
+# files / programs
+#
+driftfile /+private/local/NTP/xntp.drift
+resolver /local/NTP/bin/xntpres
+
+#
+# authentication stuff
+#
+authdelay 0.000076
+requestkey 1007
+controlkey 1006
+
+#
+# service
+#
+broadcast 131.188.31.0 version 3 # inf1-net.revue
+broadcast 131.188.34.0 version 3 # inf4-net1.revue
+broadcast 131.188.44.0 version 3 # inf4-net2.revue
+broadcast 131.188.1.255 version 3 # revue.revue
+broadcast 131.188.54.255 key 0 version 3
+broadcast 131.188.60.255 key 0 version 3
+broadcast 131.188.61.0 key 0 version 3
+broadcast 131.188.62.0 key 0 version 3
+
+#
+# Statistics
+#
+monitor yes
+
+#
+# file name prefix
+#
+statsdir /var/NTP/
+#
+# <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/contrib/xntpd/scripts/support/conf/sun4.sun4.faui45 b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui45
new file mode 100644
index 000000000000..57e77f274980
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/sun4.sun4.faui45
@@ -0,0 +1,228 @@
+#
+# NTP v3 configuration file for faui45
+#
+# sun4.sun4.faui45,v 3.1 1993/07/06 01:10:39 jbj Exp
+#
+# sun4.sun4.faui45,v
+# Revision 3.1 1993/07/06 01:10:39 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.2 1993/01/19 09:32:33 kardel
+# Release 1993/01/19 DCF77/PPS
+#
+# Revision 1.1 1992/12/10 12:58:48 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.28 1992/10/28 07:38:09 kardel
+# bear.zoo.bt.co.uk now also peer
+#
+# Revision 1.27 1992/09/17 12:56:22 kardel
+# 61 and 62 have ZEROBROADCASTS
+#
+# Revision 1.26 1992/09/17 12:46:53 kardel
+# CIP network broadcasts
+#
+# Revision 1.25 1992/09/04 12:48:44 kardel
+# dcn1 -> churchy
+#
+# Revision 1.24 1992/08/14 21:42:20 kardel
+# local clock is now preferred peer
+#
+# Revision 1.23 1992/07/17 17:11:51 kardel
+# new statistics support
+#
+# Revision 1.22 1992/07/05 22:41:18 root
+# using default module settings now
+#
+# Revision 1.21 1992/07/02 11:47:26 root
+# loop statistics added
+#
+# Revision 1.20 1992/06/26 07:30:51 kardel
+# corrected examples
+#
+# Revision 1.19 1992/06/18 16:56:05 kardel
+# running timed too (startup script magic)
+#
+# Revision 1.18 1992/06/18 13:58:45 kardel
+# precision adjusted (us resolution)
+# clock definition explanation
+#
+# Revision 1.17 1992/06/13 12:49:35 root
+# allowed ntps1-1
+#
+# Revision 1.16 1992/06/07 11:44:41 kardel
+# switch to PPS support for dcf77-0
+#
+# Revision 1.15 1992/06/03 14:02:58 kardel
+# new version (fausup notrust)
+#
+# Revision 1.14 1992/05/18 13:49:45 kardel
+# first precision update due to kernel patch
+#
+# Revision 1.13 1992/05/18 13:48:36 kardel
+# more updates
+#
+# Revision 1.12 1992/03/24 08:43:49 kardel
+# now trusting netserv.rz.uni-karlsruhe.de
+#
+# Revision 1.11 1992/03/23 15:03:43 kardel
+# sunmanager.lrz-muenchen.de is a peer
+#
+# Revision 1.10 1992/03/12 22:49:53 kardel
+# well, got to switch fudge too
+#
+# Revision 1.9 1992/03/12 22:47:07 kardel
+# adjust for next xntpv3 alpha release
+#
+# Revision 1.8 1992/02/07 11:07:35 kardel
+# switched to Meinberg PZF 535/OCXO
+#
+# Revision 1.7 1992/01/21 15:11:38 kardel
+# netserv & sunmanager must be configured server (botch on other side)
+#
+# Revision 1.6 1992/01/17 17:54:34 kardel
+# added ntps2-0, ntps2-1 to unrestricted list
+#
+# Revision 1.5 1992/01/10 10:49:03 kardel
+# Authentication correction
+#
+# Revision 1.4 1992/01/10 08:08:06 kardel
+# peer apple.com added
+# ntps1-1 added to restrictionlist
+#
+# Revision 1.3 1991/12/19 10:23:56 kardel
+# peers on STRATUM 1
+# add mailszrz
+#
+# Revision 1.2 1991/12/19 09:57:29 kardel
+# upgrade NTP V3
+#
+#
+
+#
+# Local clock definitions
+#
+precision -18 # us resolution
+
+# DCF77 - 0 - REFERENCE CLOCK / Meinberg PZF 535/OCXO
+#
+# Supported clock types Base
+# Meinberg DCF PZF535 TCXO 0
+# Meinberg DCF PZF535 OCXO 16
+# Meinberg DCF U/A 31 32
+#
+# Option PPS support (CLOCKDEFS=-DDCF -DDCFPPS)
+# PPS 128
+#
+# The device to be used is added to the base (16 devices possible
+# /dev/dcf77-0 - /dev/dcf77-15)
+#
+# If PPS support is to be used 128 has to be added to the base
+# thus a DCF77 U/A 31 without PPS would be 127.127.8.32 (device 0 - /dev/dcf77-0)
+# a DCF77 PZF535/TCXO with PPS would be 127.127.8.129 (device 1 - /dev/dcf77-1)
+# a DCF77 PZF535/OCXO with PPS would be 127.127.8.146 (device 2 - /dev/dcf77-2)
+#
+peer 127.127.8.144 prefer # PZF 535/OCXO / PPS support
+#
+# We want to provide timed service too, thus (startup script magic)
+# TIMED
+
+#
+# Local clock
+#
+peer 127.127.1.6 # Fall back stratum 6
+
+#
+# peers - local synch setup
+#
+peer ntps1-1 key 0 version 2 # to be upgrade to version 3
+peer ntps2-0 key 0 version 2 # to be upgrade to version 3
+
+#
+# European servers
+#
+peer sunmanager.lrz-muenchen.de key 0 version 2
+peer iis.ethz.ch version 3
+server netserv.rz.uni-karlsruhe.de version 2 # sorry configuration error on other side
+peer rustime01.rus.uni-stuttgart.de version 2
+peer mailszrz.zrz.tu-berlin.de version 2
+
+#
+# UK servers
+#
+peer bear.zoo.bt.co.uk version 3
+
+#
+# US Servers
+#
+peer apple.com version 2
+server churchy.udel.edu key 0 version 3
+
+#
+# files / programs
+#
+driftfile /+private/local/NTP/xntp.drift
+resolver /local/NTP/bin/xntpres
+
+#
+# authentication stuff
+#
+authdelay 0.000076
+requestkey 1007
+controlkey 1006
+
+#
+# service
+#
+broadcast 131.188.1.255 key 0 version 2 # revue.revue (still on 2)
+broadcast 131.188.34.0 key 0 version 2 # inf4-net1.revue (still on 2)
+broadcast 131.188.44.0 key 0 version 2 # inf4-net2.revue (still on 2)
+broadcast 131.188.54.255 key 0 version 3
+broadcast 131.188.60.255 key 0 version 3
+broadcast 131.188.61.0 key 0 version 3
+broadcast 131.188.62.0 key 0 version 3
+
+#
+# Statistics
+#
+monitor yes
+#
+# file name prefix
+#
+statsdir /var/NTP/
+#
+# <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/contrib/xntpd/scripts/support/conf/sun4.sun4c b/contrib/xntpd/scripts/support/conf/sun4.sun4c
new file mode 100644
index 000000000000..e1ff90259077
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/sun4.sun4c
@@ -0,0 +1,63 @@
+#
+# FAU NTP client configuration file
+#
+# sun4.sun4c,v 3.1 1993/07/06 01:10:41 jbj Exp
+#
+# sun4.sun4c,v
+# Revision 3.1 1993/07/06 01:10:41 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:58:50 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.2 1992/01/14 14:01:35 kardel
+# update for joined INF4/INF1 nets
+#
+#
+# Local fall back clock
+#
+precision -7
+#
+# Local clock
+#
+peer 127.127.1.13
+#
+broadcastclient yes
+# broadcastdelay must be figured out
+
+#
+# peers - local synch setup
+#
+#server ntps1-0 version 3
+#server ntps1-1 version 2
+#server ntps2-0 version 3
+#
+# files
+#
+driftfile /+private/local/NTP/xntp.drift
+resolver /local/NTP/bin/xntpres
+#
+# authentication stuff
+#
+authdelay 0.000144 # sun4c
+controlkey 1006
+requestkey 1007
+#
+# restrictions
+#
+# provide cheap services to the world/ prevent modifications from there
+#
+restrict default notrust lowpriotrap nomodify
+#
+# hosts on the local networks are allowed unrestricted access
+#
+restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts
+restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts
+#
+restrict 127.0.0.1 mask 255.255.255.255 # local config
+restrict 127.127.0.0 mask 255.255.0.0 # local clocks
diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4c.Lucifer b/contrib/xntpd/scripts/support/conf/sun4.sun4c.Lucifer
new file mode 100644
index 000000000000..78d3ea887958
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/sun4.sun4c.Lucifer
@@ -0,0 +1,174 @@
+#
+# NTP v3 configuration file for Lucifer
+#
+# sun4.sun4c.Lucifer,v 3.1 1993/07/06 01:10:42 jbj Exp
+#
+# sun4.sun4c.Lucifer,v
+# Revision 3.1 1993/07/06 01:10:42 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.2 1993/01/19 09:32:35 kardel
+# Release 1993/01/19 DCF77/PPS
+#
+# Revision 1.1 1992/12/10 12:58:52 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.8 1992/10/28 07:38:09 kardel
+# bear.zoo.bt.co.uk now also peer
+#
+# Revision 1.7 1992/09/17 12:56:22 kardel
+# 61 and 62 have ZEROBROADCASTS
+#
+# Revision 1.6 1992/09/17 12:46:53 kardel
+# CIP network broadcasts
+#
+# Revision 1.5 1992/08/14 21:52:02 kardel
+# local clock is now preferred peer
+#
+# Revision 1.4 1992/07/17 17:15:06 kardel
+# adedd new statistics support
+#
+# Revision 1.3 1992/07/12 16:50:16 kardel
+# new peers, restrictions, statistics, no timed
+#
+# Revision 1.2 1992/07/10 07:01:44 kardel
+# authdelay fixed
+#
+# Revision 1.1 1992/07/10 07:00:30 kardel
+# Initial revision
+#
+#
+#
+# Local clock definitions
+#
+precision -18 # us resolution
+
+# DCF77 - 0 - REFERENCE CLOCK / Meinberg PZF 535/OCXO
+#
+# Supported clock types Base
+# Meinberg DCF PZF535 TCXO 0
+# Meinberg DCF PZF535 OCXO 16
+# Meinberg DCF U/A 31 32
+# ELV DCF7000 48
+
+#
+# Option PPS support (CLOCKDEFS=-DDCF -DDCFPPS)
+# PPS 128
+#
+# The device to be used is added to the base (16 devices possible
+# /dev/dcf77-0 - /dev/dcf77-15)
+#
+# If PPS support is to be used 128 has to be added to the base
+# thus a DCF77 U/A 31 without PPS would be 127.127.8.32 (device 0 - /dev/dcf77-0)
+# a DCF77 PZF535/TCXO with PPS would be 127.127.8.129 (device 1 - /dev/dcf77-1)
+# a DCF77 PZF535/OCXO with PPS would be 127.127.8.146 (device 2 - /dev/dcf77-2)
+#
+peer 127.127.8.144 prefer # PZF 535/OCXO / PPS support
+#
+
+#
+# Local clock
+#
+peer 127.127.1.6 # Fall back stratum 6
+
+#
+# peers - local synch setup
+#
+peer ntps1-1 key 0 version 3
+peer ntps1-2 key 0 version 3
+peer ntps2-0 key 0 version 3
+
+#
+# UK servers
+#
+peer bear.zoo.bt.co.uk version 3
+
+#
+# European servers
+#
+peer sunmanager.lrz-muenchen.de key 0 version 2
+peer iis.ethz.ch version 3
+server netserv.rz.uni-karlsruhe.de version 2 # sorry configuration error on other side
+peer rustime01.rus.uni-stuttgart.de version 2
+peer mailszrz.zrz.tu-berlin.de version 2
+
+#
+# US Servers
+#
+peer apple.com version 2
+server dcn1.udel.edu key 0 version 3
+
+#
+# files / programs
+#
+driftfile /+private/local/NTP/xntp.drift
+resolver /local/NTP/bin/xntpres
+
+#
+# authentication stuff
+#
+authdelay 0.000144 # sun4c
+requestkey 1007
+controlkey 1006
+
+#
+# service
+#
+broadcast 131.188.1.255 key 0 version 3 # revue.revue (still on 2)
+broadcast 131.188.34.0 key 0 version 3 # inf4-net1.revue (still on 2)
+broadcast 131.188.44.0 key 0 version 3 # inf4-net2.revue (still on 2)
+broadcast 131.188.54.255 key 0 version 3
+broadcast 131.188.60.255 key 0 version 3
+broadcast 131.188.61.0 key 0 version 3
+broadcast 131.188.62.0 key 0 version 3
+
+#
+# Statistics
+#
+monitor yes
+
+#
+# file name prefix
+#
+statsdir /var/NTP/
+#
+# <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/contrib/xntpd/scripts/support/conf/sun4.sun4m b/contrib/xntpd/scripts/support/conf/sun4.sun4m
new file mode 100644
index 000000000000..cf1e283cb1fd
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/sun4.sun4m
@@ -0,0 +1,69 @@
+#
+# FAU NTP client configuration file
+#
+# sun4.sun4m,v 3.1 1993/07/06 01:10:43 jbj Exp
+#
+# sun4.sun4m,v
+# Revision 3.1 1993/07/06 01:10:43 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:58:55 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.2 1992/10/05 12:48:44 kardel
+# sun4m authdelay
+#
+# Revision 1.1 1992/10/05 12:48:07 kardel
+# Initial revision
+#
+# Revision 1.2 1992/01/14 14:01:35 kardel
+# update for joined INF4/INF1 nets
+#
+#
+# Local fall back clock
+#
+precision -7
+#
+# Local clock
+#
+peer 127.127.1.13
+#
+broadcastclient yes
+# broadcastdelay must be figured out
+
+#
+# peers - local synch setup
+#
+#server ntps1-0 version 3
+#server ntps1-1 version 2
+#server ntps2-0 version 3
+#
+# files
+#
+driftfile /+private/local/NTP/xntp.drift
+resolver /local/NTP/bin/xntpres
+#
+# authentication stuff
+#
+authdelay 0.000033 # sun4c
+controlkey 1006
+requestkey 1007
+#
+# restrictions
+#
+# provide cheap services to the world/ prevent modifications from there
+#
+restrict default notrust lowpriotrap nomodify
+#
+# hosts on the local networks are allowed unrestricted access
+#
+restrict 131.188.0.0 mask 255.255.0.0 nomodify notrust # allow local hosts
+restrict 131.188.1.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.31.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.34.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.44.0 mask 255.255.255.0 # allow local hosts
+restrict 131.188.40.0 mask 255.255.255.0 # allow local hosts
+#
+restrict 127.0.0.1 mask 255.255.255.255 # local config
+restrict 127.127.0.0 mask 255.255.0.0 # local clocks
diff --git a/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui42 b/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui42
new file mode 100644
index 000000000000..acc919c85f2c
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui42
@@ -0,0 +1,152 @@
+#
+# NTP v3 configuration file for faui42
+#
+# sun4.sun4m.faui42,v 3.1 1993/07/06 01:10:44 jbj Exp
+#
+# sun4.sun4m.faui42,v
+# Revision 3.1 1993/07/06 01:10:44 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.2 1993/01/19 09:32:36 kardel
+# Release 1993/01/19 DCF77/PPS
+#
+# Revision 1.1 1992/12/10 12:58:57 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.6 1992/09/15 16:19:10 kardel
+# preferrred peer
+#
+# Revision 1.5 1992/09/15 15:57:36 kardel
+# Stratum 1 again (may the Patches be with us...)
+#
+# Revision 1.4 1992/06/30 08:52:38 kardel
+# sun4m machine don't have a clock (SunOS4.1.2)
+# soory - just Stratum 2
+#
+# Revision 1.3 1992/06/18 13:58:45 kardel
+# precision adjusted (us resolution)
+# clock definition explanation
+#
+# Revision 1.2 1992/06/13 11:42:49 kardel
+# restrictions changed
+#
+# Revision 1.1 1992/06/13 11:27:11 kardel
+# Initial revision
+#
+#
+
+#
+# Local clock definitions
+#
+precision -18 # us resolution
+
+#
+# DCF77 - 0 - REFERENCE CLOCK / Meinberg PZF 535/OCXO
+#
+# Supported clock types Base
+# Meinberg DCF PZF535 TCXO 0
+# Meinberg DCF PZF535 OCXO 16
+# Meinberg DCF U/A 31 32
+#
+# Option PPS support (CLOCKDEFS=-DDCF -DDCFPPS)
+# PPS 128
+#
+# The device to be used is added to the base (16 devices possible
+# /dev/dcf77-0 - /dev/dcf77-15)
+#
+# If PPS support is to be used 128 has to be added to the base
+# thus a DCF77 U/A 31 without PPS would be 127.127.8.32 (device 0 - /dev/dcf77-0)
+# a DCF77 PZF535/TCXO with PPS would be 127.127.8.129 (device 1 - /dev/dcf77-1)
+# a DCF77 PZF535/OCXO with PPS would be 127.127.8.146 (device 2 - /dev/dcf77-2)
+#
+peer 127.127.8.144 prefer # PZF 535/OCXO / PPS support
+#
+# Local clock
+#
+peer 127.127.1.6 # Fall back stratum 6
+
+#
+# peers - local synch setup
+#
+peer ntps1-0 key 0 version 2 # to be upgrade to version 3
+peer ntps2-0 key 0 version 2 # to be upgrade to version 3
+
+#
+# European servers
+#
+peer sunmanager.lrz-muenchen.de key 0 version 2
+peer iis.ethz.ch version 3
+#server netserv.rz.uni-karlsruhe.de version 2 # sorry configuration error on other side
+peer rustime01.rus.uni-stuttgart.de version 2
+#peer mailszrz.zrz.tu-berlin.de version 2
+
+#
+# US Servers
+#
+#peer apple.com version 2
+#server dcn1.udel.edu key 0 version 3
+
+#
+# files / programs
+#
+driftfile /+private/local/NTP/xntp.drift
+resolver /local/NTP/bin/xntpres
+
+#
+# authentication stuff
+#
+authdelay 0.000047
+requestkey 1007
+controlkey 1006
+
+#
+# service
+#
+broadcast 131.188.1.255 key 0 version 3 # revue.revue (still on 2)
+broadcast 131.188.40.0 key 0 version 3 # inf4-net2.revue (still on 2)
+
+#
+# Statistics
+#
+monitor yes
+
+#
+# file name prefix
+#
+statsdir /var/NTP/
+#
+# <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/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui45m b/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui45m
new file mode 100644
index 000000000000..2c75f67545f0
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/sun4.sun4m.faui45m
@@ -0,0 +1,165 @@
+#
+# NTP v3 configuration file for Lucifer
+#
+# sun4.sun4m.faui45m,v 3.1 1993/07/06 01:10:45 jbj Exp
+#
+# sun4.sun4m.faui45m,v
+# Revision 3.1 1993/07/06 01:10:45 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.2 1993/01/19 09:32:38 kardel
+# Release 1993/01/19 DCF77/PPS
+#
+# Revision 1.1 1992/12/10 12:58:59 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.7 1992/09/17 12:56:22 kardel
+# 61 and 62 have ZEROBROADCASTS
+#
+# Revision 1.6 1992/09/17 12:46:53 kardel
+# CIP network broadcasts
+#
+# Revision 1.5 1992/08/14 21:52:02 kardel
+# local clock is now preferred peer
+#
+# Revision 1.4 1992/07/17 17:15:06 kardel
+# adedd new statistics support
+#
+# Revision 1.3 1992/07/12 16:50:16 kardel
+# new peers, restrictions, statistics, no timed
+#
+# Revision 1.2 1992/07/10 07:01:44 kardel
+# authdelay fixed
+#
+# Revision 1.1 1992/07/10 07:00:30 kardel
+# Initial revision
+#
+#
+#
+# Local clock definitions
+#
+precision -18 # us resolution
+
+# DCF77 - 0 - REFERENCE CLOCK / Meinberg PZF 535/OCXO
+#
+# Supported clock types Base
+# Meinberg DCF PZF535 TCXO 0
+# Meinberg DCF PZF535 OCXO 16
+# Meinberg DCF U/A 31 32
+# ELV DCF7000 48
+
+#
+# Option PPS support (CLOCKDEFS=-DDCF -DDCFPPS)
+# PPS 128
+#
+# The device to be used is added to the base (16 devices possible
+# /dev/dcf77-0 - /dev/dcf77-15)
+#
+# If PPS support is to be used 128 has to be added to the base
+# thus a DCF77 U/A 31 without PPS would be 127.127.8.32 (device 0 - /dev/dcf77-0)
+# a DCF77 PZF535/TCXO with PPS would be 127.127.8.129 (device 1 - /dev/dcf77-1)
+# a DCF77 PZF535/OCXO with PPS would be 127.127.8.146 (device 2 - /dev/dcf77-2)
+#
+peer 127.127.8.144 prefer # PZF 535/OCXO / PPS support
+#
+
+#
+# Local clock
+#
+peer 127.127.1.6 # Fall back stratum 6
+
+#
+# peers - local synch setup
+#
+peer ntps1-1 key 0 version 3
+peer ntps1-2 key 0 version 3
+peer ntps2-0 key 0 version 3
+
+#
+# European servers
+#
+peer sunmanager.lrz-muenchen.de key 0 version 2
+peer iis.ethz.ch version 3
+server netserv.rz.uni-karlsruhe.de version 2 # sorry configuration error on other side
+peer rustime01.rus.uni-stuttgart.de version 2
+peer mailszrz.zrz.tu-berlin.de version 2
+
+#
+# US Servers
+#
+peer apple.com version 2
+server dcn1.udel.edu key 0 version 3
+
+#
+# files / programs
+#
+driftfile /+private/local/NTP/xntp.drift
+resolver /local/NTP/bin/xntpres
+
+#
+# authentication stuff
+#
+authdelay 0.000033 # sun4m
+requestkey 1007
+controlkey 1006
+
+#
+# service
+#
+broadcast 131.188.1.255 key 0 version 3 # revue.revue (still on 2)
+broadcast 131.188.34.0 key 0 version 3 # inf4-net1.revue (still on 2)
+broadcast 131.188.44.0 key 0 version 3 # inf4-net2.revue (still on 2)
+broadcast 131.188.54.255 key 0 version 3
+broadcast 131.188.60.255 key 0 version 3
+broadcast 131.188.61.0 key 0 version 3
+broadcast 131.188.62.0 key 0 version 3
+
+#
+# Statistics
+#
+monitor yes
+
+#
+# file name prefix
+#
+statsdir /var/NTP/
+#
+# <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/contrib/xntpd/scripts/support/conf/tickconf b/contrib/xntpd/scripts/support/conf/tickconf
new file mode 100644
index 000000000000..b17dbe834743
--- /dev/null
+++ b/contrib/xntpd/scripts/support/conf/tickconf
@@ -0,0 +1,19 @@
+DEFAULT -A -p -s -q
+Lucifer 55406cfa -a 1 -p -s -q -t 10001
+faui45 24000f9b -a 1 -p -s -q
+faui10 2440213c -a 1 -p -s -q
+faui1b 54001418 -A -p -s -q -t 10001
+faui4p 5100344d -A -p -s -q -t 9999
+faui02g 1200be20 -A -p -s -q -t 9999
+faui02e 1200bbab -A -p -s -q -t 9999
+faui02f 1200bedb -A -p -s -q -t 9999
+faui03b 1200b92b -A -p -s -q -t 9999
+faui45m 726001ac -A -p -s -q -t 10001
+faui45o 72600272 -A -p -s -q -t 10001
+faui45p 7260028f -A -p -s -q -t 10001
+faui45r 72400cc7 -A -p -s -q -t 10001
+faui45s 726045be -A -p -s -q -t 10001
+faui45v 72604487 -A -p -s -q -t 10001
+faui45x 726044eb -A -p -s -q -t 10001
+faui45y 7260476d -A -p -s -q -t 10001
+faui45z 726045a1 -A -p -s -q -t 10001
diff --git a/contrib/xntpd/scripts/support/etc/cron b/contrib/xntpd/scripts/support/etc/cron
new file mode 100755
index 000000000000..07ed18949835
--- /dev/null
+++ b/contrib/xntpd/scripts/support/etc/cron
@@ -0,0 +1,18 @@
+#!/bin/sh
+#
+# cron,v 3.1 1993/07/06 01:10:50 jbj Exp
+#
+# called by cron for statistics gathering
+#
+# cron,v
+# Revision 3.1 1993/07/06 01:10:50 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:59:18 kardel
+# Prerelease NTP V3 / DCF
+#
+#
+PATH="${PATH}:/local/NTP/bin"
+export PATH
+monl -d /local/NTP/monitor -i '127\.0\.0\.1' faui10 faui45 lucifer rackety.udel.edu
diff --git a/contrib/xntpd/scripts/support/etc/crontab b/contrib/xntpd/scripts/support/etc/crontab
new file mode 100644
index 000000000000..2b2d19ced76c
--- /dev/null
+++ b/contrib/xntpd/scripts/support/etc/crontab
@@ -0,0 +1,8 @@
+#
+# NTP statistics periodic cleanup - REFERENCE SERVER ONLY
+#
+#55 23 * * * sh /local/NTP/etc/mvstats
+#
+# gather NTP client statistics - REFERENCE SERVER ONLY
+#
+0 8,18 * * * /local/NTP/etc/cron 2>/dev/null | /usr/ucb/mail -s "NTP statistics" time@informatik.uni-erlangen.de
diff --git a/contrib/xntpd/scripts/support/etc/install b/contrib/xntpd/scripts/support/etc/install
new file mode 100755
index 000000000000..169a7e5a06d7
--- /dev/null
+++ b/contrib/xntpd/scripts/support/etc/install
@@ -0,0 +1,67 @@
+#!/bin/sh
+#
+# install,v 3.1 1993/07/06 01:10:53 jbj Exp
+#
+# install,v
+# Revision 3.1 1993/07/06 01:10:53 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:59:21 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.1 1992/06/18 14:50:08 kardel
+# Initial revision
+#
+#
+NTPROOT=/local/NTP # SITE SPECIFIC: where NTP resides
+#
+# where the local NTP state files reside (xntp.drift) ussualle /etc
+# this directory must not be shared as machine dependent data ist stored there
+#
+NTPDIR="/+private/local/NTP"
+#
+# get the initial setup
+#
+if [ ! -r $NTPROOT/etc/setup ]; then
+ echo "ERROR: $NTPROOT/etc/setup missing - incorrect installation."
+ exit 1
+else
+ . $NTPROOT/etc/setup
+fi
+
+umask 022 # SITE SPECIFIC: local policy - watch out for NFS and "root" rights
+
+Mkdir() {
+ p=""
+ IFS="/"
+ set -- $@
+ IFS='
+'
+ for pnc do
+ if [ ! -d "$p/$pnc" ]; then
+ ECHO -n "creating directory $p/$pnc"
+ if mkdir "$p/$pnc"; then
+ ECHO ""
+ else
+ ECHO " - FAILED"
+ break;
+ fi
+ fi
+ p="$p/$pnc"
+ done
+}
+
+if [ ! -d "$NTPDIR" ]; then
+ ECHO "installing NTP private data area ($NTPDIR)"
+ if Mkdir "$NTPDIR"; then
+ chmod 755 "$NTPDIR"
+ ECHO "$NTPDIR created."
+ fi
+else
+ ECHO "NTP already installed."
+ if [ -f "$NTPDIR/xntp.drift" ]; then
+ ECHO "currently saved drift value:" `cat "$NTPDIR/xntp.drift"`
+ fi
+fi
+
diff --git a/contrib/xntpd/scripts/support/etc/rc b/contrib/xntpd/scripts/support/etc/rc
new file mode 100755
index 000000000000..ef8834a69f7b
--- /dev/null
+++ b/contrib/xntpd/scripts/support/etc/rc
@@ -0,0 +1,198 @@
+#!/bin/sh
+# NTP time synchronisation
+#
+# /src/NTP/REPOSITORY/v3/supportscripts/etc/rc,v 1.11 1993/07/09 13:17:00 kardel Exp
+#
+# rc,v
+# Revision 1.11 1993/07/09 13:17:00 kardel
+# local NTPROOT
+#
+# Revision 1.10 1993/07/09 11:37:29 kardel
+# Initial restructured version + GPS support
+#
+# Revision 1.9 1993/06/23 14:10:36 kardel
+# June 21st reconcilation
+#
+# Revision 1.7 1993/06/02 12:04:43 kardel
+# May 28th reconcilation & clenaup
+#
+#
+# non reference clock hosts will try to do an ntpdate on NTPSERVERS
+#
+NTPSERVERS="ntps1-0 ntps1-1 ntps2-0 ntps2-1"
+NTPROOT=/local/NTP
+
+#
+# get the initial setup
+#
+if [ ! -r $NTPROOT/etc/setup ]; then
+ echo "ERROR: $NTPROOT/etc/setup missing - incorrect installation."
+ exit 1
+else
+ . $NTPROOT/etc/setup
+fi
+
+umask 022 # SITE SPECIFIC: local policy - watch out for NFS and "root" rights
+
+msg=""
+#
+# default configuration files are named $NTPROOT/conf/<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/contrib/xntpd/scripts/support/etc/setup b/contrib/xntpd/scripts/support/etc/setup
new file mode 100755
index 000000000000..d4ea75ecfaa9
--- /dev/null
+++ b/contrib/xntpd/scripts/support/etc/setup
@@ -0,0 +1,72 @@
+#
+# setup,v 3.1 1993/07/06 01:10:55 jbj Exp
+#
+# /bin/sh sourced file for environment setup
+# expects NTPROOT variable initialized
+#
+# if not set it will be initialized to /usr/local/NTP
+#
+# setup,v
+# Revision 3.1 1993/07/06 01:10:55 jbj
+# XNTP release 3.1
+#
+#
+# Revision 1.1 1992/12/10 12:59:25 kardel
+# Prerelease NTP V3 / DCF
+#
+# Revision 1.1 1992/12/10 10:14:46 kardel
+# Initial revision
+#
+#
+NTPROOT=${NTPROOT-/usr/local/NTP}
+
+#
+# we so use our own echos, as we somes want to substitute them with a
+# file logging version durin the /etc/rc.local phase
+#
+set `type ECHO`
+
+PATH="${PATH}:$NTPROOT/bin"
+export PATH
+
+if [ "$2" = "is" ]; then
+ :
+else
+ #
+ # find out the way echos work (Rest of rc thinks BSD echo)
+ #
+ ECHOREP="`echo -n x`"
+ if [ "$ECHOREP" = "-n x" ]; then
+ ECHO () {
+ if [ "$1" = "-n" ]; then
+ shift
+ echo "$@\c"
+ else
+ echo "$@"
+ fi
+ }
+ #ECHO "System V style echo"
+ else
+ ECHO () {
+ echo "$@"
+ }
+ #ECHO "BSD style echo"
+ fi
+
+ NLECHO () {
+ echo "$@"
+ }
+
+ LOG () {
+ while read _line; do
+ ECHO "$_line"
+ done
+ }
+ #
+ # carefully find out some configuration Variables
+ #
+ ARCH="`(arch) 2>/dev/null || ((uname) > /dev/null && uname -a | awk '{ print $6; }') 2>/dev/null || echo 'no-arch'`"
+ KARCH="`(arch -k) 2>/dev/null || ((uname) > /dev/null && uname -a | awk '{ print $5 }') || echo 'no-arch'`"
+ HOSTNAME="`(hostname) 2>/dev/null || uname -n`"
+fi
+
diff --git a/contrib/xntpd/util/Makefile b/contrib/xntpd/util/Makefile
new file mode 100644
index 000000000000..7a36bf305a94
--- /dev/null
+++ b/contrib/xntpd/util/Makefile
@@ -0,0 +1,28 @@
+#
+# $Id: Makefile,v 1.2 1993/12/22 11:33:28 rgrimes Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= tickadj
+MAN8= ${.CURDIR}/../doc/tickadj.8
+CLEANFILES+= .version version.c
+
+SRCS= tickadj.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion tickadj
+
+.include <bsd.prog.mk>
diff --git a/contrib/xntpd/util/README b/contrib/xntpd/util/README
new file mode 100644
index 000000000000..2aedb006834c
--- /dev/null
+++ b/contrib/xntpd/util/README
@@ -0,0 +1,67 @@
+README file for directory ./util of the NTP Version 3 distribution
+
+This directory contains the sources for the various utility programs. See
+the README and RELNOTES files in the parent directory for directions on
+how to make and install these programs.
+
+The ntptime.c program checks the kernel configuration for the NTP user
+interface syscalls ntp_gettime() and ntp_adjtime(). If present, the
+current timekeeping data are displayed. If not, a dissapointment is
+displayed. Do "make ntptime" in this directory to make the thing,
+but be advised that, unless you have installed the kernel support,
+there will probably be missing vital header files. See the README.kern
+file in the doc directory of this distribution for further details.
+
+The jitter.c program can be used to determine the timing jitter due to
+the operating system in a gettimeofday() call. For most systems the
+dominant contribution to the jitter budget is the period of the hardware
+interrupt, usually in the range 1-10 ms. For those systems with microsecond
+counters, such as recent Sun and certain Ultrix systems, the jitter is
+dominated only by the operating system.
+
+The timetrim.c program can be used with SGI machines to implement a
+scheme to discipline the hardware clock frequency. See the source code
+for further information.
+
+The byteorder.c and longsize.c programs are used during the configuration
+process to determine the byte order (little or big endian) and longword
+size (32 or 64 bits). See the ../scripts/makefile.sh script for further
+details.
+
+The testrs6000.c program is used for testing purposes with the IBM
+RS/6000 AIX machines. Bill Jones <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/contrib/xntpd/util/byteorder.c b/contrib/xntpd/util/byteorder.c
new file mode 100644
index 000000000000..665c146153ad
--- /dev/null
+++ b/contrib/xntpd/util/byteorder.c
@@ -0,0 +1,52 @@
+/*
+ * This works on:
+ * Crays
+ * Conven
+ * sparc's
+ * Dec mip machines
+ * Dec alpha machines
+ * RS6000
+ * SGI's
+ */
+
+#include <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/contrib/xntpd/util/jitter.c b/contrib/xntpd/util/jitter.c
new file mode 100644
index 000000000000..7201e87eba2e
--- /dev/null
+++ b/contrib/xntpd/util/jitter.c
@@ -0,0 +1,73 @@
+/*
+ * This program can be used to calibrate the clock reading jitter of a
+ * particular CPU and operating system. It first tickles every element
+ * of an array, in order to force pages into memory, then repeatedly calls
+ * gettimeofday() and, finally, writes out the time values for later
+ * analysis. From this you can determine the jitter and if the clock ever
+ * runs backwards.
+ */
+#include <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/contrib/xntpd/util/kern.c b/contrib/xntpd/util/kern.c
new file mode 100644
index 000000000000..a2a667203a72
--- /dev/null
+++ b/contrib/xntpd/util/kern.c
@@ -0,0 +1,210 @@
+/*
+ * This program simulates a first-order, type-II phase-lock loop using
+ * actual code segments from modified kernel distributions for SunOS,
+ * Ultrix and OSF/1 kernels. These segments do not use any licensed code.
+ */
+#include <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/contrib/xntpd/util/longsize.c b/contrib/xntpd/util/longsize.c
new file mode 100644
index 000000000000..6bdbdfeff5f1
--- /dev/null
+++ b/contrib/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/contrib/xntpd/util/ntptime.c b/contrib/xntpd/util/ntptime.c
new file mode 100644
index 000000000000..c0512df90a87
--- /dev/null
+++ b/contrib/xntpd/util/ntptime.c
@@ -0,0 +1,220 @@
+/*
+ * NTP test program
+ *
+ * This program tests to see if the NTP user interface routines
+ * ntp_gettime() and ntp_adjtime() have been implemented in the kernel.
+ * If so, each of these routines is called to display current timekeeping
+ * data.
+ *
+ * For more information, see the README.kern file in the doc directory
+ * of the xntp3 distribution.
+ */
+#include <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));
+
+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 ntp_optind;
+ extern char *ntp_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 = ntp_getopt(argc, argv, optargs)) != EOF) switch (c) {
+ case 'c':
+ cost++;
+ break;
+ case 'e':
+ ntx.mode |= ADJ_ESTERROR;
+ ntx.esterror = atoi(ntp_optarg);
+ break;
+ case 'f':
+ ntx.mode |= ADJ_FREQUENCY;
+ ntx.frequency = (int) (atof(ntp_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(ntp_optarg);
+ break;
+ case 'o':
+ ntx.mode |= ADJ_OFFSET;
+ ntx.offset = atoi(ntp_optarg);
+ break;
+ case 'r':
+ rawtime++;
+ break;
+ case 's':
+ ntx.mode |= ADJ_STATUS;
+ ntx.status = atoi(ntp_optarg);
+ if (ntx.status < 0 || ntx.status > 4) errflg++;
+ break;
+ case 't':
+ ntx.mode |= ADJ_TIMECONST;
+ ntx.time_constant = atoi(ntp_optarg);
+ if (ntx.time_constant < 0 || ntx.time_constant > MAXTC)
+ errflg++;
+ break;
+ default:
+ errflg++;
+ }
+ if (errflg || (ntp_optind != argc)) {
+ (void) fprintf(stderr,
+ "usage: %s [-%s]\n\n\
+ -c display the time taken to call ntp_gettime (us)\n\
+ -e esterror estimate of the error (us)\n\
+ -f frequency Frequency error (-100 .. 100) (ppm)\n\
+ -h display this help info\n\
+ -m maxerror max possible error (us)\n\
+ -o offset current offset (ms)\n\
+ -r print the unix and NTP time raw\n\
+ -s status Set the status (0 .. 4)\n\
+ -t timeconstant log2 of PLL time constant (0 .. %d)\n",
+ progname, optargs, MAXTC);
+ exit(2);
+ }
+
+
+ /*
+ * Test to make sure the sigvec() works in case of invalid
+ * syscall codes.
+ */
+ newsigsys.sv_handler = pll_trap;
+ newsigsys.sv_mask = 0;
+ newsigsys.sv_flags = 0;
+ if (sigvec(SIGSYS, &newsigsys, &sigsys)) {
+ perror("sigvec() fails to save SIGSYS trap");
+ exit(1);
+ }
+
+#ifdef BADCALL
+ /*
+ * Make sure the trapcatcher works.
+ */
+ pll_control = 1;
+ (void)syscall(BADCALL, &ntv); /* dummy parameter f. ANSI compilers */
+ if (pll_control)
+ printf("sigvec() failed to catch an invalid syscall\n");
+#endif
+
+ if (cost) {
+ for (c=0; c< sizeof times / sizeof times[0]; c++) {
+ (void)ntp_gettime(&ntv);
+ if (pll_control < 0) break;
+ times[c] = ntv.time.tv_usec;
+ }
+ if (pll_control >= 0) {
+ printf("[ usec %06d:", times[0]);
+ for (c=1; c< sizeof times / sizeof times[0]; c++) printf(" %d", times[c] - times[c-1]);
+ printf(" ]\n");
+ }
+ }
+ (void)ntp_gettime(&ntv);
+ ntx.mode = 0; /* Ensure nothing is set */
+ (void)ntp_adjtime(&_ntx);
+ if (pll_control < 0) {
+ printf("NTP user interface routines are not configured in this kernel.\n");
+ goto lexit;
+ }
+
+ /*
+ * Fetch timekeeping data and display.
+ */
+ if ((status = ntp_gettime(&ntv)) < 0)
+ perror("ntp_gettime() call fails");
+ else {
+ printf("ntp_gettime() returns code %d\n", status);
+ TVTOTS(&ntv.time, &ts);
+ ts.l_uf += TS_ROUNDBIT; /* guaranteed not to overflow */
+ ts.l_ui += JAN_1970;
+ ts.l_uf &= TS_MASK;
+ printf(" time: %s, (.%06d)\n",
+ prettydate(&ts), ntv.time.tv_usec);
+ printf(" confidence interval: %ld usec, estimated error: %ld usec\n",
+ ntv.maxerror, ntv.esterror);
+ if (rawtime) printf(" ntptime=%x.%x unixtime=%x.%06d %s",
+ ts.l_ui, ts.l_uf,
+ ntv.time.tv_sec, ntv.time.tv_usec,
+ ctime(&ntv.time.tv_sec));
+ }
+ if ((status = ntp_adjtime(&ntx)) < 0) perror((errno == EPERM) ?
+ ">> Must be root to set kernel values\n>> ntp_adjtime() call fails" :
+ ">> ntp_adjtime() call fails");
+ else {
+ printf("ntp_adjtime() returns code %d\n", status);
+ ftemp = ntx.frequency;
+ ftemp /= (1 << SHIFT_USEC);
+ printf(" mode: %02x, offset: %ld usec, frequency: %6.3f ppm,\n",
+ ntx.mode, ntx.offset, ftemp);
+ printf(" confidence interval: %ld usec, estimated error: %ld usec,\n",
+ ntx.maxerror, ntx.esterror);
+ printf(" status: %d, time constant: %ld, precision: %ld usec, tolerance: %ld usec\n",
+ ntx.status, ntx.time_constant, ntx.precision,
+ ntx.tolerance);
+ }
+
+ /*
+ * Put things back together the way we found them.
+ */
+lexit: if (sigvec(SIGSYS, &sigsys, (struct sigvec *)NULL)) {
+ perror("sigvec() fails to restore SIGSYS trap");
+ exit(1);
+ }
+ exit(0);
+}
+
+/*
+ * pll1_trap - trap processor for undefined syscalls
+ */
+void
+pll_trap()
+{
+ pll_control--;
+}
diff --git a/contrib/xntpd/util/precision.c b/contrib/xntpd/util/precision.c
new file mode 100644
index 000000000000..69af19fb92ec
--- /dev/null
+++ b/contrib/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/contrib/xntpd/util/testrs6000.c b/contrib/xntpd/util/testrs6000.c
new file mode 100644
index 000000000000..9a5e0cd77634
--- /dev/null
+++ b/contrib/xntpd/util/testrs6000.c
@@ -0,0 +1,44 @@
+/* Checks for the RS/6000 AIX adjtime() bug, in which if a negative
+ * offset is given, the system gets messed up and never completes the
+ * adjustment. If the problem is fixed, this program will print the
+ * time, sit there for 10 seconds, and exit. If the problem isn't fixed,
+ * the program will print an occasional "result=nnnnnn" (the residual
+ * slew from adjtime()).
+ *
+ * Compile this with bsdcc and run it as root!
+ */
+#include <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/contrib/xntpd/util/tickadj.c b/contrib/xntpd/util/tickadj.c
new file mode 100644
index 000000000000..ab10b3728a0e
--- /dev/null
+++ b/contrib/xntpd/util/tickadj.c
@@ -0,0 +1,515 @@
+/* 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 *));
+
+/*
+ * main - parse arguments and handle options
+ */
+void
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int c;
+ int errflg = 0;
+ extern int ntp_optind;
+ extern char *ntp_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 = ntp_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(ntp_optarg);
+ if (writetickadj <= 0) {
+ (void) fprintf(stderr,
+ "%s: unlikely value for tickadj: %s\n",
+ progname, ntp_optarg);
+ errflg++;
+ }
+ break;
+ case 'A':
+ writeopttickadj = 1;
+ break;
+ case 's':
+ unsetdosync = 1;
+ break;
+ case 't':
+ writetick = atoi(ntp_optarg);
+ if (writetick <= 0) {
+ (void) fprintf(stderr,
+ "%s: unlikely value for tick: %s\n",
+ progname, ntp_optarg);
+ errflg++;
+ }
+ break;
+ default:
+ errflg++;
+ break;
+ }
+ if (errflg || ntp_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");
+ errflg++;
+ }
+
+ if (unsetdosync && (dosync_offset == 0)) {
+ (void) fprintf(stderr,
+ "No dosynctodr kernal variable\n");
+ errflg++;
+ }
+
+ if (writeopttickadj && (tickadj_offset == 0)) {
+ (void) fprintf(stderr,
+ "No tickadj kernal variable\n");
+ errflg++;
+ }
+
+ if (writetick && (tick_offset == 0)) {
+ (void) fprintf(stderr,
+ "No tick kernal variable\n");
+ errflg++;
+ }
+
+
+ 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(errflg ? 1 : 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(errflg ? 1 : 0);
+}
+
+/*
+ * getoffsets - read the magic offsets from the specified file
+ */
+static char *
+getoffsets(filex, tick_off, tickadj_off, dosync_off, noprintf_off)
+ char *filex;
+ unsigned long *tick_off;
+ unsigned long *tickadj_off;
+ unsigned long *dosync_off;
+ unsigned long *noprintf_off;
+{
+ char **kname;
+
+#if defined(SYS_AUX3) || defined(SYS_AUX2)
+#define X_TICKADJ 0
+#define X_V 1
+#define X_TICK 2
+#define X_DEF
+ static struct nlist nl[4];
+#endif
+
+#ifdef NeXT
+#define X_TICKADJ 0
+#define X_TICK 1
+#define X_DOSYNC 2
+#define X_NOPRINTF 3
+#define X_DEF
+ static struct nlist nl[] =
+ { {{"_tickadj"}},
+ {{"_tick"}},
+ {{"_dosynctodr"}},
+ {{"_noprintf"}},
+ {{""}},
+ };
+#endif
+
+#if defined(SYS_SVR4) || defined(SYS_PTX)
+#define X_TICKADJ 0
+#define X_TICK 1
+#define X_DOSYNC 2
+#define X_NOPRINTF 3
+#define X_DEF
+ static struct nlist nl[] =
+ { {{"tickadj"}},
+ {{"tick"}},
+ {{"doresettodr"}},
+ {{"noprintf"}},
+ {{""}},
+ };
+#endif /* SYS_SVR4 */
+
+#if defined(SOLARIS)||defined(RS6000)||defined(SYS_SINIXM)
+#ifndef SOLARIS_HRTIME
+#define X_TICKADJ 0
+#endif
+#define X_DOSYNC 1
+#define X_NOPRINTF 2
+#define X_DEF
+ static struct nlist nl[] =
+ { {"tickadj"},
+ {"dosynctodr"},
+ {"noprintf"},
+ {""},
+ };
+
+#if defined(RS6000)
+ int i;
+#endif
+#endif
+
+#if !defined(X_DEF)
+#define X_TICKADJ 0
+#define X_TICK 1
+#define X_DOSYNC 2
+#define X_NOPRINTF 3
+ static struct nlist nl[] =
+ { {"_tickadj"},
+ {"_tick"},
+ {"_dosynctodr"},
+ {"_noprintf"},
+ {""},
+ };
+#endif
+ static char *kernels[] = {
+ "/vmunix",
+ "/unix",
+ "/mach",
+ "/kernel/unix",
+ "/386bsd",
+ "/netbsd",
+ NULL
+ };
+ struct stat stbuf;
+
+#if defined(SYS_AUX3) || defined(SYS_AUX2)
+ strcpy (nl[X_TICKADJ].n_name, "tickadj");
+ strcpy (nl[X_V].n_name, "v");
+ strcpy (nl[X_TICK].n_name, "tick");
+ nl[3].n_name[0] = '\0';
+#endif
+
+ for (kname = kernels; *kname != NULL; kname++) {
+ if (stat(*kname, &stbuf) == -1)
+ continue;
+ if (nlist(*kname, nl) >= 0)
+ break;
+ }
+ if (*kname == NULL) {
+ (void) fprintf(stderr,
+ "%s: nlist fails: can't find/read /vmunix or /unix\n",
+ progname);
+ exit(1);
+ }
+
+ if (dokmem)
+ file = kmem;
+ else
+ file = kernel;
+
+ fd = openfile(file, O_RDONLY);
+#if defined(RS6000)
+ /*
+ * Go one more round of indirection.
+ */
+ for (i=0; i<(sizeof(nl)/sizeof(struct nlist)); i++) {
+ if (nl[i].n_value) {
+ readvar(fd, nl[i].n_value, &nl[i].n_value);
+ }
+ }
+#endif
+ *tickadj_off = 0;
+ *tick_off = 0;
+ *dosync_off = 0;
+ *noprintf_off = 0;
+
+#if defined(X_TICKADJ)
+ *tickadj_off = nl[X_TICKADJ].n_value;
+#endif
+
+#if defined(X_TICK)
+ *tick_off = nl[X_TICK].n_value;
+#endif
+
+#if defined(X_DOSYNC)
+ *dosync_off = nl[X_DOSYNC].n_value;
+#endif
+
+#if defined(X_NOPRINTF)
+ *noprintf_off = nl[X_NOPRINTF].n_value;
+#endif
+ return *kname;
+}
+
+#undef X_TICKADJ
+#undef X_TICK
+#undef X_DOSYNC
+#undef X_NOPRINTF
+
+
+/*
+ * openfile - open the file, check for errors
+ */
+static int
+openfile(name, mode)
+ char *name;
+ int mode;
+{
+ int fd;
+
+ fd = open(name, mode);
+ if (fd < 0) {
+ (void) fprintf(stderr, "%s: open %s: ", progname, name);
+ perror("");
+ exit(1);
+ }
+ return fd;
+}
+
+
+/*
+ * writevar - write a variable into the file
+ */
+static void
+writevar(fd, off, var)
+ int fd;
+ unsigned long off;
+ int var;
+{
+
+ if (lseek(fd, off, L_SET) == -1) {
+ (void) fprintf(stderr, "%s: lseek fails: ", progname);
+ perror("");
+ exit(1);
+ }
+ if (write(fd, (char *)&var, sizeof(int)) != sizeof(int)) {
+ (void) fprintf(stderr, "%s: write fails: ", progname);
+ perror("");
+ exit(1);
+ }
+}
+
+
+/*
+ * readvar - read a variable from the file
+ */
+static void
+readvar(fd, off, var)
+ int fd;
+ unsigned long off;
+ int *var;
+{
+ int i;
+
+ if (lseek(fd, off, L_SET) == -1) {
+ (void) fprintf(stderr, "%s: lseek fails: ", progname);
+ perror("");
+ exit(1);
+ }
+ i = read(fd, (char *)var, sizeof(int));
+ if (i < 0) {
+ (void) fprintf(stderr, "%s: read fails: ", progname);
+ perror("");
+ exit(1);
+ }
+ if (i != sizeof(int)) {
+ (void) fprintf(stderr, "%s: read expected %d, got %d\n",
+ progname, sizeof(int), i);
+ exit(1);
+ }
+}
diff --git a/contrib/xntpd/util/timetrim.c b/contrib/xntpd/util/timetrim.c
new file mode 100644
index 000000000000..052a587a7dff
--- /dev/null
+++ b/contrib/xntpd/util/timetrim.c
@@ -0,0 +1,85 @@
+/*
+ * timetrim.c,v 3.1 1993/07/06 01:11:06 jbj Exp
+ *
+ * "timetrim" allows setting and adjustment of the system clock frequency
+ * trim parameter on Silicon Graphics machines. The trim value native
+ * units are nanoseconds per second (10**-9), so a trim value of 1 makes
+ * the system clock step ahead 1 nanosecond more per second than a value
+ * of zero. Xntpd currently uses units of 2**-20 secs for its frequency
+ * offset (drift) values; to convert to a timetrim value, multiply by
+ * 1E9 / 2**20 (about 954).
+ *
+ * "timetrim" with no arguments just prints out the current kernel value.
+ * With a numeric argument, the kernel value is set to the supplied value.
+ * The "-i" flag causes the supplied value to be added to the kernel value.
+ * The "-n" option causes all input and output to be in xntpd units rather
+ * than timetrim native units.
+ *
+ * Note that there is a limit of +-3000000 (0.3%) on the timetrim value
+ * which is (silently?) enforced by the kernel.
+ *
+ */
+
+#include <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/contrib/xntpd/xntpd/Makefile b/contrib/xntpd/xntpd/Makefile
new file mode 100644
index 000000000000..56f5dc2eb6eb
--- /dev/null
+++ b/contrib/xntpd/xntpd/Makefile
@@ -0,0 +1,45 @@
+#
+# $Id: Makefile,v 1.4 1994/02/03 23:23:17 wollman Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= ${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= ${.CURDIR}/../lib/libntp.a
+.endif
+
+.if exists(${.CURDIR}/../parse/obj)
+LDADD+= -L${.CURDIR}/../parse/obj
+DPADD+= ${.CURDIR}/../parse/obj/libparse.a
+.else
+LDADD+= -L${.CURDIR}/../parse
+DPADD+= ${.CURDIR}/../parse/libparse.a
+.endif
+
+LDADD+= -lntp -lparse
+
+PROG= xntpd
+MAN8= ${.CURDIR}/../doc/xntpd.8
+CLEANFILES+= .version version.c
+
+SRCS= 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 refclock_gpstm.c ntp_intres.c \
+ ntp_filegen.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion xntpd
+
+.include <bsd.prog.mk>
diff --git a/contrib/xntpd/xntpd/README b/contrib/xntpd/xntpd/README
new file mode 100644
index 000000000000..45512762d187
--- /dev/null
+++ b/contrib/xntpd/xntpd/README
@@ -0,0 +1,6 @@
+README file for directory ./xntpd of the NTP Version 3 distribution
+
+This directory contains the sources for the xntpd daemon for Unix. See
+the README and RELNOTES files in the parent directory for directions on
+how to make and install this program. The current version number of this
+program is in the version.c file.
diff --git a/contrib/xntpd/xntpd/ntp_config.c b/contrib/xntpd/xntpd/ntp_config.c
new file mode 100644
index 000000000000..1b716f69fab5
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_config.c
@@ -0,0 +1,1878 @@
+/*
+ * 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 CONFIG_SETVAR 27
+
+#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 },
+ { "setvar", CONFIG_SETVAR },
+ { "", 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:v:V:";
+
+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 ntp_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 ntp_getopt() is explicitly reusable, by the
+ * way. Your own mileage may vary.
+ */
+ errflg = 0;
+ progname = argv[0];
+
+ /*
+ * Decode argument list
+ */
+ while ((c = ntp_getopt(argc, argv, xntp_options)) != EOF)
+ switch (c) {
+ case 'd':
+ ++debug;
+ break;
+ case '?':
+ ++errflg;
+ break;
+ default:
+ break;
+ }
+
+ if (errflg || ntp_optind != argc) {
+ (void) fprintf(stderr, "usage: %s [ -abd ] [ -c config_file ] [ -e encryption delay ]\n", progname);
+ (void) fprintf(stderr, "\t\t[ -f frequency file ] [ -k key file ] [ -l log file ]\n");
+ (void) fprintf(stderr, "\t\t[ -p pid file ] [ -r broadcast delay ] [ -s status directory ]\n");
+ (void) fprintf(stderr, "\t\t[ -t trusted key ] [ -v sys variable ] [ -V default sys variable ]\n");
+ exit(2);
+ }
+ ntp_optind = 0; /* reset ntp_optind to restart ntp_getopt */
+
+ 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 ntp_optind;
+ extern char *ntp_optarg;
+ extern char *Version;
+ 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;
+
+ /*
+ * install a non default variable with this daemon version
+ */
+ (void) sprintf(line, "daemon_version=\"%s\"", Version);
+ set_sys_var(line, strlen(line)+1, RO);
+
+#ifdef RESOLVE_INTERNAL
+ resolve_internal = 1;
+#endif
+
+ /*
+ * Decode argument list
+ */
+ while ((c = ntp_getopt(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 = ntp_optarg;
+ break;
+ case 'd':
+#ifdef DEBUG
+ debug++;
+#else
+ errflg++;
+#endif /* DEBUG */
+ break;
+
+ case 'e':
+ do {
+ l_fp tmp;
+
+ if (!atolfp(ntp_optarg, &tmp)) {
+ syslog(LOG_ERR,
+ "command line encryption delay value %s undecodable",
+ ntp_optarg);
+ errflg++;
+ } else if (tmp.l_ui != 0) {
+ syslog(LOG_ERR,
+ "command line encryption delay value %s is unlikely",
+ ntp_optarg);
+ errflg++;
+ } else {
+ proto_config(PROTO_AUTHDELAY, tmp.l_f);
+ }
+ } while (0);
+ break;
+
+ case 'f':
+ stats_config(STATS_FREQ_FILE, ntp_optarg);
+ break;
+
+ case 'k':
+ getauthkeys(ntp_optarg);
+ if ((int)strlen(ntp_optarg) >= MAXFILENAME) {
+ syslog(LOG_ERR,
+ "key file name too LONG (>%d, sigh), no name resolution possible",
+ MAXFILENAME);
+ } else {
+ have_keyfile = 1;
+ (void)strcpy(keyfile, ntp_optarg);
+ }
+ break;
+
+ case 'p':
+ stats_config(STATS_PID_FILE, ntp_optarg);
+ break;
+
+ case 'r':
+ do {
+ l_fp tmp;
+
+ if (!atolfp(ntp_optarg, &tmp)) {
+ syslog(LOG_ERR,
+ "command line broadcast delay value %s undecodable",
+ ntp_optarg);
+ } else if (tmp.l_ui != 0) {
+ syslog(LOG_ERR,
+ "command line broadcast delay value %s is unlikely",
+ ntp_optarg);
+ } else {
+ proto_config(PROTO_BROADDELAY, tmp.l_f);
+ }
+ } while (0);
+ break;
+
+ case 's':
+ stats_config(STATS_STATSDIR, ntp_optarg);
+ break;
+
+ case 't':
+ do {
+ int tkey;
+
+ tkey = atoi(ntp_optarg);
+ if (tkey <= 0 || tkey > NTP_MAXKEY) {
+ syslog(LOG_ERR,
+ "command line trusted key %s is unlikely",
+ ntp_optarg);
+ } else {
+ authtrust(tkey, (LONG)1);
+ }
+ } while (0);
+ break;
+
+ case 'v':
+ case 'V':
+ set_sys_var(ntp_optarg, strlen(ntp_optarg)+1, RW | ((c == 'V') ? DEF : 0));
+ break;
+
+ default:
+ errflg++;
+ break;
+ }
+ }
+
+ if (errflg || ntp_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;
+ }
+
+ memset((char *)&clock, 0, 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;
+
+ case CONFIG_SETVAR:
+ if (ntokens < 2)
+ {
+ syslog(LOG_ERR,
+ "no value for setvar command - line ignored");
+ }
+ else
+ {
+ set_sys_var(tokens[1], strlen(tokens[1])+1, RW |
+ ((((ntokens > 2) && !strcmp(tokens[2], "default"))) ? DEF : 0));
+ }
+ 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;
+ register int quoted = 0;
+
+ /*
+ * Find start of first token
+ */
+again:
+ while ((cp = fgets(line, MAXLINE, fp)) != NULL) {
+ cp = line;
+ while (ISSPACE(*cp))
+ cp++;
+ if (!ISEOL(*cp))
+ break;
+ }
+ if (cp == NULL) {
+ *ntokens = 0;
+ return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */
+ }
+
+ /*
+ * Now separate out the tokens
+ */
+ eol = 0;
+ ntok = 0;
+ while (!eol) {
+ tokenlist[ntok++] = cp;
+ while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted))
+ quoted ^= (*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.
+ */
+ memset((char *)addr, 0, sizeof(struct sockaddr_in));
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(NTP_PORT);
+ addr->sin_addr.s_addr = htonl(netnum);
+#ifdef DEBUG
+ if (debug > 1)
+ printf("getnetnum given %s, got %s (%x)\n",
+ num, ntoa(addr), netnum);
+#endif
+ return 1;
+}
+
+
+/*
+ * catchchild - receive the resolver's exit status
+ */
+static RETSIGTYPE
+catchchild(sig)
+int sig;
+{
+ /*
+ * We only start up one child, and if we're here
+ * it should have already exited. Hence the following
+ * shouldn't hang. If it does, please tell me.
+ */
+ (void) wait(0);
+}
+
+
+/*
+ * save_resolve - save configuration info into a file for later name resolution
+ */
+static void
+save_resolve(name, mode, version, minpoll, maxpoll, flags, keyid)
+ char *name;
+ int mode;
+ int version;
+ int minpoll;
+ int maxpoll;
+ int flags;
+ U_LONG keyid;
+{
+ if (res_fp == NULL) {
+ (void) strcpy(res_file, RES_TEMPFILE);
+ (void) mktemp(res_file);
+ res_fp = fopen(res_file, "w");
+ if (res_fp == NULL) {
+ syslog(LOG_ERR, "open failed for %s: %m", res_file);
+ return;
+ }
+ }
+
+#ifdef DEBUG
+ if (debug) {
+ printf("resolving %s\n", name);
+ }
+#endif
+
+ (void) fprintf(res_fp, "%s %d %d %d %d %d %lu\n", name, mode,
+ version, minpoll, maxpoll, flags, keyid);
+}
+
+
+/*
+ * abort_resolve - terminate the resolver stuff and delete the file
+ */
+static void
+abort_resolve()
+{
+ /*
+ * In an ideal world we would might reread the file and
+ * log the hosts which aren't getting configured. Since
+ * this is too much work, however, just close and delete
+ * the temp file.
+ */
+ if (res_fp != NULL)
+ (void) fclose(res_fp);
+ res_fp = NULL;
+
+ (void) unlink(res_file);
+}
+
+
+/*
+ * do_resolve - start up the resolver program
+ */
+static void
+do_resolve(program, auth_keyid, keyfile)
+ char *program;
+ U_LONG auth_keyid;
+ char *keyfile;
+{
+ register LONG i;
+ register char **ap;
+ /* 1 progname + 5 -d's + 1 -r + keyid + keyfile + tempfile + 1 */
+ char *argv[15];
+ char numbuf[15];
+ /*
+ * Clean environment so the resolver is consistant
+ */
+ static char *resenv[] = {
+ "HOME=/",
+ "SHELL=/bin/sh",
+ "TERM=dumb",
+ "USER=root",
+ NULL
+ };
+
+ if (res_fp == NULL) {
+ /* belch */
+ syslog(LOG_ERR, "internal error in do_resolve: res_fp == NULL");
+ exit(1);
+ }
+ (void) fclose(res_fp);
+ res_fp = NULL;
+
+ ap = argv;
+ *ap++ = program;
+
+ /*
+ * xntpres [-d ...] -r key# keyfile tempfile
+ */
+#ifdef DEBUG
+ i = debug;
+ if (i > 5)
+ i = 5;
+ while (i-- > 0)
+ *ap++ = "-d";
+#endif
+ *ap++ = "-r";
+
+ (void) sprintf(numbuf, "%lu", auth_keyid);
+ *ap++ = numbuf;
+ *ap++ = keyfile;
+ *ap++ = res_file;
+ *ap = NULL;
+
+ (void) signal_no_reset(SIGCHLD, catchchild);
+
+ i = fork();
+ if (i == 0) {
+ /*
+ * In child here, close up all descriptors and
+ * exec the resolver program. Close the syslog()
+ * facility gracefully in case we must reopen it.
+ */
+ (void) signal(SIGCHLD, SIG_DFL);
+ closelog();
+#if defined(NTP_POSIX_SOURCE) && !defined(SYS_386BSD)
+ i = sysconf(_SC_OPEN_MAX);
+#else
+ i = getdtablesize();
+#endif
+#ifdef DEBUG
+ while (i-- > 2)
+#else
+ while (i-- > 0)
+#endif
+ (void) close(i);
+ (void) execve(program, argv, resenv);
+
+ /*
+ * If we got here, the exec screwed up. Open the log file
+ * and print something so we don't die without complaint
+ */
+#ifndef LOG_DAEMON
+ openlog("xntpd", LOG_PID);
+#else
+#ifndef LOG_NTP
+#define LOG_NTP LOG_DAEMON
+#endif
+ openlog("xntpd", LOG_PID | LOG_NDELAY, LOG_NTP);
+#endif /* LOG_DAEMON */
+ syslog(LOG_ERR, "exec of resolver %s failed!", program);
+ abort_resolve();
+ exit(1);
+ }
+
+ if (i == -1) {
+ syslog(LOG_ERR, "fork() failed, can't start %s", program);
+ (void) signal_no_reset(SIGCHLD, SIG_DFL);
+ abort_resolve();
+ }
+}
+
+
+#ifdef RESOLVE_INTERNAL
+
+#define KEY_TYPE_ASCII 3
+
+/*
+ * do_resolve_internal - start up the resolver function (not program)
+ */
+static void
+do_resolve_internal()
+{
+ int i;
+
+ extern U_LONG req_keyid; /* request keyid */
+ extern char *req_file; /* name of the file with configuration info */
+ extern U_LONG info_auth_keyid;
+
+ if (res_fp == NULL) {
+ /* belch */
+ syslog(LOG_ERR, "internal error in do_resolve_internal: res_fp == NULL");
+ exit(1);
+ }
+
+ /* we are done with this now */
+ (void) fclose(res_fp);
+ res_fp = NULL;
+
+ /* find a keyid */
+ if (info_auth_keyid == 0)
+ req_keyid = 65535;
+ else
+ req_keyid = info_auth_keyid;
+
+ /* if doesn't exist, make up one at random */
+ if ( ! authhavekey(req_keyid) )
+ {
+ char rankey[9];
+ struct timeval now;
+
+ /* generate random key */
+ GETTIMEOFDAY(&now, (struct timezone *)0);
+ srand(now.tv_sec * now.tv_usec);
+
+ for ( i = 0; i < 8; i++ )
+ rankey[i] = (rand() % 255) + 1;
+ rankey[8] = 0;
+
+ authusekey(req_keyid, KEY_TYPE_ASCII, rankey);
+ }
+
+ /* save keyid so we will accept config requests with it */
+ info_auth_keyid = req_keyid;
+
+ req_file = res_file; /* set up pointer to res file */
+
+ (void) signal_no_reset(SIGCHLD, catchchild);
+
+ i = fork();
+ if (i == 0) {
+ /* this used to close everything
+ * I don't think this is necessary */
+ (void) signal_no_reset(SIGCHLD, SIG_DFL);
+
+ ntp_intres();
+
+ /*
+ * If we got here, the intres code screwed up.
+ * Print something so we don't die without complaint
+ */
+ syslog(LOG_ERR, "call to ntp_intres lost");
+ abort_resolve();
+ exit(1);
+ }
+
+ if (i == -1) {
+ syslog(LOG_ERR, "fork() failed, can't start ntp_intres");
+ (void) signal_no_reset(SIGCHLD, SIG_DFL);
+ abort_resolve();
+ }
+}
+#endif
diff --git a/contrib/xntpd/xntpd/ntp_control.c b/contrib/xntpd/xntpd/ntp_control.c
new file mode 100644
index 000000000000..1c7849f48820
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_control.c
@@ -0,0 +1,2658 @@
+/*
+ * 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 unsigned long count_var P((struct ctl_var *));
+static void control_unspec P((struct recvbuf *, int));
+static void read_status P((struct recvbuf *, int));
+static void read_variables P((struct recvbuf *, int));
+static void write_variables P((struct recvbuf *, int));
+static void read_clock_status P((struct recvbuf *, int));
+static void write_clock_status P((struct recvbuf *, int));
+static void set_trap P((struct recvbuf *, int));
+static void unset_trap P((struct recvbuf *, int));
+static struct ctl_trap *ctlfindtrap P((struct sockaddr_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 }
+};
+
+/*
+ * 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_VARLIST, RO, "sys_var_list" },/* 20 */
+ { 0, EOV, "" }
+};
+
+static struct ctl_var *ext_sys_var = (struct ctl_var *)0;
+
+/*
+ * System variables we print by default (in fuzzball order, more-or-less)
+ */
+static u_char def_sys_var[] = {
+ CS_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,
+ 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 */
+ { CP_DISP, PADDING,"" }, /* 35 */
+ { CP_VARLIST, RO, "peer_var_list" }, /* 36 */
+ { 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 */
+ { CC_VARLIST, RO, "clock_var_list" },/* 13 */
+ { 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.
+ */
+#include <sys/utsname.h>
+static struct utsname utsname;
+
+/*
+ * 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;
+
+ uname(&utsname);
+
+ 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);
+ }
+
+ memmove((char *)datapt, dp, 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;
+ memmove(cp, data, 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;
+{
+ 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, utsname.machine,
+ strlen(utsname.machine));
+ break;
+ case CS_SYSTEM:
+ ctl_putstr(sys_var[CS_SYSTEM].text, utsname.sysname,
+ strlen(utsname.sysname));
+ 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_VARLIST:
+ {
+ char buf[CTL_MAX_DATA_LEN];
+ register char *s, *ss, *t, *be;
+ register int i;
+ register struct ctl_var *k;
+
+ s = buf;
+ be = buf + sizeof(buf) - strlen(sys_var[CS_VARLIST].text) - 4;
+ if (s > be)
+ break; /* really long var name 8-( - Killer */
+
+ strcpy(s, sys_var[CS_VARLIST].text);
+ strcat(s, "=\"");
+ s += strlen(s);
+ t = s;
+
+ for (k = sys_var; !(k->flags &EOV); k++)
+ {
+ if (k->flags & PADDING)
+ continue;
+
+ i = strlen(k->text);
+ if (s+i+1 >= be)
+ break;
+ if (s != t)
+ *s++ = ',';
+ strcpy(s, k->text);
+ s += i;
+ }
+
+ for (k = ext_sys_var; k && !(k->flags &EOV); k++)
+ {
+ if (k->flags & PADDING)
+ continue;
+
+ ss = k->text;
+ if (!ss)
+ continue;
+
+ while (*ss && *ss != '=')
+ ss++;
+
+ i = ss - k->text;
+ if (s+i+1 >= be)
+ break;
+ if (s != t)
+ *s++ = ',';
+ strncpy(s, k->text, i);
+ s += i;
+ }
+
+ if (s+2 >= be)
+ break;
+
+ *s++ = '"';
+ *s = '\0';
+
+ ctl_putdata(buf, s - buf, 0);
+ }
+ 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;
+ case CP_VARLIST:
+ {
+ char buf[CTL_MAX_DATA_LEN];
+ register char *s, *t, *be;
+ register int i;
+ register struct ctl_var *k;
+
+ s = buf;
+ be = buf + sizeof(buf) - strlen(peer_var[CP_VARLIST].text) - 4;
+ if (s > be)
+ break; /* really long var name 8-( - Killer */
+
+ strcpy(s, peer_var[CP_VARLIST].text);
+ strcat(s, "=\"");
+ s += strlen(s);
+ t = s;
+
+ for (k = peer_var; !(k->flags &EOV); k++)
+ {
+ if (k->flags & PADDING)
+ continue;
+
+ i = strlen(k->text);
+ if (s+i+1 >= be)
+ break;
+ if (s != t)
+ *s++ = ',';
+ strcpy(s, k->text);
+ s += i;
+ }
+
+ if (s+2 >= be)
+ break;
+
+ *s++ = '"';
+ *s = '\0';
+
+ ctl_putdata(buf, s - buf, 0);
+ }
+ 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;
+ case CC_VARLIST:
+ {
+ char buf[CTL_MAX_DATA_LEN];
+ register char *s, *ss, *t, *be;
+ register int i;
+ register struct ctl_var *k;
+
+ s = buf;
+ be = buf + sizeof(buf) - strlen(clock_var[CC_VARLIST].text) - 4;
+ if (s > be)
+ break; /* really long var name 8-( - Killer */
+
+ strcpy(s, clock_var[CC_VARLIST].text);
+ strcat(s, "=\"");
+ s += strlen(s);
+ t = s;
+
+ for (k = clock_var; !(k->flags &EOV); k++)
+ {
+ if (k->flags & PADDING)
+ continue;
+
+ i = strlen(k->text);
+ if (s+i+1 >= be)
+ break;
+ if (s != t)
+ *s++ = ',';
+ strcpy(s, k->text);
+ s += i;
+ }
+
+ for (k = clock->kv_list; k && !(k->flags &EOV); k++)
+ {
+ if (k->flags & PADDING)
+ continue;
+
+ ss = k->text;
+ if (!ss)
+ continue;
+
+ while (*ss && *ss != '=')
+ ss++;
+
+ i = ss - k->text;
+ if (s+i+1 >= be)
+ break;
+ if (s != t)
+ *s++ = ',';
+ strncpy(s, k->text, i);
+ s += i;
+ *s = '\0';
+ }
+
+ if (s+2 >= be)
+ break;
+
+ *s++ = '"';
+ *s = '\0';
+
+ ctl_putdata(buf, s - buf, 0);
+ }
+ 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 struct ctl_var eol = { 0, EOV, };
+ static char buf[128];
+
+ /*
+ * Delete leading commas and white space
+ */
+ while (reqpt < reqend && (*reqpt == ',' || isspace(*reqpt))) {
+ reqpt++;
+ }
+
+ if (reqpt >= reqend)
+ return 0;
+
+ if (var_list == (struct ctl_var *)0)
+ return &eol;
+
+ /*
+ * Look for a first character match on the tag. If we find
+ * one, see if it is a full match.
+ */
+ v = var_list;
+ cp = reqpt;
+ while (!(v->flags & EOV)) {
+ if (!(v->flags & PADDING) && *cp == *(v->text)) {
+ tp = v->text;
+ while (*tp != '\0' && *tp != '=' && cp < reqend && *cp == *tp) {
+ cp++;
+ tp++;
+ }
+ if ((*tp == '\0') || (*tp == '=')) {
+ while (cp < reqend && isspace(*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;
+ int gotvar = (CS_MAXCODE>CP_MAXCODE) ? (CS_MAXCODE+1) : (CP_MAXCODE+1);
+
+ if (res_associd == 0) {
+ /*
+ * Wants system variables. Figure out which he wants
+ * and give them to him.
+ */
+ rpkt.status = htons(ctlsysstatus());
+ if (res_authokay)
+ ctl_sys_num_events = 0;
+ gotvar += count_var(ext_sys_var);
+ wants = (u_char *)emalloc(gotvar);
+ memset((char *)wants, 0, gotvar);
+ gotvar = 0;
+ while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
+ if (v->flags & EOV) {
+ if ((v = ctl_getitem(ext_sys_var, &valuep)) != 0) {
+ if (v->flags & EOV) {
+ ctl_error(CERR_UNKNOWNVAR);
+ free((char *)wants);
+ return;
+ }
+ wants[CS_MAXCODE+1+v->code] = 1;
+ gotvar = 1;
+ continue;
+ } else {
+ break; /* shouldn't happen ! */
+ }
+ }
+ wants[v->code] = 1;
+ gotvar = 1;
+ }
+ if (gotvar) {
+ for (i = 1; i <= CS_MAXCODE; i++)
+ if (wants[i])
+ ctl_putsys(i);
+ for (i = 0; ext_sys_var && !(ext_sys_var[i].flags & EOV); i++)
+ if (wants[i+CS_MAXCODE+1])
+ ctl_putdata(ext_sys_var[i].text,
+ strlen(ext_sys_var[i].text), 0);
+ } else {
+ register u_char *cs;
+ register struct ctl_var *kv;
+
+ for (cs = def_sys_var; *cs != 0; cs++)
+ ctl_putsys((int)*cs);
+ for (kv = ext_sys_var; kv && !(kv->flags & EOV); kv++)
+ if (kv->flags & DEF)
+ ctl_putdata(kv->text, strlen(kv->text), 0);
+ }
+ free((char *)wants);
+ } else {
+ register struct peer *peer;
+
+ /*
+ * Wants info for a particular peer. See if we know
+ * the guy.
+ */
+ peer = findpeerbyassoc((int)res_associd);
+ if (peer == 0) {
+ ctl_error(CERR_BADASSOC);
+ return;
+ }
+
+ rpkt.status = htons(ctlpeerstatus(peer));
+ if (res_authokay)
+ peer->num_events = 0;
+ wants = (u_char *)emalloc(gotvar);
+ memset((char*)wants, 0, gotvar);
+ gotvar = 0;
+ while ((v = ctl_getitem(peer_var, &valuep)) != 0) {
+ if (v->flags & EOV) {
+ ctl_error(CERR_UNKNOWNVAR);
+ free((char *)wants);
+ return;
+ }
+ wants[v->code] = 1;
+ gotvar = 1;
+ }
+ if (gotvar) {
+ for (i = 1; i <= CP_MAXCODE; i++)
+ if (wants[i])
+ ctl_putpeer(i, peer);
+ } else {
+ register u_char *cp;
+
+ for (cp = def_peer_var; *cp != 0; cp++)
+ ctl_putpeer((int)*cp, peer);
+ }
+ free((char *)wants);
+ }
+ ctl_flushpkt(0);
+}
+
+
+/*
+ * write_variables - write into variables. We only allow leap bit writing
+ * this way.
+ */
+/*ARGSUSED*/
+static void
+write_variables(rbufp, restrict)
+ struct recvbuf *rbufp;
+ int restrict;
+{
+ register struct ctl_var *v;
+ register int ext_var;
+ 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) {
+ ext_var = 0;
+ if (v->flags & EOV) {
+ if ((v = ctl_getitem(ext_sys_var, &valuep)) != 0) {
+ if (v->flags & EOV) {
+ ctl_error(CERR_UNKNOWNVAR);
+ return;
+ }
+ ext_var = 1;
+ } else {
+ break;
+ }
+ }
+ if (!(v->flags & CAN_WRITE)) {
+ ctl_error(CERR_PERMISSION);
+ return;
+ }
+ if (!ext_var && (*valuep == '\0' || !atoint(valuep, &val))) {
+ ctl_error(CERR_BADFMT);
+ return;
+ }
+ if (!ext_var && (val & ~LEAP_NOTINSYNC) != 0) {
+ ctl_error(CERR_BADVALUE);
+ return;
+ }
+
+ if (ext_var) {
+ char *s = emalloc(strlen(v->text)+strlen(valuep)+2);
+ char *t, *tt = s;
+
+ t = v->text;
+ while (*t && *t != '=')
+ *tt++ = *t++;
+
+ *tt++ = '=';
+ strcat(tt, valuep);
+
+ set_sys_var(s, strlen(s)+1, v->flags);
+ free(s);
+ } else {
+ /*
+ * This one seems sane. Save it.
+ */
+ switch(v->code) {
+ case CS_LEAP:
+ 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;
+ 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.
+ */
+ clock.kv_list = (struct ctl_var *)0;
+
+ refclock_control(&peer->srcadr, (struct refclockstat *)0, &clock);
+
+ /*
+ * Look for variables in the packet.
+ */
+ rpkt.status = htons(ctlclkstatus(&clock));
+ gotvar = CC_MAXCODE+1+count_var(clock.kv_list);
+ wants = (u_char *)emalloc(gotvar);
+ memset((char*)wants, 0, gotvar);
+ gotvar = 0;
+ while ((v = ctl_getitem(clock_var, &valuep)) != 0) {
+ if (v->flags & EOV) {
+ if ((v = ctl_getitem(clock.kv_list, &valuep)) != 0) {
+ if (v->flags & EOV) {
+ ctl_error(CERR_UNKNOWNVAR);
+ free((char*)wants);
+ free_varlist(clock.kv_list);
+ return;
+ }
+ wants[CC_MAXCODE+1+v->code] = 1;
+ gotvar = 1;
+ continue;
+ } else {
+ break; /* shouldn't happen ! */
+ }
+ }
+ wants[v->code] = 1;
+ gotvar = 1;
+ }
+
+ if (gotvar) {
+ for (i = 1; i <= CC_MAXCODE; i++)
+ if (wants[i])
+ ctl_putclock(i, &clock, 1);
+ for (i = 0; clock.kv_list && !(clock.kv_list[i].flags & EOV); i++)
+ if (wants[i+CC_MAXCODE+1])
+ ctl_putdata(clock.kv_list[i].text,
+ strlen(clock.kv_list[i].text), 0);
+ } else {
+ register u_char *cc;
+ register struct ctl_var *kv;
+
+ for (cc = def_clock_var; *cc != 0; cc++)
+ ctl_putclock((int)*cc, &clock, 0);
+ for (kv = clock.kv_list; kv && !(kv->flags & EOV); kv++)
+ if (kv->flags & DEF)
+ ctl_putdata(kv->text, strlen(kv->text), 0);
+ }
+
+ free((char*)wants);
+ free_varlist(clock.kv_list);
+
+ 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;
+ struct ctl_var *kv;
+
+ clock.kv_list = (struct ctl_var *)0;
+
+ 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);
+ for (kv = clock.kv_list; kv && !(kv->flags & EOV); kv++)
+ if (kv->flags & DEF)
+ ctl_putdata(kv->text, strlen(kv->text), 0);
+
+ free_varlist(clock.kv_list);
+ }
+#endif /*REFCLOCK*/
+ } else {
+ rpkt.associd = htons(peer->associd);
+ rpkt.status = htons(ctlpeerstatus(peer));
+
+ /*
+ * Dump it all. Later, maybe less.
+ */
+ for (i = 1; i <= CP_MAXCODE; i++)
+ 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;
+ struct ctl_var *kv;
+
+ clock.kv_list = (struct ctl_var *)0;
+
+ 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);
+ for (kv = clock.kv_list; kv && !(kv->flags & EOV); kv++)
+ if (kv->flags & DEF)
+ ctl_putdata(kv->text, strlen(kv->text), 0);
+
+ free_varlist(clock.kv_list);
+ }
+#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;
+}
+
+static unsigned long
+count_var(k)
+ struct ctl_var *k;
+{
+ register unsigned long c;
+
+ c = 0;
+ while (k && !(k++->flags & EOV))
+ c++;
+
+ return c;
+}
+
+char *
+add_var(kv, size, def)
+ struct ctl_var **kv;
+ unsigned long size;
+ int def;
+{
+ register unsigned long c;
+ register struct ctl_var *k;
+
+ c = count_var(*kv);
+
+ k = *kv;
+ *kv = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var));
+ if (k)
+ {
+ memmove((char *)*kv, (char *)k, sizeof(struct ctl_var)*c);
+ free((char *)k);
+ }
+
+ (*kv)[c].code = c;
+ (*kv)[c].text = (char *)emalloc(size);
+ (*kv)[c].flags = def;
+ (*kv)[c+1].code = 0;
+ (*kv)[c+1].text = (char *)0;
+ (*kv)[c+1].flags = EOV;
+ return (*kv)[c].text;
+}
+
+void
+set_var(kv, data, size, def)
+ struct ctl_var **kv;
+ char *data;
+ unsigned long size;
+ int def;
+{
+ register struct ctl_var *k;
+ register char *s, *t;
+
+ if (!data || !size)
+ return;
+
+ if ((k = *kv))
+ {
+ while (!(k->flags & EOV))
+ {
+ s = data;
+ t = k->text;
+ if (t)
+ {
+ while (*t != '=' && *s - *t == 0)
+ {
+ s++;
+ t++;
+ }
+ if (*s == *t && ((*t == '=') || !*t))
+ {
+ free(k->text);
+ k->text = (char *)emalloc(size);
+ memmove(k->text, data, size);
+ k->flags = def;
+ return;
+ }
+ }
+ else
+ {
+ k->text = (char *)emalloc(size);
+ memmove(k->text, data, size);
+ k->flags = def;
+ return;
+ }
+ k++;
+ }
+ }
+ t = add_var(kv, size, def);
+ memmove(t, data, size);
+}
+
+void
+set_sys_var(data, size, def)
+ char *data;
+ unsigned long size;
+ int def;
+{
+ set_var(&ext_sys_var, data, size, def);
+}
+
+void
+free_varlist(kv)
+ struct ctl_var *kv;
+{
+ struct ctl_var *k;
+ if (kv)
+ {
+ for (k = kv; !(k->flags & EOV); k++)
+ free(k->text);
+ free((char *)kv);
+ }
+}
diff --git a/contrib/xntpd/xntpd/ntp_filegen.c b/contrib/xntpd/xntpd/ntp_filegen.c
new file mode 100644
index 000000000000..55cf1aebab13
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_filegen.c
@@ -0,0 +1,536 @@
+/*
+ * ntp_filegen.c,v 3.12 1994/01/25 19:06:11 kardel Exp
+ *
+ * implements file generations support for NTP
+ * logfiles and statistic files
+ *
+ *
+ * Copyright (c) 1992
+ * 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/contrib/xntpd/xntpd/ntp_intres.c b/contrib/xntpd/xntpd/ntp_intres.c
new file mode 100644
index 000000000000..20561e91b82d
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_intres.c
@@ -0,0 +1,793 @@
+/* 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);
+ memmove(cp, name, 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.
+ */
+ memmove((char *)&(entry->ce_peeraddr),
+ (char *)hp->h_addr,
+ 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);
+ }
+
+ memset((char *)&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons(NTP_PORT); /* trash */
+ saddr.sin_addr.s_addr = htonl(LOCALHOST); /* garbage */
+
+ /*
+ * Make the socket non-blocking. We'll wait with select()
+ */
+#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
+ */
+ memset((char *)&reqpkt, 0, 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));
+ memmove(reqpkt.data, (char *)conf, sizeof(struct conf_peer));
+ reqpkt.keyid = htonl(req_keyid);
+
+ auth1crypt(req_keyid, (U_LONG *)&reqpkt, REQ_LEN_NOMAC);
+ gettstamp(&ts);
+ M_ADDUF(ts.l_ui, ts.l_uf, SKEWTIME);
+ HTONL_FP(&ts, &reqpkt.tstamp);
+ n = auth2crypt(req_keyid, (U_LONG *)&reqpkt, REQ_LEN_NOMAC);
+
+ /*
+ * Done. Send it.
+ */
+ n = write(sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n);
+ if (n < 0) {
+ syslog(LOG_ERR, "send to NTP server failed: %m");
+ return 0; /* maybe should exit */
+ }
+
+ /*
+ * Wait for a response. A weakness of the mode 7 protocol used
+ * is that there is no way to associate a response with a
+ * particular request, i.e. the response to this configuration
+ * request is indistinguishable from that to any other. I should
+ * fix this some day. In any event, the time out is fairly
+ * pessimistic to make sure that if an answer is coming back
+ * at all, we get it.
+ */
+ for (;;) {
+ FD_ZERO(&fdset);
+ FD_SET(sockfd, &fdset);
+ tvout.tv_sec = TIMEOUT_SEC;
+ tvout.tv_usec = TIMEOUT_USEC;
+
+ n = select(sockfd + 1, &fdset, (fd_set *)0,
+ (fd_set *)0, &tvout);
+
+ if (n <= 0) {
+ if (n < 0)
+ syslog(LOG_ERR, "select() fails: %m");
+ return 0;
+ }
+
+ n = read(sockfd, (char *)&reqpkt, REQ_LEN_MAC);
+ if (n <= 0) {
+ if (n < 0) {
+ syslog(LOG_ERR, "read() fails: %m");
+ return 0;
+ }
+ continue;
+ }
+
+ /*
+ * Got one. Check through to make sure it is what
+ * we expect.
+ */
+ if (n < RESP_HEADER_SIZE) {
+ syslog(LOG_ERR, "received runt response (%d octets)",
+ n);
+ continue;
+ }
+
+ if (!ISRESPONSE(reqpkt.rm_vn_mode)) {
+#ifdef DEBUG
+ if (debug > 1)
+ printf("received non-response packet\n");
+#endif
+ continue;
+ }
+
+ if (ISMORE(reqpkt.rm_vn_mode)) {
+#ifdef DEBUG
+ if (debug > 1)
+ printf("received fragmented packet\n");
+#endif
+ continue;
+ }
+
+ if (INFO_VERSION(reqpkt.rm_vn_mode) != NTP_VERSION
+ || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) {
+#ifdef DEBUG
+ if (debug > 1)
+ printf("version (%d) or mode (%d) incorrect\n",
+ INFO_VERSION(reqpkt.rm_vn_mode),
+ INFO_MODE(reqpkt.rm_vn_mode));
+#endif
+ continue;
+ }
+
+ if (INFO_SEQ(reqpkt.auth_seq) != 0) {
+#ifdef DEBUG
+ if (debug > 1)
+ printf("nonzero sequence number (%d)\n",
+ INFO_SEQ(reqpkt.auth_seq));
+#endif
+ continue;
+ }
+
+ if (reqpkt.implementation != IMPL_XNTPD ||
+ reqpkt.request != REQ_CONFIG) {
+#ifdef DEBUG
+ if (debug > 1)
+ printf(
+ "implementation (%d) or request (%d) incorrect\n",
+ reqpkt.implementation, reqpkt.request);
+#endif
+ continue;
+ }
+
+ if (INFO_NITEMS(reqpkt.err_nitems) != 0 ||
+ INFO_MBZ(reqpkt.mbz_itemsize) != 0 ||
+ INFO_ITEMSIZE(reqpkt.mbz_itemsize != 0)) {
+#ifdef DEBUG
+ if (debug > 1)
+ printf(
+ "nitems (%d) mbz (%d) or itemsize (%d) nonzero\n",
+ INFO_NITEMS(reqpkt.err_nitems),
+ INFO_MBZ(reqpkt.mbz_itemsize),
+ INFO_ITEMSIZE(reqpkt.mbz_itemsize));
+#endif
+ continue;
+ }
+
+ n = INFO_ERR(reqpkt.err_nitems);
+ switch (n) {
+ case INFO_OKAY:
+ /* success */
+ return 1;
+
+ case INFO_ERR_IMPL:
+ syslog(LOG_ERR,
+ "server reports implementation mismatch!!");
+ return 0;
+
+ case INFO_ERR_REQ:
+ syslog(LOG_ERR,
+ "server claims configuration request is unknown");
+ return 0;
+
+ case INFO_ERR_FMT:
+ syslog(LOG_ERR,
+ "server indicates a format error occured(!!)");
+ return 0;
+
+ case INFO_ERR_NODATA:
+ syslog(LOG_ERR,
+ "server indicates no data available (shouldn't happen)");
+ return 0;
+
+ case INFO_ERR_AUTH:
+ syslog(LOG_ERR,
+ "server returns a permission denied error");
+ return 0;
+
+ default:
+ syslog(LOG_ERR,
+ "server returns unknown error code %d", n);
+ return 0;
+ }
+ }
+}
+
+
+/*
+ * nexttoken - return the next token from a line
+ */
+static char *
+nexttoken(lptr)
+ char **lptr;
+{
+ register char *cp;
+ register char *tstart;
+
+ cp = *lptr;
+
+ /*
+ * Skip leading white space
+ */
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+
+ /*
+ * If this is the end of the line, return nothing.
+ */
+ if (*cp == '\n' || *cp == '\0') {
+ *lptr = cp;
+ return NULL;
+ }
+
+ /*
+ * Must be the start of a token. Record the pointer and look
+ * for the end.
+ */
+ tstart = cp++;
+ while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0')
+ cp++;
+
+ /*
+ * Terminate the token with a \0. If this isn't the end of the
+ * line, space to the next character.
+ */
+ if (*cp == '\n' || *cp == '\0')
+ *cp = '\0';
+ else
+ *cp++ = '\0';
+
+ *lptr = cp;
+ return tstart;
+}
+
+
+/*
+ * readconf - read the configuration information out of the file we
+ * were passed. Note that since the file is supposed to be
+ * machine generated, we bail out at the first sign of trouble.
+ */
+static void
+readconf(fp, name)
+ FILE *fp;
+ char *name;
+{
+ register int i;
+ char *token[NUMTOK];
+ U_LONG intval[NUMTOK];
+ int flags;
+ char buf[MAXLINESIZE];
+ char *bp;
+
+ while (fgets(buf, MAXLINESIZE, fp) != NULL) {
+
+ bp = buf;
+ for (i = 0; i < NUMTOK; i++) {
+ if ((token[i] = nexttoken(&bp)) == NULL) {
+ syslog(LOG_ERR,
+ "tokenizing error in file `%s', quitting",
+ name);
+ exit(1);
+ }
+ }
+
+ for (i = 1; i < NUMTOK; i++) {
+ if (!atouint(token[i], &intval[i])) {
+ syslog(LOG_ERR,
+ "format error for integer token `%s', file `%s', quitting",
+ token[i], name);
+ exit(1);
+ }
+ }
+
+ if (intval[TOK_HMODE] != MODE_ACTIVE &&
+ intval[TOK_HMODE] != MODE_CLIENT &&
+ intval[TOK_HMODE] != MODE_BROADCAST) {
+ syslog(LOG_ERR, "invalid mode (%d) in file %s",
+ intval[TOK_HMODE], name);
+ exit(1);
+ }
+
+ if (intval[TOK_VERSION] > NTP_VERSION ||
+ intval[TOK_VERSION] < NTP_OLDVERSION) {
+ syslog(LOG_ERR, "invalid version (%d) in file %s",
+ intval[TOK_VERSION], name);
+ exit(1);
+ }
+ if (intval[TOK_MINPOLL] < NTP_MINPOLL ||
+ intval[TOK_MINPOLL] > NTP_MAXPOLL) {
+ syslog(LOG_ERR, "invalid MINPOLL value (%d) in file %s",
+ intval[TOK_MINPOLL], name);
+ exit(1);
+ }
+
+ if (intval[TOK_MAXPOLL] < NTP_MINPOLL ||
+ intval[TOK_MAXPOLL] > NTP_MAXPOLL) {
+ syslog(LOG_ERR, "invalid MAXPOLL value (%d) in file %s",
+ intval[TOK_MAXPOLL], name);
+ exit(1);
+ }
+
+ if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE|FLAG_PREFER))
+ != 0) {
+ syslog(LOG_ERR, "invalid flags (%d) in file %s",
+ intval[TOK_FLAGS], name);
+ exit(1);
+ }
+
+ flags = 0;
+ if (intval[TOK_FLAGS] & FLAG_AUTHENABLE)
+ flags |= CONF_FLAG_AUTHENABLE;
+ if (intval[TOK_FLAGS] & FLAG_PREFER)
+ flags |= CONF_FLAG_PREFER;
+
+ /*
+ * This is as good as we can check it. Add it in.
+ */
+ addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE],
+ (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL],
+ (int)intval[TOK_MAXPOLL], flags, intval[TOK_KEYID]);
+ }
+}
+
+
+/*
+ * doconfigure - attempt to resolve names and configure the server
+ */
+static void
+doconfigure(dores)
+ int dores;
+{
+ register struct conf_entry *ce;
+ register struct conf_entry *ceremove;
+
+ ce = confentries;
+ while (ce != NULL) {
+ if (dores && ce->ce_peeraddr == 0) {
+ if (!findhostaddr(ce)) {
+ syslog(LOG_ERR,
+ "couldn't resolve `%s', giving up on it",
+ ce->ce_name);
+ ceremove = ce;
+ ce = ceremove->ce_next;
+ removeentry(ceremove);
+ continue;
+ }
+ }
+
+ if (ce->ce_peeraddr != 0) {
+ if (request(&ce->ce_config)) {
+ ceremove = ce;
+ ce = ceremove->ce_next;
+ removeentry(ceremove);
+ continue;
+ }
+ }
+ ce = ce->ce_next;
+ }
+}
diff --git a/contrib/xntpd/xntpd/ntp_io.c b/contrib/xntpd/xntpd/ntp_io.c
new file mode 100644
index 000000000000..614d5c52bde9
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_io.c
@@ -0,0 +1,1616 @@
+/* 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.
+ */
+
+/*
+ * 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
+#ifndef SYS_DOMAINOS
+ inter_list[i].bfd = open_socket(&inter_list[i].bcast, 0);
+ inter_list[i].flags |= INT_BCASTOPEN;
+#endif
+ }
+}
+
+
+/*
+ * io_unsetbclient - close the broadcast client sockets
+ */
+void
+io_unsetbclient()
+{
+ int i;
+
+ for (i = 1; i < ninterfaces; i++) {
+ if (!(inter_list[i].flags & INT_BCASTOPEN))
+ continue;
+ close_socket(inter_list[i].bfd);
+ inter_list[i].flags &= ~INT_BCASTOPEN;
+ }
+}
+
+
+
+/*
+ * open_socket - open a socket, returning the file descriptor
+ */
+static int
+open_socket(addr, bcast)
+ struct sockaddr_in *addr;
+ int bcast;
+{
+ int fd;
+ int on = 1, off = 0;
+
+ /* create a datagram (UDP) socket */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ if (fd > maxactivefd)
+ maxactivefd = fd;
+ FD_SET(fd, &activefds);
+
+ /* set SO_REUSEADDR since we will be binding the same port
+ number on each interface */
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on))) {
+ syslog(LOG_ERR, "setsockopt SO_REUSEADDR on fails: %m");
+ }
+
+ /*
+ * bind the local address.
+ */
+ if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
+ char buff[160];
+ sprintf(buff, "bind() fd %d, family %d, port %d, addr %08x, bcast=%d fails: %%m",
+ fd,
+ addr->sin_family,
+ addr->sin_port,
+ addr->sin_addr.s_addr,
+ bcast);
+ syslog(LOG_ERR, buff);
+ exit(1);
+ }
+
+#ifdef HAVE_SIGNALED_IO
+ init_socket_sig(fd);
+#else /* HAVE_SIGNALED_IO */
+
+ /*
+ * set non-blocking,
+ */
+#if defined(O_NONBLOCK)
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ syslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+#else /* O_NONBLOCK */
+#if defined(FNDELAY)
+ if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
+ syslog(LOG_ERR, "fcntl(FNDELAY) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+#else /* FNDELAY */
+Need non blocking I/O
+#endif /* FNDELAY */
+#endif /* O_NONBLOCK */
+#endif /* HAVE_SIGNALED_IO */
+
+ /*
+ * Turn off the SO_REUSEADDR socket option. It apparently
+ * causes heartburn on systems with multicast IP installed.
+ * On normal systems it only gets looked at when the address
+ * is being bound anyway..
+ */
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&off, sizeof(off))) {
+ syslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m");
+ }
+
+
+#ifdef SO_BROADCAST
+ /* if this interface can support broadcast, set SO_BROADCAST */
+ if (bcast) {
+ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
+ (char *)&on, sizeof(on))) {
+ syslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m");
+ }
+ }
+#endif
+
+#ifdef DEBUG
+ if (debug > 1)
+ printf("flags for fd %d: 0%o\n", fd,
+ fcntl(fd, F_GETFL, 0));
+#endif
+
+ return fd;
+}
+
+
+/*
+ * closesocket - close a socket and remove from the activefd list
+ */
+static void
+close_socket(fd)
+ int fd;
+{
+ int i, newmax;
+
+ (void) close(fd);
+ FD_CLR(fd, &activefds);
+
+ if (fd >= maxactivefd) {
+ newmax = 0;
+ for (i = 0; i < maxactivefd; i++)
+ if (FD_ISSET(i, &activefds))
+ newmax = i;
+ maxactivefd = newmax;
+ }
+}
+
+
+
+/*
+ * findbcastinter - find broadcast interface corresponding to address
+ */
+struct interface *
+findbcastinter(addr)
+ struct sockaddr_in *addr;
+{
+#ifdef SIOCGIFCONF
+ register int i;
+ register U_LONG netnum;
+
+ netnum = NSRCADR(addr);
+ for (i = 1; i < ninterfaces; i++) {
+ if (!(inter_list[i].flags & INT_BROADCAST))
+ continue;
+ if (NSRCADR(&inter_list[i].bcast) == netnum)
+ return &inter_list[i];
+ if ((NSRCADR(&inter_list[i].sin) & NSRCADR(&inter_list[i].mask))
+ == (netnum & NSRCADR(&inter_list[i].mask)))
+ return &inter_list[i];
+ }
+#endif
+ return any_interface;
+}
+
+
+/* XXX ELIMINATE getrecvbufs (almost) identical to ntpdate.c, ntptrace.c, ntp_io.c */
+/*
+ * getrecvbufs - get receive buffers which have data in them
+ *
+ * ***N.B. must be called with SIGIO blocked***
+ */
+struct recvbuf *
+getrecvbufs()
+{
+ struct recvbuf *rb;
+
+#ifdef DEBUG
+ if (debug > 4)
+ printf("getrecvbufs: %d handler interrupts, %d frames\n",
+ handler_calls, handler_pkts);
+#endif
+
+ if (full_recvbufs == 0) {
+#ifdef DEBUG
+ if (debug > 4)
+ printf("getrecvbufs called, no action here\n");
+#endif
+ return (struct recvbuf *)0; /* nothing has arrived */
+ }
+
+ /*
+ * Get the fulllist chain and mark it empty
+ */
+#ifdef DEBUG
+ if (debug > 4)
+ printf("getrecvbufs returning %d buffers\n", full_recvbufs);
+#endif
+ rb = beginlist;
+ fulllist = 0;
+ full_recvbufs = 0;
+
+ /*
+ * Check to see if we're below the low water mark.
+ */
+ if (free_recvbufs <= RECV_LOWAT) {
+ register struct recvbuf *buf;
+ register int i;
+
+ if (total_recvbufs >= RECV_TOOMANY)
+ syslog(LOG_ERR, "too many recvbufs allocated (%d)",
+ total_recvbufs);
+ else {
+ buf = (struct recvbuf *)
+ emalloc(RECV_INC*sizeof(struct recvbuf));
+ for (i = 0; i < RECV_INC; i++) {
+ buf->next = freelist;
+ freelist = buf;
+ buf++;
+ }
+
+ free_recvbufs += RECV_INC;
+ total_recvbufs += RECV_INC;
+ lowater_additions++;
+ }
+ }
+
+ /*
+ * Return the chain
+ */
+ return rb;
+}
+
+
+/* XXX ELIMINATE freerecvbuf (almost) identical to ntpdate.c, ntptrace.c, ntp_io.c */
+/*
+ * freerecvbuf - make a single recvbuf available for reuse
+ */
+void
+freerecvbuf(rb)
+ struct recvbuf *rb;
+{
+ BLOCKIO();
+ rb->next = freelist;
+ freelist = rb;
+ free_recvbufs++;
+ UNBLOCKIO();
+}
+
+
+/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
+/*
+ * sendpkt - send a packet to the specified destination. Maintain a
+ * send error cache so that only the first consecutive error for a
+ * destination is logged.
+ */
+void
+sendpkt(dest, inter, pkt, len)
+ struct sockaddr_in *dest;
+ struct interface *inter;
+ struct pkt *pkt;
+ int len;
+{
+ int cc, slot;
+ /*
+ * Send error cache. Empty slots have port == 0
+ * Set ERRORCACHESIZE to 0 to disable
+ */
+ struct cache {
+ u_short port;
+ struct in_addr addr;
+ };
+#ifndef ERRORCACHESIZE
+#define ERRORCACHESIZE 8
+#endif
+#if ERRORCACHESIZE > 0
+ static struct cache badaddrs[ERRORCACHESIZE];
+#else
+#define badaddrs ((struct cache *)0) /* Only used in empty loops! */
+#endif
+
+#ifdef DEBUG
+ if (debug)
+ printf("sendpkt(%s, %s, %d)\n", ntoa(dest),
+ ntoa(&inter->sin), len);
+#endif
+
+ for (slot = ERRORCACHESIZE; --slot >= 0; )
+ if (badaddrs[slot].port == dest->sin_port &&
+ badaddrs[slot].addr.s_addr == dest->sin_addr.s_addr)
+ break;
+
+ cc = sendto(inter->fd, (char *)pkt, len, 0, (struct sockaddr *)dest,
+ sizeof(struct sockaddr_in));
+ if (cc == -1) {
+ inter->notsent++;
+ packets_notsent++;
+ if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0) {
+ /*
+ * Remember this, if there's an empty slot
+ */
+ for (slot = ERRORCACHESIZE; --slot >= 0; )
+ if (badaddrs[slot].port == 0) {
+ badaddrs[slot].port = dest->sin_port;
+ badaddrs[slot].addr = dest->sin_addr;
+ break;
+ }
+ syslog(LOG_ERR, "sendto(%s): %m", ntoa(dest));
+ }
+ } else {
+ inter->sent++;
+ packets_sent++;
+ /*
+ * He's not bad any more
+ */
+ if (slot >= 0)
+ badaddrs[slot].port = 0;
+ }
+}
+
+
+/*
+ * input_handler - receive packets asynchronously
+ */
+void
+input_handler(cts)
+ l_fp *cts;
+{
+ register int i, n;
+ register struct recvbuf *rb;
+ register int doing;
+ register int fd;
+ struct timeval tvzero;
+ int fromlen;
+ l_fp ts;
+ fd_set fds;
+ int first = 1;
+
+ handler_calls++;
+ ts = *cts;
+
+ /*
+ * Do a poll to see who has data
+ */
+again:
+ fds = activefds;
+ tvzero.tv_sec = tvzero.tv_usec = 0;
+ n = select(maxactivefd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
+
+ /*
+ * If nothing to do, just return. If an error occurred, complain
+ * and return. If we've got some, freeze a timestamp.
+ */
+ if (n == 0)
+ return;
+ else if (n == -1) {
+ syslog(LOG_ERR, "select() error: %m");
+ return;
+ }
+ if (!first)get_systime(&ts);
+ first = 0;
+ handler_pkts += n;
+
+#ifdef REFCLOCK
+ /*
+ * Check out the reference clocks first, if any
+ */
+ if (refio != 0) {
+ register struct refclockio *rp;
+
+ for (rp = refio; rp != 0 && n > 0; rp = rp->next) {
+ fd = rp->fd;
+ if (FD_ISSET(fd, &fds)) {
+ n--;
+ if (free_recvbufs == 0) {
+ char buf[RX_BUFF_SIZE];
+
+ (void) read(fd, buf, sizeof buf);
+ packets_dropped++;
+ continue;
+ }
+
+ rb = freelist;
+ freelist = rb->next;
+ free_recvbufs--;
+
+ i = (rp->datalen == 0
+ || rp->datalen > sizeof(rb->recv_space))
+ ? sizeof(rb->recv_space) : rp->datalen;
+
+ rb->recv_length =
+ read(fd, (char *)&rb->recv_space, i);
+
+ if (rb->recv_length == -1) {
+ syslog(LOG_ERR, "clock read: %m");
+ rb->next = freelist;
+ freelist = rb;
+ free_recvbufs++;
+ continue;
+ }
+
+ /*
+ * Got one. Mark how and when it got here,
+ * put it on the full list and do bookkeeping.
+ */
+ rb->recv_srcclock = rp->srcclock;
+ rb->dstadr = 0;
+ rb->recv_time = ts;
+ rb->receiver = rp->clock_recv;
+
+ if (fulllist == 0) {
+ beginlist = rb;
+ rb->next = 0;
+ } else {
+ rb->next = fulllist->next;
+ fulllist->next = rb;
+ }
+ fulllist = rb;
+ full_recvbufs++;
+
+ rp->recvcount++;
+ packets_received++;
+ }
+ }
+ }
+#endif
+
+ /*
+ * Loop through the interfaces looking for data to read.
+ */
+ for (i = ninterfaces-1; i >= 0 && n > 0; i--) {
+ for (doing = 0; doing < 2 && n > 0; doing++) {
+ if (doing == 0) {
+ fd = inter_list[i].fd;
+ } else {
+ if (!(inter_list[i].flags & INT_BCASTOPEN))
+ break;
+ fd = inter_list[i].bfd;
+ }
+ if (FD_ISSET(fd, &fds)) {
+ n--;
+ /*
+ * Get a buffer and read the frame. If we
+ * haven't got a buffer, or this is received
+ * on the wild card socket, just dump the packet.
+ */
+#ifdef UDP_WILDCARD_DELIVERY
+/*
+ * these guys manage to put properly addressed packets into the wildcard queue
+ */
+ if (free_recvbufs == 0) {
+#else
+ if (i == 0 || free_recvbufs == 0) {
+#endif
+ char buf[RX_BUFF_SIZE];
+
+#ifndef UDP_WILDCARD_DELIVERY
+ (void) read(fd, buf, sizeof buf);
+#else
+ fromlen = 0;
+ (void) recvfrom(fd, buf, sizeof(buf), 0,
+ (struct sockaddr *)0,
+ &fromlen);
+#endif
+
+ if (i == 0)
+ packets_ignored++;
+ else
+ packets_dropped++;
+ continue;
+ }
+
+ rb = freelist;
+ freelist = rb->next;
+ free_recvbufs--;
+
+ fromlen = sizeof(struct sockaddr_in);
+ rb->recv_length = recvfrom(fd,
+ (char *)&rb->recv_space,
+ sizeof(rb->recv_space), 0,
+ (struct sockaddr *)&rb->recv_srcadr,
+ &fromlen);
+ if (rb->recv_length == -1) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ rb->next = freelist;
+ freelist = rb;
+ free_recvbufs++;
+#ifdef DEBUG
+ if (debug)
+ printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd);
+#endif
+ continue;
+ }
+#ifdef DEBUG
+ if (debug)
+ printf("input_handler: fd=%d length %d\n", fd, rb->recv_length);
+#endif
+
+ /*
+ * Got one. Mark how and when it got here,
+ * put it on the full list and do bookkeeping.
+ */
+ rb->dstadr = &inter_list[i];
+ rb->recv_time = ts;
+ rb->receiver = receive;
+
+
+ if (fulllist == 0) {
+ beginlist = rb;
+ rb->next = 0;
+ } else {
+ rb->next = fulllist->next;
+ fulllist->next = rb;
+ }
+ fulllist = rb;
+ full_recvbufs++;
+
+ inter_list[i].received++;
+ packets_received++;
+ }
+ }
+ }
+ /*
+ * Done everything from that select. Poll again.
+ */
+ goto again;
+}
+
+
+/*
+ * findinterface - utility used by other modules to find an interface
+ * given an address.
+ */
+struct interface *
+findinterface(addr)
+ struct sockaddr_in *addr;
+{
+ register int i;
+ register U_LONG saddr;
+
+ /*
+ * Just match the address portion.
+ */
+ saddr = addr->sin_addr.s_addr;
+ for (i = 0; i < ninterfaces; i++) {
+ if (inter_list[i].sin.sin_addr.s_addr == saddr)
+ return &inter_list[i];
+ }
+ return (struct interface *)0;
+}
+
+
+/*
+ * io_clr_stats - clear I/O module statistics
+ */
+void
+io_clr_stats()
+{
+ packets_dropped = 0;
+ packets_ignored = 0;
+ packets_received = 0;
+ packets_sent = 0;
+ packets_notsent = 0;
+
+ handler_calls = 0;
+ handler_pkts = 0;
+ io_timereset = current_time;
+}
+
+
+#ifdef REFCLOCK
+/*
+ * This is a hack so that I don't have to fool with these ioctls in the
+ * pps driver ... we are already non-blocking and turn on SIGIO thru
+ * another mechanisim
+ */
+int
+io_addclock_simple(rio)
+ struct refclockio *rio;
+{
+ BLOCKIO();
+ /*
+ * Stuff the I/O structure in the list and mark the descriptor
+ * in use. There is a harmless (I hope) race condition here.
+ */
+ rio->next = refio;
+ refio = rio;
+
+ if (rio->fd > maxactivefd)
+ maxactivefd = rio->fd;
+ FD_SET(rio->fd, &activefds);
+ UNBLOCKIO();
+ return 1;
+}
+
+/*
+ * io_addclock - add a reference clock to the list and arrange that we
+ * get SIGIO interrupts from it.
+ */
+int
+io_addclock(rio)
+ struct refclockio *rio;
+{
+ BLOCKIO();
+ /*
+ * Stuff the I/O structure in the list and mark the descriptor
+ * in use. There is a harmless (I hope) race condition here.
+ */
+ rio->next = refio;
+ refio = rio;
+
+#ifdef HAVE_SIGNALED_IO
+ if (init_clock_sig(rio)) {
+ UNBLOCKIO();
+ return 0;
+ }
+#endif
+
+ if (rio->fd > maxactivefd)
+ maxactivefd = rio->fd;
+ FD_SET(rio->fd, &activefds);
+
+ UNBLOCKIO();
+ return 1;
+}
+
+/*
+ * io_closeclock - close the clock in the I/O structure given
+ */
+void
+io_closeclock(rio)
+ struct refclockio *rio;
+{
+ /*
+ * Remove structure from the list
+ */
+ if (refio == rio) {
+ refio = rio->next;
+ } else {
+ register struct refclockio *rp;
+
+ for (rp = refio; rp != 0; rp = rp->next)
+ if (rp->next == rio) {
+ rp->next = rio->next;
+ break;
+ }
+
+ if (rp == 0) {
+ /*
+ * Internal error. Report it.
+ */
+ syslog(LOG_ERR,
+ "internal error: refclockio structure not found");
+ return;
+ }
+ }
+
+ /*
+ * Close the descriptor. close_socket does the right thing despite
+ * the misnomer.
+ */
+ close_socket(rio->fd);
+}
+#endif /* REFCLOCK */
+
+/*
+ * SIGPOLL and SIGIO ROUTINES.
+ */
+#ifdef HAVE_SIGNALED_IO
+/*
+ * Some systems (MOST) define SIGPOLL==SIGIO others SIGIO==SIGPOLL a few
+ * have seperate SIGIO and SIGPOLL signals. This code checks for the
+ * SIGIO==SIGPOLL case at compile time.
+ * Do not defined USE_SIGPOLL or USE_SIGIO.
+ * these are interal only to ntp_io.c!
+ */
+#if defined(USE_SIGPOLL)
+#undef USE_SIGPOLL
+#endif
+#if defined(USE_SIGIO)
+#undef USE_SIGIO
+#endif
+
+#if defined(USE_TTY_SIGPOLL)||defined(USE_UDP_SIGPOLL)
+#define USE_SIGPOLL
+#endif
+
+#if !defined(USE_TTY_SIGPOLL)||!defined(USE_UDP_SIGPOLL)
+#define USE_SIGIO
+#endif
+
+#if defined(USE_SIGIO)&&defined(USE_SIGPOLL)
+#if SIGIO==SIGPOLL
+#define USE_SIGIO
+#undef USE_SIGPOLL
+#endif /* SIGIO==SIGPOLL */
+#endif /* USE_SIGIO && USE_SIGIO */
+
+
+/*
+ * TTY instialzation routeins.
+ */
+#ifndef USE_TTY_SIGPOLL
+/*
+ * Spical cases first!
+ */
+#if defined(SYS_HPUX)
+#define CLOCK_DONE
+static int
+init_clock_sig(rio)
+ struct refclockio *rio;
+{
+ int pgrp, on = 1;
+
+ pgrp = getpid();
+ if (ioctl(rio->fd, FIOSSAIOOWN, (char *)&pgrp) == -1) {
+ syslog(LOG_ERR, "ioctl(FIOSSAIOOWN) fails for clock I/O: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ /*
+ * set non-blocking, async I/O on the descriptor
+ */
+ if (ioctl(rio->fd, FIOSNBIO, (char *)&on) == -1) {
+ syslog(LOG_ERR, "ioctl(FIOSNBIO) fails for clock I/O: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ if (ioctl(rio->fd, FIOSSAIOSTAT, (char *)&on) == -1) {
+ syslog(LOG_ERR, "ioctl(FIOSSAIOSTAT) fails for clock I/O: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+ return 0;
+}
+#endif /* SYS_HPUX */
+#if defined(SYS_AIX)&&!defined(_BSD)
+/*
+ * SYSV compatibility mode under AIX.
+ */
+#define CLOCK_DONE
+static int
+init_clock_sig(rio)
+ struct refclockio *rio;
+{
+ int pgrp, on = 1;
+
+ if (ioctl(rio->fd, FIOASYNC, (char *)&on) == -1) {
+ syslog(LOG_ERR, "ioctl(FIOASYNC) fails for clock I/O: %m");
+ return 1;
+ }
+ pgrp = -getpid();
+ if (ioctl(rio->fd, FIOSETOWN, (char*)&pgrp) == -1) {
+ syslog(LOG_ERR, "ioctl(FIOSETOWN) fails for clock I/O: %m");
+ return 1;
+ }
+
+ if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0) {
+ syslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m");
+ return 1;
+ }
+ return 0;
+}
+#endif /* AIX && !BSD */
+#ifndef CLOCK_DONE
+static int
+init_clock_sig(rio)
+ struct refclockio *rio;
+{
+ if (fcntl(rio->fd, F_SETOWN, getpid()) == -1) {
+ syslog(LOG_ERR, "fcntl(F_SETOWN) fails for clock I/O: %m");
+ return 1;
+ }
+
+ if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0) {
+ syslog(LOG_ERR,
+ "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m");
+ return 1;
+ }
+ return 0;
+}
+#endif /* CLOCK_DONE */
+#else /* !USE_TTY_SIGPOLL */
+int
+static init_clock_sig(rio)
+ struct refclockio *rio;
+{
+ if (ioctl(rio->fd, I_SETSIG, S_INPUT) < 0) {
+ syslog(LOG_ERR,
+ "ioctl(I_SETSIG, S_INPUT) fails for clock I/O: %m");
+ return 1;
+ }
+ return 0;
+}
+#endif /* !USE_TTY_SIGPOLL */
+
+
+
+#ifndef USE_UDP_SIGPOLL
+/*
+ * Socket SIGPOLL initialization routines.
+ * Special cases first!
+ */
+#if defined(SYS_HPUX) || defined(SYS_LINUX)
+#define SOCKET_DONE
+static void
+init_socket_sig(fd)
+ int fd;
+{
+ int pgrp, on = 1;
+
+ /*
+ * Big difference here for HP-UX ... why can't life be easy ?
+ */
+ if (ioctl(fd, FIOSNBIO, (char *)&on) == -1) {
+ syslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ if (ioctl(fd, FIOASYNC, (char *)&on) == -1) {
+ syslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+#if (SYS_HPUX > 7)
+ pgrp = getpid();
+#else
+ pgrp = -getpid();
+#endif
+ if (ioctl(fd, SIOCSPGRP, (char *)&pgrp) == -1) {
+ syslog(LOG_ERR, "ioctl(SIOCSPGRP) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+}
+#endif /* SYS_HPUX */
+#if defined(SYS_AIX)&&!defined(_BSD)
+/*
+ * SYSV compatibility mod under AIX
+ */
+#define SOCKET_DONE
+static void
+init_socket_sig(fd)
+ int fd;
+{
+ int pgrp, on = 1;
+
+ if (ioctl(fd, FIOASYNC, (char *)&on) == -1) {
+ syslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+ pgrp = -getpid();
+ if (ioctl(fd, FIOSETOWN, (char*)&pgrp) == -1) {
+ syslog(LOG_ERR, "ioctl(FIOSETOWN) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) {
+ syslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+}
+#endif /* AIX && !BSD */
+#if defined(UDP_BACKWARDS_SETOWN)
+/*
+ * SunOS 3.5 and Ultirx 2.0
+ */
+#define SOCKET_DONE
+static void
+init_socket_sig(fd)
+ int fd;
+{
+ /*
+ * The way Sun did it as recently as SunOS 3.5. Only
+ * in the case of sockets, of course, just to confuse
+ * the issue. Don't they even bother to test the stuff
+ * they send out? Ibid for Ultrix 2.0
+ */
+ if (fcntl(fd, F_SETOWN, -getpid()) == -1)
+ {
+ syslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m");
+ exit(1);
+ }
+ /*
+ * set non-blocking, async I/O on the descriptor
+ */
+ if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) {
+ syslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+}
+#endif /* UDP_BACKWARDS_SETOWN */
+#ifndef SOCKET_DONE
+static void
+init_socket_sig(fd)
+ int fd;
+{
+ if (fcntl(fd, F_SETOWN, getpid()) == -1)
+ {
+ syslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m");
+ exit(1);
+ }
+ /*
+ * set non-blocking, async I/O on the descriptor
+ */
+ if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) {
+ syslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+}
+#endif /* SOCKET_DONE */
+#else /* !USE_UDP_SIGPOLL */
+static void
+init_socket_sig(fd)
+ int fd;
+{
+ if (ioctl(fd, I_SETSIG, S_INPUT) < 0) {
+ syslog(LOG_ERR,
+ "ioctl(I_SETSIG, S_INPUT) fails for socket I/O: %m");
+ exit(1);
+ }
+}
+#endif /* USE_UDP_SIGPOLL */
+
+static RETSIGTYPE
+sigio_handler(sig)
+int sig;
+{
+ l_fp ts;
+
+#ifdef SYS_SVR4
+ /* This should not be necessary for a signal previously set with
+ * sigset().
+ */
+# if defined(USE_SIGIO)
+ (void) sigset(SIGIO, sigio_handler);
+# endif
+# if defined(USE_SIGPOLL)
+ (void) sigset(SIGPOLL, sigio_handler);
+# endif
+#endif /* SYS_SVR4 */
+
+ get_systime(&ts);
+ (void)input_handler(&ts);
+}
+
+/*
+ * Signal support routines.
+ */
+#ifdef NTP_POSIX_SOURCE
+static void
+set_signal()
+{
+ int n;
+ struct sigaction vec;
+
+ sigemptyset(&vec.sa_mask);
+
+#ifdef USE_SIGIO
+ sigaddset(&vec.sa_mask, SIGIO);
+#endif
+#ifdef USE_SIGPOLL
+ sigaddset(&vec.sa_mask, SIGPOLL);
+#endif
+ vec.sa_flags = 0;
+
+#if defined(USE_SIGIO)
+ vec.sa_handler = sigio_handler;
+
+ while (1) {
+ n = sigaction(SIGIO, &vec, NULL);
+ if (n == -1 && errno == EINTR) continue;
+ break;
+ }
+
+ if (n == -1) {
+ perror("sigaction");
+ exit(1);
+ }
+#endif
+#if defined(USE_SIGPOLL)
+ vec.sa_handler = sigio_handler;
+
+ while (1) {
+ n = sigaction(SIGPOLL, &vec, NULL);
+ if (n == -1 && errno == EINTR) continue;
+ break;
+ }
+
+ if (n == -1) {
+ perror("sigaction");
+ exit(1);
+ }
+#endif
+}
+
+void
+block_io_and_alarm()
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+#if defined(USE_SIGIO)
+ sigaddset(&set, SIGIO);
+#endif
+#if defined(USE_SIGPOLL)
+ sigaddset(&set, SIGPOLL);
+#endif
+ sigprocmask(SIG_BLOCK, &set, NULL);
+}
+
+static void
+block_sigio()
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+#if defined(USE_SIGIO)
+ sigaddset(&set, SIGIO);
+#endif
+#if defined(USE_SIGPOLL)
+ sigaddset(&set, SIGPOLL);
+#endif
+ sigaddset(&set, SIGALRM);
+ sigprocmask(SIG_BLOCK, &set, NULL);
+}
+
+void
+unblock_io_and_alarm()
+{
+ sigset_t unset;
+
+ sigemptyset(&unset);
+
+#if defined(USE_SIGIO)
+ sigaddset(&unset, SIGIO);
+#endif
+#if defined(USE_SIGPOLL)
+ sigaddset(&unset, SIGPOLL);
+#endif
+ sigaddset(&unset, SIGALRM);
+ sigprocmask(SIG_UNBLOCK, &unset, NULL);
+}
+
+static
+void
+unblock_sigio()
+{
+ sigset_t unset;
+
+ sigemptyset(&unset);
+
+#if defined(USE_SIGIO)
+ sigaddset(&unset, SIGIO);
+#endif
+#if defined(USE_SIGPOLL)
+ sigaddset(&unset, SIGPOLL);
+#endif
+ sigprocmask(SIG_UNBLOCK, &unset, NULL);
+}
+
+void
+wait_for_signal()
+{
+ sigset_t old;
+
+ sigprocmask(SIG_UNBLOCK, NULL, &old);
+
+#if defined(USE_SIGIO)
+ sigdelset(&old, SIGIO);
+#endif
+#if defined(USE_SIGPOLL)
+ sigdelset(&old, SIGPOLL);
+#endif
+ sigdelset(&old, SIGALRM);
+
+ sigsuspend(&old);
+}
+
+#else
+/*
+ * Must be an old bsd system.
+ * We assume there is no SIGPOLL.
+ */
+
+void
+block_io_and_alarm()
+{
+ int mask;
+
+ mask = sigmask(SIGIO)|sigmask(SIGALRM);
+ (void)sigblock(mask);
+}
+
+void
+block_sigio()
+{
+ int mask;
+
+ mask = sigmask(SIGIO);
+ (void)sigblock(mask);
+}
+
+static void
+set_signal()
+{
+ (void) signal_no_reset(SIGIO, sigio_handler);
+}
+
+void
+unblock_io_and_alarm()
+{
+ int mask, omask;
+
+ mask = sigmask(SIGIO)|sigmask(SIGALRM);
+ omask = sigblock(0);
+ omask &= ~mask;
+ (void)sigsetmask(omask);
+}
+
+void
+unblock_sigio()
+{
+ int mask, omask;
+
+ mask = sigmask(SIGIO);
+ omask = sigblock(0);
+ omask &= ~mask;
+ (void)sigsetmask(omask);
+}
+
+void
+wait_for_signal()
+{
+ int mask, omask;
+
+ mask = sigmask(SIGIO)|sigmask(SIGALRM);
+ omask = sigblock(0);
+ omask &= ~mask;
+ sigpause(omask);
+}
+#endif /* NTP_POSIX_SOURCE */
+#endif /* HAVE_SIGNALED_IO */
+
diff --git a/contrib/xntpd/xntpd/ntp_leap.c b/contrib/xntpd/xntpd/ntp_leap.c
new file mode 100644
index 000000000000..aadbb09dc346
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_leap.c
@@ -0,0 +1,315 @@
+/* ntp_leap.c,v 3.1 1993/07/06 01:11:18 jbj Exp
+ * ntp_leap - maintain leap bits and take action when a leap occurs
+ */
+#include <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/contrib/xntpd/xntpd/ntp_loopfilter.c b/contrib/xntpd/xntpd/ntp_loopfilter.c
new file mode 100644
index 000000000000..6d79c5d52ff4
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_loopfilter.c
@@ -0,0 +1,948 @@
+/*
+ * 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 */
+
+#ifdef HAVE_TERMIOS
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#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(HAVE_TERMIOS)
+ /*
+ * POSIX 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;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#if defined(STREAM)
+ 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(HAVE_TERMIOS)
+ /*
+ * System V TERMIOS 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 /* HAVE_TERMIOS */
+#if defined(HAVE_BSD_TTYS)
+
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ */
+ { struct sgttyb ttyb;
+
+ if (fdpps == -1 || ioctl(fdpps, TIOCGETP, &ttyb) < 0)
+ return;
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SYS_BAUD(int_value);
+ if (ioctl(fdpps, TIOCSETP, &ttyb) < 0)
+ return;
+ }
+#endif /* HAVE_BSD_TTYS */
+ pps_baud = int_value;
+ break;
+#endif /* PPSCLK */
+
+ default:
+ /* sigh */
+ break;
+ }
+}
+
+#if defined(KERNEL_PLL)
+/*
+ * _trap - trap processor for undefined syscalls
+ *
+ * This nugget is called by the kernel when the SYS_ntp_adjtime()
+ * syscall bombs because the silly thing has not been implemented int
+ * the kernel. In this case the phase-lock loop is emulated by
+ * the stock adjtime() syscall and a lot of indelicate abuse.
+ */
+RETSIGTYPE
+pll_trap()
+{
+ pll_control = 0;
+}
+#endif /* KERNEL_PLL */
+
+#if defined(PPSCLK)
+/*
+ * pps_receive - compute and store 1-pps signal offset
+ *
+ * This routine is called once per second when the 1-pps signal is
+ * present. It calculates the offset of the local clock relative to the
+ * 1-pps signal and saves in a circular buffer for later use. If the
+ * clock line discipline is active, its timestamp is used; otherwise,
+ * the buffer timestamp is used.
+ */
+static void
+pps_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ u_char *dpt; /* buffer pointer */
+ l_fp ts; /* l_fp temps */
+ int dpend; /* buffer length */
+
+ /*
+ * Set up pointers, check the buffer length, discard intercept
+ * character and convert unix timeval to timestamp format.
+ */
+ dpt = (u_char *)&rbufp->recv_space;
+ dpend = rbufp->recv_length;
+#if !defined(HPUXGADGET)
+ dpt++;
+ dpend--;
+#endif /* HPUXGADGET */
+ if (dpend != sizeof(struct timeval) || !buftvtots((char *)dpt, &ts))
+ ts = rbufp->recv_time;
+
+ /*
+ * Correct for uart and os delay and process sample offset.
+ */
+ L_SUB(&ts, &pps_delay);
+ L_NEG(&ts);
+ (void)pps_sample(&ts);
+}
+#endif /* PPSCLK */
+
+#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
+/*
+ * pps_sample - process pps sample offset
+ */
+int pps_sample(tsr)
+ l_fp *tsr;
+{
+ int i, j; /* temp ints */
+ LONG sort[NPPS]; /* temp array for sorting */
+ l_fp lftemp, ts; /* l_fp temps */
+ LONG ltemp; /* long temp */
+
+ /*
+ * Note the seconds offset is already in the low-order timestamp
+ * doubleword, so all we have to do is sign-extend and invert it.
+ * The resulting offset is believed only if within CLOCK_MAX.
+ */
+ ts = *tsr;
+ lftemp.l_i = lftemp.l_f = 0;
+ M_ADDF(lftemp.l_i, lftemp.l_f, ts.l_f);
+ if (ts.l_f <= -CLOCK_MAX_F || ts.l_f >= CLOCK_MAX_F) {
+ pps_time = 0;
+ return (-1);
+ }
+
+ /*
+ * Save the sample in a circular buffer for later processing.
+ */
+ nsamples++;
+ i = ((int)(nsamples)) % NPPS;
+ samples[i] = lftemp.l_f;
+ if (i != NPPS-1)
+ return (0);
+
+ /*
+ * When the buffer fills up, construct an array of sorted
+ * samples.
+ */
+ pps_time = current_time;
+ for (i = 0; i < NPPS; i++) {
+ sort[i] = samples[i];
+ for (j = 0; j < i; j++) {
+ if (sort[j] > sort[i]) {
+ ltemp = sort[j];
+ sort[j] = sort[i];
+ sort[i] = ltemp;
+ }
+ }
+ }
+
+ /*
+ * Compute offset as the average of all samples in the filter
+ * less PPS_TRIM samples trimmed from the beginning and end,
+ * dispersion as the difference between max and min of samples
+ * retained. The system stratum, root delay and root dispersion
+ * are also set here.
+ */
+ pps_offset.l_i = pps_offset.l_f = 0;
+ for (i = PPS_TRIM; i < NPPS - PPS_TRIM; i++)
+ M_ADDF(pps_offset.l_i, pps_offset.l_f, sort[i]);
+ if (L_ISNEG(&pps_offset)) {
+ L_NEG(&pps_offset);
+ for (i = 0; i < PPS_FAC; i++)
+ L_RSHIFT(&pps_offset);
+ L_NEG(&pps_offset);
+ } else {
+ for (i = 0; i < PPS_FAC; i++)
+ L_RSHIFT(&pps_offset);
+ }
+ lftemp.l_i = 0;
+ lftemp.l_f = sort[NPPS-1-PPS_TRIM] - sort[PPS_TRIM];
+ sys_maxd = LFPTOFP(&lftemp);
+#ifdef DEBUG
+ if (debug)
+ printf("pps_filter: %s %s %s\n", lfptoa(&pps_delay, 6),
+ lfptoa(&pps_offset, 6), lfptoa(&lftemp, 5));
+#endif /* DEBUG */
+ record_peer_stats(&loopback_interface->sin, ctlsysstatus(), &pps_offset,
+ sys_rootdelay, sys_rootdispersion);
+ return (0);
+}
+#endif /* PPS || PPSCLK || PPSPPS */
+
diff --git a/contrib/xntpd/xntpd/ntp_monitor.c b/contrib/xntpd/xntpd/ntp_monitor.c
new file mode 100644
index 000000000000..63af8d4d4d97
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_monitor.c
@@ -0,0 +1,306 @@
+/* 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;
+ memset((char *)&mon_mru_list, 0, 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));
+ memset((char *)mon_hash, 0,
+ MON_HASH_SIZE*sizeof(struct mon_data));
+ mon_hash_count = (int *)emalloc(MON_HASH_SIZE * sizeof(int));
+ mon_free_mem = 0;
+ mon_total_mem = 0;
+ mon_mem_increments = 0;
+ mon_free = 0;
+ mon_getmoremem();
+ mon_have_memory = 1;
+ }
+
+ md = mon_hash;
+ for (i = 0; i < MON_HASH_SIZE; i++, md++) {
+ md->hash_next = md;
+ md->hash_prev = md;
+ *(mon_hash_count + i) = 0;
+ }
+
+ mon_mru_list.mru_next = &mon_mru_list;
+ mon_mru_list.mru_prev = &mon_mru_list;
+
+ mon_enabled = 1;
+}
+
+
+/*
+ * mon_stop - stop the monitoring software
+ */
+void
+mon_stop()
+{
+ register struct mon_data *md;
+ register int i;
+
+ if (!mon_enabled)
+ return;
+
+ /*
+ * Put everything back on the free list
+ */
+ md = mon_hash;
+ for (i = 0; i < MON_HASH_SIZE; i++, md++) {
+ if (md->hash_next != md) {
+ md->hash_prev->hash_next = mon_free;
+ mon_free = md->hash_next;
+ mon_free_mem += *(mon_hash_count + i);
+ md->hash_next = md;
+ md->hash_prev = md;
+ *(mon_hash_count + i) = 0;
+ }
+ }
+
+ mon_mru_list.mru_next = &mon_mru_list;
+ mon_mru_list.mru_prev = &mon_mru_list;
+
+ mon_enabled = 0;
+}
+
+
+/*
+ * monitor - record stats about this packet
+ */
+void
+monitor(rbufp)
+ struct recvbuf *rbufp;
+{
+ register struct pkt *pkt;
+ register struct mon_data *md;
+ register U_LONG netnum;
+ register int hash;
+ register int mode;
+ register struct mon_data *mdhash;
+
+ if (!mon_enabled)
+ return;
+
+ pkt = &rbufp->recv_pkt;
+ netnum = NSRCADR(&rbufp->recv_srcadr);
+ hash = MON_HASH(netnum);
+ mode = PKT_MODE(pkt->li_vn_mode);
+
+ md = (mon_hash + hash)->hash_next;
+ while (md != (mon_hash + hash)) {
+ if (md->rmtadr == netnum && md->mode == (u_char)mode) {
+ md->lasttime = current_time;
+ md->count++;
+ md->version = PKT_VERSION(pkt->li_vn_mode);
+ md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
+
+ /*
+ * Shuffle him to the head of the
+ * mru list. What a crock.
+ */
+ md->mru_next->mru_prev = md->mru_prev;
+ md->mru_prev->mru_next = md->mru_next;
+ md->mru_next = mon_mru_list.mru_next;
+ md->mru_prev = &mon_mru_list;
+ mon_mru_list.mru_next->mru_prev = md;
+ mon_mru_list.mru_next = md;
+ return;
+ }
+ md = md->hash_next;
+ }
+
+ /*
+ * If we got here, this is the first we've heard of this
+ * guy. Get him some memory, either from the free list
+ * or from the tail of the MRU list.
+ */
+ if (mon_free_mem == 0 && mon_total_mem >= MAXMONMEM) {
+ /*
+ * Get it from MRU list
+ */
+ md = mon_mru_list.mru_prev;
+ md->mru_prev->mru_next = &mon_mru_list;
+ mon_mru_list.mru_prev = md->mru_prev;
+ md->hash_next->hash_prev = md->hash_prev;
+ md->hash_prev->hash_next = md->hash_next;
+ *(mon_hash_count + MON_HASH(md->rmtadr)) -= 1;
+ } else {
+ if (mon_free_mem == 0)
+ mon_getmoremem();
+ md = mon_free;
+ mon_free = md->hash_next;
+ mon_free_mem--;
+ }
+
+ /*
+ * Got one, initialize it
+ */
+ md->lasttime = md->firsttime = current_time;
+ md->count = 1;
+ md->rmtadr = netnum;
+ md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
+ md->mode = (u_char) mode;
+ md->version = PKT_VERSION(pkt->li_vn_mode);
+
+ /*
+ * Shuffle him into the hash table, inserting him at the
+ * end. Also put him on top of the MRU list.
+ */
+ mdhash = mon_hash + MON_HASH(netnum);
+ md->hash_next = mdhash;
+ md->hash_prev = mdhash->hash_prev;
+ mdhash->hash_prev->hash_next = md;
+ mdhash->hash_prev = md;
+ *(mon_hash_count + MON_HASH(netnum)) += 1;
+
+ md->mru_next = mon_mru_list.mru_next;
+ md->mru_prev = &mon_mru_list;
+ mon_mru_list.mru_next->mru_prev = md;
+ mon_mru_list.mru_next = md;
+}
+
+
+/*
+ * mon_getmoremem - get more memory and put it on the free list
+ */
+static void
+mon_getmoremem()
+{
+ register struct mon_data *md;
+ register int i;
+ struct mon_data *freedata;
+
+ md = (struct mon_data *)emalloc(MONMEMINC * sizeof(struct mon_data));
+ freedata = mon_free;
+ mon_free = md;
+
+ for (i = 0; i < (MONMEMINC-1); i++) {
+ md->hash_next = (md + 1);
+ md++;
+ }
+
+ /*
+ * md now points at the last. Link in the rest of the chain.
+ */
+ md->hash_next = freedata;
+
+ mon_free_mem += MONMEMINC;
+ mon_total_mem += MONMEMINC;
+ mon_mem_increments++;
+}
diff --git a/contrib/xntpd/xntpd/ntp_peer.c b/contrib/xntpd/xntpd/ntp_peer.c
new file mode 100644
index 000000000000..cadd415346a9
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_peer.c
@@ -0,0 +1,639 @@
+/* ntp_peer.c,v 3.1 1993/07/06 01:11:22 jbj Exp
+ * ntp_peer.c - management of data maintained for peer associations
+ */
+#include <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.
+ */
+ memset((char *)peer, 0, sizeof(struct peer));
+
+ peer->srcadr = *srcadr;
+ if (dstadr != 0)
+ peer->dstadr = dstadr;
+ else if (hmode == MODE_BROADCAST)
+ peer->dstadr = findbcastinter(srcadr);
+ else
+ peer->dstadr = any_interface;
+ peer->hmode = (u_char)hmode;
+ peer->version = (u_char)version;
+ peer->minpoll = (u_char)minpoll;
+ peer->maxpoll = (u_char)maxpoll;
+ peer->hpoll = peer->minpoll;
+ peer->ppoll = peer->minpoll;
+ peer->keyid = key;
+
+ if (hmode == MODE_BCLIENT) {
+ peer->estbdelay = sys_bdelay;
+ peer->flags |= FLAG_DEFBDELAY;
+ }
+
+ peer->leap = LEAP_NOTINSYNC;
+ peer->precision = DEFPRECISION;
+ peer->dispersion = NTP_MAXDISPERSE;
+ peer->stratum = STRATUM_UNSPEC;
+ peer->update = sys_clock;
+
+ for (i = 0; i < NTP_SHIFT; i++) {
+ peer->filter_order[i] = i;
+ peer->filter_error[i] = NTP_MAXDISPERSE;
+ }
+
+ /*
+ * Assign him an association ID and increment the system variable
+ */
+ peer->associd = current_association_ID;
+ if (++current_association_ID == 0)
+ ++current_association_ID;
+
+ /*
+ * Note time on statistics timers.
+ */
+ peer->timereset = current_time;
+ peer->timereachable = current_time;
+ peer->timereceived = current_time;
+
+#ifdef REFCLOCK
+ if (ISREFCLOCKADR(&peer->srcadr)) {
+ /*
+ * We let the reference clock support do clock
+ * dependent initialization. This includes setting
+ * the peer timer, since the clock may have requirements
+ * for this.
+ */
+ if (!refclock_newpeer(peer)) {
+ /*
+ * Dump it, something screwed up
+ */
+ peer->next = peer_free;
+ peer_free = peer;
+ peer_free_count++;
+ return 0;
+ }
+ } else {
+#endif
+ /*
+ * Set up timer. If initializing, just make sure we start polling
+ * in different 4 second intervals.
+ */
+ peer->event_timer.peer = peer;
+ peer->event_timer.event_handler = transmit;
+
+ if (initializing) {
+ init_peer_starttime += (1 << EVENT_TIMEOUT);
+ if (init_peer_starttime >= (1 << peer->minpoll))
+ init_peer_starttime = (1 << EVENT_TIMEOUT);
+ peer->event_timer.event_time = init_peer_starttime;
+ } else {
+ /*
+ * First expiry is set to eight seconds from now.
+ */
+ peer->event_timer.event_time
+ = (1 << (peer->minpoll - 1)) + current_time;
+ }
+ TIMER_ENQUEUE(timerqueue, &peer->event_timer);
+#ifdef REFCLOCK
+ }
+#endif
+
+ /*
+ * Put him in the hash tables.
+ */
+ i = HASH_ADDR(&peer->srcadr);
+ peer->next = peer_hash[i];
+ peer_hash[i] = peer;
+ peer_hash_count[i]++;
+
+ i = peer->associd & HASH_MASK;
+ peer->ass_next = assoc_hash[i];
+ assoc_hash[i] = peer;
+ assoc_hash_count[i]++;
+
+ return peer;
+}
+
+
+/*
+ * peer_unconfig - remove the configuration bit from a peer
+ */
+int
+peer_unconfig(srcadr, dstadr)
+ struct sockaddr_in *srcadr;
+ struct interface *dstadr;
+{
+ register struct peer *peer;
+ int num_found;
+
+ num_found = 0;
+ peer = findexistingpeer(srcadr, (struct peer *)0);
+ while (peer != 0) {
+ if (peer->flags & FLAG_CONFIG
+ && (dstadr == 0 || peer->dstadr == dstadr)) {
+ num_found++;
+ /*
+ * Tricky stuff here. If the peer is polling us
+ * in active mode, turn off the configuration bit
+ * and make the mode passive. This allows us to
+ * avoid dumping a lot of history for peers we
+ * might choose to keep track of in passive mode.
+ * The protocol will eventually terminate undesirables
+ * on its own.
+ */
+ if (peer->hmode == MODE_ACTIVE
+ && peer->pmode == MODE_ACTIVE) {
+ peer->hmode = MODE_PASSIVE;
+ peer->flags &= ~FLAG_CONFIG;
+ } else {
+ unpeer(peer);
+ peer = 0;
+ }
+ }
+ peer = findexistingpeer(srcadr, peer);
+ }
+ return num_found;
+}
+
+
+/*
+ * peer_clr_stats - clear peer module stat counters
+ */
+void
+peer_clr_stats()
+{
+ findpeer_calls = 0;
+ assocpeer_calls = 0;
+ peer_allocations = 0;
+ peer_demobilizations = 0;
+ peer_timereset = current_time;
+}
+
+/*
+ * peer_reset - reset stat counters in a peer structure
+ */
+void
+peer_reset(peer)
+ struct peer *peer;
+{
+ if (peer == 0)
+ return;
+ peer->sent = 0;
+ peer->received = 0;
+ peer->processed = 0;
+ peer->badauth = 0;
+ peer->bogusorg = 0;
+ peer->bogusrec = 0;
+ peer->bogusdelay = 0;
+ peer->oldpkt = 0;
+ peer->seldisptoolarge = 0;
+ peer->selbroken = 0;
+ peer->seltooold = 0;
+ peer->timereset = current_time;
+}
+
+
+/*
+ * peer_all_reset - reset all peer stat counters
+ */
+void
+peer_all_reset()
+{
+ struct peer *peer;
+ int hash;
+
+ for (hash = 0; hash < HASH_SIZE; hash++)
+ for (peer = peer_hash[hash]; peer != 0; peer = peer->next)
+ peer_reset(peer);
+}
diff --git a/contrib/xntpd/xntpd/ntp_proto.c b/contrib/xntpd/xntpd/ntp_proto.c
new file mode 100644
index 000000000000..88e95bbf8d13
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_proto.c
@@ -0,0 +1,2168 @@
+/* ntp_proto.c,v 3.1 1993/07/06 01:11:23 jbj Exp
+ * ntp_proto.c - NTP version 3 protocol machinery
+ */
+#include <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)
+ memmove((char *)&sys_refid, PPSREFID, 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
+ memmove((char *)&sys_refid, PPSREFID, 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
+ memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO);
+ peer->hpoll = peer->minpoll;
+ peer->dispersion = NTP_MAXDISPERSE;
+ for (i = 0; i < NTP_SHIFT; i++)
+ peer->filter_error[i] = NTP_MAXDISPERSE;
+ poll_update(peer, peer->minpoll, POLL_RANDOMCHANGE);
+ clock_select();
+
+ /*
+ * Clear out the selection counters
+ */
+ peer->candidate = 0;
+ peer->select = 0;
+ peer->correct = 0;
+ peer->was_sane = 0;
+
+ /*
+ * Since we have a chance to correct possible funniness in
+ * our selection of interfaces on a multihomed host, do so
+ * by setting us to no particular interface.
+ */
+ peer->dstadr = any_interface;
+}
+
+
+/*
+ * clock_filter - add incoming clock sample to filter register and run
+ * the filter procedure to find the best sample.
+ */
+void
+clock_filter(peer, sample_offset, sample_delay, sample_error)
+ register struct peer *peer;
+ l_fp *sample_offset;
+ s_fp sample_delay;
+ u_fp sample_error;
+{
+ register int i;
+ register u_char *ord;
+ register s_fp sample_distance, sample_soffset, skew;
+ s_fp distance[NTP_SHIFT];
+
+#ifdef DEBUG
+ if (debug)
+ printf("clock_filter(%s, %s, %s, %s)\n",
+ ntoa(&peer->srcadr), lfptoa(sample_offset, 6),
+ fptoa(sample_delay, 5), ufptoa(sample_error, 5));
+#endif
+
+ /*
+ * Update sample errors and calculate distances.
+ * We know NTP_SKEWFACTOR == 16
+ */
+ skew = sys_clock - peer->update;
+ peer->update = sys_clock;
+ for (i = 0; i < NTP_SHIFT; i++) {
+ distance[i] = peer->filter_error[i];
+ if (peer->filter_error[i] < NTP_MAXDISPERSE) {
+ peer->filter_error[i] += skew;
+ distance[i] += (peer->filter_delay[i] >> 1);
+ }
+ }
+
+ /*
+ * We keep a sort by distance of the current contents of the
+ * shift registers. We update this by (1) removing the
+ * register we are going to be replacing from the sort, and
+ * (2) reinserting it based on the new distance value.
+ */
+ ord = peer->filter_order;
+ sample_distance = sample_error + (sample_delay >> 1);
+ sample_soffset = LFPTOFP(sample_offset);
+
+ for (i = 0; i < NTP_SHIFT-1; i++) /* find old value */
+ if (ord[i] == peer->filter_nextpt)
+ break;
+ for ( ; i < NTP_SHIFT-1; i++) /* i is current, move everything up */
+ ord[i] = ord[i+1];
+ /* Here, last slot in ord[] is empty */
+
+ if (sample_error >= NTP_MAXDISPERSE)
+ /*
+ * Last slot for this guy.
+ */
+ i = NTP_SHIFT-1;
+ else {
+ register int j;
+ register u_fp *errorp;
+
+ errorp = peer->filter_error;
+ /*
+ * Find where he goes in, then shift everyone else down
+ */
+ if (peer->hmode == MODE_BCLIENT) {
+ register s_fp *soffsetp;
+ /*
+ * Sort by offset. The most positive offset
+ * should correspond to the minimum delay.
+ */
+ soffsetp = peer->filter_soffset;
+ for (i = 0; i < NTP_SHIFT-1; i++)
+ if (errorp[ord[i]] >= NTP_MAXDISPERSE
+ || sample_soffset >= soffsetp[ord[i]])
+ break;
+ } else {
+ /*
+ * Sort by distance.
+ */
+ for (i = 0; i < NTP_SHIFT-1; i++)
+ if (errorp[ord[i]] >= NTP_MAXDISPERSE
+ || sample_distance <= distance[ord[i]])
+ break;
+ }
+
+ for (j = NTP_SHIFT-1; j > i; j--)
+ ord[j] = ord[j-1];
+ }
+ ord[i] = peer->filter_nextpt;
+
+ /*
+ * Got everything in order. Insert sample in current register
+ * and increment nextpt.
+ */
+ peer->filter_delay[peer->filter_nextpt] = sample_delay;
+ peer->filter_offset[peer->filter_nextpt] = *sample_offset;
+ peer->filter_soffset[peer->filter_nextpt] = sample_soffset;
+ peer->filter_error[peer->filter_nextpt] = sample_error;
+ distance[peer->filter_nextpt] = sample_distance;
+ peer->filter_nextpt++;
+ if (peer->filter_nextpt >= NTP_SHIFT)
+ peer->filter_nextpt = 0;
+
+ /*
+ * Now compute the dispersion, and assign values to delay and
+ * offset. If there are no samples in the register, delay and
+ * offset are not touched and dispersion is set to the maximum.
+ */
+ if (peer->filter_error[ord[0]] >= NTP_MAXDISPERSE) {
+ peer->dispersion = NTP_MAXDISPERSE;
+ } else {
+ register s_fp d;
+
+ peer->delay = peer->filter_delay[ord[0]];
+ peer->offset = peer->filter_offset[ord[0]];
+ peer->soffset = LFPTOFP(&peer->offset);
+ peer->dispersion = peer->filter_error[ord[0]];
+ for (i = 1; i < NTP_SHIFT; i++) {
+ if (peer->filter_error[ord[i]] >= NTP_MAXDISPERSE)
+ d = NTP_MAXDISPERSE;
+ else {
+ d = peer->filter_soffset[ord[i]]
+ - peer->filter_soffset[ord[0]];
+ if (d < 0)
+ d = -d;
+ if (d > NTP_MAXDISPERSE)
+ d = NTP_MAXDISPERSE;
+ }
+ /*
+ * XXX This *knows* NTP_FILTER is 1/2
+ */
+ peer->dispersion += (u_fp)(d) >> i;
+ }
+ /*
+ * Calculate synchronization distance backdated to
+ * sys_lastselect (clock_select will fix it).
+ * We know NTP_SKEWFACTOR == 16
+ */
+ d = peer->delay;
+ if (d < 0)
+ d = -d;
+ d += peer->rootdelay;
+ peer->synch = (d>>1)
+ + peer->rootdispersion + peer->dispersion
+ - (sys_clock - sys_lastselect);
+ }
+ /*
+ * We're done
+ */
+}
+
+
+/*
+ * clock_select - find the pick-of-the-litter clock
+ */
+void
+clock_select()
+{
+ register struct peer *peer;
+ register int i;
+ register int nlist, nl3;
+ register s_fp d, e;
+ register int j;
+ register int n;
+ register int allow, found, k;
+ /* XXX correct? */
+ s_fp low = 0x7ffffff;
+ s_fp high = 0x00000000;
+ u_fp synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK];
+ struct peer *osys_peer;
+ static int list_alloc = 0;
+ static struct endpoint *endpoint;
+ static int *index;
+ static struct peer **peer_list;
+ static int endpoint_size = 0, index_size = 0, peer_list_size = 0;
+
+#ifdef DEBUG
+ if (debug > 1)
+ printf("clock_select()\n");
+#endif
+
+ nlist = 0;
+ for (n = 0; n < HASH_SIZE; n++)
+ nlist += peer_hash_count[n];
+ if (nlist > list_alloc) {
+ if (list_alloc > 0) {
+ free(endpoint);
+ free(index);
+ free(peer_list);
+ }
+ while (list_alloc < nlist) {
+ list_alloc += 5;
+ endpoint_size += 5 * 3 * sizeof *endpoint;
+ index_size += 5 * 3 * sizeof *index;
+ peer_list_size += 5 * sizeof *peer_list;
+ }
+ endpoint = (struct endpoint *)emalloc(endpoint_size);
+ index = (int *)emalloc(index_size);
+ peer_list = (struct peer **)emalloc(peer_list_size);
+ }
+
+ /*
+ * This first chunk of code is supposed to go through all
+ * peers we know about to find the NTP_MAXLIST peers which
+ * are most likely to succeed. We run through the list
+ * doing the sanity checks and trying to insert anyone who
+ * looks okay. We are at all times aware that we should
+ * only keep samples from the top two strata and we only need
+ * NTP_MAXLIST of them.
+ */
+ nlist = nl3 = 0; /* none yet */
+ for (n = 0; n < HASH_SIZE; n++) {
+ for (peer = peer_hash[n]; peer != 0; peer = peer->next) {
+ /*
+ * Clear peer selection stats
+ */
+ peer->was_sane = 0;
+ peer->correct = 0;
+ peer->candidate = 0;
+ peer->select = 0;
+
+ peer->flags &= ~FLAG_SYSPEER;
+ /*
+ * Update synch distance (NTP_SKEWFACTOR == 16)
+ */
+ peer->synch += (sys_clock - sys_lastselect);
+
+ if (peer->reach == 0)
+ continue; /* unreachable */
+ if (peer->stratum > 1 &&
+ peer->refid == peer->dstadr->sin.sin_addr.s_addr)
+ continue; /* sync loop */
+ if (peer->stratum >= NTP_MAXSTRATUM ||
+ peer->stratum > sys_stratum)
+ continue; /* bad stratum */
+
+ if (peer->dispersion >= NTP_MAXDISPERSE) {
+ peer->seldisptoolarge++;
+ continue; /* too noisy or broken */
+ }
+ if (peer->org.l_ui < peer->reftime.l_ui) {
+ peer->selbroken++;
+ continue; /* very broken host */
+ }
+
+ /*
+ * This one seems sane.
+ */
+ peer->was_sane = 1;
+ peer_list[nlist++] = peer;
+
+ /*
+ * Insert each interval endpoint on the sorted list.
+ */
+ e = peer->soffset + peer->synch; /* Upper end */
+ for (i = nl3 - 1; i >= 0; i--) {
+ if (e >= endpoint[index[i]].val)
+ break;
+ index[i + 3] = index[i];
+ }
+ index[i + 3] = nl3;
+ endpoint[nl3].type = 1;
+ endpoint[nl3++].val = e;
+
+ e -= peer->synch; /* Center point */
+ for ( ; i >= 0; i--) {
+ if (e >= endpoint[index[i]].val)
+ break;
+ index[i + 2] = index[i];
+ }
+ index[i + 2] = nl3;
+ endpoint[nl3].type = 0;
+ endpoint[nl3++].val = e;
+
+ e -= peer->synch; /* Lower end */
+ for ( ; i >= 0; i--) {
+ if (e >= endpoint[index[i]].val)
+ break;
+ index[i + 1] = index[i];
+ }
+ index[i + 1] = nl3;
+ endpoint[nl3].type = -1;
+ endpoint[nl3++].val = e;
+ }
+ }
+ sys_lastselect = sys_clock;
+
+#ifdef DEBUG
+ if (debug > 2)
+ for (i = 0; i < nl3; i++)
+ printf("select: endpoint %2d %s\n",
+ endpoint[index[i]].type,
+ fptoa(endpoint[index[i]].val, 6));
+#endif
+
+ i = 0;
+ j = nl3 - 1;
+ allow = nlist; /* falsetickers assumed */
+ found = 0;
+ while (allow > 0) {
+ allow--;
+ for (n = 0; i <= j; i++) {
+ n += endpoint[index[i]].type;
+ if (n < 0)
+ break;
+ if (endpoint[index[i]].type == 0)
+ found++;
+ }
+ for (n = 0; i <= j; j--) {
+ n += endpoint[index[j]].type;
+ if (n > 0)
+ break;
+ if (endpoint[index[j]].type == 0)
+ found++;
+ }
+ if (found > allow)
+ break;
+ low = endpoint[index[i++]].val;
+ high = endpoint[index[j--]].val;
+ }
+ if ((allow << 1) >= nlist) {
+ if (debug)
+ printf("clock_select: no intersection\n");
+ if (sys_peer != 0)
+ report_event(EVNT_PEERSTCHG, (struct peer *)0);
+ sys_peer = 0;
+ sys_stratum = STRATUM_UNSPEC;
+ return;
+ }
+
+#ifdef DEBUG
+ if (debug > 2)
+ printf("select: low %s high %s\n", fptoa(low, 6),
+ fptoa(high, 6));
+#endif
+
+ /*
+ * Clustering algorithm. Process intersection list to discard
+ * outlyers. First, construct candidate list in cluster order.
+ * Cluster order is determined by the sum of peer
+ * synchronization distance plus scaled stratum.
+ */
+
+ j = 0;
+ for (i = 0; i < nlist; i++) {
+ peer = peer_list[i];
+ if (peer->soffset < low || high < peer->soffset)
+ continue;
+ peer->correct = 1;
+ d = peer->synch + ((U_LONG)peer->stratum << NTP_DISPFACTOR);
+ if (j >= NTP_MAXCLOCK) {
+ if (d >= synch[j - 1])
+ continue;
+ else
+ j--;
+ }
+ for (k = j; k > 0; k--) {
+ if (d >= synch[k - 1])
+ break;
+ synch[k] = synch[k - 1];
+ peer_list[k] = peer_list[k - 1];
+ }
+ peer_list[k] = peer;
+ synch[k] = d;
+ j++;
+ }
+ nlist = j;
+#ifdef DEBUG
+ if (debug > 2)
+ for (i = 0; i < nlist; i++)
+ printf("select: candidate %s cdist %s\n",
+ ntoa(&peer_list[i]->srcadr),
+ fptoa(synch[i], 6));
+#endif
+
+ /*
+ * Now, prune outlyers by root dispersion.
+ */
+
+ for (i = 0; i < nlist; i++) {
+ peer = peer_list[i];
+ peer->candidate = i + 1;
+ error[i] = peer_list[i]->rootdispersion +
+ peer_list[i]->dispersion +
+ (sys_clock - peer_list[i]->update);
+ }
+ while (1) {
+ u_fp maxd = 0;
+ e = error[0];
+ for (k = i = nlist - 1; i >= 0; i--) {
+ u_fp sdisp = 0;
+
+ for (j = nlist - 1; j >= 0; j--) {
+ d = peer_list[i]->soffset
+ - peer_list[j]->soffset;
+ if (d < 0)
+ d = -d;
+ sdisp += d;
+ sdisp = ((sdisp>>1) + sdisp) >> 1;
+ }
+ peer_list[i]->selectdisp = sdisp;
+ if (sdisp > maxd) {
+ maxd = sdisp;
+ k = i;
+ }
+ if (error[i] < e)
+ e = error[i];
+ }
+ if (nlist <= NTP_MINCLOCK || maxd <= e ||
+ peer_list[k]->flags & FLAG_PREFER)
+ break;
+ for (j = k + 1; j < nlist; j++) {
+ peer_list[j - 1] = peer_list[j];
+ error[j - 1] = error[j];
+ }
+ nlist--;
+ }
+
+#ifdef DEBUG
+ if (debug > 1) {
+ for (i = 0; i < nlist; i++)
+ printf("select: survivor %s offset %s, cdist %s\n",
+ ntoa(&peer_list[i]->srcadr),
+ lfptoa(&peer_list[i]->offset, 6),
+ fptoa(synch[i], 5));
+ }
+#endif
+
+ /*
+ * What remains is a list of less than NTP_MINCLOCK peers.
+ * First record their order, then choose a peer. If the
+ * head of the list has a lower stratum than sys_peer
+ * choose him right off. If not, see if sys_peer is in
+ * the list. If so, keep him. If not, take the top of
+ * the list anyway. Also, clamp the polling intervals.
+ */
+ osys_peer = sys_peer;
+ for (i = nlist - 1; i >= 0; i--) {
+ if (peer_list[i]->flags & FLAG_PREFER)
+ sys_peer = peer_list[i];
+ peer_list[i]->select = i + 1;
+ peer_list[i]->flags |= FLAG_SYSPEER;
+ poll_update(peer_list[i], peer_list[i]->hpoll,
+ POLL_RANDOMCHANGE);
+ }
+ if (sys_peer == 0 || sys_peer->stratum > peer_list[0]->stratum) {
+ sys_peer = peer_list[0];
+ } else {
+ for (i = 1; i < nlist; i++)
+ if (peer_list[i] == sys_peer)
+ break;
+ if (i < nlist)
+ sys_wanderhold++;
+ else
+ sys_peer = peer_list[0];
+ }
+
+ /*
+ * If we got a new system peer from all of this, report the event.
+ */
+ if (osys_peer != sys_peer)
+ report_event(EVNT_PEERSTCHG, (struct peer *)0);
+
+ /*
+ * Combine the offsets of the survivors to form a weighted
+ * offset.
+ */
+ clock_combine(peer_list, nlist);
+}
+
+/*
+ * clock_combine - combine offsets from selected peers
+ *
+ * Note: this routine uses only those peers at the lowest stratum.
+ * Strictly speaking, this is at variance with the spec.
+ */
+void
+clock_combine(peers, npeers)
+ struct peer **peers;
+ int npeers;
+{
+ register int i, j, k;
+ register u_fp a, b, d;
+ u_fp synch[NTP_MAXCLOCK];
+ l_fp coffset[NTP_MAXCLOCK];
+ l_fp diff;
+
+ /*
+ * Sort peers by cluster distance as in the outlyer algorithm. If
+ * the preferred peer is found, use its offset only.
+ */
+ k = 0;
+ for (i = 0; i < npeers; i++) {
+ if (peers[i]->stratum > sys_peer->stratum) continue;
+ if (peers[i]->flags & FLAG_PREFER) {
+ sys_offset = peers[i]->offset;
+ pps_update = current_time;
+#ifdef DEBUG
+ printf("combine: prefer offset %s\n",
+ lfptoa(&sys_offset, 6));
+#endif
+ return;
+ }
+ d = peers[i]->synch;
+ for (j = k; j > 0; j--) {
+ if (synch[j - 1] <= d)
+ break;
+ synch[j] = synch[j - 1];
+ coffset[j] = coffset[j - 1];
+ }
+ synch[j] = d;
+ coffset[j] = peers[i]->offset;
+ k++;
+ }
+ /*
+ * Succesively combine the two offsets with the highest
+ * distance and enter the result into the sorted list.
+ */
+ for (i = k - 2; i >= 0; i--) {
+ /*
+ * The possible weights for the most distant offset
+ * are 1/2, 1/4, 1/8 and zero. We combine the synch
+ * distances as if they were variances of the offsets;
+ * the given weights allow us to stay within 16/15 of
+ * the optimum combined variance at each step, and
+ * within 8/7 on any series.
+ *
+ * The breakeven points for the weigths are found
+ * where the smaller distance is 3/8, 3/16 and 1/16
+ * of the sum, respectively.
+ */
+ d = synch[i];
+ a = (d + synch[i + 1]) >> 2; /* (d1+d2)/4 */
+ b = a>>1; /* (d1+d2)/8 */
+ if (d <= (b>>1)) /* d1 <= (d1+d2)/16 */
+ /*
+ * Below 1/16, no combination is done,
+ * we just drop the distant offset.
+ */
+ continue;
+ /*
+ * The offsets are combined by shifting their
+ * difference the appropriate number of times and
+ * adding it back in.
+ */
+ diff = coffset[i + 1];
+ L_SUB(&diff, &coffset[i]);
+ L_RSHIFT(&diff);
+ if (d >= a + b) { /* d1 >= 3(d1+d2)/8 */
+ /*
+ * Above 3/8, the weight is 1/2, and the
+ * combined distance is (d1+d2)/4
+ */
+ d = a;
+ } else {
+ a >>= 2; /* (d1+d2)/16 */
+ L_RSHIFT(&diff);
+ if (d >= a + b) { /* d1 >= 3(d1+d2)/16 */
+ /*
+ * Between 3/16 and 3/8, the weight
+ * is 1/4, and the combined distance
+ * is (9d1+d2)/16 = d1/2 + (d1+d2)/16
+ */
+ d = (d>>1) + a;
+ } else {
+ /*
+ * Between 1/16 and 3/16, the weight
+ * is 1/8, and the combined distance
+ * is (49d1+d2)/64 = 3d1/4+(d1+d2)/64
+ * (We know d > a, so the shift is safe).
+ */
+ L_RSHIFT(&diff);
+ d -= (d - a)>>2;
+ }
+ }
+ /*
+ * Now we can make the combined offset and insert it
+ * in the list.
+ */
+ L_ADD(&diff, &coffset[i]);
+ for (j = i; j > 0; j--) {
+ if (d >= synch[j - 1])
+ break;
+ synch[j] = synch[j - 1];
+ coffset[j] = coffset[j - 1];
+ }
+ synch[j] = d;
+ coffset[j] = diff;
+ }
+ /*
+ * The result is put where clock_update() can find it.
+ */
+ sys_offset = coffset[0];
+
+#ifdef DEBUG
+ if (debug) {
+ printf("combine: offset %s\n", lfptoa(&sys_offset, 6));
+ }
+#endif
+
+}
+
+
+
+/*
+ * fast_xmit - fast path send for stateless (non-)associations
+ */
+void
+fast_xmit(rbufp, rmode, authentic)
+ struct recvbuf *rbufp;
+ int rmode;
+ int authentic;
+{
+ struct pkt xpkt;
+ register struct pkt *rpkt;
+ u_char xmode;
+ u_short xkey = 0;
+ int docrypt = 0;
+ l_fp xmt_ts;
+
+#ifdef DEBUG
+ if (debug > 1)
+ printf("fast_xmit(%s, %d)\n", ntoa(&rbufp->recv_srcadr), rmode);
+#endif
+
+ /*
+ * Make up new packet and send it quick
+ */
+ rpkt = &rbufp->recv_pkt;
+ if (rmode == MODE_ACTIVE)
+ xmode = MODE_PASSIVE;
+ else
+ xmode = MODE_SERVER;
+
+ if (rbufp->recv_length >= LEN_PKT_MAC) {
+ docrypt = rbufp->recv_length - LEN_PKT_NOMAC;
+ if (authentic)
+ xkey = ntohl(rpkt->keyid);
+ }
+
+ xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap,
+ PKT_VERSION(rpkt->li_vn_mode), xmode);
+ xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
+ xpkt.ppoll = max(NTP_MINPOLL, rpkt->ppoll);
+ xpkt.precision = sys_precision;
+ xpkt.rootdelay = HTONS_FP(sys_rootdelay);
+ xpkt.rootdispersion = HTONS_FP(sys_rootdispersion +
+ (FP_SECOND >> (-(int)sys_precision)) +
+ LFPTOFP(&sys_refskew));
+ xpkt.refid = sys_refid;
+ HTONL_FP(&sys_reftime, &xpkt.reftime);
+ xpkt.org = rpkt->xmt;
+ HTONL_FP(&rbufp->recv_time, &xpkt.rec);
+
+ /*
+ * If we are encrypting, do it. Else don't. Easy.
+ */
+ if (docrypt) {
+ int maclen;
+
+ xpkt.keyid = htonl(xkey);
+ auth1crypt(xkey, (U_LONG *)&xpkt, LEN_PKT_NOMAC);
+ get_systime(&xmt_ts);
+ L_ADDUF(&xmt_ts, sys_authdelay);
+ HTONL_FP(&xmt_ts, &xpkt.xmt);
+ maclen = auth2crypt(xkey, (U_LONG *)&xpkt, LEN_PKT_NOMAC);
+ sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, &xpkt,
+ LEN_PKT_NOMAC + maclen);
+ } else {
+ /*
+ * Get xmt timestamp, then send it without mac field
+ */
+ get_systime(&xmt_ts);
+ HTONL_FP(&xmt_ts, &xpkt.xmt);
+ sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, &xpkt,
+ LEN_PKT_NOMAC);
+ }
+}
+
+/* Find the precision of the system clock by watching how the current time
+ * changes as we read it repeatedly.
+ *
+ * struct timeval is only good to 1us, which may cause problems as machines
+ * get faster, but until then the logic goes:
+ *
+ * If a machine has precision (i.e. accurate timing info) > 1us, then it will
+ * probably use the "unused" low order bits as a counter (to force time to be
+ * a strictly increaing variable), incrementing it each time any process
+ * requests the time [[ or maybe time will stand still ? ]].
+ *
+ * SO: the logic goes:
+ *
+ * IF the difference from the last time is "small" (< MINSTEP)
+ * THEN this machine is "counting" with the low order bits
+ * ELIF this is not the first time round the loop
+ * THEN this machine *WAS* counting, and has now stepped
+ * ELSE this machine has precision < time to read clock
+ *
+ * SO: if it exits on the first loop, assume "full accuracy" (1us)
+ * otherwise, take the log2(observered difference, rounded UP)
+ *
+ * MINLOOPS > 1 ensures that even if there is a STEP between the initial call
+ * and the first loop, it doesn't stop too early.
+ * Making it even greater allows MINSTEP to be reduced, assuming that the
+ * chance of MINSTEP-1 other processes getting in and calling gettimeofday
+ * between this processes's calls.
+ * Reducing MINSTEP may be necessary as this sets an upper bound for the time
+ * to actually call gettimeofday.
+ */
+
+#define DUSECS 1000000 /* us's as returned by gettime */
+#define HUSECS (1024*1024) /* Hex us's -- used when shifting etc */
+#define MINSTEP 5 /* some systems increment uS on each call */
+ /* Don't use "1" as some *other* process may read too*/
+ /*We assume no system actually *ANSWERS* in this time*/
+#define MAXLOOPS DUSECS /* if no STEP in a complete second, then FAST machine*/
+#define MINLOOPS 2 /* ensure at least this many loops */
+
+int default_get_precision()
+{
+ struct timeval tp;
+ struct timezone tzp;
+ long last;
+ int i;
+ long diff;
+ long val;
+ int minsteps = 2; /* need at least this many steps */
+
+ GETTIMEOFDAY(&tp, &tzp);
+ last = tp.tv_usec;
+ for (i = - --minsteps; i< MAXLOOPS; i++) {
+ gettimeofday(&tp, &tzp);
+ diff = tp.tv_usec - last;
+ if (diff < 0) diff += DUSECS;
+ if (diff > MINSTEP) if (minsteps-- <= 0) break;
+ last = tp.tv_usec;
+ }
+
+ syslog(LOG_INFO, "precision calculation given %dus after %d loop%s",
+ diff, i, (i==1) ? "" : "s");
+
+ diff = (diff*3) / 2; /* round it up 1.5 is approx sqrt(2) */
+ if (i >= MAXLOOPS) diff = 1; /* No STEP, so FAST machine */
+ if (i == 0) diff = 1; /* time to read clock >= precision */
+ for (i=0, val=HUSECS; val>0; i--, val >>= 1) if (diff >= val) return i;
+ return DEFAULT_SYS_PRECISION /* Something's BUST, so lie ! */;
+}
+
+/*
+ * init_proto - initialize the protocol module's data
+ */
+void
+init_proto()
+{
+ l_fp dummy;
+
+ /*
+ * Fill in the sys_* stuff. Default is don't listen
+ * to broadcasting, don't authenticate.
+ */
+ sys_leap = LEAP_NOTINSYNC;
+ sys_stratum = STRATUM_UNSPEC;
+ sys_precision = (s_char)default_get_precision();
+ sys_rootdelay = 0;
+ sys_rootdispersion = 0;
+ sys_refid = 0;
+ sys_reftime.l_ui = sys_reftime.l_uf = 0;
+ sys_refskew.l_i = NTP_MAXSKEW; sys_refskew.l_f = 0;
+ sys_peer = 0;
+ sys_poll = NTP_MINPOLL;
+ get_systime(&dummy);
+ sys_lastselect = sys_clock;
+
+ sys_bclient = 0;
+ sys_bdelay = DEFBROADDELAY;
+
+ sys_authenticate = 0;
+
+ sys_stattime = 0;
+ sys_badstratum = 0;
+ sys_oldversionpkt = 0;
+ sys_newversionpkt = 0;
+ sys_badlength = 0;
+ sys_unknownversion = 0;
+ sys_processed = 0;
+ sys_badauth = 0;
+ sys_wanderhold = 0;
+
+ syslog(LOG_NOTICE, "default precision is initialized to 2**%d", sys_precision);
+}
+
+
+/*
+ * proto_config - configure the protocol module
+ */
+void
+proto_config(item, value)
+ int item;
+ LONG value;
+{
+ /*
+ * Figure out what he wants to change, then do it
+ */
+ switch (item) {
+ case PROTO_BROADCLIENT:
+ /*
+ * Turn on/off facility to listen to broadcasts
+ */
+ sys_bclient = (int)value;
+ if (sys_bclient)
+ io_setbclient();
+ else
+ io_unsetbclient();
+ break;
+
+ case PROTO_PRECISION:
+ /*
+ * Set system precision
+ */
+ sys_precision = (s_char)value;
+ break;
+
+ case PROTO_BROADDELAY:
+ /*
+ * Set default broadcast delay
+ */
+ sys_bdelay = (((U_LONG)value) + 0x00000800) & 0xfffff000;
+ break;
+
+ case PROTO_AUTHENTICATE:
+ /*
+ * Specify the use of authenticated data
+ */
+ sys_authenticate = (int)value;
+ break;
+
+
+ case PROTO_AUTHDELAY:
+ /*
+ * Provide an authentication delay value. Round it to
+ * the microsecond. This is crude.
+ */
+ sys_authdelay = (((U_LONG)value) + 0x00000800) & 0xfffff000;
+ break;
+
+ case PROTO_MAXSKEW:
+ /*
+ * Set the maximum skew value
+ */
+ syslog(LOG_ERR,
+ "proto_config: attempt to set maxskew (obsolete)");
+ break;
+
+ case PROTO_SELECT:
+ /*
+ * Set the selection algorithm.
+ */
+ syslog(LOG_ERR,
+ "proto_config: attempt to set selection algorithm (obsolete)");
+ break;
+
+ default:
+ /*
+ * Log this error
+ */
+ syslog(LOG_ERR, "proto_config: illegal item %d, value %ld",
+ item, value);
+ break;
+ }
+}
+
+
+/*
+ * proto_clr_stats - clear protocol stat counters
+ */
+void
+proto_clr_stats()
+{
+ sys_badstratum = 0;
+ sys_oldversionpkt = 0;
+ sys_newversionpkt = 0;
+ sys_unknownversion = 0;
+ sys_badlength = 0;
+ sys_processed = 0;
+ sys_badauth = 0;
+ sys_wanderhold = 0;
+ sys_stattime = current_time;
+}
diff --git a/contrib/xntpd/xntpd/ntp_refclock.c b/contrib/xntpd/xntpd/ntp_refclock.c
new file mode 100644
index 000000000000..5199a1acbd26
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_refclock.c
@@ -0,0 +1,439 @@
+/* ntp_refclock.c,v 3.1 1993/07/06 01:11:25 jbj Exp
+ * ntp_refclock - processing support for reference clocks
+ */
+#include <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/contrib/xntpd/xntpd/ntp_request.c b/contrib/xntpd/xntpd/ntp_request.c
new file mode 100644
index 000000000000..c19d1925a818
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_request.c
@@ -0,0 +1,2341 @@
+/* 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.
+ */
+ memmove(&rpkt.data[0], exbuf, 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;
+
+ memset((char *)&addr, 0, sizeof addr);
+ addr.sin_family = AF_INET;
+ items = INFO_NITEMS(inpkt->err_nitems);
+ ipl = (struct info_peer_list *) inpkt->data;
+ ip = (struct info_peer *)prepare_pkt(srcadr, inter, inpkt,
+ sizeof(struct info_peer));
+ 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;
+
+ memset((char *)&addr, 0, sizeof addr);
+ addr.sin_family = AF_INET;
+ items = INFO_NITEMS(inpkt->err_nitems);
+ ipl = (struct info_peer_list *) inpkt->data;
+ ip = (struct info_peer_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;
+ memset((char *)&peeraddr, 0, sizeof(struct sockaddr_in));
+ peeraddr.sin_family = AF_INET;
+ peeraddr.sin_port = htons(NTP_PORT);
+
+ /*
+ * Make sure the address is valid
+ */
+#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;
+ memset((char *)&matchaddr, 0, sizeof(struct sockaddr_in));
+ memset((char *)&matchmask, 0, sizeof(struct sockaddr_in));
+ matchaddr.sin_family = AF_INET;
+ matchmask.sin_family = AF_INET;
+
+ 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
+ */
+ memset((char *)&laddr, 0, 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;
+
+ memset((char *)&addr, 0, 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;
+ }
+
+ clock.kv_list = (struct ctl_var *)0;
+
+ 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);
+
+ free_varlist(clock.kv_list);
+
+ 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;
+
+ memset((char *)&addr, 0, sizeof addr);
+ memset((char *)&clock, 0, 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;
+
+ memset((char *)&addr, 0, 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;
+ }
+
+ memset((char *)&bug, 0, sizeof bug);
+ refclock_buginfo(&addr, &bug);
+ if (bug.nvalues == 0 && bug.ntimes == 0) {
+ req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
+ return;
+ }
+
+ ic->clockadr = 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/contrib/xntpd/xntpd/ntp_restrict.c b/contrib/xntpd/xntpd/ntp_restrict.c
new file mode 100644
index 000000000000..51d896806207
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_restrict.c
@@ -0,0 +1,297 @@
+/* ntp_restrict.c,v 3.1 1993/07/06 01:11:28 jbj Exp
+ * ntp_restrict.c - find out what restrictions this host is running under
+ */
+#include <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;
+ memset((char *)resinit, 0, 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));
+ memset((char *)rl, 0,
+ INCRESLIST*sizeof(struct restrictlist));
+
+ for (i = 0; i < INCRESLIST; i++) {
+ rl->next = resfree;
+ resfree = rl;
+ rl++;
+ }
+ numresfree = INCRESLIST;
+ }
+
+ rl = resfree;
+ resfree = rl->next;
+ numresfree--;
+
+ rl->addr = addr;
+ rl->mask = mask;
+ rl->mflags = (u_short)mflags;
+
+ rl->next = rlprev->next;
+ rlprev->next = rl;
+ restrictcount++;
+ }
+ 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--;
+ memset((char *)rl, 0, sizeof(struct restrictlist));
+
+ rl->next = resfree;
+ resfree = rl;
+ numresfree++;
+ }
+ break;
+
+ default:
+ /* Oh, well */
+ break;
+ }
+
+ /* done! */
+}
diff --git a/contrib/xntpd/xntpd/ntp_timer.c b/contrib/xntpd/xntpd/ntp_timer.c
new file mode 100644
index 000000000000..e3ba54cd39bc
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_timer.c
@@ -0,0 +1,187 @@
+/* ntp_timer.c,v 3.1 1993/07/06 01:11:29 jbj Exp
+ * ntp_event.c - event timer support routines
+ */
+#include <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/contrib/xntpd/xntpd/ntp_unixclock.c b/contrib/xntpd/xntpd/ntp_unixclock.c
new file mode 100644
index 000000000000..6b661835dbb7
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_unixclock.c
@@ -0,0 +1,568 @@
+/* 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(SYS_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 SYS_BSDI
+#include <sys/proc.h>
+#endif /* SYS_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 /*RS6000*/
+#if SYS_DOMAINOS
+ *tickadj = 668;
+#else /*SYS_DOMAINOS*/
+ *tickadj = 500 / HZ;
+#endif /*SYS_DOMAINOS*/
+#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/contrib/xntpd/xntpd/ntp_util.c b/contrib/xntpd/xntpd/ntp_util.c
new file mode 100644
index 000000000000..4cbb7ac27f53
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntp_util.c
@@ -0,0 +1,466 @@
+/* ntp_util.c,v 3.1 1993/07/06 01:11:31 jbj Exp
+ * ntp_util.c - stuff I didn't have any other place for
+ */
+#include <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_INFO, "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")));
+ memmove(stats_drift_file, value, len+1);
+ memmove(stats_temp_file, value, len);
+ memmove(stats_temp_file + len, ".TEMP", 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));
+
+ memmove(key_file_name, keyfile, len+1);
+
+ authreadkeys(key_file_name);
+}
+
+
+/*
+ * rereadkeys - read the authentication key file over again.
+ */
+void
+rereadkeys()
+{
+ if (key_file_name != 0)
+ authreadkeys(key_file_name);
+}
diff --git a/contrib/xntpd/xntpd/ntpd.c b/contrib/xntpd/xntpd/ntpd.c
new file mode 100644
index 000000000000..abe86d945151
--- /dev/null
+++ b/contrib/xntpd/xntpd/ntpd.c
@@ -0,0 +1,439 @@
+/* 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 <termios.h>
+#endif
+
+#if (defined(SYS_SOLARIS)&&!defined(bsd)) || defined(__svr4__)
+#include <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) || defined(SYS_AUX3) || defined(SYS_AIX)
+ (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 */
+#ifdef SYS_DOMAINOS
+/*
+ * This breaks... the program fails to listen to any packets coming
+ * in on the UDP socket. So how do you break terminal affiliation?
+ */
+#else /* SYS_DOMAINOS */
+ {
+ int fid;
+
+ fid = open("/dev/tty", 2);
+ if (fid >= 0) {
+ (void) ioctl(fid, (U_LONG) TIOCNOTTY,
+ (char *) 0);
+ (void) close(fid);
+ }
+ (void) setpgrp(0, getpid());
+ }
+#endif /* SYS_DOMAINOS */
+#endif /* SYS_HPUX */
+#endif /* NTP_POSIX_SOURCE */
+ }
+#endif /* BSD19906 */
+#ifdef DEBUG
+ }
+#endif /* DEBUG */
+#endif /* NODETACH */
+
+ /*
+ * Logging. This may actually work on the gizmo board. Find a name
+ * to log with by using the basename of argv[0]
+ */
+ cp = strrchr(argv[0], '/');
+ if (cp == 0)
+ cp = argv[0];
+ else
+ cp++;
+
+#ifndef LOG_DAEMON
+ openlog(cp, LOG_PID);
+#else
+
+#ifndef LOG_NTP
+#define LOG_NTP LOG_DAEMON
+#endif
+ openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
+#ifdef DEBUG
+ if (debug)
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ else
+#endif /* DEBUG */
+ setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
+#endif /* LOG_DAEMON */
+
+ syslog(LOG_NOTICE, Version);
+
+
+#if defined(SYS_HPUX)
+ /*
+ * Lock text into ram, set real time priority
+ */
+ if (plock(TXTLOCK) < 0)
+ syslog(LOG_ERR, "plock() error: %m");
+ if (rtprio(0, 120) < 0)
+ syslog(LOG_ERR, "rtprio() error: %m");
+#else
+#if defined(PROCLOCK) && defined(LOCK_PROCESS)
+ /*
+ * lock the process into memory
+ */
+ if (plock(PROCLOCK) < 0)
+ syslog(LOG_ERR, "plock(): %m");
+#endif
+#if defined(NTPD_PRIO) && NTPD_PRIO != 0
+ /*
+ * Set the priority.
+ */
+#ifdef HAVE_ATT_NICE
+ nice (NTPD_PRIO);
+#endif /* HAVE_ATT_NICE */
+#ifdef HAVE_BSD_NICE
+ (void) setpriority(PRIO_PROCESS, 0, NTPD_PRIO);
+#endif /* HAVE_BSD_NICE */
+
+#endif /* !PROCLOCK || !LOCK_PROCESS */
+#endif /* SYS_HPUX */
+
+ /*
+ * Set up signals we pay attention to locally.
+ */
+#ifdef SIGDIE1
+ (void) signal_no_reset(SIGDIE1, finish);
+#endif /* SIGDIE1 */
+#ifdef SIGDIE2
+ (void) signal_no_reset(SIGDIE2, finish);
+#endif /* SIGDIE2 */
+#ifdef SIGDIE3
+ (void) signal_no_reset(SIGDIE3, finish);
+#endif /* SIGDIE3 */
+#ifdef SIGDIE4
+ (void) signal_no_reset(SIGDIE4, finish);
+#endif /* SIGDIE4 */
+
+#ifdef DEBUG
+ (void) signal_no_reset(MOREDEBUGSIG, moredebug);
+ (void) signal_no_reset(LESSDEBUGSIG, lessdebug);
+#else
+ (void) signal_no_reset(MOREDEBUGSIG, SIG_IGN);
+ (void) signal_no_reset(LESSDEBUGSIG, SIG_IGN);
+#endif /* DEBUG */
+
+ /*
+ * Call the init_ routines to initialize the data structures.
+ * Note that init_systime() may run a protocol to get a crude
+ * estimate of the time as an NTP client when running on the
+ * gizmo board. It is important that this be run before
+ * init_subs() since the latter uses the time of day to seed
+ * the random number generator. That is not the only
+ * dependency between these, either, be real careful about
+ * reordering.
+ */
+ init_auth();
+ init_util();
+ init_restrict();
+ init_mon();
+ init_systime();
+ init_timer();
+ init_lib();
+ init_random();
+ init_request();
+ init_control();
+ init_leap();
+ init_peer();
+#ifdef REFCLOCK
+ init_refclock();
+#endif
+ init_proto();
+ init_io();
+ init_loopfilter();
+
+ /*
+ * Get configuration. This (including argument list parsing) is
+ * done in a separate module since this will definitely be different
+ * for the gizmo board.
+ */
+ getconfig(argc, argv);
+ initializing = 0;
+
+ /*
+ * Report that we're up to any trappers
+ */
+ report_event(EVNT_SYSRESTART, (struct peer *)0);
+
+ /*
+ * Use select() on all on all input fd's for unlimited
+ * time. select() will terminate on SIGALARM or on the
+ * reception of input. Using select() means we can't do
+ * robust signal handling and we get a potential race
+ * between checking for alarms and doing the select().
+ * Mostly harmless, I think.
+ */
+ was_alarmed = 0;
+ rbuflist = (struct recvbuf *)0;
+ for (;;) {
+#ifndef HAVE_SIGNALED_IO
+ extern fd_set activefds;
+ extern int maxactivefd;
+
+ fd_set rdfdes;
+ int nfound;
+#else
+ block_io_and_alarm();
+#endif
+
+
+ rbuflist = getrecvbufs(); /* get received buffers */
+ if (alarm_flag) { /* alarmed? */
+ was_alarmed = 1;
+ alarm_flag = 0;
+ }
+
+ if (!was_alarmed && rbuflist == (struct recvbuf *)0) {
+ /*
+ * Nothing to do. Wait for something.
+ */
+#ifndef HAVE_SIGNALED_IO
+ rdfdes = activefds;
+ nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
+ (fd_set *)0, (struct timeval *)0);
+ if (nfound > 0) {
+ l_fp ts;
+
+ get_systime(&ts);
+ (void)input_handler(&ts);
+ }
+ else if (nfound == -1 && errno != EINTR) {
+ syslog(LOG_ERR, "select() error: %m");
+ }
+#else
+ wait_for_signal();
+#endif
+ if (alarm_flag) { /* alarmed? */
+ was_alarmed = 1;
+ alarm_flag = 0;
+ }
+ rbuflist = getrecvbufs(); /* get received buffers */
+ }
+#ifdef HAVE_SIGNALED_IO
+ unblock_io_and_alarm();
+#endif
+
+ /*
+ * Out here, signals are unblocked. Call timer routine
+ * to process expiry.
+ */
+ if (was_alarmed) {
+ timer();
+ was_alarmed = 0;
+ }
+
+ /*
+ * Call the data procedure to handle each received
+ * packet.
+ */
+ while (rbuflist != (struct recvbuf *)0) {
+ rbuf = rbuflist;
+ rbuflist = rbuf->next;
+ (rbuf->receiver)(rbuf);
+ freerecvbuf(rbuf);
+ }
+ /*
+ * Go around again
+ */
+ }
+}
+
+
+#ifdef SIGDIE1
+/*
+ * finish - exit gracefully
+ */
+static RETSIGTYPE
+finish(sig)
+int sig;
+{
+
+ /*
+ * Log any useful info before exiting.
+ */
+#ifdef notdef
+ log_exit_stats();
+#endif
+ exit(0);
+}
+#endif /* SIGDIE1 */
+
+
+#ifdef DEBUG
+/*
+ * moredebug - increase debugging verbosity
+ */
+static RETSIGTYPE
+moredebug(sig)
+int sig;
+{
+ if (debug < 255) {
+ debug++;
+ syslog(LOG_DEBUG, "debug raised to %d", debug);
+ }
+}
+
+/*
+ * lessdebug - decrease debugging verbosity
+ */
+static RETSIGTYPE
+lessdebug(sig)
+int sig;
+{
+ if (debug > 0) {
+ debug--;
+ syslog(LOG_DEBUG, "debug lowered to %d", debug);
+ }
+}
+#endif /* DEBUG */
diff --git a/contrib/xntpd/xntpd/refclock_as2201.c b/contrib/xntpd/xntpd/refclock_as2201.c
new file mode 100644
index 000000000000..97b5837c2f3b
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_as2201.c
@@ -0,0 +1,995 @@
+/*
+ * 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(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#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
+ */
+ memset((char *)gpsunits, 0, sizeof gpsunits);
+ memset((char *)unitinuse, 0, 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(HAVE_TERMIOS)
+ /*
+ * POSIX 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;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#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));
+ }
+ }
+ memset((char *)gps, 0, 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)
+ memmove((char *)&peer->refid, GPSREFID, 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)
+ memmove((char *)&peer->refid,
+ GPSREFID, 4);
+ else
+ peer->refid = htonl(GPSHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEFLAG4) {
+ sloppyclockflag[unit] = in->flags & CLK_FLAG4;
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_GPS_AS2201;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG4;
+ out->clockdesc = GPSDESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgetime2.l_ui = 0;
+ out->fudgetime2.l_uf = 0;
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = 0;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ gps = gpsunits[unit];
+ out->lencode = LENTOC;
+ out->lastcode = gps->stats;
+ out->timereset = current_time - gps->timestarted;
+ out->polls = gps->polls;
+ out->noresponse = gps->noreply;
+ out->badformat = gps->badformat;
+ out->baddata = gps->baddata;
+ out->lastevent = gps->lastevent;
+ out->currentstatus = gps->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+/*
+ * as2201_buginfo - return clock dependent debugging info
+ */
+static void
+as2201_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct gpsunit *gps;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gps_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ gps = gpsunits[unit];
+
+ bug->nvalues = 10;
+ bug->ntimes = 5;
+ if (gps->lasttime != 0)
+ bug->values[0] = current_time - gps->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = (U_LONG)gps->reason;
+ bug->values[2] = (U_LONG)gps->year;
+ bug->values[3] = (U_LONG)gps->day;
+ bug->values[4] = (U_LONG)gps->hour;
+ bug->values[5] = (U_LONG)gps->minute;
+ bug->values[6] = (U_LONG)gps->second;
+ bug->values[7] = (U_LONG)gps->msec;
+ bug->values[8] = gps->noreply;
+ bug->values[9] = gps->yearstart;
+ bug->stimes = 0x1c;
+ bug->times[0] = gps->lastref;
+ bug->times[1] = gps->lastrec;
+ bug->times[2] = gps->offset[0];
+ bug->times[3] = gps->offset[1];
+ bug->times[4] = gps->offset[2];
+}
+#endif
diff --git a/contrib/xntpd/xntpd/refclock_chu.c b/contrib/xntpd/xntpd/refclock_chu.c
new file mode 100644
index 000000000000..1c7c3bfa61c1
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_chu.c
@@ -0,0 +1,1140 @@
+/*
+ * 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(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#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
+ */
+ memset((char *)chuunits, 0, sizeof chuunits);
+ memset((char *)unitinuse, 0, 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(HAVE_TERMIOS)
+ /*
+ * POSIX 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;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+ 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));
+ }
+ }
+ memset((char *)chu, 0, 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)
+ memmove((char *)&peer->refid, CHUREFID, 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)
+ memmove((char *)&peer->refid,
+ CHUREFID, 4);
+ else
+ peer->refid = htonl(CHUHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ sloppyclockflag[unit] = in->flags & CLK_FLAG1;
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_CHU;
+ out->flags = 0;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|
+ CLK_HAVEVAL2|CLK_HAVEFLAG1;
+ out->clockdesc = CHUDESCRIPTION;
+ out->fudgetime1 = propagation_delay[unit];
+ out->fudgetime2 = fudgefactor[unit];
+ out->fudgeval1 = (long)stratumtouse[unit];
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ chu = chuunits[unit];
+ out->lencode = NCHUCHARS*4;
+ out->fudgeval2 = chu->lastcode[2*NCHUCHARS+1];
+ out->fudgeval2 *= (chu->lastcode[2*NCHUCHARS]&1)?-1:1;
+ out->lastcode = chu->asciicode;
+ out->timereset = current_time - chu->timestarted;
+ npolls = out->timereset / 6; /* **divide** */
+ out->polls = npolls;
+ out->noresponse = (npolls - chu->responses);
+ out->badformat = chu->badformat;
+ out->baddata = chu->baddata;
+ out->lastevent = chu->lastevent;
+ out->currentstatus = chu->status;
+ } else {
+ out->fudgeval2 = 0;
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+#endif
diff --git a/contrib/xntpd/xntpd/refclock_conf.c b/contrib/xntpd/xntpd/refclock_conf.c
new file mode 100644
index 000000000000..430c4a60f3fa
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_conf.c
@@ -0,0 +1,128 @@
+/*
+ * 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
+
+#if defined(GPSTM) || defined(GPSTMCLK) || defined(GPSTMPPS)
+extern struct refclock refclock_gpstm;
+#else
+#define refclock_gpstm 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 */
+ &refclock_gpstm, /* 15 REFCLK_GPSTM_TRUETIME */
+};
+
+u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *);
+
+#endif
diff --git a/contrib/xntpd/xntpd/refclock_goes.c b/contrib/xntpd/xntpd/refclock_goes.c
new file mode 100644
index 000000000000..0b53326dc5d2
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_goes.c
@@ -0,0 +1,1013 @@
+/*
+ * 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(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#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 carriage 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
+ */
+ memset((char *)goesunits, 0, sizeof goesunits);
+ memset((char *)unitinuse, 0, 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(HAVE_TERMIOS)
+ /*
+ * POSIX 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;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#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));
+ }
+ }
+ memset((char *)goes, 0, 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)
+ memmove((char *)&peer->refid, GOESREFID, 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)
+ memmove((char *)&peer->refid,
+ GOESREFID, 4);
+ else
+ peer->refid = htonl(GOESHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ readonlyclockflag[unit] = in->flags & CLK_FLAG1;
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_GOES_TRUETIME;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVETIME2|
+ CLK_HAVEVAL1|CLK_HAVEVAL2|
+ CLK_HAVEFLAG1|CLK_HAVEFLAG2;
+ out->clockdesc = GOESDESCRIPTION;
+ out->fudgetime1 = fudgefactor1[unit];
+ out->fudgetime2 = fudgefactor2[unit];
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = 0;
+ out->flags = readonlyclockflag[unit] |
+ (goes->satellite << 1);
+ if (unitinuse[unit]) {
+ out->lencode = goes->lencode;
+ out->lastcode = goes->lastcode;
+ out->timereset = current_time - goes->timestarted;
+ out->polls = goes->polls;
+ out->noresponse = goes->noreply;
+ out->badformat = goes->badformat;
+ out->baddata = goes->baddata;
+ out->lastevent = goes->lastevent;
+ out->currentstatus = goes->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+/*
+ * goes_buginfo - return clock dependent debugging info
+ */
+static void
+goes_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct goesunit *goes;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "goes_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ goes = goesunits[unit];
+
+ bug->nvalues = 11;
+ bug->ntimes = 5;
+ if (goes->lasttime != 0)
+ bug->values[0] = current_time - goes->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = (U_LONG)goes->reason;
+ bug->values[2] = (U_LONG)goes->year;
+ bug->values[3] = (U_LONG)goes->day;
+ bug->values[4] = (U_LONG)goes->hour;
+ bug->values[5] = (U_LONG)goes->minute;
+ bug->values[6] = (U_LONG)goes->second;
+ bug->values[7] = (U_LONG)goes->msec;
+ bug->values[8] = goes->noreply;
+ bug->values[9] = goes->yearstart;
+ bug->values[10] = goes->quality;
+ bug->stimes = 0x1c;
+ bug->times[0] = goes->lastref;
+ bug->times[1] = goes->lastrec;
+ bug->times[2] = goes->offset[0];
+ bug->times[3] = goes->offset[1];
+ bug->times[4] = goes->offset[2];
+}
+#endif
diff --git a/contrib/xntpd/xntpd/refclock_gpstm.c b/contrib/xntpd/xntpd/refclock_gpstm.c
new file mode 100644
index 000000000000..93abcf93773c
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_gpstm.c
@@ -0,0 +1,1015 @@
+/*
+ * refclock_gpstm - clock driver for the Kinimetrics Truetime GPSTM/TMD rcvr
+ * Version 1.0 (from Version 2.0 of the GOES driver, as of 03Jan94)
+ */
+
+#if defined(REFCLOCK) && (defined(GPSTM) || defined(GPSTMCLK) \
+ || defined(GPSTMPPS))
+
+#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"
+
+#ifdef SYS_BSDI
+#undef HAVE_BSD_TTYS
+#include <sys/ioctl.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(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+
+#if defined(STREAM)
+#include <stropts.h>
+#if defined(GPSTMCLK)
+#include <clkdefs.h>
+#endif /* GPSTMCLK */
+#endif /* STREAM */
+
+#if defined(GPSTMPPS)
+#include <sys/ppsclock.h>
+#endif /* GPSTMPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+ * Support for Kinemetrics Truetime GPS-TM/TMD Receiver
+ *
+ * Most of this code is copied from refclock_goes.c with thanks.
+ *
+ * the time code looks like follows:
+ *
+ * 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 carriage return start bit begins on 0 seconds and extends to 1 bit time.
+ *
+ * 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 GPSTM units */
+#define GPSTM232 "/dev/gpstm%d"
+#define SPEED232 B9600 /* 9600 baud */
+
+/*
+ * Radio interface parameters
+ */
+#define MAXDISPERSE (FP_SECOND>>1) /* max error for synchronized clock (0.5 s as an u_fp) */
+#define PRECISION (-20) /* precision assumed (about 1 ms) */
+#define REFID "GPS\0" /* reference id */
+#define DESCRIPTION "Kinemetrics GPS-TM/TMD Receiver" /* who we are */
+#define HSREFID 0x7f7f0f0a /* 127.127.15.10 refid hi strata */
+#define GMT 0 /* hour offset from Greenwich */
+#define NCODES 3 /* stages of median filter */
+#define BMAX 99 /* timecode buffer length */
+#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */
+#define TIMEOUT 180 /* ping the clock if it's silent this long */
+
+/*
+ * used by the state machine
+ */
+enum gpstm_event {e_Init, e_F18, e_F50, e_F51, e_TS};
+static enum {Base, Start, F18, F50, F51, F08} State[MAXUNITS];
+static time_t Last[MAXUNITS];
+static void gpstm_doevent P((int, enum gpstm_event));
+static void gpstm_initstate P((int));
+
+/*
+ * 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 */
+
+/*
+ * GPSTM unit control structure
+ */
+struct gpstm_unit {
+ 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 polled; /* Hand in a time sample? */
+ 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 character */
+ 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 gpstm_unit *gpstm_units[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 gpstm_init P((void));
+static int gpstm_start P((u_int, struct peer *));
+static void gpstm_shutdown P((int));
+static void gpstm_rep_event P((struct gpstm_unit *, int));
+static void gpstm_receive P((struct recvbuf *));
+static char gpstm_process P((struct gpstm_unit *, l_fp *, u_fp *));
+static void gpstm_poll P((int, struct peer *));
+static void gpstm_control P((u_int, struct refclockstat *,
+ struct refclockstat *));
+static void gpstm_buginfo P((int, struct refclockbug *));
+static void gpstm_send P((struct gpstm_unit *, char *));
+
+struct refclock refclock_gpstm = {
+ gpstm_start, gpstm_shutdown, gpstm_poll,
+ gpstm_control, gpstm_init, gpstm_buginfo, NOFLAGS
+};
+
+/*
+ * gpstm_init - initialize internal driver data
+ */
+static void
+gpstm_init()
+{
+ register int i;
+ /*
+ * Just zero the data arrays
+ */
+ memset((char *)gpstm_units, 0, sizeof gpstm_units);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ /*
+ * Initialize fudge factors to default.
+ */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor1[i].l_ui = 0;
+ fudgefactor1[i].l_uf = 0;
+ fudgefactor2[i].l_ui = 0;
+ fudgefactor2[i].l_uf = 0;
+ stratumtouse[i] = 0;
+ readonlyclockflag[i] = 0;
+ }
+}
+
+
+/*
+ * gpstm_start - open the device and initialize data for processing
+ */
+static int
+gpstm_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ register struct gpstm_unit *gpstm;
+ register int i;
+ int fd232;
+ char dev[20];
+
+ /*
+ * Check configuration info
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_start: unit %d invalid", unit);
+ return 0;
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "gpstm_start: unit %d in use", unit);
+ return 0;
+ }
+
+ /*
+ * Open serial port
+ */
+ (void) sprintf(dev, GPSTM232, unit);
+ fd232 = open(dev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR, "gpstm_start: open of %s: %m", dev);
+ 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,
+ "gpstm_start: ioctl(%s, TCGETA): %m", dev);
+ 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,
+ "gpstm_start: ioctl(%s, TCSETA): %m", dev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_SYSV_TTYS */
+#if defined(HAVE_TERMIOS)
+ /*
+ * POSIX serial line parameters (termios interface)
+ *
+ * The GPSTMCLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module.
+ *
+ * The GPSTMPPS 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,
+ "gpstm_start: tcgetattr(%s): %m", dev);
+ 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,
+ "gpstm_start: tcsetattr(%s): %m", dev);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: tcflush(%s): %m", dev);
+ goto screwed;
+ }
+#if defined(STREAM)
+#if defined(GPSTMCLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, I_PUSH, clk): %m", dev);
+ if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, CLK_SETSTR): %m", dev);
+#endif /* GPSTMCLK */
+#if defined(GPSTMPPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, I_PUSH, ppsclock): %m", dev);
+ else
+ fdpps = fd232;
+#endif /* GPSTMPPS */
+#endif /* STREAM */
+ }
+#endif /* HAVE_TERMIOS */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The GPSTMCLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(GPSTMCLK)
+ int ldisc = CLKLDISC;
+#endif /* GPSTMCLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TIOCGETP): %m", dev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(GPSTMCLK)
+ 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 /* GPSTMCLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TIOCSETP): %m", dev);
+ goto screwed;
+ }
+#if defined(GPSTMCLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TIOCSETD): %m", dev);
+ goto screwed;
+ }
+#endif /* GPSTMCLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Allocate unit structure
+ */
+ if (gpstm_units[unit] != 0) {
+ gpstm = gpstm_units[unit]; /* The one we want is okay */
+ } else {
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && gpstm_units[i] != 0)
+ break;
+ }
+ if (i < MAXUNITS) {
+ /*
+ * Reclaim this one
+ */
+ gpstm = gpstm_units[i];
+ gpstm_units[i] = 0;
+ } else {
+ gpstm = (struct gpstm_unit *)
+ emalloc(sizeof(struct gpstm_unit));
+ }
+ }
+ memset((char *)gpstm, 0, sizeof(struct gpstm_unit));
+ gpstm_units[unit] = gpstm;
+
+ /*
+ * Set up the structures
+ */
+ gpstm->peer = peer;
+ gpstm->unit = (u_char)unit;
+ gpstm->timestarted = current_time;
+
+ gpstm->io.clock_recv = gpstm_receive;
+ gpstm->io.srcclock = (caddr_t)gpstm;
+ gpstm->io.datalen = 0;
+ gpstm->io.fd = fd232;
+ if (!io_addclock(&gpstm->io)) {
+ goto screwed;
+ }
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success.
+ */
+ peer->precision = PRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ if (stratumtouse[unit] <= 1)
+ memmove((char *)&peer->refid, REFID, 4);
+ else
+ peer->refid = htonl(HSREFID);
+ unitinuse[unit] = 1;
+ gpstm_initstate(unit);
+ return 1;
+
+ /*
+ * Something broke; abandon ship
+ */
+screwed:
+ (void) close(fd232);
+ return 0;
+}
+
+/*
+ * gpstm_shutdown - shut down a clock
+ */
+static void
+gpstm_shutdown(unit)
+ int unit;
+{
+ register struct gpstm_unit *gpstm;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_shutdown: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "gpstm_shutdown: unit %d not in use", unit);
+ return;
+ }
+
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ gpstm = gpstm_units[unit];
+ io_closeclock(&gpstm->io);
+ unitinuse[unit] = 0;
+}
+
+
+/*
+ * gpstm_rep_event - note the occurance of an event
+ */
+static void
+gpstm_rep_event(gpstm, code)
+ struct gpstm_unit *gpstm;
+ int code;
+{
+ struct peer *peer;
+
+ peer = gpstm->peer;
+ if (gpstm->status != (u_char)code) {
+ gpstm->status = (u_char)code;
+ if (code != CEVNT_NOMINAL)
+ gpstm->lastevent = (u_char)code;
+ syslog(LOG_INFO,
+ "clock %s event %x\n", ntoa(&peer->srcadr), code);
+#ifdef DEBUG
+ if (debug) {
+ printf("gpstm_rep_event(gpstm%d, code %d)\n",
+ gpstm->unit, code);
+ }
+#endif
+ }
+ if (code == CEVNT_BADREPLY)
+ gpstm_initstate(gpstm->unit);
+}
+
+
+/*
+ * gpstm_receive - receive data from the serial interface on a clock
+ */
+static void
+gpstm_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register int i;
+ register struct gpstm_unit *gpstm;
+ 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
+ */
+ gpstm = (struct gpstm_unit *)rbufp->recv_srcclock;
+ dpt = (u_char *)&rbufp->recv_space;
+
+ /*
+ * Edit timecode to remove control chars
+ */
+ dpend = dpt + rbufp->recv_length;
+ cp = gpstm->lastcode;
+ while (dpt < dpend) {
+ if ((*cp = 0x7f & *dpt++) >= ' ') cp++;
+#ifdef GPSTMCLK
+ else if (*cp == '\r') {
+ if (dpend - dpt < 8) {
+ /* short timestamp */
+ return;
+ }
+ if (!buftvtots(dpt,&gpstm->lastrec)) {
+ /* screwy timestamp */
+ return;
+ }
+ dpt += 8;
+ }
+#endif
+ }
+ *cp = '\0';
+ gpstm->lencode = cp - gpstm->lastcode;
+ if (gpstm->lencode == 0)
+ return;
+#ifndef GPSTMCLK
+ gpstm->lastrec = rbufp->recv_time;
+#endif /* GPSTMCLK */
+#if !defined(GPSTMCLK) && !defined(GPSTMPPS) && defined(TIOCMODT)
+ do {
+ auto struct timeval cur, now;
+ register long usec;
+
+ if (ioctl(gpstm->io.fd, TIOCMODT, &cur) < 0) {
+ syslog(LOG_ERR, "TIOCMODT: %m");
+#ifdef DEBUG
+ if (debug) perror("TIOCMODT");
+ break;
+#endif
+ }
+ if (cur.tv_sec == 0) {
+ /* no timestamps yet */
+ if (debug) printf("MODT tv_sec == 0\n");
+ break;
+ }
+
+ gettimeofday(&now, NULL);
+ usec = 1000000 * (now.tv_sec - cur.tv_sec)
+ + (now.tv_usec - cur.tv_usec);
+#ifdef DEBUG
+ if (debug) printf("lastmodem: delay=%d us\n", usec);
+#endif
+ if (usec < 0 || usec > 10000) {
+ /* time warp or stale timestamp */
+ break;
+ }
+ if (!buftvtots((char *)&cur, &gpstm->lastrec)) {
+ /* screwy timestamp */
+ break;
+ }
+ } while (0);
+#endif /*TIOCMODT*/
+
+#ifdef DEBUG
+ if (debug)
+ printf("gpstm: timecode %d %s\n",
+ gpstm->lencode, gpstm->lastcode);
+#endif
+
+ cp = gpstm->lastcode;
+ gpstm->leap = 0;
+ if ((cp[0] == 'F' && isdigit(cp[1]) && isdigit(cp[2]))
+ || (cp[0] == ' ' && cp[1] == 'T' && cp[2] == 'R')) {
+ enum gpstm_event event;
+
+ syslog(LOG_NOTICE, "gpstm%d: \"%s\"", gpstm->unit, cp);
+ if (cp[1] == '5' && cp[2] == '0')
+ event = e_F50;
+ else if (cp[1] == '5' && cp[2] == '1')
+ event = e_F51;
+ else if (!strncmp(" TRUETIME Mk III", cp, 16))
+ event = e_F18;
+ else {
+ gpstm_rep_event(gpstm, CEVNT_BADREPLY);
+ return;
+ }
+ gpstm_doevent(gpstm->unit, event);
+ return;
+ } else if (gpstm->lencode == 13) {
+ /*
+ * Check timecode format 0
+ */
+ if (!isdigit(cp[0]) /* day of year */
+ || !isdigit(cp[1])
+ || !isdigit(cp[2])
+ || cp[3] != ':' /* : separator */
+ || !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]))
+ {
+ gpstm->badformat++;
+ gpstm_rep_event(gpstm, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * Convert format 0 and check values
+ */
+ gpstm->year = 0; /* fake */
+ gpstm->day = cp[0] - '0';
+ gpstm->day = MULBY10(gpstm->day) + cp[1] - '0';
+ gpstm->day = MULBY10(gpstm->day) + cp[2] - '0';
+ gpstm->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
+ gpstm->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
+ gpstm->second = MULBY10(cp[10] - '0') + cp[11] - '0';
+ gpstm->msec = 0;
+
+ if (cp[12] != ' ' && cp[12] != '.' && cp[12] != '*')
+ gpstm->leap = LEAP_NOTINSYNC;
+ else
+ gpstm->lasttime = current_time;
+
+ if (gpstm->day < 1 || gpstm->day > 366) {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADDATE);
+ return;
+ }
+ if (gpstm->hour > 23 || gpstm->minute > 59
+ || gpstm->second > 59) {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADTIME);
+ return;
+ }
+ gpstm_doevent(gpstm->unit, e_TS);
+ } else {
+ gpstm_rep_event(gpstm, 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 (!gpstm->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 = gpstm->lastrec;
+ if (!clocktime(gpstm->day, gpstm->hour, gpstm->minute,
+ gpstm->second, GMT, tstmp.l_ui,
+ &gpstm->yearstart, &gpstm->lastref.l_ui))
+ {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADTIME);
+ return;
+ }
+ MSUTOTSF(gpstm->msec, gpstm->lastref.l_uf);
+
+ i = ((int)(gpstm->coderecv)) % NCODES;
+ gpstm->offset[i] = gpstm->lastref;
+ L_SUB(&gpstm->offset[i], &tstmp);
+ if (gpstm->coderecv == 0)
+ for (i = 1; i < NCODES; i++)
+ gpstm->offset[i] = gpstm->offset[0];
+
+ gpstm->coderecv++;
+
+ /*
+ * Process the median filter, 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 (!gpstm_process(gpstm, &tstmp, &dispersion)) {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADTIME);
+ return;
+ }
+ refclock_receive(gpstm->peer, &tstmp, GMT, dispersion,
+ &gpstm->lastrec, &gpstm->lastrec, gpstm->leap);
+
+ /*
+ * We have succedded in answering the poll. Turn off the flag
+ */
+ gpstm->polled = 0;
+}
+
+/*
+ * gpstm_send - time to send the clock a signal to cough up a time sample
+ */
+static void
+gpstm_send(gpstm, cmd)
+ struct gpstm_unit *gpstm;
+ char *cmd;
+{
+#ifdef DEBUG
+ if (debug) {
+ printf("gpstm_send(gpstm%d): %s\n", gpstm->unit, cmd);
+ }
+#endif
+ if (!readonlyclockflag[gpstm->unit]) {
+ register int len = strlen(cmd);
+
+ if (write(gpstm->io.fd, cmd, len) != len) {
+ syslog(LOG_ERR, "gpstm_send: unit %d: %m",
+ gpstm->unit);
+ gpstm_rep_event(gpstm, CEVNT_FAULT);
+ }
+ }
+}
+
+/*
+ * state machine for initializing the clock
+ */
+
+static void
+gpstm_doevent(unit, event)
+ int unit;
+ enum gpstm_event event;
+{
+ struct gpstm_unit *gpstm = gpstm_units[unit];
+
+#ifdef DEBUG
+ if (debug) {
+ printf("gpstm_doevent(gpstm%d, %d)\n", unit, (int)event);
+ }
+#endif
+ if (event == e_TS && State[unit] != F51 && State[unit] != F08) {
+ gpstm_send(gpstm, "\03\r");
+ }
+
+ switch (event) {
+ case e_Init:
+ gpstm_send(gpstm, "F18\r");
+ State[unit] = Start;
+ break;
+ case e_F18:
+ gpstm_send(gpstm, "F50\r");
+ State[unit] = F18;
+ break;
+ case e_F50:
+ gpstm_send(gpstm, "F51\r");
+ State[unit] = F50;
+ break;
+ case e_F51:
+ gpstm_send(gpstm, "F08\r");
+ State[unit] = F51;
+ break;
+ case e_TS:
+ /* nothing to send - we like this mode */
+ State[unit] = F08;
+ break;
+ }
+}
+
+static void
+gpstm_initstate(unit) {
+ State[unit] = Base; /* just in case */
+ gpstm_doevent(unit, e_Init);
+}
+
+/*
+ * gpstm_process - process a pile of samples from the clock
+ */
+static char
+gpstm_process(gpstm, offset, dispersion)
+ struct gpstm_unit *gpstm;
+ 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 = gpstm->offset[i].l_ui;
+ tmp_uf = gpstm->offset[i].l_uf;
+ M_SUB(tmp_ui, tmp_uf, gpstm->offset[j].l_ui,
+ gpstm->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 (gpstm->lasttime == 0 || disp_tmp2 > MAXDISPERSE)
+ disp_tmp2 = MAXDISPERSE;
+ if (not_median1 == 0) {
+ if (not_median2 == 1)
+ median = 2;
+ else
+ median = 1;
+ } else {
+ median = 0;
+ }
+ *offset = gpstm->offset[median];
+ *dispersion = disp_tmp2;
+ return 1;
+}
+
+/*
+ * gpstm_poll - called by the transmit procedure
+ */
+static void
+gpstm_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ struct gpstm_unit *gpstm;
+
+ /*
+ * 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, "gpstm_poll: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "gpstm_poll: unit %d not in use", unit);
+ return;
+ }
+ gpstm = gpstm_units[unit];
+ if ((current_time - gpstm->lasttime) > 150) {
+ gpstm->noreply++;
+ gpstm_rep_event(gpstm_units[unit], CEVNT_TIMEOUT);
+ gpstm_initstate(gpstm->unit);
+ }
+
+ /*
+ * polled every 64 seconds. Ask our receiver to hand in a timestamp.
+ */
+ gpstm->polled = 1;
+ gpstm->polls++;
+}
+
+/*
+ * gpstm_control - set fudge factors, return statistics
+ */
+static void
+gpstm_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct gpstm_unit *gpstm;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_control: unit %d invalid", unit);
+ return;
+ }
+ gpstm = gpstm_units[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 = gpstm->peer;
+ peer->stratum = stratumtouse[unit];
+ if (stratumtouse[unit] <= 1)
+ memmove((char *)&peer->refid,
+ REFID, 4);
+ else
+ peer->refid = htonl(HSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ readonlyclockflag[unit] = in->flags & CLK_FLAG1;
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_GPSTM_TRUETIME;
+ out->haveflags = CLK_HAVETIME1 | CLK_HAVETIME2
+ | CLK_HAVEVAL1 | CLK_HAVEVAL2
+ | CLK_HAVEFLAG1;
+ out->clockdesc = DESCRIPTION;
+ out->fudgetime1 = fudgefactor1[unit];
+ out->fudgetime2 = fudgefactor2[unit];
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = 0;
+ out->flags = readonlyclockflag[unit];
+ if (unitinuse[unit]) {
+ out->lencode = gpstm->lencode;
+ out->lastcode = gpstm->lastcode;
+ out->timereset = current_time - gpstm->timestarted;
+ out->polls = gpstm->polls;
+ out->noresponse = gpstm->noreply;
+ out->badformat = gpstm->badformat;
+ out->baddata = gpstm->baddata;
+ out->lastevent = gpstm->lastevent;
+ out->currentstatus = gpstm->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;
+ }
+ }
+}
+
+/*
+ * gpstm_buginfo - return clock dependent debugging info
+ */
+static void
+gpstm_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct gpstm_unit *gpstm;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ gpstm = gpstm_units[unit];
+
+ bug->nvalues = 11;
+ bug->ntimes = 5;
+ if (gpstm->lasttime != 0)
+ bug->values[0] = current_time - gpstm->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = (U_LONG)gpstm->reason;
+ bug->values[2] = (U_LONG)gpstm->year;
+ bug->values[3] = (U_LONG)gpstm->day;
+ bug->values[4] = (U_LONG)gpstm->hour;
+ bug->values[5] = (U_LONG)gpstm->minute;
+ bug->values[6] = (U_LONG)gpstm->second;
+ bug->values[7] = (U_LONG)gpstm->msec;
+ bug->values[8] = gpstm->noreply;
+ bug->values[9] = gpstm->yearstart;
+ bug->values[10] = gpstm->quality;
+ bug->stimes = 0x1c;
+ bug->times[0] = gpstm->lastref;
+ bug->times[1] = gpstm->lastrec;
+ bug->times[2] = gpstm->offset[0];
+ bug->times[3] = gpstm->offset[1];
+ bug->times[4] = gpstm->offset[2];
+}
+
+#endif /*GPSTM et al*/
diff --git a/contrib/xntpd/xntpd/refclock_irig.c b/contrib/xntpd/xntpd/refclock_irig.c
new file mode 100644
index 000000000000..40345bbefde7
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_irig.c
@@ -0,0 +1,566 @@
+/*
+ * refclock_irig - clock driver for the IRIG audio decoder
+ */
+
+#if defined(REFCLOCK) && defined(IRIG)
+#include <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
+ */
+ memset((char *) irigunits, 0, sizeof irigunits);
+ memset((char *) unitinuse, 0, 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));
+ }
+ }
+ memset((char *) irig, 0, 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)
+ memmove((char *) &peer->refid, IRIGREFID, 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)
+ memmove((char *) &peer->refid,
+ IRIGREFID, 4);
+ else
+ peer->refid = htonl(IRIGHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ sloppyclockflag[unit] = in->flags & CLK_FLAG1;
+ }
+ }
+ if (out != 0) {
+ out->type = REFCLK_IRIG_AUDIO;
+ out->haveflags
+ = CLK_HAVETIME1 | CLK_HAVEVAL1 | CLK_HAVEVAL2 | CLK_HAVEFLAG1;
+ out->clockdesc = IRIGDESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgetime2.l_ui = 0;
+ out->fudgetime2.l_uf = 0;
+ out->fudgeval1 = (LONG) stratumtouse[unit];
+ out->fudgeval2 = 0;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ irig = irigunits[unit];
+ out->lencode = irig->lencode;
+ out->lastcode = irig->lastcode;
+ out->timereset = current_time - irig->timestarted;
+ out->polls = irig->polls;
+ out->noresponse = irig->noreply;
+ out->badformat = irig->badformat;
+ out->baddata = irig->baddata;
+ out->lastevent = irig->lastevent;
+ out->currentstatus = irig->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+/*
+ * irig_buginfo - return clock dependent debugging info
+ */
+static void
+irig_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct irigunit *irig;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "irig_buginfo: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit])
+ return;
+ irig = irigunits[unit];
+
+ bug->nvalues = 8;
+ bug->ntimes = 2;
+ if (irig->lasttime != 0)
+ bug->values[0] = current_time - irig->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[2] = (U_LONG) irig->year;
+ bug->values[3] = (U_LONG) irig->day;
+ bug->values[4] = (U_LONG) irig->hour;
+ bug->values[5] = (U_LONG) irig->minute;
+ bug->values[6] = (U_LONG) irig->second;
+ bug->values[7] = irig->yearstart;
+ bug->stimes = 0x1c;
+ bug->times[0] = irig->lastref;
+ bug->times[1] = irig->lastrec;
+}
+
+#endif
diff --git a/contrib/xntpd/xntpd/refclock_leitch.c b/contrib/xntpd/xntpd/refclock_leitch.c
new file mode 100644
index 000000000000..330712997eba
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_leitch.c
@@ -0,0 +1,704 @@
+/*
+ * 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(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#ifdef STREAM
+#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()
+{
+ memset((char*)leitchunits, 0, sizeof(leitchunits));
+ memset((char*)unitinuse, 0, 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];
+ memset((char*)leitch, 0, sizeof(*leitch));
+
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ *
+ */
+ { struct termio ttyb;
+ if (ioctl(fd232, TCGETA, &ttyb) < 0) {
+ 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(HAVE_TERMIOS)
+ /*
+ * POSIX 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;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#if defined(LEITCHCLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, I_PUSH, clk): %m", leitchdev);
+ if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, CLK_SETSTR): %m", leitchdev);
+#endif /* LEITCHCLK */
+#if defined(LEITCHPPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, I_PUSH, ppsclock): %m", leitchdev);
+ else
+ fdpps = fd232;
+#endif /* LEITCHPPS */
+#endif /* STREAM */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The LEITCHCLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(LEITCHCLK)
+ int ldisc = CLKLDISC;
+#endif /* LEITCHCLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TIOCGETP): %m", leitchdev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(LEITCHCLK)
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+#else
+ ttyb.sg_erase = ttyb.sg_kill = '\0';
+ ttyb.sg_flags = EVENP|ODDP|CRMOD;
+#endif /* LEITCHCLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev);
+ goto screwed;
+ }
+#if defined(LEITCHCLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TIOCSETD): %m",leitchdev);
+ goto screwed;
+ }
+#endif /* LEITCHCLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Set up the structures
+ */
+ leitch->peer = peer;
+ leitch->unit = unit;
+ leitch->state = STATE_IDLE;
+ leitch->fudge1 = 15; /* 15ms */
+
+ leitch->leitchio.clock_recv = leitch_receive;
+ leitch->leitchio.srcclock = (caddr_t) leitch;
+ leitch->leitchio.datalen = 0;
+ leitch->leitchio.fd = fd232;
+ if (!io_addclock(&leitch->leitchio)) {
+ goto screwed;
+ }
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success. Note that root delay and root dispersion are
+ * always zero for this clock.
+ */
+ peer->precision = 0;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = 0;
+ peer->refid = htonl(0x41544f4d); /* ATOM */
+ unitinuse[unit] = 1;
+ return(1);
+
+ /*
+ * Something broke; abandon ship.
+ */
+screwed:
+ close(fd232);
+ return(0);
+}
+
+/*
+ * leitch_receive - receive data from the serial interface on a leitch
+ * clock
+ */
+static void
+leitch_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ struct leitchunit *leitch = (struct leitchunit *)rbufp->recv_srcclock;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "leitch_recieve(%*.*s)\n",
+ rbufp->recv_length, rbufp->recv_length,
+ rbufp->recv_buffer);
+#endif
+ if (rbufp->recv_length != 7)
+ return; /* The date is return with a trailing newline,
+ discard it. */
+
+ switch (leitch->state) {
+ case STATE_IDLE: /* unexpected, discard and resync */
+ return;
+ case STATE_DATE:
+ if (!leitch_get_date(rbufp,leitch)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+ leitch_send(leitch,"T\r");
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%u\n",leitch->yearday);
+#endif
+ leitch->state = STATE_TIME1;
+ break;
+ case STATE_TIME1:
+ if (!leitch_get_time(rbufp,leitch,1)) {
+ }
+ if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
+ leitch->second, 0, rbufp->recv_time.l_ui,
+ &leitch->yearstart, &leitch->reftime1.l_ui)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%u\n", leitch->reftime1.l_ui);
+#endif
+ MSUTOTSF(leitch->fudge1, leitch->reftime1.l_uf);
+ leitch->codetime1 = rbufp->recv_time;
+ leitch->state = STATE_TIME2;
+ break;
+ case STATE_TIME2:
+ if (!leitch_get_time(rbufp,leitch,2)) {
+ }
+ if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
+ leitch->second, 0, rbufp->recv_time.l_ui,
+ &leitch->yearstart, &leitch->reftime2.l_ui)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%u\n", leitch->reftime2.l_ui);
+#endif
+ MSUTOTSF(leitch->fudge1, leitch->reftime2.l_uf);
+ leitch->codetime2 = rbufp->recv_time;
+ leitch->state = STATE_TIME3;
+ break;
+ case STATE_TIME3:
+ if (!leitch_get_time(rbufp,leitch,3)) {
+ }
+ if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
+ leitch->second, 0, rbufp->recv_time.l_ui,
+ &leitch->yearstart, &leitch->reftime3.l_ui)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%u\n", leitch->reftime3.l_ui);
+#endif
+ MSUTOTSF(leitch->fudge1, leitch->reftime3.l_uf);
+ leitch->codetime3 = rbufp->recv_time;
+ leitch_process(leitch);
+ leitch->state = STATE_IDLE;
+ break;
+ default:
+ syslog(LOG_ERR,
+ "leitech_receive: invalid state %d unit %d",
+ leitch->state, leitch->unit);
+ }
+}
+
+/*
+ * leitch_process - process a pile of samples from the clock
+ *
+ * This routine uses a three-stage median filter to calculate offset and
+ * dispersion. reduce jitter. The dispersion is calculated as the span
+ * of the filter (max - min), unless the quality character (format 2) is
+ * non-blank, in which case the dispersion is calculated on the basis of
+ * the inherent tolerance of the internal radio oscillator, which is
+ * +-2e-5 according to the radio specifications.
+ */
+static void
+leitch_process(leitch)
+ struct leitchunit *leitch;
+{
+ l_fp off;
+ s_fp delay;
+ l_fp codetime;
+ l_fp tmp_fp;
+ int isinsync = 1;
+ u_fp dispersion = 10;
+
+ delay = 20;
+
+ codetime = leitch->codetime3;
+
+ off = leitch->reftime1;
+ L_SUB(&off,&leitch->codetime1);
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr,"%u %u %u %u %d %d\n",
+ leitch->codetime1.l_ui, leitch->codetime1.l_uf,
+ leitch->reftime1.l_ui, leitch->reftime1.l_uf,
+ off.l_ui, off.l_uf);
+#endif
+ tmp_fp = leitch->reftime2;
+ L_SUB(&tmp_fp,&leitch->codetime2);
+ if (L_ISGEQ(&off,&tmp_fp))
+ off = tmp_fp;
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr,"%u %u %u %u %d %d\n",
+ leitch->codetime2.l_ui, leitch->codetime2.l_uf,
+ leitch->reftime2.l_ui, leitch->reftime2.l_uf,
+ off.l_ui, off.l_uf);
+#endif
+ tmp_fp = leitch->reftime3;
+ L_SUB(&tmp_fp,&leitch->codetime3);
+
+ if (L_ISGEQ(&off,&tmp_fp))
+ off = tmp_fp;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr,"%u %u %u %u %d %d\n",
+ leitch->codetime3.l_ui, leitch->codetime3.l_uf,
+ leitch->reftime3.l_ui, leitch->reftime3.l_uf,
+ off.l_ui, off.l_uf);
+#endif
+ refclock_receive(leitch->peer, &off, 0, dispersion, &codetime,
+ &codetime, isinsync);
+}
+
+/*
+ * leitch_timeout
+ */
+static void
+leitch_timeout(fp)
+ struct peer *fp;
+{
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "leitch_timeout()\n");
+#endif
+
+#ifdef NOTYET
+ { struct leitchunit *leitch = (struct leitchunit *)fp;
+
+ switch(leitch->state) {
+ case STATE_IDLE:
+ leitch_send(leitch,"D\r");
+ leitch->state = STATE_DATE;
+ break;
+ case STATE_DATE:
+ leitch_send(leitch,"T\r");
+ leitch->state = STATE_TIME1;
+ break;
+ case STATE_TIME1:
+ case STATE_TIME2:
+ case STATE_TIME3:
+ default:
+ break;
+ }
+
+ leitch->leitchtimer.event_time += 30;
+ TIMER_ENQUEUE(timerqueue, &leitch->leitchtimer);
+ }
+#endif /* NOTYET */
+}
+
+/*
+ * dysize
+ */
+static int
+dysize(year)
+int year;
+{
+ if (year%4) { /* not a potential leap year */
+ return (365);
+ } else {
+ if (year % 100) { /* is a leap year */
+ return (366);
+ } else {
+ if (year % 400) {
+ return (365);
+ } else {
+ return (366);
+ }
+ }
+ }
+}
+
+static int
+leitch_get_date(rbufp,leitch)
+ struct recvbuf *rbufp;
+ struct leitchunit *leitch;
+{
+ int i;
+
+ if (rbufp->recv_length < 6)
+ return(0);
+#define BAD(A) (rbufp->recv_buffer[A] < '0') || (rbufp->recv_buffer[A] > '9')
+ if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))
+ return(0);
+#define ATOB(A) ((rbufp->recv_buffer[A])-'0')
+ leitch->year = ATOB(0)*10 + ATOB(1);
+ leitch->month = ATOB(2)*10 + ATOB(3);
+ leitch->day = ATOB(4)*10 + ATOB(5);
+
+ /* sanity checks */
+ if (leitch->month > 12)
+ return(0);
+ if (leitch->day > days_in_month[leitch->month-1])
+ return(0);
+
+ /* calculate yearday */
+ i = 0;
+ leitch->yearday = leitch->day;
+
+ while ( i < (leitch->month-1) )
+ leitch->yearday += days_in_month[i++];
+
+ if ((dysize((leitch->year>90?1900:2000)+leitch->year)==365) &&
+ leitch->month > 2)
+ leitch->yearday--;
+
+ return(1);
+}
+
+/*
+ * leitch_get_time
+ */
+static int
+leitch_get_time(rbufp,leitch,which)
+ struct recvbuf *rbufp;
+ struct leitchunit *leitch;
+ int which;
+{
+ if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))
+ return(0);
+ leitch->hour = ATOB(0)*10 +ATOB(1);
+ leitch->minute = ATOB(2)*10 +ATOB(3);
+ leitch->second = ATOB(4)*10 +ATOB(5);
+
+ if ((leitch->hour > 23) || (leitch->minute > 60) ||
+ (leitch->second > 60))
+ return(0);
+ return(1);
+}
+
+#endif
diff --git a/contrib/xntpd/xntpd/refclock_local.c b/contrib/xntpd/xntpd/refclock_local.c
new file mode 100644
index 000000000000..1323ca91ed62
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_local.c
@@ -0,0 +1,307 @@
+/*
+ * refclock_local - local pseudo-clock driver
+ */
+#if defined(REFCLOCK) && defined(LOCAL_CLOCK)
+#include <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
+ */
+ memset((char *)lclunits, 0, sizeof lclunits);
+ memset((char *)unitinuse, 0, 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));
+ }
+ }
+ memset((char *)lcl, 0, 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)
+ memmove((char *)&peer->refid, LCLREFID, 4);
+ else
+ peer->refid = htonl(LCLHSREFID);
+ unitinuse[unit] = 1;
+ return 1;
+}
+
+
+/*
+ * local_shutdown - shut down a local clock
+ */
+static void
+local_shutdown(unit)
+ int unit;
+{
+ if (unit >= NUMUNITS) {
+ syslog(LOG_ERR,
+ "local clock: INTERNAL ERROR, unit number %d invalid (max 15)",
+ unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR,
+ "local clock: INTERNAL ERROR, unit number %d not in use", unit);
+ return;
+ }
+
+ unitinuse[unit] = 0;
+}
+
+
+/*
+ * local_poll - called by the transmit procedure
+ */
+static void
+local_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ l_fp off;
+ l_fp ts;
+
+ if (unit >= NUMUNITS) {
+ syslog(LOG_ERR, "local clock poll: INTERNAL: unit %d invalid",
+ unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "local clock poll: INTERNAL: unit %d unused",
+ unit);
+ return;
+ }
+ if (peer != lclunits[unit]->peer) {
+ syslog(LOG_ERR,
+ "local clock poll: INTERNAL: peer incorrect for unit %d",
+ unit);
+ return;
+ }
+
+ /*
+ * Update clock stat counters
+ */
+ lclunits[unit]->polls++;
+ lclunits[unit]->lastupdate = current_time;
+
+ /*
+ * This is pretty easy. Give the reference clock support
+ * a zero offset and our fixed dispersion. Use peer->xmt for
+ * our receive time. Use peer->xmt - 20 seconds for our
+ * reference time.
+ */
+ off.l_ui = off.l_uf = 0;
+ ts = peer->xmt;
+ ts.l_ui -= LCLREFOFFSET;
+ refclock_receive(peer, &off, 0, LCLDISPERSION,
+ &ts, &peer->xmt, 0);
+}
+
+
+
+/*
+ * local_control - set fudge factors, return statistics
+ */
+static void
+local_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ extern s_fp drift_comp;
+
+ if (unit >= NUMUNITS) {
+ syslog(LOG_ERR, "local clock: unit %d invalid (max %d)",
+ unit, NUMUNITS-1);
+ return;
+ }
+
+ /*
+ * The time1 fudge factor is the drift compensation register.
+ * The time2 fudge factor is the offset of the system clock from
+ * what the protocol has set it to be. Most useful when SLEWALWAYS
+ * is defined.
+ */
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ drift_comp = LFPTOFP(&in->fudgetime1);
+ if (in->haveflags & CLK_HAVETIME2) {
+ sys_clock_offset.l_ui = in->fudgetime2.l_ui;
+ sys_clock_offset.l_uf = in->fudgetime2.l_uf;
+ }
+ }
+ if (out != 0) {
+ out->type = REFCLK_LOCALCLOCK;
+ out->flags = 0;
+ out->haveflags = CLK_HAVETIME1;
+ out->clockdesc = LCLDESCRIPTION;
+ FPTOLFP(drift_comp, &out->fudgetime1);
+ out->fudgetime2.l_ui = sys_clock_offset.l_ui;
+ out->fudgetime2.l_uf = sys_clock_offset.l_uf;
+ out->fudgeval1 = out->fudgeval2 = 0;
+ out->lencode = 0;
+ out->lastcode = "";
+ out->badformat = 0;
+ out->baddata = 0;
+ out->noresponse = 0;
+ if (unitinuse[unit]) {
+ out->polls = lclunits[unit]->polls;
+ out->timereset =
+ current_time - lclunits[unit]->timestarted;
+ out->lastevent = lclunits[unit]->lastevent;
+ out->currentstatus = lclunits[unit]->status;
+ } else {
+ out->polls = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+#endif /* REFCLOCK */
diff --git a/contrib/xntpd/xntpd/refclock_msfees.c b/contrib/xntpd/xntpd/refclock_msfees.c
new file mode 100644
index 000000000000..b301bc2ebb23
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_msfees.c
@@ -0,0 +1,1572 @@
+/* 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 */
+ memset((char *)eesunits, 0, sizeof eesunits);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ acceptable_slop.l_ui = 0;
+ acceptable_slop.l_uf = 1 << (FRACTION_PREC -2);
+
+ onesec.l_ui = 1;
+ onesec.l_uf = 0;
+
+ /* Initialize fudge factors to default. */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor[i].l_ui = 0;
+ fudgefactor[i].l_uf = DEFFUDGETIME;
+ os_delay[i].l_ui = 0;
+ os_delay[i].l_uf = DEFOSTIME;
+ inherent_delay[i].l_ui = 0;
+ inherent_delay[i].l_uf = DEFINHTIME;
+ offset_fudge[i] = os_delay[i];
+ L_ADD(&offset_fudge[i], &fudgefactor[i]);
+ L_ADD(&offset_fudge[i], &inherent_delay[i]);
+ stratumtouse[i] = 0;
+ sloppyclockflag[i] = 0;
+ }
+}
+
+
+/* msfees_start - open the EES devices and initialize data for processing */
+static int msfees_start(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));
+ }
+ memset((char *)ees, 0, sizeof(struct eesunit));
+ eesunits[unit] = ees;
+
+ /* Set up the structures */
+ ees->peer = peer;
+ ees->unit = (u_char)unit;
+ ees->timestarted= current_time;
+ ees->ttytype = 0;
+ ees->io.clock_recv= ees_receive;
+ ees->io.srcclock= (caddr_t)ees;
+ ees->io.datalen = 0;
+ ees->io.fd = fd232;
+
+ /* Okay. Push one of the two (linked into the kernel, or dynamically
+ * loaded) STREAMS module, and give it to the I/O code to start
+ * receiving stuff.
+ */
+
+ {
+ 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) {
+ memmove((char *)&peer->refid, EESREFID, 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;
+
+ memset(&ppsclockev, 0, 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) {
+ memmove((char *)&peer->refid,
+ EESREFID, 4);
+ if (unit>0 && unit<10)
+ ((char *)&peer->refid)[3] =
+ '0' + unit;
+ }
+ else peer->refid = htonl(EESHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEVAL2) {
+ printf("Debug: %x -> %x\n", debug, in->fudgeval2);
+ syslog(LOG_ERR, "MSF%d: debug %x -> %x",
+ unit, debug, in->fudgeval2);
+ debug = in->fudgeval2;
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ sloppyclockflag[unit] = in->flags & CLK_FLAG1;
+ }
+ if (in->haveflags & CLK_HAVEFLAG2) {
+ ees->fix_pending++;
+ /* if (in->flags & CLK_FLAG2 && unitinuse[unit])
+ ees->leaphold = 0; */
+ }
+ if (in->haveflags & CLK_HAVEFLAG3 && unitinuse[unit]) {
+ printf("dump_vals: %x -> %x\n", ees->dump_vals, in->flags & CLK_FLAG3);
+ ees->dump_vals = in->flags & CLK_FLAG3;
+ }
+ if (in->haveflags & CLK_HAVEFLAG4 && unitinuse[unit]) {
+ ees->usealldata = in->flags & CLK_FLAG4;
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_MSF_EES;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1|CLK_HAVEFLAG3|CLK_HAVEFLAG4;
+ out->clockdesc = EESDESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgetime2 = os_delay[unit];
+ out->fudgeval1 = (long)stratumtouse[unit];
+ out->fudgeval2 = debug;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ out->flags |= ees->dump_vals | ees->usealldata;
+ out->lencode = ees->lencode;
+ out->lastcode = ees->lastcode;
+ out->timereset = current_time - ees->timestarted;
+ out->polls = 0; /* we don't poll */
+ out->noresponse = 0; /* ditto */
+ out->badformat = ees->badformat;
+ out->baddata = ees->baddata;
+ out->lastevent = ees->lastevent;
+ out->currentstatus = ees->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+
+/* msfees_buginfo - return clock dependent debugging info */
+static void msfees_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct eesunit *ees;
+
+ bug->nvalues = bug->ntimes = 0;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "ees clock: unit %d invalid (max %d)",
+ unit, MAXUNITS-1);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ ees = eesunits[unit];
+
+ bug->nvalues = 16;
+ bug->svalues = 0x0800;
+ bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0;
+ bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0;
+ bug->values[2] = (u_long)ees->status;
+ bug->values[3] = (u_long)ees->lastevent;
+ bug->values[4] = (u_long)ees->reason;
+ bug->values[5] = (u_long)ees->nsamples;
+ bug->values[6] = (u_long)ees->codestate;
+ bug->values[7] = (u_long)ees->day;
+ bug->values[8] = (u_long)ees->hour;
+ bug->values[9] = (u_long)ees->minute;
+ bug->values[10] = (u_long)ees->second;
+ bug->values[11] = (u_long)ees->tz;
+ bug->values[12] = ees->yearstart;
+ bug->values[13] = (ees->leaphold > current_time) ?
+ ees->leaphold - current_time : 0;
+ bug->values[14] = inherent_delay[unit].l_uf;
+ bug->values[15] = offset_fudge[unit].l_uf;
+
+ bug->ntimes = 11;
+ bug->stimes = 0x3f8;
+ bug->times[0] = ees->reftime;
+ bug->times[1] = ees->arrvtime;
+ bug->times[2] = ees->lastsampletime;
+ bug->times[3] = ees->offset;
+ bug->times[4] = ees->lowoffset;
+ bug->times[5] = ees->highoffset;
+ bug->times[6] = inherent_delay[unit];
+ bug->times[8] = os_delay[unit];
+ bug->times[7] = fudgefactor[unit];
+ bug->times[9] = offset_fudge[unit];
+ bug->times[10].l_ui = ees->yearstart;
+ bug->times[10].l_uf = 0;
+}
+
+struct refclock refclock_msfees = {
+ msfees_start, msfees_shutdown, msfees_poll,
+ msfees_control, msfees_init, msfees_buginfo, NOFLAGS
+};
+#endif /* defined(REFCLOCK) && defined(MSFEESPPS) && defined(STREAM) */
diff --git a/contrib/xntpd/xntpd/refclock_mx4200.c b/contrib/xntpd/xntpd/refclock_mx4200.c
new file mode 100644
index 000000000000..3c0d097a8d9e
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_mx4200.c
@@ -0,0 +1,1361 @@
+/*
+ * 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(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#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
+ */
+ memset((char *)mx4200units, 0, sizeof mx4200units);
+ memset((char *)unitinuse, 0, 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(HAVE_TERMIOS)
+ /*
+ * POSIX 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;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#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));
+ }
+ }
+
+ memset((char *)mx4200, 0, 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)
+ memmove((char *)&peer->refid, MX4200REFID, 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;
+ memmove(mx4200->lastcode, dpt, 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)
+ memmove((char *)&peer->refid,
+ MX4200REFID, 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];
+
+ memset((char *)bug, 0, 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;
+ memset((char *)jt, 0, sizeof(*jt));
+
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no rec-type");
+ ++cp;
+
+ /* Record type */
+ v = strtol(cp, &cp, 10);
+ if (v != PMVXG_D_TRECOVOUT)
+ return ("wrong rec-type");
+
+ /* Pulse valid indicator */
+ if (*cp++ != ',')
+ return ("no pulse-valid");
+ if (*cp == 'T')
+ *validp = 1;
+ else if (*cp == 'F')
+ *validp = 0;
+ else
+ return ("bad pulse-valid");
+ ++cp;
+
+ /* Year */
+ if (*cp++ != ',')
+ return ("no year");
+ jt->year = strtol(cp, &cp, 10);
+
+ /* Month of year */
+ if (*cp++ != ',')
+ return ("no month");
+ jt->month = strtol(cp, &cp, 10);
+
+ /* Day of month */
+ if (*cp++ != ',')
+ return ("no month day");
+ jt->monthday = strtol(cp, &cp, 10);
+
+ /* Hour */
+ if (*cp++ != ',')
+ return ("no hour");
+ jt->hour = strtol(cp, &cp, 10);
+
+ /* Minute */
+ if (*cp++ != ':')
+ return ("no minute");
+ jt->minute = strtol(cp, &cp, 10);
+
+ /* Second */
+ if (*cp++ != ':')
+ return ("no second");
+ jt->second = strtol(cp, &cp, 10);
+
+ /* Time indicator */
+ if (*cp++ != ',' || *cp++ == '\0')
+ return ("no time indicator");
+
+ /* Time recovery mode */
+ if (*cp++ != ',' || *cp++ == '\0')
+ return ("no time mode");
+
+ /* Oscillator offset */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no osc off");
+ ++cp;
+
+ /* Time mark error */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no time mark err");
+ ++cp;
+
+ /* User time bias */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no user bias");
+ ++cp;
+
+ /* Leap second flag */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no leap");
+ ++cp;
+ *leapsecp = strtol(cp, &cp, 10);
+
+ return (NULL);
+}
+
+/* Calculate the checksum */
+static u_char
+cksum(cp, n)
+ register char *cp;
+ register u_int n;
+{
+ register u_char ck;
+
+ for (ck = 0; n-- > 0; ++cp)
+ ck ^= *cp;
+ return (ck);
+}
+
+static void
+#if __STDC__
+mx4200_send(register int fd, const char *fmt, ...)
+#else
+mx4200_send(fd, fmt, va_alist)
+ register int fd;
+ const char *fmt;
+ va_dcl
+#endif
+{
+ register char *cp;
+ register int n, m;
+ va_list ap;
+ char buf[1024];
+ u_char ck;
+
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ cp = buf;
+ *cp++ = '$';
+#ifdef notdef
+ /* BSD is rational */
+ n = vsnprintf(cp, sizeof(buf) - 1, fmt, ap);
+#else
+ /* SunOS sucks */
+ (void)vsprintf(cp, fmt, ap);
+ n = strlen(cp);
+#endif
+ ck = cksum(cp, n);
+ cp += n;
+ ++n;
+#ifdef notdef
+ /* BSD is rational */
+ n += snprintf(cp, sizeof(buf) - n - 5, "*%02X\r\n", ck);
+#else
+ /* SunOS sucks */
+ sprintf(cp, "*%02X\r\n", ck);
+ n += strlen(cp);
+#endif
+
+ m = write(fd, buf, n);
+ if (m < 0)
+ syslog(LOG_ERR, "mx4200_send: write: %m (%s)", buf);
+ else if (m != n)
+ syslog(LOG_ERR, "mx4200_send: write: %d != %d (%s)", m, n, buf);
+ va_end(ap);
+}
+#endif
diff --git a/contrib/xntpd/xntpd/refclock_omega.c b/contrib/xntpd/xntpd/refclock_omega.c
new file mode 100644
index 000000000000..73be84d3859b
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_omega.c
@@ -0,0 +1,1019 @@
+/*
+ * 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(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#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
+ */
+ memset((char *)omegaunits, 0, sizeof omegaunits);
+ memset((char *)unitinuse, 0, 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(HAVE_TERMIOS)
+ /*
+ * POSIX 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;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#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));
+ }
+ }
+ memset((char *)omega, 0, 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)
+ memmove((char *)&peer->refid, OMEGAREFID, 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)
+ memmove((char *)&peer->refid,
+ OMEGAREFID, 4);
+ else
+ peer->refid = htonl(OMEGAHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ readonlyclockflag[unit] = in->flags & CLK_FLAG1;
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_OMEGA_TRUETIME;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVETIME2|
+ CLK_HAVEVAL1|CLK_HAVEVAL2|
+ CLK_HAVEFLAG1|CLK_HAVEFLAG2;
+ out->clockdesc = OMEGADESCRIPTION;
+ out->fudgetime1 = fudgefactor1[unit];
+ out->fudgetime2 = fudgefactor2[unit];
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = 0;
+ out->flags = readonlyclockflag[unit];
+ if (unitinuse[unit]) {
+ omega = omegaunits[unit];
+ out->flags |= omega->station << 1;
+ out->lencode = omega->lencode;
+ out->lastcode = omega->lastcode;
+ out->timereset = current_time - omega->timestarted;
+ out->polls = omega->polls;
+ out->noresponse = omega->noreply;
+ out->badformat = omega->badformat;
+ out->baddata = omega->baddata;
+ out->lastevent = omega->lastevent;
+ out->currentstatus = omega->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+
+/*
+ * omega_buginfo - return clock dependent debugging info
+ */
+static void
+omega_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct omegaunit *omega;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "omega_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ omega = omegaunits[unit];
+
+ bug->nvalues = 11;
+ bug->ntimes = 5;
+ if (omega->lasttime != 0)
+ bug->values[0] = current_time - omega->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = (U_LONG)omega->reason;
+ bug->values[2] = (U_LONG)omega->year;
+ bug->values[3] = (U_LONG)omega->day;
+ bug->values[4] = (U_LONG)omega->hour;
+ bug->values[5] = (U_LONG)omega->minute;
+ bug->values[6] = (U_LONG)omega->second;
+ bug->values[7] = (U_LONG)omega->msec;
+ bug->values[8] = omega->noreply;
+ bug->values[9] = omega->yearstart;
+ bug->values[10] = omega->quality;
+ bug->stimes = 0x1c;
+ bug->times[0] = omega->lastref;
+ bug->times[1] = omega->lastrec;
+ bug->times[2] = omega->offset[0];
+ bug->times[3] = omega->offset[1];
+ bug->times[4] = omega->offset[2];
+}
+#endif
diff --git a/contrib/xntpd/xntpd/refclock_parse.c b/contrib/xntpd/xntpd/refclock_parse.c
new file mode 100644
index 000000000000..69e483764354
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_parse.c
@@ -0,0 +1,3538 @@
+#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS))
+/*
+ * /src/NTP/REPOSITORY/v3/xntpd/refclock_parse.c,v 3.45 1994/01/25 19:06:27 kardel Exp
+ *
+ * refclock_parse.c,v 3.45 1994/01/25 19:06:27 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,1994
+ * 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
+ *
+ * TTY defines:
+ * HAVE_BSD_TTYS - currently unsupported
+ * HAVE_SYSV_TTYS - will use termio.h
+ * HAVE_TERMIOS - will use termios.h
+ * STREAM - will use streams and implies HAVE_TERMIOS
+ */
+
+/*
+ * 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) && !defined(HAVE_TERMIOS)
+/* #error NEED TO DEFINE ONE OF "STREAM" or "HAVE_SYSV_TTYS" */
+NEED TO DEFINE ONE OF "STREAM", "HAVE_SYSV_TTYS" or "HAVE_TERMIOS"
+#endif
+
+#ifdef STREAM
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#ifndef HAVE_TERMIOS
+#define HAVE_TERMIOS
+#endif
+#endif
+
+#ifdef HAVE_TERMIOS
+#include <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 <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.45 1994/01/25 19:06:27 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 */
+ l_fp ppsdelay; /* clock local pps 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 NO_PPSDELAY 0
+
+#define DCF_ID "DCF" /* generic DCF */
+#define DCF_A_ID "DCFa" /* AM demodulation */
+#define DCF_P_ID "DCFp" /* psuedo random phase shift */
+#define GPS_ID "GPS" /* GPS receiver */
+
+#define NOCLOCK_ROOTDELAY 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 */
+ U_LONG cl_ppsdelay; /* current PPS 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,
+ NO_PPSDELAY,
+ 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,
+ NO_PPSDELAY,
+ 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,
+ NO_PPSDELAY,
+ 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,
+ NO_PPSDELAY,
+ 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,
+ NO_PPSDELAY,
+ 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,
+ NO_PPSDELAY,
+ 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,
+ NO_PPSDELAY,
+ 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,
+ NO_PPSDELAY,
+ 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,
+ NO_PPSDELAY,
+ 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;
+ }
+ memmove((caddr_t)&parsetime,
+ (caddr_t)&rbufp->recv_space,
+ 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()
+{
+ memset((caddr_t)parseunits, 0, 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 HAVE_TERMIOS
+ 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));
+ }
+ }
+
+ memset((char *)parse, 0, 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;
+
+ parse->ppsdelay.l_ui = 0; /* we can only pre-configure delays less than 1 second */
+ parse->ppsdelay.l_uf = parse->parse_type->cl_ppsdelay;
+
+ peer->rootdelay = parse->parse_type->cl_rootdelay;
+ peer->sstclktype = parse->parse_type->cl_type;
+ peer->precision = sys_precision;
+ peer->stratum = STRATUM_REFCLOCK;
+ if (peer->stratum <= 1)
+ memmove((char *)&peer->refid, parse->parse_type->cl_id, 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
+ memset((char *)tm.c_cc, 0, 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;
+ out->kv_list = (struct ctl_var *)0;
+ }
+
+ 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)
+ {
+ parse->ppsdelay = in->fudgetime2;
+ }
+
+ if (in->haveflags & CLK_HAVEVAL1)
+ {
+ parse->peer->stratum = (u_char)(in->fudgeval1 & 0xf);
+ if (parse->peer->stratum <= 1)
+ memmove((char *)&parse->peer->refid,
+ parse->parse_type->cl_id,
+ 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, *tt;
+ register struct tm *tm;
+ register short utcoff;
+ register char sign;
+ register int i;
+ time_t tim;
+
+ outstatus[0] = '\0';
+
+ out->haveflags = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3;
+ out->clockdesc = parse->parse_type->cl_description;
+
+ out->fudgetime1 = parse->basedelay;
+
+ out->fudgetime2 = parse->ppsdelay;
+
+ 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 */
+ tt = add_var(&out->kv_list, 40, RO);
+ sprintf(tt, "refclock_ppsskew=%s", lfptoms(&off, 6));
+ }
+ }
+
+ if (PARSE_PPS(parse->time.parse_state))
+ {
+ tt = add_var(&out->kv_list, 80, RO|DEF);
+ sprintf(tt, "refclock_ppstime=\"%s\"", prettydate(&parse->time.parse_ptime.fp));
+ }
+
+ /*
+ * 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 = '+';
+ }
+
+ tt = add_var(&out->kv_list, 128, RO|DEF);
+ sprintf(tt, "refclock_time=\"");
+ tt += strlen(tt);
+
+ if (parse->time.parse_time.fp.l_ui == 0)
+ {
+ strcpy(tt, "<UNDEFINED>\"");
+ }
+ else
+ {
+ strcpy(tt, prettydate(&parse->time.parse_time.fp));
+ t = tt + strlen(tt);
+
+ sprintf(t, " (%c%02d%02d)\"", sign, utcoff / 60, utcoff % 60);
+ }
+
+ if (!PARSE_GETTIMECODE(parse, &tmpctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
+ }
+ else
+ {
+ tt = add_var(&out->kv_list, 128, RO|DEF);
+ sprintf(tt, "refclock_status=\"");
+ tt += strlen(tt);
+
+ /*
+ * copy PPS flags from last read transaction (informational only)
+ */
+ tmpctl.parsegettc.parse_state |= parse->time.parse_state &
+ (PARSEB_PPS|PARSEB_S_PPS);
+
+ (void) parsestate(tmpctl.parsegettc.parse_state, tt);
+
+ strcat(tt, "\"");
+
+ if (tmpctl.parsegettc.parse_count)
+ mkascii(outstatus+strlen(outstatus), sizeof(outstatus)- strlen(outstatus) - 1,
+ tmpctl.parsegettc.parse_buffer, tmpctl.parsegettc.parse_count - 1);
+
+ 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
+ {
+ tt = add_var(&out->kv_list, 80, RO|DEF);
+ sprintf(tt, "refclock_format=\"");
+
+ strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
+ strcat(tt,"\"");
+ }
+
+ /*
+ * gather state statistics
+ */
+
+ tt = add_var(&out->kv_list, 200, RO|DEF);
+ strcpy(tt, "refclock_states=\"");
+ tt += strlen(tt);
+
+ 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(tt, "%s%s%s: %s (%d.%02d%%)",
+ sum ? "; " : "",
+ (parse->status == i) ? "*" : "",
+ clockstatus(i),
+ l_mktime(stime),
+ percent / 100, percent % 100);
+ sum += stime;
+ tt += strlen(tt);
+ }
+ }
+
+ sprintf(tt, "; running time: %s\"", l_mktime(sum));
+
+ tt = add_var(&out->kv_list, 32, RO);
+ sprintf(tt, "refclock_id=\"%s\"", parse->parse_type->cl_id);
+
+ tt = add_var(&out->kv_list, 80, RO);
+ sprintf(tt, "refclock_iomode=\"%s\"", parse->binding->bd_description);
+
+ tt = add_var(&out->kv_list, 128, RO);
+ sprintf(tt, "refclock_driver_version=\"refclock_parse.c,v 3.45 1994/01/25 19:06:27 kardel Exp\"");
+
+ 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;
+
+ L_ADD(&offset, &parse->ppsdelay);
+
+ 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) || defined(PARSEPPS)
+ 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 || PARSEPPS */
+
+ /*
+ * 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));
+ memset((char *)parse->localdata, 0, 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 HAVE_TERMIOS
+ 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.45 1994/01/25 19:06:27 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.44 1994/01/25 17:32:23 kardel
+ * settable extended variables
+ *
+ * Revision 3.43 1994/01/23 16:28:39 kardel
+ * HAVE_TERMIOS introduced
+ *
+ * Revision 3.42 1994/01/22 11:35:04 kardel
+ * added HAVE_TERMIOS
+ *
+ * Revision 3.41 1993/11/27 18:44:37 kardel
+ * can't trust GPS166 on unsync
+ *
+ * Revision 3.40 1993/11/21 18:03:36 kardel
+ * useless declaration deleted
+ *
+ * Revision 3.39 1993/11/21 15:30:15 kardel
+ * static funcitions may be declared only at outer level
+ *
+ * Revision 3.38 1993/11/15 21:26:49 kardel
+ * conditional define comments fixed
+ *
+ * Revision 3.37 1993/11/11 11:20:49 kardel
+ * declaration fixes
+ *
+ * Revision 3.36 1993/11/10 12:17:14 kardel
+ * #ifdef glitch
+ *
+ * Revision 3.35 1993/11/01 21:15:06 kardel
+ * comments updated
+ *
+ * Revision 3.34 1993/11/01 20:01:08 kardel
+ * parse Solaris support (initial version)
+ *
+ * Revision 3.33 1993/10/30 09:44:58 kardel
+ * conditional compilation flag cleanup
+ *
+ * Revision 3.32 1993/10/22 14:28:43 kardel
+ * Oct. 22nd 1993 reconcilation
+ *
+ * Revision 3.31 1993/10/10 21:19:10 kardel
+ * compilation cleanup - (minimal porting tests)
+ *
+ * Revision 3.30 1993/10/09 21:44:35 kardel
+ * syslog strings fixed
+ *
+ * Revision 3.29 1993/10/09 14:40:15 kardel
+ * default precision setting fixed
+ *
+ * Revision 3.28 1993/10/08 14:48:22 kardel
+ * Changed offset determination logic:
+ * Take the PPS offset if it is available and the time
+ * code offset is within [-0.5..0.5[, otherwise stick
+ * to the time code offset
+ *
+ * Revision 3.27 1993/10/08 00:53:17 kardel
+ * announce also simulated PPS via CIOGETEV in ntpq cl
+ *
+ * Revision 3.26 1993/10/07 23:29:35 kardel
+ * trimble fixes
+ *
+ * Revision 3.25 1993/10/06 21:13:35 kardel
+ * test reversed (CIOGETEV support)
+ *
+ * Revision 3.24 1993/10/03 20:18:26 kardel
+ * Well, values > 999999 in the usec field from uniqtime() timestamps
+ * can prove harmful.
+ *
+ * Revision 3.23 1993/10/03 19:49:54 kardel
+ * buftvtots where failing on uninitialized time stamps
+ *
+ * Revision 3.22 1993/10/03 19:11:09 kardel
+ * restructured I/O handling
+ *
+ * Revision 3.21 1993/09/29 11:30:18 kardel
+ * special init for trimble to set EOL
+ *
+ * Revision 3.20 1993/09/27 22:46:28 kardel
+ * preserve module stack if I_PUSH parse fails
+ *
+ * Revision 3.19 1993/09/27 21:10:11 kardel
+ * wrong structure member
+ *
+ * Revision 3.18 1993/09/27 13:05:06 kardel
+ * Trimble is true polling only
+ *
+ * Revision 3.17 1993/09/27 12:47:10 kardel
+ * poll string support generalized
+ *
+ * Revision 3.16 1993/09/26 23:40:56 kardel
+ * new parse driver logic
+ *
+ * Revision 3.15 1993/09/24 15:00:51 kardel
+ * Sep 23rd distribution...
+ *
+ * Revision 3.14 1993/09/22 18:21:15 kardel
+ * support ppsclock streams module (-DSTREAM -DPPSPPS -DPARSEPPS -UPARSESTREAM)
+ *
+ * Revision 3.13 1993/09/05 15:38:33 kardel
+ * not every cpp understands #error...
+ *
+ * Revision 3.12 1993/09/02 20:04:19 kardel
+ * TTY cleanup
+ *
+ * Revision 3.11 1993/09/01 21:48:47 kardel
+ * conditional cleanup
+ *
+ * Revision 3.10 1993/09/01 11:32:45 kardel
+ * assuming HAVE_POSIX_TTYS when STREAM defined
+ *
+ * Revision 3.9 1993/08/31 22:31:46 kardel
+ * SINIX-M SysVR4 integration
+ *
+ * Revision 3.8 1993/08/27 00:29:50 kardel
+ * compilation cleanup
+ *
+ * Revision 3.7 1993/08/24 22:27:30 kardel
+ * cleaned up AUTOCONF DCF77 mess 8-) - wasn't too bad
+ *
+ * Revision 3.6 1993/08/24 21:36:23 kardel
+ * casting and ifdefs
+ *
+ * Revision 3.5 1993/07/09 23:36:59 kardel
+ * HAVE_POSIX_TTYS used to produce errors 8-( - BSD driver support still lacking
+ *
+ * Revision 3.4 1993/07/09 12:42:29 kardel
+ * RAW DCF now officially released
+ *
+ * Revision 3.3 1993/07/09 11:50:37 kardel
+ * running GPS also on 960 to be able to switch GPS/DCF77
+ *
+ * Revision 3.2 1993/07/09 11:37:34 kardel
+ * Initial restructured version + GPS support
+ *
+ * Revision 3.1 1993/07/06 10:01:07 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/contrib/xntpd/xntpd/refclock_pst.c b/contrib/xntpd/xntpd/refclock_pst.c
new file mode 100644
index 000000000000..4b8909afb801
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_pst.c
@@ -0,0 +1,1804 @@
+/*
+ * 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(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#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
+ */
+ memset((char *)pstunits, 0, sizeof pstunits);
+ memset((char *)unitinuse, 0, 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(HAVE_TERMIOS)
+ /*
+ * POSIX 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;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#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));
+ }
+ }
+ memset((char *)pst, 0, 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)
+ memmove((char *)&peer->refid, WWVREFID, 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)
+ memmove((char *)&pst->peer->refid, WWVREFID, 4);
+ else
+ memmove((char *)&pst->peer->refid, WWVHREFID, 4);
+ }
+
+ /*
+ * Give the data to the reference clock support code
+ */
+ record_clock_stats(&(pst->peer->srcadr), pst->lastcode);
+ refclock_receive(pst->peer, &off[i], 0, dispersion, &pst->reftimes[NPSTSAMPS-1],
+ &pst->rectimes[NPSTSAMPS-1], pst->leap);
+
+ /*
+ * If the don't-sync flag isn't on, we're nominal.
+ */
+ if (pst->leap == 0)
+ pst_event(pst, CEVNT_NOMINAL);
+ pst_reset(pst);
+}
+
+
+
+/*
+ * pst_receive - receive data from a PST clock, call the appropriate
+ * routine to process it, and advance the state.
+ */
+static void
+pst_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register struct pstunit *pst;
+ register U_LONG tmp;
+
+ pst = (struct pstunit *)rbufp->recv_srcclock;
+
+ /*
+ * Process based on the current state.
+ */
+ switch(pst->state) {
+ case STATE_IDLE:
+ return; /* Ignore the input */
+
+ case STATE_QV:
+ if (!pst_QV_process(pst, rbufp)) {
+ /*
+ * Set the state to idle, but request another
+ * QV poll.
+ */
+ pst->badformat++;
+ pst_event(pst, CEVNT_BADREPLY);
+ pst->state = STATE_IDLE;
+ pst->flags |= PST_DOQV;
+ } else {
+ /*
+ * This went okay. Advance the state to
+ * QM and send the request.
+ */
+ pst->state = STATE_QM;
+ pst_send(pst, "QM", 2);
+ }
+ return;
+
+ case STATE_QM:
+ if (!pst_QM_process(pst, rbufp)) {
+ /*
+ * Idle us and note the error
+ */
+ pst->badformat++;
+ pst_event(pst, CEVNT_BADREPLY);
+ pst->state = STATE_IDLE;
+ return;
+ }
+ if (pst->flags & PST_NOTIME) {
+ /*
+ * Here we aren't getting any time because the
+ * clock is still searching. Don't bother
+ * looking for anything. Remove any leap
+ * second hold, however, since this should
+ * ensure the clock is sensible.
+ */
+ pst_event(pst, CEVNT_FAULT);
+ pst->state = STATE_IDLE;
+ if (pst->nextsample > 0)
+ pst_reset(pst); /* Make sure rate low */
+ return;
+ }
+
+ /*
+ * Next is QD. Do it.
+ */
+ pst->state = STATE_QD;
+ pst_send(pst, "QD", 2);
+ return;
+
+ case STATE_QD:
+ if (!pst_QD_process(pst, rbufp)) {
+ /*
+ * Idle us and note the error
+ */
+ pst->badformat++;
+ pst_event(pst, CEVNT_BADDATE);
+ pst->state = STATE_IDLE;
+ } else {
+ /*
+ * Last step is QT.
+ */
+ pst->state = STATE_QT;
+ pst_send(pst, "QT", 2);
+ }
+ return;
+
+ case STATE_QT:
+ pst->state = STATE_IDLE;
+ if (!pst_QT_process(pst, rbufp, &pst->lastref, &pst->lastrec)) {
+ /*
+ * Note the error
+ */
+ pst->baddata++;
+ pst_event(pst, CEVNT_BADTIME);
+ return;
+ }
+ break;
+
+ default:
+ syslog(LOG_ERR,
+ "pst_receive: unit %d invalid state %d",
+ pst->unit, pst->state);
+ return;
+ }
+
+
+ /*
+ * You may not have noticed this, but the only way we end up
+ * out here is if we've completed polling and have a couple of
+ * valid time stamps. First see if we should reset the
+ * structure.
+ */
+ if (pst->nextsample > 0) {
+ tmp = pst->lastrec.l_ui - pst->rectimes[0].l_ui;
+ if (tmp > (U_LONG)psttab[pst->nextsample].tooold)
+ pst_reset(pst);
+ }
+
+ pst->rectimes[pst->nextsample] = pst->lastrec;
+ pst->reftimes[pst->nextsample] = pst->lastref;
+ pst->nextsample++;
+ if (pst->flags & PST_WWVH)
+ pst->station--;
+ else
+ pst->station++;
+
+ if (pst->flags & (PST_SIGFAULT|PST_HARDERR)) {
+ pst_event(pst, CEVNT_FAULT);
+ pst->leap = LEAP_NOTINSYNC;
+ } else if (pst->timesincesync > freerun[pst->unit]) {
+ pst_event(pst, CEVNT_PROP);
+ pst->leap = LEAP_NOTINSYNC;
+ }
+
+ if (pst->nextsample >= NPSTSAMPS)
+ pst_process(pst);
+}
+
+
+/*
+ * pst_compute_delay - compute appropriate things to tell clock about delays
+ */
+static void
+pst_compute_delay(prop_delay, prop_data)
+ U_LONG prop_delay;
+ struct pst_propagate *prop_data;
+{
+ register int code;
+ register U_LONG tsf;
+
+ /*
+ * Convert (truncate) the delay to milliseconds. Save the
+ * characters needed to send this to the clock and compute
+ * the remainder to be added in later.
+ */
+ code = tsftomsu(prop_delay, 0);
+ MSUTOTSF(code, tsf);
+ prop_data->remainder = prop_delay - tsf;
+ if (prop_data->remainder & 0x80000000)
+ prop_data->remainder = 0;
+ prop_data->msbchar = BINTOPST((code >> 2) & 0x1f);
+ prop_data->lsbchar = BINTOPST(code & 0x3);
+}
+
+
+/*
+ * pst_control - set fudge factors, return statistics
+ */
+static void
+pst_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct pstunit *pst;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "pst_control: unit %d invalid", unit);
+ return;
+ }
+
+ if (in != 0) {
+ int doqv = 0;
+
+ if (in->haveflags & CLK_HAVETIME1)
+ if (in->fudgetime1.l_ui == 0
+ && in->fudgetime1.l_uf <= PSTMAXPROP) {
+ wwv_prop_delay[unit] = in->fudgetime1;
+ doqv = 1;
+ pst_compute_delay(wwv_prop_delay[unit].l_uf,
+ &wwv_prop_data[unit]);
+ }
+ if (in->haveflags & CLK_HAVETIME2)
+ if (in->fudgetime2.l_ui == 0
+ && in->fudgetime2.l_uf <= PSTMAXPROP) {
+ wwvh_prop_delay[unit] = in->fudgetime2;
+ doqv = 1;
+ pst_compute_delay(wwvh_prop_delay[unit].l_uf,
+ &wwvh_prop_data[unit]);
+ }
+ if (in->haveflags & CLK_HAVEVAL1) {
+ stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
+ }
+ if (in->haveflags & CLK_HAVEVAL2) {
+ if (in->fudgeval2 > 0 && in->fudgeval2 < 9990)
+ freerun[unit] = (u_short)in->fudgeval2;
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ sloppyclock[unit] = in->flags & CLK_FLAG1;
+ }
+ if (unitinuse[unit]) {
+ /*
+ * Should actually reselect clock, but
+ * will wait for the next timecode
+ */
+ if (in->haveflags & CLK_HAVEVAL1) {
+ pstunits[unit]->peer->stratum
+ = stratumtouse[unit];
+ if (stratumtouse[unit] > 1)
+ pstunits[unit]->peer->refid
+ = htonl(PSTHSREFID);
+ }
+
+ if ((in->haveflags & CLK_HAVEFLAG3) &&
+ (in->flags & CLK_FLAG3)) {
+ pstunits[unit]->flags |= PST_DORESET;
+ } else if (doqv || ((in->haveflags & CLK_HAVEFLAG2) &&
+ (in->flags & CLK_FLAG2))) {
+ pstunits[unit]->flags |= PST_DOQV;
+ }
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_WWV_PST;
+ out->flags = 0;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|
+ CLK_HAVEVAL2|CLK_HAVEFLAG1;
+ out->fudgetime1 = wwv_prop_delay[unit];
+ out->fudgetime2 = wwvh_prop_delay[unit];
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = (LONG)freerun[unit];
+ out->flags = sloppyclock[unit];
+ if (unitinuse[unit]) {
+ pst = pstunits[unit];
+ out->clockdesc = pst->description;
+ out->lencode = pst->lencode;
+ out->lastcode = pst->lastcode;
+ out->timereset = current_time - pst->timestarted;
+ out->polls = pst->polls;
+ out->noresponse = pst->noreply;
+ out->badformat = pst->badformat;
+ out->baddata = pst->baddata;
+ out->lastevent = pst->lastevent;
+ out->currentstatus = pst->status;
+ } else {
+ out->clockdesc = pstdefdesc;
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+
+/*
+ * pst_buginfo - return clock dependent debugging info
+ */
+static void
+pst_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct pstunit *pst;
+ register int i;
+
+ bug->nvalues = bug->ntimes = 0;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "pst_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ pst = pstunits[unit];
+
+ bug->nvalues = 14;
+ bug->svalues = (1<<10);
+ bug->values[0] = (U_LONG)pst->nextsample;
+ bug->values[1] = (U_LONG)pst->state;
+ bug->values[2] = (U_LONG)pst->reason;
+ bug->values[3] = (U_LONG)pst->flags;
+ bug->values[4] = (U_LONG)pst->yearday;
+ bug->values[5] = (U_LONG)pst->hour;
+ bug->values[6] = (U_LONG)pst->minute;
+ bug->values[7] = (U_LONG)pst->second;
+ bug->values[8] = (U_LONG)pst->millisecond;
+ bug->values[9] = (U_LONG)pst->timezone;
+ bug->values[10] = (U_LONG)((LONG)pst->tzoffset);
+ bug->values[11] = (U_LONG)pst->timesincesync;
+ bug->values[12] = pst->yearstart;
+ bug->ntimes = ((NPSTSAMPS*2)+2) > NCLKBUGTIMES ? NCLKBUGTIMES :
+ ((NPSTSAMPS*2)+2);
+ bug->stimes = 0;
+ for (i = 0; i < (bug->ntimes-2)/2; i++) {
+ bug->times[2*i] = pst->rectimes[i];
+ bug->times[(2*i) + 1] = pst->reftimes[i];
+ }
+ bug->times[bug->ntimes - 2] = pst->lastrec;
+ bug->times[bug->ntimes - 1] = pst->lastref;
+}
+#endif
diff --git a/contrib/xntpd/xntpd/refclock_tpro.c b/contrib/xntpd/xntpd/refclock_tpro.c
new file mode 100644
index 000000000000..54d9f3cb5287
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_tpro.c
@@ -0,0 +1,498 @@
+/*
+ * refclock_tpro - clock driver for the KSI/Odetics TPRO-S IRIG-B reader
+ */
+#if defined(REFCLOCK) && defined(TPRO)
+#include <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
+ */
+ memset((char *)tprounits, 0, sizeof tprounits);
+ memset((char *)unitinuse, 0, 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));
+ }
+ }
+ memset((char *)tpro, 0, 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)
+ memmove((char *)&peer->refid, TPROREFID, 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)
+ memmove((char *)&peer->refid,
+ TPROREFID, 4);
+ else
+ peer->refid = htonl(TPROHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ sloppyclockflag[unit] = in->flags & CLK_FLAG1;
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_IRIG_TPRO;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1;
+ out->clockdesc = TPRODESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgetime2.l_ui = 0;
+ out->fudgetime2.l_uf = 0;
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = 0;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ tpro = tprounits[unit];
+ out->lencode = tpro->lencode;
+ out->lastcode = tpro->lastcode;
+ out->timereset = current_time - tpro->timestarted;
+ out->polls = tpro->polls;
+ out->noresponse = tpro->noreply;
+ out->badformat = tpro->badformat;
+ out->baddata = tpro->baddata;
+ out->lastevent = tpro->lastevent;
+ out->currentstatus = tpro->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+/*
+ * tpro_buginfo - return clock dependent debugging info
+ */
+static void
+tpro_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct tprounit *tpro;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "tpro_buginfo: unit %d invalid)", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ tpro = tprounits[unit];
+
+ bug->nvalues = 11;
+ bug->ntimes = 5;
+ if (tpro->lasttime != 0)
+ bug->values[0] = current_time - tpro->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[2] = (U_LONG)tpro->year;
+ bug->values[3] = (U_LONG)tpro->day;
+ bug->values[4] = (U_LONG)tpro->hour;
+ bug->values[5] = (U_LONG)tpro->minute;
+ bug->values[6] = (U_LONG)tpro->second;
+ bug->values[7] = (U_LONG)tpro->usec;
+ bug->values[9] = tpro->yearstart;
+ bug->stimes = 0x1c;
+ bug->times[0] = tpro->lastref;
+ bug->times[1] = tpro->lastrec;
+}
+#endif
diff --git a/contrib/xntpd/xntpd/refclock_wwvb.c b/contrib/xntpd/xntpd/refclock_wwvb.c
new file mode 100644
index 000000000000..9b2563a797db
--- /dev/null
+++ b/contrib/xntpd/xntpd/refclock_wwvb.c
@@ -0,0 +1,1045 @@
+/*
+ * 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(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#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
+ */
+ memset((char *)wwvbunits, 0, sizeof wwvbunits);
+ memset((char *)unitinuse, 0, 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(HAVE_TERMIOS)
+ /*
+ * POSIX 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;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#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));
+ }
+ }
+ memset((char *)wwvb, 0, 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)
+ memmove((char *)&peer->refid, WWVBREFID, 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)
+ memmove((char *)&peer->refid,
+ WWVBREFID, 4);
+ else
+ peer->refid = htonl(WWVBHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEFLAG4) {
+ sloppyclockflag[unit] = in->flags & CLK_FLAG4;
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_WWVB_SPECTRACOM;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG4;
+ out->clockdesc = WWVBDESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgetime2.l_ui = 0;
+ out->fudgetime2.l_uf = 0;
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = 0;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ wwvb = wwvbunits[unit];
+ out->lencode = wwvb->lencode;
+ out->lastcode = wwvb->lastcode;
+ out->timereset = current_time - wwvb->timestarted;
+ out->polls = wwvb->polls;
+ out->noresponse = wwvb->noreply;
+ out->badformat = wwvb->badformat;
+ out->baddata = wwvb->baddata;
+ out->lastevent = wwvb->lastevent;
+ out->currentstatus = wwvb->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+/*
+ * wwvb_buginfo - return clock dependent debugging info
+ */
+static void
+wwvb_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct wwvbunit *wwvb;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "wwvb_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ wwvb = wwvbunits[unit];
+
+ bug->nvalues = 11;
+ bug->ntimes = 5;
+ if (wwvb->lasttime != 0)
+ bug->values[0] = current_time - wwvb->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = (U_LONG)wwvb->reason;
+ bug->values[2] = (U_LONG)wwvb->year;
+ bug->values[3] = (U_LONG)wwvb->day;
+ bug->values[4] = (U_LONG)wwvb->hour;
+ bug->values[5] = (U_LONG)wwvb->minute;
+ bug->values[6] = (U_LONG)wwvb->second;
+ bug->values[7] = (U_LONG)wwvb->msec;
+ bug->values[8] = wwvb->noreply;
+ bug->values[9] = wwvb->yearstart;
+ bug->values[10] = wwvb->quality;
+ bug->stimes = 0x1c;
+ bug->times[0] = wwvb->lastref;
+ bug->times[1] = wwvb->lastrec;
+ bug->times[2] = wwvb->offset[0];
+ bug->times[3] = wwvb->offset[1];
+ bug->times[4] = wwvb->offset[2];
+}
+#endif
diff --git a/contrib/xntpd/xntpdc/Makefile b/contrib/xntpd/xntpdc/Makefile
new file mode 100644
index 000000000000..b5b78be48bc7
--- /dev/null
+++ b/contrib/xntpd/xntpdc/Makefile
@@ -0,0 +1,28 @@
+#
+# $Id: Makefile,v 1.2 1993/12/22 11:34:00 rgrimes Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= xntpdc
+MAN8= ${.CURDIR}/../doc/xntpdc.8
+CLEANFILES+= .version version.c
+
+SRCS= ntpdc.c ntpdc_ops.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion xntpdc
+
+.include <bsd.prog.mk>
diff --git a/contrib/xntpd/xntpdc/README b/contrib/xntpd/xntpdc/README
new file mode 100644
index 000000000000..9d0b661e6c09
--- /dev/null
+++ b/contrib/xntpd/xntpdc/README
@@ -0,0 +1,6 @@
+README file for directory ./xntpdc of the NTP Version 3 distribution
+
+This directory contains the sources for the xntpdc utility program. See
+the README and RELNOTES files in the parent directory for directions on
+how to make and install this program. The current version number of this
+program is in the version.c file.
diff --git a/contrib/xntpd/xntpdc/ntpdc.c b/contrib/xntpd/xntpdc/ntpdc.c
new file mode 100644
index 000000000000..001bd77c1e55
--- /dev/null
+++ b/contrib/xntpd/xntpdc/ntpdc.c
@@ -0,0 +1,1536 @@
+/* ntpdc.c,v 3.1 1993/07/06 01:11:59 jbj Exp
+ * xntpdc - control and monitor your xntpd daemon
+ */
+#include <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) || defined(SYS_BSDI)
+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 ntp_optind;
+ extern char *ntp_optarg;
+
+ delay_time.l_ui = 0;
+ delay_time.l_uf = DEFDELAY;
+
+ progname = argv[0];
+ while ((c = ntp_getopt(argc, argv, "c:dilnps")) != EOF)
+ switch (c) {
+ case 'c':
+ ADDCMD(ntp_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 (ntp_optind == argc) {
+ ADDHOST(DEFHOST);
+ } else {
+ for (; ntp_optind < argc; ntp_optind++)
+ ADDHOST(argv[ntp_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 */
+ memset(haveseq, 0, 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();
+ memmove(datap, (char *)rpkt.data, 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;
+
+ memset((char *)&qpkt, 0, 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) {
+ memmove((char *)qpkt.data, qdata, 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) {
+ memmove((char *)num, hp->h_addr, 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) || defined(SYS_BSDI)
+ 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) || defined(SYS_BSDI)
+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 || bsdi */
+ return strcmp(*name1, *name2);
+}
+
+
+/*
+ * printusage - print usage information for a command
+ */
+static void
+printusage(xcp, fp)
+ struct xcmd *xcp;
+ FILE *fp;
+{
+ register int i;
+
+ (void) fprintf(fp, "usage: %s", xcp->keyword);
+ for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
+ if (xcp->arg[i] & OPT)
+ (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
+ else
+ (void) fprintf(fp, " %s", xcp->desc[i]);
+ }
+ (void) fprintf(fp, "\n");
+}
+
+
+/*
+ * timeout - set time out time
+ */
+static void
+timeout(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ int val;
+
+ if (pcmd->nargs == 0) {
+ val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
+ (void) fprintf(fp, "primary timeout %d ms\n", val);
+ } else {
+ tvout.tv_sec = pcmd->argval[0].uval / 1000;
+ tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
+ * 1000;
+ }
+}
+
+
+/*
+ * delay - set delay for auth requests
+ */
+static void
+delay(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ int isneg;
+ U_LONG val;
+
+ if (pcmd->nargs == 0) {
+ val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
+ (void) fprintf(fp, "delay %d ms\n", val);
+ } else {
+ if (pcmd->argval[0].ival < 0) {
+ isneg = 1;
+ val = (U_LONG)(-pcmd->argval[0].ival);
+ } else {
+ isneg = 0;
+ val = (U_LONG)pcmd->argval[0].ival;
+ }
+
+ delay_time.l_ui = val / 1000;
+ val %= 1000;
+ delay_time.l_uf = val * 4294967; /* 2**32/1000 */
+
+ if (isneg)
+ L_NEG(&delay_time);
+ }
+}
+
+
+/*
+ * host - set the host we are dealing with.
+ */
+static void
+host(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ if (pcmd->nargs == 0) {
+ if (havehost)
+ (void) fprintf(fp, "current host is %s\n", currenthost);
+ else
+ (void) fprintf(fp, "no current host\n");
+ } else if (openhost(pcmd->argval[0].string)) {
+ (void) fprintf(fp, "current host set to %s\n", currenthost);
+ } else {
+ if (havehost)
+ (void) fprintf(fp,
+ "current host remains %s\n", currenthost);
+ else
+ (void) fprintf(fp, "still no current host\n");
+ }
+}
+
+
+/*
+ * poll - do one (or more) polls of the host via NTP
+ */
+/*ARGSUSED*/
+static void
+ntp_poll(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ (void) fprintf(fp, "poll not implemented yet\n");
+}
+
+
+/*
+ * keyid - get a keyid to use for authenticating requests
+ */
+static void
+keyid(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ if (pcmd->nargs == 0) {
+ if (info_auth_keyid == 0)
+ (void) fprintf(fp, "no keyid defined\n");
+ else
+ (void) fprintf(fp, "keyid is %u\n", info_auth_keyid);
+ } else {
+ info_auth_keyid = pcmd->argval[0].uval;
+ }
+}
+
+
+/*
+ * keytype - get type of key to use for authenticating requests
+ */
+static void
+keytype(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ if (pcmd->nargs == 0)
+ fprintf(fp, "keytype is %s",
+ (info_auth_keytype == KEY_TYPE_MD5) ? "md5" : "des");
+ else
+ switch (*(pcmd->argval[0].string)) {
+ case 'm':
+ case 'M':
+ info_auth_keytype = KEY_TYPE_MD5;
+ break;
+
+ case 'd':
+ case 'D':
+ info_auth_keytype = KEY_TYPE_DES;
+ break;
+
+ default:
+ fprintf(fp, "keytype must be 'md5' or 'des'\n");
+ }
+}
+
+
+
+/*
+ * passwd - get an authentication key
+ */
+/*ARGSUSED*/
+static void
+passwd(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ char *pass;
+
+ if (info_auth_keyid == 0) {
+ info_auth_keyid = getkeyid("Keyid: ");
+ if (info_auth_keyid == 0) {
+ (void)fprintf(fp, "Keyid must be defined\n");
+ return;
+ }
+ }
+ pass = getpass("Password: ");
+ if (*pass == '\0')
+ (void) fprintf(fp, "Password unchanged\n");
+ else
+ authusekey(info_auth_keyid, info_auth_keytype, pass);
+}
+
+
+/*
+ * hostnames - set the showhostnames flag
+ */
+static void
+hostnames(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ if (pcmd->nargs == 0) {
+ if (showhostnames)
+ (void) fprintf(fp, "hostnames being shown\n");
+ else
+ (void) fprintf(fp, "hostnames not being shown\n");
+ } else {
+ if (STREQ(pcmd->argval[0].string, "yes"))
+ showhostnames = 1;
+ else if (STREQ(pcmd->argval[0].string, "no"))
+ showhostnames = 0;
+ else
+ (void)fprintf(stderr, "What?\n");
+ }
+}
+
+
+/*
+ * setdebug - set/change debugging level
+ */
+static void
+setdebug(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ if (pcmd->nargs == 0) {
+ (void) fprintf(fp, "debug level is %d\n", debug);
+ return;
+ } else if (STREQ(pcmd->argval[0].string, "no")) {
+ debug = 0;
+ } else if (STREQ(pcmd->argval[0].string, "more")) {
+ debug++;
+ } else if (STREQ(pcmd->argval[0].string, "less")) {
+ debug--;
+ } else {
+ (void) fprintf(fp, "What?\n");
+ return;
+ }
+ (void) fprintf(fp, "debug level set to %d\n", debug);
+}
+
+
+/*
+ * quit - stop this nonsense
+ */
+/*ARGSUSED*/
+static void
+quit(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ if (havehost)
+ (void) close(sockfd); /* cleanliness next to godliness */
+ exit(0);
+}
+
+
+/*
+ * version - print the current version number
+ */
+/*ARGSUSED*/
+static void
+version(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ extern char *Version;
+
+ (void) fprintf(fp, "%s\n", Version);
+}
+
+
+/*
+ * warning - print a warning message
+ */
+static void
+warning(fmt, st1, st2)
+ char *fmt;
+ char *st1;
+ char *st2;
+{
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) fprintf(stderr, fmt, st1, st2);
+ (void) fprintf(stderr, ": ");
+ perror("");
+}
+
+
+/*
+ * error - print a message and exit
+ */
+static void
+error(fmt, st1, st2)
+ char *fmt;
+ char *st1;
+ char *st2;
+{
+ warning(fmt, st1, st2);
+ exit(1);
+}
+
+/*
+ * getkeyid - prompt the user for a keyid to use
+ */
+static U_LONG
+getkeyid(prompt)
+char *prompt;
+{
+ register char *p;
+ register c;
+ FILE *fi;
+ char pbuf[20];
+
+ if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
+ fi = stdin;
+ else
+ setbuf(fi, (char *)NULL);
+ fprintf(stderr, "%s", prompt); fflush(stderr);
+ for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
+ if (p < &pbuf[18])
+ *p++ = c;
+ }
+ *p = '\0';
+ if (fi != stdin)
+ fclose(fi);
+ return (U_LONG)atoi(pbuf);
+}
diff --git a/contrib/xntpd/xntpdc/ntpdc.h b/contrib/xntpd/xntpdc/ntpdc.h
new file mode 100644
index 000000000000..7784ebc5a672
--- /dev/null
+++ b/contrib/xntpd/xntpdc/ntpdc.h
@@ -0,0 +1,59 @@
+/* ntpdc.h,v 3.1 1993/07/06 01:12:01 jbj Exp
+ * ntpdc.h - definitions of interest to xntpdc
+ */
+#include "ntp_fp.h"
+#include "ntp.h"
+#include "ntp_request.h"
+#include "ntp_string.h"
+#include "ntp_malloc.h"
+
+/*
+ * Maximum number of arguments
+ */
+#define MAXARGS 4
+
+/*
+ * Flags for forming descriptors.
+ */
+#define OPT 0x80 /* this argument is optional, or'd with type */
+
+#define NO 0x0
+#define STR 0x1 /* string argument */
+#define UINT 0x2 /* unsigned integer */
+#define INT 0x3 /* signed integer */
+#define ADD 0x4 /* IP network address */
+
+/*
+ * Arguments are returned in a union
+ */
+typedef union {
+ char *string;
+ LONG ival;
+ U_LONG uval;
+ U_LONG netnum;
+} arg_v;
+
+/*
+ * Structure for passing parsed command line
+ */
+struct parse {
+ char *keyword;
+ arg_v argval[MAXARGS];
+ int nargs;
+};
+
+/*
+ * xntpdc includes a command parser which could charitably be called
+ * crude. The following structure is used to define the command
+ * syntax.
+ */
+struct xcmd {
+ char *keyword; /* command key word */
+ void (*handler) P((struct parse *, FILE *)); /* command handler */
+ u_char arg[MAXARGS]; /* descriptors for arguments */
+ char *desc[MAXARGS]; /* descriptions for arguments */
+ char *comment;
+};
+
+extern int doquery P((int, int, int, int, int, char *, int *, int *, char **));
+extern char * nntohost P((U_LONG));
diff --git a/contrib/xntpd/xntpdc/ntpdc_ops.c b/contrib/xntpd/xntpdc/ntpdc_ops.c
new file mode 100644
index 000000000000..55483faeba10
--- /dev/null
+++ b/contrib/xntpd/xntpdc/ntpdc_ops.c
@@ -0,0 +1,2421 @@
+/* ntpdc_ops.c,v 3.1 1993/07/06 01:12:02 jbj Exp
+ * ntpdc_ops.c - subroutines which are called to perform operations by xntpdc
+ */
+#include <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;
+ memmove(junk, (char *)&pp->refid, 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;
+ memmove(junk, (char *)&is->refid, 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;
+ memset((char *)&fudgedata, 0, 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/contrib/xntpd/xntpres/Makefile b/contrib/xntpd/xntpres/Makefile
new file mode 100644
index 000000000000..9505b1bfffe7
--- /dev/null
+++ b/contrib/xntpd/xntpres/Makefile
@@ -0,0 +1,28 @@
+#
+# $Id: Makefile,v 1.2 1993/12/22 11:34:09 rgrimes Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= xntpres
+NOMAN=
+CLEANFILES+= .version version.c
+
+SRCS= xntpres.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion xntpres
+
+.include <bsd.prog.mk>
diff --git a/contrib/xntpd/xntpres/README b/contrib/xntpd/xntpres/README
new file mode 100644
index 000000000000..06d7266b4f2c
--- /dev/null
+++ b/contrib/xntpd/xntpres/README
@@ -0,0 +1,6 @@
+README file for directory ./xntpres of the NTP Version 3 distribution
+
+This directory contains the sources for the xntpres utility program. See
+the README and RELNOTES files in the parent directory for directions on
+how to make and install this program. The current version number of this
+program is in the version.c file.
diff --git a/contrib/xntpd/xntpres/xntpres.c b/contrib/xntpd/xntpres/xntpres.c
new file mode 100644
index 000000000000..ee88b1f3be98
--- /dev/null
+++ b/contrib/xntpd/xntpres/xntpres.c
@@ -0,0 +1,846 @@
+/* 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 ntp_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 = ntp_getopt(argc, argv, "dr")) != EOF)
+ switch (c) {
+ case 'd':
+ ++debug;
+ break;
+ case 'r':
+ ++removefile;
+ break;
+ default:
+ errflg++;
+ break;
+ }
+ if (errflg || (ntp_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[ntp_optind], &req_keyid)) {
+ syslog(LOG_ERR, "undecodeable keyid %s", argv[ntp_optind]);
+ exit(1);
+ }
+
+ keyfile = argv[ntp_optind+1];
+ conffile = argv[ntp_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);
+ memmove(cp, name, 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.
+ */
+ memmove((char *)&(entry->ce_peeraddr),
+ hp->h_addr,
+ 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);
+ }
+
+ memset((char *)&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons(NTP_PORT); /* trash */
+ saddr.sin_addr.s_addr = htonl(LOCALHOST); /* garbage */
+
+
+ /*
+ * Make the socket non-blocking. We'll wait with select()
+ */
+#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
+ */
+ memset((char *)&reqpkt, 0, 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));
+ memmove(reqpkt.data, (char *)conf, 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;
+ }
+}