From c0b746e5e8d9479f05b3749cbf1f73b8928719bd Mon Sep 17 00:00:00 2001 From: Ollivier Robert Date: Thu, 9 Dec 1999 13:01:21 +0000 Subject: Virgin import of ntpd 4.0.98f --- contrib/ntp/COPYRIGHT | 151 + contrib/ntp/ChangeLog | 2737 +++++ contrib/ntp/INSTALL | 178 + contrib/ntp/Makefile.am | 95 + contrib/ntp/Makefile.in | 490 + contrib/ntp/NEWS | 83 + contrib/ntp/NOTES.y2kfixes | 107 + contrib/ntp/README | 152 + contrib/ntp/README.cvs | 24 + contrib/ntp/README.des | 20 + contrib/ntp/README.hackers | 25 + contrib/ntp/TODO | 126 + contrib/ntp/WHERE-TO-START | 41 + contrib/ntp/acconfig.h | 457 + contrib/ntp/aclocal.m4 | 253 + contrib/ntp/adjtimed/Makefile.am | 8 + contrib/ntp/adjtimed/Makefile.in | 334 + contrib/ntp/adjtimed/README | 22 + contrib/ntp/adjtimed/adjtimed.c | 491 + contrib/ntp/build | 66 + contrib/ntp/clockstuff/Makefile.am | 16 + contrib/ntp/clockstuff/Makefile.in | 342 + contrib/ntp/clockstuff/README | 31 + contrib/ntp/clockstuff/chutest.c | 816 ++ contrib/ntp/clockstuff/clktest.c | 529 + contrib/ntp/clockstuff/propdelay.c | 544 + contrib/ntp/conf/README | 17 + contrib/ntp/conf/baldwin.conf | 35 + contrib/ntp/conf/beauregard.conf | 23 + contrib/ntp/conf/dewey.conf | 42 + contrib/ntp/conf/grundoon.conf | 154 + contrib/ntp/conf/malarky.conf | 24 + contrib/ntp/conf/pogo.conf | 30 + contrib/ntp/config.guess | 1090 ++ contrib/ntp/config.h.in | 887 ++ contrib/ntp/config.sub | 1215 +++ contrib/ntp/configure | 10546 +++++++++++++++++++ contrib/ntp/configure.in | 2896 +++++ contrib/ntp/dot.emacs | 18 + contrib/ntp/excludes | 1 + contrib/ntp/html/accopt.htm | 219 + contrib/ntp/html/assoc.htm | 170 + contrib/ntp/html/authopt.htm | 281 + contrib/ntp/html/biblio.htm | 259 + contrib/ntp/html/build.htm | 206 + contrib/ntp/html/clockopt.htm | 193 + contrib/ntp/html/config.htm | 291 + contrib/ntp/html/confopt.htm | 330 + contrib/ntp/html/copyright.htm | 123 + contrib/ntp/html/debug.htm | 288 + contrib/ntp/html/driver1.htm | 157 + contrib/ntp/html/driver10.htm | 114 + contrib/ntp/html/driver11.htm | 150 + contrib/ntp/html/driver12.htm | 98 + contrib/ntp/html/driver16.htm | 43 + contrib/ntp/html/driver18.htm | 235 + contrib/ntp/html/driver19.htm | 124 + contrib/ntp/html/driver2.htm | 137 + contrib/ntp/html/driver20.htm | 131 + contrib/ntp/html/driver22.htm | 129 + contrib/ntp/html/driver23.htm | 87 + contrib/ntp/html/driver24.htm | 85 + contrib/ntp/html/driver26.htm | 109 + contrib/ntp/html/driver27.htm | 634 ++ contrib/ntp/html/driver28.htm | 133 + contrib/ntp/html/driver29.htm | 1254 +++ contrib/ntp/html/driver3.htm | 131 + contrib/ntp/html/driver30.htm | 153 + contrib/ntp/html/driver32.htm | 42 + contrib/ntp/html/driver33.htm | 38 + contrib/ntp/html/driver34.htm | 54 + contrib/ntp/html/driver4.htm | 126 + contrib/ntp/html/driver5.htm | 159 + contrib/ntp/html/driver6.htm | 253 + contrib/ntp/html/driver7.htm | 227 + contrib/ntp/html/driver8.htm | 343 + contrib/ntp/html/driver9.htm | 133 + contrib/ntp/html/exec.htm | 292 + contrib/ntp/html/extern.htm | 40 + contrib/ntp/html/gadget.htm | 111 + contrib/ntp/html/hints.htm | 26 + contrib/ntp/html/hints/a-ux | 195 + contrib/ntp/html/hints/aix | 76 + contrib/ntp/html/hints/bsdi | 65 + contrib/ntp/html/hints/changes | 13 + contrib/ntp/html/hints/decosf1 | 40 + contrib/ntp/html/hints/decosf2 | 54 + contrib/ntp/html/hints/hpux | 158 + contrib/ntp/html/hints/linux | 5 + contrib/ntp/html/hints/notes-xntp-v3 | 119 + contrib/ntp/html/hints/parse | 105 + contrib/ntp/html/hints/refclocks | 35 + contrib/ntp/html/hints/rs6000 | 56 + contrib/ntp/html/hints/sco.htm | 39 + contrib/ntp/html/hints/sgi | 74 + contrib/ntp/html/hints/solaris.html | 139 + contrib/ntp/html/hints/solaris.xtra.4023118 | 36 + contrib/ntp/html/hints/solaris.xtra.4095849 | 74 + contrib/ntp/html/hints/solaris.xtra.S99ntpd | 20 + contrib/ntp/html/hints/solaris.xtra.patchfreq | 85 + contrib/ntp/html/hints/sun4 | 15 + contrib/ntp/html/hints/svr4-dell | 8 + contrib/ntp/html/hints/svr4_package | 33 + contrib/ntp/html/hints/todo | 4 + contrib/ntp/html/hints/vxworks.html | 18 + contrib/ntp/html/hints/winnt | 207 + contrib/ntp/html/howto.htm | 315 + contrib/ntp/html/htmlprimer.htm | 1198 +++ contrib/ntp/html/index.htm | 201 + contrib/ntp/html/kern.htm | 51 + contrib/ntp/html/kernpps.htm | 26 + contrib/ntp/html/ldisc.htm | 161 + contrib/ntp/html/measure.htm | 50 + contrib/ntp/html/miscopt.htm | 162 + contrib/ntp/html/monopt.htm | 370 + contrib/ntp/html/mx4200data.htm | 445 + contrib/ntp/html/notes.htm | 1544 +++ contrib/ntp/html/ntpd.htm | 183 + contrib/ntp/html/ntpdate.htm | 185 + contrib/ntp/html/ntpdc.htm | 620 ++ contrib/ntp/html/ntpq.htm | 747 ++ contrib/ntp/html/ntptime.htm | 96 + contrib/ntp/html/ntptrace.htm | 82 + contrib/ntp/html/parsedata.htm | 407 + contrib/ntp/html/parsenew.htm | 237 + contrib/ntp/html/patches.htm | 70 + contrib/ntp/html/porting.htm | 78 + contrib/ntp/html/pps.htm | 83 + contrib/ntp/html/prefer.htm | 332 + contrib/ntp/html/quick.htm | 99 + contrib/ntp/html/rdebug.htm | 67 + contrib/ntp/html/refclock.htm | 126 + contrib/ntp/html/release.htm | 199 + contrib/ntp/html/tickadj.htm | 103 + contrib/ntp/html/vxworks.htm | 153 + contrib/ntp/html/y2k.htm | 141 + contrib/ntp/include/Makefile.am | 44 + contrib/ntp/include/Makefile.in | 273 + contrib/ntp/include/README | 4 + contrib/ntp/include/adjtime.h | 63 + contrib/ntp/include/ascii.h | 61 + contrib/ntp/include/binio.h | 41 + contrib/ntp/include/global.h | 51 + contrib/ntp/include/gps.h | 53 + contrib/ntp/include/ieee754io.h | 43 + contrib/ntp/include/iosignal.h | 23 + contrib/ntp/include/l_stdlib.h | 495 + contrib/ntp/include/mbg_gps166.h | 538 + contrib/ntp/include/md5.h | 51 + contrib/ntp/include/mx4200.h | 40 + contrib/ntp/include/ntif.h | 98 + contrib/ntp/include/ntp.h | 714 ++ contrib/ntp/include/ntp_calendar.h | 112 + contrib/ntp/include/ntp_control.h | 260 + contrib/ntp/include/ntp_datum.h | 30 + contrib/ntp/include/ntp_filegen.h | 51 + contrib/ntp/include/ntp_fp.h | 373 + contrib/ntp/include/ntp_if.h | 54 + contrib/ntp/include/ntp_io.h | 33 + contrib/ntp/include/ntp_machine.h | 512 + contrib/ntp/include/ntp_malloc.h | 19 + contrib/ntp/include/ntp_proto.h | 8 + contrib/ntp/include/ntp_refclock.h | 265 + contrib/ntp/include/ntp_request.h | 790 ++ contrib/ntp/include/ntp_select.h | 35 + contrib/ntp/include/ntp_stdlib.h | 172 + contrib/ntp/include/ntp_string.h | 48 + contrib/ntp/include/ntp_syscall.h | 48 + contrib/ntp/include/ntp_syslog.h | 77 + contrib/ntp/include/ntp_types.h | 69 + contrib/ntp/include/ntp_unixtime.h | 132 + contrib/ntp/include/ntpd.h | 381 + contrib/ntp/include/parse.h | 391 + contrib/ntp/include/parse_conf.h | 54 + contrib/ntp/include/recvbuff.h | 113 + contrib/ntp/include/trimble.h | 125 + contrib/ntp/install-sh | 238 + contrib/ntp/kernel/Makefile.am | 5 + contrib/ntp/kernel/Makefile.in | 309 + contrib/ntp/kernel/README | 200 + contrib/ntp/kernel/chuinit.c | 76 + contrib/ntp/kernel/clkinit.c | 76 + contrib/ntp/kernel/sys/Makefile.am | 8 + contrib/ntp/kernel/sys/Makefile.in | 238 + contrib/ntp/kernel/sys/README | 11 + contrib/ntp/kernel/sys/bsd_audioirig.h | 101 + contrib/ntp/kernel/sys/chudefs.h | 22 + contrib/ntp/kernel/sys/clkdefs.h | 38 + contrib/ntp/kernel/sys/i8253.h | 48 + contrib/ntp/kernel/sys/parsestreams.h | 107 + contrib/ntp/kernel/sys/pcl720.h | 95 + contrib/ntp/kernel/sys/ppsclock.h | 64 + contrib/ntp/kernel/sys/timex.h | 309 + contrib/ntp/kernel/sys/tpro.h | 34 + contrib/ntp/kernel/tty_chu.c | 276 + contrib/ntp/kernel/tty_chu_STREAMS.c | 603 ++ contrib/ntp/kernel/tty_clk.c | 317 + contrib/ntp/kernel/tty_clk_STREAMS.c | 266 + contrib/ntp/libntp/Makefile.am | 31 + contrib/ntp/libntp/Makefile.in | 796 ++ contrib/ntp/libntp/README | 5 + contrib/ntp/libntp/a_md5encrypt.c | 132 + contrib/ntp/libntp/adjtime.c | 152 + contrib/ntp/libntp/adjtimex.c | 15 + contrib/ntp/libntp/atoint.c | 50 + contrib/ntp/libntp/atolfp.c | 118 + contrib/ntp/libntp/atouint.c | 35 + contrib/ntp/libntp/authencrypt.c | 97 + contrib/ntp/libntp/authkeys.c | 574 + contrib/ntp/libntp/authparity.c | 57 + contrib/ntp/libntp/authreadkeys.c | 205 + contrib/ntp/libntp/authusekey.c | 134 + contrib/ntp/libntp/binio.c | 128 + contrib/ntp/libntp/buftvtots.c | 65 + contrib/ntp/libntp/caljulian.c | 115 + contrib/ntp/libntp/calleapwhen.c | 59 + contrib/ntp/libntp/caltontp.c | 42 + contrib/ntp/libntp/calyearstart.c | 22 + contrib/ntp/libntp/clocktime.c | 132 + contrib/ntp/libntp/clocktypes.c | 98 + contrib/ntp/libntp/decodenetnum.c | 59 + contrib/ntp/libntp/dofptoa.c | 118 + contrib/ntp/libntp/dolfptoa.c | 162 + contrib/ntp/libntp/emalloc.c | 48 + contrib/ntp/libntp/findconfig.c | 72 + contrib/ntp/libntp/fptoa.c | 25 + contrib/ntp/libntp/fptoms.c | 24 + contrib/ntp/libntp/getopt.c | 107 + contrib/ntp/libntp/gpstolfp.c | 41 + contrib/ntp/libntp/hextoint.c | 39 + contrib/ntp/libntp/hextolfp.c | 67 + contrib/ntp/libntp/humandate.c | 62 + contrib/ntp/libntp/ieee754io.c | 575 + contrib/ntp/libntp/inttoa.c | 20 + contrib/ntp/libntp/iosignal.c | 518 + contrib/ntp/libntp/lib_strbuf.c | 22 + contrib/ntp/libntp/lib_strbuf.h | 27 + contrib/ntp/libntp/log.c | 152 + contrib/ntp/libntp/log.h | 21 + contrib/ntp/libntp/machines.c | 218 + contrib/ntp/libntp/md5c.c | 350 + contrib/ntp/libntp/memmove.c | 136 + contrib/ntp/libntp/mexit.c | 34 + contrib/ntp/libntp/mfp_mul.c | 140 + contrib/ntp/libntp/mfptoa.c | 23 + contrib/ntp/libntp/mfptoms.c | 23 + contrib/ntp/libntp/mktime.c | 282 + contrib/ntp/libntp/modetoa.c | 34 + contrib/ntp/libntp/mstolfp.c | 100 + contrib/ntp/libntp/msutotsf.c | 35 + contrib/ntp/libntp/msyslog.c | 170 + contrib/ntp/libntp/netof.c | 25 + contrib/ntp/libntp/numtoa.c | 24 + contrib/ntp/libntp/numtohost.c | 39 + contrib/ntp/libntp/octtoint.c | 35 + contrib/ntp/libntp/prettydate.c | 72 + contrib/ntp/libntp/ranny.c | 82 + contrib/ntp/libntp/recvbuff.c | 277 + contrib/ntp/libntp/refnumtoa.c | 31 + contrib/ntp/libntp/statestr.c | 271 + contrib/ntp/libntp/strerror.c | 40 + contrib/ntp/libntp/syssignal.c | 123 + contrib/ntp/libntp/systime.c | 404 + contrib/ntp/libntp/tsftomsu.c | 38 + contrib/ntp/libntp/tstotv.c | 135 + contrib/ntp/libntp/tvtoa.c | 38 + contrib/ntp/libntp/tvtots.c | 159 + contrib/ntp/libntp/uglydate.c | 50 + contrib/ntp/libntp/uinttoa.c | 20 + contrib/ntp/libntp/utvtoa.c | 26 + contrib/ntp/libntp/ymd2yd.c | 37 + contrib/ntp/libparse/Makefile.am | 93 + contrib/ntp/libparse/Makefile.in | 598 ++ contrib/ntp/libparse/README | 96 + contrib/ntp/libparse/clk_computime.c | 194 + contrib/ntp/libparse/clk_dcf7000.c | 188 + contrib/ntp/libparse/clk_hopf6021.c | 280 + contrib/ntp/libparse/clk_meinberg.c | 747 ++ contrib/ntp/libparse/clk_rawdcf.c | 581 + contrib/ntp/libparse/clk_rcc8000.c | 195 + contrib/ntp/libparse/clk_schmid.c | 231 + contrib/ntp/libparse/clk_trimtaip.c | 188 + contrib/ntp/libparse/clk_trimtsip.c | 421 + contrib/ntp/libparse/clk_varitext.c | 239 + contrib/ntp/libparse/clk_wharton.c | 180 + contrib/ntp/libparse/data_mbg.c | 490 + contrib/ntp/libparse/info_trimble.c | 94 + contrib/ntp/libparse/kclk_computime.c | 17 + contrib/ntp/libparse/kclk_dcf7000.c | 17 + contrib/ntp/libparse/kclk_hopf6021.c | 17 + contrib/ntp/libparse/kclk_meinberg.c | 17 + contrib/ntp/libparse/kclk_rawdcf.c | 15 + contrib/ntp/libparse/kclk_rcc8000.c | 17 + contrib/ntp/libparse/kclk_schmid.c | 17 + contrib/ntp/libparse/kclk_trimtaip.c | 17 + contrib/ntp/libparse/kclk_trimtsip.c | 17 + contrib/ntp/libparse/kclk_varitext.c | 28 + contrib/ntp/libparse/kclk_wharton.c | 15 + contrib/ntp/libparse/kparse.c | 17 + contrib/ntp/libparse/kparse_conf.c | 17 + contrib/ntp/libparse/mkinfo_rcmd.sed | 8 + contrib/ntp/libparse/mkinfo_scmd.sed | 16 + contrib/ntp/libparse/parse.c | 917 ++ contrib/ntp/libparse/parse_conf.c | 149 + contrib/ntp/libparse/parsesolaris.c | 1173 +++ contrib/ntp/libparse/parsestreams.c | 1335 +++ contrib/ntp/libparse/trim_info.c | 35 + contrib/ntp/librsaref/Makefile.am | 50 + contrib/ntp/librsaref/Makefile.in | 346 + contrib/ntp/missing | 134 + contrib/ntp/mkinstalldirs | 32 + contrib/ntp/ntpd/Makefile.am | 45 + contrib/ntp/ntpd/Makefile.in | 907 ++ contrib/ntp/ntpd/check_y2k.c | 624 ++ contrib/ntp/ntpd/jupiter.h | 255 + contrib/ntp/ntpd/map_vme.c | 135 + contrib/ntp/ntpd/ntp_config.c | 2405 +++++ contrib/ntp/ntpd/ntp_control.c | 2652 +++++ contrib/ntp/ntpd/ntp_filegen.c | 547 + contrib/ntp/ntpd/ntp_intres.c | 970 ++ contrib/ntp/ntpd/ntp_io.c | 1754 +++ contrib/ntp/ntpd/ntp_loopfilter.c | 847 ++ contrib/ntp/ntpd/ntp_monitor.c | 354 + contrib/ntp/ntpd/ntp_peer.c | 795 ++ contrib/ntp/ntpd/ntp_proto.c | 2165 ++++ contrib/ntp/ntpd/ntp_refclock.c | 1322 +++ contrib/ntp/ntpd/ntp_request.c | 2334 ++++ contrib/ntp/ntpd/ntp_restrict.c | 460 + contrib/ntp/ntpd/ntp_timer.c | 308 + contrib/ntp/ntpd/ntp_util.c | 640 ++ contrib/ntp/ntpd/ntpd.c | 1121 ++ contrib/ntp/ntpd/refclock_acts.c | 981 ++ contrib/ntp/ntpd/refclock_arbiter.c | 429 + contrib/ntp/ntpd/refclock_arc.c | 1323 +++ contrib/ntp/ntpd/refclock_as2201.c | 388 + contrib/ntp/ntpd/refclock_atom.c | 488 + contrib/ntp/ntpd/refclock_bancomm.c | 483 + contrib/ntp/ntpd/refclock_chronolog.c | 343 + contrib/ntp/ntpd/refclock_chu.c | 1464 +++ contrib/ntp/ntpd/refclock_conf.c | 262 + contrib/ntp/ntpd/refclock_datum.c | 873 ++ contrib/ntp/ntpd/refclock_dumbclock.c | 381 + contrib/ntp/ntpd/refclock_gpsvme.c | 613 ++ contrib/ntp/ntpd/refclock_heath.c | 487 + contrib/ntp/ntpd/refclock_hpgps.c | 603 ++ contrib/ntp/ntpd/refclock_irig.c | 1079 ++ contrib/ntp/ntpd/refclock_jupiter.c | 1262 +++ contrib/ntp/ntpd/refclock_leitch.c | 619 ++ contrib/ntp/ntpd/refclock_local.c | 258 + contrib/ntp/ntpd/refclock_msfees.c | 1444 +++ contrib/ntp/ntpd/refclock_mx4200.c | 1774 ++++ contrib/ntp/ntpd/refclock_nmea.c | 411 + contrib/ntp/ntpd/refclock_oncore.c | 1660 +++ contrib/ntp/ntpd/refclock_palisade.c | 880 ++ contrib/ntp/ntpd/refclock_palisade.h | 167 + contrib/ntp/ntpd/refclock_parse.c | 5340 ++++++++++ contrib/ntp/ntpd/refclock_pst.c | 318 + contrib/ntp/ntpd/refclock_ptbacts.c | 16 + contrib/ntp/ntpd/refclock_shm.c | 320 + contrib/ntp/ntpd/refclock_tpro.c | 209 + contrib/ntp/ntpd/refclock_trak.c | 361 + contrib/ntp/ntpd/refclock_true.c | 852 ++ contrib/ntp/ntpd/refclock_ulink.c | 319 + contrib/ntp/ntpd/refclock_usno.c | 674 ++ contrib/ntp/ntpd/refclock_wwvb.c | 440 + contrib/ntp/ntpdate/Makefile.am | 20 + contrib/ntp/ntpdate/Makefile.in | 381 + contrib/ntp/ntpdate/README | 7 + contrib/ntp/ntpdate/ntpdate.c | 2036 ++++ contrib/ntp/ntpdate/ntpdate.h | 95 + contrib/ntp/ntpdate/ntptime_config.c | 557 + contrib/ntp/ntpdate/ntptimeset.c | 2174 ++++ contrib/ntp/ntpdc/Makefile.am | 21 + contrib/ntp/ntpdc/Makefile.in | 361 + contrib/ntp/ntpdc/README | 6 + contrib/ntp/ntpdc/ntpdc.c | 1689 +++ contrib/ntp/ntpdc/ntpdc.h | 59 + contrib/ntp/ntpdc/ntpdc_ops.c | 2471 +++++ contrib/ntp/ntpq/Makefile.am | 21 + contrib/ntp/ntpq/Makefile.in | 360 + contrib/ntp/ntpq/README | 6 + contrib/ntp/ntpq/ntpq.c | 3095 ++++++ contrib/ntp/ntpq/ntpq.h | 89 + contrib/ntp/ntpq/ntpq_ops.c | 1651 +++ contrib/ntp/ntptrace/Makefile.am | 19 + contrib/ntp/ntptrace/Makefile.in | 349 + contrib/ntp/ntptrace/README | 7 + contrib/ntp/ntptrace/ntptrace.c | 784 ++ contrib/ntp/ntptrace/ntptrace.h | 36 + contrib/ntp/parseutil/Makefile.am | 10 + contrib/ntp/parseutil/Makefile.in | 334 + contrib/ntp/parseutil/README | 16 + contrib/ntp/parseutil/dcfd.c | 1850 ++++ contrib/ntp/parseutil/testdcf.c | 495 + contrib/ntp/readme.y2kfixes | Bin 0 -> 8192 bytes contrib/ntp/results.y2kfixes | 76 + contrib/ntp/scripts/Makefile.am | 1 + contrib/ntp/scripts/Makefile.in | 210 + contrib/ntp/scripts/README | 30 + contrib/ntp/scripts/calc_tickadj | 38 + contrib/ntp/scripts/checktime | 79 + contrib/ntp/scripts/fixautomakedepsmagic | 28 + contrib/ntp/scripts/hpadjtime.sh | 18 + contrib/ntp/scripts/mkver.in | 31 + contrib/ntp/scripts/monitoring/README | 154 + .../ntp/scripts/monitoring/loopwatch.config.SAMPLE | 89 + contrib/ntp/scripts/monitoring/lr.pl | 145 + contrib/ntp/scripts/monitoring/ntp.pl | 478 + contrib/ntp/scripts/monitoring/ntploopstat | 457 + contrib/ntp/scripts/monitoring/ntploopwatch | 1667 +++ contrib/ntp/scripts/monitoring/ntptrap | 463 + contrib/ntp/scripts/monitoring/timelocal.pl | 77 + contrib/ntp/scripts/ntp-groper | 95 + contrib/ntp/scripts/ntp-restart | 9 + contrib/ntp/scripts/ntpver.in | 7 + contrib/ntp/scripts/plot_summary.pl | 333 + contrib/ntp/scripts/rc1/postinstall | 2 + contrib/ntp/scripts/rc1/preinstall | 6 + contrib/ntp/scripts/rc1/preremove | 4 + contrib/ntp/scripts/rc1/prototype | 19 + contrib/ntp/scripts/rc1/xntp | 29 + contrib/ntp/scripts/rc2/local.ntpd | 64 + contrib/ntp/scripts/stats.ulrich.patches | 1003 ++ contrib/ntp/scripts/stats/README | 39 + contrib/ntp/scripts/stats/README.stats | 246 + contrib/ntp/scripts/stats/README.timecodes | 149 + contrib/ntp/scripts/stats/clock.awk | 431 + contrib/ntp/scripts/stats/dupe.awk | 8 + contrib/ntp/scripts/stats/ensemble.S | 5 + contrib/ntp/scripts/stats/ensemble.awk | 17 + contrib/ntp/scripts/stats/etf.S | 15 + contrib/ntp/scripts/stats/etf.awk | 19 + contrib/ntp/scripts/stats/itf.S | 5 + contrib/ntp/scripts/stats/itf.awk | 19 + contrib/ntp/scripts/stats/loop.S | 7 + contrib/ntp/scripts/stats/loop.awk | 45 + contrib/ntp/scripts/stats/loop_summary | 2 + contrib/ntp/scripts/stats/peer.awk | 68 + contrib/ntp/scripts/stats/psummary.awk | 82 + contrib/ntp/scripts/stats/summary.sh | 88 + contrib/ntp/scripts/stats/tdata.S | 5 + contrib/ntp/scripts/stats/tdata.awk | 45 + contrib/ntp/scripts/summary.pl | 357 + contrib/ntp/scripts/support/README | 73 + contrib/ntp/scripts/support/bin/monl | 213 + contrib/ntp/scripts/support/bin/mvstats | 23 + contrib/ntp/scripts/support/conf/hp300.hp300 | 0 contrib/ntp/scripts/support/conf/hp700.hp700 | 0 .../ntp/scripts/support/conf/hp700.hp700.faui47 | 0 contrib/ntp/scripts/support/conf/hp800.hp800 | 0 contrib/ntp/scripts/support/conf/ntp.conf | 3 + contrib/ntp/scripts/support/conf/sun3.sun3 | 0 contrib/ntp/scripts/support/conf/sun4.sun4.faui01 | 0 contrib/ntp/scripts/support/conf/sun4.sun4.faui10 | 0 contrib/ntp/scripts/support/conf/sun4.sun4.faui45 | 0 contrib/ntp/scripts/support/conf/sun4.sun4c | 0 .../ntp/scripts/support/conf/sun4.sun4c.Lucifer | 0 contrib/ntp/scripts/support/conf/sun4.sun4m | 0 contrib/ntp/scripts/support/conf/sun4.sun4m.faui42 | 0 .../ntp/scripts/support/conf/sun4.sun4m.faui45m | 0 contrib/ntp/scripts/support/conf/tickconf | 19 + contrib/ntp/scripts/support/etc/cron | 18 + contrib/ntp/scripts/support/etc/crontab | 8 + contrib/ntp/scripts/support/etc/install | 67 + contrib/ntp/scripts/support/etc/rc | 198 + contrib/ntp/scripts/support/etc/setup | 72 + contrib/ntp/stamp-h.in | 1 + contrib/ntp/util/Makefile.am | 18 + contrib/ntp/util/Makefile.in | 492 + contrib/ntp/util/README | 37 + contrib/ntp/util/ansi2knr.1 | 36 + contrib/ntp/util/ansi2knr.c | 720 ++ contrib/ntp/util/byteorder.c | 56 + contrib/ntp/util/hist.c | 107 + contrib/ntp/util/jitter.c | 70 + contrib/ntp/util/kern.c | 224 + contrib/ntp/util/longsize.c | 11 + contrib/ntp/util/ntptime.c | 399 + contrib/ntp/util/precision.c | 172 + contrib/ntp/util/sht.c | 185 + contrib/ntp/util/testrs6000.c | 55 + contrib/ntp/util/tickadj.c | 904 ++ contrib/ntp/util/timetrim.c | 95 + 483 files changed, 150243 insertions(+) create mode 100644 contrib/ntp/COPYRIGHT create mode 100644 contrib/ntp/ChangeLog create mode 100644 contrib/ntp/INSTALL create mode 100644 contrib/ntp/Makefile.am create mode 100644 contrib/ntp/Makefile.in create mode 100644 contrib/ntp/NEWS create mode 100644 contrib/ntp/NOTES.y2kfixes create mode 100644 contrib/ntp/README create mode 100644 contrib/ntp/README.cvs create mode 100644 contrib/ntp/README.des create mode 100644 contrib/ntp/README.hackers create mode 100644 contrib/ntp/TODO create mode 100644 contrib/ntp/WHERE-TO-START create mode 100644 contrib/ntp/acconfig.h create mode 100644 contrib/ntp/aclocal.m4 create mode 100644 contrib/ntp/adjtimed/Makefile.am create mode 100644 contrib/ntp/adjtimed/Makefile.in create mode 100644 contrib/ntp/adjtimed/README create mode 100644 contrib/ntp/adjtimed/adjtimed.c create mode 100755 contrib/ntp/build create mode 100644 contrib/ntp/clockstuff/Makefile.am create mode 100644 contrib/ntp/clockstuff/Makefile.in create mode 100644 contrib/ntp/clockstuff/README create mode 100644 contrib/ntp/clockstuff/chutest.c create mode 100644 contrib/ntp/clockstuff/clktest.c create mode 100644 contrib/ntp/clockstuff/propdelay.c create mode 100644 contrib/ntp/conf/README create mode 100644 contrib/ntp/conf/baldwin.conf create mode 100644 contrib/ntp/conf/beauregard.conf create mode 100644 contrib/ntp/conf/dewey.conf create mode 100644 contrib/ntp/conf/grundoon.conf create mode 100644 contrib/ntp/conf/malarky.conf create mode 100644 contrib/ntp/conf/pogo.conf create mode 100755 contrib/ntp/config.guess create mode 100644 contrib/ntp/config.h.in create mode 100755 contrib/ntp/config.sub create mode 100755 contrib/ntp/configure create mode 100644 contrib/ntp/configure.in create mode 100644 contrib/ntp/dot.emacs create mode 100644 contrib/ntp/excludes create mode 100644 contrib/ntp/html/accopt.htm create mode 100644 contrib/ntp/html/assoc.htm create mode 100644 contrib/ntp/html/authopt.htm create mode 100644 contrib/ntp/html/biblio.htm create mode 100644 contrib/ntp/html/build.htm create mode 100644 contrib/ntp/html/clockopt.htm create mode 100644 contrib/ntp/html/config.htm create mode 100644 contrib/ntp/html/confopt.htm create mode 100644 contrib/ntp/html/copyright.htm create mode 100644 contrib/ntp/html/debug.htm create mode 100644 contrib/ntp/html/driver1.htm create mode 100644 contrib/ntp/html/driver10.htm create mode 100644 contrib/ntp/html/driver11.htm create mode 100644 contrib/ntp/html/driver12.htm create mode 100644 contrib/ntp/html/driver16.htm create mode 100644 contrib/ntp/html/driver18.htm create mode 100644 contrib/ntp/html/driver19.htm create mode 100644 contrib/ntp/html/driver2.htm create mode 100644 contrib/ntp/html/driver20.htm create mode 100644 contrib/ntp/html/driver22.htm create mode 100644 contrib/ntp/html/driver23.htm create mode 100644 contrib/ntp/html/driver24.htm create mode 100644 contrib/ntp/html/driver26.htm create mode 100644 contrib/ntp/html/driver27.htm create mode 100644 contrib/ntp/html/driver28.htm create mode 100644 contrib/ntp/html/driver29.htm create mode 100644 contrib/ntp/html/driver3.htm create mode 100644 contrib/ntp/html/driver30.htm create mode 100644 contrib/ntp/html/driver32.htm create mode 100644 contrib/ntp/html/driver33.htm create mode 100644 contrib/ntp/html/driver34.htm create mode 100644 contrib/ntp/html/driver4.htm create mode 100644 contrib/ntp/html/driver5.htm create mode 100644 contrib/ntp/html/driver6.htm create mode 100644 contrib/ntp/html/driver7.htm create mode 100644 contrib/ntp/html/driver8.htm create mode 100644 contrib/ntp/html/driver9.htm create mode 100644 contrib/ntp/html/exec.htm create mode 100644 contrib/ntp/html/extern.htm create mode 100644 contrib/ntp/html/gadget.htm create mode 100644 contrib/ntp/html/hints.htm create mode 100644 contrib/ntp/html/hints/a-ux create mode 100644 contrib/ntp/html/hints/aix create mode 100644 contrib/ntp/html/hints/bsdi create mode 100644 contrib/ntp/html/hints/changes create mode 100644 contrib/ntp/html/hints/decosf1 create mode 100644 contrib/ntp/html/hints/decosf2 create mode 100644 contrib/ntp/html/hints/hpux create mode 100644 contrib/ntp/html/hints/linux create mode 100644 contrib/ntp/html/hints/notes-xntp-v3 create mode 100644 contrib/ntp/html/hints/parse create mode 100644 contrib/ntp/html/hints/refclocks create mode 100644 contrib/ntp/html/hints/rs6000 create mode 100644 contrib/ntp/html/hints/sco.htm create mode 100644 contrib/ntp/html/hints/sgi create mode 100644 contrib/ntp/html/hints/solaris.html create mode 100644 contrib/ntp/html/hints/solaris.xtra.4023118 create mode 100644 contrib/ntp/html/hints/solaris.xtra.4095849 create mode 100644 contrib/ntp/html/hints/solaris.xtra.S99ntpd create mode 100644 contrib/ntp/html/hints/solaris.xtra.patchfreq create mode 100644 contrib/ntp/html/hints/sun4 create mode 100644 contrib/ntp/html/hints/svr4-dell create mode 100644 contrib/ntp/html/hints/svr4_package create mode 100644 contrib/ntp/html/hints/todo create mode 100644 contrib/ntp/html/hints/vxworks.html create mode 100644 contrib/ntp/html/hints/winnt create mode 100644 contrib/ntp/html/howto.htm create mode 100644 contrib/ntp/html/htmlprimer.htm create mode 100644 contrib/ntp/html/index.htm create mode 100644 contrib/ntp/html/kern.htm create mode 100644 contrib/ntp/html/kernpps.htm create mode 100644 contrib/ntp/html/ldisc.htm create mode 100644 contrib/ntp/html/measure.htm create mode 100644 contrib/ntp/html/miscopt.htm create mode 100644 contrib/ntp/html/monopt.htm create mode 100644 contrib/ntp/html/mx4200data.htm create mode 100644 contrib/ntp/html/notes.htm create mode 100644 contrib/ntp/html/ntpd.htm create mode 100644 contrib/ntp/html/ntpdate.htm create mode 100644 contrib/ntp/html/ntpdc.htm create mode 100644 contrib/ntp/html/ntpq.htm create mode 100644 contrib/ntp/html/ntptime.htm create mode 100644 contrib/ntp/html/ntptrace.htm create mode 100644 contrib/ntp/html/parsedata.htm create mode 100644 contrib/ntp/html/parsenew.htm create mode 100644 contrib/ntp/html/patches.htm create mode 100644 contrib/ntp/html/porting.htm create mode 100644 contrib/ntp/html/pps.htm create mode 100644 contrib/ntp/html/prefer.htm create mode 100644 contrib/ntp/html/quick.htm create mode 100644 contrib/ntp/html/rdebug.htm create mode 100644 contrib/ntp/html/refclock.htm create mode 100644 contrib/ntp/html/release.htm create mode 100644 contrib/ntp/html/tickadj.htm create mode 100644 contrib/ntp/html/vxworks.htm create mode 100644 contrib/ntp/html/y2k.htm create mode 100644 contrib/ntp/include/Makefile.am create mode 100644 contrib/ntp/include/Makefile.in create mode 100644 contrib/ntp/include/README create mode 100644 contrib/ntp/include/adjtime.h create mode 100644 contrib/ntp/include/ascii.h create mode 100644 contrib/ntp/include/binio.h create mode 100644 contrib/ntp/include/global.h create mode 100644 contrib/ntp/include/gps.h create mode 100644 contrib/ntp/include/ieee754io.h create mode 100644 contrib/ntp/include/iosignal.h create mode 100644 contrib/ntp/include/l_stdlib.h create mode 100644 contrib/ntp/include/mbg_gps166.h create mode 100644 contrib/ntp/include/md5.h create mode 100644 contrib/ntp/include/mx4200.h create mode 100644 contrib/ntp/include/ntif.h create mode 100644 contrib/ntp/include/ntp.h create mode 100644 contrib/ntp/include/ntp_calendar.h create mode 100644 contrib/ntp/include/ntp_control.h create mode 100644 contrib/ntp/include/ntp_datum.h create mode 100644 contrib/ntp/include/ntp_filegen.h create mode 100644 contrib/ntp/include/ntp_fp.h create mode 100644 contrib/ntp/include/ntp_if.h create mode 100644 contrib/ntp/include/ntp_io.h create mode 100644 contrib/ntp/include/ntp_machine.h create mode 100644 contrib/ntp/include/ntp_malloc.h create mode 100644 contrib/ntp/include/ntp_proto.h create mode 100644 contrib/ntp/include/ntp_refclock.h create mode 100644 contrib/ntp/include/ntp_request.h create mode 100644 contrib/ntp/include/ntp_select.h create mode 100644 contrib/ntp/include/ntp_stdlib.h create mode 100644 contrib/ntp/include/ntp_string.h create mode 100644 contrib/ntp/include/ntp_syscall.h create mode 100644 contrib/ntp/include/ntp_syslog.h create mode 100644 contrib/ntp/include/ntp_types.h create mode 100644 contrib/ntp/include/ntp_unixtime.h create mode 100644 contrib/ntp/include/ntpd.h create mode 100644 contrib/ntp/include/parse.h create mode 100644 contrib/ntp/include/parse_conf.h create mode 100644 contrib/ntp/include/recvbuff.h create mode 100644 contrib/ntp/include/trimble.h create mode 100755 contrib/ntp/install-sh create mode 100644 contrib/ntp/kernel/Makefile.am create mode 100644 contrib/ntp/kernel/Makefile.in create mode 100644 contrib/ntp/kernel/README create mode 100644 contrib/ntp/kernel/chuinit.c create mode 100644 contrib/ntp/kernel/clkinit.c create mode 100644 contrib/ntp/kernel/sys/Makefile.am create mode 100644 contrib/ntp/kernel/sys/Makefile.in create mode 100644 contrib/ntp/kernel/sys/README create mode 100644 contrib/ntp/kernel/sys/bsd_audioirig.h create mode 100644 contrib/ntp/kernel/sys/chudefs.h create mode 100644 contrib/ntp/kernel/sys/clkdefs.h create mode 100644 contrib/ntp/kernel/sys/i8253.h create mode 100644 contrib/ntp/kernel/sys/parsestreams.h create mode 100644 contrib/ntp/kernel/sys/pcl720.h create mode 100644 contrib/ntp/kernel/sys/ppsclock.h create mode 100644 contrib/ntp/kernel/sys/timex.h create mode 100644 contrib/ntp/kernel/sys/tpro.h create mode 100644 contrib/ntp/kernel/tty_chu.c create mode 100644 contrib/ntp/kernel/tty_chu_STREAMS.c create mode 100644 contrib/ntp/kernel/tty_clk.c create mode 100644 contrib/ntp/kernel/tty_clk_STREAMS.c create mode 100644 contrib/ntp/libntp/Makefile.am create mode 100644 contrib/ntp/libntp/Makefile.in create mode 100644 contrib/ntp/libntp/README create mode 100644 contrib/ntp/libntp/a_md5encrypt.c create mode 100644 contrib/ntp/libntp/adjtime.c create mode 100644 contrib/ntp/libntp/adjtimex.c create mode 100644 contrib/ntp/libntp/atoint.c create mode 100644 contrib/ntp/libntp/atolfp.c create mode 100644 contrib/ntp/libntp/atouint.c create mode 100644 contrib/ntp/libntp/authencrypt.c create mode 100644 contrib/ntp/libntp/authkeys.c create mode 100644 contrib/ntp/libntp/authparity.c create mode 100644 contrib/ntp/libntp/authreadkeys.c create mode 100644 contrib/ntp/libntp/authusekey.c create mode 100644 contrib/ntp/libntp/binio.c create mode 100644 contrib/ntp/libntp/buftvtots.c create mode 100644 contrib/ntp/libntp/caljulian.c create mode 100644 contrib/ntp/libntp/calleapwhen.c create mode 100644 contrib/ntp/libntp/caltontp.c create mode 100644 contrib/ntp/libntp/calyearstart.c create mode 100644 contrib/ntp/libntp/clocktime.c create mode 100644 contrib/ntp/libntp/clocktypes.c create mode 100644 contrib/ntp/libntp/decodenetnum.c create mode 100644 contrib/ntp/libntp/dofptoa.c create mode 100644 contrib/ntp/libntp/dolfptoa.c create mode 100644 contrib/ntp/libntp/emalloc.c create mode 100644 contrib/ntp/libntp/findconfig.c create mode 100644 contrib/ntp/libntp/fptoa.c create mode 100644 contrib/ntp/libntp/fptoms.c create mode 100644 contrib/ntp/libntp/getopt.c create mode 100644 contrib/ntp/libntp/gpstolfp.c create mode 100644 contrib/ntp/libntp/hextoint.c create mode 100644 contrib/ntp/libntp/hextolfp.c create mode 100644 contrib/ntp/libntp/humandate.c create mode 100644 contrib/ntp/libntp/ieee754io.c create mode 100644 contrib/ntp/libntp/inttoa.c create mode 100644 contrib/ntp/libntp/iosignal.c create mode 100644 contrib/ntp/libntp/lib_strbuf.c create mode 100644 contrib/ntp/libntp/lib_strbuf.h create mode 100644 contrib/ntp/libntp/log.c create mode 100644 contrib/ntp/libntp/log.h create mode 100644 contrib/ntp/libntp/machines.c create mode 100644 contrib/ntp/libntp/md5c.c create mode 100644 contrib/ntp/libntp/memmove.c create mode 100644 contrib/ntp/libntp/mexit.c create mode 100644 contrib/ntp/libntp/mfp_mul.c create mode 100644 contrib/ntp/libntp/mfptoa.c create mode 100644 contrib/ntp/libntp/mfptoms.c create mode 100644 contrib/ntp/libntp/mktime.c create mode 100644 contrib/ntp/libntp/modetoa.c create mode 100644 contrib/ntp/libntp/mstolfp.c create mode 100644 contrib/ntp/libntp/msutotsf.c create mode 100644 contrib/ntp/libntp/msyslog.c create mode 100644 contrib/ntp/libntp/netof.c create mode 100644 contrib/ntp/libntp/numtoa.c create mode 100644 contrib/ntp/libntp/numtohost.c create mode 100644 contrib/ntp/libntp/octtoint.c create mode 100644 contrib/ntp/libntp/prettydate.c create mode 100644 contrib/ntp/libntp/ranny.c create mode 100644 contrib/ntp/libntp/recvbuff.c create mode 100644 contrib/ntp/libntp/refnumtoa.c create mode 100644 contrib/ntp/libntp/statestr.c create mode 100644 contrib/ntp/libntp/strerror.c create mode 100644 contrib/ntp/libntp/syssignal.c create mode 100644 contrib/ntp/libntp/systime.c create mode 100644 contrib/ntp/libntp/tsftomsu.c create mode 100644 contrib/ntp/libntp/tstotv.c create mode 100644 contrib/ntp/libntp/tvtoa.c create mode 100644 contrib/ntp/libntp/tvtots.c create mode 100644 contrib/ntp/libntp/uglydate.c create mode 100644 contrib/ntp/libntp/uinttoa.c create mode 100644 contrib/ntp/libntp/utvtoa.c create mode 100644 contrib/ntp/libntp/ymd2yd.c create mode 100644 contrib/ntp/libparse/Makefile.am create mode 100644 contrib/ntp/libparse/Makefile.in create mode 100644 contrib/ntp/libparse/README create mode 100644 contrib/ntp/libparse/clk_computime.c create mode 100644 contrib/ntp/libparse/clk_dcf7000.c create mode 100644 contrib/ntp/libparse/clk_hopf6021.c create mode 100644 contrib/ntp/libparse/clk_meinberg.c create mode 100644 contrib/ntp/libparse/clk_rawdcf.c create mode 100644 contrib/ntp/libparse/clk_rcc8000.c create mode 100644 contrib/ntp/libparse/clk_schmid.c create mode 100644 contrib/ntp/libparse/clk_trimtaip.c create mode 100644 contrib/ntp/libparse/clk_trimtsip.c create mode 100644 contrib/ntp/libparse/clk_varitext.c create mode 100644 contrib/ntp/libparse/clk_wharton.c create mode 100644 contrib/ntp/libparse/data_mbg.c create mode 100644 contrib/ntp/libparse/info_trimble.c create mode 100644 contrib/ntp/libparse/kclk_computime.c create mode 100644 contrib/ntp/libparse/kclk_dcf7000.c create mode 100644 contrib/ntp/libparse/kclk_hopf6021.c create mode 100644 contrib/ntp/libparse/kclk_meinberg.c create mode 100644 contrib/ntp/libparse/kclk_rawdcf.c create mode 100644 contrib/ntp/libparse/kclk_rcc8000.c create mode 100644 contrib/ntp/libparse/kclk_schmid.c create mode 100644 contrib/ntp/libparse/kclk_trimtaip.c create mode 100644 contrib/ntp/libparse/kclk_trimtsip.c create mode 100644 contrib/ntp/libparse/kclk_varitext.c create mode 100644 contrib/ntp/libparse/kclk_wharton.c create mode 100644 contrib/ntp/libparse/kparse.c create mode 100644 contrib/ntp/libparse/kparse_conf.c create mode 100644 contrib/ntp/libparse/mkinfo_rcmd.sed create mode 100644 contrib/ntp/libparse/mkinfo_scmd.sed create mode 100644 contrib/ntp/libparse/parse.c create mode 100644 contrib/ntp/libparse/parse_conf.c create mode 100644 contrib/ntp/libparse/parsesolaris.c create mode 100644 contrib/ntp/libparse/parsestreams.c create mode 100644 contrib/ntp/libparse/trim_info.c create mode 100644 contrib/ntp/librsaref/Makefile.am create mode 100644 contrib/ntp/librsaref/Makefile.in create mode 100755 contrib/ntp/missing create mode 100755 contrib/ntp/mkinstalldirs create mode 100644 contrib/ntp/ntpd/Makefile.am create mode 100644 contrib/ntp/ntpd/Makefile.in create mode 100644 contrib/ntp/ntpd/check_y2k.c create mode 100644 contrib/ntp/ntpd/jupiter.h create mode 100644 contrib/ntp/ntpd/map_vme.c create mode 100644 contrib/ntp/ntpd/ntp_config.c create mode 100644 contrib/ntp/ntpd/ntp_control.c create mode 100644 contrib/ntp/ntpd/ntp_filegen.c create mode 100644 contrib/ntp/ntpd/ntp_intres.c create mode 100644 contrib/ntp/ntpd/ntp_io.c create mode 100644 contrib/ntp/ntpd/ntp_loopfilter.c create mode 100644 contrib/ntp/ntpd/ntp_monitor.c create mode 100644 contrib/ntp/ntpd/ntp_peer.c create mode 100644 contrib/ntp/ntpd/ntp_proto.c create mode 100644 contrib/ntp/ntpd/ntp_refclock.c create mode 100644 contrib/ntp/ntpd/ntp_request.c create mode 100644 contrib/ntp/ntpd/ntp_restrict.c create mode 100644 contrib/ntp/ntpd/ntp_timer.c create mode 100644 contrib/ntp/ntpd/ntp_util.c create mode 100644 contrib/ntp/ntpd/ntpd.c create mode 100644 contrib/ntp/ntpd/refclock_acts.c create mode 100644 contrib/ntp/ntpd/refclock_arbiter.c create mode 100644 contrib/ntp/ntpd/refclock_arc.c create mode 100644 contrib/ntp/ntpd/refclock_as2201.c create mode 100644 contrib/ntp/ntpd/refclock_atom.c create mode 100644 contrib/ntp/ntpd/refclock_bancomm.c create mode 100644 contrib/ntp/ntpd/refclock_chronolog.c create mode 100644 contrib/ntp/ntpd/refclock_chu.c create mode 100644 contrib/ntp/ntpd/refclock_conf.c create mode 100644 contrib/ntp/ntpd/refclock_datum.c create mode 100644 contrib/ntp/ntpd/refclock_dumbclock.c create mode 100644 contrib/ntp/ntpd/refclock_gpsvme.c create mode 100644 contrib/ntp/ntpd/refclock_heath.c create mode 100644 contrib/ntp/ntpd/refclock_hpgps.c create mode 100644 contrib/ntp/ntpd/refclock_irig.c create mode 100644 contrib/ntp/ntpd/refclock_jupiter.c create mode 100644 contrib/ntp/ntpd/refclock_leitch.c create mode 100644 contrib/ntp/ntpd/refclock_local.c create mode 100644 contrib/ntp/ntpd/refclock_msfees.c create mode 100644 contrib/ntp/ntpd/refclock_mx4200.c create mode 100644 contrib/ntp/ntpd/refclock_nmea.c create mode 100644 contrib/ntp/ntpd/refclock_oncore.c create mode 100644 contrib/ntp/ntpd/refclock_palisade.c create mode 100644 contrib/ntp/ntpd/refclock_palisade.h create mode 100644 contrib/ntp/ntpd/refclock_parse.c create mode 100644 contrib/ntp/ntpd/refclock_pst.c create mode 100644 contrib/ntp/ntpd/refclock_ptbacts.c create mode 100644 contrib/ntp/ntpd/refclock_shm.c create mode 100644 contrib/ntp/ntpd/refclock_tpro.c create mode 100644 contrib/ntp/ntpd/refclock_trak.c create mode 100644 contrib/ntp/ntpd/refclock_true.c create mode 100644 contrib/ntp/ntpd/refclock_ulink.c create mode 100644 contrib/ntp/ntpd/refclock_usno.c create mode 100644 contrib/ntp/ntpd/refclock_wwvb.c create mode 100644 contrib/ntp/ntpdate/Makefile.am create mode 100644 contrib/ntp/ntpdate/Makefile.in create mode 100644 contrib/ntp/ntpdate/README create mode 100644 contrib/ntp/ntpdate/ntpdate.c create mode 100644 contrib/ntp/ntpdate/ntpdate.h create mode 100644 contrib/ntp/ntpdate/ntptime_config.c create mode 100644 contrib/ntp/ntpdate/ntptimeset.c create mode 100644 contrib/ntp/ntpdc/Makefile.am create mode 100644 contrib/ntp/ntpdc/Makefile.in create mode 100644 contrib/ntp/ntpdc/README create mode 100644 contrib/ntp/ntpdc/ntpdc.c create mode 100644 contrib/ntp/ntpdc/ntpdc.h create mode 100644 contrib/ntp/ntpdc/ntpdc_ops.c create mode 100644 contrib/ntp/ntpq/Makefile.am create mode 100644 contrib/ntp/ntpq/Makefile.in create mode 100644 contrib/ntp/ntpq/README create mode 100644 contrib/ntp/ntpq/ntpq.c create mode 100644 contrib/ntp/ntpq/ntpq.h create mode 100644 contrib/ntp/ntpq/ntpq_ops.c create mode 100644 contrib/ntp/ntptrace/Makefile.am create mode 100644 contrib/ntp/ntptrace/Makefile.in create mode 100644 contrib/ntp/ntptrace/README create mode 100644 contrib/ntp/ntptrace/ntptrace.c create mode 100644 contrib/ntp/ntptrace/ntptrace.h create mode 100644 contrib/ntp/parseutil/Makefile.am create mode 100644 contrib/ntp/parseutil/Makefile.in create mode 100644 contrib/ntp/parseutil/README create mode 100644 contrib/ntp/parseutil/dcfd.c create mode 100644 contrib/ntp/parseutil/testdcf.c create mode 100755 contrib/ntp/readme.y2kfixes create mode 100644 contrib/ntp/results.y2kfixes create mode 100644 contrib/ntp/scripts/Makefile.am create mode 100644 contrib/ntp/scripts/Makefile.in create mode 100644 contrib/ntp/scripts/README create mode 100644 contrib/ntp/scripts/calc_tickadj create mode 100755 contrib/ntp/scripts/checktime create mode 100644 contrib/ntp/scripts/fixautomakedepsmagic create mode 100755 contrib/ntp/scripts/hpadjtime.sh create mode 100644 contrib/ntp/scripts/mkver.in create mode 100644 contrib/ntp/scripts/monitoring/README create mode 100644 contrib/ntp/scripts/monitoring/loopwatch.config.SAMPLE create mode 100644 contrib/ntp/scripts/monitoring/lr.pl create mode 100644 contrib/ntp/scripts/monitoring/ntp.pl create mode 100644 contrib/ntp/scripts/monitoring/ntploopstat create mode 100644 contrib/ntp/scripts/monitoring/ntploopwatch create mode 100644 contrib/ntp/scripts/monitoring/ntptrap create mode 100644 contrib/ntp/scripts/monitoring/timelocal.pl create mode 100755 contrib/ntp/scripts/ntp-groper create mode 100755 contrib/ntp/scripts/ntp-restart create mode 100644 contrib/ntp/scripts/ntpver.in create mode 100755 contrib/ntp/scripts/plot_summary.pl create mode 100644 contrib/ntp/scripts/rc1/postinstall create mode 100644 contrib/ntp/scripts/rc1/preinstall create mode 100644 contrib/ntp/scripts/rc1/preremove create mode 100644 contrib/ntp/scripts/rc1/prototype create mode 100644 contrib/ntp/scripts/rc1/xntp create mode 100644 contrib/ntp/scripts/rc2/local.ntpd create mode 100644 contrib/ntp/scripts/stats.ulrich.patches create mode 100644 contrib/ntp/scripts/stats/README create mode 100644 contrib/ntp/scripts/stats/README.stats create mode 100644 contrib/ntp/scripts/stats/README.timecodes create mode 100755 contrib/ntp/scripts/stats/clock.awk create mode 100755 contrib/ntp/scripts/stats/dupe.awk create mode 100755 contrib/ntp/scripts/stats/ensemble.S create mode 100755 contrib/ntp/scripts/stats/ensemble.awk create mode 100755 contrib/ntp/scripts/stats/etf.S create mode 100755 contrib/ntp/scripts/stats/etf.awk create mode 100755 contrib/ntp/scripts/stats/itf.S create mode 100755 contrib/ntp/scripts/stats/itf.awk create mode 100755 contrib/ntp/scripts/stats/loop.S create mode 100755 contrib/ntp/scripts/stats/loop.awk create mode 100755 contrib/ntp/scripts/stats/loop_summary create mode 100755 contrib/ntp/scripts/stats/peer.awk create mode 100755 contrib/ntp/scripts/stats/psummary.awk create mode 100755 contrib/ntp/scripts/stats/summary.sh create mode 100755 contrib/ntp/scripts/stats/tdata.S create mode 100755 contrib/ntp/scripts/stats/tdata.awk create mode 100644 contrib/ntp/scripts/summary.pl create mode 100644 contrib/ntp/scripts/support/README create mode 100644 contrib/ntp/scripts/support/bin/monl create mode 100644 contrib/ntp/scripts/support/bin/mvstats create mode 100644 contrib/ntp/scripts/support/conf/hp300.hp300 create mode 100644 contrib/ntp/scripts/support/conf/hp700.hp700 create mode 100644 contrib/ntp/scripts/support/conf/hp700.hp700.faui47 create mode 100644 contrib/ntp/scripts/support/conf/hp800.hp800 create mode 100644 contrib/ntp/scripts/support/conf/ntp.conf create mode 100644 contrib/ntp/scripts/support/conf/sun3.sun3 create mode 100644 contrib/ntp/scripts/support/conf/sun4.sun4.faui01 create mode 100644 contrib/ntp/scripts/support/conf/sun4.sun4.faui10 create mode 100644 contrib/ntp/scripts/support/conf/sun4.sun4.faui45 create mode 100644 contrib/ntp/scripts/support/conf/sun4.sun4c create mode 100644 contrib/ntp/scripts/support/conf/sun4.sun4c.Lucifer create mode 100644 contrib/ntp/scripts/support/conf/sun4.sun4m create mode 100644 contrib/ntp/scripts/support/conf/sun4.sun4m.faui42 create mode 100644 contrib/ntp/scripts/support/conf/sun4.sun4m.faui45m create mode 100644 contrib/ntp/scripts/support/conf/tickconf create mode 100644 contrib/ntp/scripts/support/etc/cron create mode 100644 contrib/ntp/scripts/support/etc/crontab create mode 100644 contrib/ntp/scripts/support/etc/install create mode 100644 contrib/ntp/scripts/support/etc/rc create mode 100644 contrib/ntp/scripts/support/etc/setup create mode 100644 contrib/ntp/stamp-h.in create mode 100644 contrib/ntp/util/Makefile.am create mode 100644 contrib/ntp/util/Makefile.in create mode 100644 contrib/ntp/util/README create mode 100644 contrib/ntp/util/ansi2knr.1 create mode 100644 contrib/ntp/util/ansi2knr.c create mode 100644 contrib/ntp/util/byteorder.c create mode 100644 contrib/ntp/util/hist.c create mode 100644 contrib/ntp/util/jitter.c create mode 100644 contrib/ntp/util/kern.c create mode 100644 contrib/ntp/util/longsize.c create mode 100644 contrib/ntp/util/ntptime.c create mode 100644 contrib/ntp/util/precision.c create mode 100644 contrib/ntp/util/sht.c create mode 100644 contrib/ntp/util/testrs6000.c create mode 100644 contrib/ntp/util/tickadj.c create mode 100644 contrib/ntp/util/timetrim.c diff --git a/contrib/ntp/COPYRIGHT b/contrib/ntp/COPYRIGHT new file mode 100644 index 000000000000..6507db7bb374 --- /dev/null +++ b/contrib/ntp/COPYRIGHT @@ -0,0 +1,151 @@ +This file is automatically generated from html/copyright.htm + + Copyright Notice + + [INLINE] "Clone me," says Dolly sheepishly + _________________________________________________________________ + + The following copyright notice applies to all files collectively + called the Network Time Protocol Version 4 Distribution. Unless + specifically declared otherwise in an individual file, this notice + applies as if the text was explicitly included in the file. +/*********************************************************************** + * * + * Copyright (c) David L. Mills 1992-1999 * + * * + * 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. * + **********************************************************************/ + + The following individuals contributed in part to the Network Time + Protocol Distribution Version 4 and are acknowledged as authors of + this work. + 1. [1]Mark Andrews Leitch atomic clock + controller + 2. [2]Viraj Bais and [3]Clayton Kirkwood + port to WindowsNT 3.5 + 3. [4]Karl Berry syslog to file option + 4. [5]Piete Brooks MSF clock driver, + Trimble PARSE support + 5. [6]Steve Clift OMEGA clock driver + 6. [7]Casey Crellin vxWorks (Tornado) port and help + with target configuration + 7. [8]Torsten Duwe Linux port + 8. [9]John A. Dundas III Apple A/UX port + 9. [10]Dennis Ferguson foundation code for + NTP Version 2 as specified in RFC-1119 + 10. [11]Glenn Hollinger GOES clock driver + 11. [12]Mike Iglesias DEC Alpha port + 12. [13]Jim Jagielski A/UX port + 13. [14]Jeff Johnson massive prototyping + overhaul + 14. [15]William L. Jones RS/6000 AIX + modifications, HPUX modifications + 15. [16]Dave Katz RS/6000 AIX port + 16. [17]Craig Leres 4.4BSD port, ppsclock, + Maganavox GPS clock driver + 17. [18]George Lindholm SunOS 5.1 port + 18. [19]Louis A. Mamakos MD5-based authentication + 19. [20]Derek Mulcahy and [21]Damon + Hart-Davis ARCRON MSF clock driver + 20. [22]Lars H. Mathiesen adaptation of foundation + code for Version 3 as specified in RFC-1305 + 21. [23]David L. Mills Version 4 foundation, + Spectractom WWVB, Austron GPS, Arbiter GPS, CHU, Heath, ATOM, + ACTS, KSI/Odetics, IRIG clock drivers; PPS support; precision + kernel; NTPv4 changes + 22. [24]Wolfgang Moeller VMS port + 23. [25]Jeffrey Mogul ntptrace utility + 24. [26]Tom Moore i386 svr4 port + 25. [27]Rainer Pruy + monitoring/trap scripts, statistics file handling + 26. [28]Dirce Richards Digital UNIX V4.0 port + 27. [29]Nick Sayer SunOS streams modules + 28. [30]Frank Kardel [31] + PARSE driver (14 reference clocks), STREAMS modules for + PARSE, support scripts, syslog cleanup + 29. [32]Ray Schnitzler Unixware1 port + 30. [33]Michael Shields USNO clock driver + 31. [34]Jeff Steinman Datum PTS clock + driver + 32. [35]Harlan Stenn GNU automake/autoconfigure + makeover + 33. [36]Kenneth Stone HP-UX port + 34. [37]Ajit Thyagarajan IP multicast support + 35. [38]Tomoaki TSURUOKA TRAK clock + driver + 36. [39]Paul A Vixie TrueTime GPS driver, generic + TrueTime clock driver + 37. [40]Ulrich Windl corrected and + validated HTML documents according to the HTML DTD + 38. [41]Greg Brackley Major rework of + WINNT port. Clean up recvbuf and iosignal code into separate + modules. + 39. [42]Sven Dietrich Palisade reference + clock driver, NT adj. residuals, integrated Greg's Winnt port. + 40. [43]Wilfredo Sánchez added support for + NetInfo + + _________________________________________________________________ + + [44][LINK] + + + [45]David L. Mills + +References + + 1. mailto: marka@syd.dms.csiro.au + 2. mailto: vbais@mailman1.intel.co + 3. mailto: kirkwood@striderfm.intel.com + 4. mailto: karl@owl.HQ.ileaf.com + 5. mailto: Piete.Brooks@cl.cam.ac.uk + 6. mailto: clift@ml.csiro.au + 7. mailto:casey@csc.co.za + 8. mailto: duwe@immd4.informatik.uni-erlangen.de + 9. mailto: dundas@salt.jpl.nasa.gov + 10. mailto: dennis@mrbill.canet.ca + 11. mailto: glenn@herald.usask.ca + 12. mailto: iglesias@uci.edu + 13. mailto: jagubox.gsfc.nasa.gov + 14. mailto: jbj@chatham.usdesign.com + 15. mailto: jones@hermes.chpc.utexas.edu + 16. mailto: dkatz@cisco.com + 17. mailto: leres@ee.lbl.gov + 18. mailto: lindholm@ucs.ubc.ca + 19. mailto: louie@ni.umd.edu + 20. mailto: derek@toybox.demon.co.uk + 21. mailto: d@hd.org + 22. mailto: thorinn@diku.dk + 23. mailto: mills@udel.edu + 24. mailto: moeller@gwdgv1.dnet.gwdg.de + 25. mailto: mogul@pa.dec.com + 26. mailto: tmoore@fievel.daytonoh.ncr.com + 27. mailto: Rainer.Pruy@informatik.uni-erlangen.de + 28. mailto: dirce@zk3.dec.com + 29. mailto: mrapple@quack.kfu.com + 30. http://www4.informatik.uni-erlangen.de/~kardel + 31. mailto: Frank.Kardel@informatik.uni-erlangen.de + 32. mailto: schnitz@unipress.com + 33. mailto: shields@tembel.org + 34. mailto: pebbles.jpl.nasa.gov + 35. mailto: harlan@pfcs.com + 36. mailto: ken@sdd.hp.com + 37. mailto: ajit@ee.udel.edu + 38. mailto: tsuruoka@nc.fukuoka-u.ac.jp + 39. mailto: vixie@vix.com + 40. mailto: Ulrich.Windl@rz.uni-regensburg.de + 41. mailto: greg.brackley@bigfoot.com + 42. mailto: Sven_Dietrich@trimble.COM + 43. mailto: wsanchez@apple.com + 44. file://localhost/backroom/ntp4/html/index.htm + 45. mailto:mills@udel.edu diff --git a/contrib/ntp/ChangeLog b/contrib/ntp/ChangeLog new file mode 100644 index 000000000000..a7abc1458223 --- /dev/null +++ b/contrib/ntp/ChangeLog @@ -0,0 +1,2737 @@ +1999-11-11 Harlan Stenn + + * configure.in: 4.0.98f + + * configure.in: DECL_PLOCK_0 and DECL_STIME_0 are for dec-osf5*, too + + * ntpd/ntpd.c: DEC OSF cleanup (editorial comments by HMS) + From: Tom Smith + + * ntpd/ntp_refclock.c: MAXUNIT bugfix + From: Marc.Brett@westgeo.com + + * ntpd/ntp_refclock.c: + * ntpd/ntpd.c: + * ntpd/refclock_arc.c: + * ntpd/refclock_as2201.c: + * ntpd/refclock_atom.c: + * ntpdc/ntpdc.c: + * ntpq/ntpq.c: + Code cleanup. + From: Marc.Brett@westgeo.com + + * include/ntp_stdlib.h: + * libntp/systime.c: + * ntpd/ntp_proto.c: + Replaced the 'sco5_oldclock' variable with 'systime_10ms_ticks'. + Cleared libntp/systime.c and include/ntp_stdlib.h of references + to SCO5_CLOCK and RELIANTUNIX_CLOCK (moved to ntpd/ntp_proto.c). + From: Kamal A Mostafa + + * configure.in: alpha-dec-osf4* -> alpha*-dec-osf4*|alpha*-dec-osf5* + From: Tom Smith + + * configure.in: Look for . If TIOCDCDTIMESTAMP is + there, we have TTYCLK. + * acconfig.h: Lose old AIOCTIMESTAMP stuff + Reported by: Kamal A Mostafa + +1999-11-10 Harlan Stenn + + * ntpd/ntpd.c (set_process_priority): Clean up nice() and setpriority() + +1999-11-09 Harlan Stenn + + * Makefile.am (EXTRA_DIST): Added README.cvs + Reported by: Kamal A Mostafa + +1999-11-08 Harlan Stenn + + * configure.in: 4.0.98e + +1999-11-07 Harlan Stenn + + * configure.in: Lose AIOCTIMESTAMP tests + + * ntpd/ntpd.c: lose select() EINTR debug warning + * ntpd/ntp_refclock.c: AIOCTIMESTAMP -> TIOCDCDTIMESTAMP. Watch + CLK_SETSTR. + * ntpd/refclock_atom.c: fdpps is only there for PPS or PPSAPI. + AIOCTIMESTAMP is gone now. + From: Kamal A Mostafa + + * configure.in (HAVE_MLOCKALL): Deal with dec-osf5 realities + * ntpd/refclock_ulink.c (ulink_poll): Fix cast. + * libntp/machines.c (ntp_set_tod): Use a long* for the argument to + stime(). + Reported by: Tom Smith + + * ntpd/ntpd.c (set_process_priority): Use whatever we have until + something works. + + * ntpd/ntp_loopfilter.c: Keep clock_frequency changes in a temp + variable so we can record it to loopstats (near as HMS can tell). + From: Dave Mills + +1999-11-06 Harlan Stenn + + * acconfig.h: RELIANTUNIX_CLOCK + * configure.in (ac_cv_var_tickadj): RELIANTUNIX_CLOCK + * libntp/systime.c (adj_systime): Reliant patches + From: Andrej Borsenkow + +1999-11-05 Harlan Stenn + + * ntpd/refclock_parse.c (parse_start): ASYNC_PPS_CD_NEG cleanup + * configure.in (ac_cv_make_ntptime): OK on Linux + From: + + * configure.in: NetBSD has PPSAPI now + F_SETOWN is needed for NetBSD + From: Jonathan Stone + +1999-11-02 Harlan Stenn + + * configure.in: 4.0.98d + + * ntpd/refclock_parse.c: Cleanup/fixes + From: John Hay + + * ntpd/refclock_parse.c: Lose #include "ntp_select.h" + * ntpd/ntpd.c: Lose #include "ntp_select.h" + * ntpd/ntp_io.c: Lose #include "ntp_select.h" + * ntpd/ntp_intres.c: Lose #include "ntp_select.h" + * libntp/iosignal.c: Lose #include "ntp_select.h" + * include/ntpd.h: #include "ntp_select.h" for declaration of activefds + Reported by: Christian Krackowizer + +1999-11-01 Harlan Stenn + + * configure.in: 4.0.98c + + * libntp/syssignal.c: Don't warn about SA_RESTART + * libntp/recvbuff.c: Fix free buffer count + From: Jeffrey C Honig + + * html/pps.htm: + * html/howto.htm: + * html/confopt.htm: + * html/clockopt.htm: + * html/uthopt.htm: + Updates. + From: Dave Mills + + * ntpd/refclock_wwvb.c: burst fixes + * ntpd/refclock_ulink.c: burst fixes + * ntpd/refclock_tpro.c: burst and NSTAGE fixes + * ntpd/refclock_pst.c: burst fixes + * ntpd/refclock_irig.c: SAMPLE -> SAMPLES + * ntpd/refclock_heath.c: burst fixes + * ntpd/refclock_dumbclock.c: burst fixes + * ntpd/refclock_chronolog.c: burst fixes + * ntpd/refclock_bancomm.c: burst fixes + * ntpd/refclock_atom.c: burst fixes + * ntpd/refclock_as2201.c: burst fixes + * ntpd/ntp_refclock.c: PPSAPI, code, and comment cleanup/fixes + * ntpd/ntp_proto.c: Broadcast/restrict cleanup + * ntpd/ntp_loopfilter.c: Cleanup and fixes + * libntp/gpstolfp.c: Lose the UL qualifiers - old compilers hate them + From: Dave Mills + +1999-10-31 Harlan Stenn + + * configure.in: TIOCSPPS cleanup + +1999-10-20 Harlan Stenn + + * configure.in: 4.0.98b + + * ntpd/refclock_atom.c: AIOCTIMESTAMP patch + * ntpd/ntpd.c: SCO clock patch + * ntpd/ntp_request.c: noselect patch + * ntpd/ntp_refclock.c: AIOCTIMESTAMP patch + * ntpd/ntp_proto.c: noselect patch + * ntpd/ntp_intres.c: noselect patch + * ntpd/ntp_config.c: noselect patch + * include/ntp_request.h: noselect patch + * include/ntp.h: noselect patch + From: Kamal A Mostafa + + * configure.in: + * acconfig.h: TTYCLK_AIOCTIMESTAMP + Stuff for Kamal + + * ntpd/refclock_atom.c (atom_pps): make "result" initialization + uglier, but more bulletproof. + + * configure.in (sys/timepps.h): Fixed. + From: John Hay + +1999-10-19 Harlan Stenn + + * ntpd/refclock_oncore.c: Rename instance.state to instance.o_state + + * refclock_oncore.c: + * refclock_mx4200.c: + * refclock_chu.c: + * refclock_atom.c: + * ntp_refclock.c: + * ntp_peer.c: + * ntp_loopfilter.c: + * include/ntp_refclock.h: + Various cleanup and fixes + From: Dave Mills + +1999-10-17 Harlan Stenn + + * ntpd/ntp_config.c (CONFIG_FILE): NT changes + From: Sven Dietrich + +1999-10-16 Harlan Stenn + + * configure.in: sys/timepps.h verification changes + + * ntpd/refclock_atom.c (atom_poll): PPS cleanup + From: Dave Mills + (atom_pps): Portability patch + From: John Hay + + + * libntp/msyslog.c: + * libntp/gpstolfp.c: + Lint cleanup + From: Jonathan Stone + + * parseutil/dcfd.c: abs() -> l_abs(), time.h (AIX 4.3.2 patches) + From: Dana Kaempen + + * ntpd/refclock_oncore.c: + * ntpd/refclock_atom.c: + * ntpd/ntp_refclock.c: + PPS cleanup + From: John.Hay@mikom.csir.co.za + + * util/ntptime.c: + * ntpdate/ntptimeset.c: + * ntpdate/ntpdate.c: + * ntpd/refclock_trak.c: + * ntpd/refclock_oncore.c: + * ntpd/refclock_mx4200.c: + * ntpd/refclock_msfees.c: + * ntpd/refclock_atom.c: + * ntpd/ntp_control.c: + * ntpd/ntp_config.c: + * configure.in: + * configure: + PPS, Solaris 7, cleanup patches + From: Marc.Brett@westgeo.com + + * ports/winnt/ntptrace/ntptrace.dsp: + * ports/winnt/ntpq/ntpq.dsp: + * ports/winnt/ntpdc/ntpdc.dsp: + * ports/winnt/ntpdate/ntpdate.dsp: + * ports/winnt/ntpd/refclock_trimbledc.c: + * ports/winnt/ntpd/ntpd.dsp: + * ports/winnt/ntpd/ntp_iocompletionport.c: + * ports/winnt/ntpd/nt_clockstuff.c: + * ports/winnt/libntp/util_clockstuff.c: + * ports/winnt/libntp/libntp.dsp: + * ports/winnt/libntp/SetSystemTime.c: + * ports/winnt/instsrv/instsrv.c: + * ports/winnt/include/sys/ioctl.h: + * ports/winnt/include/termios.h: + * ports/winnt/include/config.h: + * ports/winnt/include/clockstuff.h: + * ports/winnt/ntp.dsw: + * ntpd/refclock_shm.c: + * ntpd/refclock_palisade.c: + * ntpd/ntpd.c: + * ntpd/ntp_timer.c: + * ntpd/ntp_refclock.c: + * libntp/systime.c: + * libntp/machines.c: + NT patches + From: Sven Dietrich + +1999-10-15 Harlan Stenn + + * ntpd/refclock_wwvb.c: + * ntpd/refclock_usno.c: + * ntpd/refclock_ulink.c: + * ntpd/refclock_tpro.c: + * ntpd/refclock_pst.c: + * ntpd/refclock_parse.c: + * ntpd/refclock_palisade.c: + * ntpd/refclock_oncore.c: + * ntpd/refclock_mx4200.c: + * ntpd/refclock_msfees.c: + * ntpd/refclock_jupiter.c: + * ntpd/refclock_irig.c: + * ntpd/refclock_heath.c: + * ntpd/refclock_chu.c: + * ntpd/refclock_atom.c: + * ntpd/refclock_as2201.c: + * ntpd/refclock_arc.c: + * ntpd/refclock_arbiter.c: + * ntpd/refclock_acts.c: + * ntpd/ntp_refclock.c: + * include/ntp_refclock.h: + Bunches of fixes. + From: Dave Mills + +1999-10-10 Harlan Stenn + + * html/driver16.htm: New version + * ntpd/refclock_bancomm.c: New version + From: "Cliff, Gary" + "Ramasivan, Ganesh" + + * ntpd/refclock_ulink.c (ulink_receive): Cleanup + (ulink_poll): Cleanup + * ntpd/refclock_atom.c (atom_pps): SunOS timespec/timeval cleanup + From: Marc.Brett@westgeo.com + + * INSTALL: Point NT folks at ports/winnt + Reported by: Stephen Gildea + + * include/ntp_stdlib.h: Noise abatement + * include/ntpd.h: Noise abatement + Reported by: "W. David Higgins" + + * configure.in: DECL_STDIO_0 with gcc under solaris. + + * include/l_stdlib.h: DECL_TOUPPER_0 + DECL_STRERROR_0 + + * configure.in: Fix a bunch of implicit declarations for SunOS + + * html/release.htm: cleanup - we still provide MD5. + Reported by: Winslowe Lacesso + +1999-10-09 Harlan Stenn + + * ntpd/refclock_oncore.c: + * ntpd/refclock_atom.c: + * ntpd/ntp_refclock.c: + PPS API code updated to the current spec + From: Dave Mills + + * configure.in (ac_cv_make_tickadj): Don't make tickadj starting + with solaris2.5 + Requested by: Dave Mills + +1999-10-04 Harlan Stenn + + * configure.in: We might need -lsocket for the -lnsl check. + +1999-09-19 Harlan Stenn + + * ntpd/refclock_ulink.c: Typos in C++ comment + Reported by: Thomas.Tornblom@Sun.SE + + * configure.in: 4.0.98a + + * ntpd/ntp_config.c (getconfig): Fix typo. + From: "David E. Myers" + From: David Godfrey + From: Geoffrey Sisson + +1999-09-17 Harlan Stenn + + * configure.in: 4.0.98 + + NetInfo support: + + * config.guess + * config.sub + Add Mac OS (versions 10 and up). + + * acconfig.h + * config.h.in + * configure.in + Check for NetInfo API; add HAVE_NETINFO macro and friends. + + * include/ntp.h + * ntpd/ntp_config.c + * ntpdate/ntpdate.c + Add support for reading configuration from NetInfo. + + * ntpd/ntp_config.c + Get rid of unnecessary eol variable in tokenizer. + + * html/notes.htm + * html/ntpd.htm + * html/ntpdate.htm + Document NetInfo functionality. + + * util/tickadj.c + Use HAVE_KVM_OPEN conditional around kvm.h include. + + From: Wilfredo Sanchez + +1999-09-15 Harlan Stenn + + * acconfig.h: + * config.h.in: + * configure.in: + * html/driver34.htm: + * html/refclock.htm: + * include/ntp.h: + * libntp/clocktypes.c: + * ntpd/Makefile.am: + * ntpd/ntp_control.c: + * ntpd/refclock_conf.c: + * ntpd/refclock_ulink.c: + Ultralink driver + From: Dave Strout + +1999-09-14 Harlan Stenn + + * configure.in: ReliantUNIX patches + From: Andrej Borsenkow + + * ntpd/refclock_atom.c: PPS cleanup + * ntpd/ntp_refclock.c (refclock_ioctl): PPS cleanup + From: Dave Mills + + * ntptrace/ntptrace.c (ReceiveBuf): addserver() can return NIL. + Reported by: "Alan J. Wylie" + + * libntp/ieee754io.c: + * ntpd/ntp_proto.c: + * ntpd/ntp_refclock.c: + Lint cleanup. + From: Marc.Brett@westgeo.com + +1999-09-12 Harlan Stenn + + * ntpd/ntp_refclock.c (refclock_ioctl): Declaration cleanup. + + * ntpd/ntp_proto.c (init_proto): msyslog kern_enable at LOG_DEBUG. + + * ntpd/refclock_atom.c: Add missing declaration. + +1999-09-11 Harlan Stenn + + * configure.in (ac_cv_make_ntptime): Just look for struct + ntptimeval, not timespec or nsec (Solaris 2.7 should get ntptime + and it uses msec). + (ac_cv_var_oncore_ok): Reorder so it's a "normal" clock + + * configure.in: Solaris Kernel FLL bug fixed in 106541-07 + +1999-09-02 Harlan Stenn + + * configure.in: 4.0.97f + + * ntptrace/ntptrace.c: + * ntpdate/ntptimeset.c: + * ntpdate/ntptime_config.c: + * ntpdate/ntpdate.c: + * util/ntptime.c: + * parseutil/dcfd.c: + * libparse/parsestreams.c: + * libparse/parse_conf.c: + * libparse/parse.c: + * libparse/clk_varitext.c: + * libparse/clk_trimtsip.c: + * libparse/clk_trimtaip.c: + * libparse/clk_schmid.c: + * libparse/clk_rcc8000.c: + * libparse/clk_rawdcf.c: + * libparse/clk_meinberg.c: + * libparse/clk_hopf6021.c: + * libparse/clk_dcf7000.c: + * libparse/clk_computime.c: + * libntp/msyslog.c: + * libntp/iosignal.c: + * libntp/syssignal.c: + * adjtimed/adjtimed.c: + * ntpd/refclock_shm.c: + * ntpd/refclock_parse.c: + * ntpd/refclock_palisade.c: + * ntpd/refclock_mx4200.c: + * ntpd/refclock_jupiter.c: + * ntpd/refclock_datum.c: + * ntpd/ntpd.c: + * ntpd/ntp_util.c: + * ntpd/ntp_timer.c: + * ntpd/ntp_request.c: + * ntpd/ntp_refclock.c: + * ntpd/ntp_monitor.c: + * ntpd/ntp_loopfilter.c: + * ntpd/ntp_io.c: + * ntpd/ntp_intres.c: + * ntpd/ntp_filegen.c: + * include/l_stdlib.h: + and errno declaration cleanup. + + * ntpd/map_vme.c: cleanup some spacing. + +1999-09-01 Harlan Stenn + + * configure.in: 4.0.97e + + * configure.in (ac_cv_struct_sigaction_has_sa_sigaction): + * acconfig.h: Ditto + * parseutil/dcfd.c (main): Use it. + From: HOSAKA Eiichi + +1999-08-29 Harlan Stenn + + * configure.in: 4.0.97d + + * include/ntp_stdlib.h: Clean up previous NeXT patch. + From: Jack Bryans + + * ntpd/refclock_parse.c: Permit RTS to power a DCF77. + From: Carsten Paeth + + * ntpd/refclock_oncore.c (oncore_start): This makes the Oncore run + on systems without hardpps(). + From: Poul-Henning Kamp + +1999-08-28 Harlan Stenn + + * configure.in: 4.0.97c + + * configure.in (ac_cv_make_ntptime): Typo. + From: Ulrich Windl + +1999-08-26 Harlan Stenn + + * configure.in: 4.0.97b + + * libntp/iosignal.c: + * ntpd/ntp_peer.c: + * ntpd/refclock_nmea.c: + * ntpdate/ntptime_config.c: + * ntpdate/ntptimeset.c: + AIX, Irix, and SunOS lint cleanup + From: Marc.Brett@westgeo.com + +1999-08-24 Harlan Stenn + + * configure.in 4.0.97a + + * configure.in (AC_OUTPUT): added scripts/Makefile + * Makefile.am (SUBDIRS): Added scripts + * scripts/Makefile.am: Added + +1999-08-23 Harlan Stenn + + * ntpd/refclock_nmea.c: Patches for: + Trimble OEM Ace-II receiver. Low cost PCB with single + voltage input, external active antenna and two serial + ports with either NMEA and ITAPs output. Programmable + to be tuned for 'time' accuracy in fixed station config. + From: Nick Hibma + +1999-08-21 Harlan Stenn + + * ntpd/ntp_config.c: Added listen_to_virtual_ips support (-L flag) + * ntpd/ntp_io.c: Ditto + +1999-08-19 Harlan Stenn + + * ntpd/ntp_intres.c (request): Lint cleanup + * ntpd/ntp_control.c (ctl_putclock): Ditto + * libntp/recvbuff.c (getrecvbufs): Ditto + (get_free_recv_buffer): Ditto + * libntp/systime.c (adj_systime): Ditto + +1999-08-18 Harlan Stenn + + * configure.in: 4.0.97 + + * libntp/systime.c: + * ntpd/ntp_loopfilter.c: + * ntpd/ntpd.c: + * ports/winnt/libntp/nt_clockstuff.c: + From: Sven Dietrich + + * README.cvs: Updated. + + * configure.in: + * include/ntp_machine.h: + * libntp/mexit.c: + * ntpd/ntp_config.c: + * ntpd/ntp_peer.c: + * ntpd/ntp_restrict.c: + * ntpd/refclock_arc.c: + * ntpdate/ntpdate.c: + Irix, SunOS, AIX, lint patches + From: Marc.Brett@westgeo.com + + * util/ansi2knr.c: New release (fix for bug reported by Marc Brett) + From: "L. Peter Deutsch" + + * include/ntp_stdlib.h: NeXT portability patch + From: Jack Bryans + + * configure.in: + * dot.emacs: (cleanup) + * ntpdate/Makefile.am: + * ntpdate/ntpdate.h: + * ntpdate/ntptime_config.c: + * ntpdate/ntptimeset.c: + ntptimeset patches. + From: Jeffrey Hutzelman + + * ntpd/refclock_parse.c (local_input): ts.l_ui -> ts.fp.l_ui + +1999-08-11 Harlan Stenn + + * configure.in: 4.0.96p1 + + * ntpd/ntpd.c (sys/resource.h): Include this file only #if + HAVE_SYS_RESOURCE_H. + (set_process_priority): Use TIOCNOTTY only if it is #define'd. + * ntpd/refclock_parse.c (STREAM): STREAM does not imply HAVE_TERMIOS. + (termios.h, termio.h, fcntl.h): Do not include those files here; + they are already included by ntp_refclock.h or ntp_io.h. + * ntpd/refclock_leitch.c (sgtty.h, termios.h, termio.h): Do not + include those files here; they are already included by ntp_refclock.h. + * ntpdate/ntpdate.c (sys/resource.h) : Include that file only #if + HAVE_RESOURCE_H. + From: Philippe De Muyter + + * ntptrace/ntptrace.c (input_handler): Make it a "normal" function + definition. + Reported by: GIANNI_CATANIA@hp-italy-om6.om.hp.com + + * configure.in: pc-cygwin32 -> pc-cygwin* because of a change in + B20. + From: Stephen Gildea + +1999-08-09 Harlan Stenn + + * configure.in: 4.0.96 + + * parseutil/dcfd.c (main): Replace SA_ONSTACK and SV_ONSTACK with + HAVE_SIGACTION and HAVE_SIGVEC, respectively. HP-UX provides both + of the former but only one of the latter... + +1999-08-08 Harlan Stenn + + * configure.in: Better tests for -lnsl and -lsocket + From: Albert Chin-A-Young + + Works for me - handle openlog() and -lgen the same way. + + * Makefile.am (EXTRA_DIST): Add in the y2k notes + + * parseutil/dcfd.c: Renamed drift_comp to accum_drift + + * configure.in: Added MAKE_CHECK_Y2K support; check_y2k needs libparse. + * ntpd/Makefile.am (check_PROGRAMS): Use MAKE_CHECK_Y2K + * ntpd/Makefile.am (check-local): Added. + * parseutil/Makefile.am (check-local): Added. + + * include/ntp.h: Y2KFixes + * libparse/parse.c: Ditto + * ntpd/Makefile.am (check_PROGRAMS): Ditto + * ntpd/refclock_acts.c: Ditto + * ntpd/refclock_arc.c (arc_receive): Ditto + * ntpd/refclock_heath.c: Ditto + * ntpd/refclock_hpgps.c: Ditto + * parseutil/Makefile.am (check-local): Ditto + * parseutil/dcfd.c (check_y2k): Ditto + * NOTES.y2kfixes: Ditto + * readme.y2kfixes: Ditto + * results.y2kfixes: Ditto + * ntpd/check_y2k.c: Ditto + From: y2k@y2k.labs.att.com + +1999-08-07 Harlan Stenn + + * configure.in: Look for sys/ppstime.h. + +1999-07-31 Harlan Stenn + + * ntpd/ntp_io.c (create_sockets): Typo. + From: Doug Wells + +1999-07-29 Harlan Stenn + + * configure.in (ac_cv_struct_ntptimeval): Explicitly look for + struct ntptimeval. + (ac_cv_var_kernel_pll): Require struct ntptimeval. + Linux. Grrr. + Reported by: Ronald Kuetemeier + +1999-07-27 Harlan Stenn + + * configure.in: 4.0.95 + + * ports/winnt: New release + From: Sven Dietrich + +1999-07-26 Harlan Stenn + + * libntp/machines.c (ntp_set_tod): Bugfix + From: Andrej Borsenkow + +1999-07-25 Harlan Stenn + + * configure.in: 4.0.94b + + * acconfig.h: + * configure.in: + * libparse/Makefile.am: + * libparse/parse_conf.c: + * libparse/clk_varitext.c: + * libparse/kclk_varitext.c: + * ntpd/refclock_parse.c: VARITEXT parse clock + * ntpdate/ntpdate.c: bugfix + From: Tony McConnell + +1999-07-24 Harlan Stenn + + * include/ntp_syscall.h (ntp_gettime): Make it static + * configure.in: Added AC_C_INLINE + Reported by: "Charles C. Fu" + +1999-07-23 Harlan Stenn + + * include/ntpd.h: + * libntp/machines.c: + * libntp/systime.c: + * ntpd/ntp_config.c: + * ntpd/ntp_filegen.c: + * ntpd/ntp_io.c: + * ntpd/ntp_proto.c: + * ntpd/ntp_timer.c: + * ntpdate/ntpdate.c: Windows NT port cleanup + From: Sven Dietrich + +1999-07-22 Harlan Stenn + + * libntp/authkeys.c: + * libntp/ieee754io.c: + * libntp/iosignal.c: + * libntp/machines.c: + * libntp/mexit.c: + * libntp/recvbuff.c: + * ntpd/ntp_filegen.c: + * ntpd/ntp_loopfilter.c: + * ntpd/ntp_request.c: + * ntpd/ntp_timer.c: + * ntpd/ntpd.c: Compile/lint cleanup + From: Allen Smith + +1999-07-21 Harlan Stenn + + * configure.in: 4.0.94a + + * configure.in (ac_cv_make_ntptime): Add tv_nsec check. + + * include/Makefile.am (noinst_HEADERS): Forgot ntp_syscall.h + From: John.Hay@mikom.csir.co.za + + * configure.in: 4.0.94 + + * Makefile.am (SUBDIRS): librsaref + (dist-hook): Lose CVS subdirs in the distribution tarball + + * include/Makefile.am (noinst_HEADERS): Added iosignal.h, recvbuff.h + + * Makefile.am (dist-hook): Don't call dos2unix anymore + +1999-07-20 Harlan Stenn + + * acconfig.h: + * util/ntptime.c: FreeBSD nano patches + From: Per Hedeland and + Allen Smith + + * include/ntp.h: + include/ntp_fp.h: + include/ntp_io.h: + include/ntp_machine.h: + include/ntp_refclock.h: + include/ntp_stdlib.h: + include/ntpd.h: + libntp/Makefile.am: + libntp/emalloc.c: + libntp/machines.c: + libntp/mexit.c: + libntp/msyslog.c: + libntp/statestr.c: + libntp/syssignal.c: + libntp/systime.c: + libparse/parse.c: + libparse/parse_conf.c: + ntpd/ntp_control.c: + ntpd/ntp_intres.c: + ntpd/ntp_io.c: + ntpd/ntp_proto.c: + ntpd/ntp_refclock.c: + ntpd/ntp_request.c: + ntpd/ntp_timer.c: + ntpd/ntp_util.c: + ntpd/ntpd.c: + ntpd/refclock_nmea.c: + ntpd/refclock_palisade.c: + ntpd/refclock_palisade.h: + ntpd/refclock_shm.c: + ntpdate/ntpdate.c: + ntptrace/ntptrace.c: Cleanup + * libntp/recvbuff.c: + libntp/iosignal.c: + include/iosignal.h: + include/recvbuff.h: Added + From: Sven_Dietrich@Trimble.COM + + * README: Add README.cvs + + * configure.in (ac_cv_var_struct_ntptime_val_timespec): Typo. + From: John Hay + +1999-07-19 Harlan Stenn + + * Makefile.am (EXTRA_DIST): Lose ntpmak; "build" does a better job. + + * ntpq/Makefile.am (version.o): Use mkver + * ntptrace/Makefile.am (version.o): Ditto + * ntpdate/Makefile.am (version.o): Ditto + * ntpd/Makefile.am (version.o): Ditto + * ntpdc/Makefile.am (version.o): Ditto + + * configure.in (AC_OUTPUT): scripts/mkver + + * scripts/mkver.in: Created. Note RSAREF in the version string + +1999-07-18 Harlan Stenn + + * README.des: Updated. + + * ntpq/Makefile.am (LDADD): Add LIBRSAREF + + * ntpdc/Makefile.am (LDADD): Add LIBRSAREF + + * ntpdate/Makefile.am (LDADD): Add LIBRSAREF + + * ntpd/Makefile.am (LDADD): Add LIBRSAREF + + * configure.in (AC_OUTPUT): Added librsaref/Makefile + Added tests for making/using librsaref.a + Lose old DES stuff; AC_DEFINE(DES) if we find the rsaref stuff. + +1999-07-11 Harlan Stenn + + * ntpd/refclock_trak.c (trak_receive): disambiguate expression. + At least now it is unambiguous. It may even still be correct. + Reported by: Tom Smith + + * ntp_update (UPDATE_OPTIONS): Typo. + +1999-07-07 Harlan Stenn + + * ntp_update: Check out copyright.htm before COPYRIGHT + + * ntpd/ntp_config.c: Support for PPS assert/clear/hardpps + * ntpd/ntp_refclock.c (refclock_ioctl): Ditto + (refclock_gtlin): Ditto + * html/clockopt.htm: Document. + From: John Hay + + * html/monopt.htm: We have four types of files now + * ntpd/refclock_oncore.c: If debug is on, tell when + we are waiting for a valid almanac + From: Poul-Henning Kamp + + * include/ntp_machine.h (HAVE_TERMIOS): STREAMS does not imply + HAVE_TERMIOS !!! + * include/parse.h (timercmp): Macro defined if needed. + * ntpd/ntp_config.c (SIGCHLD): Macro defined as SIGCLD if needed. + (sys/wait.h): File included only if HAVE_SYS_WAIT_H. + * configure.in (sys/wait.h): File added to AC_CHECK_HEADERS list. + From: Philippe De Muyter + +1999-06-23 Harlan Stenn + + * ntpd/refclock_irig.c (irig_debug): NetBSD patches + From: Frederick Bruckman + + * util/ntptime.c (main): ntx.freq bugfix (-f option) + From: Frederick Bruckman + +1999-06-22 Harlan Stenn + + * configure.in: Fix typo with DECL_H_ERRNO test + + * ntpd/ntp_loopfilter.c: Lose syscall decl, it's handled in + l_stdlib.h now. + * ntpd/ntp_request.c: Ditto + * util/ntptime.c: Ditto + +Mon May 31 18:49:49 1999 Rainer Orth + + * ntpd/ntp_proto.c (proto_config): Don't set sys_bclient on + PROTO_MULTICAST_ADD, only caller can decide; remove wrong set on + PROTO_MULTICAST_DEL. + +Mon May 31 18:49:49 1999 Rainer Orth + + * ntpd/refclock_parse.c (stream_receive): Cast size_t to int to + match format. + (local_receive): Likewise. + (trimbletaip_event): Likewise. + (stream_receive): Cast struct timeval members to long to match + format. + (local_receive): Likewise. + + * ntpd/ntp_util.c (stats_config): Cast size_t to int to match + format. + + * libparse/clk_rawdcf.c (cvt_rawdcf): Cast ptr difference to int + to match format. + * ntpd/refclock_parse.c (gps16x_poll): Likewise. + + * ntpd/ntp_filegen.c (filegen_open): Use long format, cast arg to + match. + + * ntpd/refclock_parse.c (list_err): Use long format to match arg. + (parse_statistics): Likewise. + (gps16x_message): Likewise. + (cvt_ts): Use long format, cast args to match. + (parse_start): Add missing arg. + (gps16x_message): Swap args to match format. + + * ntpd/ntpd.c (ntpdmain): Cast uid to long, adapt format. + + * ntpd/ntp_intres.c (readconf): Use long format to match arg. + * ntpd/ntp_io.c (getrecvbufs): Likewise. + * ntpd/ntp_proto.c (default_get_precision): Likewise. + + * ntpd/ntp_loopfilter.c (local_clock): Cast clock_panic to int to + match format. + + * ntpd/ntp_io.c (io_multicast_add): Print s_addr member, not + struct in_addr, to match format. + + * include/ntp_stdlib.h: Declare msyslog() as printf-like for gcc + format checking. + +Fri May 28 16:39:35 1999 Rainer Orth + + * ntpdc/ntpdc_ops.c (iostats): Align timereset line. + + * ntpq/ntpq_ops.c (doopeers): Properly align header. + + * ntpdc/ntpdc_ops.c (debug): Removed declaration, already in + ntp_stdlib.h. + * ntpq/ntpq_ops.c: Likewise. + + * ntpdate/ntpdate.c (debug): Declare volatile to match + ntp_stdlib.h. + * ntpdc/ntpdc.c, ntpq/ntpq.c, ntptrace/ntptrace.c, util/tickadj.c, + util/ntptime.c: Likewise. + + * include/parse.h (debug): Don't declare to avoid clash with + ntp_stdlib.h. + + * include/Makefile.am (noinst_HEADERS): Add new ntp_syscall.h. + + * configure.in: Also check for -lrt for POSIX.1c functions. + +Wed May 26 21:03:30 1999 Rainer Orth + + * configure.in: Removed -Wwrite-strings from CFLAGS. + + * ntpdc/ntpdc.c (help): Remove superfluous cast. + * ntpq/ntpq.c (help): Likewise. + +Tue May 25 18:00:49 1999 Rainer Orth + + * ntpq/ntpq_ops.c (struct varlist): name cannot be const char * + since it may be malloc'ed. + + * ntpdc/ntpdc.c (sendrequest): Declare pass as const char *, don't + loose const in cast. + * ntpq/ntpq.c (sendrequest): Likewise. + + * ntpd/ntp_control.c (ctl_getitem): Remove superfluous cast. + * include/ntpd.h (struct ctl_var): text cannot be const char * + since it's malloc'ed. + +1999-06-22 Harlan Stenn + + * include/l_stdlib.h: Don't include , add forward + declaration of struct in_addr instead. + From: Rainer Orth + + Patch: + + * include/l_stdlib.h: Fixed syscall() declaration. + * configure.in: Updated test to match. + + * configure.in: Check if we need to declare errno and h_errno. + Check for which may provide a h_errno declaration and + which the latter needs. + * acconfig.h: Provide the necessary templates. + + * include/ntp_syscall.h: New file, hides various implementations + of ntp_adjtime() and ntp_gettime() syscalls. + * ntpd/ntp_loopfilter.c: Use it. + * ntpd/ntp_request.c: Likewise. + * ntpd/refclock_local.c: Likewise. + * util/ntptime.c: Likewise. + + * include/l_stdlib.h: Include , declare inet_ntoa if + necessary. + Moved syscall() declaration here. + + * kernel/sys/parsestreams.h: Include for it's + definition of struct ppsclockev. + Include unconditionally for definition of + CIOGETEV via TIOCGPPSEV. + * kernel/sys/ppsclock.h: Protect struct ppsclockev from + redefinition. + + * include/ntp_refclock.h: Protect it from multiple inclusion. + * include/ntp_fp.h: Likewise. + * include/ntp.h: Likewise. + + * include/ntpd.h: Include ntp_refclock.h for MAXDIAL declaration. + * libntp/authkeys.c: Include ntpd.h for current_time declaration. + + * include/ntpd.h (getauthkeys, auth_agekeys, rereadkeys): Moved + prototypes to ntp_stdlib.h + + * include/ntp_stdlib.h: Declare variables exported by libntp. + * include/ntpd.h: Likewise for ntpd. + + * libntp/authkeys.c (key_hash, authnokey, authfreekeys, + cache_flags): Made static. + * libntp/systime.c (tvu_maxslew, tsf_maxslew, sys_clock_offset, + sys_residual): Likewise. + * ntpd/ntp_intres.c (confentries): Likewise. + * ntpd/ntp_loopfilter.c (clock_offset, clock_panic): Likewise. + (pll_nano): Likewise. Removed duplicate definition. + * ntpd/ntp_peer.c (peer_free, current_association_ID, + assocpeer_calls, init_peer_starttime): Likewise. + * ntpd/ntp_proto.c (sys_offset, sys_authdly): Likewise. + * ntpd/ntp_request.c (numrequests, numresppkts, errorcounter): + Likewise. + * ntpd/ntp_restrict.c (res_calls, res_found, res_not_found, + res_timereset, res_limited_refcnt): Likewise. + * ntpd/ntpd.c (was_alarmed, worker_thread): Likewise. + + * ntpq/ntpq_ops.c: Moved declaration of external variable from + ntpq.c to file scope. + + * adjtimed/adjtimed.c: Moved declarations of external variables to + ntpd.h and ntp_stdlib.h. + * clockstuff/propdelay.c: Likewise. + * libntp/a_md5encrypt.c, libntp/authencrypt.c, libntp/authkeys.c, + libntp/mfp_mul.c, libntp/msyslog.c, libntp/systime.c: Likewise. + * ntpd/ntp_config.c, ntpd/ntp_control.c, ntpd/ntp_filegen.c, + ntpd/ntp_intres.c, ntpd/ntp_io.c, ntpd/ntp_loopfilter.c, + ntpd/ntp_monitor.c, ntpd/ntp_peer.c, ntpd/ntp_proto.c, + ntpd/ntp_refclock.c, ntpd/ntp_request.c, ntpd/ntp_restrict.c, + ntpd/ntp_timer.c, ntpd/ntp_util.c, ntpd/ntpd.c, + ntpd/refclock_acts.c, ntpd/refclock_arbiter.c, ntpd/refclock_arc.c, + ntpd/refclock_as2201.c, ntpd/refclock_atom.c, + ntpd/refclock_bancomm.c, ntpd/refclock_chronolog.c, + ntpd/refclock_chu.c, ntpd/refclock_datum.c, + ntpd/refclock_dumbclock.c, ntpd/refclock_gpsvme.c, + ntpd/refclock_heath.c, ntpd/refclock_hpgps.c, ntpd/refclock_irig.c, + ntpd/refclock_jupiter.c, ntpd/refclock_leitch.c, + ntpd/refclock_local.c, ntpd/refclock_msfees.c, + ntpd/refclock_mx4200.c, ntpd/refclock_nmea.c, + ntpd/refclock_oncore.c, ntpd/refclock_palisade.h, + ntpd/refclock_parse.c, ntpd/refclock_pst.c, ntpd/refclock_shm.c, + ntpd/refclock_tpro.c, ntpd/refclock_trak.c, ntpd/refclock_true.c, + ntpd/refclock_usno.c, ntpd/refclock_wwvb.c: Likewise. + * ntpdate/ntpdate.c: Likewise. + * ntpdc/ntpdc.c, ntpdc/ntpdc_ops.c: Likewise. + * ntpq/ntpq.c: Likewise. + * ntptrace/ntptrace.c: Likewise. + * util/ntptime.c, til/tickadj.c: Likewise. + From: Rainer Orth + + * include/ntp_machine.h: Removed superfluous yy/mm/dd comments. + * include/ntpd.h: Likewise. + * libntp/authencrypt.c: Likewise. + * libntp/a_md5encrypt.c: Likewise. + * libntp/caljulian.c: Likewise. + * libntp/ymd2yd.c: Likewise. + * libntp/syssignal.c: Likewise. + * libntp/ymd2yd.c: Likewise. + * ntpd/ntp_control.c: Likewise. + * ntpd/ntp_io.c: Likewise. + * ntpd/ntp_timer.c: Likewise. + * ntpdate/ntpdate.c: Likewise. + * ntpq/ntpq_ops.c: Likewise. + * ntpd/ntp_peer.c (findpeer): Wrap debug output in DEBUG/debug. + From: Rainer Orth + + * dot.emacs: Removed wrong indentation of substatements. + Wrap in c-style. + From: Rainer Orth + + * ntpd/refclock_palisade.c: Patches from Marc Brett + * ntpd/refclock_palisade.h: Ditto. + * util/hist.c: Ditto. + +Tue Jun 1 00:40:04 1999 Harlan Stenn + + * build: mips-dec-ultrix4.4 hates "set -e" + + * flock-build: Created + + * build: added -l option + +Mon May 31 20:28:40 1999 Harlan Stenn + + * README: Removed auto{make,conf}.patch files + +Tue May 25 01:20:53 1999 Harlan Stenn + + * Makefile.am ($(srcdir)/COPYRIGHT): Added + (EXTRA_DIST): Remove auto*.patches + +Thu May 20 01:03:00 1999 Harlan Stenn + + * Makefile.am (dist-hook): Call dos2unix on the .htm files + + * ntpd/refclock_palisade.h: Clean up declarations. + + * configure.in (ac_cv_struct_ntptimeval_timespec): Added. + (ac_cv_make_ntptime): Only if ntptimeval does not use timespec. + + * util/tickadj.c: Linux Patches + From: Reg Clemens + +Wed May 19 01:18:24 1999 Harlan Stenn + + * configure.in: 4.0.93a + + * ntpd/refclock_palisade.h: Restore some lost patches + From: Kamal A Mostafa + +Sun May 16 13:18:32 1999 Philippe De Muyter + + * libparse/clk_wharton.c (cvt_wharton_400a, inp_wharton_400a): Expect + serial output format number 1, not 5. + (clock_wharton_400a) : Likewise. + * ntpd/refclock_parse.c (parse_clockinfo): For Wharton 400a clock, + do not poll, but expect a message every second. + * html/parsedata.htm : Entry added for Wharton 400a clock. + * html/driver8.htm : Entry fixed for Wharton 400a clock. + +Sun May 16 02:59:46 1999 Harlan Stenn + + * configure.in: 4.0.93 + +Sat May 15 18:53:47 1999 Harlan Stenn + + * configure.in (ntp_refclock): ONCORE requires PPSAPI, CIOGETEV, + or TIOCGPPSEV. + Reported by: Reg Clemens + +Fri May 14 23:58:35 1999 Harlan Stenn + + * configure.in: 4.0.92h2 + + * configure.in (ac_cv_make_ntptime): Not under Linux. Yes, it + works for some people. We're tired of the complaints from the + others. + +Fri May 14 18:58:59 1999 Rainer Orth + + * libntp/authreadkeys.c (authreadkeys): Reject autokey keys. + Include ntp.h for NTP_MAXKEY definition, ntp_fp.h for types used + in ntp.h. + +Wed May 12 23:02:22 1999 Rainer Orth + + * libntp/authkeys.c (auth_delkeys): Don't remove autokey keys, + leave info on KEY_TRUSTED flag alone. + Include ntp.h for NTP_MAXKEY definition. + +Thu May 13 02:19:02 1999 Harlan Stenn + + * configure.in: 4.0.92h1 + + * configure.in: patch for ReliantUNIX + From: Andrej Borsenkow + + * ntpd/refclock_oncore.c: Patches + From: Reg Clemens + +Thu Apr 29 14:01:04 1999 Rainer Orth + + * html/*.htm: Remove unnecessary  . Cleanup

+	sections.
+
+	* configure.in: Properly align configure --help output.
+	* html/config.htm: Include this version, removing Netscape  
+	cruft.
+
+Wed Apr 28 15:08:55 1999  Rainer Orth  
+
+	* kernel/sys/parsestreams.h: Only include  if
+	struct ppsclockev is missing from system headers.
+
+	* util/tickadj.c (getoffsets): Define kernels[] only if used.
+	(openfile): Rename fd to avoid shadowing global fd.
+	(writevar): Likewise.
+	(readvar): Likewise.
+
+	* parseutil/dcfd.c (read_drift): drift_file is const char *.
+	(update_drift): Likewise.
+	(adjust_clock): Likewise.
+	(main): Likewise.
+
+	* ntpd/refclock_parse.c (gps16x_poll): Adapt format to match
+	parse->localstate type.
+
+	* ntpd/ntp_refclock.c (refclock_gtlin): Only define gotit label
+	if used.
+
+	* include/l_stdlib.h (openlog, syslog): char * args are const.
+
+	* configure.in (*-*-osf4*): Enable declaration of stime().
+
+	* ntpd/refclock_oncore.c (oncore_msg_any): Cast args to long to
+	match prototype.
+	(oncore_msg_En): Likewise.
+
+	* include/ntp_refclock.h (struct refclockstat): Declare p_lastcode
+	as const char *.
+
+	* ntpq/ntpq_ops.c (struct varlist): Define name as const.
+
+	* ntpdc/ntpdc.c (tokenize): Define cp as const char *, remove
+	wrong cast instead.
+
+	* ntpd/ntp_util.c (record_clock_stats): Make text arg const.
+	* include/ntpd.h (record_clock_stats): Adapt declaration.
+	* ntpd/refclock_oncore.c (oncore_start): Removed superfluous casts.
+	(oncore_msg_Cf): Likewise.
+	(oncore_msg_Fa): Likewise.
+	(oncore_msg_Cj): Likewise.
+	(oncore_msg_Ea): Likewise.
+	(oncore_msg_Bj): Likewise.
+
+	* configure.in (*-*-solaris2.4): Enable declarations of
+	gettimeofday(), settimeofday(); they are `protected' by
+	__cplusplus in .
+
+Tue Apr 27 21:14:47 1999  Rainer Orth  
+
+	* scripts/summary.pl: Use . as default statsdir.
+	(do_loop): Accept new loopstats format with additional sys_error
+	and clock_stability fields.
+	(do_peer): Accept new peerstats format with additional skew field.
+
+Mon Apr 26 01:50:38 1999  Harlan Stenn  
+
+	* Upgraded automake (1.4a) and autoconf (2.14.1)
+
+	* configure.in (ac_refclock_irig): We no longer need stropts.h.
+	* ntpd/refclock_irig.c: Ditto
+
+Mon Apr 26 17:33:33 1999  Rainer Orth  
+
+	* configure.in (*-*-irix6*): Don't pass MIPSpro cc-only flag -n32
+	to gcc.
+
+Thu Apr 22 15:06:40 1999  Rainer Orth  
+
+	* ntpd/ntp_config.c (getconfig): IN_CLASSD() expects address in
+	host byte order, but struct sockaddr_in.s_addr is in network byte
+	order.
+	* ntpd/ntp_io.c (io_multicast_del): Likewise.
+
+Sat Apr 24 01:00:53 1999  Harlan Stenn  
+
+	* configure.in: 4.0.92h
+
+	* ntptrace/ntptrace.c: -m maxhost patch
+	From: "R. Gary Cutbill" 
+
+	* util/ntptime.c: Patches.
+	From: Ulrich Windl 
+
+	* html/accopt.htm, html/assoc.htm, html/authopt.htm,
+	html/biblio.htm, html/build.htm, html/clockopt.htm,
+	html/confopt.htm, html/copyright.htm, html/debug.htm, 
+	html/exec.htm, html/extern.htm, html/hints.htm, html/index.htm,
+	html/kern.htm, html/miscopt.htm, html/monopt.htm, html/notes.htm,
+	html/ntpd.htm, html/ntpdate.htm, html/ntpdc.htm, html/ntpq.htm,
+	html/ntptime.htm, html/ntptrace.htm, html/patches.htm,
+	html/porting.htm, html/pps.htm, html/rdebug.htm,
+	html/refclock.htm, html/release.htm, html/tickadj.htm,
+	html/hints/solaris.html: Fixed many typos and problems.
+	* acconfig.h (DECL_CFSETISPEED_0, DECL_MRAND48_0, DECL_NLIST_0,
+	DECL_SRAND48_0, DECL_STIME_0): New templates.
+	* include/l_stdlib.h: Include termios.h to get definition of
+	speed_t.
+	(cfsetispeed, cfsetospeed, mrand48, nlist, srand48, stime): New
+	declarations.
+	(openlog): Declare 2- or 3-argument form.
+	* configure.in: Enable declarations of functions missing from
+	Ultrix V4.3 system headers.
+	* ntpd/refclock_oncore.c: Include , Ultrix V4.3
+	 needs it for dev_t.
+	From: Rainer Orth 
+
+	* ntpdc/ntpdc_ops.c: Reality checks.
+
+	* configure.in: netbsd has stubs for the timer_* stuff and doesn't
+	support PPSAPI.  IRIG requires  .
+	From: Frederick Bruckman 
+
+	* ntpdc/ntpdc_ops.c: (kerninfo)  Report in seconds regardless of
+	kernel precision.  Report kernel flags as text.
+	From: Poul-Henning Kamp 
+	
+Sun Apr 18 14:26:51 1999  Harlan Stenn  
+
+	* configure.in: 4.0.92g
+
+	* ntpd/ntp_refclock.c (refclock_ioctl): We don't want
+	PPS_HARDPPSONASSERT by default.
+	* ntpd/refclock_oncore.c: Prefer timepps.h over sys/timepps.h
+	From: Poul-Henning Kamp 
+
+Tue Apr 13 17:32:35 1999  Harlan Stenn  
+
+	* configure.in: 4.0.92f
+
+	* ntpd/ntp_refclock.c (refclock_open): VMIN should be 1, not 0
+	From: Reg Clemens 
+
+Sun Apr 11 18:26:44 1999  Harlan Stenn  
+
+	* ntpd/refclock_mx4200.c: Patches/improvements
+	* ntpd/ntpd.c (set_process_priority): Lint
+	From: Marc.Brett@westgeo.com
+
+	* util/ntptime.c: Lint, bit definition cleanup
+	From: Ulrich Windl 
+
+Wed Apr  7 03:02:23 1999  Harlan Stenn  
+
+	* ntpd/refclock_oncore.c: Use timepps.h or sys/timepps.h
+	* configure.in: Look for either timepps.h or sys/timepps.h
+	From: Poul-Henning Kamp 
+
+	* ntpd/ntp_io.c (create_sockets): Don't warn about ENXIO.
+	(Several places)
+	From: Andrej Borsenkow 
+
+	* libntp/mfp_mul.c (mfp_mul): Lint.
+	Marc.Brett@westgeo.com
+
+Sun Apr  4 03:23:53 1999  Harlan Stenn  
+
+	* configure.in: 4.0.92e
+	Dave redesigned the clock state machine.
+
+1999-02-28  Frank Kardel  
+
+	* parseutil/dcfd.c: added DCF77 module powersetup
+
+	* ntpd/refclock_parse.c (parse_control): using gmprettydate instead of prettydate()
+	(mk_utcinfo): new function for formatting GPS derived UTC information
+	(gps16x_message): changed to use mk_utcinfo()
+	(trimbletsip_message): changed to use mk_utcinfo()
+	ignoring position information in unsynchronized mode
+	(parse_start): augument linux support for optional ASYNC_LOW_LATENCY
+
+	* ntpd/ntp_control.c (ctl_putclock): cleanup of end of buffer handling
+
+	* libparse/parse.c (timepacket): removed unnecessary code
+
+	* libparse/clk_trimtsip.c (struct trimble): new member t_utcknown
+	(cvt_trimtsip): fixed status monitoring, bad receiver states are
+ 	now recognized
+
+	* libntp/prettydate.c (gmprettydate): new function for format date
+ 	and time with respect to UTC
+
+	* libntp/gpstolfp.c (GPSWRAP): update GPS rollover to 990 weeks
+
+	* include/trimble.h (CMD_RUTCPARAM): control variable name unification
+
+	* include/ntp_fp.h: added prototype for gmprettydate()
+
+Sat Feb 27 00:03:16 1999  Harlan Stenn  
+
+	* libntp/systime.c: definition
+	* ntpd/ntp_proto.c: sco5_oldclock declaration
+	* configure.in: SCO5_CLOCK for *-*-sco3.2v5*
+	* util/tickadj.c (main): SCO5_OLDCLOCK -> SCO5_CLOCK
+	From: Kees Hendrikse 
+
+	* ntpd/ntp_config.c (getconfig): Indentation cleanup
+	Deal with 'P' case better
+	* ntpd/ntpd.c: Declare set_process_priority()
+	* ntpd/refclock_dumbclock.c: Lint cleanup
+	From: Marc.Brett@westgeo.com
+
+Wed Feb 24 10:22:51 1999  Harlan Stenn  
+
+	* configure.in: 4.0.92d
+
+	* configure.in: Dave says we can't enable PARSE clocks by default.
+	Also, Solaris 2.7 still has its kernel bug - disable kernel FLL
+	there.
+	Reported by: Dave Mills 
+
+Tue Feb 23 23:37:44 1999  Harlan Stenn  
+
+	* libparse/Makefile.am (parsesolaris.o): Devious hack to deal
+	with bug in sys/systm.h .
+	Suggested by: Chaim Frenkel 
+
+Tue Feb 23 20:46:31 1999  Frank Kardel  
+
+	* ntpd/refclock_parse.c: fixed #endifs
+	(stream_receive): fixed formats
+
+Mon Feb 22 00:35:06 1999  Harlan Stenn  
+
+	* configure.in: 4.0.92c
+
+	* ntpd/refclock_chronolog.c: Lint
+	* ntpd/refclock_dumbclock.c: Ditto
+	* ntpd/refclock_oncore.c: Ditto
+	From: Marc.Brett@westgeo.com
+
+	* ntpd/refclock_oncore.c (oncore_msg_any): Call GETTIMEOFDAY, not
+	gettimeofday().
+	From: david.higgins@mail.ccur.com
+
+	* configure.in (MCAST): Not in i386-sequent-sysv4
+	Reported by: Joseph Geter 
+
+	* util/ntptime.c: Linux cleanup.
+	From: Reg Clemens 
+
+	* configure.in: Rename SCO5_OLDCLOCK to SCO5_CLOCK
+	* acconfig.h: Ditto
+
+	* ntpd/ntp_proto.c: SCO5_CLOCK stuff
+	(init_proto): Use the SCO5_CLOCK stuff
+	* libntp/systime.c: SCO5_CLOCK stuff
+	(get_systime): Use the SCO5_CLOCK stuff
+	(adj_systime): Use the SCO5_CLOCK stuff
+	From: Kees Hendrikse 
+
+	* ntpd/ntp_config.c: Added -P option and associated baggage.
+	(getstartup): Update help text
+	(getconfig): Process -P option
+	(getconfig): Update help text
+	* ntpd/ntpd.c (set_process_priority): Created.
+	(service_main): remove process priority stuff - we want to do at
+	after we start up the resolver, so call set_process_priority()
+	after getconfig().
+	From: Kamal A Mostafa 
+
+1999-02-21  Frank Kardel  
+
+	* ntpd/ntp_util.c (hourly_stats): removed unused variable
+
+	* libntp/ieee754io.c: renamed index to fieldindex to avoid index() name clash
+
+	* ntpd/refclock_parse.c (parse_start): add initialization for Linux PPSkit
+
+Sun Feb 21 17:53:33 1999  Harlan Stenn  
+
+	* ntpd/ntp_io.c (create_sockets): Skip interfaces that are really
+	just aliases.
+	From: "Erik R. Leo" 
+
+	* configure.in: 4.0.92b
+
+	* ntpd/ntpd.c (service_main): Check for an error return from
+	sched_get_priority_max().
+
+Wed Feb 17 03:48:47 1999  Harlan Stenn  
+
+	* configure.in: 4.0.92a
+
+	* configure.in: configure.in requires autoconf 2.13 or later.
+	Reported by Ulrich Windl 
+
+Wed Feb 17 00:12:11 1999  Harlan Stenn  
+
+	* acconfig.h: TERMIOS_NEEDS__SVID3
+	* configure.in: Ditto
+	* ntpd/refclock_palisade.h: Ditto
+	* include/ntp_refclock.h: Ditto
+	* ntpd/ntpd.c (service_main): We want sched_get_priority_max().
+	From: Kamal A Mostafa 
+
+	* ntpd/ntp_refclock.c (refclock_open): Zero the entire c_cc[] array.
+	From: Reg Clemens 
+
+Tue Feb 16 23:37:49 1999  Harlan Stenn  
+
+	* Updated ansi2knr
+	Reported by: Marc Brett
+
+Mon Feb 15 02:55:28 1999  Harlan Stenn  
+
+	* configure.in: 4.0.92
+
+	* ntpd/ntp_refclock.c: Added refclock_chronolog and
+	refclock_dumbclock.
+	From: Robert McMillin 
+
+Sun Feb 14 15:57:53 1999  Harlan Stenn  
+
+	* dropped SCO3 support #defines.
+	* changed SCO5_TICKADJ #define to SCO5_OLDCLOCK
+	* Added code in libntp/systime.c to accumulate changes until a whole
+	  tick can be added or dropped. Adjusted gettimeofday() output
+	  to include the contents of the accumulator.
+	* cleaned up util/tickadj.c; tickadj -As now does the right thing.
+	From: Kees Hendrikse 
+
+	* ntpq/ntpq.c: Rename delay() to auth_delay()
+	Reported by: Andrej Borsenkow 
+
+	* ntpd/refclock_palisade.h: Cleanup.
+	From: Marc.Brett@westgeo.com
+
+	* ntpd/ntp_refclock.c (refclock_ioctl): Typo.
+	From: Reg Clemens 
+
+	* ntpd/ntp_io.c (create_sockets): Only bind a given network once.
+	From: Wolfgang Rupprecht 
+
+Sat Jan 30 11:48:37 1999  Harlan Stenn  
+
+	* configure.in: 4.0.91f
+
+Thu Jan 28 22:58:40 1999  Harlan Stenn  
+
+	* ntpd/refclock_parse.c (CLK_REALTYPE): We really want ttl, not hmode.
+	* ntpd/ntp_config.c (getconfig): "mode" really should update the
+	ttl member, not the hmode member.
+
+	* ntpd/refclock_local.c: More offset cleanup from Dave.
+
+Thu Jan 28 00:15:20 1999  Harlan Stenn  
+
+	* configure.in: 4.0.91e
+
+	* ntpd/refclock_local.c: Bugfix.
+	From: Dave Mills
+
+	* ntpd/refclock_palisade.c: Lint/IRIX portability cleanup
+	* ntpd/refclock_palisade.h: Re-enable the declaration of float()
+	* ntpd/ntp_io.c (create_sockets): Initialize size to 0
+	From: Marc.Brett@westgeo.com
+
+	* ntpd/refclock_parse.c (CLK_REALTYPE): Use hmode, not ttl.
+	* configure.in (ac_cv_var_no_parenb_ignpar): Not under Linux.
+	Reported by: Thomas Quinot 
+
+	* ntpdc/ntpdc.c (my_delay): Renamed, from delay.
+	Reported by: Andrej Borsenkow 
+
+Tue Jan 26 00:56:10 1999  Harlan Stenn  
+
+	* configure.in: 4.0.91d
+
+	* ntpq/ntpq.c: Y2K patches
+	From: Marc.Brett@westgeo.com
+
+	* html/driver29.htm: New version
+	* ntpd/refclock_palisade.c: Ditto
+	* ntpd/refclock_palisade.h: Ditto
+	From: Sven_Dietrich@Trimble.COM
+
+	* upgrade ansi2knr.c
+
+	* Some stuff that Dave did.
+
+	* configure.in: 4.0.91c
+
+	* ntpd/refclock_oncore.c: Prototype cleanup.  Enum cleanup.
+	* ntpd/ntp_proto.c (clock_select): Fix memory leak.
+	* configure.in (ac_cv_struct_ppsclockev): Might need sys/time.h to
+	check for struct clockppsev.  Return pce->serial, not 0;
+	From: Marc.Brett@westgeo.com
+
+	* ntpd/refclock_oncore.c (oncore_msg_En): Clean up.
+	From: John.Hay@mikom.csir.co.za
+
+Mon Jan 25 11:50:29 1999  Philippe De Muyter  
+
+	* libparse/parse_conf.c (clockformats): Entry added for
+ 	clock_wharton_400a.
+	* libparse/clk_wharton.c: New file.
+	* libparse/Makefile.am (libparse_a_SOURCES): clk_wharton.c added;
+	(libparse_kernel_a_SOURCES): kclk_wharton.c added.
+	(kclk_wharton.o): New dependency rule.
+	* ntpd/refclock_parse.c (parse_clockinfo): Entry added for the
+	WHARTON clock (mode 15).
+	* acconfig.h (CLOCK_WHARTON_400A): New configuration macro.
+	* configure.in (CLOCK_WHARTON_400A): Macro defined like other
+	CLOCK_xxx macros.
+
+Sun Jan 24 13:51:30 1999  Harlan Stenn  
+
+	* ntpd/ntp_config.c (do_resolve_internal): Missing #ifdef DEBUG
+	From: Sven Dietrich 
+
+	* Makefile.am (SUBDIRS): Lose authstuff
+	* configure.in: Ditto
+
+Sat Jan 23 15:28:03 1999  Harlan Stenn  
+
+	* configure.in: 4.0.91b
+
+Sat Jan 23 15:02:25 1999  Harlan Stenn  
+
+	* ntpd/refclock_oncore.c: use HAVE_STRUCT_PPSCLOCKEV
+	* acconfig.h: HAVE_STRUCT_PPSCLOCKEV
+	* configure.in (ac_cv_struct_ppsclockev): Added test
+
+Thu Jan 21 15:35:25 1999  Harlan Stenn  
+
+	* configure.in: 4.0.91a
+
+	* ntpd/refclock_nmea.c (nmea_receive): Call refclock_process()
+	every second (or each time a nmea string is received).
+	From: John Hay 
+
+	* ntpd/ntp_refclock.c (refclock_ioctl): Use TIOCPPS if we have it.
+	(refclock_ioctl): Use LDISC_CLKPPS, not LDISC_PPS when deciding
+	how to set str.
+	* ntpd/ntp_loopfilter.c: Lose unused ntp_gettime() stuff.
+	* ntpd/ntp_request.c: Ditto.
+	* ntpd/refclock_local.c: Ditto.
+	* ntpd/refclock_shm.c (shm_poll): Fix the refclock_process() call.
+	* ntpd/refclock_oncore.c: patches and cleanup
+	* configure.in: ioctl/PPS checks, ONCORE cleanup
+	* acconfig.h: ONCORE cleanup
+	From: Reg Clemens 
+
+	* configure.in (CFLAGS): cc on Sequent wants -Wc,+abi-socket.
+	We also need to figure out why -lsocket isn't being detected;
+	-lsocket is needed.
+	From: Dana Kaempen 
+
+	* include/ntp_stdlib.h: AIX portability patches, header cleanup.
+	* ntptrace/ntptrace.c: Ditto.
+	* ntpdate/ntpdate.c: Ditto.
+	* ntpd/refclock_true.c: Ditto.
+	* ntpd/refclock_mx4200.c: Ditto.
+	* ntpd/refclock_jupiter.c: Ditto.
+	* libntp/msyslog.c: Ditto.
+	From: Marc.Brett@waii.com
+
+Sun Jan 10 15:15:07 1999  Harlan Stenn  
+
+	* configure.in: 4.0.91
+
+Sat Jan  9 00:11:34 1999  Harlan Stenn  
+
+	* include/ntp_stdlib.h: msyslog() is declared differently if we're
+	not __STDC__.
+
+	* include/ntp_types.h: It's HAVE_PROTOTYPES, not USE_PROTOTYPES.
+	* include/ntp_machine.h: Ditto.
+
+Fri Jan  8 20:47:10 1999  Harlan Stenn  
+
+	* configure.in: Upgrade to autoconf-2.13
+	Do the prototypes check much earlier, as it might alter CFLAGS and
+ 	things which will affect other tests.
+
+	* ntpd/ntp_request.c (do_conf): The problem was with a template
+	for "version" on an IRIX C compiler...
+	From: Marc.Brett@waii.com
+
+	* libntp/authkeys.c: #include config.h first.
+	Reported by: brian.bumpass@funb.com
+
+Thu Jan  7 00:24:35 1999  Harlan Stenn  
+
+	* util/tickadj.c (main): return() instead of exit().
+	* ntpd/ntp_request.c (do_conf): Disambiguate ||.
+	* ntpd/ntp_proto.c (clock_select): Initialize variables.
+	From: Marc.Brett@waii.com
+
+	* scripts/ntpver.in: Use PATH_SH
+
+	* configure.in (PATH_SH): Added.
+
+Tue Jan  5 19:02:51 1999  Harlan Stenn  
+
+	* configure.in: 4.0.90h
+
+	* html/driver30.htm: Updated.
+	* html/refclock.htm: Refer to driver30
+	* ntpd/refclock_oncore.c: Vastly improve and make less FreeBSD centric,
+	From: Poul-Henning Kamp  and
+		Reg.Clemens 
+
+	* include/ntp.h: Portability/lint patches
+	* libntp/binio.c: Ditto.
+	* libntp/caljulian.c: Ditto.
+	* libntp/caltontp.c: Ditto.
+	* libntp/ieee754io.c: Ditto.
+	* libntp/md5c.c: Ditto.
+	* libntp/mfp_mul.c: Ditto.
+	* libntp/msyslog.c: Ditto.
+	* libntp/statestr.c: Ditto.
+	* libntp/systime.c: Ditto.
+	* libparse/clk_trimtsip.c: Ditto.
+	* libparse/data_mbg.c: Ditto.
+	* libparse/parse.c: Ditto.
+	* ntpd/ntp_control.c: Ditto.
+	* ntpd/ntp_filegen.c: Ditto.
+	* ntpd/ntp_intres.c: Ditto.
+	* ntpd/ntp_io.c: Ditto.
+	* ntpd/ntp_peer.c: Ditto.
+	* ntpd/ntp_proto.c: Ditto.
+	* ntpd/ntp_util.c: Ditto.
+	* ntpd/ntpd.c: Ditto.
+	* ntpd/refclock_arc.c: Ditto.
+	* ntpd/refclock_chu.c: Ditto.
+	* ntpd/refclock_datum.c: Ditto.
+	* ntpd/refclock_leitch.c: Ditto.
+	* ntpd/refclock_parse.c: Ditto.
+	* ntpd/refclock_usno.c: Ditto.
+	* ntpq/ntpq.c: Ditto.
+	* util/tickadj.c: Ditto.
+	From: Marc.Brett@waii.com
+
+Mon Jan  4 00:56:55 1999  Harlan Stenn  
+
+	* configure.in: 4.0.90g
+
+	* ntpd/ntp_config.c (getconfig): MODE was setting ttl, not hmode.
+	Reported by: Carsten Emde 
+
+Fri Dec  4 01:01:14 1998  Harlan Stenn  
+
+	* configure.in: 4.0.90f
+
+	* ntpd/refclock_mx4200.c: New version
+	From: Marc.Brett@waii.com
+
+1998-12-02  Harlan Stenn  
+
+	* ntpd/ntp_config.c (do_resolve_internal): If fork fails, say why.
+	Reported by: Jeff_Dennison@admin.tc.faa.gov
+
+	* ntpd/ntpd.c (ntpdmain):  fork() can return a -1.  Someday we'll
+	report this condition...
+
+1998-12-02  Harlan Stenn  
+
+	* configure.in: 4.0.90e
+
+	* ntpd/refclock_palisade.c: Reformat code so ansi2knr will work
+	* ntpd/refclock_palisade.h: Ditto
+	From: Marc.Brett@waii.com
+
+Sun Nov 29 21:00:53 1998  Harlan Stenn  
+
+	* configure.in: 4.0.90d
+
+	* configure.in (CFLAGS): Use "-O2 -g3 -n32" by default for Irix6.2
+	and later.
+	Reported by: Jack Bryans 
+
+1998-11-29  Harlan Stenn  
+
+	* configure.in: 4.0.90c
+
+	* ntpd/refclock_oncore.c (oncore_msg_En): Convert to nano
+	From: John Hay 
+
+	* include/ntp_request.h (RM_VN_MODE): Add version parameter, so
+	xntpdc will work across v3 and v4.
+	* ntpd/ntp_request.c: Track requested version
+	(req_ack): Use requested version in RM_VN_MODE
+	(more_pkt): Ditto
+	(flush_pkt): Ditto
+	(process_private): Get requested version
+	* ntpd/ntp_intres.c (request): Use default version
+	* ntpdc/ntpdc.c (sendrequest): Ditto
+	From: John Hay 
+
+Fri Nov 27 14:27:21 1998  Harlan Stenn  
+
+	* ntpd/refclock_palisade.c: Lint cleanup
+	* ntpd/refclock_palisade.h: Ditto.
+	From: Marc Brett 
+
+Mon Nov 23 04:45:03 1998  Harlan Stenn  
+
+	* configure.in: 4.0.90b
+
+	* New code and cleanup for the NT stuff
+	From: Carl Byington 
+
+Sat Nov 21 21:21:45 1998  Harlan Stenn  
+
+	* configure.in: 4.0.90a
+
+	* libntp/systime.c (step_systime): net_set_tod calls clock_settime.
+	* libntp/machines.c (ntp_set_tod): Take a 2nd arg for NT.
+	* include/ntp_machine.h: ntp_set_tod() has 2 args always.
+	* ports/winnt/bldrel.bat: Typo.
+	From: Carl Byington 
+
+	* ntpd/ntp_intres.c (findhostaddr): h_errno is a #define under AIX.
+	* configure.in:  clock_settime is a stub in AIX4.
+	From: Perry Ross 
+
+	* libntp/Makefile.am (EXTRA_DIST): Lose libntp.mak
+	* ntpd/Makefile.am (EXTRA_DIST): Ditto.
+	* ntpdate/Makefile.am (EXTRA_DIST): Ditto.
+	* ntpdc/Makefile.am (EXTRA_DIST): Ditto.
+	* ntpq/Makefile.am (EXTRA_DIST): Ditto.
+	From: Greg Schueman 
+
+Sat Nov 21 12:33:16 1998  Harlan Stenn  
+
+	* configure.in: 4.0.90
+
+	Nano changes from Dave Mills.
+
+Thu Nov 19 04:23:46 1998  Harlan Stenn  
+
+	* include/ntp_machine.h: STREAM also needs HAVE_SYS_STREAM_H
+	Reported by: Ronald Cole 
+
+Mon Nov 16 19:17:34 1998  Harlan Stenn  
+
+	* configure.in: 4.0.73e14
+
+	* util/ntptime.c (main): Protect STA_NANO
+
+	* ntpd/refclock_oncore.c: General overhaul and simplifications.
+	The new manual clarifies a lot of fine points, and the driver has
+	been suitably simplified.  Uses Site Survey if possible, otherwise
+	does it by hand.  Should also work with non-UT models, as long as
+	they talk the Motorola Binary Protocol.  The driver Doesn't (need
+	to) know where the author lives anymore.
+	From: Poul-Henning Kamp 
+
+	* ntpd/refclock_palisade.h: New version.
+	* ntpd/refclock_palisade.c: New version.
+	From: Sven Dietrich 
+
+Sat Oct 24 01:19:21 1998  Harlan Stenn  
+
+	* configure.in: 4.0.73e13
+
+	* ntpdc/ntpdc_ops.c (clkbug): Patches
+	* ntpd/ntp_refclock.c (refclock_buginfo): Patches
+	From: Marc.Brett@waii.com
+
+Sat Oct 10 20:13:14 1998  Harlan Stenn  
+
+	* configure.in: 4.0.73e12
+
+	* ntpd/ntp_util.c (hourly_stats): Added prio_set stuff.
+
+	* ntpd/ntpd.c (ntpdmain): HAVE_SETPGRP_0 typo.
+	* parseutil/dcfd.c (detach): Ditto.
+	* ntpd/ntp_control.c (ctl_putpeer): Sometimes, peer->dstadr is
+	NIL.
+	From: Perry Ross 
+
+	* ntpd/ntpd.c:
+	Some systems use sys/sched.h, not sched.h (Irix)
+	* configure.in (CFLAGS): nextstep needs -posix.
+	Reported by: Jack Bryans 
+
+Sat Oct  3 02:32:46 1998  Harlan Stenn  
+
+	* configure.in: 4.0.73e11
+
+	* configure.in (ac_refclock_palisade): Needs termios.
+
+	* libntp/mktime.c: Some systems need sys/types.h
+
+	* configure.in: Added AC_TYPE_SIZE_T and AC_CHECK_TYPE(time_t, long)
+	The time_t stuff should only be needed on Older machines, so the
+	fact that I'm using a long shouldn't be a problem (hollow laugh).
+
+	* include/l_stdlib.h: Sometimes we need to #include 
+
+	* libntp/Makefile.am (../include/des.h): Typo.
+
+Fri Oct  2 20:52:47 1998  Harlan Stenn  
+
+	* ntpd/ntp_intres.c (request): Accept responses back thru V2.
+
+Thu Oct  1 00:11:16 1998  Harlan Stenn  
+
+	* configure.in: 4.0.73e9
+
+	* ntpd/ntpd.c (catch_danger): Added.
+	(ntpdmain): AIX SIGDANGER stuff
+	From: Lars-Owe Ivarsson 
+
+	* configure.in:
+	* include/ntp_machine.h:
+	* include/ntp_string.h:
+	* libntp/machines.c:
+	* libparse/clk_hopf6021.c:
+	* libparse/clk_trimtsip.c:
+	* ntpd/refclock_leitch.c:
+	* ntpd/refclock_palisade.c:
+	* ntpd/refclock_parse.c:
+	Here are some patches to suppress warnings from various compilers
+	(IRIX 5.3, MipsPro C 7.1 on IRIX 6.4, AIX 4.1) and loaders (IRIX
+	5.3, IRIX 6.4).  Shouldn't affect functionality at all.
+	From: Marc Brett 
+	(I got similar patches for AIX from Lars-Owe Ivarsson
+	)
+
+Thu Sep 24 21:33:50 1998  Harlan Stenn  
+
+	* configure.in: '73e8
+
+	* configure.in: AIX4 stubs the POSIX timer_ stuff,
+	sched_setscheduler, and mlockall.
+	Reported by: Lars-Owe Ivarsson 
+
+	* configure.in: OpenBSD stubs the POSIX timer_ stuff.
+	Reported by:  sidney august cammeresi iv 
+	(and several other folks whose names I can't find at the moment)
+
+Mon Sep 21 15:35:23 1998  Harlan Stenn  
+
+	* configure.in: '73e7
+
+	* ntpd/refclock_parse.c: Missing declaration
+	From: Marc Brett 
+
+	* include/README: Remove old MCAST descriptions
+
+	* include/Makefile.am (noinst_HEADERS): Lose sun-in.h .
+
+Mon Sep 21 14:50:12 1998  Harlan Stenn  
+
+	* ntpdate/ntpdate.c (timer): Properly format the definition.
+
+Sun Sep 20 23:02:50 1998  Harlan Stenn  
+
+	* configure.in: '73e6
+
+	* include/Makefile.am (noinst_HEADERS): Renamed in.h to sun-in.h
+
+Fri Sep 18 01:05:55 1998  Harlan Stenn  
+
+	* configure.in: '73e5
+
+	* ntpd/refclock_palisade.c: SCO patch
+	From: Kamal A Mostafa 
+
+	* libparse/clk_trimtsip.c (cvt_trimtsip): Fix rollover bug.
+	From: "Michael J. Tubby B.Sc. G8TIC" 
+
+	* libntp/authencrypt.c:
+	* libntp/systime.c:
+	* ntpd/refclock_acts.c:
+	* ntpd/refclock_arbiter.c:
+	* ntpd/refclock_arc.c:
+	* ntpd/refclock_as2201.c:
+	* ntpd/refclock_atom.c:
+	* ntpd/refclock_chu.c:
+	* ntpd/refclock_conf.c:
+	* ntpd/refclock_datum.c:
+	* ntpd/refclock_heath.c:
+	* ntpd/refclock_hpgps.c:
+	* ntpd/refclock_irig.c:
+	* ntpd/refclock_leitch.c:
+	* ntpd/refclock_nmea.c:
+	* ntpd/refclock_palisade.c:
+	* ntpd/refclock_parse.c:
+	* ntpd/refclock_pst.c:
+	* ntpd/refclock_trak.c:
+	* ntpd/refclock_true.c:
+	* ntpd/refclock_usno.c:
+	* ntpd/refclock_wwvb.c:
+	Typos, cleanup, and bugfixes
+	From: Marc Brett 
+
+	* ntpd/ntp_timer.c (timer): Typo.
+	* include/ntp_refclock.h: in refclockstat, clockdesc should be const.
+	* ntpd/ntp_io.c (create_sockets): Typo.
+	* ntpd/ntp_control.c (free_varlist): Use the appropriate cast when
+	calling free().
+	(set_var): Use char *td for non-const char data.
+	(ctl_getitem): Use char * for non-const data.
+	(Many of these reported by Marc Brett)
+
+Sun Sep 13 19:19:09 1998  Harlan Stenn  
+
+	* ntpd/ntpd.c: Added nofork declaration.
+	(ntpdmain): Initialize it...
+	* ntpd/ntp_config.c: added nofork.
+	Updated ntp_options.
+	(getstartup): Updated "usage" string.  Deal with -n flag.
+	(getconfig): Ditto.
+	From: Jeffrey Hutzelman 
+
+	* ntpd/ntp_io.c (open_socket): Use ntoa() to print out the address
+	when bind() fails. (in 2 places)
+	Reported by: "Markus W. Fehr" 
+	Only soft-fail if an interface is unavailable.
+	(create_sockets):  Don't SO_REUSEADDR if the interface is unavailable.
+	From: "Markus W. Fehr" 
+
+	* configure.in:  If we --disable-all-clocks, then don't enable
+	parse clocks by default.
+	Reported by: Marion Hakanson 
+
+Sat Aug 22 23:58:14 1998  Frank Kardel  
+
+	* ntpd/refclock_parse.c (local_input): fixed IO handling for non-STREAM IO
+
+Sun Aug 16 20:13:32 1998  Frank Kardel  
+
+	* libntp/ieee754io.c: debug information only compile for LIBDEBUG case
+
+	* ntpd/refclock_parse.c (gps16x_message): reduced UTC parameter information (dropped A0,A1)
+	made uval a local variable (killed one of the last globals)
+	(sendetx): added logging of messages when in debug mode
+	(trimble_check): added periodic checks to facilitate re-initialization
+	(trimbletsip_init): made use of EOL character if in non-kernel operation
+	(trimbletsip_message): extended message interpretation
+	(getdbl): fixed data conversion
+
+	* libparse/parse_conf.c (clockformats): Trimble TSIP driver now also
+	available for kernel operation
+
+	* libparse/info_trimble.c: re-generated
+
+	* libparse/clk_trimtsip.c (cvt_trimtsip): initial kernel capable version (no more floats)
+	(clock_trimtsip =): new format name
+
+	* libparse/clk_trimtaip.c (clock_trimtaip =): changed format name
+
+	* include/trimble.h (CMD_RSTATTRACK): renamed mode 6 variable name
+
+	* scripts/monitoring/ntploopwatch: moved emacs mode selector
+
+Mon Aug 10 15:32:48 1998  Harlan Stenn  
+
+	* ntpd/refclock_acts.c: Patch cleanup
+	* ntpd/ntp_refclock.c: Patch cleanup
+	* ntpd/ntp_timer.c: Patch cleanup
+	From: qli@huey.udel.edu
+
+Wed Jul 29 15:23:21 1998  Harlan Stenn  
+
+	* libntp/machines.c: IRIX needs time.h
+	Reported by: Judith E Bush 
+
+	* ntpd/ntpd.c (service_main): Better AIX PROCLOCK fix.
+	From: Matt Ladendorf  and
+	Grover Davidson 
+
+Wed Jul 29 01:36:48 1998  Harlan Stenn  
+
+	* include/ntpd.h (MAXINTERFACES): Moved here...
+	* ntpd/ntp_io.c: From here...
+	(create_sockets): Only deal with MAXINTERFACES.
+	(create_sockets): Only deal with specified interfaces.
+
+	* ntpd/ntp_config.c (CONFIG_LISTEN): Added
+	Added ifnum and listenaddrs[]
+	(getconfig): Added defn for "addr"
+	(getconfig): Initialize ifnum.
+
+	* ntpd/ntpd.c (service_main): call init_io after getconfig
+	From: Vebjorn Ljosa 
+
+Wed Jul 29 00:42:28 1998  Harlan Stenn  
+
+	* ntpd/refclock_palisade.c: Use NEED_HPUX9_TIOCM_STUFF
+
+	* acconfig.h (NEED_HPUX9_TIOCM_STUFF):  Added.
+
+	* configure.in (REFCLOCK_PALISADE): Needs termio*.h
+	(NEED_HPUX9_TIOCM_STUFF): Added.
+
+	* ntpd/ntp_io.c (create_sockets): Use strchr instead of strstr.
+
+	* libntp/mktime.c: #include 
+
+	* libntp/ieee754io.c: #include 
+
+Wed Jul 29 00:24:22 1998  Harlan Stenn  
+
+	* ntpd/refclock_acts.c (ACTS_MAXPOLL): 14 -> 18.
+	Import current_nextdate
+	(acts_receive): Update peer->nextdate with current_nextdate
+	(acts_poll): Call acts_timeout() (debugging)
+
+	* ntpd/ntp_refclock.c: Export current_nextdate.
+	(refclock_transmit): Check peer->valid >= NTP_SHIFT - 2, not >.
+	(refclock_transmit): hpoll wiggles, update current_nextdate
+
+	* ntpd/ntp_timer.c: #include "ntp_refclock.h"
+	(MODE_MANUAL): Added.
+	(timer): MODE_MANUAL stuff
+
+	From: qli@huey.udel.edu
+
+Tue Jul 28 23:23:15 1998  Harlan Stenn  
+
+	* configure.in: Check for inet_ntoa in -lbind .
+
+	* ntpd/ntpd.c: #undef PROCLOCK for AIX.
+
+Mon Jul 20 01:06:24 1998  Harlan Stenn  
+
+	* configure.in (AC_TYPE_SIZE_T): Added.
+
+Sat Jul 11 09:38:30 1998  Harlan Stenn  
+
+	* configure.in: 4.0.73e
+
+	* ports/winnt/: Replaced with new code (no SHM or PALISADE)
+	From: Greg Schueman 
+
+Fri Jul 10 12:12:59 1998  Harlan Stenn  
+
+	* configure.in: 4.0.73d
+
+	* include/ntp_machine.h (HAVE_SRANDOM): VxWorks patches
+	(HAVE_RANDOM): Ditto.
+	(CALL): Ditto.
+	From: Casey Crellin 
+
+	* ntpd/refclock_parse.c (local_input): Typo.
+	Reported by: Tony Li 
+
+Wed Jul  8 01:49:01 1998  Harlan Stenn  
+
+	* configure.in: 4.0.73c
+
+	* PARSE patches from Frank Kardel
+
+	* libntp/machines.c (ntp_set_tod): Get it right.
+
+Sun Jul  5 22:15:34 1998  Harlan Stenn  
+
+	* configure.in: 4.0.73a
+
+	* kernel/sys/timex.h (MOD_CANSCALE): Add rest of patch to handle
+	scaling.
+	From: Poul-Henning Kamp 
+
+Wed Jun 10 21:16:01 1998  Harlan Stenn  
+
+	* configure.in: 4.0.73
+
+	* ntpd/ntp_loopfilter.c (local_clock): MOD_CANSCALE patches, and
+	be careful with the integration if we're nearly perfect.
+	From: Poul-Henning Kamp 
+
+	* util/tickadj.c (main): Typo fix...
+	From: Marion Hakanson 
+
+	* ntpd/ntp_io.c (create_sockets): Attempt to ignore alias
+	interfaces.
+	From: Kenneth Maupin 
+
+	* ntpd/ntp_refclock.c: PPS fixes
+	* ntpd/refclock_msfees.c (msfees_start): Portability fixes and
+	PPS/STREAM enhancements
+	From: John Hay 
+
+	* ntpd/ntp_refclock.c (refclock_gtlin): Patch...
+	From: Jonathan Stone 
+
+Sun Jun 28 18:43:30 1998  Frank Kardel  
+
+	* libntp/buftvtots.c (buftvtots): using WORD_BIGENDIAN instead of XNTP_BIG_ENDIAN
+
+	* libparse/clk_trimtsip.c (getflt): fixed ENDIAN issue
+	(getdbl): fixed ENDIAN issue
+	(getint): use get_msb_short()
+	(cvt_trimtsip): use gpstolfp() for conversion
+
+	* libntp/Makefile.am (libntp_a_SOURCES): added gpstolfp.c source
+
+	* libntp/binio.c: added {get,put}_msb_{short,long}() functions
+
+	* include/ntp_fp.h: added gpstolfp() prototype
+
+	* include/binio.h: added binio MSB prototypes
+
+Sat Jun 13 13:48:17 1998  Frank Kardel  
+
+	* parseutil/testdcf.c: signed/unsigned
+	SYSV clock name clash fixed
+
+	* parseutil/dcfd.c: signed/unsigned
+	SYSV clock name clash fixed
+	year wrapping at 1998
+	ctype macros take ints as args
+
+	* ntptrace/ntptrace.c (decodeipaddr): ctype macros take ints as args
+
+	* ntpq/ntpq_ops.c (doprintpeers): signed/unsigned
+
+	* ntpq/ntpq.c: ctype macros take ints as args
+	signed/unsigned
+
+	* ntpdc/ntpdc.c: signed/unsigned
+
+	* ntpd/refclock_usno.c: signed/unsigned
+
+	* ntpd/refclock_true.c (true_send): signed/unsigned, name clashes
+
+	* ntpd/refclock_parse.c: signed/unsigned, name clashes
+
+	* ntpd/refclock_nmea.c (nmea_receive): ctype macros take ints as args
+
+	* ntpd/refclock_heath.c (heath_receive): prototypes (signed/unsigned issues)
+
+	* ntpd/refclock_arc.c: prototypes (signed/unsigned issues)
+
+	* ntpd/refclock_acts.c: prototypes (signed/unsigned issues)
+
+	* ntpd/ntpd.c: prototypes (signed/unsigned issues)
+
+	* ntpd/ntp_util.c (getauthkeys): prototypes (signed/unsigned issues)
+	fix SYSV clock name clash
+
+	* ntpd/ntp_request.c: prototypes (signed/unsigned issues)
+	fix SYSV clock name clash
+
+	* ntpd/ntp_io.c (input_handler): variable naming, signed/unsigned
+
+	* ntpd/ntp_intres.c (readconf): signed/unsigned issues
+
+	* ntpd/ntp_control.c: prototypes (signed/unsigned issues)
+	fix SYSV clock name clash
+
+	* ntpd/ntp_config.c: fix SYSV clock name clash
+        ctype macros take ints as args
+
+	* libparse/parsestreams.c: dirt (debug) removed
+
+	* libparse/parsesolaris.c: more prototypes
+	fix name clashes
+	allow for ansi2knr
+
+	* libparse/parse.c: bcopy/memcpy cleanup
+	fix SYSV clock name clash
+
+	* libparse/clk_trimtsip.c (cvt_trimtsip): fix SYSV clock name clash
+
+	* libparse/clk_trimtaip.c (cvt_trimtaip): fix SYSV clock name clash
+
+	* libparse/clk_schmid.c (cvt_schmid): fix SYSV clock name clash
+
+	* libparse/clk_rcc8000.c (cvt_rcc8000): fix SYSV clock name clash
+
+	* libparse/clk_rawdcf.c (cvt_rawdcf): fix SYSV clock name clash
+
+	* libparse/clk_hopf6021.c (cvt_hopf6021): fix SYSV clock name clash
+
+	* libparse/clk_dcf7000.c (cvt_dcf7000): fix SYSV clock name clash
+
+	* libparse/clk_computime.c: fix SYSV clock name clash
+
+	* libntp/octtoint.c (octtoint): ctype macros take ints as args
+
+	* libntp/mstolfp.c (mstolfp): ctype macros take ints as args
+
+	* libntp/hextolfp.c (hextolfp): ctype macros take ints as args
+
+	* libntp/hextoint.c (hextoint): ctype macros take ints as args
+
+	* libntp/decodenetnum.c (decodenetnum): ctype macros take ints as args
+
+	* libntp/atouint.c (atouint): ctype macros take ints as args
+
+	* libntp/atolfp.c (atolfp): ctype macros take ints as args
+
+	* libntp/atoint.c (atoint): ctype macros take ints as args
+
+	* kernel/sys/parsestreams.h:  STREAM macro gone in favor of HAVE_SYS_STREAM_H
+
+	* include/parse.h: STREAM macro gone in favor of HAVE_SYS_STREAM_H
+
+Fri Jun 12 11:08:53 1998  Frank Kardel  
+
+	* ntpd/ntp_timer.c: prototype fixes (ansi2knr/knr compiler)
+
+	* ntpd/ntp_proto.c (make_keylist): type cast for e(!!!)malloc()
+
+	* libparse/Makefile.am: adjust for ansi2knr
+
+	* libntp/ieee754io.c: ansi2knr compatibility
+
+	* include/ntp_refclock.h: added pps_sample() extern declaration
+	added refclock_process_offset() extern declaration
+
+	* include/ntp.h: fixed function * prototypes
+
+	* ntpd/refclock_parse.c (bind): added input routine
+	(local_input): added input routine
+
+	* ntpd/ntp_io.c (input_handler): direct input processing for
+	refclocks to save input recv buffers
+
+	* include/ntp_refclock.h: added int io_input(struct recvbuf *)
+	pointer to allow direct processing of read refclock data in
+	order to save many bug recv buffers on single character input
+	(problem with "fast" machines)
+
+	* parse_conf.c:  conditional compile macros fixed
+
+	* parse.c:  conditional compile macros fixed
+	printf prototype
+
+	* clk_trimtaip.c:  conditional compile macros fixed
+	printf prototype
+
+	* clk_schmid.c:  conditional compile macros fixed
+	printf prototype
+
+	* clk_rcc8000.c:  conditional compile macros fixed
+	printf prototype
+
+	* clk_hopf6021.c:  conditional compile macros fixed
+	printf prototype
+
+	* clk_dcf7000.c: conditional compile macros fixed
+	printf prototype
+
+	* clk_computime.c: conditional compile macros fixed
+	printf prototype
+
+Sat Jun  6 07:41:54 1998  Frank Kardel  
+
+	* ntpd/refclock_palisade.c: fixed termio.h / termios.h inclusion
+
+	* include/ntp_refclock.h: made refclockproc/clockdesc const
+
+	* ntpd/ntp_control.c (ctl_putpeer): avoided ambigous 'else' (gcc)
+
+	* ntpd/refclock_parse.c (parse_start): added BURST mode initialisation
+
+	* scripts/stats/summary.sh (CLOCK): allow for Y2K log files
+
+	* libparse/clk_rawdcf.c: simplified condidional compile expression
+
+Wed May 27 08:10:43 1998  Frank Kardel  
+
+	* include/Makefile.am (noinst_HEADERS): added new header files
+	mbg_gps166.h binio.h ascii.h ieee754io.h
+
+	* ntpdc/ntpdc.c (sendrequest): fixed info_auth_keyid setting it
+	got accidentally trashed every other round
+
+Mon May 25 22:55:07 1998  Frank Kardel  
+
+	* configure.in: PARSE clocks are enabled by default whenever
+	possible (termio.h or termios.h present)
+	removed RAWDCF_SETDTR feature
+
+	* acconfig.h: removed RAWDCF_SETDTR option (now implicit by
+	compilation and run time configuration)
+
+	* ntpd/refclock_parse.c (rawdcf_init): offer a RAWDCF clock (type 14)
+	that attempts to set the DTR modem line for receiver power
+
+	* libparse/clk_meinberg.c (cvt_meinberg): support current standard
+	Meinberg data formats
+
+Sun May 24 09:43:19 1998  Frank Kardel  
+
+	* libparse/clk_rawdcf.c (pps_rawdcf): trigger pps on zero going
+	edge - that is simpler wiring (Rx->DCD).
+
+	* parseutil/testdcf.c (wday): const keyword
+
+	* parseutil/dcfd.c (cvt_rawdcf): sign issues and calling interfaces
+
+	* ntpq/ntpq.c (MAXVARLEN): adjusted internal buffer length for
+	variable values
+
+	* ntpd/refclock_parse.c: adjust to new io handling (fixed formats
+	only)
+	(mkreadable): don't include >"< in readable ASCII output (-> ntpq
+	parsing)
+	output debug messages to stdout instead of msyslog()
+	fixed version information string
+
+	* ntpd/refclock_atom.c (pps_sample): new auxiliary pps interface
+
+	* libparse/parsestreams.c (parserput): get event status consistent
+	with direct calls
+	(zs_xsisr): simulate CARRIER status to avoid unnecessary M_xHANGUP
+	events
+
+	* libparse/parsesolaris.c (parserput): get event status consistent
+	with direct calls
+	(zs_xsisr): simulate CARRIER status to avoid unnecessary M_xHANGUP
+	events
+
+	* libparse/parse.c: removed old input cruft
+	(parse_restart): new generic input help function
+	(parse_addchar): ditto
+	(parse_end): ditto
+	(pps_one): new generic pps help function
+	(pps_zero): ditto
+
+	* libparse/clk_trimtsip.c (clock_trimtsip =): new input handling
+
+	* libparse/clk_trimtaip.c (clock_trimtaip =): new input handling
+	(inp_trimtaip): new input handler
+
+	* libparse/clk_schmid.c (clock_schmid =): new input handling
+	(inp_schmid): new input handler
+
+	* libparse/clk_rcc8000.c (clock_rcc8000 =): new input handling
+	(inp_rcc8000): new input handler
+
+	* libparse/clk_rawdcf.c (clock_rawdcf =): new input handling
+	(snt_rawdcf): adjusted to new input handling
+	(inp_rawdcf): new input handler
+
+	* libparse/clk_meinberg.c (clock_meinberg): new input handling
+	(gps_input): new input handler
+	(mbg_input): new input handler
+
+	* libparse/clk_hopf6021.c (clock_hopf6021 =): new input handling
+	(inp_hopf6021): new input handler
+
+	* libparse/clk_dcf7000.c (clock_dcf7000 =): new input handling
+	(inp_dcf7000): new input handler
+
+	* libparse/clk_computime.c (clock_computime =): new input handling
+	(inp_computime): new input handler
+
+	* libparse/Makefile.am: link kernel module with libntp.a
+
+	* include/parse.h (struct parse): removed old data structure cruft
+	(new input model) new PARSE_INP* macros for input handling
+	removed old SYNC_* macros from old input model
+	(struct clockformat): removed old parse functions in favor of the
+	new input model
+	updated prototypes
+
+	* include/ntp_refclock.h: prototype for refclock_atom pps_sample()
+	interface
+
+	* acconfig.h: added PPS_SAMPLE define
+	* configure.in (LIBPARSE): added PPS_SAMPLE configuration
+	
+
+	* libntp/systime.c (adj_systime): debug output (> level 6) for
+	adjtime results
+
+	* libntp/mfp_mul.c (mfp_mul): controlled debug output
+
+	* libntp/ieee754io.c (get_byte): controlled debug output
+	(fetch_ieee754): ditto
+	(put_ieee754): ditto
+
+Tue May  5 20:09:51 1998  Harlan Stenn  
+
+	* configure.in: document DES is not usually present.
+
+Wed Apr 29 22:00:22 1998  Harlan Stenn  
+
+	* configure.in: 4.0.72h
+
+	* authstuff/Makefile.am (check-local-rsn): check-local doesn't
+	work with RSAREF...
+	Reported by: "Auteria Wally Winzer Jr." 
+
+	* libntp/machines.c: the settime() choices were ordered badly.
+	Reported by: Michael Joosten 
+
+Sat Apr 25 00:35:53 1998  Harlan Stenn  
+
+	* configure.in (ac_cv_var_no_parenb_ignpar): Undo the kernel PLL
+	block I just installed - Dave wants to control this via
+	KERNEL_FLL_BUG.
+
+Fri Apr 24 20:35:57 1998  Harlan Stenn  
+
+	* libntp/Makefile.am (libntp_a_DEPENDENCIES): Set per libntp_a_LIBADD
+
+	* configure.in: Do a better job of blocking kernel PLL under
+	solaris2.6.
+
+Fri Apr 24 00:41:12 1998  Harlan Stenn  
+
+	* configure.in: 4.0.72f
+	(ac_cv_struct_nlist_n_un): Don't look for ntp_adjtime or
+	ntp_gettime under solaris2.6.
+
+	* ntpd/ntp_proto.c (process_packet): Give verbose error messages
+
+	* include/global.h (PROTOTYPES): Drive via HAVE_PROTOTYPES.
+
+Wed Apr 22 16:55:55 1998  Harlan Stenn  
+
+	* configure.in (ac_cv_var_use_des): Added. 4.0.72e.
+	* libntp/Makefile.am (libntp_a_LIBADD): Added DESOBJS
+
+Tue Apr 21 02:08:06 1998  Harlan Stenn  
+
+	* ntpd/refclock_arc.c (arc_receive): Typo...
+	From: Sam Steingold 
+
+Fri Apr 10 03:05:35 1998  Harlan Stenn  
+
+	* configure.in (ac_refclock_chu): AUDIO_CHU support.  Disabled by
+	default, and currently only supported on SunOS and Solaris.
+	* acconfig.h: AUDIO_CHU
+
+Wed Apr  8 19:53:53 1998  Harlan Stenn  
+
+	* libntp/Makefile.am (EXTRA_DIST): Added mktime.c
+
+	* configure.in:  AC_REPLACE_FUNCS(mktime).
+	(--enable-dst-minutes=60): Added, for (missing) mktime().
+
+	* ntpd/refclock_heath.c (heath_receive): Use mktime() instead of
+	the old hack.
+
+Tue Apr  7 21:15:14 1998  Harlan Stenn  
+
+	* configure.in (LIBOBJS): Hack it before AC_OUTPUT to deal with
+	ANSI2KNR-filtering rules.
+	From: Jim Meyering 
+
+Mon Apr  6 01:40:45 1998  Harlan Stenn  
+
+	* libntp/strerror.c: ANSIfy strerror's definition.
+
+Thu Mar 12 20:24:45 1998  Harlan Stenn  
+
+	* libntp/statestr.c: Only #include  if HAVE_CONFIG_H is
+	#define'd.
+	From: Sven Dietrich 
+
+Wed Mar 11 00:27:32 1998  Harlan Stenn  
+
+	* configure.in: Cygwin needs to check for the advapi32 library.
+	NT doesn't support a root user, so don't bother with getuid().
+	Also, don't bother with umask().
+
+	* ntpd/ntp_io.c: cygwin32 patches
+	* ntpd/ntp_proto.c: Ditto.
+	* ntpd/ntpd.c: Ditto.
+	* ntpd/ntp_timer.c: Ditto.
+	* ntpdate/ntpdate.c: Ditto.
+	* libntp/machines.c: Ditto.
+	* libntp/systime.c: Ditto.
+	* include/ntp_machine.h: Ditto.
+	* include/ntp_unixtime.h: Ditto.
+	From: Sven Dietrich 
+
+Tue Mar 10 22:26:14 1998  Harlan Stenn  
+
+	* configure.in (ac_cv_make_tickadj): Added.
+	Now that tickadj is the only(?) utility that cares about tick and
+	tickadj, we don't need to have NOKMEM and no PRESET_* be fatal.
+
+Sat Mar  7 02:57:17 1998  Harlan Stenn  
+
+	* ntpd/ntp_loopfilter.c (local_clock): Patch STA_FLL check
+	From: Poul-Henning Kamp 
+
+	* various: Renamed ACTS to CLOCK_ACTS, ARBITER to CLOCK_ARBITER,
+	ARCRON_MSF to CLOCK_ARCRON_MSF, AS2201 to CLOCK_AS2201, BANC to
+	CLOCK_BANC, DATUM to CLOCK_DATUM, GPSVME to CLOCK_GPSVME, HEATH to
+	CLOCK_HEATH, HPGPS to CLOCK_HPGPS, IRIG to CLOCK_IRIG, JUPITER to
+	CLOCK_JUPITER, LEITCH to CLOCK_LEITCH, MSFEES to CLOCK_MSFEES,
+	MX4200 to CLOCK_MX4200, NMEA to CLOCK_NMEA, PALISADE to
+	CLOCK_PALISADE, PARSE to CLOCK_PARSE, PPS720 to CLOCK_PPS720, PST
+	to CLOCK_PST, PTBACTS to CLOCK_PTBACTS, SHM_CLOCK to CLOCK_SHM,
+	ONCORE to CLOCK_ONCORE, TPRO to CLOCK_TPRO, TRAK to CLOCK_TRAK,
+	TRUETIME to CLOCK_TRUETIME, USNO to CLOCK_USNO, WWVB to CLOCK_WWVB
+
+	* Makefile.am (ETAGS_ARGS): Added acconfig.h
+
+	* various: Renamed LOCAL_CLOCK to CLOCK_LOCAL.
+
+	* configure.in: First cut at  *-pc-cygwin32 support
+	Requested by: Sven Dietrich 
+
+	* configure.in: gdt-surveying code is gone.  Sigh.
+	Reported by: Poul-Henning Kamp 
+
+Wed Mar  4 21:41:06 1998  Harlan Stenn  
+
+	* many places: Renamed ATOM to CLOCK_ATOM
+
+Tue Mar  3 03:18:13 1998  Harlan Stenn  
+
+	* ntpd/ntp_timer.c (timer): Only call refclock_transmit if
+	REFCLOCK is #define'd.
+	Reported by a bunch of folks.
+
+Mon Mar  2 03:46:07 1998  Harlan Stenn  
+
+	* configure.in (ntp_refclock): Use CLOCK_CHU, which no longer
+	needs any special headers.
+	* ntpd/refclock_chu.c: Call it CLOCK_CHU
+	(chu_receive): Define it correctly.
+
+	* include/winnt/sys/time.h (gettimeofday): Prototypes are OK.
+	(settimeofday): Prototypes are OK.
+	From: JJEVNISEK@qgraph.com
+
+	* ntpq/ntpq_ops.c: varlist name and value aren't const.
+	* ntpdc/ntpdc_ops.c (fudge): The flags are u_val, not val.
+	* ntpdc/ntpdc.c: const cleanup, exit cleanup.
+	* ntpd/refclock_wwvb.c (wwvb_receive): Move the definition of tz
+	somewhere more normal.
+	* ntpd/ntp_request.c (do_trustkey): kp gets u_long data, not
+	u_int32 (but Harlan thinks this patch may be wrong).
+	* ntpd/ntp_refclock.c (refclock_process): clocktime needs
+	offset.l_ui, not offset.l_i .
+	* ntpd/ntp_control.c (set_var): t isn't const.
+	* libntp/a_md5encrypt.c (session_key): Cast 2nd arg to MD5auth_setkey.
+	* include/ntpd.h: ctl_var's text field isn't const.
+	* include/ntp_refclock.h: clockdesc isn't const.
+	From: Marc Brett 
+
+	* ntpd/ntp_loopfilter.c (local_clock): Limit ntv.constant to
+	MAXTC, and log error returns from ntp_adjtime.
+	From: Juha Sarlin 
+
+Mon Mar  2 03:05:23 1998  Harlan Stenn  
+
+	* configure.in (ac_cv_var_kernel_fll_bug): KERNEL_FLL_BUG
+	* acconfig.h: KERNEL_FLL_BUG: added.
+	* ntpd/ntp_loopfilter.c (local_clock): Only avoid STA_FLL if
+	KERNEL_FLL_BUG is #define'd (Solaris2.6)
+
+Sat Feb 21 00:45:10 1998  Harlan Stenn  
+
+	* automake-1.2d.patches: Added ansi2knr.o rules.
+
+	* ntpd/refclock_tpro.c: P() stuff
+
+Fri Feb 20 20:10:20 1998  Harlan Stenn  
+
+	* configure.in: Improve the ${CC} -pipe test (cygwin-32's gcc -pipe
+	silently does nothing).
+	Reported by: Sven Dietrich 
+
+Wed Feb 18 00:51:08 1998  Harlan Stenn  
+
+* configure.in: 4.0.72 released.
+
+* configure.in:AC_REPLACE_FUNCS(strerror), check for poll.h, and deal
+  with the --enable-JUPITER stuff.
+* libntp/Makefile.am (libntp_a_LIBADD): Added (for strerror support).
+* libntp/clocktypes.c: Added REFCLK_GPS_JUPITER.
+* ntpdate/ntpdate.c: poll() support
+* ntpd/Makefile.am: Add refclock_jupiter.c
+* ntpd/refclock_conf.c: Added refclock_jupiter
+* ntpd/refclock_mx4200.c (mx4200_pps): Bugfixes.
+* include/ntp.h (REFCLK_GPS_JUPITER): Added, and bumped REFCLK_MAX.
+  From: Craig Leres 
+
+Mon Feb 16 21:02:42 1998  Harlan Stenn  
+
+	* ntpd/ntp_proto.c: P()
+
+Mon Feb 16 12:43:11 1998  Harlan Stenn  
+
+* include/ntp_types.h: Added P() prototyping hack back in.
+* include/parse.h: Ditto.
+* include/ntpd.h:  Ditto.
+* include/ntp_unixtime.h:  Ditto.
+* include/ntp_stdlib.h: Ditto.
+* include/ntp_select.h: Ditto.
+* include/ntp_refclock.h: Ditto.
+* include/ntp_fp.h: Ditto.
+* include/md5.h: Ditto.
+* include/ntp_filegen.h: Ditto.
+* include/ntp_calendar.h: Ditto.
+* include/l_stdlib.h: Ditto.
+
+	* configure.in (ACTS): Sometimes, TIOCMBIS is in sys/ioctl.h
+	  Reported by Kenneth Jaldehag 
+	* configure.in (HEATH): Ditto.
+	* configure.in (PTBACTS): Ditto.
+	* configure.in (USNO): Ditto.
+
+Sat Feb 14 00:02:14 1998  Harlan Stenn  
+
+	* ntpd/refclock_irig.c (irig_rf): Rename sincos[] to sin_cos[].
+
+Fri Feb 13 22:22:08 1998  Harlan Stenn  
+
+	* include/ntp.h (RANDPOLL): Use random or mrand48.
+	* ntpd/ntp_config.c (do_resolve_internal): Ditto.
+	* ntpd/ntp_peer.c (unpeer): Ditto.
+	* ntpd/ntp_proto.c (make_keylist): Ditto.
+
+	* ntpd/ntpd.c (xntpdmain): Use srandom or srand48.
+
+	* configure.in: Look for {s,}random() and [ms]rand48().
+
+Wed Feb 11 22:50:24 1998  Harlan Stenn  
+
+	* ntpd/ntp_restrict.c (hack_restrict): Renamed restrict()
+	* include/ntpd.h: Ditto
+	* ntpd/ntp_request.c (do_restrict): Ditto
+	* ntpd/ntp_config.c (getconfig):
+	* ntpd/ntp_io.c (create_sockets): Ditto.
+
+1998-01-23  Harlan Stenn  
+
+	* ntpd/refclock_irig.c: Allow either  or
+	 .  From Dave Mills.
+
+	* configure.in: Under SunOS, it's sun/audioio.h .
+
+1998-01-22  Harlan Stenn  
+
+	* html/driver6.html: Updated header file info
+	* html/irig.html: Ditto.
+	* configure.in: sys/bsd_audioirig.h replaced with sys/audioio.h
+	for new irig driver that Dave installed.
+
+1998-01-08  Harlan Stenn  
+
+	* Many places: Lose the P(()) prototype stuff
+
+	* util/tickadj.c (writevar): Make offset an off_t
+	(readvar): Ditto
+	(getoffsets): Make offsets off_t
+
+	* adjtimed/adjtimed.c (GetClockRate): Fix lseek arg 2.
+	(SetClockRate): Ditto
+
+	* Many things in many places from many people.
+
+	* configure.in: Added AC_TYPE_OFF_T
+
+1997-11-26  Harlan Stenn  
+
+	* ntpd/refclock_palisade.c: ANSIfied.
+
+Wed Sep  3 23:51:44 1997  Harlan Stenn  
+
+	* configure.in (AM_C_PROTOTYPES): Added.
+
+	* Makefile.am (AUTOMAKE_OPTIONS): Added ansi2knr.
+
diff --git a/contrib/ntp/INSTALL b/contrib/ntp/INSTALL
new file mode 100644
index 000000000000..0c73fefed39b
--- /dev/null
+++ b/contrib/ntp/INSTALL
@@ -0,0 +1,178 @@
+Basic Installation
+==================
+
+   These are generic *nix installation instructions.
+
+   For Windows/NT, please see ports/winnt.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes a while.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/contrib/ntp/Makefile.am b/contrib/ntp/Makefile.am
new file mode 100644
index 000000000000..53a77603c54c
--- /dev/null
+++ b/contrib/ntp/Makefile.am
@@ -0,0 +1,95 @@
+#AUTOMAKE_OPTIONS = foreign dist-tarZ #distdir=$(PACKAGE)$(VERSION)
+#AUTOMAKE_OPTIONS = util/ansi2knr foreign dist-tarZ no-dependencies
+AUTOMAKE_OPTIONS = util/ansi2knr foreign dist-tarZ
+
+SUBDIRS = \
+	scripts \
+	include \
+	libntp	\
+	libparse	\
+	librsaref	\
+	ntpd	\
+	ntpdate	\
+	ntpdc	\
+	ntpq	\
+	ntptrace	\
+	parseutil	\
+	adjtimed	\
+	clockstuff	\
+	kernel	\
+	util
+
+EXTRA_DIST = ChangeLog COPYRIGHT NEWS README.cvs README.des README.hackers TODO WHERE-TO-START acconfig.h config.guess config.h.in config.sub excludes install-sh dot.emacs build NOTES.y2kfixes readme.y2kfixes results.y2kfixes
+#ETAGS_ARGS = $(srcdir)/Makefile.am $(srcdir)/configure.in
+ETAGS_ARGS = Makefile.am configure.in acconfig.h
+
+# DIST_CPDIRS = conf html scripts 
+# DIST_MKDIRS = adjtime clockstuff kernel libparse ppsclock
+#DIST_HOOK_DIRS = conf html patches ports scripts
+# HMS: make ports be the last directory...
+DIST_HOOK_DIRS = conf html scripts ports
+
+BUILT_SOURCES = $(srcdir)/COPYRIGHT
+
+$(srcdir)/COPYRIGHT: html/copyright.htm
+	( echo "This file is automatically generated from html/copyright.htm" ; lynx -dump $(srcdir)/html/copyright.htm ) > $(srcdir)/COPYRIGHT.new && mv $(srcdir)/COPYRIGHT.new $(srcdir)/COPYRIGHT
+
+# local-dist: dist-tarZ
+
+dist-hook:
+	-for i in $(DIST_HOOK_DIRS); do \
+	  mkdir $(distdir)/$$i ; \
+	  cp -rp $(srcdir)/$$i $(distdir) ; \
+	done ; \
+	find $(distdir) -type d -name CVS -exec rm -rf '{}' \; ; \
+	# find $(distdir)/html -name '*.htm' -exec dos2unix {} {} \; ; \
+	# cp -rp $(srcdir)/include/winnt $(distdir)/include
+
+dist-export: distdir
+	rm $(distdir)/libntp/authdes.c
+	cp $(distdir)/libntp/authdes.c.export $(distdir)/libntp/authdes.c
+	chmod -R a+r $(distdir)
+	mv $(distdir) $(distdir)-export
+	$(TAR) chozf $(distdir)-export.tar.gz $(distdir)-export
+	rm -rf $(distdir)-export
+
+Makefile: .warning
+
+CVO=`$(srcdir)/config.guess`
+
+.buildcvo:
+	echo "$(CVO)" > .buildcvo
+
+.checkcvo: .buildcvo FRC.checkcvo
+	@if [ "`cat .buildcvo`" != "$(CVO)" ];then	\
+		echo "This directory was configured for `cat .buildcvo`"; \
+		echo "but this machine is a $(CVO)";	\
+		exit 1;	\
+	fi
+
+BHOST=`(hostname || uname -n)`
+
+.buildhost:
+	echo "$(BHOST)" > .buildhost
+
+.checkhost: .buildhost FRC.checkhost
+	@if [ "`cat .buildhost`" != "$(BHOST)" ];then	\
+		echo "Built on `cat .buildhost` but this is $(BHOST)"; \
+		echo " "; \
+	fi
+
+.warning:
+	@echo "Compiling with GCC now generates lots of new warnings."
+	@echo " "
+	@echo "Don't be concerned. They're just warnings."
+	@echo " "
+	@echo "Don't send bug reports about the warnings, either."
+	@echo " "
+	@echo "Feel free to send patches that fix these warnings, though."
+	@echo " "
+	@sleep 1
+	@touch .warning
+
+FRC.distwarn FRC.checkcvo FRC.checkhost:
+
+dot.emacs: FRC.distwarn
diff --git a/contrib/ntp/Makefile.in b/contrib/ntp/Makefile.in
new file mode 100644
index 000000000000..c8a8d7f880d3
--- /dev/null
+++ b/contrib/ntp/Makefile.in
@@ -0,0 +1,490 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+AMTAR = @AMTAR@
+AMTARFLAGS = @AMTARFLAGS@
+AWK = @AWK@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CHUTEST = @CHUTEST@
+CLKTEST = @CLKTEST@
+CPP = @CPP@
+DCFD = @DCFD@
+LDFLAGS = @LDFLAGS@
+LIBPARSE = @LIBPARSE@
+LIBRSAREF = @LIBRSAREF@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+MAKE_ADJTIMED = @MAKE_ADJTIMED@
+MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@
+MAKE_LIBPARSE = @MAKE_LIBPARSE@
+MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@
+MAKE_LIBRSAREF = @MAKE_LIBRSAREF@
+MAKE_NTPTIME = @MAKE_NTPTIME@
+MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@
+MAKE_TICKADJ = @MAKE_TICKADJ@
+PACKAGE = @PACKAGE@
+PATH_SH = @PATH_SH@
+PROPDELAY = @PROPDELAY@
+RANLIB = @RANLIB@
+RSAREF = @RSAREF@
+TESTDCF = @TESTDCF@
+U = @U@
+VERSION = @VERSION@
+
+#AUTOMAKE_OPTIONS = foreign dist-tarZ #distdir=$(PACKAGE)$(VERSION)
+#AUTOMAKE_OPTIONS = util/ansi2knr foreign dist-tarZ no-dependencies
+
+
+AUTOMAKE_OPTIONS = util/ansi2knr foreign dist-tarZ
+
+SUBDIRS = \
+	scripts \
+	include \
+	libntp	\
+	libparse	\
+	librsaref	\
+	ntpd	\
+	ntpdate	\
+	ntpdc	\
+	ntpq	\
+	ntptrace	\
+	parseutil	\
+	adjtimed	\
+	clockstuff	\
+	kernel	\
+	util
+
+
+EXTRA_DIST = ChangeLog COPYRIGHT NEWS README.cvs README.des README.hackers TODO WHERE-TO-START acconfig.h config.guess config.h.in config.sub excludes install-sh dot.emacs build NOTES.y2kfixes readme.y2kfixes results.y2kfixes
+#ETAGS_ARGS = $(srcdir)/Makefile.am $(srcdir)/configure.in
+ETAGS_ARGS = Makefile.am configure.in acconfig.h
+
+# DIST_CPDIRS = conf html scripts 
+# DIST_MKDIRS = adjtime clockstuff kernel libparse ppsclock
+#DIST_HOOK_DIRS = conf html patches ports scripts
+# HMS: make ports be the last directory...
+DIST_HOOK_DIRS = conf html scripts ports
+
+BUILT_SOURCES = $(srcdir)/COPYRIGHT
+
+CVO = `$(srcdir)/config.guess`
+
+BHOST = `(hostname || uname -n)`
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = 
+DIST_SOURCES = 
+DIST_COMMON =  README ./stamp-h.in ChangeLog INSTALL Makefile.am \
+Makefile.in NEWS TODO acconfig.h aclocal.m4 config.guess config.h.in \
+config.sub configure configure.in install-sh missing mkinstalldirs
+
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4):  configure.in 
+	cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+	cd $(srcdir) && $(AUTOCONF)
+
+config.h: stamp-h
+	@if test ! -f $@; then \
+		rm -f stamp-h; \
+		$(MAKE) stamp-h; \
+	else :; fi
+stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h stamp-hT
+	@echo timestamp > stamp-hT 2> /dev/null
+	cd $(top_builddir) \
+	  && CONFIG_FILES= CONFIG_HEADERS=config.h \
+	     $(SHELL) ./config.status
+	@mv stamp-hT stamp-h
+$(srcdir)/config.h.in: $(srcdir)/./stamp-h.in
+	@if test ! -f $@; then \
+		rm -f $(srcdir)/./stamp-h.in; \
+		$(MAKE) $(srcdir)/./stamp-h.in; \
+	else :; fi
+$(srcdir)/./stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h
+	@rm -f $(srcdir)/./stamp-h.in $(srcdir)/./stamp-h.inT
+	@echo timestamp > $(srcdir)/./stamp-h.inT 2> /dev/null
+	cd $(top_srcdir) && $(AUTOHEADER)
+	@mv $(srcdir)/./stamp-h.inT $(srcdir)/./stamp-h.in
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+	-rm -f config.h
+
+maintainer-clean-hdr:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive  \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+	  rev="$$subdir $$rev"; \
+	  if test "$$subdir" = "."; then dot_seen=yes; else :; fi; \
+	done; \
+	test "$$dot_seen" = "no" && rev=". $$rev"; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  ${AWK:-awk} '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+   if test "$$subdir" = .; then :; else \
+	    test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+   fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  ${AWK:-awk} '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	-rm -rf $(distdir)
+	GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf -
+	mkdir $(distdir)/=build
+	mkdir $(distdir)/=inst
+	dc_install_base=`cd $(distdir)/=inst && pwd`; \
+	cd $(distdir)/=build \
+	  && ../configure --srcdir=.. --prefix=$$dc_install_base \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist
+	-rm -rf $(distdir)
+	@banner="$(distdir).tar.gz is ready for distribution"; \
+	dashes=`echo "$$banner" | sed s/./=/g`; \
+	echo "$$dashes"; \
+	echo "$$banner"; \
+	echo "$$dashes"
+dist: distdir
+	-chmod -R a+r $(distdir)
+	$(AMTAR) ch$(AMTARFLAGS)f - $(distdir) | GZIP=$(GZIP_ENV) gzip -c > $(distdir).tar.gz
+	-rm -rf $(distdir)
+dist-tarZ: distdir
+	-chmod -R a+r $(distdir)
+	$(AMTAR) ch$(AMTARFLAGS)f - $(distdir) | compress -c > $(distdir).tar.Z
+	-rm -rf $(distdir)
+dist-all: distdir
+	-chmod -R a+r $(distdir)
+	$(AMTAR) ch$(AMTARFLAGS)f - $(distdir) | GZIP=$(GZIP_ENV) gzip -c > $(distdir).tar.gz
+	$(AMTAR) ch$(AMTARFLAGS)f - $(distdir) | compress -c > $(distdir).tar.Z
+	-rm -rf $(distdir)
+distdir: $(DISTFILES)
+	-rm -rf $(distdir)
+	mkdir $(distdir)
+	-chmod 777 $(distdir)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$d/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+	for subdir in $(SUBDIRS); do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d $(distdir)/$$subdir \
+	    || mkdir $(distdir)/$$subdir \
+	    || exit 1; \
+	    chmod 777 $(distdir)/$$subdir; \
+	    (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	$(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+all-recursive-am: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+install-exec-am:
+install-exec: install-exec-recursive
+
+install-data-am:
+install-data: install-data-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am:
+uninstall: uninstall-recursive
+all-am: Makefile config.h
+all-redirect: all-recursive-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean-am:  mostlyclean-hdr mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am:  clean-hdr clean-tags clean-generic mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am:  distclean-hdr distclean-tags distclean-generic clean-am
+
+distclean: distclean-recursive
+	-rm -f config.status
+
+maintainer-clean-am:  maintainer-clean-hdr maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f config.status
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+install-recursive uninstall-recursive install-data-recursive \
+uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck all-recursive-am \
+install-exec-am install-exec install-data-am install-data install-am \
+install uninstall-am uninstall all-redirect all-am all install-strip \
+installdirs-am installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+$(srcdir)/COPYRIGHT: html/copyright.htm
+	( echo "This file is automatically generated from html/copyright.htm" ; lynx -dump $(srcdir)/html/copyright.htm ) > $(srcdir)/COPYRIGHT.new && mv $(srcdir)/COPYRIGHT.new $(srcdir)/COPYRIGHT
+
+# local-dist: dist-tarZ
+
+dist-hook:
+	-for i in $(DIST_HOOK_DIRS); do \
+	  mkdir $(distdir)/$$i ; \
+	  cp -rp $(srcdir)/$$i $(distdir) ; \
+	done ; \
+	find $(distdir) -type d -name CVS -exec rm -rf '{}' \; ; \
+	# find $(distdir)/html -name '*.htm' -exec dos2unix {} {} \; ; \
+	# cp -rp $(srcdir)/include/winnt $(distdir)/include
+
+dist-export: distdir
+	rm $(distdir)/libntp/authdes.c
+	cp $(distdir)/libntp/authdes.c.export $(distdir)/libntp/authdes.c
+	chmod -R a+r $(distdir)
+	mv $(distdir) $(distdir)-export
+	$(TAR) chozf $(distdir)-export.tar.gz $(distdir)-export
+	rm -rf $(distdir)-export
+
+Makefile: .warning
+
+.buildcvo:
+	echo "$(CVO)" > .buildcvo
+
+.checkcvo: .buildcvo FRC.checkcvo
+	@if [ "`cat .buildcvo`" != "$(CVO)" ];then	\
+		echo "This directory was configured for `cat .buildcvo`"; \
+		echo "but this machine is a $(CVO)";	\
+		exit 1;	\
+	fi
+
+.buildhost:
+	echo "$(BHOST)" > .buildhost
+
+.checkhost: .buildhost FRC.checkhost
+	@if [ "`cat .buildhost`" != "$(BHOST)" ];then	\
+		echo "Built on `cat .buildhost` but this is $(BHOST)"; \
+		echo " "; \
+	fi
+
+.warning:
+	@echo "Compiling with GCC now generates lots of new warnings."
+	@echo " "
+	@echo "Don't be concerned. They're just warnings."
+	@echo " "
+	@echo "Don't send bug reports about the warnings, either."
+	@echo " "
+	@echo "Feel free to send patches that fix these warnings, though."
+	@echo " "
+	@sleep 1
+	@touch .warning
+
+FRC.distwarn FRC.checkcvo FRC.checkhost:
+
+dot.emacs: FRC.distwarn
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/contrib/ntp/NEWS b/contrib/ntp/NEWS
new file mode 100644
index 000000000000..8fee9b0adb7d
--- /dev/null
+++ b/contrib/ntp/NEWS
@@ -0,0 +1,83 @@
+(4.0.98)
+* Solaris kernel FLL bug is fixed in 106541-07
+* Bug/lint cleanup
+* PPS cleanup
+* ReliantUNIX patches
+* NetInfo support
+* Ultralink driver
+* Trimble OEM Ace-II support
+* DCF77 power choices
+* Oncore improvements
+(4.0.97)
+* NT patches
+* AIX,SunOS,IRIX portability
+* NeXT portability
+* ntptimeset utility added
+* cygwin portability patches
+(4.0.96)
+* -lnsl, -lsocket, -lgen configuration patches
+* Y2K patches from AT&T
+* Linux portability cruft
+(4.0.95)
+* NT port cleanup/replacement
+* a few portability fixes
+* VARITEXT Parse clock added
+(4.0.94)
+* PPS updates (including ntp.config options)
+* Lose the old DES stuff in favor of the (optional) RSAREF stuff
+* html cleanup/updates
+* numerous drivers cleaned up
+* numerous portability patches and code cleanup
+(4.0.93)
+* Oncore refclock needs PPS or one of two ioctls.
+* Don't make ntptime under Linux.  It doesn't compile for too many folks.
+* Autokey cleanup
+* ReliantUnix patches
+* html cleanup
+* tickadj cleanup
+* PARSE cleanup
+* IRIX -n32 cleanup
+* byte order cleanup
+* ntptrace improvements and patches
+* ntpdc improvements and patches
+* PPS cleanup
+* mx4200 cleanup
+* New clock state machine
+* SCO cleanup
+* Skip alias interfaces
+(4.0.92)
+* chronolog and dumbclock refclocks
+* SCO updates
+* Cleanup/bugfixes
+* Y2K patches
+* Updated palisade driver
+* Plug memory leak
+* wharton kernel clock
+* Oncore clock upgrades
+* NMEA clock improvements
+* PPS improvements
+* AIX portability patches
+(4.0.91)
+* New ONCORE driver
+* New MX4200 driver
+* Palisade improvements
+* config file bugfixes and problem reporting
+* autoconf upgrade and cleanup
+* HP-UX, IRIX lint cleanup
+* AIX portability patches
+* NT cleanup
+(4.0.90)
+* Nanoseconds
+* New palisade driver
+* New Oncore driver
+(4.0.73)
+* README.hackers added
+* PARSE driver is working again
+* Solaris 2.6 has nasty kernel bugs.  DO NOT enable pll!
+* DES is out of the distribution.
+(4.0.72)
+* K&R C compiling should work again.
+* IRIG patches.
+* MX4200 driver patches.
+* Jupiter driver added.
+* Palisade driver added.  Needs work (ANSI, ntoh/hton, sizeof double, ???)
diff --git a/contrib/ntp/NOTES.y2kfixes b/contrib/ntp/NOTES.y2kfixes
new file mode 100644
index 000000000000..cf181c1377f1
--- /dev/null
+++ b/contrib/ntp/NOTES.y2kfixes
@@ -0,0 +1,107 @@
+Name of the Application: xntp
+
+Version Number:  4.0.91
+
+Download Size: 4541953 bytes
+
+Downloaded from: http://www.eecis.udel.edu/~ntp/
+
+Operating Systems Supported: many
+
+Operating Systems Tested: unix
+
+Testing
+
+Dates tested (CPU clock set)
+
+	1999-12-31
+	2000-01-01
+	2000-02-29
+
+	Critical fragments of code tested with other dates by special
+	algorithms.
+
+Hardware Platform: Sun Sparc
+
+OS: Solaris 2.6
+
+Compiler: gcc
+
+Version: 2.8.1
+
+Repairs:  9
+
+No. of files Repaired: 13
+
+
+Compilation of Patches Required: yes
+
+Results Description:
+
+1)	Tested suspicious code.
+
+2)	Repaired problem code and added documentation to ntp.h.
+
+3)	Verified ntpd works on critical Y2K dates.
+
+
+Comments:
+
+1)	Errors were found in improper use of tm_year within struct tm,
+	calculations that did not support year 2000 as a leap year
+	(it truly is, despite any unchanged comments remaining in 
+	the NTP source), and some incorrect date calculations, while
+	not traditional Y2K errors, would break in the year 2000.
+
+2)	include/ntpd.h
+    	Added some definitions and documentation about the right way
+        of doing things.  Definitions used by most, if not all, of
+        the Y2K repairs.
+
+Cautions:
+
+1)	Some of the Y2K repairs were to reference clock drivers that
+	we did not have the local hardware to test.  While I believe
+	the changes are sound, they really need to be tested.
+	This includes:
+
+		refclock_arc.c
+		refclock_heath.c
+		refclock_hpgps.c
+
+	Also, parseutil/dcfd.c is another hardware dependent module that
+	was repaired without live testing.
+
+Non-Y2K Problems Observed:
+
+1)	Inconsistent casts of variables containing time values may
+	make expansion to 64 bit integer values in a portable manner
+	difficult.
+
+2)	libntp/caltontp.c:
+        Has logic I believe will fail starting in year 2100 or so.
+        Left unchanged/untested as it works well beyond basic NTP 2036 
+	limit checked by check_y2k.c.
+        If NTP is implemented on 64-bit machines, this should be fixed
+
+3)	ntpd/refclock_acts.c:
+	ACTS time format has changed somewhat since the code was written.
+	In particular the '*' '#' character switch no longer occurs...
+	only '*' is typed.
+
+      NOTE: Author (falsely) stated Y2K is NOT a leap year when it 
+      really is.
+
+      TRUTH: ACTS will go beyond Y2K: it uses FourDigitYear % 100 values
+      for year so year 2000 will revert to "00".
+
+
+4)     ntpd/refclock_oncore.c
+       Some very strange logic in manipulating year values:
+       1122         instance->pp->year = buf[6]*256+buf[7];
+       Multiply by 256????
+ 
+    Response from PHK:
+       The entire protocol is binary, the year is a 16 bit quantity 
+       which according to the manual can have the range 1998-2018. 
+ 
diff --git a/contrib/ntp/README b/contrib/ntp/README
new file mode 100644
index 000000000000..a5916d856a40
--- /dev/null
+++ b/contrib/ntp/README
@@ -0,0 +1,152 @@
+The ntp Distribution Base Directory
+
+This directory and its subdirectories contain the Network Time Protocol
+Version 4 (NTP) distribution for Unix and Windows/NT systems.  This release
+may still work on VxWorks, too.
+
+The contents of the base directory are given in this file. The contents of
+subdirectories are given in the README files in each subdirectory.
+
+A complete explanation of the configure, compile and install process, as
+well as setting up an NTP subnet, is in the HTML pages in the ./html/
+directory. For more information on NTP and how to get a working setup,
+read WHERE-TO-START.
+
+For Windows/NT, visit html/hints/winnt .
+
+The base directory ./ contains the autoconfiguation files, source
+directories and related stuff:
+
+COPYRIGHT	Excerpt from the HTML file ./html/copyright.html. This file
+		specifies copyright conditions, together with a list of
+		major authors and electric addresses.
+
+INSTALL		Generic installation instructions for autoconf-based programs.
+		Unless you really know what you are doing, you should read the
+		directions in the HTML pages, starting with ./html/index.htm.
+
+NEWS		What's new in this release.
+
+README		This file.
+
+README.cvs	Instructions for folks who use the CVS-repository
+		version of NTP.
+
+README.des	If you *need* DES support.
+
+README.hackers	Notes to folks who want to hack on the code.
+
+TODO            List of items the NTP developers are working on.
+
+WHERE-TO-START	Hints on what to read in order to get a working
+		configuration.
+
+Makefile.am	Automake file configuration file. Edit only if you have the
+		GNU automake and autoconf utilities installed.
+
+Makefile.in	Autoconf make file template for Unix.
+
+acconfig.h	Autoconf template header file. Edit only if you
+		have the GNU automake and autoconf utilities installed.
+
+adjtimed        Directory containing the sources for the adjtime daemon
+		for HP/UX systems prior to HP-UX 10.0.
+
+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.
+
+build		A script to build the distribution in A.`config.guess`
+		subdirectory (more or less).
+
+clockstuff	Directory containing sources for miscellaneous programs
+		to test certain auxiliary 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.
+
+conf            Directory containing a motley collection of
+		configuration files for various systems. For example only.
+
+config.guess	Script used to identify the machine architecture and
+		operating system.
+
+config.h.in	Configuration file generated automatically from
+		configure.in. Do not edit.
+
+configure	Script used to configure the distribution. See the HTML pages
+		(./html/index.htm) for a complete description of the options
+		available.
+
+configure.in	Master configuration template. Edit only if you have the
+		GNU automake and autoconf utilities installed.
+
+dot.emacs	C-mode indentation rules for code "Just the way Dave likes it".
+
+flock_build	(UDel only) Build the distribution on a number of
+		different platforms.
+
+html            Directory containing a complete set of documentation on
+		building and configuring a NTP server or client. The
+		documentation is in the form of HTML files suitable for
+		browsing and contains links to additional documentation
+		at various web sites. If a browser is unavailable, an
+		ordinary text editor can be used.
+
+include		Directory containing include header files used by most
+		programs in the distribution.
+
+install-sh	Script to install a program, script or data file.
+
+kernel		Directory containing sources for kernel programs such as
+		line disciplines and STREAMS modules used with the CHU
+		decoder and precision PPS signals.
+
+libntp		Directory containing library source code used by most
+		programs in the distribution.
+
+librsaref	Staging directory for RSAREF.
+
+ntp_update	Update an NTP CVS tree.
+
+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 files 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/Solaris 5.3 streams
+		module for parse squats here.
+
+patches		Directory containing patches already applied to this
+		distribution. These are included for record and to help
+		in possible porting problems.
+
+scripts		Directory containing scripts to build the configuration
+		files in this directory and then the makefiles used in
+		various dependent directories. the subdirectories
+		monitoring and support hold various perl and shell
+		scripts for visualizing synchronization and daemon startup.
+
+stamp.h.in	Configuration file generated automatically from configure.in.
+		Do not edit.
+
+util            Directory containing sources for various utility and
+		testing programs.
+
+David L. Mills (mills@udel.edu)
+21 June 1998
diff --git a/contrib/ntp/README.cvs b/contrib/ntp/README.cvs
new file mode 100644
index 000000000000..b9f352a7179b
--- /dev/null
+++ b/contrib/ntp/README.cvs
@@ -0,0 +1,24 @@
+To get the NTP distribution via anonymous CVS:
+
+    cvs -d :pserver:anoncvs@www.ntp.org:/cvs/ntp login
+
+the password is: anoncvs
+
+    cvs -d :pserver:anoncvs@www.ntp.org:/cvs/ntp co ntp
+
+after which the "ntp_update" script in the top-level of the tree should
+keep things in synch and properly timestamped.
+
+There are some mailing lists for the NTP CVS distribution.  For more
+information, send a message to  with the "lists" in
+the body of the message.
+
+If you get NTP via CVS, you will need to build the release using GNU make
+and gcc.
+
+You can then "make dist" to build a release tarball that does not require
+GNU make or gcc.
+
+The reason GNU make and gcc are required is because the repository version
+of NTP does not have the make dependencies built-in.  These dependencies
+are created dynamically, and this dynamic process requires GNU make and gcc.
diff --git a/contrib/ntp/README.des b/contrib/ntp/README.des
new file mode 100644
index 000000000000..072d72e85950
--- /dev/null
+++ b/contrib/ntp/README.des
@@ -0,0 +1,20 @@
+If you want DES support in ntp:
+
+- Use MD5 instead:
+- - convert your DES keys to MD5 by changing the 'A', 'N' or 'S' to 'M'
+
+If you *need* DES support:
+
+- first see if you can simply "want" DES support instead
+- Get RSAREF or RSAEURO (or a reasonable facsimile thereof)
+- - Unpack it in the top-level source directory of the NTP distribution
+    (You should see directories like ports, rsaref2, scripts)
+
+When you run configure, the Right Thing will happen.
+
+Be advised that the RSA DES code is not quite as portable os one might
+wish for.  In particular, DES under NTP will only work between machines
+of the same "endianness".
+
+Dave would prefer that new/alternative encryption schemes follow the
+RSA API.
diff --git a/contrib/ntp/README.hackers b/contrib/ntp/README.hackers
new file mode 100644
index 000000000000..230cd3239c07
--- /dev/null
+++ b/contrib/ntp/README.hackers
@@ -0,0 +1,25 @@
+Notes to hackers.
+
+---
+
+Dave likes this code indented formatted in a consistent way.
+The file "dot.emacs" has the emacs C-mode indentation style that Dave likes.
+
+---
+
+NTP4 uses ANSI C.  Some folks are blessed with a pre-ansi C compiler.  We
+support them by using "ansi2knr" in the Makefiles, which is automatically
+detected and selected by the configure process.
+
+For ansi2knr to work, we MUST define functions as follows:
+
+type stuff
+function_name ( actual parameters )
+
+While the whitespace is optional, the function name MUST start at column 0.
+
+---
+
+We'd like to see *all* system function declarations live in include/l_stdlib.h
+and NEVER appear in the .c files.
+
diff --git a/contrib/ntp/TODO b/contrib/ntp/TODO
new file mode 100644
index 000000000000..e57a2c46b2bd
--- /dev/null
+++ b/contrib/ntp/TODO
@@ -0,0 +1,126 @@
+
+      *** IF YOU CAN HELP FIX ANY OF THESE THINGS, PLEASE DO! ***
+
+970711: Look Real Hard at changing the key stuff from u_long to u_int32.
+
+970711: Make sure it's safe to convert proto_config's 2nd argument from
+	u_long to u_int32.  Watch "set" in ntp_request.c:setclr_flags().
+
+970318: in hourly_stats(?), squawk if the magnitude of the drift is,
+	say, >400.
+
+970301: Implement the utmp/wtmp timestamping on time steps.
+
+970210: Find a way to dump the current configuration to either syslog or
+	a file.
+
+CPP macros we need to handle:
+
+ SUN_3_3_STINKS  (this will be easy to handle if anybody still needs it)
+
+Problems that need to be fixed:
+
+- Get rid of the old SYS_* macros:
+  (It's worth noting that any code that would have been "enabled" by any
+  of these macros has not been used since 5.83, and there have been very
+  few complaints...)
+
+  SYS_44BSD:
+   authstuff/md5driver.c
+
+  SYS_BSDI:
+   authstuff/md5driver.c
+
+  SYS_DECOSF1:
+   util/ntptime.c
+
+  SYS_DOMAINOS:
+   parseutil/dcfd.c
+   xntpd/ntpd.c
+
+  SYS_HPUX:
+   kernel/sys/ppsclock.h
+   ntpdate/ntpdate.c
+   ntptrace/ntptrace.c
+
+  SYS_PTX:
+   libntp/machines.c
+
+  SYS_SOLARIS:
+   libparse/parse.c
+   libparse/clk_trimtsip.c
+   xntpd/ntp_io.c
+   xntpd/ntp_refclock.c
+   xntpd/ntpd.c
+
+  SYS_SUNOS4:
+   libparse/parse.c
+   libparse/clk_trimsip.c
+
+  SYS_WINNT:
+   include/ntp.h
+   include/ntp_fp.h
+   include/ntp_if.h
+   include/ntp_machine.h
+   include/ntp_select.h
+   include/ntp_syslog.h
+   include/ntp_unixtime.h
+   include/ntpd.h
+   libntp/libntp.mak
+   libntp/machines.c
+   libntp/mexit.c
+   libntp/msyslog.c
+   libntp/systime.c
+   ntpdate/ntpdate.c
+   ntpdate/ntpdate.mak
+   ntpq/ntpq.c
+   ntpq/ntpq.mak
+   ntpq/ntpq_ops.c
+   ntptrace/ntptrace.c
+   ntptrace/ntptrace.mak
+   xntpd/ntp_config.c
+   xntpd/ntp_filegen.c
+   xntpd/ntp_intres.c
+   xntpd/ntp_io.c
+   xntpd/ntp_loopfilter.c
+   xntpd/ntp_peer.c
+   xntpd/ntp_proto.c
+   xntpd/ntp_refclock.c
+   xntpd/ntp_timer.c
+   xntpd/ntp_unixclock.c
+   xntpd/ntp_util.c
+   xntpd/ntpd.c
+   xntpd/xntpd.mak
+   xntpdc/ntpdc.c
+   xntpdc/xntpdc.mak
+
+- config.guess might need help to identify:
+
+  Fujitsu's UXP				--enable-adjtime-is-accurate
+					--enable-step-slew
+
+  Unixware				--enable-adjtime-is-accurate
+					--enable-tick=10000
+					--enable-tickadj=80
+					--enable-udp-wildcard
+					--disable-step-slew
+
+  DomainOS				--enable-adjtime-is-accurate
+					--disable-kmem
+					--enable-tick=1000000
+
+  OpenVMS				--enable-slew-always
+					--enable-hourly-todr-sync
+
+  Is adjtime accurate on ALL sysv4* machines?
+  Can we identify DomainOS with *-apollo-* ?
+  Do we catch all Unixware machines with *-univel-sysv* ?
+
+- How can we test if UDP_WILDCARD_DELIVERY should be used?
+
+- Combine enable-step-slew and enable-ntpdate-step
+
+- Make sure enable-hourly-todr-sync is always disabled
+  What about NextStep and OpenVMS, where hourly TODR sync used to be enabled?
+
+- Check dcfd.c for variables that need to be volatile.
diff --git a/contrib/ntp/WHERE-TO-START b/contrib/ntp/WHERE-TO-START
new file mode 100644
index 000000000000..2e3e77b26eb1
--- /dev/null
+++ b/contrib/ntp/WHERE-TO-START
@@ -0,0 +1,41 @@
+The Network Time Protocol (NTP) Version 4 Distribution
+
+This is a distribution of the Network Time Protocol (NTP) Version 4
+sources and documentation. NTP can be used by Unix, DEC VMS and
+Microsoft Windows NT platforms to synchronize the computer clock to
+external sources of time, such as other NTP time servers or a local
+radio clock. The daemon included in this distribution can operate as a
+server, a client, or a relay from a set of servers to a dependent client
+population on a local net. This distribution includes the daemon itself,
+plus utility programs and supporting documentation.
+
+You are welcome to the lot, with due consideration of the copyright
+information in the COPYRIGHT file. 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 ntp-.tar.Z in the pub/ntp directory on
+louie.udel.edu and  is the version number. The current version
+number can be found on the NTP web page .
+
+A considerable amount of documentation, including build instructions,
+configuration advice, program usage and miscellaneous information is
+included in the ./html directory of this distribution. The intended
+access method is using a web browser such as netscape; however, the
+pages have been formatted so that viewing with an ordinary text editor
+is practical. Start the browser on the ./html/index.htm page, which
+contains additional instructions and hotlinks to the remaining pages.
+Some hotlinks for the larger documents, such as related technical
+memoranda, reports and papers, lead to other web sites where this
+information is stashed. We apologize for the inconvenience this may
+cause for users without Internet and World Wide Web access.
+
+If you are an old hand and just want to build the distribution, you
+might find the INSTALL file a useful shortcut. A descriptive list of all
+files in the base directory of this distribution is in the README file.
+A list of "significant" changes for the release is in the NEWS file.
+
+If you're interested in helping us test pre-release versions of ntpd,
+please look in .
+
+David L. Mills (mills@udel.edu)
+21 June 1998
diff --git a/contrib/ntp/acconfig.h b/contrib/ntp/acconfig.h
new file mode 100644
index 000000000000..82051d95219e
--- /dev/null
+++ b/contrib/ntp/acconfig.h
@@ -0,0 +1,457 @@
+/* Package */
+#undef PACKAGE
+
+/* Version */
+#undef VERSION
+
+/* debugging code */
+#undef DEBUG
+
+/* Minutes per DST adjustment */
+#undef DSTMINUTES
+
+/* MD5 authentication */
+#undef MD5
+
+/* DES authentication (COCOM only) */
+#undef DES
+
+/* time_t */
+#undef time_t
+
+/* reference clock interface */
+#undef REFCLOCK
+
+/* Audio CHU? */
+#undef AUDIO_CHU
+
+/* ACTS modem service */
+#undef CLOCK_ACTS
+
+/* Arbiter 1088A/B GPS receiver */
+#undef CLOCK_ARBITER
+
+/* DHD19970505: ARCRON support. */
+#undef CLOCK_ARCRON_MSF
+
+/* Austron 2200A/2201A GPS receiver */
+#undef CLOCK_AS2201
+
+/* PPS interface */
+#undef CLOCK_ATOM
+
+/* PPS auxiliary interface for ATOM */
+#undef PPS_SAMPLE
+
+/* Datum/Bancomm bc635/VME interface */
+#undef CLOCK_BANC
+
+/* ELV/DCF7000 clock */
+#undef CLOCK_DCF7000
+
+/* HOPF 6021 clock */
+#undef CLOCK_HOPF6021
+
+/* Meinberg clocks */
+#undef CLOCK_MEINBERG
+
+/* DCF77 raw time code */
+#undef CLOCK_RAWDCF
+
+/* RCC 8000 clock */
+#undef CLOCK_RCC8000
+
+/* Schmid DCF77 clock */
+#undef CLOCK_SCHMID
+
+/* Trimble GPS receiver/TAIP protocol */
+#undef CLOCK_TRIMTAIP
+
+/* Trimble GPS receiver/TSIP protocol */
+#undef CLOCK_TRIMTSIP
+
+/* WHARTON 400A Series protocol */
+#undef CLOCK_WHARTON_400A
+
+/* VARITEXT protocol */
+#undef CLOCK_VARITEXT
+
+/* Diems Computime Radio Clock */
+#undef CLOCK_COMPUTIME
+
+/* Datum Programmable Time System */
+#undef CLOCK_DATUM
+
+/* TrueTime GPS receiver/VME interface */
+#undef CLOCK_GPSVME
+
+/* Heath GC-1000 WWV/WWVH receiver */
+#undef CLOCK_HEATH
+
+/* HP 58503A GPS receiver */
+#undef CLOCK_HPGPS
+
+/* Sun IRIG audio decoder */
+#undef CLOCK_IRIG
+
+/* Rockwell Jupiter GPS clock */
+#undef CLOCK_JUPITER
+
+/* Leitch CSD 5300 Master Clock System Driver */
+#undef CLOCK_LEITCH
+
+/* local clock reference */
+#undef CLOCK_LOCAL
+
+/* EES M201 MSF receiver */
+#undef CLOCK_MSFEES
+
+/* Magnavox MX4200 GPS receiver */
+#undef CLOCK_MX4200
+
+/* NMEA GPS receiver */
+#undef CLOCK_NMEA
+
+/* Palisade clock */
+#undef CLOCK_PALISADE
+
+/* PARSE driver interface */
+#undef CLOCK_PARSE
+
+/* PARSE kernel PLL PPS support */
+#undef PPS_SYNC
+
+/* PCL 720 clock support */
+#undef CLOCK_PPS720
+
+/* PST/Traconex 1020 WWV/WWVH receiver */
+#undef CLOCK_PST
+
+/* PTB modem service */
+#undef CLOCK_PTBACTS
+
+/* clock thru shared memory */
+#undef CLOCK_SHM
+
+/* Motorola UT Oncore GPS */
+#undef CLOCK_ONCORE
+
+/* KSI/Odetics TPRO/S GPS receiver/IRIG interface */
+#undef CLOCK_TPRO
+
+/* TRAK 8810 GPS receiver */
+#undef CLOCK_TRAK
+
+/* Kinemetrics/TrueTime receivers */
+#undef CLOCK_TRUETIME
+
+/* USNO modem service */
+#undef CLOCK_USNO
+
+/* Spectracom 8170/Netclock/2 WWVB receiver */
+#undef CLOCK_WWVB
+
+/* Ultralink M320 WWVB receiver */
+#undef CLOCK_ULINK
+
+/* Chronolog K-series WWVB receiver */
+#undef CLOCK_CHRONOLOG
+
+/* Dumb generic hh:mm:ss local clock */
+#undef CLOCK_DUMBCLOCK
+
+/* define if we need to declare int errno; */
+#undef DECL_ERRNO
+
+/* define if we may declare int h_errno; */
+#undef DECL_H_ERRNO
+
+/* define if it's OK to declare char *sys_errlist[]; */
+#undef CHAR_SYS_ERRLIST
+
+/* define if it's OK to declare int syscall P((int, struct timeval *, struct timeval *)); */
+#undef DECL_SYSCALL
+
+/* define if we have syscall is buggy (Solaris 2.4) */
+#undef SYSCALL_BUG
+
+/* Do we need extra room for SO_RCVBUF? (HPUX <8) */
+#undef NEED_RCVBUF_SLOP
+
+/* Should we open the broadcast socket? */
+#undef OPEN_BCAST_SOCKET
+
+/* Do we want the HPUX FindConfig()? */
+#undef NEED_HPUX_FINDCONFIG
+
+/* canonical system (cpu-vendor-os) string */
+#undef STR_SYSTEM
+
+/* define if NetInfo support is available */
+#undef HAVE_NETINFO
+
+/* define if [gs]ettimeofday() only takes 1 argument */
+#undef SYSV_TIMEOFDAY
+
+/* define if struct sockaddr has sa_len */
+#undef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
+
+/* define if struct clockinfo has hz */
+#undef HAVE_HZ_IN_STRUCT_CLOCKINFO
+
+/* define if struct sigaction has sa_sigaction */
+#undef HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION
+
+/* define if struct clockinfo has tickadj */
+#undef HAVE_TICKADJ_IN_STRUCT_CLOCKINFO
+
+/* define if struct ntptimeval uses time.tv_nsec instead of time.tv_usec */ 
+#undef HAVE_TV_NSEC_IN_NTPTIMEVAL 
+
+/* Does a system header defind struct ppsclockev? */
+#undef HAVE_STRUCT_PPSCLOCKEV
+
+/* define if function prototypes are OK */
+#undef HAVE_PROTOTYPES
+
+/* define if setpgrp takes 0 arguments */
+#undef HAVE_SETPGRP_0
+
+/* hardwire a value for tick? */
+#undef PRESET_TICK
+
+/* hardwire a value for tickadj? */
+#undef PRESET_TICKADJ
+
+/* is adjtime() accurate? */
+#undef ADJTIME_IS_ACCURATE
+
+/* should we NOT read /dev/kmem? */
+#undef NOKMEM
+
+/* use UDP Wildcard Delivery? */
+#undef UDP_WILDCARD_DELIVERY
+
+/* always slew the clock? */
+#undef SLEWALWAYS
+
+/* step, then slew the clock? */
+#undef STEP_SLEW
+
+/* force ntpdate to step the clock if !defined(STEP_SLEW) ? */
+#undef FORCE_NTPDATE_STEP
+
+/* synch TODR hourly? */
+#undef DOSYNCTODR
+
+/* do we set process groups with -pid? */
+#undef UDP_BACKWARDS_SETOWN
+
+/* must we have a CTTY for fsetown? */
+#undef USE_FSETOWNCTTY
+
+/* can we use SIGIO for tcp and udp IO? */
+#undef HAVE_SIGNALED_IO
+
+/* can we use SIGPOLL for UDP? */
+#undef USE_UDP_SIGPOLL
+
+/* can we use SIGPOLL for tty IO? */
+#undef USE_TTY_SIGPOLL
+
+/* should we use clock_settime()? */
+#undef USE_CLOCK_SETTIME
+
+/* do we want the CHU driver? */
+#undef CLOCK_CHU
+
+/* do we have the ppsclock streams module? */
+#undef PPS
+
+/* do we have the tty_clk line discipline/streams module? */
+#undef TTYCLK
+
+/* does the kernel support precision time discipline? */
+#undef KERNEL_PLL
+
+/* does the kernel support multicasting IP? */
+#undef MCAST
+
+/* do we have ntp_{adj,get}time in libc? */
+#undef NTP_SYSCALLS_LIBC
+
+/* do we have ntp_{adj,get}time in the kernel? */
+#undef NTP_SYSCALLS_STD
+
+/* do we have STREAMS/TLI? (Can we replace this with HAVE_SYS_STROPTS_H? */
+#undef STREAMS_TLI
+
+/* do we need an s_char typedef? */
+#undef NEED_S_CHAR_TYPEDEF
+
+/* include the GDT Surveying code? */
+#undef GDT_SURVEYING
+
+/* does SIOCGIFCONF return size in the buffer? */
+#undef SIZE_RETURNED_IN_BUFFER
+
+/* what is the name of TICK in the kernel? */
+#undef K_TICK_NAME
+
+/* Is K_TICK_NAME (nsec_per_tick, for example) in nanoseconds? */
+#undef TICK_NANO
+
+/* what is the name of TICKADJ in the kernel? */
+#undef K_TICKADJ_NAME
+
+/* Is K_TICKADJ_NAME (hrestime_adj, for example) in nanoseconds? */
+#undef TICKADJ_NANO
+
+/* what is (probably) the name of DOSYNCTODR in the kernel? */
+#undef K_DOSYNCTODR_NAME
+
+/* what is (probably) the name of NOPRINTF in the kernel? */
+#undef K_NOPRINTF_NAME
+
+/* do we need HPUX adjtime() library support? */
+#undef NEED_HPUX_ADJTIME
+
+/* Might nlist() values require an extra level of indirection (AIX)? */
+#undef NLIST_EXTRA_INDIRECTION
+
+/* Should we recommend a minimum value for tickadj? */
+#undef MIN_REC_TICKADJ
+
+/* Is there a problem using PARENB and IGNPAR (IRIX)? */
+#undef NO_PARENB_IGNPAR
+
+/* Should we not IGNPAR (Linux)? */
+#undef RAWDCF_NO_IGNPAR
+
+/* Does the compiler like "volatile"? */
+#undef volatile
+
+/* Does qsort expect to work on "void *" stuff? */
+#undef QSORT_USES_VOID_P
+
+/* What is the fallback value for HZ? */
+#undef DEFAULT_HZ
+
+/* Do we need to override the system's idea of HZ? */
+#undef OVERRIDE_HZ
+
+/* Do we want the SCO clock hacks? */
+#undef SCO5_CLOCK
+
+/* Do we want the ReliantUNIX clock hacks? */
+#undef RELIANTUNIX_CLOCK
+
+/* Does the kernel have an FLL bug? */
+#undef KERNEL_FLL_BUG
+
+/* Define if you have the TIOCGPPSEV ioctl (Solaris) */
+#undef HAVE_TIOCGPPSEV
+
+/* Define if you have the TIOCSPPS ioctl (Solaris) */
+#undef HAVE_TIOCSPPS
+
+/* Define if you have the CIOGETEV ioctl (SunOS, Linux) */
+#undef HAVE_CIOGETEV
+
+/* Define if you have the TIOCGSERIAL, TIOCSSERIAL, ASYNC_PPS_CD_POS, and ASYNC_PPS_CD_NEG ioctls (linux) */
+#undef HAVE_TIO_SERIAL_STUFF
+
+/* Define if you use struct timespec rather than struct timeval (time in ns rather than us) */
+#undef HAVE_TIMESPEC
+
+/* Define if you have the interface in the Draft RFC */
+#undef HAVE_PPSAPI
+
+/* Do we need to #define _SVID3 when we #include ? */
+#undef TERMIOS_NEEDS__SVID3
+
+/***/
+
+/* Which way should we declare... */
+
+/* adjtime()? */
+#undef DECL_ADJTIME_0
+
+/* bcopy()? */
+#undef DECL_BCOPY_0
+
+/* bzero()? */
+#undef DECL_BZERO_0
+
+/* cfset[io]speed()? */
+#undef DECL_CFSETISPEED_0
+
+/* ioctl()? */
+#undef DECL_IOCTL_0
+
+/* IPC? (bind, connect, recvfrom, sendto, setsockopt, socket) */
+#undef DECL_IPC_0
+
+/* memmove()? */
+#undef DECL_MEMMOVE_0
+
+/* memset()? */
+#undef DECL_MEMSET_0
+
+/* mkstemp()? */
+#undef DECL_MKSTEMP_0
+
+/* mktemp()? */
+#undef DECL_MKTEMP_0
+
+/* mrand48()? */
+#undef DECL_MRAND48_0
+
+/* nlist()? */
+#undef DECL_NLIST_0
+
+/* plock()? */
+#undef DECL_PLOCK_0
+
+/* rename()? */
+#undef DECL_RENAME_0
+
+/* select()? */
+#undef DECL_SELECT_0
+
+/* setitimer()? */
+#undef DECL_SETITIMER_0
+
+/* setpriority()? */
+#undef DECL_SETPRIORITY_0
+#undef DECL_SETPRIORITY_1
+
+/* sigvec()? */
+#undef DECL_SIGVEC_0
+
+/* srand48()? */
+#undef DECL_SRAND48_0
+
+/* stdio stuff? */
+#undef DECL_STDIO_0
+
+/* stime()? */
+#undef DECL_STIME_0
+
+/* strtol()? */
+#undef DECL_STRTOL_0
+
+/* syslog() stuff? */
+#undef DECL_SYSLOG_0
+
+/* time()? */
+#undef DECL_TIME_0
+
+/* [gs]ettimeofday()? */
+#undef DECL_TIMEOFDAY_0
+
+/* tolower()? */
+#undef DECL_TOLOWER_0
+
+/* toupper()? */
+#undef DECL_TOUPPER_0
diff --git a/contrib/ntp/aclocal.m4 b/contrib/ntp/aclocal.m4
new file mode 100644
index 000000000000..4c96f8238645
--- /dev/null
+++ b/contrib/ntp/aclocal.m4
@@ -0,0 +1,253 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+AC_DEFUN(AM_CONFIG_HEADER,
+[AC_PREREQ([2.12])
+AC_CONFIG_HEADER([$1])
+dnl When config.status generates a header, we must update the stamp-h file.
+dnl This file resides in the same directory as the config header
+dnl that is generated.  We must strip everything past the first ":",
+dnl and everything past the last "/".
+AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
+ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
+<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
+<>; do
+  case " <<$>>CONFIG_HEADERS " in
+  *" <<$>>am_file "*<<)>>
+    echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
+    ;;
+  esac
+  am_indx=`expr "<<$>>am_indx" + 1`
+done<<>>dnl>>)
+changequote([,]))])
+
+# Do all the work for Automake.  This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AC_PROG_INSTALL])
+dnl We require 2.13 because we rely on SHELL being computed by configure.
+AC_PREREQ([2.13])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+dnl We check for tar when the user configures the end package.
+dnl This is sad, since we only need this for "dist".  However,
+dnl there's no other good way to do it.  We prefer GNU tar if
+dnl we can find it.  If we can't find a tar, it doesn't really matter.
+AC_CHECK_PROGS(AMTAR, gnutar gtar tar)
+AMTARFLAGS=
+if test -n "$AMTAR"; then
+  if $SHELL -c "$AMTAR --version" > /dev/null 2>&1; then
+    dnl We have GNU tar.
+    AMTARFLAGS=o
+  fi
+fi
+AC_SUBST(AMTARFLAGS)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "[$]*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "[$]*" != "X $srcdir/configure conftestfile" \
+      && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "[$]2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+   $1=$2
+   AC_MSG_RESULT(found)
+else
+   $1="$3/missing $2"
+   AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
+
+# serial 1
+
+AC_DEFUN(AM_C_PROTOTYPES,
+[AC_REQUIRE([AM_PROG_CC_STDC])
+AC_REQUIRE([AC_PROG_CPP])
+AC_MSG_CHECKING([for function prototypes])
+if test "$am_cv_prog_cc_stdc" != no; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(PROTOTYPES,1,[Define if compiler has function prototypes])
+  U= ANSI2KNR=
+else
+  AC_MSG_RESULT(no)
+  U=_ ANSI2KNR=./ansi2knr
+  # Ensure some checks needed by ansi2knr itself.
+  AC_HEADER_STDC
+  AC_CHECK_HEADERS(string.h)
+fi
+AC_SUBST(U)dnl
+AC_SUBST(ANSI2KNR)dnl
+])
+
+
+# serial 1
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so.  This macro tries various
+# options that select ANSI C on some system or another.  It considers the
+# compiler to be in ANSI C mode if it handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{am_cv_prog_cc_stdc} is set to @samp{no}.  If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN(AM_PROG_CC_STDC,
+[AC_REQUIRE([AC_PROG_CC])
+AC_BEFORE([$0], [AC_C_INLINE])
+AC_BEFORE([$0], [AC_C_CONST])
+dnl Force this before AC_PROG_CPP.  Some cpp's, eg on HPUX, require
+dnl a magic option to avoid problems with ANSI preprocessor commands
+dnl like #elif.
+dnl FIXME: can't do this because then AC_AIX won't work due to a
+dnl circular dependency.
+dnl AC_BEFORE([$0], [AC_PROG_CPP])
+AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(am_cv_prog_cc_stdc,
+[am_cv_prog_cc_stdc=no
+ac_save_CC="$CC"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX 10.20 and later	-Ae
+# HP-UX older versions	-Aa -D_HPUX_SOURCE
+# SVR4			-Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  AC_TRY_COMPILE(
+[#include 
+#include 
+#include 
+#include 
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+], [
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+],
+[am_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CC="$ac_save_CC"
+])
+if test -z "$am_cv_prog_cc_stdc"; then
+  AC_MSG_RESULT([none needed])
+else
+  AC_MSG_RESULT($am_cv_prog_cc_stdc)
+fi
+case "x$am_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $am_cv_prog_cc_stdc" ;;
+esac
+])
+
diff --git a/contrib/ntp/adjtimed/Makefile.am b/contrib/ntp/adjtimed/Makefile.am
new file mode 100644
index 000000000000..14a44c6aedab
--- /dev/null
+++ b/contrib/ntp/adjtimed/Makefile.am
@@ -0,0 +1,8 @@
+#AUTOMAKE_OPTIONS = ../ansi2knr #no-dependencies
+AUTOMAKE_OPTIONS = ../util/ansi2knr
+bin_PROGRAMS = @MAKE_ADJTIMED@
+EXTRA_PROGRAMS = adjtimed
+INCLUDES = -I$(top_srcdir)/include
+LDADD = ../libntp/libntp.a
+#EXTRA_DIST = TAGS
+ETAGS_ARGS = Makefile.am
diff --git a/contrib/ntp/adjtimed/Makefile.in b/contrib/ntp/adjtimed/Makefile.in
new file mode 100644
index 000000000000..f90fd26996f6
--- /dev/null
+++ b/contrib/ntp/adjtimed/Makefile.in
@@ -0,0 +1,334 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+AMTAR = @AMTAR@
+AMTARFLAGS = @AMTARFLAGS@
+AWK = @AWK@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CHUTEST = @CHUTEST@
+CLKTEST = @CLKTEST@
+CPP = @CPP@
+DCFD = @DCFD@
+LDFLAGS = @LDFLAGS@
+LIBPARSE = @LIBPARSE@
+LIBRSAREF = @LIBRSAREF@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+MAKE_ADJTIMED = @MAKE_ADJTIMED@
+MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@
+MAKE_LIBPARSE = @MAKE_LIBPARSE@
+MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@
+MAKE_LIBRSAREF = @MAKE_LIBRSAREF@
+MAKE_NTPTIME = @MAKE_NTPTIME@
+MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@
+MAKE_TICKADJ = @MAKE_TICKADJ@
+PACKAGE = @PACKAGE@
+PATH_SH = @PATH_SH@
+PROPDELAY = @PROPDELAY@
+RANLIB = @RANLIB@
+RSAREF = @RSAREF@
+TESTDCF = @TESTDCF@
+U = @U@
+VERSION = @VERSION@
+
+#AUTOMAKE_OPTIONS = ../ansi2knr #no-dependencies
+
+
+AUTOMAKE_OPTIONS = ../util/ansi2knr
+bin_PROGRAMS = @MAKE_ADJTIMED@
+EXTRA_PROGRAMS = adjtimed
+INCLUDES = -I$(top_srcdir)/include
+LDADD = ../libntp/libntp.a
+#EXTRA_DIST = TAGS
+ETAGS_ARGS = Makefile.am
+subdir = adjtimed
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LIBS = @LIBS@
+ANSI2KNR = ../util/ansi2knr
+adjtimed_SOURCES = adjtimed.c
+adjtimed_OBJECTS =  adjtimed$U.o
+adjtimed_LDADD = $(LDADD)
+adjtimed_DEPENDENCIES =  ../libntp/libntp.a
+adjtimed_LDFLAGS = 
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES =  adjtimed.c
+DIST_COMMON =  README Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+SOURCES = adjtimed.c
+OBJECTS = adjtimed$U.o
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .c .o
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps adjtimed/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+	-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \
+	    echo "  $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f"; \
+	     $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \
+	  echo " rm -f $(DESTDIR)$(bindir)/$$f"; \
+	  rm -f $(DESTDIR)$(bindir)/$$f; \
+	done
+
+.c.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+../util/ansi2knr: ../util/ansi2knr.o
+	cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr
+
+../util/ansi2knr.o:
+	cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o
+
+
+mostlyclean-kr:
+	-rm -f *_.c
+
+clean-kr:
+
+distclean-kr:
+
+maintainer-clean-kr:
+adjtimed$U.o:
+
+adjtimed: $(adjtimed_OBJECTS) $(adjtimed_DEPENDENCIES)
+	@rm -f adjtimed
+	$(LINK) $(adjtimed_LDFLAGS) $(adjtimed_OBJECTS) $(adjtimed_LDADD) $(LIBS)
+adjtimed_.c: adjtimed.c $(ANSI2KNR)
+	$(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/adjtimed.c; then echo $(srcdir)/adjtimed.c; else echo adjtimed.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > adjtimed_.c
+adjtimed_.o : $(ANSI2KNR)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  ${AWK:-awk} '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  ${AWK:-awk} '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$d/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+adjtimed.o adjtimed.lo: adjtimed.c ../include/ntp_syslog.h \
+	../include/ntp_stdlib.h ../include/ntp_types.h \
+	../include/ntp_machine.h ../config.h ../include/ntp_proto.h \
+	../include/ntp_string.h ../include/l_stdlib.h \
+	../include/adjtime.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-binPROGRAMS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(bindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-binPROGRAMS mostlyclean-compile \
+		mostlyclean-kr mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-binPROGRAMS clean-compile clean-kr clean-tags \
+		clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-binPROGRAMS distclean-compile distclean-kr \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-binPROGRAMS \
+		maintainer-clean-compile maintainer-clean-kr \
+		maintainer-clean-tags maintainer-clean-generic \
+		distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-kr distclean-kr clean-kr \
+maintainer-clean-kr tags mostlyclean-tags distclean-tags clean-tags \
+maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all install-strip installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/contrib/ntp/adjtimed/README b/contrib/ntp/adjtimed/README
new file mode 100644
index 000000000000..d4bd593a26b5
--- /dev/null
+++ b/contrib/ntp/adjtimed/README
@@ -0,0 +1,22 @@
+------------------------------------------------------------------------------
+The adjtimed daemon emulates the BSD adjtime(2) system call.  The
+adjtime() routine communicates with this daemon via SYSV messages.
+
+The emulation uses an undocumented kernel variable (as of 6.0/2.0
+and later releases) and as such it cannot be guaranteed to work in
+future HP-UX releases.  Perhaps HP-UX will have a real adjtime(2)
+system call in the future.
+
+Author: Tai Jin (tai@sde.hp.com)
+------------------------------------------------------------------------------
+
+IMPORTANT NOTE: This stuff must be compiled with no optimization !!
+
+NOTE: This code is known to work as of 8.0 on s300's, s700's and s800's.
+      PLEASE do not modify it unless you have access to kernel sources
+      and fully understand the implications of any changes you are making.
+      One person already has trashed adjtimed by making it do "the right 
+      thing".  This is not an exact replacement for BSD adjtime(2), don't
+      try to make it into one.
+
+	 -- Ken
diff --git a/contrib/ntp/adjtimed/adjtimed.c b/contrib/ntp/adjtimed/adjtimed.c
new file mode 100644
index 000000000000..f38e66dd0f75
--- /dev/null
+++ b/contrib/ntp/adjtimed/adjtimed.c
@@ -0,0 +1,491 @@
+/*************************************************************************/
+/* (c) Copyright Tai Jin, 1988.  All Rights Reserved.                    */
+/*     Hewlett-Packard Laboratories.                                     */
+/*                                                                       */
+/* Permission is hereby granted for unlimited modification, use, and     */
+/* distribution.  This software is made available with no warranty of    */
+/* any kind, express or implied.  This copyright notice must remain      */
+/* intact in all versions of this software.                              */
+/*                                                                       */
+/* The author would appreciate it if any bug fixes and enhancements were */
+/* to be sent back to him for incorporation into future versions of this */
+/* software.  Please send changes to tai@iag.hp.com or ken@sdd.hp.com.   */
+/*************************************************************************/
+
+#ifndef lint
+static char RCSid[] = "adjtimed.c,v 3.1 1993/07/06 01:04:45 jbj Exp";
+#endif
+
+/*
+ * Adjust time daemon.
+ * This daemon adjusts the rate of the system clock a la BSD's adjtime().
+ * The adjtime() routine uses SYSV messages to communicate with this daemon.
+ *
+ * Caveat: This emulation uses an undocumented kernel variable.  As such, it
+ * cannot be guaranteed to work in future HP-UX releases.  Fortunately,
+ * it will no longer be needed in HPUX 10.01 and later.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "ntp_syslog.h"
+#include "ntp_stdlib.h"
+
+#include "adjtime.h"
+
+double atof (const char *);
+
+int InitClockRate (void);
+int AdjustClockRate (register struct timeval *delta, register struct timeval *olddelta);
+long GetClockRate (void);
+int SetClockRate (long);
+void ResetClockRate (void);
+void Cleanup (void);
+void Exit (int);
+
+#define MILLION		1000000L
+
+/* emacs cc-mode goes nuts if we split the next line... */
+#define tvtod(tv)	((double)tv.tv_sec + ((double)tv.tv_usec / (double)MILLION))
+
+char *progname = NULL;
+int verbose = 0;
+int sysdebug = 0;
+static int mqid;
+static double oldrate = 0.0;
+
+int
+main(
+	int argc,
+	char *argv[]
+	)
+{
+	struct timeval remains;
+	struct sigvec vec;
+	MsgBuf msg;
+	char ch;
+	int nofork = 0;
+	int fd;
+
+	progname = argv[0];
+
+#ifdef LOG_LOCAL6
+	openlog("adjtimed", LOG_PID, LOG_LOCAL6);
+#else
+	openlog("adjtimed", LOG_PID);
+#endif
+
+	while ((ch = ntp_getopt(argc, argv, "hkrvdfp:")) != EOF) {
+		switch (ch) {
+		    case 'k':
+		    case 'r':
+			if ((mqid = msgget(KEY, 0)) != -1) {
+				if (msgctl(mqid, IPC_RMID, (struct msqid_ds *)0) == -1) {
+					msyslog(LOG_ERR, "remove old message queue: %m");
+					perror("adjtimed: remove old message queue");
+					exit(1);
+				}
+			}
+
+			if (ch == 'k')
+			    exit(0);
+
+			break;
+
+		    case 'v':
+			++verbose, nofork = 1;
+			break;
+
+		    case 'd':
+			++sysdebug;
+			break;
+
+		    case 'f':
+			nofork = 1;
+			break;
+
+		    case 'p':
+			fputs("adjtimed: -p option ignored\n", stderr);
+			break;
+
+		    default:
+			puts("usage: adjtimed -hkrvdf");
+			puts("-h\thelp");
+			puts("-k\tkill existing adjtimed, if any");
+			puts("-r\trestart (kills existing adjtimed, if any)");
+			puts("-v\tdebug output (repeat for more output)");
+			puts("-d\tsyslog output (repeat for more output)");
+			puts("-f\tno fork");
+			msyslog(LOG_ERR, "usage error");
+			exit(1);
+		} /* switch */
+	} /* while */
+
+	if (!nofork) {
+		switch (fork()) {
+		    case 0:
+			close(fileno(stdin));
+			close(fileno(stdout));
+			close(fileno(stderr));
+
+#ifdef TIOCNOTTY
+			if ((fd = open("/dev/tty")) != -1) {
+				ioctl(fd, TIOCNOTTY, 0);
+				close(fd);
+			}
+#else
+			setpgrp();
+#endif
+			break;
+
+		    case -1:
+			msyslog(LOG_ERR, "fork: %m");
+			perror("adjtimed: fork");
+			exit(1);
+
+		    default:
+			exit(0);
+		} /* switch */
+	} /* if */
+
+	if (nofork) {
+		setvbuf(stdout, NULL, _IONBF, BUFSIZ);
+		setvbuf(stderr, NULL, _IONBF, BUFSIZ);
+	}
+
+	msyslog(LOG_INFO, "started");
+	if (verbose) printf("adjtimed: started\n");
+
+	if (InitClockRate() == -1)
+	    Exit(2);
+
+	(void)signal(SIGHUP, SIG_IGN);
+	(void)signal(SIGINT, SIG_IGN);
+	(void)signal(SIGQUIT, SIG_IGN);
+	(void)signal(SIGTERM, Cleanup);
+
+	vec.sv_handler = ResetClockRate;
+	vec.sv_flags = 0;
+	vec.sv_mask = ~0;
+	sigvector(SIGALRM, &vec, (struct sigvec *)0);
+
+	if (msgget(KEY, IPC_CREAT|IPC_EXCL) == -1) {
+		if (errno == EEXIST) {
+			msyslog(LOG_ERR, "message queue already exists, use -r to remove it");
+			fputs("adjtimed: message queue already exists, use -r to remove it\n",
+			      stderr);
+			Exit(1);
+		}
+
+		msyslog(LOG_ERR, "create message queue: %m");
+		perror("adjtimed: create message queue");
+		Exit(1);
+	}
+
+	if ((mqid = msgget(KEY, 0)) == -1) {
+		msyslog(LOG_ERR, "get message queue id: %m");
+		perror("adjtimed: get message queue id");
+		Exit(1);
+	}
+  
+	/* Lock process in memory to improve response time */
+	if (plock(PROCLOCK)) {
+		msyslog(LOG_ERR, "plock: %m");
+		perror("adjtimed: plock");
+		Cleanup();
+	}
+
+	/* Also raise process priority.
+	 * If we do not get run when we want, this leads to bad timekeeping
+	 * and "Previous time adjustment didn't complete" gripes from xntpd.
+	 */
+	if (nice(-10) == -1) {
+		msyslog(LOG_ERR, "nice: %m");
+		perror("adjtimed: nice");
+		Cleanup();
+	}
+
+	for (;;) {
+		if (msgrcv(mqid, &msg.msgp, MSGSIZE, CLIENT, 0) == -1) {
+			if (errno == EINTR) continue;
+			msyslog(LOG_ERR, "read message: %m");
+			perror("adjtimed: read message");
+			Cleanup();
+		}
+
+		switch (msg.msgb.code) {
+		    case DELTA1:
+		    case DELTA2:
+			AdjustClockRate(&msg.msgb.tv, &remains);
+
+			if (msg.msgb.code == DELTA2) {
+				msg.msgb.tv = remains;
+				msg.msgb.mtype = SERVER;
+
+				while (msgsnd(mqid, &msg.msgp, MSGSIZE, 0) == -1) {
+					if (errno == EINTR) continue;
+					msyslog(LOG_ERR, "send message: %m");
+					perror("adjtimed: send message");
+					Cleanup();
+				}
+			}
+
+			if (remains.tv_sec + remains.tv_usec != 0L) {
+				if (verbose) {
+					printf("adjtimed: previous correction remaining %.6fs\n",
+					       tvtod(remains));
+				}
+				if (sysdebug) {
+					msyslog(LOG_INFO, "previous correction remaining %.6fs",
+						tvtod(remains));
+				}
+			}
+			break;
+
+		    default:
+			fprintf(stderr, "adjtimed: unknown message code %d\n", msg.msgb.code);
+			msyslog(LOG_ERR, "unknown message code %d", msg.msgb.code);
+		} /* switch */
+	} /* loop */
+} /* main */
+
+/*
+ * Default clock rate (old_tick).
+ */
+#define DEFAULT_RATE	(MILLION / HZ)
+#define UNKNOWN_RATE	0L
+#define TICK_ADJ	5	/* standard adjustment rate, microsec/tick */
+
+static long default_rate = DEFAULT_RATE;
+static long tick_rate = HZ;	/* ticks per sec */
+static long slew_rate = TICK_ADJ * HZ; /* in microsec/sec */
+
+int
+AdjustClockRate(
+	register struct timeval *delta,
+	register struct timeval *olddelta
+	)
+{
+	register long rate, dt, leftover;
+	struct itimerval period, remains;
+ 
+	dt = (delta->tv_sec * MILLION) + delta->tv_usec;
+
+	if (verbose)
+	    printf("adjtimed: new correction %.6fs\n", (double)dt / (double)MILLION);
+	if (sysdebug)
+	    msyslog(LOG_INFO, "new correction %.6fs", (double)dt / (double)MILLION);
+	if (verbose > 2) printf("adjtimed: leftover %ldus\n", leftover);
+	if (sysdebug > 2) msyslog(LOG_INFO, "leftover %ldus", leftover);
+	rate = dt;
+
+	/*
+	 * Apply a slew rate of slew_rate over a period of dt/slew_rate seconds.
+	 */
+	if (dt > 0) {
+		rate = slew_rate;
+	} else {
+		rate = -slew_rate;
+		dt = -dt;
+	}
+	period.it_value.tv_sec = dt / slew_rate;
+	period.it_value.tv_usec = (dt % slew_rate) * (MILLION / slew_rate);
+	/*
+	 * Note: we assume the kernel will convert the specified period into ticks
+	 * using the modified clock rate rather than an assumed nominal clock rate,
+	 * and therefore will generate the timer interrupt after the specified
+	 * number of true seconds, not skewed seconds.
+	 */
+
+	if (verbose > 1)
+	    printf("adjtimed: will be complete in %lds %ldus\n",
+		   period.it_value.tv_sec, period.it_value.tv_usec);
+	if (sysdebug > 1)
+	    msyslog(LOG_INFO, "will be complete in %lds %ldus",
+		    period.it_value.tv_sec, period.it_value.tv_usec);
+	/*
+	 * adjust the clock rate
+	 */
+	if (dt) {
+		if (SetClockRate((rate / tick_rate) + default_rate) == -1) {
+			msyslog(LOG_ERR, "set clock rate: %m");
+			perror("adjtimed: set clock rate");
+		}
+	}
+	/*
+	 * start the timer
+	 * (do this after changing the rate because the period has been rounded down)
+	 */
+	period.it_interval.tv_sec = period.it_interval.tv_usec = 0L;
+	setitimer(ITIMER_REAL, &period, &remains);
+	/*
+	 * return old delta
+	 */
+	if (olddelta) {
+		dt = ((remains.it_value.tv_sec * MILLION) + remains.it_value.tv_usec) *
+			oldrate;
+		olddelta->tv_sec = dt / MILLION;
+		olddelta->tv_usec = dt - (olddelta->tv_sec * MILLION); 
+	}
+
+	oldrate = (double)rate / (double)MILLION;
+	return(0);
+} /* AdjustClockRate */
+
+static struct nlist nl[] = {
+#ifdef __hp9000s800
+#ifdef PRE7_0
+	{ "tick" },
+#else
+	{ "old_tick" },
+#endif
+#else
+	{ "_old_tick" },
+#endif
+	{ "" }
+};
+
+static int kmem;
+
+/*
+ * The return value is the clock rate in old_tick units or -1 if error.
+ */
+long
+GetClockRate(void)
+{
+	long rate, mask;
+
+	if (lseek(kmem, (off_t)nl[0].n_value, 0) == -1L)
+	    return (-1L);
+
+	mask = sigblock(sigmask(SIGALRM));
+
+	if (read(kmem, (caddr_t)&rate, sizeof(rate)) != sizeof(rate))
+	    rate = UNKNOWN_RATE;
+
+	sigsetmask(mask);
+	return (rate);
+} /* GetClockRate */
+
+/*
+ * The argument is the new rate in old_tick units.
+ */
+int
+SetClockRate(
+	long rate
+	)
+{
+	long mask;
+
+	if (lseek(kmem, (off_t)nl[0].n_value, 0) == -1L)
+	    return (-1);
+
+	mask = sigblock(sigmask(SIGALRM));
+
+	if (write(kmem, (caddr_t)&rate, sizeof(rate)) != sizeof(rate)) {
+		sigsetmask(mask);
+		return (-1);
+	}
+
+	sigsetmask(mask);
+
+	if (rate != default_rate) {
+		if (verbose > 3) {
+			printf("adjtimed: clock rate (%lu) %ldus/s\n", rate,
+			       (rate - default_rate) * tick_rate);
+		}
+		if (sysdebug > 3) {
+			msyslog(LOG_INFO, "clock rate (%lu) %ldus/s", rate,
+				(rate - default_rate) * tick_rate);
+		}
+	}
+
+	return (0);
+} /* SetClockRate */
+
+int
+InitClockRate(void)
+{
+	if ((kmem = open("/dev/kmem", O_RDWR)) == -1) {
+		msyslog(LOG_ERR, "open(/dev/kmem): %m");
+		perror("adjtimed: open(/dev/kmem)");
+		return (-1);
+	}
+
+	nlist("/hp-ux", nl);
+
+	if (nl[0].n_type == 0) {
+		fputs("adjtimed: /hp-ux has no symbol table\n", stderr);
+		msyslog(LOG_ERR, "/hp-ux has no symbol table");
+		return (-1);
+	}
+	/*
+	 * Set the default to the system's original value
+	 */
+	default_rate = GetClockRate();
+	if (default_rate == UNKNOWN_RATE) default_rate = DEFAULT_RATE;
+	tick_rate = (MILLION / default_rate);
+	slew_rate = TICK_ADJ * tick_rate;
+	fprintf(stderr,"default_rate=%ld, tick_rate=%ld, slew_rate=%ld\n",default_rate,tick_rate,slew_rate);
+
+	return (0);
+} /* InitClockRate */
+
+/*
+ * Reset the clock rate to the default value.
+ */
+void
+ResetClockRate(void)
+{
+	struct itimerval it;
+
+	it.it_value.tv_sec = it.it_value.tv_usec = 0L;
+	setitimer(ITIMER_REAL, &it, (struct itimerval *)0);
+
+	if (verbose > 2) puts("adjtimed: resetting the clock");
+	if (sysdebug > 2) msyslog(LOG_INFO, "resetting the clock");
+
+	if (GetClockRate() != default_rate) {
+		if (SetClockRate(default_rate) == -1) {
+			msyslog(LOG_ERR, "set clock rate: %m");
+			perror("adjtimed: set clock rate");
+		}
+	}
+
+	oldrate = 0.0;
+} /* ResetClockRate */
+
+void
+Cleanup(void)
+{
+	ResetClockRate();
+
+	if (msgctl(mqid, IPC_RMID, (struct msqid_ds *)0) == -1) {
+		if (errno != EINVAL) {
+			msyslog(LOG_ERR, "remove message queue: %m");
+			perror("adjtimed: remove message queue");
+		}
+	}
+
+	Exit(2);
+} /* Cleanup */
+
+void
+Exit(status)
+     int status;
+{
+	msyslog(LOG_ERR, "terminated");
+	closelog();
+	if (kmem != -1) close(kmem);
+	exit(status);
+} /* Exit */
diff --git a/contrib/ntp/build b/contrib/ntp/build
new file mode 100755
index 000000000000..e23865a3aaeb
--- /dev/null
+++ b/contrib/ntp/build
@@ -0,0 +1,66 @@
+#! /bin/sh
+
+LOGF=make.log
+case "$1" in
+ -l) LOG=1
+    shift
+    ;;
+ *) LOG=0
+    ;;
+esac
+
+CONFIG_ARGS="$@"
+
+IAM=`hostname || uname -n`
+
+#set -e
+#set -x
+
+CVO=`./config.guess`
+case "$CVO" in
+ *-*-*) ;;
+ *) echo "config.guess returned <$CVO>, which makes no sense to me."
+    exit 1
+    ;;
+esac
+
+MYNAME=`IFS=. ; set $IAM ; echo $1`
+
+case "$IAM" in
+ *.udel.edu)
+    BDIR=A.$MYNAME
+    ;;
+ *)
+    BDIR=A.$CVO
+    ;;
+esac
+
+CCSUF=""
+
+case "$CC" in
+ '') ;;
+ *) CCSUF="-$CC"
+    ;;
+esac
+
+BDIR="$BDIR$CCSUF"
+
+[ -d "$BDIR" ] || mkdir $BDIR
+[ -f "$BDIR/.buildcvo" ] || echo $CVO > $BDIR/.buildcvo
+[ -f "$BDIR/.buildhost" ] || echo $IAM > $BDIR/.buildhost
+
+cd $BDIR
+
+(
+cp /dev/null $LOGF
+
+[ -f config.status ] || ../configure $CONFIG_ARGS
+
+case "$MAKE" in
+ '') make && make check
+     ;;
+ *)  $MAKE && $MAKE check
+     ;;
+esac
+) >> $LOGF 2>&1
+
diff --git a/contrib/ntp/clockstuff/Makefile.am b/contrib/ntp/clockstuff/Makefile.am
new file mode 100644
index 000000000000..44e85a842214
--- /dev/null
+++ b/contrib/ntp/clockstuff/Makefile.am
@@ -0,0 +1,16 @@
+#AUTOMAKE_OPTIONS = ../ansi2knr no-dependencies
+AUTOMAKE_OPTIONS = ../util/ansi2knr
+noinst_PROGRAMS = @PROPDELAY@ @CHUTEST@ @CLKTEST@
+EXTRA_PROGRAMS = propdelay chutest clktest
+
+INCLUDES = -I$(top_srcdir)/include
+# We need -lm (and perhaps $(COMPAT) for propdelay, -lntp for {chu,clk}test
+propdelay_LDADD = -lm
+chutest_LDADD = ../libntp/libntp.a
+clktest_LDADD = ../libntp/libntp.a
+ETAGS_ARGS = Makefile.am
+#EXTRA_DIST = TAGS
+
+chutest: ../libntp/libntp.a
+
+clktest: ../libntp/libntp.a
diff --git a/contrib/ntp/clockstuff/Makefile.in b/contrib/ntp/clockstuff/Makefile.in
new file mode 100644
index 000000000000..67797b8b9a68
--- /dev/null
+++ b/contrib/ntp/clockstuff/Makefile.in
@@ -0,0 +1,342 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+AMTAR = @AMTAR@
+AMTARFLAGS = @AMTARFLAGS@
+AWK = @AWK@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CHUTEST = @CHUTEST@
+CLKTEST = @CLKTEST@
+CPP = @CPP@
+DCFD = @DCFD@
+LDFLAGS = @LDFLAGS@
+LIBPARSE = @LIBPARSE@
+LIBRSAREF = @LIBRSAREF@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+MAKE_ADJTIMED = @MAKE_ADJTIMED@
+MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@
+MAKE_LIBPARSE = @MAKE_LIBPARSE@
+MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@
+MAKE_LIBRSAREF = @MAKE_LIBRSAREF@
+MAKE_NTPTIME = @MAKE_NTPTIME@
+MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@
+MAKE_TICKADJ = @MAKE_TICKADJ@
+PACKAGE = @PACKAGE@
+PATH_SH = @PATH_SH@
+PROPDELAY = @PROPDELAY@
+RANLIB = @RANLIB@
+RSAREF = @RSAREF@
+TESTDCF = @TESTDCF@
+U = @U@
+VERSION = @VERSION@
+
+#AUTOMAKE_OPTIONS = ../ansi2knr no-dependencies
+
+
+AUTOMAKE_OPTIONS = ../util/ansi2knr
+noinst_PROGRAMS = @PROPDELAY@ @CHUTEST@ @CLKTEST@
+EXTRA_PROGRAMS = propdelay chutest clktest
+
+INCLUDES = -I$(top_srcdir)/include
+# We need -lm (and perhaps $(COMPAT) for propdelay, -lntp for {chu,clk}test
+propdelay_LDADD = -lm
+chutest_LDADD = ../libntp/libntp.a
+clktest_LDADD = ../libntp/libntp.a
+ETAGS_ARGS = Makefile.am
+subdir = clockstuff
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(noinst_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LIBS = @LIBS@
+ANSI2KNR = ../util/ansi2knr
+chutest_SOURCES = chutest.c
+chutest_OBJECTS =  chutest$U.o
+chutest_DEPENDENCIES =  ../libntp/libntp.a
+chutest_LDFLAGS = 
+clktest_SOURCES = clktest.c
+clktest_OBJECTS =  clktest$U.o
+clktest_DEPENDENCIES =  ../libntp/libntp.a
+clktest_LDFLAGS = 
+propdelay_SOURCES = propdelay.c
+propdelay_OBJECTS =  propdelay$U.o
+propdelay_DEPENDENCIES = 
+propdelay_LDFLAGS = 
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES =  chutest.c clktest.c propdelay.c
+DIST_COMMON =  README Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+GZIP_ENV = --best
+SOURCES = chutest.c clktest.c propdelay.c
+OBJECTS = chutest$U.o clktest$U.o propdelay$U.o
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .c .o
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps clockstuff/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstPROGRAMS:
+
+clean-noinstPROGRAMS:
+	-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+
+distclean-noinstPROGRAMS:
+
+maintainer-clean-noinstPROGRAMS:
+
+.c.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+../util/ansi2knr: ../util/ansi2knr.o
+	cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr
+
+../util/ansi2knr.o:
+	cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o
+
+
+mostlyclean-kr:
+	-rm -f *_.c
+
+clean-kr:
+
+distclean-kr:
+
+maintainer-clean-kr:
+chutest$U.o:
+clktest$U.o:
+propdelay$U.o:
+
+propdelay: $(propdelay_OBJECTS) $(propdelay_DEPENDENCIES)
+	@rm -f propdelay
+	$(LINK) $(propdelay_LDFLAGS) $(propdelay_OBJECTS) $(propdelay_LDADD) $(LIBS)
+chutest_.c: chutest.c $(ANSI2KNR)
+	$(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/chutest.c; then echo $(srcdir)/chutest.c; else echo chutest.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > chutest_.c
+clktest_.c: clktest.c $(ANSI2KNR)
+	$(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clktest.c; then echo $(srcdir)/clktest.c; else echo clktest.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clktest_.c
+propdelay_.c: propdelay.c $(ANSI2KNR)
+	$(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/propdelay.c; then echo $(srcdir)/propdelay.c; else echo propdelay.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > propdelay_.c
+chutest_.o clktest_.o propdelay_.o : $(ANSI2KNR)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  ${AWK:-awk} '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  ${AWK:-awk} '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$d/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+chutest.o chutest.lo: chutest.c ../include/ntp_fp.h \
+	../include/ntp_types.h ../include/ntp_machine.h ../config.h \
+	../include/ntp_proto.h ../include/ntp.h \
+	../include/ntp_unixtime.h
+clktest.o clktest.lo: clktest.c ../include/ntp_fp.h \
+	../include/ntp_types.h ../include/ntp_machine.h ../config.h \
+	../include/ntp_proto.h ../include/ntp.h \
+	../include/ntp_unixtime.h
+propdelay.o propdelay.lo: propdelay.c ../include/ntp_stdlib.h \
+	../include/ntp_types.h ../include/ntp_machine.h ../config.h \
+	../include/ntp_proto.h ../include/ntp_string.h \
+	../include/l_stdlib.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-noinstPROGRAMS mostlyclean-compile \
+		mostlyclean-kr mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstPROGRAMS clean-compile clean-kr clean-tags \
+		clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstPROGRAMS distclean-compile distclean-kr \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstPROGRAMS \
+		maintainer-clean-compile maintainer-clean-kr \
+		maintainer-clean-tags maintainer-clean-generic \
+		distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \
+clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-kr distclean-kr clean-kr \
+maintainer-clean-kr tags mostlyclean-tags distclean-tags clean-tags \
+maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all install-strip installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+#EXTRA_DIST = TAGS
+
+chutest: ../libntp/libntp.a
+
+clktest: ../libntp/libntp.a
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/contrib/ntp/clockstuff/README b/contrib/ntp/clockstuff/README
new file mode 100644
index 000000000000..c7f972773aec
--- /dev/null
+++ b/contrib/ntp/clockstuff/README
@@ -0,0 +1,31 @@
+README file for directory ./clockstuff of the NTP Version 4 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/ntp/clockstuff/chutest.c b/contrib/ntp/clockstuff/chutest.c
new file mode 100644
index 000000000000..785c253edbce
--- /dev/null
+++ b/contrib/ntp/clockstuff/chutest.c
@@ -0,0 +1,816 @@
+/* chutest.c,v 3.1 1993/07/06 01:05:21 jbj Exp
+ * chutest - test the CHU clock
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "../include/ntp_fp.h"
+#include "../include/ntp.h"
+#include "../include/ntp_unixtime.h"
+
+#ifdef CHULDISC
+#ifdef STREAM
+# ifdef HAVE_SYS_CHUDEFS_H
+#include 
+#endif
+#include 
+#endif
+#endif
+
+#ifdef CHULDISC
+# ifdef HAVE_SYS_CHUDEFS_H
+#include 
+#endif
+#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
+ */
+int
+main(
+	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(
+	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
+ */
+int
+process_raw(
+	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
+ */
+int
+raw_filter(
+	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
+ */
+int
+process_ldisc(
+	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
+ */
+void
+error(
+	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(void)
+{
+
+	/*
+	 * 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(
+	struct chucode *chuc,
+	l_fp *rtime
+	)
+{
+	register int i;
+	register u_long date_ui;
+	register u_long tmp;
+	register u_char *code;
+	int isneg;
+	int imin;
+	int imax;
+	u_long reftime;
+	l_fp off[NCHUCHARS];
+	l_fp ts;
+	int day, hour, minute, second;
+	static u_char lastcode[NCHUCHARS];
+	extern u_long calyearstart();
+	extern char *mfptoa();
+	void chu_process();
+	extern char *prettydate();
+
+	/*
+	 * We'll skip the checks made in the kernel, but assume they've
+	 * been done.  This means that all characters are BCD and
+	 * the intercharacter spacing isn't unreasonable.
+	 */
+
+	/*
+	 * print the code
+	 */
+	for (i = 0; i < NCHUCHARS; i++)
+	    printf("%c%c", (chuc->codechars[i] & 0xf) + '0',
+		   ((chuc->codechars[i]>>4) & 0xf) + '0');
+	printf("\n");
+
+	/*
+	 * Format check.  Make sure the two halves match.
+	 */
+	for (i = 0; i < NCHUCHARS/2; i++)
+	    if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) {
+		    (void) printf("Bad format, halves don't match\n");
+		    return;
+	    }
+	
+	/*
+	 * Break out the code into the BCD nibbles.  Only need to fiddle
+	 * with the first half since both are identical.  Note the first
+	 * BCD character is the low order nibble, the second the high order.
+	 */
+	code = lastcode;
+	for (i = 0; i < NCHUCHARS/2; i++) {
+		*code++ = chuc->codechars[i] & 0xf;
+		*code++ = (chuc->codechars[i] >> 4) & 0xf;
+	}
+
+	/*
+	 * If the first nibble isn't a 6, we're up the creek
+	 */
+	code = lastcode;
+	if (*code++ != 6) {
+		(void) printf("Bad format, no 6 at start\n");
+		return;
+	}
+
+	/*
+	 * Collect the day, the hour, the minute and the second.
+	 */
+	day = *code++;
+	day = MULBY10(day) + *code++;
+	day = MULBY10(day) + *code++;
+	hour = *code++;
+	hour = MULBY10(hour) + *code++;
+	minute = *code++;
+	minute = MULBY10(minute) + *code++;
+	second = *code++;
+	second = MULBY10(second) + *code++;
+
+	/*
+	 * Sanity check the day and time.  Note that this
+	 * only occurs on the 31st through the 39th second
+	 * of the minute.
+	 */
+	if (day < 1 || day > 366
+	    || hour > 23 || minute > 59
+	    || second < 31 || second > 39) {
+		(void) printf("Failed date sanity check: %d %d %d %d\n",
+			      day, hour, minute, second);
+		return;
+	}
+
+	/*
+	 * Compute seconds into the year.
+	 */
+	tmp = (u_long)(MULBY24((day-1)) + hour);	/* hours */
+	tmp = MULBY60(tmp) + (u_long)minute;		/* minutes */
+	tmp = MULBY60(tmp) + (u_long)second;		/* seconds */
+
+	/*
+	 * Now the fun begins.  We demand that the received time code
+	 * be within CLOCK_WAYTOOBIG of the receive timestamp, but
+	 * there is uncertainty about the year the timestamp is in.
+	 * Use the current year start for the first check, this should
+	 * work most of the time.
+	 */
+	date_ui = tmp + yearstart;
+	if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG)
+	    && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG))
+	    goto codeokay;	/* looks good */
+
+	/*
+	 * Trouble.  Next check is to see if the year rolled over and, if
+	 * so, try again with the new year's start.
+	 */
+	date_ui = calyearstart(rtime->l_ui);
+	if (date_ui != yearstart) {
+		yearstart = date_ui;
+		date_ui += tmp;
+		(void) printf("time %u, code %u, difference %d\n",
+			      date_ui, rtime->l_ui, (long)date_ui-(long)rtime->l_ui);
+		if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG)
+		    && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG))
+		    goto codeokay;	/* okay this time */
+	}
+
+	ts.l_uf = 0;
+	ts.l_ui = yearstart;
+	printf("yearstart %s\n", prettydate(&ts));
+	printf("received %s\n", prettydate(rtime));
+	ts.l_ui = date_ui;
+	printf("date_ui %s\n", prettydate(&ts));
+
+	/*
+	 * Here we know the year start matches the current system
+	 * time.  One remaining possibility is that the time code
+	 * is in the year previous to that of the system time.  This
+	 * is only worth checking if the receive timestamp is less
+	 * than CLOCK_WAYTOOBIG seconds into the new year.
+	 */
+	if ((rtime->l_ui - yearstart) < CLOCK_WAYTOOBIG) {
+		date_ui = tmp + calyearstart(yearstart - CLOCK_WAYTOOBIG);
+		if ((rtime->l_ui - date_ui) < CLOCK_WAYTOOBIG)
+		    goto codeokay;
+	}
+
+	/*
+	 * One last possibility is that the time stamp is in the year
+	 * following the year the system is in.  Try this one before
+	 * giving up.
+	 */
+	date_ui = tmp + calyearstart(yearstart + (400*24*60*60)); /* 400 days */
+	if ((date_ui - rtime->l_ui) >= CLOCK_WAYTOOBIG) {
+		printf("Date hopelessly off\n");
+		return;		/* hopeless, let it sync to other peers */
+	}
+
+    codeokay:
+	reftime = date_ui;
+	/*
+	 * We've now got the integral seconds part of the time code (we hope).
+	 * The fractional part comes from the table.  We next compute
+	 * the offsets for each character.
+	 */
+	for (i = 0; i < NCHUCHARS; i++) {
+		register u_long tmp2;
+
+		off[i].l_ui = date_ui;
+		off[i].l_uf = chutable[i];
+		tmp = chuc->codetimes[i].tv_sec + JAN_1970;
+		TVUTOTSF(chuc->codetimes[i].tv_usec, tmp2);
+		M_SUB(off[i].l_ui, off[i].l_uf, tmp, tmp2);
+	}
+
+	/*
+	 * Here is a *big* problem.  What one would normally
+	 * do here on a machine with lots of clock bits (say
+	 * a Vax or the gizmo board) is pick the most positive
+	 * offset and the estimate, since this is the one that
+	 * is most likely suffered the smallest interrupt delay.
+	 * The trouble is that the low order clock bit on an IBM
+	 * RT, which is the machine I had in mind when doing this,
+	 * ticks at just under the millisecond mark.  This isn't
+	 * precise enough.  What we can do to improve this is to
+	 * average all 10 samples and rely on the second level
+	 * filtering to pick the least delayed estimate.  Trouble
+	 * is, this means we have to divide a 64 bit fixed point
+	 * number by 10, a procedure which really sucks.  Oh, well.
+	 * First compute the sum.
+	 */
+	date_ui = 0;
+	tmp = 0;
+	for (i = 0; i < NCHUCHARS; i++)
+	    M_ADD(date_ui, tmp, off[i].l_ui, off[i].l_uf);
+	if (M_ISNEG(date_ui, tmp))
+	    isneg = 1;
+	else
+	    isneg = 0;
+	
+	/*
+	 * Here is a multiply-by-0.1 optimization that should apply
+	 * just about everywhere.  If the magnitude of the sum
+	 * is less than 9 we don't have to worry about overflow
+	 * out of a 64 bit product, even after rounding.
+	 */
+	if (date_ui < 9 || date_ui > 0xfffffff7) {
+		register u_long prod_ui;
+		register u_long prod_uf;
+
+		prod_ui = prod_uf = 0;
+		/*
+		 * This code knows the low order bit in 0.1 is zero
+		 */
+		for (i = 1; i < NZPOBITS; i++) {
+			M_LSHIFT(date_ui, tmp);
+			if (ZEROPTONE & (1<
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "../include/ntp_fp.h"
+#include "../include/ntp.h"
+#include "../include/ntp_unixtime.h"
+
+#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
+
+#if defined(ULT_2_0_SUCKS)
+#ifndef sigmask
+#define	sigmask(m)	(1<<(m))
+#endif
+#endif
+
+#ifndef STREAM
+#ifndef CLKLDISC
+CLOCK_LINE_DISCIPLINE_NEEDED_BY_THIS_PROGRAM;
+#endif
+#endif
+
+/*
+ * Mask for blocking SIGIO and SIGALRM
+ */
+#define	BLOCKSIGMASK	(sigmask(SIGIO)|sigmask(SIGALRM))
+
+/*
+ * speed table
+ */
+struct speeds {
+	int bps;
+	int rate;
+} speedtab[] = {
+	{ 300,		B300 },
+	{ 1200,		B1200 },
+	{ 2400,		B2400 },
+	{ 4800,		B4800 },
+	{ 9600,		B9600 },
+	{ 19200,	EXTA },
+	{ 38400,	EXTB },
+	{ 0,		0 }
+};
+
+char *progname;
+int debug;
+
+#ifdef CLKLDISC
+#define	DEFMAGIC	'\r'
+#endif
+
+#ifdef CLKLDISC
+# ifdef STREAM
+#  include 
+#  ifdef HAVE_SYS_CLKDEFS_H
+#   include 
+#  endif
+#  define DEFMAGIC	"\r"
+# endif
+#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;
+
+volatile int wasalarmed;
+volatile int iosig;
+
+struct timeval lasttv;
+
+extern u_long ustotslo[];
+extern u_long ustotsmid[];
+extern u_long ustotshi[];
+
+/*
+ * main - parse arguments and handle options
+ */
+int
+main(
+	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
+ */
+int
+doboth(
+	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
+ */
+int
+doioonly(
+	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
+ */
+int
+doio(
+	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++ = '>';
+		}
+		if (
+#ifdef CLKLDISC
+			(*rp == (char)magic1 || *rp == (char)magic2)
+#else
+			( 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.
+ */
+int
+doalarm(
+	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
+ */
+void
+alarming(void)
+{
+	wasalarmed = 1;
+}
+
+/*
+ * ioready - handle SIGIO interrupt
+ */
+void
+ioready(void)
+{
+	iosig = 1;
+}
diff --git a/contrib/ntp/clockstuff/propdelay.c b/contrib/ntp/clockstuff/propdelay.c
new file mode 100644
index 000000000000..3ce571c2510e
--- /dev/null
+++ b/contrib/ntp/clockstuff/propdelay.c
@@ -0,0 +1,544 @@
+/* propdelay.c,v 3.1 1993/07/06 01:05:24 jbj Exp
+ * propdelay - compute propagation delays
+ *
+ * cc -o propdelay propdelay.c -lm
+ *
+ * "Time and Frequency Users' Manual", NBS Technical Note 695 (1977).
+ */
+
+/*
+ * This can be used to get a rough idea of the HF propagation delay
+ * between two points (usually between you and the radio station).
+ * The usage is
+ *
+ * propdelay latitudeA longitudeA latitudeB longitudeB
+ *
+ * where points A and B are the locations in question.  You obviously
+ * need to know the latitude and longitude of each of the places.
+ * The program expects the latitude to be preceded by an 'n' or 's'
+ * and the longitude to be preceded by an 'e' or 'w'.  It understands
+ * either decimal degrees or degrees:minutes:seconds.  Thus to compute
+ * the delay between the WWVH (21:59:26N, 159:46:00W) and WWV (40:40:49N,
+ * 105:02:27W) you could use:
+ *
+ * propdelay n21:59:26 w159:46 n40:40:49 w105:02:27
+ *
+ * By default it prints out a summer (F2 average virtual height 350 km) and
+ * winter (F2 average virtual height 250 km) number.  The results will be
+ * quite approximate but are about as good as you can do with HF time anyway.
+ * You might pick a number between the values to use, or use the summer
+ * value in the summer and switch to the winter value when the static
+ * above 10 MHz starts to drop off in the fall.  You can also use the
+ * -h switch if you want to specify your own virtual height.
+ *
+ * You can also do a
+ *
+ * propdelay -W n45:17:47 w75:45:22
+ *
+ * to find the propagation delays to WWV and WWVH (from CHU in this
+ * case), a
+ *
+ * propdelay -C n40:40:49 w105:02:27
+ *
+ * to find the delays to CHU, and a
+ *
+ * propdelay -G n52:03:17 w98:34:18
+ *
+ * to find delays to GOES via each of the three satellites.
+ */
+
+#include 
+#include 
+
+#include "ntp_stdlib.h"
+
+extern	double	sin	(double);
+extern	double	cos	(double);
+extern	double	acos	(double);
+extern	double	tan	(double);
+extern	double	atan	(double);
+extern	double	sqrt	(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		(double, double, double, double, double, char *);
+static	double	latlong		(char *, int);
+static	double	greatcircle	(double, double, double, double);
+static	double	waveangle	(double, double, int);
+static	double	propdelay	(double, double, int);
+static	int	finddelay	(double, double, double, double, double, double *);
+static	void	satdoit		(double, double, double, double, double, double, char *);
+static	void	satfinddelay	(double, double, double, double, double *);
+static	double	satpropdelay	(double);
+
+/*
+ * main - parse arguments and handle options
+ */
+int
+main(
+	int argc,
+	char *argv[]
+	)
+{
+	int c;
+	int errflg = 0;
+	double lat1, long1;
+	double lat2, long2;
+	double lat3, long3;
+
+	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(
+	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(
+	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(
+	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(
+	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(
+	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(
+	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(
+	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(
+	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(
+	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/ntp/conf/README b/contrib/ntp/conf/README
new file mode 100644
index 000000000000..f06e44f5ae7c
--- /dev/null
+++ b/contrib/ntp/conf/README
@@ -0,0 +1,17 @@
+README file for directory ./conf of the NTP Version 4 distribution
+
+This directory contains example run-time configuration files for the
+NTP Version 4 daemon ntpd. 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.
+
+See the Config.local.dist file in the base directory for an explanation
+of the defines used.
+
+The files Config.* are used to generate fullblown binaries suitable for
+distribution with the systems shown as suffix. While this can result
+in some degree of useless code, the degree is small compared to the
+size of the baseline code. The files *.conf are representative NTP
+run-time configuration files, which normally live in /etc/ntp.conf.
diff --git a/contrib/ntp/conf/baldwin.conf b/contrib/ntp/conf/baldwin.conf
new file mode 100644
index 000000000000..0781825f990d
--- /dev/null
+++ b/contrib/ntp/conf/baldwin.conf
@@ -0,0 +1,35 @@
+#
+# NTP configuration file (ntp.conf)
+# baldwin.udel.edu
+#
+# This illustrates the use of an external clock with the local clock
+# driver, as well as a multicast server. The prefer keyword on the
+# local clock driver declares an external clock and that the time of
+# this server should not be wiggled by an NTP peer, unless the
+# external clock comes unstuck. Note the use of the multicast group
+# ID assigned to NTP, 224.0.1.1, which identifies this as a multicast
+# server rather than a broadcast one. The other NTP peers are known
+# stratum-1 chimes intended as backup should the external clock croak.
+#
+peer 127.127.1.0 prefer		# local clock driver
+fudge 127.127.12.0 stratum 0 refid GPS
+broadcast 224.0.1.1 key 6 ttl 127
+peer rackety.udel.edu		# (Sun4c/40 IPC)
+peer barnstable.udel.edu	# (Sun4c/65 SS1+)
+peer mizbeaver.udel.edu		#(Bancomm bc700LAN)
+peer pogo.udel.edu		# (Sun4c/65 SS1+)
+#
+# Miscellaneous stuff
+#
+driftfile /etc/ntp.drift        # path for drift file
+statsdir /baldwin/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
+#
+keys /usr/local/etc/ntp.keys	# path for keys file
+trustedkey 3 4 5 6 14 15	# define trusted keys
+requestkey 15			# key (7) for accessing server variables
+controlkey 15			# key (6) for accessing server variables
diff --git a/contrib/ntp/conf/beauregard.conf b/contrib/ntp/conf/beauregard.conf
new file mode 100644
index 000000000000..72f735b17eae
--- /dev/null
+++ b/contrib/ntp/conf/beauregard.conf
@@ -0,0 +1,23 @@
+#
+# NTP configuration file (ntp.conf)
+# bearegard.udel.edu
+#
+server 127.127.18.1		# NIST ACTS modem driver
+fudge 127.127.18.1 time1 .0035
+phone atdt913034944774 atdt913034944785 atdt913034944774
+#phone atdt913034944812 atdt913034948497 atdt913034948022
+#
+# Miscellaneous stuff
+#
+driftfile /etc/ntp.drift	# path for drift file
+statsdir /beauregard/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
+#
+keys /usr/local/etc/ntp.keys	# path for keys file
+trustedkey 3 4 5 6 14 15	# define trusted keys
+requestkey 15			# key (7) for accessing server variables
+controlkey 15			# key (6) for accessing server variables
diff --git a/contrib/ntp/conf/dewey.conf b/contrib/ntp/conf/dewey.conf
new file mode 100644
index 000000000000..ea4f3d4f4844
--- /dev/null
+++ b/contrib/ntp/conf/dewey.conf
@@ -0,0 +1,42 @@
+#
+# NTP configuration file (ntp.conf)
+#
+# Generic configuration file for UDel NTP stratum-2 time servers. Don't
+# forget each server should have a /etc/ntp.drift and /etc/ntp.keys file.
+#
+# Stratum-1 peers. Each server should chime two different stratum-1
+# servers from the following list. Each stratum-1 server should be used
+# only once.
+#
+#peer 128.8.10.1		# umd1.umd.edu
+#peer 18.72.0.3 version 2	# bitsy.mit.edu
+peer 132.249.16.1		# fuzz.sdsc.edu
+peer 128.118.46.3 version 2     # otc1.psu.edu
+#peer 128.9.2.129		# wwvb.isi.edu
+#peer 130.43.2.2 version 2	# apple.com
+#peer 16.1.0.22			# clepsydra.dec.com
+#peer 130.105.1.156 version 2	# clock.osf.orga
+#peer 128.96.60.5 version 2	# pi.bellcore.com
+#peer 128.4.1.1			# rackety.udel.edu
+#peer 129.116.3.5		# shorty.chpc.utexas.edu
+#
+# Stratum-2 peers. Each server should chime all of the others in this
+# list except itself.
+#
+peer 128.175.1.1		# huey.udel.edu (VAX)
+#peer 128.175.1.2		# dewey.udel.edu (VAX)
+peer 128.175.1.3		# louie.udel.edu (SPARC)
+peer 128.175.2.15		# snow-white.ee.udel.edu (SPARC)
+peer 128.175.7.4		# sol.cis.udel.edu (SPARC)
+#
+# Miscellaneous stuff
+#
+driftfile /etc/ntp.drift	# path for drift file
+#
+# Authentication stuff. Note the different authentication delay on
+# VAX and SPARC.
+#
+keys /usr/local/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
diff --git a/contrib/ntp/conf/grundoon.conf b/contrib/ntp/conf/grundoon.conf
new file mode 100644
index 000000000000..44629230e6ac
--- /dev/null
+++ b/contrib/ntp/conf/grundoon.conf
@@ -0,0 +1,154 @@
+#
+# NTP configuration file (ntp.conf)
+# grundoon.udel.edu
+#
+# This machine can best be described as the kitchen sink. It has, in
+# addition to the baseboard tty ports ttya and ttyb, an 8-line
+# Serial/Parallel Interface (SPIF) with ports ttyz00 through ttyz07. The
+# configuration includes the following drivers, clock addresses and Unix
+# device names.
+#
+# Local Clock			127.127.1.0	/dev/audio
+# PST 1020 WWV/WWVH Receiver	127.127.3.1	/dev/pst1
+# Spectracom 8170 WWVB Receiver	127.127.4.1	/dev/wwvb1
+# IRIG Audio Decoder		127.127.6.0	/dev/audio
+# Scratchbuilt CHU Receiver	127.127.7.1	/dev/chu1
+# NIST ACTS modem		127.127.18.1	/dev/acts1
+# Heath GC-1000 WWV Receiver	127.127.19.1	/dev/pst1
+# PPS Clock			127.127.22.1	none
+#
+# This machine has the kernel modifications described in the README.kern
+# file, as well as the tty_clk, tty_chu and ppsclock streams modules.
+#
+# Spectracom 8170/Netclock-2 WWVB receiver. This receiver is equipped
+# with a 1-pps and IRIG outputs. The 1-pps signal is connected via the
+# ppsclock streams module and the carrier detect line of the CHU
+# receiver below (ttyb). The IRIG signal is connected via an attenuator
+# to the audio port (/dev/audio). The propagation delay computed from
+# geographical coordinates is 8.8 ms, while the receiver delay
+# calibrated at the factory is 17.3 ms, for a total delay of 26.1 ms.
+# This is confirmed within 0.1 ms at the 1-pps signal output using a
+# portable cesium clock. We add a fudge time1 of 3.5 ms so the driver
+# time agrees with the 1-pps signal to within 1 ms. The fudge flag4 is
+# set to cause the receiver to dump the quality table once each day to
+# the clockstats file. 
+
+#
+#server 127.127.4.1		# /dev/wwvb1 -> /dev/ttyz03
+#fudge 127.127.4.1 time1 0.0035 flag4 1
+#
+# IRIG Audio Decoder. The IRGI signal of the Spectracom WWVB receiver is
+# connected to the audio codec via a resistor attenuator. We add a fudge
+# time1 of 3.5 ms so the driver agrees with the calibrated 1-pps signal
+# to within 0.1 ms. We also specify a reference ID of WWVB to indicate
+# the signal origin. Note the prefer keyword in the server line, which
+# favors this driver over all others that survive the clock selection
+# algorithm. See README.refclock for further insight on this feature.
+#
+server 127.127.6.0 prefer	# /dev/audio
+fudge 127.127.6.0 time1 0.0005 refid WWVB
+
+#
+# PST/Traconex 1020 WWV/WWVH Receier. The internal DIPswitches are set
+# as near as possible to the delays to WWV (8.8 ms) and WWVH (28.1 ms),
+# as computed from geographical coordinates. We add a fudge time1 of 5.9
+# ms so the driver time agrees with the 1-pps signal to within 1 ms for
+# WWV. We also set the stratum to 1, so this receiver will not normally
+# be selected, unless the primary WWVB receiver comes unstuck.
+#
+server 127.127.3.1		# /dev/pst1 -> ttyz05
+fudge 127.127.3.1 time1 0.0059 stratum 1
+
+#
+# Scratchbuilt CHU Receiver. The audio signal from a computer controlled
+# CHU receiver is connected to a gadget box, which contains a 103A modem
+# chip and level converter operating at 300 bps. The propagation delay
+# computed from geographical coordinates is 3.0 ms, which is the value
+# of the fudge time1 parameter. We add a fudge time2 of 9.9 ms so that
+# the driver time agrees with the 1-pps signal to within a few ms,
+# ordinarily the best possible with this receiver. The fudge flag3 is
+# set because the 1-pps signal happens to be connected vit the carrier
+# detect line on this port (ttyb). We also set the stratum to 1, so this
+# receiver will not normally be selected, unless the primary WWVB
+# receiver comes unstuck.
+#
+server 127.127.7.1		# /dev/chu1 -> /dev/ttyb
+fudge 127.127.7.1 time1 0.0030 time2 0.0099 flag3 1 stratum 1
+
+#
+# NIST Automated Computer Time Service. This driver calls a special
+# telephone number in Boulder, CO, to fetch the time directly from the
+# NIST cesium farm. The details of the complicated calling program are
+# in the README.refclock file. The Practical Peripherals 9600SA modem
+# does not work correctly with the ACTS echo-delay scheme for
+# automatically calculating the propagation delay, so the fudge flag2 is
+# set to disable the feature. Instead, we add a fudge time1 of 65.0 ms
+# so that the driver time agrees with th e1-pps signal to within 1 ms.
+# The phone command specifies three alternate telephone numbers,
+# including AT modem command prefix, which will be tried one after the
+# other at each measurement attempt. In this case, a cron job is used to
+# set fudge flag1, causing a measurement attempt, every six hours.
+#
+server 127.127.18.1		# /dev/acts1 -> /dev/ttyz00
+fudge 127.127.18.1 time1 0.0650	flag2 1
+phone atdt13034944774 atdt13034944785 atdt13034944774
+
+#
+# Heath GC-1000 Most Accurate Clock. This is a WWV receiver with a
+# claimed accuracy better than 100 ms under "hi spec" conditions, but
+# such conditions are not frequent. The propagation delay DIPswitchs are
+# set to 9 ms, as close as possible to the 8.8 ms computed from
+# geographical coordinates. We add a fudge time2 of 40.0 ms so that the
+# driver time agrees with the 1-pps signal to within 50 ms, ordinarily
+# the best possible with this receiver. We also set the stratum to 1, so
+# this receiver will not normally be selected, unless the primary WWVB
+# receiver comes unstuck.
+#
+server 127.127.19.1		# /dev/heath1 -> ttyz07
+fudge 127.127.19.1 time1 0.040 stratum 1
+
+#
+# Undisciplined Local Clock. This is a fake driver intended for backup
+# and when no outside source of synchronized time is available. The
+# default stratum is usually 3, but in this case we elect to use stratum
+# 0. Since the server line does not have the prefer keyword, this driver
+# is never used for synchronization, unless no other other
+# synchronization source is available. In case the local host is
+# controlled by some external source, such as an external oscillator or
+# another protocol, the prefer keyword would cause the local host to
+# disregard all other synchronization sources, unless the kernel
+# modifications are in use and declare an unsynchronized condition.
+#
+server 127.127.1.0		# local clock
+fudge 127.127.1.0 stratum 0 
+
+#
+# PPS Clock. This driver is used to capture a 1-pps signal when the PPS
+# kernel modifications are not in use. It can be configured for the
+# tty_clk or ppsclock streams module or no module at all, assuming the
+# RS232 connector is properly wired. Normally, the 1-pps signal is
+# generated by a radio clock, in this cast the Spectracom clock
+# 127.127.4.1 also configured for this host. When used this way, the
+# associated radio clock normally has the prefer keyword in the serve
+# command line. The PPS driver then will be selected only if the prefer
+# peer is operating within nominal error bounds. See the README.refclock
+# file for further details.
+#
+#server 127.127.22.1		# pps clock
+
+#
+# Miscellaneous stuff. We enable authentication in order to prevent
+#
+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
+#
+keys /usr/local/etc/ntp.keys	# path for keys file
+trustedkey 1 2 3 4 5 6 14 15	# define trusted keys
+requestkey 15			# key (7) for accessing server variables
+controlkey 15			# key (6) for accessing server variables
diff --git a/contrib/ntp/conf/malarky.conf b/contrib/ntp/conf/malarky.conf
new file mode 100644
index 000000000000..adf5eb39d4d4
--- /dev/null
+++ b/contrib/ntp/conf/malarky.conf
@@ -0,0 +1,24 @@
+#
+# NTP configuration file (ntp.conf)
+#
+# This is for a broadcast/multicast client. Except for the statistics
+# stuff, this can be done with only a commmand line of the form
+#
+# /usr/local/bin/xntpd -a -k /usr/local/bin/ntp.keys -m -t 3
+#
+multicastclient			# listen on default 224.0.1.1
+#
+# Miscellaneous stuff
+#
+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
+#
+keys /usr/local/etc/ntp.keys	# path for key file
+trustedkey 3 4 5 6 14		# define trusted keys
+requestkey 14			# key (7) for accessing server variables
+controlkey 14			# key (6) for accessing server variables
diff --git a/contrib/ntp/conf/pogo.conf b/contrib/ntp/conf/pogo.conf
new file mode 100644
index 000000000000..e97d4c5c7bfd
--- /dev/null
+++ b/contrib/ntp/conf/pogo.conf
@@ -0,0 +1,30 @@
+#
+# NTP configuration file (ntp.conf)
+# pogo.udel.edu
+#
+server 127.127.10.1 prefer	# austron 2201A gps receiver
+peer 128.4.1.1			# rackety.udel.edu (Sun4c/40 IPC)
+peer 128.4.1.2			# mizbeaver.udel.edu (Bancomm bc700LAN)
+peer 128.4.1.4			# barnstable.udel.edu (Sun4c/65 SS1+)
+peer 128.4.1.5 maxpoll 8	# churchy.udel.edu (cisco IGS router)
+peer 132.163.135.130 maxpoll 8	# time_A.timefreq.bldrdoc.gov (Cesium)
+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 (Cesium)
+peer 192.36.143.150 maxpoll 8	# Time1.Stupi.SE (Cesium)
+#
+# Miscellaneous stuff
+#
+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
+#
+keys /usr/local/etc/ntp.keys	# path for keys file
+trustedkey 3 4 5 6 14		# define trusted keys
+requestkey 15			# key (7) for accessing server variables
+controlkey 15			# key (6) for accessing server variables
diff --git a/contrib/ntp/config.guess b/contrib/ntp/config.guess
new file mode 100755
index 000000000000..8ccccbce0367
--- /dev/null
+++ b/contrib/ntp/config.guess
@@ -0,0 +1,1090 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
+#   Free Software Foundation, Inc.
+#
+# This file 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 of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner .
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+# Please send patches to the Autoconf mailing list .
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# Use $HOST_CC if defined. $CC may point to a cross-compiler
+if test x"$CC_FOR_BUILD" = x; then
+  if test x"$HOST_CC" != x; then
+    CC_FOR_BUILD="$HOST_CC"
+  else
+    if test x"$CC" != x; then
+      CC_FOR_BUILD="$CC"
+    else
+      CC_FOR_BUILD=cc
+    fi
+  fi
+fi
+
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    alpha:OSF1:*:*)
+	if test $UNAME_RELEASE = "V4.0"; then
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+	fi
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	cat <$dummy.s
+	.globl main
+	.ent main
+main:
+	.frame \$30,0,\$26,0
+	.prologue 0
+	.long 0x47e03d80 # implver $0
+	lda \$2,259
+	.long 0x47e20c21 # amask $2,$1
+	srl \$1,8,\$2
+	sll \$2,2,\$2
+	sll \$0,3,\$0
+	addl \$1,\$0,\$0
+	addl \$2,\$0,\$0
+	ret \$31,(\$26),1
+	.end main
+EOF
+	$CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+	if test "$?" = 0 ; then
+		./$dummy
+		case "$?" in
+			7)
+				UNAME_MACHINE="alpha"
+				;;
+			15)
+				UNAME_MACHINE="alphaev5"
+				;;
+			14)
+				UNAME_MACHINE="alphaev56"
+				;;
+			10)
+				UNAME_MACHINE="alphapca56"
+				;;
+			16)
+				UNAME_MACHINE="alphaev6"
+				;;
+		esac
+	fi
+	rm -f $dummy.s $dummy
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit 0 ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-cbm-sysv4
+	exit 0;;
+    amiga:NetBSD:*:*)
+      echo m68k-cbm-netbsd${UNAME_RELEASE}
+      exit 0 ;;
+    amiga:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit 0 ;;
+    arc64:OpenBSD:*:*)
+	echo mips64el-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    arc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    hkmips:OpenBSD:*:*)
+	echo mips-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    pmax:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sgi:OpenBSD:*:*)
+	echo mips-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit 0;;
+    arm32:NetBSD:*:*)
+	echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+	exit 0 ;;
+    SR2?01:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit 0 ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit 0 ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    i86pc:SunOS:5.*:*)
+	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit 0 ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit 0 ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    atari*:NetBSD:*:*)
+	echo m68k-atari-netbsd${UNAME_RELEASE}
+	exit 0 ;;
+    atari*:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor 
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    sun3*:NetBSD:*:*)
+	echo m68k-sun-netbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sun3*:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mac68k:NetBSD:*:*)
+	echo m68k-apple-netbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mac68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+	echo m88k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit 0 ;;
+    macppc:NetBSD:*:*)
+        echo powerpc-apple-netbsd${UNAME_RELEASE}
+        exit 0 ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit 0 ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD $dummy.c -o $dummy \
+	  && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+	  && rm $dummy.c $dummy && exit 0
+	rm -f $dummy.c $dummy
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit 0 ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit 0 ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit 0 ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+        if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
+	if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+	     -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	fi
+        else echo i586-dg-dgux${UNAME_RELEASE}
+        fi
+ 	exit 0 ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit 0 ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit 0 ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+	exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i?86:AIX:*:*)
+	echo i386-ibm-aix
+	exit 0 ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		sed 's/^		//' << EOF >$dummy.c
+		#include 
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		$CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+		rm -f $dummy.c $dummy
+		echo rs6000-ibm-aix3.2.5
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit 0 ;;
+    *:AIX:*:4)
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=4.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC NetBSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+              sed 's/^              //' << EOF >$dummy.c
+              #include 
+              #include 
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+	($CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+	rm -f $dummy.c $dummy
+	esac
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    3050*:HI-UX:*:*)
+	sed 's/^	//' << EOF >$dummy.c
+	#include 
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+	rm -f $dummy.c $dummy
+	echo unknown-hitachi-hiuxwe2
+	exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit 0 ;;
+    *9??*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit 0 ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit 0 ;;
+    i?86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit 0 ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit 0 ;;
+    hppa*:OpenBSD:*:*)
+	echo hppa-unknown-openbsd
+	exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:*:*:*)
+	echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE}
+	exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+	exit 0 ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE}
+	exit 0 ;;
+    CRAY*T3E:*:*:*)
+	echo t3e-cray-unicosmk${UNAME_RELEASE}
+	exit 0 ;;
+    CRAY-2:*:*:*)
+	echo cray2-cray-unicos
+        exit 0 ;;
+    F300:UNIX_System_V:*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    F301:UNIX_System_V:*:*)
+       echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+       exit 0 ;;
+    hp3[0-9][05]:NetBSD:*:*)
+	echo m68k-hp-netbsd${UNAME_RELEASE}
+	exit 0 ;;
+    hp300:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    i?86:BSD/386:*:* | i?86:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:FreeBSD:*:*)
+	if test -x /usr/bin/objformat; then
+	    if test "elf" = "`/usr/bin/objformat`"; then
+		echo ${UNAME_MACHINE}-unknown-freebsdelf`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
+		exit 0
+	    fi
+	fi
+	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit 0 ;;
+    *:NetBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+	exit 0 ;;
+    *:OpenBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+	exit 0 ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit 0 ;;
+    i*:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i386-pc-interix
+	exit 0 ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit 0 ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit 0 ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    *:GNU:*:*)
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit 0 ;;
+    *:Linux:*:*)
+	# uname on the ARM produces all sorts of strangeness, and we need to
+	# filter it out.
+	case "$UNAME_MACHINE" in
+	  armv*)		      UNAME_MACHINE=$UNAME_MACHINE ;;
+	  arm* | sa110*)	      UNAME_MACHINE="arm" ;;
+	esac
+
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	ld_help_string=`cd /; ld --help 2>&1`
+	ld_supported_emulations=`echo $ld_help_string \
+			 | sed -ne '/supported emulations:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported emulations: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_emulations" in
+	  i?86linux)  echo "${UNAME_MACHINE}-pc-linux-gnuaout"      ; exit 0 ;;
+	  i?86coff)   echo "${UNAME_MACHINE}-pc-linux-gnucoff"      ; exit 0 ;;
+	  sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+	  armlinux)   echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+	  m68klinux)  echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+	  elf32ppc)
+		# Determine Lib Version
+		cat >dummy.c <
+#if defined(__GLIBC__)
+extern char __libc_version[];
+extern char __libc_release[];
+#endif
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+#if defined(__GLIBC__)
+  printf("%s %s\n", __libc_version, __libc_release);
+#else
+  printf("unkown\n");
+#endif
+  return 0;
+}
+EOF
+		LIBC=""
+		${CC-cc} dummy.c -o dummy 2>/dev/null
+		if test "$?" = 0 ; then
+			./dummy | grep 1\.99 > /dev/null
+			if test "$?" = 0 ; then
+				LIBC="libc1"
+			fi
+		fi	
+		rm -f dummy.c dummy
+		echo powerpc-unknown-linux-gnu${LIBC} ; exit 0 ;;
+	esac
+
+	if test "${UNAME_MACHINE}" = "alpha" ; then
+		sed 's/^	//'  <$dummy.s
+		.globl main
+		.ent main
+	main:
+		.frame \$30,0,\$26,0
+		.prologue 0
+		.long 0x47e03d80 # implver $0
+		lda \$2,259
+		.long 0x47e20c21 # amask $2,$1
+		srl \$1,8,\$2
+		sll \$2,2,\$2
+		sll \$0,3,\$0
+		addl \$1,\$0,\$0
+		addl \$2,\$0,\$0
+		ret \$31,(\$26),1
+		.end main
+EOF
+		LIBC=""
+		$CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+		if test "$?" = 0 ; then
+			./$dummy
+			case "$?" in
+			7)
+				UNAME_MACHINE="alpha"
+				;;
+			15)
+				UNAME_MACHINE="alphaev5"
+				;;
+			14)
+				UNAME_MACHINE="alphaev56"
+				;;
+			10)
+				UNAME_MACHINE="alphapca56"
+				;;
+			16)
+				UNAME_MACHINE="alphaev6"
+				;;
+			esac
+
+			objdump --private-headers $dummy | \
+			  grep ld.so.1 > /dev/null
+			if test "$?" = 0 ; then
+				LIBC="libc1"
+			fi
+		fi
+		rm -f $dummy.s $dummy
+		echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+	elif test "${UNAME_MACHINE}" = "mips" ; then
+	  cat >$dummy.c </dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+	  rm -f $dummy.c $dummy
+	else
+	  # Either a pre-BFD a.out linker (linux-gnuoldld)
+	  # or one that does not give us useful --help.
+	  # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+	  # If ld does not provide *any* "supported emulations:"
+	  # that means it is gnuoldld.
+	  echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
+	  test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+	  case "${UNAME_MACHINE}" in
+	  i?86)
+	    VENDOR=pc;
+	    ;;
+	  *)
+	    VENDOR=unknown;
+	    ;;
+	  esac
+	  # Determine whether the default compiler is a.out or elf
+	  cat >$dummy.c <
+#ifdef __cplusplus
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+#  if __GLIBC__ >= 2
+    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+#  else
+    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+#  endif
+# else
+   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+	  $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+	  rm -f $dummy.c $dummy
+	fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i?86:DYNIX/ptx:4*:*)
+	echo i386-sequent-sysv4
+	exit 0 ;;
+    i?86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit 0 ;;
+    i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+	fi
+	exit 0 ;;
+    i?86:*:5:7*)
+	UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+	(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+	(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) && UNAME_MACHINE=i586
+	(/bin/uname -X|egrep '^Machine.*Pent.*II' >/dev/null) && UNAME_MACHINE=i686
+	(/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) && UNAME_MACHINE=i585
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}${UNAME_VERSION}-sysv${UNAME_RELEASE}
+	exit 0 ;;
+    i?86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit 0 ;;
+    pc:*:*:*)
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+	echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit 0 ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit 0 ;;
+    M68*:*:R3V[567]*:*)
+	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit 0 ;;
+    i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit 0 ;;
+    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                           # says 
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes .
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit 0 ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit 0 ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit 0 ;;
+    news*:NEWS-OS:*:6*)
+	echo mips-sony-newsos6
+	exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit 0 ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit 0 ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:"Mac OS":*:*)
+	echo `uname -p`-apple-macos${UNAME_RELEASE}
+	exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <
+# include 
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include 
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+  printf ("vax-dec-bsd\n"); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit 0 ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit 0 ;;
+    c34*)
+	echo c34-convex-bsd
+	exit 0 ;;
+    c38*)
+	echo c38-convex-bsd
+	exit 0 ;;
+    c4*)
+	echo c4-convex-bsd
+	exit 0 ;;
+    esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/contrib/ntp/config.h.in b/contrib/ntp/config.h.in
new file mode 100644
index 000000000000..f722c7de78eb
--- /dev/null
+++ b/contrib/ntp/config.h.in
@@ -0,0 +1,887 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if type char is unsigned and you are not using gcc.  */
+#ifndef __CHAR_UNSIGNED__
+#undef __CHAR_UNSIGNED__
+#endif
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to `int' if  doesn't define.  */
+#undef gid_t
+
+/* Define as __inline if that's what the C compiler calls it.  */
+#undef inline
+
+/* Define if on MINIX.  */
+#undef _MINIX
+
+/* Define if your struct nlist has an n_un member.  */
+#undef NLIST_NAME_UNION
+
+/* Define if you have .  */
+#undef NLIST_STRUCT
+
+/* Define to `long' if  doesn't define.  */
+#undef off_t
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if  doesn't define.  */
+#undef size_t
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both  and .  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your  declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define to `int' if  doesn't define.  */
+#undef uid_t
+
+/* Define if your processor stores words with the most significant
+   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
+#undef WORDS_BIGENDIAN
+
+/* debugging code */
+#undef DEBUG
+
+/* Minutes per DST adjustment */
+#undef DSTMINUTES
+
+/* MD5 authentication */
+#undef MD5
+
+/* DES authentication (COCOM only) */
+#undef DES
+
+/* time_t */
+#undef time_t
+
+/* reference clock interface */
+#undef REFCLOCK
+
+/* Audio CHU? */
+#undef AUDIO_CHU
+
+/* ACTS modem service */
+#undef CLOCK_ACTS
+
+/* Arbiter 1088A/B GPS receiver */
+#undef CLOCK_ARBITER
+
+/* DHD19970505: ARCRON support. */
+#undef CLOCK_ARCRON_MSF
+
+/* Austron 2200A/2201A GPS receiver */
+#undef CLOCK_AS2201
+
+/* PPS interface */
+#undef CLOCK_ATOM
+
+/* PPS auxiliary interface for ATOM */
+#undef PPS_SAMPLE
+
+/* Datum/Bancomm bc635/VME interface */
+#undef CLOCK_BANC
+
+/* ELV/DCF7000 clock */
+#undef CLOCK_DCF7000
+
+/* HOPF 6021 clock */
+#undef CLOCK_HOPF6021
+
+/* Meinberg clocks */
+#undef CLOCK_MEINBERG
+
+/* DCF77 raw time code */
+#undef CLOCK_RAWDCF
+
+/* RCC 8000 clock */
+#undef CLOCK_RCC8000
+
+/* Schmid DCF77 clock */
+#undef CLOCK_SCHMID
+
+/* Trimble GPS receiver/TAIP protocol */
+#undef CLOCK_TRIMTAIP
+
+/* Trimble GPS receiver/TSIP protocol */
+#undef CLOCK_TRIMTSIP
+
+/* WHARTON 400A Series protocol */
+#undef CLOCK_WHARTON_400A
+
+/* VARITEXT protocol */
+#undef CLOCK_VARITEXT
+
+/* Diems Computime Radio Clock */
+#undef CLOCK_COMPUTIME
+
+/* Datum Programmable Time System */
+#undef CLOCK_DATUM
+
+/* TrueTime GPS receiver/VME interface */
+#undef CLOCK_GPSVME
+
+/* Heath GC-1000 WWV/WWVH receiver */
+#undef CLOCK_HEATH
+
+/* HP 58503A GPS receiver */
+#undef CLOCK_HPGPS
+
+/* Sun IRIG audio decoder */
+#undef CLOCK_IRIG
+
+/* Rockwell Jupiter GPS clock */
+#undef CLOCK_JUPITER
+
+/* Leitch CSD 5300 Master Clock System Driver */
+#undef CLOCK_LEITCH
+
+/* local clock reference */
+#undef CLOCK_LOCAL
+
+/* EES M201 MSF receiver */
+#undef CLOCK_MSFEES
+
+/* Magnavox MX4200 GPS receiver */
+#undef CLOCK_MX4200
+
+/* NMEA GPS receiver */
+#undef CLOCK_NMEA
+
+/* Palisade clock */
+#undef CLOCK_PALISADE
+
+/* PARSE driver interface */
+#undef CLOCK_PARSE
+
+/* PARSE kernel PLL PPS support */
+#undef PPS_SYNC
+
+/* PCL 720 clock support */
+#undef CLOCK_PPS720
+
+/* PST/Traconex 1020 WWV/WWVH receiver */
+#undef CLOCK_PST
+
+/* PTB modem service */
+#undef CLOCK_PTBACTS
+
+/* clock thru shared memory */
+#undef CLOCK_SHM
+
+/* Motorola UT Oncore GPS */
+#undef CLOCK_ONCORE
+
+/* KSI/Odetics TPRO/S GPS receiver/IRIG interface */
+#undef CLOCK_TPRO
+
+/* TRAK 8810 GPS receiver */
+#undef CLOCK_TRAK
+
+/* Kinemetrics/TrueTime receivers */
+#undef CLOCK_TRUETIME
+
+/* USNO modem service */
+#undef CLOCK_USNO
+
+/* Spectracom 8170/Netclock/2 WWVB receiver */
+#undef CLOCK_WWVB
+
+/* Ultralink M320 WWVB receiver */
+#undef CLOCK_ULINK
+
+/* Chronolog K-series WWVB receiver */
+#undef CLOCK_CHRONOLOG
+
+/* Dumb generic hh:mm:ss local clock */
+#undef CLOCK_DUMBCLOCK
+
+/* define if we need to declare int errno; */
+#undef DECL_ERRNO
+
+/* define if we may declare int h_errno; */
+#undef DECL_H_ERRNO
+
+/* define if it's OK to declare char *sys_errlist[]; */
+#undef CHAR_SYS_ERRLIST
+
+/* define if it's OK to declare int syscall P((int, struct timeval *, struct timeval *)); */
+#undef DECL_SYSCALL
+
+/* define if we have syscall is buggy (Solaris 2.4) */
+#undef SYSCALL_BUG
+
+/* Do we need extra room for SO_RCVBUF? (HPUX <8) */
+#undef NEED_RCVBUF_SLOP
+
+/* Should we open the broadcast socket? */
+#undef OPEN_BCAST_SOCKET
+
+/* Do we want the HPUX FindConfig()? */
+#undef NEED_HPUX_FINDCONFIG
+
+/* canonical system (cpu-vendor-os) string */
+#undef STR_SYSTEM
+
+/* define if NetInfo support is available */
+#undef HAVE_NETINFO
+
+/* define if [gs]ettimeofday() only takes 1 argument */
+#undef SYSV_TIMEOFDAY
+
+/* define if struct sockaddr has sa_len */
+#undef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
+
+/* define if struct clockinfo has hz */
+#undef HAVE_HZ_IN_STRUCT_CLOCKINFO
+
+/* define if struct sigaction has sa_sigaction */
+#undef HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION
+
+/* define if struct clockinfo has tickadj */
+#undef HAVE_TICKADJ_IN_STRUCT_CLOCKINFO
+
+/* define if struct ntptimeval uses time.tv_nsec instead of time.tv_usec */ 
+#undef HAVE_TV_NSEC_IN_NTPTIMEVAL 
+
+/* Does a system header defind struct ppsclockev? */
+#undef HAVE_STRUCT_PPSCLOCKEV
+
+/* define if function prototypes are OK */
+#undef HAVE_PROTOTYPES
+
+/* define if setpgrp takes 0 arguments */
+#undef HAVE_SETPGRP_0
+
+/* hardwire a value for tick? */
+#undef PRESET_TICK
+
+/* hardwire a value for tickadj? */
+#undef PRESET_TICKADJ
+
+/* is adjtime() accurate? */
+#undef ADJTIME_IS_ACCURATE
+
+/* should we NOT read /dev/kmem? */
+#undef NOKMEM
+
+/* use UDP Wildcard Delivery? */
+#undef UDP_WILDCARD_DELIVERY
+
+/* always slew the clock? */
+#undef SLEWALWAYS
+
+/* step, then slew the clock? */
+#undef STEP_SLEW
+
+/* force ntpdate to step the clock if !defined(STEP_SLEW) ? */
+#undef FORCE_NTPDATE_STEP
+
+/* synch TODR hourly? */
+#undef DOSYNCTODR
+
+/* do we set process groups with -pid? */
+#undef UDP_BACKWARDS_SETOWN
+
+/* must we have a CTTY for fsetown? */
+#undef USE_FSETOWNCTTY
+
+/* can we use SIGIO for tcp and udp IO? */
+#undef HAVE_SIGNALED_IO
+
+/* can we use SIGPOLL for UDP? */
+#undef USE_UDP_SIGPOLL
+
+/* can we use SIGPOLL for tty IO? */
+#undef USE_TTY_SIGPOLL
+
+/* do we want the CHU driver? */
+#undef CLOCK_CHU
+
+/* do we have the ppsclock streams module? */
+#undef PPS
+
+/* do we have the tty_clk line discipline/streams module? */
+#undef TTYCLK
+
+/* does the kernel support precision time discipline? */
+#undef KERNEL_PLL
+
+/* does the kernel support multicasting IP? */
+#undef MCAST
+
+/* do we have ntp_{adj,get}time in libc? */
+#undef NTP_SYSCALLS_LIBC
+
+/* do we have ntp_{adj,get}time in the kernel? */
+#undef NTP_SYSCALLS_STD
+
+/* do we have STREAMS/TLI? (Can we replace this with HAVE_SYS_STROPTS_H? */
+#undef STREAMS_TLI
+
+/* do we need an s_char typedef? */
+#undef NEED_S_CHAR_TYPEDEF
+
+/* does SIOCGIFCONF return size in the buffer? */
+#undef SIZE_RETURNED_IN_BUFFER
+
+/* what is the name of TICK in the kernel? */
+#undef K_TICK_NAME
+
+/* Is K_TICK_NAME (nsec_per_tick, for example) in nanoseconds? */
+#undef TICK_NANO
+
+/* what is the name of TICKADJ in the kernel? */
+#undef K_TICKADJ_NAME
+
+/* Is K_TICKADJ_NAME (hrestime_adj, for example) in nanoseconds? */
+#undef TICKADJ_NANO
+
+/* what is (probably) the name of DOSYNCTODR in the kernel? */
+#undef K_DOSYNCTODR_NAME
+
+/* what is (probably) the name of NOPRINTF in the kernel? */
+#undef K_NOPRINTF_NAME
+
+/* do we need HPUX adjtime() library support? */
+#undef NEED_HPUX_ADJTIME
+
+/* Might nlist() values require an extra level of indirection (AIX)? */
+#undef NLIST_EXTRA_INDIRECTION
+
+/* Should we recommend a minimum value for tickadj? */
+#undef MIN_REC_TICKADJ
+
+/* Is there a problem using PARENB and IGNPAR (IRIX)? */
+#undef NO_PARENB_IGNPAR
+
+/* Should we not IGNPAR (Linux)? */
+#undef RAWDCF_NO_IGNPAR
+
+/* Does the compiler like "volatile"? */
+#undef volatile
+
+/* Does qsort expect to work on "void *" stuff? */
+#undef QSORT_USES_VOID_P
+
+/* What is the fallback value for HZ? */
+#undef DEFAULT_HZ
+
+/* Do we need to override the system's idea of HZ? */
+#undef OVERRIDE_HZ
+
+/* Do we want the SCO clock hacks? */
+#undef SCO5_CLOCK
+
+/* Do we want the ReliantUNIX clock hacks? */
+#undef RELIANTUNIX_CLOCK
+
+/* Does the kernel have an FLL bug? */
+#undef KERNEL_FLL_BUG
+
+/* Define if you have the TIOCGPPSEV ioctl (Solaris) */
+#undef HAVE_TIOCGPPSEV
+
+/* Define if you have the TIOCSPPS ioctl (Solaris) */
+#undef HAVE_TIOCSPPS
+
+/* Define if you have the CIOGETEV ioctl (SunOS, Linux) */
+#undef HAVE_CIOGETEV
+
+/* Define if you have the TIOCGSERIAL, TIOCSSERIAL, ASYNC_PPS_CD_POS, and ASYNC_PPS_CD_NEG ioctls (linux) */
+#undef HAVE_TIO_SERIAL_STUFF
+
+/* Define if you use struct timespec rather than struct timeval (time in ns rather than us) */
+#undef HAVE_TIMESPEC
+
+/* Define if you have the interface in the Draft RFC */
+#undef HAVE_PPSAPI
+
+/* Do we need to #define _SVID3 when we #include ? */
+#undef TERMIOS_NEEDS__SVID3
+
+/* adjtime()? */
+#undef DECL_ADJTIME_0
+
+/* bcopy()? */
+#undef DECL_BCOPY_0
+
+/* bzero()? */
+#undef DECL_BZERO_0
+
+/* cfset[io]speed()? */
+#undef DECL_CFSETISPEED_0
+
+/* ioctl()? */
+#undef DECL_IOCTL_0
+
+/* IPC? (bind, connect, recvfrom, sendto, setsockopt, socket) */
+#undef DECL_IPC_0
+
+/* memmove()? */
+#undef DECL_MEMMOVE_0
+
+/* mkstemp()? */
+#undef DECL_MKSTEMP_0
+
+/* mktemp()? */
+#undef DECL_MKTEMP_0
+
+/* mrand48()? */
+#undef DECL_MRAND48_0
+
+/* nlist()? */
+#undef DECL_NLIST_0
+
+/* plock()? */
+#undef DECL_PLOCK_0
+
+/* rename()? */
+#undef DECL_RENAME_0
+
+/* select()? */
+#undef DECL_SELECT_0
+
+/* setitimer()? */
+#undef DECL_SETITIMER_0
+
+/* setpriority()? */
+#undef DECL_SETPRIORITY_0
+#undef DECL_SETPRIORITY_1
+
+/* sigvec()? */
+#undef DECL_SIGVEC_0
+
+/* srand48()? */
+#undef DECL_SRAND48_0
+
+/* stdio stuff? */
+#undef DECL_STDIO_0
+
+/* stime()? */
+#undef DECL_STIME_0
+
+/* strtol()? */
+#undef DECL_STRTOL_0
+
+/* syslog() stuff? */
+#undef DECL_SYSLOG_0
+
+/* time()? */
+#undef DECL_TIME_0
+
+/* [gs]ettimeofday()? */
+#undef DECL_TIMEOFDAY_0
+
+/* tolower()? */
+#undef DECL_TOLOWER_0
+
+/* toupper()? */
+#undef DECL_TOUPPER_0
+
+/* The number of bytes in a int.  */
+#undef SIZEOF_INT
+
+/* The number of bytes in a long.  */
+#undef SIZEOF_LONG
+
+/* The number of bytes in a signed char.  */
+#undef SIZEOF_SIGNED_CHAR
+
+/* Define if you have the K_open function.  */
+#undef HAVE_K_OPEN
+
+/* Define if you have the __adjtimex function.  */
+#undef HAVE___ADJTIMEX
+
+/* Define if you have the __ntp_gettime function.  */
+#undef HAVE___NTP_GETTIME
+
+/* Define if you have the clock_settime function.  */
+#undef HAVE_CLOCK_SETTIME
+
+/* Define if you have the daemon function.  */
+#undef HAVE_DAEMON
+
+/* Define if you have the getbootfile function.  */
+#undef HAVE_GETBOOTFILE
+
+/* Define if you have the getdtablesize function.  */
+#undef HAVE_GETDTABLESIZE
+
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the gettimeofday function.  */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define if you have the getuid function.  */
+#undef HAVE_GETUID
+
+/* Define if you have the kvm_open function.  */
+#undef HAVE_KVM_OPEN
+
+/* Define if you have the memcpy function.  */
+#undef HAVE_MEMCPY
+
+/* Define if you have the memlk function.  */
+#undef HAVE_MEMLK
+
+/* Define if you have the memmove function.  */
+#undef HAVE_MEMMOVE
+
+/* Define if you have the memset function.  */
+#undef HAVE_MEMSET
+
+/* Define if you have the mkstemp function.  */
+#undef HAVE_MKSTEMP
+
+/* Define if you have the mktime function.  */
+#undef HAVE_MKTIME
+
+/* Define if you have the mlockall function.  */
+#undef HAVE_MLOCKALL
+
+/* Define if you have the mrand48 function.  */
+#undef HAVE_MRAND48
+
+/* Define if you have the nice function.  */
+#undef HAVE_NICE
+
+/* Define if you have the nlist function.  */
+#undef HAVE_NLIST
+
+/* Define if you have the ntp_adjtime function.  */
+#undef HAVE_NTP_ADJTIME
+
+/* Define if you have the ntp_gettime function.  */
+#undef HAVE_NTP_GETTIME
+
+/* Define if you have the plock function.  */
+#undef HAVE_PLOCK
+
+/* Define if you have the pututline function.  */
+#undef HAVE_PUTUTLINE
+
+/* Define if you have the pututxline function.  */
+#undef HAVE_PUTUTXLINE
+
+/* Define if you have the random function.  */
+#undef HAVE_RANDOM
+
+/* Define if you have the rtprio function.  */
+#undef HAVE_RTPRIO
+
+/* Define if you have the sched_setscheduler function.  */
+#undef HAVE_SCHED_SETSCHEDULER
+
+/* Define if you have the setlinebuf function.  */
+#undef HAVE_SETLINEBUF
+
+/* Define if you have the setpgid function.  */
+#undef HAVE_SETPGID
+
+/* Define if you have the setpriority function.  */
+#undef HAVE_SETPRIORITY
+
+/* Define if you have the setsid function.  */
+#undef HAVE_SETSID
+
+/* Define if you have the settimeofday function.  */
+#undef HAVE_SETTIMEOFDAY
+
+/* Define if you have the setvbuf function.  */
+#undef HAVE_SETVBUF
+
+/* Define if you have the sigaction function.  */
+#undef HAVE_SIGACTION
+
+/* Define if you have the sigset function.  */
+#undef HAVE_SIGSET
+
+/* Define if you have the sigsuspend function.  */
+#undef HAVE_SIGSUSPEND
+
+/* Define if you have the sigvec function.  */
+#undef HAVE_SIGVEC
+
+/* Define if you have the srand48 function.  */
+#undef HAVE_SRAND48
+
+/* Define if you have the srandom function.  */
+#undef HAVE_SRANDOM
+
+/* Define if you have the stime function.  */
+#undef HAVE_STIME
+
+/* Define if you have the strchr function.  */
+#undef HAVE_STRCHR
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the sysconf function.  */
+#undef HAVE_SYSCONF
+
+/* Define if you have the sysctl function.  */
+#undef HAVE_SYSCTL
+
+/* Define if you have the timer_create function.  */
+#undef HAVE_TIMER_CREATE
+
+/* Define if you have the timer_settime function.  */
+#undef HAVE_TIMER_SETTIME
+
+/* Define if you have the umask function.  */
+#undef HAVE_UMASK
+
+/* Define if you have the uname function.  */
+#undef HAVE_UNAME
+
+/* Define if you have the updwtmp function.  */
+#undef HAVE_UPDWTMP
+
+/* Define if you have the updwtmpx function.  */
+#undef HAVE_UPDWTMPX
+
+/* Define if you have the vsprintf function.  */
+#undef HAVE_VSPRINTF
+
+/* Define if you have the  header file.  */
+#undef HAVE__SYS_SYNC_QUEUE_H
+
+/* Define if you have the  header file.  */
+#undef HAVE__SYS_SYNC_SEMA_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_ARPA_NAMESER_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_BSTRING_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_ERRNO_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_MACHINE_INLINE_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_NET_IF_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_NETDB_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_NETINET_IN_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_NETINET_IP_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_NETINFO_NI_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_POLL_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_RESOLV_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SCHED_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SGTTY_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_STDLIB_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SUN_AUDIOIO_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_AUDIOIO_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_CLKDEFS_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_FILE_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_I8253_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_LOCK_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_MMAN_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_MODEM_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_PCL720_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_PPSCLOCK_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_PPSTIME_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_PROC_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_SCHED_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_SIO_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_STAT_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_STREAM_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_STROPTS_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_SYSCTL_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_SYSSGI_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_TERMIOS_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_TIMEPPS_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_TIMERS_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_TIMEX_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_TPRO_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_TYPES_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_TERMIO_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_TERMIOS_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_TIMEPPS_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_TIMEX_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_UTMP_H
+
+/* Define if you have the  header file.  */
+#undef HAVE_UTMPX_H
+
+/* Define if you have the advapi32 library (-ladvapi32).  */
+#undef HAVE_LIBADVAPI32
+
+/* Define if you have the elf library (-lelf).  */
+#undef HAVE_LIBELF
+
+/* Define if you have the gen library (-lgen).  */
+#undef HAVE_LIBGEN
+
+/* Define if you have the kvm library (-lkvm).  */
+#undef HAVE_LIBKVM
+
+/* Define if you have the ld library (-lld).  */
+#undef HAVE_LIBLD
+
+/* Define if you have the mld library (-lmld).  */
+#undef HAVE_LIBMLD
+
+/* Define if you have the nsl library (-lnsl).  */
+#undef HAVE_LIBNSL
+
+/* Define if you have the rt library (-lrt).  */
+#undef HAVE_LIBRT
+
+/* Define if you have the socket library (-lsocket).  */
+#undef HAVE_LIBSOCKET
+
+/* Name of package */
+#undef PACKAGE
+
+/* Version number of package */
+#undef VERSION
+
+/* Define if compiler has function prototypes */
+#undef PROTOTYPES
+
+/* Do we have struct ntptimeval? */
+#undef HAVE_STRUCT_NTPTIMEVAL
+
+/* Does ntptimeval use struct timespec? */
+#undef TIMESPEC_IN_NTPTIMEVAL
+
diff --git a/contrib/ntp/config.sub b/contrib/ntp/config.sub
new file mode 100755
index 000000000000..eaa862353f38
--- /dev/null
+++ b/contrib/ntp/config.sub
@@ -0,0 +1,1215 @@
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+#   Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file 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 of the License, 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+	echo Configuration name missing. 1>&2
+	echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+	echo "or     $0 ALIAS" 1>&2
+	echo where ALIAS is a recognized configuration type. 1>&2
+	exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+	*local*)
+		echo $1
+		exit 0
+		;;
+	*)
+	;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  linux-gnu*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple)
+		os=
+		basic_machine=$1
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=vxworks
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+		| arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
+		| 580 | i960 | h8300 \
+		| hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+		| alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \
+		| we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
+		| 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
+		| mips64orion | mips64orionel | mipstx39 | mipstx39el \
+		| mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
+		| mips64vr5000 | miprs64vr5000el \
+		| sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
+		| thumb | d10v)
+		basic_machine=$basic_machine-unknown
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65)
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i[34567]86)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
+	      | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+	      | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
+	      | xmp-* | ymp-* \
+	      | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \
+	      | alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \
+	      | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
+	      | clipper-* | orion-* \
+	      | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+	      | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
+	      | mips64el-* | mips64orion-* | mips64orionel-* \
+	      | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
+	      | mipstx39-* | mipstx39el-* \
+	      | f301-* | armv*-* | t3e-* \
+	      | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
+	      | thumb-* | v850-* | d30v-* | tic30-* | c30-* )
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-cbm
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-cbm
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-cbm
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	cray2)
+		basic_machine=cray2-cray
+		os=-unicos
+		;;
+	[ctj]90-cray)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i[34567]86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i[34567]86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i[34567]86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i[34567]86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	i386-go32 | go32)
+		basic_machine=i386-unknown
+		os=-go32
+		;;
+	i386-mingw32 | mingw32)
+		basic_machine=i386-unknown
+		os=-mingw32
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | *MiNT)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mipsel*-linux*)
+		basic_machine=mipsel-unknown
+		os=-linux-gnu
+		;;
+	mips*-linux*)
+		basic_machine=mips-unknown
+		os=-linux-gnu
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	msdos)
+		basic_machine=i386-unknown
+		os=-msdos
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-corel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+        pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pentium | p5 | k5 | k6 | nexen)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexen-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=rs6000-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+	        ;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+	        ;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sparclite-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=t3e-cray
+		os=-unicos
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xmp)
+		basic_machine=xmp-cray
+		os=-unicos
+		;;
+        xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	mips)
+		if [ x$os = x-linux-gnu ]; then
+			basic_machine=mips-unknown
+		else
+			basic_machine=mips-mips
+		fi
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sparc | sparcv9)
+		basic_machine=sparc-sun
+		;;
+        cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	c4x*)
+		basic_machine=c4x-none
+		os=-coff
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -rhapsody* | -macos* | -openstep* | -oskit*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+	      | -macos* | -mpw* | -magic* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-ns2 )
+	        os=-nextstep2
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+        -*mint | -*MiNT)
+	        os=-mint
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-corel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+        *-gould)
+		os=-sysv
+		;;
+        *-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+        *-sgi)
+		os=-irix
+		;;
+        *-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f301-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-vxsim* | -vxworks*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -*MiNT)
+				vendor=atari
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
diff --git a/contrib/ntp/configure b/contrib/ntp/configure
new file mode 100755
index 000000000000..e8fa8143953b
--- /dev/null
+++ b/contrib/ntp/configure
@@ -0,0 +1,10546 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.14.1 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --enable-debugging      + include debugging code"
+ac_help="$ac_help
+  --enable-dst-minutes=60 + minutes per DST adjustment"
+ac_help="$ac_help
+  --enable-md5            + include support for MD5 keys"
+ac_help="$ac_help
+  --enable-BANCOMM        - Datum/Bancomm bc635/VME interface"
+ac_help="$ac_help
+  --enable-GPSVME         - TrueTime GPS receiver/VME interface"
+ac_help="$ac_help
+  --enable-SHM            - SHM clock attached thru shared memory"
+ac_help="$ac_help
+  --enable-all-clocks     + include all suitable non-PARSE clocks:"
+ac_help="$ac_help
+  --enable-ACTS           + ACTS modem service"
+ac_help="$ac_help
+  --enable-ARBITER        + Arbiter 1088A/B GPS receiver"
+ac_help="$ac_help
+  --enable-ARCRON-MSF     + Arcron MSF receiver"
+ac_help="$ac_help
+  --enable-AS2201         + Austron 2200A/2201A GPS receiver"
+ac_help="$ac_help
+  --enable-ATOM           + PPS interface"
+ac_help="$ac_help
+  --enable-CHU            + CHU modem/decoder"
+ac_help="$ac_help
+  --enable-AUDIO-CHU      s - CHU audio/decoder"
+ac_help="$ac_help
+  --enable-DATUM          s Datum Programmable Time System"
+ac_help="$ac_help
+  --enable-HEATH          s Heath GC-1000 WWV/WWVH receiver"
+ac_help="$ac_help
+  --enable-HPGPS          + HP 58503A GPS receiver"
+ac_help="$ac_help
+  --enable-IRIG           s Sun IRIG audio decoder"
+ac_help="$ac_help
+  --enable-LEITCH         + Leitch CSD 5300 Master Clock System Driver"
+ac_help="$ac_help
+  --enable-LOCAL-CLOCK    + local clock reference"
+ac_help="$ac_help
+  --enable-MSFEES         + EES M201 MSF receiver"
+ac_help="$ac_help
+  --enable-MX4200         s Magnavox MX4200 GPS receiver"
+ac_help="$ac_help
+  --enable-NMEA           + NMEA GPS receiver"
+ac_help="$ac_help
+  --enable-ONCORE         + Motorola VP/UT Oncore GPS receiver"
+ac_help="$ac_help
+  --enable-PALISADE       + Palisade clock"
+ac_help="$ac_help
+  --enable-PST            + PST/Traconex 1020 WWV/WWVH receiver"
+ac_help="$ac_help
+  --enable-JUPITER        s Rockwell Jupiter GPS receiver"
+ac_help="$ac_help
+  --enable-PTBACTS        s PTB modem service"
+ac_help="$ac_help
+  --enable-TPRO           s KSI/Odetics TPRO/S GPS receiver/IRIG interface"
+ac_help="$ac_help
+  --enable-TRAK           + TRAK 8810 GPS receiver"
+ac_help="$ac_help
+  --enable-CHRONOLOG      + Chrono-log K-series WWVB receiver"
+ac_help="$ac_help
+  --enable-DUMBCLOCK      + Dumb generic hh:mm:ss local clock"
+ac_help="$ac_help
+  --enable-TRUETIME       s Kinemetrics/TrueTime receivers"
+ac_help="$ac_help
+  --enable-WWVB           + Spectracom 8170/Netclock/2 WWVB receiver"
+ac_help="$ac_help
+  --enable-ULINK           + Ultralink WWVB receiver"
+ac_help="$ac_help
+  --enable-USNO           s USNO modem service"
+ac_help="$ac_help
+  --enable-parse-clocks   - include all suitable PARSE clocks:"
+ac_help="$ac_help
+  --enable-COMPUTIME      s Diem Computime Radio Clock"
+ac_help="$ac_help
+  --enable-DCF7000        s ELV/DCF7000 clock"
+ac_help="$ac_help
+  --enable-HOPF6021       s HOPF 6021 clock"
+ac_help="$ac_help
+  --enable-MEINBERG       s Meinberg clocks"
+ac_help="$ac_help
+  --enable-RAWDCF         s DCF77 raw time code"
+ac_help="$ac_help
+  --enable-RCC8000        s RCC 8000 clock"
+ac_help="$ac_help
+  --enable-SCHMID         s Schmid DCF77 clock"
+ac_help="$ac_help
+  --enable-TRIMTAIP       s Trimble GPS receiver/TAIP protocol"
+ac_help="$ac_help
+  --enable-TRIMTSIP       s Trimble GPS receiver/TSIP protocol"
+ac_help="$ac_help
+  --enable-WHARTON        s WHARTON 400A Series clock"
+ac_help="$ac_help
+  --enable-VARITEXT       s VARITEXT clock"
+ac_help="$ac_help
+  --enable-kmem           s read /dev/kmem for tick and/or tickadj"
+ac_help="$ac_help
+  --enable-accurate-adjtime
+                          s the adjtime() call is accurate"
+ac_help="$ac_help
+  --enable-tick=VALUE     s force a value for 'tick'"
+ac_help="$ac_help
+  --enable-tickadj=VALUE  s force a value for 'tickadj'"
+ac_help="$ac_help
+  --enable-udp-wildcard   s use UDP wildcard delivery"
+ac_help="$ac_help
+  --enable-slew-always    s always slew the time"
+ac_help="$ac_help
+  --enable-step-slew      s step and slew the time"
+ac_help="$ac_help
+  --enable-ntpdate-step   s if ntpdate should step the time"
+ac_help="$ac_help
+  --enable-hourly-todr-sync
+                          s if we should sync TODR hourly"
+ac_help="$ac_help
+  --enable-kernel-fll-bug s if we should avoid a kernel FLL bug"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.14.1"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# 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.
+ac_unique_file=ntpd/ntp_refclock.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+      test -f "$cache_file" && . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:664: checking host system type" >&5
+if test "x$ac_cv_host" = "x" || (test "x$host" != "xNONE" && test "x$host" != "x$ac_cv_host_alias"); then
+
+# Make sure we can run config.sub.
+  if $ac_config_sub sun4 >/dev/null 2>&1; then :
+    else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+  fi
+
+  ac_cv_host_alias=$host
+  case "$ac_cv_host_alias" in
+  NONE)
+    case $nonopt in
+    NONE)
+      if ac_cv_host_alias=`$ac_config_guess`; then :
+      else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+      fi ;;
+    *) ac_cv_host_alias=$nonopt ;;
+    esac ;;
+  esac
+
+  ac_cv_host=`$ac_config_sub $ac_cv_host_alias`
+  ac_cv_host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+  ac_cv_host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+  ac_cv_host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+else
+  echo $ac_n "(cached) $ac_c" 1>&6
+fi
+
+echo "$ac_t""$ac_cv_host" 1>&6
+
+host=$ac_cv_host
+host_alias=$ac_cv_host_alias
+host_cpu=$ac_cv_host_cpu
+host_vendor=$ac_cv_host_vendor
+host_os=$ac_cv_host_os
+
+
+
+
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+echo "configure:705: checking target system type" >&5
+if test "x$ac_cv_target" = "x" || (test "x$target" != "xNONE" && test "x$target" != "x$ac_cv_target_alias"); then
+
+# Make sure we can run config.sub.
+  if $ac_config_sub sun4 >/dev/null 2>&1; then :
+    else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+  fi
+
+  ac_cv_target_alias=$target
+  case "$ac_cv_target_alias" in
+  NONE)
+    case $nonopt in
+    NONE)
+      ac_cv_target_alias=$host_alias ;;
+
+    *) ac_cv_target_alias=$nonopt ;;
+    esac ;;
+  esac
+
+  ac_cv_target=`$ac_config_sub $ac_cv_target_alias`
+  ac_cv_target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+  ac_cv_target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+  ac_cv_target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+else
+  echo $ac_n "(cached) $ac_c" 1>&6
+fi
+
+echo "$ac_t""$ac_cv_target" 1>&6
+
+target=$ac_cv_target
+target_alias=$ac_cv_target_alias
+target_cpu=$ac_cv_target_cpu
+target_vendor=$ac_cv_target_vendor
+target_os=$ac_cv_target_os
+
+
+
+
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:745: checking build system type" >&5
+if test "x$ac_cv_build" = "x" || (test "x$build" != "xNONE" && test "x$build" != "x$ac_cv_build_alias"); then
+
+# Make sure we can run config.sub.
+  if $ac_config_sub sun4 >/dev/null 2>&1; then :
+    else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+  fi
+
+  ac_cv_build_alias=$build
+  case "$ac_cv_build_alias" in
+  NONE)
+    case $nonopt in
+    NONE)
+      ac_cv_build_alias=$host_alias ;;
+
+    *) ac_cv_build_alias=$nonopt ;;
+    esac ;;
+  esac
+
+  ac_cv_build=`$ac_config_sub $ac_cv_build_alias`
+  ac_cv_build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+  ac_cv_build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+  ac_cv_build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+else
+  echo $ac_n "(cached) $ac_c" 1>&6
+fi
+
+echo "$ac_t""$ac_cv_build" 1>&6
+
+build=$ac_cv_build
+build_alias=$ac_cv_build_alias
+build_cpu=$ac_cv_build_cpu
+build_vendor=$ac_cv_build_vendor
+build_os=$ac_cv_build_os
+
+
+
+
+
+# Do some error checking and defaulting for the host and target type.
+# The inputs are:
+#    configure --host=HOST --target=TARGET --build=BUILD NONOPT
+#
+# The rules are:
+# 1. You are not allowed to specify --host, --target, and nonopt at the
+#    same time.
+# 2. Host defaults to nonopt.
+# 3. If nonopt is not specified, then host defaults to the current host,
+#    as determined by config.guess.
+# 4. Target and build default to nonopt.
+# 5. If nonopt is not specified, then target and build default to host.
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+case $host---$target---$nonopt in
+NONE---*---* | *---NONE---* | *---*---NONE) ;;
+*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
+esac
+
+test "$host_alias" != "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+
+cat >> confdefs.h < conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},;$program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:847: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"\${ac_cv_path_install+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:904: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "$*" != "X $srcdir/configure conftestfile" \
+      && test "$*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { echo "configure: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+   fi
+
+   test "$2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:942: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+
+PACKAGE=ntp
+
+VERSION=4.0.98f
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <> confdefs.h <&6
+echo "configure:989: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+   ACLOCAL=aclocal
+   echo "$ac_t""found" 1>&6
+else
+   ACLOCAL="$missing_dir/missing aclocal"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:1002: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+   AUTOCONF=autoconf
+   echo "$ac_t""found" 1>&6
+else
+   AUTOCONF="$missing_dir/missing autoconf"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:1015: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+   AUTOMAKE=automake
+   echo "$ac_t""found" 1>&6
+else
+   AUTOMAKE="$missing_dir/missing automake"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:1028: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+   AUTOHEADER=autoheader
+   echo "$ac_t""found" 1>&6
+else
+   AUTOHEADER="$missing_dir/missing autoheader"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:1041: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+   MAKEINFO=makeinfo
+   echo "$ac_t""found" 1>&6
+else
+   MAKEINFO="$missing_dir/missing makeinfo"
+   echo "$ac_t""missing" 1>&6
+fi
+
+for ac_prog in gnutar gtar tar
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1058: checking for $ac_word" >&5
+if eval "test \"\${ac_cv_prog_AMTAR+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$AMTAR"; then
+  ac_cv_prog_AMTAR="$AMTAR" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_AMTAR="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+AMTAR="$ac_cv_prog_AMTAR"
+if test -n "$AMTAR"; then
+  echo "$ac_t""$AMTAR" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AMTAR" && break
+done
+
+AMTARFLAGS=
+if test -n "$AMTAR"; then
+  if $SHELL -c "$AMTAR --version" > /dev/null 2>&1; then
+        AMTARFLAGS=o
+  fi
+fi
+
+
+
+
+ac_cv_var_oncore_ok=no
+
+iCFLAGS="$CFLAGS"
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1104: checking for $ac_word" >&5
+if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1134: checking for $ac_word" >&5
+if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32* | *CYGWIN*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1185: checking for $ac_word" >&5
+if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:1217: checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 1228 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:1233: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:1259: checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:1264: checking whether we are using GNU C" >&5
+if eval "test \"\${ac_cv_prog_gcc+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:1292: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"\${ac_cv_prog_cc_g+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1324: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"\${ac_cv_prog_CPP+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1345: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1362: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1379: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+
+case "$target" in
+ *-pc-cygwin*)
+    CFLAGS="$CFLAGS -DSYS_CYGWIN32"
+    ;;
+ i386-sequent-sysv4)
+    case "$CC" in
+     cc)
+	CFLAGS="$CFLAGS -Wc,+Abi-socket"
+	;;
+    esac
+esac
+
+case "$host" in
+ $target)
+    ;;
+ *) case "$target" in
+     *-*-vxworks*)
+	# Quick and dirty sanity check
+	case "$VX_KERNEL" in
+	 '') { echo "configure: error: Please follow the directions in html/vxworks.html!" 1>&2; exit 1; }
+	    ;;
+	esac
+        CFLAGS="$CFLAGS -DSYS_VXWORKS"
+        ;;
+    esac
+    ;;
+esac
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1437: checking for $ac_word" >&5
+if eval "test \"\${ac_cv_prog_AWK+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_AWK="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+  echo "$ac_t""$AWK" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1467: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+rm -f conftest*
+
+case "$GCC" in
+ yes)
+    CFLAGS="$CFLAGS -Wall"
+    # CFLAGS="$CFLAGS -Wtraditional"
+    CFLAGS="$CFLAGS -Wshadow"
+    # CFLAGS="$CFLAGS -Wwrite-strings"
+    CFLAGS="$CFLAGS -Wconversion"
+    CFLAGS="$CFLAGS -Wpointer-arith"
+    CFLAGS="$CFLAGS -Wcast-qual"
+    # CFLAGS="$CFLAGS -Wcast-align"
+    CFLAGS="$CFLAGS -Wstrict-prototypes"
+
+    echo $ac_n "checking whether ${CC-cc} -pipe works""... $ac_c" 1>&6
+echo "configure:1509: checking whether ${CC-cc} -pipe works" >&5
+if eval "test \"\${ac_cv_prog_cc_pipe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+    if test -z "`${CC-cc} -pipe -c conftest.c 2>&1`" -a -s conftest.o; then
+      ac_cv_prog_cc_pipe=yes
+    else
+      ac_cv_prog_cc_pipe=no
+    fi
+    rm -f conftest*
+    
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_pipe" 1>&6
+
+    case "$ac_cv_prog_cc_pipe" in
+     yes)
+	CFLAGS="$CFLAGS -pipe"
+	;;
+    esac
+    ;;
+esac
+
+ac_busted_vpath_in_make=no
+
+case "$target" in
+ *-*-irix6.1*)	# 64 bit only
+    ;;
+ *-*-irix6*)	# 6.2 (and later?)
+    ac_busted_vpath_in_make=yes
+    # don't pass -n32 to gcc, it cannot handle and doesn't need it
+    if test "$GCC" != yes; then
+      case "$CFLAGS" in
+       *-n32*) ;;
+       *-n64*) ;;
+       *) case "$iCFLAGS" in
+	   '') CFLAGS="-O2 -g3 -n32" ;;
+	   *)  CFLAGS="$CFLAGS -n32" ;;
+	  esac
+	  ;;
+      esac
+      case "$LDFLAGS" in
+       *-n32*) ;;
+       *-n64*) ;;
+       *) LDFLAGS="$LDFLAGS -n32" ;;
+      esac
+    fi
+    ;;
+ *-next-nextstep3)
+    CFLAGS="$CFLAGS -posix" ;;
+ *-*-solaris2.5.1)
+    ac_busted_vpath_in_make=yes
+    ;;
+esac
+
+case "$ac_busted_vpath_in_make$srcdir" in
+ no*) ;;
+ yes.) ;;
+ *) case "`${MAKE-make} -v -f /dev/null 2>/dev/null | sed -e 's/GNU Make version \(1-9.]*\).*/\1/' -e q`" in
+     '')
+	{ echo "configure: error: building outside of the main directory requires GNU make" 1>&2; exit 1; }
+	;;
+     *) ;;
+    esac
+    ;;
+esac
+
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1579: checking whether ln -s works" >&5
+if eval "test \"\${ac_cv_prog_LN_S+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:1601: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"\${ac_cv_prog_gcc_traditional+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&6
+echo "configure:1647: checking for AIX" >&5
+cat > conftest.$ac_ext <&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:1672: checking for minix/config.h" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1682: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  MINIX=yes
+else
+  echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:1720: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+  echo "$ac_t""yes" 1>&6
+  ISC=yes # If later tests want to check for ISC.
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  if test "$GCC" = yes; then
+    CC="$CC -posix"
+  else
+    CC="$CC -Xp"
+  fi
+else
+  echo "$ac_t""no" 1>&6
+  ISC=
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1743: checking for $ac_word" >&5
+if eval "test \"\${ac_cv_prog_RANLIB+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "sh", so it can be a program name with args.
+set dummy sh; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1773: checking for $ac_word" >&5
+if eval "test \"\${ac_cv_path_PATH_SH+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$PATH_SH" in
+  /*)
+  ac_cv_path_PATH_SH="$PATH_SH" # Let the user override the test with a path.
+  ;;
+  ?:/*)			 
+  ac_cv_path_PATH_SH="$PATH_SH" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_PATH_SH="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+PATH_SH="$ac_cv_path_PATH_SH"
+if test -n "$PATH_SH"; then
+  echo "$ac_t""$PATH_SH" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+case "$target" in
+ *-*-vxworks*)
+    ac_link="$ac_link $VX_KERNEL"
+    ;;
+esac
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1824: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"\${ac_cv_path_install+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+case "$target" in
+ *-pc-cygwin*)
+    echo $ac_n "checking for main in -ladvapi32""... $ac_c" 1>&6
+echo "configure:1884: checking for main in -ladvapi32" >&5
+ac_lib_var=`echo advapi32'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ladvapi32  $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo advapi32 | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <&6
+fi
+
+    ;;
+esac
+echo $ac_n "checking for nlist in -lelf""... $ac_c" 1>&6
+echo "configure:1929: checking for nlist in -lelf" >&5
+ac_lib_var=`echo elf'_'nlist | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lelf  $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo elf | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <&6
+fi
+
+echo $ac_n "checking for main in -lkvm""... $ac_c" 1>&6
+echo "configure:1976: checking for main in -lkvm" >&5
+ac_lib_var=`echo kvm'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lkvm  $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo kvm | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <&6
+fi
+		echo $ac_n "checking for nlist in -lld""... $ac_c" 1>&6
+echo "configure:2018: checking for nlist in -lld" >&5
+ac_lib_var=`echo ld'_'nlist | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lld  $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo ld | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <&6
+fi
+
+echo $ac_n "checking for nlist in -lmld""... $ac_c" 1>&6
+echo "configure:2065: checking for nlist in -lmld" >&5
+ac_lib_var=`echo mld'_'nlist | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lmld  $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo mld | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <&6
+fi
+
+echo $ac_n "checking for gethostent""... $ac_c" 1>&6
+echo "configure:2112: checking for gethostent" >&5
+if eval "test \"\${ac_cv_func_gethostent+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostent();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_gethostent) || defined (__stub___gethostent)
+choke me
+#else
+f = gethostent;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2141: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_gethostent=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_gethostent=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostent`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for gethostent in -lnsl""... $ac_c" 1>&6
+echo "configure:2159: checking for gethostent in -lnsl" >&5
+ac_lib_var=`echo nsl'_'gethostent | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lnsl -lsocket $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <&6
+fi
+
+fi
+
+echo $ac_n "checking for openlog""... $ac_c" 1>&6
+echo "configure:2208: checking for openlog" >&5
+if eval "test \"\${ac_cv_func_openlog+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char openlog();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_openlog) || defined (__stub___openlog)
+choke me
+#else
+f = openlog;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2237: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_openlog=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_openlog=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'openlog`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for openlog in -lgen""... $ac_c" 1>&6
+echo "configure:2255: checking for openlog in -lgen" >&5
+ac_lib_var=`echo gen'_'openlog | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgen  $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo gen | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <&6
+fi
+
+fi
+
+
+echo $ac_n "checking for sched_setscheduler in -lrt""... $ac_c" 1>&6
+echo "configure:2305: checking for sched_setscheduler in -lrt" >&5
+ac_lib_var=`echo rt'_'sched_setscheduler | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lrt  $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo rt | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <&6
+echo $ac_n "checking for sched_setscheduler in -lposix4""... $ac_c" 1>&6
+echo "configure:2350: checking for sched_setscheduler in -lposix4" >&5
+ac_lib_var=`echo posix4'_'sched_setscheduler | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lposix4  $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo posix4 | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <&6
+fi
+
+fi
+
+echo $ac_n "checking for setsockopt""... $ac_c" 1>&6
+echo "configure:2399: checking for setsockopt" >&5
+if eval "test \"\${ac_cv_func_setsockopt+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char setsockopt();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_setsockopt) || defined (__stub___setsockopt)
+choke me
+#else
+f = setsockopt;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2428: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_setsockopt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_setsockopt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'setsockopt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for setsockopt in -lsocket""... $ac_c" 1>&6
+echo "configure:2446: checking for setsockopt in -lsocket" >&5
+ac_lib_var=`echo socket'_'setsockopt | sed 'y%./+-%__p_%'`
+if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket  $LIBS"
+cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <&6
+fi
+
+fi
+
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:2496: checking for ANSI C header files" >&5
+if eval "test \"\${ac_cv_header_stdc+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#include 
+#include 
+#include 
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2509: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <
+#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
+if { (eval echo configure:2576: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in bstring.h errno.h fcntl.h memory.h netdb.h poll.h resolv.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2603: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2613: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_hdr in sched.h sgtty.h stdlib.h string.h termio.h termios.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2643: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2653: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_hdr in timepps.h timex.h unistd.h utmp.h utmpx.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2683: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2693: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_hdr in arpa/nameser.h net/if.h netinet/in.h netinet/ip.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2723: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2733: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_hdr in netinfo/ni.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2763: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2773: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <> confdefs.h <<\EOF
+#define HAVE_NETINFO 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in sun/audioio.h sys/audioio.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2806: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2816: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_hdr in sys/clkdefs.h sys/file.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2846: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2856: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+case "$target" in
+ *-*-sunos4*) ;;
+ *) for ac_hdr in sys/ioctl.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2888: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2898: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+for ac_hdr in sys/lock.h sys/mman.h sys/modem.h sys/param.h sys/ppsclock.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2930: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2940: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_hdr in sys/ppstime.h sys/proc.h sys/resource.h sys/sched.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2970: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2980: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+case "$target" in
+ *-*-sco*)
+    for ac_hdr in sys/sio.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3012: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3022: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+ *sgi*)
+    for ac_hdr in sys/syssgi.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3054: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3064: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+ *)
+    for ac_hdr in sys/select.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3096: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3106: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+for ac_hdr in sys/sockio.h sys/stat.h sys/stream.h sys/stropts.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3138: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3148: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_hdr in sys/sysctl.h sys/termios.h sys/time.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3178: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3188: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+cat > conftest.$ac_ext <
+#ifdef PPS_API_VERS_1
+yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  for ac_hdr in sys/timepps.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3230: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3240: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+fi
+rm -f conftest*
+
+for ac_hdr in sys/timers.h sys/timex.h sys/tpro.h sys/types.h sys/wait.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3273: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3283: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:3310: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"\${ac_cv_header_time+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#include 
+#include 
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:3324: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+case "$target" in
+*-convex-*)
+  for ac_hdr in /sys/sync/queue.h /sys/sync/sema.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3350: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3360: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+  ;;
+*-*-bsdi*)
+  for ac_hdr in machine/inline.h sys/pcl720.h sys/i8253.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3392: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3402: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+  ;;
+esac
+
+ac_safe=`echo "nlist.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for nlist.h""... $ac_c" 1>&6
+echo "configure:3433: checking for nlist.h" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3443: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define NLIST_STRUCT 1
+EOF
+
+echo $ac_n "checking for n_un in struct nlist""... $ac_c" 1>&6
+echo "configure:3464: checking for n_un in struct nlist" >&5
+if eval "test \"\${ac_cv_struct_nlist_n_un+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+int main() {
+struct nlist n; n.n_un.n_name = 0;
+; return 0; }
+EOF
+if { (eval echo configure:3476: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_nlist_n_un=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_nlist_n_un=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_nlist_n_un" 1>&6
+if test $ac_cv_struct_nlist_n_un = yes; then
+  cat >> confdefs.h <<\EOF
+#define NLIST_NAME_UNION 1
+EOF
+
+fi
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for basic volatile support""... $ac_c" 1>&6
+echo "configure:3501: checking for basic volatile support" >&5
+if eval "test \"\${ac_cv_c_volatile+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_volatile=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_volatile=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_c_volatile" 1>&6
+case "$ac_cv_c_volatile" in
+ yes)
+    ;;
+ *) cat >> confdefs.h <<\EOF
+#define volatile 
+EOF
+
+    ;;
+esac
+
+case "$target" in
+ sparc-*-solaris2*)
+    # Assume that solaris2 is Ansi C...
+    ;;
+ *)
+    
+
+
+echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6
+echo "configure:3547: checking for ${CC-cc} option to accept ANSI C" >&5
+if eval "test \"\${am_cv_prog_cc_stdc+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  am_cv_prog_cc_stdc=no
+ac_save_CC="$CC"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX 10.20 and later	-Ae
+# HP-UX older versions	-Aa -D_HPUX_SOURCE
+# SVR4			-Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  cat > conftest.$ac_ext <
+#include 
+#include 
+#include 
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+
+int main() {
+
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+
+; return 0; }
+EOF
+if { (eval echo configure:3601: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  am_cv_prog_cc_stdc="$ac_arg"; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+CC="$ac_save_CC"
+
+fi
+
+if test -z "$am_cv_prog_cc_stdc"; then
+  echo "$ac_t""none needed" 1>&6
+else
+  echo "$ac_t""$am_cv_prog_cc_stdc" 1>&6
+fi
+case "x$am_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $am_cv_prog_cc_stdc" ;;
+esac
+
+
+
+echo $ac_n "checking for function prototypes""... $ac_c" 1>&6
+echo "configure:3627: checking for function prototypes" >&5
+if test "$am_cv_prog_cc_stdc" != no; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define PROTOTYPES 1
+EOF
+
+  U= ANSI2KNR=
+else
+  echo "$ac_t""no" 1>&6
+  U=_ ANSI2KNR=./ansi2knr
+  # Ensure some checks needed by ansi2knr itself.
+  echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:3640: checking for ANSI C header files" >&5
+if eval "test \"\${ac_cv_header_stdc+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#include 
+#include 
+#include 
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3653: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <
+#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
+if { (eval echo configure:3720: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+  for ac_hdr in string.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3747: checking for $ac_hdr" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3757: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <&6
+fi
+done
+
+fi
+
+    ;;
+esac
+echo $ac_n "checking if C compiler permits function prototypes""... $ac_c" 1>&6
+echo "configure:3788: checking if C compiler permits function prototypes" >&5
+if eval "test \"\${ac_cv_have_prototypes+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_have_prototypes=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_have_prototypes=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_have_prototypes" 1>&6
+if test "$ac_cv_have_prototypes" = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_PROTOTYPES 1
+EOF
+
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:3825: checking for working const" >&5
+if eval "test \"\${ac_cv_c_const+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:3879: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+case "$host" in
+ $target)
+    echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
+echo "configure:3902: checking whether byte ordering is bigendian" >&5
+if eval "test \"\${ac_cv_c_bigendian+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat > conftest.$ac_ext <
+#include 
+int main() {
+
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:3920: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat > conftest.$ac_ext <
+#include 
+int main() {
+
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:3935: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_bigendian=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_bigendian=no
+fi
+rm -f conftest*
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_bigendian=no
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_bigendian=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_c_bigendian" 1>&6
+if test $ac_cv_c_bigendian = yes; then
+  cat >> confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+fi
+
+    ;;
+ *) case "$target" in
+     i*86-*-vxworks*)
+	# LITTLEENDIAN
+	;;
+     *-*-vxworks*)
+	cat >> confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+	;;
+     *) { echo "configure: error: Cross-compiling needs explicit byte order" 1>&2; exit 1; }
+	;;
+    esac
+    ;;
+esac
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:4008: checking return type of signal handlers" >&5
+if eval "test \"\${ac_cv_type_signal+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#include 
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:4030: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <&6
+echo "configure:4049: checking for off_t" >&5
+if eval "test \"\${ac_cv_type_off_t+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#if STDC_HEADERS
+#include 
+#include 
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  eval "ac_cv_type_off_t=yes"
+else
+  rm -rf conftest*
+  eval "ac_cv_type_off_t=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_type_'off_t`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+  cat >> confdefs.h <&6
+echo "configure:4084: checking for size_t" >&5
+if eval "test \"\${ac_cv_type_size_t+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#if STDC_HEADERS
+#include 
+#include 
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  eval "ac_cv_type_size_t=yes"
+else
+  rm -rf conftest*
+  eval "ac_cv_type_size_t=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_type_'size_t`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+  cat >> confdefs.h <&6
+echo "configure:4119: checking for time_t" >&5
+if eval "test \"\${ac_cv_type_time_t+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#if STDC_HEADERS
+#include 
+#include 
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])time_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  eval "ac_cv_type_time_t=yes"
+else
+  rm -rf conftest*
+  eval "ac_cv_type_time_t=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_type_'time_t`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+  cat >> confdefs.h <&6
+echo "configure:4154: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"\${ac_cv_struct_tm+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#include 
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:4167: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+echo $ac_n "checking for a fallback value for HZ""... $ac_c" 1>&6
+echo "configure:4189: checking for a fallback value for HZ" >&5
+if eval "test \"\${ac_cv_var_default_hz+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_var_default_hz=100
+case "$target" in
+ alpha*-dec-osf4*|alpha*-dec-osf5*)
+    ac_cv_var_default_hz=1024
+    ;;
+ mips-dec-ultrix4*)
+    ac_cv_var_default_hz=256
+    ;;
+esac
+fi
+
+echo "$ac_t""$ac_cv_var_default_hz" 1>&6
+cat >> confdefs.h <&6
+echo "configure:4211: checking if we need to override the system's value for HZ" >&5
+if eval "test \"\${ac_cv_var_override_hz+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_var_override_hz=no
+case "$target" in
+ alpha*-dec-osf4*|alpha*-dec-osf5*)
+    ac_cv_var_override_hz=yes
+    ;;
+ mips-dec-ultrix4*)
+    ac_cv_var_override_hz=yes
+    ;;
+ *-*-freebsd*)
+    ac_cv_var_override_hz=yes
+    ;;
+ *-*-sunos4*)
+    ac_cv_var_override_hz=yes
+    ;;
+esac
+fi
+
+echo "$ac_t""$ac_cv_var_override_hz" 1>&6
+case "$ac_cv_var_override_hz" in
+ yes)
+    cat >> confdefs.h <<\EOF
+#define OVERRIDE_HZ 1
+EOF
+
+    ;;
+esac
+
+
+
+echo $ac_n "checking struct sigaction for sa_sigaction""... $ac_c" 1>&6
+echo "configure:4245: checking struct sigaction for sa_sigaction" >&5
+if eval "test \"\${ac_cv_struct_sigaction_has_sa_sigaction+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  
+    cat > conftest.$ac_ext <
+int main() {
+struct sigaction act; act.sa_sigaction = 0;
+; return 0; }
+EOF
+if { (eval echo configure:4258: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_sigaction_has_sa_sigaction=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_sigaction_has_sa_sigaction=no
+    
+fi
+rm -f conftest*
+  
+
+fi
+
+echo "$ac_t""$ac_cv_struct_sigaction_has_sa_sigaction" 1>&6
+if test $ac_cv_struct_sigaction_has_sa_sigaction = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION 1
+EOF
+
+fi
+
+echo $ac_n "checking for struct ppsclockev""... $ac_c" 1>&6
+echo "configure:4282: checking for struct ppsclockev" >&5
+if eval "test \"\${ac_cv_struct_ppsclockev+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#ifdef HAVE_SYS_TERMIOS_H
+# include 
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include 
+#endif
+#ifdef HAVE_SYS_PPSCLOCK_H
+# include 
+#endif
+int main() {
+
+extern struct ppsclockev *pce;
+return pce->serial;
+; return 0; }
+EOF
+if { (eval echo configure:4306: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_ppsclockev=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_ppsclockev=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_struct_ppsclockev" 1>&6
+if test $ac_cv_struct_ppsclockev = yes; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_STRUCT_PPSCLOCKEV 1
+EOF
+
+fi
+
+echo $ac_n "checking struct sockaddr for sa_len""... $ac_c" 1>&6
+echo "configure:4328: checking struct sockaddr for sa_len" >&5
+if eval "test \"\${ac_cv_struct_sockaddr_has_sa_len+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#include 
+int main() {
+
+extern struct sockaddr *ps;
+return ps->sa_len;
+; return 0; }
+EOF
+if { (eval echo configure:4344: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_sockaddr_has_sa_len=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_sockaddr_has_sa_len=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_struct_sockaddr_has_sa_len" 1>&6
+if test $ac_cv_struct_sockaddr_has_sa_len = yes; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_SA_LEN_IN_STRUCT_SOCKADDR 1
+EOF
+
+fi
+
+echo $ac_n "checking struct clockinfo for hz""... $ac_c" 1>&6
+echo "configure:4366: checking struct clockinfo for hz" >&5
+if eval "test \"\${ac_cv_struct_clockinfo_has_hz+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+int main() {
+
+extern struct clockinfo *pc;
+return pc->hz;
+; return 0; }
+EOF
+if { (eval echo configure:4381: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_clockinfo_has_hz=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_clockinfo_has_hz=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_struct_clockinfo_has_hz" 1>&6
+if test $ac_cv_struct_clockinfo_has_hz = yes; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_HZ_IN_STRUCT_CLOCKINFO 1
+EOF
+
+fi
+
+echo $ac_n "checking struct clockinfo for tickadj""... $ac_c" 1>&6
+echo "configure:4403: checking struct clockinfo for tickadj" >&5
+if eval "test \"\${ac_cv_struct_clockinfo_has_tickadj+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+int main() {
+
+extern struct clockinfo *pc;
+return pc->tickadj;
+; return 0; }
+EOF
+if { (eval echo configure:4418: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_clockinfo_has_tickadj=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_clockinfo_has_tickadj=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_struct_clockinfo_has_tickadj" 1>&6
+if test $ac_cv_struct_clockinfo_has_tickadj = yes; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_TICKADJ_IN_STRUCT_CLOCKINFO 1
+EOF
+
+fi
+
+echo $ac_n "checking for struct ntptimeval""... $ac_c" 1>&6
+echo "configure:4440: checking for struct ntptimeval" >&5
+if eval "test \"\${ac_cv_struct_ntptimeval+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#include 
+int main() {
+struct ntptimeval n;
+; return 0; }
+EOF
+if { (eval echo configure:4454: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_ntptimeval=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_ntptimeval=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_ntptimeval" 1>&6
+if test $ac_cv_struct_ntptimeval = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRUCT_NTPTIMEVAL 1
+EOF
+
+fi
+
+echo $ac_n "checking struct ntptimeval for time.tv_nsec""... $ac_c" 1>&6
+echo "configure:4475: checking struct ntptimeval for time.tv_nsec" >&5
+if eval "test \"\${ac_cv_struct_ntptimeval_tv_nsec+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#else
+# ifdef HAVE_TIME_H
+# include 
+# endif
+#endif
+#ifdef HAVE_SYS_TIMEX_H
+#include 
+#else
+# ifdef HAVE_TIMEX_H
+# include 
+# endif
+#endif
+int main() {
+
+extern struct ntptimeval *ntv;
+return ntv->time.tv_nsec;
+; return 0; }
+EOF
+if { (eval echo configure:4503: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_ntptimeval_tv_nsec=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_ntptimeval_tv_nsec=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_struct_ntptimeval_tv_nsec" 1>&6
+if test "$ac_cv_struct_ntptimeval_tv_nsec" = "yes"; then
+	cat >> confdefs.h <<\EOF
+#define HAVE_TV_NSEC_IN_NTPTIMEVAL 1
+EOF
+
+fi
+
+echo $ac_n "checking for struct timespec in struct ntptimeval""... $ac_c" 1>&6
+echo "configure:4525: checking for struct timespec in struct ntptimeval" >&5
+if eval "test \"\${ac_cv_struct_ntptimeval_timespec+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#include 
+int main() {
+struct ntptimeval n; n.time.tv_nsec = 0;
+; return 0; }
+EOF
+if { (eval echo configure:4538: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_ntptimeval_timespec=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_ntptimeval_timespec=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_ntptimeval_timespec" 1>&6
+if test $ac_cv_struct_ntptimeval_timespec = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIMESPEC_IN_NTPTIMEVAL 1
+EOF
+
+fi
+
+echo $ac_n "checking for inline""... $ac_c" 1>&6
+echo "configure:4559: checking for inline" >&5
+if eval "test \"\${ac_cv_c_inline+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_inline=$ac_kw; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+
+fi
+
+echo "$ac_t""$ac_cv_c_inline" 1>&6
+case "$ac_cv_c_inline" in
+  inline | yes) ;;
+  no) cat >> confdefs.h <<\EOF
+#define inline 
+EOF
+ ;;
+  *)  cat >> confdefs.h <&6
+echo "configure:4599: checking whether char is unsigned" >&5
+if eval "test \"\${ac_cv_c_char_unsigned+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$GCC" = yes; then
+  # GCC predefines this symbol on systems where it applies.
+cat > conftest.$ac_ext <&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_c_char_unsigned=yes
+else
+  rm -rf conftest*
+  ac_cv_c_char_unsigned=no
+fi
+rm -f conftest*
+
+else
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_char_unsigned=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_char_unsigned=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_c_char_unsigned" 1>&6
+if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then
+  cat >> confdefs.h <<\EOF
+#define __CHAR_UNSIGNED__ 1
+EOF
+
+fi
+		case "$host" in
+ $target)
+    echo $ac_n "checking size of signed char""... $ac_c" 1>&6
+echo "configure:4663: checking size of signed char" >&5
+if eval "test \"\${ac_cv_sizeof_signed_char+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(signed char));
+  exit(0);
+}
+EOF
+if { (eval echo configure:4682: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_signed_char=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_signed_char=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_signed_char" 1>&6
+cat >> confdefs.h <&6
+echo "configure:4705: checking size of signed char" >&5
+if eval "test \"\${ac_cv_sizeof_signed_char+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_signed_char=1
+else
+  cat > conftest.$ac_ext <
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(signed char));
+  exit(0);
+}
+EOF
+if { (eval echo configure:4724: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_signed_char=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_signed_char=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_signed_char" 1>&6
+cat >> confdefs.h <&2; exit 1; }
+        ;;
+    esac
+    ;;
+esac
+
+case "$host" in
+ $target)
+    echo $ac_n "checking size of int""... $ac_c" 1>&6
+echo "configure:4753: checking size of int" >&5
+if eval "test \"\${ac_cv_sizeof_int+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(int));
+  exit(0);
+}
+EOF
+if { (eval echo configure:4772: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_int=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_int" 1>&6
+cat >> confdefs.h <&6
+echo "configure:4795: checking size of int" >&5
+if eval "test \"\${ac_cv_sizeof_int+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_int=4
+else
+  cat > conftest.$ac_ext <
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(int));
+  exit(0);
+}
+EOF
+if { (eval echo configure:4814: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_int=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_int" 1>&6
+cat >> confdefs.h <&2; exit 1; }
+	;;
+    esac
+    ;;
+esac
+
+case "$host" in
+ $target)
+    echo $ac_n "checking size of long""... $ac_c" 1>&6
+echo "configure:4843: checking size of long" >&5
+if eval "test \"\${ac_cv_sizeof_long+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(long));
+  exit(0);
+}
+EOF
+if { (eval echo configure:4862: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_long=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_long=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_long" 1>&6
+cat >> confdefs.h <&6
+echo "configure:4885: checking size of long" >&5
+if eval "test \"\${ac_cv_sizeof_long+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_long=4
+else
+  cat > conftest.$ac_ext <
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(long));
+  exit(0);
+}
+EOF
+if { (eval echo configure:4904: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_long=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_long=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_long" 1>&6
+cat >> confdefs.h <&2; exit 1; }
+	;;
+    esac
+    ;;
+esac
+
+echo $ac_n "checking for s_char""... $ac_c" 1>&6
+echo "configure:4931: checking for s_char" >&5
+if eval "test \"\${ac_cv_type_s_char+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#if STDC_HEADERS
+#include 
+#include 
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])s_char[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  eval "ac_cv_type_s_char=yes"
+else
+  rm -rf conftest*
+  eval "ac_cv_type_s_char=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_type_'s_char`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+  cat >> confdefs.h <> confdefs.h <<\EOF
+#define NEED_S_CHAR_TYPEDEF 1
+EOF
+
+    ;;
+ no1no)
+    # We have signed chars, can say 'signed char', no s_char typedef.
+    cat >> confdefs.h <<\EOF
+#define NEED_S_CHAR_TYPEDEF 1
+EOF
+
+    ;;
+ yes0no)
+    # We have unsigned chars, can't say 'signed char', no s_char typedef.
+    { echo "configure: error: No way to specify a signed character!" 1>&2; exit 1; }
+    ;;
+ yes1no)
+    # We have unsigned chars, can say 'signed char', no s_char typedef.
+    cat >> confdefs.h <<\EOF
+#define NEED_S_CHAR_TYPEDEF 1
+EOF
+
+    ;;
+esac
+echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6
+echo "configure:4996: checking for uid_t in sys/types.h" >&5
+if eval "test \"\${ac_cv_type_uid_t+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "uid_t" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_uid_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_uid_t" 1>&6
+if test $ac_cv_type_uid_t = no; then
+  cat >> confdefs.h <<\EOF
+#define uid_t int
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define gid_t int
+EOF
+
+fi
+
+
+case "$target" in
+ *-*-linux*)
+    for ac_func in __adjtimex __ntp_gettime
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5035: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5064: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+case "$target" in
+ *-*-aix4*)
+	# (prr) aix 4.1 doesn't have clock_settime, but in aix 4.3 it's a stub
+	# (returning ENOSYS).  I didn't check 4.2.  If, in the future,
+	# IBM pulls its thumbs out long enough to implement clock_settime,
+	# this conditional will need to change.  Maybe use AC_TRY_RUN
+	# instead to try to set the time to itself and check errno.
+    ;;
+ *) for ac_func in clock_settime
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5101: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5130: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+for ac_func in daemon getbootfile getdtablesize getrusage
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5159: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5188: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_func in gettimeofday
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5215: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5244: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+case "$target" in
+ *-pc-cygwin*)
+    ;;
+ *) for ac_func in getuid
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5274: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5303: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+for ac_func in K_open kvm_open memcpy memmove memset
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5332: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5361: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+case "$target" in
+ *-*-sco3.2v5.0.*)
+    # Just stubs.  Idiots.
+    ;;
+ *) for ac_func in mkstemp
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5392: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5421: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+for ac_func in mktime
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5450: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5479: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+case "$target" in
+ *-*-aix4*)
+    # Just a stub.  Idiots.
+    ;;
+ *-*-irix*)
+    # Just stubs in Irix.  Idiots.
+    ;;
+ *-*-sco3.2v5.0.*)
+    # Just stubs.  Idiots.
+    ;;
+ alpha*-dec-osf4*|alpha*-dec-osf5*)
+    # mlockall is there, as a #define calling memlk via 
+    # Not easy to test for - cheat.
+    for ac_func in memlk
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5521: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5550: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    for ac_func in mlockall
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5577: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5606: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+ *) for ac_func in mlockall
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5634: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5663: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+for ac_func in nice nlist
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5692: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5721: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+case "$target" in
+ *-*-solaris2.6)
+    # Broken...
+    ;;
+ *) for ac_func in ntp_adjtime ntp_gettime
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5752: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5781: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+for ac_func in plock pututline pututxline rtprio
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5810: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5839: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_func in random srandom mrand48 srand48
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5866: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5895: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+case "$target" in
+ *-*-aix4*)
+    # Just a stub in AIX 4.  Idiots.
+    ;;
+ *-*-solaris2.5*)
+    # Just stubs in solaris2.5.  Idiots.
+    ;;
+ *) for ac_func in sched_setscheduler
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5929: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5958: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+for ac_func in setlinebuf
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5987: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6016: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_func in setpgid setpriority setsid settimeofday setvbuf sigaction
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6043: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6072: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_func in sigvec sigset sigsuspend stime strchr sysconf sysctl
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6099: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6128: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+for ac_func in strerror
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6155: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6184: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+case "$target" in
+ *-*-aix4*)
+    # Just stubs.  Idiots.
+    ;;
+ *-*-netbsd*)
+    # Just stubs.  Idiots.
+    ;;
+ *-*-openbsd*)
+    # Just stubs.  Idiots.
+    ;;
+ *) for ac_func in timer_create timer_settime
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6223: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6252: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+case "$target" in
+ *-pc-cygwin*)
+    # I have no idea...
+    ;;
+ *) for ac_func in umask
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6285: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6314: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+    ;;
+esac
+for ac_func in uname updwtmp updwtmpx vsprintf
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:6343: checking for $ac_func" >&5
+if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+char (*f)();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:6372: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <&6
+fi
+done
+
+
+echo $ac_n "checking number of arguments to gettimeofday()""... $ac_c" 1>&6
+echo "configure:6398: checking number of arguments to gettimeofday()" >&5
+if eval "test \"\${ac_cv_func_Xettimeofday_nargs+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+int main() {
+
+gettimeofday((struct timeval*)0,(struct timezone*)0);
+settimeofday((struct timeval*)0,(struct timezone*)0);
+
+; return 0; }
+EOF
+if { (eval echo configure:6413: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_func_Xettimeofday_nargs=2
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_Xettimeofday_nargs=1
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_func_Xettimeofday_nargs" 1>&6
+if test $ac_cv_func_Xettimeofday_nargs = 1; then
+	cat >> confdefs.h <<\EOF
+#define SYSV_TIMEOFDAY 1
+EOF
+
+fi
+
+echo $ac_n "checking number of arguments taken by setpgrp()""... $ac_c" 1>&6
+echo "configure:6435: checking number of arguments taken by setpgrp()" >&5
+if eval "test \"\${ac_cv_func_setpgrp_nargs+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#endif
+#ifdef HAVE_UNISTD_H
+# include 
+#endif
+
+int main() {
+setpgrp(0,0);
+; return 0; }
+EOF
+if { (eval echo configure:6454: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_func_setpgrp_nargs=2
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_setpgrp_nargs=0
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_func_setpgrp_nargs" 1>&6
+if test $ac_cv_func_setpgrp_nargs = 0; then
+        cat >> confdefs.h <<\EOF
+#define HAVE_SETPGRP_0 1
+EOF
+
+fi
+
+save_CFLAGS=$CFLAGS
+CFLAGS="$CFLAGS -I$srcdir/include"
+
+echo $ac_n "checking argument pointer type of qsort()'s compare function and base""... $ac_c" 1>&6
+echo "configure:6479: checking argument pointer type of qsort()'s compare function and base" >&5
+if eval "test \"\${ac_cv_func_qsort_argtype+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_func_qsort_argtype=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_qsort_argtype=char
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_func_qsort_argtype" 1>&6
+case "$ac_cv_func_qsort_argtype" in
+ void)
+    cat >> confdefs.h <<\EOF
+#define QSORT_USES_VOID_P 1
+EOF
+
+    ;;
+esac
+
+CFLAGS=$save_CFLAGS
+
+echo $ac_n "checking if we need to declare 'errno'""... $ac_c" 1>&6
+echo "configure:6533: checking if we need to declare 'errno'" >&5
+if eval "test \"\${ac_cv_decl_errno+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#endif
+int main() {
+errno = 0;
+; return 0; }
+EOF
+if { (eval echo configure:6547: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_decl_errno=no
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_decl_errno=yes
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_decl_errno" 1>&6
+case "$ac_cv_decl_errno" in
+ yes) cat >> confdefs.h <<\EOF
+#define DECL_ERRNO 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if we may declare 'h_errno'""... $ac_c" 1>&6
+echo "configure:6568: checking if we may declare 'h_errno'" >&5
+if eval "test \"\${ac_cv_decl_h_errno+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#ifdef HAVE_NETINET_IN_H
+#include 
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#include 
+#endif
+#ifdef HAVE_NETDB_H
+#include 
+#endif
+#ifdef HAVE_RESOLV_H
+#include 
+#endif
+int main() {
+extern int h_errno;
+; return 0; }
+EOF
+if { (eval echo configure:6592: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_decl_h_errno=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_decl_h_errno=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_decl_h_errno" 1>&6
+case "$ac_cv_decl_h_errno" in
+ yes) cat >> confdefs.h <<\EOF
+#define DECL_H_ERRNO 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if declaring 'char *sys_errlist' is ok""... $ac_c" 1>&6
+echo "configure:6613: checking if declaring 'char *sys_errlist' is ok" >&5
+if eval "test \"\${ac_cv_decl_sys_errlist+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#ifdef HAVE_ERRNO_H
+#include 
+#endif
+int main() {
+  extern char *sys_errlist[];
+  
+; return 0; }
+EOF
+if { (eval echo configure:6629: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_decl_sys_errlist=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_decl_sys_errlist=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_decl_sys_errlist" 1>&6
+case "$ac_cv_decl_sys_errlist" in
+ yes) cat >> confdefs.h <<\EOF
+#define CHAR_SYS_ERRLIST 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if declaring 'syscall()' is ok""... $ac_c" 1>&6
+echo "configure:6650: checking if declaring 'syscall()' is ok" >&5
+if eval "test \"\${ac_cv_decl_syscall+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#endif
+#ifdef HAVE_UNISTD_H
+# include 
+#endif
+#ifdef HAVE_PROTOTYPES
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+
+int main() {
+extern int syscall P((int, ...));
+; return 0; }
+EOF
+if { (eval echo configure:6674: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_decl_syscall=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_decl_syscall=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_decl_syscall" 1>&6
+case "$ac_cv_decl_syscall" in
+ yes) cat >> confdefs.h <<\EOF
+#define DECL_SYSCALL 1
+EOF
+ ;;
+esac
+
+case "$target" in
+ *-*-osf45*)
+    cat >> confdefs.h <<\EOF
+#define DECL_PLOCK_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_STIME_0 1
+EOF
+
+    ;;
+ *-*-riscos4*)
+    cat >> confdefs.h <<\EOF
+#define DECL_ADJTIME_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_BZERO_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_IOCTL_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_IPC_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_MEMMOVE_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_MKTEMP_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_RENAME_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SELECT_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SETITIMER_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SETPRIORITY_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_STDIO_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_STRTOL_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SYSLOG_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_TIME_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_TIMEOFDAY_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_TOLOWER_0 1
+EOF
+
+    ;;
+ *-*-solaris2*)
+    cat >> confdefs.h <<\EOF
+#define DECL_MKSTEMP_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SETPRIORITY_1 1
+EOF
+
+    case "$target" in
+     *-*-solaris2.4)
+        cat >> confdefs.h <<\EOF
+#define DECL_TIMEOFDAY_0 1
+EOF
+
+	;;
+    esac
+    ;;
+ *-*-sunos4*)
+    cat >> confdefs.h <<\EOF
+#define DECL_ADJTIME_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_BCOPY_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_BZERO_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_IOCTL_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_IPC_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_MEMMOVE_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_MKTEMP_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_MKSTEMP_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_MRAND48_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_RENAME_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SELECT_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SETITIMER_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SETPRIORITY_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SIGVEC_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SRAND48_0 1
+EOF
+
+    case "`basename $ac_cv_prog_CC`" in
+     acc*) ;;
+     *) cat >> confdefs.h <<\EOF
+#define DECL_STDIO_0 1
+EOF
+
+	;;
+    esac
+    cat >> confdefs.h <<\EOF
+#define DECL_STRTOL_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SYSLOG_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_TIME_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_TIMEOFDAY_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_TOLOWER_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_TOUPPER_0 1
+EOF
+
+    ;;
+ *-*-ultrix4*)
+    cat >> confdefs.h <<\EOF
+#define DECL_ADJTIME_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_BZERO_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_CFSETISPEED_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_IOCTL_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_IPC_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_MKTEMP_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_MRAND48_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_NLIST_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_PLOCK_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SELECT_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SETITIMER_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SETPRIORITY_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SRAND48_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_STIME_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_SYSLOG_0 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define DECL_TIMEOFDAY_0 1
+EOF
+
+    ;;
+esac
+
+case "$target" in
+ *-*-sco3.2*)
+    cat >> confdefs.h <<\EOF
+#define TERMIOS_NEEDS__SVID3 1
+EOF
+
+    ;;
+esac
+
+echo $ac_n "checking if we should use a streams device for ifconfig""... $ac_c" 1>&6
+echo "configure:6961: checking if we should use a streams device for ifconfig" >&5
+if eval "test \"\${ac_cv_var_use_streams_device_for_ifconfig+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_var_use_streams_device_for_ifconfig=no
+fi
+
+echo "$ac_t""$ac_cv_var_use_streams_device_for_ifconfig" 1>&6
+
+echo $ac_n "checking if we need extra room for SO_RCVBUF""... $ac_c" 1>&6
+echo "configure:6971: checking if we need extra room for SO_RCVBUF" >&5
+if eval "test \"\${ac_cv_var_rcvbuf_slop+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=no
+case "$target" in
+ *-*-hpux[567]*)
+    ans=yes
+    ;;
+esac
+ac_cv_var_rcvbuf_slop=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_rcvbuf_slop" 1>&6
+case "$ac_cv_var_rcvbuf_slop" in
+ yes) cat >> confdefs.h <<\EOF
+#define NEED_RCVBUF_SLOP 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if we will open the broadcast socket""... $ac_c" 1>&6
+echo "configure:6993: checking if we will open the broadcast socket" >&5
+if eval "test \"\${ac_cv_var_open_bcast_socket+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=yes
+case "$target" in
+ *-*-domainos)
+    ans=no
+    ;;
+ *-*-linux*)
+    ans=no
+    ;;
+esac
+ac_cv_var_open_bcast_socket=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_open_bcast_socket" 1>&6
+case "$ac_cv_var_open_bcast_socket" in
+ yes) cat >> confdefs.h <<\EOF
+#define OPEN_BCAST_SOCKET 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if we want the HPUX version of FindConfig()""... $ac_c" 1>&6
+echo "configure:7018: checking if we want the HPUX version of FindConfig()" >&5
+if eval "test \"\${ac_cv_var_hpux_findconfig+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=no
+case "$target" in
+ *-*-hpux*)
+    ans=yes
+    ;;
+esac
+ac_cv_var_hpux_findconfig=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_hpux_findconfig" 1>&6
+case "$ac_cv_var_hpux_findconfig" in
+ yes) cat >> confdefs.h <<\EOF
+#define NEED_HPUX_FINDCONFIG 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if process groups are set with -pid""... $ac_c" 1>&6
+echo "configure:7040: checking if process groups are set with -pid" >&5
+if eval "test \"\${ac_cv_arg_setpgrp_negpid+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$target" in
+ *-*-hpux[567]*)
+    ans=no
+    ;;
+ *-*-hpux*)
+    ans=yes
+    ;;
+ *-*-linux*)
+    ans=yes
+    ;;
+ *-*-sunos3*)
+    ans=yes
+    ;;
+ *-*-ultrix2*)
+    ans=yes
+    ;;
+ *)
+    ans=no
+    ;;
+esac
+ac_cv_arg_setpgrp_negpid=$ans
+fi
+
+echo "$ac_t""$ac_cv_arg_setpgrp_negpid" 1>&6
+case "$ac_cv_arg_setpgrp_negpid" in
+ yes) cat >> confdefs.h <<\EOF
+#define UDP_BACKWARDS_SETOWN 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if we need a ctty for F_SETOWN""... $ac_c" 1>&6
+echo "configure:7076: checking if we need a ctty for F_SETOWN" >&5
+if eval "test \"\${ac_cv_func_ctty_for_f_setown+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$target" in
+ *-*-bsdi2*)
+    ans=yes
+    ;;
+ *-*-freebsd*)
+    ans=yes
+    ;;
+ *-*-netbsd*)
+    ans=yes
+    ;;
+ *-*-osf*)
+    ans=yes
+    ;;
+ *) ans=no
+    ;;
+esac
+ac_cv_func_ctty_for_f_setown=$ans
+fi
+
+echo "$ac_t""$ac_cv_func_ctty_for_f_setown" 1>&6
+case "$ac_cv_func_ctty_for_f_setown" in
+ yes) cat >> confdefs.h <<\EOF
+#define USE_FSETOWNCTTY 1
+EOF
+ ;;
+esac
+
+ntp_warning='GRONK'
+echo $ac_n "checking if we'll use clock_settime or settimeofday or stime""... $ac_c" 1>&6
+echo "configure:7109: checking if we'll use clock_settime or settimeofday or stime" >&5
+case "$ac_cv_func_clock_settime$ac_cv_func_settimeofday$ac_cv_func_stime" in
+ yes*)
+    ntp_warning=''
+    ans='clock_settime()'
+    ;;
+ noyes*)
+    ntp_warning='But clock_settime() would be better (if we had it)'
+    ans='settimeofday()'
+    ;;
+ nonoyes)
+    ntp_warning='Which is the worst of the three'
+    ans='stime()'
+    ;;
+ *) 
+    case "$host" in
+     $target) ntp_warning='Which leaves us with nothing to use!'
+    ans=none
+    ;;
+esac
+esac
+echo "$ac_t""$ans" 1>&6
+case "$ntp_warning" in
+ '') ;;
+ *) echo "configure: warning: *** $ntp_warning ***" 1>&2
+    ;;
+esac
+
+echo $ac_n "checking if we have a losing syscall()""... $ac_c" 1>&6
+echo "configure:7138: checking if we have a losing syscall()" >&5
+if eval "test \"\${ac_cv_var_syscall_bug+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$target" in
+ *-*-solaris2.4*)
+    ans=yes
+    ;;
+ *) ans=no
+    ;;
+esac
+ac_cv_var_syscall_bug=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_syscall_bug" 1>&6
+case "$ac_cv_var_syscall_bug" in
+ yes) cat >> confdefs.h <<\EOF
+#define SYSCALL_BUG 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking for Streams/TLI""... $ac_c" 1>&6
+echo "configure:7161: checking for Streams/TLI" >&5
+if eval "test \"\${ac_cv_var_streams_tli+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+   case "$ac_cv_header_sys_stropts_h" in
+  yes)
+     ans=no
+     # There must be a better way...
+     case "$target" in
+      *-*-ptx*)
+         ans=yes
+         ;;
+     esac
+     ;;
+ esac
+ ac_cv_var_streams_tli=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_streams_tli" 1>&6
+case "$ac_cv_var_streams_tli" in
+ yes)
+    cat >> confdefs.h <<\EOF
+#define STREAMS_TLI 1
+EOF
+
+    ;;
+esac
+
+echo $ac_n "checking for SIGIO""... $ac_c" 1>&6
+echo "configure:7190: checking for SIGIO" >&5
+if eval "test \"\${ac_cv_hdr_def_sigio+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#ifdef SIGIO
+   yes
+#endif
+  
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_hdr_def_sigio=yes
+else
+  rm -rf conftest*
+  ac_cv_hdr_def_sigio=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_hdr_def_sigio" 1>&6
+
+echo $ac_n "checking if we want to use signalled IO""... $ac_c" 1>&6
+echo "configure:7218: checking if we want to use signalled IO" >&5
+if eval "test \"\${ac_cv_var_signalled_io+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=no
+case "$ac_cv_hdr_def_sigio" in
+ yes)
+    ans=yes
+    case "$target" in
+     alpha*-dec-osf4*|alpha*-dec-osf5*)
+        ans=no
+        ;;
+     *-convex-*)
+        ans=no
+        ;;
+     *-dec-*)
+        ans=no
+        ;;
+     *-pc-cygwin*)
+	ans=no
+	;;
+     *-sni-sysv*)
+        ans=no
+        ;;
+     *-univel-sysv*)
+        ans=no
+	;;
+     *-*-irix6*)
+	ans=no
+	;;
+     *-*-freebsd*)
+	ans=no
+	;;
+     *-*-linux*)
+	ans=no
+	;;
+    esac
+    ;;
+esac
+ac_cv_var_signalled_io=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_signalled_io" 1>&6
+case "$ac_cv_var_signalled_io" in
+ yes) cat >> confdefs.h <<\EOF
+#define HAVE_SIGNALED_IO 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking for SIGPOLL""... $ac_c" 1>&6
+echo "configure:7269: checking for SIGPOLL" >&5
+if eval "test \"\${ac_cv_hdr_def_sigpoll+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#ifdef SIGPOLL
+  yes
+#endif
+ 
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_hdr_def_sigpoll=yes
+else
+  rm -rf conftest*
+  ac_cv_hdr_def_sigpoll=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_hdr_def_sigpoll" 1>&6
+
+echo $ac_n "checking for SIGSYS""... $ac_c" 1>&6
+echo "configure:7297: checking for SIGSYS" >&5
+if eval "test \"\${ac_cv_hdr_def_sigsys+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#ifdef SIGSYS
+  yes
+#endif
+ 
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_hdr_def_sigsys=yes
+else
+  rm -rf conftest*
+  ac_cv_hdr_def_sigsys=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_hdr_def_sigsys" 1>&6
+
+echo $ac_n "checking if we can use SIGPOLL for UDP I/O""... $ac_c" 1>&6
+echo "configure:7325: checking if we can use SIGPOLL for UDP I/O" >&5
+if eval "test \"\${ac_cv_var_use_udp_sigpoll+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=no
+case "$ac_cv_hdr_def_sigpoll" in
+ yes)
+        case "$target" in
+     mips-sgi-irix*)
+	ans=no
+	;;
+     vax-dec-bsd)
+        ans=no
+        ;;
+     *-pc-cygwin*)
+	ans=no
+	;;
+     *-sni-sysv*)
+        ans=no
+        ;;
+     *-*-aix4*)
+        ans=no
+        ;;
+     *-*-hpux*)
+        ans=no
+        ;;
+     *-*-linux*)
+	ans=no
+	;;
+     *-*-osf*)
+        ans=no
+        ;;
+     *-*-sunos*)
+	ans=no
+	;;
+     *-*-ultrix*)
+        ans=no
+        ;;
+     *) ans=yes
+        ;;
+    esac
+        ;;
+esac
+ac_cv_var_use_udp_sigpoll=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_use_udp_sigpoll" 1>&6
+case "$ac_cv_var_use_udp_sigpoll" in
+ yes) cat >> confdefs.h <<\EOF
+#define USE_UDP_SIGPOLL 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if we can use SIGPOLL for TTY I/O""... $ac_c" 1>&6
+echo "configure:7380: checking if we can use SIGPOLL for TTY I/O" >&5
+if eval "test \"\${ac_cv_var_use_tty_sigpoll+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=no
+case "$ac_cv_hdr_def_sigpoll" in
+ yes)
+    case "$target" in
+     mips-sgi-irix*)
+        ans=no
+        ;;
+     vax-dec-bsd)
+        ans=no
+        ;;
+     *-pc-cygwin*)
+	ans=no
+	;;
+     *-sni-sysv*)
+        ans=no
+        ;;
+     *-*-aix4*)
+	ans=no
+	;;
+     *-*-hpux*)
+        ans=no
+        ;;
+     *-*-linux*)
+	ans=no
+	;;
+     *-*-osf*)
+        ans=no
+        ;;
+     *-*-sunos*)
+	ans=no
+	;;
+     *-*-ultrix*)
+        ans=no
+        ;;
+     *) ans=yes
+        ;;
+    esac
+    ;;
+esac
+ac_cv_var_use_tty_sigpoll=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_use_tty_sigpoll" 1>&6
+case "$ac_cv_var_use_tty_sigpoll" in
+ yes) cat >> confdefs.h <<\EOF
+#define USE_TTY_SIGPOLL 1
+EOF
+ ;;
+esac
+
+case "$ac_cv_header_sys_sio_h" in
+ yes)
+    echo $ac_n "checking sys/sio.h for TIOCDCDTIMESTAMP""... $ac_c" 1>&6
+echo "configure:7437: checking sys/sio.h for TIOCDCDTIMESTAMP" >&5
+if eval "test \"\${ac_cv_hdr_def_tiocdcdtimestamp+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#ifdef TIOCDCDTIMESTAMP
+  yes
+#endif
+     
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_hdr_def_tiocdcdtimestamp=yes
+else
+  rm -rf conftest*
+  ac_cv_hdr_def_tiocdcdtimestamp=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_hdr_def_tiocdcdtimestamp" 1>&6
+    ;;
+esac
+
+echo $ac_n "checking if nlist() values might require extra indirection""... $ac_c" 1>&6
+echo "configure:7467: checking if nlist() values might require extra indirection" >&5
+if eval "test \"\${ac_cv_var_nlist_extra_indirection+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=no
+case "$target" in
+ *-*-aix*)
+    ans=yes
+    ;;
+esac
+ac_cv_var_nlist_extra_indirection=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_nlist_extra_indirection" 1>&6
+case "$ac_cv_var_nlist_extra_indirection" in
+ yes) cat >> confdefs.h <<\EOF
+#define NLIST_EXTRA_INDIRECTION 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking for a minimum recommended value of tickadj""... $ac_c" 1>&6
+echo "configure:7489: checking for a minimum recommended value of tickadj" >&5
+if eval "test \"\${ac_cv_var_min_rec_tickadj+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=no
+case "$target" in
+ *-*-aix*)
+    ans=40
+    ;;
+esac
+ac_cv_var_min_rec_tickadj=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_min_rec_tickadj" 1>&6
+case "$ac_cv_var_min_rec_tickadj" in
+ ''|no) ;;
+ *) cat >> confdefs.h <&6
+echo "configure:7512: checking if the TTY code permits PARENB and IGNPAR" >&5
+if eval "test \"\${ac_cv_var_no_parenb_ignpar+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=no
+case "$target" in
+ i?86-*-linux*)
+    ans=yes
+    ;;
+ mips-sgi-irix*)
+    ans=yes
+    ;;
+esac
+ac_cv_var_no_parenb_ignpar=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_no_parenb_ignpar" 1>&6
+case "$ac_cv_var_no_parenb_ignpar" in
+ yes) cat >> confdefs.h <<\EOF
+#define NO_PARENB_IGNPAR 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if we're including debugging code""... $ac_c" 1>&6
+echo "configure:7537: checking if we're including debugging code" >&5
+# Check whether --enable-debugging or --disable-debugging was given.
+if test "${enable_debugging+set}" = set; then
+  enableval="$enable_debugging"
+  ntp_ok=$enableval
+else
+  ntp_ok=yes
+fi
+
+if test "$ntp_ok" = "yes"; then
+    cat >> confdefs.h <<\EOF
+#define DEBUG 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking for a the number of minutes in a DST adjustment""... $ac_c" 1>&6
+echo "configure:7555: checking for a the number of minutes in a DST adjustment" >&5
+# Check whether --enable-dst_minutes or --disable-dst_minutes was given.
+if test "${enable_dst_minutes+set}" = set; then
+  enableval="$enable_dst_minutes"
+  ans=$enableval
+else
+  ans=60
+fi
+
+cat >> confdefs.h <&6
+
+echo $ac_n "checking if we have the tty_clk line discipline/streams module""... $ac_c" 1>&6
+echo "configure:7571: checking if we have the tty_clk line discipline/streams module" >&5
+if eval "test \"\${ac_cv_var_tty_clk+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$ac_cv_header_sys_clkdefs_h$ac_cv_hdr_def_tiocdcdtimestamp" in
+  *yes*) ac_cv_var_tty_clk=yes ;;
+ esac
+fi
+
+echo "$ac_t""$ac_cv_var_tty_clk" 1>&6
+case "$ac_cv_var_tty_clk" in
+ yes) cat >> confdefs.h <<\EOF
+#define TTYCLK 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking for the ppsclock streams module""... $ac_c" 1>&6
+echo "configure:7589: checking for the ppsclock streams module" >&5
+if eval "test \"\${ac_cv_var_ppsclock+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_var_ppsclock=$ac_cv_struct_ppsclockev
+fi
+
+echo "$ac_t""$ac_cv_var_ppsclock" 1>&6
+case "$ac_cv_var_ppsclock" in
+ yes) cat >> confdefs.h <<\EOF
+#define PPS 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking for kernel multicast support""... $ac_c" 1>&6
+echo "configure:7605: checking for kernel multicast support" >&5
+if eval "test \"\${ac_cv_var_mcast+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_var_mcast=no
+  case "$target" in
+   i386-sequent-sysv4) ;;
+   *) cat > conftest.$ac_ext <
+#ifdef IP_ADD_MEMBERSHIP
+   yes
+#endif
+  
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_var_mcast=yes
+fi
+rm -f conftest*
+ ;;
+  esac
+fi
+
+echo "$ac_t""$ac_cv_var_mcast" 1>&6
+case "$ac_cv_var_mcast" in
+ yes) cat >> confdefs.h <<\EOF
+#define MCAST 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking availability of ntp_{adj,get}time()""... $ac_c" 1>&6
+echo "configure:7640: checking availability of ntp_{adj,get}time()" >&5
+if eval "test \"\${ac_cv_var_ntp_syscalls+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_var_ntp_syscalls=no
+ case "$ac_cv_func___adjtimex" in
+  yes)
+    ac_cv_var_ntp_syscalls=libc
+    ;;
+  *) case "$ac_cv_func_ntp_adjtime$ac_cv_func_ntp_gettime" in
+      yesyes)
+        ac_cv_var_ntp_syscalls=libc
+        ;;
+      *) cat > conftest.$ac_ext <
+#if defined(SYS_ntp_gettime) && defined(SYS_ntp_adjtime)
+           yes
+#endif
+          
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_var_ntp_syscalls=kernel
+fi
+rm -f conftest*
+
+         ;;
+     esac
+     ;;
+ esac
+fi
+
+echo "$ac_t""$ac_cv_var_ntp_syscalls" 1>&6
+case "$ac_cv_var_ntp_syscalls" in
+ libc)
+    cat >> confdefs.h <<\EOF
+#define NTP_SYSCALLS_LIBC 1
+EOF
+
+    ;;
+ kernel)
+    cat >> confdefs.h <<\EOF
+#define NTP_SYSCALLS_STD 1
+EOF
+
+    ;;
+ *)
+    ;;
+esac
+
+echo $ac_n "checking if sys/timex.h has STA_FLL""... $ac_c" 1>&6
+echo "configure:7694: checking if sys/timex.h has STA_FLL" >&5
+if eval "test \"\${ac_cv_var_sta_fll+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+#ifdef STA_FLL
+    yes
+#endif
+    
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_var_sta_fll=yes
+else
+  rm -rf conftest*
+  ac_cv_var_sta_fll=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_var_sta_fll" 1>&6
+
+echo $ac_n "checking if we have kernel PLL support""... $ac_c" 1>&6
+echo "configure:7722: checking if we have kernel PLL support" >&5
+if eval "test \"\${ac_cv_var_kernel_pll+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$ac_cv_header_sys_timex_h$ac_cv_struct_ntptimeval$ac_cv_var_sta_fll$ac_cv_var_ntp_syscalls" in
+ *no*)
+    ac_cv_var_kernel_pll=no
+    ;;
+ *) ac_cv_var_kernel_pll=yes
+    ;;
+esac
+fi
+
+echo "$ac_t""$ac_cv_var_kernel_pll" 1>&6
+case "$ac_cv_var_kernel_pll" in
+ yes)
+    cat >> confdefs.h <<\EOF
+#define KERNEL_PLL 1
+EOF
+
+    ;;
+esac
+
+echo $ac_n "checking if SIOCGIFCONF returns buffer size in the buffer""... $ac_c" 1>&6
+echo "configure:7746: checking if SIOCGIFCONF returns buffer size in the buffer" >&5
+if eval "test \"\${ac_cv_var_size_returned_in_buffer+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=no
+  case "$target" in
+   *-fujitsu-uxp*)
+      ans=yes
+      ;;
+   *-ncr-sysv4*)
+      ans=yes
+      ;;
+   *-univel-sysv*)
+      ans=yes
+      ;;
+  esac
+  ac_cv_var_size_returned_in_buffer=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_size_returned_in_buffer" 1>&6
+case "$ac_cv_var_size_returned_in_buffer" in
+ yes) cat >> confdefs.h <<\EOF
+#define SIZE_RETURNED_IN_BUFFER 1
+EOF
+ ;;
+esac
+
+
+echo $ac_n "checking if we want to use MD5 authentication""... $ac_c" 1>&6
+echo "configure:7775: checking if we want to use MD5 authentication" >&5
+if eval "test \"\${ac_cv_var_use_md5+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-md5 or --disable-md5 was given.
+if test "${enable_md5+set}" = set; then
+  enableval="$enable_md5"
+  ans=$enableval
+else
+  ans=yes
+fi
+
+ac_cv_var_use_md5=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_use_md5" 1>&6
+case "$ac_cv_var_use_md5" in
+ yes) cat >> confdefs.h <<\EOF
+#define MD5 1
+EOF
+ ;;
+esac
+
+# Check for ioctls TIOCGPPSEV
+echo $ac_n "checking ioctl TIOCGPPSEV""... $ac_c" 1>&6
+echo "configure:7800: checking ioctl TIOCGPPSEV" >&5
+if test "$ac_cv_header_termios_h" = "yes"; then
+    cat > conftest.$ac_ext <
+#ifdef TIOCGPPSEV
+         yes
+#endif
+	 
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ntp_ok=yes
+else
+  rm -rf conftest*
+  ntp_ok=no
+fi
+rm -f conftest*
+
+else
+ntp_ok=no
+fi
+
+if test "$ntp_ok" = "yes"; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_TIOCGPPSEV 1
+EOF
+
+    ac_cv_var_oncore_ok=yes
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+# Check for ioctls TIOCSPPS
+echo $ac_n "checking ioctl TIOCSPPS""... $ac_c" 1>&6
+echo "configure:7836: checking ioctl TIOCSPPS" >&5
+if test "$ac_cv_header_termios_h" = "yes"; then
+    cat > conftest.$ac_ext <
+#ifdef TIOCSPPS
+         yes
+#endif
+	 
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ntp_ok=yes
+else
+  rm -rf conftest*
+  ntp_ok=no
+fi
+rm -f conftest*
+
+else
+    ntp_ok=no
+fi
+
+if test "$ntp_ok" = "yes"; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_TIOCSPPS 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+# Check for ioctls CIOGETEV
+echo $ac_n "checking ioctl CIOGETEV""... $ac_c" 1>&6
+echo "configure:7871: checking ioctl CIOGETEV" >&5
+if test "$ac_cv_header_sys_ppsclock_h" = "yes"; then
+    cat > conftest.$ac_ext <
+#ifdef CIOGETEV
+         yes
+#endif
+	 
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ntp_ok=yes
+else
+  rm -rf conftest*
+  ntp_ok=no
+fi
+rm -f conftest*
+
+else
+ntp_ok=no
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ac_cv_var_oncore_ok=yes
+    cat >> confdefs.h <<\EOF
+#define HAVE_CIOGETEV 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+# Check for header timepps.h, if found then we have PPS API (Draft RFC) stuff.
+# there is NO way that I can tell to tell if a given OS is using timespec or
+# timeval so just set it here for the one case that is KNOWN to use timespec.
+
+case "$ac_cv_header_timepps_h$ac_cv_header_sys_timepps_h" in
+ *yes*)
+    cat >> confdefs.h <<\EOF
+#define HAVE_PPSAPI 1
+EOF
+
+    ac_cv_var_oncore_ok=yes
+    cat >> confdefs.h <<\EOF
+#define HAVE_TIMESPEC 1
+EOF
+
+    ;;
+esac
+
+# Check for ioctls TIOCGSERIAL, TIOCSSERIAL, ASYNC_PPS_CD_POS, ASYNC_PPS_CD_NEG
+ac_safe=`echo "linux/serial.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for linux/serial.h""... $ac_c" 1>&6
+echo "configure:7926: checking for linux/serial.h" >&5
+if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:7936: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking ioctl TIOCGSERIAL""... $ac_c" 1>&6
+echo "configure:7958: checking ioctl TIOCGSERIAL" >&5
+case "$ac_cv_header_sys_ppsclock_h$ac_cv_header_linux_serial_h" in
+  yesyes)
+    cat > conftest.$ac_ext <
+typedef int u_int;
+
+#include 
+#include 
+
+#ifdef TIOCGSERIAL
+#ifdef TIOCSSERIAL
+#ifdef ASYNC_PPS_CD_POS
+#ifdef ASYNC_PPS_CD_NEG
+#ifdef CIOGETEV
+         yes
+#endif
+#endif
+#endif
+#endif
+#endif
+	 
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ntp_ok=yes
+fi
+rm -f conftest*
+
+	;;
+  *)
+	ntp_ok=no
+	;;
+esac
+
+if test "$ntp_ok" = "yes"; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_TIO_SERIAL_STUFF 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+
+ntp_refclock=no
+
+# HPUX only, and by explicit request
+echo $ac_n "checking Datum/Bancomm bc635/VME interface""... $ac_c" 1>&6
+echo "configure:8009: checking Datum/Bancomm bc635/VME interface" >&5
+# Check whether --enable-BANCOMM or --disable-BANCOMM was given.
+if test "${enable_BANCOMM+set}" = set; then
+  enableval="$enable_BANCOMM"
+  ntp_ok=$enableval
+else
+  ntp_ok=no
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_BANC 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$target" in
+ yes*-*-hpux*) ;;
+ yes*) echo "configure: warning: *** But the expected answer is... no ***" 1>&2 ;;
+esac
+
+#HPUX only, and only by explicit request
+echo $ac_n "checking TrueTime GPS receiver/VME interface""... $ac_c" 1>&6
+echo "configure:8033: checking TrueTime GPS receiver/VME interface" >&5
+# Check whether --enable-GPSVME or --disable-GPSVME was given.
+if test "${enable_GPSVME+set}" = set; then
+  enableval="$enable_GPSVME"
+  ntp_ok=$enableval
+else
+  ntp_ok=no
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_GPSVME 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$target" in
+ yes*-*-hpux*) ;;
+ yes*) echo "configure: warning: *** But the expected answer is... no ***" 1>&2 ;;
+esac
+
+echo $ac_n "checking for PCL720 clock support""... $ac_c" 1>&6
+echo "configure:8056: checking for PCL720 clock support" >&5
+case "$ac_cv_header_machine_inline_h$ac_cv_header_sys_pcl720_h$ac_cv_header_sys_i8253_h" in
+ yesyesyes)
+    cat >> confdefs.h <<\EOF
+#define CLOCK_PPS720 1
+EOF
+
+    ans=yes
+    ;;
+ *)
+    ans=no
+    ;;
+esac
+echo "$ac_t""$ans" 1>&6
+
+echo $ac_n "checking for SHM clock attached thru shared memory""... $ac_c" 1>&6
+echo "configure:8072: checking for SHM clock attached thru shared memory" >&5
+# Check whether --enable-SHM or --disable-SHM was given.
+if test "${enable_SHM+set}" = set; then
+  enableval="$enable_SHM"
+  ntp_ok=$enableval
+else
+  ntp_ok=no
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_SHM 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking for default inclusion of all suitable non-PARSE clocks""... $ac_c" 1>&6
+echo "configure:8091: checking for default inclusion of all suitable non-PARSE clocks" >&5
+# Check whether --enable-all-clocks or --disable-all-clocks was given.
+if test "${enable_all_clocks+set}" = set; then
+  enableval="$enable_all_clocks"
+  ntp_eac=$enableval
+else
+  ntp_eac=yes
+fi
+
+echo "$ac_t""$ntp_eac" 1>&6
+
+echo $ac_n "checking if we have support for PARSE clocks""... $ac_c" 1>&6
+echo "configure:8103: checking if we have support for PARSE clocks" >&5
+case "$ac_cv_header_termio_h$ac_cv_header_termios_h" in
+ *yes*)
+    ntp_canparse=yes
+    ;;
+ *) ntp_canparse=no
+    ;;
+esac
+echo "$ac_t""$ntp_canparse" 1>&6
+
+# Requires modem control
+echo $ac_n "checking ACTS modem service""... $ac_c" 1>&6
+echo "configure:8115: checking ACTS modem service" >&5
+# Check whether --enable-ACTS or --disable-ACTS was given.
+if test "${enable_ACTS+set}" = set; then
+  enableval="$enable_ACTS"
+  ntp_ok=$enableval
+else
+  cat > conftest.$ac_ext <
+#ifdef HAVE_SYS_IOCTL_H
+#include 
+#endif
+#ifdef TIOCMBIS
+         yes
+#endif
+         
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ntp_ok=$ntp_eac
+else
+  rm -rf conftest*
+  ntp_ok=no
+fi
+rm -f conftest*
+
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_ACTS 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking Arbiter 1088A/B GPS receiver""... $ac_c" 1>&6
+echo "configure:8155: checking Arbiter 1088A/B GPS receiver" >&5
+# Check whether --enable-ARBITER or --disable-ARBITER was given.
+if test "${enable_ARBITER+set}" = set; then
+  enableval="$enable_ARBITER"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_ARBITER 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking Arcron MSF receiver""... $ac_c" 1>&6
+echo "configure:8174: checking Arcron MSF receiver" >&5
+# Check whether --enable-ARCRON_MSF or --disable-ARCRON_MSF was given.
+if test "${enable_ARCRON_MSF+set}" = set; then
+  enableval="$enable_ARCRON_MSF"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_ARCRON_MSF 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking Austron 2200A/2201A GPS receiver""... $ac_c" 1>&6
+echo "configure:8193: checking Austron 2200A/2201A GPS receiver" >&5
+# Check whether --enable-AS2201 or --disable-AS2201 was given.
+if test "${enable_AS2201+set}" = set; then
+  enableval="$enable_AS2201"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_AS2201 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking PPS interface""... $ac_c" 1>&6
+echo "configure:8212: checking PPS interface" >&5
+# Check whether --enable-ATOM or --disable-ATOM was given.
+if test "${enable_ATOM+set}" = set; then
+  enableval="$enable_ATOM"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_ATOM 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking CHU modem/decoder""... $ac_c" 1>&6
+echo "configure:8231: checking CHU modem/decoder" >&5
+# Check whether --enable-CHU or --disable-CHU was given.
+if test "${enable_CHU+set}" = set; then
+  enableval="$enable_CHU"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_CHU 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+ac_refclock_chu=$ntp_ok
+
+echo $ac_n "checking CHU audio/decoder""... $ac_c" 1>&6
+echo "configure:8251: checking CHU audio/decoder" >&5
+# Check whether --enable-AUDIO-CHU or --disable-AUDIO-CHU was given.
+if test "${enable_AUDIO_CHU+set}" = set; then
+  enableval="$enable_AUDIO_CHU"
+  ntp_ok=$enableval
+else
+  ntp_ok=no
+fi
+
+if test "$ntp_ok" = "yes"; then
+    cat >> confdefs.h <<\EOF
+#define AUDIO_CHU 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ac_refclock_chu$target" in
+ yesyes*-*-sunos*) ;;
+ yesyes*-*-solaris*) ;;
+ yes*) echo "configure: warning: *** But the expected answer is...no ***" 1>&2 ;;
+esac
+
+# Not under HP-UX
+echo $ac_n "checking Datum Programmable Time System""... $ac_c" 1>&6
+echo "configure:8275: checking Datum Programmable Time System" >&5
+# Check whether --enable-DATUM or --disable-DATUM was given.
+if test "${enable_DATUM+set}" = set; then
+  enableval="$enable_DATUM"
+  ntp_ok=$enableval
+else
+  case "$ac_cv_header_termios_h" in
+    yes)
+        ntp_ok=$ntp_eac
+        ;;
+    *) ntp_ok=no
+        ;;
+    esac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_DATUM 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+# Requires modem control
+echo $ac_n "checking Heath GC-1000 WWV/WWVH receiver""... $ac_c" 1>&6
+echo "configure:8301: checking Heath GC-1000 WWV/WWVH receiver" >&5
+# Check whether --enable-HEATH or --disable-HEATH was given.
+if test "${enable_HEATH+set}" = set; then
+  enableval="$enable_HEATH"
+  ntp_ok=$enableval
+else
+  cat > conftest.$ac_ext <
+#ifdef HAVE_SYS_IOCTL_H
+#include 
+#endif
+#ifdef TIOCMBIS
+         yes
+#endif
+         
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ntp_ok=$ntp_eac
+else
+  rm -rf conftest*
+  ntp_ok=no
+fi
+rm -f conftest*
+
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_HEATH 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking HP 58503A GPS receiver""... $ac_c" 1>&6
+echo "configure:8341: checking HP 58503A GPS receiver" >&5
+# Check whether --enable-HPGPS or --disable-HPGPS was given.
+if test "${enable_HPGPS+set}" = set; then
+  enableval="$enable_HPGPS"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_HPGPS 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking Sun IRIG audio decoder""... $ac_c" 1>&6
+echo "configure:8360: checking Sun IRIG audio decoder" >&5
+# Check whether --enable-IRIG or --disable-IRIG was given.
+if test "${enable_IRIG+set}" = set; then
+  enableval="$enable_IRIG"
+  ntp_ok=$enableval
+else
+  case "$ac_cv_header_sun_audioio_h$ac_cv_header_sys_audioio_h" in
+     *yes*)
+	ntp_ok=$ntp_eac
+	;;
+     *)	ntp_ok=no
+	;;
+    esac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_IRIG 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ac_cv_header_sun_audioio_h$ac_cv_header_sys_audioio_h" in
+ yesnono) echo "configure: warning: *** But the expected answer is... no ***" 1>&2 ;;
+esac
+
+echo $ac_n "checking Leitch CSD 5300 Master Clock System Driver""... $ac_c" 1>&6
+echo "configure:8388: checking Leitch CSD 5300 Master Clock System Driver" >&5
+# Check whether --enable-LEITCH or --disable-LEITCH was given.
+if test "${enable_LEITCH+set}" = set; then
+  enableval="$enable_LEITCH"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_LEITCH 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking local clock reference""... $ac_c" 1>&6
+echo "configure:8407: checking local clock reference" >&5
+# Check whether --enable-LOCAL-CLOCK or --disable-LOCAL-CLOCK was given.
+if test "${enable_LOCAL_CLOCK+set}" = set; then
+  enableval="$enable_LOCAL_CLOCK"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_LOCAL 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking EES M201 MSF receiver""... $ac_c" 1>&6
+echo "configure:8426: checking EES M201 MSF receiver" >&5
+# Check whether --enable-MSFEES or --disable-MSFEES was given.
+if test "${enable_MSFEES+set}" = set; then
+  enableval="$enable_MSFEES"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_MSFEES 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+# Not Ultrix
+echo $ac_n "checking Magnavox MX4200 GPS receiver""... $ac_c" 1>&6
+echo "configure:8446: checking Magnavox MX4200 GPS receiver" >&5
+# Check whether --enable-MX4200 or --disable-MX4200 was given.
+if test "${enable_MX4200+set}" = set; then
+  enableval="$enable_MX4200"
+  ntp_ok=$enableval
+else
+  case "$ac_cv_var_ppsclock" in
+     yes) ntp_ok=$ntp_eac
+        ;;
+     *) ntp_ok=no
+        ;;
+    esac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_MX4200 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$target" in
+ yes*-*-ultrix*) echo "configure: warning: *** But the expected answer is... no ***" 1>&2 ;;
+esac
+
+echo $ac_n "checking NMEA GPS receiver""... $ac_c" 1>&6
+echo "configure:8473: checking NMEA GPS receiver" >&5
+# Check whether --enable-NMEA or --disable-NMEA was given.
+if test "${enable_NMEA+set}" = set; then
+  enableval="$enable_NMEA"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_NMEA 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking for ONCORE Motorola VP/UT Oncore GPS""... $ac_c" 1>&6
+echo "configure:8492: checking for ONCORE Motorola VP/UT Oncore GPS" >&5
+# Check whether --enable-ONCORE or --disable-ONCORE was given.
+if test "${enable_ONCORE+set}" = set; then
+  enableval="$enable_ONCORE"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+case "$ac_cv_var_oncore_ok" in
+ no) ntp_ok=no ;;
+esac
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_ONCORE 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking for Palisade clock""... $ac_c" 1>&6
+echo "configure:8514: checking for Palisade clock" >&5
+# Check whether --enable-PALISADE or --disable-PALISADE was given.
+if test "${enable_PALISADE+set}" = set; then
+  enableval="$enable_PALISADE"
+  ntp_ok=$enableval
+else
+  case "$ac_cv_header_termios_h" in
+    yes)
+        ntp_ok=$ntp_eac
+        ;;
+    *) ntp_ok=no
+        ;;
+    esac
+fi
+
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_PALISADE 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking PST/Traconex 1020 WWV/WWVH receiver""... $ac_c" 1>&6
+echo "configure:8540: checking PST/Traconex 1020 WWV/WWVH receiver" >&5
+# Check whether --enable-PST or --disable-PST was given.
+if test "${enable_PST+set}" = set; then
+  enableval="$enable_PST"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_PST 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+# Not Ultrix
+echo $ac_n "checking Rockwell Jupiter GPS receiver""... $ac_c" 1>&6
+echo "configure:8560: checking Rockwell Jupiter GPS receiver" >&5
+# Check whether --enable-JUPITER or --disable-JUPITER was given.
+if test "${enable_JUPITER+set}" = set; then
+  enableval="$enable_JUPITER"
+  ntp_ok=$enableval
+else
+  case "$ac_cv_var_ppsclock" in
+#     yes) ntp_ok=$ntp_eac
+#        ;;
+     *) ntp_ok=no
+        ;;
+    esac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_JUPITER 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$target" in
+ yes*-*-ultrix*) echo "configure: warning: *** But the expected answer is... no ***" 1>&2 ;;
+esac
+
+# Requires modem control
+echo $ac_n "checking PTB modem service""... $ac_c" 1>&6
+echo "configure:8588: checking PTB modem service" >&5
+# Check whether --enable-PTBACTS or --disable-PTBACTS was given.
+if test "${enable_PTBACTS+set}" = set; then
+  enableval="$enable_PTBACTS"
+  ntp_ok=$enableval
+else
+  cat > conftest.$ac_ext <
+#ifdef HAVE_SYS_IOCTL_H
+#include 
+#endif
+#ifdef TIOCMBIS
+         yes
+#endif
+         
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ntp_ok=$ntp_eac
+else
+  rm -rf conftest*
+  ntp_ok=no
+fi
+rm -f conftest*
+
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_PTBACTS 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking KSI/Odetics TPRO/S GPS receiver/IRIG interface""... $ac_c" 1>&6
+echo "configure:8628: checking KSI/Odetics TPRO/S GPS receiver/IRIG interface" >&5
+# Check whether --enable-TPRO or --disable-TPRO was given.
+if test "${enable_TPRO+set}" = set; then
+  enableval="$enable_TPRO"
+  ntp_ok=$enableval
+else
+  case "$ac_cv_header_sys_tpro_h" in
+     yes)
+	ntp_ok=$ntp_eac
+	;;
+     *)	ntp_ok=no
+	;;
+    esac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_TPRO 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ac_cv_header_sys_tpro" in
+ yesno) echo "configure: warning: *** But the expected answer is... no ***" 1>&2 ;;
+esac
+
+echo $ac_n "checking TRAK 8810 GPS receiver""... $ac_c" 1>&6
+echo "configure:8656: checking TRAK 8810 GPS receiver" >&5
+# Check whether --enable-TRAK or --disable-TRAK was given.
+if test "${enable_TRAK+set}" = set; then
+  enableval="$enable_TRAK"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_TRAK 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking Chrono-log K-series WWVB receiver""... $ac_c" 1>&6
+echo "configure:8675: checking Chrono-log K-series WWVB receiver" >&5
+# Check whether --enable-CHRONOLOG or --disable-CHRONOLOG was given.
+if test "${enable_CHRONOLOG+set}" = set; then
+  enableval="$enable_CHRONOLOG"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_CHRONOLOG 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking Dumb generic hh:mm:ss local clock""... $ac_c" 1>&6
+echo "configure:8694: checking Dumb generic hh:mm:ss local clock" >&5
+# Check whether --enable-DUMBCLOCK or --disable-DUMBCLOCK was given.
+if test "${enable_DUMBCLOCK+set}" = set; then
+  enableval="$enable_DUMBCLOCK"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_DUMBCLOCK 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+# Not on a vax-dec-bsd
+echo $ac_n "checking Kinemetrics/TrueTime receivers""... $ac_c" 1>&6
+echo "configure:8714: checking Kinemetrics/TrueTime receivers" >&5
+# Check whether --enable-TRUETIME or --disable-TRUETIME was given.
+if test "${enable_TRUETIME+set}" = set; then
+  enableval="$enable_TRUETIME"
+  ntp_ok=$enableval
+else
+  case "$target" in
+     vax-dec-bsd)
+	ntp_ok=no
+	;;
+     *)
+	ntp_ok=$ntp_eac
+	;;
+    esac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_TRUETIME 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$target" in
+ yesvax-dec-bsd) echo "configure: warning: *** But the expected answer is... no ***" 1>&2 ;;
+esac
+
+echo $ac_n "checking Spectracom 8170/Netclock/2 WWVB receiver""... $ac_c" 1>&6
+echo "configure:8743: checking Spectracom 8170/Netclock/2 WWVB receiver" >&5
+# Check whether --enable-WWVB or --disable-WWVB was given.
+if test "${enable_WWVB+set}" = set; then
+  enableval="$enable_WWVB"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_WWVB 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking Ultralink M320 WWVB receiver""... $ac_c" 1>&6
+echo "configure:8762: checking Ultralink M320 WWVB receiver" >&5
+# Check whether --enable-ULINK or --disable-ULINK was given.
+if test "${enable_ULINK+set}" = set; then
+  enableval="$enable_ULINK"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_ULINK 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+# Requires modem control
+echo $ac_n "checking USNO modem service""... $ac_c" 1>&6
+echo "configure:8782: checking USNO modem service" >&5
+# Check whether --enable-USNO or --disable-USNO was given.
+if test "${enable_USNO+set}" = set; then
+  enableval="$enable_USNO"
+  ntp_ok=$enableval
+else
+  cat > conftest.$ac_ext <
+#ifdef HAVE_SYS_IOCTL_H
+#include 
+#endif
+#ifdef TIOCMBIS
+         yes
+#endif
+         
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ntp_ok=$ntp_eac
+else
+  rm -rf conftest*
+  ntp_ok=no
+fi
+rm -f conftest*
+
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_USNO 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+
+echo $ac_n "checking for default inclusion of all suitable PARSE clocks""... $ac_c" 1>&6
+echo "configure:8822: checking for default inclusion of all suitable PARSE clocks" >&5
+# Check whether --enable-parse-clocks or --disable-parse-clocks was given.
+if test "${enable_parse_clocks+set}" = set; then
+  enableval="$enable_parse_clocks"
+  ntp_eapc=$enableval
+else
+  case "$ntp_eac" in
+     yes) ntp_eapc=$ntp_canparse ;;
+     *) ntp_eapc=no ;;
+    esac
+    ntp_eapc=no
+fi
+
+echo "$ac_t""$ntp_eapc" 1>&6
+
+case "$ntp_eac$ntp_eapc$ntp_canparse" in
+ noyes*)
+    { echo "configure: error: "--enable-parse-clocks" requires "--enable-all-clocks"." 1>&2; exit 1; }
+    ;;
+ yesyesno)
+    { echo "configure: error: You said "--enable-parse-clocks" but PARSE isn't supported on this platform!" 1>&2; exit 1; }
+    ;;
+ *) ;;
+esac
+
+ntp_libparse=no
+ntp_parseutil=no
+ntp_rawdcf=no
+
+echo $ac_n "checking Diem Computime Radio Clock""... $ac_c" 1>&6
+echo "configure:8852: checking Diem Computime Radio Clock" >&5
+# Check whether --enable-COMPUTIME or --disable-COMPUTIME was given.
+if test "${enable_COMPUTIME+set}" = set; then
+  enableval="$enable_COMPUTIME"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_COMPUTIME 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+echo $ac_n "checking ELV/DCF7000 clock""... $ac_c" 1>&6
+echo "configure:8877: checking ELV/DCF7000 clock" >&5
+# Check whether --enable-DCF7000 or --disable-DCF7000 was given.
+if test "${enable_DCF7000+set}" = set; then
+  enableval="$enable_DCF7000"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_DCF7000 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+echo $ac_n "checking HOPF 6021 clock""... $ac_c" 1>&6
+echo "configure:8902: checking HOPF 6021 clock" >&5
+# Check whether --enable-HOPF6021 or --disable-HOPF6021 was given.
+if test "${enable_HOPF6021+set}" = set; then
+  enableval="$enable_HOPF6021"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_HOPF6021 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+echo $ac_n "checking Meinberg clocks""... $ac_c" 1>&6
+echo "configure:8927: checking Meinberg clocks" >&5
+# Check whether --enable-MEINBERG or --disable-MEINBERG was given.
+if test "${enable_MEINBERG+set}" = set; then
+  enableval="$enable_MEINBERG"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_MEINBERG 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+echo $ac_n "checking DCF77 raw time code""... $ac_c" 1>&6
+echo "configure:8952: checking DCF77 raw time code" >&5
+# Check whether --enable-RAWDCF or --disable-RAWDCF was given.
+if test "${enable_RAWDCF+set}" = set; then
+  enableval="$enable_RAWDCF"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_parseutil=yes
+    ntp_refclock=yes
+    ntp_rawdcf=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_RAWDCF 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+case "$ntp_rawdcf" in
+ yes)
+    echo $ac_n "checking if we must enable parity for RAWDCF""... $ac_c" 1>&6
+echo "configure:8981: checking if we must enable parity for RAWDCF" >&5
+if eval "test \"\${ac_cv_var_rawdcf_parity+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=no
+    case "$target" in
+     *-*-linux*)
+        ans=yes
+        ;;
+    esac
+    ac_cv_var_rawdcf_parity=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_rawdcf_parity" 1>&6
+    case "$ac_cv_var_rawdcf_parity" in
+     yes) cat >> confdefs.h <<\EOF
+#define RAWDCF_NO_IGNPAR 1
+EOF
+ ;;
+    esac
+    ;;
+
+ *) # HMS: Is this a good idea?
+    ac_cv_var_rawdcf_parity=no
+    ;;
+esac
+
+echo $ac_n "checking RCC 8000 clock""... $ac_c" 1>&6
+echo "configure:9009: checking RCC 8000 clock" >&5
+# Check whether --enable-RCC8000 or --disable-RCC8000 was given.
+if test "${enable_RCC8000+set}" = set; then
+  enableval="$enable_RCC8000"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_RCC8000 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+echo $ac_n "checking Schmid DCF77 clock""... $ac_c" 1>&6
+echo "configure:9034: checking Schmid DCF77 clock" >&5
+# Check whether --enable-SCHMID or --disable-SCHMID was given.
+if test "${enable_SCHMID+set}" = set; then
+  enableval="$enable_SCHMID"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_SCHMID 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+echo $ac_n "checking Trimble GPS receiver/TAIP protocol""... $ac_c" 1>&6
+echo "configure:9059: checking Trimble GPS receiver/TAIP protocol" >&5
+# Check whether --enable-TRIMTAIP or --disable-TRIMTAIP was given.
+if test "${enable_TRIMTAIP+set}" = set; then
+  enableval="$enable_TRIMTAIP"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_TRIMTAIP 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+echo $ac_n "checking Trimble GPS receiver/TSIP protocol""... $ac_c" 1>&6
+echo "configure:9084: checking Trimble GPS receiver/TSIP protocol" >&5
+# Check whether --enable-TRIMTSIP or --disable-TRIMTSIP was given.
+if test "${enable_TRIMTSIP+set}" = set; then
+  enableval="$enable_TRIMTSIP"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_TRIMTSIP 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+echo $ac_n "checking WHARTON 400A Series clock""... $ac_c" 1>&6
+echo "configure:9109: checking WHARTON 400A Series clock" >&5
+# Check whether --enable-WHARTON or --disable-WHARTON was given.
+if test "${enable_WHARTON+set}" = set; then
+  enableval="$enable_WHARTON"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_WHARTON_400A 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+echo $ac_n "checking VARITEXT clock""... $ac_c" 1>&6
+echo "configure:9134: checking VARITEXT clock" >&5
+# Check whether --enable-VARITEXT or --disable-VARITEXT was given.
+if test "${enable_VARITEXT+set}" = set; then
+  enableval="$enable_VARITEXT"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eapc
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_VARITEXT 1
+EOF
+
+fi
+echo "$ac_t""$ntp_ok" 1>&6
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    { echo "configure: error: That's a parse clock and this system doesn't support it!" 1>&2; exit 1; }
+    ;;
+esac
+
+
+
+
+echo $ac_n "checking if we need to make and use the parse libraries""... $ac_c" 1>&6
+echo "configure:9162: checking if we need to make and use the parse libraries" >&5
+ans=no
+case "$ntp_libparse" in
+ yes)
+    ans=yes
+    cat >> confdefs.h <<\EOF
+#define CLOCK_PARSE 1
+EOF
+
+    LIBPARSE=../libparse/libparse.a
+    MAKE_LIBPARSE=libparse.a
+    MAKE_CHECK_Y2K=check_y2k
+    cat >> confdefs.h <<\EOF
+#define PPS_SAMPLE 1
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define CLOCK_ATOM 1
+EOF
+
+    ;;
+esac
+echo "$ac_t""$ans" 1>&6
+
+
+
+
+echo $ac_n "checking if we need to make and use the RSAREF library""... $ac_c" 1>&6
+echo "configure:9190: checking if we need to make and use the RSAREF library" >&5
+ans=no
+if test -f $srcdir/rsaref2/source/rsa.c
+then
+    ans=yes
+    LIBRSAREF=../librsaref/librsaref.a
+    MAKE_LIBRSAREF=librsaref.a
+    cat >> confdefs.h <<\EOF
+#define DES 1
+EOF
+
+fi
+echo "$ac_t""$ans" 1>&6
+
+
+
+
+echo $ac_n "checking if we can make dcf parse utilities""... $ac_c" 1>&6
+echo "configure:9208: checking if we can make dcf parse utilities" >&5
+ans=no
+if test "$ntp_parseutil" = "yes"; then
+    case "$target" in
+     *-*-sunos4*|*-*-solaris2*|*-*-linux*)
+	ans="dcfd testdcf"
+	DCFD=dcfd
+        TESTDCF=testdcf
+	;;
+    esac
+fi
+echo "$ac_t""$ans" 1>&6
+
+
+echo $ac_n "checking if we can build kernel streams modules for parse""... $ac_c" 1>&6
+echo "configure:9223: checking if we can build kernel streams modules for parse" >&5
+ans=no
+case "$ntp_parseutil$ac_cv_header_sys_stropts_h" in
+ yesyes)
+    case "$target" in
+     sparc-*-sunos4*)
+        case "$ac_cv_var_kernel_pll" in
+	yes)
+	    cat >> confdefs.h <<\EOF
+#define PPS_SYNC 1
+EOF
+
+	    ;;
+	esac
+	ans=parsestreams
+	MAKE_PARSEKMODULE=parsestreams.loadable_module.o
+	;;
+     sparc-*-solaris2*)
+	ans=parsesolaris
+	MAKE_PARSEKMODULE=parse
+	;;
+    esac
+    ;;
+esac
+echo "$ac_t""$ans" 1>&6
+
+echo $ac_n "checking if we need basic refclock support""... $ac_c" 1>&6
+echo "configure:9250: checking if we need basic refclock support" >&5
+if test "$ntp_refclock" = "yes"; then
+    cat >> confdefs.h <<\EOF
+#define REFCLOCK 1
+EOF
+
+fi
+echo "$ac_t""$ntp_refclock" 1>&6
+
+			
+
+echo $ac_n "checking if we want HP-UX adjtimed support""... $ac_c" 1>&6
+echo "configure:9262: checking if we want HP-UX adjtimed support" >&5
+case "$target" in
+ *-*-hpux[56789]*)
+    ans=yes
+    ;;
+ *) ans=no
+    ;;
+esac
+if test "$ans" = "yes"; then
+    MAKE_ADJTIMED=adjtimed
+    cat >> confdefs.h <<\EOF
+#define NEED_HPUX_ADJTIME 1
+EOF
+
+fi
+echo "$ac_t""$ans" 1>&6
+
+echo $ac_n "checking if we can read kmem""... $ac_c" 1>&6
+echo "configure:9280: checking if we can read kmem" >&5
+if eval "test \"\${ac_cv_var_can_kmem+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-kmem or --disable-kmem was given.
+if test "${enable_kmem+set}" = set; then
+  enableval="$enable_kmem"
+  ans=$enableval
+else
+      case "$ac_cv_func_nlist$ac_cv_func_K_open$ac_cv_func_kvm_open" in
+     *yes*)
+	ans=yes
+	;;
+     *) ans=no
+	;;
+    esac
+    case "$target" in
+     *-*-aix*)
+	#ans=no
+	;;
+     *-*-domainos)	# Won't be found...
+	ans=no
+	;;
+     *-*-hpux*)
+	#ans=no
+	;;
+     *-*-irix[456]*)
+	ans=no
+	;;
+     *-*-linux*)
+	ans=no
+	;;
+     *-*-winnt3.5)
+	ans=no
+	;;
+    esac
+        
+fi
+
+ac_cv_var_can_kmem=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_can_kmem" 1>&6
+
+case "$ac_cv_var_can_kmem" in
+ *yes*) ;;
+ *) cat >> confdefs.h <<\EOF
+#define NOKMEM 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if adjtime is accurate""... $ac_c" 1>&6
+echo "configure:9333: checking if adjtime is accurate" >&5
+if eval "test \"\${ac_cv_var_adjtime_is_accurate+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-accurate-adjtime or --disable-accurate-adjtime was given.
+if test "${enable_accurate_adjtime+set}" = set; then
+  enableval="$enable_accurate_adjtime"
+  ans=$enableval
+else
+      case "$target" in
+      i386-sequent-ptx*)
+	 ans=no
+	 ;;
+      i386-unknown-osf1*)
+	 ans=yes
+	 ;;
+      mips-sgi-irix[456]*)
+	 ans=yes
+	 ;;
+      *-fujitsu-uxp*)
+	 ans=yes
+	 ;;
+      *-ibm-aix4*)
+	 ans=yes
+	 ;;
+      *-*-linux*)
+	 ans=yes
+	 ;;
+      *-*-solaris2.[01]*)
+	 ans=no
+	 ;;
+      *-*-solaris2*)
+         ans=yes
+         ;;
+      *) ans=no
+	 ;;
+     esac
+          
+fi
+
+ac_cv_var_adjtime_is_accurate=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_adjtime_is_accurate" 1>&6
+case "$ac_cv_var_adjtime_is_accurate" in
+ yes) cat >> confdefs.h <<\EOF
+#define ADJTIME_IS_ACCURATE 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking the name of 'tick' in the kernel""... $ac_c" 1>&6
+echo "configure:9385: checking the name of 'tick' in the kernel" >&5
+if eval "test \"\${ac_cv_var_nlist_tick+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=_tick
+case "$target" in
+ m68*-hp-hpux*) # HP9000/300?
+    ans=_old_tick
+    ;;
+ *-apple-aux[23]*)
+    ans=tick
+    ;;
+ *-hp-hpux*)
+    ans=old_tick
+    ;;
+ *-ibm-aix[34]*)
+    ans=no
+    ;;
+ *-*-ptx*)
+    ans=tick
+    ;;
+ *-*-sco3.2v[45]*)
+    ans=no
+    ;;
+ *-*-solaris2*)
+    ans=nsec_per_tick
+    ;;
+ *-*-sysv4*)
+    ans=tick
+    ;;
+esac
+ac_cv_var_nlist_tick=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_nlist_tick" 1>&6
+case "$ac_cv_var_nlist_tick" in
+ ''|no) ;;	# HMS: I think we can only get 'no' here...
+ *) cat >> confdefs.h <&6
+echo "configure:9429: checking for the units of 'tick'" >&5
+if eval "test \"\${ac_cv_var_tick_nano+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=usec
+case "$target" in
+ *-*-solaris2*)
+    ans=nsec
+    ;;
+esac
+ac_cv_var_tick_nano=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_tick_nano" 1>&6
+case "$ac_cv_var_tick_nano" in
+ nsec)
+    cat >> confdefs.h <<\EOF
+#define TICK_NANO 1
+EOF
+
+    ;;
+esac
+#
+echo $ac_n "checking the name of 'tickadj' in the kernel""... $ac_c" 1>&6
+echo "configure:9453: checking the name of 'tickadj' in the kernel" >&5
+if eval "test \"\${ac_cv_var_nlist_tickadj+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=_tickadj
+case "$target" in
+ m68*-hp-hpux*) # HP9000/300?
+    ans=_tickadj
+    ;;
+ *-apple-aux[23]*)
+    ans=tickadj
+    ;;
+ *-hp-hpux10*)
+    ans=no
+    ;;
+ *-hp-hpux9*)
+    ans=no
+    ;;
+ *-hp-hpux*)
+    ans=tickadj
+    ;;
+ *-*-aix*)
+    ans=tickadj
+    ;;
+ *-*-ptx*)
+    ans=tickadj
+    ;;
+ *-*-sco3.2v4*)
+    ans=no
+    ;;
+ *-*-sco3.2v5.0*)
+    ans=clock_drift
+    ;;
+ *-*-solaris2*)
+    ans=no	# hrestime_adj
+    ;;
+ *-*-sysv4*)
+    ans=tickadj
+    ;;
+esac
+ac_cv_var_nlist_tickadj=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_nlist_tickadj" 1>&6
+case "$ac_cv_var_nlist_tickadj" in
+ ''|no) ;;	# HMS: I think we can only get 'no' here...
+ *) cat >> confdefs.h <&6
+echo "configure:9506: checking for the units of 'tickadj'" >&5
+if eval "test \"\${ac_cv_var_tickadj_nano+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ans=usec
+case "$target" in
+ *-*-solaris2*)
+    ans=nsec
+    ;;
+esac
+ac_cv_var_tickadj_nano=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_tickadj_nano" 1>&6
+case "$ac_cv_var_tickadj_nano" in
+ nsec)
+    cat >> confdefs.h <<\EOF
+#define TICKADJ_NANO 1
+EOF
+
+    ;;
+esac
+#
+echo $ac_n "checking half-heartedly for 'dosynctodr' in the kernel""... $ac_c" 1>&6
+echo "configure:9530: checking half-heartedly for 'dosynctodr' in the kernel" >&5
+if eval "test \"\${ac_cv_var_nlist_dosynctodr+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$target" in
+ *-apple-aux[23]*)
+    ans=no
+    ;;
+ *-sni-sysv*)
+    ans=dosynctodr
+    ;;
+ *-*-aix*)
+    ans=dosynctodr
+    ;;
+ *-*-hpux*)
+    ans=no
+    ;;
+ *-*-nextstep*)
+    ans=_dosynctodr
+    ;;
+ *-*-ptx*)
+    ans=doresettodr
+    ;;
+ *-*-sco3.2v4*)
+    ans=no
+    ;;
+ *-*-sco3.2v5*)
+    ans=track_rtc
+    ;;
+ *-*-solaris2*)
+    ans=dosynctodr
+    ;;
+ *-*-sysv4*)
+    ans=doresettodr
+    ;;
+ *)
+    ans=_dosynctodr
+    ;;
+esac
+ac_cv_var_nlist_dosynctodr=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_nlist_dosynctodr" 1>&6
+case "$ac_cv_var_nlist_dosynctodr" in
+ no) ;;
+ *)  cat >> confdefs.h <&6
+echo "configure:9583: checking half-heartedly for 'noprintf' in the kernel" >&5
+if eval "test \"\${ac_cv_var_nlist_noprintf+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$target" in
+ *-apple-aux[23]*)
+    ans=no
+    ;;
+ *-sni-sysv*)
+    ans=noprintf
+    ;;
+ *-*-aix*)
+    ans=noprintf
+    ;;
+ *-*-hpux*)
+    ans=no
+    ;;
+ *-*-ptx*)
+    ans=noprintf
+    ;;
+ *-*-nextstep*)
+    ans=_noprintf
+    ;;
+ *-*-solaris2*)
+    ans=noprintf
+    ;;
+ *-*-sysv4*)
+    ans=noprintf
+    ;;
+ *)
+    ans=_noprintf
+    ;;
+esac
+ac_cv_var_nlist_noprintf=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_nlist_noprintf" 1>&6
+case "$ac_cv_var_nlist_noprintf" in
+ no) ;;
+ *)  cat >> confdefs.h <&6
+echo "configure:9633: checking for a default value for 'tick'" >&5
+if eval "test \"\${ac_cv_var_tick+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-tick or --disable-tick was given.
+if test "${enable_tick+set}" = set; then
+  enableval="$enable_tick"
+  ans=$enableval
+else
+  ans=no
+     case "$target" in
+      XXX-*-pc-cygwin*)
+	 ;;
+      *-univel-sysv*)
+	 ans=10000
+	 ;;
+      *-*-irix*)
+	 ans=10000
+	 ;;
+      *-*-linux*)
+	 ans=txc.tick
+	 ;;
+      *-*-winnt3.5)
+	 ans='(every / 10)'
+	 ;;
+      *)
+	 ans='1000000L/hz'
+	 ;;
+     esac
+fi
+
+ac_cv_var_tick=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_tick" 1>&6
+case "$ac_cv_var_tick" in
+ ''|no) ;;	# HMS: I think we can only get 'no' here...
+ *) cat >> confdefs.h <&6
+echo "configure:9677: checking for a default value for 'tickadj'" >&5
+if eval "test \"\${ac_cv_var_tickadj+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-tickadj or --disable-tickadj was given.
+if test "${enable_tickadj+set}" = set; then
+  enableval="$enable_tickadj"
+  ans=$enableval
+else
+  ans='500/hz'
+  case "$target" in
+   *-fujitsu-uxp*)
+      case "$ac_cv_var_adjtime_is_accurate" in
+       yes) ans='tick/16' ;;
+      esac
+      ;;
+   XXX-*-pc-cygwin*)
+      ans=no
+      ;;
+   *-univel-sysv*)
+      ans=80
+      ;;
+   *-*-aix*)
+      case "$ac_cv_var_can_kmem" in
+       no) ans=1000 ;;
+      esac
+      ;;
+   *-*-domainos)	# Skippy: won't be found...
+      case "$ac_cv_var_can_kmem" in
+       no) ans=668 ;;
+      esac
+      ;;
+   *-*-hpux*)
+      case "$ac_cv_var_adjtime_is_accurate" in
+       yes) ans='tick/16' ;;
+      esac
+      ;;
+   *-*-irix*)
+      ans=150
+      ;;
+   *-*-sco3.2v5.0*)
+      ans=10000L/hz
+      ;;
+   *-*-solaris2*)
+      case "$ac_cv_var_adjtime_is_accurate" in
+       yes)
+          #ans='tick/16'
+	  ;;
+      esac
+      ;;
+   *-*-winnt3.5)
+      ans=50
+      ;;
+  esac
+fi
+
+ac_cv_var_tickadj=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_tickadj" 1>&6
+case "$ac_cv_var_tickadj" in
+ ''|no) ;;	# HMS: I think we can only get 'no' here...
+ *) cat >> confdefs.h <> confdefs.h <<\EOF
+#define RELIANTUNIX_CLOCK 1
+EOF
+ ;;
+esac
+
+case "$target" in
+ *-*-sco3.2v5*) cat >> confdefs.h <<\EOF
+#define SCO5_CLOCK 1
+EOF
+ ;;
+esac
+
+ac_cv_make_tickadj=yes
+case "$ac_cv_var_can_kmem$ac_cv_var_tick$ac_cv_var_tickadj" in
+ nonono)	# Don't read KMEM, no presets.  Bogus.
+    echo "configure: warning: Can't read kmem" 1>&2
+    ac_cv_make_tickadj=no
+    ;;
+ nono*)		# Don't read KMEM, no PRESET_TICK but PRESET_TICKADJ.  Bogus.
+    echo "configure: warning: Can't read kmem but no PRESET_TICK.  No tickadj." 1>&2
+    ac_cv_make_tickadj=no
+    ;;
+ no*no)		# Don't read KMEM, PRESET_TICK but no PRESET_TICKADJ.  Bogus.
+    echo "configure: warning: Can't read kmem but no PRESET_TICKADJ.  No tickadj." 1>&2
+    ac_cv_make_tickadj=no
+    ;;
+ no*)		# Don't read KMEM, PRESET_TICK and PRESET_TICKADJ.  Cool.
+    ;;
+ yesnono)	# Read KMEM, no presets.  Cool.
+    ;;
+ yesno*)	# Read KMEM, no PRESET_TICK but PRESET_TICKADJ.  Bogus.
+    echo "configure: warning: PRESET_TICKADJ is defined but not PRESET_TICK.  Please report this." 1>&2
+    ;;
+ yes*no)	# Read KMEM, PRESET_TICK but no PRESET_TICKADJ.  Cool.
+    ;;
+ yes*)		# READ KMEM, PRESET_TICK and PRESET_TICKADJ.
+    ;;
+ *)		# Generally bogus.
+    { echo "configure: error: This shouldn't happen." 1>&2; exit 1; }
+    ;;
+esac
+
+case "$target" in
+ mips-sni-sysv4*)
+    # tickadj is pretty useless on newer versions of ReliantUNIX
+    # Do not bother
+    ac_cv_make_tickadj=no
+ ;;
+ *-*-solaris2*)
+    # DLM says tickadj is a no-no starting with solaris2.5
+    case "$target" in
+     *-*-solaris2.0-4*) ;;
+     *) ac_cv_make_tickadj=no ;;
+    esac
+ ;;
+esac
+
+
+echo $ac_n "checking if we want and can make the tickadj utility""... $ac_c" 1>&6
+echo "configure:9810: checking if we want and can make the tickadj utility" >&5
+if eval "test \"\${ac_cv_make_tickadj+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_make_tickadj=yes
+fi
+
+echo "$ac_t""$ac_cv_make_tickadj" 1>&6
+case "$ac_cv_make_tickadj" in
+ yes)
+    MAKE_TICKADJ=tickadj
+    ;;
+esac
+
+
+echo $ac_n "checking if we want and can make the ntptime utility""... $ac_c" 1>&6
+echo "configure:9826: checking if we want and can make the ntptime utility" >&5
+if eval "test \"\${ac_cv_make_ntptime+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$target" in
+ *) case "$ac_cv_struct_ntptimeval$ac_cv_var_kernel_pll" in
+     yesyes)
+	ans=yes
+	;;
+     *)
+	ans=no
+	;;
+    esac
+    ;;
+esac
+ac_cv_make_ntptime=$ans
+fi
+
+echo "$ac_t""$ac_cv_make_ntptime" 1>&6
+case "$ac_cv_make_ntptime" in
+ yes)
+    MAKE_NTPTIME=ntptime
+    ;;
+esac
+
+echo $ac_n "checking if we want UDP wildcard delivery""... $ac_c" 1>&6
+echo "configure:9852: checking if we want UDP wildcard delivery" >&5
+if eval "test \"\${ac_cv_var_udp_wildcard_delivery+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-udp-wildcard or --disable-udp-wildcard was given.
+if test "${enable_udp_wildcard+set}" = set; then
+  enableval="$enable_udp_wildcard"
+  ans=$enableval
+else
+  ans=no
+     case "$target" in
+      *-fujitsu-uxp*)
+	 ans=yes
+	 ;;
+      *-univel-sysv*)
+	 ans=yes
+	 ;;
+      *-*-aix3.2*)
+	 ans=yes
+	 ;;
+      *-*-aix4*)
+	 ans=yes
+	 ;;
+      *-*-bsdi*)
+	 ans=yes
+	 ;;
+      *-*-domainos)
+	 ans=yes
+	 ;;
+      *-*-freebsd*)
+	ans=yes
+	;;
+      *-*-hpux*)
+	 ans=yes
+	 ;;
+      *-*-irix6*)
+	 ans=yes
+	 ;;
+      *-*-linux*)
+	 ans=yes
+	 ;;
+      *-*-osf*)
+	 ans=yes
+	 ;;
+      *-*-ptx*)
+	 ans=yes
+	 ;;
+      *-*-solaris2*)
+	 ans=yes
+	 ;;
+      *-*-sunos4*)
+	 ans=yes
+	 ;;
+     esac
+fi
+
+ac_cv_var_udp_wildcard_delivery=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_udp_wildcard_delivery" 1>&6
+case "$ac_cv_var_udp_wildcard_delivery" in
+ yes) cat >> confdefs.h <<\EOF
+#define UDP_WILDCARD_DELIVERY 1
+EOF
+ ;;
+esac
+
+case "$host" in
+ $target)
+    ;;
+ *) case "$target" in
+     *-*-vxworks*)
+        LDFLAGS="$LDFLAGS -r"
+        ;;
+    esac
+    ;;
+esac
+
+echo $ac_n "checking if we should always slew the time""... $ac_c" 1>&6
+echo "configure:9931: checking if we should always slew the time" >&5
+if eval "test \"\${ac_cv_var_slew_always+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-slew-always or --disable-slew-always was given.
+if test "${enable_slew_always+set}" = set; then
+  enableval="$enable_slew_always"
+  ans=$enableval
+else
+      case "$target" in
+      *-apple-aux[23]*)
+	 ans=yes
+	 ;;
+      *-*-bsdi[012]*)
+	 ans=no
+	 ;;
+      *-*-bsdi*)
+	 ans=yes
+	 ;;
+      *-*-openvms*)	# HMS: won't be found
+	 ans=yes
+	 ;;
+      *) ans=no
+	 ;;
+     esac
+          
+fi
+
+ac_cv_var_slew_always=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_slew_always" 1>&6
+case "$ac_cv_var_slew_always" in
+ yes) cat >> confdefs.h <<\EOF
+#define SLEWALWAYS 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if we should step and slew the time""... $ac_c" 1>&6
+echo "configure:9971: checking if we should step and slew the time" >&5
+if eval "test \"\${ac_cv_var_step_slew+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-step-slew or --disable-step-slew was given.
+if test "${enable_step_slew+set}" = set; then
+  enableval="$enable_step_slew"
+  ans=$enableval
+else
+      case "$target" in
+      *-sni-sysv*)
+	 ans=yes
+	 ;;
+      *-univel-sysv*)
+	 ans=no
+	 ;;
+      *-*-ptx*)
+	 ans=yes
+	 ;;
+      *-*-solaris2.[012]*)
+	 ans=yes
+	 ;;
+      *-*-sysv4*)	# HMS: Does this catch Fujitsu UXP?
+	 ans=yes
+	 ;;
+      *) ans=no
+	 ;;
+     esac
+          
+fi
+
+ac_cv_var_step_slew=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_step_slew" 1>&6
+case "$ac_cv_var_step_slew" in
+ yes) cat >> confdefs.h <<\EOF
+#define STEP_SLEW 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if ntpdate should step the time""... $ac_c" 1>&6
+echo "configure:10014: checking if ntpdate should step the time" >&5
+if eval "test \"\${ac_cv_var_ntpdate_step+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-ntpdate-step or --disable-ntpdate-step was given.
+if test "${enable_ntpdate_step+set}" = set; then
+  enableval="$enable_ntpdate_step"
+  ans=$enableval
+else
+      case "$target" in
+      *-apple-aux[23]*)
+	 ans=yes
+	 ;;
+      *) ans=no
+	 ;;
+     esac
+          
+fi
+
+ac_cv_var_ntpdate_step=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_ntpdate_step" 1>&6
+case "$ac_cv_var_ntpdate_step" in
+ yes) cat >> confdefs.h <<\EOF
+#define FORCE_NTPDATE_STEP 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if we should sync TODR clock every hour""... $ac_c" 1>&6
+echo "configure:10045: checking if we should sync TODR clock every hour" >&5
+if eval "test \"\${ac_cv_var_sync_todr+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-hourly-todr-sync or --disable-hourly-todr-sync was given.
+if test "${enable_hourly_todr_sync+set}" = set; then
+  enableval="$enable_hourly_todr_sync"
+  ans=$enableval
+else
+  case "$target" in
+      *-*-nextstep*)
+	 ans=yes
+	 ;;
+      *-*-openvms*)	# HMS: won't be found
+	 ans=yes
+	 ;;
+      *) ans=no
+	 ;;
+     esac
+fi
+
+ac_cv_var_sync_todr=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_sync_todr" 1>&6
+case "$ac_cv_var_sync_todr" in
+ yes) cat >> confdefs.h <<\EOF
+#define DOSYNCTODR 1
+EOF
+ ;;
+esac
+
+echo $ac_n "checking if we should avoid kernel FLL bug""... $ac_c" 1>&6
+echo "configure:10078: checking if we should avoid kernel FLL bug" >&5
+if eval "test \"\${ac_cv_var_kernel_fll_bug+set}\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # Check whether --enable-kernel-fll-bug or --disable-kernel-fll-bug was given.
+if test "${enable_kernel_fll_bug+set}" = set; then
+  enableval="$enable_kernel_fll_bug"
+  ans=$enableval
+else
+      case "$target" in
+     *-*-solaris2.6)
+	 ans=yes
+	 ;;
+     *-*-solaris2.7)
+	 case "`uname -v`" in
+	  Generic_106541-07)
+	     ans=no
+	     ;;
+	  *) ans=yes
+	     ;;
+	 esac
+	 ;;
+     *) ans=no
+	 ;;
+    esac
+        
+fi
+
+ac_cv_var_kernel_fll_bug=$ans
+fi
+
+echo "$ac_t""$ac_cv_var_kernel_fll_bug" 1>&6
+case "$ac_cv_var_kernel_fll_bug" in
+ yes) cat >> confdefs.h <<\EOF
+#define KERNEL_FLL_BUG 1
+EOF
+ ;;
+esac
+
+case "$host" in
+ $target)
+    ;;
+ *) case "$target" in
+     *-*-vxworks*)
+        LDFLAGS="$LDFLAGS -r"
+        ;;
+    esac
+    ;;
+esac
+
+# This is necessary so that .o files in LIBOBJS are also built via
+# the ANSI2KNR-filtering rules.
+LIBOBJS=`echo $LIBOBJS|sed 's/\.o /\$U.o /g;s/\.o$/\$U.o/'`
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS </dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.14.1"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile adjtimed/Makefile clockstuff/Makefile \
+include/Makefile kernel/Makefile kernel/sys/Makefile libntp/Makefile \
+libparse/Makefile librsaref/Makefile ntpd/Makefile ntpdc/Makefile \
+ntpdate/Makefile ntpq/Makefile ntptrace/Makefile parseutil/Makefile \
+scripts/Makefile scripts/mkver scripts/ntpver util/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@AMTAR@%$AMTAR%g
+s%@AMTARFLAGS@%$AMTARFLAGS%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@AWK@%$AWK%g
+s%@LN_S@%$LN_S%g
+s%@RANLIB@%$RANLIB%g
+s%@PATH_SH@%$PATH_SH%g
+s%@U@%$U%g
+s%@ANSI2KNR@%$ANSI2KNR%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@LIBPARSE@%$LIBPARSE%g
+s%@MAKE_LIBPARSE@%$MAKE_LIBPARSE%g
+s%@MAKE_LIBPARSE_KERNEL@%$MAKE_LIBPARSE_KERNEL%g
+s%@MAKE_CHECK_Y2K@%$MAKE_CHECK_Y2K%g
+s%@RSAREF@%$RSAREF%g
+s%@LIBRSAREF@%$LIBRSAREF%g
+s%@MAKE_LIBRSAREF@%$MAKE_LIBRSAREF%g
+s%@TESTDCF@%$TESTDCF%g
+s%@DCFD@%$DCFD%g
+s%@MAKE_PARSEKMODULE@%$MAKE_PARSEKMODULE%g
+s%@PROPDELAY@%$PROPDELAY%g
+s%@CHUTEST@%$CHUTEST%g
+s%@CLKTEST@%$CLKTEST%g
+s%@MAKE_ADJTIMED@%$MAKE_ADJTIMED%g
+s%@MAKE_TICKADJ@%$MAKE_TICKADJ%g
+s%@MAKE_NTPTIME@%$MAKE_NTPTIME%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
+ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_uB='\([ 	]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+chmod +x scripts/ntpver scripts/mkver
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || $SHELL $CONFIG_STATUS || exit 1
+
+#test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h])
diff --git a/contrib/ntp/configure.in b/contrib/ntp/configure.in
new file mode 100644
index 000000000000..2facc50efafd
--- /dev/null
+++ b/contrib/ntp/configure.in
@@ -0,0 +1,2896 @@
+dnl -*-fundamental-*-
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(ntpd/ntp_refclock.c)
+AC_CANONICAL_SYSTEM
+AC_DEFINE_UNQUOTED(STR_SYSTEM, "$target")
+AM_CONFIG_HEADER(config.h)
+AC_ARG_PROGRAM
+AM_INIT_AUTOMAKE(ntp, 4.0.98f)
+AC_PREREQ(2.13)
+
+ac_cv_var_oncore_ok=no
+
+dnl Grab any initial CFLAGS so we can pick better defaults.
+iCFLAGS="$CFLAGS"
+
+dnl  we need to check for cross compile tools for vxWorks here
+AC_PROG_CC
+AC_PROG_CPP
+
+case "$target" in
+ *-pc-cygwin*)
+    CFLAGS="$CFLAGS -DSYS_CYGWIN32"
+    ;;
+ i386-sequent-sysv4)
+    case "$CC" in
+     cc)
+	CFLAGS="$CFLAGS -Wc,+Abi-socket"
+	;;
+    esac
+esac
+
+case "$host" in
+ $target)
+    ;;
+ *) case "$target" in
+     *-*-vxworks*)
+	# Quick and dirty sanity check
+	case "$VX_KERNEL" in
+	 '') AC_MSG_ERROR(Please follow the directions in html/vxworks.html!)
+	    ;;
+	esac
+        CFLAGS="$CFLAGS -DSYS_VXWORKS"
+        ;;
+    esac
+    ;;
+esac
+
+dnl  we need to check for cross compile tools for vxWorks here
+AC_PROG_AWK
+AC_PROG_MAKE_SET
+
+rm -f conftest*
+
+case "$GCC" in
+ yes)
+    CFLAGS="$CFLAGS -Wall"
+    # CFLAGS="$CFLAGS -Wtraditional"
+    CFLAGS="$CFLAGS -Wshadow"
+    # CFLAGS="$CFLAGS -Wwrite-strings"
+    CFLAGS="$CFLAGS -Wconversion"
+    CFLAGS="$CFLAGS -Wpointer-arith"
+    CFLAGS="$CFLAGS -Wcast-qual"
+    # CFLAGS="$CFLAGS -Wcast-align"
+    CFLAGS="$CFLAGS -Wstrict-prototypes"
+
+    AC_CACHE_CHECK(whether ${CC-cc} -pipe works, ac_cv_prog_cc_pipe,
+    [echo 'void f(){}' > conftest.c
+    if test -z "`${CC-cc} -pipe -c conftest.c 2>&1`" -a -s conftest.o; then
+      ac_cv_prog_cc_pipe=yes
+    else
+      ac_cv_prog_cc_pipe=no
+    fi
+    rm -f conftest*
+    ])
+
+    case "$ac_cv_prog_cc_pipe" in
+     yes)
+	CFLAGS="$CFLAGS -pipe"
+	;;
+    esac
+    ;;
+esac
+
+ac_busted_vpath_in_make=no
+
+case "$target" in
+ *-*-irix6.1*)	# 64 bit only
+    ;;
+ *-*-irix6*)	# 6.2 (and later?)
+    ac_busted_vpath_in_make=yes
+    # don't pass -n32 to gcc, it cannot handle and doesn't need it
+    if test "$GCC" != yes; then
+      case "$CFLAGS" in
+       *-n32*) ;;
+       *-n64*) ;;
+       *) case "$iCFLAGS" in
+	   '') CFLAGS="-O2 -g3 -n32" ;;
+	   *)  CFLAGS="$CFLAGS -n32" ;;
+	  esac
+	  ;;
+      esac
+      case "$LDFLAGS" in
+       *-n32*) ;;
+       *-n64*) ;;
+       *) LDFLAGS="$LDFLAGS -n32" ;;
+      esac
+    fi
+    ;;
+ *-next-nextstep3)
+    CFLAGS="$CFLAGS -posix" ;;
+ *-*-solaris2.5.1)
+    ac_busted_vpath_in_make=yes
+    ;;
+dnl This is currently commented out by bor. 
+dnl The new versions of ReliantUNIX round adjtime() interval down
+dnl to 1/100s (system tick). This makes tickadj actually useless.
+dnl So, I'd better not use additional flags.
+dnl I leave it here just in case anybody has better idea
+dnl  mips-sni-sysv4* )
+dnl     #
+dnl     # Add flags for 64 bit file access to enable tickadj to access /dev/kmem
+dnl     #
+dnl     if getconf _LFS_CFLAGS > /dev/null 2>&1 ; then
+dnl       CFLAGS="$CFLAGS `getconf _LFS_CFLAGS`"
+dnl     fi
+dnl     ;;
+esac
+
+case "$ac_busted_vpath_in_make$srcdir" in
+ no*) ;;
+ yes.) ;;
+ *) case "`${MAKE-make} -v -f /dev/null 2>/dev/null | sed -e 's/GNU Make version \(1-9.]*\).*/\1/' -e q`" in
+     '')
+	AC_MSG_ERROR(building outside of the main directory requires GNU make)
+	;;
+     *) ;;
+    esac
+    ;;
+esac
+
+AC_SUBST(CFLAGS)dnl
+AC_SUBST(LDFLAGS)dnl
+
+AC_PROG_LN_S
+AC_PROG_GCC_TRADITIONAL
+AC_AIX
+AC_MINIX
+AC_ISC_POSIX
+AC_PROG_RANLIB
+AC_PATH_PROG(PATH_SH, sh)
+
+case "$target" in
+ *-*-vxworks*)
+    ac_link="$ac_link $VX_KERNEL"
+    ;;
+esac
+
+AC_PROG_INSTALL
+
+case "$target" in
+ *-pc-cygwin*)
+    AC_CHECK_LIB(advapi32, main)
+    ;;
+esac
+AC_CHECK_LIB(elf, nlist)
+dnl AC_CHECK_LIB(kvm, main, , , -lelf)
+AC_CHECK_LIB(kvm, main)		dnl We already know about -lelf here...
+AC_CHECK_LIB(ld, nlist)
+AC_CHECK_LIB(mld, nlist)
+AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent, , , -lsocket))
+AC_CHECK_FUNC(openlog, , AC_CHECK_LIB(gen, openlog))
+
+dnl Digital UNIX V4.0 and Solaris 7 have POSIX.1c functions in -lrt
+dnl Solaris 2.6 only has -lposix4; in Solaris 7, this is a symlink to -lrt,
+dnl so only use one of them
+AC_CHECK_LIB(rt, sched_setscheduler, ,
+	AC_CHECK_LIB(posix4, sched_setscheduler))
+AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt))
+
+AC_HEADER_STDC
+AC_CHECK_HEADERS(bstring.h errno.h fcntl.h memory.h netdb.h poll.h resolv.h)
+AC_CHECK_HEADERS(sched.h sgtty.h stdlib.h string.h termio.h termios.h)
+AC_CHECK_HEADERS(timepps.h timex.h unistd.h utmp.h utmpx.h)
+AC_CHECK_HEADERS(arpa/nameser.h net/if.h netinet/in.h netinet/ip.h)
+AC_CHECK_HEADERS(netinfo/ni.h, [AC_DEFINE(HAVE_NETINFO)])
+AC_CHECK_HEADERS(sun/audioio.h sys/audioio.h)
+dnl AC_CHECK_HEADERS(sys/chudefs.h)
+AC_CHECK_HEADERS(sys/clkdefs.h sys/file.h)
+case "$target" in
+ *-*-sunos4*) ;;
+ *) AC_CHECK_HEADERS(sys/ioctl.h)
+    ;;
+esac
+AC_CHECK_HEADERS(sys/lock.h sys/mman.h sys/modem.h sys/param.h sys/ppsclock.h)
+AC_CHECK_HEADERS(sys/ppstime.h sys/proc.h sys/resource.h sys/sched.h)
+case "$target" in
+ *-*-sco*)
+    AC_CHECK_HEADERS(sys/sio.h)
+    ;;
+ *sgi*)
+    AC_CHECK_HEADERS(sys/syssgi.h)
+    ;;
+ *)
+    AC_CHECK_HEADERS(sys/select.h)
+    ;;
+esac
+AC_CHECK_HEADERS(sys/sockio.h sys/stat.h sys/stream.h sys/stropts.h)
+AC_CHECK_HEADERS(sys/sysctl.h sys/termios.h sys/time.h)
+AC_EGREP_CPP(yes,
+[#include 
+#ifdef PPS_API_VERS_1
+yes
+#endif
+], AC_CHECK_HEADERS(sys/timepps.h))
+AC_CHECK_HEADERS(sys/timers.h sys/timex.h sys/tpro.h sys/types.h sys/wait.h)
+AC_HEADER_TIME
+case "$target" in
+*-convex-*)
+  AC_CHECK_HEADERS(/sys/sync/queue.h /sys/sync/sema.h)
+  ;;
+*-*-bsdi*)
+  AC_CHECK_HEADERS(machine/inline.h sys/pcl720.h sys/i8253.h)
+  ;;
+esac
+
+AC_CHECK_HEADER(nlist.h,
+[AC_DEFINE(NLIST_STRUCT)
+AC_CACHE_CHECK([for n_un in struct nlist], ac_cv_struct_nlist_n_un,
+[AC_TRY_COMPILE([#include ],
+[struct nlist n; n.n_un.n_name = 0;],
+ac_cv_struct_nlist_n_un=yes, ac_cv_struct_nlist_n_un=no)])
+if test $ac_cv_struct_nlist_n_un = yes; then
+  AC_DEFINE(NLIST_NAME_UNION)
+fi
+])dnl
+
+AC_CACHE_CHECK(for basic volatile support, ac_cv_c_volatile,
+[AC_TRY_COMPILE([],[
+volatile int x;],
+	ac_cv_c_volatile=yes,
+	ac_cv_c_volatile=no)
+])
+case "$ac_cv_c_volatile" in
+ yes)
+    ;;
+ *) AC_DEFINE(volatile,)
+    ;;
+esac
+
+case "$target" in
+ sparc-*-solaris2*)
+    # Assume that solaris2 is Ansi C...
+    ;;
+ *)
+    AM_C_PROTOTYPES
+    ;;
+esac
+AC_CACHE_CHECK(if C compiler permits function prototypes, ac_cv_have_prototypes,
+[AC_TRY_COMPILE([
+extern int foo (short);
+int foo(short i) { return i; }],[
+int i;], ac_cv_have_prototypes=yes, ac_cv_have_prototypes=no)
+])
+if test "$ac_cv_have_prototypes" = yes; then
+  AC_DEFINE(HAVE_PROTOTYPES)
+fi
+
+AC_C_CONST
+case "$host" in
+ $target)
+    AC_C_BIGENDIAN
+    ;;
+ *) case "$target" in
+     i*86-*-vxworks*)
+	# LITTLEENDIAN
+	;;
+     *-*-vxworks*)
+	AC_DEFINE(WORDS_BIGENDIAN)
+	;;
+     *) AC_MSG_ERROR(Cross-compiling needs explicit byte order)
+	;;
+    esac
+    ;;
+esac
+AC_TYPE_SIGNAL
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_CHECK_TYPE(time_t, long)
+AC_STRUCT_TM
+
+AC_CACHE_CHECK(for a fallback value for HZ, ac_cv_var_default_hz,
+[ac_cv_var_default_hz=100
+case "$target" in
+ alpha*-dec-osf4*|alpha*-dec-osf5*)
+    ac_cv_var_default_hz=1024
+    ;;
+ mips-dec-ultrix4*)
+    ac_cv_var_default_hz=256
+    ;;
+esac])
+AC_DEFINE_UNQUOTED(DEFAULT_HZ, $ac_cv_var_default_hz)
+
+AC_CACHE_CHECK(if we need to override the system's value for HZ, ac_cv_var_override_hz,
+[ac_cv_var_override_hz=no
+case "$target" in
+ alpha*-dec-osf4*|alpha*-dec-osf5*)
+    ac_cv_var_override_hz=yes
+    ;;
+ mips-dec-ultrix4*)
+    ac_cv_var_override_hz=yes
+    ;;
+ *-*-freebsd*)
+    ac_cv_var_override_hz=yes
+    ;;
+ *-*-sunos4*)
+    ac_cv_var_override_hz=yes
+    ;;
+esac])
+case "$ac_cv_var_override_hz" in
+ yes)
+    AC_DEFINE(OVERRIDE_HZ)
+    ;;
+esac
+
+dnl AC_CACHE_CHECK(ut_host in struct utmp, ac_cv_func_ut_host_in_utmp,
+dnl [AC_TRY_LINK([#include 
+dnl #include ], [struct utmp ut; ut.ut_host;],
+dnl ac_cv_func_ut_host_in_utmp=yes, ac_cv_func_ut_host_in_utmp=no)])
+dnl if test $su_cv_func_ut_host_in_utmp = yes; then
+dnl   AC_DEFINE(HAVE_UT_HOST)
+dnl fi
+
+dnl AC_MSG_CHECKING(if we can get the system boot time)
+dnl AC_CACHE_VAL(su_cv_have_boot_time,
+dnl [AC_EGREP_CPP(yes,
+dnl [#ifdef HAVE_UTMPX_H
+dnl #include 
+dnl #else
+dnl #include 
+dnl #endif
+dnl #ifdef BOOT_TIME
+dnl yes
+dnl #endif
+dnl ], su_cv_have_boot_time=yes, su_cv_have_boot_time=no)])
+dnl AC_MSG_RESULT($su_cv_have_boot_time)
+
+AC_CACHE_CHECK(
+  struct sigaction for sa_sigaction,
+  ac_cv_struct_sigaction_has_sa_sigaction,
+  [
+    AC_TRY_COMPILE(
+      [#include ],
+      [struct sigaction act; act.sa_sigaction = 0;],
+      ac_cv_struct_sigaction_has_sa_sigaction=yes,
+      ac_cv_struct_sigaction_has_sa_sigaction=no
+    )
+  ]
+)
+if test $ac_cv_struct_sigaction_has_sa_sigaction = yes; then
+  AC_DEFINE(HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION)
+fi
+
+AC_CACHE_CHECK(for struct ppsclockev, ac_cv_struct_ppsclockev,
+[AC_TRY_COMPILE([
+#include 
+#ifdef HAVE_SYS_TERMIOS_H
+# include 
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include 
+#endif
+#ifdef HAVE_SYS_PPSCLOCK_H
+# include 
+#endif],[
+extern struct ppsclockev *pce;
+return pce->serial;],
+	ac_cv_struct_ppsclockev=yes,
+	ac_cv_struct_ppsclockev=no)
+])
+if test $ac_cv_struct_ppsclockev = yes; then
+    AC_DEFINE(HAVE_STRUCT_PPSCLOCKEV)
+fi
+
+AC_CACHE_CHECK(struct sockaddr for sa_len, ac_cv_struct_sockaddr_has_sa_len,
+[AC_TRY_COMPILE([
+#include 
+#include ],[
+extern struct sockaddr *ps;
+return ps->sa_len;],
+	ac_cv_struct_sockaddr_has_sa_len=yes,
+	ac_cv_struct_sockaddr_has_sa_len=no)
+])
+if test $ac_cv_struct_sockaddr_has_sa_len = yes; then
+    AC_DEFINE(HAVE_SA_LEN_IN_STRUCT_SOCKADDR)
+fi
+
+AC_CACHE_CHECK(struct clockinfo for hz, ac_cv_struct_clockinfo_has_hz,
+[AC_TRY_COMPILE([
+#include ],[
+extern struct clockinfo *pc;
+return pc->hz;],
+	ac_cv_struct_clockinfo_has_hz=yes,
+	ac_cv_struct_clockinfo_has_hz=no)
+])
+if test $ac_cv_struct_clockinfo_has_hz = yes; then
+    AC_DEFINE(HAVE_HZ_IN_STRUCT_CLOCKINFO)
+fi
+
+AC_CACHE_CHECK(struct clockinfo for tickadj, ac_cv_struct_clockinfo_has_tickadj,
+[AC_TRY_COMPILE([
+#include ],[
+extern struct clockinfo *pc;
+return pc->tickadj;],
+	ac_cv_struct_clockinfo_has_tickadj=yes,
+	ac_cv_struct_clockinfo_has_tickadj=no)
+])
+if test $ac_cv_struct_clockinfo_has_tickadj = yes; then
+    AC_DEFINE(HAVE_TICKADJ_IN_STRUCT_CLOCKINFO)
+fi
+
+AC_CACHE_CHECK([for struct ntptimeval], ac_cv_struct_ntptimeval,
+[AC_TRY_COMPILE([
+#include 
+#include ],
+[struct ntptimeval n;],
+ac_cv_struct_ntptimeval=yes, ac_cv_struct_ntptimeval=no)])
+if test $ac_cv_struct_ntptimeval = yes; then
+  AC_DEFINE(HAVE_STRUCT_NTPTIMEVAL, 1, [Do we have struct ntptimeval?])
+fi
+
+AC_CACHE_CHECK(struct ntptimeval for time.tv_nsec, ac_cv_struct_ntptimeval_tv_nsec,
+[AC_TRY_COMPILE([
+#ifdef HAVE_SYS_TIME_H
+#include 
+#else
+# ifdef HAVE_TIME_H
+# include 
+# endif
+#endif
+#ifdef HAVE_SYS_TIMEX_H
+#include 
+#else
+# ifdef HAVE_TIMEX_H
+# include 
+# endif
+#endif],[
+extern struct ntptimeval *ntv;
+return ntv->time.tv_nsec;],
+	ac_cv_struct_ntptimeval_tv_nsec=yes,
+	ac_cv_struct_ntptimeval_tv_nsec=no)
+])
+if test "$ac_cv_struct_ntptimeval_tv_nsec" = "yes"; then
+	AC_DEFINE(HAVE_TV_NSEC_IN_NTPTIMEVAL)
+fi
+
+AC_CACHE_CHECK([for struct timespec in struct ntptimeval], ac_cv_struct_ntptimeval_timespec,
+[AC_TRY_COMPILE([#include 
+#include ],
+[struct ntptimeval n; n.time.tv_nsec = 0;],
+ac_cv_struct_ntptimeval_timespec=yes, ac_cv_struct_ntptimeval_timespec=no)])
+if test $ac_cv_struct_ntptimeval_timespec = yes; then
+  AC_DEFINE(TIMESPEC_IN_NTPTIMEVAL, 1, [Does ntptimeval use struct timespec?])
+fi
+
+AC_C_INLINE
+AC_C_CHAR_UNSIGNED		dnl CROSS_COMPILE?
+case "$host" in
+ $target)
+    AC_CHECK_SIZEOF(signed char)
+    ;;
+ *) case "$target" in
+     *-*-vxworks*)
+	AC_CHECK_SIZEOF(signed char, 1)
+	;;
+     *) AC_MSG_ERROR(Cross-compiling needs explicit SIZEOF_SIGNED_LONG)
+        ;;
+    esac
+    ;;
+esac
+
+case "$host" in
+ $target)
+    AC_CHECK_SIZEOF(int)
+    ;;
+ *) case "$target" in
+     *-*-vxworks*)
+	AC_CHECK_SIZEOF(int, 4)
+        ;;
+     *) AC_MSG_ERROR(Cross-compiling needs explicit SIZEOF_INT)
+	;;
+    esac
+    ;;
+esac
+
+case "$host" in
+ $target)
+    AC_CHECK_SIZEOF(long)
+    ;;
+ *) case "$target" in
+     *-*-vxworks*)
+	AC_CHECK_SIZEOF(long, 4)
+        ;;
+     *) AC_MSG_ERROR(Cross-compiling needs explicit SIZEOF_LONG)
+	;;
+    esac
+    ;;
+esac
+
+AC_CHECK_TYPE(s_char, signed char)
+case "$ac_cv_c_char_unsigned$ac_cv_sizeof_signed_char$ac_cv_type_s_char" in
+ *yes)
+    # We have a typedef for s_char.  Might as well believe it...
+    ;;
+ no0no)
+    # We have signed chars, can't say 'signed char', no s_char typedef.
+    AC_DEFINE(NEED_S_CHAR_TYPEDEF)
+    ;;
+ no1no)
+    # We have signed chars, can say 'signed char', no s_char typedef.
+    AC_DEFINE(NEED_S_CHAR_TYPEDEF)
+    ;;
+ yes0no)
+    # We have unsigned chars, can't say 'signed char', no s_char typedef.
+    AC_MSG_ERROR(No way to specify a signed character!)
+    ;;
+ yes1no)
+    # We have unsigned chars, can say 'signed char', no s_char typedef.
+    AC_DEFINE(NEED_S_CHAR_TYPEDEF)
+    ;;
+esac
+AC_TYPE_UID_T
+
+case "$target" in
+ *-*-linux*)
+    AC_CHECK_FUNCS(__adjtimex __ntp_gettime)
+    ;;
+esac
+case "$target" in
+ *-*-aix4*)
+	# (prr) aix 4.1 doesn't have clock_settime, but in aix 4.3 it's a stub
+	# (returning ENOSYS).  I didn't check 4.2.  If, in the future,
+	# IBM pulls its thumbs out long enough to implement clock_settime,
+	# this conditional will need to change.  Maybe use AC_TRY_RUN
+	# instead to try to set the time to itself and check errno.
+    ;;
+ *) AC_CHECK_FUNCS(clock_settime)
+    ;;
+esac
+AC_CHECK_FUNCS(daemon getbootfile getdtablesize getrusage)
+AC_CHECK_FUNCS(gettimeofday)
+case "$target" in
+ *-pc-cygwin*)
+    ;;
+ *) AC_CHECK_FUNCS(getuid)
+    ;;
+esac
+AC_CHECK_FUNCS(K_open kvm_open memcpy memmove memset)
+case "$target" in
+ *-*-sco3.2v5.0.*)
+    # Just stubs.  Idiots.
+    ;;
+ *) AC_CHECK_FUNCS(mkstemp)
+    ;;
+esac
+AC_REPLACE_FUNCS(mktime)
+case "$target" in
+ *-*-aix4*)
+    # Just a stub.  Idiots.
+    ;;
+ *-*-irix*)
+    # Just stubs in Irix.  Idiots.
+    ;;
+ *-*-sco3.2v5.0.*)
+    # Just stubs.  Idiots.
+    ;;
+ alpha*-dec-osf4*|alpha*-dec-osf5*)
+    # mlockall is there, as a #define calling memlk via 
+    # Not easy to test for - cheat.
+    AC_CHECK_FUNCS(memlk, [ac_cv_func_mlockall='yes'])
+    AC_CHECK_FUNCS(mlockall)
+    ;;
+ *) AC_CHECK_FUNCS(mlockall)
+    ;;
+esac
+AC_CHECK_FUNCS(nice nlist)
+case "$target" in
+ *-*-solaris2.6)
+    # Broken...
+    ;;
+ *) AC_CHECK_FUNCS(ntp_adjtime ntp_gettime)
+    ;;
+esac
+AC_CHECK_FUNCS(plock pututline pututxline rtprio)
+AC_CHECK_FUNCS(random srandom mrand48 srand48)
+case "$target" in
+ *-*-aix4*)
+    # Just a stub in AIX 4.  Idiots.
+    ;;
+ *-*-solaris2.5*)
+    # Just stubs in solaris2.5.  Idiots.
+    ;;
+ *) AC_CHECK_FUNCS(sched_setscheduler)
+    ;;
+esac
+AC_CHECK_FUNCS(setlinebuf)
+AC_CHECK_FUNCS(setpgid setpriority setsid settimeofday setvbuf sigaction)
+AC_CHECK_FUNCS(sigvec sigset sigsuspend stime strchr sysconf sysctl)
+AC_REPLACE_FUNCS(strerror)
+case "$target" in
+ *-*-aix4*)
+    # Just stubs.  Idiots.
+    ;;
+ *-*-netbsd*)
+    # Just stubs.  Idiots.
+    ;;
+ *-*-openbsd*)
+    # Just stubs.  Idiots.
+    ;;
+ *) AC_CHECK_FUNCS(timer_create timer_settime)
+    ;;
+esac
+case "$target" in
+ *-pc-cygwin*)
+    # I have no idea...
+    ;;
+ *) AC_CHECK_FUNCS(umask)
+    ;;
+esac
+AC_CHECK_FUNCS(uname updwtmp updwtmpx vsprintf)
+
+AC_CACHE_CHECK(number of arguments to gettimeofday(), ac_cv_func_Xettimeofday_nargs,
+[AC_TRY_COMPILE([#include ],[
+gettimeofday((struct timeval*)0,(struct timezone*)0);
+settimeofday((struct timeval*)0,(struct timezone*)0);
+],
+	ac_cv_func_Xettimeofday_nargs=2, ac_cv_func_Xettimeofday_nargs=1)
+])
+if test $ac_cv_func_Xettimeofday_nargs = 1; then
+	AC_DEFINE(SYSV_TIMEOFDAY)
+fi
+
+AC_CACHE_CHECK(number of arguments taken by setpgrp(), ac_cv_func_setpgrp_nargs,
+[AC_TRY_COMPILE([
+#ifdef HAVE_SYS_TYPES_H
+# include 
+#endif
+#ifdef HAVE_UNISTD_H
+# include 
+#endif
+],[setpgrp(0,0);],
+        ac_cv_func_setpgrp_nargs=2, ac_cv_func_setpgrp_nargs=0)
+])
+if test $ac_cv_func_setpgrp_nargs = 0; then
+        AC_DEFINE(HAVE_SETPGRP_0)
+fi
+
+save_CFLAGS=$CFLAGS
+CFLAGS="$CFLAGS -I$srcdir/include"
+
+AC_CACHE_CHECK(argument pointer type of qsort()'s compare function and base,
+ac_cv_func_qsort_argtype,
+[AC_TRY_COMPILE([
+#include "l_stdlib.h"
+
+#ifdef HAVE_PROTOTYPES
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+
+extern void *base;
+extern sortfunc P((const void *, const void *));
+int sortfunc(a, b)
+  const void *a;
+  const void *b; { return 0; }
+],[
+qsort(base, 2, sizeof(char *), sortfunc);
+],
+	ac_cv_func_qsort_argtype=void, ac_cv_func_qsort_argtype=char)
+])
+case "$ac_cv_func_qsort_argtype" in
+ void)
+    AC_DEFINE(QSORT_USES_VOID_P)
+    ;;
+esac
+
+CFLAGS=$save_CFLAGS
+
+AC_CACHE_CHECK(if we need to declare 'errno', ac_cv_decl_errno,
+[AC_TRY_COMPILE([#ifdef HAVE_ERRNO_H
+#include 
+#endif],
+  [errno = 0;],
+  ac_cv_decl_errno=no, ac_cv_decl_errno=yes)])
+case "$ac_cv_decl_errno" in
+ yes) AC_DEFINE(DECL_ERRNO) ;;
+esac
+
+dnl FIXME: from ntpd/ntp_intres.c, but there's no info which header produces
+dnl the clash.   isn't currently used.
+dnl
+dnl (prr) aix 4.3 defines h_errno as (*(int *)h_errno_which()) for
+dnl MT purposes.  This makes the line "extern int h_errno" choke
+dnl the compiler.  Hopefully adding !defined(h_errno) fixes this
+dnl without breaking any other platforms.
+dnl
+AC_CACHE_CHECK(if we may declare 'h_errno', ac_cv_decl_h_errno,
+[AC_TRY_COMPILE([#include 
+#ifdef HAVE_NETINET_IN_H
+#include 
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#include 
+#endif
+#ifdef HAVE_NETDB_H
+#include 
+#endif
+#ifdef HAVE_RESOLV_H
+#include 
+#endif],
+  [extern int h_errno;],
+  ac_cv_decl_h_errno=yes, ac_cv_decl_h_errno=no)])
+case "$ac_cv_decl_h_errno" in
+ yes) AC_DEFINE(DECL_H_ERRNO) ;;
+esac
+
+dnl See if char *sys_errlist[] is OK.
+dnl If you get the quoting right on the next line, you tried something I didn't.
+AC_CACHE_CHECK(if declaring 'char *sys_errlist[]' is ok, ac_cv_decl_sys_errlist,
+[AC_TRY_COMPILE([#include 
+#ifdef HAVE_ERRNO_H
+#include 
+#endif],
+  changequote(<<, >>)dnl
+  <>
+  changequote([, ]),
+  ac_cv_decl_sys_errlist=yes, ac_cv_decl_sys_errlist=no)])
+case "$ac_cv_decl_sys_errlist" in
+ yes) AC_DEFINE(CHAR_SYS_ERRLIST) ;;
+esac
+
+AC_CACHE_CHECK(if declaring 'syscall()' is ok, ac_cv_decl_syscall,
+[AC_TRY_COMPILE([
+#ifdef HAVE_SYS_TYPES_H
+# include 
+#endif
+#ifdef HAVE_UNISTD_H
+# include 
+#endif
+#ifdef HAVE_PROTOTYPES
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+],
+  [extern int syscall P((int, ...));],
+  ac_cv_decl_syscall=yes, ac_cv_decl_syscall=no)])
+case "$ac_cv_decl_syscall" in
+ yes) AC_DEFINE(DECL_SYSCALL) ;;
+esac
+
+case "$target" in
+ *-*-osf[45]*)
+    AC_DEFINE(DECL_PLOCK_0)
+    AC_DEFINE(DECL_STIME_0)
+    ;;
+ *-*-riscos4*)
+    AC_DEFINE(DECL_ADJTIME_0)
+    AC_DEFINE(DECL_BZERO_0)
+    AC_DEFINE(DECL_IOCTL_0)
+    AC_DEFINE(DECL_IPC_0)
+    AC_DEFINE(DECL_MEMMOVE_0)
+    AC_DEFINE(DECL_MKTEMP_0)
+    AC_DEFINE(DECL_RENAME_0)
+    AC_DEFINE(DECL_SELECT_0)
+    AC_DEFINE(DECL_SETITIMER_0)
+    AC_DEFINE(DECL_SETPRIORITY_0)
+    AC_DEFINE(DECL_STDIO_0)
+    AC_DEFINE(DECL_STRTOL_0)
+    AC_DEFINE(DECL_SYSLOG_0)
+    AC_DEFINE(DECL_TIME_0)
+    AC_DEFINE(DECL_TIMEOFDAY_0)
+    AC_DEFINE(DECL_TOLOWER_0)
+    ;;
+ *-*-solaris2*)
+    AC_DEFINE(DECL_MKSTEMP_0)
+    AC_DEFINE(DECL_SETPRIORITY_1)
+    case "$target" in
+     *-*-solaris2.4)
+        AC_DEFINE(DECL_TIMEOFDAY_0)
+	;;
+    esac
+    ;;
+ *-*-sunos4*)
+    AC_DEFINE(DECL_ADJTIME_0)
+    AC_DEFINE(DECL_BCOPY_0)
+    AC_DEFINE(DECL_BZERO_0)
+    AC_DEFINE(DECL_IOCTL_0)
+    AC_DEFINE(DECL_IPC_0)
+    AC_DEFINE(DECL_MEMMOVE_0)
+    AC_DEFINE(DECL_MKTEMP_0)
+    AC_DEFINE(DECL_MKSTEMP_0)
+    AC_DEFINE(DECL_MRAND48_0)
+    AC_DEFINE(DECL_RENAME_0)
+    AC_DEFINE(DECL_SELECT_0)
+    AC_DEFINE(DECL_SETITIMER_0)
+    AC_DEFINE(DECL_SETPRIORITY_0)
+    AC_DEFINE(DECL_SIGVEC_0)
+    AC_DEFINE(DECL_SRAND48_0)
+    case "`basename $ac_cv_prog_CC`" in
+     acc*) ;;
+     *) AC_DEFINE(DECL_STDIO_0)
+	;;
+    esac
+    AC_DEFINE(DECL_STRTOL_0)
+    AC_DEFINE(DECL_SYSLOG_0)
+    AC_DEFINE(DECL_TIME_0)
+    AC_DEFINE(DECL_TIMEOFDAY_0)
+    AC_DEFINE(DECL_TOLOWER_0)
+    AC_DEFINE(DECL_TOUPPER_0)
+    ;;
+ *-*-ultrix4*)
+    AC_DEFINE(DECL_ADJTIME_0)
+    AC_DEFINE(DECL_BZERO_0)
+    AC_DEFINE(DECL_CFSETISPEED_0)
+    AC_DEFINE(DECL_IOCTL_0)
+    AC_DEFINE(DECL_IPC_0)
+    AC_DEFINE(DECL_MKTEMP_0)
+    AC_DEFINE(DECL_MRAND48_0)
+    AC_DEFINE(DECL_NLIST_0)
+    AC_DEFINE(DECL_PLOCK_0)
+    AC_DEFINE(DECL_SELECT_0)
+    AC_DEFINE(DECL_SETITIMER_0)
+    AC_DEFINE(DECL_SETPRIORITY_0)
+    AC_DEFINE(DECL_SRAND48_0)
+    AC_DEFINE(DECL_STIME_0)
+    AC_DEFINE(DECL_SYSLOG_0)
+    AC_DEFINE(DECL_TIMEOFDAY_0)
+    ;;
+esac
+
+case "$target" in
+ *-*-sco3.2*)
+    AC_DEFINE(TERMIOS_NEEDS__SVID3)
+    ;;
+esac
+
+AC_CACHE_CHECK(if we should use a streams device for ifconfig,
+ ac_cv_var_use_streams_device_for_ifconfig,
+ ac_cv_var_use_streams_device_for_ifconfig=no)
+
+AC_CACHE_CHECK(if we need extra room for SO_RCVBUF, ac_cv_var_rcvbuf_slop,
+[ans=no
+changequote(<<, >>)dnl
+case "$target" in
+ *-*-hpux[567]*)
+    ans=yes
+    ;;
+esac
+changequote([, ])dnl
+ac_cv_var_rcvbuf_slop=$ans])
+case "$ac_cv_var_rcvbuf_slop" in
+ yes) AC_DEFINE(NEED_RCVBUF_SLOP) ;;
+esac
+
+AC_CACHE_CHECK(if we will open the broadcast socket, ac_cv_var_open_bcast_socket,
+[ans=yes
+case "$target" in
+ *-*-domainos)
+    ans=no
+    ;;
+ *-*-linux*)
+    ans=no
+    ;;
+esac
+ac_cv_var_open_bcast_socket=$ans])
+case "$ac_cv_var_open_bcast_socket" in
+ yes) AC_DEFINE(OPEN_BCAST_SOCKET) ;;
+esac
+
+AC_CACHE_CHECK(if we want the HPUX version of FindConfig(), ac_cv_var_hpux_findconfig,
+[ans=no
+case "$target" in
+ *-*-hpux*)
+    ans=yes
+    ;;
+esac
+ac_cv_var_hpux_findconfig=$ans])
+case "$ac_cv_var_hpux_findconfig" in
+ yes) AC_DEFINE(NEED_HPUX_FINDCONFIG) ;;
+esac
+
+AC_CACHE_CHECK(if process groups are set with -pid, ac_cv_arg_setpgrp_negpid,
+[changequote(<<, >>)dnl
+case "$target" in
+ *-*-hpux[567]*)
+    ans=no
+    ;;
+ *-*-hpux*)
+    ans=yes
+    ;;
+ *-*-linux*)
+    ans=yes
+    ;;
+ *-*-sunos3*)
+    ans=yes
+    ;;
+ *-*-ultrix2*)
+    ans=yes
+    ;;
+ *)
+    ans=no
+    ;;
+esac
+changequote([, ])dnl
+ac_cv_arg_setpgrp_negpid=$ans])
+case "$ac_cv_arg_setpgrp_negpid" in
+ yes) AC_DEFINE(UDP_BACKWARDS_SETOWN) ;;
+esac
+
+AC_CACHE_CHECK(if we need a ctty for F_SETOWN, ac_cv_func_ctty_for_f_setown,
+[case "$target" in
+ *-*-bsdi2*)
+    ans=yes
+    ;;
+ *-*-freebsd*)
+    ans=yes
+    ;;
+ *-*-netbsd*)
+    ans=yes
+    ;;
+ *-*-osf*)
+    ans=yes
+    ;;
+ *) ans=no
+    ;;
+esac
+ac_cv_func_ctty_for_f_setown=$ans])
+case "$ac_cv_func_ctty_for_f_setown" in
+ yes) AC_DEFINE(USE_FSETOWNCTTY) ;;
+esac
+
+ntp_warning='GRONK'
+AC_MSG_CHECKING(if we'll use clock_settime or settimeofday or stime)
+case "$ac_cv_func_clock_settime$ac_cv_func_settimeofday$ac_cv_func_stime" in
+ yes*)
+    ntp_warning=''
+    ans='clock_settime()'
+    ;;
+ noyes*)
+    ntp_warning='But clock_settime() would be better (if we had it)'
+    ans='settimeofday()'
+    ;;
+ nonoyes)
+    ntp_warning='Which is the worst of the three'
+    ans='stime()'
+    ;;
+ *) 
+    case "$host" in
+     $target) ntp_warning='Which leaves us with nothing to use!'
+    ans=none
+    ;;
+esac
+esac
+AC_MSG_RESULT($ans)
+case "$ntp_warning" in
+ '') ;;
+ *) AC_MSG_WARN(*** $ntp_warning ***)
+    ;;
+esac
+
+AC_CACHE_CHECK(if we have a losing syscall(), ac_cv_var_syscall_bug,
+[case "$target" in
+ *-*-solaris2.4*)
+    ans=yes
+    ;;
+ *) ans=no
+    ;;
+esac
+ac_cv_var_syscall_bug=$ans])
+case "$ac_cv_var_syscall_bug" in
+ yes) AC_DEFINE(SYSCALL_BUG) ;;
+esac
+
+AC_CACHE_CHECK(for Streams/TLI, ac_cv_var_streams_tli,
+[ case "$ac_cv_header_sys_stropts_h" in
+  yes)
+     ans=no
+     # There must be a better way...
+     case "$target" in
+      *-*-ptx*)
+         ans=yes
+         ;;
+     esac
+     ;;
+ esac
+ ac_cv_var_streams_tli=$ans])
+case "$ac_cv_var_streams_tli" in
+ yes)
+    AC_DEFINE(STREAMS_TLI)
+    ;;
+esac
+
+AC_CACHE_CHECK(for SIGIO, ac_cv_hdr_def_sigio,
+ AC_EGREP_CPP(yes,
+  [#include 
+#ifdef SIGIO
+   yes
+#endif
+  ], ac_cv_hdr_def_sigio=yes, ac_cv_hdr_def_sigio=no))
+
+dnl Override those system that have a losing SIGIO
+AC_CACHE_CHECK(if we want to use signalled IO, ac_cv_var_signalled_io,
+[ans=no
+case "$ac_cv_hdr_def_sigio" in
+ yes)
+    ans=yes
+    case "$target" in
+     alpha*-dec-osf4*|alpha*-dec-osf5*)
+        ans=no
+        ;;
+     *-convex-*)
+        ans=no
+        ;;
+     *-dec-*)
+        ans=no
+        ;;
+     *-pc-cygwin*)
+	ans=no
+	;;
+     *-sni-sysv*)
+        ans=no
+        ;;
+     *-univel-sysv*)
+        ans=no
+	;;
+     *-*-irix6*)
+	ans=no
+	;;
+     *-*-freebsd*)
+	ans=no
+	;;
+     *-*-linux*)
+	ans=no
+	;;
+    esac
+    ;;
+esac
+ac_cv_var_signalled_io=$ans])
+case "$ac_cv_var_signalled_io" in
+ yes) AC_DEFINE(HAVE_SIGNALED_IO) ;;
+esac
+
+AC_CACHE_CHECK(for SIGPOLL, ac_cv_hdr_def_sigpoll,
+ AC_EGREP_CPP(yes,
+ [#include 
+#ifdef SIGPOLL
+  yes
+#endif
+ ], ac_cv_hdr_def_sigpoll=yes, ac_cv_hdr_def_sigpoll=no))
+
+AC_CACHE_CHECK(for SIGSYS, ac_cv_hdr_def_sigsys,
+ AC_EGREP_CPP(yes,
+ [#include 
+#ifdef SIGSYS
+  yes
+#endif
+ ], ac_cv_hdr_def_sigsys=yes, ac_cv_hdr_def_sigsys=no))
+
+AC_CACHE_CHECK(if we can use SIGPOLL for UDP I/O, ac_cv_var_use_udp_sigpoll,
+[ans=no
+case "$ac_cv_hdr_def_sigpoll" in
+ yes)
+    changequote(<<, >>)dnl
+    case "$target" in
+     mips-sgi-irix*)
+	ans=no
+	;;
+     vax-dec-bsd)
+        ans=no
+        ;;
+     *-pc-cygwin*)
+	ans=no
+	;;
+     *-sni-sysv*)
+        ans=no
+        ;;
+     *-*-aix4*)
+        ans=no
+        ;;
+     *-*-hpux*)
+        ans=no
+        ;;
+     *-*-linux*)
+	ans=no
+	;;
+     *-*-osf*)
+        ans=no
+        ;;
+     *-*-sunos*)
+	ans=no
+	;;
+     *-*-ultrix*)
+        ans=no
+        ;;
+     *) ans=yes
+        ;;
+    esac
+    changequote([, ])dnl
+    ;;
+esac
+ac_cv_var_use_udp_sigpoll=$ans])
+case "$ac_cv_var_use_udp_sigpoll" in
+ yes) AC_DEFINE(USE_UDP_SIGPOLL) ;;
+esac
+
+AC_CACHE_CHECK(if we can use SIGPOLL for TTY I/O, ac_cv_var_use_tty_sigpoll,
+[ans=no
+case "$ac_cv_hdr_def_sigpoll" in
+ yes)
+    case "$target" in
+     mips-sgi-irix*)
+        ans=no
+        ;;
+     vax-dec-bsd)
+        ans=no
+        ;;
+     *-pc-cygwin*)
+	ans=no
+	;;
+     *-sni-sysv*)
+        ans=no
+        ;;
+     *-*-aix4*)
+	ans=no
+	;;
+     *-*-hpux*)
+        ans=no
+        ;;
+     *-*-linux*)
+	ans=no
+	;;
+     *-*-osf*)
+        ans=no
+        ;;
+     *-*-sunos*)
+	ans=no
+	;;
+     *-*-ultrix*)
+        ans=no
+        ;;
+     *) ans=yes
+        ;;
+    esac
+    ;;
+esac
+ac_cv_var_use_tty_sigpoll=$ans])
+case "$ac_cv_var_use_tty_sigpoll" in
+ yes) AC_DEFINE(USE_TTY_SIGPOLL) ;;
+esac
+
+case "$ac_cv_header_sys_sio_h" in
+ yes)
+    AC_CACHE_CHECK(sys/sio.h for TIOCDCDTIMESTAMP, ac_cv_hdr_def_tiocdcdtimestamp,
+     AC_EGREP_CPP(yes,
+[#include 
+#ifdef TIOCDCDTIMESTAMP
+  yes
+#endif
+     ], ac_cv_hdr_def_tiocdcdtimestamp=yes, ac_cv_hdr_def_tiocdcdtimestamp=no))
+    ;;
+esac
+
+AC_CACHE_CHECK(if nlist() values might require extra indirection,
+ac_cv_var_nlist_extra_indirection,
+[ans=no
+case "$target" in
+ *-*-aix*)
+    ans=yes
+    ;;
+esac
+ac_cv_var_nlist_extra_indirection=$ans])
+case "$ac_cv_var_nlist_extra_indirection" in
+ yes) AC_DEFINE(NLIST_EXTRA_INDIRECTION) ;;
+esac
+
+AC_CACHE_CHECK(for a minimum recommended value of tickadj,
+ac_cv_var_min_rec_tickadj,
+[ans=no
+case "$target" in
+ *-*-aix*)
+    ans=40
+    ;;
+esac
+ac_cv_var_min_rec_tickadj=$ans])
+case "$ac_cv_var_min_rec_tickadj" in
+ ''|no) ;;
+ *) AC_DEFINE_UNQUOTED(MIN_REC_TICKADJ, $ac_cv_var_min_rec_tickadj) ;;
+esac
+
+AC_CACHE_CHECK(if the TTY code permits PARENB and IGNPAR,
+ac_cv_var_no_parenb_ignpar,
+[ans=no
+case "$target" in
+ i?86-*-linux*)
+    ans=yes
+    ;;
+ mips-sgi-irix*)
+    ans=yes
+    ;;
+esac
+ac_cv_var_no_parenb_ignpar=$ans])
+case "$ac_cv_var_no_parenb_ignpar" in
+ yes) AC_DEFINE(NO_PARENB_IGNPAR) ;;
+esac
+
+AC_MSG_CHECKING(if we're including debugging code)
+AC_ARG_ENABLE(debugging,	[  --enable-debugging      + include debugging code],
+    [ntp_ok=$enableval], [ntp_ok=yes])
+if test "$ntp_ok" = "yes"; then
+    AC_DEFINE(DEBUG)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(for a the number of minutes in a DST adjustment)
+AC_ARG_ENABLE(dst_minutes,	[  --enable-dst-minutes=60 + minutes per DST adjustment],
+    [ans=$enableval], [ans=60])
+AC_DEFINE_UNQUOTED(DSTMINUTES, $ans)
+AC_MSG_RESULT($ans)
+
+AC_CACHE_CHECK(if we have the tty_clk line discipline/streams module,
+ ac_cv_var_tty_clk,
+ [case "$ac_cv_header_sys_clkdefs_h$ac_cv_hdr_def_tiocdcdtimestamp" in
+  *yes*) ac_cv_var_tty_clk=yes ;;
+ esac])
+case "$ac_cv_var_tty_clk" in
+ yes) AC_DEFINE(TTYCLK) ;;
+esac
+
+AC_CACHE_CHECK(for the ppsclock streams module,
+ ac_cv_var_ppsclock,
+ ac_cv_var_ppsclock=$ac_cv_struct_ppsclockev)
+case "$ac_cv_var_ppsclock" in
+ yes) AC_DEFINE(PPS) ;;
+esac
+
+AC_CACHE_CHECK(for kernel multicast support, ac_cv_var_mcast,
+  [ac_cv_var_mcast=no
+  case "$target" in
+   i386-sequent-sysv4) ;;
+   *) AC_EGREP_CPP(yes,
+  [#include 
+#ifdef IP_ADD_MEMBERSHIP
+   yes
+#endif
+  ], ac_cv_var_mcast=yes) ;;
+  esac])
+case "$ac_cv_var_mcast" in
+ yes) AC_DEFINE(MCAST) ;;
+esac
+
+AC_CACHE_CHECK([availability of ntp_{adj,get}time()], ac_cv_var_ntp_syscalls,
+ [ac_cv_var_ntp_syscalls=no
+ case "$ac_cv_func___adjtimex" in
+  yes)
+    ac_cv_var_ntp_syscalls=libc
+    ;;
+  *) case "$ac_cv_func_ntp_adjtime$ac_cv_func_ntp_gettime" in
+      yesyes)
+        ac_cv_var_ntp_syscalls=libc
+        ;;
+      *) AC_EGREP_CPP(yes,
+         [#include 
+#if defined(SYS_ntp_gettime) && defined(SYS_ntp_adjtime)
+           yes
+#endif
+          ], ac_cv_var_ntp_syscalls=kernel)
+         ;;
+     esac
+     ;;
+ esac])
+case "$ac_cv_var_ntp_syscalls" in
+ libc)
+    AC_DEFINE(NTP_SYSCALLS_LIBC)
+    ;;
+ kernel)
+    AC_DEFINE(NTP_SYSCALLS_STD)
+    ;;
+ *)
+    ;;
+esac
+
+AC_CACHE_CHECK(if sys/timex.h has STA_FLL, ac_cv_var_sta_fll,
+[AC_EGREP_CPP(yes,
+    [#include 
+#ifdef STA_FLL
+    yes
+#endif
+    ], ac_cv_var_sta_fll=yes, ac_cv_var_sta_fll=no)])
+
+AC_CACHE_CHECK(if we have kernel PLL support, ac_cv_var_kernel_pll,
+[dnl ac_cv_var_ntp_syscalls is {no,libc,kernel}
+case "$ac_cv_header_sys_timex_h$ac_cv_struct_ntptimeval$ac_cv_var_sta_fll$ac_cv_var_ntp_syscalls" in
+ *no*)
+    ac_cv_var_kernel_pll=no
+    ;;
+ *) ac_cv_var_kernel_pll=yes
+    ;;
+esac])
+case "$ac_cv_var_kernel_pll" in
+ yes)
+    AC_DEFINE(KERNEL_PLL)
+    ;;
+esac
+
+AC_CACHE_CHECK(if SIOCGIFCONF returns buffer size in the buffer, ac_cv_var_size_returned_in_buffer,
+  [ans=no
+  case "$target" in
+   *-fujitsu-uxp*)
+      ans=yes
+      ;;
+   *-ncr-sysv4*)
+      ans=yes
+      ;;
+   *-univel-sysv*)
+      ans=yes
+      ;;
+  esac
+  ac_cv_var_size_returned_in_buffer=$ans])
+case "$ac_cv_var_size_returned_in_buffer" in
+ yes) AC_DEFINE(SIZE_RETURNED_IN_BUFFER) ;;
+esac
+
+dnl AC_CACHE_CHECK(if we want GDT surveying code, ac_cv_var_gdt_surveying,
+dnl [AC_ARG_ENABLE(gdt-surveying,	[  --enable-gdt-surveying   - include GDT survey code],
+dnl     [ans=$enableval], [ans=no])
+dnl ac_cv_var_gdt_surveying=$ans])
+dnl case "$ac_cv_var_gdt_surveying" in
+dnl  yes) AC_DEFINE(GDT_SURVEYING) ;;
+dnl esac
+
+AC_CACHE_CHECK(if we want to use MD5 authentication, ac_cv_var_use_md5,
+[AC_ARG_ENABLE(md5,          	[  --enable-md5            + include support for MD5 keys],
+    [ans=$enableval], [ans=yes])
+ac_cv_var_use_md5=$ans])
+case "$ac_cv_var_use_md5" in
+ yes) AC_DEFINE(MD5) ;;
+esac
+
+# Check for ioctls TIOCGPPSEV
+AC_MSG_CHECKING(ioctl TIOCGPPSEV)
+if test "$ac_cv_header_termios_h" = "yes"; then
+    AC_EGREP_CPP(yes,
+    [#include 
+#ifdef TIOCGPPSEV
+         yes
+#endif
+	 ], ntp_ok=yes, ntp_ok=no)
+else
+ntp_ok=no
+fi
+
+if test "$ntp_ok" = "yes"; then
+    AC_DEFINE(HAVE_TIOCGPPSEV)
+    ac_cv_var_oncore_ok=yes
+fi
+AC_MSG_RESULT($ntp_ok)
+
+# Check for ioctls TIOCSPPS
+AC_MSG_CHECKING(ioctl TIOCSPPS)
+if test "$ac_cv_header_termios_h" = "yes"; then
+    AC_EGREP_CPP(yes,
+    [#include 
+#ifdef TIOCSPPS
+         yes
+#endif
+	 ], ntp_ok=yes, ntp_ok=no)
+else
+    ntp_ok=no
+fi
+
+if test "$ntp_ok" = "yes"; then
+    AC_DEFINE(HAVE_TIOCSPPS)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+# Check for ioctls CIOGETEV
+AC_MSG_CHECKING(ioctl CIOGETEV)
+if test "$ac_cv_header_sys_ppsclock_h" = "yes"; then
+    AC_EGREP_CPP(yes,
+    [#include 
+#ifdef CIOGETEV
+         yes
+#endif
+	 ], ntp_ok=yes, ntp_ok=no)
+else
+ntp_ok=no
+fi
+
+if test "$ntp_ok" = "yes"; then
+    ac_cv_var_oncore_ok=yes
+    AC_DEFINE(HAVE_CIOGETEV)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+# Check for header timepps.h, if found then we have PPS API (Draft RFC) stuff.
+# there is NO way that I can tell to tell if a given OS is using timespec or
+# timeval so just set it here for the one case that is KNOWN to use timespec.
+
+case "$ac_cv_header_timepps_h$ac_cv_header_sys_timepps_h" in
+ *yes*)
+    AC_DEFINE(HAVE_PPSAPI)
+    ac_cv_var_oncore_ok=yes
+    AC_DEFINE(HAVE_TIMESPEC)
+    ;;
+esac
+
+# Check for ioctls TIOCGSERIAL, TIOCSSERIAL, ASYNC_PPS_CD_POS, ASYNC_PPS_CD_NEG
+AC_CHECK_HEADER(linux/serial.h)
+AC_MSG_CHECKING(ioctl TIOCGSERIAL, TIOCSSERIAL, ASYNC_PPS_CD_POS, ASYNC_PPS_CD_NEG)
+case "$ac_cv_header_sys_ppsclock_h$ac_cv_header_linux_serial_h" in
+  yesyes)
+    AC_EGREP_CPP(yes,
+    [#include 
+typedef int u_int;
+
+#include 
+#include 
+
+#ifdef TIOCGSERIAL
+#ifdef TIOCSSERIAL
+#ifdef ASYNC_PPS_CD_POS
+#ifdef ASYNC_PPS_CD_NEG
+#ifdef CIOGETEV
+         yes
+#endif
+#endif
+#endif
+#endif
+#endif
+	 ], ntp_ok=yes)
+	;;
+  *)
+	ntp_ok=no
+	;;
+esac
+
+if test "$ntp_ok" = "yes"; then
+    AC_DEFINE(HAVE_TIO_SERIAL_STUFF)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+dnl dnl These are for OPT_PROGRAMS in authstuff/
+dnl AC_SUBST(AUTHCERT)
+dnl AC_SUBST(AUTHSPEED)
+dnl AC_SUBST(MD5DRIVER)
+dnl AC_SUBST(KEYPARITY)
+dnl AC_SUBST(MAKEIPFP)
+dnl AC_SUBST(MAKEPC1)
+dnl AC_SUBST(MAKEPC2)
+dnl AC_SUBST(MAKESP)
+dnl AC_SUBST(MKRANDKEYS)
+dnl AC_SUBST(OMAKEIPFP)
+dnl AC_SUBST(UNIXCERT)
+
+ntp_refclock=no
+
+# HPUX only, and by explicit request
+AC_MSG_CHECKING(Datum/Bancomm bc635/VME interface)
+AC_ARG_ENABLE(BANCOMM,		[  --enable-BANCOMM        - Datum/Bancomm bc635/VME interface],
+    [ntp_ok=$enableval], [ntp_ok=no])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_BANC)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$target" in
+ yes*-*-hpux*) ;;
+ yes*) AC_WARN(*** But the expected answer is... no ***) ;;
+esac
+
+#HPUX only, and only by explicit request
+AC_MSG_CHECKING(TrueTime GPS receiver/VME interface)
+AC_ARG_ENABLE(GPSVME,		[  --enable-GPSVME         - TrueTime GPS receiver/VME interface],
+    [ntp_ok=$enableval], [ntp_ok=no])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_GPSVME)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$target" in
+ yes*-*-hpux*) ;;
+ yes*) AC_WARN(*** But the expected answer is... no ***) ;;
+esac
+
+AC_MSG_CHECKING(for PCL720 clock support)
+case "$ac_cv_header_machine_inline_h$ac_cv_header_sys_pcl720_h$ac_cv_header_sys_i8253_h" in
+ yesyesyes)
+    AC_DEFINE(CLOCK_PPS720)
+    ans=yes
+    ;;
+ *)
+    ans=no
+    ;;
+esac
+AC_MSG_RESULT($ans)
+
+AC_MSG_CHECKING(for SHM clock attached thru shared memory)
+AC_ARG_ENABLE(SHM,		[  --enable-SHM            - SHM clock attached thru shared memory],
+    [ntp_ok=$enableval], [ntp_ok=no])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_SHM)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(for default inclusion of all suitable non-PARSE clocks)
+AC_ARG_ENABLE(all-clocks,	[  --enable-all-clocks     + include all suitable non-PARSE clocks:],
+    [ntp_eac=$enableval], [ntp_eac=yes])
+AC_MSG_RESULT($ntp_eac)
+
+AC_MSG_CHECKING(if we have support for PARSE clocks)
+case "$ac_cv_header_termio_h$ac_cv_header_termios_h" in
+ *yes*)
+    ntp_canparse=yes
+    ;;
+ *) ntp_canparse=no
+    ;;
+esac
+AC_MSG_RESULT($ntp_canparse)
+
+# Requires modem control
+AC_MSG_CHECKING(ACTS modem service)
+AC_ARG_ENABLE(ACTS,		[  --enable-ACTS           + ACTS modem service],
+    [ntp_ok=$enableval],
+    [AC_EGREP_CPP(yes,
+        [#include 
+#ifdef HAVE_SYS_IOCTL_H
+#include 
+#endif
+#ifdef TIOCMBIS
+         yes
+#endif
+         ], ntp_ok=$ntp_eac, ntp_ok=no)])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_ACTS)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(Arbiter 1088A/B GPS receiver)
+AC_ARG_ENABLE(ARBITER,		[  --enable-ARBITER        + Arbiter 1088A/B GPS receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_ARBITER)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(Arcron MSF receiver)
+AC_ARG_ENABLE(ARCRON_MSF,	[  --enable-ARCRON-MSF     + Arcron MSF receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_ARCRON_MSF)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(Austron 2200A/2201A GPS receiver)
+AC_ARG_ENABLE(AS2201,		[  --enable-AS2201         + Austron 2200A/2201A GPS receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_AS2201)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(PPS interface)
+AC_ARG_ENABLE(ATOM,		[  --enable-ATOM           + PPS interface],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_ATOM)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(CHU modem/decoder)
+AC_ARG_ENABLE(CHU,    		[  --enable-CHU            + CHU modem/decoder],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_CHU)
+fi
+AC_MSG_RESULT($ntp_ok)
+ac_refclock_chu=$ntp_ok
+
+AC_MSG_CHECKING(CHU audio/decoder)
+AC_ARG_ENABLE(AUDIO-CHU,	[  --enable-AUDIO-CHU      s - CHU audio/decoder],
+    [ntp_ok=$enableval], [ntp_ok=no])
+if test "$ntp_ok" = "yes"; then
+    AC_DEFINE(AUDIO_CHU)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ac_refclock_chu$target" in
+ yesyes*-*-sunos*) ;;
+ yesyes*-*-solaris*) ;;
+ yes*) AC_WARN(*** But the expected answer is...no ***) ;;
+esac
+
+# Not under HP-UX
+AC_MSG_CHECKING(Datum Programmable Time System)
+AC_ARG_ENABLE(DATUM,		[  --enable-DATUM          s Datum Programmable Time System],
+    [ntp_ok=$enableval],
+    [case "$ac_cv_header_termios_h" in
+    yes)
+        ntp_ok=$ntp_eac
+        ;;
+    *) ntp_ok=no
+        ;;
+    esac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_DATUM)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+# Requires modem control
+AC_MSG_CHECKING(Heath GC-1000 WWV/WWVH receiver)
+AC_ARG_ENABLE(HEATH,		[  --enable-HEATH          s Heath GC-1000 WWV/WWVH receiver],
+    [ntp_ok=$enableval],
+    [AC_EGREP_CPP(yes,
+        [#include 
+#ifdef HAVE_SYS_IOCTL_H
+#include 
+#endif
+#ifdef TIOCMBIS
+         yes
+#endif
+         ], ntp_ok=$ntp_eac, ntp_ok=no)])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_HEATH)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(HP 58503A GPS receiver)
+AC_ARG_ENABLE(HPGPS,		[  --enable-HPGPS          + HP 58503A GPS receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_HPGPS)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(Sun IRIG audio decoder)
+AC_ARG_ENABLE(IRIG,  		[  --enable-IRIG           s Sun IRIG audio decoder],
+    [ntp_ok=$enableval],
+    [case "$ac_cv_header_sun_audioio_h$ac_cv_header_sys_audioio_h" in
+     *yes*)
+	ntp_ok=$ntp_eac
+	;;
+     *)	ntp_ok=no
+	;;
+    esac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_IRIG)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ac_cv_header_sun_audioio_h$ac_cv_header_sys_audioio_h" in
+ yesnono) AC_WARN(*** But the expected answer is... no ***) ;;
+esac
+
+AC_MSG_CHECKING(Leitch CSD 5300 Master Clock System Driver)
+AC_ARG_ENABLE(LEITCH,		[  --enable-LEITCH         + Leitch CSD 5300 Master Clock System Driver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_LEITCH)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(local clock reference)
+AC_ARG_ENABLE(LOCAL-CLOCK,	[  --enable-LOCAL-CLOCK    + local clock reference],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_LOCAL)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(EES M201 MSF receiver)
+AC_ARG_ENABLE(MSFEES,		[  --enable-MSFEES         + EES M201 MSF receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_MSFEES)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+# Not Ultrix
+AC_MSG_CHECKING(Magnavox MX4200 GPS receiver)
+AC_ARG_ENABLE(MX4200,		[  --enable-MX4200         s Magnavox MX4200 GPS receiver],
+    [ntp_ok=$enableval],
+    [case "$ac_cv_var_ppsclock" in
+     yes) ntp_ok=$ntp_eac
+        ;;
+     *) ntp_ok=no
+        ;;
+    esac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_MX4200)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$target" in
+ yes*-*-ultrix*) AC_WARN(*** But the expected answer is... no ***) ;;
+esac
+
+AC_MSG_CHECKING(NMEA GPS receiver)
+AC_ARG_ENABLE(NMEA,  		[  --enable-NMEA           + NMEA GPS receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_NMEA)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(for ONCORE Motorola VP/UT Oncore GPS)
+AC_ARG_ENABLE(ONCORE,		[  --enable-ONCORE         + Motorola VP/UT Oncore GPS receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+case "$ac_cv_var_oncore_ok" in
+ no) ntp_ok=no ;;
+esac
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_ONCORE)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(for Palisade clock)
+AC_ARG_ENABLE(PALISADE,		[  --enable-PALISADE       + Palisade clock],
+    [ntp_ok=$enableval],
+    [case "$ac_cv_header_termios_h" in
+    yes)
+        ntp_ok=$ntp_eac
+        ;;
+    *) ntp_ok=no
+        ;;
+    esac])
+
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_PALISADE)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(PST/Traconex 1020 WWV/WWVH receiver)
+AC_ARG_ENABLE(PST,		[  --enable-PST            + PST/Traconex 1020 WWV/WWVH receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_PST)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+# Not Ultrix
+AC_MSG_CHECKING(Rockwell Jupiter GPS receiver)
+AC_ARG_ENABLE(JUPITER,		[  --enable-JUPITER        s Rockwell Jupiter GPS receiver],
+    [ntp_ok=$enableval],
+    [case "$ac_cv_var_ppsclock" in
+#     yes) ntp_ok=$ntp_eac
+#        ;;
+     *) ntp_ok=no
+        ;;
+    esac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_JUPITER)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$target" in
+ yes*-*-ultrix*) AC_WARN(*** But the expected answer is... no ***) ;;
+esac
+
+# Requires modem control
+AC_MSG_CHECKING(PTB modem service)
+AC_ARG_ENABLE(PTBACTS,		[  --enable-PTBACTS        s PTB modem service],
+    [ntp_ok=$enableval],
+    [AC_EGREP_CPP(yes,
+        [#include 
+#ifdef HAVE_SYS_IOCTL_H
+#include 
+#endif
+#ifdef TIOCMBIS
+         yes
+#endif
+         ], ntp_ok=$ntp_eac, ntp_ok=no)])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_PTBACTS)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(KSI/Odetics TPRO/S GPS receiver/IRIG interface)
+AC_ARG_ENABLE(TPRO,		[  --enable-TPRO           s KSI/Odetics TPRO/S GPS receiver/IRIG interface],
+    [ntp_ok=$enableval],
+    [case "$ac_cv_header_sys_tpro_h" in
+     yes)
+	ntp_ok=$ntp_eac
+	;;
+     *)	ntp_ok=no
+	;;
+    esac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_TPRO)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ac_cv_header_sys_tpro" in
+ yesno) AC_WARN(*** But the expected answer is... no ***) ;;
+esac
+
+AC_MSG_CHECKING(TRAK 8810 GPS receiver)
+AC_ARG_ENABLE(TRAK,		[  --enable-TRAK           + TRAK 8810 GPS receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_TRAK)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(Chrono-log K-series WWVB receiver)
+AC_ARG_ENABLE(CHRONOLOG,	[  --enable-CHRONOLOG      + Chrono-log K-series WWVB receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_CHRONOLOG)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(Dumb generic hh:mm:ss local clock)
+AC_ARG_ENABLE(DUMBCLOCK,	[  --enable-DUMBCLOCK      + Dumb generic hh:mm:ss local clock],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_DUMBCLOCK)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+# Not on a vax-dec-bsd
+AC_MSG_CHECKING(Kinemetrics/TrueTime receivers)
+AC_ARG_ENABLE(TRUETIME,		[  --enable-TRUETIME       s Kinemetrics/TrueTime receivers],
+    [ntp_ok=$enableval],
+    [case "$target" in
+     vax-dec-bsd)
+	ntp_ok=no
+	;;
+     *)
+	ntp_ok=$ntp_eac
+	;;
+    esac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_TRUETIME)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$target" in
+ yesvax-dec-bsd) AC_WARN(*** But the expected answer is... no ***) ;;
+esac
+
+AC_MSG_CHECKING(Spectracom 8170/Netclock/2 WWVB receiver)
+AC_ARG_ENABLE(WWVB,		[  --enable-WWVB           + Spectracom 8170/Netclock/2 WWVB receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_WWVB)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(Ultralink M320 WWVB receiver)
+AC_ARG_ENABLE(ULINK,		[  --enable-ULINK           + Ultralink WWVB receiver],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_ULINK)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+# Requires modem control
+AC_MSG_CHECKING(USNO modem service)
+AC_ARG_ENABLE(USNO,		[  --enable-USNO           s USNO modem service],
+    [ntp_ok=$enableval],
+    [AC_EGREP_CPP(yes,
+        [#include 
+#ifdef HAVE_SYS_IOCTL_H
+#include 
+#endif
+#ifdef TIOCMBIS
+         yes
+#endif
+         ], ntp_ok=$ntp_eac, ntp_ok=no)])
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_USNO)
+fi
+AC_MSG_RESULT($ntp_ok)
+
+AC_MSG_CHECKING(for default inclusion of all suitable PARSE clocks)
+AC_ARG_ENABLE(parse-clocks,	[  --enable-parse-clocks   - include all suitable PARSE clocks:],
+    [ntp_eapc=$enableval],
+    [case "$ntp_eac" in
+     yes) ntp_eapc=$ntp_canparse ;;
+     *) ntp_eapc=no ;;
+    esac
+    ntp_eapc=no])
+AC_MSG_RESULT($ntp_eapc)
+
+case "$ntp_eac$ntp_eapc$ntp_canparse" in
+ noyes*)
+    AC_MSG_ERROR("--enable-parse-clocks" requires "--enable-all-clocks".)
+    ;;
+ yesyesno)
+    AC_MSG_ERROR(You said "--enable-parse-clocks" but PARSE isn't supported on this platform!)
+    ;;
+ *) ;;
+esac
+
+ntp_libparse=no
+ntp_parseutil=no
+ntp_rawdcf=no
+
+AC_MSG_CHECKING(Diem Computime Radio Clock)
+AC_ARG_ENABLE(COMPUTIME,	[  --enable-COMPUTIME      s Diem Computime Radio Clock],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_COMPUTIME)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+
+AC_MSG_CHECKING(ELV/DCF7000 clock)
+AC_ARG_ENABLE(DCF7000,		[  --enable-DCF7000        s ELV/DCF7000 clock],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_DCF7000)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+
+AC_MSG_CHECKING(HOPF 6021 clock)
+AC_ARG_ENABLE(HOPF6021,		[  --enable-HOPF6021       s HOPF 6021 clock],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_HOPF6021)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+
+AC_MSG_CHECKING(Meinberg clocks)
+AC_ARG_ENABLE(MEINBERG,		[  --enable-MEINBERG       s Meinberg clocks],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_MEINBERG)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+
+AC_MSG_CHECKING(DCF77 raw time code)
+AC_ARG_ENABLE(RAWDCF,		[  --enable-RAWDCF         s DCF77 raw time code],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_parseutil=yes
+    ntp_refclock=yes
+    ntp_rawdcf=yes
+    AC_DEFINE(CLOCK_RAWDCF)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+
+case "$ntp_rawdcf" in
+ yes)
+    AC_CACHE_CHECK(if we must enable parity for RAWDCF,
+    ac_cv_var_rawdcf_parity,
+    [ans=no
+    case "$target" in
+     *-*-linux*)
+        ans=yes
+        ;;
+    esac
+    ac_cv_var_rawdcf_parity=$ans])
+    case "$ac_cv_var_rawdcf_parity" in
+     yes) AC_DEFINE(RAWDCF_NO_IGNPAR) ;;
+    esac
+    ;;
+
+ *) # HMS: Is this a good idea?
+    ac_cv_var_rawdcf_parity=no
+    ;;
+esac
+
+AC_MSG_CHECKING(RCC 8000 clock)
+AC_ARG_ENABLE(RCC8000,		[  --enable-RCC8000        s RCC 8000 clock],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_RCC8000)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+
+AC_MSG_CHECKING(Schmid DCF77 clock)
+AC_ARG_ENABLE(SCHMID,		[  --enable-SCHMID         s Schmid DCF77 clock],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_SCHMID)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+
+AC_MSG_CHECKING(Trimble GPS receiver/TAIP protocol)
+AC_ARG_ENABLE(TRIMTAIP,		[  --enable-TRIMTAIP       s Trimble GPS receiver/TAIP protocol],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_TRIMTAIP)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+
+AC_MSG_CHECKING(Trimble GPS receiver/TSIP protocol)
+AC_ARG_ENABLE(TRIMTSIP,		[  --enable-TRIMTSIP       s Trimble GPS receiver/TSIP protocol],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_TRIMTSIP)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+
+AC_MSG_CHECKING(WHARTON 400A Series clock)
+AC_ARG_ENABLE(WHARTON,		[  --enable-WHARTON        s WHARTON 400A Series clock],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_WHARTON_400A)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+
+AC_MSG_CHECKING(VARITEXT clock)
+AC_ARG_ENABLE(VARITEXT,		[  --enable-VARITEXT       s VARITEXT clock],
+    [ntp_ok=$enableval], [ntp_ok=$ntp_eapc])
+if test "$ntp_ok" = "yes"; then
+    ntp_libparse=yes
+    ntp_refclock=yes
+    AC_DEFINE(CLOCK_VARITEXT)
+fi
+AC_MSG_RESULT($ntp_ok)
+case "$ntp_ok$ntp_canparse" in
+ yesno)
+    AC_MSG_ERROR(That's a parse clock and this system doesn't support it!)
+    ;;
+esac
+AC_SUBST(LIBPARSE)
+AC_SUBST(MAKE_LIBPARSE)
+AC_SUBST(MAKE_LIBPARSE_KERNEL)
+AC_SUBST(MAKE_CHECK_Y2K)
+AC_MSG_CHECKING(if we need to make and use the parse libraries)
+ans=no
+case "$ntp_libparse" in
+ yes)
+    ans=yes
+    AC_DEFINE(CLOCK_PARSE)
+    LIBPARSE=../libparse/libparse.a
+    MAKE_LIBPARSE=libparse.a
+    MAKE_CHECK_Y2K=check_y2k
+    AC_DEFINE(PPS_SAMPLE)
+    AC_DEFINE(CLOCK_ATOM)
+    ;;
+esac
+AC_MSG_RESULT($ans)
+
+AC_SUBST(RSAREF)
+AC_SUBST(LIBRSAREF)
+AC_SUBST(MAKE_LIBRSAREF)
+AC_MSG_CHECKING(if we need to make and use the RSAREF library)
+ans=no
+if test -f $srcdir/rsaref2/source/rsa.c
+then
+    ans=yes
+    LIBRSAREF=../librsaref/librsaref.a
+    MAKE_LIBRSAREF=librsaref.a
+    AC_DEFINE(DES)
+fi
+AC_MSG_RESULT($ans)
+
+AC_SUBST(TESTDCF)
+AC_SUBST(DCFD)
+
+AC_MSG_CHECKING(if we can make dcf parse utilities)
+ans=no
+if test "$ntp_parseutil" = "yes"; then
+    case "$target" in
+     *-*-sunos4*|*-*-solaris2*|*-*-linux*)
+	ans="dcfd testdcf"
+	DCFD=dcfd
+        TESTDCF=testdcf
+	;;
+    esac
+fi
+AC_MSG_RESULT($ans)
+
+AC_SUBST(MAKE_PARSEKMODULE)
+AC_MSG_CHECKING(if we can build kernel streams modules for parse)
+ans=no
+case "$ntp_parseutil$ac_cv_header_sys_stropts_h" in
+ yesyes)
+    case "$target" in
+     sparc-*-sunos4*)
+        case "$ac_cv_var_kernel_pll" in
+	yes)
+	    AC_DEFINE(PPS_SYNC)
+	    ;;
+	esac
+	ans=parsestreams
+	MAKE_PARSEKMODULE=parsestreams.loadable_module.o
+	;;
+     sparc-*-solaris2*)
+	ans=parsesolaris
+	MAKE_PARSEKMODULE=parse
+	;;
+    esac
+    ;;
+esac
+AC_MSG_RESULT($ans)
+
+AC_MSG_CHECKING(if we need basic refclock support)
+if test "$ntp_refclock" = "yes"; then
+    AC_DEFINE(REFCLOCK)
+fi
+AC_MSG_RESULT($ntp_refclock)
+
+dnl Things that can be made in clockstuff/
+AC_SUBST(PROPDELAY)	dnl Set to "propdelay"
+AC_SUBST(CHUTEST)	dnl Set to "chutest"
+AC_SUBST(CLKTEST)	dnl Set to "clktest"
+
+AC_SUBST(MAKE_ADJTIMED)
+AC_MSG_CHECKING(if we want HP-UX adjtimed support)
+changequote(<<, >>)dnl
+case "$target" in
+ *-*-hpux[56789]*)
+    ans=yes
+    ;;
+ *) ans=no
+    ;;
+esac
+changequote([, ])dnl
+if test "$ans" = "yes"; then
+    MAKE_ADJTIMED=adjtimed
+    AC_DEFINE(NEED_HPUX_ADJTIME)
+fi
+AC_MSG_RESULT($ans)
+
+AC_CACHE_CHECK(if we can read kmem, ac_cv_var_can_kmem,
+[AC_ARG_ENABLE(kmem,		[  --enable-kmem           s read /dev/kmem for tick and/or tickadj],
+    [ans=$enableval],
+    [changequote(<<, >>)dnl
+    case "$ac_cv_func_nlist$ac_cv_func_K_open$ac_cv_func_kvm_open" in
+     *yes*)
+	ans=yes
+	;;
+     *) ans=no
+	;;
+    esac
+    case "$target" in
+     *-*-aix*)
+	#ans=no
+	;;
+     *-*-domainos)	# Won't be found...
+	ans=no
+	;;
+     *-*-hpux*)
+	#ans=no
+	;;
+     *-*-irix[456]*)
+	ans=no
+	;;
+     *-*-linux*)
+	ans=no
+	;;
+     *-*-winnt3.5)
+	ans=no
+	;;
+    esac
+    changequote([, ])dnl
+    ])
+ac_cv_var_can_kmem=$ans])
+
+case "$ac_cv_var_can_kmem" in
+ *yes*) ;;
+ *) AC_DEFINE(NOKMEM) ;;
+esac
+
+AC_CACHE_CHECK(if adjtime is accurate, ac_cv_var_adjtime_is_accurate,
+[AC_ARG_ENABLE(accurate-adjtime, [  --enable-accurate-adjtime
+                          s the adjtime() call is accurate],
+    [ans=$enableval],
+    [changequote(<<, >>)dnl
+    case "$target" in
+      i386-sequent-ptx*)
+	 ans=no
+	 ;;
+      i386-unknown-osf1*)
+	 ans=yes
+	 ;;
+      mips-sgi-irix[456]*)
+	 ans=yes
+	 ;;
+      *-fujitsu-uxp*)
+	 ans=yes
+	 ;;
+      *-ibm-aix4*)
+	 ans=yes
+	 ;;
+      *-*-linux*)
+	 ans=yes
+	 ;;
+      *-*-solaris2.[01]*)
+	 ans=no
+	 ;;
+      *-*-solaris2*)
+         ans=yes
+         ;;
+      *) ans=no
+	 ;;
+     esac
+     changequote([, ])dnl
+     ])
+ac_cv_var_adjtime_is_accurate=$ans])
+case "$ac_cv_var_adjtime_is_accurate" in
+ yes) AC_DEFINE(ADJTIME_IS_ACCURATE) ;;
+esac
+
+AC_CACHE_CHECK([the name of 'tick' in the kernel],
+ac_cv_var_nlist_tick,
+[changequote(<<, >>)dnl
+ans=_tick
+case "$target" in
+ m68*-hp-hpux*) # HP9000/300?
+    ans=_old_tick
+    ;;
+ *-apple-aux[23]*)
+    ans=tick
+    ;;
+ *-hp-hpux*)
+    ans=old_tick
+    ;;
+ *-ibm-aix[34]*)
+    ans=no
+    ;;
+ *-*-ptx*)
+    ans=tick
+    ;;
+ *-*-sco3.2v[45]*)
+    ans=no
+    ;;
+ *-*-solaris2*)
+    ans=nsec_per_tick
+    ;;
+ *-*-sysv4*)
+    ans=tick
+    ;;
+esac
+changequote([, ])dnl
+ac_cv_var_nlist_tick=$ans])
+case "$ac_cv_var_nlist_tick" in
+ ''|no) ;;	# HMS: I think we can only get 'no' here...
+ *) AC_DEFINE_UNQUOTED(K_TICK_NAME, "$ac_cv_var_nlist_tick") ;;
+esac
+#
+AC_CACHE_CHECK([for the units of 'tick'],
+ac_cv_var_tick_nano,
+[changequote(<<, >>)dnl
+ans=usec
+case "$target" in
+ *-*-solaris2*)
+    ans=nsec
+    ;;
+esac
+changequote([, ])dnl
+ac_cv_var_tick_nano=$ans])
+case "$ac_cv_var_tick_nano" in
+ nsec)
+    AC_DEFINE(TICK_NANO)
+    ;;
+esac
+#
+AC_CACHE_CHECK([the name of 'tickadj' in the kernel],
+ac_cv_var_nlist_tickadj,
+[changequote(<<, >>)dnl
+ans=_tickadj
+case "$target" in
+ m68*-hp-hpux*) # HP9000/300?
+    ans=_tickadj
+    ;;
+ *-apple-aux[23]*)
+    ans=tickadj
+    ;;
+ *-hp-hpux10*)
+    ans=no
+    ;;
+ *-hp-hpux9*)
+    ans=no
+    ;;
+ *-hp-hpux*)
+    ans=tickadj
+    ;;
+ *-*-aix*)
+    ans=tickadj
+    ;;
+ *-*-ptx*)
+    ans=tickadj
+    ;;
+ *-*-sco3.2v4*)
+    ans=no
+    ;;
+ *-*-sco3.2v5.0*)
+    ans=clock_drift
+    ;;
+ *-*-solaris2*)
+    ans=no	# hrestime_adj
+    ;;
+ *-*-sysv4*)
+    ans=tickadj
+    ;;
+esac
+changequote([, ])dnl
+ac_cv_var_nlist_tickadj=$ans])
+case "$ac_cv_var_nlist_tickadj" in
+ ''|no) ;;	# HMS: I think we can only get 'no' here...
+ *) AC_DEFINE_UNQUOTED(K_TICKADJ_NAME, "$ac_cv_var_nlist_tickadj") ;;
+esac
+#
+AC_CACHE_CHECK([for the units of 'tickadj'],
+ac_cv_var_tickadj_nano,
+[changequote(<<, >>)dnl
+ans=usec
+case "$target" in
+ *-*-solaris2*)
+    ans=nsec
+    ;;
+esac
+changequote([, ])dnl
+ac_cv_var_tickadj_nano=$ans])
+case "$ac_cv_var_tickadj_nano" in
+ nsec)
+    AC_DEFINE(TICKADJ_NANO)
+    ;;
+esac
+#
+AC_CACHE_CHECK([half-heartedly for 'dosynctodr' in the kernel],
+ac_cv_var_nlist_dosynctodr,
+[changequote(<<, >>)dnl
+case "$target" in
+ *-apple-aux[23]*)
+    ans=no
+    ;;
+ *-sni-sysv*)
+    ans=dosynctodr
+    ;;
+ *-*-aix*)
+    ans=dosynctodr
+    ;;
+ *-*-hpux*)
+    ans=no
+    ;;
+ *-*-nextstep*)
+    ans=_dosynctodr
+    ;;
+ *-*-ptx*)
+    ans=doresettodr
+    ;;
+ *-*-sco3.2v4*)
+    ans=no
+    ;;
+ *-*-sco3.2v5*)
+    ans=track_rtc
+    ;;
+ *-*-solaris2*)
+    ans=dosynctodr
+    ;;
+ *-*-sysv4*)
+    ans=doresettodr
+    ;;
+ *)
+    ans=_dosynctodr
+    ;;
+esac
+changequote([, ])dnl
+ac_cv_var_nlist_dosynctodr=$ans])
+case "$ac_cv_var_nlist_dosynctodr" in
+ no) ;;
+ *)  AC_DEFINE_UNQUOTED(K_DOSYNCTODR_NAME, "$ac_cv_var_nlist_dosynctodr")
+     ;;
+esac
+#
+AC_CACHE_CHECK([half-heartedly for 'noprintf' in the kernel],
+ac_cv_var_nlist_noprintf,
+[changequote(<<, >>)dnl
+case "$target" in
+ *-apple-aux[23]*)
+    ans=no
+    ;;
+ *-sni-sysv*)
+    ans=noprintf
+    ;;
+ *-*-aix*)
+    ans=noprintf
+    ;;
+ *-*-hpux*)
+    ans=no
+    ;;
+ *-*-ptx*)
+    ans=noprintf
+    ;;
+ *-*-nextstep*)
+    ans=_noprintf
+    ;;
+ *-*-solaris2*)
+    ans=noprintf
+    ;;
+ *-*-sysv4*)
+    ans=noprintf
+    ;;
+ *)
+    ans=_noprintf
+    ;;
+esac
+changequote([, ])dnl
+ac_cv_var_nlist_noprintf=$ans])
+case "$ac_cv_var_nlist_noprintf" in
+ no) ;;
+ *)  AC_DEFINE_UNQUOTED(K_NOPRINTF_NAME, "$ac_cv_var_nlist_noprintf")
+     ;;
+esac
+
+dnl The tick/tickadj sections were written by Skippy, who never learned
+dnl that it's impolite (horridly gross) to show your guts in public.
+
+dnl	tick		tickadj	
+dnl	10000		80	    Unixware
+dnl	1000000L/hz	tick/16     (Solaris,UXPV,HPUX) && ADJTIME_IS_ACCURATE
+dnl	10000		150	    sgi IRIX
+dnl	1000000L/hz	1000	    RS6000 && NOKMEM
+dnl	1000000L/hz	668	    DOMAINOS && NOKMEM
+dnl	1000000L/hz	500/HZ	    other && NOKMEM
+dnl	txc.tick	1	    Linux
+dnl	(every / 10)	50	    WinNT - tickadj is roughly 500/hz
+dnl	1000000L/hz	(nlist)     (Solaris && !ADJTIME_IS_ACCURATE),
+dnl				    (RS6000 && !NOKMEM), SINIX MIPS
+
+dnl But we'll only use these "values" if we can't find anything else.
+
+AC_CACHE_CHECK(for a default value for 'tick', ac_cv_var_tick,
+[AC_ARG_ENABLE(tick,		[  --enable-tick=VALUE     s force a value for 'tick'],
+    [ans=$enableval],
+    [ans=no
+     case "$target" in
+      XXX-*-pc-cygwin*)
+	 ;;
+      *-univel-sysv*)
+	 ans=10000
+	 ;;
+      *-*-irix*)
+	 ans=10000
+	 ;;
+      *-*-linux*)
+	 ans=txc.tick
+	 ;;
+      *-*-winnt3.5)
+	 ans='(every / 10)'
+	 ;;
+      *)
+	 ans='1000000L/hz'
+	 ;;
+     esac])
+ac_cv_var_tick=$ans])
+case "$ac_cv_var_tick" in
+ ''|no) ;;	# HMS: I think we can only get 'no' here...
+ *) AC_DEFINE_UNQUOTED(PRESET_TICK, $ac_cv_var_tick) ;;
+esac
+
+AC_CACHE_CHECK(for a default value for 'tickadj', ac_cv_var_tickadj,
+[AC_ARG_ENABLE(tickadj,		[  --enable-tickadj=VALUE  s force a value for 'tickadj'],
+  [ans=$enableval],
+  [ans='500/hz'
+  case "$target" in
+   *-fujitsu-uxp*)
+      case "$ac_cv_var_adjtime_is_accurate" in
+       yes) ans='tick/16' ;;
+      esac
+      ;;
+   XXX-*-pc-cygwin*)
+      ans=no
+      ;;
+   *-univel-sysv*)
+      ans=80
+      ;;
+   *-*-aix*)
+      case "$ac_cv_var_can_kmem" in
+       no) ans=1000 ;;
+      esac
+      ;;
+   *-*-domainos)	# Skippy: won't be found...
+      case "$ac_cv_var_can_kmem" in
+       no) ans=668 ;;
+      esac
+      ;;
+   *-*-hpux*)
+      case "$ac_cv_var_adjtime_is_accurate" in
+       yes) ans='tick/16' ;;
+      esac
+      ;;
+   *-*-irix*)
+      ans=150
+      ;;
+   *-*-sco3.2v5.0*)
+      ans=10000L/hz
+      ;;
+   *-*-solaris2*)
+      case "$ac_cv_var_adjtime_is_accurate" in
+       yes)
+          #ans='tick/16'
+	  ;;
+      esac
+      ;;
+   *-*-winnt3.5)
+      ans=50
+      ;;
+  esac])
+ac_cv_var_tickadj=$ans])
+case "$ac_cv_var_tickadj" in
+ ''|no) ;;	# HMS: I think we can only get 'no' here...
+ *) AC_DEFINE_UNQUOTED(PRESET_TICKADJ, $ac_cv_var_tickadj) ;;
+esac
+
+# Newer versions of ReliantUNIX round adjtime() values down to
+# 1/100s (system tick). Sigh ...
+# Unfortunately, there is no easy way to know if particular release
+# has this "feature" or any obvious way to test for it.
+case "$target" in
+ mips-sni-sysv4*) AC_DEFINE(RELIANTUNIX_CLOCK) ;;
+esac
+
+case "$target" in
+ *-*-sco3.2v5*) AC_DEFINE(SCO5_CLOCK) ;;
+esac
+
+ac_cv_make_tickadj=yes
+case "$ac_cv_var_can_kmem$ac_cv_var_tick$ac_cv_var_tickadj" in
+ nonono)	# Don't read KMEM, no presets.  Bogus.
+    AC_MSG_WARN(Can't read kmem, no PRESET_TICK or PRESET_TICKADJ.  No tickadj.)
+    ac_cv_make_tickadj=no
+    ;;
+ nono*)		# Don't read KMEM, no PRESET_TICK but PRESET_TICKADJ.  Bogus.
+    AC_MSG_WARN(Can't read kmem but no PRESET_TICK.  No tickadj.)
+    ac_cv_make_tickadj=no
+    ;;
+ no*no)		# Don't read KMEM, PRESET_TICK but no PRESET_TICKADJ.  Bogus.
+    AC_MSG_WARN(Can't read kmem but no PRESET_TICKADJ.  No tickadj.)
+    ac_cv_make_tickadj=no
+    ;;
+ no*)		# Don't read KMEM, PRESET_TICK and PRESET_TICKADJ.  Cool.
+    ;;
+ yesnono)	# Read KMEM, no presets.  Cool.
+    ;;
+ yesno*)	# Read KMEM, no PRESET_TICK but PRESET_TICKADJ.  Bogus.
+    AC_MSG_WARN(PRESET_TICKADJ is defined but not PRESET_TICK.  Please report this.)
+    ;;
+ yes*no)	# Read KMEM, PRESET_TICK but no PRESET_TICKADJ.  Cool.
+    ;;
+ yes*)		# READ KMEM, PRESET_TICK and PRESET_TICKADJ.
+    ;;
+ *)		# Generally bogus.
+    AC_MSG_ERROR(This shouldn't happen.)
+    ;;
+esac
+
+case "$target" in
+ mips-sni-sysv4*)
+    # tickadj is pretty useless on newer versions of ReliantUNIX
+    # Do not bother
+    ac_cv_make_tickadj=no
+ ;;
+ *-*-solaris2*)
+    # DLM says tickadj is a no-no starting with solaris2.5
+    case "$target" in
+     *-*-solaris2.[0-4]*) ;;
+     *) ac_cv_make_tickadj=no ;;
+    esac
+ ;;
+esac
+
+AC_SUBST(MAKE_TICKADJ)
+AC_CACHE_CHECK(if we want and can make the tickadj utility, ac_cv_make_tickadj,
+ac_cv_make_tickadj=yes)
+case "$ac_cv_make_tickadj" in
+ yes)
+    MAKE_TICKADJ=tickadj
+    ;;
+esac
+
+AC_SUBST(MAKE_NTPTIME)
+AC_CACHE_CHECK(if we want and can make the ntptime utility, ac_cv_make_ntptime,
+[case "$target" in
+ *) case "$ac_cv_struct_ntptimeval$ac_cv_var_kernel_pll" in
+     yesyes)
+	ans=yes
+	;;
+     *)
+	ans=no
+	;;
+    esac
+    ;;
+esac
+ac_cv_make_ntptime=$ans])
+case "$ac_cv_make_ntptime" in
+ yes)
+    MAKE_NTPTIME=ntptime
+    ;;
+esac
+
+AC_CACHE_CHECK(if we want UDP wildcard delivery, ac_cv_var_udp_wildcard_delivery,
+[AC_ARG_ENABLE(udp-wildcard,	[  --enable-udp-wildcard   s use UDP wildcard delivery],
+    [ans=$enableval],
+    [ans=no
+     case "$target" in
+      *-fujitsu-uxp*)
+	 ans=yes
+	 ;;
+      *-univel-sysv*)
+	 ans=yes
+	 ;;
+      *-*-aix3.2*)
+	 ans=yes
+	 ;;
+      *-*-aix4*)
+	 ans=yes
+	 ;;
+      *-*-bsdi*)
+	 ans=yes
+	 ;;
+      *-*-domainos)
+	 ans=yes
+	 ;;
+      *-*-freebsd*)
+	ans=yes
+	;;
+      *-*-hpux*)
+	 ans=yes
+	 ;;
+      *-*-irix6*)
+	 ans=yes
+	 ;;
+      *-*-linux*)
+	 ans=yes
+	 ;;
+      *-*-osf*)
+	 ans=yes
+	 ;;
+      *-*-ptx*)
+	 ans=yes
+	 ;;
+      *-*-solaris2*)
+	 ans=yes
+	 ;;
+      *-*-sunos4*)
+	 ans=yes
+	 ;;
+     esac])
+ac_cv_var_udp_wildcard_delivery=$ans])
+case "$ac_cv_var_udp_wildcard_delivery" in
+ yes) AC_DEFINE(UDP_WILDCARD_DELIVERY) ;;
+esac
+
+case "$host" in
+ $target)
+    ;;
+ *) case "$target" in
+     *-*-vxworks*)
+        LDFLAGS="$LDFLAGS -r"
+        ;;
+    esac
+    ;;
+esac
+
+AC_CACHE_CHECK(if we should always slew the time, ac_cv_var_slew_always,
+[AC_ARG_ENABLE(slew-always,	 [  --enable-slew-always    s always slew the time],
+    [ans=$enableval],
+    [changequote(<<, >>)dnl
+    case "$target" in
+      *-apple-aux[23]*)
+	 ans=yes
+	 ;;
+      *-*-bsdi[012]*)
+	 ans=no
+	 ;;
+      *-*-bsdi*)
+	 ans=yes
+	 ;;
+      *-*-openvms*)	# HMS: won't be found
+	 ans=yes
+	 ;;
+      *) ans=no
+	 ;;
+     esac
+     changequote([, ])dnl
+     ])
+ac_cv_var_slew_always=$ans])
+case "$ac_cv_var_slew_always" in
+ yes) AC_DEFINE(SLEWALWAYS) ;;
+esac
+
+AC_CACHE_CHECK(if we should step and slew the time, ac_cv_var_step_slew,
+[AC_ARG_ENABLE(step-slew,	 [  --enable-step-slew      s step and slew the time],
+    [ans=$enableval],
+    [changequote(<<, >>)dnl
+    case "$target" in
+      *-sni-sysv*)
+	 ans=yes
+	 ;;
+      *-univel-sysv*)
+	 ans=no
+	 ;;
+      *-*-ptx*)
+	 ans=yes
+	 ;;
+      *-*-solaris2.[012]*)
+	 ans=yes
+	 ;;
+      *-*-sysv4*)	# HMS: Does this catch Fujitsu UXP?
+	 ans=yes
+	 ;;
+      *) ans=no
+	 ;;
+     esac
+     changequote([, ])dnl
+     ])
+ac_cv_var_step_slew=$ans])
+case "$ac_cv_var_step_slew" in
+ yes) AC_DEFINE(STEP_SLEW) ;;
+esac
+
+AC_CACHE_CHECK(if ntpdate should step the time, ac_cv_var_ntpdate_step,
+[AC_ARG_ENABLE(ntpdate-step,	 [  --enable-ntpdate-step   s if ntpdate should step the time],
+    [ans=$enableval],
+    [changequote(<<, >>)dnl
+    case "$target" in
+      *-apple-aux[23]*)
+	 ans=yes
+	 ;;
+      *) ans=no
+	 ;;
+     esac
+     changequote([, ])dnl
+     ])
+ac_cv_var_ntpdate_step=$ans])
+case "$ac_cv_var_ntpdate_step" in
+ yes) AC_DEFINE(FORCE_NTPDATE_STEP) ;;
+esac
+
+AC_CACHE_CHECK(if we should sync TODR clock every hour, ac_cv_var_sync_todr,
+[AC_ARG_ENABLE(hourly-todr-sync, [  --enable-hourly-todr-sync
+                          s if we should sync TODR hourly],
+    [ans=$enableval],
+    [case "$target" in
+      *-*-nextstep*)
+	 ans=yes
+	 ;;
+      *-*-openvms*)	# HMS: won't be found
+	 ans=yes
+	 ;;
+      *) ans=no
+	 ;;
+     esac])
+ac_cv_var_sync_todr=$ans])
+case "$ac_cv_var_sync_todr" in
+ yes) AC_DEFINE(DOSYNCTODR) ;;
+esac
+
+AC_CACHE_CHECK(if we should avoid kernel FLL bug, ac_cv_var_kernel_fll_bug,
+[AC_ARG_ENABLE(kernel-fll-bug, [  --enable-kernel-fll-bug s if we should avoid a kernel FLL bug],
+    [ans=$enableval],
+    [changequote(<<, >>)dnl
+    case "$target" in
+     *-*-solaris2.6)
+	 ans=yes
+	 ;;
+     *-*-solaris2.7)
+	 case "`uname -v`" in
+	  Generic_106541-07)
+	     ans=no
+	     ;;
+	  *) ans=yes
+	     ;;
+	 esac
+	 ;;
+     *) ans=no
+	 ;;
+    esac
+    changequote([, ])dnl
+    ])
+ac_cv_var_kernel_fll_bug=$ans])
+case "$ac_cv_var_kernel_fll_bug" in
+ yes) AC_DEFINE(KERNEL_FLL_BUG) ;;
+esac
+
+case "$host" in
+ $target)
+    ;;
+ *) case "$target" in
+     *-*-vxworks*)
+        LDFLAGS="$LDFLAGS -r"
+        ;;
+    esac
+    ;;
+esac
+
+# This is necessary so that .o files in LIBOBJS are also built via
+# the ANSI2KNR-filtering rules.
+LIBOBJS=`echo $LIBOBJS|sed 's/\.o /\$U.o /g;s/\.o$/\$U.o/'`
+
+AC_OUTPUT(Makefile adjtimed/Makefile clockstuff/Makefile \
+include/Makefile kernel/Makefile kernel/sys/Makefile libntp/Makefile \
+libparse/Makefile librsaref/Makefile ntpd/Makefile ntpdc/Makefile \
+ntpdate/Makefile ntpq/Makefile ntptrace/Makefile parseutil/Makefile \
+scripts/Makefile scripts/mkver scripts/ntpver util/Makefile,
+[chmod +x scripts/ntpver scripts/mkver])
+#test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h])
diff --git a/contrib/ntp/dot.emacs b/contrib/ntp/dot.emacs
new file mode 100644
index 000000000000..04241e7f7fd0
--- /dev/null
+++ b/contrib/ntp/dot.emacs
@@ -0,0 +1,18 @@
+;; This is how Dave Mills likes to see the code formatted.
+
+(defconst ntp-c-style
+  '((c-basic-offset . 8)
+    (c-offsets-alist . ((arglist-intro	      . +)
+			(case-label	      . *)
+			(statement-case-intro . *)
+			(statement-cont	      . *)
+			(substatement-open    . 0))))
+  "Dave L. Mills; programming style for use with ntp")
+
+(defun ntp-c-mode-common-hook ()
+  ;; add ntp c style
+  (c-add-style "ntp" ntp-c-style nil))
+
+(add-hook 'c-mode-common-hook 'ntp-c-mode-common-hook)
+
+;; 1997112600
diff --git a/contrib/ntp/excludes b/contrib/ntp/excludes
new file mode 100644
index 000000000000..36cb351e93b0
--- /dev/null
+++ b/contrib/ntp/excludes
@@ -0,0 +1 @@
+*.obj *.pch *.bsc *.pdb *.sbr nt*.zip *.tar *.gz *.ilk beta*.zip
diff --git a/contrib/ntp/html/accopt.htm b/contrib/ntp/html/accopt.htm
new file mode 100644
index 000000000000..d64a0d11a0dd
--- /dev/null
+++ b/contrib/ntp/html/accopt.htm
@@ -0,0 +1,219 @@
+
+
+   
+   
+   Access Control Options
+
+
+
+
+

+Access Control Options

+ +
+

+Access Control Support

+ntpd 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. Additional information and examples can be found in the Notes +on Configuring NTP and Setting up a NTP Subnet page. + +

The restriction facility was implemented in conformance with the access +policies for the original NSFnet backbone time servers. 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. +

+Access Control Commands

+ +
+
+restrict numeric_address [mask numeric_mask] [flag] +[...]
+ +
+The numeric_address argument, expressed in dotted-quad +form, is the address of an host or network. The mask argument, +also expressed in dotted-quad form, defaults to 255.255.255.255, +meaning that the numeric_address 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 numeric_address +is normally given in dotted-quad format, the text string default, +with no mask option, may be used to indicate the default entry.
+ +
+In the current implementation, flag always restricts 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:
+ +
+ +
+
+ignore
+ +
+Ignore all packets from hosts which match this entry. If this flag is specified +neither queries nor time server polls will be responded to.
+ +
+ +
+noquery
+ +
+Ignore all NTP mode 6 and 7 packets (i.e. information queries and configuration +requests) from the source. Time service is not affected.
+ +
+ +
+nomodify
+ +
+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.
+ +
+ +
+notrap
+ +
+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.
+ +
+ +
+lowpriotrap
+ +
+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.
+ +
+ +
+noserve
+ +
+Ignore NTP packets whose mode is other than 6 or 7. In effect, time service +is denied, though queries may still be permitted.
+ +
+ +
+nopeer
+ +
+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.
+ +
+ +
+notrust
+ +
+Treat these hosts normally in other respects, but never use them as synchronization +sources.
+ +
+ +
+limited
+ +
+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 client_limit hosts that have +shown up at the server and that have been active during the last client_limit_period +seconds are accepted. Requests from other clients from the same net are +rejected. Only time request packets are taken into account. Query packets +sent by the ntpq and ntpdc programs are not subject to +these limits. A history of clients is kept using the monitoring capability +of ntpd. Thus, monitoring is always active as long as there is +a restriction entry with the limited flag.
+ +
+ +
+ntpport
+ +
+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 ntpport +and non-ntpport may be specified. The ntpport is considered +more specific and is sorted later in the list.
+ +
+
+ +
+Default restriction list entries, with the flags ignore, ntpport, +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).
+ +
+ +
+clientlimit limit
+ +
+Set the client_limit variable, which limits the number of simultaneous +access-controlled clients. The default value for this variable is 3.
+ +
+ +
+clientperiod period
+ +
+Set the client_limit_period variable, which specifies the number +of seconds after which a client is considered inactive and thus no longer +is counted for client limit restriction. The default value for this variable +is 3600 seconds.
+
+ +
+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/assoc.htm b/contrib/ntp/html/assoc.htm new file mode 100644 index 000000000000..69cb7bc5b1f2 --- /dev/null +++ b/contrib/ntp/html/assoc.htm @@ -0,0 +1,170 @@ + + + + + Release Notes + + + + +

+Association Management

+ +
+

+Association Modes

+This release of the NTP Version 4 (NTPv4) daemon for Unix incorporates +new features and refinements to the NTP Version 3 (NTPv3) algorithms. However, +it continues the tradition of retaining backwards compatibility with older +versions. The NTPv4 version has been under development for quite a while +and isn't finished yet. In fact, quite a number of NTPv4 features have +already been implemented in the current NTPv3, including a number of new +operating modes for automatic server discovery and improved accuracy in +occasionally-connected networks. Following is an extended abstract describing +the new features.. + +

An ephemeral association of some mode is mobilized when a message arrives +from another client or server. For instance, a symmetric-passive association +is mobilized upon arrival of a message from a symmetric- active peer. A +client association is mobilized upon arrival of a broadcast message from +a multicast server or a server message from a manycast server. Ephemeral +associations are demobilized when either (a) the server becomes unreachable +or (b) an error occurs on initial contact before the association is mobilized. + +

The one exception to (a) and (b) above is when +autokey is in use and the initial +authentication check fails due to unknown +key identifier or autokey mismatch. This exception is necessary because +the Unix kernel does not bind the local address until the first packet +is received. The result in broadcast mode is a rather painful initial exchange, +where authentication fails until after the first round of messages. The +result in multicast mode is in general fatal, especially if multiple interfaces +are in use. As promiscuous modes such as multicast and manycast require +authentication for reliable and safe operation, autokey is in general useless +with these modes until and if the input/output machinery is overhauled. + +

Following is a summary of the protocol operations for each mode. + +

Peer Modes (Active and Passive) +

    In these modes, two client/server peers agree to back each other up, +should the synchronization source for either peer fail. One or both peers +is configured in symmetric-active mode using the peer command. Alternatively, +one - the active peer - is configured in this mode and the other, the passive +peer, operates in symmetric-passive mode and requires no prior configuration. +Both association scenarios operate in NTPv4 as in NTPv3; however, several +bugs in the handling of keys and recovery of resources when an active peer +fails, have been corrected in NTPv4. The original NTPv3 authentication +scheme is applicable in this mode, as well as the new NTPv3 autokey scheme.
+Client/Server Modes +
    In these modes, a client sends a request to the server and expects +a reply at some future time. The client is configured in client mode using +the server (sic) command; the server requires no prior configuration. The +original NTPv3 authentication scheme is applicable in this mode, as well +as the new NTPv3 autokey scheme.
+Broadcast/Multicast Modes +
    In these modes, the server generates messages at intervals specified +by the minpoll subcommand. When using IP multicast addresses, the scope +of the multicast tree is specified by the ttl subcommand in hops. When +using a local interface broadcast address, the scope is limited to the +attached subnet. The client responds to the first message received by waiting +an interval randomized over the minpoll interval, in order to avoid implosions. +Then, it polls the server in burst mode, in order to accumulate data to +reliably set the host clock. This normally results in eight client/server +cycles over a 32-s interval. When the next multicast message is received, +the client computes the offset between the system clock just set and the +apparent time of the multicast message in order to correct the apparent +time in future multicast messages.
+Manycast Mode +
    In this mode, a configured client broadcasts a request message as in +client mode to a designated multicast group address. All servers configured +as manycast clients and in ttl range respond with a server reply message. +Each reply mobilizes a persistent client/server association as in client +mode. Then, the NTP intersection and clustering algorithms act to discard +all but the "best" of these associations, which then continue as in client/server +mode.
+ +

+Burst Mode

+Burst mode can be configured when the network attachment requires an initial +calling or training procedure. Each poll initiates a burst of eight request +messages at intervals randomized over the range 3-5 s. The reply messages +update the clock filter, which then selects the best (most accurate) among +them. When the last reply in the burst is sent, the next reply updates +the client variables and system clock in the usual manner, as if only a +single request/reply cycle had occurred. This mode does produce additional +network overhead and can cause trouble if used indiscriminately. It should +only be used where the poll interval is expected to settle to values above +1024 s. +

+Revised Error Checking

+It is very important to avoid spurious mobilizations from possibly broken +or rogue servers; in particular, to avoid denial-of-service attacks. In +order to resist such attacks, arriving messages that might mobilize ephemeral +associations are carefully screened using a series of eleven sanity checks. +
    +
  1. +Duplicate packet. This message is a duplicate of one previously received.
  2. + +
      +
  3. +Bogus packet. This message did not result from a message previously sent, +or messages have been received out of order.
  4. + +
      +
  5. +Unsynchronized. The server has not yet stored the previous timestamps.
  6. + +
      +
  7. +Invalid delay or dispersion. Either the delay or dispersion or both computed +from the message timestamps are above the normal range.
  8. + +
      +
  9. +Authentication failed. The sent MAC does not match the received MAC, either +due to the wrong key material or damaged message.
  10. + +
      +
  11. +Server unsynchronized. The server indicates unsynchronized in the leap +bits included in the packet.
  12. + +
      +
  13. +Server stratum check. The server is operating at a stratum above the normal +range.
  14. + +
      +
  15. +Delay/dispersion check. The related server packet data values are above +the normal range.
  16. + +
      +
  17. +Autokey failed. The hash of the current session key does not match the +most recent key identifiers used. (The hash is repeated four times, in +order to recover from lost packets whenever possible.)
  18. + +
      +
  19. +Access denied. The sender has been blocked by the access control list.
  20. + +
      +
  21. +Key not found. The key identifier does not match any identifier in the +key list or the key has expired or been revoked.
  22. +
+Failure to pass tests 5-11 is sufficient evidence to discard the packet +without forming an association. However, failure to pass tests 1-4 is not +necessarily grounds to reject the packet, since subsequent packets may +be acceptable. In this case, the association is mobilized, but only the +packet timestamps are stored. For the moment, and until the cryptographic +signature algorithm is available, test 9 is temporarily disabled. +
+
+
+David L. Mills (mills@udel.edu)
+ +
  + + diff --git a/contrib/ntp/html/authopt.htm b/contrib/ntp/html/authopt.htm new file mode 100644 index 000000000000..506d4f33e35e --- /dev/null +++ b/contrib/ntp/html/authopt.htm @@ -0,0 +1,281 @@ + +Authentication Options +

+Authentication Options +


+ +

Authentication Support

+ +Authentication support allows the NTP client to verify that the server +is in fact known and trusted and not an intruder intending accidentally +or on purpose to masquerade as that server. The NTPv3 specification RFC-1305 +defines an scheme which provides cryptographic authentication of received +NTP packets. Originally, this was done using the Data Encryption Standard +(DES) operating in Cipher Block Chaining (CBC) mode, commonly called DES-CBC. +Subsequently, this was augmented by the RSA Message Digest 5 (MD5) using +a private key, commonly called keyed-MD5. Either algorithm computes a message +digest, or one-way hash, which can be used to verify the server has the +correct private key and key identifier. NTPv4 retains this scheme and, +in addition, provides a new autokey scheme based on reverse hashing +and public key cryptography. Authentication can be configured separately +for each association using the key or autokey subcommands +on the peer, server, broadcast and manycastclient +commands as described in the  Configuration Options +page. + +

The authentication options specify the suite of keys, select the key +for each configured association and manage the configuration operations, +as described below. The auth flag which controls these functions +can be set or reset by the enable and disable configuration +commands and also by remote configuration commands sent by a ntpdc +program running in another machine. If this flag is set, persistent peer +associations and remote configuration commands are effective only if cryptographically +authenticated. If this flag is disabled, these operations are effective +even if not cryptographic authenticated. It should be understood that operating +in the latter mode invites a significant vulnerability where a rogue hacker +can seriously disrupt client operations. + +

The auth flag affects all authentication procedures described +below; however, it operates differently if cryptographic support is compiled +in the distribution. If this support is available and the flag is enabled, +then persistent associations are mobilized and remote configuration commands +are effective only if successfully authenticated. If the support is unavailable +and the flag is enabled, then it is not possible under any conditions to +mobilize persistent associations or respond to remote configuration commands. +The auth flag normally defaults to set if cryptographic support +is available and to reset otherwise. + +

With the above vulnerabilities in mind, it is desirable to set the auth +flag in all cases. One aspect which is often confusing is the name resolution +process which maps server names in the configuration file to IP addresses. +In order to protect against bogus name server messages, this process is +authenticated using an internally generated key which is normally invisible +to the user. However, if cryptographic support is unavailable and the auth +flag is enabled, the name resolution process will fail. This can be avoided +either by specifying IP addresses instead of host names, which is generally +inadvisable, or by leaving the flag disabled and enabling it once the name +resolution process is complete. +

+Private Key Scheme

+The original RFC-1305 specification allows any one of possibly 65,536 keys, +each distinguished a 32-bit key identifier, to authenticate an association. +The servers involved must agree on the key and key identifier to authenticate +their messages. Keys and related information are specified in a key file, +usually called ntp.keys, which should be exchanged and stored +using secure procedures beyond the scope of the NTP protocol itself. Besides +the keys used for ordinary NTP associations, additional ones can be used +as passwords for the ntpq and ntpdc +utility programs. + +

When ntpd is first started, it reads the key file and installs +the keys in the key cache. However, the keys must be activated before they +can be used with the trusted command. This allows, for instance, +the installation of possibly several batches of keys and then activating +or inactivating each batch remotely using ntpdc. This also provides +a revocation capability that can be used if a key becomes compromised. +The requestkey command selects the key used as the password for +the ntpdc utility, while the controlkey command selects +the key used as the password for the the ntpq utility. +

+Autokey Scheme

+The original NTPv3 authentication scheme described in RFC-1305 continues +to be supported. In NTPv4, an additional authentication scheme called autokey +is available. It operates much like the S-KEY scheme, in that a session +key list is constructed and the entries used in reverse order. A description +of the scheme, along with a comprehensive security analysis, is contained +in a technical report available from the IETF web page www.ietf.org +. + +

The autokey scheme is specifically designed for multicast modes, where +clients normally do not send messages to the server. In these modes, the +server uses the scheme to generate a key list by repeated hashing of a +secret value. The list is used in reverse order to generate a unique session +key for each message sent. The client regenerates the session key and verifies +the hash matches the previous session key. Each message contains the public +values binding the session key to the secret value, but these values need +to be verified only when the server generates a new key list or more than +four server messages have been lost. + +

The scheme is appropriate for client/server and symmetric-peer modes +as well. In these modes, the client generates a session key as in multicast +modes. The server regenerates the session key and uses it to formulates +a reply using its own public values. The client verifies the key identifier +of the reply matches the request, verifies the public values and validates +the message. In peer mode, each peer independently generates a key list +and operates as in the multicast mode. + +

The autokey scheme requires no change to the NTP packet header format +or message authentication code (MAC), which is appended to the header; +however, if autokey is in use, an extensions field is inserted between +the header and MAC. The extensions field contains a random public value +which is updated at intervals specified by the revoke command, together +with related cryptographic values used in the signing algorithm. The format +of the extensions field is defined in Internet Draft draft-NTP- auth-coexist-00.txt. +The MAC itself is constructed in the same way as NTPv3, but using the original +NTP header and the extensions field padded to a 64-bit boundary. Each new +public value is encrypted by the host private value. It is the intent of +the design, not yet finalized, that the public value, encrypted public +value, public key and certificate be embedded in the extensions field where +the client can decrypt as needed. However, the relatively expensive encryption +and decryption operations are necessary only when the public value is changed. + +

Note that both the original NTPv3 authentication scheme and the new +NTPv4 autokey scheme operate separately for each configured association, +so there may be several session key lists operating independently at the +same time. Since all keys, including session keys, occupy the same key +cache, provisions have been made to avoid collisions, where some random +roll happens to collide with another already generated. Since something +like four billion different session key identifiers are available, the +chances are small that this might happen. If it happens during generation, +the generator terminates the current session key list. By the time the +next list is generated, the collided key will probably have been expired +or revoked. + +

While permanent keys have lifetimes that expire only when manually revoked, +random session keys have a lifetime specified at the time of generation. +When generating a key list for an association, the lifetime of each key +is set to expire one poll interval later than it is scheduled to be used. +The maximum lifetime of any key in the list is specified by the autokey +command. Lifetime enforcement is a backup to the normal procedure that +revokes the last-used key at the time the next key on the key list is used. +

+Authentication Commands

+ +
+
+keys keyfile
+ +
+Specifies the file name containing the encryption keys and key identifiers +used by ntpd, ntpq and ntpdc when operating +in authenticated mode. The format of this file is described later in this +document.
+ +
+ +
+trustedkey key [...]
+ +
+Specifies the encryption key identifiers which are trusted for the purposes +of authenticating peers suitable for synchronization, as well as keys used +by the ntpq and ntpdc programs. The authentication procedures +require that both the local and remote servers share the same key and key +identifier for this purpose, although different keys can be used with different +servers. The key arguments are 32-bit unsigned integers +with values less than 65,536. Note that NTP key 0 is used to indicate an +invalid key and/or key identifier, so should not be used for any other +purpose.
+ +
+ +
+requestkey key
+ +
+Specifies the key identifier to use with the ntpdc program, which +uses a proprietary protocol specific to this implementation of ntpd. +This program is useful to diagnose and repair problems that affect ntpd +operation. The key argument to this command is a 32-bit +key identifier for a previously defined trusted key.  If no requestkey +command is included in the configuration file, or if the keys don't +match, any request to change a server variable with be denied.
+ +
+ +
+controlkey key
+ +
+Specifies the key identifier to use with the ntpq program, which +uses the standard protocol defined in RFC-1305. This program is useful +to diagnose and repair problems that affect ntpd operation. The +key argument to this command is a 32-bit key identifier +for a trusted key in the key cache. If no controlkey command is +included in the configuration file, or if the keys don't match, any request +to change a server variable with be denied.
+
+ +

+Authentication Key File Format

+In the case of DES, the keys are 56 bits long with, depending on type, +a parity check on each byte. In the case of MD5, the keys are 64 bits (8 +bytes). ntpd reads its keys from a file specified using the -k +command line option or the 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. + +

The key file uses the same comment conventions as the configuration +file. Key entries use a fixed format of the form + +

keyno type key + +

where keyno is a positive integer, type +is a single character which defines the key format, and key +is the key itself. + +

The key may be given in one of three different formats, controlled by +the type character. The three key types, and corresponding +formats, are listed following. +

+
+S
+ +
+The key is a 64-bit hexadecimal number in the format specified in the DES +specification; that is, the high order seven 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 0101010101010101.
+ +
+ +
+N
+ +
+The key 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 8080808080808080.
+ +
+ +
+A
+ +
+The key is a 1-to-8 character ASCII string. A key is formed from this by +using the low order 7 bits of each ASCII character in the string, with +zeroes 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.
+ +
+ +
+M
+ +
+The key 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.
+
+Note that the keys used by the ntpq and ntpdc programs +are checked against passwords requested by the programs and entered by +hand, so it is generally appropriate to specify these keys in ASCII format.  +
+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/biblio.htm b/contrib/ntp/html/biblio.htm new file mode 100644 index 000000000000..3396481bebcd --- /dev/null +++ b/contrib/ntp/html/biblio.htm @@ -0,0 +1,259 @@ + +Protocol Conformance Statement +

+Protocol Conformance Statement +

+
From The +Wizard of Oz, L. Frank Baum + +

Say it three times and it must be right. +
+


+ +

The Network Time Protocol (NTP) is used to synchronize the time of +a computer client or server to another server or reference time source, +such as a radio or satellite receiver or modem. It provides accuracies +typically within a millisecond on LANs up to a few tens of milliseconds +on WANs relative to Coordinated Universal Time (UTC), as provided by a +Global Positioning Service (GPS) receiver, for example. + +

Typical NTP configurations utilize multiple redundant servers and +diverse network paths, in order to achieve high accuracy and +reliability. Some configurations include cryptographic authentication to +prevent accidental or malicious protocol attacks. Information on the NTP +architecture, protocol and algorithms can be found in the following +articles and reports, which are available online. General issues of the +concepts and facilities assumed by NTP are discussed in tne Executive Summary - Computer Network Time +Synchronization page, while issues related to the NTP timescale and +pending century are discussed in the Network Time +Protocol Year 2000 Conformance Statement page, both of which are +included in this document. + +

Note that network timekeeping technology continues to advance and may +obsolete some of the following documents. For a current list of all +papers, reports, briefings and other documents relevant to the NTP +community, see the David L. +Mills web page. + +

The NTP architecture, protocol and algorithm models are described in + +

    + +
  • Mills, D.L. Internet time synchronization: the Network Time +Protocol. IEEE Trans. Communications COM-39, 10 (October 1991), +1482-1493. +PostScript | +PDF. Also in: Yang, Z., and T.A. Marsland (Eds.). Global States +and Time in Distributed Systems. IEEE Computer Society Press, Los +Alamitos, CA, 1994, 91-102. +
+ +The NTP specification and implementation has evolved over the last two +decades to the current Version 4 of the protocol. This version includes +significant enhancements in accuracy and reliability, as determined by +experience in an estimated total of well over 100,000 clients and +servers in the Internet, while retaining backward compatibility with +previous versions. + +

This software distribution contains an implementation of the NTP +Version 4 architecture, protocol and algorithms. While a formal +specification of this version is not yet available, this version is +fully compliant with the previous NTP Version 3 specification and +implementation defined in +

    + +
  • Mills, D.L. Network Time Protocol (Version 3) specification, +implementation and analysis. Network Working Group Report RFC-1305, +University of Delaware, March 1992, 113 pp. Abstract: +PostScript) | +PDF, Body: +PostScript) | +PDF, Appendices: +PostScript | +PDF. + +
+ +The NTP Version 4 implementation adds a number of extensions and +refinements to the previous version, including an autonomous +configuration and authentication capability, improved clock discipline +algorithms capable of submicrosecond accuracy and many other +refinements. Specific changes since the Version 3 specification was +issued include: + +
    + +

  1. Support for precision-time kernel modifications, as described +in
  2. + +

    Mills, D.L. Unix kernel modifications for precision time +synchronization. Electrical Engineering Department Report 94-10-1, +University of Delaware, October 1994, 24 pp. Abstract: +PostScript | +PDF, Body: +PostScript | +PDF. Major revision and update of: Network Working Group Report +RFC-1589, University of Delaware, March 1994. 31 pp. ASCII + +

  3. Support for IP Multicasting, as described in
  4. + +

    Mills, D.L, and A. Thyagarajan. Network time protocol version 4 +proposed changes. Electrical Engineering Department Report 94-10-2, +University of Delaware, October 1994, 32 pp. Abstract: +PostScript | +PDF, Body: +PostScript | +PDF + +

  5. A new hybrid phase/frequency-lock clock discipline, which +replaces the RFC-1305 local clock algorithm, as described in
  6. + + +

    Mills, D.L. Clock discipline algorithms for the Network Time Protocol +Version 4. Electrical Engineering Report 97-3-3, University of Delaware, +March 1997, 35 pp. Abstract: +PostScript | +PDF, Body: +PostScript | +PDF + +

    Mills, D.L. Improved algorithms for synchronizing computer network +clocks. IEEE/ACM Trans. Networks 3, 3 (June 1995), 245-254. +PostScript | +PDF + +

  7. Engineered refinements to radio clock drivers and interface code, +as describedin:
  8. + +

    Mills, D.L. Precision synchronization of computer network clocks. +ACM Computer Communication Review 24, 2 (April 1994). 28-43. +PostScript | +PDF + +

  9. Support for over two dozen reference clock drivers for all known +national and international radio, satellite and modem standard time +services known at this time. See the Reference +Clock Drivers page.
  10. + +

  11. A new security model and authentication scheme based on public- +key cryptography called autokey, as described in
  12. + +

    Mills, D.L., T.S. Glassey, and M.E. McNeil. Coexistence and +interoperability of NTP authentication schemes. Internet Draft +draft-mills-ntp-auth-coexist-00.txt, University of Delaware and Coastek +InfoSys, Inc., November 1997, 8 pp. ASCII + +

    Mills, D.L. Authentication scheme for distributed, ubiquitous, real- +time protocols. Proc. Advanced Telecommunications/Information +Distribution Research Program (ATIRP) Conference (College Park MD, +January 1997), 293-298. +PostScript | +PDF + +

    Mills, D.L. Proposed authentication enhancements for the Network Time +Protocol version 4. Electrical Engineering Report 96-10-3, University of +Delaware, October 1996, 36 pp. Abstract: +PostScript | +PDF, Body: +PostScript | +PDF + +

  13. Support for the MD5 cryptographic hash algorithm, in addition to +the DES-CBC algorithm described in RFC-1305, as described in the ntpd - Network Time Protocol (NTP) daemon +page.
  14. + +

  15. The prefer-peer scheme, as described in the Mitigation Rules and the prefer Keyword +page.
  16. + +

  17. Specification for the Simple Network Time Protocol (SNTP), as +described in
  18. + +

    Mills, D.L. Simple network time protocol (SNTP) version 4 for IPv4, +IPv6 and OSI. Network Working Group Report RFC-2030, University of +Delaware, October 1996, 18 pp. +ASCII. Obsoletes RFC-1769 and RFC-1361. + +

  19. Performance surveys for NTP Version 4 can be found in
  20. + +

  21. Mills, D.L., A. Thyagarajan and B.C. Huffman. Internet +timekeeping around the globe. Proc. Precision Time and Time Interval +(PTTI) Applications and Planning Meeting (Long Beach CA, December +1997), 365-371. Paper: +PostScript | +PDF, Slides: +HTML | +PostScript | +PowerPoint | +PDF
  22. + +

  23. Mills, D.L. The network computer as precision timekeeper. +Proc. Precision Time and Time Interval (PTTI) Applications and +Planning Meeting (Reston VA, December 1996), 96-108. Paper: +PostScript | +PDF, Slides: +HTML | +PostScript | +PowerPoint | +PDF
  24. + +
+ +
David L. Mills <mills@udel.edu> +
diff --git a/contrib/ntp/html/build.htm b/contrib/ntp/html/build.htm new file mode 100644 index 000000000000..c321bf35a8c6 --- /dev/null +++ b/contrib/ntp/html/build.htm @@ -0,0 +1,206 @@ + +Building and Installing the Distribution +

+Building and Installing the Distribution +

+ +From pogo, Walt Kelly + +

For putting out compiler fires. +


+ +

Building and Installing the Distribution

+ +As a practical matter, every computer architecture and operating system +version seems to be different than any other. The device drivers may be +different, the input/output system may bew idiosyncratic and the +libraries may have different semantics. It is not possible in a software +distribution such as this one to support every individual sysdtem with a +common set of binaries, even with the same system but different +versions. Therefore, it is necessary to configure each system +individually for each system and version, both at compile time and at +run time. In almost all cases, these procedures are completely automatic +and all the newbie user need do is type "make" and the autoconfigure +system does the rest. There are some exceptions, as noted below. + +

The autoconfigure system inspects the hardware and software +environment and tests for the presence of system header files and the +contents of these files to determine if certain features are available. +When one or more of these features are present, the code is compiled to +use them; if not, no special code is compiled. However, even if the code +is compiled to use these features, the code does a special test at run +time to see if one or more are actually present and avoids using them if +not present. In such cases a warning message is sent to the system log, +but the daemon should still work properly. + +Some programs included in this distribution use cryptographic algorithms +to verify server authenticity and credentials. As required by the +International Trade in Arms Regulations (ITAR), now called the Defense +Trade Regulations (DTR), certain cryptographic products and media, +including the Data Encryption Standard (DES), cannot be exported without +per-instance license. For this reason, the DES encryption routine has +been removed from the the current version, even though it is used only +to compute a message digest. Current DTR regulations allow export of the +the MD5 message digest routine, which is in fact the preferred +algorithm, and this is included in the current +version. + +

The NTP authentication routines conform to the interface used by RSA +Laboratories in the rsaref20.zip package, which is downloadable +from ftp.rsa.com or via the web at www.rsa.com. +Outside the U.S. and Canada, the functionally identical +rsaeuro.zip package is available from J.S.A. Kapp and other +sources. The recommended way to integrate the DES routines in either +package with the NTP build procedures is to copy the desc.c +file from the ./source directory in the package to the +./libntp directory in the distribution. Then copy the header +files rsaref.h, des.h and md2.h in the +./source directory to the ./include directory. Do not +copy the global.h header file; the one in the distribution has +been modified. These steps must be completed before the configuration +process described below. + +

Building and Installing under Unix

+ +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 modern Unix versions (compilers are likely to be an +add-on product - consider using the GNU tools and gcc +compiler in this case). For a successful build, all of these tools +should be accessible via the current path. + +

Configuration

+ +Use the ./configure command to perform an automatic +configuration procedure. This procedure normally includes the debugging +code, which can be useful in diagnosing problems found in initial test, +and all reference clock drivers known to work with each machine and +operating system. Unless memory space is at a premium, this is a +sensible strategy and saves lots of messy fiddling. If you need to +delete either the debugging code or one or more or all reference clock +drivers to save space, see the Configuration +Options page. + +

If your site supports multiple architectures and uses NFS to share +files, you can use a single source tree to compile executables for all +architectures. While running on a target architecture machine and with +the distribution base directory active, create a subdirectory using a +command like mkdir A.`config.guess`, which will create an +architecture-specific directory with name peculiar to the architecture +and operating system. Then change to this directory and configure with +the ../configure command. The remaining steps are the same +whether building in the base directory or in the subdirectory. + +

Compilation

+ +Peruse the operating-system-specific information for your architecture +under Hints and Kinks. + +

Use the make command to compile all source modules, +construct the libraries and link the distribution. 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 +inconsistencies, especially about pointer variables. This is usually the +case when the system header files are not up to ANSI standards or +gcc-isms, when gcc is not installed properly, or when operating +system updates and patches are applied and gcc is not reinstalled. While +the autoconfigure process is quite thorough, the Unix programming +cultures of the various workstation makers still remain idiosyncratic. + +

Installation

+ +As root, use the make install command to install the binaries +in the destination directory. You must of course have write permission +on the install destination directory. This includes the programs ntpd (the daemon), ntpdc (an ntpd-dependent query +program), ntpq (a standard query +program), ntpdate (an rdate +replacement for boot time date setting and sloppy time keeping) and +ntptrace (a utility useful to find +the primary (stratum-1) servers). In some systems, the tickadj (a utility useful to adjust kernel +variables) is installed. If the precision time kernel modifications are +present, the ntptime (a utility +useful to debug kernel time functions) is installed. + +

You are now ready to configure the daemon and start it. You will need +to create a NTP configuration file ntp.conf and possibly a +cryptographic key file ntp.keys. Directions for doing that are +in the Notes on Configuring NTP and Setting up a NTP +Subnet. The behavior when the daemon starts for the first time can +be counterintuitive. To reduce the level of angst, see the Quick Start page. A tutorial on debugging technique +is in NTP Debugging Technique. + +

If problems peculiar to the particular hardware and software +environment (e.g. operating system -specific issues) are suspected, +browse the Hints and Kinks page. + +

Bug reports of a general nature can be sent to David Mills <mills@udel.edu>. Bug reports of a +specific nature on features implemented by the programmer corps +mentioned in the Copyright page should be +sent directly to the implementor listed in that page, with copy to +mills@udel.edu. + +

Please include the version of the source distribution (e.g., ntp- +4.0.70a) in your bug report. + +

Please include the output of config.guess in your +bug report. + +

It will look something like: pdp11-dec-fuzzos3.4 + +

Additional make commands + +

+ +
make clean
+ +
Cleans out object files, programs and temporary files.
+ +
make distclean
+ +
Does the work of clean, but cleans out all directories in +preparation for a new distribution release.
+ +
make dist
+ +
+Does the work of make distclean, but constructs compressed tar +files for distribution. You must have GNU automake to perform this +function.
+ +
+ +

Building and Installing under Windows NT

+ +Under Windows NT, you will need Visual C++ 5.0 or above, +InstallShield SDK, Perl5 and some version of the +archiving program ZIP. Note that the version of +InstallShield that comes with VC++5.0 is not useable here, +since it does not include the command line tools. + +

See the ./scripts/wininstall/readme.nt file for directions +to compile the sources, build the libraries and link the executables. +Initiate the build by running either bldrel.bat or +blddbg.bat to compile all of the source and create an +InstallShield based graphical installation package. + +

To install the executables, make sure that you are logged in as a +system account, or one with administrator privileges such as the +"administrator" account. As part of the build an InstallShield +based graphical installer was created. Run +\ntp\scripts\wininstall\intel\disk1\setup.exe to begin the +installation. This installer will prompt for basic defaults, +copy the binaries, install the service, and start it up. The other +option is to run \ntp\scripts\wininstall\distrib\install.bat +which will do the basic installation from the command line. + +


David L. +Mills <mills@udel.edu> +
diff --git a/contrib/ntp/html/clockopt.htm b/contrib/ntp/html/clockopt.htm new file mode 100644 index 000000000000..b128b42e8f21 --- /dev/null +++ b/contrib/ntp/html/clockopt.htm @@ -0,0 +1,193 @@ + +Reference Clock Options +

+Reference Clock Options +


+ +

Reference Clock Support

+ +The NTP Version 4 daemon supports many different radio, satellite and +modem reference clocks plus a special pseudo-clock used for backup or +when no other clock source is available. Detailed descriptions of +individual device drivers and options can be found in the Reference Clock Drivers page. Additional +information can be found in the pages referenced there, including the Debugging Hints for Reference Clock Drivers and How To Write a Reference Clock Driver pages. In +many drivers, support for a PPS signal is available as described in Pulse-per-second (PPS) Signal Interfacing page. Many +drivers support special line discipline/streams modules which can +significantly improve the accuracy using the driver. These are described +in the Line Disciplines and Streams Drivers +page. + +

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 and USNO in +the U.S. The interface between the computer and the timecode receiver is +device dependent, but is usually a serial port. A device driver specific +to each reference clock must be selected and compiled in the +distribution; however, most common radio, satellite and modem clocks are +included by default. Note that an attempt to configure a reference clock +when the driver has not been included or the hardware port has not been +appropriately configured results in a scalding remark to the system log +file, but is otherwise non hazardous. + +

For the purposes of configuration, ntpd treats reference +clocks in a manner analogous to normal NTP peers as much as possible. +Reference clocks are identified by a syntactically correct but invalid +IP address, in order to distinguish them from normal NTP peers. +Reference clock addresses are of the form 127.127.t.u, +where t is an integer denoting the clock type and +u indicates the unit number. While it may seem overkill, +it is in fact sometimes useful to configure multiple reference clocks of +the same type, in which case the unit numbers  must be unique. + +

The server command is used to configure a reference clock, +where the address argument in that command is the clock +address. The key, version and ttl options are +not used for reference clock support. The mode option is added +for reference clock support, as described below. The prefer +option can be useful to persuade the server to cherish a reference clock +with somewhat more enthusiasm than other reference clocks or peers. +Further information on this option can be found in the Mitigation Rules and the prefer Keyword +page. The minpoll and maxpoll options have meaning +only for selected clock drivers. See the individual clock driver +document pages for additional information. + +

The stratum number of a reference clock is by default zero. Since the +ntpd daemon adds one to the stratum of each peer, a primary +server ordinarily displays stratum one. In order to provide engineered +backups, it is often useful to specify the reference clock stratum as +greater than zero. The stratum option is used for this purpose. +Also, in cases involving both a reference clock and a pulse-per-second +(PPS) discipline signal, it is useful to specify the reference clock +identifier as other than the default, depending on the driver. The +refid option is used for this purpose. Except where noted, +these options apply to all clock drivers. + +

Reference Clock Commands

+ +
server 127.127.t.u [prefer] [mode int] +[minpoll int] [maxpoll int]
+
This command can be used to configure reference clocks in special +ways. The options are interpreted as follows:
+ +
prefer
+
Marks the reference clock as preferred. All other things being +equal, this host will be chosen for synchronization among a set of +correctly operating hosts. See the Mitigation Rules +and the prefer Keyword page for further information.
+ +
mode int
+
Specifies a mode number which is interpreted in a device-specific +fashion. For instance, it selects a dialing protocol in the ACTS driver +and a device subtype in the parse drivers.
+ +
minpoll int
+
maxpoll int
+
These options specify the minimum and maximum polling interval for +reference clock messages, in seconds to the power of two. For most +directly connected reference clocks, both minpoll and +maxpoll default to 6 (64 s). For modem reference clocks, +minpoll defaults to 10 (17.1 m) and maxpoll defaults +to 14 (4.5 h). The allowable range is 4 (16 s) to 17 (36.4 h) +inclusive.
+ +
+ +
fudge 127.127.t.u [time1 sec] [time2 sec] +[stratum int] [refid string] [mode int] [flag1 0|1] +[flag2 0|1] [flag3 0|1] [flag4 0|1]
+
This command can be used to configure reference clocks in special +ways. It must immediately follow the server command which +configures the driver. Note that the same capability is possible at run +time using the ntpdc program. The +options are interpreted as follows:
+ +
+ +
time1 sec
+
Specifies a constant to be added to the time offset produced by the +driver, a fixed-point decimal number in seconds. This is used as a +calibration constant to adjust the nominal time offset of a particular +clock to agree with an external standard, such as a precision PPS +signal. It also provides a way to correct a systematic error or bias due +to serial port latencies, different cable lengths or receiver internal +delay. The specified offset is in addition to the propagation delay +provided by other means, such as internal DIPswitches. Where a +calibration for an individual system and driver is available, an +approximate correction is noted in the driver documentation pages.
+ +
time2 secs
+
Specifies a fixed-point decimal number in seconds, which is +interpreted in a driver-dependent way. See the descriptions of specific +drivers in the reference clock drivers +page.
+ +
stratum int
+
Specifies the stratum number assigned to the driver, an integer +between 0 and 15. This number overrides the default stratum number +ordinarily assigned by the driver itself, usually zero.
+ +
refid string
+
Specifies an ASCII string of from one to four characters which +defines the reference identifier used by the driver. This string +overrides the default identifier ordinarily assigned by the driver +itself.
+ +
mode int
+
Specifies a mode number which is interpreted in a device-specific +fashion. For instance, it selects a dialing protocol in the ACTS driver +and a device subtype in the parse drivers.
+ +
flag1 flag2 flag3 flag4
+
These four flags are used for customizing the clock driver. The +interpretation of these values, and whether they are used at all, is a +function of the particular clock driver. However, by convention +flag4 is used to enable recording monitoring data to the +clockstats file configured with the filegen command. +When a PPS signal is available, a special automatic calibration facility +is provided. If the flag1 switch is set and the PPS signal is +actively disciplining the system time, the calibration value is +automatically adjusted to maintain a residual offset of zero. Further +information on the filegen command can be found in the Monitoring Options page.
+ +
+ +
pps device [assert|clear] [hardpps]
+
Specifies the name and options for the serial port device to which +the PPS signal is connected. Note, this command replaces use of +fudge flag3, which was used for the same purpose in NTPv3. Note +that this command should preceed the server and fudge +command for the same device. Note also that the assert, +clear and hardpps options are only available if the +ppsapi standard PPS interface is available.
+ +
+ +
device
+
Specify the device name associated with the PPS signal. The name +must match exactly the link name specified in the driver documentation +page.
+ +
assert
+
clear
+
Using assert or clear specifies if the high going +or low going edge of the signal must be used. The default is +assert.
+ +
hardpps
+
This flag is used to tell the kernel that the signal from this +device must be used to drive hardpps().
+ +
The assert, clear and hardpps options +are only available if the PPSAPI is used.
+ +
+ +
David L. Mills <mills@udel.edu> +
diff --git a/contrib/ntp/html/config.htm b/contrib/ntp/html/config.htm new file mode 100644 index 000000000000..f8606f2fc8b7 --- /dev/null +++ b/contrib/ntp/html/config.htm @@ -0,0 +1,291 @@ + +Configuration Options +

+Configuration Options +

+ +From pogo, Walt Kelly +

+ +

Basic Configuration Options - the configure utility

+ +The following options are for compiling and installing a working version +of the NTP distribution. In most cases, the build process is completely +automatic. In some cases where memory space is at a premium, or the +binaries are to be installed in a different place, it is possible to +tailor the configuration to remove such features as reference clock +driver support, debugging support, and so forth. + +

Configuration options are specified as arguments to the +configure script. Following is a summary of the current +options: + +

Usage: configure [options] [host] +
Options: [defaults in brackets after descriptions] +

Configuration
+
+  --cache-file=FILE      cache test
+results in FILE
+  --
+help           &n
+bsp;     print this message
+  --no-
+create           
+do not create output files
+  --quiet, --silent      do not print
+`checking...' messages
+  --
+version           
+;   print the version of autoconf that created
+            
+            
+configure
+Directory and file names
+
+  --prefix=PREFIX        install
+architecture-independent files in
+            
+            
+PREFIX [/usr/local]
+  --exec-prefix=EPREFIX  install architecture-dependent files
+in EPREFIX
+            
+            
+[same as prefix]
+  --
+bindir=DIR          
+user executables in DIR [EPREFIX/bin]
+  --
+sbindir=DIR          system
+admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR       program
+executables in DIR [EPREFIX/libexec]
+  --
+datadir=DIR          read-
+only architecture-independent data in DIR
+            
+            
+[PREFIX/share]
+  --sysconfdir=DIR       read-only
+single-machine data in DIR
+            
+            
+[PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-
+independent data in DIR
+            
+            
+[PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine
+data in DIR
+            
+            
+[PREFIX/var]
+  --
+libdir=DIR          
+object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR       C header
+files in DIR [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc
+in DIR
+            
+            
+[/usr/include]
+  --
+infodir=DIR          info
+documentation in DIR [PREFIX/info]
+  --
+mandir=DIR          
+man documentation in DIR [PREFIX/man]
+  --
+srcdir=DIR          
+find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM run sed PROGRAM on installed
+program
+            
+            
+names
+Host type
+
+  --
+build=BUILD         
+configure for building on BUILD [BUILD=HOST]
+  --
+host=HOST          &nb
+sp; configure for HOST [guessed]
+  --target=TARGET       
+configure for TARGET [TARGET=HOST]
+ +
Features and packages
+
+  --disable-FEATURE      do not include
+FEATURE (same as --enable-
+            
+            
+FEATURE=no)
+  --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]   use PACKAGE [ARG=yes]
+  --without-PACKAGE      do not use
+PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR       X include
+files are in DIR
+  --x-libraries=DIR      X library files
+are in DIR
+
+--enable- and --disable- with options recognized
+
+    
+debugging          
+Include debugging code [enable]
+     gdt-
+surveying       Include GDT survey code
+[disable]
+    
+md5           &nb
+sp;     Include support for MD5 keys [enable]
+    
+des           &nb
+sp;     Include support for DES keys [enable]
+     all-
+clocks          Include
+drivers for all reference clocks
+            
+            
+[enable]
+
+  Radio Clocks (these are ordinarily enabled, if supported by the
+            
+            
+machine and operating system)
+
+    
+ACTS           &n
+bsp;    NIST dialup clock
+    
+ARBITER           
+;  Arbiter 1088A/B GPS receiver
+    
+AS2201           
+   Austron 2200A or 2201A GPS receiver
+    
+ATOM           &n
+bsp;    ATOM clock
+    
+BANCOMM           
+;  BANCOMM clock
+    
+CHU           &nb
+sp;     CHU clock
+    
+DATUM           &
+nbsp;   Datum Programmable Time System
+    
+DCF7000           
+;  ELV/DCF7000
+    
+GPSVME           
+   GPS-VME Clock
+    
+HEATH           &
+nbsp;   HeathKit GC-1000 Most Accurate Clock
+    
+HOPF6021          &nbs
+p; HOPF6021 Radio Clock support
+    
+HPGPS           &
+nbsp;   HP 58503A GPS Time & Frequency receiver
+    
+IRIG           &n
+bsp;    IRIG (Audio) Clock
+    
+LEITCH           
+   Leitch CSD 5300 Master Clock System Driver
+     LOCAL-
+CLOCK         Local Clock driver
+    
+MEINBERG          &nbs
+p; Meinberg clocks
+    
+MSFEES           
+   MSFEES clock
+    
+MOTO           &n
+bsp;    Motorola GPS clock
+    
+MX4200           
+   MX4200 clock
+    
+NMEA           &n
+bsp;    NMEA GPS clock
+    
+PARSE           &
+nbsp;   PARSE clock code
+    
+PST           &nb
+sp;     PST/Traconex 1020 WWV/H receiver
+    
+PTBACTS           
+;  PTB dialup clock support
+    
+RAWDCF           
+   use raw DCF77 time code
+    
+RCC8000           
+;  RCC8000 Radio Clock support
+    
+SCHMID           
+   SCHMID DCF77 clock support
+    
+TRAK           &n
+bsp;    TRAK 8810 GPS station clock
+    
+TPRO           &n
+bsp;    KSI/Odetics TPRO/S IRIG Interface
+    
+TRIMTAIP          &nbs
+p; Trimble GPS/TAIP Protocol
+    
+TRIMTSIP          &nbs
+p; Trimble GPS/TSIP Protocol
+    
+TRUETIME          &nbs
+p; Kinemetrics/TrueTime (generic) receiver
+    
+WWVB           &n
+bsp;    Spectracom 8170 or Netclock/2 WWVB receiver
+    
+USNO           &n
+bsp;    US Naval Observatory dialup clock
+  Miscellany
+
+     accurate-adjtime    The
+adjtime() call is accurate
+    
+kmem           &n
+bsp;    Read kmem
+    
+tick=VALUE          Force a
+value for 'tick'
+    
+tickadj=VALUE       Force a value for
+'tickadj'
+     udp-
+wildcard        Use UDP wildcard
+delivery
+     slew-
+always         Always slew the
+time
+     step-
+slew           Step
+and slew the time
+     ntpdate-
+step        If ntpdate should step
+the time
+     hourly-todr-sync    If we should
+sync TODR hourly
+ +
David L. Mills <mills@udel.edu> +
diff --git a/contrib/ntp/html/confopt.htm b/contrib/ntp/html/confopt.htm new file mode 100644 index 000000000000..68ddf7fa30e8 --- /dev/null +++ b/contrib/ntp/html/confopt.htm @@ -0,0 +1,330 @@ + +Configuration Options +

+Configuration Options +


+ +

Configuration Support

+ +

Following is a description of the configuration commands in +NTPv4. These commands have the same basic functions as in NTPv3 +and in some cases new functions and new operands. The various +modes are determined by the command keyword and the type of the +required IP address. Addresses are classed by type as (s) a +remote server or peer (IP class A, B and C), (b) the broadcast +address of a local interface, (m) a multicast address (IP class +D), or (r) a reference clock address (127.127.x.x). Note that, +while autokey and burst modes are supported by these commands, +their effect in some weird mode combinations can be meaningless +or even destructive.

+ +
+
peer address [autokey | key key] + [burst] [version version] + [prefer] [minpoll minpoll] + [maxpoll maxpoll]
+
 
+
server address [autokey | + key key] [burst] [version version] + [prefer] [minpoll minpoll] + [maxpoll maxpoll]
+
 
+
broadcast address [autokey | + key key] [burst] [version version] + [minpoll minpoll] [maxpoll + maxpoll] [ttl ttl]
+
 
+
manycastclient address + [autokey | key key] [burst] + [version version] [minpoll minpoll + [maxpoll maxpoll] + [ttl ttl]
+
 
+
These four commands specify the time server name or + address to be used and the mode in which to operate. The address + can be either a DNS name or a IP address in + dotted-quad notation. Additional information on + association behavior can be found in the Association Management page.
+
 
+
+
server
+
For type s and r addresses, this operates as the + NTPv3 server command, which mobilizes a + persistent client mode association. The server + command specifies that the local server is to + operate in client mode with the specified remote + server. In this mode, the local server can be + synchronized to the remote server, but the remote + server can never be synchronized to the local + server.
+
 
+
peer
+
For type s addresses (only), this operates as the + current peer command, which mobilizes a + persistent symmetric-active mode association, + except that additional modes are available. This + command should NOT be used for type b, m or r + addresses.
+
 
+
The peer command specifies that the + local server is to operate in symmetric active + mode with the remote server. In this mode, the + local server can be synchronized to the remote + server and, in addition, the remote server can be + synchronized by the local server. This is useful + in a network of servers where, depending on + various failure scenarios, either the local or + remote server may be the better source of time.
+
 
+
broadcast
+
For type b and m addresses (only), this is + operates as the current NTPv3 broadcast command, + which mobilizes a persistent broadcast mode + association, except that additional modes are + available. Multiple commands can be used to + specify multiple local broadcast interfaces + (subnets) and/or multiple multicast groups. Note + that local broadcast messages go only to the + interface associated with the subnet specified, + but multicast messages go to all interfaces. In + the current implementation, the source address + used for these messages is the Unix host default + address.
+
 
+
In broadcast mode, the local server sends + periodic broadcast messages to a client + population at the address specified, + which is usually the broadcast address on (one + of) the local network(s) or a multicast address + assigned to NTP. The IANA has assigned the + multicast group address 224.0.1.1 exclusively to + NTP, but other nonconflicting addresses can be + used to contain the messages within + administrative boundaries.. Ordinarily, this + specification applies only to the local server + operating as a sender; for operation as a + broadcast client, see the broadcastclient + or multicastclient commands below.
+
 
+
manycastclient
+
For type m addresses (only), this mobilizes a + manycast client-mode association for the + multicast address specified. In this case a + specific address must be supplied which matches + the address used on the manycastserver command + for the designated manycast servers. The NTP + multicast address 224.0.1.1 assigned by the IANA + should NOT be used, unless specific means are + taken to avoid spraying large areas of the + Internet with these messages and causing a + possibly massive implosion of replies at the + sender.
+
 
+
The manycast command specifies that the + local server is to operate in client mode with + the remote server that are discovered as the + result of broadcast/multicast messages. The + client broadcasts a request message to the group + address associated with the specified address + and specifically enabled servers respond + to these messages. The client selects the servers + providing the best time and continues as with the + server command. The remaining servers + are discarded as if never heard.
+
 
+
+
+
Options
+
 
+
+
autokey
+
All packets sent to the address are to include + authentication fields encrypted using the autokey + scheme.
+
 
+
burst
+
At each poll interval, send a burst of eight + packets spaced, instead of the usual one.
+
 
+
key key
+
All packets sent to the address are to include + authentication fields encrypted using the + specified key identifier, which is an + unsigned 32-bit integer less than 65536. The + default is to include no encryption field.
+
 
+
version version
+
Specifies the version number to be used for + outgoing NTP packets. Versions 1-4 are the + choices, with version 4 the default.
+
 
+
prefer
+
Marks the server as preferred. All other things + being equal, this host will be chosen for + synchronization among a set of correctly + operating hosts. See the Mitigation + Rules and the prefer Keyword page + for further information.
+
 
+
ttl ttl
+
This option is used only with broadcast mode. It + specifies the time-to-live ttl to + use on multicast packets. Selection of the proper + value, which defaults to 127, is something of a + black art and must be coordinated with the + network administrator.
+
 
+
minpoll minpoll
+
maxpoll maxpoll
+
These options specify the minimum and maximum + polling intervals for NTP messages, in seconds to + the power of two. The default range is 6 (64 s) + to 10 (1,024 s).The allowable range is 4 (16 s) + to 17 (36.4 h) inclusive.
+
 
+
+
+
broadcastclient
+
This command directs the local server to listen for and + respond to broadcast messages received on any local + interface. Upon hearing a broadcast message for the first + time, the local server measures the nominal network delay + using a brief client/server exchange with the remote + server, then enters the broadcastclient mode, in which it + listens for and synchronizes to succeeding broadcast + messages. Note that, in order to avoid accidental or + malicious disruption in this mode, both the local and + remote servers should operate using authentication and + the same trusted key and key identifier.
+
 
+
multicastclient [address] + [...]
+
This command directs the local server to listen for + multicast messages at the group address(es) of the global + network. The default address is that assigned by the + Numbers Czar to NTP (224.0.1.1). This command operates in + the same way as the broadcastclient command, but + uses IP multicasting. Support for this command requires a + multicast kernel.
+
 
+
driftfile driftfile
+
This command specifies the name of the file used to + record the frequency offset of the local clock + oscillator. If the file exists, it is read at startup in + order to set the initial frequency offset and then + updated once per hour with the current frequency offset + computed by the daemon. If the file does not exist or + this command is not given, the initial frequency offset + is assumed zero. In this case, it may take some hours for + the frequency to stabilize and the residual timing errors + to subside.
+
 
+
The file format consists of a single line containing a + single floating point number, which records the frequency + offset measured in parts-per-million (PPM). The file is + updated by first writing the current drift value into a + temporary file and then renaming this file to replace the + old version. This implies that ntpd must have + write permission for the directory the drift file is + located in, and that file system links, symbolic or + otherwise, should be avoided.
+
 
+
manycastserver address [...]
+
This command directs the local server to listen for and + respond to broadcast messages received on any local + interface, and in addition enables the server to respond + to client mode messages to the multicast group + address(es) (type m) specified. At least one address is + required, but The NTP multicast address 224.0.1.1 + assigned by the IANA should NOT be used, unless specific + means are taken to limit the span of the reply and avoid + a possibly massive implosion at the original sender.
+
 
+
revoke [logsec]
+
Specifies the interval between recomputations of the + private value used with the autokey feature, which + ordinarily requires an expensive public- key computation. + The default value is 12 (65,536 s or about 18 hours). For + poll intervals above the specified interval, a new + private value will be recomputed for every message sent.
+
 
+
autokey [logsec]
+
Specifies the interval between regenerations of the + session key list used with the autokey feature. Note that + the size of the key list for each association depends on + this interval and the current poll interval. The default + value is 12 (4096 s or about 1.1 hours). For poll + intervals above the specified interval, a session key + list with a single entry will be regenerated for every + message sent.
+
 
+
enable [auth | bclient | kernel | monitor | ntp | + stats]
+
disable [auth | bclient | kernel | monitor | ntp | + stats]
+
Provides a way to enable or disable various server + options. Flags not mentioned are unaffected. Note that + all of these flags can be controlled remotely using the ntpdc utility program.
+
 
+
+
auth
+
Enables the server to synchronize with + unconfigured peers only if the peer has been + correctly authenticated using a trusted key and + key identifier. The default for this flag is + enable.
+
 
+
bclient
+
When enabled, this is identical to the broadcastclient + command. The default for this flag is disable.
+
 
+
kernel
+
Enables the precision-time kernel support for the + ntp_adjtime() system call, if + implemented. Ordinarily, support for this routine + is detected automatically when the NTP daemon is + compiled, so it is not necessary for the user to + worry about this flag. It flag is provided + primarily so that this support can be disabled + during kernel development.
+
 
+
monitor
+
Enables the monitoring facility. See the ntpdc + program and the monlist command or + further information. The default for this flag is + enable.
+
 
+
ntp
+
Enables the server to adjust its local clock by + means of NTP. If disabled, the local clock + free-runs at its intrinsic time and frequency + offset. This flag is useful in case the local + clock is controlled by some other device or + protocol and NTP is used only to provide + synchronization to other clients. In this case, + the local clock driver can be used to provide + this function and also certain time variables for + error estimates and leap-indicators. See the Reference Clock Drivers page + for further information. The default for this + flag is enable.
+
 
+
stats
+
Enables the statistics facility. See the Monitoring Options page for + further information. The default for this flag is + enable.
+
 
+
+
+
+ +
+ +
+ David L. Mills (mills@udel.edu) +
+ + diff --git a/contrib/ntp/html/copyright.htm b/contrib/ntp/html/copyright.htm new file mode 100644 index 000000000000..d5d8243d94a5 --- /dev/null +++ b/contrib/ntp/html/copyright.htm @@ -0,0 +1,123 @@ + +Copyright Notice +

+Copyright Notice +

+ +"Clone +me," says Dolly sheepishly +

+ +

The following copyright notice applies to all files collectively called the Network Time Protocol Version 4 Distribution. Unless specifically declared otherwise in an individual file, this notice applies as if the text was explicitly included in the file. +
+ +

/***********************************************************************
+ *                                                                     *
+ * Copyright (c) David L. Mills 1992-1999                              *
+ *                                                                     *
+ * 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.                                                           *
+ **********************************************************************/
+ +The following individuals contributed in part to the Network Time Protocol Distribution Version 4 and are acknowledged as authors of this work. + +
    + +
  1. Mark Andrews <marka@syd.dms.csiro.au> Leitch atomic clock controller
  2. + +
  3. Viraj Bais <vbais@mailman1.intel.com> and Clayton Kirkwood <kirkwood@striderfm.intel.com> port to WindowsNT 3.5
  4. + +
  5. Karl Berry <karl@owl.HQ.ileaf.com> syslog to file option
  6. + +
  7. Piete Brooks <Piete.Brooks@cl.cam.ac.uk> MSF clock driver, Trimble PARSE support
  8. + +
  9. Steve Clift <clift@ml.csiro.au> OMEGA clock driver
  10. + +
  11. Casey Crellin <casey@csc.co.za> vxWorks (Tornado) port and help with target configuration
  12. + +
  13. Torsten Duwe <duwe@immd4.informatik.uni-erlangen.de> Linux port
  14. + +
  15. John A. Dundas III <dundas@salt.jpl.nasa.gov> Apple A/UX port
  16. + +
  17. Dennis Ferguson <dennis@mrbill.canet.ca> foundation code for NTP Version 2 as specified in RFC-1119
  18. + +
  19. Glenn Hollinger <glenn@herald.usask.ca> GOES clock driver
  20. + +
  21. Mike Iglesias <iglesias@uci.edu> DEC Alpha port
  22. + +
  23. Jim Jagielski <jim@jagubox.gsfc.nasa.gov> A/UX port
  24. + +
  25. Jeff Johnson <jbj@chatham.usdesign.com> massive prototyping overhaul
  26. + +
  27. William L. Jones <jones@hermes.chpc.utexas.edu> RS/6000 AIX modifications, HPUX modifications
  28. + +
  29. Dave Katz <dkatz@cisco.com> RS/6000 AIX port
  30. + +
  31. Craig Leres <leres@ee.lbl.gov> 4.4BSD port, ppsclock, Maganavox GPS clock driver
  32. + +
  33. George Lindholm <lindholm@ucs.ubc.ca> SunOS 5.1 port
  34. + +
  35. +Louis A. Mamakos <louie@ni.umd.edu> +MD5-based authentication
  36. + +
  37. Derek Mulcahy <derek@toybox.demon.co.uk> and Damon Hart-Davis <d@hd.org> ARCRON MSF clock driver
  38. + +
  39. Lars H. Mathiesen <thorinn@diku.dk> adaptation of foundation code for Version 3 as specified in RFC-1305
  40. + +
  41. David L. Mills <mills@udel.edu> Version 4 foundation, Spectractom WWVB, Austron GPS, Arbiter GPS, CHU, Heath, ATOM, ACTS, KSI/Odetics, IRIG clock drivers; PPS support; precision kernel; NTPv4 changes
  42. + +
  43. Wolfgang Moeller <moeller@gwdgv1.dnet.gwdg.de> VMS port
  44. + +
  45. Jeffrey Mogul <mogul@pa.dec.com> ntptrace utility
  46. + +
  47. Tom Moore <tmoore@fievel.daytonoh.ncr.com> i386 svr4 port
  48. + +
  49. Rainer Pruy <Rainer.Pruy@informatik.uni-erlangen.de> monitoring/trap scripts, statistics file handling
  50. + +
  51. Dirce Richards <dirce@zk3.dec.com> Digital UNIX V4.0 port
  52. + +
  53. Nick Sayer <mrapple@quack.kfu.com> SunOS streams modules
  54. + +
  55. Frank Kardel +<Frank.Kardel@informatik.uni-erlangen.de> +PARSE <GENERIC> driver (14 reference clocks), STREAMS modules for PARSE, support scripts, syslog cleanup
  56. + +
  57. Ray Schnitzler <schnitz@unipress.com> Unixware1 port
  58. + +
  59. Michael Shields <shields@tembel.org> USNO clock driver
  60. + +
  61. Jeff Steinman <jss@pebbles.jpl.nasa.gov> Datum PTS clock driver
  62. + +
  63. Harlan Stenn <harlan@pfcs.com> GNU automake/autoconfigure makeover
  64. + +
  65. Kenneth Stone <ken@sdd.hp.com> HP-UX port
  66. + +
  67. Ajit Thyagarajan <ajit@ee.udel.edu>IP multicast support
  68. + +
  69. Tomoaki TSURUOKA <tsuruoka@nc.fukuoka-u.ac.jp>TRAK clock driver
  70. + +
  71. Paul A Vixie <vixie@vix.com> TrueTime GPS driver, generic TrueTime clock driver
  72. + +
  73. Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de> corrected and validated HTML documents according to the HTML DTD
  74. + +
  75. Greg Brackley <greg.brackley@bigfoot.com> Major rework of WINNT port. Clean up recvbuf and iosignal code into separate modules.
  76. + +
  77. Sven Dietrich <sven_dietrich@trimble.com> Palisade reference clock driver, NT adj. residuals, integrated Greg's Winnt port.
  78. + +
  79. Wilfredo Sánchez <wsanchez@apple.com> added support for NetInfo
  80. +
+ +
David L. Mills <mills@udel.edu> + diff --git a/contrib/ntp/html/debug.htm b/contrib/ntp/html/debug.htm new file mode 100644 index 000000000000..bf160497953f --- /dev/null +++ b/contrib/ntp/html/debug.htm @@ -0,0 +1,288 @@ + +NTP Debugging Techniques +

+NTP Debugging Techniques +

+ +Pogo Possum, with toolkit +and bug, Walt Kelly +

+ +

Once the NTP software distribution has been compiled and installed +and the configuration file constructed, the next step is to verify +correct operation and fix any bugs that may result. Usually, the command +line that starts the daemon is included in the system startup file, so +it is executed only at system boot time; however, the daemon can be +stopped and restarted from root at any time. Usually, no command-line +arguments are required, unless special actions described in the +ntpd page are required. Once started, +the daemon will begin sending messages, as specified in the +configuration file, and interpreting received messages. + +

The best way to verify correct operation is using the ntpq and ntpdc +utility programs, either on the server itself or from another machine +elsewhere in the network. The ntpq program implements the +management functions specified in Appendix A of the NTP specification +RFC-1305, Appendix A. The ntpdc program implements +additional functions not provided in the standard. Both programs can be +used to inspect the state variables defined in the specification and, in +the case of ntpdc, additional ones of interest. In addition, +the ntpdc program can be used to selectively enable and disable +some functions of the daemon while the daemon is running. + +

In extreme cases with elusive bugs, the daemon can operate in two +modes, depending on the presence of the -d command-line debug +switch. If not present, the daemon detaches from the controlling +terminal and proceeds autonomously. If one or more -d switches +are present, the daemon does not detach and generates special output +useful for debugging. In general, interpretation of this output requires +reference to the sources. However, a single -d does produce +only mildly cryptic output and can be very useful in finding problems +with configuration and network troubles. With a little experience, the +volume of output can be reduced by piping the output to grep +and specifying the keyword of the trace you want to see. + +

Some problems are immediately apparent when the daemon first starts +running. The most common of these are the lack of a ntp (UDP port 123) +in the host /etc/services file. Note that NTP does not use TCP +in any form. Other problems are apparent in the system log file. The log +file should show the startup banner, some cryptic initialization data, +and the computed precision value. The next most common problem is +incorrect DNS names. Check that each DNS name used in the configuration +file responds to the Unix ping command. + +

When first started, the daemon normally polls the servers listed in +the configuration file at 64-second intervals. In order to allow a +sufficient number of samples for the NTP algorithms to reliably +discriminate between correctly operating servers and possible intruders, +at least four valid messages from at least one server is required before +the daemon can set the local clock. However, if the current local time +is greater than 1000 seconds in error from the server time, the daemon +will not set the local clock; instead, it will plant a message in the +system log and shut down. It is necessary to set the local clock to +within 1000 seconds first, either by a time-of-year hardware clock, by +first using the ntpdate program or +manually be eyeball and wristwatch. + +

After starting the daemon, run the ntpq program using the +-n switch, which will avoid possible distractions due to name +resolution problems. Use the pe 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: + +

ntpq>pe
+remote      refid       st t when poll reach   delay  offset   disp
+===================================================================
++128.4.2.6  132.249.16.1 2 u  131  256   373    9.89   16.28  23.25
+*128.4.1.20 .WWVB.       1 u  137  256   377  280.62   21.74  20.23
+-128.8.2.88 128.8.10.1   2 u  49   128   376  294.14    5.94  17.47
++128.4.2.17 .WWVB.       1 u  173  256   377  279.95   20.56  16.40
+
+ +The host addresses shown in the remote column should agree with +the DNS 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. Be prepared for surprises in cases where +the peer has multiple addresses or multiple names. The refid +entry shows the current source of synchronization for each peer, while +the st reveals the stratum, t the type (u = +unicast, m = multicast, l = local, - = don't +know), and poll the polling interval in seconds. The +when entry shows the time since the peer was last heard, +normally in seconds, while the reach entry shows the status of +the reachability register (see RFC-1305) in octal. The remaining entries +show the latest delay, offset and dispersion computed for the peer in +milliseconds. Note that in NTP Version 4 the dispersion entry includes +only the RMS error component; earlier versions included all components. + +

The tattletale character at the left margin displays the +synchronization status of each peer. The currently selected peer is +marked *, while additional peers designated acceptable for +synchronization, but not currently selected, are marked +. +Peers marked * and + are included in a weighted +average computation to set the local clock; the data produced by peers +marked with other symbols are discarded. See the ntpq +documentation for the meaning of these symbols. + +

Additional details for each peer separately can be determined by the +following procedure. First, use the as command to display an +index of association identifiers, such as + +

ntpq>as
+ind assID status conf reach auth condition last_event cnt
+=========================================================
+ 1  11670   7414   no   yes   ok candidate  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 candidate  reachable   1
+ 
+ +Each line in this billboard is associated with the corresponding line +the pe billboard above. Next, use the rv command and +the respective identifier to display a detailed synopsis of the selected +peer, such as + +
ntpq>rv 11670
+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
+
+ +A detailed explanation of the fields in this billboard are beyond the +scope of this discussion; however, most variables defined in the +specification RFC-1305 can be found. The most useful portion for +debugging is the last three lines, which give the roundtrip delay, clock +offset and dispersion for each of the last eight measurement rounds, all +in milliseconds. Note that the dispersion, which is an estimate of the +error, increases as the age of the sample increases. From these data, it +is usually possible to determine the incidence of severe packet loss, +network congestion, and unstable local clock oscillators. There are no +hard and fast rules here, since every case is unique; however, if one or +more of the rounds show zeros, or if the clock offset changes +dramatically in the same direction for each round, cause for alarm +exists. + +

Finally, the state of the local clock can be determined using the +rv command (without the argument), such as + +

ntpq>rv
+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
+
+ +The most useful data in this billboard show when the clock was last +adjusted reftime, together with its status and most recent +exception event. An explanation of these data is in the specification +RFC-1305. + +

When nothing seems to happen in the pe billboard after some +minutes, there may be a network problem. The most common network problem +is an access controlled router on the path to the selected peer. No +known public NTP time server selectively restricts access at this time, +although this may change in future; however, many private networks do. +It also may be the case that the server is down or running in +unsynchronized mode due to a local problem. Use the ntpq +program to spy on its own variables in the same way you can spy on your +own. + +

Once the daemon has set the local clock, it will continuously track +the discrepancy between local time and NTP time and adjust the local +clock accordingly. There are two components of this adjustment, time and +frequency. These adjustments are automatically determined by the clock +discipline algorithm, which functions as a hybrid phase/frequency +feedback loop. The behavior of this algorithm is carefully controlled to +minimize residual errors due to network jitter and frequency variations +of the local clock hardware oscillator that normally occur in practice. +However, when started for the first time, the algorithm may take some +time to converge on the intrinsic frequency error of the host machine. + +

It has sometimes been the experience that the local clock oscillator +frequency error is too large for the NTP discipline algorithm, which can +correct frequency errors as large as 43 seconds per day. There are two +possibilities that may result in this problem. First, the hardware time- +of-year clock chip must be disabled when using NTP, since this can +destabilize the discipline process. This is usually done using the +tickadj program and the -s +command line argument, but other means may be necessary. For instance, +in the Sun Solaris kernel, this can be done using a command in the +system startup file. + +

Normally, the daemon will adjust the local clock in small steps in +such a way that system and user programs are unaware of its operation. +The adjustment process operates continuously as long as the apparent +clock error exceeds 128 milliseconds, which for most Internet paths is a +quite rare event. If the event is simply an outlyer due to an occasional +network delay spike, the correction is simply discarded; however, if the +apparent time error persists for an interval of about 20 minutes, the +local clock is stepped to the new value (as an option, the daemon can be +compiled to slew at an accelerated rate to the new value, rather than be +stepped). This behavior is designed to resist errors due to severely +congested network paths, as well as errors due to confused radio clocks +upon the epoch of a leap second. + +

Debugging Checklist

+ +If the ntpq or ntpdc programs do not show that +messages are being received by the daemon or that received messages do +not result in correct synchronization, verify the following: + +
    + +

  1. Verify the /etc/services file host machine is configured +to +accept UDP packets on the NTP port 123. NTP is specifically designed to +use UDP and does not respond to TCP.
  2. + +

  3. Check the system log for ntpd messages about +configuration +errors, name-lookup failures or initialization problems.
  4. + +

  5. Using the ntpdc program and iostats command, +verify that the received packets and packets sent counters are +incrementing. If the packets send counter does not increment and the +configuration file includes designated servers, something may be wrong +in the network configuration of the ntpd host. If this counter does +increment and packets are actually being sent to the network, but the +received packets counter does not increment, something may be wrong in +the network or the server may not be responding.
  6. + +

  7. If both the packets sent counter and received packets counter do +increment, but the rec timestamp in the pe billboard +shows far from the current date, received packets are probably being +discarded for some reason. There is a handy, undocumented state variable +flash visible in the pebillboard. The value is in hex +and normally has the value zero (OK). However, if something is wrong, +the bits of this variable, reading from the right, correspond to the +sanity checks listed in Section 3.4.3 of the NTP specification RFC-1305. A bit other than zero indicates the associated sanity +check failed.
  8. + +

  9. If the org, rec and xmt timestamps in the +pe billboard appear current, but the local clock is not set, as +indicated by a stratum number less than 16 in the rv command +without arguments, verify that valid clock offset, roundtrip delay and +dispersion are displayed for at least one peer. The clock offset should +be less than 1000 seconds, the roundtrip delay less than one second and +the dispersion less than one second.
  10. + + +

  11. While the algorithm can tolerate a relatively large frequency +error (up to 500 parts per million or 43 seconds per day), various +configuration errors (and in some cases kernel bugs) can exceed this +tolerance, leading to erratic behavior. This can result in frequent loss +of synchronization, together with wildly swinging offsets. Use the +ntpdc program (or temporary configuration file) and disable +pll command to prevent the ntpd daemon from setting the +clock. Using the ntpq or ntpdc programs, watch the +apparent offset as it varies over time to determine the intrinsic +frequency error. If the error increases by more than 22 milliseconds per +64-second poll interval, the intrinsic frequency must be reduced by some +means. The easiest way to do this is with the tickadj program and the -t +command line argument.
  12. + +
+ +
David L. Mills <mills@udel.edu> +
diff --git a/contrib/ntp/html/driver1.htm b/contrib/ntp/html/driver1.htm new file mode 100644 index 000000000000..1f88e7de0180 --- /dev/null +++ b/contrib/ntp/html/driver1.htm @@ -0,0 +1,157 @@ + + + + + Undisciplined Local Clock + + + + +

+Undisciplined Local Clock

+ +
+

+Synopsis

+Address: 127.127.1.u +
Reference ID: LCL +
Driver ID: LOCAL +

+Description

+This driver is intended for use in an isolated network where no external +source of synchronization such as a radio clock or modem is available. +It allows a designated time server to act as a primary server to provide +synchronization to other clients on the network. Pick a machine that has +a good clock oscillator (Digital machines are good, Sun machines are not) +and configure it with this driver. Set the clock using the best means available, +like eyeball-and-wristwatch. Then, point all the other machines at this +one or use broadcast (not multicast) mode to distribute time. + +

Another application for this driver is if a particular server clock +is to be used as the clock of last resort when all other normal synchronization +sources have gone away. This is especially useful if that server has an +ovenized oscillator. For this you would configure this driver at a stratum +greater than any other likely sources of time (say 3 or 4) to prevent the +server taking over when legitimate sources are still available. + +

A third application for this driver is when an external discipline source +is available, such as the NIST lockclock program, which synchronizes +the local clock via a telephone modem and the NIST Automated Computer Time +Service (ACTS), or the Digital Time Synchronization Service (DTSS), which +runs on DCE machines. In this case the stratum should be set at zero, indicating +a bona fide stratum-1 source. In the case of DTSS, the local clock can +have a rather large jitter, depending on the interval between corrections +and the intrinsic frequency error of the clock oscillator. In extreme cases, +this can cause clients to exceed the 128-ms slew window and drop off the +NTP subnet. + +

In the case where a NTP time server is synchronized to some device or +protocol that is not external to the NTP daemon itself, some means should +be provided to pass such things as error and health values to the NTP daemon +for dissemination to its clients. If this is not done, there is a very +real danger that the device or protocol could fail and with no means to +tell NTP clients of the mishap. When ordinary Unix system calls like adjtime() +are used to discipline the kernel clock, there is no obvious way this can +be done without modifying the code for each case. However, when a modified +kernel with the ntp_adjtime() system call  is available, +that routine can be used for the same purpose as the adjtime() +routine and in addition provided with the estimated error, maximum error, +and leap-indicator values. This is the preferred way to synchronize the +kernel clock and pass information to the NTP clients. + +

In the default mode the behavior of the clock selection algorithm is +modified when this driver is in use. The algorithm is designed so that +this driver will never be selected unless no other discipline source is +available. This can be overridden with the prefer keyword of the +server configuration command, in which case only this driver will +be selected for synchronization and all other discipline sources will be +ignored. This behavior is intended for use when an external discipline +source controls the system clock. See the Mitigation +Rules and the prefer Keyword page for a detailed description +of the exact behavior. + +

The stratum for this driver is set at 3 by default, but can be changed +by the fudge configuration command and/or the ntpdc utility. +The reference ID is LCL by default, but can be changed using the +same mechanisms. *NEVER* configure this driver to operate at a stratum +which might possibly disrupt a client with access to a bona fide primary +server, unless the local clock oscillator is reliably disciplined by another +source. *NEVER NEVER* configure a server which might devolve to +an undisciplined local clock to use multicast mode. + +

This driver provides a mechanism to trim the local clock in both time +and frequency, as well as a way to manipulate the leap bits. The fudge +time1 parameter adjusts the time (in seconds) and the fudge time2 +parameter adjusts the frequency (in parts per million). Both parameters +are additive and operate only once; that is, each command (as from ntpdc) +adds signed increments in time or frequency to the nominal local clock +time and frequency. +

+Monitor Data

+No filegen clockstats monitor data are produced by this driver. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Specifies the frequency offset calibration factor, in parts per million, +with default 0.0.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 3.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default LCL.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+ + +

Additional Information + +

Reference Clock Drivers

+ +
+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver10.htm b/contrib/ntp/html/driver10.htm new file mode 100644 index 000000000000..bdf314ae46e2 --- /dev/null +++ b/contrib/ntp/html/driver10.htm @@ -0,0 +1,114 @@ + + + + + Austron 2200A/2201A GPS Receivers + + + + +

+Austron 2200A/2201A GPS Receivers

+ +
+

+Synopsis

+Address: 127.127.10.u +
Reference ID: GPS +
Driver ID: GPS_AS2201 +
Serial Port: /dev/gpsu; 9600 baud, 8-bits, no parity +
Features: tty_clk +

+Description

+This driver supports the 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 Buffer Module, Output Buffer +Module, IRIG-B Interface Module and LORAN Assist Module. It requires the +RS232 Buffered Serial Interface module for communication with the driver. +For operation with multiple computers, it requires the ppsclock +streams module described in the Line Disciplines and +Streams Modules page. The streams module requires a gadget box and +1-PPS level converter, such as described in the Pulse-per-second +(PPS) Signal Interfacing page. + +

For use with a single computer, the receiver can be connected directly +to the receiver. For use with multiple computers, one of them is connected +directly to the receiver and generates the polling messages. The other +computers just listen to the receiver output directly or through a buffer +amplifier. For computers that just listen, fudge flag2 must be +set and the ppsclock streams module configured on each of them. + +

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 ntp3 distribution. +

+Monitor Data

+When enabled by the flag4 fudge flag, every received timecode +is written as-is to the clockstats file. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default GPS.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Set for computers that listen-only.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Enable verbose clockstats recording if set.
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver11.htm b/contrib/ntp/html/driver11.htm new file mode 100644 index 000000000000..6e5dd7a3f171 --- /dev/null +++ b/contrib/ntp/html/driver11.htm @@ -0,0 +1,150 @@ + + + + + Arbiter 1088A/B GPS Receiver + + + + +

+Arbiter 1088A/B GPS Receiver

+ +
+

+Synopsis

+Address: 127.127.11.u +
Reference ID: GPS +
Driver ID: GPS_ARBITER +
Serial Port: /dev/gpsu; 9600 baud, 8-bits, no parity +
Features: tty_clk +

+Description

+This driver supports the Arbiter 1088A/B Satellite Controlled Clock. The +claimed accuracy of this clock is 100 ns relative to the PPS output when +receiving four or more satellites. + +

The receiver should be configured before starting the NTP daemon, in +order to establish reliable position and operating conditions. It does +not initiate surveying or hold mode. For use with NTP, the daylight savings +time feature should be disables (D0 command) and the broadcast +mode set to operate in UTC (BU command). + +

The timecode format supported by this driver is selected by the poll +sequence B5, which initiates a line in the following format to +be repeated once per second until turned off by the B0 command. + +

Format B5 (24 ASCII printing characters): +

<cr><lf>i yy ddd hh:mm:ss.000bbb
+
+on-time = <cr>
+i = synchronization flag (' ' = locked, '?' = unlocked)
+yy = year of century
+ddd = day of year
+hh:mm:ss = hours, minutes, seconds
+.000 = fraction of second (not used)
+bbb = tailing spaces for fill
+The alarm condition is indicated by a '?' at i, which indicates the receiver +is not synchronized. In normal operation, a line consisting of the timecode +followed by the time quality character (TQ) followed by the receiver status +string (SR) is written to the clockstats file. + +

The time quality character is encoded in IEEE P1344 standard: + +

Format TQ (IEEE P1344 estimated worst-case time quality) +

0       clock locked, maximum accuracy
+F       clock failure, time not reliable
+4       clock unlocked, accuracy < 1 us
+5       clock unlocked, accuracy < 10 us
+6       clock unlocked, accuracy < 100 us
+7       clock unlocked, accuracy < 1 ms
+8       clock unlocked, accuracy < 10 ms
+9       clock unlocked, accuracy < 100 ms
+A       clock unlocked, accuracy < 1 s
+B       clock unlocked, accuracy < 10 s
+The status string is encoded as follows: + +

Format SR (25 ASCII printing characters) +

V=vv S=ss T=t P=pdop E=ee
+
+vv = satellites visible
+ss = relative signal strength
+t = satellites tracked
+pdop = position dilution of precision (meters)
+ee = hardware errors
+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. +

+Monitor Data

+When enabled by the flag4 fudge flag, an additional line containing +the latitude, longitude, elevation and optional deviation data is written +to the clockstats file. The deviation data operates with an external +pulse-per-second (PPS) input, such as a cesium oscillator or another radio +clock. The PPS input should be connected to the B event channel and the +radio initialized for deviation data on that channel. The deviation data +consists of the mean offset and standard deviation of the external PPS +signal relative the GPS signal, both in microseconds over the last 16 seconds. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default GPS.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Enable verbose clockstats recording if set.
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver12.htm b/contrib/ntp/html/driver12.htm new file mode 100644 index 000000000000..57dbb71912d1 --- /dev/null +++ b/contrib/ntp/html/driver12.htm @@ -0,0 +1,98 @@ + + + + + KSI/Odetics TPRO/S IRIG Interface + + + + +

+KSI/Odetics TPRO/S IRIG Interface

+ +
+

+Synopsis

+Address: 127.127.12.u +
Reference ID: IRIG +
Driver ID: IRIG_TPRO +
TPRO Device: /dev/tprou +
Requires: KSI/Odetics device driver, /usr/include/sys/tpro.h header file +

+Description

+This driver supports the KSI/Odetics TPRO and 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 Arbiter, Austron, Odetics, Spectracom and TrueTime, +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. + +

Using the TPRO interface as a NTP reference clock provides precision +time only to ntpd and its clients. With suitable kernel modifications, +it is possible to use the TPRO as the CPU system clock, avoiding errors +introduced by the CPU clock oscillator wander. See the A +Kernel Model for Precision Timekeeping page for further details. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default IRIG.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver16.htm b/contrib/ntp/html/driver16.htm new file mode 100644 index 000000000000..a4b9f0c29bf9 --- /dev/null +++ b/contrib/ntp/html/driver16.htm @@ -0,0 +1,43 @@ + + + + + + + Bancomm bc635VME Time and Frequency Processor + + + +

+bc635VME/bc350VXI Time and Frequency Processor

+ +
+

+Synopsis

+Address: 127.127.16.u +
Reference ID: BTFP +
Driver ID: GPS_BANCOMM +
Bancomm Device:  /dev/btfp0 +
Requires: Bancomm bc635 TFP device module driver for +SunOS 4.x/SunOS 5.x +

+Description

+This is the clock driver for the Bancomm bc635VME Time and Frequency Processor. +It requires the BANCOMM bc635VME / +
bc350VXI Time and Frequency Processor Module Driver for SunOS 4.x/SunOS +5.x UNIX Systems. +

Most of this code is originally from refclock_bancomm.c with thanks. +It has been modified and tested on an UltraSparc IIi-cEngine +
running Solaris 2.6. A port for HPUX is not available henceforth. +
  +

+Additional Information

+ +


Reference +Clock Drivers +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver18.htm b/contrib/ntp/html/driver18.htm new file mode 100644 index 000000000000..5410d9807607 --- /dev/null +++ b/contrib/ntp/html/driver18.htm @@ -0,0 +1,235 @@ + + + + + NIST Modem Time Service + + + + +

+NIST Modem Time Service

+ +
+

+Synopsis

+Address: 127.127.18.u +
Reference ID: NIST +
Driver ID: ACTS_NIST +
Serial Port: /dev/actsu; 1200 baud, 8-bits, no parity +
Features: tty_clk +
Requires: /usr/include/sys/termios.h header file with modem +control +

+Description

+This driver supports the NIST Automated Computer Time Service (ACTS). It +periodically dials a prespecified telephone number, receives the NIST timecode +data and calculates the local clock correction. It designed primarily for +use when neither a radio clock nor connectivity to Internet time servers +is available. For the best accuracy, the individual telephone line/modem +delay needs to be calibrated using outside sources. + +

The ACTS is located at NIST Boulder, CO, telephone 303 494 4774. A toll +call from Newark, DE, costs between three and four cents, although it is +not clear what carrier and time of day discounts apply. The modem dial +string will differ depending on local telephone configuration, etc., and +is specified by the phone command in the configuration file. The argument +to this command is an AT command for a Hayes compatible modem. + +

The driver can operate in either of two modes, as determined by the +mode parameter in the server configuration command. In mode 0 the driver +operates continuously at intervals determined by the fudge time1 parameter, +as described above. In mode 1 the driver is enabled only when no other +sources of synchronization are available and when we have gone more than +MAXOUTAGE (3600 s) since last synchronized by other sources of synchronization. + +

The accuracy produced by this driver should be in the range of a millisecond +or two, but may need correction due to the delay characteristics of the +individual modem involved. For undetermined reasons, some modems work with +the ACTS echo-delay measurement scheme and some don't. This driver tries +to do the best it can with what it gets. Initial experiments with a Practical +Peripherals 9600SA modem here in Delaware suggest an accuracy of a millisecond +or two can be achieved without the scheme by using a fudge time1 value +of 65.0 ms. In either case, the dispersion for a single call involving +ten samples is about 1.3 ms. + +

For reliable call management, this driver requires a 1200-bps modem +with a Hayes-compatible command set and control over the modem data terminal +ready (DTR) control line. Present restrictions require the use of a POSIX-compatible +programming interface, although other interfaces may work as well. The +ACTS telephone number and modem setup string are hard-coded in the driver +and may require changes for nonstandard modems or special circumstances. + +

The fudge time1 parameter represents a propagation-delay correction +factor which is added to the value computed by ACTS when the echo-delay +scheme is used. This scheme does not work with all modems; for those that +don't, fudge flag2 should be set to disable the feature. In this case the +fudge time1 parameter represents the total propagation delay due to all +causes and must be determined by external calibration. + +

The ACTS call interval is determined by a counter initially set to the +fudge time2 parameter. At each poll interval, minpoll (usually 64 s) is +subtracted from the counter. When the counter is equal to or less than +zero, the fudge flag1 is set, which causes up to three call attempts to +be made to ACTS. The fudge flag1 is reset after a valid clock update has +been determined or by a device fault, timeout or manually using ntpdc. +After a valid clock update, the counter is reset for the next interval. +Setting the fudge time2 parameter to zero disables automatic call +attempts. Manual call attempts can be made at any time by setting fudge +flag1 using ntpdc. + +

The NIST timecode message is transmitted at 1200 bps in the following +format: +

+jjjjj yy-mm-dd hh:mm:ss tt l uuu mmmmm UTC(NIST) *
+
+jjjjj = modified Julian day
+yy-mm-dd = year, month, day
+hh:mm:ss = hours, minutes, seconds
+tt = DST indicator (see driver listing)
+l = leap-second warning (see driver listing)
+uuu = DUT1 correction (see driver listing)
+mmmmm = modem calibration (see driver listing)
+on-time = '*'
+The timecode message is transmitted continuously after a signon banner, +which this driver ignores. The driver also ignores all but the yy-mm-dd, +hh:mm:ss and on-time character '*' fields, although it checks the format +of all fields of the message. A timestamp is captured at the '*' character, +as required by the ACTS specification, and used as the reference time of +the timecode. If a message with an on-time character of '#' is received, +the driver updates the propagation delay. The driver disconnects when (a) +ten valid messages have been received, (b) no message has been received +for 15 s, (c) an on-time character of '#' is received. These messages are +processed by a trimmed-mean filter to reduce timing noise and then by the +usual NTP algorithms to develop the clock correction. + +

Since the accumulated error grows with the interval between calls, it +is important that the intrinsic frequency error be minimized. This can +be done by observing difference in offsets between two calls placed some +hours apart and calculating the uncorrected frequency error. This error, +as a fixed-point value in parts-per-million, should be installed in the +ntp.drift file before the daemon is started. Some experimentation may be +necessary in order to reduce the intrinsic frequency error to the order +of 1 ppm. + +

The behavior of the clock selection algorithm is modified when this +driver is in use. The algorithm is designed so that this driver will never +be selected unless no other discipline source is available. This can be +overridden with the prefer keyword of the server configuration command, +in which case only this driver will be selected for synchronization and +all other discipline sources will be ignored. + +

Unlike other drivers, each ACTS call generates one clock correction +and that correction is processed immediately. There is no wait to allow +the clock filter to accumulate samples. In addition, the watchdog timeout +of the local clock algorithm is disabled, so that a correction received +from this driver that exceeds CLOCK_MAX (128 ms) causes an immediate step/slew. + +

Since the interval between updates can be much longer than used with +ordinary NTP peers, the local clock procedure has been modified to operate +in either of two modes, depending on whether the interval between updates +is less than or greater than CLOCK_MAXSEC (1200 s). If less than this value, +the local clock procedure operates using the standard NTP phase-lock loop +as with other NTP peers. If greater than this value, the procedure operates +using a modified frequency-lock loop suggested by Judah Levine in his lockclock +algorithm designed specifically for ACTS. +

+Call Management

+Since ACTS will be a toll call in most areas of the country, it is necessary +to carefully manage the call frequency. This can be done in two ways, by +specifying the interval between calls, or by setting a flag bit manually +or via a cron job. The call interval is determined by a counter initially +set to the fudge time2 parameter. At each poll interval, minpoll (usually +64 s) is subtracted from the counter. When the counter is equal to or less +than zero, the fudge flag1 is set, which causes up to three call attempts +to be made. The fudge flag1 is reset after ten offset samples have been +determined in a single call or by a device fault, timeout or manually using +ntpdc. Upon successful completion of a call, the eight samples have been +shifted into the clock filter, the local clock updated and the counter +reset for the next interval. Setting the fudge time2 parameter to zero +disables automatic call attempts. + +

Manual call attempts can be made at any time by setting fudge flag1 +using ntpdc. For example, the ntpdc command +

+fudge 127.127.18.1 flags 1
+will ask for a key identifier and password and, if authenticated by the +server, will set flag1. There may be a short delay until the expiration +of the current poll timeout. + +

The flag1 can be set from a cron job in the following way. Construct +a file with contents +

keyid 11
+passwd dialup
+fudge 127.127.18.1 flags 1
+quit
+Then, run the following program at specified times as required. +
/usr/local/bin/ntpdc <file
+ +

+Monitor Data

+When enabled by the flag4 fudge flag, every received timecode +is written as-is to the clockstats file. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default NIST.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver19.htm b/contrib/ntp/html/driver19.htm new file mode 100644 index 000000000000..a5cd5e0da8bf --- /dev/null +++ b/contrib/ntp/html/driver19.htm @@ -0,0 +1,124 @@ + + + + + Heath WWV/WWVH Receiver + + + + +

+Heath WWV/WWVH Receiver

+ +
+

+Synopsis

+Address: 127.127.19.u +
Reference ID: WWV +
Driver ID: WWV_HEATH +
Serial Port: /dev/heathu; 1200 baud, 8-bits, no parity +
Features: tty_clk +
Requires: /usr/include/sys/termios.h header file with modem +control +

+Description

+This driver supports the Heath GC-1000 Most Accurate Clock, with RS232C +Output Accessory. This is a WWV/WWVH receiver somewhat less robust than +other supported receivers. Its claimed accuracy is 100 ms when actually +synchronized to the broadcast signal, but this doesn't happen even most +of the time, due to propagation conditions, ambient noise sources, etc. +When not synchronized, the accuracy is at the whim of the internal clock +oscillator, which can wander into the sunset without warning. Since the +indicated precision is 100 ms, expect a host synchronized only to this +thing to wander to and fro, occasionally being rudely stepped when the +offset exceeds the default CLOCK_MAX of 128 ms. + +

The internal DIPswitches should be set to operate at 1200 baud in MANUAL +mode and the current year. The external DIPswitches should be set to GMT +and 24-hour format. It is very important that the year be set correctly +in the DIPswitches; otherwise, the day of year will be incorrect after +28 April of a normal or leap year. + +

In MANUAL mode the clock responds to a rising edge of the request to +send (RTS) modem control line by sending the timecode. Therefore, it is +necessary that the operating system implement the TIOCMBIC and +TIOCMBIS ioctl system calls and TIOCM_RTS control bit. +Present restrictions require the use of a POSIX-compatible programming +interface, although other interfaces may work as well. + +

The clock message consists of 23 ASCII printing characters in the following +format: +

hh:mm:ss.f     dd/mm/yr<cr>
+
+hh:mm:ss.f = hours, minutes, seconds
+f = deciseconds ('?' when out of spec)
+dd/mm/yr = day, month, year
+The alarm condition is indicated by '?', rather than a digit, at A. Note +that 0?:??:??.? is displayed before synchronization is first established +and hh:mm:ss.? once synchronization is established and then lost again +for about a day. + +

A fudge time1 value of .07 s appears to center the clock offset residuals. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default WWV.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver2.htm b/contrib/ntp/html/driver2.htm new file mode 100644 index 000000000000..885a1b20211d --- /dev/null +++ b/contrib/ntp/html/driver2.htm @@ -0,0 +1,137 @@ + + + + + Trak 8820 GPS Receiver + + + + +

+Trak 8820 GPS Receiver

+ +
+

+Synopsis

+Address: 127.127.2.u +
Reference ID: GPS +
Driver ID: GPS_TRAK +
Serial Port: /dev/traku; 9600 baud, 8-bits, no parity +
Features: tty_clk +

+Description

+This driver supports the Trak 8820 GPS Station Clock. The claimed accuracy +at the 1-PPS output is 200-300 ns relative to the broadcast signal; however, +in most cases the actual accuracy is limited by the precision of the timecode +and the latencies of the serial interface and operating system. + +

For best accuracy, this radio requires the tty_clk line discipline, +which captures a timestamp at the * on-time character of the timecode. +Using this discipline the jitter is in the order of 1 ms and systematic +error about 0.5 ms. If unavailable, the buffer timestamp is used, which +is captured at the \r ending the timecode message. This introduces +a systematic error of 23 character times, or about 24 ms at 9600 bps, together +with a jitter well over 8 ms on Sun IPC-class machines. + +

Using the menus, the radio should be set for 9600 bps, one stop bit +and no parity. It should be set to operate in computer (no echo) mode. +The timecode format includes neither the year nor leap-second warning. + +

In operation, this driver sends a RQTS\r request to the radio +at initialization in order to put it in continuous time output mode. The +radio then sends the following message once each second: +

*RQTS U,ddd:hh:mm:ss.0,q<cr><lf>
+
+on-time = '*'
+ddd = day of year
+hh:mm:ss = hours, minutes, seconds
+q = quality indicator (phase error), 0-6:
+     0 > 20 us
+     6 > 10 us
+     5 > 1 us
+     4 > 100 ns
+     3 > 10 ns
+     2 < 10 ns
+The alarm condition is indicated by 0 at Q, which means +the radio has a phase error greater than 20 us relative to the broadcast +time. The absence of year, DST and leap-second warning in this format is +also alarmed. + +

The continuous time mode is disabled using the RQTX\r request, +following which the radio sends a RQTX DONE<cr><lf> response. +In the normal mode, other control and status requests are effective, including +the leap-second status request RQLS<cr>. The radio responds +with RQLS yy,mm,dd<cr><lf>, where yy,mm,dd are +the year, month and day. Presumably, this gives the epoch of the next leap +second, RQLS 00,00,00 if none is specified in the GPS message. +Specified in this form, the information is generally useless and is ignored +by the driver. +

+Monitor Data

+When enabled by the flag4 fudge flag, every received timecode +is written as-is to the clockstats file. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default GPS.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+ + +

Additional Information + +

Reference Clock Drivers

+ +
+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver20.htm b/contrib/ntp/html/driver20.htm new file mode 100644 index 000000000000..e6a4bd2a83d1 --- /dev/null +++ b/contrib/ntp/html/driver20.htm @@ -0,0 +1,131 @@ + + + + + Generic NMEA GPS Receiver + + + + +

+Generic NMEA GPS Receiver

+ +
+

+Synopsis

+Address: 127.127.20.u +
Reference ID: GPS +
Driver ID: GPS_NMEA +
Serial Port: /dev/gpsu; 4800 baud, 8-bits, no parity +
Features: tty_clk +

+Description

+This driver supports GPS receivers with the $GPRMC NMEA output string. +The driver expect the receiver to be set up to transmit a $GPRMC +message every second. + +

The accuracy depend on the receiver used. Inexpesive GPS models are +available with a claimed PPS signal accuracy of 1 ms +or better relative to the broadcast signal. However, in most cases the +actual accuracy is limited by the precision of the timecode and the latencies +of the serial interface and operating system. + +

The $GPRMC message that the GPS transmits look like this: +

$GPRMC,POS_UTC,POS_STAT,LAT,LAT_REF,LON,LON_REF,SPD,HDG,DATE,MAG_VAR,MAG_REF*CC<cr><lf>
+
+  POS_UTC  - UTC of position. Hours, minutes and seconds. (hhmmss)
+  POS_STAT - Position status. (A = Data valid, V = Data invalid)
+  LAT      - Latitude (llll.ll)
+  LAT_REF  - Latitude direction. (N = North, S = South)
+  LON      - Longitude (yyyyy.yy)
+  LON_REF  - Longitude direction (E = East, W = West)
+  SPD      - Speed over ground. (knots) (x.x)
+  HDG      - Heading/track made good (degrees True) (x.x)
+  DATE     - Date (ddmmyy)
+  MAG_VAR  - Magnetic variation (degrees) (x.x)
+  MAG_REF  - Magnetic variation (E = East, W = West)
+  CC       - Checksum (optional)
+  <cr><lf> - Sentence terminator.
+The driver will send a $PMOTG,RMC,0000*1D<cr><lf> message +each time a $GPRMC string is needed. This is not needed on most +GPS receivers because they automatically send the $GPRMC string +every second and will only work on GPS receivers that understand the $PMOTG +string. Others will just ignore it. +

+Setting up the Garmin GPS-25XL

+Switch off all output with by sending it the following string. +
"$PGRMO,,2<cr><lf>"
+Now switch only $GPRMC on by sending it the following string. +
"$PGRMO,GPRMC,1<cr><lf>"
+On some systems the PPS signal isn't switched on by default. It can be +switched on by sending the following string. +
"$PGRMC,,,,,,,,,,,,2<cr><lf>"
+ +

+Monitor Data

+The $GPRMC string that is used is written to the clockstats file. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default GPS.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+ + +

Additional Information + +

Reference Clock Drivers

+ +
+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver22.htm b/contrib/ntp/html/driver22.htm new file mode 100644 index 000000000000..313d2b8232b2 --- /dev/null +++ b/contrib/ntp/html/driver22.htm @@ -0,0 +1,129 @@ + + + + + PPS Clock Discipline + + + + +

+PPS Clock Discipline

+ +
+

+Synopsis

+Address: 127.127.22.u +
Reference ID: PPS +
Driver ID: PPS +
Serial Port: /dev/ppsu; 9600 baud, 8-bits, no parity +
Features: tty_clk +

+Description

+This driver furnishes an interface for pulse-per-second (PPS) signals produced +by a cesium clock, radio clock or related equipment. It can be used to +remove accumulated jitter and retime a secondary server when synchronized +to a primary server over a congested, wide-area network and before redistributing +the time to local clients. + +

In order for this driver to work, the local clock must be set to within ++-500 ms by another means, such as a radio clock or NTP itself. The PPS +signal is connected via a serial port and gadget box +consisting of a one-shot and RS232 level converter. When operated at 38.4 +kbps with a SPARCstation IPC, this arrangement has a worst-case jitter +less than 26 us. + +

There are three ways in which this driver can be used. The first way +uses the ppsclock line discipline and works only for the baseboard +serial ports of the Sun SPARCstation running SunOS 4.x. The PPS signal +is connected via the gadget box to the carrier detect (DCD) line of a serial +port. The signal is activated for this port by a fudge flag3 1 +command following the server command in the configuration file. +This causes the ppsclock streams module to be configured for that +port and to capture a timestamp at the on-time transition of the PPS signal. +This driver then reads the timestamp directly by a designated ioctl() +system call. This provides the most accurate time and least jitter of any +other scheme. There is no need to configure a dedicated device for this +purpose, which ordinarily is the device used for the associated radio clock. + +

The second way uses the tty_clk line discipline and works for +any architecture supporting a serial port. If after a few seconds this +driver finds no ppsclock module configured, it attempts to open +a serial port device /dev/pps%d, where %d is the unit +number, and assign the tty_clk line discipline to it. If the line +discipline fails, no harm is done except the accuracy is reduced somewhat. +The pulse generator in the gadget box must be adjusted to produce a start +bit of length 26 usec at 38400 bps. Used with the tty_clk line +discipline, this produces an ASCII DEL character ('\377') followed by a +timestamp at the on-time transition of the PPS signal. + +

The third way involves an auxiliary radio clock driver which calls the +PPS driver with a timestamp captured by that driver. This use is documented +in the source code for the driver(s) involved. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0. This parameter can be used to compensate for the UART +and OS delays. Allow about 247 us for UART delays at 38400 bps and about +1 ms for SunOS streams nonsense.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default PPS.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+ + +

Additional Information + +

Reference Clock Drivers

+ +
+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver23.htm b/contrib/ntp/html/driver23.htm new file mode 100644 index 000000000000..6633999eca1c --- /dev/null +++ b/contrib/ntp/html/driver23.htm @@ -0,0 +1,87 @@ + + + + + PTB Modem Time Service + + + + +

+PTB Modem Time Service

+ +
+

+Synopsis

+Address: 127.127.23.u +
Reference ID: PTB +
Driver ID: ACTS_PTP +
Serial Port: /dev/ptbu; 1200 baud, 8-bits, no parity +
Requires: /usr/include/sys/termios.h header file with modem +control +

+Description

+No further information available. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default PTB.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this drivert.
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver24.htm b/contrib/ntp/html/driver24.htm new file mode 100644 index 000000000000..70c623bbc1d0 --- /dev/null +++ b/contrib/ntp/html/driver24.htm @@ -0,0 +1,85 @@ + + + + + USNO Modem Time Service + + + + +

+USNO Modem Time Service

+ +
+

+Synopsis

+Address: 127.127.24.u +
Reference ID: USNO +
Driver ID: ACTS_USNO +
Serial Port: /dev/cuau; 1200 baud, 8-bits, no parity +
Requires: /usr/include/sys/termios.h header file with modem +control +

+Description

+No information available. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default USNO.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Enable clockstats recording if set.
+
+ +
+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver26.htm b/contrib/ntp/html/driver26.htm new file mode 100644 index 000000000000..eabbc96554e9 --- /dev/null +++ b/contrib/ntp/html/driver26.htm @@ -0,0 +1,109 @@ + + + + + Hewlett Packard 58503A GPS Receiver + + + + +

+Hewlett Packard 58503A GPS Receiver

+ +
+

+Synopsis

+Address: 127.127.26.u +
Reference ID: GPS +
Driver ID: GPS_HP +
Serial Port: /dev/hpgpsu; 9600 baud, 8-bits, no parity +

+Description

+This driver supports the HP 58503A Time and Frequency Reference Receiver. +It uses HP SmartClock (TM) to implement an Enhanced GPS receiver. The receiver +accuracy when locked to GPS in normal operation is better than 1 usec. +The accuracy when operating in holdover is typically better than 10 us +per day. It receiver should be operated with factory default settings. +Initial driver operation: expects the receiver to be already locked to +GPS, configured and able to output timecode format 2 messages. + +

The driver uses the poll sequence :PTIME:TCODE? to get a response +from the receiver. The receiver responds with a timecode string of ASCII +printing characters, followed by a <cr><lf>, followed by a prompt +string issued by the receiver, in the following format: +

T#yyyymmddhhmmssMFLRVcc<cr><lf>
+The driver processes the response at the <cr> and <lf><cr> and +<lf>, so what the driver sees is the prompt from the previous poll, +followed by this timecode. The prompt from the current poll is (usually) +left unread until the next poll. So (except on the very first poll) the +driver sees this: +
T#yyyymmddhhmmssMFLRVcc<cr><lf>
+The T is the on-time character, at 980 msec. before the next 1PPS edge. +The # is the timecode format type. We look for format 2. Without any of +the CLK or PPS stuff, then, the receiver buffer timestamp at the <cr>y +is 24 characters later, which is about 25 msec. at 9600 bps, so the first +approximation for fudge time1 is nominally -0.955 seconds. This number +probably needs adjusting for each machine / OS type, so far: -0.955000 +on an HP 9000 Model 712/80 HP-UX 9.05 -0.953175 on an HP 9000 Model 370 +HP-UX 9.10 +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default GPS.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+
+ +
+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver27.htm b/contrib/ntp/html/driver27.htm new file mode 100644 index 000000000000..686e985b1b77 --- /dev/null +++ b/contrib/ntp/html/driver27.htm @@ -0,0 +1,634 @@ + + + + + Arcron MSF Receiver + + + + +

+Arcron MSF Receiver

+ +
+

+Synopsis

+Address: 127.127.27.u +
Reference ID: MSFa +
Driver ID: MSF_ARCRON +
Serial Port: /dev/arcu; 300 baud, 8-bits, 2-stop, no +parity +
Features: tty_clk +

+Description

+This driver supports the Arcron MSF receiver, and would probably also support +the DCF77 variant of the same clock. The clock reports its ID as ``MSFa'' +to indicate MSF as a source and the use of the ARCRON driver. + +

This documentation describes version V1.1 (1997/06/23) of the source +and has been tested (amongst others) against ntpd3-5.90 on Solaris-1 (SunOS +4.1.3_U1 on an SS1 serving as a router and firewall) and against ntpd3-5.90 +on Solaris-2.5 (on a SS1+ and TurboSPARC 170MHz). This code will probably +work, and show increased stability, reduced jitter and more efficiency +(fewer context switches) with the tty_clk discipline/STREAMS module +installed, but this has not been tested. For a to-do list see the comments +at the start of the code. + +

This code has been significantly slimmed down since the V1.0 version, +roughly halving the memory footprint of its code and data. + +

This driver is designed to allow the unit to run from batteries as designed, +for something approaching the 2.5 years expected in the usual stand-alone +mode, but no battery-life measurements have been taken. + +

Much of this code is originally from the other refclock driver files +with thanks. The code was originally made to work with the clock by Derek +Mulcahy, with modifications by Damon Hart-Davis. +Thanks also to Lyndon David +for some of the specifications of the clock. + +

There is support for a Tcl/Tk monitor written by Derek Mulcahy that +examines the output stats; see the ARC +Rugby MSF Receiver page for more details and the code. + +

Look at the notes at the start of the code for further information; +some of the more important details follow. + +

The driver interrogates the clock at each poll (ie every 64s by default) +for a timestamp. The clock responds at the start of the next second (with +the start bit of the first byte being on-time). The time is in `local' +format, including the daylight savings adjustment when it is in effect. +The driver code converts the time back to UTC. + +

The clock claims to be accurate to within about 20ms of the MSF-broadcast +time, and given the low data transmission speed from clock to host, and +the fact that the clock is not in continuous sync with MSF, it seems sensible +to set the `precision' of this clock to -5 or -4, -4 being used in this +code, which builds in a reported dispersion of over 63ms (ie says ``This +clock is not very good.''). You can improve the reported precision to -4 +(and thus reduce the base dispersion to about 31ms) by setting the fudge +flag3 to 1. + +

Even a busy and slow IP link can yield lower dispersions than this from +polls of primary time servers on the Internet, which reinforces the idea +that this clock should be used as a backup in case of problems with such +an IP link, or in the unfortunate event of failure of more accurate sources +such as GPS. + +

By default this clock reports itself to be at stratum 2 rather than +the usual stratum 0 for a refclock, because it is not really suited to +be used as other than a backup source. The stratum reported can be changed +with the fudge directive to be whatever you like. After careful +monitoring of your clock, and appropriate choice of the time1 +fudge factor to remove systematic errors in the clock's reported time, +you might fudge the clock to stratum 1 to allow a stratum-2 secondary server +to sync to it. + +

The driver code arranges to resync the clock to MSF at intervals of +a little less than an hour (deliberately avoiding the same time each hour +to avoid any systematic problems with the signal or host). Whilst resyncing, +the driver supplements the normal polls for time from the clock with polls +for the reception signal quality reported by the clock. If the signal quality +is too low (0--2 out of a range of 0--5), we chose not to trust the clock +until the next resync (which we bring forward by about half an hour). If +we don't catch the resync, and so don't know the signal quality, we do +trust the clock (because this would generally be when the signal is very +good and a resync happens quickly), but we still bring the next resync +forward and reduce the reported precision (and thus increase reported dispersion). + +

If we force resyncs to MSF too often we will needlessly exhaust the +batteries the unit runs from. During clock resync this driver tries to +take enough time samples to avoid ntpd losing sync in case this +clock is the current peer. By default the clock would only resync to MSF +about once per day, which would almost certainly not be acceptable for +NTP purposes. + +

The driver does not force an immediate resync of the clock to MSF when +it starts up to avoid excessive battery drain in case ntpd is +going to be repeatedly restarted for any reason, and also to allow enough +samples of the clock to be taken for ntpd to sync immediately +to this clock (and not remain unsynchronised or to sync briefly to another +configured peer, only to hop back in a few poll times, causing unnecessary +disturbance). This behaviour should not cause problems because the driver +will not accept the timestamps from the clock if the status flag delivered +with the time code indicates that the last resync attempt was unsuccessful, +so the initial timestamps will be close to reality, even if with up to +a day's clock drift in the worst case (the clock by default resyncs to +MSF once per day). + +

The clock has a peculiar RS232 arrangement where the transmit lines +are powered from the receive lines, presumably to minimise battery drain. +This arrangement has two consequences: +

    +
  • +Your RS232 interface must drive both +ve and -ve
  • + +
  • +You must (in theory) wait for an echo and a further 10ms between characters
  • +
+This driver, running on standard Sun hardware, seems to work fine; note +the use of the send_slow() routine to queue up command characters +to be sent once every two seconds. + +

Three commands are sent to the clock by this driver. Each command consists +of a single letter (of which only the bottom four bits are significant), +followed by a CR (ASCII 13). Each character sent to the clock should be +followed by a delay to allow the unit to echo the character, and then by +a further 10ms. Following the echo of the command string, there may be +a response (ie in the cae of the g and o commands below), +which in the case of the o command may be delayed by up to 1 second +so as the start bit of the first byte of the response can arrive on time. +The commands and their responses are: +

+
+g CR
+ +
+Request for signal quality. Answer only valid during (late part of) resync +to MSF signal. The response consists of two characters as follows:
+ +
    +
    +
    +bit 7
    + +
    +parity
    + +
    +bit 6
    + +
    +always 0
    + +
    +bit 5
    + +
    +always 1
    + +
    +bit 4
    + +
    +always 1
    + +
    +bit 3
    + +
    +always 0
    + +
    +bit 2
    + +
    +always 0
    + +
    +bit 1
    + +
    +always 1
    + +
    +bit 0
    + +
    += 0 if no reception attempt at the moment, = 1 if reception attempt (ie +resync) in progress
    +
    + +
    +
    +bit 7
    + +
    +parity
    + +
    +bit 6
    + +
    +always 0
    + +
    +bit 5
    + +
    +always 1
    + +
    +bit 4
    + +
    +always 1
    + +
    +bit 3
    + +
    +always 0
    + +
    +bit 2--0
    + +
    +reception signal quality in the range 0--5 (very poor to very good); if +in the range 0--2 no successful reception is to be expected. The reported +value drops to zero when not resyncing, ie when first returned byte is +not `3'.
    +
    +
+ +
+h CR
+ +
+Request to resync to MSF. Can take up from about 30s to 360s. Drains batteries +so should not be used excessively. After this the clock time and date should +be correct and the phase within 20ms of time as transmitted from Rugby +MSF (remember to allow for propagation time). By default the clock resyncs +once per day shortly after 2am (presumably to catch transitions to/from +daylight saving time quickly). With this driver code we resync at least +once per hour to minimise clock wander.
+ +
+o CR
+ +
+Request timestamp. Start bit of first byte of response is on-time, so may +be delayed up to 1 second. Note that when the BST mode is in effect the +time is GMT/UTC +0100, ie an hour ahead of UTC to reflect local time in +the UK. The response data is as follows:
+ +
    +
  1. +hours tens (hours range from 00 to 23)
  2. + +
  3. +hours units
  4. + +
  5. +minutes tens (minutes range from 00 to 59)
  6. + +
  7. +minutes units
  8. + +
  9. +seconds tens (seconds presumed to range from 00 to 60 to allow for leap +second)
  10. + +
  11. +seconds units
  12. + +
  13. +day of week 1 (Monday) to 7 (Sunday)
  14. + +
  15. +day of month tens (day ranges from 01 to 31)
  16. + +
  17. +day of month units
  18. + +
  19. +month tens (months range from 01 to 12)
  20. + +
  21. +month units
  22. + +
  23. +year tens (years range from 00 to 99)
  24. + +
  25. +year units
  26. + +
  27. +BST/UTC status
  28. + +
    +
    +bit 7
    + +
    +parity
    + +
    +bit 6
    + +
    +always 0
    + +
    +bit 5
    + +
    +always 1
    + +
    +bit 4
    + +
    +always 1
    + +
    +bit 3
    + +
    +always 0
    + +
    +bit 2
    + +
    += 1 if UTC is in effect (reverse of bit 1)
    + +
    +bit 1
    + +
    += 1 if BST is in effect (reverse of bit 2)
    + +
    +bit 0
    + +
    += 1 if BST/UTC change pending
    +
    + +
  29. +clock status
  30. + +
      +
    +bit 7
    + +
    +parity
    + +
    +bit 6
    + +
    +always 0
    + +
    +bit 5
    + +
    +always 1
    + +
    +bit 4
    + +
    +always 1
    + +
    +bit 3
    + +
    += 1 if low battery is detected
    + +
    +bit 2
    + +
    += 1 if last resync failed (though officially undefined for the MSF clock)
    + +
    +bit 1
    + +
    += 1 if at least one reception attempt since 0230 for the MSF clock was +successful (0300 for the DCF77 clock)
    + +
    +bit 0
    + +
    += 1 if the clock has valid time---reset to zero when clock is reset (eg +at power-up), and set to 1 after first successful resync attempt.
    +
    +
+The driver only accepts time from the clock if the bottom three bits of +the status byte are 011. The leap-year logic for computing day-in-year +is only valid until 2099, and the clock will ignore stamps from the clock +that claim BST is in effect in the first hour of each year. If the UK parliament +decides to move us to +0100/+0200 time as opposed to the current +0000/+0100 +time, it is not clear what effect that will have on the time broadcast +by MSF, and therefore on this driver's usefulness.
+A typical ntp.conf configuration file for this driver might be: +
# hostname(n) means we expect (n) to be the stratum at which hostname runs.
+
+#------------------------------------------------------------------------------
+# SYNCHRONISATION PARTNERS
+# ========================
+
+# Our betters...
+server 127.127.27.0 # ARCRON MSF radio clock(1).
+# Fudge stratum and other features as required.
+# ADJUST time1 VALUE FOR YOUR HOST, CLOCK AND LOCATION!
+fudge 127.127.27.0 stratum 1 time1 0.016 flag3 1 flag4 1
+
+peer 11.22.33.9 # tick(1--2).
+peer 11.22.33.4 # tock(3), boot/NFS server.
+
+# This shouldn't get swept away unless left untouched for a long time.
+driftfile /var/tmp/ntp.drift
+
+#------------------------------------------------------------------------------
+# RESTRICTIONS
+# ============
+
+# By default, don't trust and don't allow modifications.  Ignore in fact.
+restrict default ignore notrust nomodify
+
+# Allow others in our subnet to check us out...
+restrict 11.22.33.0 mask 255.255.255.0 nomodify notrust
+
+# Trust our peers for time.  Don't trust others in case they are insane.
+restrict 127.127.27.0 nomodify
+restrict 11.22.33.4 nomodify
+restrict 11.22.33.9 nomodify
+
+# Allow anything from the local host.
+restrict 127.0.0.1
+There are a few #defines in the code that you might wish to play +with: +
+
+ARCRON_KEEN
+ +
+With this defined, the code is relatively trusting of the clock, and assumes +that you will have the clock as one of a few time sources, so will bend +over backwards to use the time from the clock when available and avoid +ntpd dropping sync from the clock where possible. You may wish +to undefine this, especially if you have better sources of time or your +reception is ropey. However, there are many checks built in even with this +flag defined.
+ +
+ARCRON_OWN_FILTER
+ +
+When defined, the code uses its own median-filter code rather than that +available in ntp_refclock.c since the latter seems to have a minor +bug, at least in version 3-5.90. If this bug goes away this flag should +be turned off to avoid duplication of code. (The bug, if that's what it +is, causes the last raw offset to be used rather than the median offset.)
+ + +

Without this defined (and without ARCRON_MULTIPLE_SAMPLES below) +a typical set of offsets reported and used to drive the clock-filter algorithm +is (oldest last): +

filtoffset=  -4.32  -34.82   -0.78    0.89    2.76    4.58   -3.92   -2.17
+Look at that spike! + +

With this defined a typical set of offsets is: +

filtoffset=  -7.06   -7.06   -2.91   -2.91   -2.91   -1.27   -9.54   -6.70
+with the repeated values being some evidence of outlyers being discarded. +
+ARCRON_MULTIPLE_SAMPLES
+ +
+When is defined, we regard each character in the returned timecode as at +a known delay from the start of the second, and use the smallest (most +negative) offset implied by any such character, ie with the smallest kernel-induced +display, and use that. This helps to reduce jitter and spikes.
+ +
+ARCRON_LEAPSECOND_KEEN
+ +
+When is defined, we try to do a resync to MSF as soon as possible in the +first hour of the morning of the first day of the first and seventh months, +ie just after a leap-second insertion or deletion would happen if it is +going to. This should help compensate for the fact that this clock does +not continuously sample MSF, which compounds the fact that MSF itself gives +no warning of an impending leap-second event. This code did not seem functional +at the leap-second insertion of 30th June 1997 so is by default disabled.
+ +
+PRECISION
+ +
+Currently set to -4, but you may wish to set it to -5 +if you are more conservative, or to -6 if you have particularly +good experience with the clock and you live on the edge. Note that the +flag3 fudge value will improve the reported dispersion one notch +if clock signal quality is known good. So maybe just leave this alone. +B^)
+ +
+NSAMPLES
+ +
+Should be at least 3 to help smooth out sampling jitters. Can be more, +but if made too long can make ntpd overshoot on clock corrections +and can hold onto bad samples longer than you would like. With this set +to 4 and NKEEP set to 3 this allows the occasional bad sample +(in my experience less than 1 value in 10) to be dropped. (Note that there +seems to be some sort of `beat' effect in the offset with a periodicity +of about 7 samples as of this writing (1997/05/11) still under investigation; +a filter of approximately this length should be able to almost completely +suppress this effect.) Note that if the fudge-factor flag3 is +set to 1, a larger NSAMPLES is used.
+
+ +

+Monitor Data

+Each timecode is written to the clockstats file with a signal +quality value appended (`0'--`5' as reported by the clock, or `6' for unknown). + +

Each resync and result (plus gaining or losing MSF sync) is logged to +the system log at level LOG_NOTICE; note that each resync drains +the unit's batteries, so the syslog entry seems justified. + +

Syslog entries are of the form: +

May 10 10:15:24 oolong ntpd[615]: ARCRON: unit 0: sending resync command
+May 10 10:17:32 oolong ntpd[615]: ARCRON: sync finished, signal quality 5: OK, will use clock
+May 10 11:13:01 oolong ntpd[615]: ARCRON: unit 0: sending resync command
+May 10 11:14:06 oolong ntpd[615]: ARCRON: sync finished, signal quality -1: UNKNOWN, will use clock anyway
+May 10 11:41:49 oolong ntpd[615]: ARCRON: unit 0: sending resync command
+May 10 11:43:57 oolong ntpd[615]: ARCRON: sync finished, signal quality 5: OK, will use clock
+May 10 12:39:26 oolong ntpd[615]: ARCRON: unit 0: sending resync command
+May 10 12:41:34 oolong ntpd[615]: ARCRON: sync finished, signal quality 3: OK, will use clock
+ +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0. On a Sun SparcStation 1 running SunOS 4.1.3_U1, with +the receiver in London, a value of 0.020 (20ms) seems to be appropriate.
+ +
+time2 time
+ +
+Not currently used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0. +It is suggested that the clock be fudged to stratum 1 so this it is used +a backup time source rather than a primary when more accurate sources are +available.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default MSFa.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+If set to 1, better precision is reported (and thus lower dispersion) while +clock's received signal quality is known to be good.
+ +
+flag4 0 | 1
+ +
+If set to 1, a longer-than-normal (8-stage rather than 4-stage) median +filter is used, to provide some extra smoothing of clock output and reduction +in jitter, at the cost of extra clock overshoot. Probably not advisable +unless the server using this clock has other sources it can use to help +mitigate the overshoot.
+
+ +

+Additional Information

+Reference Clock Drivers + +

ARC Rugby MSF Receiver +page  +


+
+Damon Hart-Davis (d@hd.org)
+ + + diff --git a/contrib/ntp/html/driver28.htm b/contrib/ntp/html/driver28.htm new file mode 100644 index 000000000000..787ccb41786d --- /dev/null +++ b/contrib/ntp/html/driver28.htm @@ -0,0 +1,133 @@ + + + + + Shared memoy Driver + + + + +

+Shared Memory Driver

+ +
+

+Synopsis

+Address: 127.127.28.u +
Reference ID: SHM +
Driver ID: SHM +

+Description

+This driver receives its reference clock info from a shared memory-segment. +The shared memory-segment is created with owner-only access for unit 0 +and 1, and world access for unit 2 and 3 +

+Structure of shared memory-segment

+ +
struct shmTime {
+  int    mode; /* 0 - if valid set
+                *       use values, 
+                *       clear valid
+                * 1 - if valid set 
+                *       if count before and after read of 
+                *       values is equal,
+                *         use values 
+                *       clear valid
+                */
+  int    count;
+  time_t clockTimeStampSec;      /* external clock */
+  int    clockTimeStampUSec;     /* external clock */
+  time_t receiveTimeStampSec;    /* internal clock, when external value was received */
+  int    receiveTimeStampUSec;   /* internal clock, when external value was received */
+  int    leap;
+  int    precision;
+  int    nsamples;
+  int    valid;
+  int    dummy[10]; 
+};
+ +

+Operation mode=0

+When the poll-method of the driver is called, the valid-flag of the shared +memory-segment is checked: + +

If set, the values in the record (clockTimeStampSec, clockTimeStampUSec, +receiveTimeStampSec, receiveTimeStampUSec, leap, precision) are passed +to ntp, and the valid-flag is cleared. + +

If not set, a timeout is reported to ntp, nothing else happend +

+Operation mode=1

+When the poll-method of the driver is called, the valid-flag of the shared +memory-segment is checked: + +

If set, the count-field of the record is remembered, and the values +in the record (clockTimeStampSec, clockTimeStampUSec, receiveTimeStampSec, +receiveTimeStampUSec, leap, precision) are read. Then, the remembered count +is compared to the count now in the record. If both are equal, the values +read from the record are passed to ntp. If they differ, another process +has modified the record while it was read out (was not able to produce +this case), and failure is reported to ntp. The valid flag is cleared. + +

If not set, a timeout is reported to ntp, nothing else happend +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default SHM.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+ + +

Additional Information + +

Reference Clock Drivers

+ + + diff --git a/contrib/ntp/html/driver29.htm b/contrib/ntp/html/driver29.htm new file mode 100644 index 000000000000..3cddfc2a355c --- /dev/null +++ b/contrib/ntp/html/driver29.htm @@ -0,0 +1,1254 @@ + + + + + Trimble Palisade Receiver + + + +

+Trimble Palisade Receiver +

+ +

+

+ +

+Synopsis

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Address: 
+
127.127.29.u
+
Reference ID:
+
GPS
+
Driver ID:
+
GPS_PALISADE
+
Serial Port:
+
/dev/palisadeu
+
Serial I/O:
+
9600 baud, 8-bits, 1-stop, odd parity
+ +

+Description

+The refclock_palisade driver supports Trimble +Navigation's Palisade Smart Antenna GPS receiver. +
Additional software and information about the Palisade GPS is available +from: http://www.trimble.com/oem/ntp. +
Latest NTP driver source, executables and documentation is maintained +at: +ftp://ftp.trimble.com/pub/ntp +

This documentation describes version 7.12 of the GPS Firmware and version +2.46 (July 15, 1999) and later, of the driver source. +
  +

+Operating System Compatibility

+The Palisade driver has been tested on the following software and hardware +platforms: +
  +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PlatformOperating SystemNTP SourcesAccuracy
i386 (PC) LinuxNTP Distribution10 us
i386 (PC) Windows NTftp://ftp.trimble.com/pub/ntp1 ms
SUNSolaris 2.xNTP Distribution50 us
Hewlett-PackardHPUX 9, 10, 11http://us-support.external.hp.com50 us
VariousFree BSDNTP Distribution20 us
+ +

+GPS Receiver

+The Palisade GPS receiver is an 8-channel smart antenna, housing the GPS +receiver, antenna and interface in a single unit, and is designed for rooftop +deployment in static timing applications. +

Palisade generates a PPS synchronized to UTC within +/- 100 ns.  +The Palisade's external event input with 40 nanosecond resolution is utilized +by the Palisade NTP driver for asynchronous precision time transfer. +

No user initialization of the receiver is required. This driver is compatible +with the following versions of Palisade: +
  +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Version
+
+
Event Input
+
+
Trimble Part Number
+
+
7.02
+
+
No
+
+
26664-00
+
+
7.02E
+
+
Yes
+
+
26664-10
+
+
7.12
+
+
Yes
+
+
38158-00
+
+ +
+
Note: When using Palisade 26664-00, you must set fudge flag2 to 1 in +ntp.conf. +See configuration.
+ +
+

+GPS Installation

+A location with unobstructed view of the horizon is recommended. Palisade +is designed to be securely mounted atop standard 3/4 inch threaded pipe. +

The 12 conductor (dia. 10 mm)  power and I/O cable must be routed +from the rooftop site to the NTP server and properly strain relieved. +

+GPS Connection

+The Palisade is equipped with dual (A & B) RS-422 serial interfaces +and a differential TTL PPS output. An RS-232 / RS-422 Interface Module +is supplied with the Palisade NTP Synchronization Kit. Palisade port +A must be connected to the NTP host server. Maximum antenna cable length +is 500 meters. See the pinouts table for detailed +connection Information. +

Palisade's port B provides a TSIP (Trimble Standard +Interface Protocol) interface for diagnostics, configuration, and monitoring. +Port B and the PPS output are not currently used by the Palisade NTP reference +clock driver. +
 

+
+ +

+O/S Serial Port Configuration

+The driver attempts to open the device /dev/palisadeu +where +u is the NTP refclock unit number as defined by the +LSB of the refclock address.  Valid refclock unit numbers are 0 - +3. +

The user is expected to provide a symbolic link to an available serial +port device.  This is typically performed by a command such as: +

ln -s /dev/ttyS0 /dev/palisade0
+Windows NT does not support symbolic links to device files. COMx: +is used by the driver, based on the refclock unit number, where unit 1 +corresponds to COM1: and unit 3 corresponds to COM3: +
  +

+NTP Configuration

+Palisade NTP configuration file "ntp.conf" with event polling: +
#------------------------------------------------------------------------------ +
# The Primary reference +
server 127.127.29.0 # Trimble Palisade GPS Refclock Unit #0 +
peer terrapin.csc.ncsu.edu # internet server +
# Drift file for expedient re-synchronization after downtime or +reboot. +
driftfile /etc/ntp.drift +
#------------------------------------------------------------------------------ +

Configuration without event polling: +
#------------------------------------------------------------------------------ +
# The Primary reference +
server 127.127.29.0 # Trimble Palisade GPS (Stratum 1). +
# Set packet delay +
fudge 127.127.29.0 time1 0.020 +
# and set flag2 to turn off event polling. +
fudge 127.127.29.0 flag2 1 +
#------------------------------------------------------------------------------ +
  +

+Time Transfer and Polling

+Time transfer to the NTP host is performed via the Palisade's comprehensive +time packet output. The time packets are output once per second, and whenever +an event timestamp is requested. +

The driver requests an event time stamp at the end of each polling interval, +by pulsing the RTS (request to send) line on the serial port. The Palisade +GPS responds with a time stamped event packet. +

Time stamps are reported by the Palisade with respect to UTC time. The +GPS receiver must download UTC offset information from GPS satellites. +After an initial UTC download, the receiver will always start with correct +UTC offset information. +
  +

+Run NTP in Debugging Mode

+The following procedure is recommended for installing and testing a Palisade +NTP driver: +
    +
  1. +Perform initial checkout procedures. Place the GPS receiver outdoors; with +clear view of the sky. Allow the receiver to obtain an UTC almanac.
  2. + +
  3. +Verify presence of timing packets by observing the 1 Hz (PPS) led on the +interface module. It should flash once per second.
  4. + +
  5. +Connect Palisade's port A to the NTP host.
  6. + +
  7. +Configure NTP and the serial I/O port on the host system.
  8. + +
  9. +Initially use fudge flag2 in ntp.conf, +to disable event polling (see configuration).
  10. + +
  11. +Run NTP in debug mode (-d -d), to observe Palisade_receive events.
  12. + +
  13. +The driver reports the tracking status of the +receiver. Make sure it is tracking several satellites.
  14. + +
  15. +Remove fudge flag2 and restart ntpd in debug mode to observe palisade_receive +events.
  16. + +
  17. +If event polling fails, verify the connections and +that the host hardware supports RTS control.
  18. +
+ +

+Event Logging

+System and Event log entries are generated by NTP to report significant +system events. Administrators should monitor the system log to observe +NTP error messages. Log entries generated by the Palisade NTP reference +clock driver will be of the form: +
+
Nov 14 16:16:21 terrapin ntpd[1127]: Palisade #0: message
+
+ +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0. If event capture is not used, time1 should be set to +20 milliseconds to correct serial line and operating system delays incurred +in capturing time stamps from the synchronous packets.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, GPS.
+ +
+flag2 0 +| 1
+ +
+When set to 1, driver does not use hardware event capture. The synchronous +packet output by the receiver at the beginning of each second is time stamped +by the driver. If triggering the event pulse fails, the driver falls back +to this mode automatically.
+
+ +

+DEFINEs

+The following constants are defined in the driver source code. These defines +may be modified to improve performance or adapt to new operating systems. +
  +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LabelDefinitionDefault Value
DEVICEThe serial port device to be used by the driver/dev/palisadeu
PRECISIONAccuracy of time transfer1 microsecond
CURRENT_UTCValid GPS - UTC offset13
SPEED232Host RS-232 baud rateB9600
TRMB_MINPOLL Minimum polling interval5 (32 seconds)
TRMB_MAXPOLLMaximum interval between polls7 (128 seconds)
+ +

+Data Format

+Palisade port A can output two synchronous time packets. The NTP driver +can use either packet for synchronization. Packets are formatted as follows: +

+Packet 8F-AD (Primary NTP Packet)

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ByteItemTypeMeaning
0Sub-Packet IDBYTESubcode 0xAD
1 - 2Event CountINTEGERExternal event count recorded (0 = PPS)
3 - 10Fractional SecondDOUBLETime elapsed in current second (s)
11HourBYTEHour (0 - 23)
12MinuteBYTEMinute (0 - 59)
13SecondBYTESecond (0 - 59; 60 = leap)
14DayBYTEDate (1 - 31)
15MonthBYTEMonth (1 - 12)
16 - 17YearINTEGERYear (4 digit)
18Receiver StatusBYTETracking Status
19UTC FlagsBYTELeap Second Flags
20ReservedBYTEContains 0xFF
21ReservedBYTEContains 0xFF
+ +
+

+Leap Second Flag Definition:

+Bit 0:  (1) UTC Time is available +
Bits 1 - 3: Undefined +
Bit 4:  (1) Leap Scheduled: Leap second pending asserted by GPS +control segment. +
Bit 5:  (1) Leap Pending: set 24 hours before, until beginning +of leap second. +
Bit 6:  (1) GPS Leap Warning: 6 hours before until 6 hours after +leap event +
Bit 7:  (1) Leap In Progress. Only set during the leap second. +

+Tracking Status Flag Definitions:

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CodeMeaningAccuracyReceiver Mode
0Receiver is Navigating+/- 1 usSelf Survey
1Static 1 Sat. Timing Mode +/- 1 us1-D Timing
2Approximate Time20 - 50 msAcquisition
3StartupN/AInitialization
4StartupN/AInitialization
5Dilution of Position too High 5 ppmSelf Survey
6Static 1 Sat. Timing: Sat. not usable5 ppm1-D Timing
7No Satellites UsableN/ASelf Survey
8Only 1 Satellite Usable20 - 50 msSelf Survey
9Only 2 Satellite Usable20 - 50 msSelf Survey
10Only 3 Satellites Usable20 - 50 msSelf Survey
11Invalid SolutionN/AError
12Differential Corrections N/AN/A
13Overdetermined Fixes+/- 100 nsTiming Steady State
+ +

+Packet 8F-0B (Comprehensive Timing Packet)

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ByteItemTypeMeaning
0Sub-Packet IDBYTESubcode 0x0B
1 - 2Event CountINTEGERExternal event count recorded (0 = PPS)
3 - 10UTC / GPS TOWDOUBLEUTC / GPS time of week (seconds)
11DateBYTEDay of Month
12MonthBYTEMonth of Event
13 - 14YearINTYear of event
15Receiver ModeBYTEReceiver operating dimensions:  +
0: Horizontal (2D)  +
1: Full Position (3D)  +
2: Single Satellite (0D)  +
3: Automatic (2D / 3D)  +
4: DGPS reference  +
5: Clock hold (2D)  +
6: Over determined Clock
15 - 17UTC OffsetINTEGERUTC Offset value (seconds)
18 - 25Oscillator BiasDOUBLEOscillator BIAS (meters)
26 - 33Oscillator Drift RateDOUBLEOscillator Drift (meters / second)
34 - 37Bias UncertaintySINGLEOscillator bias uncertainty (meters)
38 - 41Drift UncertaintySINGLEOscillator bias rate uncertainty (m / sec)
42 - 49LatitudeDOUBLELatitude in radians
50 - 57LongitudeDOUBLELongitude in radians
58 - 65AltitudeDOUBLEAltitude above mean sea level, in meters
66 - 73Satellite IDBYTESV Id No. of tracked satellites
+ +

+Pinouts

+The following connections are required when connecting +Palisade with a host: +
  +
  +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DescriptionHostPalisade 
Port ADB-9DB-25RS-232RS-422Palisade Pin
Receive Data 23<-->GreenGreen / Blue8 (T-) & 10 (T+)
Request to Send74<-->GrayGray / White6 (R-) & 7 (R+)
Signal Ground57<-->BlackBlack9 (GND)
Port B
Receive Data 23<-->BrownBrown / Yellow4 (T-) & 5 (T+)
Transmit Data32<-->VioletOrange/ Violet2 (R-) & 3 (R+)
Signal Ground57<-->BlackBlack9 (GND)
+ +
Note: If driving the RS-422 inputs on the Palisade single ended, +i.e. using the Green and Gray connections only, does not work on all serial +ports. Use of the Palisade NTP Synchronization Interface Module is recommended.
+ +
The 12 pin connector pinout definition: +
Face the round 12 pin connector at the end of the cable, with the notch +turned upwards. +
Pin 1 is to the left of the notch. Pins 2 - 8 wrap around the bottom, +counterclockwise to pin 9 on the right of the notch. Pin 10 is just below +the notch. Pins 10 (top), 11 (bottom left) and 12 (bottom right) form a +triangle in the center of the connector.
+ +
Pinouts for the Palisade NTP host adapter +(Trimble PN 37070) DB-25 M connector are as follows:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DB-25MConductor PalisadeDescription
Red1Power
Black9Ground
9Black/White12PPS -
10 Green8Transmit Port A (T-)
11 Brown4Transmit Port B (T-)
12 Gray7Receive Port A (R+)
13Orange3Receive Port B (R+)
21Orange/White11PPS +
22Blue10Transmit Port A (T+)
23Yellow5Transmit Port B (T+)
24White6Receive Port A (R-)
25Violet2Receive Port B (R-)
+ +

+


+

Questions or Comments: +
Sven Dietrich +
Trimble Navigation Ltd. +

(last updated July 29, 1999) +
  + + diff --git a/contrib/ntp/html/driver3.htm b/contrib/ntp/html/driver3.htm new file mode 100644 index 000000000000..47511d85b962 --- /dev/null +++ b/contrib/ntp/html/driver3.htm @@ -0,0 +1,131 @@ + + + + + PSTI/Traconex 1020 WWV/WWVH Receiver + + + + +

+PSTI/Traconex 1020 WWV/WWVH Receiver

+ +
+

+Synopsis

+Address: 127.127.3.u +
Reference ID: WWV +
Driver ID: WWV_PST +
Serial Port: /dev/wwvu; 9600 baud, 8-bits, no parity +
Features: tty_clk +

+Description

+This driver supports the PSTI 1010 and Traconex 1020 WWV/WWVH Receivers. +No specific claim of accuracy is made for these receiver, but actual experience +suggests that 10 ms would be a conservative assumption. + +

The DIP-switches should be set for 9600 bps line speed, 24-hour day-of-year +format and UTC time zone. Automatic correction for DST should be disabled. +It is very important that the year be set correctly in the DIP-switches; +otherwise, the day of year will be incorrect after 28 April of a normal +or leap year. The propagation delay DIP-switches should be set according +to the distance from the transmitter for both WWV and WWVH, as described +in the instructions. While the delay can be set only to within 11 ms, the +fudge time1 parameter can be used for vernier corrections. + +

Using the poll sequence QTQDQM, the response timecode is in +three sections totalling 50 ASCII printing characters, as concatenated +by the driver, in the following format: +

ahh:mm:ss.fffs<cr> yy/dd/mm/ddd<cr>
+frdzycchhSSFTttttuuxx<cr>
+
+on-time = first <cr>
+hh:mm:ss.fff = hours, minutes, seconds, milliseconds
+a = AM/PM indicator (' ' for 24-hour mode)
+yy = year (from DIPswitches)
+dd/mm/ddd = day of month, month, day of year
+s = daylight-saving indicator (' ' for 24-hour mode)
+f = frequency enable (O = all frequencies enabled)
+r = baud rate (3 = 1200, 6 = 9600)
+d = features indicator (@ = month/day display enabled)
+z = time zone (0 = UTC)
+y = year (5 = 91)
+cc = WWV propagation delay (52 = 22 ms)
+hh = WWVH propagation delay (81 = 33 ms)
+SS = status (80 or 82 = operating correctly)
+F = current receive frequency (4 = 15 MHz)
+T = transmitter (C = WWV, H = WWVH)
+tttt = time since last update (0000 = minutes)
+uu = flush character (03 = ^c)
+xx = 94 (unknown)
+The alarm condition is indicated by other than 8 at a, +which occurs during initial synchronization and when received signal is +lost for an extended period; unlock condition is indicated by other than +0000 in the tttt subfield. +

+Monitor Data

+When enabled by the flag4 fudge flag, every received timecode +is written as-is to the clockstats file. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default WWV.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Not used by this driver.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver30.htm b/contrib/ntp/html/driver30.htm new file mode 100644 index 000000000000..8d547b180c43 --- /dev/null +++ b/contrib/ntp/html/driver30.htm @@ -0,0 +1,153 @@ + + + + + + Motorola Oncore GPS Receiver + + + + +

+Motorola Oncore GPS receiver

+ +
+

+Synopsis

+ +Address: 127.127.30.0 +
Reference ID: GPS +
Driver ID: ONCORE +
Serial Port: /dev/cuaa0; 9600 baud, 8-bits, no parity +
PPS Port: /dev/xpps0; PPS_CAPTUREASSERT +required, PPS_OFFSETASSERT supported. +

+Description

+This driver supports various models of the Motorola Oncore GPS +receivers. as long as they support the Motorola Binary +Protocol. + +

The two most interesting version of the Oncore are the "UT+"  +and the "Remote" which is a prepackaged "UT+".  The evaluation kit +can also be recommended, it interfaces to a PC straightaway, using the +parallel port for PPS input (supported under FreeBSD), and packs the +receiver in a nice and sturdy box. +
  +

+ + + + + + + + + + + + + + + +
+
UT+ oncore
+
+
Evaluation kit
+
+
Oncore Remote
+
+ +

The driver requires a standard PPS interface for the pulse- +per-second output from the receiver.  The serial data stream alone +does not provide precision time stamps (0-50msec variance, according to +the manual), whereas the PPS output is precise down to 50 nsec (1 sigma) +for the UT models.

The driver will use the "position hold" mode if +available, with either the receivers built-in site-survey or a similar +algorithm implemented in this driver. +

+Monitor Data

+The driver is quite chatty on stdout if ntpd is run with +debugging.  +A manual will be required though. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default +0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default GPS.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Assume GPS receiver is on a mobile platform if set.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+
+Additional Information +

The driver has been developed under FreeBSD, and may still be pretty +FreeBSD centric.  Patches are most welcome. +

Performance +

Really good.  With the UT+, the generated PPS pulse is +referenced +to UTC(GPS) with better than 50 nsec (1 sigma) accuracy.  The +limiting factor will be the timebase of the computer and the precision +with which you can timestamp the rising flank of the +PPS signal.  +Using FreeBSD,  a FPGA based Timecounter/PPS interface +and +an ovenized quartz oscillator, that performance has been reproduced. + For +more details on this aspect:  Sub-Microsecond +timekeeping under FreeBSD +


+
+Poul-Henning Kamp (phk@FreeBSD.org)
+ + + diff --git a/contrib/ntp/html/driver32.htm b/contrib/ntp/html/driver32.htm new file mode 100644 index 000000000000..208ad5c02e42 --- /dev/null +++ b/contrib/ntp/html/driver32.htm @@ -0,0 +1,42 @@ + + + +Chrono-log K-series WWVB receiver + + + +

Chrono-log K-series WWVB receiver

+ +
+

Synopsis

+Address: 127.127.32.u
+Reference ID: CHRONOLOG
+Driver ID: CHRONOLOG
+Serial Port: /dev/chronologu; 2400 bps, 8-bits, +no parity
+
Features: (none) +

Description

+This driver supports the Chrono-log K-series WWVB receiver. This is a +very old receiver without provisions for leap seconds, quality codes, +etc. It assumes output in the local time zone, and that the C library +mktime()/localtime() routines will correctly convert back and forth +between local and UTC. There is a hack in the driver for permitting +UTC, but it has not been tested. + +

Most of this code is originally from refclock_wwvb.c with thanks. It +has been so mangled that wwvb is not a recognizable ancestor. +

+Timecode format: Y yy/mm/ddCLZhh:mm:ssCL
+Y - year/month/date line indicator
+yy/mm/dd -- two-digit year/month/day
+C - \r (carriage return)
+L - \n (newline)
+Z - timestamp indicator
+hh:mm:ss - local time
+
+
+
+ +Last modified: Sun Feb 14 11:57:27 EST 1999 + + diff --git a/contrib/ntp/html/driver33.htm b/contrib/ntp/html/driver33.htm new file mode 100644 index 000000000000..768cfe72667f --- /dev/null +++ b/contrib/ntp/html/driver33.htm @@ -0,0 +1,38 @@ + + + +Dumb Clock + + + +

Dumb Clock

+ +
+

Synopsis

+Address: 127.127.33.u
+Reference ID: DUMBCLOCK
+Driver ID: DUMBCLOCK
+Serial Port: /dev/dumbclocku; 9600 bps, 8-bits, +no parity
+
Features: (none) +

Description

+This driver supports a dumb ASCII clock that only emits localtime at a reliable +interval. This has no provisions for leap seconds, quality codes, +etc. It assumes output in the local time zone, and that the C library +mktime()/localtime() routines will correctly convert back and forth +between local and UTC. + +

Most of this code is originally from refclock_wwvb.c with thanks. It +has been so mangled that wwvb is not a recognizable ancestor. +

+Timecode format: hh:mm:ssCL
+hh:mm:ss - local time
+C - \r (carriage return)
+L - \n (newline)
+
+
+
+ +Last modified: Sun Feb 14 12:07:01 EST 1999 + + diff --git a/contrib/ntp/html/driver34.htm b/contrib/ntp/html/driver34.htm new file mode 100644 index 000000000000..e9dcdbca4e65 --- /dev/null +++ b/contrib/ntp/html/driver34.htm @@ -0,0 +1,54 @@ + + + +Dumb Clock + + + +

Ultralink Clock

+ +
+

Synopsis

+Address: 127.127.34.u
+Reference ID: ULINK
+Driver ID: ULINK
+Serial Port: /dev/ulinku; 9600 bps, 8-bits, +no parity
+
Features: (none) +

Description

+This driver supports the Ultralink Model 320 RS-232 powered WWVB receiver. PDF specs available on www.linuxfoundary.com. While the unit may support them, this driver does nothing with leap seconds, quality codes, etc. (though it probably should). + +

Most of this code is originally from refclock_wwvb.c with thanks. Any mistakes are mine. Any improvements are welcome. + +

+  The timecode format is:
+ 
+   SQRYYYYDDD+HH:MM:SS.mmLT
+ 
+  where:
+ 
+  S = 'S' -- sync'd in last hour, '0'-'9' - hours x 10 since last update, else '?'
+  Q = Number of correlating time-frames, from 0 to 5
+  R = 'R' -- reception in progress, 'N' -- Noisy reception, ' ' -- standby mode
+  YYYY = year from 1990 to 2089
+  DDD = current day from 1 to 366
+  + = '+' if current year is a leap year, else ' '
+  HH = UTC hour 0 to 23
+  MM = Minutes of current hour from 0 to 59
+  SS = Seconds of current minute from 0 to 59
+  mm = 10's milliseconds of the current second from 00 to 99
+  L  = Leap second pending at end of month -- 'I' = inset, 'D'=delete
+  T  = DST <-> STD transition indicators
+ 
+  Note that this driver does not do anything with the L or T flags.
+ 
+  The M320 also has a 'U' command which returns UT1 correction information.  It
+  is not used in this driver.
+
+
+
+
root
+ +Last modified: Tue Sep 14 05:53:08 EDT 1999 + + diff --git a/contrib/ntp/html/driver4.htm b/contrib/ntp/html/driver4.htm new file mode 100644 index 000000000000..4f3abd756afe --- /dev/null +++ b/contrib/ntp/html/driver4.htm @@ -0,0 +1,126 @@ + +Spectracom 8170 and Netclock/2 WWVB Receivers +

+Spectracom 8170 and Netclock/2 WWVB Receivers +


+ +

Synopsis

+ +Address: 127.127.4.u +
Reference ID: WWVB +
Driver ID: WWVB_SPEC +
Serial Port: /dev/wwvbu; 9600 baud, 8-bits, no +parity +
Features: tty_clk + +

Description

+ +This driver supports all known Spectracom radio and satellite clocks, +including the Model 8170 and Netclock/2 WWVB Synchronized Clocks and the +Netclock/GPS GPS Master Clock. The claimed accuracy of the WWVB clocks +is 100 usec relative to the broadcast signal. These clocks have proven a +reliable source of time, except in some parts of the country with high +levels of conducted RF interference. WIth the GPS clock the claimed +accuracy is 130 ns. However, in most cases the actual accuracy is +limited by the precision of the timecode and the latencies of the serial +interface and operating system. + +

The DIPswitches on these clocks should be set to 24-hour display, +AUTO DST off, data format 0 or 2 (see below) and baud rate 9600. If this +clock is used as the source for the IRIG Audio Decoder +(refclock_irig.c in this distribution), set the DIPswitches for +AM IRIG output and IRIG format 1 (IRIG B with signature control). + +

There are two timecode formats used by these clocks. Format 0, which +is available with all clocks, and format 2, which is available with all +clocks except the original (unmodified) Model 8170. + +

Format 0 (22 ASCII printing characters): +
<cr><lf>i ddd hh:mm:ss TZ=zz<cr><lf> + +

on-time = first <cr> +
i = synchronization flag (' ' = in synch, '?' = out synch) +
hh:mm:ss = hours, minutes, seconds + +

The alarm condition is indicated by other than ' ' at i, +which occurs during initial synchronization and when received signal is +lost for about ten hours. + +

Format 2 (24 ASCII printing characters): +
lt;cr>lf>iqyy ddd hh:mm:ss.fff ld + +

on-time = <cr> +
i = synchronization flag (' ' = in synch, '?' = out synch) +
q = quality indicator (' ' = locked, 'A'...'D' = unlocked) +
yy = year (as broadcast) +
ddd = day of year +
hh:mm:ss.fff = hours, minutes, seconds, milliseconds + +

The alarm condition is indicated by other than ' ' at i, +which occurs during initial synchronization and when received signal is +lost for about ten hours. The unlock condition is indicated by other +than ' ' at q. + +

The q is normally ' ' when the time error is less than 1 ms +and a character in the set A...D when the time error is less +than 10, 100, 500 and greater than 500 ms respectively. The l +is normally ' ', but is set to L early in the month of an +upcoming UTC leap second and reset to ' ' on the first day of the +following month. The d is set to S for standard time +S, I on the day preceding a switch to daylight time, +D for daylight time and O on the day preceding a +switch to standard time. The start bit of the first +<cr> is synchronized to the indicated time as returned. + +

This driver does not need to be told which format is in use - it +figures out which one from the length of the message. 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. + +

Monitor Data

+ +The driver writes each timecode as received to the clockstats +file. When enabled by the flag4 fudge flag, a table of quality +data maintained internally by the Netclock/2 is retrieved and written to +the clockstats file when the first timecode message of a new +dayis received. + +

Fudge Factors

+ +
+ +
time1 time
+
Specifies the time offset calibration factor, in seconds and +fraction, +with default 0.0.
+ +
time2 time
+
Not used by this driver.
+ +
stratum number
+
Specifies the driver stratum, in decimal from 0 to 15, with default +0.
+ +
refid string
+
Specifies the driver reference identifier, an ASCII string from one +to four characters, with default WWVB.
+ +
flag1 0 | 1
+
Not used by this driver.
+ +
flag2 0 | 1
+
Not used by this driver.
+ +
flag3 0 | 1
+
Not used by this driver.
+ +
flag4 0 | 1
+
Enable verbose clockstats recording if set.
+ +
+ +Additional Information + +

Reference Clock Drivers +


David L. Mills (mills@udel.edu)
diff --git a/contrib/ntp/html/driver5.htm b/contrib/ntp/html/driver5.htm new file mode 100644 index 000000000000..edbd0458292b --- /dev/null +++ b/contrib/ntp/html/driver5.htm @@ -0,0 +1,159 @@ + + + + + TrueTime GPS/GOES/OMEGA Receivers + + + + +

+TrueTime GPS/GOES/OMEGA Receivers

+ +
+

+Synopsis

+Address: 127.127.5.u +
Reference ID: GPS, OMEGA, GOES +
Driver ID: TRUETIME +
Serial Port: /dev/trueu; 9600 baud, 8-bits, no parity +
Features: tty_clk +

+Description

+This driver supports several models models of Kinemetrics/TrueTime timing +receivers, including 468-DC MK III GOES Synchronized Clock, GPS- DC MK +III and GPS/TM-TMD GPS Synchronized Clock, XL-DC (a 151-602-210, reported +by the driver as a GPS/TM-TMD), GPS-800 TCU (an 805-957 with the RS232 +Talker/Listener module), OM-DC OMEGA Synchronized Clock, and very likely +others in the same model family that use the same timecode formats. + +

Most of this code is originally from refclock_wwvb.c with thanks. It +has been so mangled that wwvb is not a recognizable ancestor. +

Timcode format: ADDD:HH:MM:SSQCL
+
+A - control A (this is stripped before we see it)
+Q - Quality indication (see below)
+C - Carriage return
+L - Line feed
+
+Quality codes indicate possible error of
+
+        468-DC GOES Receiver:
+        GPS-TM/TMD Receiver:
+                ? +/- 500 milliseconds  # +/- 50 milliseconds
+                * +/- 5 milliseconds    . +/- 1 millisecond
+                space less than 1 millisecond
+
+        OM-DC OMEGA Receiver:
+
+                > +/- 5 seconds
+
+                ? +/- 500 milliseconds  # +/- 50 milliseconds
+                * +/- 5 milliseconds    . +/- 1 millisecond
+
+                A-H less than 1 millisecond. Character indicates which
+station
+                is being received as follows: A = Norway, B = Liberia,
+                C = Hawaii, D = North Dakota, E = La Reunion, F =
+Argentina,
+                G = Australia, H = Japan.
+The carriage return start bit begins on 0 seconds and extends to 1 bit +time. + +

Notes on 468-DC and OMEGA receiver: + +

Send the clock a R or C and once per second a timestamp +will appear. Send a R to get the satellite position once (GOES +only). + +

Notes on the 468-DC receiver: + +

Since the old east/west satellite locations are only historical, you +can't set your clock propagation delay settings correctly and still use +automatic mode. The manual says to use a compromise when setting the switches. +This results in significant errors. The solution; use fudge time1 and time2 +to incorporate corrections. If your clock is set for 50 and it should be +58 for using the west and 46 for using the east, use the line + +

fudge 127.127.5.0 time1 +0.008 time2 -0.004 + +

This corrects the 4 milliseconds advance and 8 milliseconds retard needed. +The software will ask the clock which satellite it sees. + +

The PCL720 from PC Labs has an Intel 8253 look-alike, as well as a bunch +of TTL input and output pins, all brought out to the back panel. If you +wire a PPS signal (such as the TTL PPS coming out of a GOES or other Kinemetrics/Truetime +clock) to the 8253's GATE0, and then also wire the 8253's OUT0 to the PCL720's +INPUT3.BIT0, then we can read CTR0 to get the number of microseconds since +the last PPS upward edge, mediated by reading OUT0 to find out if the counter +has wrapped around (this happens if more than 65535us (65ms) elapses between +the PPS event and our being called.) +

+Monitor Data

+When enabled by the flag4 fudge flag, every received timecode +is written as-is to the clockstats file. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +to be used for the West satellite, with default 0.0.
+ +
+time2 time
+ +
+. Specifies the time offset calibration factor, in seconds and fraction, +to be used for the East satellite, with default 0.0.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default TRUE.
+ +
+flag1 0 | 1
+ +
+Silence the clock side of ntpd, just reading the clock without trying to +write to it.
+ +
+flag2 0 | 1
+ +
+Generate a debug file /tmp/true%d.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver6.htm b/contrib/ntp/html/driver6.htm new file mode 100644 index 000000000000..a728a542adf2 --- /dev/null +++ b/contrib/ntp/html/driver6.htm @@ -0,0 +1,253 @@ + + + + + IRIG Audio Decoder II for Sun SPARCstation + + + + +

+IRIG Audio Decoder

+ +
+

+Synopsis

+Address: 127.127.6.u +
Reference ID: IRIG +
Driver ID: IRIG_AUDIO +
Audio Device: /dev/audio and /dev/audioctl + +

Note: This driver supersedes an older one of the same name, address +and ID which required replacing the original kernel audio driver with another +which works only on older Sun SPARCstation systems. The new driver described +here uses the stock kernel audio driver and works in SunOS 4.1.3 and Solaris +2.6 versions and probably all versions in between. The new driver requires +no modification of the operating system. While it is generic and likely +portable to other systems, it is somewhat slower than the original, since +the extensive signal conditioning, filtering and decoding is done in user +space, not kernel space. +

+Description

+This driver supports the Inter-Range Instrumentation Group (IRIG) standard +time distribution signal using the audio codec native to the Sun SPARCstation. +This signal is generated by several radio clocks, including those made +by Arbiter, Austron, Bancomm, Odetics, Spectracom and TrueTime, among others, +although it is often an add-on option. The signal is connected via an optional +attenuator box and cable to either the microphone or line-in ports on a +Sun SPARCstation /dev/audio audio codec device. The driver receives, +demodulates and decodes the IRIG-B and IRIG-E signal formats using internal +filters designed to reduce the effects of noise and interfering signals. + +

The IRIG signal format uses an amplitude-modulated carrier with pulse-width +modulated data bits. For IRIG-B, the carrier frequency is 1000 Hz and bit +rate 100 b/s; for IRIG-E, the carrier frequenchy is 100 Hz and bit rate +10 b/s. While IRIG-B provides the best accuracy, generally within a few +tens of microseconds relative to IRIG time, it can also generate a significant +load on the processor with older workstations. Generally, the accuracy +with IRIG-E is about ten times worse than IRIG-B, but the processor load +is ten times less. + +

The program processes 8000-Hz mu-law companded samples using separate +signal filters for IRIG-B and IRIG-E, a comb filter, envelope detector +and automatic threshold corrector. Cycle crossings relative to the corrected +slice level determine the width of each pulse and its value - zero, one +or position identifier. The data encode 20 BCD digits which determine the +second, minute, hour and day of the year and sometimes the year and synchronization +condition. The comb filter exponentially averages the corresponding samples +of successive baud intervals in order to reliably identify the reference +carrier cycle. A type-II phase-lock loop (PLL) performs additional integration +and interpolation to accurately determine the zero crossing of that cycle, +which determines the reference timestamp. A pulse-width discriminator demodulates +the data pulses, which are then encoded as the BCD digits of the timecode. +The timecode and reference timestamp are updated once each second with +IRIG-B (ten seconds with IRIG-E) and local clock offset samples saved for +later processing. At poll intervals of 64 s, the saved samples are processed +by a trimmed-mean filter and used to update the system clock. + +

Infinite impulse response (IIR) filters are used with both IRIG-B and +IRIG-E formats. An 800-Hz highpass filter is used for IRIG-B and a 130-Hz +lowpass filter for IRIG-E. These are intended for use with noisy signals, +such as might be received over a telephone line or radio circuit, or when +interfering signals may be present in the audio passband. The driver determines +which IRIG format is in use by sampling the amplitude of each filter output +and selecting the one with maximum signal. An automatic gain control feature +provides protection against overdriven or underdriven input signal amplitudes. +It is designed to maintain adequate demodulator signal amplitude while +avoiding occasional noise spikes. In order to assure reliable capture, +the decompanded input signal amplitude must be greater than 100 units and +the codec sample frequency error less than 250 PPM (.025 percent). + +

The program performs a number of error checks to protect against overdriven +or underdriven input signal levels, incorrect signal format or improper +hardware configuration. Specifically, if any of the following errors occur +for a timecode, the data are rejected. Secifically, if any of the following +errors occur for a time measurement, the data are rejected. +

    +
  1. +The peak carrier amplitude is less than 100 units. This usually means dead +IRIG signal source, broken cable or wrong input port.
  2. + +
      +
  3. +The frequency error is greater than +-250 PPM (.025 percent). This usually +means broken codec hardware or wrong codec configuration.
  4. + +
      +
  5. +The modulation index is less than 0.5. This usually means overdriven IRIG +signal or wrong IRIG format.
  6. + +
      +
  7. +A frame synchronization error has occured. This usually means wrong IRIG +signal format or the IRIG signal source has lost synchronization (signature +control).
  8. + +
      +
  9. +A data decoding error has occured. This usually means wrong IRIG signal +format.
  10. + +
      +
  11. +The current second of the day is not exactly one greater than the previous +one. This usually means a very noisy IRIG signal or insufficient CPU resources.
  12. + +
      +
  13. +An audio codec error (overrun) occured. This usually means insufficient +CPU resources, as sometimes happens with Sun SPARC IPCs when doing something +useful.
  14. +
+Note that additional checks are done elsewhere in the reference clock interface +routines. + +

Unlike other drivers, which can have multiple instantiations, this one +supports only one. It does not seem likely that more than one audio codec +would be useful in a single machine. More than one would probably chew +up too much CPU time anyway. +

+IRIG-B Timecode Format

+The 100 elements of the IRIG timecode are numbered from 0 through 99. Position +identifiers occur at elements 0, 9, 19 and every ten thereafter to 99. +The control function (CF) elements begin at element 50 (CF 1) and extend +to element 78 (CF 27). The straight-binary-seconds (SBS) field, which encodes +the seconds of the UTC day, begins at element 80 (CF 28) and extends to +element 97 (CF 44). The encoding of elements 50 (CF 1) through 78 (CF 27) +is device dependent. This driver presently decodes the CF elements, but +does nothing with them. + +

Where feasible, the IRIG signal source should be operated with signature +control so that, if the signal is lost or mutilated, the source produces +an unmodulated signal, rather than possibly random digits. The driver will +automatically reject the data and declare itself unsynchronized in this +case. Some devices, in particular Spectracom radio/satellite clocks, provide +additional year and status indication in the format: +

     Element   CF        Function
+     -------------------------------------
+     55        6         time sync status
+     60-63     10-13     BCD year units
+     65-68     15-18     BCD year tens
+Other devices set these elements to zero. +

+Performance

+The mu-law companded data format allows considerable latitude in signal +levels; however, an automatic gain control (AGC) function is implemented +to further compensate for varying input signal levels and to avoid signal +distortion. For proper operation, the IRIG signal source should be configured +for analog signal levels, NOT digital TTL levels. + +

The accuracy of the system clock synchronized to the IRIG-B source with +this driver and the ntpd daemon is 10-20 microseconds with a Sun +UltraSPARC II and maybe twice that with a Sun SPARC IPC. The processor +resources consumed by the daemon can be significant, ranging from about +1.2 percent on the faster UltraSPARC II to 38 percent on the slower SPARC +IPC. However, the overall timing accuracy is limited by the resolution +and stability of the CPU clock oscillator and the interval between clock +corrections, which is 64 s with this driver. This performance, while probably +the best that can be achieved by the daemon itself, can be improved with +assist from the PPS discipline as described elsewhere in the documentation. +

+Monitor Data

+The timecode format used for debugging and data recording includes data +helpful in diagnosing problems with the IRIG signal and codec connections. +With debugging enabled (-d -d -d on the ntpd command line), the driver +produces one line for each timecode in the following format: +
00 1 98 23 19:26:52 721 143 0.694 47 20 0.083 66.5 3094572411.00027
+The first field containes the error flags in hex, where the hex bits are +interpreted as below. This is followed by the IRIG status indicator, year +of century, day of year and time of day. The status indicator and year +are not produced by some IRIG devices. Following these fields are the signal +amplitude (0-8100), codec gain (0-255), field phase (0-79), time constant +(2-20), modulation index (0-1), carrier phase error (0+-0.5) and carrier +frequency error (PPM). The last field is the on-time timestamp in NTP format. +The fraction part is a good indicator of how well the driver is doing. +With an UltrSPARC 30, this is normally within a few tens of microseconds +relative to the IRIG-B signal and within a few hundred microseconds with +IRIG-E. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default IRIG.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Specifies the microphone port if set to zero or the line-in port if set +to one. It does not seem useful to specify the compact disc player port.
+ +
+flag3 0 | 1
+ +
+Enables audio monitoring of the input signal. For this purpose, the speaker +volume must be set before the driver is started.
+ +
+flag4 0 | 1
+ +
+Enable verbose clockstats recording if set.
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver7.htm b/contrib/ntp/html/driver7.htm new file mode 100644 index 000000000000..0394fbfb3291 --- /dev/null +++ b/contrib/ntp/html/driver7.htm @@ -0,0 +1,227 @@ + + + + + Canadian CHU Radio Modem/Audio Decoder + + + + +

+CHU Audio/Modem Decoder

+ +
+

+Synopsis

+Address: 127.127.7.u +
Reference ID: CHU +
Driver ID: CHU +
Serial Port: /dev/chuu; 300 baud, 8-bits, no parity +
Audio Device: /dev/audio and /dev/audioctl +

+Description

+This driver synchronizes the computer time using data encoded in radio +transmissions from Canadian time/frequency station CHU in Ottawa, Ontario. +Transmissions are made continuously on 3330 kHz, 7335 kHz and 14670 kHz +in upper sideband, compatible AM mode. An ordinary shortwave receiver can +be tuned manually to one of these frequencies or, in the case of ICOM receivers, +the receiver can be tuned automatically using the minimuf and +icom programs as propagation conditions change throughout the +day and night. + +

This driver replaces an earlier one built by Dennis Ferguson in 1988. +The earlier driver required a special line discipline which preprocessed +the signal in order to improve accuracy and avoid errors. The new driver +includes more powerful algorithms implemented directly in the driver and +requires no line discipline. It decodes the data using a maximum-likelihood +technique which exploits the considerable degree of redundancy available +to maximize accuracy and minimize errors. + +

While there are currently no known commercial CHU receivers, a simple +but effective receiver/demodulator can be constructed from an ordinary +shortwave receiver and Bell 103 compatible, 300-bps modem or modem chip, +as described in the Pulse-per-second +(PPS) Signal Interfacing page. The driver can be compiled to use this +modem to receive the radio signal and demodulate the data. Alternatively, +the driver can be compiled to use the audio codec of the Sun workstation +or another with compatible audio drivers. In the latter case, the driver +implements the modem using DSP routines, so the radio can be connected +directly to either the microphone on line input port. + +

The CHU time broadcast includes an audio signal compatible with the +Bell 103 modem standard (mark = 2225 Hz, space = 2025 Hz). It consist of +nine, ten-character bursts transmitted at 300 bps and beginning each second +from second 31 to second 39 of the minute. Each character consists of eight +data bits plus one start bit and two stop bits to encode two hex digits. +The burst data consist of five characters (ten hex digits) followed by +a repeat of these characters. In format A, the characters are repeated +in the same polarity; in format B, the characters are repeated in the opposite +polarity. + +

Format A bursts are sent at seconds 32 through 39 of the minute in hex +digits + +

    6dddhhmmss6dddhhmmss + +

The first ten digits encode a frame marker (6) followed by +the day (ddd), hour (hh in UTC), minute (mm) +and the second (ss). Since format A bursts are sent during the +third decade of seconds the tens digit of ss is always 3. The +driver uses this to determine correct burst synchronization. These digits +are then repeated with the same polarity. + +

Format B bursts are sent at second 31 of the minute in hex digits + +

    xdyyyyttaaxdyyyyttaa + +

The first ten digits encode a code (x described below) followed +by the DUT1 (d in deciseconds), Gregorian year (yyyy), +difference TAI - UTC (tt) and daylight time indicator (aa) +peculiar to Canada. These digits are then repeated with inverted polarity. + +

The x is coded + +

1    Sign of DUT (0 = +) +
2    Leap second warning. One second will be added. +
4    Leap second warning. One second will be subtracted. +This is not likely to happen in our universe. +
8    Even parity bit for this nibble. + +

By design, the last stop bit of the last character in the burst coincides +with 0.5 second. Since characters have 11 bits and are transmitted at 300 +bps, the last stop bit of the first character coincides with 0.5 - 10 * +11/300 = 0.133 second. Depending on the UART, character interrupts can +vary somewhere between the beginning of bit 9 and end of bit 11. These +eccentricities can be corrected along with the radio propagation delay +using fudge time1. +

+Debugging aids

+The timecode format used for debugging and data recording includes data +helpful in diagnosing problems with the radio signal and serial connections. +With debugging enabled (-d -d -d on the ntpd command +line), the driver produces one line for each burst in two formats corresponding +to format A and B. Following is format A: + +

    n b f s m code + +

where n is the number of characters in the burst (0-11), b +the burst distance (0-40), f the field alignment (-1, 0, +1), s the synchronization distance (0-16), m the burst +number (2-9) and code the burst characters as received. Note that +the hex digits in each character are reversed, so the burst + +

    10 38 0 16 9 06851292930685129293 + +

is interpreted as containing 11 characters with burst distance 38, field +alignment 0, synchronization distance 16 and burst number 9. The nibble-swapped +timecode shows day 58, hour 21, minute 29 and second 39. + +

When the audio driver is compiled, format A is preceded by the gain +(0-255) and relative signal level (0-9999). The receiver volume control +should be set so that the gain is near the middle of the range 0-255, which +results in a signal level near 1000. + +

Following is format B: + +

    n b s code + +

where n is the number of characters in the burst (0-11), b +the burst distance (0-40), s the synchronization distance +(0-40) and code the burst characters as received. Note that the +hex digits in each character are reversed and the last ten digits inverted, +so the burst + +

    11 40 1091891300ef6e76ecff + +

is interpreted as containing 11 characters with burst distance 40. The +nibble-swapped timecode shows DUT1 +0.1 second, year 1998 and TAI - UTC +31 seconds. + +

In addition to the above, the reference timecode is updated and written +to the clockstats file and debug score after the last burst received in +the minute. The format is + +

    qq yyyy ddd hh:mm:ss nn dd tt + +

where qq are the error flags, as described below, yyyy +is the year, ddd the day, hh:mm:ss the time of day, +nn the number of format A bursts received during the previous +minute, dd the decoding distance and tt the number of +timestamps. The error flags are cleared after every update. + +

For accuracy better than the low milliseconds, the fudge time1 +variable can be used to set the propagation delay and compensate for inherent +latencies in the serial port hardware and operating system. This can be +done conveniently using the minimuf program. +

+Monitor Data

+When enabled by the flag4 fudge flag, every received timecode +burst in both format A or format B is written to the clockstats +file. +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default CHU.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+When the audio driver is compiled, this flag selects the audio input +port, where 0 is the mike port (default) and 1 is the line-in port. It +does not seem useful to select the compact disc player port.
+ +
+flag3 0 | 1
+ +
+When the audio driver is compiled, this flag enables audio monitoring of +the input signal. For this purpose, the speaker volume must be set +before the driver is started.
+ +
+flag4 0 | 1
+ +
+Enable verbose clockstats recording if set.
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/driver8.htm b/contrib/ntp/html/driver8.htm new file mode 100644 index 000000000000..890b6c5e9706 --- /dev/null +++ b/contrib/ntp/html/driver8.htm @@ -0,0 +1,343 @@ + +Generic Reference Driver +

+Generic Reference Driver +


+ +

Synopsis

+ +Address: 127.127.8.u +
Reference ID: PARSE +
Driver ID: GENERIC +
Serial Port: /dev/refclock-u; TTY mode according to +clock type + +

Description

+ +The timecode of these receivers is sampled via a STREAMS module in the +kernel (The STREAMS module has been designed for use with SUN Systems +under SunOS 4.1.x or Solaris 2.3 - 2.6. It can be linked directly into +the kernel or loaded via the loadable driver mechanism). This STREAMS +module can be adapted to be able to convert different time code formats. +If the daemon is compiled without the STREAM definition synchronization +will work without the Sun streams module, though accuracy is +significantly degraded. This feature allows to use PARSE also on non Sun +machines. + +

The actual receiver status is mapped into various synchronization +states generally used by receivers. The STREAMS module is configured to +interpret the time codes of DCF C51, PZF535, PZF509, GPS166, Trimble SV6 +GPS, ELV DCF7000, Schmid, Wharton 400A and low cost receivers (see list +below). + +

The reference clock support in ntp contains the necessary +configuration tables for those receivers. In addition to supporting +several 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 synchronization. + +

CAUTION: The PPS configuration option is different from the hardware +PPS signal, which is also supported (see below), as it controls the way +ntpd is synchronized to the reference clock, while the hardware PPS +signal controls the way time offsets are determined. + +

The use of the PPS option requires receivers with an accuracy of +better than 1ms. + +

Fudge factors + +

Only two fudge factors are utilized. The time1 fudge factor defines +the phase offset of the synchronization character to the actual time. On +the availability of PPS information the time2 fudge factor defines the +skew between the PPS time stamp and the receiver timestamp of the PPS +signal. This parameter is usually zero, as usually the PPS signal is +believed in time and OS delays should be corrected in the machine +specific section of the kernel driver. time2 needs only be set when the +actual PPS signal is delayed for some reason. The flag1 enables input +filtering. This a median filter with continuous sampling. The flag2 +selects averaging of the samples remaining after the filtering. Leap +second-handling is controlled with the flag3. 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). flag3 should never be set. PPS handling is enabled by adding +128 to the mode parameter in the server/peer command. + +

ntpq (8) +

timecode variable + +

The ntpq program can read clock variables command list several +variables. +These hold the following information: refclock_time is the local time +with +the offset to UTC (format HHMM). The currently active receiver flags are +listed in refclock_status. Additional feature flags of the receiver are +optionally listed in parentheses. The actual time code is listed in +timecode. +A qualification of the decoded time code format is following in +refclock_format. The last piece of information is the overall running +time and the accumulated times for the clock event states in +refclock_states. When PPS information is present additional variable are +available. refclock_ppstime lists then the PPS timestamp and +refclock_ppsskew lists the difference between RS232 +derived timestamp and the PPS timestamp. + +

Currently, fourteen clock types (devices /dev/refclock-0 - +/dev/refclock-3) are supported by the PARSE driver. +
A note on the implementations: +

  • These implementations where mainly done WITHOUT +actual access to the hardware. Thus not all implementations provide full +support. The development was done with the help of many souls who had +the hardware and where so kind to borrow me their time an patience +during the development and debugging cycle. Thus for continued support +and quality direct access to the receivers is a big help. Nevertheless i +am not prepared to buy these reference clocks - donations to me +(kardel@acm.org) are welcome as +long as they work within Europe 8-). + +

    Verified implementations are: +

      +
    • +RAWDCF variants + +

      These variants are tested for the decoding with my own homegrown +receivers. Interfacing with specific commercial products may involve +some fiddeling with cables. Especially commericial RAWDCF receivers have +a seemingly unlimited number of ways to draw power from the RS232 port +and to encode the DCF77 datastream. You are mainly on your own here +unless i have a sample of the receiver. +

    • +Meinberg clocks + +

      These implementations are verified by the Meinberg people themselves +and i have access to one of these clocks.

    +
+The pictures below refer to the respective clock and where taken from +the vendors web pages. They are linked to the respective vendors. +
    +
  • +server 127.127.8.0-3 mode 0 + +

    Meinberg PZF535/PZF509 receiver (FM +demodulation/TCXO / 50us) +
    +

  • +server 127.127.8.0-3 mode 1 + +

    Meinberg PZF535/PZF509 +receiver (FM demodulation/OCXO / 50us) +
    BILD PZF509 +
    +

  • +server 127.127.8.0-3 mode 2 + +

    Meinberg DCF U/A +31/DCF C51 receiver +(AM demodulation / 4ms) +
    BILD C51 +
    +

  • +server 127.127.8.0-3 mode 3 + +

    ELV DCF7000 (sloppy AM +demodulation +/ 50ms) +
    +

  • +server 127.127.8.0-3 mode 4 + +

    Walter Schmid DCF receiver Kit (AM demodulation / +1ms) +
    +

  • +server 127.127.8.0-3 mode 5 + +

    RAW DCF77 100/200ms pulses (Conrad DCF77 receiver module / +5ms) +
    +

  • +server 127.127.8.0-3 mode 6 + +

    RAW DCF77 100/200ms pulses (TimeBrick DCF77 receiver module +/ 5ms) +
    +

  • +server 127.127.8.0-3 mode 7 + +

    Meinberg GPS166/GPS167 +receiver (GPS / <<1us) +
    BILD GPS167 +
    +

  • +server 127.127.8.0-3 mode 8 +

    IGEL clock +
    +
    +

  • +server 127.127.8.0-3 mode 9 + +

    Trimble SVeeSix +GPS receiverTAIP protocol (GPS / <<1us) +
    +

  • +server 127.127.8.0-3 mode 10 + +

    Trimble SVeeSix +GPS receiver TSIP protocol (GPS / <<1us) (no kernel support +yet) +
    SVeeSix-CM3 +
    Lassen-SK8 +
    +

  • +server 127.127.8.0-3 mode 11 + +

    Radiocode Clocks Ltd RCC 8000 Intelligent Off-Air Master +Clock +support +
    +

  • +server 127.127.8.0-3 mode 12 + +

    HOPF Funkuhr +6021 +
    DCF77-Interface Board +
    +

  • +server 127.127.8.0-3 mode 13 + +

    Diem's Computime Radio Clock +
    +

  • +server 127.127.8.0-3 mode 14 + +

    RAWDCF receiver (DTR=high/RTS=low) + +

  • +server 127.127.8.0-3 mode 15 + +

    WHARTON 400A Series Clocks with a 404.2 Serial +Interface +

+

+Actual data formats and set-up requirements of the various clocks can be +found in NTP PARSE clock data formats. + +

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 syslog facility. Every hour +a summary of the accumulated times for the clock states is listed via +syslog. + +

PPS support is only available when the receiver is completely +synchronized. The receiver is believed to deliver correct time for an +additional period of time after losing synchronizations, 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 clockinfo +field of the reference clock implementation. This parameter cannot be +configured by ntpdc. + +

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. To select PPS support +the STREAMS driver for PARSE must be loaded and the mode parameter ist +the mode value of above plus 128. If 128 is not added to the mode value +PPS will be detected to be available but it will not be used. For PPS to +be used you MUST add 128 to the mode parameter. + +

For the Meinberg GPS166/GPS167 receiver is also a special firmware +release available (Uni-Erlangen). This release should be used for proper +operation. + +

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 +synchronization. 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 +synchronizations 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. + +

Monitor Data

+ +Clock states statistics are written hourly the the syslog service. +Online information can be found by examining the clock variable via the +ntpq cv command. + +

Fudge Factors

+ +
+ +
time1 time
+
Specifies the time offset calibration factor, in seconds and +fraction, with default depending on clock type.
+ +
time2 time
+
Specifies the offset if the PPS signal to the actual time. (PPS fine +tuning).
+ +
stratum number
+
Specifies the driver stratum, in decimal from 0 to 15, with default +0.
+ +
refid string
+
Specifies the driver reference identifier, an ASCII string from one +to four characters, with default according to current clock type.
+ +
flag1 0 | 1
+
Not used by this driver.
+ +
flag2 0 | 1
+
Not used by this driver.
+ +
flag3 0 | 1
+
delete next leap second instead of adding it.
+ +
+flag4 0 | 1
+
Delete next leap second instead of adding it - flag will be re- +defined soon - so don't use it. Statistics are provided by more common +means (syslog, clock variable via ntpq)
+ +
+ +

Making your own PARSE clocks

+ +The parse clock mechanismis deviated from the way other ntp reference +clocks work. For a short description how to build parse reference clocks +see making PARSE clocks + +

Additional Information + +

Reference Clock Drivers + +


David L. Mills <mills@udel.edu> +
diff --git a/contrib/ntp/html/driver9.htm b/contrib/ntp/html/driver9.htm new file mode 100644 index 000000000000..8a11a0216997 --- /dev/null +++ b/contrib/ntp/html/driver9.htm @@ -0,0 +1,133 @@ + + + + + Magnavox MX4200 GPS Receiver + + + + +

+Magnavox MX4200 GPS Receiver

+ +
+

+Synopsis

+Address: 127.127.9.u +
Reference ID: GPS +
Driver ID: GPS_MX4200 +
Serial Port: /dev/gpsu; 4800 baud, 8-bits, no parity +
Features: ppsclock (required) +

+Description

+This driver supports the Magnavox MX4200 Navigation Receiver adapted to +precision timing applications. It requires the ppsclock line +discipline or streams module described in the Line +Disciplines and Streams Modules page. It also requires a gadget box and 1-PPS level converter, such as +described in the Pulse-per-second (PPS) Signal +Interfacing page. + +

This driver supports all compatible receivers such as the 6-channel +MX4200, MX4200D, and the 12-channel MX9212, MX9012R, MX9112. + +

+ +Leica MX9400N Navigator +Leica Geosystems acquired +the Magnavox commercial GPS technology business in February of 1994. +They now market and support former Magnavox GPS products such as the +MX4200 and its successors.

+ +
+Leica MX9400N Navigator. + +

+ +

+Operating Modes

+This driver supports two modes of operation, static and mobile, controlled +by clock flag 2. + +

In static mode (the default) the driver assumes that the GPS antenna +is in a fixed location. The receiver is initially placed in a "Static, +3D Nav" mode, where latitude, longitude, elevation and time are calculated +for a fixed station. A DOP-weighted running average position is calculated +from this data. After 24 hours, the receiver is placed into a "Known Position" +mode, initialized with the calculated position, and then solves only for +time. + +

In mobile mode, the driver assumes the GPS antenna is mounted on a moving +platform such as a car, ship, or aircraft. The receiver is placed in "Dynamic, +3D Nav" mode and solves for position, altitude and time while moving. No +position averaging is performed. +

+Monitor Data

+The driver writes each timecode as received to the clockstats +file. Documentation for the NMEA-0183 proprietary +sentences produced by the MX4200 can be found in +MX4200 Receiver Data Format. + +

+Fudge Factors

+ +
+
+time1 time
+ +
+Specifies the time offset calibration factor, in seconds and fraction, +with default 0.0.
+ +
+time2 time
+ +
+Not used by this driver.
+ +
+stratum number
+ +
+Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+ +
+refid string
+ +
+Specifies the driver reference identifier, an ASCII string from one to +four characters, with default GPS.
+ +
+flag1 0 | 1
+ +
+Not used by this driver.
+ +
+flag2 0 | 1
+ +
+Assume GPS receiver is on a mobile platform if set.
+ +
+flag3 0 | 1
+ +
+Not used by this driver.
+ +
+flag4 0 | 1
+ +
+Not used by this driver.
+
+Additional Information + +

Reference Clock Drivers  +


+
+David L. Mills (mills@udel.edu)
+ + + diff --git a/contrib/ntp/html/exec.htm b/contrib/ntp/html/exec.htm new file mode 100644 index 000000000000..756d987cdc26 --- /dev/null +++ b/contrib/ntp/html/exec.htm @@ -0,0 +1,292 @@ + +Executive Summary - Computer Network Time Synchronization +

+Executive Summary - Computer Network Time Synchronization +

+ + +from Alice's Adventures in Wonderland, by Lewis Carroll, +illustrations by Sir John Tenniel + +

The executive is the one on the left. + +


+ +

Introduction

+ +

The standard timescale used by most nations of the world is Universal +Coordinated Time (UTC), which is based on the Earth's rotation about its +axis, and the Gregorian Calendar, which is based on the Earth's rotation +about the Sun. The UTC timescale is disciplined with respect to +International Atomic Time (TAI) by inserting leap seconds at intervals +of about 18 months. UTC time is disseminated by various means, including +radio and satellite navigation systems, telephone modems and portable +clocks. + +

Special purpose receivers are available for many time-dissemination +services, including the Global Position System (GPS) and other services +operated by various national governments. For reasons of cost and +convenience, it is not possible to equip every computer with one of +these receivers. However, it is possible to equip some number of +computers acting as primary time servers to synchronize a much larger +number of secondary servers and clients connected by a common network. +In order to do this, a distributed network clock synchronization +protocol is required which can read a server clock, transmit the reading +to one or more clients and adjust each client clock as required. +Protocols that do this include the Network Time Protocol (NTP), Digital +Time Synchronization Protocol (DTSS) and others found in the literature +(See "Further Reading" at the end of this article.) + +

Protocol Design Issues

+ +

The synchronization protocol determines the time offset of the server +clock relative to the client clock. The various synchronization +protocols in use today provide different means to do this, but they all +follow the same general model. On request, the server sends a message +including its current clock value or timestamp and the client +records its own timestamp upon arrival of the message. For the best +accuracy, the client needs to measure the server-client propagation +delay to determine its clock offset relative to the server. Since it is +not possible to determine the one-way delays, unless the actual clock +offset is known, the protocol measures the total roundtrip delay and +assumes the propagation times are statistically equal in each direction. +In general, this is a useful approximation; however, in the Internet of +today, network paths and the associated delays can differ significantly +due to the individual service providers. + +

The community served by the synchronization protocol can be very +large. For instance, the NTP community in the Internet of 1998 includes +over 230 primary time servers, synchronized by radio, satellite and +modem, and well over 100,000 secondary servers and clients. In addition, +there are many thousands of private communities in large government, +corporate and institution networks. Each community is organized as a +tree graph or subnet, with the primary servers at the root and +secondary servers and clients at increasing hop count, or stratum level, +in corporate, department and desktop networks. It is usually necessary +at each stratum level to employ redundant servers and diverse network +paths in order to protect against broken software, hardware and network +links. +

Synchronization protocols work in one or more association modes, +depending on the protocol design. Client/server mode, also called +master/slave mode, is supported in both DTSS and NTP. In this mode, a +client synchronizes to a stateless server as in the conventional RPC +model. NTP also supports symmetric mode, which allows either of two peer +servers to synchronize to the other, in order to provide mutual backup. +DTSS and NTP support a broadcast mode which allows many clients to +synchronize to one or a few servers, reducing network traffic when large +numbers of clients are involved. In NTP, IP multicast can be used when +the subnet spans multiple networks. + +

Configuration management can be a serious problem in large subnets. +Various schemes which index public databases and network directory +services are used in DTSS and NTP to discover servers. Both protocols +use broadcast modes to support large client populations; but, since +listen-only clients cannot calibrate the delay, accuracy can suffer. In +NTP, clients determine the delay at the time a server is first +discovered by polling the server in client/server mode and then +reverting to listen-only mode. In addition, NTP clients can broadcast a +special "manycast" message to solicit responses from nearby servers and +continue in client/server mode with the respondents. + +

Computer Clock Modelling and Error Analysis

+ +Most computers include a quartz resonator-stabilized oscillator and +hardware counter that interrupts the processor at intervals of a few +milliseconds. At each interrupt, a quantity called tick is added +to a system variable representing the clock time. The clock can be read +by system and application programs and set on occasion to an external +reference. Once set, the clock readings increment at a nominal rate, +depending on the value of tick. Typical Unix system kernels +provide a programmable mechanism to increase or decrease the value of +tick by a small, fixed amount in order to amortize a given time +adjustment smoothly over multiple tick intervals. + +

Clock errors are due to variations in network delay and latencies in +computer hardware and software (jitter), as well as clock oscillator +instability (wander). The time of a client relative to its server can be +expressed + +

T(t) = T(t0) + +R(t - t0) + 1/2 D(t - +T0)2,
+ +

where t is the current time, T is the time offset at +the last measurement update t0, R is the +frequency offset and D is the drift due to resonator ageing. All +three terms include systematic offsets that can be corrected and random +variations that cannot. Some protocols, including DTSS, estimate only +the first term in this expression, while others, including NTP, estimate +the first two terms. Errors due to the third term, while important to +model resonator aging in precision applications, are neglected, since +they are usually dominated by errors in the first two terms. + +

The synchronization protocol estimates T(t0) +(and R(t0), where relevant) at regular +intervals t and adjusts the clock to minimize +T(t) in future. In common cases, R can have +systematic offsets of several hundred parts-per-million (PPM) with +random variations of several PPM due to ambient temperature changes. If +not corrected, the resulting errors can accumulate to seconds per day. +In order that these errors do not exceed a nominal specification, the +protocol must periodically re-estimate T and R and +compensate for variations by adjusting the clock at regular intervals. +As a practical matter, for nominal accuracies of tens of milliseconds, +this requires clients to exchange messages with servers at intervals in +the order of tens of minutes. + +

Analysis of quartz-resonator stabilized oscillators show that errors +are a function of the averaging time, which in turn depends on the +interval between corrections. At correction intervals less than a few +hundred seconds, errors are dominated by jitter, while, at intervals +greater than this, errors are dominated by wander. As explained later, +the characteristics of each regime determine the algorithm used to +discipline the clock. These errors accumulate at each stratum level from +the root to the leaves of the subnet tree. It is possible to quantify +these errors by statistical means, as in NTP. This allows real-time +applications to adjust audio or video playout delay, for example. +However, the required statistics may be different for various classes of +applications. Some applications need absolute error bounds guaranteed +never to exceeded, as provided by the following correctness principles. + +

Correctness Principles

+ +

Applications requiring reliable time synchronization such as air +traffic control must have confidence that the local clock is correct +within some bound relative to a given timescale such as UTC. There is a +considerable body of literature that studies these issues with respect +to various failure models such as fail-stop and Byzantine disagreement. +While these models inspire much confidence in a theoretical setting, +most require multiple message rounds for each measurement and would be +impractical in a large computer network such as the Internet. However, +it can be shown that the worst-case error in reading a remote server +clock cannot exceed one-half the roundtrip delay measured by the client. +This is a valuable insight, since it permits strong statements about the +correctness of the timekeeping system. + +

In the Probabilistic Clock Synchronization (PCS) scheme devised by +Cristian, a maximum error tolerance is established in advance and time +value samples associated with roundtrip delays that exceed twice this +value are discarded. By the above argument, the remaining samples must +represent time values within the specified tolerance. As the tolerance +is decreased, more samples fail the test until a point where no samples +survive. The tolerance can be adjusted for the best compromise between +the highest accuracy consistent with acceptable sample survival rate. + +

In a scheme devised by Marzullo and exploited in NTP and DTSS, the +worst-case error determined for each server determines a correctness +interval. If each of a number of servers are in fact synchronized to a +common timescale, the actual time must be contained in the intersection +of their correctness intervals. If some intervals do not intersect, then +the clique containing the maximum number of intersections is assumed +correct truechimers and the others assumed incorrect +falsetickers. Only the truechimers are used to adjust the +system +clock. + +

Data Grooming Algorithms

+ +By its very nature, clock synchronization is a continuous process, +resulting in a sequence of measurements with each of possibly several +servers and resulting in a clock adjustment. In some protocols, crafted +algorithms are used to improve the time and frequency estimates and +refine the clock adjustment. Algorithms described in the literature are +based on trimmed-mean and median filter methods. The clock filter +algorithm used in NTP is based on the above observation that the +correctness interval depends on the roundtrip delay. The algorithm +accumulates offset/delay samples in a window of several samples and +selects the offset sample associated with the minimum delay. In general, +larger window sizes provide better estimates; however, stability +considerations limit the window size to about eight. +

The same principle could be used when selecting the best subset of +servers and combining their offsets to determine the clock adjustment. +However, different servers often show different systematic offsets, so +the best statistic for the central tendency of the server population may +not be obvious. Various kinds of clustering algorithms have been found +useful for this purpose. The one used in NTP sorts the offsets by a +quality metric, then calculates the variance of all servers relative to +each server separately. The algorithm repeatedly discards the outlyer +with the largest variance until further discards will not improve the +residual variance or until a minimum number of servers remain. The final +clock adjustment is computed as a weighted average of the survivors. + +

At the heart of the synchronization protocol is the algorithm used to +adjust the system clock in accordance with the final adjustment +determined by the above algorithms. This is called the clock discipline +algorithm or simply the discipline. Such algorithms can be classed +according to whether they minimize the time offset or frequency offset +or both. For instance, the discipline used in DTSS minimizes only the +time offset, while the one used in NTP minimizes both time and frequency +offsets. While the DTSS algorithm cannot remove residual errors due to +systematic frequency errors, the NTP algorithm is more complicated and +less forgiving of design and implementation mistakes. + +

All clock disciplines function as a feedback loop, with measured +offsets used to adjust the clock oscillator phase and frequency to match +the external synchronization source. The behavior of feedback loops is +well understood and modelled by mathematical analysis. The significant +design parameter is the time constant, or responsiveness to external or +internal variations in time or frequency. Optimum selection of time +constant depends on the interval between update messages. In general, +the longer these intervals, the larger the time constant and vice versa. +In practice and with typical network configurations the optimal poll +intervals vary between one and twenty minutes for network paths to some +thousands of minutes for modem paths. + +

Further Reading

+ +
    + +

  1. Cristian, F. Probabilistic clock synchronization. In Distributed +Computing 3, Springer Verlag, 1989, 146-158.
  2. + +

  3. Digital Time Service Functional Specification Version T.1.0.5. +DigitalEquipment Corporation, 1989.
  4. + +

  5. Gusella, R., and S. Zatti. TEMPO - A network time controller for +a distributed Berkeley UNIX system. IEEE Distributed Processing +Technical Committee Newsletter 6, NoSI-2 (June 1984), 7-15. Also in: +Proc. Summer 1984 USENIX (Salt Lake City, June 1984).
  6. + +

  7. Kopetz, H., and W. Ochsenreiter. Clock synchronization in +distributed real-time systems. IEEE Trans. Computers C-36, 8 (August +1987), 933-939.
  8. + +

  9. Lamport, L., and P.M. Melliar-Smith. Synchronizing clocks in the +presence of faults. JACM 32, 1 (January 1985), 52-78.
  10. + +

  11. Marzullo, K., and S. Owicki. Maintaining the time in a +distributed system. ACM Operating Systems Review 19, 3 (July 1985), 44- +54.
  12. + +

  13. Mills, D.L. Internet time synchronization: the Network Time +Protocol. IEEE Trans. Communications COM-39, 10 (October 1991), 1482- +1493. Also in: Yang, Z., and T.A. Marsland (Eds.). Global States and +Time in Distributed Systems, IEEE Press, Los Alamitos, CA, 91-102.
  14. +

  15. Mills, D.L. Modelling and analysis of computer network clocks. +Electrical Engineering Department Report 92-5-2, University of Delaware, +May 1992, 29 pp.
  16. + +

  17. NIST Time and Frequency Dissemination Services. NBS Special +Publication432 (Revised 1990), National Institute of Science and +Technology, U.S. Department of Commerce, 1990.
  18. + +

  19. Schneider, F.B. A paradigm for reliable clock synchronization. +Department of Computer Science Technical Report TR 86-735, Cornell +University, February 1986.
  20. + +

  21. Srikanth, T.K., and S. Toueg. Optimal clock synchronization. JACM +34, 3 (July 1987), 626-645.
  22. + +

  23. Stein, S.R. Frequency and time - their measurement and +characterization (Chapter 12). In: E.A. Gerber and A. Ballato (Eds.). +Precision Frequency Control, Vol. 2, Academic Press, New York 1985, 191- +232, 399-416. Also in: Sullivan, D.B., D.W. Allan, D.A. Howe and F.L. +Walls (Eds.). Characterization of Clocks and Oscillators. National +Institute of Standards and Technology Technical Note 1337, U.S. +Government Printing Office (January, 1990), TN61-TN119.
  24. + +
+ +
David L. Mills <mills@udel.edu> +
diff --git a/contrib/ntp/html/extern.htm b/contrib/ntp/html/extern.htm new file mode 100644 index 000000000000..d44d24333ef0 --- /dev/null +++ b/contrib/ntp/html/extern.htm @@ -0,0 +1,40 @@ + +External Clock Discipline and the Local Clock Driver +

+External Clock Discipline and the Local Clock Driver +


+ +

The NTPv4 implementation includes provisions for an external clock, where the system clock is implemented by some external hardware device. One implementation might take the form of a bus peripheral with a high resolution counter disciplined by a GPS receiver, for example. Another implementation might involve another synchronization protocol, such as the Digital Time Synchronization Service (DTSS), where the system time is disciplined to this protocol and NTP clients of the server obtain synchronization indirectly via the server. A third implementation might be a completely separate clock discipline algorithm and synchronization protocol, such as the Lockclock algorithm used with NIST Automated Computer Time Service (ACTS) modem synchronized time. + +

When external clocks are used in conjunction with NTP service, some way needs to be provided for the external clock driver and NTP daemon ntpd to communicate and determine which discipline is in control. This is necessary in order to provide backup, for instance if the external clock or protocol were to fail synchronization service fall back to other means, such as a local reference clock or another NTP server. In addition, when the external clock and driver are in control, some means needs to be provided for the clock driver to pass on status information and error statistics to the NTP daemon. + +

Control and monitoring functions for the external clock and driver are implemented using the Local Clock (type 1) driver and the ntp_adjtime() system call. This system call is implemented by special kernel provisions included in the kernel of several operating systems, including Solaris, Digital Unix, FreeBSD and Linux, and possibly others. When the external clock is disabled or not implemented, the system call is used to pass time and frequency information, as well as error statistics, to the kernel. Besides disciplining the system time, the same interface can be used by other applications to determine the operating parameters of the discipline. When the external clock is enabled, ntpd does not discipline the system clock, nor does it maintain the error statistics. In this case, the external clock and driver do this using mechanisms unknown to ntpd; however, in this case the kernel state variables are retrieved at 64-s intervals by the Local Clock driver and used by the clock selection and mitigation algorithms to determine the system variables presented to other NTP clients and peers. In this way, downstream clients and servers in the NTP subnet can make an intelligent choice when more than one server is available. + +

In order to implement a reliable mitigation between ordinary NTP sources and the external clock source, a protocol is necessary between the local clock driver and the external clock driver. This is implemented using Boolean variables and certain bits in the kernel clock status word. The Boolean variables include the following: + +

ntp__enable. set/reset by enable command. enables ntp clock discipline + +

ntp_control. set during initial configuration if kernel support is available + +kern_enable +Set/reset by enable commandexit + +If this switch is set, the daemon computes the offset, frequency, maximum error, estimated error, time constand and status bits, then provides them to the kernel via ntp_adjtime(). If this switch is set, these values are not passed to the kernel; however, the daemon retrieves their present values and uses them in place of the values computed by the daemon. + +pps_update +set in the protocol routine if the prefer peer has survived and has offset less than 128 ms; otherwise set to zero. + +pps_control +Updated to the current time by kernel support if the PPS signal is enabled and working correctly. Set to zero in the adjust routine if the interval since the last update exceeds 120 s. + + +

The ntp_enable and kern_enable are set by the configuration module. Normally, both switches default on, so the daemon can control the time and the kernel discipline can be used, if available. The pps_update switch is set by the protocol module when it believes the PPS provider source is legitimate and operating within nominals. The ntp_control switch is set during configuration by interrogating the kernel. If both the kern_enable and ntp_control siwitches are set, the daemon disciplines the clock via the kernel and the internal daemon discipline is disabled. + +

The external clock driver controls the system time and clock selection in the following way. Normally, the driver adjusts the kernel time using the ntp_adjtime() system call in the same way as the daemon. In the case where the kernel discipline is to be used intact, the clock offset is provided in this call and the loop operates as specified. In the case where the driver steers only the frequency, the offset is specified as zero + + +d PLL/ + +


David L. Mills <mills@udel.edu> +
diff --git a/contrib/ntp/html/gadget.htm b/contrib/ntp/html/gadget.htm new file mode 100644 index 000000000000..80274535ecda --- /dev/null +++ b/contrib/ntp/html/gadget.htm @@ -0,0 +1,111 @@ + +Gadget Box PPS Level Converter and CHU Modem +

+Gadget Box PPS Level Converter and CHU Modem +

+ +A Gadget Box built by Chuck Hanavin + +

+ +

Introduction

+ +

Many radio clocks used as a primary reference source for NTP servers +produce a pulse-per-second (PPS) signal that can be used to improve +accuracy to a high degree. However, the signals produced are usually +incompatible with the modem interface signals on the serial ports used +to connect the signal to the host. The gadget box consists of a handful +of electronic components assembled in a small aluminum box. It includes +level converters and a optional radio modem designed to decode the radio +timecode signals transmitted by the Canadian time and frequency station +CHU. A complete set of schematics, PCB artwork, drill templates can be +obrtained via the web as the distribution gadget.tar.Z, or by +anonymous FTP from ftp.udel.edu in the pub/ntp directory. + +

The gadget box is assembled in a 5"x3"x2" aluminum +minibox containing the level converter and modem circuitry. It includes +two subcircuits. One of these converts a TTL positive edge into a fixed- +width pulse at EIA levels and is for use with a timecode receiver or +oscillator including a TTL PPS output. The other converts the timecode +modulation broadcast by Canadian time/frequency standard station CHU +into a 300-bps serial character stream at EIA levels and is for use with +the tty_clk and chu_tty line disciplines in +the ntp3 distribution. + +

This archive contains complete construction details for the gadget +box, including schematic, parts list and artwork for a two-sided, +printed-circuit board. All files are in PostScript, with the exception +of this file and an information file, which are in ASCII. The artwork is +in the 1:1 scale and is suitable for direct printing on photographic +resist for each side of the board. While a plated-through-holes process +is most convenient, it is possible to bridge the two sides using +soldered wires where necessary. + +

Circuit Description

+ +

Following is a brief functional description of the device. See the +schematic diagram gadget.s01 for reference. The audio output of a +shortwave radio tuned to CHU at 3330, 7335 or 14670 kHz is connected to +J2. A level of at least 30 mV peak-peak is required, such as provided by +the recorder output on many receivers. The input level is adjusted by +potentiometer R8 so that the timecode modulation broadcast at 31-39 +seconds past the minute reliably lights green LED1, but the signals +broadcast during other seconds of the minute do not. + +

Opamp U4A provides low-impedance drive for the bridged-tee bandpass +filter U4B. The filter has a bandpass of about 600 Hz at the 6-dB points +and a center frequency of about 2150 Hz. It is designed to avoid +aliasing effects with receivers of relatively wide bandpass +characteristics. The modem itself is implemented by U2 and its +associated circuitry. Resistors R4 and R1 are a 40-dB pad which matches +the filter output to the modem input. U2 is a TTL/EIA level converter +with integral power supply for bipolar signals. The modem output is +available at pin 3 (receive data) of DB25 connector J1. + +

The TTL PPS signal is connected via J3 to a retriggerable one-shot +U3A, which generates a TTL pulse of width determined by potentiometer +R7. The pulse width is determined by the bit rate of the attached serial +port. In the common case the width is one bit-time, such as 26 us for +38.4 kbps, for example. This appears to the port as a single start bit +of zero followed by eight bits of ones and a stop bit of one. The second +one-shot U3B generates a 200-ms pulse suitable for driving the amber +LED3 as a visual monitor. The output of U3A is converted to EIA levels +by U1 and appears at pin 12 (secondary receive data) of J1. + +

If only the PPS circuit is required, U2 and U4 can be deleted and the +gadget box powered from the EIA modem-control signal at pin 20 (terminal +ready) of J1, assuming this signal is placed in the on (positive +voltage) condition by the computer program. J1 is wired to keep most +finicky UARTs and terminal-driver programs happy. If the CHU circuit is +required, an external 12-volt AC transformer or 9-12-volt DC supply +connected to J4 is required. Red LED2 indicates power is supplied to the +box. + +

Files + +

Following is a list of files included in this archive. All files are +in PostScript, except the README and +gadget.lst files, which are in ASCII. The files +gadget.s01, gadget.s02 and gadget.lst were +generated using the Schema schematic-capture program from Omation. The +printed-circuit files *.lpr were generated using Schema- +PCB, also from Omation. + +

Files + +

README - helpful information +
gadget.s01 - circuit schematic +
gadget.s02 - minibox assembly drawing +
gadget.lst - net list, pin list, parts list, etc. +
gen0102.lpr - pcb x-ray diagram +
art01.lpr - pcb artword side 1 +
art02.lpr - pcb artwork side 2 +
adt0127.lpr - pcb assembly drawing +
dd0124.lpr - pcb drill drawing +
sm0228.lpr - pcb solder mask (side 2) +
sst0126.lpr - pcb silkscreen mask (side 1) + +


David L. Mills <mills@udel.edu> +
diff --git a/contrib/ntp/html/hints.htm b/contrib/ntp/html/hints.htm new file mode 100644 index 000000000000..066b4dba899a --- /dev/null +++ b/contrib/ntp/html/hints.htm @@ -0,0 +1,26 @@ + +Hints and Kinks +

+Hints and Kinks +


+ +

This is an index for a set of troubleshooting notes contained in +individual text files in the ./hints directory. They were +supplied by various volunteers in the form of mail messages, patches or +just plain word of mouth. Each note applies to a specific computer and +operating system and gives information found useful in setting up the +NTP distribution or site configuration. The notes are very informal and +subject to errors; no attempt has been made to verify the accuracy of +the information contained in them. + +

Additions or corrections to this list or the information contained in +the notes is solicited. The most useful submissions include the name of +the computer manufacturer (and model numbers where appropriate), +operating system (specific version(s) where appropriate), problem +description, problem solution and submitter's name and electric address. +If the submitter is willing to continue debate on the problem, please so +advise. Bash here for a directory listing. + +


David L. Mills <mills@udel.edu> +
diff --git a/contrib/ntp/html/hints/a-ux b/contrib/ntp/html/hints/a-ux new file mode 100644 index 000000000000..f8c26d2188b6 --- /dev/null +++ b/contrib/ntp/html/hints/a-ux @@ -0,0 +1,195 @@ +------------- +INTRODUCTION: +------------- +Last revision: 06-Jul-1994 + +Included in this distribution of XNTP V3 is a configuration file suitable +for use under Apple's A/UX Version 3.x.x There is also one for A/UX 2.0.1 +but it has not been fully tested. To make the executables follow the steps +outlined below. + +*** NOTE: You must have gcc installed to successfully compile the current +distribution; the native cc supplied with A/UX will NOT correctly compile +this source. See the FAQ in comp.unix.aux for places to obtain gcc from +and how to install it. + +---------------------- +MAKING XNTPD FOR A/UX: +---------------------- + +First, you need to create the makefiles (after you've downloaded the +source, of course): + + % make clean + % make refconf + +After that, you should edit Config.local to make sure that BINDIR is +correct for where you wish the programs to be "installed". The default +(and what I use) is /usr/local/etc. Make sure that DEFS_LOCAL and +CLOCKDEFS are commented out! Presently, only the LOCAL_CLOCK/REFCLOCK +clock is used and supported. + + +After this is done (you should be told that your system is A/UX 3), make +'xntpd' (the options to 'gcc' are held in compilers/aux3.gcc): + + % make + +I do not normally use the `make install' option and so have not verified its +compatibility with A/UX. Rather, I pull out each of the executables and +place them in the locally appropriate locations. + +--------------- +STARTING XNTPD: +--------------- + +At this point you need to set things up so that 'xntpd' is started upon +boot-up. You can do this in 1 of 2 ways: either add entries in /etc/inittab +or, more ideally, create and use an /etc/rc.local file. Since rc.local is +what I recommend, here's how you do it: + +By default, A/UX doesn't have rc.local, so you'll need to add the following to +/etc/inittab: + + net6:2:wait:/etc/syslogd # set to "wait" to run a syslog daemon ++ jmj0:2:wait:/etc/rc.local 1>/dev/syscon 2>&1 # Local stuff + dbg2::wait:/etc/telinit v # turn off init's verbose mode + +Now, the look of a sample /etc/rc.local is as follows: + + #!/bin/sh + : + : rc.local + : + # @(#)Copyright Apple Computer 1987 Version 1.17 of rc.sh on 91/11/08 15:56:21 (ATT 1.12) + + + # Push line discipline/set the device so it will print + /etc/line_sane 1 + echo " " + echo "Entering rc.local..." + + set `/bin/who -r` + if [ "$7" = 2 ] + then + /bin/echo " now setting the time..." + /usr/local/etc/ntpdate -s -b + sleep 5 + # + # start up 'xntpd' if we want + # + if [ -f /etc/ntp.conf ] + then + /bin/echo " setting tick and tickadj..." + /usr/local/etc/tickadj -t 16672 -a 54 + sleep 5 + /bin/echo " starting xntpd..." + /usr/local/etc/xntpd <&- > /dev/null 2>&1 + sleep 5 + fi + # + fi + + echo "Leaving rc.local..." + +There are a few things to notice about the above: + + o When run, 'ntpdate' forces your clock to the time returned by the + host(s) specified by (you'll need to replace this + be the IP address(es) of your timehosts. This is good since it gets + things close to start off with. You can use more than one time + server. + + o 'tickadj' is also called. This does two things: changes the + default value of 'tick' (which the the amount of time, in ms, that + is added to the clock every 1/60 seconds) and changes the value + of 'tickadj' which the the amount that is added or subtracted + from 'tickadj' when adjtime() is called. + + Now Mac clocks are pretty bad and tend to be slow. Sooo, instead of + having A/UX add the default of 16666ms every 1/60th of a second, you + may want it to add more (or less) so that it keeps better time. The + above value works for me but your "best" value may be different and + will likely require some fooling around to find the best value. As a + general rule of thumb, if you see 'xntpd' make a lot of negative clock + adjustments, then your clock is fast and you'll need to _decrease_ + the value of 'tick'. If your adjustments are positive, then you need + to increase 'tick'. To make a guess on how fast/slow your clock is, + use 'ntpdate' to sync your clock. Now watch 'xntpd' and see how it + operates. If, for example, it resets your clock by 1 second every 30 + minutes, then your clock is (1/(30*60)) is about 0.056% off and you'll + need to adjust 'tick' by 16666*0.00056 or about 9 (i.e. 'tick' should + be ~16675 if slow or ~16657 if fast) + + A/UX's default value of 'tickadj' is 1666 which is too big for + 'xntpd'... so it also needs to be adjusted. I like using larger + values then the recommended value of 9 for 'tickadj' (although not + anything near as big as 1666) since this allows for quick slews + when adjusting the clock. Even with semi-large values of 'tickadj' + (~200), getting 5ms (1/200 s) accuracy is easy. + + +Finally, before A/UX and 'xntpd' will work happily together, you need to +patch the kernel. This is due to the fact that A/UX attempts to keep the +UNIX-software clock and the Mac-hardware clock in sync. Neither the h/w or +the s/w clock are too accurate. Also, 'xntpd' will be attempting to adjust +the software clock as well, so having A/UX muck around with it is asking +for headaches. What you therefore need to do is tell the kernel _not_ to +sync the s/w clock with the h/w one. This is done using 'adb'. The +following is a shell script that will do the patch for you: + + #! /bin/sh + adb -w /unix < +Newsgroups: comp.protocols.time.ntp +to: mills@udel.edu +return-receipt-to: rocky@panix.com +Subject: time and AIX 3.2.5 raw tty bug + +This posting isn't strictly about NTP, any program that may stop the +clock or set the clock backwards is subject to the AIX 3.2.5 bug. + +On AIX 3.2.5, there is a bug in the tty driver for a raw device which +may crash the box under certain conditions: basically a read() on a +raw tty in effect, a character was read but not as many as specified +by VMIN when a read timeout occurred. VTIME specifies the timeout. See +the AIX manual page on termios.h or that include file. for Information +on VMIN (or MIN) VTIME (or TIME). + +A remedy other than to not use raw tty's is to apply patch U435110. + +Details of the problem report follow. + +> ABSTRACT: +> IX43779: TRAP IN PSX_TIMEO +> +> ORIGINATING DETAILS: +> Stacktrace shows: +> IAR: 01460214 posixdd:psx_timeo + 8bf4: ti 4,r12,0x0 +> *LR: 014601a0 posixdd:psx_timeo + 8b80 +> 00212c60: 014604f4 posixdd:psx_timer + 8ed4 +> 00212cc0: 0144b74c ttydd:tty_do_offlevel + 4284 +> 00212d20: 000216fc .i_offlevel + 8c +> 00212d70: 00021d78 .i_softint + c8 +> 00001004: 00008714 .finish_interrupt + 80 +> +> RESPONDER SUMMARY: +> AIX asserted in psx_timeo(). Reason for the assert was that +> the current time was behind psx_ctime. Since this state +> can occur when the current time is changed after a character +> is received but before the VTIME interbyte timer pops, we +> should not assert on this. +> +> RESPONDER CONCLUSION: +> Removed the requirement that current time > psx_ctime by +> adding a new L_ntimersub macro that is used instead of the +> ntimersub macro in time.h. Also added a test for (current +> time - psx_ctime) being negative, in that case we do not +> adjust the new timeout. +> +> Reported to Correct a PTF in Error: NO +> Reported as a Highly pervasive problem: NO +> +> PE Apar?: NoPE +> Hiper Apar?: NoHiper +> Status: CLOSED PER +> Component Name: AIX V3 FOR RS/6 +> Version: 320 +> Component ID: 575603001 +> Submitted: 94/05/03 +> Closed: 94/05/05 +> ChangeTeam: TX2527 +> +> APAR FIXED BY: U431696 U432151 U432844 U432870 U432979 +> U433049 U433081 U433459 U433876 U433906 U434598 U434453 +> U434672 U434737 U435110 + diff --git a/contrib/ntp/html/hints/bsdi b/contrib/ntp/html/hints/bsdi new file mode 100644 index 000000000000..3b8bc386efea --- /dev/null +++ b/contrib/ntp/html/hints/bsdi @@ -0,0 +1,65 @@ +hints/bsdi + +Author: Bdale Garbee, bdale@gag.com +Last revision: 27Oct94 (Paul Vixie) + +Included in this distribution of XNTP is a configuration file suitable +for use with BSDI's BSD/OS 1.1 (formerly BSD/386 1.1). On this system, +the "cc" command is GCC 1.4x rather than PCC or GCC 2.x. It is imperative +that "cc" be used since it predefines the symbol __bsdi__; if you want to +use another compiler you will need to add -D__bsdi__ to catch the various +#ifdef's required for this system. + +The Kinemetrics/Truetime GPS-TM/TMD driver is known to work on this system. +The GPS-805 and GOES should also work fine. Hell, they should all work fine +but it's hard to test very many locally. + +Due to BNR2's strict interpretation of POSIX and XNTP's use of SIGIO, BSD/OS +can only handle one refclock per daemon. We're working this out with the +system architects. + +The config file is machine/bsdi, and the following steps should be all that +are required to install and use the bits. + +Note that you will need GNU sed; the version supplied with BSD/OS 1.1 loops +endlessly during "make refconf". Likewise you should get GNU make, which +the instructions below assume that you have put in /usr/local/bin/gnumake. + +To build the software: + + rm -f Config.local + gnumake refconf + gnumake MAKE=gnumake + +To install the software: + + gnumake install + + This will place all of the executables in /usr/local/etc. The config + file is expected to be /usr/local/etc/xntp.conf and the key file for + the optional authentication is /etc/ntp.keys. + + Craft a config file and a key file, and put them in the right places. + There is information on how to do this elsewhere in the documentation, + the only thing I'll mention is that I put the drift file in + /var/log/ntp.drift, and the authdelay on my 486DX/50 system is + 0.000064. Your mileage will vary, learn to use the authspeed tools + if you're going to authenticate. + + In the file /etc/rc.local, make sure that the invocation of ntpd is + commented out, and add an invocation of xntpd. Here's what I'm using: + + echo -n 'starting local daemons:' + + if [ -f /etc/ntp.keys -a -f /usr/local/etc/xntp.conf ]; then + echo -n ' xntpd'; /usr/local/etc/xntpd + fi + + #XXX# echo -n ' ntpd'; /usr/libexec/ntpd -t + +At this point, you should be good to go. Try running /usr/local/etc/xntpd and +using ntpq or xntpdc to see if things are working, then pay attention the next +time you reboot to make sure that xntpd is being invoked, and use ntpq or +xntpdc again to make sure all is well. + +Enjoy! diff --git a/contrib/ntp/html/hints/changes b/contrib/ntp/html/hints/changes new file mode 100644 index 000000000000..177e562b6dc6 --- /dev/null +++ b/contrib/ntp/html/hints/changes @@ -0,0 +1,13 @@ +Ulrich Windl (xntpd/refclock_parse.c): + - Added support to supply power from RS232 with CLOCK_RAWDCF. + Known to work with Linux 1.2. + - Made Linux ignore parity errors with CLOCK_RAWDCF. + +Ulrich Windl (parse/util/dcfd.c): + - Removed conflicting prototype for Linux (sscanf) + - Corrected spelling error + - Made Linux ignore parity errors. + - Added support to supply power from RS232 with CLOCK_RAWDCF. + +Ulrich Windl (parse/util/testdcf.c): + - Made Linux ignore parity errors. diff --git a/contrib/ntp/html/hints/decosf1 b/contrib/ntp/html/hints/decosf1 new file mode 100644 index 000000000000..bc4ce0bb294d --- /dev/null +++ b/contrib/ntp/html/hints/decosf1 @@ -0,0 +1,40 @@ +Some major changes were necessary to make xntp v3 run on the DEC Alpha +hardware running DEC OSF/1. All "long" and "u_long" declarations and +casts in the code were changed to "LONG" and "U_LONG" and a new header +file (include/ntp_types.h) was added. The new header file defines +LONG as int and U_LONG as u_int for the Alpha hardware and as long +and u_long for anything else. A couple of #ifs where changed in +ntpq and xntpdc to get the result of a signal defined correctly. The +Config.decosf1 file built the programs here with no problems. + +I don't have a radio clock here, so none of that code has been tested. +I have run xntpd, xntpdc, xntpres, ntpq, ntpdate, and tickadj under +DEC OSF/1 v1.2-2 (BL10). + +Mike Iglesias Internet: iglesias@draco.acs.uci.edu +University of California, Irvine BITNET: iglesias@uci +Office of Academic Computing uucp: ...!ucbvax!ucivax!iglesias +Distributed Computing Support phone: (714) 856-6926 + +Support for NTP Version 2 is included with the current OSF/1 release. If +you are upgrading to NTP Version 3 with this distribution, you should not +use the xntpd or ntpq programs that come with the OSF/1 release. The +older programs should be replaced by the newer programs of the same name, +either in situ or via a link to a tranquil spot like /usr/local/bin. The +make install script in the this distribution don't work due to a silly +install program incompatibility, so you will need to copy the programs by +hand. + +Don't use the setup utility to install or configure the xntpd installation, +as it will cheerfully clobber your painstakingly crafted ntp.conf program. +However, assuming you put this file in /etc/ntp.conf, you can use the +/sbin/init.d/xntpd script to start and stop the daemon. + +This distribution compiles with nominal mumur with the stock cc compiler +that comes with OSF/1. + +Dave Mills +Electrical Engineering Department +Unibergisty of Delabunch +mills@udel.edu + diff --git a/contrib/ntp/html/hints/decosf2 b/contrib/ntp/html/hints/decosf2 new file mode 100644 index 000000000000..e4a8828cc508 --- /dev/null +++ b/contrib/ntp/html/hints/decosf2 @@ -0,0 +1,54 @@ +Problems with DEC OSF/1 V2.0 + +Compilation using gcc fails with ntp_config.c. The problem is an apparent +error in the /usr/include/sys/procset.h and /usr/include/sys/wait.h +include files. + +cowbird:/usr/include/sys# diff -c wait.h.orig wait.h +*** wait.h.orig Tue Feb 22 02:41:38 1994 +--- wait.h Thu Aug 25 14:52:57 1994 +*************** +*** 298,304 **** + #else + + _BEGIN_CPLUSPLUS +! extern int waitid(idtype_t, id_t, siginfo_t *, int); + _END_CPLUSPLUS + #endif /* _NO_PROTO */ + +--- 298,304 ---- + #else + + _BEGIN_CPLUSPLUS +! extern int waitid(idtype_t, pid_t, siginfo_t *, int); + _END_CPLUSPLUS + #endif /* _NO_PROTO */ + +cowbird:/usr/include/sys# diff -c procset.h.orig procset.h +*** procset.h.orig Tue Feb 22 02:41:44 1994 +--- procset.h Thu Aug 25 14:43:52 1994 +*************** +*** 86,95 **** + */ + + idtype_t p_lidtype; /* The id type for the left set. */ +! id_t p_lid; /* The id for the left set. */ + + idtype_t p_ridtype; /* The id type of for right set. */ +! id_t p_rid; /* The id of the right set. */ + } procset_t; + + +--- 86,95 ---- + */ + + idtype_t p_lidtype; /* The id type for the left set. */ +! pid_t p_lid; /* The id for the left set. */ + + idtype_t p_ridtype; /* The id type of for right set. */ +! pid_t p_rid; /* The id of the right set. */ + } procset_t; + +Also, if using gcc from the freeware disk, either replace syscall.h +in the directory /usr/local/lib/gcc-lib/alpha-dec-osf1/2.3.3/include +or replace with a link to /usr/include/sys/syscall.h. diff --git a/contrib/ntp/html/hints/hpux b/contrib/ntp/html/hints/hpux new file mode 100644 index 000000000000..1640d057a350 --- /dev/null +++ b/contrib/ntp/html/hints/hpux @@ -0,0 +1,158 @@ +Last update: Sun Mar 13 15:05:31 PST 1994 + +This file hopefully describes the whatever and however of how to get xntp +running on hpux 7.0 and later s300. s400, s700, and s800. + +First off, all the standard disclaimers hold here ... HP doesn't have anthing +to do with this stuff. I fool with it in my spare time because we use it and +because I like to. We just happen to have a lot of HP machines around here :-) +Xntpd has been in use here for several years and has a fair amount of mileage +on various HP platforms within the company. I can't really guarantee bug fixes +but I'd certainly like to hear about bugs and I won't hestitate to look at +any fixes sent to me. + +Now lets talk OS. If you don't have 7.0 or later, pretty much hang it up now. +This stuff has run here on pretty much everything from 8.0 upward on s300, +s700, and s800. It is known to run on 7.0 s300/s400 but all reports are +from the field and not my personal experience. + +If you are lucky enough to have a s300 or s400 with 9.03, then you no longer +have to worry about adjtimed as HP-UX now has adjtime(2). The rest of you +will have to wait on 10.0 which will have adjtime(2) and a supported though +a bit older version of xntpd. + +Next, let me explain a bit about how this stuff works on HP-UX's that do not +have adjtime(2). The directory adjtime contains libadjtime.a and the adjtimed +daemon. Instead of the adjtime(2) system call, we use a library routine to +talk to adjtimed thru message queues. Adjtimed munges into /dev/kmem and +causes the clock to skew properly as needed. PLEASE NOTE that the adjtime +code provided here is NOT a general replacement for adjtime(2) ... use of +this adjtime(3)/adjtimed(8) other than with xntpd may yield very odd results. + +What to do to get this stuff running ? + + * If you are running an OS less than 10.0 or do not have a s300/s400 + with 9.03 or better + -> cd machines + -> vi hpux + -> (change -DSYS_HPUX=? to match whatever you are running [7,8,9]) + -> cd .. + + * Say "make makeconfig" + + * Say "make", sit back for a few minutes. + + * cd authstuff + * Say "./authcert < certdata" and check the output. Every line should + end with "OK" ... if not, we got trouble. + * Now try "./authspeed auth.samplekeys". What we want to + remember here is the "authentication delay in CPU time" + * cd .. + + * Say "make install" + + * I'd suggest reading the xntp docs about now :-) ... seriously !! + + * One thing I have added to this version of xntpd is a way to select + config files if you are sharing /usr/local thru NFS or whatever. + If the file /usr/local/etc/xntp.conf happens to be a directory, the + files in that directory are searched until a match is found. The + rules for a match are: + + 1. Our hostname + 2. default. (as in default.375 or default.850) + 3. default + + * Ok, make sure adjtimed is running (just start it up for now with + "/usr/local/etc/adjtimed"). Using -z as an option will get you + a usage message. + + * Now start up xntpd and watch it work. + + * Make sure that adjtimed gets started at boot right before xntpd. + We do this in /etc/netbsdsrc. They must both run as root !! + +Possible problems ? + + * On some 320's and 835's we have had to run adjtimed with "-p 45" or + so to get rid of syslog messages about "last adjust did not finish". + + * At 9.0, there is a problem with DIAGMON (patch available from the + response center) which causes it to delete the message queue that + adjtimed/xntpd use to communicate. (see next note for result) + + * Xntpd has been known to get really ticked off when adjtime() fails + which is usually only while running the emulation code on HP-UX. + When it gets mad, it usually jumps the clock into never never land. + Possible reasons for this are adjtimed being killed or just never + started or adjtimed being completely swapped out on a really busy + machine (newer adjtimed try to lock themselves in memory to prevent + this one). + +Anything else ... just drop me a line at ken@sdd.hp.com + +Received: from louie.udel.edu by huey.udel.edu id aa14418; 15 Jun 95 9:19 EDT +Received: from host5.colby.edu (host-05.colby.edu) by host-04.colby.edu with ESMTP (1.37.109.15/Colby 1.1) + id AA165442355; Thu, 15 Jun 1995 09:19:16 -0400 +Received: by host5.colby.edu (1.37.109.15/Colby 1.1) + id AA056252339; Thu, 15 Jun 1995 09:18:59 -0400 +Date: Thu, 15 Jun 1995 09:18:59 -0400 (EDT) +From: "Jeff A. Earickson" +To: Mills@huey.udel.edu +Subject: More minor bugs in xntp3.4s +In-Reply-To: <9506150022.aa12727@huey.udel.edu> +Message-Id: +Mime-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII + +Dave, + After reading the hpux hints file, I realized I didn't install or +start adjtimed. In the course of doing this, I discovered that: + +--> $(TOP) is not defined in adjtime/Makefile, so "make install" can't + find the install.sh script. + +--> "make install" from the main Makefile never goes into the adjtime + directory, so I added the following two lines into the install + target of the main Makefile: + + @echo installing from adjtime + @cd adjtime && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install + +This twiddle may not be right for all systems, but it got adjtimed +installed for me. + + You might also want to add to the hpux hints file that one way to +fire things up at boot time is to add the following lines to the localrc +function of /etc/rc: + + #---daemons for Network Time Protocol (version 3.4s) + #---note that adjtimed is only needed for HP-UX 9.X, not 10.0 + #---adjtimed must be running or xntpd won't work right... + if [ -x /usr/local/bin/adjtimed ]; then + /usr/local/bin/adjtimed -r & echo -n ' adjtimed' + if [ -x /usr/local/bin/xntpd ]; then + /usr/local/bin/xntpd & echo -n ' xntpd' + fi + fi + +I discovered that the "-r" option of adjtimed is needed to clear out any +trash from a previous execution of it. Otherwise adjtimed quietly dies +and leaves xntpd in the lurch... + +Thanks for the help. + +** Jeff A. Earickson, Ph.D PHONE: 207-872-3659 +** Senior UNIX Sysadmin, Information Technology EMAIL: jaearick@colby.edu +** Colby College, 4214 Mayflower Hill, FAX: 207-872-3555 +** Waterville ME, 04901-8842 + +On Thu, 15 Jun 1995 Mills@huey.udel.edu wrote: + +> Jeff, +> +> Read the hpux file in the hints directory. +> +> Dave +> + diff --git a/contrib/ntp/html/hints/linux b/contrib/ntp/html/hints/linux new file mode 100644 index 000000000000..b06a36a63465 --- /dev/null +++ b/contrib/ntp/html/hints/linux @@ -0,0 +1,5 @@ +The kernel PLL interface is broken, I know. +Update RSN. + + Torsten + (duwe@informatik.uni-erlangen.de) diff --git a/contrib/ntp/html/hints/notes-xntp-v3 b/contrib/ntp/html/hints/notes-xntp-v3 new file mode 100644 index 000000000000..ba027f2105fe --- /dev/null +++ b/contrib/ntp/html/hints/notes-xntp-v3 @@ -0,0 +1,119 @@ +Notes for NTP Version 3 + +This version operates in much the same manner as Version 2 with the +following changes and additions: + +1. The protocol machinery operates in conformance with the RFC1305 NTP + Version 3 specification. The most visible characteristic of this + version is that the poll intervals for all polls, even selected + ones, is significantly increased. This is especially desirable when + serving a large client population. This implementation supports + previous versions as non-configured peers; for version-2 configured + peers a "version 2" keyword should be included on the "peer" line. + +2. The configuration file has a new keyword: statfile , where + is the name of a statistics file." When present, each clock + update generates an entry of the form: + + . + + where is the modified Julian day, . is the time of + day, is the peer address and is the peer status. + The , and are the measured offset, delay and + dispersion, respectively, of the peer clock relative to the local + clock. About once per day the current file is closed and a new one + created with names ., where starts at one and + increments for each new generation. + +3. A number of additional platforms are supported. See ./Config file + for details. + +4. A driver for the TrueTime 468DC GOES Synchronized Clock is + included. This driver (refclock_goes.c) should also work for other + TrueTime radio clocks, since all use the same format. + +5. A replacement driver for the Spectracom 8170 WWVB Synchronized + Clock is included. This driver (refclock_wwvb.c) (a) does not + require a 1-pulse-per-second signal, (b) supports both format 0 + (original 8170) and format 2 (Netclock/2 and upgraded 8170), (c) + can be connected to more than one computer and (d) automatically + compensates for all serial baud rates. + +6. A driver for the German time/frequency station DCF77 is included. + This requires a special STREAMS module. + +7. In Version 2 special line-discipline modules were required for the + CHU and WWVB drivers. This code continues to work in Version 3, + although it is no longer needed for the WWVB driver. However, this + code does not work under STREAMS, as used in SunOS 4.1.1. + Equivalent STREAMS modules are supplied with Version 3. + +8. Support for an external 1-pulse-per-second (pps) signal is + provided. The signal is connected to a serial port (see + xntpd/ntp_loopfilter.c for details). When present the leading edge + of the pulse establishes the on-time epoch within an interval + established by the selected radio clock or other NTP time server. + Use of the pps is indicated when the tattletale displayed by ntpq + changes from "*" to "o". + +9. The clock-selection and poll-update procedures have been modified + slightly in order to achieve better performance on high speed LANs + with compromise in performance on typical WANs. + +10. In order to comply with U.S. Commerce Department regulations, the DES + encryption routine lib/authdes.c cannot be exported. For exportable + versions of this distribution a DES-encrypted version of this routine + lib/authdes.c.des is included along with an unencrypted version + lib/authdes.c.export, which allows normal operation, but without the + NTP authentication feature. Further information is available in the + lib/authdes.c.export file. + +11. As an alternative to the DES-based authentication mechanism, an + implementation of the RSA Message Digest 5 algorithm is provided. + (see applicable copyright information in the library files). + +12. A driver for the Magnavox MX4200 GPS clock. + +13. A STREAMS module which captures carrier-detect data-lead transitions to + connect a precision source of 1-pps, yet avoid the ugly overhead in the + usual STREAMS processing. See the ppsclock subdirectory. + +14. Support for the Apple A/UX operating system and enhanced support for the + Hewlet-Packard HP/UX operating system. See the various README and Config + files for further information. + +See the COPYRIGHT file for authors and copyright information. Note that some +modules in this distribution contain copyright information that supersedes +the copyright information in that file. + +If I missed something or neglected to give due credit, please advise. + +David L. Mills +University of Delaware +31 May 1992, amended 23 July 1992, 25 October 1992 + +Bugs and notes + +A bug in the original tty_clk_STREAMS.c module has been fixed. + +The poll-interval randomization feature of poll_update (in +xntpd/ntp_proto.c) has been extended to apply when the poll interval is +increased, as well as reduced. This spreads the update messages in time +and helps avoid unpleasant bursts of messages. + +In the clock_select algorithm the peers selected for combining are +limited to those survivors at the lowest stratum, not the entire list. +This helps avoid whiplash when large numbers of peers are at the same +stratum. + +The number formerly displayed by ntpq as "compliance" is now the time +constant of integration. + +The DNS resolver xntpd/ntp_intres.c is now integrated into xntpd, making +configuration of multiple hosts easier. + +System and peer event are now written to the system log at priority +LOG_INFO. + +The leap-second code was fixed to avoid broadcasting leap warnings on +all except the last day of June and December. diff --git a/contrib/ntp/html/hints/parse b/contrib/ntp/html/hints/parse new file mode 100644 index 000000000000..d2523515e839 --- /dev/null +++ b/contrib/ntp/html/hints/parse @@ -0,0 +1,105 @@ +Compilation: + Usual thing: rm -f Config.local ; make for vanilla + make refconf for reference clock (e. g. DCF77) + +Directory contents: + + hints/PARSE - this file + + xntpd/refclock_parse.c + - reference clock support for DCF77/GPS in xntp + parse/parse.c + - Reference clock data parser framework + parse/parse_conf.c + - parser configuration (clock types) + parse/clk_meinberg.c + - Meinberg clock formats (DCF U/A 31, PZF 535, GPS166) + parse/clk_schmid.c + - Schmid receiver (DCF77) + parse/clk_rawdcf.c + - 100/200ms pulses via 50 Baud line (DCF77) + parse/clk_dcf7000.c + - ELV DCF7000 (DCF77) + parse/clk_trimble.c + - Trimble SV6 GPS receiver + + If you want to add new clock types please check + with kardel@informatik.uni-erlangen.de. These files + implement the conversion of RS232 data streams into + timing information used by refclock_parse.c which is + mostly generic except for NTP configuration constants. + + parse/Makefile.kernel + - *SIMPLE* makefile to build a loadable STREAMS + module for SunOS 4.x / SunOS 5.x systems + + parse/parsestreams.c + - SUN Streams module (loadable) for radio clocks + This streams module is designed for SunOS 4.1.X. + + parse/parsesolaris.c + - SUN Streams module (loadable) for radio clocks. + This streams module is designed for SunOS 5.x + Beware this is still new - so it might crash + your machine (we have seen it working, though). + + parse/parsetest.c + - simple test program for STREAMS module. Its so simple, + that it doesn't even set TTY-modes, thus they got to + be correct on startup - works for Meinberg receivers + + parse/testdcf.c + - test program for raw DCF77 (100/200ms pulses) + receivers + + include/parse.h - interface to "parse" module and more + include/parse_conf.h + - interface to "parse" configuration + + include/sys/parsestreams.h + - STREAMS specific definitions + + scripts/support + - scripts (perl & sh) for statistics and rc startup + the startup scripts are used in Erlangen for + starting the daemon on a variety of Suns and HPs + and for Reference Clock startup on Suns + These scripts may or may not be helpful to you. + +Supported clocks: + Meinberg DCF U/A 31 + Meinberg PZF535/TCXO (Software revision PZFUERL 4.6) + Meinberg PZF535/OCXO (Software revision PZFUERL 4.6) + Meinberg GPS166 (Software version for Uni-Erlangen) + ELV DCF7000 (not recommended - casual/emergency use only) + Conrad DCF77 receiver (email: time@informatik.uni-erlangen.de) + + level converter + TimeBrick (email: time@informatik.uni-erlangen.de) + Schmid Receiver Kit + Trimble SV6 GPS receiver + +Addresses: + Meinberg Funkuhren + Auf der Landwehr 22 + 31812 Bad Pyrmont + Germany + Tel.: 05281/20 18 + FAX: 05281/60 81 80 + + ELV Kundenservice + Postfach 1000 + 26787 Leer + Germany + Tel.: 0491/60 08 88 + + Walter Schmidt + Eichwisrain 14 + 8634 Hombrechtikon + Switzerland + +If you have problems mail to: + + time@informatik.uni-erlangen.de + +We'll help (conditions permitting) + diff --git a/contrib/ntp/html/hints/refclocks b/contrib/ntp/html/hints/refclocks new file mode 100644 index 000000000000..17e76434a307 --- /dev/null +++ b/contrib/ntp/html/hints/refclocks @@ -0,0 +1,35 @@ +This is a short overview for the reference clocks currently supported +by xntp V3. (Ultimate wisdom can be obtained from xntpd/refclock_*.c +this file was derived from that information - unfortunately some comments +in the files tend to get stale - so use with caution) + +Refclock address Type +127.127.0.x no clock (fails to configure) +127.127.1.x local clock - use local clock as reference +127.127.2.x no clock (fails to configure) +127.127.3.x PSTI 1010/1020 WWV Clock +127.127.4.x SPECTRACOM WWVB receiver 8170 and Netclock/2 +127.127.5.x Kinimetric Truetime 468-DC GOES receiver +127.127.6.x IRIG audio decode (Sun & modified BSD audio driver) +127.127.7.x CHU Timecode (via normal receiver & Bell 103 modem) +127.127.8.x PARSE (generic driver for a bunch of DCF/GPS clocks + can be extended for other clocks too) + 8.0-3 Meinberg PZF535/TCXO + 8.4-7 Meinberg PZF535/OCXO + 8.8-11 Meinberg DCF U/A 31 + 8.12-15 ELV DCF7000 + 8.16-19 Walter Schmid DCF receiver (Kit) + 8.20-23 Conrad DCF77 receiver module + level converter (Kit) + 8.24-27 TimeBrick (limited availability ask + time@informatik.uni-erlangen.de) + 8.28-31 Meinberg GPS166 + 8.32-35 Trimble SV6 GPS receiver +127.127.9.x MX4200 GPS receiver +127.127.10.x Austron 2201A GPS Timing Receiver +127.127.11.x Kinemetrics Truetime OM-DC OMEGA Receiver +127.127.12.x KSI/Odetecs TPRO-S IRIG-B / TPRO-SAT GPS +127.127.13.x Leitch: CSD 5300 Master Clock System Driver +127.127.14.x MSFEES +127/127.15.x TrueTime GPS/TM-TMD +127.127.16.x Bancomm GPS/IRIG Ticktock +127.127.17.x Datum Programmable Time System diff --git a/contrib/ntp/html/hints/rs6000 b/contrib/ntp/html/hints/rs6000 new file mode 100644 index 000000000000..8561ac29b1b0 --- /dev/null +++ b/contrib/ntp/html/hints/rs6000 @@ -0,0 +1,56 @@ +15.7.1993 +xntp3 compiles now again on AIX. I have disabled prototyping and added +the switch -D_NO_PROTO which disables prototyping in the system include +files. + +Matthias Ernst maer@nmr.lpc.ethz.ch +-------------------------------------------------------------------------------- +Xntp version 3 now support the cc compiler for AIX. +The Config.aix will now use cc by default. You can still compile xntp +with the bsd compiler by changing "COMP= cc" to "COMP= bsdcc" and +and removing the "-DSTUPID_SIGNAL" option from the "DEFS" option. + +xntp and tickadj was also modified so that the value of tickadj is read +form the kernel and can be set by tickadj. For now I would not set +tickadj below 40 us. + +Bill Jones +jones@chpc.utexas.edu +------------------------------------------------------------------------------- + +This is a modified version of xntp version 3 for the RS6000. It works for +AIX 3.2 and these are the same changes as have been applied tothe version 2 +implementation of xntp. It works fine for us but I have not tested all of +the features, especially the local clock support for the RS6000 is not tested +at all. + +Matthias Ernst, ETH-Zuerich, Switzerland - maer@nmr.lpc.ethz.ch + +-------------------------------------------------------------------------------- + +Here the original README.rs6000 for the version 2 implementation: + +A hacked version of xntp for the IBM RS/6000 under AIX 3.1 can be found +in xntp.rs6000.tar.Z. [ if still available at all - Frank Kardel 93/12/3 ] + +This will not work on older versions of AIX due to a kernel bug; to find +out whether you have the kernel bug, compile and run testrs6000.c (see +comments in the code for instructions). + +xntp and testrs6000 require "bsdcc" to compile. This is simply another +entry point into the xlc compiler with various options set for BSD +compatibility. If your system does not have bsdcc, do the following: + +link /bin/bsdcc to /bin/xlc + +put the following into /etc/xlc.cfg: + +* BSD compatibility +bsdcc: use = DEFLT + crt = /lib/crt0.o + mcrt = /lib/mcrt0.o + gcrt = /lib/gcrt0.o + libraries = -lbsd, -lc + proflibs = -L/lib/profiled,-L/usr/lib/profiled + options = -H512,-T512, -qlanglvl=extended, -qnoro, -D_BSD, -D_NONSTD_TYPES, -D_NO_PROTO, -tp,-B/lib/ + diff --git a/contrib/ntp/html/hints/sco.htm b/contrib/ntp/html/hints/sco.htm new file mode 100644 index 000000000000..2273faa7a436 --- /dev/null +++ b/contrib/ntp/html/hints/sco.htm @@ -0,0 +1,39 @@ + + + SCO Unix hints + + +

SCO Unix hints

+ +

Older SCO Unix versions

+

+ NTP 4.0.x does not run on SCO Unix prior to version 3.2.5.0.0. If you + need NTP on an older SCO Unix system and don't mind to modify your + kernel, use 3.5.91 which has patches for SCO Unix 3.2.4.x. Apply the + kernel modifications as described in + XNTP on SCO + 3.2.4.2. + +

Compiling NTP

+

+ Delete the old SCO supplied NTP programs using the "custom" + utility. Run the NTP configure program with CFLAGS="-b elf -K + processor-type" for best results. + +

Running NTP

+

+ Run "tickadj -As" after every reboot to set the variables + "clock_drift" and "track_rtc" to the right values. +

+ Run "ntpd" with a high negative nice-value, i.e. + "nice --19 ntpd" for best results. + +

More information

+

+ More information on the way SCO Unix and NTP interact can be found in + NTP on SCO Unix, + which includes links to precompiled versions of NTP. +

+ Kees Hendrikse, January 1999 + + diff --git a/contrib/ntp/html/hints/sgi b/contrib/ntp/html/hints/sgi new file mode 100644 index 000000000000..5e4f7de6d597 --- /dev/null +++ b/contrib/ntp/html/hints/sgi @@ -0,0 +1,74 @@ +adjtime, tick and tickadj: +-------------------------- + +The SGI value for HZ is 100 under Irix 4, with the system clock running +in nominal mode (ftimer off), so the value for tick is 10000 usec. +Tickadj is a bit more tricky because of the behaviour of adjtime(), +which seems to try to perform the correction over 100-200 seconds, with +a rate limit of 0.04 secs/sec for large corrections. Corrections of +less than 0.017 seconds generally complete in less than a second, +however. + +Some measured rates are as follows: + + Delta Rate (sec/sec) + + > 1 0.04 + 0.75 0.04 + 0.6 0.004 + 0.5 0.004 + 0.4 0.0026 + 0.3 0.0026 + 0.2 0.0013 + 0.1 0.0015 + 0.05 0.0015 + 0.02 0.0003 + 0.01 0.015 +Strange. Anyway, since adjtime will complete adjustments of less than +17msec in less than a second, whether the fast clock is on or off, I +have used a value of 150usec/tick for the tickadj value. + +Fast clock: +----------- + +I get smoother timekeeping if I turn on the fast clock, thereby making +the clock tick at 1kHz rather than 100Hz. With the fast clock off, I +see a sawtooth clock offset with an amplitude of 5msec. With it on, +the amplitude drops to 0.5msec (surprise!). This may be a consequence +of having a local reference clock which spits out the time at exactly +one-second intervals - I am probably seeing sampling aliasing between +that and the machine clock. This may all be irrelevant for machines +without a local reference clock. Fiddling with the fast clock doesn't +seem to compromise the above choices for tick and tickadj. + +I use the "ftimer" program to switch the fast clock on when the system +goes into multiuser mode, but you can set the "fastclock" flag in +/usr/sysgen/master.d/kernel to have it on by default. See ftimer(1). + +timetrim: +--------- + +Irix has a kernel variable called timetrim which adjusts the system +time increment, effectively trimming the clock frequency. Xntpd could +use this rather than adjtime() to do it's frequency trimming, but I +haven't the time to explore this. There is a utility program, +"timetrim", in the util directory which allows manipulation of the +timetrim value in both SGI and xntpd native units. You can fiddle with +default timetrim value in /usr/sysgen/master.d/kernel, but I think +that's ugly. I just use xntpd to figure out the right value for +timetrim for a particular CPU and then set it using "timetrim" when +going to multiuser mode. + +Serial I/O latency: +------------------- + +If you use a local clock on an RS-232 line, look into the kernel +configuration stuff with regard to improving the input latency (check +out /usr/sysgen/master.d/[sduart|cdsio]). I have a Kinemetrics OM-DC +hooked onto /dev/ttyd2 (the second CPU board RS-232 port) on an SGI +Crimson, and setting the duart_rsrv_duration flag to 0 improves things +a bit. + + +12 Jan 93 +Steve Clift, CSIRO Marine Labs, Hobart, Australia (clift@ml.csiro.au) diff --git a/contrib/ntp/html/hints/solaris.html b/contrib/ntp/html/hints/solaris.html new file mode 100644 index 000000000000..8595fbfc3e17 --- /dev/null +++ b/contrib/ntp/html/hints/solaris.html @@ -0,0 +1,139 @@ + + +Solaris hints and kinks + + +Information on compiling and executing ntpd under Solaris. +
+Last Updated: Sun Jun 21 01:32:18 EDT 1998, +John Hawkinson, + <jhawk@MIT.EDU> +

+If you're not running Solaris 2.5.1 or later, it is likely +that you will have problems; upgrading would be a really good plan. +

+

All Solaris versions

+

+Proper operation of ntp under Solaris requires setting the kernel +variable dosynctodr to zero (meaning "do not synchronize the clock +to the hardware time-of-day clock"). This can be done with the +tickadj utility: +

+tickadj -s +
+If you prefer, it can also be done with the native Solaris kernel debugger: +
+echo dosynctodr/W0 | adb -k -w /dev/ksyms /dev/mem +
+

+Or, it can also be set by adding a line to /etc/system: +

+set dosynctodr = 0 +
+

+Instead of the tick kernel variable, which many operating +systems use to control microseconds added to the system time every +clock tick (c.f. Dealing +with Frequency Tolerance Violations), Solaris has the variables +nsec_per_tick and usec_per_tick. +

+nsec_per_tick and usec_per_tick control the number of +nanoseconds and microseconds, respectively, added to the system clock +each clock interrupt. Enterprising souls may set these based on +information collected by ntpd in the /etc/ntp.drift file +to correct for individual hardware variations. +

+On UltraSPARC systems, nsec_per_tick and usec_per_tick +are ignored in favor of the cpu_tick_freq variable, which +should be automatically be determined by the PROM in an accurate +fashion. +

+In general, the same ntp binaries should not be used across multiple +operating system releases. There is enough variation in the core operating +system support for timekeeping that a rebuild of ntpd for the idiosyncracies +of your specific operating system version is advisable. +

+It is recommended that ntp be started via a script like this one, installed in +/etc/init.d/ntpd with a symbol link from +/etc/rc2.d/S99ntpd. + +

Solaris 2.6

+

+Solaris 2.6 adds support for kernel PLL timekeeping, but breaks this +support in such a fashion that using it worse than not. This is SUN Bug ID 4095849, and it is not yet +fixed as of June 1998. +

+

Solaris 2.5 and 2.5.1

+

+On UltraSPARC systems, calculation of cpu_tick_freq is broken +such that values that are off by significant amounts may be used +instead. This unfortunately means that ntpd may have severe problems +keeping synchronization. This is SUN Bug ID +4023118. Bryan Cantrill of Sun +posted patchfreq, a workaround script, +to comp.protocols.time.ntp in March of 1997. +

+


+

OLD DATA

+I can't vouch for the accuracy the information below this +rule. It may be significantly dated or incorrect. +

+

+

Solaris 2.2

+

+Solaris 2.2 and later contain completely re-written clock code to +provide high resolution microsecond timers. A benefit of the +re-written clock code is that adjtime does not round off its +adjustments, so ntp does not have to compensate for this +rounding. Under Solaris 2.2 and later, ntp #define's +ADJTIME_IS_ACCURATE, and does not look for the tickadj +kernel variable. +

+

Solaris 2.1

+(This originally written by William L. Jones <jones@chpc.utexas.edu>) +

+Solaris 2.1 contains fairly traditional clock code, with tick +and tickadj. +

+Since settimeofday under Solaris 2.1 only sets the seconds part of timeval +care must be used in starting xntpd. I suggest the following start +up script: +

+tickadj -s -a 1000 +
ntpdate -v server1 server2 +
sleep 20 +
ntpdate -v server1 server2 +
sleep 20 +
tickadj -a 200 +
xntpd +
+ +The first tickadj turns of the time of day clock and sets the tick +adjust value to 1 millisecond. This will insure that an adjtime value +of at most 2 seconds will complete in 20 seconds. +

+The first ntpdate will set the time to within two seconds +using settimeofday or it will adjust time using adjtime. +

+The first sleep insures the adjtime has completed for the first ntpdate. +

+The second ntpdate will use adjtime to set the time of day since the +clock should be within 2 seconds of the correct time. +

+The second tickadj set the tick adjust system value to 5 microseconds. +

+The second sleeps insure that adjtime will complete before starting +the next xntpd. +

+I tried running with a tickadj of 5 microseconds with out much success. +200 microseconds seems to work well. +

+


+Prior versions of this file had major text contributed by: + +
  • Denny Gentry <denny@eng.sun.com> +
  • + + diff --git a/contrib/ntp/html/hints/solaris.xtra.4023118 b/contrib/ntp/html/hints/solaris.xtra.4023118 new file mode 100644 index 000000000000..84c5d15214b2 --- /dev/null +++ b/contrib/ntp/html/hints/solaris.xtra.4023118 @@ -0,0 +1,36 @@ + Bug Id: 4023118 + Category: kernel + Subcategory: other + State: integrated + Synopsis: sun4u doesn't keep accurate time + Description: + +[ bmc, 12/20/96 ] + +The clock on a sun4u drifts unacceptably. On a typical 143 mHz Ultra, +the clock took 1.0001350 seconds to count 1 second. While this may seem +trivial, it adds up quickly. In this case, the TOD chip will have to +pull the clock forward by 2 seconds every 4 hours and 7 minutes. +This drift rate is so high, that the clock is close to being too broken +for NTP to guarantee correctness (in order for NTP's mechanism to work, +it must be assured that the local clock drifts no more than 20 ms in 64 +seconds; this particular 143 mHz Ultra will drift by nearly 9 ms in that +period). This problem has been reproduced on virtually all sun4u +classes. + +The fundamental problem lies in the kernel's perception of ticks per +second. The PROM is responsible for determining this figure exactly, +and the kernel extracts it into the variable cpu_tick_freq. On sun4u's, +this number is disconcertingly round: 143000000, 167000000, 248000000, +etc. Indeed, a simple experiment revealed that these numbers were +quite far from the actual ticks per second. Typical was the 143 mHz +Ultra which was discovered to tick around 142,980,806 (+/- 10) times +per second. + + Work around: + + Integrated in releases: s297_27 + Duplicate of: + Patch id: + See also: + Summary: diff --git a/contrib/ntp/html/hints/solaris.xtra.4095849 b/contrib/ntp/html/hints/solaris.xtra.4095849 new file mode 100644 index 000000000000..8d3ce8074cfd --- /dev/null +++ b/contrib/ntp/html/hints/solaris.xtra.4095849 @@ -0,0 +1,74 @@ + Bug Id: 4095849 + Category: kernel + Subcategory: syscall + State: evaluated + Synopsis: time_constant value >6 with PLL in use leads to integer divide + zero trap panic + Description: +If the time_constant parameter is 7 or higher, and the phase-lock looping model +is in use, the system will take a "integer divide zero trap" panic in +the clock routine as soon as the time_offset becomes non-zero. + +time_constant defaults to 0. The only place it is set is in the ntp_adjtime +system call, from the 'constant' element of the timex structure argument. + + Work around: +Never set the constant element of the timex structure passed to ntp_adjtime to +a value larger than 6. + +satish.mynam@Eng 1998-04-30 +1. Use Sun's version of NTP software instead of PD version. This problem +is not seen with Sun's NTP version (which is mostly eqivalent to PD NTP 3.4 +plus some Sun's local functionality futures). + +2. Workaround for the public domain NTP version ONLY: + ===================================================== +The workaround for public domain NTP version is to disable the +KERNEL_PLL from the NTP code. This way ntp_Adjtime() system call is +totally bypassed without sacrificing any of the functionality of the +NTP. The only hit you might see is the way kernel precision timminig +is done without the PLL algorithm in the kernel. + + The easiest way to disable ntp_adjtime option is(without changing + any makefiles or other config files) to disable the KERNEL_PLL + value in the ./config.h file. + +After doing a ./configure for probing for all the necessary tools(compilers, +os version, libraries), please comment out KERNEL_PLL macro in +the ./config.h file. This will disable the KERNEL_PLL part of the source +code and the newly obtained xntpd is just similar to the old one but it +does not use ntp_adjtime() system call. This prevents it from panic'ng +the kernel. + +/*#define KERNEL_PLL 1*/ + +I complied a new xntpd binary this way and it does nothave any ntp_adjtime() +related stuff. + +Default: +======= +/net/divya/export/home/mynam/public_domain/ntp/xntp3-5.92/xntpd>strings +xntpd | +grep ntp_adjtime +354:adj_frequency: ntp_adjtime failed: %m +357:loop_config: ntp_adjtime() failed: %m +435:get_kernel_info: ntp_adjtime() failed: %m + +With KERNEL_PLL disabled in config.h file +-======================= + +/net/divya/export/home/mynam/public_domain/ntp/xntp3-5.92/xntpd>strings +xntpd.nopll | grep ntp_adjtime + + Integrated in releases: + Duplicate of: + Patch id: + See also: 4133517 + Summary: +If the time_constant parameter is 7 or higher, and the phase-lock looping model +is in use, the system will take a "integer divide zero trap" panic in +the clock routine as soon as the time_offset becomes non-zero. + +time_constant defaults to 0. The only place it is set is in the ntp_adjtime +system call, from the 'constant' element of the timex structure argument. +---------------------------------------------------------------------------- diff --git a/contrib/ntp/html/hints/solaris.xtra.S99ntpd b/contrib/ntp/html/hints/solaris.xtra.S99ntpd new file mode 100644 index 000000000000..33662ba73fd0 --- /dev/null +++ b/contrib/ntp/html/hints/solaris.xtra.S99ntpd @@ -0,0 +1,20 @@ +#!/bin/sh +if [ $1 = "start" ]; then + if [ -x /usr/local/bin/xntpd ]; then + echo "Starting NTP daemon, takes about 1 minute... " + # The following line is unnecessary if you turn off + # dosynctodr in /etc/system. + /usr/local/bin/tickadj -s + /usr/local/bin/ntpdate -v server1 server2 + sleep 5 + /usr/local/bin/xntpd + fi +else + if [ $1 = "stop" ]; then + pid=`/usr/bin/ps -e | /usr/bin/grep xntpd | /usr/bin/sed -e 's/^ *//' -e 's/ .*//'` + if [ "${pid}" != "" ]; then + echo "Stopping Network Time Protocol daemon " + /usr/bin/kill ${pid} + fi + fi +fi diff --git a/contrib/ntp/html/hints/solaris.xtra.patchfreq b/contrib/ntp/html/hints/solaris.xtra.patchfreq new file mode 100644 index 000000000000..9600881500e8 --- /dev/null +++ b/contrib/ntp/html/hints/solaris.xtra.patchfreq @@ -0,0 +1,85 @@ +#!/bin/ksh + +# +# File: patchfreq +# Author: Bryan Cantrill (bmc@eng.sun.com), Solaris Performance +# Modified: Sat Apr 26 04:00:59 PDT 1997 +# +# This is a little script to patch a 5.5 or 5.5.1 kernel to get around +# the cpu_tick_freq inaccuracy. Before running this script, one must +# know the true frequency of one's CPU; this can be derived by NTP, +# or by observing the clock relative to the time-of-day chip over a +# long period of time (the TOD will pull system time when it drifts +# by more than two seconds). +# +# Patching a kernel can render a machine unbootable; do not run this +# script unless you are prepared to accept that possibility. It +# is advisable to have a backout path (e.g. net booting, an alternate +# boot disk, an installation CD) should your machine fail to boot. +# +# This is not a product of Sun Microsystems, and is provided "as is", +# without warranty of any kind expressed or implied including, but not +# limited to, the suitability of this script for any purpose. +# + +if [ $# -eq 0 ]; then + echo "Usage: $0 cpu_tick_freq [ alternate_kernel ]" + exit 1 +fi + +cpu_tick_freq=$1 +kernel=/platform/sun4u/kernel/unix + +if [ $# -eq 2 ]; then + kernel=$2 +fi + +if [ ! -w $kernel ]; then + echo "$0: Cannot open $kernel for writing." + exit 1 +fi + +arch=`echo utsname+404?s | adb $kernel | cut -d: -f2` + +if [ ! $arch = "sun4u" ]; then + echo "Patch only applies to sun4u" + exit 1 +fi + +rel=`echo utsname+202?s | adb $kernel | cut -d: -f2` + +if [ ! $rel = "5.5" ] && [ ! $rel = "5.5.1" ]; then + echo "Patch only applies to 5.5 or 5.5.1..." + exit 1 +fi + +nop="1000000" # nop +store_mask="ffffe000" # mask out low 13 bits +store="da256000" # st %o5, [%l5 + offset] + +instr=`echo setcpudelay+34?X | adb $kernel | cut -d: -f 2 | nawk '{ print $1 }'` + +if [ $instr = $nop ]; then + echo "Instruction already patched..." +else + let masked="(16#$store_mask & 16#$instr) - 16#$store" + if [ $masked -ne 0 ]; then + echo "Couldn't find instruction to patch; aborting." + exit 1 + fi + + if ! echo setcpudelay+34?W $nop | adb -w $kernel 1> /dev/null + then + echo "adb returned an unexpected error; aborting." + fi +fi + +echo "Patching cpu_tick_freq to $cpu_tick_freq..." + +if ! echo cpu_tick_freq?W 0t$cpu_tick_freq | adb -w $kernel 1> /dev/null; then + echo "adb returned an unexpected error; aborting." + exit 1 +fi + +echo "$kernel successfully patched." +exit 0 diff --git a/contrib/ntp/html/hints/sun4 b/contrib/ntp/html/hints/sun4 new file mode 100644 index 000000000000..424fa1873824 --- /dev/null +++ b/contrib/ntp/html/hints/sun4 @@ -0,0 +1,15 @@ +Notes on CPU clock oscillator tolerance with SunOS 4.1.1 and 4.1.3 + +A bug in SunOS 4.1.1 results in the kernel time losing 1 microsecond +per tick of the system clock. The bug was fixed (bugid 1094383) for +SunOS 4.1.1 and corrected in SunOS 4.1.3. The easiest way to fix this +is to replace the 4.1.1 binary clock.o with the corresponding 4.1.3 +binary. Without this change it is necessary to use the tickadj program +included in this distribution with the -t 9999 option. + +The tickadj option will work in all cases except when the kernel has +been modified to correct the CPU clock oscillator frequency using a +1-pps signal from a precision source. The bugfix must be installed for +this wrinkle to work properly. + +Dave Mills (mills@udel.edu) diff --git a/contrib/ntp/html/hints/svr4-dell b/contrib/ntp/html/hints/svr4-dell new file mode 100644 index 000000000000..2c92f8a6337e --- /dev/null +++ b/contrib/ntp/html/hints/svr4-dell @@ -0,0 +1,8 @@ +Notes on the DELL SVR4. + +You should use -DSETTIMEOFDAY_BROKEN. + +Philip.Gladstone@mail.citicorp.com + +(XXX But there is no checking for SETTIMEOFDAY_BROKEN in the code) + diff --git a/contrib/ntp/html/hints/svr4_package b/contrib/ntp/html/hints/svr4_package new file mode 100644 index 000000000000..b9f5ca391f34 --- /dev/null +++ b/contrib/ntp/html/hints/svr4_package @@ -0,0 +1,33 @@ +Date: Wed, 12 Apr 1995 12:42:03 +0100 +Message-ID: <513.797686923@concurrent.co.uk> +From: Andy Chittenden + +Dave + +Here is a uuencoded, compressed tar file. The only file I've +changed is Makefile - I've included the full file rather than diffs. +There are some new files as well: + + xntp shell script that starts up ntp during boot up + (the packaging stuff creates links to it so it comes + up at run level 2). As with all svr4 start/stop + scripts, it takes one parameter which is either + start or stop. It assumes that ntp.conf is in + /etc/inet/ntp.conf (where it should be on svr4 + machines). + prototype describes the file contents of the package. + You might like to review its contents to + see whether you want to include any other + files or remove some. NB I've made the man + pages go into 1m as they should on svr4. + preinstall runs before installation takes place. It + ensures that ntp is down if it is up before + installing a replacement package + postinstall starts up ntp after package installation. + preremove brings down ntp before removing the package. + +You create a package using "make package". This creates a file +called xntp.pkg. To install this package, you use +"pkgadd -d `pwd`/xntp.pkg xntp". This will start up ntp if +/etc/inet/ntp.conf exists. If you don't want the package anymore, use +"pkgrm xntp". I have tested this on Solaris 2.4. diff --git a/contrib/ntp/html/hints/todo b/contrib/ntp/html/hints/todo new file mode 100644 index 000000000000..e0e5ffa37696 --- /dev/null +++ b/contrib/ntp/html/hints/todo @@ -0,0 +1,4 @@ +Ulrich Windl : + Any change in a source file in the lib directory causes all files to + be recompiled (because the objects are removed). Add a better rule for + make to update the library. Maybe just remove "-rm -f $?". diff --git a/contrib/ntp/html/hints/vxworks.html b/contrib/ntp/html/hints/vxworks.html new file mode 100644 index 000000000000..4df83c5afd56 --- /dev/null +++ b/contrib/ntp/html/hints/vxworks.html @@ -0,0 +1,18 @@ + + + vxWorks Port of NTP + + + +

    VxWorks port of NTP

    + +

    Please look at the Vxworks file in the html directory. + +

    Casey Crellin
    +casey@csc.co.za

    + +


    +

    + + + diff --git a/contrib/ntp/html/hints/winnt b/contrib/ntp/html/hints/winnt new file mode 100644 index 000000000000..6fd7c84aa74d --- /dev/null +++ b/contrib/ntp/html/hints/winnt @@ -0,0 +1,207 @@ +------------- +INTRODUCTION: +------------- +Last revision 27 July 1999 Version 4.0.95. + +This version compiles under WINNT with Visual C 6.0. + +Greg Brackley and Sven Dietrich + +Significant changes: +-Visual Studio v6.0 support +-Winsock 2.0 support +-Use of I/O completion ports for sockets and comm port I/O +-Removed the use of multimedia timers (from ntpd, others need removing) +-Use of waitable timers (with user mode APC) and performance counters to fake getting a better time +-Trimble Palisade NTP Reference Clock support +-General cleanup, prototyping of functions +-Moved receiver buffer code to a separate module (removed unused members from the recvbuff struct) +-Moved io signal code to a separate module + +Compiling Instructions: +1. Requires Perl to be installed, and the Perl environment variable to be set correctly +2. Open the .\ports\winnt\ntp.dsw +3. Batch build of all debug projects compile + + +Last revision: 20-Oct-1996 + +This version corrects problems with building the XNTP +version 3.5-86 distribution under Windows NT. + +The following files were modified: + blddbg.bat + bldrel.bat + include\ntp_machine.h + xntpd\ntp_unixclock.c + xntpd\ntp_refclock.c + scripts\wininstall\build.bat + scripts\wininstall\setup.rul + scripts\wininstall\readme.nt + scripts\wininstall\distrib\ntpog.wri + html\hints\winnt (this file) + +In order to build the entire Windows NT distribution you +need to modify the file scripts\wininstall\build.bat +with the installation directory of the InstallShield +software. Then, simply type "bldrel" for non-debug +or "blddbg" for debug executables. + + + +Greg Schueman + + + +Last revision: 07-May-1996 + +This set of changes fixes all known bugs, and it includes +several major enhancements. + +Many changes have been made both to the build environment as +well as the code. There is no longer an ntp.mak file, instead +there is a buildntall.bat file that will build the entire +release in one shot. The batch file requires Perl. Perl +is easily available from the NT Resource Kit or on the Net. + +The multiple interface support was adapted from Larry Kahn's +work on the BIND NT port. I have not been able to test it +adequately as I only have NT servers with one network +interfaces on which to test. + +Enhancements: +* Event Logging now works correctly. +* Version numbers now work (requires Perl during build) +* Support for multiple network interface cards (untested) +* NTP.CONF now default, but supports ntp.ini if not found +* Installation procedure automated. +* All paths now allow environment variables such as %windir% + +Bug fixes: +* INSTSRV replaced, works correctly +* Cleaned up many warnings +* Corrected use of an uninitialized variable in XNTPD +* Fixed ntpdate -b option +* Fixed ntpdate to accept names as well as IP addresses + (Winsock WSAStartup was called after a gethostbyname()) +* Fixed problem with "longjmp" in xntpdc/ntpdc.c that + caused a software exception on doing a Control-C in xntpdc. + A Cntrl-C now terminates the program. + +See below for more detail: + + Note: SIGINT is not supported for any Win32 application including + Windows NT and Windows 95. When a CTRL+C interrupt occurs, Win32 + operating systems generate a new thread to specifically handle that + interrupt. This can cause a single-thread application such as UNIX, + to become multithreaded, resulting in unexpected behavior. + + +Possible enhancements and things left to do: +* Reference clock drivers for NT (at least Local Clock support) +* Control Panel Applet +* InstallShield based installation, like NT BIND has +* Integration with NT Performance Monitor +* SNMP integration +* Fully test multiple interface support + + +Known problems: +* bug in ntptrace - if no Stratum 1 servers are available, + such as on an IntraNet, the application crashes. + + + + +Last revision: 12-Apr-1995 + + +This NTPv3 distribution includes a sample configuration file and the project +makefiles for WindowsNT 3.5 platform using Microsoft Visual C++ 2.0 compiler. +Also included is a small routine to install the NTP daemon as a "service" +on a WindowsNT box. Besides xntpd, the utilities that have been ported are +ntpdate and xntpdc. The port to WindowsNT 3.5 has been tested using a Bancomm +TimeServe2000 GPS receiver clock that acts as a strata 1 NTP server with no +authentication (it has not been tested with any refclock drivers compiled in). +Following are the known flaws in this port: +1) currently, I do not know of a way in NT to get information about multiple + network interface cards. The current port uses just one socket bound to + INADDR_ANY address. Therefore when dealing with a multihomed NT time server, + clients should point to the default address on the server (otherwise the + reply is not guaranteed to come from the same interface to which the + request was sent). Working with Microsoft to get this resolved. +2) There is some problem with "longjmp" in xntpdc/ntpdc.c that causes a + software exception on doing a Control-C in xntpdc. Be patient! +3) The error messages logged by xntpd currently contain only the numerical + error code. Corresponding error message string has to be looked up in + "Books Online" on Visual C++ 2.0 under the topic "Numerical List of Error + Codes". + + +---------------------------------------------------- +MAKING XNTPD FOR WindowsNT 3.5 using Visual C++ 2.0: +---------------------------------------------------- + +Separate projects are needed for xntpd, ntpdate, xntpdc, and the library +containing routines used by them. + +1) First build the static library composed of routines in the lib + subdirectory of the distribution. Load the project by opening the + corresponding makefile libntp.mak (in the lib subdirectory of the + distribution) by choosing the Open option in the File menu. This should + display a list of files contained in this project. Then choose the + "Rebuild All" option from the Project menu in order to compile the + routines into a library. The libntp.lib static library is created in + the lib/WinDebug directory + + You can now choose to build xntpd, ntpdate, and xntpdc in any order. + +2) To build xntpd, load the project by opening the corresponding makefile + xntpd.mak (in the xntpd subdirectory of the distribution), and rebuild + all files. The xntpd.exe executable is created in the xntpd/WinDebug + directory. + +3) repeat the above step for ntpdate and xntpdc + + +------------------------------------------------- +INSTALLING XNTPD AS A SERVICE UNDER WindowsNT 3.5 +------------------------------------------------- + +At this point you need to install 'xntpd' as a service. First modify the +sample configuration file conf/config.winnt35 in the distribution to +suit your needs. Then install it as "%SystemRoot%\NTP.INI" (%SystemRoot% +is an environmental variable that can be determined by typing "set" at +the "Command Prompt" or from the "System" icon in the "Control Panel", +NTP.INI is the suggested name for the "ntp.conf" file in Windows environment). +The instsrv.c program in the util subdirectory of the distribution can +be used to install 'xntpd' as a service and start automatically at boot +time. Compile instsrv.c, and enter form the command prompt + "instsrv.exe NetWorkTimeProtocol " +Clicking on the "Services" icon in the "Control Panel" ("Main" group +in the "Program Manager") will display the list of currently installed +services in a dialog box. The NetworkTimeProtocol service should show +up in this list. Select it in the list and hit the "Start" button in +the dialog box. The NTP service should start. View the event log by +clicking on the "Event Viewer" icon in the "Administrative Tools" group +of the "Program Manager", there should be several successful startup +messages from NTP. NTP will keep running and restart automatically when +the machine is rebooted. + +You can change the start mode (automatic/manual) and other startup +parameters correponding to the NTP service (eg. location of conf file) +also in the "Services" dialog box if you wish. + +There is no clean way to run 'ntpdate' before starting 'xntpd' at boot +time, unlike the Unix environment. 'xntpd' will step the clock upto +a 1000 seconds. While there is no reason that the system clock should +be that much off during bootup if 'xntpd' was running before bootup, +you may want to increase the CLOCK_WAYTOOBIG parameter in include/ntp.h +from 1000 to, say, MAXINT. + +You can also use instsrv.c to delete the NTP service + "instsrv.exe NetworkTimeProtocol remove" + + +Viraj Bais + diff --git a/contrib/ntp/html/howto.htm b/contrib/ntp/html/howto.htm new file mode 100644 index 000000000000..7d03df9cdd8c --- /dev/null +++ b/contrib/ntp/html/howto.htm @@ -0,0 +1,315 @@ + +How to Write a Reference Clock Driver +

    +How to Write a Reference Clock Driver +


    + +

    Description

    + +

    Reference clock support maintains the fiction that the clock is +actually an ordinary peer in the NTP tradition, but operating at a +synthetic stratum of zero. The entire suite of algorithms used to filter +the received data, select the best clocks or peers and combine them to +produce a local clock correction operate just like ordinary NTP peers. +In this way, defective clocks can be detected and removed from the peer +population. As no packets are exchanged with a reference clock; however, +the transmit, receive and packet procedures are replaced with separate +code to simulate them. + +

    Radio and modem reference clocks by convention have addresses in the +form 127.127.t.u, where t is the clock +type and u in the range 0-3 is used to distinguish multiple +instances of clocks of the same type. Most clocks require a serial port +or special bus peripheral. The particular device is normally specified +by adding a soft link /dev/devicedd to the particular +hardware device involved, where d corresponds to the +unit number. + +

    The best way to understand how the clock drivers work is to study the +ntp_refclock.c module and one of the drivers already +implemented, such as refclock_wwvb.c. Routines +refclock_transmit() and refclock_receive() maintain +the peer variables in a state analogous to a network peer and pass +received data on through the clock filters. Routines +refclock_peer() and refclock_unpeer() are called to +initialize and terminate reference clock associations, should this ever +be necessary. A set of utility routines is included to open serial +devices, process sample data, edit input lines to extract embedded +timestamps and to perform various debugging functions. + +

    The main interface used by these routines is the +refclockproc structure, which contains for most drivers the +decimal equivalents of the year, day, month, hour, second and +millisecond/microsecond decoded from the ASCII timecode. Additional +information includes the receive timestamp, exception report, statistics +tallies, etc. The support routines are passed a pointer to the +peer structure, which is used for all peer-specific processing +and contains a pointer to the refclockproc structure, which in +turn contains a pointer to the unit structure, if used. For legacy +purposes, a table typeunit[type][unit] contains the peer +structure pointer for each configured clock type and unit. + +

    The reference clock interface supports auxiliary functions to support +in-stream timestamping, pulse-per-second (PPS) interfacing and precision +time kernel support. In most cases the drivers do not need to be aware +of them, since they are detected at autoconfigure time and loaded +automatically when the device is opened. These include the +tty_clk and ppsclock STREAMS modules and +ppsapi PPS interface described in the Line +Disciplines and Streams Modules page. The tty_clk module +reduces latency errors due to the operating system and serial port code +in slower systems. The ppsclock module is an interface for the +PPS signal provided by some radios. The ppsapi PPS interface +replaces the ppsclock STREAMS module and is expected to become +the IETF standard cross-platform interface for PPS signals. In either +case, the PPS signal can be connected via a level converter/pulse +generator described in the Gadget Box PPS Level +Converter and CHU Modem page. + +

    By convention, reference clock drivers are named in the form +refclock_xxxx.c, where xxxx is a unique +string. Each driver is assigned a unique type number, long-form driver +name, short-form driver name, and device name. The existing assignments +are in the Reference Clock Drivers page +and its dependencies. All drivers supported by the particular hardware +and operating system are automatically detected in the autoconfigure +phase and conditionally compiled. They are configured when the daemon is +started according to the configuration file, as described in the Configuration Options page. + +

    The standard clock driver interface includes a set of common support +routines some of which do such things as start and stop the device, open +the serial port, and establish special functions such as PPS signal +support. Other routines read and write data to the device and process +time values. Most drivers need only a little customizing code to, for +instance, transform idiosyncratic timecode formats to standard form, +poll the device as necessary, and handle exception conditions. A +standard interface is available for remote debugging and monitoring +programs, such as ntpq and ntpdc, as well as +the filegen facility, which can be used to record device +status on a continuous basis. + +

    The general organization of a typical clock driver includes a +receive-interrupt routine to read a timecode from the I/O buffer and +convert to internal format, generally in days, hours, minutes, seconds +and fraction. Some timecode formats include provisions for leap-second +warning and determine the clock hardware and software health. The +interrupt routine then calls refclock_process() with these data +and the timestamp captured at the on-time character of the timecode. +This routine saves each sample as received in a circular buffer, which +can store from a few up to 60 samples, in cases where the timecodes +arrive one per second. + +

    The refclock_transmit() routine in the interface is called +by the system at intervals defined by the poll interval in the peer +structure, generally 64 s. This routine in turn calls the transmit poll +routine in the driver. In the intended design, the driver calls the +refclock_receive() to process the offset samples that have +accumulated since the last poll and produce the final offset and +variance. The samples are processed by recursively discarding median +outlyers until about 60 percent of samples remain, then averaging the +surviving samples. When a reference clock must be explicitly polled to +produce a timecode, the driver can reset the poll interval so that the +poll routine is called a specified number of times at 1-s intervals. + +

    The interface code and this documentation have been developed over +some time and required not a little hard work converting old drivers, +etc. Should you find success writing a driver for a new radio or modem +service, please consider contributing it to the common good. Send the +driver file itself and patches for the other files to Dave Mills +(mills@udel.edu). + +

    Conventions, Fudge Factors and Flags

    + +

    Most drivers support manual or automatic calibration for systematic +offset bias using values encoded in the fudge configuration +command. By convention, the time1 value defines the calibration +offset in seconds. For those drivers that support statistics collection +using the filegen utility and the clockstats file, the +flag4 switch enables the utility. When a PPS signal is +available, a special automatic calibration facility is provided. If the +flag1 switch is set and the PPS signal is actively disciplining +the system time, the calibration value is automatically adjusted to +maintain a residual offset of zero. Should the PPS signal or the prefer +peer fail, the adjustment is frozen and the remaining drivers continue +to discipline the system clock with a minimum of residual error. + +

    Files Which Need to be Changed

    + +

    A new reference clock implementation needs to supply, in addition to +the driver itself, several changes to existing files. + +

    + +
    ./include/ntp.h +
    The reference clock type defines are used in many places. Each +driver is assigned a unique type number. Unused numbers are clearly +marked in the list. A unique REFCLK_xxxx +identification code should be recorded in the list opposite its assigned +type number. + +

    ./libntp/clocktypes.c +
    The ./libntp/clktype array is used by certain display +functions. A unique short-form name of the driver should be entered +together with its assigned identification code. + +

    ./ntpd/ntp_control.c +
    The clocktypes array is used for certain control +message displays functions. It should be initialized with the reference +clock class assigned to the driver, as per the NTP specification +RFC-1305. See the ./include/ntp_control.h header file for +the assigned classes. + +

    ./ntpd/refclock_conf.c +
    This file contains a list of external structure definitions which +are conditionally defined. A new set of entries should be installed +similar to those already in the table. The refclock_conf +array is a set of pointers to transfer vectors in the individual +drivers. The external name of the transfer vector should be initialized +in correspondence with the type number. + +

    ./acconfig.h +
    This is a configuration file used by the autoconfigure scheme. Add +two lines in the form: + +

    +  /* Define if we have a FOO clock */
    +  #undef FOO
    +
    + +

    where FOO is the define used to cause the driver to be included in +the distribution. + +

    ./configure.in +
    This is a configuration file used by the autoconfigure scheme. Add +lines similar to the following: + +

    +  AC_MSG_CHECKING(FOO clock_description)
    +  AC_ARG_ENABLE(FOO, [  --enable-FOO        clock_description],
    +      [ntp_ok=$enableval], [ntp_ok=$ntp_eac])
    +  if test "$ntp_ok" = "yes"; then
    +      ntp_refclock=yes
    +      AC_DEFINE(FOO)
    +  fi
    +  AC_MSG_RESULT($ntp_ok)
    +
    + +

    (Note that $ntp_eac is the value from -- +{dis,en}able-all-clocks for non-PARSE clocks and +$ntp_eacp is the value from --{dis,en}able-parse- +clocks for PARSE clocks. See the documentation on the autoconf +and automake tools from the GNU distributions.) + +

    ./ntpd/Makefile.am +

    This is the makefile prototype used by the autoconfigure scheme. +Add the driver file name to the entries already in the +ntpd_SOURCES list. + +

    Patches to automake-1.0 are required for the +autoconfigure scripts to work properly. The file automake- +1.0.patches can be used for this purpose. + +

    ./ntpd/Makefile.am +
    Do the following sequence of commands: + +

    +  automake
    +  autoconf
    +  autoheader
    +  configure
    +
    + +

    or simply run make, which will do this command sequence +automatically. + +

    + +

    Interface Routine Overview

    + +
    + +
    refclock_newpeer - initialize and start a reference +clock +
    This routine allocates and initializes the interface structure which +supports a reference clock in the form of an ordinary NTP peer. A +driver-specific support routine completes the initialization, if used. +Default peer variables which identify the clock and establish its +reference ID and stratum are set here. It returns one if success and +zero if the clock address is invalid or already running, insufficient +resources are available or the driver declares a bum rap. +

    refclock_unpeer - shut down a clock +
    This routine is used to shut down a clock and return its resources +to the system. + +

    refclock_transmit - simulate the transmit procedure +
    This routine implements the NTP transmit procedure for a reference +clock. This provides a mechanism to call the driver at the NTP poll +interval, as well as provides a reachability mechanism to detect a +broken radio or other madness. + +

    refclock_sample - process a pile of samples from the +clock +
    This routine converts the timecode in the form days, hours, minutes, +seconds, milliseconds/microseconds to internal timestamp format. It then +calculates the difference from the receive timestamp and assembles the +samples in a shift register. It implements a recursive median filter to +suppress spikes in the data, as well as determine a rough dispersion +estimate. A configuration constant time adjustment +fudgetime1 can be added to the final offset to compensate +for various systematic errors. The routine returns one if success and +zero if failure due to invalid timecode data or very noisy offsets. + +

    Note that no provision is included for the year, as provided by some +(but not all) radio clocks. Ordinarily, the year is implicit in the Unix +file system and hardware/software clock support, so this is ordinarily +not a problem. Nevertheless, the absence of the year should be +considered more a bug than a feature and may be supported in future. + +

    refclock_receive - simulate the receive and packet +procedures +
    This routine simulates the NTP receive and packet procedures for a +reference clock. This provides a mechanism in which the ordinary NTP +filter, selection and combining algorithms can be used to suppress +misbehaving radios and to mitigate between them when more than one is +available for backup. + +

    refclock_gtlin - groom next input line and extract +timestamp +
    This routine processes the timecode received from the clock and +removes the parity bit and control characters. If a timestamp is present +in the timecode, as produced by the tty_clk line +discipline/streams module, it returns that as the timestamp; otherwise, +it returns the buffer timestamp. The routine return code is the number +of characters in the line. + +

    refclock_open - open serial port for reference clock +
    This routine opens a serial port for I/O and sets default options. +It returns the file descriptor if success and zero if failure. + +

    refclock_ioctl - set serial port control functions +
    This routine attempts to hide the internal, system-specific details +of serial ports. It can handle POSIX (termios), SYSV +(termio) and BSD (sgtty) interfaces with +varying degrees of success. The routine sets up the tty_clk, +chu_clk and ppsclock streams module/line discipline, +if compiled in the daemon and requested in the call. The routine returns +one if success and zero if failure. + +

    refclock_control - set and/or return clock values +
    This routine is used mainly for debugging. It returns designated +values from the interface structure that can be displayed using ntpdc +and the clockstat command. It can also be used to initialize +configuration variables, such as fudgetimes, fudgevalues, +reference ID and stratum. + +

    refclock_buginfo - return debugging info +
    This routine is used mainly for debugging. It returns designated +values from the interface structure that can be displayed using +ntpdc and the clkbug command. + +
    + +
    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/htmlprimer.htm b/contrib/ntp/html/htmlprimer.htm new file mode 100644 index 000000000000..898a5833e0a2 --- /dev/null +++ b/contrib/ntp/html/htmlprimer.htm @@ -0,0 +1,1198 @@ + + + +A Beginner's Guide to HTML + + + +

    A Beginner's Guide to HTML

    + +

    +This is a primer for producing documents in HTML, the markup language +used by the World Wide Web. + +

    + +

    Acronym Expansion

    +
    +
    WWW +
    World Wide Web (or Web, for short). +
    SGML +
    Standard Generalized Markup Language -- this is a standard for + describing markup languages. +
    DTD +
    Document Type Definition -- this is a specific markup language, + written using SGML. +
    HTML +
    HyperText Markup Language -- HTML is a SGML DTD. In practical + terms, HTML is a collection of styles (indicated by markup tags) + that define the various components of a World Wide Web document. +HTML was invented by Tim Berners-Lee while at CERN. He is now director +of the W3 Consortium. +
    + +

    What This Primer Doesn't Cover

    +

    +This primer assumes that you have: + +

      +
    • at least a passing knowledge of how to use NCSA Mosaic or some + other Web browser +
    • a general understanding of how Web servers and client browsers + work +
    • access to a Web server for which you would like to produce HTML + documents, or that you wish to produce HTML documents for personal + use +
    + +

    Creating HTML Documents

    +

    +HTML documents are in plain (also known as ASCII) text format and can +be created using any text editor (e.g., Emacs or vi on UNIX machines). +A couple of Web browsers (tkWWW for X Window System machines and CERN's +Web browser for NeXT computers) include rudimentary HTML editors in +a WYSIWYG environment. There are also some WYSIWIG editors available +now (e.g. HotMetal for Sun Sparcstations, HTML Edit for Macintoshes). +You may wish to try one of them first before delving into the details +of HTML. +

    + You can preview a document in progress with NCSA Mosaic (and + some other Web browsers). Open it with the Open Local + command under the File menu. + +

    + After you edit the source HTML file, save the changes. Return + to NCSA Mosaic and Reload the document. The + changes are reflected in the on-screen display. + +

    + +

    The Minimal HTML Document

    +

    +Here is a bare-bones example of HTML: + +

    +    <TITLE>The simplest HTML example</TITLE>
    +    <H1>This is a level-one heading</H1>
    +    Welcome to the world of HTML. 
    +    This is one paragraph.<P>
    +    And this is a second.<P>
    +
    + +Click here to see the formatted version +of the example. + +

    +HTML uses markup tags to tell the Web browser how to display the text. +The above example uses: + +

      +
    • the <TITLE> tag (and corresponding </TITLE> + tag), which specifies the title of the document +
    • the <H1> header tag (and corresponding </H1>) +
    • the <P> paragraph-separator tag +
    + +

    +HTML tags consist of a left angle bracket (<), (a ``less +than'' symbol to mathematicians), followed by name of the tag and closed +by a right angular bracket (>). Tags are usually paired, +e.g. <H1> and </H1>. The ending +tag looks just like the starting tag except a slash (/) precedes the +text within the brackets. In the example, <H1> tells +the Web browser to start formatting a level-one heading; </H1> +tells the browser that the heading is complete. + +

    +The primary exception to the pairing rule is the <P> +tag. There is no such thing as </P>. + +

    +NOTE: HTML is not case sensitive. <title> +is equivalent to <TITLE> or <TiTlE>. + + +

    +Not all tags are supported by all World Wide Web browsers. If a browser +does not support a tag, it just ignores it. + +

    Basic Markup Tags

    +

    Title

    +

    +Every HTML document should have a title. A title is generally displayed +separately from the document and is used primarily for document identification +in other contexts (e.g., a WAIS search). Choose about half a dozen +words that describe the document's purpose. +

    + In the X Window System and Microsoft Windows versions of NCSA + Mosaic, the Document Title field is at the + top of the screen just below the pulldown menus. In NCSA + Mosaic for Macintosh, text tagged as <TITLE> + appears as the window title. + +
    + +

    Headings

    +

    +HTML has six levels of headings, numbered 1 through 6, with 1 being +the most prominent. Headings are displayed in larger and/or bolder +fonts than normal body text. The first heading in each document should +be tagged <H1>. The syntax of the heading tag is: + +

    +<Hy>Text of heading +</Hy > + +

    +where y is a number between 1 and 6 specifying the level +of the heading. + +

    +For example, the coding for the ``Headings'' section heading above +is + +

    +    <H3>Headings</H3>
    +
    + +
    Title versus first heading
    +

    +In many documents, the first heading is identical to the title. For +multipart documents, the text of the first heading should be suitable +for a reader who is already browsing related information (e.g., a chapter +title), while the title tag should identify the document in a wider +context (e.g., include both the book title and the chapter title, although +this can sometimes become overly long). + +

    Paragraphs

    +

    +Unlike documents in most word processors, carriage returns in HTML +files aren't significant. Word wrapping can occur at any point in your +source file, and multiple spaces are collapsed into a single space. +(There are couple of exceptions; space following a <P> +or <Hy> tag, for example, +is ignored.) Notice that in the bare-bones example, the first paragraph +is coded as + +

    +    Welcome to HTML.
    +    This is the first paragraph. <P>
    +
    + +

    +In the source file, there is a line break between the sentences. A +Web browser ignores this line break and starts a new paragraph only +when it reaches a <P> tag. + +

    +Important: You must separate paragraphs with <P>. +The browser ignores any indentations or blank lines in the source text. +HTML relies almost entirely on the tags for formatting instructions, +and without the <P> tags, the document becomes one +large paragraph. (The exception is text tagged as ``preformatted,'' +which is explained below.) For instance, the following would produce +identical output as the first bare-bones HTML example: + +

    +    <TITLE>The simplest HTML example</TITLE><H1>This is a level 
    +    one heading</H1>Welcome to the world of HTML. This is one 
    +    paragraph.<P>And this is a second.<P>
    +
    + +

    +However, to preserve readability in HTML files, headings should be +on separate lines, and paragraphs should be separated by blank lines +(in addition to the <P> tags). +

    + NCSA Mosaic handles <P> by ending the current paragraph + and inserting a blank line. + +
    + +

    +In HTML+, a successor to HTML currently in development, <P> +becomes a ``container'' of text, just as the text of a level-one heading +is ``contained'' within<H1> ... </H1>: + +

    +    <P>
    +    This is a paragraph in HTML+.
    +    </P>
    +
    + +

    +The difference is that the </P> closing tag can +always be omitted. (That is, if a browser sees a <P>, +it knows that there must be an implied </P> to end +the previous paragraph.) In other words, in HTML+, <P> +is a beginning-of-paragraph marker. + +

    +The advantage of this change is that you will be able to specify formatting +options for a paragraph. For example, in HTML+, you will be able to +center a paragraph by coding + +

    +    <P ALIGN=CENTER>
    +    This is a centered paragraph. This is HTML+, so you can't do it yet.
    +
    + +

    +This change won't effect any documents you write now, and they will +continue to look just the same with HTML+ browsers. + +

    Linking to Other Documents

    +

    +The chief power of HTML comes from its ability to link regions of text +(and also images) to another document. The browser highlights these +regions (usually with color and/or underlines) to indicate that they +are hypertext links (often shortened to hyperlinks or simply +links). + +

    +HTML's single hypertext-related tag is <A>, which +stands for anchor. To include an anchor in your document: + +

      +
    1. Start the anchor with <A . (There's a space after + the A.) +
    2. Specify the document that's being pointed to by entering the parameter + HREF="filename" + followed by a closing right angle bracket: > +
    3. Enter the text that will serve as the hypertext link in the current + document. +
    4. Enter the ending anchor tag: </A>. +
    + +

    +Here is an sample hypertext reference: + +

    +    <A HREF="MaineStats.html">Maine</A>
    +
    + +

    +This entry makes the word ``Maine'' the hyperlink to the document MaineStats.html, +which is in the same directory as the first document. You can link +to documents in other directories by specifying the relative path +from the current document to the linked document. For example, a link +to a file NJStats.html located in the subdirectory AtlanticStates +would be: + +

    +    <A HREF="AtlanticStates/NJStats.html">New Jersey</A>
    +
    + +

    +These are called relative links. You can also use the absolute +pathname of the file if you wish. Pathnames use the standard UNIX syntax. + +

    Relative Links Versus Absolute Pathnames

    +

    +In general, you should use relative links, because + +

      +
    1. You have less to type. +
    2. It's easier to move a group of documents to another location, because + the relative path names will still be valid. +
    + +

    +However, use absolute pathnames when linking to documents that are +not directly related. For example, consider a group of documents that +comprise a user manual. Links within this group should be relative +links. Links to other documents (perhaps a reference to related software) +should use full path names. This way, if you move the user manual to +a different directory, none of the links would have to be updated. + +

    Uniform Resource Locator

    +

    +The World Wide Web uses Uniform Resource Locators (URLs) to specify +the location of files on other servers. A URL includes the type of +resource being accessed (e.g., gopher, WAIS), the address of the server, +and the location of the file. The syntax is: + +

    +scheme://host.domain[:port]/path/filename + +

    +where scheme is one of + +

    +
    file +
    +
    +
    a file on your local system, or a file on an anonymous FTP server + +
    http +
    a file on a World Wide Web server +
    gopher +
    a file on a Gopher server +
    WAIS +
    a file on a WAIS server +
    news +
    an Usenet newsgroup +
    telnet +
    a connection to a Telnet-based service +
    + +

    +The port number can generally be omitted. (That means unless +someone tells you otherwise, leave it out.) + +

    +For example, to include a link to this primer in your document, you +would use + +

    +    <A HREF = "http://www.ncsa.uiuc.edu/General/Internet/WWW/HTMLPrimer.html"> 
    +    NCSA's Beginner's Guide to HTML</A>
    +
    + +

    +This would make the text ``NCSA's Beginner's Guide to HTML'' a hyperlink +to this document. + +

    +For more information on URLs, look at + +

    + +

    Links to Specific Sections in Other Documents

    +

    +Anchors can also be used to move to a particular section in a document. +Suppose you wish to set a link from document A and a specific section +in document B. (Call this file documentB.html.) First +you need to set up a named anchor in document B. For example, +to set up an anchor named ``Jabberwocky'' to document B, enter + +

    +    Here's <A NAME = "Jabberwocky">some text</a>
    +
    + +

    +Now when you create the link in document A, include not only the filename, +but also the named anchor, separated by a hash mark (#). + +

    +    This is my <A HREF = "documentB.html#Jabberwocky">link</A> to document B.
    +
    + +

    +Now clicking on the word ``link'' in document A sends the reader directly +to the words ``some text'' in document B. + +

    Links to Specific Sections Within the Current Document

    +

    +The technique is exactly the same except the filename is omitted. + +

    +For example, to link to the Jabberwocky anchor from within the same +file (Document B), use + +

    +    This is <A HREF = "#Jabberwocky">Jabberwocky link</A> from within Document B.
    +
    + +

    Additional Markup Tags

    +

    +The preceding is sufficient to produce simple HTML documents. For more +complex documents, HTML has tags for several types of lists, preformatted +sections, extended quotations, character formatting, and other items. + +

    Lists

    +

    +HTML supports unnumbered, numbered, and definition lists. + +

    Unnumbered Lists

    +

    +To make an unnumbered list, + +

      +
    1. Start with an opening list <UL> tag. +
    2. Enter the <LI> tag followed by the individual + item. (No closing </LI> tag is needed.) +
    3. End with a closing list </UL> tag. +
    + +

    +Below an example two-item list: + +

    +    <UL>
    +    <LI> apples
    +    <LI> bananas
    +    </UL>
    +
    + +

    +The output is: + +

      +
    • apples +
    • bananas +
    + +

    +The <LI> items can contain multiple paragraphs. +Just separate the paragraphs with the <P> paragraph +tags. + +

    Numbered Lists

    +

    +A numbered list (also called an ordered list, from which the tag name +derives) is identical to an unnumbered list, except it uses <OL> +instead of <UL>. The items are tagged using the +same <LI> tag. The following HTML code + +

    +    <OL>
    +    <LI> oranges
    +    <LI> peaches
    +    <LI> grapes
    +    </OL>
    +
    + +

    +produces this formatted output: + +

      +
    1. oranges +
    2. peaches +
    3. grapes +
    + +

    Definition Lists

    +

    +A definition list usually consists of alternating a term (abbreviated +as DT) and a definition (abbreviated as DD). +Web browsers generally format the definition on a new line. + +

    +The following is an example of a definition list: + +

    +    <DL>
    +    <DT> NCSA
    +    <DD> NCSA, the National Center for Supercomputing Applications,
    +         is located on the campus of the University of Illinois 
    +         at Urbana-Champaign. NCSA is one of the participants in the
    +         National MetaCenter for Computational Science and Engineering.
    +    <DT> Cornell Theory Center
    +    <DD> CTC is located on the campus of Cornell University in Ithaca,
    +         New York. CTC is another participant in the National MetaCenter
    +         for Computational Science and Engineering.
    +    </DL>
    +
    + +

    +The output looks like: + +

    +
    NCSA +
    NCSA, the National Center for Supercomputing Applications, is located + on the campus of the University of Illinois at Urbana-Champaign. + NCSA is one of the participants in the National MetaCenter for + Computational Science and Engineering. +
    Cornell Theory Center +
    CTC is located on the campus of Cornell University in Ithaca, New + York. CTC is another participant in the National MetaCenter for + Computational Science and Engineering. +
    + +

    +The <DT> and <DD> entries can +contain multiple paragraphs (separated by <P> paragraph +tags), lists, or other definition information. + +

    Nested Lists

    +

    +Lists can be arbitrarily nested, although in practice you probably +should limit the nesting to three levels. You can also have a number +of paragraphs, each containing a nested list, in a single list item. + +

    + An example nested list: + +

    +    <UL>
    +    <LI> A few New England states:
    +        <UL>
    +        <LI> Vermont
    +        <LI> New Hampshire
    +        </UL>
    +    <LI> One Midwestern state:
    +        <UL>
    +        <LI> Michigan
    +        </UL>
    +    </UL>
    +
    + +

    +The nested list is displayed as + +

      +
    • A few New England states: +
        +
      • Vermont +
      • New Hampshire +
      +
    • One Midwestern state: +
        +
      • Michigan +
      +
    + +

    Preformatted Text

    +

    +Use the <PRE> tag (which stands for ``preformatted'') +to generate text in a fixed-width font and cause spaces, new lines, +and tabs to be significant. (That is, multiple spaces are displayed +as multiple spaces, and lines break in the same locations as in the +source HTML file.) This is useful for program listings. For example, +the following lines + +

    +    <PRE>
    +      #!/bin/csh                           
    +      cd $SCR                             
    +      cfs get mysrc.f:mycfsdir/mysrc.f   
    +      cfs get myinfile:mycfsdir/myinfile   
    +      fc -02 -o mya.out mysrc.f           
    +      mya.out                              
    +      cfs save myoutfile:mycfsdir/myoutfile 
    +      rm *                                
    +    </PRE>
    +
    + +

    +display as + +

    +      #!/bin/csh                           
    +      cd $SCR                             
    +      cfs get mysrc.f:mycfsdir/mysrc.f   
    +      cfs get myinfile:mycfsdir/myinfile   
    +      fc -02 -o mya.out mysrc.f           
    +      mya.out                              
    +      cfs save myoutfile:mycfsdir/myoutfile 
    +      rm *
    +
    + +

    +Hyperlinks can be used within <PRE> sections. You +should avoid using other HTML tags within <PRE> +sections, however. + +

    +Note that because <, >, and & have special meaning in HTML, +you have to use their escape sequences (&lt;, &gt;, +and &amp;, respectively) to enter these characters. +See the section +Special Characters for more information. + +

    Extended Quotations

    +

    +Use the <BLOCKQUOTE> tag to include quotations in +a separate block on the screen. Most browsers generally indent to separate +it from surrounding text. + +

    +An example: + +

    +    <BLOCKQUOTE>
    +    I still have a dream. It is a dream deeply rooted in the
    +    American dream. <P>
    +    I have a dream that one day this nation will rise up and 
    +    live out the true meaning of its creed. We hold these truths 
    +    to be self-evident that all men are created equal. <P>
    +    </BLOCKQUOTE>
    +
    + +

    +The result is: +

    + I still have a dream. It is a dream deeply rooted in the American + dream. + +

    + I have a dream that one day this nation will rise up and live out + the true meaning of its creed. We hold these truths to be self-evident + that all men are created equal. + +

    + +

    Addresses

    +

    +The <ADDRESS> tag is generally used to specify the +author of a document and a means of contacting the author (e.g., an +email address). This is usually the last item in a file. + +

    +For example, the last line of the online version of this guide is + +

    +    <ADDRESS>
    +    A Beginner's Guide to HTML / NCSA / pubs@ncsa.uiuc.edu
    +    </ADDRESS>
    +
    + +

    +The result is +

    A Beginner's Guide to HTML / NCSA / pubs@ncsa.uiuc.edu
    + +

    +NOTE: <ADDRESS> is not +used for postal addresses. See ``Forced Line Breaks'' on page 10 to +see how to format postal addresses. + +

    Character Formatting

    +

    +You can code individual words or sentences with special styles. There +are two types of styles: logical and physical. Logical styles +tag text according to its meaning, while physical styles +specify the specific appearance of a section. For example, in the preceding +sentence, the words ``logical styles'' was tagged as a ``definition.'' +The same effect (formatting those words in italics), could have been +achieved via a different tag that specifies merely ``put these words +in italics.'' + +

    Physical Versus Logical: Use Logical Styles When Possible

    +

    +If physical and logical styles produce the same result on the screen, +why are there both? We devolve, for a couple of paragraphs, into the +philosophy of SGML, which can be summed in a Zen-like mantra: ``Trust +your browser.'' + +

    +In the ideal SGML universe, content is divorced from presentation. +Thus, SGML tags a level-one heading as a level-one heading, but does +not specify that the level-one heading should be, for instance, 24-point +bold Times centered on the top of a page. The advantage of this approach +(it's similar in concept to style sheets in many word processors) is +that if you decide to change level-one headings to be 20-point left-justified +Helvetica, all you have to do is change the definition of the level-one +heading in the presentation device (i.e., your World Wide Web browser). + +

    +The other advantage of logical tags is that they help enforce consistency +in your documents. It's easier to tag something as <H1> +than to remember that level-one headings are 24-point bold Times or +whatever. The same is true for character styles. For example, consider +the <STRONG> tag. Most browsers render it in bold +text. However, it is possible that a reader would prefer that these +sections be displayed in red instead. Logical styles offer this flexibility. + +

    Logical Styles

    +
    +
    <DFN> +
    for a word being defined. Typically displayed in italics. (NCSA + Mosaic is a World Wide Web browser.) +
    <EM> +
    for emphasis. Typically displayed in italics. (Watch out for + pickpockets.) +
    <CITE> +
    for titles of books, films, etc. Typically displayed in italics. + (A Beginner's Guide to HTML) +
    <CODE> +
    for snippets of computer code. Displayed in a fixed-width font. + (The <stdio.h> header file) +
    <KBD> +
    for user keyboard entry. Should be displayed in a bold fixed-width + font, but many browsers render it in the plain fixed-width font. + (Enter passwd to change your password.) +
    <SAMP> +
    for computer status messages. Displayed in a fixed-width font. + (Segmentation fault: Core dumped.) +
    <STRONG> +
    for strong emphasis. Typically displayed in bold. (Important) + +
    <VAR> +
    for a ``metasyntactic'' variable, where the user is to replace + the variable with a specific instance. Typically displayed in italics. + (rm filename deletes the file.) +
    + +

    Physical Styles

    +
    +
    <B> +
    bold text +
    <I> +
    italic text +
    <TT> +
    typewriter text, e.g. fixed-width font. +
    + +

    Using Character Tags

    +

    +To apply a character style, + +

      +
    1. Start with <tag>, where + tag is the desired character formatting tag, + to indicate the beginning of the tagged text. +
    2. Enter the tagged text. +
    3. End the passage with </tag>. +
    + +

    Special Characters

    +

    Escape Sequences

    +

    +Four characters of the ASCII character set -- the left angle bracket +(<), the right angle bracket (>), the ampersand (&) and the +double quote (") -- have special meaning within HTML and therefore +cannot be used ``as is'' in text. (The angle brackets are used to indicate +the beginning and end of HTML tags, and the ampersand is used to indicate +the beginning of an escape sequence.) + +

    +To use one of these characters in an HTML document, you must enter +its escape sequence instead: + +

    +
    &lt; +
    the escape sequence for < +
    &gt; +
    the escape sequence for > +
    &amp; +
    the escape sequence for & +
    &quot; +
    the escape sequence for " +
    + +

    +Additional escape sequences support accented characters. For example: + +

    +
    &ouml; +
    the escape sequence for a lowercase o with an umlaut: ö + +
    &ntilde; +
    the escape sequence for a lowercase n with an tilde: ñ +
    &Egrave; +
    the escape sequence for an uppercase E with a grave accent: È + +
    + +

    + A full +list of supported characters is available. + +

    +NOTE: Unlike the rest of HTML, the escape sequences +are case sensitive. You cannot, for instance, use &LT; instead +of &lt;. + +

    Forced Line Breaks

    +

    +The <BR> tag forces a line break with no extra space +between lines. (By contrast, most browsers format the <P> +paragraph tag with an additional blank line to more clearly indicate +the beginning the new paragraph.) + +

    +One use of <BR> is in formatting addresses: + +

    +    National Center for Supercomputing Applications<BR>
    +    605 East Springfield Avenue<BR>
    +    Champaign, Illinois 61820-5518<BR>
    +
    + +

    Horizontal Rules

    +

    +The <HR> tag produces a horizontal line the width +of the browser window. + +

    In-line Images

    +

    +Most Web browsers can display in-line images (that is, images next +to text) that are in X Bitmap (XBM) or GIF format. Each image takes +time to process and slows down the initial display of the document, +so generally you should not include too many or overly large images. + +

    +To include an in-line image, use + +

    +    <IMG SRC=image_URL>
    +
    + +

    +where image_URL is the URL of the image file. The syntax +for IMG SRC URLs is identical to that used in an anchor +HREF. If the image file is a GIF file, then the filename +part of image_URL must end with .gif. +Filenames of X Bitmap images must end with .xbm. + +

    +By default the bottom +of an image is aligned with the text as shown in this paragraph. + +

    + +Add the ALIGN=TOP +option if you want the browser to align adjacent text with the top +of the image as shown in this paragraph. The full in-line image tag +with the top alignment is: + +

    +    <IMG ALIGN=top SRC=image_URL>
    +
    + +

    + +ALIGN=MIDDLE +aligns the text with the center of the image. + +

    Alternate Text for Browsers That Can't Display Images

    +

    +Some World Wide Web browsers, primarily those that run on VT100 terminals, +cannot display images. The ALT option allows you to specify +text to be displayed when an image cannot be. For example: + +

    +    <IMG SRC = "UpArrow.gif" ALT = "Up">
    +
    + +

    +where UpArrow.gif is the picture of an upward pointing +arrow. With NCSA Mosaic and other graphics-capable viewers, the user +sees the up arrow graphic. With a VT100 browser, such as lynx, the +user sees the word ``Up.'' + +

    External Images, Sounds, and Animations

    +

    +You may want to have an image open as a separate document when a user +activates a link on either a word or a smaller, in-line version of +the image included in your document. This is considered an external +image and is useful if you do not wish to slow down the loading of +the main document with large in-line images. + +

    +To include a reference to an external image, use + +

    +    <A HREF = image_URL>link anchor</A>
    +
    + +

    +Use the same syntax is for links to external animations and sounds. +The only difference is the file extension of the linked file. For example, + +

    +<A HREF = "QuickTimeMovie.mov">link anchor</A> + +

    +specifies a link to a QuickTime movie. Some common file types and their +extensions are: + +

    +
    File Type +
    Extension +
    Plain text +
    .txt +
    HTML document +
    .html +
    GIF image +
    .gif +
    TIFF image +
    .tiff +
    XBM bitmap image +
    .xbm +
    JPEG image +
    .jpg or .jpeg +
    PostScript file +
    .ps +
    AIFF sound +
    .aiff +
    AU sound +
    .au +
    QuickTime movie +
    .mov +
    MPEG movie +
    .mpeg or .mpg +
    + +

    +Make sure your intended audience has the necessary viewers. Most UNIX +workstations, for instance, cannot view QuickTime movies. + +

    Troubleshooting

    +

    Avoid Overlapping Tags

    +

    +Consider this snippet of HTML: + +

    +    <B>This is an example of <DFN>overlapping</B> HTML tags.</DFN>
    +
    + +

    +The word ``overlapping'' is contained within both the <B> +and <DFN> tags. How does the browser format it? +You won't know until you look, and different browsers will likely react +differently. In general, avoid overlapping tags. + +

    Embed Anchors and Character Tags, But Nothing Else

    +

    +It is acceptable to embed anchors within another HTML element: + +

    +    <H1><A HREF = "Destination.html">My heading</A></H1>
    +
    + +

    +Do not embed a heading or another HTML element within an anchor: + +

    +    <A HREF = "Destination.html">
    +    <H1>My heading</H1>
    +    </A>
    +
    + +

    +Although most browsers currently handle this example, it is forbidden +by the official HTML and HTML+ specifications, and will not work with +future browsers. + +

    +Character tags modify the appearance of other tags: + +

    +    <UL><LI><B>A bold list item</B>
    +        <UL>
    +        <LI><I>An italic list item</I>
    +    </UL>
    +
    + +

    +However, avoid embedding other types of HTML element tags. For example, +it is tempting to embed a heading within a list, in order to make the +font size larger: + +

    +    <UL><LI><H1>A large heading</H1>
    +        <UL>
    +        <LI><H2>Something slightly smaller</H2>
    +    </UL>
    +
    + +

    +Although some browsers, such as NCSA Mosaic for the X Window System, +format this construct quite nicely, it is unpredictable (because it +is undefined) what other browsers will do. For compatibility with all +browsers, avoid these kinds of constructs. + +

    +What's the difference between embedding a <B> within +a <LI> tag as opposed to embedding a <H1> +within a <LI>? This is again a question of SGML. +The semantic meaning of <H1> is that it's the main +heading of a document and that it should be followed by the content +of the document.Thus it doesn't make sense to find a <H1> +within a list. + +

    +Character formatting tags also are generally not additive. You might +expect that + +

    +    <B><I>some text</I></B>
    +
    + +

    +would produce bold-italic text. On some browsers it does; other browsers +interpret only the innermost tag (here, the italics). + +

    Check Your Links

    +

    +When an <IMG> tag points at an image that does not +exist, a dummy image is substituted. When this happens, make sure that +the referenced image does in fact exist, that the hyperlink has the +correct information in the URL, and that the file permission is set +appropriately (world-readable). + +

    A Longer Example

    +

    +Here is a longer example of an HTML document: + +

    +    <HEAD>
    +    <TITLE>A Longer Example</TITLE>
    +    </HEAD>
    +    <BODY>
    +    <H1>A Longer Example</H1>
    +    This is a simple HTML document. This is the first
    +    paragraph. <P>
    +    This is the second paragraph, which shows special effects.  This is a 
    +    word in <I>italics</I>.  This is a word in <B>bold</B>.
    +    Here is an in-lined GIF image: <IMG SRC = "myimage.gif">. 
    +    <P>
    +    This is the third paragraph, which demonstrates links.  Here is 
    +    a hypertext link from the word <A HREF = "subdir/myfile.html">foo</A>
    +    to a document called "subdir/myfile.html". (If you 
    +    try to follow this link, you will get an error screen.) <P> 
    +    <H2>A second-level header</H2>
    +    Here is a section of text that should display as a 
    +    fixed-width font: <P>
    +    <PRE>
    +        On the stiff twig up there
    +        Hunches a wet black rook
    +        Arranging and rearranging its feathers in the rain ...
    +    </PRE>
    +    This is a unordered list with two items: <P>
    +    <UL>
    +    <LI> cranberries
    +    <LI> blueberries
    +    </UL>
    +    This is the end of my example document. <P>
    +    <ADDRESS>Me (me@mycomputer.univ.edu)</ADDRESS>
    +    </BODY>
    +
    + +Click here to see the formatted version. + +

    +In addition to tags already discussed, this example also uses the <HEAD> +... </HEAD> and <BODY> ... </BODY> +tags, which separate the document into introductory information about +the document and the main text of the document. These tags don't change +the appearance of the formatted document at all, but are useful for +several purposes (for example, NCSA Mosaic for Macintosh 2.0, for example, +allows you to browse just the header portion of document before deciding +whether to download the rest), and it is recommended that you use these +tags. + +

    For More Information

    +

    +This guide is only an introduction to HTML and not a comprehensive +reference. Below are additional sources of information. + +

    Fill-out Forms

    +

    +One major feature not discussed here is fill-out forms, which allows +users to return information to the World Wide Web server. For information +on fill-out forms, look at this + Fill-out +Forms Overview + +

    Style Guides

    +

    +The following offer advice on how to write ``good'' HTML: + +

    + +

    Other Introductory Documents

    +These cover similar information as this guide: + + +

    Additional References

    + +
    +
    +National Center for Supercomputing Applications / pubs@ncsa.uiuc.edu +
    + + diff --git a/contrib/ntp/html/index.htm b/contrib/ntp/html/index.htm new file mode 100644 index 000000000000..a676c871e88a --- /dev/null +++ b/contrib/ntp/html/index.htm @@ -0,0 +1,201 @@ + +The Network Time Protocol (NTP) Distribution +

    +The Network Time Protocol (NTP) Distribution +

    + +From pogo, Walt Kelly + +

    Pleased to meet you. +


    + +

    Introduction

    + +Note: The software contained in this distribution is available without +charge under the conditions set forth in the Copyright Notice. + +

    The Network Time Protocol (NTP) is used to synchronize the time of a +computer client or server to another server or reference time source, +such as a radio or satellite receiver or modem. It provides client +accuracies typically within a millisecond on LANs and up to a few tens +of milliseconds on WANs relative to a primary server synchronized to +Coordinated Universal Time (UTC) via a Global Positioning Service (GPS) +receiver, for example. Typical NTP configurations utilize multiple +redundant servers and diverse network paths, in order to achieve high +accuracy and reliability. Some configurations include cryptographic +authentication to prevent accidental or malicious protocol attacks. + +

    Background information on computer network time synchronization can +be found on the Executive Summary - Computer Network +Time Synchronization page. Discussion on protocol conformance issues +and interoperability with previous NTP versions can be found in the Protocol Conformance Statement page. Discussion on +year-2000 issues can be found in the Year 2000 +Conformance Statement page. Background information, bibliography and +briefing slides suitable for presentations can be found in the Network Time +Synchronization Project page. + +

    Building and Installing NTP

    + +The Building and Installing the Distribution +page presents an overview of the procedures for compiling the +distribution and installing it on a typical client or server. The build +procedures inspect the system hardware and software environment and +automatically select the appropriate options for that environment. While +these procedures work with most computers and operating systems marketed +today, exceptions requiring manual intervention do exist, as documented +in the Configuration Options and Release Notes pages. + +

    Bringing up a NTP primary server requires a radio or satellite +receiver or modem. The distribution includes hardware drivers for over +two dozen radio clocks and modem services. A list of the particular +receivers and modem drivers supported in the distribution is given in +the Reference Clock Drivers page. For most +popular workstations marketed by Digital, Sun and Hewlett Packard, as +well as widely available Unix clones such as FreeBSD and Linux, the +automatic build procedures select all drivers that run on the target +machine. While this increases the size of the executable binary +somewhat, individual drivers can be included or excluded using the +configure utility documented in the Configuration Options page. + +

    Configuring Clients and Servers

    +

    NTP is by its very nature a complex distributed network application +and can be configured and used for a great many widely divergent +timekeeping scenarios. The documentation presented on these pages +attempts to cover the entire suite of configuration, operation and +maintenance facilities which this distribution supports. However, most +applications will need only a few of these facilities. If this is the +case, the Quick Start page may be useful to get a +simple workstation on the air with an existing server. + +

    However, in order to participate in the existing NTP synchronization +subnet and obtain accurate, reliable time, it is usually necessary to +construct an appropriate configuration file, commonly called +ntp.conf, which establishes the servers and/or external +receivers or modems to be used by this particular machine. Directions +for constructing this file are in the Notes on +Configuring NTP and Setting up a NTP Subnet page. However, in many +common cases involving simple network topologies and workstations, the +file data can be specified entirely on the command line. + +

    The most important factor in providing accurate, reliable time is the +selection of modes and servers to be used in the configuration file. NTP +support for one or more computers is normally engineered as part of the +existing NTP synchronization subnet. The existing NTP subnet consists of +a multiply redundant hierarchy of servers and clients, with each level +in the hierarchy identified by stratum number. Primary servers operate +at stratum one and provide synchronization to secondary servers +operating at stratum two and so on to higher strata. In this hierarchy, +clients are simply servers that have no dependents. + +

    The NTP subnet in early 1998 includes 70 public primary (stratum 1) +servers synchronized directly to UTC by radio, satellite or modem and +located in every continent of the globe, except Antarctica (soon). +Normally, client workstations and servers with a relatively small number +of clients do not synchronize to primary servers. There are 106 public +secondary (stratum 2) servers synchronized to the primary servers and +providing synchronization to a total in excess of 100,000 clients and +servers in the Internet. The current lists are maintained in the Information on Time +and Frequency Services page, which is updated frequently. There are +numerous private primary and secondary servers not normally available to +the public as well. You are strongly discouraged from using these +servers, since they sometimes hide in little ghettos behind dinky links +to the outside world and your traffic can bring up expensive ISDN lines, +causing much grief and frustration. + +

    Resolving Problems

    + +Like other things Internet, the NTP synchronization subnets tend to be +large and devilishly intricate, with many opportunities for +misconfiguration and network problems. The NTP engineering model is +specifically designed to help isolate and repair such problems using an +integrated management protocol, together with a suite of monitoring and +debugging tools. There is an optional data recording facility which can +be used to record normal and aberrant operation, log problems to the +system log facility, and retain records of client access. The NTP Debugging Techniques and Hints and Kinks pages contain useful information +for identifying problems and devising solutions. + +

    Users are requested to report bugs, offer suggestions and contribute +additions to this distribution. The Patching +Procedures page suggests procedures which greatly simplify +distribution updates, while the Porting Hints +page suggest ways to make porting this code to new hardware and +operating systems easier. Additional information on reference clock +driver construction and debugging can be found in the Reference Clock Drivers page. Further +information on NTP in the Internet can be found in the NTP +web page. + +

    Program Manual Pages

    + + + +

    Supporting Documentation

    + + + +

    Application Notes

    + + + +
    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/kern.htm b/contrib/ntp/html/kern.htm new file mode 100644 index 000000000000..b1ee383d7ee3 --- /dev/null +++ b/contrib/ntp/html/kern.htm @@ -0,0 +1,51 @@ + +A Kernel Model for Precision Timekeeping +

    +A Kernel Model for Precision Timekeeping +


    + +

    The technical memorandum: A Kernel Model for Precision +Timekeeping +(PostScript) describes an engineering model which implements a +precision time-of-day function for a generic operating system. The model +is based on the principles of disciplined oscillators using phase-lock +loops (PLL) and frequency-lock loops (FLL) often found in the +engineering literature. The model uses a hybrid PLL/FLL discipline +algorithm implemented in the kernel. The hybrid loop provides automatic +time and frequency steering with update intervals from a few seconds to +over one day. + +

    The hybrid PLL/FLL has been implemented in the Unix kernels for +several workstations, including those made by Sun Microsystems, Digital +and Hewlett Packard. Currently, the modifications are in licensed +kernels for Digital Unix 4.0 and Sun Solaris 2.6. Since these specific +implementations involve modifications to licensed code, they cannot be +provided directly. Inquiries should be directed to the manufacturer's +representatives. In addition to the licensed kernels, the hybrid PLL/FLL +has been implemented in the nonlicensed kernels for Linux and FreeBSD. +The engineering model for these implementations, including a simulator +with code segments almost identical to the implementations, but not +involving licensed code, is available via the web at kernel.tar.Z or by +anonymous FTP from ftp.udel.edu in the pub/ntp directory. + +

    The model changes the way the system clock is adjusted in time and +frequency, as well as provides mechanisms to discipline its time and +frequency to an external precision timing source, such as a pulse-per- +second (PPS) signal. The model incorporates a generic system-call +interface for use with the Network Time Protocol (NTP) or similar time +synchronization protocol. The NTP software daemons for Version 3 +xntpd and Version 4  ntpd operate with this model +to provide synchronization limited in principle only by the accuracy and +stability of the external timing source. There are two new system calls +defined in the model, ntp_gettime(), which returns a structure +including the current time, estimated error and maximum error, and +ntp_adjtime(), which provides a means to adjust kernel +variables, including the current time and frequency offsets. Further +information on the calling sequences and variable definitions are in the +/usr/include/sys/timex.h file.  + +


    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/kernpps.htm b/contrib/ntp/html/kernpps.htm new file mode 100644 index 000000000000..fe003f78d17f --- /dev/null +++ b/contrib/ntp/html/kernpps.htm @@ -0,0 +1,26 @@ + +A Kernel Programming Interface for Precision Time Signals +Network Performance Evaluation +

    +A Kernel Programming Interface for Precision Time Signals +


    + +

    The technical memorandum: A Kernel Programming Interface for +Precision Time Signals +(PostScript) describes a proposed programming interface for +external precision time signals, such as the pulse-per-second (PPS) +signal generated by some radio clocks and cesium oscillators. + +

    The memorandum argues for a generic capability in the ubiquitous Unix +kernel, which could be used for a wide variety of measurement +applications, including network time synchronization and experiments +involving performance measurement and evaluation of computer networks +and transmission systems. The hardware to do this requires only a serial +port and a modem control lead, such as the data carrier detect (DCD) +lead, which can be driven by an external source via a level +converter/pulse generator. + +


    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/ldisc.htm b/contrib/ntp/html/ldisc.htm new file mode 100644 index 000000000000..5dd732699882 --- /dev/null +++ b/contrib/ntp/html/ldisc.htm @@ -0,0 +1,161 @@ + + +Line Disciplines and Streams Modules +

    +Line Disciplines and Streams Modules +


    + +

    Description

    + +

    Most radio and modem clocks used for a primary (stratum-1) NTP server +utilize serial ports operating at speeds of 9600 baud or greater. The +timing jitter contributed by the serial port hardware and software +driver can accumulate to several milliseconds on a typical Unix +workstation. In order to reduce these errors, a set of special line +disciplines and stream modules can be configured in the Unix kernel. +These routines intercept special characters or signals provided by the +radio or modem clock and save a local timestamp for later processing. + +

    The routines can be compiled in the kernel in older BSD-derived +systems, or installed as System V streams modules and either compiled in +the kernel or dynamically loaded when required. In either case, they +require minor changes in some kernel files and in the NTP daemon +ntpd. The streams modules can be pushed and popped from +the streams stack using conventional System V streams program +primitives. Note that not all Unix kernels support line disciplines and +of those that do, not all support System V streams. The disciplines here +are known to work correctly with SunOS 4.x kernels, but have not been +tested for other kernels. + +

    There are two line disciplines and a special streams module included +in the distribution. Support for each in ntpd is enabled +by adding flags to the DEFS_LOCAL line of the +ntpd configuration file ./Config.local. This +can be done automatically by the autoconfiguration build procedures, or +can be inserted/deleted after the process has completed. + +

    + +
    tty_clk +
    This routine intercepts characters received from the serial port and +passes unchanged all except a set of designated characters to the +generic serial port discipline. For each of the exception characters, +the character is inserted in the receiver buffer followed by a local +timestamp in Unix timeval format. Both +select() and SIGIO are supported by the +routine. The -DTTYCLK flag is used to compile support for +this discipline in ntpd. This flag is automatically +included if the clkdefs.h file is found in the +/usr/include/sys directory, or it can be added (or deleted) +manually. This module must be configured in the kernel during the kernel +build process, as described in the README file in the +./kernel directory. + +

    tty_chu +
    This routine is a special purpose line discipline for receiving a +special timecode broadcast by Canadian time and frequency standard +station CHU. The radio signal is first demodulated by the 300-baud modem +included in the gadget box, then processed by the discipline and finally +processed by the CHU modem driver (type 7) described in the Reference Clock Drivers page. This discipline +should be used in raw mode. The -DCHUCLK flag is used to +compile support for this discipline in ntpd. This flag is +automatically included if the chudefs.h file is found in +the /usr/include/sys directory, or it can be added (or +deleted) manually. This module must be configured in the kernel during +the kernel build process, as described in the README file +in the ./kernel directory. +

    ppsclock +
    This routine is a special purpose streams module which monitors the +state of the data carrier detect (DCD) modem interface signal. It is +normally used in connection with a pulse-per-second (PPS) signal +generated by some radio clocks, which requires a hardware level +converter/pulse generator, such as described in the Gadget Box PPS Level Converter and CHU Modem page. +For each positive-going edge of the DCD signal, the +ppsclock module captures a timestamp in Unix +timeval format for later retrieval using a special +ioctl() system call. The -DPPS flag is used to +compile support for this module in ntpd. This flag is +automatically included if the ppsclock.h file is found in +the /sys/sys directory, or it can be added (or deleted) +manually. This module must also be configured in the kernel during the +kernel build process, as described in the README file in +the ./kernel directory. + +
    + +

    There are two versions of both the tty_clk and +chu_clk programs. The tty_clk.c and +chu_clk.c are designed for use with older BSD systems and +are compiled in the kernel. The tty_clk_STREAMS.c and +chu_clk_STREAMS.c are designed for use with System V +streams, in which case they can be either compiled in the kernel or +dynamically loaded. Since these programs are small, unobtrusive, and do +nothing unless specifically enabled by an application program, it +probably doesn't matter which version is chosen. Instructions on how to +configure and build a kernel supporting either or both of these line +disciplines is in the README file in the +./kernel directory. + +

    How to Use the tty_clk Line Discipline

    + +

    The tty_clk line discipline defines a new ioctl(), +CLK_SETSTR, which takes a pointer to a string of no more +than 32 characters. Until the first CLK_SETSTR is +performed, the discipline will simply pass through characters. Once it +is passed a string by CLK_SETSTR, any character in that +string will be immediately followed by a timestamp in Unix +timeval format. You can change the string whenever you want +by doing another CLK_SETSTR. The character must be an +exact, 8 bit match. The character '\000' cannot, be used, as it is the +string terminator. Passing an empty string to CLK_SETSTR +turns off timestamping. Passing NULL will produce undefined +results. + +

    How to Use the tty_chu Line Discipline

    + +

    The tty_chu line discipline translates data received from the CHU +modem and returns chucode structures, as defined in +chudefs.h, and expected by the Scratchbuilt CHU Receiver reference clock +driver. Depending on the settings of PEDANTIC and +ANAL_RETENTIVE used when compiling the kernel, some +checking of the data may or may not be necessary. + +

    How to Use the ppsclock Stream Module

    + +

    The ppsclock streams module implements an ioctl() +CIOGETEV, which takes a pointer to the structure + +

    +struct ppsclockev {
    +     struct timeval tv;
    +     u_int serial;
    +};
    +
    + +

    The ppsclock module is pushed on the streams stack of the serial port +connected to the PPS signal. The port must be configured for local +operation, rather than remote (modem) operation. At each positive-going +edge of the DCD signal, the routine latches the current local timestamp +and increments a counter. At each CIOGETEV ioctl() call, +the current values of the timestamp and counter are returned in the +ppsclockev structure. + +

    TIOCDCDTIMESTAMP timestamping

    + +

    On FreeBSD 2.2 and later systems the TIOCDCDTIMESTAMP ioctl is used +to read the timestamp when the DCD serial go active. To use this the +PPS signal must be tied to the serial port DCD signal through the +appropriate level converters and pulse stretch circuitry if necessary. +This enhances the accuracy of the driver to a few microseconds. Using +FreeBSD 2.2 the measured delay between activation of the PPS signal and +the time the timestamp is made on a 66MHz 486DX2 is 19us and on a +100MHz Pentium is 6us. The driver does NOT compensate for this. + +

    The TIOCDCDTIMESTAMP timestamping ioctl() is used automatically +on FreeBSD systems if available. It is integrated into the +refclock_gtlin() function so any driver using it will benefit from +the enhanced accuracy. + +


    David L. Mills (mills@udel.edu)
    diff --git a/contrib/ntp/html/measure.htm b/contrib/ntp/html/measure.htm new file mode 100644 index 000000000000..a06261dd0e21 --- /dev/null +++ b/contrib/ntp/html/measure.htm @@ -0,0 +1,50 @@ + +Time and Time Interval Measurement with Application to Computer and +Network Performance Evaluation +

    +Time and Time Interval Measurement with Application to Computer and +Network Performance Evaluation +


    + +

    The technical memorandum: Time and Time Interval Measurement +with Application to Computer and Network Performance Evaluation +(PostScript) describes a number of techniques for conducting +experiments typical of computer network and transmission systems +engineering. + +

    In most experiments in which time is involved, it is necessary to +develop estimates of time, frequency and measurement errors from a +series of time measurements between the clocks of a number of computers +and ancillary devices interconnected by some kind of computer network. +However, time is not a physical quantity, such as mass, nor can it be +measured relative to an absolute frame of reference, such as velocity. +The only way to measure time in our universe is to compare the reading +of one clock, which runs according to its own timescale, with another +clock, which runs according to a given timescale, at some given instant +or epoch. The errors arise from the precision of time comparisons and +the accuracy of frequency estimates between the timescales involved. + +

    The usual data collected during a performance run of some experiment +might include time offsets, time delays, frequency offsets and various +error statistics. While time offsets between two clocks can be measured +directly, frequency offsets can be estimated only from two or more time +offsets made over some time interval in the experiment. In practice, a +sequence of time comparisons can be performed over the lifetime of the +experiment and the instantaneous frequency estimated either in real time +with a recurrence relation, or retrospectively with a polynomial fit to +the data. + +

    Estimating time and frequency errors in real time has been studied by +a distinct subspecies of physicists who have made a career of the +technology involved. Various means including autoregressive models, +Kalman filters and simple weighted-average algorithms are used +extensively by national standards laboratories to model cesium-clock +ensembles. These techniques have been adapted to computer network and +transmission engineering problems as well. This memorandum explores +issues in performing experiments of this type and summarizes various +techniques found useful in practice. + +


    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/miscopt.htm b/contrib/ntp/html/miscopt.htm new file mode 100644 index 000000000000..af5ee3cdf117 --- /dev/null +++ b/contrib/ntp/html/miscopt.htm @@ -0,0 +1,162 @@ + + + + + Miscellaneous Options + + + + +

    +Miscellaneous Options

    + +
    +
    +
    +broadcastdelay seconds
    + +
    +The broadcast and multicast modes require a special calibration to determine +the network delay between the local and remote servers. Ordinarily, this +is done automatically by the initial protocol exchanges between the local +and remote servers. In some cases, the calibration procedure may fail due +to network or server access controls, for example. This command specifies +the default delay to be used under these circumstances. Typically (for +Ethernet), a number between 0.003 and 0.007 seconds is appropriate. The +default when this command is not used is 0.004 seconds.
    + +
    + +
    +trap host_address [port port_number] [interface interface_address]
    + +
    +This command configures a trap receiver at the given host address and port +number for 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 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.
    + +
    +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.
    + +
    + +
    +setvar variable [default]
    + +
    +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 form name = value is followed +by the 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 override any variables defined via the setvar mechanism. +There are three special variables that contain the names of all variable +of the same group. The sys_var_list holds the names of all system +variables. The peer_var_list holds the names of all peer variables +and the clock_var_list holds the names of the reference clock +variables.
    + +
    + +
    +logfile logfile
    + +
    +This command specifies the location of an alternate log file to be used +instead of the default system syslog facility.
    + +
    + +
    +logconfig configkeyword
    + +
    +This command controls the amount and type of output written to the system +syslog facility or the alternate logfile log file. By +default, all output is turned on. All configkeyword keywords +can be prefixed with =, + and -, where = +sets the syslogmask, + adds and - removes messages. +syslog messages can be controlled in four classes (, peer, +sys and sync). Within these classes four types of messages +can be controlled.
    + +
    +Informational messages (info) control configuration information. +Event messages (events) control logging of events (reachability, +synchronization, alarm conditions). Statistical output is controlled with +the statistics keyword. The final message group is the status +messages. This describes mainly the synchronizations status. Configuration +keywords are formed by concatenating the message class with the event class. +The allprefix can be used instead of a message class. A message +class may also be followed by the all keyword to enable/disable +all messages of the respective message class.
    + +
    +Thus, a minimal log configuration could look like this:
    + +
    +logconfig = syncstatus +sysevents
    + +
    +This would just list the synchronizations state of ntpd and the +major system events. For a simple reference server, the following minimum +message configuration could be useful:
    + +
    +logconfig = syncall +clockall
    + +
    +This configuration will list all clock information and synchronization +information. All other events and messages about peers, system events and +so on is suppressed.
    +
    + +

    +Variables

    +Most variables used by the NTP protocol can be examined with the ntpdc +(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 setvar directive or the leap warning bits. +The leap warning bits can be set in the leapwarning variable up +to one month ahead. Both the leapwarning and leapindication +variables have a slightly different encoding than the usual leap bits interpretation: +
    +
    +00
    + +
    +The daemon passes the leap bits of its synchronization source (usual mode +of operation).
    + +
    +01/10
    + +
    +A leap second is added/deleted (operator forced leap second).
    + +
    +11
    + +
    +Leap information from the synchronizations source is ignored (thus LEAP_NOWARNING +is passed on).
    +
    + +
    +
    +David L. Mills (mills@udel.edu)
    + + + diff --git a/contrib/ntp/html/monopt.htm b/contrib/ntp/html/monopt.htm new file mode 100644 index 000000000000..fc6ba84e0ca3 --- /dev/null +++ b/contrib/ntp/html/monopt.htm @@ -0,0 +1,370 @@ + + + + + Monitoring Options + + + + +

    +Monitoring Options

    + +
    +

    +Monitoring Support

    +ntpd includes a comprehensive monitoring facility suitable for +continuous, long term recording of server and client timekeeping performance. +See the statistics command below for a listing and example of +each type of statistics currently supported. Statistic files are managed +using file generation sets and scripts in the ./scripts directory of this +distribution. Using these facilities and Unix cron jobs, the data +can be automatically summarized and archived for retrospective analysis. +

    +Monitoring Commands

    + +
    +
    +statistics name [...]
    + +
    +Enables writing of statistics records. Currently, four kinds of name +statistics are supported.
    + +
    + +
    +
    +loopstats
    + +
    +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 loopstats:
    + +
    50935 75440.031 0.000006019 13.778190 0.000351733 0.013380 6
    + +
    +The first two fields show the date (Modified Julian Day) and time (seconds +and fraction past UTC midnight). The next five fields show time offset +(seconds), frequency offset (parts per million - PPM), RMS jitter (seconds), +Allan deviation (PPM) and clock discipline time constant.
    + +
    + +
    +peerstats
    + +
    +Enables recording of peer statistics information. This includes statistics +records of all peers of a NTP server and of special signals, where present +and configured. Each valid update appends a line of the following form +to the current element of a file generation set named peerstats:
    + +
    48773 10847.650 127.127.4.1 9714 -0.001605 0.00000 0.00142
    + +
    +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 RMS jitter, all +in seconds.
    + +
    + +
    +clockstats
    + +
    +Enables recording of clock driver statistics information. Each update received +from a clock driver appends a line of the following form to the file generation +set named clockstats:
    + +
    49213 525.624 127.127.4.1 93 226 00:08:29.606 D
    + +
    +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.
    + +
    + +
    +rawstats
    + +
    +Enables recording of raw-timestamp statistics information. This includes +statistics records of all peers of a NTP server and of special signals, +where present and configured. Each NTP message received from a peer or +clock driver appends a line of the following form to the file generation +set named rawstats:
    + +
    + +
    +50928 2132.543 128.4.1.1 128.4.1.20 3102453281.584327000 3102453281.58622800031 +02453332.540806000 3102453332.541458000
    + +
    + 
    + +
    +The first two fields show the date (Modified Julian Day) and time (seconds +and fraction past UTC midnight). The next field shows the peer or clock +address in dotted-quad notation, The final four fields show the originate, +receive, transmit and final NTP timestamps in order. The timestamp values +are as received and before processing by the various data smoothing and +mitigation algorithms.
    +
    + +
    + +
    +statsdir directory_path
    + +
    +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, which is useful +for handling statistics logs.
    + +
    + +
    +filegen name [file filename] [type typename] [link +| nolink] [enable | disable]
    + +
    + 
    + +
    +Configures setting of generation file set name. Generation file +sets provide a means for handling files that are continuously 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 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 risk of disturbing the operation of ntpd. (Most important: +they can be removed to free space for new data produced.)
    + +
    + +
    +Note that this command can be sent from the ntpdc program running +at a remote location.
    + +
    + +
    +
    +name
    + +
    +This is the type of the statistics records, as shown in the statististics +command.
    + +
    +
    + +
    +file filename
    + +
    +
    +This is the file name for the statistics records. Filenames of set members +are built from three elements:
    + +
    + +
    +
    +prefix
    + +
    +This is a constant filename path. It is not subject to modifications via +the filegen option. 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 generation can be configured +using the statsdir option explained above.
    + +
    + +
    +filename
    + +
    +This string is directly concatenated to the prefix mentioned above (no +intervening / (slash)). This can be modified using the file +argument to the filegen statement. No .. elements are +allowed in this component to prevent filenames referring to parts outside +the filesystem hierarchy denoted by prefix.
    + +
    + +
    +suffix
    + +
    +This part is reflects individual elements of a file set. It is generated +according to the type of a file set.
    +
    + +
    +
    + +
    +type typename
    + +
    +
    +A file generation set is characterized by its type. The following types +are supported:
    + +
    + +
    +
    +none
    + +
    +The file set is actually a single plain file.
    + +
    + +
    +pid
    + +
    +One element of file set is used per incarnation of a ntpd server. +This type does not perform any changes to file set members during runtime, +however it provides an easy way of separating files belonging to different +ntpd server incarnations. The set member filename is built by +appending a . (dot) to concatenated prefix and filename +strings, and appending the decimal representation of the process ID of +the ntpd server process.
    + +
    + +
    +day
    + +
    +One file generation set element is created per day. A day is defined as +the period between 00:00 and 24:00 UTC. The file set member suffix consists +of a . (dot) and a day specification in the form YYYYMMDD. +YYYY is a 4-digit year number (e.g., 1992). MM is a two digit +month number. DD is a two digit day number. Thus, all information +written at 10 December 1992 would end up in a file named prefix +filename.19921210.
    + +
    + +
    +week
    + +
    +Any file set member contains data related to a certain week of a year. +The term week is defined by computing day-of-year 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 4-digit year number, the +letter W, and a 2-digit week number. For example, information +from January, 10th 1992 would end up in a file with suffix .1992W1.
    + +
    + +
    +month
    + +
    +One generation file set element is generated per month. The file name suffix +consists of a dot, a 4-digit year number, and a 2-digit month.
    + +
    + +
    +year
    + +
    +One generation file element is generated per year. The filename suffix +consists of a dot and a 4 digit year number.
    + +
    + +
    +age
    + +
    +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 a, and an 8-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. Information is only written to a file generation by specifying +enabl; output is prevented by specifying disable.
    + +
    +
    +
    + +
    +link | nolink
    + +
    +
    +It is convenient to be able to access the current element of a file generation +set by a fixed name. This feature is enabled by specifying link +and disabled using nolink. If link 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 C, +and the pid of the ntpd 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.
    + +
    +
    + +
    +enable | disable
    + +
    +
    +Enables or disables the recording function.
    +
    +
    + +
    +
    +David L. Mills (mills@udel.edu)
    + + + diff --git a/contrib/ntp/html/mx4200data.htm b/contrib/ntp/html/mx4200data.htm new file mode 100644 index 000000000000..212360764076 --- /dev/null +++ b/contrib/ntp/html/mx4200data.htm @@ -0,0 +1,445 @@ + + + +MX4200 Receiver Data Format + +

    MX4200 Receiver Data Format

    + +
    +

    Table of Contents

    + + + +
    + +

    Control Port Sentences

    + +

    The Control (CDU) Port is used to initialize, monitor, and control +the receiver. The structure of the control port sentences is based on +the NMEA-0183 Standard for Interfacing Marine Electronics +Navigation Devices (version 1.5). For more details, please refer to +the NMEA-0183 Specification available from the National Marine Electronics +Association.

    + +

    Reserved characters are used to indicate the beginning and the end +of records in the data stream, and to delimit data fields within a +sentence. Only printable ASCII characters (Hex 20 through 7F) may be +used in a sentence. Table 2 lists the reserved +characters and defines their usage. Table 1 +illustrates the general Magnavox proprietary NMEA sentence format. +

    + +

    Table 1. Magnavox Proprietary NMEA Sentence +Format

    + +

    + +$PMVXG,XXX,...................*CK + + +

    + + +
    Character Meaning +
    $ Sentence Start Character +
    P Special ID (P = Proprietary) +
    MVX Originator ID (MVX = Magnavox) +
    G Interface ID (G = GPS) +
    XXX Sentence Type +
    ... Data +
    * Optional Checksum Field Delimiter +
    CK Optional Checksum +
    + +

    Table 2. NMEA Sentence Reserved Characters

    + + +
    Character Hex Value Usage +
    $ 24 Start of Sentence Identifier +
    {cr}{lf} 0D 0A End of Sentence Identifier +
    , 2C Sentence Delimiter +
    * 2A Optional Checksum Field Delimiter +
    + +

    Following the start character $, are five characters +which constitute the block label of the sentence. For Magnavox +proprietary sentences, this label is always PMVXG. The +next field after the block label is the sentence type, consisting of +three decimal digits.

    + +

    The data, delimited by commas, follows the sentence type. Note that +the receiver uses a free-format parsing algorithm, so you need not send +the exact number of characters shown in the examples. You will need to +use the commas to determine how many bytes of data need to be +retrieved.

    + +

    The notation CK shown in Table 1 +symbolically indicates the optional checksum in the examples. The +checksum is computed by exclusive-ORing all of the bytes between the +$ and the * characters. The $ , +* and the checksum are not included in the checksum +computation.

    + +

    Checksums are optional for Control Port input sentences, but are +highly recommended to limit the effects of communication errors. +Magnavox receivers always generate checksums for Control Port output +sentences.

    + +

    ASCII data characters are transmitted in the following format:

    + + +
    Data Bits 8 (msb always 0) +
    Parity None +
    Stop Bits 1 +
    + +

    NULL fields are fields which do not contain any data. They would +appear as two commas together in the sentence format, except for the +final field. Some Magnavox proprietary sentences require that the +format contain NULL fields. mandatory NULL fields are identified by an +'*' next to the respective field.

    + +
    + +

    Control Port Input Sentences

    +These are the subset of the MX4200 control port input sentences sent by +the NTP driver to the GPS receiver. + +
    + +

    $PMVXG,000

    +

    Initialization/Mode Control - Part A

    +Initializes the time, position and antenna height of the MX4200. + +

    + +
    Field Description Units Format Default Range +
    1 Day Int 1-31 +
    2 Month Int 1-12 +
    3 Year Int 1991-9999 +
    4 GMT Time HHMMSS Int 000000-235959 +
    5 WGS-84 Latitude DDMM.MMMMFloat0.0 0 - 8959.9999 +
    6 North/South Indicator Char N N,S +
    7 WGS-84 Longitude DDDMM.MMMMFloat0.0 0 - 17959.9999 +
    8 East/West Indicator Char E E,W +
    9 Altitude (height above Mean Sea Level) in meters (WGS-84) MetersFloat0.0+/-99999.0 +
    10 Not Used +
    +Example:
    +$PMVXG,000,,,,,,,,,,*48
    +$PMVXG,000,,,,,5128.4651,N,00020.0715,W,58.04,*4F + +


    + +

    $PMVXG,001

    +

    Initialization/Mode Control - Part B

    +Specifies various navigation parameters: Altitude aiding, acceleration +DOP limits, and satellite elevation limits. + +

    + +
    Field Description Units Format Default Range +
    *1 Constrain Altitude Int 1 0=3D Only
    1=Auto
    2=2D Only +
    2 Not Used +
    *3 Horizontal Acceleration Factorm/sec^2 Float 1.0 0.5-10.0 +
    *4 Not Used +
    *5 VDOP Limit Int 10 1-9999 +
    *6 HDOP Limit Int 10 1-9999 +
    7 Elevation Limit Deg Int 5 0-90 +
    8 Time Output Mode Char U U=UTC
    L=Local Time +
    9 Local Time Offset HHMM Int 0 +/- 0-2359 +
    +Example:
    +$PMVXG,001,3,,0.1,0.1,10,10,5,U,0*06 + +


    + + +

    $PMVXG,007

    +

    Control Port Output Configuration

    +This message enables or disables output of the specified sentence and +defines the output rate. The user sends this message for each sentence +that the receiver is to output. + +

    + +
    Field Description Units Format Default Range +
    1 Control Port Output Block Label Char +
    2 Clear Current Output List Int 0=No
    1=Yes +
    3 Add/Delete Sentence from List Int 1=Append
    2=Delete +
    4 Not Used +
    5 Sentence Output Rate Sec Int 1-9999 +
    6 # digits of Precision for CGA and GLL sentences Int 2 2-4 +
    7 Not Used +
    8 Not Used +
    +Example:
    +$PMVXG,007,022,0,1,,1,,,*4F + +


    + + +

    $PMVXG,023

    +

    Time Recovery Configuration

    +This message is used to enable/disable the time recovery feature of the +receiver. The time synchronization for the 1PPS output is specified in +addition to a user time bias and an error tolerance for a valid pulse. +This record is accepted in units configured for time recovery. If the +back panel contains a 1PPS outlet, the receiver is a time recovery +unit. + +

    + +
    Field Description Units Format Default Range +
    *1 Time Recovery Mode Char D D=Dynamic
    S=Static
    K=Known Position
    N=No Time Recovery +
    2 Time Synchronization Char G U=UTC
    G=GPS +
    3 Time Mark Mode Char A A=Always
    V=Valid Pulses Only +
    4 Maximum Time Error Nsec Int 100 50-1000 +
    5 User Time Bias Nsec Int 0 +/- 99999 +
    6 ASCII Time Message Control Int 0 0=No Output
    1=830 to Control Port
    2=830 to Equipment Port +
    7 Known Pos PRN Int 0 1-32
    0=Track All Sats +
    +Example:
    +$PMVXG,023,S,U,A,500,0,1,*16 + +


    + + +

    $CDGPQ,YYY

    +

    Query From a Remote Device / Request to Output a Sentence

    +Enables the controller to request a one-time transmission of a specific +block label. To output messages at a periodic rate, refer to input +sentence $PMVXG,007. + +

    + +
    Field Description Units Format Default Range +
    1:CD ID of Remote Device Char (See NMEA-0183) +
    2:GP GPS Char (See NMEA-0183) +
    3:Q Query Char (See NMEA-0183) +
    4:YYY Label of Desired Sentence Char Any Valid NMEA or Magnavox Sentence Type +
    +Example:
    +$CDGPQ,030*5E + + + +


    +

    Control Port Output Sentences

    +These are the subset of the MX4200 control port output sentences +recognized by the NTP driver. + +
    + +

    $PMVXG,000

    +

    Receiver Status

    +Returns the current status of the receiver including the operating +mode, number of satellites visible, and the number of satellites being +tracked. + +

    + +
    Field Description Units Format Range +
    1 Current Receiver Status Char ACQ=Reacquisition
    ALT=Constellation Selection
    IAC=Initial Acquisition
    IDL=Idle, No Satellites
    NAV=Navigating
    STS=Search The Sky
    TRK=Tracking +
    2 Number of Satellites that should be Visible Int 0-12 +
    3 Number of Satellites being Tracked Int 0-12 +
    4 Time since Last Navigation HHMM Int 0-2359 +
    5 Initialization Status Int 0=Waiting for Initialization
    1=Initialization Complete +
    +Example:
    +$PMVXG,000,TRK,3,3,0122,1*19 + +


    + +

    $PMVXG,021

    +

    Position, Height, Velocity

    +This sentence gives the receiver position, height, navigation mode and +velocity north/east. This sentence is intended for post analysis +applications. + +

    + +
    Field Description Units Format Range +
    1 UTC Measurement Time Seconds into the weekFloat0-604800.00 +
    2 WGS-84 Latitude DDMM.MMMMFloat 0-89.9999 +
    3 North/South Indicator Char N, S +
    4 WGS-84 Longitude DDDMM.MMMM Float 0-179.9999 +
    5 East/West Indicator Char E, W +
    6 Altitude (MSL) Meters Float +
    7 Geoidal Height Meters Float +
    8 Velocity East M/Sec Float +
    9 Velocity North M/Sec Float +
    10 Navigation Mode Int Navigating
    + 1=Position From a Remote Device
    + 2=2D
    + 3=3D
    + 4=2D differential
    + 5=3D differential
    + Not Navigating
    + 51=Too Few Satellites
    + 52=DOPs too large
    + 53=Position STD too large
    + 54=Velocity STD too large
    + 55=Too many iterations for velocity
    + 56=Too many iterations for position
    + 57=3 Sat Startup failed +
    +Example:
    +$PMVXG,021,142244.00,5128.4744,N,00020.0593,W,00054.4,0047.4,0000.1,-000.2,03*66 + +


    + +

    $PMVXG,022

    +

    DOPs

    +This sentence reports the DOP (Dilution Of Precision) values actually +used in the measurement processing corresponding to the satellites +listed. The satellites are listed in receiver channel order. Fields +11-16 are output only on 12-channel receivers. + +

    + +
    Field Description Units Format Range +
    1 UTC Measurement Time Seconds into the weekFloat0-604800.00 +
    2 East DOP (EDOP) Float +
    3 North DOP (NDOP) Float +
    4 Vertical DOP (VDOP) Float +
    5 PRN on Channel #1 Int 1-32 +
    6 PRN on Channel #2 Int 1-32 +
    7 PRN on Channel #3 Int 1-32 +
    8 PRN on Channel #4 Int 1-32 +
    9 PRN on Channel #5 Int 1-32 +
    10 PRN on Channel #6 Int 1-32 +
    11 PRN on Channel #7 Int 1-32 +
    12 PRN on Channel #8 Int 1-32 +
    13 PRN on Channel #9 Int 1-32 +
    14 PRN on Channel #10 Int 1-32 +
    15 PRN on Channel #11 Int 1-32 +
    16 PRN on Channel #12 Int 1-32 +
    +Example:
    +$PMVXG,022,142243.00,00.7,00.8,01.9,27,26,10,09,13,23*77 + +


    + +

    $PMVXG,030

    +

    Software Configuration

    +This sentence contains the navigation processor and baseband firmware +version numbers. + +

    + +
    Field Description Units Format Range +
    1 Nav Processor Version Number Char +
    2 Baseband Firmware Version Number Char +
    +Example:
    +$PMVXG,030,DA35,015 + +


    + +

    $PMVXG,101

    +

    Control Sentence Accept/Reject

    +This sentence is returned (on the Control Port) for every +$PMVXG and $XXGPQ sentence that is +received. + +

    + +
    Field Description Units Format Range +
    1 Sentence ID Char +
    2 Accept/Reject Status Int 0=Sentence Accepted
    + 1=Bad Checksum
    + 2=Illegal Value
    + 3=Unrecognized ID
    + 4=Wrong # of fields
    + 5=Required Data Field Missing
    + 6=Requested Sentence Unavailable +
    3 Bad Field Index Int +
    4 Requested Sentence ID (If field #1 = GPQ) Char +
    +Example:
    +$PMVXG,101,GPQ,0,,030*0D + +


    + +

    $PMVXG,523

    +

    Time Recovery Configuration

    +This sentence contains the configuration of the time recovery function +of the receiver. + +

    + +
    Field Description Units Format Range +
    1 Time Recovery Mode Char D=Dynamic
    S=Static
    K=Known Position
    N=No Time Recovery +
    2 Time Synchronization Char U=UTC Time
    G=GPS Time +
    3 Time Mark Mode Char A=Always Output Time Pulse
    V=Only when Valid +
    4 Maximum Time Error for which a time mark will be considered valid Nsec Int +
    5 User Time Bias Nsec Int +
    6 Time Message Control Int 0=No Message
    1=830 to Control Port
    2=830 to Equipment Port +
    7 Not Used +
    +Example:
    +$PMVXG,523,S,U,A,0500,000000,1,0*23 + +


    + +

    $PMVXG,830

    +

    Time Recovery Results

    +This sentence is output approximately 1 second preceding the 1PPS +output. It indicates the exact time of the next pulse, whether or not +the time mark will be valid (based on operator-specified error +tolerance), the time to which the pulse is synchronized, the receiver +operating mode, and the time error of the last 1PPS +output. The leap second flag (Field #11) is not output by older +receivers. + +

    + +
    Field Description Units Format Range +
    1 Time Mark Valid Char T=Valid
    F=Not Valid +
    2 Year Int 1993- +
    3 Month Int 1-12 +
    4 Day Nsec Int 1-31 +
    5 Time HH:MM:SSInt 00:00:00-23:59:59 +
    6 Time Synchronization Char U=UTC
    G=GPS +
    7 Operating Mode Char D=Dynamic
    S=Static
    K=Known Position +
    8 Oscillator Offset - estimate of oscillator frequency error PPB Int +
    9 Time Mark Error of last pulse Nsec Int +
    10 User Time Bias Nsec Int +
    11 Leap Second Flag - indicates that a leap second will occur. + This value is usually zero except during the week + prior to a leap second occurence, when this value + will be set to +/-1. A value of +1 indicates + that GPS time will be 1 second further ahead of + UTC time. + Int -1,0,1 +
    +Example:
    +$PMVXG,830,T,1998,10,12,15:30:46,U,S,000298,00003,000000,01*02 + +


    + + + + diff --git a/contrib/ntp/html/notes.htm b/contrib/ntp/html/notes.htm new file mode 100644 index 000000000000..6b20cbc44ab6 --- /dev/null +++ b/contrib/ntp/html/notes.htm @@ -0,0 +1,1544 @@ + +Notes on Configuring NTP and Setting up a NTP Subnet</H3> +

    +Notes on Configuring NTP and Setting up a NTP Subnet

    + + + +From NBS Special Publication 432 (out of print) +
    + +

    Introduction

    + +This document is a collection of notes concerning the use of ntpd and +relatedprograms, 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 and includes many +changes and additions resulting from the NTP Version 3 specification and +new Version 4 implementation features. It supersedes earlier documents, +which should no longer be used +for new configurations. + +

    ntpd includes a complete implementation of the NTP Version +3 specification, as defined in: + +

      + +

    • Mills, D.L. Network Time Protocol (Version 3) specification, +implementation and analysis. Network Working Group Report RFC-1305, +University of Delaware, March 1992, 113 pp. Abstract: +PostScript | +PDF, Body: +PostScript | +PDF, Appendices: +PostScript | +PDF + +
    +Additional features have are described for NTP +Version 4. 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, ntpd uses NTP timestamp +format for external communication and double precision floating point +arithmetic internally. ntpd fully implements NTP Versions 2 and +3 authentication and in addition Version 4 autokey. It supports the NTP +mode-6 control message facility along with a private mode-7 control- +message facility used to remotely reconfigure the system and monitor a +considerable amount of internal detail. As extensions to the +specification, a flexible address-and-mask restriction facility has been +included. + +

    The code is biased towards the needs of a busy time server with +numerous, often 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 probably +excess baggage for a high stratum client. In such cases, a stripped-down +version of the protocol, the Simple Network Time Protocol (SNTP) can be +used. SNTP and NTP servers and clients can interwork in most situations, +as described in: Mills, D.L. Simple Network Time Protocol (SNTP). +Network Working Group Report RFC-2030, University of Delaware, October +1996, 14 pp. +(ASCII). + +

    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, MSF, DCF77, GOES and GPS radio +and satellite time services and USNO, ACTS and PTB modem time services. +It also supports the IRIG-B and IRIG-E signal format connected via an +audio codec. 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 conforms in most respects to the NTP +Version 3 specification RFC-1305, a number of improvements have been +made which are described in the conformance statement in the Further Information and Bibliography page. It has +been specifically tuned to achieve the highest accuracy possible on +whatever hardware and operating-system platform is available. In +general, its precision and stability are limited only by the +characteristics of the onboard clock source used by the hardware +and operating system, 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 the +radio clock and interface to the order of a millisecond or less. The +code includes special features to support a pulse-per-second (PPS) +signal and/or an IRIG-B signal generated by some radio clocks. When used +in conjunction with a suitable hardware level converter, the accuracy +can be improved to a few tens of 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 NTP Version 4 distribution includes, in addition to the daemon +itself (ntpd), several utility programs, +including two remote-monitoring programs ( +ntpq, ntpdc), a remote +clock-setting program similar to the Unix rdate program +(ntpdate), a traceback utility u seful 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 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 workstations 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. ntpd +is quite fat. This is rotten if your intended platform for the daemon is +memory limited. ntpd 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 completely hacked out. Much was +learned from the addition of support for a variety of radio clocks, +with the result that some radio clock drivers 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 protocols. In particular, NTP does not attempt to synchronize +clocks to each other. Rather, each server attempts to synchronize to +Universal +Coordinated Time (UTC) 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. However, in networks isolated from UTC +sources, +provisions can made to nominate one of them as a phantom UTC source. + +

    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 by no means 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. This is, however, not always 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 used. +Configuring +an association in symmetric-active mode (usually indicated by a +peer +declaration in the configuration file) 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 +the +configuration file) 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. + +

    Where the requirements in accuracy and reliability are modest, +clients +can be configured to use broadcast and/or multicast modes. These modes +are not normally utilized by servers with dependent clients. The +advantage +of these modes is that clients do not need to be configured for a +specific +server, so that all clients operating can use the same configuration +file. +Broadcast mode requires a broadcast server on the same subnet, while +multicast +mode requires support for IP multicast on the client machine, as well as +connectivity via the MBONE to a multicast server. Since broadcast +messages +are not propagated by routers, only those broadcast servers on the same +subnet will be used. There is at present no way to select which of +possibly +many multicast servers will be used, since all operate on the same group +address. + +

    Where the maximum accuracy and reliability provided by NTP are +needed, +clients and servers operate in either client/server or symmetric modes. +Symmetric modes are most often used between two or more servers +operating +as a mutually redundant group. In these modes, the servers in the group +members arrange the synchronization paths for maximum performance, +depending +on network jitter and propagation delay. If one or more of the group +members +fail, the remaining members automatically reconfigure as required. +Dependent +clients and servers normally operate in client/server mode, in which a +client or dependent server can be synchronized to a group member, but no +group member can synchronize to the client or dependent server. This +provides +protection against malfunctions or protocol attacks. + +

    Servers that provide synchronization to a sizeable population of +clients +normally operate as a group of three or more mutually redundant servers, +each operating with three or more stratum-one or stratum-two servers in +client-server modes, as well as all other members of the group in +symmetric +modes. This provides protection against malfunctions in which one or +more +servers fail to operate or provide incorrect time. The NTP algorithms +have +been specifically engineered to resist attacks where some fraction of +the +configured synchronization sources accidently or purposely provide +incorrect +time. In these cases a special voting procedure is used to identify +spurious +sources and discard their data. +

    +Configuring Your Subnet

    +At startup time the ntpd 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 the Building and Installing +the +Distribution page. 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 operating +in broadcast/multicast mode is available, which requires the client to +operate in a broadcastclient mode. + +

    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 the list of public time servers, +which +can be accessed via the NTP web +page. These data are 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 ntpdc 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 approaching a 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 in the lists of public servers 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. Under no conditions should servers not in these +lists be used without prior permission, as to do so can create severe +problems +in the local infrastructure, especially in cases of dial-up access to +the +Internet. + +

    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 listed for public access. 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 this 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. After some period with no outside timing source (currently one +day), a host will declare itself unsynchronized and provide this +information +to local application programs. + +

    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 anyway 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. ntpd 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 NTP specification in +order +to protect against hostile intruders 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 and multicast modes, 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: +

      +
    • +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 occurrence 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.
    • + +
        +
    • +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.
    • +
        +
    • +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. +

    +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 host whimsy
    +     # (expected to operate at stratum 2)
    +
    +     server rackety.udel.edu
    +     server umd1.umd.edu
    +     server lilben.tn.cornell.edu
    +
    +     driftfile /etc/ntp.drift
    +(Note the use of host names, although host addresses in dotted-quad +notation +can also be used. It is always preferable to use names rather than +addresses, +since over time the addresses can change, while the names seldom +change.) + +

    This particular host is expected to operate as a client at stratum 2 +by virtue of the server keyword and the fact that two of the +three +servers declared (the first two) 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 mentioned above. 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 +distribution; +however, ntpd 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 declared 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. If a local source +of UTC time is available, 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 desirable feature, a +driftfile +declaration should always be included in the configuration file. + +

    An implication in the above is that, should ntpd 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. + +

    +Configuring NTP with NetInfo

    +If NetInfo support is compiled into NTP, you can opt to configure ntp +in your NetInfo domain. NTP will look int he NetInfo directory +/locations/ntp for property/value pairs which are equivalent +the the lines in the configuration file described above. Each +configuration keyword may have a coresponding property in NetInfo. +Each value for a given property is treated as arguments to that property, +similar to a line in the configuration file. + +

    For example, the configuration shown in the configuration file above +can be duplicated in NetInfo by adding a property "server" with +values "rackety.udel.edu", "umd1.umd.edu", and +"lilben.tn.cornell.edu"; and a property "driftfile" +with the single value "/etc/ntp.drift". + +

    Values may contain multiple tokens similar to the arguments available +in the configuration file. For example, to use mimsy.mil as an +NTP version 1 time server, you would add a value "mimsy.mil version +1" to the "server" property. + +

    +Ntp4 Versus Previous Versions

    +There are several items of note when dealing with a mixture of +ntp4 +and previous distributions of NTP Version 2 (ntpd) and NTP +Version +1 (ntp3.4). The ntp4 implementation conforms to the +NTP +Version 3 specification RFC-1305 and, in addition, contains additional +feaures documented in the Release Notes page. +As such, by default when no additional information is available +concerning +the preferences of the peer, ntpd claims to be version 4 in the +packets that it sends from configured associations. The version +subcommand +of the server, peer, broadcast and +manycastclient +command can be used to change the default. In unconfigured +(ephemeral) +associaitons, the daemon always replies in the same version as the +request. + +

    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 version 2 implementation is compatible with +the version 3 algorithms and protocol. The version 1 implementation +contains +most of the version 2 algorithms, but without important features for +clock +selection and robustness. Nevertheless, in most respects the NTP +versions +are backwards compatible. The sticky part here is that, when a previous +version implementation receives a packet claiming to be from a version +4 server, it discards it without further processing. Hence there is a +danger +that in some situations synchronization with previous versions will +fail. + +

    The trouble occurs when an previous version is to be included in an +ntpd configuration file. With no further indication, +ntpd +will send packets claiming to be version 4 when it polls. To get around +this, ntpd allows a qualifier to be added to configuration +entries +to indicate which version to use when polling. Hence the entries +

         # specify NTP version 1
    +
    +     server mimsy.mil version
    +1     # server running ntpd version 1
    +     server apple.com version
    +2     # server running ntpd version 2
    +will cause version 1 packets to be sent to the host mimsy.mil and +version +2 packets to be sent to apple.com. If you are testing ntpd +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, once called NTP Version 0. +

    +Traffic Monitoring

    +ntpd 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, ntpd 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 feature is +normally +enabled, but can be disabled if desired using the configuration file +entry: +

         # disable monitoring feature
    +     disable monitor
    +The recorded information can be displayed using the ntpdc query +program, described briefly below. +

    +Address-and-Mask Restrictions

    +The address-and-mask configuration facility supported by ntpd +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 is not. 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 ntpd +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 +keyword, 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), if 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

    +ntpd 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/128-bit cryptographic checksum of the packet +contents +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. For this reason, the +DES +algorithm is not included in the current distribution. Directions for +obtaining +it in other countries is in the Building and +Installing +the Distribution page. 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 enable auth configuration declaration, which +is currently the default. 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
    +
    +     keys /usr/local/etc/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.000094       # authentication delay
    +(Sun4c/50 IPX)
    +There are a couple of previously unmentioned things in here. The +keys +line specifies the path to the keys file (see below and the +ntpd +document page for details 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 +minimizing +the frequency of delicate key-distribution procedures. The +requestkey +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 +line establishes the key to be used for mode-7 private control +messages +used by the ntpdc utility program. These keys are used to +prevent +unauthorized modification of daemon variables. + +

    Ordinarily, the authentication delay; that is, the 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) is +computed +automatically by the daemon. If necessary, the delay can be overriden by +the authdelay line, which is used as a correction for the +transmit +timestamp. This can be computed for your CPU by the authspeed +program included in the distribution. The usage is illustrated by +the +following: +

         # for DES keys
    +
    +     authspeed -n 30000 auth.samplekeys
    +     # for MD5 keys
    +
    +     authspeed -mn 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 root). 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. An alternative with NTP +Version 4 is the autokey feature, which uses random session keys and +public-key +cruptography and avoids the key file entirely. While this feature is not +completely finished yet, details can be found in the Release +Notes page. +

    +Query Programs

    +Three utility query programs are included with the distribution, +ntpq, +ntptrace and ntpdc. ntpq is a 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. + +

    ntpdc is a horrid program which uses NTP private mode-7 +control +messages to query local or remote servers. The format and contents of +these +messages are specific to this version of ntpd and some older +versions. +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 +ntpdc +is that it provides a user interface to the run time reconfiguration +facility. +See the respective document pages for details on the use of these +programs. +

    +Run-Time Reconfiguration

    +ntpd 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 default-configured 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 ntpdc +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 slightly different encoding than the usual interpretation: +

           
    +Value           Action
    +
    +        
    +00           &nbs
    +p; The daemon passes the leap bits of its
    +            
    +           
    +synchronisation source (usual mode of operation)
    +
    +        01/10   A leap
    +second is added/deleted
    +
    +        
    +11           &nbs
    +p; Leap information from the synchronization 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 (ntpdc) 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 typeable (in ASCII format) from +the keyboard. +

    +Name Resolution

    +ntpd includes the capability to specify host names requiring +resolution +in peer and server declarations in the configuration +file. However, in some outposts of the Internet, name resolution 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. + +

    In order to prevent configuration delays due to the name resolver, +the +daemon runs the name resolution process in parallel with the main daemon +code. 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 the name resolver from the temporary file. +The server then continues on normally but with the offending +peers/servers +omitted from its configuration. + +

    As each name is resolved, it configures the associated entry into the +server using the same mode-7 run time reconfiguration facility that +ntpdc +uses. If temporary resolver failures occur, the resolver will +periodically +retry the requests until a definite response is received. The program +will +continue to run until all entries have been resolved. +

    +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. For the NTP Version 4 release, this tolerance +has been increased to +-500 PPM. + +

    However, in the case of certain notorious platforms, in particular +Sun +4.1.1 systems, the performance can be improved by adjusting 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, in microseconds per +tick. When the time is being adjusted via a call to the system routine +adjtime(), the kernel increases or reduces tick by +tickadj +microseconds per tick 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 +tickadj +code needs to concern itself with the internal implementation of +tickadj +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 tickadj program can be used to adjust the values of +tick +and tickadj. This 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 tick and the value of tickadj) so it +can avoid exceeding this limit. It is important to note that not all +systems +will allow inspection or modification of kernel variables other than at +system build time. It is also important to know that, with the current +NTP tolerances, it is rarely necessary to make these changes, but in +many +cases they will substantially improve the general accurace of the time +service. + +

    Unfortunately, the value of tickadj set by default is almost +always too large for ntpd. 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 these variables, it will not change the values, +even if they are unsuitable. You must do this yourself before the daemon +is started using the tickadj program included in the +./util +directory of the distribution. Note that the latter program will also +compute +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 change the value of tick if asked. This is +handy +to compensate for kernel bugs which cause the clock to run with a very +large frequency error, as with SunOS 4.1.1 systems. It can also be used +to 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 ntpd +is trying to keep it under control. In some systems, such as recent Sun +Solaris kernels, the dosynctodr variable is the only one that +can be changed by the tickadj program. In this and other modern +kernels, it is not necessary to change the other variables in any case. + +

    In order to maintain reasonable correctness bounds, as well as +reasonably +good accuracy with acceptable polling intervals, ntpd will +complain +if the frequency error is greater than 500 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 SunOS 4.1.1 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. This is in fact the case on many current Unix +systems. +

    +Tuning Your Subnet

    +There are several parameters available for tuning the NTP subnet for +maximum +accuracy and minimum jitter. One of these is the prefer +configuration +declaration described in Mitigation Rules and the +prefer Keyword documentation page. 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: +

         # preferred server declaration
    +
    +     peer rackety.udel.edu 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

    +ntpd understands leap seconds and will attempt to take +appropriate +action when one occurs. In principle, every host running ntpd will +insert +a leap second in the local timescale in precise synchronization with +UTC. +This requires that the leap-warning bits be activated some time prior to +the occurrence 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 +ntpd +and the time- conversion routines of each host. The implementation is +independent +of the idiosyncrasies 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 occurrence 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- +simultaneous +commit procedure, for example. While this information is maintained in +the ntpd 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

    +ntpd 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 magnificent +redundancy be required. + +

    Because clocks look much like peers, both configuration file syntax +and run time reconfiguration commands can 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 +ntpdc 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 of 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 Reference +Clock Drivers document page and in the individual driver documents +accessible via that page. +

    +Towards the Ultimate Tick

    +This section considers 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-area +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 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 distribution are used together with the 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 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 a few tens +of microseconds with a fast RISC- based platform. + +

    There are three ways to implement PPS support, depending on the radio +clock model, platform model and serial line interface. These are +described +in detail in the application notes mentioned in the The +Network Time Protocol (NTP) Distribution document page. Each of +these +requires circuitry to convert the TTL signal produced by most clocks to +the EIA levels used by most serial interfaces. The Gadget +Box PPS Level Converter and CHU Modem document page describes a +device +designed to do this. 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 PPS mechanism used by ntpd. The PPS support +depends +on a continuous source of 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 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 +PPS support is disabled and the timecode used directly to control the +local +clock. +

    +Parting Shots

    +There are several undocumented programs which can be useful in unusual +cases. They can be found in the ./clockstuff and +./authstuff +directories of the distribution. One 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. Other programs of interest include +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.  + +
    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/ntpd.htm b/contrib/ntp/html/ntpd.htm new file mode 100644 index 000000000000..a90dfcbd5fc8 --- /dev/null +++ b/contrib/ntp/html/ntpd.htm @@ -0,0 +1,183 @@ + +<TT>ntpd</TT> - Network Time Protocol (NTP) daemon +

    +ntpd - Network Time Protocol (NTP) daemon +


    + +

    Synopsis

    + +ntpd [ -aAbdm ] [ -c conffile ] [ -f driftfile ] [ -k +keyfile ] [ -l logfile ] [ -p pidfile ] [ -r +broadcastdelay ] [ -s statsdir ] [ -t key ] [ -v +variable ] [ -V +variable ] + +

    Description

    + +ntpd is an operating system daemon which sets and maintains the +system time-of-day in synchronism with Internet standard time servers. +ntpd is a complete implementation of the Network Time Protocol +(NTP) version 4, but also retains compatibility with version 3, as +defined by RFC-1305, and version 1 and 2, as defined by RFC-1059 and +RFC-1119, respectively. ntpd does most computations in 64-bit +floating point arithmetic and does relatively clumsy 64-bit fixed point +operations only when necessary to preserve the unltimate precision, +about 232 picoseconds. While the ultimate precision, is not achievable +with ordinary workstations and networks of today, it may be required +with future nanosecond CPU clocks and gigabit LANs. + +

    The daemon can operate in any of several modes, including symmetric +active/passive, client/server broadcast/multicast and manycast. A +broadcast/multicast or manycast client can discover remote servers, +compute server-client propagation delay correction factors and configure +itself automatically. This makes it possible to deploy a fleet of +workstations without specifying configuration details specific to the +local environment. + +

    Ordinarily, ntpd reads the ntp.conf configuration +file at startup time in order to determine the synchronization sources +and operating modes. It is also possible to specify a working, although +limited, configuration entirely on the command line, obviating the need +for a configuration file. This may be particularly appropriate when the +local host is to be configured as a broadcast/multicast client or +manycast client, with all peers being determined by listening to +broadcasts at run time. + +

    If NetInfo support is built into ntpd, then ntpd will +attempt to read its configuration from the NetInfo if the default ntp.conf +file cannot be read and no file is specified by the -c option. + +

    Various internal ntpd variables can be displayed and +configuration options altered while the daemon is running using the +ntpq and ntpdc utility programs. + +

    When ntpd starts it looks at the value of umask, +and if it's zero ntpd will set the umask to +022. + +

    Command Line Options

    + +
    + +
    -a
    +
    Enable authentication mode (default).
    + +
    -A
    +
    Disable authentication mode.
    + +
    -b
    +
    Synchronize using NTP broadcast messages.
    + +
    -c conffile
    +
    Specify the name and path of the configuration file.
    + +
    -d
    +
    Specify debugging mode. This flag may occur multiple times, with +each occurrence indicating greater detail of display.
    + +
    -D level
    +
    Specify debugging level directly.
    + +
    -f driftfile
    +
    Specify the name and path of the drift file.
    + +
    -g
    +
    Normally, the daemon exits if the offset exceeds a 1000-s sanity +limit. This option overrides this limit and allows the time to be set to +any value without restriction.
    + +
    -k keyfile
    +
    Specify the name and path of the file containing the NTP +authentication keys.
    + +
    -l logfile
    +
    Specify the name and path of the log file. The default is the system +log facility.
    + +
    -m
    +
    Synchronize using NTP multicast messages on the IP multicast group +address 224.0.1.1 (requires multicast kernel).
    + +
    -p pidfile
    +
    Specify the name and path to record the daemon's process ID.
    + +
    -P
    +
    Override the priority limit set by the operating system. Not +recommended for sissies.
    + +
    -r broadcastdelay
    +
    Specify the default propagation delay from the broadcast/multicast +server and this computer. This is necessary only if the delay cannot be +computed automatically by the protocol.
    + +
    -s statsdir
    +
    Specify the directory path for files created by the statistics +facility.
    + +
    -t key
    +
    Add a key number to the trusted key list.
    + +
    -v variable
    +
    -V variable
    +
    Add a system variable listed by default.
    + +
    -x
    +
    Ordinarily, if the time is to be adjusted more than 128 ms, it is +stepped, not gradually slewed. This option forces the time to be slewed +in all cases. Note: Since the slew rate is limited to 0.5 ms/s, each +second of adjustment requires an amortization interval of 2000 s. Thus, +an adjustment of many seconds can take hours or days to amortize.
    + +
    + +

    The Configuration File

    + +The ntpd configuration file is read at initial startup in order +to specify the synchronization sources, modes and other related +information. Usually, it is installed in the /etc directory, +but could be installed elsewhere (see the -c conffile +command line option). The file format is similar to other Unix +configuration files - comments begin with a # character and +extend to the end of the line; blank lines are ignored. Configuration +commands consist of an initial keyword followed by a list of arguments, +some of which may be optional, separated by whitespace. Commands may not +be continued over multiple lines. Arguments may be host names, host +addresses written in numeric, dotted-quad form, integers, floating +point numbers (when specifying times in seconds) and text strings. +Optional arguments are delimited by [ ] in the following +descriptions, while alternatives are separated by |. The +notation [ ... ] means an optional, indefinite repetition of +the last item before the [ ... ]. + +

    See the following pages for configuration and control options. While +there is a rich set of options available, the only required option is +one or more server, peer, broadcast or +manycastclient commands described in the Configuration Options +page. The Notes on Configuring NTP and Setting up a +NTP Subnet page contains an extended discussion of these options. + +

    Configuration Options +
    Authentication Options +
    Monitoring Options +
    Access Control Options +
    Reference Clock Options +
    Miscellaneous Options + +

    Files

    + +/etc/ntp.conf - the default name of the configuration file +
    /etc/ntp.drift - the default name of the drift file +
    /etc/ntp.keys - the default name of the key file + +

    Bugs

    + +ntpd 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. + +
    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/ntpdate.htm b/contrib/ntp/html/ntpdate.htm new file mode 100644 index 000000000000..a7f532fef0e5 --- /dev/null +++ b/contrib/ntp/html/ntpdate.htm @@ -0,0 +1,185 @@ + + + + + ntpdate - set the date and time via NTP + + + + +

    +ntpdate - set the date and time via NTP

    + +
    +

    +Synopsis

    +ntpdate [ -bBdoqsuv ] [ -a key ] [ -e authdelay ] [ -k +keyfile ] [ -o version ] [ -p samples ] [ -t timeout +] server [ ... ] +

    +Description

    +ntpdate sets the local date and time by polling the Network Time +Protocol (NTP) server(s) given as the server 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 a subset of +the NTP clock filter and selection algorithms are applied to select the +best of these. Note that the accuracy and reliability of ntpdate +depends on the number of servers, the number of polls each time it is run +and the interval between runs. + +

    ntpdate can be run manually as necessary to set the host clock, +or it can be run from the host startup script to set the clock at boot +time. This is useful in some cases to set the clock initially before starting +the NTP daemon ntpd. It is also possible to run ntpdate +from a cron script. However, it is important to note that ntpdate +with contrived cron scripts is no substitute for the NTP daemon, +which uses sophisticated algorithms to maximize accuracy and reliability +while minimizing resource use. Finally, since ntpdate does not +discipline the host clock frequency as does ntpd, the accuracy +using ntpdate is limited. + +

    Time adjustments are made by ntpdate in one of two ways. If +ntpdate determines the clock is in error more than 0.5 second +it will simply step the time by calling the system settimeofday() +routine. If the error is less than 0.5 seconds, it will slew the time by +calling the system adjtime() routine. The latter technique is +less disruptive and more accurate when the error is small, and works quite +well when ntpdate is run by cron every hour or two. + +

    ntpdate will decline to set the date if an NTP server daemon +(e.g., ntpd) is running on the same host. When running ntpdate +on a regular basis from cron 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. + +

    If NetInfo support is compiled into ntpdate, then the +server argument is optional if ntpdate can find a time +server in the NetInfo configuration for ntpd. + +

    +Command Line Options

    + +
    +
    +-a key
    + +
    +Enable the authentication function and specify the key identifier to be +used for authentication as the argument keyntpdate. The +keys and key identifiers must match in both the client and server key files. +The default is to disable the authentication function.
    + +
    +-B
    + +
    +Force the time to always be slewed using the adjtime() system call, even +if the measured offset is greater than +-128 ms. The default is to step +the time using settimeofday() if the offset is greater than +-128 ms. Note +that, if the offset is much greater than +-128 ms in this case, that it +can take a long time (hours) to slew the clock to the correct value. During +this time. the host should not be used to synchronize clients.
    + +
    +-b
    + +
    +Force the time to be stepped using the settimeofday() system call, rather +than slewed (default) using the adjtime() system call. This option should +be used when called from a startup file at boot time.
    + +
    +-d
    + +
    +Enable the debugging mode, in which ntpdate will go through all +the steps, but not adjust the local clock. Information useful for general +debugging will also be printed.
    + +
    +-e authdelay
    + +
    +Specify the processing delay to perform an authentication function as the +value authdelay, in seconds and fraction (see ntpd for +details). This number is usually small enough to be negligible for most +purposes, though specifying a value may improve timekeeping on very slow +CPU's.
    + +
    +-k keyfile
    + +
    +Specify the path for the authentication key file as the string keyfile. +The default is /etc/ntp.keys. This file should be in the format +described in ntpd.
    + +
    +-o version
    + +
    +Specify the NTP version for outgoint packets as the integer version, +which can be 1 or 2. The default is 3. This allows ntpdate to +be used with older NTP versions.
    + +
    +-p samples
    + +
    +Specify the number of samples to be acquired from each server as the integer +samples, with values from 1 to 8 inclusive. The default is 4.
    + +
    +-q
    + +
    +Query only - don't set the clock.
    + +
    +-s
    + +
    +Divert logging output from the standard output (default) to the system +syslog facility. This is designed primarily for convenience of +cron scripts.
    + +
    +-t timeout
    + +
    +Specify the maximum time waiting for a server response as the value timeout, +in seconds and fraction. The value is is rounded to a multiple of 0.2 seconds. +The default is 1 second, a value suitable for polling across a LAN.
    + +
    +-u
    + +
    +Direct ntpdate to use an unprivileged port or outgoing packets. +This is most useful when behind a firewall that blocks incoming traffic +to privileged ports, and you want to synchronise with hosts beyond the +firewall. Note that the -d option always uses unprivileged ports.
    + +
    +-v
    + +
    +Be verbose. This option will cause ntpdate's version identification +string to be logged.
    +
    + +

    +Files

    +/etc/ntp.keys - encryption keys used by ntpdate. +

    +Bugs

    +The slew adjustment is actually 50% larger than the measured offset, since +this (it is argued) will tend to keep a badly drifting clock more accurate. +This is probably not a good idea and may cause a troubling hunt for some +values of the kernel variables tick and tickadj.  +
    +
    +David L. Mills (mills@udel.edu)
    + + + diff --git a/contrib/ntp/html/ntpdc.htm b/contrib/ntp/html/ntpdc.htm new file mode 100644 index 000000000000..52d1fdfe25bb --- /dev/null +++ b/contrib/ntp/html/ntpdc.htm @@ -0,0 +1,620 @@ + + + + + ntpdc - special NTP query program + + + + +

    +ntpdc - special NTP query program

    + +
    +

    +Synopsis

    +ntpdc [ -ilnps ] [ -c command ] [ host ] [ ... ] +

    +Description

    +ntpdc is used to query the ntpd 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 ntpdc +interface. In addition, nearly all the configuration options which can +be specified at start up using ntpd's configuration file may also be specified +at run time using ntpdc. + +

    If one or more request options is included on the command line when +ntpdc 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 localhost by default. If no request options are given, ntpdc +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 localhost when no other host is specified. ntpdc +will prompt for commands if the standard input is a terminal device. + +

    ntpdc 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. ntpdc makes no attempt to retransmit requests, and will +time requests out if the remote host is not heard from within a suitable +timeout time. + +

    The operation of ntpdc are specific to the particular implementation +of the ntpd daemon and can be expected to work only with this +and maybe some previous versions of the daemon. Requests from a remote +ntpdc program which affect the state of the local server must +be authenticated, which requires both the remote program and local server +share a common key and key identifier. +

    +Command Line Options

    +Specifying a command line option other than -i or -n +will cause the specified query (queries) to be sent to the indicated host(s) +immediately. Otherwise, ntpdc will attempt to read interactive +format commands from the standard input. +
    +
    +-c command
    + +
    +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 -c options may be given.
    + +
    +-i
    + +
    +Force ntpdc to operate in interactive mode. Prompts will be written +to the standard output and commands read from the standard input.
    + +
    +-l
    + +
    +Obtain a list of peers which are known to the server(s). This switch is +equivalent to -c listpeers.
    + +
    +-n
    + +
    +Output all host addresses in dotted-quad numeric format rather than converting +to the canonical host names.
    + +
    +-p
    + +
    +Print a list of the peers known to the server as well as a summary of their +state. This is equivalent to -c peers.
    + +
    +-s
    + +
    +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 -p switch. This is equivalent +to -c dmpeers.
    +
    + +

    +Interactive Commands

    +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 <, followed by a file name, +to the command line. + +

    A number of interactive format commands are executed entirely within +the ntpdc program itself and do not result in NTP mode 7 requests +being sent to a server. These are described following. +

    +
    +? [ command_keyword ]
    + +
    helpl [ command_keyword ] +
    +A ? by itself will print a list of all the command keywords known +to this incarnation of ntpq. A ? followed by a command +keyword will print funcation and usage information about the command. This +command is probably a better source of information about ntpq +than this manual page.
    + +
    +delay milliseconds
    + +
    +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 timestamps +in authenticated requests, so this command may be obsolete.
    + +
    +host hostname
    + +
    +Set the host to which future queries will be sent. Hostname may be either +a host name or a numeric address.
    + +
    +hostnames [ yes | no ]
    + +
    +If yes is specified, host names are printed in information displays. +If no is specified, numeric addresses are printed instead. The +default is yes, unless modified using the command line -n +switch.
    + +
    +keyid keyid
    + +
    +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.
    + +
    +quit
    + +
    +Exit ntpdc.
    + +
    +passwd
    + +
    +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.
    + +
    +timeout millseconds
    + +
    +Specify a timeout period for responses to server queries. The default is +about 8000 milliseconds. Note that since ntpdc retries each query +once after a timeout, the total waiting time for a timeout will be twice +the timeout value set.
    +
    + +

    +Control Message Commands

    +Query commands result in NTP mode 7 packets containing requests for information +being sent to the server. These are read-only commands in that they make +no modification of the server configuration state. +
    +
    +listpeers
    + +
    +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.
    + +
    +peers
    + +
    +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 + denotes symmetric active, a - indicates +symmetric passive, a = means the remote server is being polled +in client mode, a ^ indicates that the server is broadcasting +to this address, a ~ denotes that the remote peer is sending broadcasts +and a * marks the peer the server is currently synchonizing to.
    + + +

    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 REFCLK(implementation number, parameter). +On hostnames no only IP-addresses will be displayed. +

    +dmpeers
    + +
    +A slightly different peer summary list. Identical to the output of the +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 . indicates that this peer +was cast off in the falseticker detection, while a + indicates +that the peer made it through. A * denotes the peer the server +is currently synchronizing with.
    + +
    +showpeer peer_address [...]
    + +
    +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.
    + +
    +pstats peer_address [...]
    + +
    +Show per-peer statistic counters associated with the specified peer(s).
    + +
    +clockinfo clock_peer_address [...]
    + +
    +Obtain and print information concerning a peer clock. The values obtained +provide information on the setting of fudge factors and other clock performance +information.
    + +
    +kerninfo
    + +
    +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.
    + +
    +loopinfo [ oneline | multiline ]
    + +
    +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 +offset is the last offset given to the loop filter by the packet +processing code. The frequency is the frequency error of the local +clock in parts-per-million (ppm). The time_const controls the +stiffness of the phase-lock loop and thus the speed at which it can adapt +to oscillator drift. The watchdog timer value is the number of +seconds which have elapsed since the last sample offset was given to the +loop filter. The oneline and multiline options specify +the format in which this information is to be printed, with multiline +as the default.
    + +
    +sysinfo
    + +
    +Print a variety of system state variables, i.e., state related to the local +server. All except the last four lines are described in the NTP Version +3 specification, RFC-1305.
    + +
    +
    +The system flags show various system flags, some of which can +be set and cleared by the enable and disable configuration +commands, respectively. These are the auth, bclient, +monitor, pll, pps and stats flags. +See the ntpd documentation for the meaning of these flags. There +are two additional flags which are read only, the kernel_pll and +kernel_pps. These flags indicate the synchronization status when +the precision time kernel modifications are in use. The kernel_pll +indicates that the local clock is being disciplined by the kernel, while +the kernel_pps indicates the kernel discipline is provided by the PPS signal.
    + +
    +The stability is the residual frequency error remaining after +the system frequency correction is applied and is intended for maintenance +and debugging. In most architectures, this value will initially decrease +from as high as 500 ppm to a nominal value in the range .01 to 0.1 ppm. +If it remains high for some time after starting the daemon, something may +be wrong with the local clock, or the value of the kernel variable tick +may be incorrect.
    + +
    +The broadcastdelay shows the default broadcast delay, as set by +the broadcastdelay configuration command.
    + +
    +The authdelay shows the default authentication delay, as set by +the authdelay configuration command.
    +
    + +
    +sysstats
    + +
    +Print statistics counters maintained in the protocol module.
    + +
    +memstats
    + +
    +Print statistics counters related to memory allocation code.
    + +
    +iostats
    + +
    +Print statistics counters maintained in the input-output module.
    + +
    +timerstats
    + +
    +Print statistics counters maintained in the timer/event queue support code.
    + +
    +reslist
    + +
    +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.
    + +
    +monlist [ version ]
    + +
    +Obtain and print traffic counts collected and maintained by the monitor +facility. The version number should not normally need to be specified.
    + +
    +clkbug clock_peer_address [...]
    + +
    +Obtain debugging information for a reference clock driver. This information +is provided only by some clock drivers and is mostly undecodable without +a copy of the driver source in hand.
    +
    + +

    +Runtime Configuration Requests

    +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 xtnpdc. This can be done using the keyid +and 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. + +

    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. + +

    The following commands all make authenticated requests. +

    +
    +addpeer peer_address [ keyid ] [ version ] [ prefer +]
    + +
    +Add a configured peer association at the given address and operating in +symmetric active mode. 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. If the optional keyid +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 version# +can be 1, 2 or 3 and defaults to 3. 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.
    + +
    +addserver peer_address [ keyid ] [ version ] [ +prefer ]
    + +
    +Identical to the addpeer command, except that the operating mode is client.
    + +
    +broadcast peer_address [ keyid ] [ version ] [ +prefer ]
    + +
    +Identical to the addpeer command, except that the operating mode is broadcast. +In this case a valid key identifier and key are required. The peer_address +parameter can be the broadcast address of the local network or a multicast +group address assigned to NTP. If a multicast address, a multicast-capable +kernel is required.
    + +
    +unconfig peer_address [...]
    + +
    +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.
    + +
    +fudge peer_address [ time1 ] [ time2 ] [ stratum +] [ refid ]
    + +
    +This command provides a way to set certain data for a reference clock. +See the source listing for further information.
    + +
    +enable [ flag ] [ ... ]
    + +
    disable [ flag ] [ ... ] +
    +These commands operate in the same way as the enable and disable +configuration file commands of ntpd. Following is a description +of the flags. Note that only the auth, bclient, monitor, +pll, pps and stats flags can be set by ntpdc; +the pll_kernel and pps_kernel flags are read-only.
    + +
    +
    +auth
    + +
    +Enables the server to synchronize with unconfigured peers only if the peer +has been correctly authenticated using a trusted key and key identifier. +The default for this flag is enable.
    + +
    +bclient
    + +
    +Enables the server to listen for a message from a broadcast or multicast +server, as in the multicastclient command with default address. +The default for this flag is disable.
    + +
    +monitor
    + +
    +Enables the monitoring facility. See the ntpdc program and the +monlist command or further information. The default for this flag +is enable.
    + +
    +pll
    + +
    +Enables the server to adjust its local clock by means of NTP. If disabled, +the local clock free-runs at its intrinsic time and frequency offset. This +flag is useful in case the local clock is controlled by some other device +or protocol and NTP is used only to provide synchronization to other clients. +In this case, the local clock driver is used. See the Reference +Clock Drivers page for further information. The default for this flag +is enable.
    + +
    +pps
    + +
    +Enables the pulse-per-second (PPS) signal when frequency and time is disciplined +by the precision time kernel modifications. See the A +Kernel Model for Precision Timekeeping page for further information. +The default for this flag is disable.
    + +
    +stats
    + +
    +Enables the statistics facility. See the Monitoring +Options page for further information. The default for this flag is +enable.
    + +
    +pll_kernel
    + +
    +When the precision time kernel modifications are installed, this indicates +the kernel controls the clock discipline; otherwise, the daemon controls +the clock discipline.
    + +
    +pps_kernel
    + +
    +When the precision time kernel modifications are installed and a pulse-per-second +(PPS) signal is available, this indicates the PPS signal controls the clock +discipline; otherwise, the daemon or kernel controls the clock discipline, +as indicated by the pll_kernel flag.
    +
    + +
    +restrict address mask flag [ flag ]
    + +
    +This command operates in the same way as the restrict configuration +file commands of ntpd.
    + +
    +unrestrict address mask flag [ flag ]
    + +
    +Unrestrict the matching entry from the restrict list.
    + +
    +delrestrict address mask [ ntpport ]
    + +
    +Delete the matching entry from the restrict list.
    + +
    +readkeys
    + +
    +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 ntpd configuration file). This allows encryption keys to +be changed without restarting the server.
    + +
    +trustkey keyid [...]
    + +
    +untrustkey keyid [...]
    + +
    +These commands operate in the same way as the trustedkey and untrustkey +configuration file commands of ntpd.
    + +
    +authinfo
    + +
    +Returns information concerning the authentication module, including known +keys and counts of encryptions and decryptions which have been done.
    + +
    +traps
    + +
    +Display the traps set in the server. See the source listing for further +information.
    + +
    +addtrap [ address [ port ] [ interface ]
    + +
    +Set a trap for asynchronous messages. See the source listing for further +information.
    + +
    +clrtrap [ address [ port ] [ interface]
    + +
    +Clear a trap for asynchronous messages. See the source listing for further +information.
    + +
    +reset
    + +
    +Clear the statistics counters in various modules of the server. See the +source listing for further information.
    +
    + +

    +Bugs

    +ntpdc 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.  +
    +
    +David L. Mills (mills@udel.edu)
    + + + diff --git a/contrib/ntp/html/ntpq.htm b/contrib/ntp/html/ntpq.htm new file mode 100644 index 000000000000..930886736d15 --- /dev/null +++ b/contrib/ntp/html/ntpq.htm @@ -0,0 +1,747 @@ + + + + + ntpq - standard NTP query program + + + + +

    +pq - standard NTP query program

    + +
    +

    +Synopsis

    +ntpq [-inp] [-c command] [host] [...] +

    +Description

    +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. +ntpq can also obtain and print a list of peers in a common format +by sending multiple queries to the server. + +

    If one or more request options is included on the command line when +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 localhost by default. If no request options are given, 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 localhost when no other host is specified. ntpq +will prompt for commands if the standard input is a terminal device. + +

    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. ntpq makes one attempt to retransmit requests, and will +time requests out if the remote host is not heard from within a suitable +timeout time. + +

    Command line options are described following. Specifying a command line +option other than -i or -n will cause the specified query (queries) to +be sent to the indicated host(s) immediately. Otherwise, ntpq +will attempt to read interactive format commands from the standard input. +

    +
    +-c
    + +
    +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 -c options may be given.
    + +
    +-i
    + +
    +Force ntpq to operate in interactive mode. Prompts will be written +to the standard output and commands read from the standard input.
    + +
    +-n
    + +
    +Output all host addresses in dotted-quad numeric format rather than converting +to the canonical host names.
    + +
    +-p
    + +
    +Print a list of the peers known to the server as well as a summary of their +state. This is equivalent to the peers interactive command.
    +
    + +

    +Internal Commands

    +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 "<", followed by a file name, to the +command line. A number of interactive format commands are executed entirely +within the ntpq program itself and do not result in NTP mode 6 +requests being sent to a server. These are described following. +
    +
    +? [command_keyword]
    + +
    helpl [ command_keyword ] +
    +A "?" by itself will print a list of all the command keywords +known to this incarnation of ntpq. A "?" followed by +a command keyword will print funcation and usage information about the +command. This command is probably a better source of information about +ntpq than this manual page.
    + +
    + +
    +addvars variable_name [ = value] [...]
    + +
    rmvars variable_name [...] +
    clearvars +
    +The data carried by NTP mode 6 messages consists of a list of items of +the form variable_name = value, where the " += value" is ignored, and can be omitted, in requests to the +server to read variables. ntpq maintains an internal list in which +data to be included in control messages can be assembled, and sent using +the readlist and writelist commands described below. The 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 rmvars command can be used to remove individual +variables from the list, while the clearlist command removes all variables +from the list.
    + +
    + +
    +authenticate yes | no
    + +
    +Normally ntpq does not authenticate requests unless they are write +requests. The command authenticate yes causes 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.
    + +
    + +
    +cooked
    + +
    +Causes output from query commands to be "cooked". Variables which +are recognized by the server will have their values reformatted for human +consumption. Variables which ntpq thinks should have a decodeable +value but didn't are marked with a trailing "?".
    + +
    + +
    +debug more | less | off
    + +
    +Turns internal query program debugging on and off.
    + +
    + +
    +delay milliseconds
    + +
    +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 timestamps +in authenticated requests, so this command may be obsolete.
    + +
    + +
    +host hostname
    + +
    +Set the host to which future queries will be sent. Hostname may be either +a host name or a numeric address.
    + +
    + +
    +hostnames [yes | no]
    + +
    +If "yes" is specified, host names are printed in information displays. +If "no" is specified, numeric addresses are printed instead. The +default is "yes", unless modified using the command line -n +switch.
    + +
    + +
    +keyid keyid
    + +
    +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.
    + +
    + +
    +ntpversion 1 | 2 | 3 | 4
    + +
    +Sets the NTP version number which 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.
    + +
    + +
    +quit
    + +
    +Exit ntpq.
    + +
    + +
    +passwd
    + +
    +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.
    + +
    + +
    +raw
    + +
    +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.
    + +
    + +
    +timeout millseconds
    + +
    +Specify a timeout period for responses to server queries. The default is +about 5000 milliseconds. Note that since ntpq retries each query +once after a timeout, the total waiting time for a timeout will be twice +the timeout value set.
    +
    + +

    +Control Message Commands

    +Each peer known to an NTP server has a 16 bit integer association 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. + +

    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 peers command, which will +send a preprogrammed series of messages to obtain the data it needs, and +the mreadlist and mreadvar commands, which will iterate over a range of +associations. +

    +
    +associations
    + +
    +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 See the peers command +for a decode of the condition field. Note that the data returned +by the "associations" command is cached internally in 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 +and index may be used as an alternative.
    + +
    + +
    +clockvar [assocID] [variable_name [ = value [...] +] [...]
    + +
    +cv [assocID] [variable_name [ = value [...] ] +[...]
    + +
    +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 "system clock" 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.
    + +
    + +
    +lassocations
    + +
    +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 "associations" 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 "associations" +command is used, but are included in the output of "lassociations".
    + +
    + +
    +lpassociations
    + +
    +Print data for all associations, including out-of-spec client associations, +from the internally cached list of associations. This command differs from +"passociations" only when dealing with fuzzballs.
    + +
    + +
    +lpeers
    + +
    +Like R 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.
    + +
    + +
    +mreadlist assocID assocID
    + +
    mrl assocID assocID +
    +Like the 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 associations command.
    + +
    + +
    +mreadvar assocID assocID [ variable_name [ = value +[ ... ]
    + +
    mrv assocID assocID [ variable_name [ = value +[ ... ] +
    +Like the 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 associations command.
    + +
    + +
    +opeers
    + +
    +An old form of the peers command with the reference ID replaced +by the local interface address.
    + +
    + +
    +passociations
    + +
    +Prints association data concerning in-spec peers from the internally cached +list of associations. This command performs identically to the "associations" +except that it displays the internally stored data rather than making a +new query.
    + +
    + +
    +peers
    + +
    +Obtains a current list 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 this is unknown), the stratum of the remote +peer, the type of the peer (local, unicast, multicast or broadcast), when +the last packet was received, the polling interval, in seconds, the reachability +register, in octal, and the current estimated delay, offset and dispersion +of the peer, all in milliseconds.
    + +
    + +
    +The character in the left margin indicates the fate of this peer in the +clock selection process. Folowing is a list of these characters, the pidgeon +used in the rv command, and a short explanation of the condition +revealed.
    + +
    + +
    +space reject
    + +
    +
    +The peer is discarded as unreachable, synchronized to this server (synch +loop) or outrageous synchronization distance.
    + +
    +
    + +
    +x     falsetick
    + +
    +
    +The peer is discarded by the intersection algorithm as a falseticker.
    + +
    +
    + +
    +.     excess
    + +
    +
    +The peer is discarded as not among the first ten peers sorted by synchronization +distance and so is probably a poor candidate for further consideration.
    + +
    +
    + +
    +-     outlyer
    + +
    +
    +The peer is discarded by the clustering algorithm as an outlyer.
    + +
    +
    + +
    ++     candidat
    + +
    +
    +The peer is a survivor and a candidate for the combining algorithm.
    + +
    +
    + +
    +#     selected
    + +
    +
    +The peer is a survivor, but not among the first six peers sorted by synchronization +distance. If the assocation is ephemeral, it may be demobilized to conserve +resources.
    + +
    +
    + +
    +*     sys.peer
    + +
    +
    +The peer has been declared the system peer and lends its variables to the +system variables.
    +
    + +
    + 
    + +
    +o     pps.peer
    + +
    +
    +The peer has been declared the system peer and lends its variables to the +system variables. However, the actual system synchronization is derived +from a pulse-per-second (PPS) signal, either indirectly via the PPS reference +clock driver or directly via kernel interface.
    + +
    +
    + +
    +The flash variable is not defined in the NTP specification, but +is included as a valuable debugging aid. It displays the results of the +packet sanity checks defined in the NTP specification TEST1 through +TEST9. The bits for each test read in increasing sequency from +the least significant bit and are defined as follows.
    + +
    + +
    +The following TEST1 through TEST4 enumerate procedure +errors. The packet timestamps may or may not be believed, but the remaining +header data are ignored.
    + +
    +
    +
    + +
    +TEST1
    + +
    +
    +Duplicate packet. A copy from somewhere.
    +
    + +
    +
    +
    + +
    +TEST2
    + +
    +
    +Bogus packet. It is not a reply to a message previously sent. This can +happen when the NTP daemon is restarted and before a peer notices.
    + +
    +
    + +
    +TEST3
    + +
    +
    +Unsynchronized. One or more timestamp fields are missing. This normally +happens when the first packet from a peer is received.
    + +
    +
    + +
    +TEST4
    + +
    +
    +Either peer delay or peer dispersion is greater than one second. Ya gotta +be kidding.
    + +
    +
    + +
    +The following TEST5 through TEST10 ennumerate errors +in the packet header. The packet is discarded without inspecting its contents.
    + +
    +
    +
    + +
    +TEST5
    + +
    +
    +Cryptographic authentication fails. See the Authentication +Options page.
    + +
    +
    + +
    +TEST6
    + +
    +
    +Peer is unsynchronized. Wind up its clock first.
    + +
    +
    + +
    +TEST7
    + +
    +
    +Peer stratum is greater than 15. The peer is probably unsynchronized.
    + +
    +
    + +
    +TEST8
    + +
    +
    +Either root delay or root dispersion is greater than one second. Too far +from home.
    +
    + +
    +
    +
    + +
    +TEST9
    + +
    +
    +Peer cryptographic authentication fails. Either the key identifier or key +is wrong or somebody trashed our packet.
    + +
    +
    + +
    +TEST10
    + +
    +
    +Access is denied. See the Access Control Options +page.
    + +
    +
    + +
    +pstatus assocID
    + +
    +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.
    + +
    + +
    +readlist [ assocID ]
    + +
    rl [ assocID ] +
    +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.
    + +
    + +
    +readvar assocID variable_name [ = value ] [ ... +]
    + +
    rv assocID [ variable_name [ = value ] [ ... +] +
    +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.
    + +
    + +
    +writevar assocID variable_name [ = value [ ... +]
    + +
    +Like the readvar request, except the specified variables are written instead +of read.
    + +
    + +
    +writelist [ assocID ]
    + +
    +Like the readlist request, except the internal list variables are written +instead of read.
    +
    + +

    +Bugs

    +The peers command is non-atomic and may occasionally result in spurious +error messages about invalid associations occurring and terminating the +command. The timeout time is a fixed constant, which means you wait a long +time for timeouts since it assumes sort of a worst case. The program should +improve the timeout estimate as it sends queries to a particular host, +but doesn't.  +
    +
    +David L. Mills (mills@udel.edu)
    + + + diff --git a/contrib/ntp/html/ntptime.htm b/contrib/ntp/html/ntptime.htm new file mode 100644 index 000000000000..3cc454487de3 --- /dev/null +++ b/contrib/ntp/html/ntptime.htm @@ -0,0 +1,96 @@ + + + + + ntptime - read kernel time variables + + + + +

    +ntptime - read kernel time variables

    + +
    +

    +Synopsis

    +ntptime [ -chr ] [ -e est_error ] [ -f frequency ] [ +-m max_error ] [ -o offset ] [ -s status ] [ -t time_constant +] +

    +Description

    +This program is useful only with special kernels described in the A +Kernel Model for Precision Timekeeping page. It reads and displays +time-related kernel variables using the ntp_gettime() system call. +A similar display can be obtained using the ntpdc program and +kerninfo command. +

    +Options

    + +
    +
    +-c
    + +
    +Display the execution time of ntptime itself.
    + +
    +-e est_error
    + +
    +Specify estimated error, in microseconds.
    + +
    +-f frequency
    + +
    +Specify frequency offset, in parts per million.
    + +
    +-h
    + +
    +Display times in Unix timeval format. Default is NTP format.
    + +
    +-l
    + +
    +Specify the leap bits as a code from 0 to 3.
    + +
    +-m max_error
    + +
    +Display help information.
    + +
    +-o offset
    + +
    +Specify clock offset, in microseconds.
    + +
    +-r
    + +
    +Display Unix and NTP times in raw format.
    + +
    +-s status
    + +
    +Specify clock status. Better know what you are doing.
    + +
    +-t time_constant
    + +
    +Specify time constant, an integer in the range 0-4.
    +
    + +
    +
    +David L. Mills (mills@udel.edu)
    + + + diff --git a/contrib/ntp/html/ntptrace.htm b/contrib/ntp/html/ntptrace.htm new file mode 100644 index 000000000000..675c347a566a --- /dev/null +++ b/contrib/ntp/html/ntptrace.htm @@ -0,0 +1,82 @@ + + + + + ntptrace - trace a chain of NTP servers back to the primary +source + + + + +

    +ntptrace - trace a chain of NTP servers back to the primary source

    + +
    +

    +Synopsis

    +ntptrace [ -vdn ] [ -r retries ] [ -t timeout ] [ server +] +

    +Description

    +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. +Here is an example of the output from ntptrace: +
    % ntptrace
    +localhost: stratum 4, offset 0.0019529, synch distance 0.144135
    +server2ozo.com: stratum 2, offset 0.0124263, synch distance 0.115784
    +usndh.edu: stratum 1, offset 0.0019298, synch distance 0.011993, refid
    +'WWVB'
    +On each line, the fields are (left to right): the host name, the host stratum, +the time offset between that host and the local host (as measured by ntptrace; +this is why it is not always zero for "localhost"), the host synchronization +distance, and (only for stratum-1 servers) the reference clock ID. All +times are given in seconds. Note that the stratum is the server hop count +to the primary source, while the synchronization distance is the estimated +error relative to the primary source. These terms are precisely defined +in RFC-1305. +

    +Options

    + +
    +
    +-d
    + +
    +Turns on some debugging output.
    + +
    +-n
    + +
    +Turns off the printing of host names; instead, host IP addresses are given. +This may be useful if a nameserver is down.
    + +
    +-r retries
    + +
    +Sets the number of retransmission attempts for each host (default = 5).
    + +
    +-t timeout
    + +
    +Sets the retransmission timeout (in seconds) (default = 2).
    + +
    +-v
    + +
    +Prints verbose information about the NTP servers.
    +
    + +

    +Bugs

    +This program makes no attempt to improve accuracy by doing multiple samples.  +
    +
    +David L. Mills (mills@udel.edu)
    + + + diff --git a/contrib/ntp/html/parsedata.htm b/contrib/ntp/html/parsedata.htm new file mode 100644 index 000000000000..a756079cefc2 --- /dev/null +++ b/contrib/ntp/html/parsedata.htm @@ -0,0 +1,407 @@ + +NTP PARSE clock data formats +

    NTP PARSE clock data formats

    + +

    The parse driver currently supports several clocks with different +query mechanisms. In order for you to find a sample that might be +similar to a clock you might want to integrate into parse i'll sum +up the major features of the clocks (this information is distributed +in the parse/clk_*.c and ntpd/refclock_parse.c files). + +


    +

    Meinberg clocks

    +
    +Meinberg: start=<STX>, end=<ETX>, sync on start
    +      pattern="\2D:  .  .  ;T: ;U:  .  .  ;    \3"
    +      pattern="\2  .  .  ;  ;   :  :  ;        \3"
    +      pattern="\2  .  .  ;  ;   :  :  ;    :  ;        ;   .         .       "
    +
    +

    + Meinberg is a german manufacturer of time code receivers. Those clocks + have a pretty common output format in the stock version. In order to + support NTP Meinberg was so kind to produce some special versions of + the firmware for the use with NTP. So, if you are going to use a + Meinberg clock please ask whether there is a special Uni Erlangen + version. + You can reach Meinberg via the Web. + Information can also be ordered via eMail from info@meinberg.de + +

    + General characteristics: +
    + Meinberg clocks primarily output pulse per second and a describing + ASCII string. This string can be produced in two modes. either upon + the reception of a question mark or every second. NTP uses the latter + mechanism. The DCF77 variants have a pretty good relationship between + RS232 time code and the PPS signal while the GPS receiver has no fixed + timeing between the datagram and the pulse (you need to use PPS with + GPS!) on DCF77 you might get away without the PPS signal. +

    +	The preferred tty setting for Meinberg is:
    +		CFLAG		(B9600|CS7|PARENB|CREAD|HUPCL)
    +		IFLAG		(IGNBRK|IGNPAR|ISTRIP)
    +		OFLAG		0
    +		LFLAG		0
    +        
    +
    +	The tty setting for Meinberg GPS 166/167 receivers is:
    +		CFLAG		(B19200|CS8|PARENB|CREAD|HUPCL)
    +		IFLAG		(IGNBRK|IGNPAR|ISTRIP)
    +		OFLAG		0
    +		LFLAG		0
    +        
    + +

    + The clock is run at datagram once per second. + Stock dataformat is: +

    +    <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 ' '
    +<D>             = 'U' if UTC time code is deliverd else ' '
    +<A>             = '!' during the hour preceeding an daylight saving time
    +                      start/end change
    +<A>             = 'A' if a leap second is announced
    +
    + +
    +        <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
    +
    + +

    For the Meinberg parse look into clock_meinberg.c + +
    +

    Raw DCF77 Data via serial line

    +

    RAWDCF: end=TIMEOUT>1.5s, sync each char (any char),generate psuedo time + codes, fixed format +

    + direct DCF77 code input + +

    In Europe it is relatively easy/cheap the receive the german time code + transmitter DCF77. The simplest version to process its signal is to + feed the 100/200ms pulse of the demodulated AM signal via a level + converter to an RS232 port at 50Baud. parse/clk_rawdcf.c holds all + necessary decoding logic for the time code which is transmitted each + minute for one minute. A bit of the time code is sent once a second. + +

    +	The preferred tty setting is:
    +		CFLAG           (B50|CS8|CREAD|CLOCAL)
    +		IFLAG		0
    +		OFLAG		0
    + 		LFLAG		0
    +
    + +

    DCF77 raw time code

    + + +

    From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig +und Berlin, März 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
    +
    + +
    +

    Schmid clock

    + +

    + Schmid clock: needs poll, binary input, end='\xFC', sync start + +

    + The Schmid clock is a DCF77 receiver that sends a binary + time code at the reception of a flag byte. The contents + if the flag byte determined the time code format. The + binary time code is delimited by the byte 0xFC. +

    +	TTY setup is:
    +		CFLAG		(B1200|CS8|CREAD|CLOCAL)
    +		IFLAG		0
    +		OFLAG		0
    + 		LFLAG		0
    +
    +
    + + +

    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)
    +
    + +
    +

    Trimble SV6 ASCII time code (TAIP)

    + +

    + Trimble SV6: needs poll, ascii timecode, start='>', end='<', + query='>QTM<', eol='<' + +

    Trimble SV6 is a GPS receiver with PPS output. It needs to be polled. + It also need a special tty mode setup (EOL='<'). +

    +	TTY setup is:
    +		CFLAG            (B4800|CS8|CREAD)
    +		IFLAG            (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
    +		OFLAG            (OPOST|ONLCR)
    +		LFLAG            (ICANON|ECHOK)
    +
    +	Special flags are:
    +		PARSE_F_PPSPPS	    - use CIOGETEV for PPS time stamping
    +		PARSE_F_PPSONSECOND - the time code is not related to
    +				      the PPS pulse (so use the time code
    +				      only for the second epoch)
    +
    +	Timecode
    +	0000000000111111111122222222223333333	/ char
    +	0123456789012345678901234567890123456	\ posn
    +	>RTMhhmmssdddDDMMYYYYoodnnvrrrrr;*xx<	Actual
    +	----33445566600112222BB7__-_____--99-	Parse
    +	>RTM                      1     ;*  < 	Check
    +
    + +
    +

    ELV DCF7000

    +

    + ELV DCF7000: end='\r', pattern=" - - - - - - - \r" +

    + The ELV DCF7000 is a cheap DCF77 receiver sending each second + a time code (though not very precise!) delimited by '`r' +

    +	Timecode
    +	  YY-MM-DD-HH-MM-SS-FF\r
    +
    +		FF&0x1	- DST
    +		FF&0x2	- DST switch warning
    +		FF&0x4  - unsynchronised
    +
    +
    +

    HOPF 6021 und Kompatible

    + +

    + HOPF Funkuhr 6021 mit serieller Schnittstelle + Created by F.Schnekenbuehl <frank@comsys.dofn.de> from clk_rcc8000.c + Nortel DASA Network Systems GmbH, Department: ND250 + A Joint venture of Daimler-Benz Aerospace and Nortel. + +

    + hopf Funkuhr 6021 
    +      used with 9600,8N1,
    +      UTC via serial line
    +      "Sekundenvorlauf" ON
    +      ETX zum Sekundenvorlauf ON
    +      dataformat 6021
    +      output time and date
    +      transmit with control characters
    +      transmit evry second
    + 
    +  Type 6021 Serial Output format
    +
    +      000000000011111111 / char
    +      012345678901234567 \ position
    +      sABHHMMSSDDMMYYnre  Actual
    +       C4110046231195     Parse
    +      s              enr  Check
    +
    +  s = STX (0x02), e = ETX (0x03)
    +  n = NL  (0x0A), r = CR  (0x0D)
    +
    +  A B - Status and weekday
    + 
    +  A - Status
    +
    +      8 4 2 1
    +      x x x 0  - no announcement
    +      x x x 1  - Summertime - wintertime - summertime announcement
    +      x x 0 x  - Wintertime
    +      x x 1 x  - Summertime
    +      0 0 x x  - Time/Date invalid
    +      0 1 x x  - Internal clock used 
    +      1 0 x x  - Radio clock
    +      1 1 x x  - Radio clock highprecision
    +
    +  B - 8 4 2 1
    +      0 x x x  - MESZ/MEZ
    +      1 x x x  - UTC
    +      x 0 0 1  - Monday
    +      x 0 1 0  - Tuesday
    +      x 0 1 1  - Wednesday
    +      x 1 0 0  - Thursday
    +      x 1 0 1  - Friday
    +      x 1 1 0  - Saturday
    +      x 1 1 1  - Sunday
    +
    +
    +

    Diem Computime Clock

    + +

    + The Computime receiver sends a datagram in the following format every minute +

       
    +   Timestamp	T:YY:MM:MD:WD:HH:MM:SSCRLF 
    +   Pos          0123456789012345678901 2 3
    +		0000000000111111111122 2 2
    +   Parse        T:  :  :  :  :  :  :  \r\n
    +   
    +   T	Startcharacter "T" specifies start of the timestamp 
    +   YY	Year MM	Month 1-12 
    +   MD	Day of the month 
    +   WD	Day of week 
    +   HH	Hour 
    +   MM   Minute 
    +   SS   Second
    +   CR   Carriage return 
    +   LF   Linefeed
    +
    +
    +

    WHARTON 400A Series Clock with a 404.2 Serial interface

    + +

    + The WHARTON 400A Series clock is able to send date/time serial messages + in 7 output formats. We use format 1 here because it is the shortest. + We set up the clock to send a datagram every second. + For use with this driver, the WHARTON 400A Series clock must be set-up + as follows : +

    +  					Programmable	Selected
    +  					Option No	Option
    +	BST or CET display		3		9 or 11
    +	No external controller		7		0
    +	Serial Output Format 1		9		1
    +	Baud rate 9600 bps		10		96
    +	Bit length 8 bits		11		8
    +	Parity even			12		E
    +
    + WHARTON 400A Series output format 1 is as follows : +
    +   Timestamp	STXssmmhhDDMMYYSETX
    +   Pos		0  12345678901234
    +  		0  00000000011111
    +  
    +   STX	start transmission (ASCII 0x02)
    +   ETX	end transmission (ASCII 0x03)
    +   ss	Second expressed in reversed decimal (units then tens)
    +   mm	Minute expressed in reversed decimal
    +   hh	Hour expressed in reversed decimal
    +   DD	Day of month expressed in reversed decimal
    +   MM	Month expressed in reversed decimal (January is 1)
    +   YY	Year (without century) expressed in reversed decimal
    +   S	Status byte : 0x30 +
    +		bit 0	0 = MSF source		1 = DCF source
    +		bit 1	0 = Winter time		1 = Summer time
    +		bit 2	0 = not synchronised	1 = synchronised
    +		bit 3	0 = no early warning	1 = early warning
    +
    diff --git a/contrib/ntp/html/parsenew.htm b/contrib/ntp/html/parsenew.htm new file mode 100644 index 000000000000..0ef60bc06002 --- /dev/null +++ b/contrib/ntp/html/parsenew.htm @@ -0,0 +1,237 @@ + +Making PARSE Clocks +

    How to build new PARSE clocks

    + +

    Here is an attempt to sketch out what you need to do in order to +add another clock to the parse driver: +Currently the implementation is being cleaned up - so not all information +in here is completely correct. Refer to the included code where in doubt. + + +

    Prerequisites: +

      +
    • Does the system you want the clock connect to have the include files +termio.h or termios.h ? (You need that for the parse driver) +
    + + +

    What to do: + + +

    Make a conversion module (libparse/clk_*.c) + +

      +
    1. What ist the time code format ? +
        +
      • find year, month, day, hour, minute, second, status (synchronised or +not), possibly time zone information (you need to give the offset to UTC) +You will have to convert the data from a string into a struct clocktime: +
        +      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 */
        +	time_t utcoffset;     /* true utc time instead of date/time */
        +	long flags;           /* current clock status */
        +      };
        +
        + +

        Conversion is usually simple and straight forward. For the flags following +values can be OR'ed together: +

        +     PARSEB_ANNOUNCE           switch time zone warning (informational only)
        +     PARSEB_POWERUP            no synchronisation - clock confused (must set then)
        +     PARSEB_NOSYNC             timecode currently not confirmed (must set then)
        +                               usually on reception error when there is still a
        +                               chance the the generated time is still ok.
        +
        +     PARSEB_DST                DST in effect (informational only)
        +     PARSEB_UTC                timecode contains UTC time (informational only)
        +     PARSEB_LEAPADD            LEAP addition warning (prior to leap happening - must set when imminent)
        +			       also used for time code that do not encode the
        +			       direction (as this is currently the default).
        +     PARSEB_LEAPDEL            LEAP deletion warning (prior to leap happening - must set when imminent)
        +     PARSEB_ALTERNATE          backup transmitter (informational only)
        +     PARSEB_POSITION           geographic position available (informational only)
        +     PARSEB_LEAPSECOND         actual leap second (this time code is the leap
        +                               second - informational only)
        +
        + +

        These are feature flags denoting items that are supported by the clock: +

        +     PARSEB_S_LEAP             supports LEAP - might set PARSEB_LEAP
        +     PARSEB_S_ANTENNA          supports ANTENNA - might set PARSEB_ALTERNATE
        +     PARSEB_S_PPS              supports PPS time stamping
        +     PARSEB_S_POSITION         supports position information (GPS)
        +   
        + +

        If the utctime field is non zero this value will be take as + time code value. This allows for conversion routines that + already have the utc time value. The utctime field gives the seconds + since Jan 1st 1970, 0:00:00. The useconds field gives the respective + usec value. The fields for date and time (down to second resolution) + will be ignored. + + +

        Conversion is done in the cvt_* routine in parse/clk_*.c files. look in + them for examples. The basic structure is: + +

        +     struct clockformat <yourclock>_format = {
        +       lots of fields for you to fill out (see below)
        +     };
        +
        +     static cvt_<yourclock>()
        +       ...
        +     {
        +       if (<I do not recognize my time code>) {
        +         return CVT_NONE;
        +       } else {
        +         if (<conversion into clockformat is ok>) {
        +           <set all necessary flags>;
        +           return CVT_OK;
        +         } else {
        +           return CVT_FAIL|CVT_BADFMT;
        +         }
        +       }
        +
        + + +

        The struct clockformat is the interface to the rest of the parse + driver - it holds all information necessary for finding the + clock message and doing the appropriate time stamping. + +

        +struct clockformat
        +{
        +  u_long (*input)();
        +  /* input routine - your routine - cvt_<yourclock> */
        +  u_long (*convert)();
        +  /* conversion routine - your routine - cvt_<yourclock> */
        +  /* routine for handling RS232 sync events (time stamps) - usually sync_simple */
        +  u_long (*syncpps)(); 
        +  /* PPS input routine - usually pps_one */
        +  void           *data;
        +  /* local parameters - any parameters/data/configuration info your conversion
        +     routine might need */
        +  char           *name;
        +  /* clock format name - Name of the time code */
        +  unsigned short  length;
        +  /* maximum length of data packet for your clock format */
        +  u_long   flags;
        + /* information for the parser what to look for */
        +};
        +
        + + +

        The above should have given you some hints on how to build a clk_*.c + file with the time code conversion. See the examples and pick a clock + closest to yours and tweak the code to match your clock. + + +

        In order to make your clk_*.c file usable a reference to the clockformat + structure must be put into parse_conf.c. +

      +
    2. TTY setup and initialisation/configuration will be done in +ntpd/refclock_parse.c. +
        +
      • Find out the exact tty settings for your clock (baud rate, parity, +stop bits, character size, ...) and note them in terms of +termio*.h c_cflag macros. +
      • in ntpd/refclock_parse.c fill out a new the struct clockinfo element +(that allocates a new "IP" address - see comments) +(see all the other clocks for example) +
        +   struct clockinfo
        +     {
        +      u_long  cl_flags;             /* operation flags (io modes) */
        +	 PARSE_F_PPSPPS       use loopfilter PPS code (CIOGETEV)
        +	 PARSE_F_PPSONSECOND  PPS pulses are on second
        +	 usually flags stay 0 as they are used only for special setups
        +
        +    void  (*cl_poll)();           /* active poll routine */
        +         The routine to call when the clock needs data sent to it in order to
        +         get a time code from the clock (e.g. Trimble clock)
        +
        +    int   (*cl_init)();           /* active poll init routine */
        +         The routine to call for very special initializations.
        +
        +    void  (*cl_event)();          /* special event handling (e.g. reset clock) */
        +         What to do, when an event happens - used to re-initialize clocks on timeout.
        +
        +    void  (*cl_end)();            /* active poll end routine */
        +         The routine to call to undo any special initialisation (free memory/timers)
        +
        +    void   *cl_data;              /* local data area for "poll" mechanism */
        +         local data for polling routines
        +
        +    u_fp    cl_rootdelay;         /* rootdelay */
        +         NTP rootdelay estimate (usually 0)
        +
        +	     u_long  cl_basedelay;         /* current offset - unsigned l_fp
        +                                              fractional part (fraction) by
        +                                              which the RS232 time code is
        +                                              delayed from the actual time. */
        +
        +    u_long  cl_ppsdelay;          /* current PPS offset - unsigned l_fp fractional
        +         time (fraction) by which the PPS time stamp is delayed (usually 0)
        +   part */
        +
        +    char   *cl_id;                /* ID code (usually "DCF") */
        +         Refclock id - (max 4 chars)
        +
        +    char   *cl_description;       /* device name */
        +         Name of this device.
        +
        +    char   *cl_format;            /* fixed format */
        +         If the data format cann not ne detected automatically this is the name
        +	 as in clk_*.c clockformat.
        +
        +    u_char  cl_type;              /* clock type (ntp control) */
        +         Type if clock as in clock status word (ntp control messages) - usually 0
        +	 
        +    u_long  cl_maxunsync;         /* time to trust oscillator after loosing synch
        +  */
        +         seconds a clock can be trusted after loosing synchronisation.
        +
        +    u_long  cl_speed;             /* terminal input & output baudrate */
        +    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 */
        +         termio*.h tty modes.
        +
        +    u_long  cl_samples;           /* samples for median filter */
        +    u_long  cl_keep;              /* samples for median filter to keep */
        +         median filter parameters - smoothing and rejection of bad samples
        +  } clockinfo[] = {
        +  ...,<other clocks>,...
        +  { < your parameters> },
        +  };
        +
        +
        +
      +
    + +

    Well, this is very sketchy, i know. But I hope it helps a little bit. +The best way is to look which clock comes closest to your and tweak that +code. + +

    Two sorts of clocks are used with parse. Clocks that automatically send +their time code (once a second) do not need entries in the poll routines because +they send the data all the time. The second sort are the clocks that need a +command sent to them in order to reply with a time code (like the Trimble +clock). + +

    For questions: kardel@acm.org. + +

    Please include an exact description on how your clock works. (initialisation, +TTY modes, strings to be sent to it, responses received from the clock). +


    +Frank Kardel diff --git a/contrib/ntp/html/patches.htm b/contrib/ntp/html/patches.htm new file mode 100644 index 000000000000..154d4b8a53c5 --- /dev/null +++ b/contrib/ntp/html/patches.htm @@ -0,0 +1,70 @@ + +Patching Procedures +

    +Patching Procedures +

    + +From pogo, Walt Kelly +

    + +

    A distribution so widely used as this one eventually develops +numerous barnacles as the result of porting +to new systems, idiosyncratic new features and just plain bugs. In order +to help keep order and make maintenance bearable, we ask that proposed +changes to the distribution be submitted in the following form. + +

      + +

    1. Please submit patches to David L. +Mills <mills@udel.edu> in the form of either unified-diffs +(diff -u) or context-diffs (diff -c).
    2. + +

    3. Please include the output from +config.guess in the description of your patch. If +config.guess does not produce any output for your machine, +please fix that, too!
    4. + +

    5. Please base the patch on the root directory of the distribution. +The preferred procedure here is to copy your patch to the root directory +and mumble
    6. + +

      patch -p <your_patch> + +

    7. Please avoid patching the RCS subdirectories; better yet, clean +them out before submitting patches.
    8. + +

    9. If you have whole new files, as well as patches, wrap the files +and patches in a shell script. If you need to compress it, use either +GNU zip or the stock Unix compress utility.
    10. + +

    11. Don't forget the documentation that may be affected by the patch. +Send us patches for the ./html files as well. See the A Beginner's Guide to HTML page for a +tutorial.
    12. + +

    13. We would be glad to include your name, electric address and +descriptive phrase in the Copyright page, +if you wish.
    14. + +
    + +

    Prior to ntp3-5.83 (releases up to and including ntp3.5f) a +complete patch history back to the dark ages was kept in the +./patches directory, which might have been helpful to see +if the same problem occured in another port, etc. Patches were saved in +that directory with file name in the form patch.nnn, +where nnn was approaching 200. All patches in that directory have +been made; so, if yours was there, it was in the distribution. + +

    Since we have been getting multple patches for some bugs, plus many +changes are implemented locally, no two maintainers here use the same +tools, and since we're not using any bug-tracking software or even +source code control, there is currently no tracking of specific changes. + +

    The best way to see what's changed between two distributions is to +run a diff against them. +

    Thanks for your contribution and happy chime. + +


    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/porting.htm b/contrib/ntp/html/porting.htm new file mode 100644 index 000000000000..d541d4e1da88 --- /dev/null +++ b/contrib/ntp/html/porting.htm @@ -0,0 +1,78 @@ + +Porting Hints +

    +Porting Hints +


    + +

    NOTE: The following procedures have been replaced by GNU automake and +autoconfigure. This page is to be updated in the next release. + +

    Porting to a new machine or operating system ordinarily requires +updating the ./machines directory and the +./compilers directories in order to define the build +environment and autoconfigure means. You will probably have to modify +the ntp_machines.h file and "l_stdlib.h" files +as well. The two most famous trouble spots are the I/O code in +./ntpd/ntp_io.c and the clock adjustment code in +./ntpd/ntp_unixclock.c. + +

    These are the rules so that older bsd systems and the POSIX standard +system can coexist together. + +

      + +
    1. If you use select then include +"ntp_select.h". select is not standard, since +it is very system dependent as to where it is defined. The logic to +include the right system dependent include file is in +"ntp_select.h". + +

    2. Always use POSIX definition of strings. Include +"ntp_string.h" instead 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. 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. + +

    8. 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. + +

    9. 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 separate section for each +system. Really this will make it easier to maintain. + +

    See include/ntp_machines.h for the various compile time +options. + +

    When you are satisfied the port works and that other ports are not +adversely affected, please send patches for +the system files you have changed, as well as any documentation that +should be updated, including the advice herein. + +

    Good luck. + +


    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/pps.htm b/contrib/ntp/html/pps.htm new file mode 100644 index 000000000000..a002c1f048c1 --- /dev/null +++ b/contrib/ntp/html/pps.htm @@ -0,0 +1,83 @@ + +Pulse-per-second (PPS) Signal Interfacing +

    +Pulse-per-second (PPS) Signal Interfacing +


    + +

    Some radio clocks and related timekeeping gear have a pulse-per- +second (PPS) signal that can be used to discipline the local clock +oscillator to a high degree of precision, typically to the order less +than 20 ms in time and 0.01 PPM in frequency. +The PPS signal can be connected in either of two ways: via the data +leads of a serial port or via the modem control leads. Either way +requires conversion of the PPS signal, usually at TTL levels, to RS232 +levels, which can be done using a circuit such as described in the Gadget Box PPS Level Converter and CHU Modem page. + +

    The data leads interface requires regenerating the PPS pulse and +converting to RS232 signal levels, so that the pulse looks like a +legitimate ASCII character to a serial port. The tty_clk line +discipline/streams module inserts a timestamp following this character +in the input data stream. The PPS Clock +Discipline driver uses this timestamp to determine the time of +arrival of the PPS pulse to within 26 us at 38.4 kbps while eliminating +error due to operating system queues and service times. + +

    The modem control leads interface requires converting to RS232 levels +and connecting to the data carrier detect (DCD) lead of a serial port. +The ppsclock and ppsapi streams modules capture a +timestamp upon transition of the DCD signal. Note that the +ppsclock module functionality has been subsumed by the new +ppsapi interface specification, which is supported by the NTP +daemon. As the latter is expected to become an IETF cross-platform +standard, it should be used in new configurations. The PPS Clock +Discipline driver reads the latest timestamp with a designated system +call or interface routine to determine the time of arrival of the PPS +pulse to within a few microseconds. Alternatively, if provisions have +been made in the kernel for PPS signals, the signal is captured directly +by the kernel serial driver without using the PPS driver. + +

    The tty_clk module is included in the NTP software +distribution, while the +ppsclock module can be obtained via the web at that link or by +anonymous FTP from ftp.udel.edu in the pub/ntp directory. Both +the tty_clk and ppsclock modules are described in the +Line Disciplines and Streams Drivers page. +Directions for building the modules themselves are in the +./kernel directory. Directions on how to configure +ntpd to operate with these modules is described in Building and Installing the Distribution page. + +

    The PPS driver is operates in conjunction with another reference +clock driver that produces the PPS pulse, as described in the Mitigation Rules and the prefer Keyword +page. One of the drivers described in the Reference Clock Drivers page furnishes +the coarse timecode used to disambiguate the seconds numbering of the +PPS pulse itself. The NTP daemon mitigates between the radio clock +driver and PPS driver as described in that page in order to +provide the most accurate time, while respecting the various types of +equipment failures that could happen. + +

    For the utmost time quality, some Unix system kernels support a PPS +signal directly, as described in the A Kernel Model +for Precision Timekeeping page. Specifically, the ppsclock module +can be used to interface the PPS signal directly to the kernel for use +as discipline sources for both time and frequency. These sources can be +separately enabled and monitored using the ntp_adjtime() system +call described in that page and the /usr/include/sys/timex.h +header file. The presence of these kernel provisions is automatically +detected and supporting code compiled. + +

    In some configurations may have multiple radio clocks, each with PPS +outputs, as well as a kernel provisions for the PPS signal. In order to +provide the highest degree of redundancy and survivability, the kernel +PPS discipline, tty_clk module, ppsclock module and +kernel modifications may all be in use at the same time, each backing up +the other. The sometimes complicated mitigation rules are described in +the Mitigation Rules and the prefer Keyword page. + +


    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/prefer.htm b/contrib/ntp/html/prefer.htm new file mode 100644 index 000000000000..edb51520dcbc --- /dev/null +++ b/contrib/ntp/html/prefer.htm @@ -0,0 +1,332 @@ + + + + + Mitigation Rules and the ``prefer'' Keyword + + + + +

    +Mitigation Rules and the prefer Keyword

    + +
    +

    +Introduction

    +The mechanics of the NTP algorithms which select the best data sample from +each available peer and the best subset of the peer population have been +finely crafted to resist network jitter, faults in the network or peer +operations, and to deliver the best possible accuracy. Most of the time +these algorithms do a good job without requiring explicit manual tailoring +of the configuration file. However, there are times when the accuracy can +be improved by some careful tailoring. The following sections explain how +to do this using explicit configuration items and special signals, when +available, that are generated by some radio clocks. + +

    In order to provide robust backup sources, primary (stratum-1) servers +are usually operated in a diversity configuration, in which the server +operates with a number of remote peers in addition to one or more radio +or modem clocks operating as local peers. In these configurations the suite +of algorithms used in NTP to refine the data from each peer separately +and to select and weight the data from a number of peers are used with +the entire ensemble of remote peers and local peers. As the result of these +algorithms, a set of survivors are identified which can presumably +provide the most reliable and accurate time. Ordinarily, the individual +clock offsets of the survivors are combined on a weighted average basis +to produce an offset used to control the system clock. + +

    However, because of small but significant systematic time offsets between +the survivors, it is in general not possible to achieve the lowest jitter +and highest stability in these configurations. This happens because the +selection algorithm tends to clockhop between survivors of substantially +the same quality, but showing small systematic offsets between them. In +addition, there are a number of configurations involving pulse-per-second +(PPS) signals, modem backup services and other special cases, so that a +set of mitigation rules becomes necessary to select a single peer from +among the survivors. These rules are based on a set of special characteristics +of the various peers and reference clock drivers specified in the configuration +file. +

    +The prefer Peer

    +The mitigation rules are designed to provide an intelligent selection between +various peers of substantially the same statistical quality. They is designed +to provide the best quality time without compromising the normal operation +of the NTP algorithms. The mitigation scheme in its present form is not +an integral component of the NTP Version 3 specification RFC- 1305. but +is to be included in the version 4 specification when it is published. +The scheme is based on the concept of prefer peer, which is specified +by including the prefer keyword with the associated server +or peer command in the configuration file. This keyword can be +used with any peer or server, but is most commonly used with a radio clock. +While the scheme does not forbid it, it does not seem useful to designate +more than one peer as preferred, since the additional complexities to mitigate +among them do not seem justified from on-air experience. + +

    The prefer scheme works on the set of peers that have survived the sanity +checks and intersection algorithms of the clock selection procedures. Ordinarily, +the members of this set can be considered truechimers and any one +of them could in principle provide correct time; however, due to various +error contributions, not all can provide the most accurate and stable time. +The job of the clustering algorithm, which is invoked at this point, is +to select the best subset of the survivors providing the least variance +in the combined ensemble average, compared to the variance in each member +of the subset separately. The detailed operation of the clustering algorithm, +which is given in the specification, is not important here, other than +to point out it operates in rounds, where a survivor, presumably the worst +of the lot, is discarded in each round until one of several termination +conditions is met. + +

    In the prefer scheme the clustering algorithm is modified so that the +prefer peer is never discarded; on the contrary, its potential removal +becomes a termination condition. If the original algorithm were about to +toss out the prefer peer, the algorithm terminates right there. The prefer +peer can still be discarded by the sanity checks and intersection algorithms, +of course, but it will always survive the clustering algorithm. If it does +not survive or for some reason it fails to provide updates, it will eventually +become unreachable and the clock selection will remitigate to select the +next best source. + +

    Along with this behavior, the clock selection procedures are modified +so that the combining algorithm is not used when a prefer peer is present. +Instead, the offset of the prefer peer is used exclusively as the synchronization +source. In the usual case involving a radio clock and a flock of remote +stratum-1 peers, and with the radio clock designated a prefer peer, the +result is that the high quality radio time disciplines the server clock +as long as the radio itself remains operational and with valid time, as +determined from the remote peers, sanity checks and intersection algorithm. +

    +Peer Classification

    +In order to understand the effects of the various intricate schemes involved, +it is necessary to understand some arcane details on how the algorithms +decide on a synchronization source, when more than one source is available. +This is done on the basis of a set of explicit mitigation rules, which +define special classes of remote and local peers as a function of configuration +declarations and reference clock driver type: +
      +
    1. +The prefer peer is designated using the prefer keyword with the +server or peer commands. All other things being equal, +this peer will be selected for synchronization over all other survivors +of the clock selection procedures.
    2. + +
        +
    3. +When a PPS signal is connected via the PPS Clock Discipline driver (type +22), this is called the PPS peer. This driver provides precision +clock corrections only within one second, so is always operated in conjunction +with another peer or reference clock driver, which provides the seconds +numbering. The PPS peer is active only under conditions explained below.
    4. + +
        +
    5. +When the Undisciplined Local Clock driver (type 1) is configured, this +is called the local clock peer. This is used either as a backup +reference source (stratum greater than zero), should all other synchronization +sources fail, or as the primary reference source (stratum zero) in cases +where the kernel time is disciplined by some other means of synchronization, +such as the NIST lockclock scheme, or another synchronization +protocol, such as the Digital Time Synchronization Service (DTSS).
    6. + +
        +
    7. +When a modem driver such as the Automated Computer Time Service driver +(type 18) is configured, this is called the modem peer. This is +used either as a backup reference source, should all other primary sources +fail, or as the (only) primary reference source.
    8. + +
        +
    9. +Where support is available, the PPS signal may be processed directly by +the kernel, as described in the A Kernel Model for Precision +Timekeeping page. This is called the kernel discipline. The +PPS signal can discipline the kernel in both frequency and time. The frequency +discipline is active as long as the PPS interface device and signal itself +is operating correctly, as determined by the kernel algorithms. The time +discipline is active only under conditions explained below.
    10. +
    +Reference clock drivers operate in the manner described in the Reference +Clock Drivers page and its dependencies. The drivers are ordinarily +operated at stratum zero, so that as the result of ordinary NTP operations, +the server itself operates at stratum one, as required by the NTP specification. +In some cases described below, the driver is intentionally operated at +an elevated stratum, so that it will be selected only if no other survivor +is present with a lower stratum. In the case of the PPS peer or kernel +time discipline, these sources appear active only if the prefer peer has +survived the intersection and clustering algorithms, as described below, +and its clock offset relative to the current local clock is less than a +specified value, currently 128 ms. + +

    The modem clock drivers are a special case. Ordinarily, the update interval +between modem calls to synchronize the system clock is many times longer +than the interval between polls of either the remote or local peers. In +order to provide the best stability, the operation of the clock discipline +algorithm changes gradually from a phase-lock mode at the shorter update +intervals to a frequency-lock mode at the longer update intervals. If both +remote or local peers together with a modem peer are operated in the same +configuration, what can happen is that first the clock selection algorithm +can select one or more remote/local peers and the clock discipline algorithm +will optimize for the shorter update intervals. Then, the selection algorithm +can select the modem peer, which requires a much different optimization. +The intent in the design is to allow the modem peer to control the system +clock either when no other source is available or, if the modem peer happens +to be marked as prefer, then it always controls the clock, as long as it +passes the sanity checks and intersection algorithm. There still is room +for suboptimal operation in this scheme, since a noise spike can still +cause a clockhop either way. Nevertheless, the optimization function is +slow to adapt, so that a clockhop or two does not cause much harm. + +

    The local clock driver is another special case. Normally, this driver +is eligible for selection only if no other source is available. When selected, +vernier adjustments introduced via the configuration file or remotely using +the ntpdc program can be used to trim +the local clock frequency and time. However, if the local clock driver +is designated the prefer peer, this driver is always selected and all other +sources are ignored. This behavior is intended for use when the kernel +time is controlled by some means external to NTP, such as the NIST lockclock +algorithm or  another time synchronization protocol such as DTSS. +In this case the only way to disable the local clock driver is to mark +it unsynchronized using the leap indicator bits. In the case of modified +kernels with the ntp_adjtime() system call, this can be done automatically +if the external synchronization protocol uses it to discipline the kernel +time. +

    +Mitigation Rules

    +The mitigation rules apply in the intersection and clustering algorithms +described in the NTP specification. The intersection algorithm first scans +all peers with a persistent association and includes only those that satisfy +specified sanity checks. In addition to the checks required by the specification, +the mitigation rules require either the local-clock peer or modem peer +to be included only if marked as the prefer peer. The intersection algorithm +operates on the included population to select only those peers believed +to represent the correct time. If one or more peers survive the operation, +processing continues in the clustering algorithm. Otherwise, if there is +a modem peer, it is declared the only survivor; otherwise, if there is +a local-clock peer, it is declared the only survivor. Processing then continues +in the clustering algorithm. + +

    The clustering algorithm repeatedly discards outlyers in order to reduce +the residual jitter in the survivor population. As required by the NTP +specification, these operations continue until either a specified minimum +number of survivors remain or the minimum select dispersion of the population +is greater than the maximum peer dispersion of any member. The mitigation +rules require an additional terminating condition which stops these operations +at the point where the prefer peer is about to be discarded. + +

    The mitigation rules establish the choice of system peer, which +determine the stratum, reference identifier and several other system variables +which are visible to clients of the local server. In addition, they establish +which source or combination of sources control the local clock. +

      +
    1. +If there is a prefer peer and it is the local-clock peer or the modem peer; +or, if there is a prefer peer and the kernel time discipline is active, +choose the prefer peer as the system peer and its offset as the system +clock offset. If the prefer peer is the local-clock peer, an offset can +be calculated by the driver to produce a frequency offset in order to correct +for systematic frequency errors. In case a source other than NTP is controlling +the system clock, corrections determined by NTP can be ignored by using +the disable pll in the configuration file. If the prefer peer +is the modem peer, it must be the primary source for the reasons noted +above. If the kernel time discipline is active, the system clock offset +is ignored and the corrections handled directly by the kernel.
    2. + +
    3. +If the above is not the case and there is a PPS peer, then choose it as +the system peer and its offset as the system clock offset.
    4. + +
    5. +If the above is not the case and there is a prefer peer (not the local-clock +or modem peer in this case), then choose it as the system peer and its +offset as the system clock offset.
    6. + +
    7. +If the above is not the case and the peer previously chosen as the system +peer is in the surviving population, then choose it as the system peer +and average its offset along with the other survivors to determine the +system clock offset. This behavior is designed to avoid excess jitter due +to clockhopping, when switching the system peer would not materially improve +the time accuracy.
    8. + +
    9. +If the above is not the case, then choose the first candidate in the list +of survivors ranked in order of synchronization distance and average its +offset along with the other survivors to determine the system clock offset. +This is the default case and the only case considered in the current NTP +specification.
    10. +
    + +

    +Using the Pulse-per-Second (PPS) Signal

    +Most radio clocks are connected using a serial port operating at speeds +of 9600 bps or higher. The accuracy using typical timecode formats, where +the on-time epoch is indicated by a designated ASCII character, like carriage-return +<cr>, is limited to a millisecond at best and a few milliseconds +in typical cases. However, some radios produce a PPS signal which can be +used to improve the accuracy with typical workstation servers to the order +of a few tens of microseconds. The details of how this can be accomplished +are discussed in the Pulse-per-second (PPS) Signal Interfacing +page. The following paragraphs discuss how the PPS signal is affected by +the mitigation rules. + +

    First, it should be pointed out that the PPS signal is inherently ambiguous, +in that it provides a precise seconds epoch, but does not provide a way +to number the seconds. In principle and most commonly, another source of +synchronization, either the timecode from an associated radio clock, or +even one or more remote NTP servers, is available to perform that function. +In all cases, a specific, configured peer or server must be designated +as associated with the PPS signal. This is done using the prefer +keyword as described previously. The PPS signal can be associated in this +way with any peer, but is most commonly used with the radio clock generating +the PPS signal. + +

    The PPS signal can be used in two ways to discipline the local clock, +one using a special PPS driver described in the PPS +Clock Discipline page, the other using PPS signal support in the kernel, +as described in the A Kernel Model for Precision Timekeeping +page. In either case, the signal must be present and within nominal jitter +and wander error tolerances. In addition, the associated prefer peer must +have survived the sanity checks and intersection algorithms and the dispersion +settled below 1 s. This insures that the radio clock hardware is operating +correctly and that, presumably, the PPS signal is operating correctly as +well. Second, the absolute offset of the local clock from that peer must +be less than 128 ms, or well within the 0.5-s unambiguous range of the +PPS signal itself. In the case of the PPS driver, the time offsets generated +from the PPS signal are propagated via the clock filter to the clock selection +procedures just like any other peer. Should these pass the sanity checks +and intersection algorithms, they will show up along with the offsets of +the prefer peer itself. Note that, unlike the prefer peer, the PPS peer +samples are not protected from discard by the clustering algorithm. These +complicated procedures insure that the PPS offsets developed in this way +are the most accurate, reliable available for synchronization. + +

    The PPS peer remains active as long as it survives the intersection +algorithm and the prefer peer is reachable; however, like any other clock +driver, it runs a reachability algorithm on the PPS signal itself. If for +some reason the signal fails or displays gross errors, the PPS peer will +either become unreachable or stray out of the survivor population. In this +case the clock selection remitigates as described above. + +

    When kernel support for the PPS signal is available, the PPS signal +is interfaced to the kernel serial driver code via a modem control lead. +As the PPS signal is derived from external equipment, cables, etc., which +sometimes fail, a good deal of error checking is done in the kernel to +detect signal failure and excessive noise. The way in which the mitigation +rules affect the kernel discipline is as follows. + +

    In order to operate, the kernel support must be enabled by the enable +pll command in the configuration file and the signal must be present +and within nominal jitter and wander error tolerances. In the NTP daemon, +the PPS discipline is active only when the prefer peer is among the survivors +of the clustering algorithm, and its absolute offset is within 128 ms, +as in the PPS driver. Under these conditions the kernel disregards updates +produced by the NTP daemon and uses its internal PPS source instead. The +kernel maintains a watchdog timer for the PPS signal; if the signal has +not been heard or is out of tolerance for more than some interval, currently +two minutes, the kernel discipline is declared inoperable and operation +continues as if it were not present.  +


    +
    +David L. Mills (mills@udel.edu)
    + + + diff --git a/contrib/ntp/html/quick.htm b/contrib/ntp/html/quick.htm new file mode 100644 index 000000000000..5ce009924aca --- /dev/null +++ b/contrib/ntp/html/quick.htm @@ -0,0 +1,99 @@ + +Quick Start +

    +Quick Start +

    + +FAX test image for SATNET (1979). + +

    The baby panda was scanned at University College London and used +as a FAX test image for a demonstration of the DARPA Atlantic +SATNET Program and the first transatlantic Internet connection in 1978. +The computing system used for that demonstration was called the Fuzzball +. As it happened, this was also the first Internet multimedia +presentation and the first to use NTP in regular operation. The image +was widely copied and used for testing purpose throughout much of the +1980s. +
    + +

    Introduction

    + +

    This page describes what to expect when the NTP daemon ntpd +is started for the first time. The discussion presumes the programs in +this distribution have been compiled and installed as described in the +Building and Installing the Distribution page. + +

    When the daemon is started, whether for the first or subsequent +times, a number of roundtrip samples are required to accumulate reliable +measurements of network path delay and clock offset relative to the +server. Normally, this takes about four minutes, after which the local +clock is synchronized to the server. The daemon behavior at startup +depends on whether a drift file ntp.drift exists. This file +contains the latest estimate of local clock frequency error. When the +daemon is started for the first time, it is created after about one hour +of operation and updated once each hour after that. When the daemon is +started and the file does not exist, the daemon enters a special mode +designed to quickly adapt to the particular system clock oscillator time +and frequency error. This takes approximately 15 minutes, after which +the time and frequency are set to nominal values and the daemon enters +normal mode, where the time and frequency are continuously tracked +relative to the server. + +

    As a practical matter, once the local clock has been set, it very +rarely strays more than 128 ms relative to the server, even under +extreme cases of network path congestion and jitter. Sometimes, in +particular when the daemon is first started, the relative clock offset +exceeds 128 ms. In such cases the normal behavior of the daemon is to +set the clock directly, rather than rely on gradual corrections. This +may cause the clock to be set backwards, if the local clock time is more +than 128 s in the future relative to the server. In some applications, +this behavior may be unacceptable. If the -x option is included +on the command line that starts the daemon, the clock will never be +stepped and only slew corrections will be used. + +

    The issues should be carefully explored before deciding to use the +-x option. The maximum slew rate possible is limited to 500 +parts-per-million (PPM) as a consequence of the correctness principles +on which the NTP protocol and algorithm design are based. As a result, +the local clock can take a long time to converge to an acceptable +offset, about 2000 s for each second the clock is outside the acceptable +range. During this interval the local clock will not be consistent with +any other network clock and the system cannot be used for distributed +applications that require correctly synchronized network time. + +

    There may be an occasional outlyer, where an individual measurement +exceeds 128 ms. When the frequency of occurrence of these outlyers is +low, the measurement is discarded and operation continues with the next +one. However, if the outlyers persist for an interval longer than about +15 minutes, the next value is believed and the clock stepped or slewed +as determined by the -x option. The usual reason for this +behavior is when a leap second has occurred, but the reference clock +receiver has not synchronized to it. When leap second support is +implemented in the kernel, the kernel implements it as directed by the +NTP daemon. If this happens and the reference clock source +resynchronizes correctly within 15 minutes, the transient misbehavior of +the source is transparent. + +

    It has been observed that, as the result of extreme network +congestion, the roundtrip delays can exceed three seconds and the +synchronization distance, which is equal to one-half the roundtrip delay +plus the error budget terms, can become very large. When the +synchronization distance exceeds one second, the offset measurement is +discarded. If this condition persists for several poll intervals, the +server may be declared unreachable. Sometimes the large jitter results +in large frequency errors which result in straying outside the +acceptable offset range and an eventual step or slew time correction. If +following such a correction the frequency error is so large that the +first sample is outside the acceptable range, the daemon enters the same +state as when the ntp.drift file is not present. The intent of +this behavior is to quickly correct the frequency and restore operation +to the normal tracking mode. In the most extreme cases +(time.ien.it comes to mind), there may be occasional step/slew +corrections and subsequent frequency corrections. It helps in these +cases to use burst mode when configuring the server. + +


    David L. Mills <mills@udel.edu> +
    + diff --git a/contrib/ntp/html/rdebug.htm b/contrib/ntp/html/rdebug.htm new file mode 100644 index 000000000000..472b09f67e86 --- /dev/null +++ b/contrib/ntp/html/rdebug.htm @@ -0,0 +1,67 @@ + + +Debugging Hints for Reference Clock Drivers +

    +Debugging Hints for Reference Clock Drivers +


    + +

    The ntpq and ntpdc utility programs can be used to +debug reference clocks, either on the server itself or from another +machine elsewhere in the network. The server is compiled, installed and +started using the command-line switches described in the ntpd page. The first thing to look for +are error messages on the system log. If none occur, the daemon has +started, opened the devices specified and waiting for peers and radios +to come up. + +

    The next step is to be sure the RS232 messages, if used, are getting +to and from the clock. The most reliable way to do this is with an RS232 +tester and to look for data flashes as the driver polls the clock and/or +as data arrive from the clock. Our experience is that the overwhelming +fraction of problems occurring during installation are due to problems +such as miswired connectors or improperly configured device links at +this stage. + +

    If RS232 messages are getting to and from the clock, the variables of +interest can be inspected using the ntpq program and +various commands described on the documentation page. First, use the +pe and as commands to display billboards +showing the peer configuration and association IDs for all peers, +including the radio clock peers. The assigned clock address should +appear in the pe billboard and the association ID for it at +the same relative line position in the as billboard. If +things are operating correctly, after a minute or two samples should +show up in the pe display line for the clock. + +

    Additional information is available with the rv and +clockvar commands, which take as argument the association +ID shown in the as billboard. The rv command +with no argument shows the system variables, while the rv +command with association ID argument shows the peer variables for the +clock, as well as any other peers of interest. The clockvar +command with argument shows the peer variables specific to reference +clock peers, including the clock status, device name, last received +timecode (if relevant), and various event counters. In addition, a +subset of the fudge parameters is included. + +

    The ntpdc utility program can be used for detailed +inspection of the clock driver status. The most useful are the +clockstat and clkbug commands described in the +document page. While these commands permit getting quite personal with +the particular driver involved, their use is seldom necessary, unless an +implementation bug shows up. + +

    Most drivers write a message to the clockstats file as +each timecode or surrogate is received from the radio clock. By +convention, this is the last ASCII timecode (or ASCII gloss of a binary- +coded one) received from the radio clock. This file is managed by the +filegen facility described in the ntpd page +and requires specific commands in the configuration file. This forms a +highly useful record to discover anomalies during regular operation of +the clock. The scripts included in the ./scripts/stats +directory can be run from a cron job to collect and +summarize these data on a daily or weekly basis. The summary files have +proven invaluable to detect infrequent misbehavior due to clock +implementation bugs in some radios. +


    David L. Mills (mills@udel.edu)
    diff --git a/contrib/ntp/html/refclock.htm b/contrib/ntp/html/refclock.htm new file mode 100644 index 000000000000..5747e3fea656 --- /dev/null +++ b/contrib/ntp/html/refclock.htm @@ -0,0 +1,126 @@ + +Reference Clock Drivers +

    +Reference Clock Drivers +

    + +From top: + +
      + +
    • Austron 2100A GPS Receiver with LORAN-C assist
    • +
    • Austron 2000 LORAN-C Receiver>
    • +
    • Spectracom 8170 WWVB Receiver
    • +
    • Hewlett Packard 5061A Cesium Beam Standard
    • + +
    + +
    +The Tardis +
    + +

    Reference Clock Drivers

    + +Support for most of the commonly available radio and modem clocks is +included in the default configuration of the NTP daemon for Unix +ntpd. Individual clocks can be activated by configuration file +commands, specifically the server and fudge commands +described in the ntpd program manual +page. The following discussion presents Information on how to select +and configure the device drivers in a running Unix system. + +

    Radio and modem clocks by convention have addresses in the form +127.127.t.u, where t is the clock type and u is a +unit number in the range 0-3 used to distinguish multiple instances of +clocks of the same type. Most of these clocks require support in the +form of a serial port or special bus peripheral, but some can work +directly from the audio codec found in some workstations. The particular +device is normally specified by adding a soft link +/dev/deviceu to the particular hardware device involved, +where u correspond to the unit number above. + +

    Following is a list showing the type and title of each driver +currently implemented. The compile-time identifier for each is shown in +parentheses. Click on a selected type for specific description and +configuration documentation, including the clock address, reference ID, +driver ID, device name and speed, and features (line disciplines, etc.). +For those drivers without specific documentation, please contact the +author listed in the copyright page. + +

    Type 1 Undisciplined Local Clock +(LOCAL) +
    Type 2 Trak 8820 GPS Receiver +(GPS_TRAK) +
    Type 3 PSTI/Traconex 1020 WWV/WWVH +Receiver +(WWV_PST) +
    Type 4 Spectracom 8170 and Netclock/2 WWVB +Receivers (WWVB_SPEC) +
    Type 5 TrueTime GPS/GOES/OMEGA Receivers +(TRUETIME) +
    Type 6 IRIG Audio Decoder +(IRIG_AUDIO) +
    Type 7 CHU Audio/Modem Decoder +(CHU) +
    Type 8 Generic Reference Driver +(PARSE) +
    Type 9 Magnavox MX4200 GPS Receiver +(GPS_MX4200) +
    Type 10 Austron 2200A/2201A GPS Receivers +(GPS_AS2201) +
    Type 11 Arbiter 1088A/B GPS Receiver +(GPS_ARBITER) +
    Type 12 KSI/Odetics TPRO/S IRIG Interface +(IRIG_TPRO) +
    Type 13 Leitch CSD 5300 Master Clock Controller +(ATOM_LEITCH) +
    Type 14 EES M201 MSF Receiver (MSF_EES) +
    Type 15 * TrueTime generic receivers +
    Type 16 Bancomm GPS/IRIG Receiver (GPS_BANCOMM) +
    Type 17 Datum Precision Time System (GPS_DATUM) +
    Type 18 NIST Modem Time Service +(ACTS_NIST) +
    Type 19 Heath WWV/WWVH Receiver +(WWV_HEATH) +
    Type 20 Generic NMEA GPS Receiver +(NMEA) +
    Type 21 TrueTime GPS-VME Interface (GPS_VME) +
    Type 22 PPS Clock Discipline +(PPS) +
    Type 23 PTB Modem Time Service +(ACTS_PTB) +
    Type 24 USNO Modem Time Service +(ACTS_USNO) +
    Type 25 * TrueTime generic receivers +
    Type 26 Hewlett Packard 58503A GPS +Receiver +(GPS_HP) +
    Type 27 Arcron MSF Receiver +(MSF_ARCRON) +
    Type 28 Shared memory driver +(SHM) +
    Type 29 Trimble Navigation Palisade GPS (GPS_PALISADE) +
    Type 30 Motorola UT Oncore GPS +(GPS_ONCORE) +
    Type 31 Rockwell Jupiter GPS (GPS_JUPITER) +
    Type 34 Ultralink WWVB receivers + +

    * All TrueTime receivers are now supported by one driver, type 5. +Types +15 and 25 will be retained only for a limited time and may be reassigned +in future. + +

    Additional Information + +

    Mitigation Rules and the prefer +Keyword +
    Debugging Hints for Reference Clock Drivers +
    Line Disciplines and Streams Drivers +
    Pulse-per-second (PPS) Signal Interfacing +
    How To Write a Reference Clock Driver +
    The Network Time Protocol (NTP) +Distribution   + +


    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/release.htm b/contrib/ntp/html/release.htm new file mode 100644 index 000000000000..8b29cb9f412a --- /dev/null +++ b/contrib/ntp/html/release.htm @@ -0,0 +1,199 @@ + +NTP Version 4 Release Notes +

    +NTP Version 4 Release Notes +

    + + Alice's Adventures in +Wonderland, by Lewis Carroll, illustrations by Sir John Tenniel +

    + +

    NTP Version 4 Release Notes

    + +This release of the NTP Version 4 (NTPv4) daemon for Unix incorporates +new features and refinements to the NTP Version 3 (NTPv3) algorithms. +However, it continues the tradition of retaining backwards compatibility +with older versions. The NTPv4 version has been under development for +quite a while and isn't finished yet. In fact, quite a number of NTPv4 +features have already been implemented in the current NTPv3. The primary +purpose of this release is to verify the remaining new code compiles and +runs in the various architectures, operating systems and hardware +complement that can't be verified here. Of particular interest are +Windows NT, VMS and various reference clock drivers. As always, +corrections and bugfixes are warmly received, especially in the form of +context diffs. + +

    This note summarizes the differences between this software release of +NTPv4, called ntp-4.x.x, and the previous NTPv3 version, called +xntp3-5.x.x + +

      + +

    1. Most of the extensive calculations are now done using 64-bit +floating-point format, rather than 64-bit fixed-point format. The +motivation for this is to reduce size, improve speed and avoid messy +bounds checking. Workstations of today are much faster than when the +original NTP version was designed in the early 1980s, and it is rare to +find a processor architecture that does not support it. The fixed-point +format is still used with raw timestamps, in order to retain the full +precision of about 212 picoseconds. However, the algorithms which +process raw timestamps all produce fixed-point differences before +converting to double. The differences are ordinarily quite small +so can be expressed without loss of accuracy in double format.
    2. + +

    3. The clock discipline algorithm has been redesigned to improve +accuracy, reduce the impact of network jitter and allow an increase in +poll intervals to well over one day with only moderate sacrifice in +accuracy. The NTPv4 design allows servers to increase the poll intervals +even when synchronized directly to the peer. In NTPv3 the poll interval +in such cases was clamped to the minimum, usually 64 s. For those +servers with hundreds of clients, the new design can dramatically reduce +the network load.
    4. + +

    5. A burst-mode feature is available which +results in good accuracy with intermittent connections typical of PPP +and ISDN services. When enabled, at each poll interval the server sends +eight messages over the next 30-s interval and processes them in a +batch. Outlyers due to initial dial-up delays, etc., are avoided and the +server synchronizes with its peer generally within 30 s.
    6. + +

    7. In addition to the NTPv3 authentication scheme, which uses +private-key cryptography, a new NTPv4 autokey +authentication scheme is available. Autokey uses public-key +technology and avoids the need to distribute keys by separate means. The +design is such that full accuracy is available without degradation due +to processing demands of the public-key routines. It can be used in any +of the NTP association modes, but is most useful in broadcast/multicast +modes.
    8. + +

    9. NTPv4 includes two new association modes which in most +applications can avoid per-host configuration altogether. Both of these +are based on multicast technology. They provide for automatic discovery +and configuration of servers and clients. In multicast +mode, a server sends a message at fixed intervals using specified +multicast addresses, while clients listen on these addresses. Upon +receiving the message, a client exchanges several messages with the +server in order to calibrate the multicast propagation delay between the +client and server. In manycast mode, a client +sends a message and expects one or more servers to reply. Using +engineered algorithms, the client selects an appropriate subset of +servers from the messages received and continues in ordinary +client/server operation with them. The manycast scheme can provide +somewhat better accuracy than the multicast scheme at the price of +additional network overhead.
    10. + +

    11. The reference clock driver interface is smaller, more rational +and moreaccurate. Support for pulse-per-second (PPS) signals has been +extended to all drivers as an intrinsic function. Most of the drivers in +NTPv3 have been converted to this interface, but some, including the +PARSE subinterface, have yet to be overhauled. New drivers have been +added for several GPS receivers now on the market. Drivers for the +Canadian standard time and frequency station CHU and for audio IRIG +signals have been updated and capabilites added to allow direct +connection of these signals to the Sun audio port +/dev/audio.
    12. + +

    13. In all except a very few cases, all timing intervals are +randomized, so that the tendency for NTPv3 to bunch messages, especially +with a large number of configured associations, is minimized.
    14. + +

    15. In NTPv3 a large number of weeds and useless code had grown over +the years since the original NTPv1 code was implemented almost ten years +ago. Using a powerful weedwacker, much of the shrubbery has been +removed, with effect a substantial reduction in size of almost 40 +percent.
    16. + +

    17. The entire distribution has been converted to gnu +automake, which should greatly ease the task of porting to new and +different programming environments, as well as reduce the incidence of +bugs due to improper handling of idiosyncratic kernel functions.
    18. +
    + +

    Nasty Surprises

    + +There are a few things different about this release that have changed +since the latest NTP Version 3 release. Following are a few things to +worry about: + +
      + +

    1. As required by Defense Trade Regulations (DTR), the cryptographic +routines supporting the Data Encryption Standard (DES) has been removed +from the export version of the distribtution. These routines are readily +available in most countries from RSA Laboratories. Directions for their +use are in the Building and Installing the +Distribution page.
    2. + +

    3. As the result of the above, the ./authstuff directory, +intended as a development and testing aid for porting cryptographic +routines to exotic architectures, has been removed. Developers should +note the NTP authentication routines use the interface defined in the +rsaref2.0 package available from RSA laboratories.
    4. + +

    5. The enable and disable commands have a few changes in their +arguments see the ntpd Configuration +Options page for details.
    6. + +

    7. The scheme for enabling the ppsclock line +discipline/streams module has changed. Formerly, it was enabled by +setting fudge flag3 for the serial port connected to the PPS +signal. Now, there is an explicit command pps used to designate +the device name. See the Reference Clock +Options page for details.
    8. + +

    9. While in fact not a new problem, some obscure option combinations +require the server and peer commands to follow the +others; in particular, the enable and pps commands +should preceed these commands.
    10. + +
    + +

    Caveats

    + +This release has been compiled and tested on several systems, including +SunOS 4.1.3, Solaris 2.5.1 and 2.6, Alpha 4.0, Ultrix 4.4, Linux, +FreeBSD and HP-UX 10.02. It has not been compiled for Windows NT or VMS. +We are relying on the NTP volunteer brigade to do that. Known problems +are summarized below: + +
      + +

    1. To work properly in all cases, the enable and +pps commands, if used, should appear before the server +and fudge commands in the configuration file.
    2. + +

    3. The precision time kernel modifications now in stock Solaris 2.6 +have bugs. The kernel discipline has been disabled by default. For +testing, the kernel can be enabled using the enable kernel +command either in the configuration file or via ntpdc.
    4. + +

    5. On Alpha 4.0 with reference clocks configured, debugging with the +-d options doesn't work.
    6. + +

    7. The autokey function requires an NTP header extensions field, +which is documented in an internet draft and implemented in this +release. This field holds the public-key signature and certificate; +however, the detailed format for these data have not yet been +determined. It is expected this will happen in the near future and that +implementation of the required algorithms will quickly follow using +available cryptographic algorithms.
    8. + +

    9. The manycast function still needs some work. Ideally, the +existing I/O routines would be enhanced to include the capability to +determine the source address on every multicast packet sent, so that the +autokey function could reliably construct the correct cryptosum. +Meanwhile, the utility of manycast in conjunction with autokey is +limited to clients with only a single network +interface.
    10. + +

    11. The HTML documentation has been partially updated. However, most +of the NTPv3 documentation continues to apply to NTPv4. Until the update +happens, what you see is what you get. We are always happy to accept +comments, corrections and bug reports. However, we are most thrilled +upon receipt of patches to fix the dang bugs.
    12. + +
    + +
    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/html/tickadj.htm b/contrib/ntp/html/tickadj.htm new file mode 100644 index 000000000000..7d3a863e5669 --- /dev/null +++ b/contrib/ntp/html/tickadj.htm @@ -0,0 +1,103 @@ + + + + + tickadj - set time-related kernel variables + + + + +

    +tickadj - set time-related kernel variables

    + +
    +

    +Synopsis

    +tickadj [ -Aqs ] [ -a tickadj ] [ -t tick ] +

    +Description

    +The tickadj program reads, and optionally modifies, several timekeeping-related +variables in the running kernel, via /dev/kmem. The particular +variables it is concerned with are tick, which is the number of +microseconds added to the system time during a clock interrupt, tickadj, +which sets the slew rate and resolution used by the adjtime system +call, and dosynctodr, which indicates to the kernels on some machines +whether they should internally adjust the system clock to keep it in line +with time-of-day clock or not. + +

    By default, with no arguments, tickadj reads the variables +of interest in the kernel and displays them. At the same time, it determines +an "optimal" value for the value of the tickadj variable if the +intent is to run the ntpd Network Time Protocol (NTP) daemon, +and prints this as well. Since the operation of tickadj when reading +the kernel mimics the operation of similar parts of the ntpd program +fairly closely, this can be useful when debugging problems with ntpd. + +

    Note that tickadj should be run with some caution when being +used for the first time on different types of machines. The operations +which tickadj tries to perform are not guaranteed to work on all +Unix machines and may in rare cases cause the kernel to crash. +

    +Command Line Options

    + +
    +
    +-a tickadj
    + +
    +Set the kernel variable tickadj to the value tickadj +specified.
    + +
    +-A
    + +
    +Set the kernel variable tickadj to an internally computed "optimal" +value.
    + +
    +-t tick
    + +
    +Set the kernel variable tick to the value tick +specified.
    + +
    +-s
    + +
    +Set the kernel variable dosynctodr to zero, which disables the +hardware time-of-year clock, a prerequisite for running the ntpd +daemon under SunOS4.
    + +
    +-q
    + +
    +Normally, tickadj is quite verbose about what it is doing. The +-q flag tells it to shut up about everything except errors.
    +
    + +

    +Files

    + +
    +/vmunix
    +
    +/unix
    +
    +/dev/kmem
    + +

    +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 adjtime 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 tickadj program went away.  +
    +
    +David L. Mills (mills@udel.edu)
    + + + diff --git a/contrib/ntp/html/vxworks.htm b/contrib/ntp/html/vxworks.htm new file mode 100644 index 000000000000..b6fae8069924 --- /dev/null +++ b/contrib/ntp/html/vxworks.htm @@ -0,0 +1,153 @@ + + + vxWorks Port of NTP + + + +

    VxWorks port of NTP

    + +

    Creating a port for vxWorks posed some problems. This port may help +as a starting point for similar ports to real-time OS's and other embeddable +kernels, particularly where main() is not allowed, and where the configure +scripts need to be altered.

    + +

    Configuration issues

    + +

    I decided to do as little invasive surgery as possible on the NTP code, +so I brought the vxWorks header tree in line with the standard unix tree. +The following changes were needed, as a side effect these changes will +allow for easy porting of other autoconfigure enabled code.

    + +

    Where I have 386 you will need to put in your target type. The vxWorks +tree entry point is /usr/wind. If these are the same for your system, you +should be able to cut and paste the changes.

    + +

    WARNING: Check you are not overwriting files, before entering +the following: there should be no conflict, but check first...

    + +

    export CC="cc386 -nostdlib -m486 -DCPU=I80486 -I/usr/wind/target/h" +
    +export RANLIB=ranlib386
    +export AR=ar386
    +export VX_KERNEL=/usr/wind/target/config/ims_std_bsp/vxWorks
    +cd /usr/wind/target/sys
    +ln -s ../signal.h
    +ln -s ../time.h
    +ln -s socket.h sockio.h
    +ln -s ../selectLib.h select.h
    +ln -s ../timers.h
    +touch file.h param.h resource.h utsname.h var.h ../netdb.h ../a.out.h ../termios.h +
    +echo " ******ADD #include \"sys/times.h\" to sys/time.h +"

    + +

    The configure script must be changed in the following way to get the +linking tests to work, once in the correct directory issue the following +commands:
    +sed -e 's%main.*()%vxmain()%' configure > configure.vxnew
    +mv configure.vxnew configure
    +chmod 755 configure

    +

    The new version 4 of NTP requires some maths functions so it links in the +maths library (-lm) in the ntpd Makefile.am +change the line "ntpd_LDADD = $(LDADD) -lm" by removing the "-lm".
    +You are now ready to compile

    + + +


    +The configure.in file needed to be altered +to allow for a host-target configuration to take place.

    + +
      +
    • The define SYS_VXWORKS was added to the compilation flags.
    • + +
    • Little endianess is set if the target is of type iX86.
    • + +
    • The size of char, integer, long values are all set. If Wind River ever +changes these values they will need to be updated.
    • + +
    • clock_settime() is defined to be used for setting the clock.
    • + +
    • The Linking flags have -r added to allow for relinking into the vxWorks +kernel
    • +
    + +

    Unfortunately I have had to make use of the ntp_machine.h +file to add in the checks that would have been checked at linking stage +by autoconf, a better method should be devised.

    + +
      +
    • There is now a NO_MAIN_ALLOWED define that simulates command line args, +this allows the use of the normal startup sysntax.
    • + +
    • POSIX timers have been added.
    • + +
    • Structures normally found in netdb.h have been added with, the corresponding +code is in machines.c . Where possible +the defines for these have been kept non-vxWorks specific.
    • +
    + +

    Unfortunately there are still quite a few SYS_VXWORKS type defines in +the source, but I have eliminated as many as possible. You have the choice +of using the usrtime.a library avaliable from the vxworks archives or forgoing +adjtime() and using the clock_[get|set]time().The ntp_machine.h +file clearly marks how to do this.

    + +

    Compilation issues

    + +

    You will need autoconf and automake ... available free from the gnu +archives worldwide.

    + +

    The variable arch is the target architecture (e.g. i486)

    + +

    mkdir A.vxworks (or whatever....)
    +cd A.vxworks
    +../configure --target=arch-wrs-vxworks [any other options]
    +make

    + +

    Options I normally use are the --disable-all-clocks --enable-LOCAL-CLOCK flags. +The program should proceed to compile without problem. The daemon ntpd, +ntpdate, ntptrace, ntpdc, ntpq programs and of course the libraries are +all fully ported. The other utilities are not, but they should be easy +to port.

    + +

    Running the software

    + +

    Load in the various files, call them in the normal vxWorks function +type manner. Here are some examples. Refer to the man pages for further +information.

    + +

    ld < ntpdate/ntpdate
    +ld < ntpd/ntpd
    +ld < ntptrace/ntptrace
    +ld < ntpq/ntpq
    +ld < ntpdc/ntpdc
    +ntpdate ("-b", "192.168.0.245")
    +sp(ntpd, "-c", "/export/home/casey/ntp/ntp.conf") +
    +ntpdc("-c", "monlist", "192.168.0.244") +
    +ntpq("-c", "peers", "192.168.0.244")
    +ntptrace("192.168.0.244")
    +

    + +

    Bugs and such

    + +

    Should you happen across any bugs, please let me know, or better yet +fix them and submit a patch. Remember to make you patch general for Vxworks, +not just for your particular architecture. +CCII Systems +(Pty) Ltd, my ex employers, sponsored the time to this port. +Please let me know how it goes, I would be most interested in offsets +and configurations.

    + +


    +

    + +

    Casey Crellin
    +casey@csc.co.za

    + +


    +

    + + + diff --git a/contrib/ntp/html/y2k.htm b/contrib/ntp/html/y2k.htm new file mode 100644 index 000000000000..3609ee32c97b --- /dev/null +++ b/contrib/ntp/html/y2k.htm @@ -0,0 +1,141 @@ + +Network Time Protocol Year 2000 Conformance Statement +

    +Network Time Protocol Year 2000 Conformance Statement +

    + + +from Alice's Adventures in Wonderland, by Lewis Carroll, +illustrations by Sir John Tenniel + +

    The Mad Hatter and the March Hare are discussing whether the Teapot +serial number should have two or four digits. + +


    + +

    Introduction

    + +By the year 2000, the Network Time Protocol (NTP) will have been in +use for over two decades and remain the longest running, continuously +operating application protocol in the Internet. There is some concern, +especially in government and financial institutions, that NTP might +cause Internet applications to misbehave in terrible ways on the epoch +of the next century. This document presents an analysis of the various +hazards that might result in incorrect time values upon this epoch. It +concludes that incorrect time values due to the NTP timescale, protocol +design and reference implementation are highly unlikely. However, it is +possible that external reference time sources used by NTP could +misbehave and cause NTP servers to distribute incorrect time values to +significant portions of the Internet. Note that, while this document +addresses the issues specifically with respect to Unix systems, the +issues are equally applicable to Windows and VMS systems. + +

    The NTP Timescale

    + +It will be helpful in understanding the issues raised in this document +to consider the concept of a universal timescale. The conventional civil +timescale used in most parts of the world is based on Universal +Coordinated Time (UTC sic), formerly known as Greenwich Mean Time (GMT). +UTC is based on International Atomic Time (TAI sic), which is derived +from hundreds of cesium clocks in the national standards laboratories of +many countries. Deviations of UTC from TAI are implemented in the form +of leap seconds, which occur on average every eighteen months. For +almost every computer application today, UTC represents the universal +timescale extending into the indefinite past and indefinite future. We +know of course that the UTC timescale did not exist prior to 1972, the +Gregorian calendar did not exist prior to 1582, the Julian calendar did +not exist prior to 54 BC and we cannot predict exactly when the next +leap second will occur. Nevertheless, most folks would prefer that, even +if we can't get future seconds numbering right beyond the next leap +second, at least we can get the days numbering right until the end of +reason. + +

    The universal timescale can be implemented using a binary counter of +indefinite width and with the unit seconds bit placed somewhere in the +middle. The counter is synchronized to UTC such that it runs at the same +rate and the units increment coincides with the UTC seconds tick. The +NTP timescale is constructed from 64 bits of this counter, of which 32 +bits number the seconds and 32 bits represent the fraction. With this +design, the counter runs in 136-year cycles, called eras, the latest of +which began with a counter value of zero at 0h 1 January 1900. The +design assumption is that further low order bits, if required, are +provided by local interpolation, while further high order bits, when +required, are provided by external means. The important point to be made +here is that the high order bits must ultimately be provided by +astronomers and disseminated to the population by international means. +Ultimately, should a need exist to align a particular NTP era to the +current calendar, the operating system in which NTP is embedded must +provide the necessary high order bits, most conveniently from the file +system or flash memory. + +

    The Year 2000 Era

    + +With respect to the year 2000 issue, the most important thing to observe +about the NTP timescale is that it knows nothing about days, years or +centuries, only the seconds since the beginning of the latest era, the +current one of which began on 1 January 1900. On 1 January 1970 when +Unix life began, the NTP timescale showed 2,208,988,800 and on 1 January +1972 when UTC life began, it showed 2,272,060,800. On the last second of +year 1999, the NTP timescale will show 3,155,672,599 and one second +later on the first second of the next century will show 3,155,672,600. +Other than this observation, the NTP timescale has no knowledge of or +provision for any of these eclectic seconds. + +

    The NTP timescale is almost never used directly by system or +application programs. The generic Unix kernel keeps time in seconds and +microseconds (or nanoseconds) to provide both time of day and interval +timer functions. In order to synchronize the Unix clock, NTP must +convert to and from its representation and Unix representation. Unix +kernels implement the time of day function using two 32-bit counters, +one representing the seconds since Unix life began and the other the +microseconds or nanoseconds of the second. In principle, the seconds +counter will wrap around in 136-year eras, the next of which will begin +in 2106. How the particular Unix semantics interprets the counter values +is of concern, but is beyond the scope of discussion here. + +

    While incorrect time values due to the NTP timescale and protocol +design or reference implementation upon the epoch of the next century +are highly unlikely, hazards remain due to incorrect software external +to NTP. These hazards include the Unix kernel and library routines which +convert Unix time to and from conventional civil time in seconds, +minutes, hours, days and years. Although NTP uses these routines to +format monitoring data displays, they are not used to read or set the +NTP clock. They may in fact cause problems with certain application +programs, but this is not an issue which concerns NTP correctness. + +

    While it is extremely unlikely that NTP will produce incorrect time +values upon the epoch, it is possible that some external source to which +NTP synchronizes may produce a discontinuity which could then induce a +NTP discontinuity. The NTP primary (stratum 1) time servers, which are +the ultimate time references for the entire NTP population, obtain time +from various sources, including radio and satellite receivers and +telephone modems. Not all sources provide year information and not all +of these provide time in four-digit form. In point of fact, the NTP +reference implementation does not use the year information, even if +available. Instead, the year information is provided from the file +system, which itself depends on the Unix clock. + +

    The NTP protocol specification requires the apparent NTP time derived +from external servers to be compared to the file system time before the +clock is set. If the discrepancy is over 1000 seconds, an error alarm is +raised requiring manual intervention. This makes it very unlikely that +even a clique of seriously corrupted NTP servers will result in +incorrect time values. In the case of embedded computers with no file +system, the design assumption is that the current era be established +from flash memory or a clock chip previously set by manual means. + +

    It is essential that any clock synchronization protocol, including +NTP, include provisions for multiple-server redundancy and multiple- +route diversity. Past experience has demonstrated the wisdom of this +approach, which protects clients against hardware and software faults, +as well as incorrectly operating reference sources and sometimes even +buggy software. For the most reliable service, we recommend multiple +reference sources for primary servers, including a backup radio or +satellite receiver or telephone modem. We also recommend that primary +servers run NTP with other primary servers to provide additional +redundancy and mutual backup should the reference sources themselves +fail or operate incorrectly. + +


    David L. Mills <mills@udel.edu> +
    diff --git a/contrib/ntp/include/Makefile.am b/contrib/ntp/include/Makefile.am new file mode 100644 index 000000000000..1f80c16cf4fb --- /dev/null +++ b/contrib/ntp/include/Makefile.am @@ -0,0 +1,44 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +ETAGS_ARGS = $(srcdir)/Makefile.am +#EXTRA_DIST = TAGS + +noinst_HEADERS = \ + adjtime.h \ + ascii.h \ + binio.h \ + global.h \ + gps.h \ + ieee754io.h \ + iosignal.h \ + l_stdlib.h \ + mbg_gps166.h \ + md5.h \ + mx4200.h \ + ntif.h \ + ntp.h \ + ntp_calendar.h \ + ntp_control.h \ + ntp_datum.h \ + ntp_filegen.h \ + ntp_fp.h \ + ntp_if.h \ + ntp_io.h \ + ntp_machine.h \ + ntp_malloc.h \ + ntp_proto.h \ + ntp_refclock.h \ + ntp_request.h \ + ntp_select.h \ + ntp_stdlib.h \ + ntp_string.h \ + ntp_syscall.h \ + ntp_syslog.h \ + ntp_types.h \ + ntp_unixtime.h \ + ntpd.h \ + parse.h \ + parse_conf.h \ + recvbuff.h \ + trimble.h + diff --git a/contrib/ntp/include/Makefile.in b/contrib/ntp/include/Makefile.in new file mode 100644 index 000000000000..0453bf4f00ea --- /dev/null +++ b/contrib/ntp/include/Makefile.in @@ -0,0 +1,273 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ../util/ansi2knr +ETAGS_ARGS = $(srcdir)/Makefile.am +#EXTRA_DIST = TAGS + +noinst_HEADERS = \ + adjtime.h \ + ascii.h \ + binio.h \ + global.h \ + gps.h \ + ieee754io.h \ + iosignal.h \ + l_stdlib.h \ + mbg_gps166.h \ + md5.h \ + mx4200.h \ + ntif.h \ + ntp.h \ + ntp_calendar.h \ + ntp_control.h \ + ntp_datum.h \ + ntp_filegen.h \ + ntp_fp.h \ + ntp_if.h \ + ntp_io.h \ + ntp_machine.h \ + ntp_malloc.h \ + ntp_proto.h \ + ntp_refclock.h \ + ntp_request.h \ + ntp_select.h \ + ntp_stdlib.h \ + ntp_string.h \ + ntp_syscall.h \ + ntp_syslog.h \ + ntp_types.h \ + ntp_unixtime.h \ + ntpd.h \ + parse.h \ + parse_conf.h \ + recvbuff.h \ + trimble.h + +subdir = include +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps include/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-tags clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/include/README b/contrib/ntp/include/README new file mode 100644 index 000000000000..5d818dc002f8 --- /dev/null +++ b/contrib/ntp/include/README @@ -0,0 +1,4 @@ +README file for directory ./include of the NTP Version 4 distribution + +This directory contains the include files used by most programs in this +distribution. diff --git a/contrib/ntp/include/adjtime.h b/contrib/ntp/include/adjtime.h new file mode 100644 index 000000000000..74d91eb2719d --- /dev/null +++ b/contrib/ntp/include/adjtime.h @@ -0,0 +1,63 @@ +/*************************************************************************/ +/* (c) Copyright Tai Jin, 1988. All Rights Reserved. */ +/* Hewlett-Packard Laboratories. */ +/* */ +/* Permission is hereby granted for unlimited modification, use, and */ +/* distribution. This software is made available with no warranty of */ +/* any kind, express or implied. This copyright notice must remain */ +/* intact in all versions of this software. */ +/* */ +/* The author would appreciate it if any bug fixes and enhancements were */ +/* to be sent back to him for incorporation into future versions of this */ +/* software. Please send changes to tai@iag.hp.com or ken@sdd.hp.com. */ +/*************************************************************************/ + +/* "adjtime.h,v 3.1 1993/07/06 01:04:43 jbj Exp" */ +/* adjtime.h,v + * Revision 3.1 1993/07/06 01:04:43 jbj + * NTP release 3.1 + * + * + * Revision 1.5 90/02/07 15:34:18 15:34:18 src (Source Hacker) + * CHANGED KEY !!! + * + * Revision 1.4 89/02/09 12:26:35 12:26:35 tai (Tai Jin (Guest)) + * *** empty log message *** + * + * Revision 1.4 89/02/09 12:26:35 12:26:35 tai (Tai Jin) + * added comment + * + * Revision 1.3 88/08/30 01:08:29 01:08:29 tai (Tai Jin) + * fix copyright notice again + * + * Revision 1.2 88/08/30 00:51:55 00:51:55 tai (Tai Jin) + * fix copyright notice + * + * Revision 1.1 88/04/02 14:56:54 14:56:54 tai (Tai Jin) + * Initial revision + * */ + +#include "ntp_types.h" + +#define KEY 659847L + +typedef union { + struct msgbuf msgp; + struct { + long mtype; + int code; + struct timeval tv; + } msgb; +} MsgBuf; + +#define MSGSIZE (sizeof(int) + sizeof(struct timeval)) +/* + * mtype values + */ +#define CLIENT 1L +#define SERVER 2L +/* + * code values + */ +#define DELTA1 0 +#define DELTA2 1 diff --git a/contrib/ntp/include/ascii.h b/contrib/ntp/include/ascii.h new file mode 100644 index 000000000000..c679362c1226 --- /dev/null +++ b/contrib/ntp/include/ascii.h @@ -0,0 +1,61 @@ +/* + * /src/NTP/ntp-4/include/ascii.h,v 4.1 1998/07/11 10:05:22 kardel RELEASE_19990228_A + * + * $Created: Sun Jul 20 11:42:53 1997 $ + * + * Copyright (C) 1997 by Frank Kardel + */ +#ifndef ASCII_H +#define ASCII_H + +/* + * just name the common ASCII control codes + */ +#define NUL 0 +#define SOH 1 +#define STX 2 +#define ETX 3 +#define EOT 4 +#define ENQ 5 +#define ACK 6 +#define BEL 7 +#define BS 8 +#define HT 9 +#define NL 10 +#define VT 11 +#define NP 12 +#define CR 13 +#define SO 14 +#define SI 15 +#define DLE 16 +#define DC1 17 +#define DC2 18 +#define DC3 19 +#define DC4 20 +#define NAK 21 +#define SYN 22 +#define ETB 23 +#define CAN 24 +#define EM 25 +#define SUB 26 +#define ESC 27 +#define FS 28 +#define GS 29 +#define RS 30 +#define US 31 +#define SP 32 +#define DEL 127 + +#endif +/* + * ascii.h,v + * Revision 4.1 1998/07/11 10:05:22 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.0 1998/04/10 19:50:38 kardel + * Start 4.0 release version numbering + * + * Revision 4.0 1998/04/10 19:50:38 kardel + * Start 4.0 release version numbering + * + */ diff --git a/contrib/ntp/include/binio.h b/contrib/ntp/include/binio.h new file mode 100644 index 000000000000..49feee9a21c9 --- /dev/null +++ b/contrib/ntp/include/binio.h @@ -0,0 +1,41 @@ +/* + * /src/NTP/ntp-4/include/binio.h,v 4.2 1998/06/28 16:52:15 kardel RELEASE_19990228_A + * + * $Created: Sun Jul 20 13:03:05 1997 $ + * + * Copyright (C) 1997-1998 by Frank Kardel + */ +#ifndef BINIO_H +#define BINIO_H + +#include "ntp_stdlib.h" + +long get_lsb_short P((unsigned char **)); +void put_lsb_short P((unsigned char **, long)); +long get_lsb_long P((unsigned char **)); +void put_lsb_long P((unsigned char **, long)); + +long get_msb_short P((unsigned char **)); +void put_msb_short P((unsigned char **, long)); +long get_msb_long P((unsigned char **)); +void put_msb_long P((unsigned char **, long)); + +#endif +/* + * binio.h,v + * Revision 4.2 1998/06/28 16:52:15 kardel + * added binio MSB prototypes for {get,put}_msb_{short,long} + * + * Revision 4.1 1998/06/12 15:07:40 kardel + * fixed prototyping + * + * Revision 4.0 1998/04/10 19:50:38 kardel + * Start 4.0 release version numbering + * + * Revision 1.1 1998/04/10 19:27:32 kardel + * initial NTP VERSION 4 integration of PARSE with GPS166 binary support + * + * Revision 1.1 1997/10/06 20:55:37 kardel + * new parse structure + * + */ diff --git a/contrib/ntp/include/global.h b/contrib/ntp/include/global.h new file mode 100644 index 000000000000..469572454d4c --- /dev/null +++ b/contrib/ntp/include/global.h @@ -0,0 +1,51 @@ +/* GLOBAL.H - RSAREF types and constants */ + +/* Copyright (C) RSA Laboratories, a division of RSA Data Security, + Inc., created 1991. All rights reserved. + */ + +/* + * Note: the modifications are necessary for little-endian machines + */ +#include "ntp_types.h" /* local modification */ + +#ifndef _GLOBAL_H_ +#define _GLOBAL_H_ 1 + +/* PROTOTYPES should be set to one if and only if the compiler supports + function argument prototyping. + The following makes PROTOTYPES default to 1 if it has not already been + defined as 0 with C compiler flags. + */ +#ifdef HAVE_PROTOTYPES +#define PROTOTYPES 1 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef unsigned short int UINT2; + +/* UINT4 defines a four byte word */ +typedef u_int32 UINT4; /* local modification */ + +#ifndef NULL_PTR +#define NULL_PTR ((POINTER)0) +#endif + +#ifndef UNUSED_ARG +#define UNUSED_ARG(x) x = *(&x); +#endif + +/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. + If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif + +#endif /* end _GLOBAL_H_ */ diff --git a/contrib/ntp/include/gps.h b/contrib/ntp/include/gps.h new file mode 100644 index 000000000000..d4f2dbc672ae --- /dev/null +++ b/contrib/ntp/include/gps.h @@ -0,0 +1,53 @@ +/****************************************************************************/ +/* gps.h */ +/* TrueTime GPS-VME and VME-SG */ +/* VME controller hardware commands and parameters. */ +/* created 010694 res */ +/* History: revised for 747i 3/94 */ +/****************************************************************************/ + + +#define GPS_VME "/dev/vme2" /* the device file for the GPS board */ + /* change it to whatever yours is */ +#define PRIO 120 /* set the realtime priority */ +#define NREGS 7 /* number of registers we will use */ + +#define GFRZ1 0x0020 /* freeze cmd addr gen reg. 1 */ +#define GREG1A 0x0021 /* Gen reg. 1 Word A (units microsec to 0.001 sec) */ +#define GREG1B 0x0040 /* Gen reg. 1 Word B (units 0.01 sec to tens sec ) */ +#define GREG1C 0x0041 /* Gen reg 1 Word C (units mins and hours) */ +#define GREG1D 0x0042 /* Gen reg. 1 Word D (units days and status) */ +#define GREG1E 0x0043 /* Gen reg. 1 Word E (units Years ) */ +#define GUFRZ1 0x0022 /* unfreeze cmd addr gen reg 1 */ + +#define MASKDAY 0x0FFF /* mask for units days */ +#define MASKHI 0xFF00 +#define MASKLO 0x00FF +/* Use the following ASCII hex values: N(0x004e),S(0x0053),E(0x0045), + W(0x0057), +(0x002B), - (0x002D) */ + +#define LAT1 0x0048 /* Lat (degrees) */ +#define LAT2 0x0049 /* Lat (min, sec) */ +#define LAT3 0x004A /* Lat (N/S, tenths sec) */ +#define LON1 0x004B /* Lon (degrees) */ +#define LON2 0x004C /* Lon (min, sec) */ +#define LON3 0x004D /* Lon (E/W, tenths sec) */ +#define ELV1 0x004E /* Elev. (sign, 10,000 and 1000 ) */ +#define ELV2 0x004F /* Elev. (100, 10s, units, and .1) */ + +#define CFREG1 0x0050 /* config. register 1 */ +#define CFREG2 0x00A0 /* config. register 2 */ +#define PMODE 0x00A4 /* Position mode */ +#define LOCAL 0x0051 /* Local hours offset */ +#define RATE 0x0054 /* Pulse rate output select */ +#define DAC 0x0055 /* OSC Control (DAC) select */ + +#define PUMS 0x0056 /* Gen. preset register unit millisec */ +#define PMS 0x0057 /* Gen. preset register units hundreds and tens ms */ +#define PSEC 0x0058 /* Gen. preset register units tens and unit seconds */ +#define PMIN 0x0059 /* Gen. preset register units tens and unit minutes */ +#define PHRS 0x005A /* Gen. preset register units tens and unit hours */ +#define PDYS1 0x005B /* Gen. preset register units tens and unit days */ +#define PDYS2 0x005C /* Gen. preset register units hundreds days */ +#define PYRS1 0x005D /* Gen. preset register units tens and unit years */ +#define PYRS2 0x005E /* Gen. preset reg. units thousands and hundreds yrs */ diff --git a/contrib/ntp/include/ieee754io.h b/contrib/ntp/include/ieee754io.h new file mode 100644 index 000000000000..f691acc3c2ae --- /dev/null +++ b/contrib/ntp/include/ieee754io.h @@ -0,0 +1,43 @@ +/* + * /src/NTP/ntp-4/include/ieee754io.h,v 4.0 1998/04/10 19:50:40 kardel RELEASE_19990228_A + * + * $Created: Sun Jul 13 12:22:11 1997 $ + * + * Copyright (C) 1997 by Frank Kardel + */ +#ifndef IEEE754IO_H +#define IEEE754IO_H + +#define IEEE_SINGLE 1 +#define IEEE_DOUBLE 2 + +#define IEEE_MSB 1 +#define IEEE_LSB 2 + +#define IEEE_OK 0 /* conversion ok */ +#define IEEE_BADCALL 1 /* bad call parameters */ +#define IEEE_NAN 2 /* found an NaN */ +#define IEEE_POSINFINITY 3 /* positive infinity */ +#define IEEE_NEGINFINITY 4 /* negative infinity */ +#define IEEE_POSOVERFLOW 5 /* positive overflow */ +#define IEEE_NEGOVERFLOW 6 /* negative overflow */ + +#define IEEE_OFFSETS 8 /* number of byte positions */ +typedef unsigned char offsets_t[IEEE_OFFSETS]; + +int fetch_ieee754 P((unsigned char **bufp, int size, l_fp *lfpp, offsets_t offsets)); +int put_ieee754 P((unsigned char **bufpp, int size, l_fp *lfpp, offsets_t offsets)); + +#endif +/* + * ieee754io.h,v + * Revision 4.0 1998/04/10 19:50:40 kardel + * Start 4.0 release version numbering + * + * Revision 1.1 1998/04/10 19:27:33 kardel + * initial NTP VERSION 4 integration of PARSE with GPS166 binary support + * + * Revision 1.1 1997/10/06 20:55:37 kardel + * new parse structure + * + */ diff --git a/contrib/ntp/include/iosignal.h b/contrib/ntp/include/iosignal.h new file mode 100644 index 000000000000..bd74e096d00b --- /dev/null +++ b/contrib/ntp/include/iosignal.h @@ -0,0 +1,23 @@ +#if !defined _ntp_iosignaled_h +#define _ntp_iosignaled_h + +#include "ntp_refclock.h" + +#if defined(HAVE_SIGNALED_IO) +extern void block_sigio P((void)); +extern void unblock_sigio P((void)); +extern int init_clock_sig P((struct refclockio *)); +extern void init_socket_sig P((int)); +extern void set_signal P((void)); +RETSIGTYPE sigio_handler P((int)); + +# define BLOCKIO() ((void) block_sigio()) +# define UNBLOCKIO() ((void) unblock_sigio()) + +#else + +# define BLOCKIO() +# define UNBLOCKIO() +#endif /* HAVE_SIGNALED_IO */ + +#endif diff --git a/contrib/ntp/include/l_stdlib.h b/contrib/ntp/include/l_stdlib.h new file mode 100644 index 000000000000..fdabe67163f7 --- /dev/null +++ b/contrib/ntp/include/l_stdlib.h @@ -0,0 +1,495 @@ +/* + * Proto types for machines that are not ANSI and POSIX compliant. + * This is optional + */ + +#ifndef _l_stdlib_h +#define _l_stdlib_h + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STDLIB_H +# include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +/* Needed for speed_t. */ +#ifdef HAVE_TERMIOS_H +# include +#endif + +#ifdef HAVE_ERRNO_H +# include +#endif + +#include "ntp_types.h" +#include "ntp_proto.h" + +/* Let's try to keep this more or less alphabetized... */ + +#ifdef DECL_ADJTIME_0 +struct timeval; +extern int adjtime P((struct timeval *, struct timeval *)); +#endif + +#ifdef DECL_BCOPY_0 +#ifndef bcopy +extern void bcopy P((const char *, char *, int)); +#endif +#endif + +#ifdef DECL_BZERO_0 +#ifndef bzero +extern void bzero P((char *, int)); +#endif +#endif + +#ifdef DECL_CFSETISPEED_0 +struct termios; +extern int cfsetispeed P((struct termios *, speed_t)); +extern int cfsetospeed P((struct termios *, speed_t)); +#endif + +extern char * getpass P((const char *)); + +#ifdef DECL_INET_NTOA_0 +struct in_addr; +extern char * inet_ntoa P((struct in_addr)); +#endif + +#ifdef DECL_IOCTL_0 +extern int ioctl P((int, u_long, char *)); +#endif + +#ifdef DECL_IPC_0 +struct sockaddr; +extern int bind P((int, struct sockaddr *, int)); +extern int connect P((int, struct sockaddr *, int)); +extern int recv P((int, char *, int, int)); +extern int recvfrom P((int, char *, int, int, struct sockaddr *, int *)); +extern int send P((int, char *, int, 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)); +#endif + +#ifdef DECL_MEMMOVE_0 +extern void * memmove P((void *, const void *, size_t)); +#endif + +#ifdef DECL_MEMSET_0 +extern char * memset P((char *, int, int)); +#endif + +#ifdef DECL_MKSTEMP_0 +extern int mkstemp P((char *)); +#endif + +#ifdef DECL_MKTEMP_0 +extern char *mktemp P((char *)); +#endif + +#ifdef DECL_MRAND48_0 +extern long mrand48 P((void)); +#endif + +#ifdef DECL_NLIST_0 +struct nlist; +extern int nlist P((const char *, struct nlist *)); +#endif + +#ifdef DECL_PLOCK_0 +extern int plock P((int)); +#endif + +#ifdef DECL_RENAME_0 +extern int rename P((const char *, const char *)); +#endif + +#ifdef DECL_SELECT_0 +#ifdef _ntp_select_h +extern int select P((int, fd_set *, fd_set *, fd_set *, struct timeval *)); +#endif +#endif + +#ifdef DECL_SETITIMER_0 +struct itimerval; +extern int setitimer P((int , struct itimerval *, struct itimerval *)); +#endif + +#ifdef PRIO_PROCESS +#ifdef DECL_SETPRIORITY_0 +extern int setpriority P((int, int, int)); +#endif +#ifdef DECL_SETPRIORITY_1 +extern int setpriority P((int, id_t, int)); +#endif +#endif + +#ifdef DECL_SIGVEC_0 +struct sigvec; +extern int sigvec P((int, struct sigvec *, struct sigvec *)); +#endif + +#ifdef DECL_SRAND48_0 +extern void srand48 P((long)); +#endif + +#ifdef DECL_STDIO_0 +#if defined(FILE) || defined(BUFSIZ) +extern int _flsbuf P((int, FILE *)); +extern int _filbuf P((FILE *)); +extern int fclose P((FILE *)); +extern int fflush P((FILE *)); +extern int fprintf P((FILE *, const char *, ...)); +extern int fscanf P((FILE *, const char *, ...)); +extern int fputs P((const char *, FILE *)); +extern int fputc P((int, FILE *)); +extern int fread P((char *, int, int, FILE *)); +extern void perror P((const char *)); +extern int printf P((const char *, ...)); +extern int setbuf P((FILE *, char *)); +# ifdef HAVE_SETLINEBUF +extern int setlinebuf P((FILE *)); +# endif +extern int setvbuf P((FILE *, char *, int, int)); +extern int scanf P((const char *, ...)); +extern int sscanf P((const char *, const char *, ...)); +extern int vfprintf P((FILE *, const char *, ...)); +extern int vsprintf P((char *, const char *, ...)); +#endif +#endif + +#ifdef DECL_STIME_0 +extern int stime P((const time_t *)); +#endif + +#ifdef DECL_STRERROR_0 +extern char * strerror P((int errnum)); +#endif + +#ifdef DECL_STRTOL_0 +extern long strtol P((const char *, char **, int)); +#endif + +#ifdef DECL_SYSCALL +extern int syscall P((int, ...)); +#endif + +#ifdef DECL_SYSLOG_0 +extern void closelog P((void)); +#ifndef LOG_DAEMON +extern void openlog P((const char *, int)); +#else +extern void openlog P((const char *, int, int)); +#endif +extern int setlogmask P((int)); +extern void syslog P((int, const char *, ...)); +#endif + +#ifdef DECL_TIME_0 +extern time_t time P((time_t *)); +#endif + +#ifdef DECL_TIMEOFDAY_0 +#ifdef SYSV_TIMEOFDAY +extern int gettimeofday P((struct timeval *)); +extern int settimeofday P((struct timeval *)); +#else /* not SYSV_TIMEOFDAY */ +struct timezone; +extern int gettimeofday P((struct timeval *, struct timezone *)); +extern int settimeofday P((struct timeval *, void *)); +#endif /* not SYSV_TIMEOFDAY */ +#endif + +#ifdef DECL_TOLOWER_0 +extern int tolower P((int)); +#endif + +#ifdef DECL_TOUPPER_0 +extern int toupper P((int)); +#endif + +/* + * Necessary variable declarations. + */ +#ifdef DECL_ERRNO +extern int errno; +#endif + +#ifdef DECL_H_ERRNO +extern int h_errno; +#endif + +/*******************************************************/ + +#if 0 +/* + * Unprotoyped 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 (void *, int , int, + int P((*compar)(void *, void *))); +extern long random P((void)); +extern long mrand48 P((void)); +extern int setpgrp P((int, int)); +extern void srandom P((unsigned int)); +extern void bcopy P((const 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((const 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 rename P((char *, char *)); +#if 0 +extern int read P((int, void *, size_t)); +extern int write P((int, const void *, size_t)); +#endif +extern int unlink P((const char *)); +extern int link P((const char *, const char *)); + +#ifdef FILE +extern int fclose P((FILE *)); +extern int fflush P((FILE *)); +extern int fprintf P((FILE *, char *, ...)); +extern int fscanf 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 sscanf P((char *, char *, ...)); +extern int vsprintf P((char *, char *, ...)); +extern int _flsbuf P((int, FILE *)); +extern int _filbuf P((FILE *)); +extern void perror P((char *)); +#ifdef HAVE_SETLINEBUF +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 P(()); +extern char *memset P(()); +extern int memcmp P(()); +#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 DEC OSF/1 + */ +#ifdef SYS_DECOSF1 +#ifndef _MACHINE_ENDIAN_H_ +#define _MACHINE_ENDIAN_H_ +extern u_short htons P((u_short)); +extern u_short ntohs P((u_short)); +extern u_int32 htonl P((u_int32)); +extern u_int32 ntohl P((u_int32)); +#endif /* _MACHINE_ENDIAN_H_ */ + +/* +extern char * getpass P((char *)); +*/ +extern char * mktemp P((char *)); +#ifndef SYS_IX86OSF1 +extern int ioctl P((int, u_long, char *)); +extern void bzero P((char *, int)); +#endif + +#ifdef SOCK_DGRAM +extern int bind P((int, const struct sockaddr *, int)); +extern int connect P((int, const struct sockaddr *, int)); +extern int socket P((int, int, int)); +extern int sendto P((int, const void *, int, int, const struct sockaddr *, int)); +extern int setsockopt P((int, int, int, const void *, int)); +extern int recvfrom P((int, void *, int, int, struct sockaddr *, int *)); +#endif /* SOCK_STREAM */ + +#ifdef _ntp_select_h +extern int select P((int, fd_set *, fd_set *, fd_set *, struct timeval *)); +#endif + +#endif /* DECOSF1 */ + +/* + * 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 *)); + +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 + +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 gettimeofday P((struct timeval *, struct timezone *)); +extern int settimeofday P((struct timeval *, struct timezone *)); +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 bzero /* XXX macro prototyping clash */ +extern void bzero P((char *, int)); +extern int bcmp P((char *, char *, int)); +extern void bcopy P((const char *, char *, int)); +#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((const 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)); +#ifdef _TIME_H_ +extern int gettimeofday P((struct timeval *, struct timezone *)); +extern int settimeofday P((struct timeval *, struct timezone *)); +#endif +#endif + +#ifdef _RESOURCE_H_ +extern int getrusage P((int, struct rusage *)); +#endif + +#endif /* SYS_ULTRIX */ + +#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 */ + +#ifdef SYS_BSD +#define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000) +#endif + +#endif /* 0 */ +#endif /* l_stdlib_h */ diff --git a/contrib/ntp/include/mbg_gps166.h b/contrib/ntp/include/mbg_gps166.h new file mode 100644 index 000000000000..71107517e9d2 --- /dev/null +++ b/contrib/ntp/include/mbg_gps166.h @@ -0,0 +1,538 @@ +/* + * /src/NTP/ntp-4/include/mbg_gps166.h,v 4.1 1998/06/12 15:07:30 kardel RELEASE_19990228_A + * + * $Created: Sun Jul 20 09:20:50 1997 $ + * + * Copyright (C) 1997, 1998 by Frank Kardel + */ +#ifndef MBG_GPS166_H +#define MBG_GPS166_H + + +/***************************************************************************/ +/* */ +/* File: GPSSERIO.H 4.1 */ +/* */ +/* Project: Common C Library */ +/* */ +/* Compiler: Borland C++ */ +/* */ +/* Author: M. Burnicki, Meinberg Funkuhren */ +/* */ +/* */ +/* Description: */ +/* This file defines structures and codes to be used to access GPS166 */ +/* via its serial interface COM0. COM0 should be set to a high baud */ +/* rate, default is 19200. */ +/* */ +/* Standard GPS166 serial operation is to send a time string that is */ +/* compatible with Meinberg UA31 or PZF535 DCF77 radio remote clocks. */ +/* That string can be transmitted automatically once per second, once */ +/* per minute or on request per ASCII '?'. */ +/* */ +/* Parameter setup or parameter readout works using blocks of binary */ +/* data which have to be isolated from the standard string. A block of */ +/* data starts with a SOH code (ASCII Start Of Header, 0x01) followed */ +/* by a message header with constant length and a data portion with */ +/* variable length. The first field (cmd) of the message header holds */ +/* the command code rsp. the type of data to be transmitted. The next */ +/* field (len) gives the number of data bytes that are transmitted */ +/* after the header. This number ranges from 0 to sizeof( MSG_DATA ). */ +/* The third field (data_csum) holds a checksum of all data bytes and */ +/* the last field of the header finally holds the checksum of the. */ +/* header. */ +/* */ +/***************************************************************************/ + +/* the control codes defined below are to be or'ed with a command/type code */ + +#define GPS_REQACK 0x8000 /* to GPS166: request acknowledge */ +#define GPS_ACK 0x4000 /* from GPS166: acknowledge a command */ +#define GPS_NACK 0x2000 /* from GPS166: error receiving command */ + +#define GPS_CTRL_MSK 0xF000 /* masks control code from command */ + + +/* The codes below specify commands/types of data to be supplied to GPS166: */ + +/* GPS166 auto-message to host */ +/* ţ host request, GPS166 response */ +/* ţ ţ host download to GPS166 */ +/* ţ ţ ţ */ +enum { /* ţ ţ ţ */ + /* system data */ + GPS_AUTO_ON = 0x000, /* ţ ţ ţ X ţ enable auto-messages from GPS166 */ + GPS_AUTO_OFF, /* ţ ţ ţ X ţ disable auto-messages from GPS166 */ + GPS_SW_REV, /* ţ ţ X ţ ţ request software revision */ + GPS_STAT, /* ţ ţ X ţ ţ request status of buffered variables */ + GPS_TIME, /* ţ X ţ ţ X ţ current time or capture or init board time */ + GPS_POS_XYZ, /* ţ ţ X ţ X ţ current position in ECEF coords */ + GPS_POS_LLA, /* ţ ţ X ţ X ţ current position in geographic coords */ + GPS_TZDL, /* ţ ţ X ţ X ţ time zone / daylight saving */ + GPS_PORT_PARM, /* ţ ţ X ţ X ţ parameters of the serial ports */ + GPS_SYNTH, /* ţ ţ X ţ X ţ synthesizer's frequency and phase */ + GPS_ANT_INFO, /* ţ X ţ X ţ ţ time diff after antenna disconnect */ + GPS_UCAP, /* ţ X ţ X ţ ţ user capture */ + + /* GPS data */ + GPS_CFGH = 0x100, /* ţ ţ X ţ X ţ SVs' configuration and health codes */ + GPS_ALM, /* ţ ţ X ţ X ţ one SV's almanac */ + GPS_EPH, /* ţ ţ X ţ X ţ one SV's ephemeris */ + GPS_UTC, /* ţ ţ X ţ X ţ UTC correction parameters */ + GPS_IONO, /* ţ ţ X ţ X ţ ionospheric correction parameters */ + GPS_ASCII_MSG /* ţ ţ X ţ ţ the GPS ASCII message */ +}; + +/* + * modelled after GPSDEFS.H Revision 1.5 + */ +/***************************************************************************/ +/* */ +/* File: GPSDEFS.H 4.1 */ +/* */ +/* Project: Common C Library */ +/* */ +/* Compiler: Borland C++ */ +/* */ +/* Author: M. Burnicki, Meinberg Funkuhren */ +/* */ +/* */ +/* Description: */ +/* General definitions to be used with GPS166 */ +/* GPS166 Rev. 1.23 or above */ +/* */ +/* Modifications: see file GPSLIB.TXT */ +/* */ +/***************************************************************************/ +#define _GPSDEFS_H +/* the type of various checksums */ + +#ifndef _CSUM_DEFINED + typedef unsigned short CSUM; +# define _CSUM_DEFINED +#endif + +/* the message header */ + +typedef struct { + unsigned short gps_cmd; + unsigned short gps_len; + unsigned short gps_data_csum; + unsigned short gps_hdr_csum; +} GPS_MSG_HDR; + +/* a struct used to hold the software revision information */ + +typedef struct { + unsigned short code; /* e.g. 0x0120 means rev. 1.20 */ + unsigned char name[17]; /* used to identify customized versions */ +} SW_REV; + +/* GPS ASCII message */ + +typedef struct { + CSUM csum; /* checksum of the remaining bytes */ + short valid; /* flag data are valid */ + char s[23]; /* 22 chars GPS ASCII message plus trailing zero */ +} ASCII_MSG; + +#define MIN_SVNO 1 /* min. SV number */ +#define MAX_SVNO 32 /* max. SV number */ +#define N_SVNO ( MAX_SVNO - MIN_SVNO + 1) /* number of possibly active SVs */ + + +typedef short SVNO; /* the number of a SV */ +typedef unsigned short HEALTH; /* a SV's health code */ +typedef unsigned short CFG; /* a SV's configuration code */ +typedef unsigned short IOD; /* Issue-Of-Data code */ + +/* Date and time referred to the linear time scale defined by GPS. */ +/* GPS time is defined by the number of weeks since midnight from */ +/* January 5, 1980 to January 6, 1980 plus the number of seconds of */ +/* the current week plus fractions of a second. GPS time differs from */ +/* UTC because UTC is corrected with leap seconds while GPS time scale */ +/* is continuous. */ + +typedef struct { + unsigned short wn; /* the week number since GPS has been installed */ + unsigned long sec; /* the second of that week */ + unsigned long tick; /* fractions of a second; scale: 1E-7 */ +} T_GPS; + + +/* Local date and time computed from GPS time. The current number */ +/* of leap seconds have to be added to get UTC from GPS time. */ +/* Additional corrections could have been made according to the */ +/* time zone/daylight saving parameters (TZDL, see below) defined */ +/* by the user. The status field can be checked to see which corrections */ +/* have been applied. */ + +#ifndef _TM_DEFINED + typedef struct { + short year; /* 0..9999 */ + char month; /* 1..12 */ + char mday; /* 1..31 */ + short yday; /* 1..366 */ + char wday; /* 0..6 == Sun..Sat */ + char hour; /* 0..23 */ + char minute; /* 0..59 */ + char second; /* 0..59 */ + long frac; /* fractions of a second, scale 1E-7 */ + long offs_from_utc; /* local time's offset from UTC */ + unsigned short status; /* flags */ + } TM; + + /* status flags used with conversion from GPS time to local time */ + +# define TM_UTC 0x01 /* UTC correction has been made */ +# define TM_LOCAL 0x02 /* UTC has been converted to local time */ +# define TM_DL_ANN 0x04 /* state of daylight saving is going to change */ +# define TM_DL_ENB 0x08 /* daylight saving is enabled */ +# define TM_LS_ANN 0x10 /* leap second will be inserted */ +# define TM_LS_ENB 0x20 /* current second is leap second */ + +# define _TM_DEFINED +#endif + + +/* the status flags below are defined starting with rev. 1.32 */ + +#define TM_ANT_DISCONN 0x1000 /* antenna currently disconnected */ +#define TM_SYN_FLAG 0x2000 /* TIME_SYN output is low */ +#define TM_NO_SYNC 0x4000 /* not sync'ed after reset */ +#define TM_NO_POS 0x8000 /* position not computed after reset, */ + /* LOCK LED off */ + +/* a struct used to transmit information on date and time */ + +typedef struct { + short channel; /* -1: the current time; 0, 1: capture 0, 1 */ + T_GPS t; /* time in GPS format */ + TM tm; /* that time converted to local time */ +} TTM; + + + +/* Two types of variables used to store a position. Type XYZ is */ +/* used with a position in earth centered, earth fixed (ECEF) */ +/* coordinates whereas type LLA holds such a position converted */ +/* to geographic coordinates as defined by WGS84 (World Geodetic */ +/* System from 1984). */ + +#ifndef _XYZ_DEFINED + /* sequence and number of components of a cartesian position */ + enum { XP, YP, ZP, N_XYZ }; + + /* a type of array holding a cartesian position */ + typedef l_fp XYZ[N_XYZ]; /* values are in [m] */ + +# define _XYZ_DEFINED +#endif + + +#ifndef _LLA_DEFINED + /* sequence and number of components of a geographic position */ + enum { LAT, LON, ALT, N_LLA }; /* latitude, longitude, altitude */ + + /* a type of array holding a geographic position */ + typedef l_fp LLA[N_LLA]; /* lon, lat in [rad], alt in [m] */ + +# define _LLA_DEFINED +#endif + +/* Synthesizer parameters. Synthesizer frequency is expressed as a */ +/* four digit decimal number (freq) to be multiplied by 0.1 Hz and an */ +/* base 10 exponent (range). If the effective frequency is less than */ +/* 10 kHz its phase is synchronized corresponding to the variable phase. */ +/* Phase may be in a range from -360° to +360° with a resolution of 0.1°, */ +/* so the resulting numbers to be stored are in a range of -3600 to +3600. */ + +/* Example: */ +/* Assume the value of freq is 2345 (decimal) and the value of phase is 900. */ +/* If range == 0 the effective frequency is 234.5 Hz with a phase of +90°. */ +/* If range == 1 the synthesizer will generate a 2345 Hz output frequency */ +/* and so on. */ + +/* Limitations: */ +/* If freq == 0 the synthesizer is disabled. If range == 0 the least */ +/* significant digit of freq is limited to 0, 3, 5 or 6. The resulting */ +/* frequency is shown in the examples below: */ +/* freq == 1230 --> 123.0 Hz */ +/* freq == 1233 --> 123 1/3 Hz (real 1/3 Hz, NOT 123.3 Hz) */ +/* freq == 1235 --> 123.5 Hz */ +/* freq == 1236 --> 123 2/3 Hz (real 2/3 Hz, NOT 123.6 Hz) */ + +/* If range == MAX_RANGE the value of freq must not exceed 1200, so the */ +/* output frequency is limited to 12 MHz. */ + +/* Phase will be ignored if the resulting frequency is greater or equal */ +/* to 10 kHz. */ + +#define MAX_SYNTH_FREQ 1200 /* if range == MAX_SYNTH_RANGE */ +#define MIN_SYNTH_RANGE 0 +#define MAX_SYNTH_RANGE 5 +#define MAX_SYNTH_PHASE 3600 + +typedef struct { + short freq; /* four digits used; scale: 0.1; e.g. 1234 -> 123.4 Hz */ + short range; /* scale factor for freq; 0..MAX_SYNTH_RANGE */ + short phase; /* -MAX_SYNTH_PHASE..+MAX_SYNTH_PHASE; >0 -> pulses later */ +} SYNTH; + + + +/* Time zone/daylight saving parameters. */ + +/* the name of a time zone, 5 characters plus trailing zero */ +typedef char TZ_NAME[6]; + +typedef struct { + long offs; /* offset from UTC to local time [sec] */ + long offs_dl; /* additional offset if daylight saving enabled [sec] */ + TM tm_on; /* date/time when daylight saving starts */ + TM tm_off; /* date/time when daylight saving ends */ + TZ_NAME name[2]; /* names without and with daylight saving enabled */ +} TZDL; + +/* The constant below is defined beginning with software rev. 1.29. */ +/* If the year in tzdl.tmon and tzdl.tm_off is or'ed with that constant, */ +/* the receiver automatically generates daylight saving year by year. */ +/* See GPSLIB.TXT for more information. */ + +#define DL_AUTO_FLAG 0x8000 + +/* Example: */ +/* for automatic daylight saving enable/disable in Central Europe, */ +/* the variables are to be set as shown below: */ +/* offs = 3600L one hour from UTC */ +/* offs_dl = 3600L one additional hour if daylight saving enabled */ +/* tm_on = first Sunday from March 25, 02:00:00h ( year |= DL_AUTO_FLAG ) */ +/* tm_off = first Sunday from Sept 24, 03:00:00h ( year |= DL_AUTO_FLAG ) */ +/* name[0] == "MEZ " name if daylight saving not enabled */ +/* name[1] == "MESZ " name if daylight saving is enabled */ + + + + +/* the structure below was defined in rev. 1.31. It reflects the status */ +/* of the antenna, the times of last disconnect/reconnect and the boards */ +/* clock offset after the phase of disconnection. */ + +typedef struct { + short status; /* current status of antenna */ + TM tm_disconn; /* time of antenna disconnect */ + TM tm_reconn; /* time of antenna reconnect */ + long delta_t; /* clock offset at reconnect time, units: TICKS_PER_SEC */ +} ANT_INFO; + + +/* the status field may be set to one of the values below: */ + +enum { + ANT_INVALID, /* struct not set yet because ant. has not been disconn. */ + ANT_DISCONN, /* ant. now disconn., tm_reconn and delta_t not set */ + ANT_RECONN /* ant. has been disconn. and reconn., all fields valid */ +}; + + +/* Summary of configuration and health data of all SVs. */ + +typedef struct { + CSUM csum; /* checksum of the remaining bytes */ + short valid; /* flag data are valid */ + + T_GPS tot_51; /* time of transmission, page 51 */ + T_GPS tot_63; /* time of transmission, page 63 */ + T_GPS t0a; /* complete reference time almanac */ + + CFG cfg[N_SVNO]; /* SV configuration from page 63 */ + HEALTH health[N_SVNO]; /* SV health from pages 51, 63 */ +} CFGH; + + + +/* UTC correction parameters */ + +typedef struct { + CSUM csum; /* checksum of the remaining bytes */ + short valid; /* flag data are valid */ + + T_GPS t0t; /* Reference Time UTC Parameters [sec] */ + l_fp A0; /* ± Clock Correction Coefficient 0 [sec] */ + l_fp A1; /* ± Clock Correction Coefficient 1 [sec/sec] */ + + ushort WNlsf; /* week number of nearest leap second */ + short DNt; /* the day number at the end of which LS is inserted */ + char delta_tls; /* */ + char delta_tlsf; /* */ + +} UTC; + +/* a struct used to hold the settings of a serial port */ + +#ifndef _COM_PARM_DEFINED + typedef long BAUD_RATE; + + /* indices used to identify a parameter in the framing string */ + enum { F_DBITS, F_PRTY, F_STBITS }; + + /* types of handshake */ + enum { HS_NONE, HS_XONXOFF, HS_RTSCTS }; + + typedef struct { + BAUD_RATE baud_rate; /* e.g. 19200L */ + char framing[4]; /* e.g. "8N1" */ + short handshake; /* a numeric value, only HS_NONE supported yet */ + } COM_PARM; + +#define _COM_PARM_DEFINED +#endif + + + +/* the codes below define what has to comes out of the serial ports */ + +enum { STR_ON_REQ, STR_PER_SEC, + STR_PER_MIN, N_STR_MODE_0, /* COM0 and COM1 */ + STR_UCAP = N_STR_MODE_0, + STR_UCAP_REQ, N_STR_MODE_1 /* COM1 only */ + }; + + +#define N_COM 2 /* the number of serial ports */ + +/* the structure used to store the modes of both serial ports */ + +typedef struct { + COM_PARM com[N_COM]; /* COM0 and COM1 settings */ + u_char mode[N_COM]; /* COM0 and COM1 output mode */ +} PORT_PARM; + +/* Ephemeris parameters of one specific SV. Needed to compute the position */ +/* of a satellite at a given time with high precision. Valid for an */ +/* interval of 4 to 6 hours from start of transmission. */ + +typedef struct { + CSUM csum; /* checksum of the remaining bytes */ + short valid; /* flag data are valid */ + + HEALTH health; /* health indication of transmitting SV [---] */ + IOD IODC; /* Issue Of Data, Clock */ + IOD IODE2; /* Issue of Data, Ephemeris (Subframe 2) */ + IOD IODE3; /* Issue of Data, Ephemeris (Subframe 3) */ + T_GPS tt; /* time of transmission */ + T_GPS t0c; /* Reference Time Clock [---] */ + T_GPS t0e; /* Reference Time Ephemeris [---] */ + + l_fp sqrt_A; /* Square Root of semi-major Axis [sqrt(m)] */ + l_fp e; /* Eccentricity [---] */ + l_fp M0; /* ± Mean Anomaly at Ref. Time [rad] */ + l_fp omega; /* ± Argument of Perigee [rad] */ + l_fp OMEGA0; /* ± Longit. of Asc. Node of orbit plane [rad] */ + l_fp OMEGADOT; /* ± Rate of Right Ascension [rad/sec] */ + l_fp deltan; /* ± Mean Motion Diff. from computed value [rad/sec] */ + l_fp i0; /* ± Inclination Angle [rad] */ + l_fp idot; /* ± Rate of Inclination Angle [rad/sec] */ + l_fp crc; /* ± Cosine Corr. Term to Orbit Radius [m] */ + l_fp crs; /* ± Sine Corr. Term to Orbit Radius [m] */ + l_fp cuc; /* ± Cosine Corr. Term to Arg. of Latitude [rad] */ + l_fp cus; /* ± Sine Corr. Term to Arg. of Latitude [rad] */ + l_fp cic; /* ± Cosine Corr. Term to Inclination Angle [rad] */ + l_fp cis; /* ± Sine Corr. Term to Inclination Angle [rad] */ + + l_fp af0; /* ± Clock Correction Coefficient 0 [sec] */ + l_fp af1; /* ± Clock Correction Coefficient 1 [sec/sec] */ + l_fp af2; /* ± Clock Correction Coefficient 2 [sec/sec˛] */ + l_fp tgd; /* ± estimated group delay differential [sec] */ + + u_short URA; /* predicted User Range Accuracy */ + + u_char L2code; /* code on L2 channel [---] */ + u_char L2flag; /* L2 P data flag [---] */ + +} EPH; + +/* Almanac parameters of one specific SV. A reduced precision set of */ +/* parameters used to check if a satellite is in view at a given time. */ +/* Valid for an interval of more than 7 days from start of transmission. */ + +typedef struct { + CSUM csum; /* checksum of the remaining bytes */ + short valid; /* flag data are valid */ + + HEALTH health; /* [---] */ + T_GPS t0a; /* Reference Time Almanac [sec] */ + + l_fp sqrt_A; /* Square Root of semi-major Axis [sqrt(m)] */ + l_fp e; /* Eccentricity [---] */ + + l_fp M0; /* ± Mean Anomaly at Ref. Time [rad] */ + l_fp omega; /* ± Argument of Perigee [rad] */ + l_fp OMEGA0; /* ± Longit. of Asc. Node of orbit plane [rad] */ + l_fp OMEGADOT; /* ± Rate of Right Ascension [rad/sec] */ + l_fp deltai; /* ± [rad] */ + l_fp af0; /* ± Clock Correction Coefficient 0 [sec] */ + l_fp af1; /* ± Clock Correction Coefficient 1 [sec/sec] */ +} ALM; + + +/* ionospheric correction parameters */ + +typedef struct { + CSUM csum; /* checksum of the remaining bytes */ + short valid; /* flag data are valid */ + + l_fp alpha_0; /* Ionosph. Corr. Coeff. Alpha 0 [sec] */ + l_fp alpha_1; /* Ionosph. Corr. Coeff. Alpha 1 [sec/deg] */ + l_fp alpha_2; /* Ionosph. Corr. Coeff. Alpha 2 [sec/deg^2] */ + l_fp alpha_3; /* Ionosph. Corr. Coeff. Alpha 3 [sec/deg^3] */ + + l_fp beta_0; /* Ionosph. Corr. Coeff. Beta 0 [sec] */ + l_fp beta_1; /* Ionosph. Corr. Coeff. Beta 1 [sec/deg] */ + l_fp beta_2; /* Ionosph. Corr. Coeff. Beta 2 [sec/deg^2] */ + l_fp beta_3; /* Ionosph. Corr. Coeff. Beta 3 [sec/deg^3] */ + +} IONO; + +void mbg_tm_str P((unsigned char **, TM *)); +void mbg_tgps_str P((unsigned char **, T_GPS *)); +void get_mbg_header P((unsigned char **, GPS_MSG_HDR *)); +void put_mbg_header P((unsigned char **, GPS_MSG_HDR *)); +void get_mbg_sw_rev P((unsigned char **, SW_REV *)); +void get_mbg_ascii_msg P((unsigned char **, ASCII_MSG *)); +void get_mbg_svno P((unsigned char **, SVNO *)); +void get_mbg_health P((unsigned char **, HEALTH *)); +void get_mbg_cfg P((unsigned char **, CFG *)); +void get_mbg_tgps P((unsigned char **, T_GPS *)); +void get_mbg_tm P((unsigned char **, TM *)); +void get_mbg_ttm P((unsigned char **, TTM *)); +void get_mbg_synth P((unsigned char **, SYNTH *)); +void get_mbg_tzdl P((unsigned char **, TZDL *)); +void get_mbg_antinfo P((unsigned char **, ANT_INFO *)); +void get_mbg_cfgh P((unsigned char **, CFGH *)); +void get_mbg_utc P((unsigned char **, UTC *)); +void get_mbg_lla P((unsigned char **, LLA)); +void get_mbg_xyz P((unsigned char **, XYZ)); +void get_mbg_portparam P((unsigned char **, PORT_PARM *)); +void get_mbg_eph P((unsigned char **, EPH *)); +void get_mbg_alm P((unsigned char **, ALM *)); +void get_mbg_iono P((unsigned char **, IONO *)); + +unsigned long mbg_csum P((unsigned char *, unsigned int)); + +#endif +/* + * mbg_gps166.h,v + * Revision 4.1 1998/06/12 15:07:30 kardel + * fixed prototyping + * + * Revision 4.0 1998/04/10 19:50:42 kardel + * Start 4.0 release version numbering + * + * Revision 1.1 1998/04/10 19:27:34 kardel + * initial NTP VERSION 4 integration of PARSE with GPS166 binary support + * + * Revision 1.1 1997/10/06 20:55:38 kardel + * new parse structure + * + */ diff --git a/contrib/ntp/include/md5.h b/contrib/ntp/include/md5.h new file mode 100644 index 000000000000..8241647601b3 --- /dev/null +++ b/contrib/ntp/include/md5.h @@ -0,0 +1,51 @@ +/* MD5.H - header file for MD5C.C + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. 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. + */ + +#ifndef _MD5_H_ +#define _MD5_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*#include "global.h" */ + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init PROTO_LIST ((MD5_CTX *)); +void MD5Update PROTO_LIST + ((MD5_CTX *, unsigned char *, unsigned int)); +void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/ntp/include/mx4200.h b/contrib/ntp/include/mx4200.h new file mode 100644 index 000000000000..6ea2c6039cf6 --- /dev/null +++ b/contrib/ntp/include/mx4200.h @@ -0,0 +1,40 @@ + +/* 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 13 /* 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/ntp/include/ntif.h b/contrib/ntp/include/ntif.h new file mode 100644 index 000000000000..837785272d24 --- /dev/null +++ b/contrib/ntp/include/ntif.h @@ -0,0 +1,98 @@ +/* this is a hacked version of if.h from unix to contain the stuff we need only to build named (bind) with + the minimal amount of changes... by l. kahn */ + + /* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef _NET_IF_H +#define _NET_IF_H + + +/* #pragma ident "@(#)if.h 1.3 93/06/30 SMI" +/* if.h 1.26 90/05/29 SMI; from UCB 7.1 6/4/86 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Structures defining a network interface, providing a packet + * transport mechanism (ala level 0 of the PUP protocols). + * + * Each interface accepts output datagrams of a specified maximum + * length, and provides higher level routines with input datagrams + * received from its medium. + * + * Output occurs when the routine if_output is called, with three parameters: + * (*ifp->if_output)(ifp, m, dst) + * Here m is the mbuf chain to be sent and dst is the destination address. + * The output routine encapsulates the supplied datagram if necessary, + * and then transmits it on its medium. + * + * On input, each interface unwraps the data received by it, and either + * places it on the input queue of a internetwork datagram routine + * and posts the associated software interrupt, or passes the datagram to a raw + * packet input routine. + * + * Routines exist for locating interfaces by their addresses + * or for locating a interface on a certain network, as well as more general + * routing and gateway routines maintaining information used to locate + * interfaces. These routines live in the files if.c and route.c + */ + +/* + * Structure defining a queue for a network interface. + * + * (Would like to call this struct ``if'', but C isn't PL/1.) + */ +/* + * Interface request structure used for socket + * ioctl's. All interface ioctl's must have parameter + * definitions which begin with ifr_name. The + * remainder may be interface specific. + */ +#ifdef FD_SETSIZE +#undef FD_SETSIZE +#endif +#define FD_SETSIZE 512 +#include +typedef char *caddr_t; + +int get_winnt_interfaces(); + +struct ifreq { +#define IFNAMSIZ 16 + char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + struct sockaddr ifru_addr; + char nt_mask[IFNAMSIZ]; /* new field to store mask returned from nt lookup l. kahn */ + +#define ifr_addr ifru_addr /* address */ +#define ifr_mask nt_mask /* nt mask in character form */ + +}; + +/* + * Structure used in SIOCGIFCONF request. + * Used to retrieve interface configuration + * for machine (useful for programs which + * must know all networks accessible). + */ +struct ifconf { + int ifc_len; /* size of associated buffer */ + union { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NET_IF_H */ + diff --git a/contrib/ntp/include/ntp.h b/contrib/ntp/include/ntp.h new file mode 100644 index 000000000000..790e0a5e0aca --- /dev/null +++ b/contrib/ntp/include/ntp.h @@ -0,0 +1,714 @@ +/* + * ntp.h - NTP definitions for the masses + */ + +#ifndef NTP_H +#define NTP_H + +#include "ntp_types.h" +#include + + /* common definitions for Y2K repairs [ Y2KFixes */ + + /* (this might better be put in ntp_calendar.h) */ +#define YEAR_BREAK 500 /* assume years < this are tm_year values: */ + /* Break < AnyFourDigitYear + && Break > Anytm_yearYear */ +#define YEAR_PIVOT 98 /* 97/98: assume years < this are year 2000+ */ + /* FYI: official UNIX pivot year is 68/69 */ + + /* Number of Days since (mythical) 1.BC Gregorian to 1 January of given year*/ +#define julian0(year) \ + ( \ + ( (year) * 365 ) + ( (year) > 0 \ + ? ( ((year)+3) / 4 - ((year-1) / 100) + ((year-1) / 400) ) \ + : 0 ) \ + ) + + /* Number of days since start of NTP time to 1 January of given year */ +#define ntp0(year) ( julian0(year) - julian0(1900) ) + + /* Number of days since start of UNIX time to 1 January of given year */ +#define unix0(year) ( julian0(year) - julian0(1970) ) + + /* LEAP YEAR test for full 4-digit years (e.g, 1999, 2010) */ +#define isleap_4(y) /* a TRUE and PROPER leap year test */ \ + ((y)%4 == 0 && !((y)%100 == 0 && !(y%400 == 0))) + /* NOTE: year 2000 TRULY IS A LEAP YEAR!!! */ + + /* LEAP YEAR test for tm_year (struct tm) years (e.g, 99, 110) */ +#define isleap_tm(y) /* a TRUE and PROPER leap year test */ \ + ((y)%4 == 0 && !((y)%100 == 0 && !(((y)+1900)%400 == 0))) + + /* to convert simple two-digit years to tm_year style years: + if ( year < YEAR_PIVOT ) year += 100; + + * to convert either two-digit OR tm_year years to four-digit years: + if ( year < YEAR_PIVOT ) year += 100; + if ( year < YEAR_BREAK ) year += 1900; + + CALL TO STANDARD: + * As the Internet is an INTERNATIONAL network, it makes SENSE to use + the international standard ISO 8601 to format dates and times. + Basically this is yyyy-mm-dd for years and hh:mm:ss for times + (joining the two togeather in computer readable media calls for + yyyy-mm-ddThh:mm:ss, though yyyy-mm-dd hh:mm:ss is often used + for human readable forms even though it is not not strictly + valid ISO 8601). Standard time-zone offsets ([+-]hh:mm) are allowed. + ghealton ] Y2KFixes */ + +/* + * 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. + */ +#ifdef NEED_S_CHAR_TYPEDEF +# if SIZEOF_SIGNED_CHAR +typedef signed char s_char; +# else +typedef char s_char; +# endif + /* XXX: Why is this sequent bit INSIDE this test? */ +# ifdef sequent +# undef SO_RCVBUF +# undef SO_SNDBUF +# endif +#endif +#ifndef TRUE +# define TRUE 1 +#endif /* TRUE */ +#ifndef FALSE +# define FALSE 0 +#endif /* FALSE */ + +/* + * NTP protocol parameters. See section 3.2.6 of the specification. + */ +#define NTP_VERSION ((u_char)4) /* 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_UNREACH 16 /* poll interval backoff count */ +#define NTP_MINDPOLL 6 /* log2 default min poll interval (64 s) */ +#define NTP_MAXDPOLL 10 /* log2 default max poll interval (~17 m) */ +#define NTP_MINPOLL 4 /* log2 min poll interval (16 s) */ +#define NTP_MAXPOLL 17 /* log2 max poll interval (~4.5 h) */ +#define NTP_MINCLOCK 3 /* minimum survivors */ +#define NTP_CANCLOCK 6 /* minimum candidates */ +#define NTP_MAXCLOCK 10 /* maximum candidates */ +#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 */ +#define NTP_MAXSESSION 100 /* maximum entries on session key list */ +#define NTP_AUTOMAX 12 /* log2 default max session key lifetime */ +#define KEY_REVOKE 16 /* log2 default key revoke timeout */ +#define NTP_FWEIGHT .5 /* clock filter weight */ +#define NTP_SWEIGHT .75 /* select weight */ +#define CLOCK_SGATE 10. /* popcorn spike gate */ +#define BURST_INTERVAL1 4 /* first interburst interval (log2) */ +#define BURST_INTERVAL2 1 /* succeeding interburst intervals (log2) */ + +/* + * Operations for jitter (variance) calculations (these use doubles). + * Note that we carefully separate the jitter component from the dispersion + * component (frequency error plus precision). The frequency error + * component is computed as CLOCK_PHI times the difference between the epoch + * of the time measurement and the reference time. The precision componen + * is computed as the square root of the mean of the squares of a zero- + * mean, uniform distribution of unit maximum amplitude. Whether this + * makes statistical sense may be arguable. + */ +#define SQUARE(x) ((x) * (x)) +#define SQRT(x) (sqrt(x)) +#define DIFF(x, y) (SQUARE((x) - (y))) +#define LOGTOD(a) ((a) < 0 ? 1. / (1L << -(a)) : \ + 1L << (int)(a)) /* log2 to double */ +#define UNIVAR(x) (SQUARE(.28867513 * LOGTOD(x))) /* std uniform distr */ +#define ULOGTOD(a) (1L << (int)(a)) /* ulog2 to double */ +#define MAXDISPERSE 16. /* max dispersion (square) */ +#define MINDISPERSE .01 /* min dispersion */ +#define MAXDISTANCE 1. /* max root distance */ + +/* + * 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. + */ +#define CLOCK_PHI 15e-6 /* max frequency wander */ + +#define EVENT_TIMEOUT 0 /* one second, that is */ + +/* + * 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 */ + int last_ttl; /* last TTL specified */ + volatile 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 INT_MULTICAST 8 /* multicasting enabled */ + +/* + * 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 0x0001 /* duplicate packet received */ +#define TEST2 0x0002 /* bogus packet received */ +#define TEST3 0x0004 /* protocol unsynchronized */ +#define TEST4 0x0008 /* peer delay/dispersion bounds check */ +#define TEST5 0x0010 /* peer authentication failed */ +#define TEST6 0x0020 /* peer clock unsynchronized */ +#define TEST7 0x0040 /* peer stratum out of bounds */ +#define TEST8 0x0080 /* root delay/dispersion bounds check */ +#define TEST9 0x0100 /* peer not authenticated */ +#define TEST10 0x0200 /* access denied */ + +/* + * 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 */ + struct refclockproc *procptr; /* pointer to reference clock stuff */ + 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 burst; /* packets remaining in burst */ + u_char version; /* version number */ + u_int flags; /* peer flags */ + u_char cast_flags; /* flags MDF_?CAST */ + u_int flash; /* protocol error tally bits */ + u_char refclktype; /* reference clock type */ + u_char refclkunit; /* reference clock unit number */ + u_char sstclktype; /* clock type for system status word */ + u_int32 refid; /* peer reference ID */ + l_fp reftime; /* update epoch */ + u_long keyid; /* current key ID */ + u_long pkeyid; /* previous key ID (autokey) */ + u_long *keylist; /* session key identifier list */ + int keynumber; /* session key identifier number */ + u_short associd; /* association ID, a unique integer */ + u_char ttl; /* time to live (multicast) */ + +/* **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 + double estbdelay; /* broadcast offset */ + u_char status; /* peer status */ + u_char pollsw; /* what it says */ + u_char reach; /* reachability, NTP_WINDOW bits */ + u_char unreach; /* unreachable count */ + u_short filter_nextpt; /* index into filter shift register */ + double filter_delay[NTP_SHIFT]; /* delay part of shift register */ + double filter_offset[NTP_SHIFT]; /* offset part of shift register */ + double filter_disp[NTP_SHIFT]; /* dispersion part of shift register */ + u_long filter_epoch[NTP_SHIFT]; /* epoch part of shift register */ + u_char filter_order[NTP_SHIFT]; /* we keep the filter sorted here */ + l_fp org; /* originate time stamp */ + l_fp rec; /* receive time stamp */ + l_fp xmt; /* transmit time stamp */ + double offset; /* peer clock offset */ + double delay; /* peer roundtrip delay */ + double variance; /* peer variance (jitter) */ + double disp; /* peer dispersion */ + double rootdelay; /* roundtrip delay to primary clock */ + double rootdispersion; /* dispersion to primary clock */ + u_long epoch; /* reference epoch */ + +/* ***End of clear-to-zero area.*** */ +/* Everything that is cleared to zero goes above here */ + u_long update; /* receive epoch */ +#define end_clear_to_zero update + u_long outdate; /* send time last packet */ + u_long nextdate; /* send time next packet */ + u_long nextaction; /* peer local activity timeout (refclocks mainly) */ + void (*action) P((struct peer *));/* action timeout function */ + /* + * 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 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 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 */ +#define MODE_MCLIENT 9 /* multicast 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_MCAST1 0x4 /* multicast client/server mode */ +#define FLAG_MCAST2 0x8 /* multicast client mode */ +#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 */ +#define FLAG_BURST 0x100 /* burst mode */ +#define FLAG_SKEY 0x200 /* autokey authentication */ +#define FLAG_NOSELECT 0x400 /* this is a "noselect" 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 (u_int32)"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., lockclock) */ +#define REFCLK_GPS_TRAK 2 /* TRAK 8810 GPS Receiver */ +#define REFCLK_WWV_PST 3 /* PST/Traconex 1020 WWV/H */ +#define REFCLK_WWVB_SPECTRACOM 4 /* Spectracom 8170/Netclock WWVB */ +#define REFCLK_TRUETIME 5 /* TrueTime (generic) Receivers */ +#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,MSF) */ +#define REFCLK_GPS_MX4200 9 /* Magnavox MX4200 GPS */ +#define REFCLK_GPS_AS2201 10 /* Austron 2201A GPS */ +#define REFCLK_GPS_ARBITER 11 /* Arbiter 1088A/B/ GPS */ +#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 /* EES M201 MSF Receiver */ +#define REFCLK_GPSTM_TRUE 15 /* OLD TrueTime GPS/TM-TMD Receiver */ +#define REFCLK_IRIG_BANCOMM 16 /* Bancomm GPS/IRIG Interface */ +#define REFCLK_GPS_DATUM 17 /* Datum Programmable Time System */ +#define REFCLK_NIST_ACTS 18 /* NIST Auto Computer Time Service */ +#define REFCLK_WWV_HEATH 19 /* Heath GC1000 WWV/WWVH Receiver */ +#define REFCLK_GPS_NMEA 20 /* NMEA based GPS clock */ +#define REFCLK_GPS_VME 21 /* TrueTime GPS-VME Interface */ +#define REFCLK_ATOM_PPS 22 /* 1-PPS Clock Discipline */ +#define REFCLK_PTB_ACTS 23 /* PTB Auto Computer Time Service */ +#define REFCLK_USNO 24 /* Naval Observatory dialup */ +#define REFCLK_GPS_HP 26 /* HP 58503A Time/Frequency Receiver */ +#define REFCLK_ARCRON_MSF 27 /* ARCRON MSF radio clock. */ +#define REFCLK_SHM 28 /* clock attached thru shared memory */ +#define REFCLK_PALISADE 29 /* Trimble Navigation Palisade GPS */ +#define REFCLK_ONCORE 30 /* Motorola UT Oncore GPS */ +#define REFCLK_GPS_JUPITER 31 /* Rockwell Jupiter GPS receiver */ +#define REFCLK_CHRONOLOG 32 /* Chrono-log K WWVB receiver */ +#define REFCLK_DUMBCLOCK 33 /* Dumb localtime clock */ +#define REFCLK_ULINK 34 /* Ultralink M320 WWVB receiver */ +#define REFCLK_MAX 34 /* Grow as needed... */ + +/* + * 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 */ + u_fp rootdelay; /* distance to primary clock */ + u_fp rootdispersion; /* clock dispersion */ + u_int32 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_int32) + 8) /* DES */ +#define MAX_MAC_LEN (sizeof(u_int32) + 16) /* MD5 */ + + /* + * The length of the packet less MAC must be a multiple of 64 + * bits. For normal private-key cryptography, the cryptosum + * covers only the raw NTP header. For autokey cryptography, + * the heade is incresed by 64 bits to contain the field length + * and private value. + */ + u_int32 keyid1; /* key identifier 1 */ + u_int32 keyid2; /* key identifier 2 */ + u_int32 keyid3; /* key identifier 3 */ + u_char mac[MAX_MAC_LEN]; /* mac */ +}; + +/* + * Packets can come in two flavours, one with a mac and one without. + */ +#define LEN_PKT_NOMAC (sizeof(struct pkt) - MAX_MAC_LEN - 3 * sizeof(u_int32)) + +/* + * Minimum size of packet with a MAC: has to include at least a key number. + */ +#define LEN_PKT_MAC (LEN_PKT_NOMAC + sizeof(u_int32)) + +/* + * 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))) + + +/* + * 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) + +/* + * How we randomize polls. The poll interval is a power of two. + * We chose a random value which is between 1/4 and 3/4 of the + * poll interval we would normally use and which is an even multiple + * of the EVENT_TIMEOUT. The random number routine, given an argument + * spread value of n, returns an integer between 0 and (1< (b)) ? (a) : (b)) +#define min3(a,b,c) min(min((a),(b)), (c)) + + +/* + * Configuration items. These are for the protocol module (proto_config()) + */ +#define PROTO_BROADCLIENT 1 +#define PROTO_PRECISION 2 /* (not used) */ +#define PROTO_AUTHENTICATE 3 +#define PROTO_BROADDELAY 4 +#define PROTO_AUTHDELAY 5 /* (not used) */ +#define PROTO_MULTICAST_ADD 6 +#define PROTO_MULTICAST_DEL 7 +#define PROTO_NTP 8 +#define PROTO_KERNEL 9 +#define PROTO_MONITOR 10 +#define PROTO_FILEGEN 11 + +/* + * Configuration items for the loop filter + */ +#define LOOP_DRIFTINIT 1 /* set initial frequency offset */ +#define LOOP_DRIFTCOMP 2 /* set frequency offset */ +#define LOOP_PPSDELAY 3 /* set pps delay */ +#define LOOP_PPSBAUD 4 /* 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 ntpd PID file */ + +#define MJD_1970 40587 /* MJD for 1 Jan 1970 */ + +/* + * Default parameters. We use these in the absence of something better. + */ +#define DEFBROADDELAY 4e-3 /* default broadcast offset */ +#define INADDR_NTP 0xe0000101 /* NTP multicast address 224.0.1.1 */ +/* + * 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 *mru_next; /* next structure in MRU list */ + struct mon_data *mru_prev; /* previous structure in MRU list */ + struct mon_data *fifo_next; /* next structure in FIFO list */ + struct mon_data *fifo_prev; /* previous structure in FIFO list */ + u_long lastdrop; /* last time dropped due to RES_LIMIT*/ + u_long lasttime; /* last time data updated */ + u_long firsttime; /* time structure initialized */ + u_long count; /* count we have seen */ + u_int32 rmtadr; /* address of remote host */ + struct interface *interface; /* interface on which this arrived */ + u_short rmtport; /* remote port last came from */ + u_char mode; /* mode of incoming packet */ + u_char version; /* version of incoming packet */ + u_char cast_flags; /* flags MDF_?CAST */ +}; + +#define MDF_UCAST 0x1 /* unicast packet */ +#define MDF_MCAST 0x2 /* multicast packet */ +#define MDF_BCAST 0x4 /* broadcast packet */ +#define MDF_LCAST 0x8 /* local packet */ +#define MDF_ACAST 0x10 /* manycast packet */ + +/* + * Values used with mon_enabled to indicate reason for enabling monitoring + */ +#define MON_OFF 0x00 /* no monitoring */ +#define MON_ON 0x01 /* monitoring explicitly enabled */ +#define MON_RES 0x02 /* implicit monitoring for RES_LIMITED */ +/* + * Structure used for restrictlist entries + */ +struct restrictlist { + struct restrictlist *next; /* link to next entry */ + u_int32 addr; /* host address (host byte order) */ + u_int32 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_LIMITED 0x100 /* limit per net number of clients */ + +#define RES_ALLFLAGS \ + (RES_IGNORE|RES_DONTSERVE|RES_DONTTRUST|RES_NOQUERY\ + |RES_NOMODIFY|RES_NOPEER|RES_NOTRAP|RES_LPTRAP|RES_LIMITED) + +/* + * 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 { + double val; /* offset of endpoint */ + int type; /* interval entry/exit */ +}; + +/* + * Defines for association matching + */ +#define AM_MODES 10 /* total number of modes */ +#define NO_PEER 0 /* action when no peer is found */ + +/* + * Association matching AM[] return codes + */ +#define AM_ERR -1 +#define AM_NOMATCH 0 +#define AM_PROCPKT 1 +#define AM_FXMIT 2 +#define AM_MANYCAST 3 +#define AM_NEWPASS 4 +#define AM_NEWBCL 5 +#define AM_POSSBCL 6 + +/* NetInfo configuration locations */ +#ifdef HAVE_NETINFO +#define NETINFO_CONFIG_DIR "/config/ntp" +#endif + +#endif /* NTP_H */ diff --git a/contrib/ntp/include/ntp_calendar.h b/contrib/ntp/include/ntp_calendar.h new file mode 100644 index 000000000000..95e2c12974ba --- /dev/null +++ b/contrib/ntp/include/ntp_calendar.h @@ -0,0 +1,112 @@ +/* + * ntp_calendar.h - definitions for the calendar time-of-day routine + */ +#ifndef NTP_CALENDAR_H +#define NTP_CALENDAR_H + +#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 *)); + +/* + * Additional support stuff for Ed Rheingold's calendrical calculations + */ + +/* + * Start day of NTP time as days past the imaginary date 12/1/1 BC. + * P((This is the beginning of the Christian Era, or BCE.)) + */ +#define DAY_NTP_STARTS 693596 +/* + * The Gregorian calendar is based on a 400 year cycle. This is the number + * of days in each cycle. + */ +#define GREGORIAN_CYCLE_DAYS 146097 + +/* + * Days in a normal 100 year leap year calendar. We lose a leap year day + * in years evenly divisible by 100 but not by 400. + */ +#define GREGORIAN_NORMAL_CENTURY_DAYS 36524 + +/* + * Days in a normal 4 year leap year calendar cycle. + */ +#define GREGORIAN_NORMAL_LEAP_CYCLE_DAYS 1461 + +#define is_leapyear(y) (y%4 == 0 && !(y%100 == 0 && !(y%400 == 0))) + +#endif diff --git a/contrib/ntp/include/ntp_control.h b/contrib/ntp/include/ntp_control.h new file mode 100644 index 000000000000..dbcc2c659ff3 --- /dev/null +++ b/contrib/ntp/include/ntp_control.h @@ -0,0 +1,260 @@ +/* + * 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_SST_TS_PPS 0x20 /* time source is PPS signal */ + +#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 /* reject */ +#define CTL_PST_SEL_SANE 1 /* x falsetick */ +#define CTL_PST_SEL_CORRECT 2 /* . excess */ +#define CTL_PST_SEL_SELCAND 3 /* - outlyer */ +#define CTL_PST_SEL_SYNCCAND 4 /* + candidat */ +#define CTL_PST_SEL_DISTSYSPEER 5 /* # selected */ +#define CTL_PST_SEL_SYSPEER 6 /* * sys.peer */ +#define CTL_PST_SEL_PPS 7 /* o pps.peer */ + +#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_STATE 10 +#define CS_OFFSET 11 +#define CS_DRIFT 12 +#define CS_COMPLIANCE 13 +#define CS_CLOCK 14 +#define CS_PROCESSOR 15 +#define CS_SYSTEM 16 +#define CS_STABIL 17 +#define CS_VARLIST 18 + +#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_JITTER 26 +#define CP_DISPERSION 27 +#define CP_KEYID 28 +#define CP_FILTDELAY 29 +#define CP_FILTOFFSET 30 +#define CP_PMODE 31 +#define CP_RECEIVED 32 +#define CP_SENT 33 +#define CP_FILTERROR 34 +#define CP_FLASH 35 +#define CP_DISP 36 +#define CP_VARLIST 37 + +#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 */ + +/* + * Types of things we may deal with + * shared between ntpq and library + */ +#define TYPE_SYS 1 +#define TYPE_PEER 2 +#define TYPE_CLOCK 3 diff --git a/contrib/ntp/include/ntp_datum.h b/contrib/ntp/include/ntp_datum.h new file mode 100644 index 000000000000..2aa2cb742d01 --- /dev/null +++ b/contrib/ntp/include/ntp_datum.h @@ -0,0 +1,30 @@ +struct btfp_time /* Structure for reading 5 time words */ + /* in one ioctl(2) operation. */ +{ + unsigned short btfp_time[5]; /* Time words 0,1,2,3, and 4. (16bit)*/ +}; + +/***** Simple ioctl commands *****/ + +#define RUNLOCK _IO('X',19) /* Release Capture Lockout */ +#define RCR0 _IOR('X',22,unsigned int) /* Read control register */ +#define WCR0 _IOW('X',23,unsigned int) /* Write control register */ + +/***** Compound ioctl commands *****/ + +/* Read all 5 time words in one call. */ +#define READTIME _IOR('X',32,struct btfp_time) +#define VMEFD "/dev/btfp0" + + struct vmedate { /* structure returned by get_vmetime.c */ + unsigned short year; + unsigned short doy; + unsigned short hr; + unsigned short mn; + unsigned short sec; + unsigned long frac; + unsigned short status; + }; + +#define PRIO 120 /* set the realtime priority */ +#define NREGS 7 /* number of registers we will use */ diff --git a/contrib/ntp/include/ntp_filegen.h b/contrib/ntp/include/ntp_filegen.h new file mode 100644 index 000000000000..8217dbc11670 --- /dev/null +++ b/contrib/ntp/include/ntp_filegen.h @@ -0,0 +1,51 @@ +/* + * ntp_filegen.h,v 3.9 1996/12/01 16:02:45 kardel Exp + * + * definitions for NTP file generations support + * + * + * Copyright (C) 1992, 1996 by Rainer Pruy + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * 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((const char *, FILEGEN *)); diff --git a/contrib/ntp/include/ntp_fp.h b/contrib/ntp/include/ntp_fp.h new file mode 100644 index 000000000000..027add32d9ba --- /dev/null +++ b/contrib/ntp/include/ntp_fp.h @@ -0,0 +1,373 @@ +/* + * ntp_fp.h - definitions for NTP fixed/floating-point arithmetic + */ + +#ifndef NTP_FP_H +#define NTP_FP_H + +#include +#include +#include + +#include "ntp_types.h" + +/* + * NTP uses two fixed point formats. The first (l_fp) is the "long" + * format and is 64 bits long with the decimal between bits 31 and 32. + * This is used for time stamps in the NTP packet header (in network + * byte order) and for internal computations of offsets (in local host + * byte order). We use the same structure for both signed and unsigned + * values, which is a big hack but saves rewriting all the operators + * twice. Just to confuse this, we also sometimes just carry the + * fractional part in calculations, in both signed and unsigned forms. + * Anyway, an l_fp looks like: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Integral Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Fractional Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +typedef struct { + union { + u_int32 Xl_ui; + int32 Xl_i; + } Ul_i; + union { + u_int32 Xl_uf; + int32 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 int32 s_fp; +typedef u_int32 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) >= 0x00010000) ? 0x7fffffff : \ + (((x_i) <= -0x00010000) ? 0x80000000 : \ + (((x_i)<<16) | (((x_f)>>16)&0xffff)))) +#define LFPTOFP(v) MFPTOFP((v)->l_i, (v)->l_f) + +#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) + +#define MAXLFP(v) ((v)->l_ui = 0x7fffffff, (v)->l_uf = 0xffffffff) +#define MINLFP(v) ((v)->l_ui = 0x80000000, (v)->l_uf = 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) = -((s_fp)(v_i)); \ + else { \ + (v_f) = -((s_fp)(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_int32 lo_tmp; \ + register u_int32 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_int32 lo_tmp; \ + register u_int32 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_int32 lo_tmp; \ + register u_int32 hi_tmp; \ + \ + if ((a_f) == 0) { \ + (r_i) -= (a_i); \ + } else { \ + lo_tmp = ((r_f) & 0xffff) + ((-((s_fp)(a_f))) & 0xffff); \ + hi_tmp = (((r_f) >> 16) & 0xffff) \ + + (((-((s_fp)(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_int32)(v_f) >> 1; \ + if ((v_i) & 01) \ + (v_f) |= 0x80000000; \ + (v_i) = (u_int32)(v_i) >> 1; \ + } while (0) + +#define M_RSHIFT(v_i, v_f) /* v >>= 1, v is signed */ \ + do { \ + (v_f) = (u_int32)(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_int32 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_int32 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 int32 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_int32)(a_i)) > ((u_int32)(b_i)) || \ + ((a_i) == (b_i) && ((u_int32)(a_f)) >= ((u_int32)(b_f)))) + +#define M_ISGEQ(a_i, a_f, b_i, b_f) /* a >= b signed */ \ + (((int32)(a_i)) > ((int32)(b_i)) || \ + ((a_i) == (b_i) && ((u_int32)(a_f)) >= ((u_int32)(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_ISZERO(v) ((v)->l_ui == 0 && (v)->l_uf == 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) + +/* + * s_fp/double and u_fp/double conversions + */ +#define FRIC 65536. /* 2^16 as a double */ +#define DTOFP(r) ((s_fp)((r) * FRIC)) +#define DTOUFP(r) ((u_fp)((r) * FRIC)) +#define FPTOD(r) ((double)(r) / FRIC) + +/* + * l_fp/double conversions + */ +#define FRAC 4294967296. /* 2^32 as a double */ +#define M_DTOLFP(d, r_i, r_uf) /* double to l_fp */ \ + do { \ + register double d_tmp; \ + \ + d_tmp = (d); \ + if (d_tmp < 0) { \ + d_tmp = -d_tmp; \ + (r_i) = (int32)(d_tmp); \ + (r_uf) = (u_int32)(((d_tmp) - (double)(r_i)) * FRAC); \ + M_NEG((r_i), (r_uf)); \ + } else { \ + (r_i) = (int32)(d_tmp); \ + (r_uf) = (u_int32)(((d_tmp) - (double)(r_i)) * FRAC); \ + } \ + } while (0) +#define M_LFPTOD(r_i, r_uf, d) /* l_fp to double */ \ + do { \ + register l_fp l_tmp; \ + \ + l_tmp.l_i = (r_i); \ + l_tmp.l_f = (r_uf); \ + if (l_tmp.l_i < 0) { \ + M_NEG(l_tmp.l_i, l_tmp.l_uf); \ + (d) = -((double)l_tmp.l_i + ((double)l_tmp.l_uf) / FRAC); \ + } else { \ + (d) = (double)l_tmp.l_i + ((double)l_tmp.l_uf) / FRAC; \ + } \ + } while (0) +#define DTOLFP(d, v) M_DTOLFP((d), (v)->l_ui, (v)->l_uf) +#define LFPTOD(v, d) M_LFPTOD((v)->l_ui, (v)->l_uf, (d)) + +/* + * Prototypes + */ +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 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 void gpstolfp P((int, int, unsigned long, l_fp *)); +extern int mstolfp P((const char *, l_fp *)); +extern char * prettydate P((l_fp *)); +extern char * gmprettydate P((l_fp *)); +extern char * uglydate P((l_fp *)); +extern void mfp_mul P((int32 *, u_int32 *, int32, u_int32, int32, u_int32)); + +extern void get_systime P((l_fp *)); +extern int step_systime P((double)); +extern int adj_systime P((double)); + +#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) + +#endif /* NTP_FP_H */ diff --git a/contrib/ntp/include/ntp_if.h b/contrib/ntp/include/ntp_if.h new file mode 100644 index 000000000000..0be015601234 --- /dev/null +++ b/contrib/ntp/include/ntp_if.h @@ -0,0 +1,54 @@ +/* + * Sockets are not standard. + * So hide uglyness in include file. + */ +/* was: defined(SYS_CONVEXOS9) */ +#if defined(HAVE__SYS_SYNC_QUEUE_H) && defined(HAVE__SYS_SYNC_SEMA_H) +# include "/sys/sync/queue.h" +# include "/sys/sync/sema.h" +#endif + +/* was: defined(SYS_AIX) */ +#if defined(TIME_WITH_SYS_TIME) +# include +# include +#endif + +/* was: (defined(SYS_SOLARIS) && !defined(bsd)) || defined(SYS_SUNOS4) */ +/* was: defined(SYS_UNIXWARE1) */ +#ifdef HAVE_SYS_SOCKIO_H +# include +#endif + +/* was: #if defined(SYS_PTX) || defined(SYS_SINIXM) */ +#ifdef HAVE_SYS_STREAM_H +# include +#endif +#ifdef HAVE_SYS_STROPTS_H +# include +#endif + +/* Was: #if defined(SYS_SVR4) */ +#if defined(USE_STREAMS_DEVICE_FOR_IF_CONFIG) +# include +# undef SIOCGIFCONF +# undef SIOCGIFFLAGS +# undef SIOCGIFADDR +# undef SIOCGIFBRDADDR +# undef SIOCGIFNETMASK +# define SIOCGIFCONF IPIOC_GETIFCONF +# define SIOCGIFFLAGS IPIOC_GETIFFLAGS +# define SIOCGIFADDR IPIOC_GETIFADDR +# define SIOCGIFBRDADDR IPIOC_GETIFBRDADDR +# define SIOCGIFNETMASK IPIOC_GETIFNETMASK +#if 0 /* We don't need this now that sys/sockio.h is handled above */ +# else /* USE_STREAMS_DEVICE_FOR_IF_CONFIG */ +# include +#endif +# endif /* USE_STREAMS_DEVICE_FOR_IF_CONFIG */ +/* was #endif SYS_SVR4 */ + + +#ifdef HAVE_NET_IF_H +# include +#endif /* HAVE_NET_IF_H */ diff --git a/contrib/ntp/include/ntp_io.h b/contrib/ntp/include/ntp_io.h new file mode 100644 index 000000000000..0ef4fa65386f --- /dev/null +++ b/contrib/ntp/include/ntp_io.h @@ -0,0 +1,33 @@ +#if !defined _NTP_IO_H +#define _NTP_IO_H +/* + * POSIX says use to get O_* symbols and + * SEEK_SET symbol form . + */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#ifdef HAVE_SYS_FILE_H +# include +#endif +#ifdef HAVE_FCNTL_H +# include +#endif +#if !defined(SEEK_SET) && defined(L_SET) +# define SEEK_SET L_SET +#endif + +#ifdef SYS_WINNT +# include +# include "win32_io.h" +#endif + +#endif diff --git a/contrib/ntp/include/ntp_machine.h b/contrib/ntp/include/ntp_machine.h new file mode 100644 index 000000000000..4f7f345d8eba --- /dev/null +++ b/contrib/ntp/include/ntp_machine.h @@ -0,0 +1,512 @@ +/* + * Collect all machine dependent idiosyncrasies in one place. + */ + +#ifndef __ntp_machine +#define __ntp_machine + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include "ntp_proto.h" + +/* + + HEY! CHECK THIS OUT! + + The first half of this file is obsolete, and is only there to help + reconcile "what went before" with "current behavior". + + The per-system SYS_* #defins ARE NO LONGER USED, with the temporary + exception of SYS_WINNT. + + If you find a hunk of code that is bracketed by a SYS_* macro and you + *know* that it is still needed, please let us know. In many cases the + code fragment is now handled somewhere else by autoconf choices. + +*/ + +/* + +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 + NTP_SYSCALLS_LIBC - ntp_adjtime() and ntp_gettime() are in libc. + +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 + + HAVE_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 ? +*/ + +/* + * Set up for prototyping (duplicated from ntp_types.h) + */ +#ifndef P +#if defined(__STDC__) || defined(HAVE_PROTOTYPES) +#define P(x) x +#else /* not __STDC__ and not HAVE_PROTOTYPES */ +#define P(x) () +#endif /* not __STDC__ and not HAVE_PROTOTYPES */ +#endif /* P */ + +#if 0 + +/* + * IRIX 4.X and IRIX 5.x + */ +#if defined(SYS_IRIX4)||defined(SYS_IRIX5) +# define ADJTIME_IS_ACCURATE +# define LOCK_PROCESS +#endif + +/* + * Ultrix + * Note: posix version has NTP_POSIX_SOURCE and HAVE_SIGNALED_IO + */ +#if defined(SYS_ULTRIX) +# define S_CHAR_DEFINED +# define NTP_SYSCALLS_STD +# define HAVE_MODEM_CONTROL +#endif + +/* + * AUX + */ +#if defined(SYS_AUX2) || defined(SYS_AUX3) +# define NO_SIGNED_CHAR_DECL +# 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 LOG_NTP LOG_LOCAL1 +#endif + +/* + * HPUX + */ +#if defined(SYS_HPUX) +# define getdtablesize() sysconf(_SC_OPEN_MAX) +# define setlinebuf(f) setvbuf(f, NULL, _IOLBF, 0) +# define NO_SIGNED_CHAR_DECL +# define LOCK_PROCESS +#endif + +/* + * BSD/OS 2.0 and above + */ +#if defined(SYS_BSDI) +# define USE_FSETOWNCTTY /* this funny system demands a CTTY for FSETOWN */ +#endif + +/* + * FreeBSD 2.0 and above + */ +#ifdef SYS_FREEBSD +# define KERNEL_PLL +#endif + +/* + * Linux + */ +#if defined(SYS_LINUX) +# define ntp_adjtime __adjtimex +#endif + +/* + * PTX + */ +#if defined(SYS_PTX) +# define LOCK_PROCESS +struct timezone { int __0; }; /* unused placebo */ +/* + * no comment !@! + */ +typedef unsigned int u_int; +# ifndef _NETINET_IN_SYSTM_INCLUDED /* i am about to comment... */ +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned long u_long; +# endif +#endif + +/* + * UNIX V.4 on and NCR 3000 + */ +#if defined(SYS_SVR4) +# define STREAM +# define LOCK_PROCESS +# define SIZE_RETURNED_IN_BUFFER +#endif + +/* + * (Univel/Novell) Unixware1 SVR4 on intel x86 processor + */ +#if defined(SYS_UNIXWARE1) +/* #define _POSIX_SOURCE */ +# define STREAM +# define STREAMS +# undef STEP_SLEW /* TWO step */ +# define LOCK_PROCESS +# define SIZE_RETURNED_IN_BUFFER +# include +# include +# include +#endif + +/* + * DomainOS + */ +#if defined(SYS_DOMAINOS) +# define NTP_SYSCALLS_STD +/* older versions of domain/os don't have class D */ +# ifndef IN_CLASSD +# define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000) +# define IN_CLASSD_NET 0xf0000000 +# define IN_CLASSD_NSHIFT 28 +# define IN_CLASSD_HOST 0xfffffff +# define IN_MULTICAST(i) IN_CLASSD(i) +# endif +#endif + +/* + * Fujitsu UXP/V + */ +#if defined(SYS_UXPV) +# define LOCK_PROCESS +# define SIZE_RETURNED_IN_BUFFER +#endif + + +#endif /* 0 */ + +/* + * Windows NT + */ +#if defined(SYS_WINNT) +# if !defined(HAVE_CONFIG_H) || !defined(__config) + error "NT requires config.h to be included" +# endif /* HAVE_CONFIG_H) */ + +#if defined SYS_WINNT +# define ifreq _INTERFACE_INFO +# define ifr_flags iiFlags +# define ifr_addr iiAddress.AddressIn +# define ifr_broadaddr iiBroadcastAddress.AddressIn +# define ifr_mask iiNetmask.AddressIn +#endif /* SYS_WINNT */ + +# define isascii __isascii +# define isatty _isatty +# define mktemp _mktemp +# define getpid GetCurrentProcessId +# include +# include +# undef interface + typedef char *caddr_t; +#endif /* SYS_WINNT */ + +int ntp_set_tod P((struct timeval *tvp, void *tzp)); + +#if defined (SYS_CYGWIN32) +#include +#define __int64 long long +#endif + +/*casey Tue May 27 15:45:25 SAT 1997*/ +#ifdef SYS_VXWORKS + +/* casey's new defines */ +#define NO_MAIN_ALLOWED 1 +#define NO_NETDB 1 +#define NO_RENAME 1 + +/* in vxWorks we use FIONBIO, but the others are defined for old systems, so + * all hell breaks loose if we leave them defined we define USE_FIONBIO to + * undefine O_NONBLOCK FNDELAY O_NDELAY where necessary. + */ +#define USE_FIONBIO 1 +/* end my new defines */ + +#define TIMEOFDAY 0x0 /* system wide realtime clock */ +#define HAVE_GETCLOCK 1 /* configure does not set this ... */ +#define HAVE_NO_NICE 1 /* configure does not set this ... */ +#define HAVE_RANDOM 1 /* configure does not set this ... */ +#define HAVE_SRANDOM 1 /* configure does not set this ... */ + +#define NODETACH 1 + +/* vxWorks specific additions to take care of its + * unix (non)complicance + */ + +#include "vxWorks.h" +#include "ioLib.h" +#include "taskLib.h" +#include "time.h" + +extern int sysClkRateGet P(()); + +/* usrtime.h + * Bob Herlien's excellent time code find it at: + * ftp://ftp.atd.ucar.edu/pub/vxworks/vx/usrTime.shar + * I would recommend this instead of clock_[g|s]ettime() plus you get + * adjtime() too ... casey + */ +/* +extern int gettimeofday P(( struct timeval *tp, struct timezone *tzp )); +extern int settimeofday P((struct timeval *, struct timezone *)); +extern int adjtime P(( struct timeval *delta, struct timeval *olddelta )); + */ + +/* in machines.c */ +extern void sleep P((int seconds)); +extern void alarm P((int seconds)); +/* machines.c */ + + +/* this is really this */ +#define getpid taskIdSelf +#define getclock clock_gettime +#define fcntl ioctl +#define _getch getchar +#define random rand +#define srandom srand + +/* define this away for vxWorks */ +#define openlog(x,y) +/* use local defines for these */ +#undef min +#undef max + +#endif /* SYS_VXWORKS */ + +#ifdef NO_NETDB +/* These structures are needed for gethostbyname() etc... */ +/* structures used by netdb.h */ +struct hostent { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + int h_addrtype; /* host address type */ + int h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +#define h_addr h_addr_list[0] /* address, for backward compatibility */ +}; + +struct servent { + char *s_name; /* official service name */ + char **s_aliases; /* alias list */ + int s_port; /* port # */ + char *s_proto; /* protocol to use */ +}; +extern int h_errno; + +#define TRY_AGAIN 2 + +struct hostent *gethostbyname P((char * netnum)); +struct hostent *gethostbyaddr P((char * netnum, int size, int addr_type)); +/* type is the protocol */ +struct servent *getservbyname P((char *name, char *type)); +#endif /* NO_NETDB */ + +#ifdef NO_MAIN_ALLOWED +/* we have no main routines so lets make a plan */ +#define CALL(callname, progname, callmain) \ + extern int callmain (int,char**); \ + void callname (a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) \ + char *a0; \ + char *a1; \ + char *a2; \ + char *a3; \ + char *a4; \ + char *a5; \ + char *a6; \ + char *a7; \ + char *a8; \ + char *a9; \ + char *a10; \ + { \ + char *x[11]; \ + int argc; \ + char *argv[] = {progname,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; \ + int i; \ + for (i=0;i<11;i++) \ + x[i] = NULL; \ + x[0] = a0; \ + x[1] = a1; \ + x[2] = a2; \ + x[3] = a3; \ + x[4] = a4; \ + x[5] = a5; \ + x[6] = a6; \ + x[7] = a7; \ + x[8] = a8; \ + x[9] = a9; \ + x[10] = a10; \ + argc=1; \ + for (i=0; i<11;i++) \ + if (x[i]) \ + { \ + argv[argc++] = x[i]; \ + } \ + callmain(argc,argv); \ + } +#endif /* NO_MAIN_ALLOWED */ +/*casey Tue May 27 15:45:25 SAT 1997*/ + +/* + * Here's where autoconfig starts to take over + */ +#ifdef HAVE_SYS_STROPTS_H +# ifdef HAVE_SYS_STREAM_H +# define STREAM +# 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 */ + +#ifdef HAVE_RTPRIO +# define HAVE_NO_NICE +#else +# ifdef HAVE_SETPRIORITY +# define HAVE_BSD_NICE +# else +# ifdef HAVE_NICE +# define HAVE_ATT_NICE +# endif +# endif +#endif + +#if !defined(HAVE_ATT_NICE) \ + && !defined(HAVE_BSD_NICE) \ + && !defined(HAVE_NO_NICE) \ + && !defined(SYS_WINNT) +#include "ERROR: You must define one of the HAVE_xx_NICE defines!" +#endif + +/* + * use only one tty model - no use in initialising + * a tty in three ways + * HAVE_TERMIOS is preferred over HAVE_SYSV_TTYS over HAVE_BSD_TTYS + */ + +#ifdef HAVE_TERMIOS_H +# define HAVE_TERMIOS +#else +# ifdef HAVE_TERMIO_H +# define HAVE_SYSV_TTYS +# else +# ifdef HAVE_SGTTY_H +# define HAVE_BSD_TTYS +# endif +# endif +#endif + +#ifdef HAVE_TERMIOS +# undef HAVE_BSD_TTYS +# undef HAVE_SYSV_TTYS +#endif + +#ifdef HAVE_SYSV_TTYS +# undef HAVE_BSD_TTYS +#endif + +#if !defined(SYS_WINNT) && !defined(VMS) && !defined(SYS_VXWORKS) +# if !defined(HAVE_SYSV_TTYS) \ + && !defined(HAVE_BSD_TTYS) \ + && !defined(HAVE_TERMIOS) +#include "ERROR: no tty type defined!" +# endif +#endif /* SYS_WINNT || VMS || SYS_VXWORKS*/ + +#ifdef WORDS_BIGENDIAN +# define XNTP_BIG_ENDIAN 1 +#else +# define XNTP_LITTLE_ENDIAN 1 +#endif + +/* + * 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/ntp/include/ntp_malloc.h b/contrib/ntp/include/ntp_malloc.h new file mode 100644 index 000000000000..099c83effe90 --- /dev/null +++ b/contrib/ntp/include/ntp_malloc.h @@ -0,0 +1,19 @@ +/* + * Define malloc and friends. + */ +#ifndef _ntp_malloc_h +#define _ntp_malloc_h + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_STDLIB_H +# include +#else /* HAVE_STDLIB_H */ +# ifdef HAVE_MALLOC_H +# include +# endif +#endif /* HAVE_STDLIB_H */ + +#endif /* _ntp_malloc_h */ diff --git a/contrib/ntp/include/ntp_proto.h b/contrib/ntp/include/ntp_proto.h new file mode 100644 index 000000000000..2a888c2cc257 --- /dev/null +++ b/contrib/ntp/include/ntp_proto.h @@ -0,0 +1,8 @@ +#ifndef __ntp_proto_h +#define __ntp_proto_h + +#ifdef HAVE_CONFIG_H +#include +#endif + +#endif /* __ntp_proto_h */ diff --git a/contrib/ntp/include/ntp_refclock.h b/contrib/ntp/include/ntp_refclock.h new file mode 100644 index 000000000000..ad278a3c5576 --- /dev/null +++ b/contrib/ntp/include/ntp_refclock.h @@ -0,0 +1,265 @@ +/* + * ntp_refclock.h - definitions for reference clock support + */ + +#ifndef NTP_REFCLOCK_H +#define NTP_REFCLOCK_H + +#include "ntp_types.h" + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(HAVE_TERMIOS) +# ifdef TERMIOS_NEEDS__SVID3 +# define _SVID3 +# endif +# include +# ifdef TERMIOS_NEEDS__SVID3 +# undef _SVID3 +# endif +#endif + +#if defined(HAVE_SYS_MODEM_H) +#include +#endif + +#if defined(STREAM) +#include +#if defined(CLK) +#include +#endif /* CLK */ +#endif /* STREAM */ + +#include "recvbuff.h" + +#if !defined(SYSV_TTYS) && !defined(STREAM) & !defined(BSD_TTYS) +#define BSD_TTYS +#endif /* SYSV_TTYS STREAM BSD_TTYS */ + +#define SAMPLE(x) if ((pp->coderecv + 1) % MAXSTAGE != \ + pp->codeproc % MAXSTAGE) \ + pp->filter[pp->coderecv++ % MAXSTAGE] = \ + (x); + +/* + * 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 and descriptions. These must agree with + * lib/clocktypes.c and ntpd/refclock_conf.c. + */ +struct clktype { + int code; /* driver "major" number */ + const char *clocktype; /* long description */ + const char *abbrev; /* short description */ +}; + +/* + * Configuration 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 + +/* + * Constant for disabling event reporting in + * refclock_receive. ORed in leap + * parameter + */ +#define REFCLOCK_OWN_STATES 0x80 + +/* + * Structure for returning clock status + */ +struct refclockstat { + u_char type; /* clock type */ + u_char flags; /* clock flags */ + u_char haveflags; /* bit array of valid flags */ + u_short lencode; /* length of last timecode */ + const char *p_lastcode; /* last timecode received */ + u_int32 polls; /* transmit polls */ + u_int32 noresponse; /* no response to poll */ + u_int32 badformat; /* bad format timecode received */ + u_int32 baddata; /* invalid data timecode received */ + u_int32 timereset; /* driver resets */ + const char *clockdesc; /* ASCII description */ + double fudgetime1; /* configure fudge time1 */ + double fudgetime2; /* configure fudge time2 */ + int32 fudgeval1; /* configure fudge value1 */ + int32 fudgeval2; /* configure fudge value2 */ + u_char currentstatus; /* clock status */ + u_char lastevent; /* last exception event */ + u_char leap; /* leap bits */ + 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; /* link to next structure */ + void (*clock_recv) P((struct recvbuf *)); /* completion routine */ + int (*io_input) P((struct recvbuf *)); /* input routine - + to avoid excessive buffer use + due to small bursts + of refclock input data */ + caddr_t srcclock; /* pointer to clock structure */ + int datalen; /* lenth of data */ + int fd; /* file descriptor */ + u_long recvcount; /* count of receive completions */ +}; + +/* + * Structure for returning debugging info + */ +#define NCLKBUGVALUES 16 +#define NCLKBUGTIMES 32 + +struct refclockbug { + u_char nvalues; /* values following */ + u_char ntimes; /* times following */ + u_short svalues; /* values format sign array */ + u_int32 stimes; /* times format sign array */ + u_int32 values[NCLKBUGVALUES]; /* real values */ + l_fp times[NCLKBUGTIMES]; /* real times */ +}; + +/* + * Structure interface between the reference clock support + * ntp_refclock.c and the driver utility routines + */ +#define MAXSTAGE 60 /* max median filter stages */ +#define NSTAGE 5 /* default median filter stages */ +#define BMAX 128 /* max timecode length */ +#define GMT 0 /* I hope nobody sees this */ +#define MAXDIAL 60 /* max length of modem dial strings */ + +/* + * Line discipline flags. These require line discipline or streams + * modules to be installed/loaded in the kernel. If specified, but not + * installed, the code runs as if unspecified. + */ +#define LDISC_STD 0x0 /* standard */ +#define LDISC_CLK 0x1 /* tty_clk \n intercept */ +#define LDISC_CLKPPS 0x2 /* tty_clk \377 intercept */ +#define LDISC_ACTS 0x4 /* tty_clk #* intercept */ +#define LDISC_CHU 0x8 /* tty_chu */ +#define LDISC_PPS 0x10 /* ppsclock */ +#define LDISC_RAW 0x20 /* raw binary */ + +struct refclockproc { + struct refclockio io; /* I/O handler structure */ + caddr_t unitptr; /* pointer to unit structure */ + u_char leap; /* leap/synchronization code */ + u_char currentstatus; /* clock status */ + u_char lastevent; /* last exception event */ + u_char type; /* clock type */ + const char *clockdesc; /* clock description */ + + char a_lastcode[BMAX]; /* last timecode received */ + u_short lencode; /* length of last timecode */ + + int year; /* year of eternity */ + int day; /* day of year */ + int hour; /* hour of day */ + int minute; /* minute of hour */ + int second; /* second of minute */ + int msec; /* millisecond of second */ + long usec; /* microsecond of second (alt) */ + u_long yearstart; /* beginning of year */ + int coderecv; /* put pointer */ + int codeproc; /* get pointer */ + l_fp lastref; /* timecode timestamp */ + l_fp lastrec; /* local timestamp */ + double offset; /* mean offset */ + double disp; /* sample dispersion */ + double variance; /* sample variance */ + double filter[MAXSTAGE]; /* median filter */ + + /* + * Configuration data + */ + double fudgetime1; /* fudge time1 */ + double fudgetime2; /* fudge time2 */ + u_int32 refid; /* reference identifier */ + u_char sloppyclockflag; /* fudge flags */ + + /* + * Status tallies + */ + u_long timestarted; /* time we started this */ + u_long polls; /* polls sent */ + u_long noreply; /* no replies to polls */ + u_long badformat; /* bad format reply */ + u_long baddata; /* bad data reply */ +}; + +/* + * Structure interface between the reference clock support + * ntp_refclock.c and particular clock drivers. This must agree with the + * structure defined in the driver. + */ +#define noentry 0 /* flag for null routine */ +#define NOFLAGS 0 /* flag for null flags */ + +struct refclock { + int (*clock_start) P((int, struct peer *)); + void (*clock_shutdown) P((int, struct peer *)); + void (*clock_poll) P((int, struct peer *)); + void (*clock_control) P((int, struct refclockstat *, + struct refclockstat *, struct peer *)); + void (*clock_init) P((void)); + void (*clock_buginfo) P((int, struct refclockbug *, struct peer *)); + u_long clock_flags; +}; + +/* + * Function prototypes + */ +/* + * auxiliary PPS interface (implemented by refclock_atom()) + */ +extern int pps_sample P((l_fp *)); +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 *)); +extern int refclock_open P((char *, int, int)); +extern void refclock_transmit P((struct peer *)); +extern int refclock_ioctl P((int, int)); +extern int refclock_process P((struct refclockproc *)); +extern void refclock_process_offset P((struct refclockproc *, l_fp, l_fp, double)); +extern void refclock_report P((struct peer *, int)); +extern int refclock_gtlin P((struct recvbuf *, char *, int, + l_fp *)); +#endif /* REFCLOCK */ + +#endif /* NTP_REFCLOCK_H */ diff --git a/contrib/ntp/include/ntp_request.h b/contrib/ntp/include/ntp_request.h new file mode 100644 index 000000000000..87dba8815433 --- /dev/null +++ b/contrib/ntp/include/ntp_request.h @@ -0,0 +1,790 @@ +/* + * ntp_request.h - definitions for the ntpd 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_int32 keyid; /* encryption key */ + char mac[MAX_MAC_LEN-sizeof(u_int32)]; /* (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, version) \ + ((u_char)(((resp)?RESP_BIT:0)\ + |((more)?MORE_BIT:0)\ + |((version?version:(NTP_OLDVERSION+1))<<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)((((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 ntpd. + */ +#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 10. + +/* + * Universal request codes go here. There aren't any. + */ + +/* + * NTPD 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 /* (not used) */ +#define REQ_NOMONITOR 15 /* (not used) */ +#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 /* (not used) */ +#define REQ_DONT_DIRTY_HACK 25 /* (not used) */ +#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 /* (not used) */ +#define REQ_GET_CLOCKINFO 36 /* get clock information */ +#define REQ_SET_CLKFUDGE 37 /* set clock fudge factors */ +#define REQ_GET_KERNEL 38 /* get kernel pll/pps information */ +#define REQ_GET_CLKBUGINFO 39 /* get clock debugging info */ +#define REQ_SET_PRECISION 41 /* (not used) */ +#define REQ_MON_GETLIST_1 42 /* return data collected by monitor v1 */ + +/* + * Flags in the peer information returns + */ +#define INFO_FLAG_CONFIG 0x1 +#define INFO_FLAG_SYSPEER 0x2 +#define INFO_FLAG_BURST 0x4 +#define INFO_FLAG_REFCLOCK 0x8 +#define INFO_FLAG_PREFER 0x10 +#define INFO_FLAG_AUTHENABLE 0x20 +#define INFO_FLAG_SEL_CANDIDATE 0x40 +#define INFO_FLAG_SHORTLIST 0x80 + +/* + * Flags in the system information returns + */ +#define INFO_FLAG_BCLIENT 0x1 +#define INFO_FLAG_AUTHENTICATE 0x2 +#define INFO_FLAG_NTP 0x4 +#define INFO_FLAG_KERNEL 0x8 +#define INFO_FLAG_MONITOR 0x40 +#define INFO_FLAG_FILEGEN 0x80 +#define INFO_FLAG_PLL_SYNC 0x10 +#define INFO_FLAG_PPS_SYNC 0x20 + +/* + * 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_int32 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_int32 dstadr; /* local address (zero for undetermined) */ + u_int32 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_int32 dstadr; /* local address */ + u_int32 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 flash; /* old peer.flash */ + u_char ttl; /* peer.ttl */ + u_short flash2; /* new peer.flash */ + u_short associd; /* association ID */ + u_int32 keyid; /* peer.keyid */ + u_int32 pkeyid; /* unused */ + u_int32 refid; /* peer.refid */ + u_int32 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_fp selectdisp; /* peer select dispersion */ + int32 unused1; /* (obsolete) */ + int32 unused2; + int32 unused3; + int32 unused4; + int32 unused5; + int32 unused6; + int32 unused7; + s_fp estbdelay; /* broadcast offset */ +}; + + +/* + * Peer statistics structure + */ +struct info_peer_stats { + u_int32 dstadr; /* local address */ + u_int32 srcadr; /* remote address */ + u_short srcport; /* remote port */ + u_short flags; /* peer flags */ + u_int32 timereset; /* time counters were reset */ + u_int32 timereceived; /* time since a packet received */ + u_int32 timetosend; /* time until a packet sent */ + u_int32 timereachable; /* time peer has been reachable */ + u_int32 sent; /* number sent */ + u_int32 unused1; /* (unused) */ + u_int32 processed; /* number processed */ + u_int32 unused2; /* (unused) */ + u_int32 badauth; /* bad authentication */ + u_int32 bogusorg; /* bogus origin */ + u_int32 oldpkt; /* duplicate */ + u_int32 unused3; /* (unused) */ + u_int32 unused4; /* (unused) */ + u_int32 seldisp; /* bad dispersion */ + u_int32 selbroken; /* bad reference time */ + u_int32 unused5; /* (unused) */ + u_char candidate; /* select order */ + u_char unused6; /* (unused) */ + u_char unused7; /* (unused) */ + u_char unused8; /* (unused) */ +}; + + +/* + * Loop filter variables + */ +struct info_loop { + l_fp last_offset; + l_fp drift_comp; + u_int32 compliance; + u_int32 watchdog_timer; +}; + + +/* + * System info. Mostly the sys.* variables, plus a few unique to + * the implementation. + */ +struct info_sys { + u_int32 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_int32 refid; /* reference ID of sync source */ + l_fp reftime; /* system reference time */ + u_int32 poll; /* system poll interval */ + u_char flags; /* system flags */ + u_char unused1; /* unused */ + u_char unused2; /* unused */ + u_char unused3; /* unused */ + s_fp bdelay; /* default broadcast offset */ + s_fp frequency; /* frequency residual (scaled ppm) */ + l_fp authdelay; /* default authentication delay */ + u_fp stability; /* clock stability (scaled ppm) */ +}; + + +/* + * System stats. These are collected in the protocol module + */ +struct info_sys_stats { + u_int32 timeup; /* time we have been up and running */ + u_int32 timereset; /* time since these were last cleared */ + u_int32 badstratum; /* packets claiming an invalid stratum */ + u_int32 oldversionpkt; /* old version packets received */ + u_int32 newversionpkt; /* new version packets received */ + u_int32 unknownversion; /* don't know version packets */ + u_int32 badlength; /* packets with bad length */ + u_int32 processed; /* packets processed */ + u_int32 badauth; /* packets dropped because of authorization */ + u_int32 wanderhold; /* (obsolete) */ + u_int32 limitrejected; /* rejected because of client limitation */ +}; + + +/* + * System stats - old version + */ +struct old_info_sys_stats { + u_int32 timeup; /* time we have been up and running */ + u_int32 timereset; /* time since these were last cleared */ + u_int32 badstratum; /* packets claiming an invalid stratum */ + u_int32 oldversionpkt; /* old version packets received */ + u_int32 newversionpkt; /* new version packets received */ + u_int32 unknownversion; /* don't know version packets */ + u_int32 badlength; /* packets with bad length */ + u_int32 processed; /* packets processed */ + u_int32 badauth; /* packets dropped because of authorization */ + u_int32 wanderhold; +}; + + +/* + * Peer memory statistics. Collected in the peer module. + */ +struct info_mem_stats { + u_int32 timereset; /* time since reset */ + u_short totalpeermem; + u_short freepeermem; + u_int32 findpeer_calls; + u_int32 allocations; + u_int32 demobilizations; + u_char hashcount[HASH_SIZE]; +}; + + +/* + * I/O statistics. Collected in the I/O module + */ +struct info_io_stats { + u_int32 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_int32 dropped; /* dropped packets */ + u_int32 ignored; /* ignored packets */ + u_int32 received; /* received packets */ + u_int32 sent; /* packets sent */ + u_int32 notsent; /* packets not sent */ + u_int32 interrupts; /* interrupts we've handled */ + u_int32 int_received; /* received by interrupt handler */ +}; + + +/* + * Timer stats. Guess where from. + */ +struct info_timer_stats { + u_int32 timereset; /* time since reset */ + u_int32 alarms; /* alarms we've handled */ + u_int32 overflows; /* timer overflows */ + u_int32 xmtcalls; /* calls to xmit */ +}; + + +/* + * Structure for passing peer configuration information + */ +struct conf_peer { + u_int32 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 ttl; /* time to live (multicast) or refclock mode */ + u_short unused; /* unused */ + u_int32 keyid; /* key to use for this association */ +}; + +#define CONF_FLAG_AUTHENABLE 0x1 +#define CONF_FLAG_PREFER 0x2 +#define CONF_FLAG_BURST 0x4 +#define CONF_FLAG_NOSELECT 0x8 +#define CONF_FLAG_SKEY 0x10 + +/* + * Structure for passing peer deletion information. Currently + * we only pass the address and delete all configured peers with + * this addess. + */ +struct conf_unpeer { + u_int32 peeraddr; /* address of peer */ +}; + +/* + * Structure for carrying system flags. + */ +struct conf_sys_flags { + u_int32 flags; +}; + +/* + * System flags we can set/clear + */ +#define SYS_FLAG_BCLIENT 0x1 +#define SYS_FLAG_AUTHENTICATE 0x2 +#define SYS_FLAG_NTP 0x4 +#define SYS_FLAG_KERNEL 0x8 +#define SYS_FLAG_MONITOR 0x10 +#define SYS_FLAG_FILEGEN 0x20 + +/* + * Structure used for returning restrict entries + */ +struct info_restrict { + u_int32 addr; /* match address */ + u_int32 mask; /* match mask */ + u_int32 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_int32 addr; /* match address */ + u_int32 mask; /* match mask */ + u_short flags; /* restrict flags */ + u_short mflags; /* match flags */ +}; + + +/* + * Structure used for returning monitor data + */ +struct info_monitor_1 { + u_int32 lasttime; /* last packet from this host */ + u_int32 firsttime; /* first time we received a packet */ + u_int32 lastdrop; /* last time we rejected a packet due to client limitation policy */ + u_int32 count; /* count of packets received */ + u_int32 addr; /* host address */ + u_int32 daddr; /* destination host address */ + u_int32 flags; /* flags about destination */ + 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 returning monitor data + */ +struct info_monitor { + u_int32 lasttime; /* last packet from this host */ + u_int32 firsttime; /* first time we received a packet */ + u_int32 lastdrop; /* last time we rejected a packet due to client limitation policy */ + u_int32 count; /* count of packets received */ + u_int32 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 returning monitor data (old format + */ +struct old_info_monitor { + u_int32 lasttime; /* last packet from this host */ + u_int32 firsttime; /* first time we received a packet */ + u_int32 count; /* count of packets received */ + u_int32 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_int32 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_int32 timereset; /* time counters were reset */ + u_int32 numkeys; /* number of keys we know */ + u_int32 numfreekeys; /* number of free keys */ + u_int32 keylookups; /* calls to authhavekey() */ + u_int32 keynotfound; /* requested key unknown */ + u_int32 encryptions; /* number of encryptions */ + u_int32 decryptions; /* number of decryptions */ + u_int32 expired; /* number of expired keys */ + u_int32 keyuncached; /* calls to encrypt/decrypt with uncached key */ +}; + + +/* + * Structure used to pass trap information to the client + */ +struct info_trap { + u_int32 local_address; /* local interface address */ + u_int32 trap_address; /* remote client's address */ + u_short trap_port; /* remote port number */ + u_short sequence; /* sequence number */ + u_int32 settime; /* time trap last set */ + u_int32 origtime; /* time trap originally set */ + u_int32 resets; /* number of resets on this trap */ + u_int32 flags; /* trap flags, as defined in ntp_control.h */ +}; + +/* + * Structure used to pass add/clear trap information to the client + */ +struct conf_trap { + u_int32 local_address; /* local interface address */ + u_int32 trap_address; /* remote client's address */ + u_short trap_port; /* remote client's port */ + u_short unused; /* (unused) */ +}; + + +/* + * Structure used to return statistics from the control module + */ +struct info_control { + u_int32 ctltimereset; + u_int32 numctlreq; /* number of requests we've received */ + u_int32 numctlbadpkts; /* number of bad control packets */ + u_int32 numctlresponses; /* # resp packets sent */ + u_int32 numctlfrags; /* # of fragments sent */ + u_int32 numctlerrors; /* number of error responses sent */ + u_int32 numctltooshort; /* number of too short input packets */ + u_int32 numctlinputresp; /* number of responses on input */ + u_int32 numctlinputfrag; /* number of fragments on input */ + u_int32 numctlinputerr; /* # input pkts with err bit set */ + u_int32 numctlbadoffset; /* # input pkts with nonzero offset */ + u_int32 numctlbadversion; /* # input pkts with unknown version */ + u_int32 numctldatatooshort; /* data too short for count */ + u_int32 numctlbadop; /* bad op code found in packet */ + u_int32 numasyncmsgs; /* # async messages we've sent */ +}; + + +/* + * Structure used to return clock information + */ +struct info_clock { + u_int32 clockadr; + u_char type; + u_char flags; + u_char lastevent; + u_char currentstatus; + u_int32 polls; + u_int32 noresponse; + u_int32 badformat; + u_int32 baddata; + u_int32 timestarted; + l_fp fudgetime1; + l_fp fudgetime2; + int32 fudgeval1; + int32 fudgeval2; +}; + + +/* + * Structure used for setting clock fudge factors + */ +struct conf_fudge { + u_int32 clockadr; + u_int32 which; + l_fp fudgetime; + int32 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_int32 clockadr; + u_char nvalues; + u_char ntimes; + u_short svalues; + u_int32 stimes; + u_int32 values[NUMCBUGVALUES]; + l_fp times[NUMCBUGTIMES]; +}; + +/* + * Structure used for returning kernel pll/PPS information + */ +struct info_kernel { + int32 offset; + int32 freq; + int32 maxerror; + int32 esterror; + u_short status; + u_short shift; + int32 constant; + int32 precision; + int32 tolerance; + +/* + * Variables used only if PPS signal discipline is implemented + */ + int32 ppsfreq; + int32 jitter; + int32 stabil; + int32 jitcnt; + int32 calcnt; + int32 errcnt; + int32 stbcnt; +}; diff --git a/contrib/ntp/include/ntp_select.h b/contrib/ntp/include/ntp_select.h new file mode 100644 index 000000000000..79c0fc0a56bf --- /dev/null +++ b/contrib/ntp/include/ntp_select.h @@ -0,0 +1,35 @@ +/* + * Not all machines define FD_SET in sys/types.h + */ +#ifndef _ntp_select_h +#define _ntp_select_h + +/* Was: (defined(RS6000)||defined(SYS_PTX))&&!defined(_BSD) */ +/* Could say: !defined(FD_SET) && defined(HAVE_SYS_SELECT_H) */ +#if defined(HAVE_SYS_SELECT_H) && !defined(_BSD) +#ifndef SYS_VXWORKS +#include +#else +#include +extern int select P((int width, fd_set *pReadFds, fd_set *pWriteFds, + fd_set *pExceptFds, struct timeval *pTimeOut)); + +#endif +#endif + +#if !defined(FD_SET) && !defined(SYS_WINNT) +#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 + +#if defined(VMS) +typedef struct { + unsigned int fds_bits[1]; +} fd_set; +#endif + +#endif /* _ntp_select_h */ diff --git a/contrib/ntp/include/ntp_stdlib.h b/contrib/ntp/include/ntp_stdlib.h new file mode 100644 index 000000000000..6a2a85221267 --- /dev/null +++ b/contrib/ntp/include/ntp_stdlib.h @@ -0,0 +1,172 @@ +/* + * ntp_stdlib.h - Prototypes for NTP lib. + */ +#include + +#include "ntp_types.h" +#include "ntp_string.h" +#include "l_stdlib.h" + +/* + * Handle gcc __attribute__ if available. + */ +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || (defined(__STRICT_ANSI__)) +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __format__ format +# define __printf__ printf +# endif +#endif + +#if defined(__STDC__) || defined(HAVE_STDARG_H) +# include +extern void msyslog P((int, const char *, ...)) + __attribute__((__format__(__printf__, 2, 3))); +#else +# include +extern void msyslog P(()); +#endif + +#if 0 /* HMS: These seem to be unused now */ +extern void auth_des P((u_long *, u_char *)); +extern void auth_delkeys P((void)); +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 *)); +#endif + +extern void auth1crypt P((u_long, u_int32 *, int)); +extern int auth2crypt P((u_long, u_int32 *, int)); +extern void auth_delkeys P((void)); +extern int auth_havekey P((u_long)); +extern int authdecrypt P((u_long, u_int32 *, int, int)); +extern int authencrypt P((u_long, u_int32 *, int)); +extern int authhavekey P((u_long)); +extern int authistrusted P((u_long)); +extern int authreadkeys P((const char *)); +extern void authtrust P((u_long, int)); +extern int authusekey P((u_long, int, const u_char *)); + +extern u_long calleapwhen P((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_int32 *)); +#if defined SYS_WINNT && defined DEBUG +# define emalloc(_c) debug_emalloc(_c, __FILE__, __LINE__) +extern void * debug_emalloc P((u_int, char *, int)); +#else +extern void * emalloc P((u_int)); +#endif +extern int ntp_getopt P((int, char **, const char *)); +extern void init_auth P((void)); +extern void init_lib P((void)); +extern void init_random P((void)); +extern struct savekey *auth_findkey P((u_long)); +extern int auth_moremem P((void)); +extern int ymd2yd P((int, int, int)); + +#ifdef DES +extern int DESauthdecrypt P((u_char *, u_int32 *, int, int)); +extern int DESauthencrypt P((u_char *, u_int32 *, int)); +extern void DESauth_setkey P((u_long, const u_int32 *)); +extern void DESauth_subkeys P((const u_int32 *, u_char *, u_char *)); +extern void DESauth_des P((u_int32 *, u_char *)); +extern int DESauth_parity P((u_int32 *)); +#endif /* DES */ + +#ifdef MD5 +extern int MD5authdecrypt P((u_char *, u_int32 *, int, int)); +extern int MD5authencrypt P((u_char *, u_int32 *, int)); +extern void MD5auth_setkey P((u_long, const u_char *, const int)); +extern u_long session_key P((u_int32, u_int32, u_long, 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 * humanlogtime P((void)); +extern char * inttoa P((long)); +extern char * mfptoa P((u_long, u_long, int)); +extern char * mfptoms P((u_long, u_long, int)); +extern const char * modetoa P((int)); +extern const char * eventstr P((int)); +extern const char * ceventstr P((int)); +extern char * statustoa P((int, int)); +extern const char * sysstatstr P((int)); +extern const char * peerstatstr P((int)); +extern const char * clockstatstr P((int)); +extern u_int32 netof P((u_int32)); +extern char * numtoa P((u_int32)); +extern char * numtohost P((u_int32)); +extern int octtoint P((const char *, u_long *)); +extern u_long ranp2 P((int)); +extern char * refnumtoa P((u_int32)); +extern int tsftomsu P((u_long, int)); +extern char * uinttoa P((u_long)); + +extern int decodenetnum P((const char *, u_int32 *)); + +extern const char * FindConfig P((const char *)); + +extern void signal_no_reset P((int, RETSIGTYPE (*func)(int))); + +extern void getauthkeys P((char *)); +extern void auth_agekeys P((void)); +extern void rereadkeys P((void)); + +/* + * Variable declarations for libntp. + */ + +/* + * Defined by any program. + */ +extern volatile int debug; /* debugging flag */ + +/* authkeys.c */ +extern u_long authkeynotfound; /* keys not found */ +extern u_long authkeylookups; /* calls to lookup keys */ +extern u_long authnumkeys; /* number of active keys */ +extern u_long authkeyexpired; /* key lifetime expirations */ +extern u_long authkeyuncached; /* cache misses */ +extern u_long authencryptions; /* calls to encrypt */ +extern u_long authdecryptions; /* calls to decrypt */ + +extern int authnumfreekeys; + +/* + * The key cache. We cache the last key we looked at here. + */ +extern u_long cache_keyid; /* key identifier */ +extern u_char * cache_key; /* key pointer */ +extern u_int cache_keylen; /* key length */ + +/* clocktypes.c */ +struct clktype; +extern struct clktype clktypes[]; + +/* getopt.c */ +extern char * ntp_optarg; /* global argument pointer */ +extern int ntp_optind; /* global argv index */ + +/* machines.c */ +extern const char *set_tod_using; + +/* mexit.c */ +#if defined SYS_WINNT || defined SYS_CYGWIN32 +extern HANDLE hServDoneEvent; +#endif + +/* systime.c */ +extern int systime_10ms_ticks; /* adj sysclock in 10ms increments */ + +extern double sys_maxfreq; /* max frequency correction */ + +/* version.c */ +extern const char *Version; /* version declaration */ diff --git a/contrib/ntp/include/ntp_string.h b/contrib/ntp/include/ntp_string.h new file mode 100644 index 000000000000..f7f0092ae493 --- /dev/null +++ b/contrib/ntp/include/ntp_string.h @@ -0,0 +1,48 @@ +/* + * Define string ops: strchr strrchr memcmp memmove memset + */ + +#ifndef _ntp_string_h +#define _ntp_string_h + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_MEMORY_H +# include +#endif + +#ifdef HAVE_STRING_H +# include +#endif + +#ifdef HAVE_BSTRING_H +# include +#endif + +#ifndef STDC_HEADERS +# ifndef HAVE_STRCHR +# include +# define strchr index +# define strrchr rindex +# endif +# ifndef __GNUC__ +char *strchr(), *strrchr(); +# endif +# ifndef HAVE_MEMCPY +# define NTP_NEED_BOPS +# endif +#endif /* STDC_HEADERS */ + +#ifdef NTP_NEED_BOPS +# define memcmp(a,b,c) bcmp(a,b,(int)c) +# define memmove(t,f,c) bcopy(f,t,(int)c) +# define memcpy(t,f,c) bcopy(f,t,(int)c) +# define memset(a,x,c) if (x == 0x00) bzero(a,(int)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/ntp/include/ntp_syscall.h b/contrib/ntp/include/ntp_syscall.h new file mode 100644 index 000000000000..ff649c9a10df --- /dev/null +++ b/contrib/ntp/include/ntp_syscall.h @@ -0,0 +1,48 @@ +/* + * ntp_syscall.h - various ways to perform the ntp_adjtime() and ntp_gettime() + * system calls. + */ + +#ifndef NTP_SYSCALL_H +#define NTP_SYSCALL_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_TIMEX_H +# include +#endif + +#ifdef NTP_SYSCALLS_STD +# define ntp_adjtime(t) syscall(SYS_ntp_adjtime, (t)) +# define ntp_gettime(t) syscall(SYS_ntp_gettime, (t)) +#else /* !NTP_SYSCALLS_STD */ +# ifdef HAVE___ADJTIMEX +extern int __adjtimex P((struct timex *)); + +# define ntp_adjtime(t) __adjtimex((t)) + +static inline int +ntp_gettime( + struct ntptimeval *ntv + ) +{ + struct timex tntx; + int result; + + tntx.modes = 0; + result = __adjtimex (&tntx); + ntv->time = tntx.time; + ntv->maxerror = tntx.maxerror; + ntv->esterror = tntx.esterror; + return(result); +} +# else /* !HAVE__ADJTIMEX */ +# ifdef HAVE___NTP_GETTIME +# define ntp_gettime(t) __ntp_gettime((t)) +# endif +# endif /* !HAVE_ADJTIMEX */ +#endif /* !NTP_SYSCALLS_STD */ + +#endif /* NTP_SYSCALL_H */ diff --git a/contrib/ntp/include/ntp_syslog.h b/contrib/ntp/include/ntp_syslog.h new file mode 100644 index 000000000000..8e47c5673982 --- /dev/null +++ b/contrib/ntp/include/ntp_syslog.h @@ -0,0 +1,77 @@ +/* + * A hack for platforms which require specially built syslog facilities + */ + +#ifndef NTP_SYSLOG_H +#define NTP_SYSLOG_H + +#ifdef GIZMO +# include "gizmo_syslog.h" +#else /* !GIZMO */ + +# ifdef VMS +extern void msyslog(); +# else +# ifndef SYS_VXWORKS +# include +# endif +# endif /* VMS */ + +# include + +#endif /* GIZMO */ + +extern int syslogit; +extern FILE *syslog_file; + +#if defined(VMS) || defined (SYS_VXWORKS) +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but signification condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ +#endif /* VMS || VXWORKS */ + +/* + * syslog output control + */ +#define NLOG_INFO 0x00000001 +#define NLOG_EVENT 0x00000002 +#define NLOG_STATUS 0x00000004 +#define NLOG_STATIST 0x00000008 + +#define NLOG_OSYS 0 /* offset for system flags */ +#define NLOG_SYSMASK 0x0000000F /* system log events */ +#define NLOG_SYSINFO 0x00000001 /* system info log events */ +#define NLOG_SYSEVENT 0x00000002 /* system events */ +#define NLOG_SYSSTATUS 0x00000004 /* system status (sync/unsync) */ +#define NLOG_SYSSTATIST 0x00000008 /* system statistics output */ + +#define NLOG_OPEER 4 /* offset for peer flags */ +#define NLOG_PEERMASK 0x000000F0 /* peer log events */ +#define NLOG_PEERINFO 0x00000010 /* peer info log events */ +#define NLOG_PEEREVENT 0x00000020 /* peer events */ +#define NLOG_PEERSTATUS 0x00000040 /* peer status (sync/unsync) */ +#define NLOG_PEERSTATIST 0x00000080 /* peer statistics output */ + +#define NLOG_OCLOCK 8 /* offset for clock flags */ +#define NLOG_CLOCKMASK 0x00000F00 /* clock log events */ +#define NLOG_CLOCKINFO 0x00000100 /* clock info log events */ +#define NLOG_CLOCKEVENT 0x00000200 /* clock events */ +#define NLOG_CLOCKSTATUS 0x00000400 /* clock status (sync/unsync) */ +#define NLOG_CLOCKSTATIST 0x00000800 /* clock statistics output */ + +#define NLOG_OSYNC 12 /* offset for sync flags */ +#define NLOG_SYNCMASK 0x0000F000 /* sync log events */ +#define NLOG_SYNCINFO 0x00001000 /* sync info log events */ +#define NLOG_SYNCEVENT 0x00002000 /* sync events */ +#define NLOG_SYNCSTATUS 0x00004000 /* sync status (sync/unsync) */ +#define NLOG_SYNCSTATIST 0x00008000 /* sync statistics output */ + +extern unsigned long ntp_syslogmask; +#define NLOG(_X_) if (ntp_syslogmask & (_X_)) + +#endif /* NTP_SYSLOG_H */ diff --git a/contrib/ntp/include/ntp_types.h b/contrib/ntp/include/ntp_types.h new file mode 100644 index 000000000000..820c72aeedd1 --- /dev/null +++ b/contrib/ntp/include/ntp_types.h @@ -0,0 +1,69 @@ +/* + * ntp_types.h - defines how int32 and u_int32 are treated. + * For 64 bit systems like the DEC Alpha, they have 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 us as a packet 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(HAVE_PROTOTYPES) +#define P(x) x +#else /* not __STDC__ and not HAVE_PROTOTYPES */ +#define P(x) () +#endif /* not __STDC__ and HAVE_PROTOTYPES */ +#endif /* P */ + +/* + * VMS DECC (v4.1), {u_char,u_short,u_long} are only in SOCKET.H, + * and u_int isn't defined anywhere + */ +#if defined(VMS) +#include +typedef unsigned int u_int; +/* + * Note: VMS DECC has long == int (even on __alpha), + * so the distinction below doesn't matter + */ +#endif /* VMS */ + +#if (SIZEOF_INT == 4) +# ifndef int32 +# define int32 int +# endif +# ifndef u_int32 +# define u_int32 unsigned int +# endif +#else /* not sizeof(int) == 4 */ +# if (SIZEOF_LONG == 4) +# else /* not sizeof(long) == 4 */ +# ifndef int32 +# define int32 long +# endif +# ifndef u_int32 +# define u_int32 unsigned long +# endif +# endif /* not sizeof(long) == 4 */ +# include "Bletch: what's 32 bits on this machine?" +#endif /* not sizeof(int) == 4 */ + +#endif /* _NTP_TYPES_ */ + diff --git a/contrib/ntp/include/ntp_unixtime.h b/contrib/ntp/include/ntp_unixtime.h new file mode 100644 index 000000000000..9dd23f0e8eda --- /dev/null +++ b/contrib/ntp/include/ntp_unixtime.h @@ -0,0 +1,132 @@ +/* + * ntp_unixtime.h - contains constants and macros for converting between + * NTP time stamps (l_fp) and Unix times (struct timeval) + */ + +#include "ntp_types.h" + +#include + +/* gettimeofday() takes two args in BSD and only one in SYSV */ +# if defined(HAVE_SYS_TIMERS_H) && defined(HAVE_GETCLOCK) +# include +int getclock (int clock_type, struct timespec *tp); +/* Don't #define GETTIMEOFDAY because we shouldn't be using it in this case. */ +# define SETTIMEOFDAY(a, b) (settimeofday(a, b)) +# else /* not (HAVE_SYS_TIMERS_H && HAVE_GETCLOCK) */ +# ifdef SYSV_TIMEOFDAY +# define GETTIMEOFDAY(a, b) (gettimeofday(a)) +# define SETTIMEOFDAY(a, b) (settimeofday(a)) +# else /* ! SYSV_TIMEOFDAY */ +#if defined SYS_CYGWIN32 +# define GETTIMEOFDAY(a, b) (gettimeofday(a, b)) +# define SETTIMEOFDAY(a, b) (settimeofday_NT(a)) +#else +# define GETTIMEOFDAY(a, b) (gettimeofday(a, b)) +# define SETTIMEOFDAY(a, b) (settimeofday(a, b)) +#endif +# endif /* SYSV_TIMEOFDAY */ +# endif /* not (HAVE_SYS_TIMERS_H && HAVE_GETCLOCK) */ + +/* + * 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 = (u_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/ntp/include/ntpd.h b/contrib/ntp/include/ntpd.h new file mode 100644 index 000000000000..1a83d6eb0a6c --- /dev/null +++ b/contrib/ntp/include/ntpd.h @@ -0,0 +1,381 @@ +/* + * ntpd.h - Prototypes for ntpd. + */ + +#include "ntp_syslog.h" +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_select.h" +#include "ntp_malloc.h" +#include "ntp_refclock.h" +#include "recvbuff.h" + +#define MAXINTERFACES 512 + +#ifdef SYS_WINNT +#define exit service_exit +extern void service_exit (int); +/* declare the service threads */ +void service_main (DWORD, LPTSTR *); +void service_ctrl (DWORD); +void worker_thread (void *); +#define sleep(x) Sleep((DWORD) x * 1000 /* milliseconds */ ); +#else +#define closesocket close +#endif /* SYS_WINNT */ + +/* 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 *)); + +extern double fabs P((double)); +extern double sqrt P((double)); + +/* 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 **, const 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 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 io_multicast_add P((u_int32)); +extern void io_multicast_del P((u_int32)); +extern void kill_asyncio P((void)); + +extern void sendpkt P((struct sockaddr_in *, struct interface *, int, 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((struct peer *, double, double)); +extern void adj_host_clock P((void)); +extern void loop_config P((int, double)); + +/* ntp_monitor.c */ +extern void init_mon P((void)); +extern void mon_start P((int)); +extern void mon_stop P((int)); +extern void ntp_monitor P((struct recvbuf *)); + +/* ntp_peer.c */ +extern void init_peer P((void)); +extern struct peer *findexistingpeer P((struct sockaddr_in *, struct peer *, int)); +extern struct peer *findpeer P((struct sockaddr_in *, struct interface *, int, int, int *)); +extern struct peer *findpeerbyassoc P((int)); +extern struct peer *newpeer P((struct sockaddr_in *, struct interface *, int, 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, int, int, u_long)); +extern void peer_reset P((struct peer *)); +extern int peer_unconfig P((struct sockaddr_in *, struct interface *, int)); +extern void unpeer P((struct peer *)); +extern void key_expire_all P((void)); +extern struct peer *findmanycastpeer P((l_fp *)); +extern void peer_config_manycast P((struct peer *, 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 *)); +extern void clock_select P((void)); + +/* + * 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 *, int)); + +extern void clear P((struct peer *)); +extern void clock_filter P((struct peer *, double, double, double)); +extern void init_proto P((void)); +extern void proto_config P((int, u_long, double)); +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 *)); +extern void refclock_transmit P((struct peer *)); +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 hack_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_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, double, double, double, double)); +extern void record_loop_stats P((void)); +extern void record_clock_stats P((struct sockaddr_in *, const char *)); +extern void record_raw_stats P((struct sockaddr_in *, struct sockaddr_in *, l_fp *, l_fp *, l_fp *, l_fp *)); + +/* + * Variable declarations for ntpd. + */ + +/* ntp_config.c */ +extern char const * progname; +extern char sys_phone[][MAXDIAL]; /* ACTS phone numbers */ +extern char pps_device[]; /* PPS device name */ +#if defined(HAVE_SCHED_SETSCHEDULER) +extern int config_priority_override; +extern int config_priority; +#endif + +/* ntp_control.c */ +struct ctl_trap; +extern struct ctl_trap ctl_trap[]; +extern int num_ctl_traps; +extern u_long ctl_auth_keyid; /* keyid used for authenticating write requests */ + +/* + * Statistic counters to keep track of requests and responses. + */ +extern u_long ctltimereset; /* time stats reset */ +extern u_long numctlreq; /* number of requests we've received */ +extern u_long numctlbadpkts; /* number of bad control packets */ +extern u_long numctlresponses; /* number of resp packets sent with data */ +extern u_long numctlfrags; /* number of fragments sent */ +extern u_long numctlerrors; /* number of error responses sent */ +extern u_long numctltooshort; /* number of too short input packets */ +extern u_long numctlinputresp; /* number of responses on input */ +extern u_long numctlinputfrag; /* number of fragments on input */ +extern u_long numctlinputerr; /* number of input pkts with err bit set */ +extern u_long numctlbadoffset; /* number of input pkts with nonzero offset */ +extern u_long numctlbadversion; /* number of input pkts with unknown version */ +extern u_long numctldatatooshort; /* data too short for count */ +extern u_long numctlbadop; /* bad op code found in packet */ +extern u_long numasyncmsgs; /* number of async messages we've sent */ + +/* ntp_intres.c */ +extern u_long req_keyid; /* request keyid */ +extern char * req_file; /* name of the file with configuration info */ + +/* + * Other statistics of possible interest + */ +extern volatile u_long packets_dropped; /* total number of packets dropped on reception */ +extern volatile u_long packets_ignored; /* packets received on wild card interface */ +extern volatile u_long packets_received;/* total number of packets received */ +extern u_long packets_sent; /* total number of packets sent */ +extern u_long packets_notsent; /* total number of packets which couldn't be sent */ + +extern volatile u_long handler_calls; /* number of calls to interrupt handler */ +extern volatile u_long handler_pkts; /* number of pkts received by handler */ +extern u_long io_timereset; /* time counters were reset */ + +/* + * Interface stuff + */ +extern struct interface *any_interface; /* pointer to default interface */ +extern struct interface *loopback_interface; /* point to loopback interface */ + +/* + * File descriptor masks etc. for call to select + */ +extern fd_set activefds; +extern int maxactivefd; + +/* ntp_loopfilter.c */ +extern double drift_comp; /* clock frequency (ppm) */ +extern double clock_stability; /* clock stability (ppm) */ +extern double clock_max; /* max offset allowed before step (s) */ +extern u_long pps_control; /* last pps sample time */ + +/* + * Clock state machine control flags + */ +extern int ntp_enable; /* clock discipline enabled */ +extern int pll_control; /* kernel support available */ +extern int kern_enable; /* kernel support enabled */ +extern int ext_enable; /* external clock enabled */ +extern int pps_update; /* pps update valid */ +extern int allow_set_backward; /* step corrections allowed */ +extern int correct_any; /* corrections > 1000 s allowed */ + +/* + * Clock state machine variables + */ +extern u_char sys_poll; /* log2 of system poll interval */ +extern int state; /* clock discipline state */ +extern int tc_counter; /* poll-adjust counter */ +extern u_long last_time; /* time of last clock update (s) */ +extern double last_offset; /* last clock offset (s) */ +extern double allan_xpt; /* Allan intercept (s) */ +extern double sys_error; /* system standard error (s) */ + +/* ntp_monitor.c */ +extern struct mon_data mon_mru_list; +extern struct mon_data mon_fifo_list; +extern int mon_enabled; + +/* ntp_peer.c */ +extern struct peer *peer_hash[]; /* peer hash table */ +extern int peer_hash_count[]; /* count of peers in each bucket */ +extern struct peer *assoc_hash[]; /* association ID hash table */ +extern int assoc_hash_count[]; +extern int peer_free_count; + +/* + * Miscellaneous statistic counters which may be queried. + */ +extern u_long peer_timereset; /* time stat counters were zeroed */ +extern u_long findpeer_calls; /* number of calls to findpeer */ +extern u_long assocpeer_calls; /* number of calls to findpeerbyassoc */ +extern u_long peer_allocations; /* number of allocations from the free list */ +extern u_long peer_demobilizations; /* number of structs freed to free list */ +extern int total_peer_structs; /* number of peer structs in circulation */ +extern int peer_associations; /* number of active associations */ + +/* ntp_proto.c */ +/* + * System variables are declared here. See Section 3.2 of the + * specification. + */ +extern u_char sys_leap; /* system leap indicator */ +extern u_char sys_stratum; /* stratum of system */ +extern s_char sys_precision; /* local clock precision */ +extern double sys_rootdelay; /* distance to current sync source */ +extern double sys_rootdispersion; /* dispersion of system clock */ +extern u_int32 sys_refid; /* reference source for local clock */ +extern l_fp sys_reftime; /* time we were last updated */ +extern struct peer *sys_peer; /* our current peer */ +extern u_long sys_automax; /* maximum session key lifetime */ + +/* + * Nonspecified system state variables. + */ +extern int sys_bclient; /* we set our time to broadcasts */ +extern double sys_bdelay; /* broadcast client default delay */ +extern int sys_authenticate; /* requre authentication for config */ +extern l_fp sys_authdelay; /* authentication delay */ +extern u_long sys_private; /* private value for session seed */ +extern int sys_manycastserver; /* 1 => respond to manycast client pkts */ + +/* + * Statistics counters + */ +extern u_long sys_stattime; /* time when we started recording */ +extern u_long sys_badstratum; /* packets with invalid stratum */ +extern u_long sys_oldversionpkt; /* old version packets received */ +extern u_long sys_newversionpkt; /* new version packets received */ +extern u_long sys_unknownversion; /* don't know version packets */ +extern u_long sys_badlength; /* packets with bad length */ +extern u_long sys_processed; /* packets processed */ +extern u_long sys_badauth; /* packets dropped because of auth */ +extern u_long sys_limitrejected; /* pkts rejected due to client count per net */ + +/* ntp_refclock.c */ +#ifdef REFCLOCK +#if defined(PPS) || defined(HAVE_PPSAPI) +extern int fdpps; /* pps file descriptor */ +#endif /* PPS */ +#endif + +/* ntp_request.c */ +extern u_long info_auth_keyid; /* keyid used to authenticate requests */ + +/* ntp_restrict.c */ +extern struct restrictlist *restrictlist; /* the restriction list */ +extern u_long client_limit; +extern u_long client_limit_period; + +/* ntp_timer.c */ +extern volatile int alarm_flag; /* alarm flag */ +extern u_long sys_revoke; /* keys revoke timeout */ +extern volatile u_long alarm_overflow; +extern u_long current_time; /* current time (s) */ +extern u_long timer_timereset; +extern u_long timer_overflows; +extern u_long timer_xmtcalls; + +/* ntp_util.c */ +extern int stats_control; /* write stats to fileset? */ + +/* ntpd.c */ +extern volatile int debug; /* debugging flag */ +extern int nofork; /* no-fork flag */ +extern int initializing; /* initializing flag */ + +/* refclock_conf.c */ +#ifdef REFCLOCK +extern struct refclock *refclock_conf[]; /* refclock configuration table */ +extern u_char num_refclock_conf; +#endif diff --git a/contrib/ntp/include/parse.h b/contrib/ntp/include/parse.h new file mode 100644 index 000000000000..56a92e95d15a --- /dev/null +++ b/contrib/ntp/include/parse.h @@ -0,0 +1,391 @@ +/* + * /src/NTP/ntp-4/include/parse.h,v 4.5 1998/08/09 22:23:32 kardel RELEASE_19990228_A + * + * parse.h,v 4.5 1998/08/09 22:23:32 kardel RELEASE_19990228_A + * + * Copyright (C) 1989-1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * 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 4.5 1998/08/09 22:23:32 kardel RELEASE_19990228_A"; +#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(HAVE_SYS_STREAM_H) +#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 unsigned int splx P((unsigned int)); +extern unsigned int splhigh P((void)); +extern unsigned int splclock P((void)); +#define MALLOC(_X_) (char *)kmem_alloc(_X_) +#define FREE(_X_, _Y_) kmem_free((caddr_t)_X_, _Y_) +#else +#include +#define MALLOC(_X_) (char *)kmem_alloc(_X_, KM_SLEEP) +#define FREE(_X_, _Y_) kmem_free((caddr_t)_X_, _Y_) +#endif +#else +#define MALLOC(_X_) malloc(_X_) +#define FREE(_X_, _Y_) free(_X_) +#endif + +#if defined(PARSESTREAM) && defined(HAVE_SYS_STREAM_H) +#include +#include +#else /* STREAM */ +#include +#include "ntp_syslog.h" +#ifdef 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 */ + +#if defined(timercmp) && defined(__GNUC__) +#undef timercmp +#endif + +#if !defined(timercmp) +#define timercmp(tvp, uvp, cmp) \ + ((tvp)->tv_sec cmp (uvp)->tv_sec || \ + ((tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)) +#endif + +#ifndef TIMES10 +#define TIMES10(_X_) (((_X_) << 3) + ((_X_) << 1)) +#endif + +/* + * state flags + */ +#define PARSEB_POWERUP 0x00000001 /* no synchronisation */ +#define PARSEB_NOSYNC 0x00000002 /* timecode currently not confirmed */ + +/* + * time zone information + */ +#define PARSEB_ANNOUNCE 0x00000010 /* switch time zone warning (DST switch) */ +#define PARSEB_DST 0x00000020 /* DST in effect */ +#define PARSEB_UTC 0x00000040 /* UTC time */ + +/* + * leap information + */ +#define PARSEB_LEAPDEL 0x00000100 /* LEAP deletion warning */ +#define PARSEB_LEAPADD 0x00000200 /* LEAP addition warning */ +#define PARSEB_LEAPS 0x00000300 /* LEAP warnings */ +#define PARSEB_LEAPSECOND 0x00000400 /* actual leap second */ +/* + * optional status information + */ +#define PARSEB_ALTERNATE 0x00001000 /* alternate antenna used */ +#define PARSEB_POSITION 0x00002000 /* position available */ +#define PARSEB_MESSAGE 0x00004000 /* addtitional message data */ +/* + * feature information + */ +#define PARSEB_S_LEAP 0x00010000 /* supports LEAP */ +#define PARSEB_S_ANTENNA 0x00020000 /* supports antenna information */ +#define PARSEB_S_PPS 0x00040000 /* supports PPS time stamping */ +#define PARSEB_S_POSITION 0x00080000 /* supports position information (GPS) */ + +/* + * time stamp availability + */ +#define PARSEB_TIMECODE 0x10000000 /* valid time code sample */ +#define PARSEB_PPS 0x20000000 /* valid PPS sample */ + +#define PARSE_TCINFO (PARSEB_ANNOUNCE|PARSEB_POWERUP|PARSEB_NOSYNC|PARSEB_DST|\ + PARSEB_UTC|PARSEB_LEAPS|PARSEB_ALTERNATE|PARSEB_S_LEAP|\ + PARSEB_S_LOCATION|PARSEB_TIMECODE|PARSEB_MESSAGE) + +#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_LEAPADD(x) (PARSE_SYNC(x) && (((x) & PARSEB_LEAPS) == PARSEB_LEAPADD)) +#define PARSE_LEAPDEL(x) (PARSE_SYNC(x) && (((x) & PARSEB_LEAPS) == PARSEB_LEAPDEL)) +#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) +#define PARSE_MESSAGE(x) ((x) & PARSEB_MESSAGE) + +/* + * operation flags - lower nibble contains fudge flags + */ +#define PARSE_STATISTICS 0x08 /* enable statistics */ +#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 */ + +/* + * size of buffers + */ +#define PARSE_TCMAX 400 /* maximum addition data size */ + +typedef union timestamp +{ + struct timeval tv; /* timeval - kernel view */ + l_fp fp; /* fixed point - ntp view */ +} timestamp_t; + +/* + * standard time stamp structure + */ +struct parsetime +{ + u_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 usec error */ + u_long parse_state; /* current receiver state */ + unsigned short parse_format; /* format code */ + unsigned short parse_msglen; /* length of message */ + unsigned char parse_msg[PARSE_TCMAX]; /* original messages */ +}; + +typedef struct parsetime parsetime_t; + +/*---------- STREAMS interface ----------*/ + +#ifdef HAVE_SYS_STREAM_H +/* + * ioctls + */ +#define PARSEIOC_ENABLE (('D'<<8) + 'E') +#define PARSEIOC_DISABLE (('D'<<8) + 'D') +#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 + +/* + * ioctl structure + */ +union parsectl +{ + struct parsegettc + { + u_long parse_state; /* last state */ + u_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 + { + u_long parse_cs; /* character size (needed for stripping) */ + } parsesetcs; +}; + +typedef union parsectl parsectl_t; + +/*------ for conversion routines --------*/ + +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) */ + + /* + * private data - fixed format only + */ + unsigned short parse_plen; /* length of private data */ + void *parse_pdata; /* private data pointer */ + + /* + * 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 */ + u_long parse_lstate; /* last state code */ + char *parse_ldata; /* last data buffer */ + unsigned short parse_ldsize; /* last data buffer length */ + u_long parse_badformat; /* number of unparsable pakets */ + + timestamp_t parse_lastchar; /* last time a character was received */ + 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 */ + time_t utctime; /* the actual time - alternative to date/time */ + u_long flags; /* current clock status */ +}; + +typedef struct clocktime clocktime_t; + +/* + * parser related return/error codes + */ +#define CVT_MASK (unsigned)0x0000000F /* conversion exit code */ +#define CVT_NONE (unsigned)0x00000001 /* format not applicable */ +#define CVT_FAIL (unsigned)0x00000002 /* conversion failed - error code returned */ +#define CVT_OK (unsigned)0x00000004 /* conversion succeeded */ +#define CVT_SKIP (unsigned)0x00000008 /* conversion succeeded */ +#define CVT_ADDITIONAL (unsigned)0x00000010 /* additional data is available */ +#define CVT_BADFMT (unsigned)0x00000100 /* general format error - (unparsable) */ +#define CVT_BADDATE (unsigned)0x00000200 /* date field incorrect */ +#define CVT_BADTIME (unsigned)0x00000400 /* time field incorrect */ + +/* + * return codes used by special input parsers + */ +#define PARSE_INP_SKIP 0x00 /* discard data - may have been consumed */ +#define PARSE_INP_TIME 0x01 /* time code assembled */ +#define PARSE_INP_PARSE 0x02 /* parse data using normal algorithm */ +#define PARSE_INP_DATA 0x04 /* additional data to pass up */ +#define PARSE_INP_SYNTH 0x08 /* just pass up synthesized time */ + +/* + * PPS edge info + */ +#define SYNC_ZERO 0x00 +#define SYNC_ONE 0x01 + +struct clockformat +{ + /* special input protocol - implies fixed format */ + u_long (*input) P((parse_t *, unsigned int, timestamp_t *)); + /* conversion routine */ + u_long (*convert) P((unsigned char *, int, struct format *, clocktime_t *, void *)); + /* routine for handling RS232 sync events (time stamps) */ + /* PPS input routine */ + u_long (*syncpps) P((parse_t *, int, timestamp_t *)); + /* time code synthesizer */ + + void *data; /* local parameters */ + const char *name; /* clock format name */ + unsigned short length; /* maximum length of data packet */ + unsigned short plen; /* length of private data - implies fixed format */ +}; + +typedef struct clockformat clockformat_t; + +/* + * parse interface + */ +extern int parse_ioinit P((parse_t *)); +extern void parse_ioend P((parse_t *)); +extern int parse_ioread P((parse_t *, unsigned int, timestamp_t *)); +extern int parse_iopps P((parse_t *, int, timestamp_t *)); +extern void parse_iodone P((parse_t *)); +extern int parse_timecode P((parsectl_t *, parse_t *)); +extern int parse_getfmt P((parsectl_t *, parse_t *)); +extern int parse_setfmt P((parsectl_t *, parse_t *)); +extern int parse_setcs P((parsectl_t *, parse_t *)); + +extern unsigned int parse_restart P((parse_t *, unsigned int)); +extern unsigned int parse_addchar P((parse_t *, unsigned int)); +extern unsigned int parse_end P((parse_t *)); + +extern int Strok P((const unsigned char *, const unsigned char *)); +extern int Stoi P((const unsigned char *, long *, int)); + +extern time_t parse_to_unixtime P((clocktime_t *, u_long *)); +extern u_long updatetimeinfo P((parse_t *, u_long)); +extern void syn_simple P((parse_t *, timestamp_t *, struct format *, u_long)); +extern u_long pps_simple P((parse_t *, int, timestamp_t *)); +extern u_long pps_one P((parse_t *, int, timestamp_t *)); +extern u_long pps_zero P((parse_t *, int, timestamp_t *)); +extern int parse_timedout P((parse_t *, timestamp_t *, struct timeval *)); + +#endif + +/* + * History: + * + * parse.h,v + * Revision 4.5 1998/08/09 22:23:32 kardel + * 4.0.73e2 adjustments + * + * Revision 4.4 1998/06/14 21:09:27 kardel + * Sun acc cleanup + * + * Revision 4.3 1998/06/13 11:49:25 kardel + * STREAM macro gone in favor of HAVE_SYS_STREAM_H + * + * Revision 4.2 1998/06/12 15:14:25 kardel + * fixed prototypes + * + * Revision 4.1 1998/05/24 10:07:59 kardel + * removed old data structure cruft (new input model) + * new PARSE_INP* macros for input handling + * removed old SYNC_* macros from old input model + * (struct clockformat): removed old parse functions in favor of the + * new input model + * updated prototypes + * + * form V3 3.31 - log info deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/include/parse_conf.h b/contrib/ntp/include/parse_conf.h new file mode 100644 index 000000000000..0a30eb635203 --- /dev/null +++ b/contrib/ntp/include/parse_conf.h @@ -0,0 +1,54 @@ +/* + * /src/NTP/ntp-4/include/parse_conf.h,v 4.2 1998/06/14 21:09:28 kardel RELEASE_19990228_A + * + * parse_conf.h,v 4.2 1998/06/14 21:09:28 kardel RELEASE_19990228_A + * + * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * 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 prshrcsid[] = "parse_conf.h,v 4.2 1998/06/14 21:09:28 kardel RELEASE_19990228_A"; +#endif + +/* + * field location structure + */ +#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 + { + unsigned short offset; /* offset into buffer */ + unsigned short length; /* length of field */ + } field_offsets[O_COUNT]; + const unsigned char *fixed_string; /* string with must be chars (blanks = wildcards) */ + u_long flags; +}; +#endif diff --git a/contrib/ntp/include/recvbuff.h b/contrib/ntp/include/recvbuff.h new file mode 100644 index 000000000000..687bc9659a6d --- /dev/null +++ b/contrib/ntp/include/recvbuff.h @@ -0,0 +1,113 @@ +#if !defined __recvbuff_h +#define __recvbuff_h + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "ntp.h" +#include "ntp_fp.h" +#include "ntp_types.h" + +/* + * 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 40 /* this is way too many buffers */ + +#if defined HAVE_IO_COMPLETION_PORT +# include "ntp_iocompletionport.h" +#include "ntp_timer.h" + +# define RECV_BLOCK_IO() EnterCriticalSection(&RecvCritSection) +# define RECV_UNBLOCK_IO() LeaveCriticalSection(&RecvCritSection) + +/* Return the event which is set when items are added to the full list + */ +extern HANDLE get_recv_buff_event P((void)); +#else +# define RECV_BLOCK_IO() +# define RECV_UNBLOCK_IO() +#endif + + +/* + * 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; + struct peer *X_recv_peer; + } X_from_where; +#define recv_srcadr X_from_where.X_recv_srcadr +#define recv_srcclock X_from_where.X_recv_srcclock +#define recv_peer X_from_where.X_recv_peer +#if defined HAVE_IO_COMPLETION_PORT + IoCompletionInfo iocompletioninfo; + WSABUF wsabuff; + DWORD AddressLength; +#else + struct sockaddr_in srcadr; /* where packet came from */ +#endif + struct interface *dstadr; /* interface datagram arrived thru */ + int fd; /* fd on which it was received */ + l_fp recv_time; /* time of arrival */ + void (*receiver) P((struct recvbuf *)); /* routine to receive buffer */ + int recv_length; /* number of octets received */ + union { + struct pkt X_recv_pkt; + u_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 +}; + +extern void init_recvbuff P((int)); + +/* freerecvbuf - make a single recvbuf available for reuse + */ +extern void freerecvbuf P((struct recvbuf *)); + + +extern struct recvbuf * getrecvbufs P((void)); + +/* Get a free buffer (typically used so an async + * read can directly place data into the buffer + * + * The buffer is removed from the free list. Make sure + * you put it back with freerecvbuf() or + */ +extern struct recvbuf *get_free_recv_buffer P((void)); + +/* Add a buffer to the full list + */ +extern void add_full_recv_buffer P((struct recvbuf *)); + +/*extern void process_recv_buffers P((void)); */ + +/* number of recvbufs on freelist */ +extern u_long free_recvbuffs P((void)); +extern u_long full_recvbuffs P((void)); +extern u_long total_recvbuffs P((void)); +extern u_long lowater_additions P((void)); + +/* Returns the next buffer in the full list. + * + */ +extern struct recvbuf *get_full_recv_buffer P((void)); + +#endif /* defined __recvbuff_h */ + diff --git a/contrib/ntp/include/trimble.h b/contrib/ntp/include/trimble.h new file mode 100644 index 000000000000..58a1a3aa8cf9 --- /dev/null +++ b/contrib/ntp/include/trimble.h @@ -0,0 +1,125 @@ +/* + * /src/NTP/ntp-4/include/trimble.h,v 4.4 1999/02/28 11:41:11 kardel RELEASE_19990228_A + * + * $Created: Sun Aug 2 16:16:49 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#ifndef TRIMBLE_H +#define TRIMBLE_H + +/* + * Trimble packet command codes - commands being sent/received + * keep comments formatted as shown - they are used to generate + * translation tables + */ +#define CMD_CCLROSC 0x1D /* clear oscillator offset */ +#define CMD_CCLRRST 0x1E /* clear battery backup and RESET */ +#define CMD_CVERSION 0x1F /* return software version */ +#define CMD_CALMANAC 0x20 /* almanac */ +#define CMD_CCURTIME 0x21 /* current time */ +#define CMD_CMODESEL 0x22 /* mode select (2-d, 3-D, auto) */ +#define CMD_CINITPOS 0x23 /* initial position */ +#define CMD_CRECVPOS 0x24 /* receiver position fix mode */ +#define CMD_CRESET 0x25 /* soft reset & selftest */ +#define CMD_CRECVHEALTH 0x26 /* receiver health */ +#define CMD_CSIGNALLV 0x27 /* signal levels */ +#define CMD_CMESSAGE 0x28 /* GPS system message */ +#define CMD_CALMAHEALTH 0x29 /* almanac healt page */ +#define CMD_C2DALTITUDE 0x2A /* altitude for 2-D mode */ +#define CMD_CINITPOSLLA 0x2B /* initial position LLA */ +#define CMD_COPERPARAM 0x2C /* operating parameters */ +#define CMD_COSCOFFSET 0x2D /* oscillator offset */ +#define CMD_CSETGPSTIME 0x2E /* set GPS time */ +#define CMD_CUTCPARAM 0x2F /* UTC parameters */ +#define CMD_CACCPOSXYZ 0x31 /* accurate initial position (XYZ/ECEF) */ +#define CMD_CACCPOS 0x32 /* accurate initial position */ +#define CMD_CANALOGDIG 0x33 /* analog to digital */ +#define CMD_CSAT1SAT 0x34 /* satellite for 1-Sat mode */ +#define CMD_CIOOPTIONS 0x35 /* I/O options */ +#define CMD_CVELOCAID 0x36 /* velocity aiding of acquisition */ +#define CMD_CSTATLSTPOS 0x37 /* status and values of last pos. and vel. */ +#define CMD_CLOADSSATDT 0x38 /* load satellite system data */ +#define CMD_CSATDISABLE 0x39 /* satellite disable */ +#define CMD_CLASTRAW 0x3A /* last raw measurement */ +#define CMD_CSTATSATEPH 0x3B /* satellite ephemeris status */ +#define CMD_CSTATTRACK 0x3C /* tracking status */ +#define CMD_CCHANADGPS 0x3D /* configure channel A for differential GPS */ +#define CMD_CADDITFIX 0x3E /* additional fix data */ +#define CMD_CDGPSFIXMD 0x62 /* set/request differential GPS position fix mode */ +#define CMD_CDGPSCORR 0x65 /* differential correction status */ +#define CMD_CPOSFILT 0x71 /* position filter parameters */ +#define CMD_CHEIGHTFILT 0x73 /* height filter control */ +#define CMD_CHIGH8CNT 0x75 /* high-8 (best 4) / high-6 (overdetermined) control */ +#define CMD_CMAXDGPSCOR 0x77 /* maximum rate of DGPS corrections */ +#define CMD_CSUPER 0x8E /* super paket */ + +#define CMD_RDATAA 0x3D /* data channel A configuration:trimble_channelA:RO */ +#define CMD_RALMANAC 0x40 /* almanac data for sat:gps_almanac:RO */ +#define CMD_RCURTIME 0x41 /* GPS time:gps_time:RO */ +#define CMD_RSPOSXYZ 0x42 /* single precision XYZ position:gps_position(XYZ):RO|DEF */ +#define CMD_RVELOXYZ 0x43 /* velocity fix (XYZ ECEF):gps_velocity(XYZ):RO|DEF */ +#define CMD_RBEST4 0x44 /* best 4 satellite selection:trimble_best4:RO|DEF */ +#define CMD_RVERSION 0x45 /* software version:trimble_version:RO|DEF */ +#define CMD_RRECVHEALTH 0x46 /* receiver health:trimble_receiver_health:RO|DEF */ +#define CMD_RSIGNALLV 0x47 /* signal levels of all satellites:trimble_signal_levels:RO */ +#define CMD_RMESSAGE 0x48 /* GPS system message:gps-message:RO|DEF */ +#define CMD_RALMAHEALTH 0x49 /* almanac health page for all satellites:gps_almanac_health:RO */ +#define CMD_RSLLAPOS 0x4A /* single LLA position:gps_position(LLA):RO|DEF */ +#define CMD_RMACHSTAT 0x4B /* machine code / status:trimble_status:RO|DEF */ +#define CMD_ROPERPARAM 0x4C /* operating parameters:trimble_opparam:RO */ +#define CMD_ROSCOFFSET 0x4D /* oscillator offset:trimble_oscoffset:RO */ +#define CMD_RSETGPSTIME 0x4E /* response to set GPS time:trimble_setgpstime:RO */ +#define CMD_RUTCPARAM 0x4F /* UTC parameters:gps_utc_correction:RO|DEF */ +#define CMD_RANALOGDIG 0x53 /* analog to digital:trimble_analogdigital:RO */ +#define CMD_RSAT1BIAS 0x54 /* one-satellite bias & bias rate:trimble_sat1bias:RO */ +#define CMD_RIOOPTIONS 0x55 /* I/O options:trimble_iooptions:RO */ +#define CMD_RVELOCFIX 0x56 /* velocity fix (ENU):trimble_velocfix */ +#define CMD_RSTATLSTFIX 0x57 /* status and values of last pos. and vel.:trimble_status_lastpos:RO */ +#define CMD_RLOADSSATDT 0x58 /* response to load satellite system data:trimble_loaddata:RO */ +#define CMD_RSATDISABLE 0x59 /* satellite disable:trimble_satdisble:RO */ +#define CMD_RLASTRAW 0x5A /* last raw measurement:trimble_lastraw:RO */ +#define CMD_RSTATSATEPH 0x5B /* satellite ephemeris status:trimble_ephstatus:RO */ +#define CMD_RSTATTRACK 0x5C /* tracking status:trimble_tracking_status:RO|DEF */ +#define CMD_RADDITFIX 0x5E /* additional fix data:trimble_addfix:RO */ +#define CMD_RALLINVIEW 0x6D /* all in view satellite selection:trimble_satview:RO|DEF */ +#define CMD_RPOSFILT 0x72 /* position filter parameters:trimble_posfilt:RO */ +#define CMD_RHEIGHTFILT 0x74 /* height filter control:trimble_heightfilt:RO */ +#define CMD_RHIGH8CNT 0x76 /* high-8 (best 4) / high-6 (overdetermined) control:trimble_high8control:RO */ +#define CMD_RMAXAGE 0x78 /* DC MaxAge:trimble_dgpsmaxage:RO */ +#define CMD_RDGPSFIX 0x82 /* differential position fix mode:trimble_dgpsfixmode:RO */ +#define CMD_RDOUBLEXYZ 0x83 /* double precision XYZ:gps_position_ext(XYZ):RO|DEF */ +#define CMD_RDOUBLELLA 0x84 /* double precision LLA:gps_position_ext(LLA):RO|DEF */ +#define CMD_RDGPSSTAT 0x85 /* differential correction status:trimble_dgpsstatus:RO */ +#define CMD_RSUPER 0x8F /* super paket::0 */ + +typedef struct cmd_info +{ + unsigned char cmd; /* command code */ + const char *cmdname; /* command name */ + const char *cmddesc; /* command description */ + const char *varname; /* name of variable */ + int varmode; /* mode of variable */ +} cmd_info_t; + +extern cmd_info_t trimble_rcmds[]; +extern cmd_info_t trimble_scmds[]; + +extern cmd_info_t *trimble_convert P((unsigned int cmd, cmd_info_t *tbl)); + +#endif +/* + * trimble.h,v + * Revision 4.4 1999/02/28 11:41:11 kardel + * (CMD_RUTCPARAM): control variable name unification + * + * Revision 4.3 1998/12/20 23:45:25 kardel + * fix types and warnings + * + * Revision 4.2 1998/08/16 18:45:05 kardel + * (CMD_RSTATTRACK): renamed mode 6 variable name + * + * Revision 4.1 1998/08/09 22:24:35 kardel + * Trimble TSIP support + * + */ diff --git a/contrib/ntp/install-sh b/contrib/ntp/install-sh new file mode 100755 index 000000000000..58719246f040 --- /dev/null +++ b/contrib/ntp/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/contrib/ntp/kernel/Makefile.am b/contrib/ntp/kernel/Makefile.am new file mode 100644 index 000000000000..b3cfc9d6d815 --- /dev/null +++ b/contrib/ntp/kernel/Makefile.am @@ -0,0 +1,5 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +SUBDIRS = sys +ETAGS_ARGS = Makefile.am +EXTRA_DIST = chuinit.c clkinit.c tty_chu.c tty_chu_STREAMS.c tty_clk.c tty_clk_STREAMS.c diff --git a/contrib/ntp/kernel/Makefile.in b/contrib/ntp/kernel/Makefile.in new file mode 100644 index 000000000000..1a4d1ed96071 --- /dev/null +++ b/contrib/ntp/kernel/Makefile.in @@ -0,0 +1,309 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ../util/ansi2knr +SUBDIRS = sys +ETAGS_ARGS = Makefile.am +EXTRA_DIST = chuinit.c clkinit.c tty_chu.c tty_chu_STREAMS.c tty_clk.c tty_clk_STREAMS.c +subdir = kernel +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps kernel/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + if test "$$subdir" = "."; then dot_seen=yes; else :; fi; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: install-recursive uninstall-recursive install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all install-strip \ +installdirs-am installdirs mostlyclean-generic distclean-generic \ +clean-generic maintainer-clean-generic clean mostlyclean distclean \ +maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/kernel/README b/contrib/ntp/kernel/README new file mode 100644 index 000000000000..253d04e4e8d5 --- /dev/null +++ b/contrib/ntp/kernel/README @@ -0,0 +1,200 @@ +Installing Line Disciplines and Streams Modules + +Description + +Most radio and modem clocks used for a primary (stratum-1) NTP server +utilize serial ports operating at speeds of 9600 baud or greater. The +timing jitter contributed by the serial port hardware and software +discipline can accumulate to several milliseconds on a typical Unix +workstation. In order to reduce these errors, a set of special line +disciplines can be configured in the operating system process. These +disciplines intercept special characters or signals provided by the +radio or modem clock and save a local timestamp for later processing. + +The disciplines can be compiled in the kernel in older BSD-derived +systems, or installed as System V streams modules and either compiled in +the kernel or dynamically loaded when required. In either case, they +require reconfiguration of the Unix kernel and provisions in the NTP +daemon xntpd. The streams modules can be pushed and popped from the +streams stack using conventional System V streams program primitives. +Note that not all Unix kernels support line disciplines and of those +that do, not all support System V streams. The disciplines here are +known to work correctly with SunOS 4.x kernels, but have not been tested +for other kernels. + +There are two line disciplines included in the distribution. Support for +each is enabled by adding flags to the DEFS_LOCAL line of the build +configuration file ./Config.local. This can be done automatically by the +autoconfiguration build procedures, or can be inserted/deleted after the +process has completed. + +tty_clk (CLK) + + This discipline intercepts characters received from the serial port + and passes unchanged all except a set of designated characters to + the generic serial port discipline. For each of the exception + characters, the character is inserted in the receiver buffer + followed by a timestamp in Unix timeval format. Both select() and + SIGIO are supported by the discipline. The -DCLK flag is used to + compile support for this disipline in the NTP daemon. This flag is + included if the clkdefs.h file is found in the /sys/sys directory, + or it can be added (or deleted) manually. + +tty_chu (CHU) + + This discipline is a special purpose line discipline for receiving + a special timecode broadcast by Canadian time and frequency + standard station CHU. The radio signal is first demodulated by the + 300-baud modem included in the gadget box, then processed by the + discipline and finally processed by the Scratchbuilt CHU Receiver + discipline (type 7). This discipline should be used in raw mode. + The -DCHU flag is used to compile support for this disipline in the + NTP daemon. This flag is included if the chudefs.h file is found in + the /sys/sys directory, or it can be added (or deleted) manually. + +There are two sets of line disciplines. The tty_clk.c and chu_clk.c are +designed for use with older BSD systems and are compiled in the kernel. +The tty_clk_STREAMS.c and chu_clk_STREAMS.c are designed for use with +System V streams, in which case they can be either compiled in the +kernel or dynamically loaded. Since these disciplines are small, +unobtrusive, and to nothing unless specifically enabled by an +application program, it probably doesn't matter which method is choosen. + +Compiling with the Kernel + +The following procedures are for the tty_clk line discipline; for the +chu_clk, change "tty" to "chu". +1. Copy tty_clk.c into /sys/os and clkdefs.h into /sys/sys. + +2. For SunOS 4.x systems, edit /sys/os/tty_conf.c using some facsimile + of the following lines: + + #include "clk.h" + ... + #if NCLK > 0 + int clkopen(), clkclose(), clkwrite(), clkinput(), clkioctl(); + #endif + ... + #if NCLK > 0 + { clkopen, clkclose, ttread, clkwrite, clkioctl, + clkinput, nodev, nulldev, ttstart, nullmodem, /* 10 CLK */ + ttselect }, + #else + { nodev, nodev, nodev, nodev, nodev, + nodev, nodev, nodev, nodev, nodev, + nodev }, + #endif + + For Ultrix 4.x systems, edit /sys/data/tty_conf_data.c using some + facsimile of the following lines: + + #include "clk.h" + ... + #if NCLK > 0 + int clkopen(), clkclose(), clkwrite(), clkinput(), clkioctl(); + #endif + ... + #if NCLK > 0 + clkopen, clkclose, ttread, clkwrite, clkioctl, /* 10 CLK */ + clkinput, nodev, nulldev, ttstart, nulldev, + #else + nodev, nodev, nodev, nodev, nodev, + nodev, nodev, nodev, nodev, nodev, + #endif + + If the kernel doesn't include the ??select() entry in the structure + (i.e., there are only ten entry points in the structure) just leave + it out. Also note that the number you give the line discipline (10 + in most kernels) will be specific to that kernel and will depend on + what is in there already. The entries sould be in order with no + missing space; that is, if there are only seven disciplines already + defined and you want to use 10 for good reason, you should define a + dummy 9th entry like this: + + nodev, nodev, nodev, nodev, nodev, /* 9 CLK */ + nodev, nodev, nodev, nodev, nodev, + +3. Edit /sys/h/ioctl.h and include a line somewhere near where other + line disciplines are defined like: + + #define CLKLDISC 10 /* clock line discipline */ + + The "10" should match what you used as the number in the preceding + step. + +4. Edit /sys/conf/files and add a line which looks like: + + sys/tty_clk.c optional clk + +5. Edit the kernel configuration file to include the following: + + pseudo-device tty 4 # TTY clock support +6. Run config, then make clean, then make depend, then make vmunix, + then reboot the new kernel. + +Installing as a streams module + +The following procedures are for the tty_clk_STREAMS line discipline; +for the tty_chu_STREAMS, change "clk" to "chu". + +1. Copy your choice to /sys/os, removing the "_STREAMS" in the + filename. + +2. Copy the clkdefs.h file to /usr/include/sys, then construct a soft + link to /sys/sys. + +3. Append to /sys/conf.common/files.cmn: + + os/tty_tty.c optional tty + +4. Edit /sys/sun/str_conf.c. You'll want to add lines in three places. + It'll be sort of clear where when you see the file. + + #include "tty.h" + ... + #if NTTY > 0 + extern struct streamtab ttyinfo; + #endif + ... + #if NTTY > 0 + { "tty", &ttyinfo }, + #endif + +5. Edit /sys/[arch]/conf/[k-name] (substituting the architecture and + kernel name) to stick in: + + pseudo-device tty 4 # TTY clock support + + You can change "4" to anything you like. It will limit the number + of instantiations of the tty discipline you can use at the same + time. + +6. Run config, then make clean, then make depend, then make vmunix, + then reboot the new kernel. + +Both disciplines can be dynamically loaded using streams procedures +specific to the kernel. Before using the chu_clk discipline, all other +streams modules that may already be on the stack should be popped, then +the discipline should be pushed on the stack. + +How to Use the tty_clk Line Discipline + +The tty_clk line discipline defines a new ioctl(), CLK_SETSTR, which +takes a pointer to a string of no more than CLK_MAXSTRSIZE characters. +Until the first CLK_SETSTR is performed, the discipline will simply pass +through characters. Once it is passed a string by CLK_SETSTR, any +character in that string will be immediately followed by a timestamp in +Unix timeval format. You can change the string whenever you want by +doing another CLK_SETSTR. The character must be an exact, 8 bit match. +The character '\000' cannot, unfortunately, be used, as it is the string +terminator. Passing an empty string to CLK_SETSTR turns off stamping. +Passing NULL will produce undefined results. + +How to Use the tty_chu Line Discipline +The tty_chu line discipline translates data received from the CHU modem +and returns chucode structures, as defined in chudefs.h, and expected by +the Scratchbuilt CHU Receiver reference clock driver. Depending on the +settings of PEDANTIC and ANAL_RETENTIVE used when compiling the kernel, +some checking of the data may or may not be necessary. + +David L. Mills (mills@udel.edu) diff --git a/contrib/ntp/kernel/chuinit.c b/contrib/ntp/kernel/chuinit.c new file mode 100644 index 000000000000..5d73e52e21f3 --- /dev/null +++ b/contrib/ntp/kernel/chuinit.c @@ -0,0 +1,76 @@ +/* +** dynamically loadable chu driver +** +** /src/NTP/REPOSITORY/v3/kernel/chuinit.c,v 1.1.1.1 1994/07/11 07:56:25 kardel Exp +** +** william robertson +*/ + +#include +#include +#include +#include +#include + +#include +#include + +extern int findmod(); /* os/str_io.c */ + +extern struct streamtab chuinfo; + +struct vdldrv vd = { + VDMAGIC_USER, + "chu" + }; + + +int +xxxinit(function_code, vdp, vdi, vds) +unsigned int function_code; +struct vddrv *vdp; +addr_t vdi; +struct vdstat *vds; +{ + register int i = 0; + register int j; + + switch (function_code) { + case VDLOAD: + + if (findmod("chu") >= 0) { + log(LOG_ERR, "chu stream module already loaded\n"); + return (EADDRINUSE); + } + + i = findmod("\0"); + + if (i == -1 || fmodsw[i].f_name[0] != '\0') + return(-1); + + for (j = 0; vd.Drv_name[j] != '\0'; j++) /* XXX check bounds */ + fmodsw[i].f_name[j] = vd.Drv_name[j]; + + fmodsw[i].f_name[j] = '\0'; + fmodsw[i].f_str = &chuinfo; + + vdp->vdd_vdtab = (struct vdlinkage *) &vd; + + return(0); + + case VDUNLOAD: + if ((i = findmod(vd.Drv_name)) == -1) + return(-1); + + fmodsw[i].f_name[0] = '\0'; + fmodsw[i].f_str = 0; + + return(0); + + case VDSTAT: + return(0); + + default: + return(EIO); + } +} diff --git a/contrib/ntp/kernel/clkinit.c b/contrib/ntp/kernel/clkinit.c new file mode 100644 index 000000000000..1af57fd4460e --- /dev/null +++ b/contrib/ntp/kernel/clkinit.c @@ -0,0 +1,76 @@ +/* +** dynamically loadable clk driver +** +** /src/NTP/REPOSITORY/v3/kernel/clkinit.c,v 1.1.1.1 1994/07/11 07:56:25 kardel Exp +** +** william robertson +*/ + +#include +#include +#include +#include +#include + +#include +#include + +extern int findmod(); /* os/str_io.c */ + +extern struct streamtab clkinfo; + +struct vdldrv vd = { + VDMAGIC_USER, + "clk" + }; + + +int +xxxinit(function_code, vdp, vdi, vds) +unsigned int function_code; +struct vddrv *vdp; +addr_t vdi; +struct vdstat *vds; +{ + register int i = 0; + register int j; + + switch (function_code) { + case VDLOAD: + + if (findmod("clk") >= 0) { + log(LOG_ERR, "clk stream module already loaded\n"); + return (EADDRINUSE); + } + + i = findmod("\0"); + + if (i == -1 || fmodsw[i].f_name[0] != '\0') + return(-1); + + for (j = 0; vd.Drv_name[j] != '\0'; j++) /* XXX check bounds */ + fmodsw[i].f_name[j] = vd.Drv_name[j]; + + fmodsw[i].f_name[j] = '\0'; + fmodsw[i].f_str = &clkinfo; + + vdp->vdd_vdtab = (struct vdlinkage *) &vd; + + return(0); + + case VDUNLOAD: + if ((i = findmod(vd.Drv_name)) == -1) + return(-1); + + fmodsw[i].f_name[0] = '\0'; + fmodsw[i].f_str = 0; + + return(0); + + case VDSTAT: + return(0); + + default: + return(EIO); + } +} diff --git a/contrib/ntp/kernel/sys/Makefile.am b/contrib/ntp/kernel/sys/Makefile.am new file mode 100644 index 000000000000..ba405cdf49c0 --- /dev/null +++ b/contrib/ntp/kernel/sys/Makefile.am @@ -0,0 +1,8 @@ +#AUTOMAKE_OPTIONS = ../../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../../util/ansi2knr +noinst_HEADERS = bsd_audioirig.h chudefs.h clkdefs.h i8253.h parsestreams.h \ +pcl720.h ppsclock.h timex.h tpro.h +#EXTRA_DIST= TAGS +# HMS: Avoid bug in automake +#ETAGS_ARGS = "" +ETAGS_ARGS = Makefile.am diff --git a/contrib/ntp/kernel/sys/Makefile.in b/contrib/ntp/kernel/sys/Makefile.in new file mode 100644 index 000000000000..530f3861f876 --- /dev/null +++ b/contrib/ntp/kernel/sys/Makefile.in @@ -0,0 +1,238 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = ../.. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../../util/ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ../../util/ansi2knr +noinst_HEADERS = bsd_audioirig.h chudefs.h clkdefs.h i8253.h parsestreams.h \ +pcl720.h ppsclock.h timex.h tpro.h + +#EXTRA_DIST= TAGS +# HMS: Avoid bug in automake +#ETAGS_ARGS = "" +ETAGS_ARGS = Makefile.am +subdir = kernel/sys +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../../config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps kernel/sys/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-tags clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/kernel/sys/README b/contrib/ntp/kernel/sys/README new file mode 100644 index 000000000000..b9d95d926407 --- /dev/null +++ b/contrib/ntp/kernel/sys/README @@ -0,0 +1,11 @@ +README file for directory ./kernel/sys of the NTP Version 3 distribution + +This directory contains system header files used by the clock discipline +and STREAMS modules in the .. (./kernel) directory. + +If the precision-time kernel (KERNEL_PLL define) is configured, the +installation process requires the header file /usr/include/sys/timex.h +for the particular architecture to be in place. The file timex.h included +in this distribution is for Suns; the files for other systems can be +found in the kernel distributions available from the manufacturer's +representatives. diff --git a/contrib/ntp/kernel/sys/bsd_audioirig.h b/contrib/ntp/kernel/sys/bsd_audioirig.h new file mode 100644 index 000000000000..9b7c69009fb8 --- /dev/null +++ b/contrib/ntp/kernel/sys/bsd_audioirig.h @@ -0,0 +1,101 @@ +/* + * $Header: bsd_audioirig.h,v 1.0 93/08/02 12:42:00 + */ + +#ifndef _BSD_AUDIOIRIG_H_ +#define _BSD_AUDIOIRIG_H_ + +#include + +/********************************************************************/ +/* user interface */ + +/* + * irig ioctls + */ +#if defined(__STDC__) || (!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/ntp/kernel/sys/chudefs.h b/contrib/ntp/kernel/sys/chudefs.h new file mode 100644 index 000000000000..f5549f58b828 --- /dev/null +++ b/contrib/ntp/kernel/sys/chudefs.h @@ -0,0 +1,22 @@ +/* + * 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/ntp/kernel/sys/clkdefs.h b/contrib/ntp/kernel/sys/clkdefs.h new file mode 100644 index 000000000000..afbc77a8f1ac --- /dev/null +++ b/contrib/ntp/kernel/sys/clkdefs.h @@ -0,0 +1,38 @@ +/* + * Defines for the "clk" timestamping STREAMS module + */ + +#if defined(sun) +#include +#else +#include +#endif + +/* + * First, we need to define the maximum size of the set of + * characters to timestamp. 32 is MORE than enough. + */ + +#define CLK_MAXSTRSIZE 32 +struct clk_tstamp_charset { /* XXX to use _IOW not _IOWN */ + char val[CLK_MAXSTRSIZE]; +}; + +/* + * 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 defined(__STDC__) /* XXX avoid __STDC__=0 on SOLARIS */ +#define CLK_SETSTR _IOW('K', 01, struct clk_tstamp_charset) +#else +#define CLK_SETSTR _IOW(K, 01, struct clk_tstamp_charset) +#endif + diff --git a/contrib/ntp/kernel/sys/i8253.h b/contrib/ntp/kernel/sys/i8253.h new file mode 100644 index 000000000000..70965931691f --- /dev/null +++ b/contrib/ntp/kernel/sys/i8253.h @@ -0,0 +1,48 @@ +/* Copyright (c) 1995 Vixie Enterprises + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Vixie Enterprises not be used in advertising or publicity + * pertaining to distribution of the document or software without specific, + * written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND VIXIE ENTERPRISES DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VIXIE ENTERPRISES + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef _I8253_DEFINED +#define _I8253_DEFINED + +typedef union { + unsigned char i; + struct { + unsigned int bcd : 1; +#define i8253_binary 0 +#define i8253_bcd 1 + unsigned int mode : 3; +#define i8253_termcnt 0 +#define i8253_oneshot 1 +#define i8253_rategen 2 +#define i8253_sqrwave 3 +#define i8253_softstb 4 +#define i8253_hardstb 5 + unsigned int rl : 2; +#define i8253_latch 0 +#define i8253_lsb 1 +#define i8253_msb 2 +#define i8253_lmb 3 + unsigned int cntr : 2; +#define i8253_cntr_0 0 +#define i8253_cntr_1 1 +#define i8253_cntr_2 2 + } s; +} i8253_ctrl; + +#endif /*_I8253_DEFINED*/ diff --git a/contrib/ntp/kernel/sys/parsestreams.h b/contrib/ntp/kernel/sys/parsestreams.h new file mode 100644 index 000000000000..b12e92c338e2 --- /dev/null +++ b/contrib/ntp/kernel/sys/parsestreams.h @@ -0,0 +1,107 @@ +/* + * /src/NTP/ntp-4/kernel/sys/parsestreams.h,v 4.4 1998/06/14 21:09:32 kardel RELEASE_19990228_A + * + * parsestreams.h,v 4.4 1998/06/14 21:09:32 kardel RELEASE_19990228_A + * + * Copyright (c) 1989-1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * 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 sysparsehrcsid[] = "parsestreams.h,v 4.4 1998/06/14 21:09:32 kardel RELEASE_19990228_A"; +#endif + +#undef PARSEKERNEL +#if defined(KERNEL) || defined(_KERNEL) +#ifndef PARSESTREAM +#define PARSESTREAM +#endif +#endif +#if defined(PARSESTREAM) && defined(HAVE_SYS_STREAM_H) +#define PARSEKERNEL + +#ifdef HAVE_SYS_TERMIOS_H +#include +#endif + +#include + +#define NTP_NEED_BOPS + +#if defined(PARSESTREAM) && (defined(_sun) || defined(__sun)) && defined(HAVE_SYS_STREAM_H) +/* + * 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 + */ +#undef HAVE_STRING_H /* don't include that at kernel level - prototype mismatch in Solaris 2.6 */ +#include "ntp_string.h" +#else +#include +#endif + +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 ---------------------------------*/ + +#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 + +extern int parsedebug; + +#ifdef DEBUG_PARSE + +#define parseprintf(X, Y) if ((X) & parsedebug) printf Y + +#else + +#define parseprintf(X, Y) + +#endif +#endif + +/* + * parsestreams.h,v + * Revision 4.4 1998/06/14 21:09:32 kardel + * Sun acc cleanup + * + * Revision 4.3 1998/06/13 18:14:32 kardel + * make mem*() to b*() mapping magic work on Solaris too + * + * Revision 4.2 1998/06/13 15:16:22 kardel + * fix mem*() to b*() function macro emulation + * + * Revision 4.1 1998/06/13 11:50:37 kardel + * STREAM macro gone in favor of HAVE_SYS_STREAM_H + * + * Revision 4.0 1998/04/10 19:51:30 kardel + * Start 4.0 release version numbering + * + * Revision 1.2 1998/04/10 19:27:42 kardel + * initial NTP VERSION 4 integration of PARSE with GPS166 binary support + * + */ diff --git a/contrib/ntp/kernel/sys/pcl720.h b/contrib/ntp/kernel/sys/pcl720.h new file mode 100644 index 000000000000..e8638ae33534 --- /dev/null +++ b/contrib/ntp/kernel/sys/pcl720.h @@ -0,0 +1,95 @@ +/* Copyright (c) 1995 Vixie Enterprises + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Vixie Enterprises not be used in advertising or publicity + * pertaining to distribution of the document or software without specific, + * written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND VIXIE ENTERPRISES DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VIXIE ENTERPRISES + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef _PCL720_DEFINED +#define _PCL720_DEFINED + +#define pcl720_data(base,bit) (base+(bit>>3)) +#define pcl720_data_0_7(base) (base+0) +#define pcl720_data_8_15(base) (base+1) +#define pcl720_data_16_23(base) (base+2) +#define pcl720_data_24_31(base) (base+3) +#define pcl720_cntr(base,cntr) (base+4+cntr) /* cntr: 0..2 */ +#define pcl720_cntr_0(base) (base+4) +#define pcl720_cntr_1(base) (base+5) +#define pcl720_cntr_2(base) (base+6) +#define pcl720_ctrl(base) (base+7) + +#ifndef DEBUG_PCL720 +#define pcl720_inb(x) inb(x) +#define pcl720_outb(x,y) outb(x,y) +#else +static unsigned char pcl720_inb(int addr) { + unsigned char x = inb(addr); + fprintf(DEBUG_PCL720, "inb(0x%x) -> 0x%x\n", addr, x); + return (x); +} +static void pcl720_outb(int addr, unsigned char x) { + outb(addr, x); + fprintf(DEBUG_PCL720, "outb(0x%x, 0x%x)\n", addr, x); +} +#endif + +#define pcl720_load(Base,Cntr,Mode,Val) \ + ({ register unsigned int b = Base, c = Cntr, v = Val; \ + i8253_ctrl ctrl; \ + \ + ctrl.s.bcd = i8253_binary; \ + ctrl.s.mode = Mode; \ + ctrl.s.rl = i8253_lmb; \ + ctrl.s.cntr = c; \ + pcl720_outb(pcl720_ctrl(b), ctrl.i); \ + pcl720_outb(pcl720_cntr(b,c), v); \ + pcl720_outb(pcl720_cntr(b,c), v >> 8); \ + v; \ + }) + +#define pcl720_read(Base,Cntr) \ + ({ register unsigned int b = Base, c = Cntr, v; \ + i8253_ctrl ctrl; \ + \ + ctrl.s.rl = i8253_latch; \ + ctrl.s.cntr = i8253_cntr_0; \ + pcl720_outb(pcl720_ctrl(b), ctrl.i); \ + v = pcl720_inb(pcl720_cntr_0(b)); \ + v |= (pcl720_inb(pcl720_cntr_0(b)) << 8); \ + v; \ + }) + +#define pcl720_input(Base) \ + ({ register unsigned int b = Base, v; \ + \ + v = pcl720_inb(pcl720_data_0_7(b)); \ + v |= (pcl720_inb(pcl720_data_8_15(b)) << 8); \ + v |= (pcl720_inb(pcl720_data_16_23(b)) << 16); \ + v |= (pcl720_inb(pcl720_data_24_31(b)) << 24); \ + v; \ + }) + +#define pcl720_output(Base,Value) \ + ({ register unsigned int b = Base, v = Value; \ + \ + pcl720_outb(pcl720_data_0_7(b), v); \ + pcl720_outb(pcl720_data_8_15(b), v << 8); \ + pcl720_outb(pcl720_data_16_23(b), v << 16); \ + pcl720_outb(pcl720_data_24_31(b), v << 24); \ + v; \ + }) + +#endif /*_PCL720_DEFINED*/ diff --git a/contrib/ntp/kernel/sys/ppsclock.h b/contrib/ntp/kernel/sys/ppsclock.h new file mode 100644 index 000000000000..b0fe407339b3 --- /dev/null +++ b/contrib/ntp/kernel/sys/ppsclock.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef TIOCGPPSEV +#define PPSCLOCKSTR "ppsclock" + +#ifndef HAVE_STRUCT_PPSCLOCKEV +struct ppsclockev { + struct timeval tv; + u_int serial; +}; +#endif + +#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__ */ +#else +#define CIOGETEV TIOCGPPSEV +#endif diff --git a/contrib/ntp/kernel/sys/timex.h b/contrib/ntp/kernel/sys/timex.h new file mode 100644 index 000000000000..d42ec08d0f8a --- /dev/null +++ b/contrib/ntp/kernel/sys/timex.h @@ -0,0 +1,309 @@ +/****************************************************************************** + * * + * Copyright (c) David L. Mills 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. * + * * + ******************************************************************************/ + +/* + * Modification history timex.h + * + * 26 Sep 94 David L. Mills + * Added defines for hybrid phase/frequency-lock loop. + * + * 19 Mar 94 David L. Mills + * Moved defines from kernel routines to header file and added new + * defines for PPS phase-lock loop. + * + * 20 Feb 94 David L. Mills + * Revised status codes and structures for external clock and PPS + * signal discipline. + * + * 28 Nov 93 David L. Mills + * Adjusted parameters to improve stability and increase poll + * interval. + * + * 17 Sep 93 David L. Mills + * Created file + */ +/* + * This header file defines the Network Time Protocol (NTP) interfaces + * for user and daemon application programs. These are implemented using + * private syscalls and data structures and require specific kernel + * support. + * + * NAME + * ntp_gettime - NTP user application interface + * + * SYNOPSIS + * #include + * + * int syscall(SYS_ntp_gettime, tptr) + * + * int SYS_ntp_gettime defined in syscall.h header file + * struct ntptimeval *tptr pointer to ntptimeval structure + * + * NAME + * ntp_adjtime - NTP daemon application interface + * + * SYNOPSIS + * #include + * + * int syscall(SYS_ntp_adjtime, mode, tptr) + * + * int SYS_ntp_adjtime defined in syscall.h header file + * struct timex *tptr pointer to timex structure + * + */ +#ifndef _SYS_TIMEX_H_ +#define _SYS_TIMEX_H_ 1 + +#ifndef MSDOS /* Microsoft specific */ +#include +#endif /* MSDOS */ + +/* + * The following defines establish the engineering parameters of the + * phase-lock loop (PLL) model used in the kernel implementation. These + * parameters have been carefully chosen by analysis for good stability + * and wide dynamic range. + * + * The hz variable is defined in the kernel build environment. It + * 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. SHIFT_HZ expresses the same value as the nearest power of two + * in order to avoid hardware multiply operations. + * + * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen + * for a slightly underdamped convergence characteristic. SHIFT_KH + * establishes the damping of the FLL and is chosen by wisdom and black + * art. + * + * MAXTC establishes the maximum time constant of the PLL. With the + * SHIFT_KG and SHIFT_KF values given and a time constant range from + * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours, + * respectively. + */ +#define SHIFT_HZ 7 /* log2(hz) */ +#define SHIFT_KG 6 /* phase factor (shift) */ +#define SHIFT_KF 16 /* PLL frequency factor (shift) */ +#define SHIFT_KH 2 /* FLL frequency factor (shift) */ +#define MAXTC 6 /* maximum time constant (shift) */ + +/* + * The following defines establish the scaling of the various variables + * used by the PLL. They are chosen to allow the greatest precision + * possible without overflow of a 32-bit word. + * + * SHIFT_SCALE defines the scaling (shift) of the time_phase variable, + * which serves as a an extension to the low-order bits of the system + * clock variable time.tv_usec. + * + * SHIFT_UPDATE defines the scaling (shift) of the time_offset variable, + * which represents the current time offset with respect to standard + * time. + * + * SHIFT_USEC defines the scaling (shift) of the time_freq and + * time_tolerance variables, which represent the current frequency + * offset and maximum frequency tolerance. + * + * FINEUSEC is 1 us in SHIFT_UPDATE units of the time_phase variable. + */ +#define SHIFT_SCALE 22 /* phase scale (shift) */ +#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */ +#define SHIFT_USEC 16 /* frequency offset scale (shift) */ +#define FINEUSEC (1L << SHIFT_SCALE) /* 1 us in phase units */ + +/* + * The following defines establish the performance envelope of the PLL. + * They insure it operates within predefined limits, in order to satisfy + * correctness assertions. 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. + * + * MAXPHASE must be set greater than or equal to CLOCK.MAX (128 ms), as + * defined in the NTP specification. CLOCK.MAX establishes the maximum + * time offset allowed before the system time is reset, rather than + * incrementally adjusted. Here, the maximum offset is clamped to + * MAXPHASE only in order to prevent overflow errors due to defective + * protocol implementations. + * + * MAXFREQ is the maximum frequency tolerance of the CPU clock + * oscillator plus the maximum slew rate allowed by the protocol. It + * should be set to at least the frequency tolerance of the oscillator + * plus 100 ppm for vernier frequency adjustments. If the kernel + * PPS discipline code is configured (PPS_SYNC), the oscillator time and + * frequency are disciplined to an external source, presumably with + * negligible time and frequency error relative to UTC, and MAXFREQ can + * be reduced. + * + * MAXTIME is the maximum jitter tolerance of the PPS signal if the + * kernel PPS discipline code is configured (PPS_SYNC). + * + * MINSEC and MAXSEC define the lower and upper bounds on the interval + * between protocol updates. + */ +#define MAXPHASE 512000L /* max phase error (us) */ +#ifdef PPS_SYNC +#define MAXFREQ (512L << SHIFT_USEC) /* max freq error (100 ppm) */ +#define MAXTIME (200L << PPS_AVG) /* max PPS error (jitter) (200 us) */ +#else +#define MAXFREQ (512L << SHIFT_USEC) /* max freq error (200 ppm) */ +#endif /* PPS_SYNC */ +#define MINSEC 16L /* min interval between updates (s) */ +#define MAXSEC 1200L /* max interval between updates (s) */ + +#ifdef PPS_SYNC +/* + * The following defines are used only if a pulse-per-second (PPS) + * signal is available and connected via a modem control lead, such as + * produced by the optional ppsclock feature incorporated in the Sun + * asynch driver. They establish the design parameters of the frequency- + * lock loop used to discipline the CPU clock oscillator to the PPS + * signal. + * + * PPS_AVG is the averaging factor for the frequency loop, as well as + * the time and frequency dispersion. + * + * PPS_SHIFT and PPS_SHIFTMAX specify the minimum and maximum + * calibration intervals, respectively, in seconds as a power of two. + * + * PPS_VALID is the maximum interval before the PPS signal is considered + * invalid and protocol updates used directly instead. + * + * MAXGLITCH is the maximum interval before a time offset of more than + * MAXTIME is believed. + */ +#define PPS_AVG 2 /* pps averaging constant (shift) */ +#define PPS_SHIFT 2 /* min interval duration (s) (shift) */ +#define PPS_SHIFTMAX 8 /* max interval duration (s) (shift) */ +#define PPS_VALID 120 /* pps signal watchdog max (s) */ +#define MAXGLITCH 30 /* pps signal glitch max (s) */ +#endif /* PPS_SYNC */ + +/* + * The following defines and structures define the user interface for + * the ntp_gettime() and ntp_adjtime() system calls. + * + * Control mode codes (timex.modes) + */ +#define MOD_OFFSET 0x0001 /* set time offset */ +#define MOD_FREQUENCY 0x0002 /* set frequency offset */ +#define MOD_MAXERROR 0x0004 /* set maximum time error */ +#define MOD_ESTERROR 0x0008 /* set estimated time error */ +#define MOD_STATUS 0x0010 /* set clock status bits */ +#define MOD_TIMECONST 0x0020 /* set pll time constant */ +#define MOD_CANSCALE 0x0040 /* kernel can scale offset field */ +#define MOD_DOSCALE 0x0080 /* userland wants to scale offset field */ + +/* + * Status codes (timex.status) + */ +#define STA_PLL 0x0001 /* enable PLL updates (rw) */ +#define STA_PPSFREQ 0x0002 /* enable PPS freq discipline (rw) */ +#define STA_PPSTIME 0x0004 /* enable PPS time discipline (rw) */ +#define STA_FLL 0x0008 /* select frequency-lock mode (rw) */ + +#define STA_INS 0x0010 /* insert leap (rw) */ +#define STA_DEL 0x0020 /* delete leap (rw) */ +#define STA_UNSYNC 0x0040 /* clock unsynchronized (rw) */ +#define STA_FREQHOLD 0x0080 /* hold frequency (rw) */ + +#define STA_PPSSIGNAL 0x0100 /* PPS signal present (ro) */ +#define STA_PPSJITTER 0x0200 /* PPS signal jitter exceeded (ro) */ +#define STA_PPSWANDER 0x0400 /* PPS signal wander exceeded (ro) */ +#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */ + +#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */ + +#define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \ + STA_PPSERROR | STA_CLOCKERR) /* read-only bits */ + +/* + * Clock states (time_state) + */ +#define TIME_OK 0 /* no leap second warning */ +#define TIME_INS 1 /* insert leap second warning */ +#define TIME_DEL 2 /* delete leap second warning */ +#define TIME_OOP 3 /* leap second in progress */ +#define TIME_WAIT 4 /* leap second has occurred */ +#define TIME_ERROR 5 /* clock not synchronized */ + +/* + * NTP user interface (ntp_gettime()) - 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 (ro) */ + long maxerror; /* maximum error (us) (ro) */ + long esterror; /* estimated error (us) (ro) */ +}; + +/* + * NTP daemon interface - (ntp_adjtime()) used to discipline CPU clock + * oscillator + */ +struct timex { + unsigned int modes; /* clock mode bits (wo) */ + long offset; /* time offset (us) (rw) */ + long freq; /* frequency offset (scaled ppm) (rw) */ + long maxerror; /* maximum error (us) (rw) */ + long esterror; /* estimated error (us) (rw) */ + int status; /* clock status bits (rw) */ + long constant; /* pll time constant (rw) */ + long precision; /* clock precision (us) (ro) */ + long tolerance; /* clock frequency tolerance (scaled + * ppm) (ro) */ + /* + * The following read-only structure members are implemented + * only if the PPS signal discipline is configured in the + * kernel. + */ + long ppsfreq; /* pps frequency (scaled ppm) (ro) */ + long jitter; /* pps jitter (us) (ro) */ + int shift; /* interval duration (s) (shift) (ro) */ + long stabil; /* pps stability (scaled ppm) (ro) */ + long jitcnt; /* jitter limit exceeded (ro) */ + long calcnt; /* calibration intervals (ro) */ + long errcnt; /* calibration errors (ro) */ + long stbcnt; /* stability limit exceeded (ro) */ + +}; +#ifdef __FreeBSD__ + +/* + * sysctl identifiers underneath kern.ntp_pll + */ +#define NTP_PLL_GETTIME 1 /* used by ntp_gettime() */ +#define NTP_PLL_MAXID 2 /* number of valid ids */ + +#define NTP_PLL_NAMES { \ + { 0, 0 }, \ + { "gettime", CTLTYPE_STRUCT }, \ + } + +#ifndef KERNEL +#include + +__BEGIN_DECLS +extern int ntp_gettime __P((struct ntptimeval *)); +extern int ntp_adjtime __P((struct timex *)); +__END_DECLS + +#endif /* not KERNEL */ + +#endif /* __FreeBSD__ */ +#endif /* _SYS_TIMEX_H_ */ diff --git a/contrib/ntp/kernel/sys/tpro.h b/contrib/ntp/kernel/sys/tpro.h new file mode 100644 index 000000000000..f276f81bead0 --- /dev/null +++ b/contrib/ntp/kernel/sys/tpro.h @@ -0,0 +1,34 @@ +/* + * 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/ntp/kernel/tty_chu.c b/contrib/ntp/kernel/tty_chu.c new file mode 100644 index 000000000000..4615875e77e0 --- /dev/null +++ b/contrib/ntp/kernel/tty_chu.c @@ -0,0 +1,276 @@ +/* tty_chu.c,v 3.1 1993/07/06 01:07:30 jbj Exp + * tty_chu.c - CHU line driver + */ + +#include "chu.h" +#if NCHU > 0 + +#include "../h/param.h" +#include "../h/types.h" +#include "../h/systm.h" +#include "../h/dir.h" +#include "../h/user.h" +#include "../h/ioctl.h" +#include "../h/tty.h" +#include "../h/proc.h" +#include "../h/file.h" +#include "../h/conf.h" +#include "../h/buf.h" +#include "../h/uio.h" + +#include "../h/chudefs.h" + +/* + * Line discipline for receiving CHU time codes. + * Does elementary noise elimination, takes time stamps after + * the arrival of each character, returns a buffer full of the + * received 10 character code and the associated time stamps. + */ +#define NUMCHUBUFS 3 + +struct chudata { + u_char used; /* Set to 1 when structure in use */ + u_char lastindex; /* least recently used buffer */ + u_char curindex; /* buffer to use */ + u_char sleeping; /* set to 1 when we're sleeping on a buffer */ + struct chucode chubuf[NUMCHUBUFS]; +} chu_data[NCHU]; + +/* + * Number of microseconds we allow between + * character arrivals. The speed is 300 baud + * so this should be somewhat more than 30 msec + */ +#define CHUMAXUSEC (50*1000) /* 50 msec */ + +int chu_debug = 0; + +/* + * Open as CHU time discipline. Called when discipline changed + * with ioctl, and changes the interpretation of the information + * in the tty structure. + */ +/*ARGSUSED*/ +chuopen(dev, tp) + dev_t dev; + register struct tty *tp; +{ + register struct chudata *chu; + + /* + * Don't allow multiple opens. This will also protect us + * from someone opening /dev/tty + */ + if (tp->t_line == CHULDISC) + return (EBUSY); + ttywflush(tp); + for (chu = chu_data; chu < &chu_data[NCHU]; chu++) + if (!chu->used) + break; + if (chu >= &chu[NCHU]) + return (EBUSY); + chu->used++; + chu->lastindex = chu->curindex = 0; + chu->sleeping = 0; + chu->chubuf[0].ncodechars = 0; + tp->T_LINEP = (caddr_t) chu; + return (0); +} + +/* + * Break down... called when discipline changed or from device + * close routine. + */ +chuclose(tp) + register struct tty *tp; +{ + register int s = spl5(); + + ((struct chudata *) tp->T_LINEP)->used = 0; + tp->t_cp = 0; + tp->t_inbuf = 0; + tp->t_rawq.c_cc = 0; /* clear queues -- paranoid */ + tp->t_canq.c_cc = 0; + tp->t_line = 0; /* paranoid: avoid races */ + splx(s); +} + +/* + * Read a CHU buffer. Sleep on the current buffer + */ +churead(tp, uio) + register struct tty *tp; + struct uio *uio; +{ + register struct chudata *chu; + register struct chucode *chucode; + register int s; + + if ((tp->t_state&TS_CARR_ON)==0) + return (EIO); + + chu = (struct chudata *) (tp->T_LINEP); + + s = spl5(); + chucode = &(chu->chubuf[chu->lastindex]); + while (chu->curindex == chu->lastindex) { + chu->sleeping = 1; + sleep((caddr_t)chucode, TTIPRI); + } + chu->sleeping = 0; + if (++(chu->lastindex) >= NUMCHUBUFS) + chu->lastindex = 0; + splx(s); + + return (uiomove((caddr_t)chucode, sizeof(*chucode), UIO_READ, uio)); +} + +/* + * Low level character input routine. + * If the character looks okay, grab a time stamp. If the stuff in + * the buffer is too old, dump it and start fresh. If the character is + * non-BCDish, everything in the buffer too. + */ +chuinput(c, tp) + register int c; + register struct tty *tp; +{ + register struct chudata *chu = (struct chudata *) tp->T_LINEP; + register struct chucode *chuc; + register int i; + long sec, usec; + struct timeval tv; + + /* + * Do a check on the BSDness of the character. This delays + * the time stamp a bit but saves a fair amount of overhead + * when the static is bad. + */ + if (((c) & 0xf) > 9 || (((c)>>4) & 0xf) > 9) { + chuc = &(chu->chubuf[chu->curindex]); + chuc->ncodechars = 0; /* blow all previous away */ + return; + } + + /* + * Call microtime() to get the current time of day + */ + microtime(&tv); + + /* + * Compute the difference in this character's time stamp + * and the last. If it exceeds the margin, blow away all + * the characters currently in the buffer. + */ + chuc = &(chu->chubuf[chu->curindex]); + i = (int)chuc->ncodechars; + if (i > 0) { + sec = tv.tv_sec - chuc->codetimes[i-1].tv_sec; + usec = tv.tv_usec - chuc->codetimes[i-1].tv_usec; + if (usec < 0) { + sec -= 1; + usec += 1000000; + } + if (sec != 0 || usec > CHUMAXUSEC) { + i = 0; + chuc->ncodechars = 0; + } + } + + /* + * Store the character. If we're done, have to tell someone + */ + chuc->codechars[i] = (u_char)c; + chuc->codetimes[i] = tv; + + if (++i < NCHUCHARS) { + /* + * Not much to do here. Save the count and wait + * for another character. + */ + chuc->ncodechars = (u_char)i; + } else { + /* + * Mark this buffer full and point at next. If the + * next buffer is full we overwrite it by bumping the + * next pointer. + */ + chuc->ncodechars = NCHUCHARS; + if (++(chu->curindex) >= NUMCHUBUFS) + chu->curindex = 0; + if (chu->curindex == chu->lastindex) + if (++(chu->lastindex) >= NUMCHUBUFS) + chu->lastindex = 0; + chu->chubuf[chu->curindex].ncodechars = 0; + + /* + * Wake up anyone sleeping on this. Also wake up + * selectors and/or deliver a SIGIO as required. + */ + if (tp->t_rsel) { + selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); + tp->t_state &= ~TS_RCOLL; + tp->t_rsel = 0; + } + if (tp->t_state & TS_ASYNC) + gsignal(tp->t_pgrp, SIGIO); + if (chu->sleeping) + (void) wakeup((caddr_t)chuc); + } +} + +/* + * Handle ioctls. We reject all tty-style except those that + * change the line discipline. + */ +chuioctl(tp, cmd, data, flag) + struct tty *tp; + int cmd; + caddr_t data; + int flag; +{ + + if ((cmd>>8) != 't') + return (-1); + switch (cmd) { + case TIOCSETD: + case TIOCGETD: + case TIOCGETP: + case TIOCGETC: + return (-1); + } + return (ENOTTY); /* not quite appropriate */ +} + + +chuselect(dev, rw) + dev_t dev; + int rw; +{ + register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; + struct chudata *chu; + int s = spl5(); + + chu = (struct chudata *) (tp->T_LINEP); + + switch (rw) { + + case FREAD: + if (chu->curindex != chu->lastindex) + goto win; + if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_RCOLL; + else + tp->t_rsel = u.u_procp; + break; + + case FWRITE: + goto win; + } + splx(s); + return (0); +win: + splx(s); + return (1); +} +#endif NCHU diff --git a/contrib/ntp/kernel/tty_chu_STREAMS.c b/contrib/ntp/kernel/tty_chu_STREAMS.c new file mode 100644 index 000000000000..f46e25d2ab51 --- /dev/null +++ b/contrib/ntp/kernel/tty_chu_STREAMS.c @@ -0,0 +1,603 @@ +/* + * CHU STREAMS module for SunOS + * + * Version 2.6 + * + * Copyright 1991-1994, Nick Sayer + * + * Special thanks to Greg Onufer for his debug assists. + * Special thanks to Matthias Urlichs for the 4.1.x loadable driver support + * code. + * Special wet-noodle whippings to Sun for not properly documenting + * ANYTHING that makes this stuff at all possible. + * + * Should be PUSHed directly on top of a serial I/O channel. + * Provides complete chucode structures to user space. + * + * COMPILATION: + * + * + * To make a SunOS 4.1.x compatable loadable module (from the ntp kernel + * directory): + * + * % cc -c -I../include -DLOADABLE tty_chu_STREAMS.c + * + * The resulting .o file is the loadable module. Modload it + * thusly: + * + * % modload tty_chu_STREAMS.o -entry _chuinit + * + * When none of the instances are pushed in a STREAM, you can + * modunload the driver in the usual manner if you wish. + * + * As an alternative to loading it dynamically you can compile it + * directly into the kernel by hacking str_conf.c. See the README + * file for more details on doing it the old fashioned way. + * + * + * To make a Solaris 2.x compatable module (from the ntp kernel + * directory): + * + * % {gcc,cc} -c -I../include -DSOLARIS2 tty_chu_STREAMS.c + * % ld -r -o /usr/kernel/strmod/chu tty_chu_STREAMS.o + * % chmod 755 /usr/kernel/strmod/chu + * + * The OS will load it for you automagically when it is first pushed. + * + * If you get syntax errors from (really references + * to types that weren't typedef'd in gcc's version of types.h), + * add -D_SYS_TIMER_H to blot out the miscreants. + * + * Under Solaris 2.2 and previous, do not attempt to modunload the + * module unless you're SURE it's not in use. I haven't tried it, but + * I've been told it won't do the right thing. Under Solaris 2.3 (and + * presumably future revs) an attempt to unload the module when it's in + * use will properly refuse with a "busy" message. + * + * + * HISTORY: + * + * v2.6 - Mutexed the per-instance chucode just to be safe. + * v2.5 - Fixed show-stopper bug in Solaris 2.x - qprocson(). + * v2.4 - Added dynamic allocation support for Solaris 2.x. + * v2.3 - Added support for Solaris 2.x. + * v2.2 - Added SERVICE IMMEDIATE hack. + * v2.1 - Added 'sixth byte' heuristics. + * v2.0 - first version with an actual version number. + * Added support for new CHU 'second 31' data format. + * Deleted PEDANTIC and ANAL_RETENTIVE. + * + */ + +#ifdef SOLARIS2 +# ifndef NCHU +# define NCHU 1 +# endif +# define _KERNEL +#elif defined(LOADABLE) +# ifndef NCHU +# define NCHU 3 +# define KERNEL +# endif +#else +# include "chu.h" +#endif + +#if NCHU > 0 + +/* + * Number of microseconds we allow between + * character arrivals. The speed is 300 baud + * so this should be somewhat more than 30 msec + */ +#define CHUMAXUSEC (60*1000) /* 60 msec */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef SOLARIS2 + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +#ifdef LOADABLE + +#include +#include +#include +#include +#include +#include + +#endif + + +static struct module_info rminfo = { 0, "chu", 0, INFPSZ, 0, 0 }; +static struct module_info wminfo = { 0, "chu", 0, INFPSZ, 0, 0 }; +static int chuopen(), churput(), chuwput(), chuclose(); + +static struct qinit rinit = { churput, NULL, chuopen, chuclose, NULL, + &rminfo, NULL }; + +static struct qinit winit = { chuwput, NULL, NULL, NULL, NULL, + &wminfo, NULL }; + +struct streamtab chuinfo = { &rinit, &winit, NULL, NULL }; + +/* + * Here's our private data type and structs + */ +struct priv_data +{ +#ifdef SOLARIS2 + kmutex_t chucode_mutex; +#else + char in_use; +#endif + struct chucode chu_struct; +}; + +#ifndef SOLARIS2 +struct priv_data our_priv_data[NCHU]; +#endif + +#ifdef SOLARIS2 + +static struct fmodsw fsw = +{ + "chu", + &chuinfo, + D_NEW | D_MP +}; + +extern struct mod_ops mod_strmodops; + +static struct modlstrmod modlstrmod = +{ + &mod_strmodops, + "CHU timecode decoder v2.6", + &fsw +}; + +static struct modlinkage modlinkage = +{ + MODREV_1, + (void*) &modlstrmod, + NULL +}; + +int _init() +{ + return mod_install(&modlinkage); +} + +int _info(foo) +struct modinfo *foo; +{ + return mod_info(&modlinkage,foo); +} + +int _fini() +{ + return mod_remove(&modlinkage); +} + +#endif /* SOLARIS2 */ + +#ifdef LOADABLE + +# ifdef sun + +static struct vdldrv vd = +{ + VDMAGIC_PSEUDO, + "chu", + NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0, +}; + +static struct fmodsw *chu_fmod; + +/*ARGSUSED*/ +chuinit (fc, vdp, vdi, vds) + unsigned int fc; + struct vddrv *vdp; + addr_t vdi; + struct vdstat *vds; +{ + switch (fc) { + case VDLOAD: + { + int dev, i; + + /* Find free entry in fmodsw */ + for (dev = 0; dev < fmodcnt; dev++) { + if (fmodsw[dev].f_str == NULL) + break; + } + if (dev == fmodcnt) + return (ENODEV); + chu_fmod = &fmodsw[dev]; + + /* If you think a kernel would have strcpy() you're mistaken. */ + for (i = 0; i <= FMNAMESZ; i++) + chu_fmod->f_name[i] = wminfo.mi_idname[i]; + + chu_fmod->f_str = &chuinfo; + } + vdp->vdd_vdtab = (struct vdlinkage *) & vd; + + { + int i; + + for (i=0; if_name[0] = '\0'; + chu_fmod->f_str = NULL; + return 0; + case VDSTAT: + return 0; + default: + return EIO; + } +} + +# endif /* sun */ + +#endif /* LOADABLE */ + +#if !defined(LOADABLE) && !defined(SOLARIS2) + +char chu_first_open=1; + +#endif + +/*ARGSUSED*/ +static int chuopen(q, dev, flag, sflag) +queue_t *q; +dev_t dev; +int flag; +int sflag; +{ + int i; + +#if !defined(LOADABLE) && !defined(SOLARIS2) + if (chu_first_open) + { + chu_first_open=0; + + for(i=0;iq_ptr = kmem_alloc( sizeof(struct priv_data), KM_SLEEP ); + ((struct priv_data *) q->q_ptr)->chu_struct.ncodechars = 0; + + mutex_init(&((struct priv_data *) q->q_ptr)->chucode_mutex,"Chucode Mutex",MUTEX_DRIVER,NULL); + qprocson(q); + + if (!putnextctl1(WR(q), M_CTL, MC_SERVICEIMM)) + { + qprocsoff(q); + mutex_destroy(&((struct priv_data *)q->q_ptr)->chucode_mutex); + kmem_free(q->q_ptr, sizeof(struct chucode) ); + return (EFAULT); + } + + return 0; + +#else + for(i=0;iq_ptr))=&(our_priv_data[i]); + our_priv_data[i].in_use++; + our_priv_data[i].chu_struct.ncodechars = 0; + if (!putctl1(WR(q)->q_next, M_CTL, MC_SERVICEIMM)) + { + our_priv_data[i].in_use=0; + u.u_error = EFAULT; + return (OPENFAIL); + } + return 0; + } + + u.u_error = EBUSY; + return (OPENFAIL); +#endif + +} + +/*ARGSUSED*/ +static int chuclose(q, flag) +queue_t *q; +int flag; +{ +#ifdef SOLARIS2 + qprocsoff(q); + mutex_destroy(&((struct priv_data *)q->q_ptr)->chucode_mutex); + kmem_free(q->q_ptr, sizeof(struct chucode) ); +#else + ((struct priv_data *) (q->q_ptr))->in_use=0; +#endif + return (0); +} + +/* + * Now the crux of the biscuit. + * + * We will be passed data from the man downstairs. If it's not a data + * packet, it must be important, so pass it along unmunged. If, however, + * it is a data packet, we're gonna do special stuff to it. We're going + * to pass each character we get to the old line discipline code we + * include below for just such an occasion. When the old ldisc code + * gets a full chucode struct, we'll hand it back upstairs. + * + * chuinput takes a single character and q (as quickly as possible). + * passback takes a pointer to a chucode struct and q and sends it upstream. + */ + +void chuinput(); +void passback(); + +static int churput(q, mp) +queue_t *q; +mblk_t *mp; +{ + mblk_t *bp; + + switch(mp->b_datap->db_type) + { + case M_DATA: + for(bp=mp; bp!=NULL; bp=bp->b_cont) + { + while(bp->b_rptr < bp->b_wptr) + chuinput( ((u_char)*(bp->b_rptr++)) , q ); + } + freemsg(mp); + break; + default: + putnext(q,mp); + break; + } + +} + +/* + * Writing to a chu device doesn't make sense, but we'll pass them + * through in case they're important. + */ + +static int chuwput(q, mp) +queue_t *q; +mblk_t *mp; +{ + putnext(q,mp); +} + +/* + * Take a pointer to a filled chucode struct and a queue and + * send the chucode stuff upstream + */ + +void passback(outdata,q) +struct chucode *outdata; +queue_t *q; +{ + mblk_t *mp; + int j; + + mp=(mblk_t*) allocb(sizeof(struct chucode),BPRI_LO); + + if (mp==NULL) + { +#ifdef SOLARIS2 + cmn_err(CE_WARN,"chu module couldn't allocate message block"); +#else + log(LOG_ERR,"chu: cannot allocate message"); +#endif + return; + } + + for(j=0;jb_wptr++ = *( ((char*)outdata) + j ); + + putnext(q,mp); +} + +/* + * This routine was copied nearly verbatim from the old line discipline. + */ +void chuinput(c,q) +register u_char c; +queue_t *q; +{ + register struct chucode *chuc; + register int i; + long sec, usec; + struct timeval tv; + + /* + * Quick, Batman, get a timestamp! We need to do this + * right away. The time between the end of the stop bit + * and this point is critical, and should be as nearly + * constant and as short as possible. (Un)fortunately, + * the Sun's clock granularity is so big this isn't a + * major problem. + * + * uniqtime() is totally undocumented, but there you are. + */ + uniqtime(&tv); + +#ifdef SOLARIS2 + mutex_enter(&((struct priv_data *)q->q_ptr)->chucode_mutex); +#endif + + /* + * Now, locate the chu struct once so we don't have to do it + * over and over. + */ + chuc=&(((struct priv_data *) (q->q_ptr))->chu_struct); + + /* + * Compute the difference in this character's time stamp + * and the last. If it exceeds the margin, blow away all + * the characters currently in the buffer. + */ + i = (int)chuc->ncodechars; + if (i > 0) + { + sec = tv.tv_sec - chuc->codetimes[i-1].tv_sec; + usec = tv.tv_usec - chuc->codetimes[i-1].tv_usec; + if (usec < 0) + { + sec -= 1; + usec += 1000000; + } + if (sec != 0 || usec > CHUMAXUSEC) + { + i = 0; + chuc->ncodechars = 0; + } + } + + /* + * Store the character. + */ + chuc->codechars[i] = (u_char)c; + chuc->codetimes[i] = tv; + + /* + * Now we perform the 'sixth byte' heuristics. + * + * This is a long story. + * + * We used to be able to count on the first byte of the code + * having a '6' in the LSD. This prevented most code framing + * errors (garbage before the first byte wouldn't typically + * have a 6 in the LSD). That's no longer the case. + * + * We can get around this, however, by noting that the 6th byte + * must be either equal to or one's complement of the first. + * If we get a sixth byte that ISN'T like that, then it may + * well be that the first byte is garbage. The right thing + * to do is to left-shift the whole buffer one count and + * continue to wait for the sixth byte. + */ + if (i == NCHUCHARS/2) + { + register u_char temp_byte; + + temp_byte=chuc->codechars[i] ^ chuc->codechars[0]; + + if ( (temp_byte) && (temp_byte!=0xff) ) + { + register int t; + /* + * No match. Left-shift the buffer and try again + */ + for(t=0;t<=NCHUCHARS/2;t++) + { + chuc->codechars[t]=chuc->codechars[t+1]; + chuc->codetimes[t]=chuc->codetimes[t+1]; + } + + i--; /* This is because of the ++i immediately following */ + } + } + + /* + * We done yet? + */ + if (++i < NCHUCHARS) + { + /* + * We're not done. Not much to do here. Save the count and wait + * for another character. + */ + chuc->ncodechars = (u_char)i; + } + else + { + /* + * We are done. Mark this buffer full and pass it along. + */ + chuc->ncodechars = NCHUCHARS; + + /* + * Now we have a choice. Either the front half and back half + * have to match, or be one's complement of each other. + * + * So let's try the first byte and see + */ + + if(chuc->codechars[0] == chuc->codechars[NCHUCHARS/2]) + { + chuc->chutype = CHU_TIME; + for( i=0; i<(NCHUCHARS/2); i++) + if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) + { + chuc->ncodechars = 0; +#ifdef SOLARIS2 + mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex); +#endif + return; + } + } + else + { + chuc->chutype = CHU_YEAR; + for( i=0; i<(NCHUCHARS/2); i++) + if (((chuc->codechars[i] ^ chuc->codechars[i+(NCHUCHARS/2)]) & 0xff) + != 0xff ) + { + chuc->ncodechars = 0; +#ifdef SOLARIS2 + mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex); +#endif + return; + } + } + + passback(chuc,q); /* We're done! */ + chuc->ncodechars = 0; /* Start all over again! */ + } +#ifdef SOLARIS2 + mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex); +#endif +} + +#endif /* NCHU > 0 */ diff --git a/contrib/ntp/kernel/tty_clk.c b/contrib/ntp/kernel/tty_clk.c new file mode 100644 index 000000000000..072061039bf3 --- /dev/null +++ b/contrib/ntp/kernel/tty_clk.c @@ -0,0 +1,317 @@ +/* tty_clk.c,v 3.1 1993/07/06 01:07:33 jbj Exp + * tty_clk.c - Generic line driver for receiving radio clock timecodes + */ + +#include "clk.h" +#if NCLK > 0 + +#include "../h/param.h" +#include "../h/types.h" +#include "../h/systm.h" +#include "../h/dir.h" +#include "../h/user.h" +#include "../h/ioctl.h" +#include "../h/tty.h" +#include "../h/proc.h" +#include "../h/file.h" +#include "../h/conf.h" +#include "../h/buf.h" +#include "../h/uio.h" +#include "../h/clist.h" + +/* + * This line discipline is intended to provide well performing + * generic support for the reception and time stamping of radio clock + * timecodes. Most radio clock devices return a string where a + * particular character in the code (usually a \r) is on-time + * synchronized with the clock. The idea here is to collect characters + * until (one of) the synchronization character(s) (we allow two) is seen. + * When the magic character arrives we take a timestamp by calling + * microtime() and insert the eight bytes of struct timeval into the + * buffer after the magic character. We then wake up anyone waiting + * for the buffer and return the whole mess on the next read. + * + * To use this the calling program is expected to first open the + * port, and then to set the port into raw mode with the speed + * set appropriately with a TIOCSETP ioctl(), with the erase and kill + * characters set to those to be considered magic (yes, I know this + * is gross, but they were so convenient). If only one character is + * magic you can set then both the same, or perhaps to the alternate + * parity versions of said character. After getting all this set, + * change the line discipline to CLKLDISC and you are on your way. + * + * The only other bit of magic we do in here is to flush the receive + * buffers on writes if the CRMOD flag is set (hack, hack). + */ + +/* + * We run this very much like a raw mode terminal, with the exception + * that we store up characters locally until we hit one of the + * magic ones and then dump it into the rawq all at once. We keep + * the buffered data in clists since we can then often move it to + * the rawq without copying. For sanity we limit the number of + * characters between specials, and the total number of characters + * before we flush the rawq, as follows. + */ +#define CLKLINESIZE (256) +#define NCLKCHARS (CLKLINESIZE*4) + +struct clkdata { + int inuse; + struct clist clkbuf; +}; +#define clk_cc clkbuf.c_cc +#define clk_cf clkbuf.c_cf +#define clk_cl clkbuf.c_cl + +struct clkdata clk_data[NCLK]; + +/* + * Routine for flushing the internal clist + */ +#define clk_bflush(clk) (ndflush(&((clk)->clkbuf), (clk)->clk_cc)) + +int clk_debug = 0; + +/*ARGSUSED*/ +clkopen(dev, tp) + dev_t dev; + register struct tty *tp; +{ + register struct clkdata *clk; + + /* + * Don't allow multiple opens. This will also protect us + * from someone opening /dev/tty + */ + if (tp->t_line == CLKLDISC) + return (EBUSY); + ttywflush(tp); + for (clk = clk_data; clk < &clk_data[NCLK]; clk++) + if (!clk->inuse) + break; + if (clk >= &clk_data[NCLK]) + return (EBUSY); + clk->inuse++; + clk->clk_cc = 0; + clk->clk_cf = clk->clk_cl = NULL; + tp->T_LINEP = (caddr_t) clk; + return (0); +} + + +/* + * Break down... called when discipline changed or from device + * close routine. + */ +clkclose(tp) + register struct tty *tp; +{ + register struct clkdata *clk; + register int s = spltty(); + + clk = (struct clkdata *)tp->T_LINEP; + if (clk->clk_cc > 0) + clk_bflush(clk); + clk->inuse = 0; + tp->t_line = 0; /* paranoid: avoid races */ + splx(s); +} + + +/* + * Receive a write request. We pass these requests on to the terminal + * driver, except that if the CRMOD bit is set in the flags we + * first flush the input queues. + */ +clkwrite(tp, uio) + register struct tty *tp; + struct uio *uio; +{ + if (tp->t_flags & CRMOD) { + register struct clkdata *clk; + int s; + + s = spltty(); + if (tp->t_rawq.c_cc > 0) + ndflush(&tp->t_rawq, tp->t_rawq.c_cc); + clk = (struct clkdata *) tp->T_LINEP; + if (clk->clk_cc > 0) + clk_bflush(clk); + (void)splx(s); + } + ttwrite(tp, uio); +} + + +/* + * Low level character input routine. + * If the character looks okay, grab a time stamp. If the stuff in + * the buffer is too old, dump it and start fresh. If the character is + * non-BCDish, everything in the buffer too. + */ +clkinput(c, tp) + register int c; + register struct tty *tp; +{ + register struct clkdata *clk; + register int i; + register long s; + struct timeval tv; + + /* + * Check to see whether this isn't the magic character. If not, + * save the character and return. + */ +#ifdef ultrix + if (c != tp->t_cc[VERASE] && c != tp->t_cc[VKILL]) { +#else + if (c != tp->t_erase && c != tp->t_kill) { +#endif + clk = (struct clkdata *) tp->T_LINEP; + if (clk->clk_cc >= CLKLINESIZE) + clk_bflush(clk); + if (putc(c, &clk->clkbuf) == -1) { + /* + * Hopeless, no clists. Flush what we have + * and hope things improve. + */ + clk_bflush(clk); + } + return; + } + + /* + * Here we have a magic character. Get a timestamp and store + * everything. + */ + microtime(&tv); + clk = (struct clkdata *) tp->T_LINEP; + + if (putc(c, &clk->clkbuf) == -1) + goto flushout; + +#ifdef CLKLDISC + /* + * STREAMS people started writing timestamps this way. + * It's not my fault, I am just going along with the flow... + */ + for (i = 0; i < sizeof(struct timeval); i++) + if (putc(*( ((char*)&tv) + i ), &clk->clkbuf) == -1) + goto flushout; +#else + /* + * This is a machine independant way of puting longs into + * the datastream. It has fallen into disuse... + */ + s = tv.tv_sec; + for (i = 0; i < sizeof(long); i++) { + if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1) + goto flushout; + s <<= 8; + } + + s = tv.tv_usec; + for (i = 0; i < sizeof(long); i++) { + if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1) + goto flushout; + s <<= 8; + } +#endif + + /* + * If the length of the rawq exceeds our sanity limit, dump + * all the old crap in there before copying this in. + */ + if (tp->t_rawq.c_cc > NCLKCHARS) + ndflush(&tp->t_rawq, tp->t_rawq.c_cc); + + /* + * Now copy the buffer in. There is a special case optimization + * here. If there is nothing on the rawq at present we can + * just copy the clists we own over. Otherwise we must concatenate + * the present data on the end. + */ + s = (long)spltty(); + if (tp->t_rawq.c_cc <= 0) { + tp->t_rawq = clk->clkbuf; + clk->clk_cc = 0; + clk->clk_cl = clk->clk_cf = NULL; + (void) splx((int)s); + } else { + (void) splx((int)s); + catq(&clk->clkbuf, &tp->t_rawq); + clk_bflush(clk); + } + + /* + * Tell the world + */ + ttwakeup(tp); + return; + +flushout: + /* + * It would be nice if this never happened. Flush the + * internal clists and hope someone else frees some of them + */ + clk_bflush(clk); + return; +} + + +/* + * Handle ioctls. We reject most tty-style except those that + * change the line discipline and a couple of others.. + */ +clkioctl(tp, cmd, data, flag) + struct tty *tp; + int cmd; + caddr_t data; + int flag; +{ + int flags; + struct sgttyb *sg; + + if ((cmd>>8) != 't') + return (-1); + switch (cmd) { + case TIOCSETD: + case TIOCGETD: + case TIOCGETP: + case TIOCGETC: + case TIOCOUTQ: + return (-1); + + case TIOCSETP: + /* + * He likely wants to set new magic characters in. + * Do this part. + */ + sg = (struct sgttyb *)data; +#ifdef ultrix + tp->t_cc[VERASE] = sg->sg_erase; + tp->t_cc[VKILL] = sg->sg_kill; +#else + tp->t_erase = sg->sg_erase; + tp->t_kill = sg->sg_kill; +#endif + return (0); + + case TIOCFLUSH: + flags = *(int *)data; + if (flags == 0 || (flags & FREAD)) { + register struct clkdata *clk; + + clk = (struct clkdata *) tp->T_LINEP; + if (clk->clk_cc > 0) + clk_bflush(clk); + } + return (-1); + + default: + break; + } + return (ENOTTY); /* not quite appropriate */ +} +#endif NCLK diff --git a/contrib/ntp/kernel/tty_clk_STREAMS.c b/contrib/ntp/kernel/tty_clk_STREAMS.c new file mode 100644 index 000000000000..13b0a25f1d89 --- /dev/null +++ b/contrib/ntp/kernel/tty_clk_STREAMS.c @@ -0,0 +1,266 @@ +/* tty_clk_STREAMS.c,v 3.1 1993/07/06 01:07:34 jbj Exp + * Timestamp STREAMS module for SunOS 4.1 + * + * Copyright 1991, Nick Sayer + * + * Special thanks to Greg Onufer for his debug assists. + * + * Should be PUSHed directly on top of a serial I/O channel. + * For any character in a user-designated set, adds a kernel + * timestamp to that character. + * + * BUGS: + * + * Only so many characters can be timestamped. This number, however, + * is adjustable. + * + * The null character ($00) cannot be timestamped. + * + * The M_DATA messages passed upstream will not be the same + * size as when they arrive from downstream, even if no + * timestamp character is in the message. This, however, + * should not affect anything. + * + */ + +#include "clk.h" +#if NCLK > 0 +/* + * How big should the messages we pass upstream be? + */ +#define MESSAGE_SIZE 128 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct module_info rminfo = { 0, "clk", 0, INFPSZ, 0, 0 }; +static struct module_info wminfo = { 0, "clk", 0, INFPSZ, 0, 0 }; +static int clkopen(), clkrput(), clkwput(), clkclose(); + +static struct qinit rinit = { clkrput, NULL, clkopen, clkclose, NULL, + &rminfo, NULL }; + +static struct qinit winit = { clkwput, NULL, NULL, NULL, NULL, + &wminfo, NULL }; + +struct streamtab clkinfo = { &rinit, &winit, NULL, NULL }; + +struct priv_data_type +{ + char in_use; + char string[CLK_MAXSTRSIZE]; +} priv_data[NCLK]; + +char first_open=1; + +/* + * God only knows why, but linking with strchr() fails + * on my system, so here's a renamed copy. + */ + +u_char *str_chr(s,c) +u_char *s; +int c; +{ + while (*s) + if(*s++ == c) + return (s-1); + return NULL; +} + +/*ARGSUSED*/ +static int clkopen(q, dev, flag, sflag) +queue_t *q; +dev_t dev; +int flag; +int sflag; +{ + int i; + +/* Damn it! We can't even have the global data struct properly + initialized! So we have a mark to tell us to init the global + data on the first open */ + + if (first_open) + { + first_open=0; + + for(i=0;iq_ptr))=priv_data+i; + priv_data[i].string[0]=0; + return (0); + } + u.u_error = EBUSY; + return (OPENFAIL); +} + +/*ARGSUSED*/ +static int clkclose(q, flag) +queue_t *q; +int flag; +{ + ((struct priv_data_type *) (q->q_ptr))->in_use=0; + + return (0); +} + +/* + * Now the crux of the biscuit. + * + * If it's an M_DATA package, we take each character and pass + * it to clkchar. + */ + +void clkchar(); + +static int clkrput(q, mp) +queue_t *q; +mblk_t *mp; +{ + mblk_t *bp; + + switch(mp->b_datap->db_type) + { + case M_DATA: + clkchar(0,q,2); + for(bp=mp; bp!=NULL; bp=bp->b_cont) + { + while(bp->b_rptr < bp->b_wptr) + clkchar( ((u_char)*(bp->b_rptr++)) , q , 0 ); + } + clkchar(0,q,1); + freemsg(mp); + break; + default: + putnext(q,mp); + break; + } + +} + +/* + * If it's a matching M_IOCTL, handle it. + */ + +static int clkwput(q, mp) +queue_t *q; +mblk_t *mp; +{ + struct iocblk *iocp; + + switch(mp->b_datap->db_type) + { + case M_IOCTL: + iocp=(struct iocblk*) mp->b_rptr; + if (iocp->ioc_cmd==CLK_SETSTR) + { + strncpy( ((struct priv_data_type *) (RD(q)->q_ptr))->string, + (char *) mp->b_cont->b_rptr,CLK_MAXSTRSIZE); + /* make sure it's null terminated */ + ((struct priv_data_type *) (RD(q)->q_ptr))->string[CLK_MAXSTRSIZE-1]=0; + mp->b_datap->db_type = M_IOCACK; + qreply(q,mp); + } + else + putnext(q,mp); + break; + default: + putnext(q,mp); + break; + } +} + +/* + * Now clkchar. It takes a character, a queue pointer and an action + * flag and depending on the flag either: + * + * 0 - adds the character to the current message. If there's a + * timestamp to be done, do that too. If the message is less than + * 8 chars from being full, link in a new one, and set it up for + * the next call. + * + * 1 - sends the whole mess to Valhala. + * + * 2 - set things up. + * + * Yeah, it's an ugly hack. Complaints may be filed with /dev/null. + */ + + +void clkchar(c,q,f) + register u_char c; + queue_t *q; + char f; +{ + static char error; + static mblk_t *message,*mp; + struct timeval tv; + +/* Get a timestamp ASAP! */ + uniqtime(&tv); + + switch(f) + { + case 1: + if (!error) + putnext(q,message); + break; + case 2: + mp=message= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO); + error=(message==NULL); + if (error) + log(LOG_ERR,"clk: cannot allocate message - data lost"); + break; + case 0: + if (error) /* If we had an error, forget it. */ + return; + + *mp->b_wptr++=c; /* Put the char away first. + + /* If it's in the special string, append a struct timeval */ + + if (str_chr( ((struct priv_data_type *) (q->q_ptr))->string , + c )!=NULL) + { + int i; + + for (i=0;ib_wptr++= *( ((char*)&tv) + i ); + } + + /* If we don't have space for a complete struct timeval, and a + char, it's time for a new mp block */ + + if (((mp->b_wptr-mp->b_rptr)+sizeof(struct timeval)+2)>MESSAGE_SIZE) + { + mp->b_cont= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO); + error=(mp->b_cont==NULL); + if (error) + { + log(LOG_ERR,"clk: cannot allocate message - data lost"); + freemsg(message); + } + mp=mp->b_cont; + } + + break; + } +} + +#endif diff --git a/contrib/ntp/libntp/Makefile.am b/contrib/ntp/libntp/Makefile.am new file mode 100644 index 000000000000..9ba3c097d914 --- /dev/null +++ b/contrib/ntp/libntp/Makefile.am @@ -0,0 +1,31 @@ +#AUTOMAKE_OPTIONS = ../ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +noinst_LIBRARIES = libntp.a +libntp_a_SOURCES = a_md5encrypt.c adjtime.c atoint.c atolfp.c atouint.c \ + authencrypt.c authkeys.c authparity.c authreadkeys.c authusekey.c \ + buftvtots.c caljulian.c calleapwhen.c caltontp.c calyearstart.c \ + clocktime.c clocktypes.c decodenetnum.c dofptoa.c dolfptoa.c \ + emalloc.c findconfig.c fptoa.c fptoms.c getopt.c hextoint.c \ + hextolfp.c humandate.c inttoa.c lib_strbuf.c machines.c md5c.c \ + memmove.c mexit.c mfptoa.c mfptoms.c modetoa.c mstolfp.c msutotsf.c \ + msyslog.c netof.c numtoa.c numtohost.c octtoint.c prettydate.c \ + ranny.c refnumtoa.c statestr.c syssignal.c systime.c tsftomsu.c \ + tstotv.c tvtoa.c tvtots.c uglydate.c uinttoa.c utvtoa.c ymd2yd.c \ + mfp_mul.c binio.c ieee754io.c gpstolfp.c recvbuff.c iosignal.c +libntp_a_LIBADD = @LIBOBJS@ +libntp_a_DEPENDENCIES = @LIBOBJS@ +INCLUDES = -I$(top_srcdir)/include +ETAGS_ARGS = Makefile.am + +noinst_HEADERS = lib_strbuf.h log.h + +../include/des.h: + touch ../include/des.h + +EXTRA_DIST = README $(HEADERS) adjtimex.c log.c strerror.c mktime.c + +#mktime_.c: mktime.c $(ANSI2KNR) +# $(ANSI2KNR) $< mktime_.c + +#strerror_.c: strerror.c $(ANSI2KNR) +# $(ANSI2KNR) $< strerror_.c diff --git a/contrib/ntp/libntp/Makefile.in b/contrib/ntp/libntp/Makefile.in new file mode 100644 index 000000000000..53eda6771c6f --- /dev/null +++ b/contrib/ntp/libntp/Makefile.in @@ -0,0 +1,796 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ../util/ansi2knr +noinst_LIBRARIES = libntp.a +libntp_a_SOURCES = a_md5encrypt.c adjtime.c atoint.c atolfp.c atouint.c \ + authencrypt.c authkeys.c authparity.c authreadkeys.c authusekey.c \ + buftvtots.c caljulian.c calleapwhen.c caltontp.c calyearstart.c \ + clocktime.c clocktypes.c decodenetnum.c dofptoa.c dolfptoa.c \ + emalloc.c findconfig.c fptoa.c fptoms.c getopt.c hextoint.c \ + hextolfp.c humandate.c inttoa.c lib_strbuf.c machines.c md5c.c \ + memmove.c mexit.c mfptoa.c mfptoms.c modetoa.c mstolfp.c msutotsf.c \ + msyslog.c netof.c numtoa.c numtohost.c octtoint.c prettydate.c \ + ranny.c refnumtoa.c statestr.c syssignal.c systime.c tsftomsu.c \ + tstotv.c tvtoa.c tvtots.c uglydate.c uinttoa.c utvtoa.c ymd2yd.c \ + mfp_mul.c binio.c ieee754io.c gpstolfp.c recvbuff.c iosignal.c + +libntp_a_LIBADD = @LIBOBJS@ +libntp_a_DEPENDENCIES = @LIBOBJS@ +INCLUDES = -I$(top_srcdir)/include +ETAGS_ARGS = Makefile.am + +noinst_HEADERS = lib_strbuf.h log.h + +EXTRA_DIST = README $(HEADERS) adjtimex.c log.c strerror.c mktime.c +subdir = libntp +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +ANSI2KNR = ../util/ansi2knr +am_libntp_a_OBJECTS = a_md5encrypt$U.o adjtime$U.o atoint$U.o \ +atolfp$U.o atouint$U.o authencrypt$U.o authkeys$U.o authparity$U.o \ +authreadkeys$U.o authusekey$U.o buftvtots$U.o caljulian$U.o \ +calleapwhen$U.o caltontp$U.o calyearstart$U.o clocktime$U.o \ +clocktypes$U.o decodenetnum$U.o dofptoa$U.o dolfptoa$U.o emalloc$U.o \ +findconfig$U.o fptoa$U.o fptoms$U.o getopt$U.o hextoint$U.o \ +hextolfp$U.o humandate$U.o inttoa$U.o lib_strbuf$U.o machines$U.o \ +md5c$U.o memmove$U.o mexit$U.o mfptoa$U.o mfptoms$U.o modetoa$U.o \ +mstolfp$U.o msutotsf$U.o msyslog$U.o netof$U.o numtoa$U.o numtohost$U.o \ +octtoint$U.o prettydate$U.o ranny$U.o refnumtoa$U.o statestr$U.o \ +syssignal$U.o systime$U.o tsftomsu$U.o tstotv$U.o tvtoa$U.o tvtots$U.o \ +uglydate$U.o uinttoa$U.o utvtoa$U.o ymd2yd$U.o mfp_mul$U.o binio$U.o \ +ieee754io$U.o gpstolfp$U.o recvbuff$U.o iosignal$U.o +libntp_a_OBJECTS = $(am_libntp_a_OBJECTS) +AR = ar +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libntp_a_SOURCES) +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) Makefile.am Makefile.in mktime.c \ +strerror.c + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +SOURCES = $(libntp_a_SOURCES) +OBJECTS = $(am_libntp_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps libntp/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: +../util/ansi2knr: ../util/ansi2knr.o + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr + +../util/ansi2knr.o: + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o + + +mostlyclean-kr: + -rm -f *_.c + +clean-kr: + +distclean-kr: + +maintainer-clean-kr: +a_md5encrypt$U.o: +adjtime$U.o: +atoint$U.o: +atolfp$U.o: +atouint$U.o: +authencrypt$U.o: +authkeys$U.o: +authparity$U.o: +authreadkeys$U.o: +authusekey$U.o: +buftvtots$U.o: +caljulian$U.o: +calleapwhen$U.o: +caltontp$U.o: +calyearstart$U.o: +clocktime$U.o: +clocktypes$U.o: +decodenetnum$U.o: +dofptoa$U.o: +dolfptoa$U.o: +emalloc$U.o: +findconfig$U.o: +fptoa$U.o: +fptoms$U.o: +getopt$U.o: +hextoint$U.o: +hextolfp$U.o: +humandate$U.o: +inttoa$U.o: +lib_strbuf$U.o: +machines$U.o: +md5c$U.o: +memmove$U.o: +mexit$U.o: +mfptoa$U.o: +mfptoms$U.o: +modetoa$U.o: +mstolfp$U.o: +msutotsf$U.o: +msyslog$U.o: +netof$U.o: +numtoa$U.o: +numtohost$U.o: +octtoint$U.o: +prettydate$U.o: +ranny$U.o: +refnumtoa$U.o: +statestr$U.o: +syssignal$U.o: +systime$U.o: +tsftomsu$U.o: +tstotv$U.o: +tvtoa$U.o: +tvtots$U.o: +uglydate$U.o: +uinttoa$U.o: +utvtoa$U.o: +ymd2yd$U.o: +mfp_mul$U.o: +binio$U.o: +ieee754io$U.o: +gpstolfp$U.o: +recvbuff$U.o: +iosignal$U.o: + +libntp.a: $(libntp_a_OBJECTS) $(libntp_a_DEPENDENCIES) + -rm -f libntp.a + $(AR) cru libntp.a $(libntp_a_OBJECTS) $(libntp_a_LIBADD) + $(RANLIB) libntp.a +a_md5encrypt_.c: a_md5encrypt.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/a_md5encrypt.c; then echo $(srcdir)/a_md5encrypt.c; else echo a_md5encrypt.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > a_md5encrypt_.c +adjtime_.c: adjtime.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/adjtime.c; then echo $(srcdir)/adjtime.c; else echo adjtime.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > adjtime_.c +atoint_.c: atoint.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/atoint.c; then echo $(srcdir)/atoint.c; else echo atoint.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > atoint_.c +atolfp_.c: atolfp.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/atolfp.c; then echo $(srcdir)/atolfp.c; else echo atolfp.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > atolfp_.c +atouint_.c: atouint.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/atouint.c; then echo $(srcdir)/atouint.c; else echo atouint.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > atouint_.c +authencrypt_.c: authencrypt.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/authencrypt.c; then echo $(srcdir)/authencrypt.c; else echo authencrypt.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > authencrypt_.c +authkeys_.c: authkeys.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/authkeys.c; then echo $(srcdir)/authkeys.c; else echo authkeys.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > authkeys_.c +authparity_.c: authparity.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/authparity.c; then echo $(srcdir)/authparity.c; else echo authparity.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > authparity_.c +authreadkeys_.c: authreadkeys.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/authreadkeys.c; then echo $(srcdir)/authreadkeys.c; else echo authreadkeys.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > authreadkeys_.c +authusekey_.c: authusekey.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/authusekey.c; then echo $(srcdir)/authusekey.c; else echo authusekey.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > authusekey_.c +binio_.c: binio.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/binio.c; then echo $(srcdir)/binio.c; else echo binio.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > binio_.c +buftvtots_.c: buftvtots.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/buftvtots.c; then echo $(srcdir)/buftvtots.c; else echo buftvtots.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > buftvtots_.c +caljulian_.c: caljulian.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/caljulian.c; then echo $(srcdir)/caljulian.c; else echo caljulian.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > caljulian_.c +calleapwhen_.c: calleapwhen.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/calleapwhen.c; then echo $(srcdir)/calleapwhen.c; else echo calleapwhen.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > calleapwhen_.c +caltontp_.c: caltontp.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/caltontp.c; then echo $(srcdir)/caltontp.c; else echo caltontp.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > caltontp_.c +calyearstart_.c: calyearstart.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/calyearstart.c; then echo $(srcdir)/calyearstart.c; else echo calyearstart.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > calyearstart_.c +clocktime_.c: clocktime.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clocktime.c; then echo $(srcdir)/clocktime.c; else echo clocktime.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clocktime_.c +clocktypes_.c: clocktypes.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clocktypes.c; then echo $(srcdir)/clocktypes.c; else echo clocktypes.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clocktypes_.c +decodenetnum_.c: decodenetnum.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/decodenetnum.c; then echo $(srcdir)/decodenetnum.c; else echo decodenetnum.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > decodenetnum_.c +dofptoa_.c: dofptoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/dofptoa.c; then echo $(srcdir)/dofptoa.c; else echo dofptoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > dofptoa_.c +dolfptoa_.c: dolfptoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/dolfptoa.c; then echo $(srcdir)/dolfptoa.c; else echo dolfptoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > dolfptoa_.c +emalloc_.c: emalloc.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/emalloc.c; then echo $(srcdir)/emalloc.c; else echo emalloc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > emalloc_.c +findconfig_.c: findconfig.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/findconfig.c; then echo $(srcdir)/findconfig.c; else echo findconfig.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > findconfig_.c +fptoa_.c: fptoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/fptoa.c; then echo $(srcdir)/fptoa.c; else echo fptoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > fptoa_.c +fptoms_.c: fptoms.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/fptoms.c; then echo $(srcdir)/fptoms.c; else echo fptoms.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > fptoms_.c +getopt_.c: getopt.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/getopt.c; then echo $(srcdir)/getopt.c; else echo getopt.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > getopt_.c +gpstolfp_.c: gpstolfp.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/gpstolfp.c; then echo $(srcdir)/gpstolfp.c; else echo gpstolfp.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > gpstolfp_.c +hextoint_.c: hextoint.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/hextoint.c; then echo $(srcdir)/hextoint.c; else echo hextoint.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > hextoint_.c +hextolfp_.c: hextolfp.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/hextolfp.c; then echo $(srcdir)/hextolfp.c; else echo hextolfp.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > hextolfp_.c +humandate_.c: humandate.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/humandate.c; then echo $(srcdir)/humandate.c; else echo humandate.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > humandate_.c +ieee754io_.c: ieee754io.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ieee754io.c; then echo $(srcdir)/ieee754io.c; else echo ieee754io.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ieee754io_.c +inttoa_.c: inttoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/inttoa.c; then echo $(srcdir)/inttoa.c; else echo inttoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > inttoa_.c +iosignal_.c: iosignal.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/iosignal.c; then echo $(srcdir)/iosignal.c; else echo iosignal.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > iosignal_.c +lib_strbuf_.c: lib_strbuf.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/lib_strbuf.c; then echo $(srcdir)/lib_strbuf.c; else echo lib_strbuf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > lib_strbuf_.c +machines_.c: machines.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/machines.c; then echo $(srcdir)/machines.c; else echo machines.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > machines_.c +md5c_.c: md5c.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/md5c.c; then echo $(srcdir)/md5c.c; else echo md5c.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > md5c_.c +memmove_.c: memmove.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/memmove.c; then echo $(srcdir)/memmove.c; else echo memmove.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > memmove_.c +mexit_.c: mexit.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/mexit.c; then echo $(srcdir)/mexit.c; else echo mexit.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > mexit_.c +mfp_mul_.c: mfp_mul.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/mfp_mul.c; then echo $(srcdir)/mfp_mul.c; else echo mfp_mul.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > mfp_mul_.c +mfptoa_.c: mfptoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/mfptoa.c; then echo $(srcdir)/mfptoa.c; else echo mfptoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > mfptoa_.c +mfptoms_.c: mfptoms.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/mfptoms.c; then echo $(srcdir)/mfptoms.c; else echo mfptoms.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > mfptoms_.c +mktime_.c: mktime.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/mktime.c; then echo $(srcdir)/mktime.c; else echo mktime.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > mktime_.c +modetoa_.c: modetoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/modetoa.c; then echo $(srcdir)/modetoa.c; else echo modetoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > modetoa_.c +mstolfp_.c: mstolfp.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/mstolfp.c; then echo $(srcdir)/mstolfp.c; else echo mstolfp.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > mstolfp_.c +msutotsf_.c: msutotsf.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/msutotsf.c; then echo $(srcdir)/msutotsf.c; else echo msutotsf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > msutotsf_.c +msyslog_.c: msyslog.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/msyslog.c; then echo $(srcdir)/msyslog.c; else echo msyslog.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > msyslog_.c +netof_.c: netof.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/netof.c; then echo $(srcdir)/netof.c; else echo netof.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > netof_.c +numtoa_.c: numtoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/numtoa.c; then echo $(srcdir)/numtoa.c; else echo numtoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > numtoa_.c +numtohost_.c: numtohost.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/numtohost.c; then echo $(srcdir)/numtohost.c; else echo numtohost.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > numtohost_.c +octtoint_.c: octtoint.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/octtoint.c; then echo $(srcdir)/octtoint.c; else echo octtoint.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > octtoint_.c +prettydate_.c: prettydate.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/prettydate.c; then echo $(srcdir)/prettydate.c; else echo prettydate.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > prettydate_.c +ranny_.c: ranny.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ranny.c; then echo $(srcdir)/ranny.c; else echo ranny.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ranny_.c +recvbuff_.c: recvbuff.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/recvbuff.c; then echo $(srcdir)/recvbuff.c; else echo recvbuff.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > recvbuff_.c +refnumtoa_.c: refnumtoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refnumtoa.c; then echo $(srcdir)/refnumtoa.c; else echo refnumtoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refnumtoa_.c +statestr_.c: statestr.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/statestr.c; then echo $(srcdir)/statestr.c; else echo statestr.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > statestr_.c +strerror_.c: strerror.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/strerror.c; then echo $(srcdir)/strerror.c; else echo strerror.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > strerror_.c +syssignal_.c: syssignal.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/syssignal.c; then echo $(srcdir)/syssignal.c; else echo syssignal.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > syssignal_.c +systime_.c: systime.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/systime.c; then echo $(srcdir)/systime.c; else echo systime.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > systime_.c +tsftomsu_.c: tsftomsu.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/tsftomsu.c; then echo $(srcdir)/tsftomsu.c; else echo tsftomsu.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > tsftomsu_.c +tstotv_.c: tstotv.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/tstotv.c; then echo $(srcdir)/tstotv.c; else echo tstotv.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > tstotv_.c +tvtoa_.c: tvtoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/tvtoa.c; then echo $(srcdir)/tvtoa.c; else echo tvtoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > tvtoa_.c +tvtots_.c: tvtots.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/tvtots.c; then echo $(srcdir)/tvtots.c; else echo tvtots.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > tvtots_.c +uglydate_.c: uglydate.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/uglydate.c; then echo $(srcdir)/uglydate.c; else echo uglydate.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > uglydate_.c +uinttoa_.c: uinttoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/uinttoa.c; then echo $(srcdir)/uinttoa.c; else echo uinttoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > uinttoa_.c +utvtoa_.c: utvtoa.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/utvtoa.c; then echo $(srcdir)/utvtoa.c; else echo utvtoa.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > utvtoa_.c +ymd2yd_.c: ymd2yd.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ymd2yd.c; then echo $(srcdir)/ymd2yd.c; else echo ymd2yd.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ymd2yd_.c +a_md5encrypt_.o adjtime_.o atoint_.o atolfp_.o atouint_.o \ +authencrypt_.o authkeys_.o authparity_.o authreadkeys_.o authusekey_.o \ +binio_.o buftvtots_.o caljulian_.o calleapwhen_.o caltontp_.o \ +calyearstart_.o clocktime_.o clocktypes_.o decodenetnum_.o dofptoa_.o \ +dolfptoa_.o emalloc_.o findconfig_.o fptoa_.o fptoms_.o getopt_.o \ +gpstolfp_.o hextoint_.o hextolfp_.o humandate_.o ieee754io_.o inttoa_.o \ +iosignal_.o lib_strbuf_.o machines_.o md5c_.o memmove_.o mexit_.o \ +mfp_mul_.o mfptoa_.o mfptoms_.o mktime_.o modetoa_.o mstolfp_.o \ +msutotsf_.o msyslog_.o netof_.o numtoa_.o numtohost_.o octtoint_.o \ +prettydate_.o ranny_.o recvbuff_.o refnumtoa_.o statestr_.o strerror_.o \ +syssignal_.o systime_.o tsftomsu_.o tstotv_.o tvtoa_.o tvtots_.o \ +uglydate_.o uinttoa_.o utvtoa_.o ymd2yd_.o : $(ANSI2KNR) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +a_md5encrypt.o: a_md5encrypt.c ../include/ntp_machine.h ../config.h \ + ../include/ntp_proto.h ../include/ntp_types.h \ + ../include/ntp_fp.h ../include/ntp_string.h ../include/global.h \ + ../include/md5.h ../include/ntp_stdlib.h ../include/l_stdlib.h +adjtime.o: adjtime.c ../config.h +atoint.o: atoint.c ../include/ntp_types.h ../include/ntp_machine.h \ + ../config.h ../include/ntp_proto.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +atolfp.o: atolfp.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_string.h +atouint.o: atouint.c ../include/ntp_types.h ../include/ntp_machine.h \ + ../config.h ../include/ntp_proto.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +authencrypt.o: authencrypt.c ../include/ntp_machine.h ../config.h \ + ../include/ntp_proto.h +authkeys.o: authkeys.c ../config.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../include/ntp_proto.h \ + ../include/ntp_fp.h ../include/ntp.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_string.h \ + ../include/ntp_stdlib.h ../include/l_stdlib.h +authparity.o: authparity.c ../include/ntp_stdlib.h \ + ../include/ntp_types.h ../include/ntp_machine.h ../config.h \ + ../include/ntp_proto.h ../include/ntp_string.h \ + ../include/l_stdlib.h +authreadkeys.o: authreadkeys.c ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h ../config.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_syslog.h +authusekey.o: authusekey.c ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_string.h ../include/ntp_stdlib.h \ + ../include/l_stdlib.h +binio.o: binio.c ../include/binio.h ../include/ntp_stdlib.h \ + ../include/ntp_types.h ../include/ntp_machine.h ../config.h \ + ../include/ntp_proto.h ../include/ntp_string.h \ + ../include/l_stdlib.h +buftvtots.o: buftvtots.c ../config.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp_unixtime.h +caljulian.o: caljulian.c ../include/ntp_types.h ../include/ntp_machine.h \ + ../config.h ../include/ntp_proto.h ../include/ntp_calendar.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +calleapwhen.o: calleapwhen.c ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_calendar.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +caltontp.o: caltontp.c ../include/ntp_types.h ../include/ntp_machine.h \ + ../config.h ../include/ntp_proto.h ../include/ntp_calendar.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +calyearstart.o: calyearstart.c ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_calendar.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +clocktime.o: clocktime.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +clocktypes.o: clocktypes.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp.h lib_strbuf.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +decodenetnum.o: decodenetnum.c ../include/ntp_stdlib.h \ + ../include/ntp_types.h ../include/ntp_machine.h ../config.h \ + ../include/ntp_proto.h ../include/ntp_string.h \ + ../include/l_stdlib.h +desc.o: desc.c ../include/global.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/rsaref.h ../include/md2.h ../include/md5.h \ + ../include/des.h +dofptoa.o: dofptoa.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + lib_strbuf.h ../include/ntp_string.h ../include/ntp_stdlib.h \ + ../include/l_stdlib.h +dolfptoa.o: dolfptoa.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + lib_strbuf.h ../include/ntp_string.h ../include/ntp_stdlib.h \ + ../include/l_stdlib.h +emalloc.o: emalloc.c ../include/ntp_types.h ../include/ntp_machine.h \ + ../config.h ../include/ntp_proto.h ../include/ntp_malloc.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h ../include/ntp_syslog.h +findconfig.o: findconfig.c ../config.h ../include/ntp_stdlib.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp_string.h \ + ../include/l_stdlib.h +fptoa.o: fptoa.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +fptoms.o: fptoms.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h +getopt.o: getopt.c ../include/ntp_stdlib.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_string.h ../include/l_stdlib.h +gpstolfp.o: gpstolfp.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h +hextoint.o: hextoint.c ../include/ntp_stdlib.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_string.h ../include/l_stdlib.h +hextolfp.o: hextolfp.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_string.h ../include/ntp_stdlib.h \ + ../include/l_stdlib.h +humandate.o: humandate.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_unixtime.h lib_strbuf.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +ieee754io.o: ieee754io.c ../config.h ../include/l_stdlib.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/ntp_fp.h \ + ../include/ieee754io.h +inttoa.o: inttoa.c lib_strbuf.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +iosignal.o: iosignal.c ../config.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h ../include/ntp_if.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h ../include/iosignal.h +lib_strbuf.o: lib_strbuf.c lib_strbuf.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h +machines.o: machines.c ../config.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp_syslog.h \ + ../include/ntp_stdlib.h ../include/ntp_types.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_unixtime.h +md5c.o: md5c.c ../include/global.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/md5.h +memmove.o: memmove.c ../config.h +mexit.o: mexit.c +mfp_mul.o: mfp_mul.c ../include/ntp_stdlib.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_fp.h +mfptoa.o: mfptoa.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +mfptoms.o: mfptoms.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +modetoa.o: modetoa.c lib_strbuf.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +mstolfp.o: mstolfp.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +msutotsf.o: msutotsf.c ../include/ntp_types.h ../include/ntp_machine.h \ + ../config.h ../include/ntp_proto.h +msyslog.o: msyslog.c ../config.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../include/ntp_proto.h \ + ../include/ntp_string.h ../include/ntp_stdlib.h \ + ../include/l_stdlib.h ../include/ntp_syslog.h +netof.o: netof.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +numtoa.o: numtoa.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + lib_strbuf.h ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +numtohost.o: numtohost.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h lib_strbuf.h +octtoint.o: octtoint.c ../include/ntp_stdlib.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_string.h ../include/l_stdlib.h +prettydate.o: prettydate.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_unixtime.h lib_strbuf.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +ranny.o: ranny.c ../include/ntp_stdlib.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_string.h ../include/l_stdlib.h +recvbuff.o: recvbuff.c ../config.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_syslog.h ../include/ntp_io.h \ + ../include/recvbuff.h ../include/ntp.h ../include/iosignal.h \ + ../include/ntp_refclock.h +refnumtoa.o: refnumtoa.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + lib_strbuf.h ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +statestr.o: statestr.c ../config.h ../include/ntp_stdlib.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp_string.h \ + ../include/l_stdlib.h ../include/ntp_fp.h ../include/ntp.h \ + lib_strbuf.h ../include/ntp_refclock.h ../include/recvbuff.h \ + ../include/ntp_control.h +syssignal.o: syssignal.c ../config.h ../include/ntp_syslog.h \ + ../include/ntp_stdlib.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../include/ntp_proto.h \ + ../include/ntp_string.h ../include/l_stdlib.h +systime.o: systime.c ../config.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_syslog.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +tsftomsu.o: tsftomsu.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +tstotv.o: tstotv.c ../include/ntp_types.h ../include/ntp_machine.h \ + ../config.h ../include/ntp_proto.h +tvtoa.o: tvtoa.c lib_strbuf.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h ../include/ntp_unixtime.h +tvtots.o: tvtots.c ../include/ntp_types.h ../include/ntp_machine.h \ + ../config.h ../include/ntp_proto.h +uglydate.o: uglydate.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_unixtime.h lib_strbuf.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +uinttoa.o: uinttoa.c lib_strbuf.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +utvtoa.o: utvtoa.c lib_strbuf.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h ../include/ntp_unixtime.h +ymd2yd.o: ymd2yd.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-kr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-kr clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile distclean-kr \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-kr \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-kr distclean-kr clean-kr \ +maintainer-clean-kr tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +../include/des.h: + touch ../include/des.h + +#mktime_.c: mktime.c $(ANSI2KNR) +# $(ANSI2KNR) $< mktime_.c + +#strerror_.c: strerror.c $(ANSI2KNR) +# $(ANSI2KNR) $< strerror_.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/libntp/README b/contrib/ntp/libntp/README new file mode 100644 index 000000000000..fac718548990 --- /dev/null +++ b/contrib/ntp/libntp/README @@ -0,0 +1,5 @@ +README file for directory ./libntp of the NTP Version 4 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/ntp/libntp/a_md5encrypt.c b/contrib/ntp/libntp/a_md5encrypt.c new file mode 100644 index 000000000000..76f9c4fadd2a --- /dev/null +++ b/contrib/ntp/libntp/a_md5encrypt.c @@ -0,0 +1,132 @@ +/* + * MD5 interface for rsaref2.0 + * + * These routines implement an interface for the RSA Laboratories + * implementation of the Message Digest 5 (MD5) algorithm. This + * algorithm is included in the rsaref2.0 package available from RSA in + * the US and foreign countries. Further information is available at + * www.rsa.com. + */ + +#include "ntp_machine.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef MD5 +#include + +#include "ntp_types.h" +#include "ntp_fp.h" +#include "ntp_string.h" +#include "global.h" +#include "md5.h" +#include "ntp_stdlib.h" + +#define BLOCK_OCTETS 16 /* message digest size */ +#define NTP_MAXKEY 65535 /* max identifier from ntp.h */ + + +/* + * MD5authencrypt - generate MD5 message authenticator + * + * Returns length of authenticator field. + */ +int +MD5authencrypt( + u_char *key, /* key pointer */ + u_int32 *pkt, /* packet pointer */ + int length /* packet length */ + ) +{ + MD5_CTX ctx; + u_char digest[BLOCK_OCTETS]; + int i; + + /* + * MD5 with key identifier concatenated with packet. + */ + MD5Init(&ctx); + MD5Update(&ctx, key, (u_int)cache_keylen); + MD5Update(&ctx, (u_char *)pkt, (u_int)length); + MD5Final(digest, &ctx); + i = length / 4; + memmove((char *)&pkt[i + 1], (char *)digest, BLOCK_OCTETS); + return (BLOCK_OCTETS + 4); +} + + +/* + * MD5authdecrypt - verify MD5 message authenticator + * + * Returns one if authenticator valid, zero if invalid. + */ +int +MD5authdecrypt( + u_char *key, /* key pointer */ + u_int32 *pkt, /* packet pointer */ + int length, /* packet length */ + int size /* MAC size */ + ) +{ + MD5_CTX ctx; + u_char digest[BLOCK_OCTETS]; + + /* + * MD5 with key identifier concatenated with packet. + */ + if (size != BLOCK_OCTETS + 4) + return (0); + MD5Init(&ctx); + MD5Update(&ctx, key, (u_int)cache_keylen); + MD5Update(&ctx, (u_char *)pkt, (u_int)length); + MD5Final(digest, &ctx); + return (!memcmp((char *)digest, (char *)pkt + length + 4, + BLOCK_OCTETS)); +} + + +/* + * session_key - generate session key from supplied plaintext. + * + * Returns hashed session key for validation. + */ +u_long +session_key( + u_int32 srcadr, /* source address */ + u_int32 dstadr, /* destination address */ + u_long keyno, /* key identifier */ + u_long lifetime /* key lifetime */ + ) +{ + MD5_CTX ctx; + u_int32 header[3]; + u_long keyid; + u_char digest[BLOCK_OCTETS]; + + /* + * Generate the session key and retrieve the hash for later. If + * the lifetime is greater than zero, call the key trusted. + */ + header[0] = htonl(srcadr); + header[1] = htonl(dstadr); + header[2] = htonl(keyno); + MD5Init(&ctx); + MD5Update(&ctx, (u_char *)header, sizeof(header)); + MD5Final(digest, &ctx); + memcpy(&keyid, digest, 4); + if (lifetime != 0) { + MD5auth_setkey(keyno, digest, BLOCK_OCTETS); + authtrust(keyno, (int)lifetime); + } +#ifdef DEBUG + if (debug > 1) + printf( + "session_key: from %s to %s keyid %08lx hash %08lx life %ld\n", + numtoa(htonl(srcadr)), numtoa(htonl(dstadr)), keyno, + keyid, lifetime); +#endif + return (keyid); +} +#endif /* MD5 */ diff --git a/contrib/ntp/libntp/adjtime.c b/contrib/ntp/libntp/adjtime.c new file mode 100644 index 000000000000..72be86090b47 --- /dev/null +++ b/contrib/ntp/libntp/adjtime.c @@ -0,0 +1,152 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef NEED_HPUX_ADJTIME +/*************************************************************************/ +/* (c) Copyright Tai Jin, 1988. All Rights Reserved. */ +/* Hewlett-Packard Laboratories. */ +/* */ +/* Permission is hereby granted for unlimited modification, use, and */ +/* distribution. This software is made available with no warranty of */ +/* any kind, express or implied. This copyright notice must remain */ +/* intact in all versions of this software. */ +/* */ +/* The author would appreciate it if any bug fixes and enhancements were */ +/* to be sent back to him for incorporation into future versions of this */ +/* software. Please send changes to tai@iag.hp.com or ken@sdd.hp.com. */ +/*************************************************************************/ + +/* + * Revision history + * + * 9 Jul 94 David L. Mills, Unibergity of Delabunch + * Implemented variable threshold to limit age of + * corrections; reformatted code for readability. + */ + +#ifndef lint +static char RCSid[] = "adjtime.c,v 3.1 1993/07/06 01:04:42 jbj Exp"; +#endif + +#include +#include +#include +#include +#include +#include "adjtime.h" + +#define abs(x) ((x) < 0 ? -(x) : (x)) + +/* + * The following paramters are appropriate for an NTP adjustment + * interval of one second. + */ +#define ADJ_THRESH 200 /* initial threshold */ +#define ADJ_DELTA 4 /* threshold decrement */ + +static long adjthresh; /* adjustment threshold */ +static long saveup; /* corrections accumulator */ + +/* + * clear_adjtime - reset accumulator and threshold variables + */ +void +_clear_adjtime(void) +{ + saveup = 0; + adjthresh = ADJ_THRESH; +} + +/* + * adjtime - hp-ux copout of the standard Unix adjtime() system call + */ +int +adjtime( + register struct timeval *delta, + register struct timeval *olddelta + ) +{ + struct timeval newdelta; + + /* + * Corrections greater than one second are done immediately. + */ + if (delta->tv_sec) { + adjthresh = ADJ_THRESH; + saveup = 0; + return(_adjtime(delta, olddelta)); + } + + /* + * Corrections less than one second are accumulated until + * tripping a threshold, which is initially set at ADJ_THESH and + * reduced in ADJ_DELTA steps to zero. The idea here is to + * introduce large corrections quickly, while making sure that + * small corrections are introduced without excessive delay. The + * idea comes from the ARPAnet routing update algorithm. + */ + saveup += delta->tv_usec; + if (abs(saveup) >= adjthresh) { + adjthresh = ADJ_THRESH; + newdelta.tv_sec = 0; + newdelta.tv_usec = saveup; + saveup = 0; + return(_adjtime(&newdelta, olddelta)); + } else { + adjthresh -= ADJ_DELTA; + } + + /* + * While nobody uses it, return the residual before correction, + * as per Unix convention. + */ + if (olddelta) + olddelta->tv_sec = olddelta->tv_usec = 0; + return(0); +} + +/* + * _adjtime - does the actual work + */ +int +_adjtime( + register struct timeval *delta, + register struct timeval *olddelta + ) +{ + register int mqid; + MsgBuf msg; + register MsgBuf *msgp = &msg; + + /* + * Get the key to the adjtime message queue (note that we must + * get it every time because the queue might have been removed + * and recreated) + */ + if ((mqid = msgget(KEY, 0)) == -1) + return (-1); + msgp->msgb.mtype = CLIENT; + msgp->msgb.tv = *delta; + if (olddelta) + msgp->msgb.code = DELTA2; + else + msgp->msgb.code = DELTA1; + + /* + * Tickle adjtimed and snatch residual, if indicated. Lots of + * fanatic error checking here. + */ + if (msgsnd(mqid, &msgp->msgp, MSGSIZE, 0) == -1) + return (-1); + if (olddelta) { + if (msgrcv(mqid, &msgp->msgp, MSGSIZE, SERVER, 0) == -1) + return (-1); + *olddelta = msgp->msgb.tv; + } + return (0); +} + +#else /* not NEED_HPUX_ADJTIME */ +int adjtime_bs; +#endif /* not NEED_HPUX_ADJTIME */ diff --git a/contrib/ntp/libntp/adjtimex.c b/contrib/ntp/libntp/adjtimex.c new file mode 100644 index 000000000000..03e9d79e359e --- /dev/null +++ b/contrib/ntp/libntp/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/ntp/libntp/atoint.c b/contrib/ntp/libntp/atoint.c new file mode 100644 index 000000000000..46cd96d19cf7 --- /dev/null +++ b/contrib/ntp/libntp/atoint.c @@ -0,0 +1,50 @@ +/* + * atoint - convert an ascii string to a signed long, with error checking + */ +#include +#include + +#include "ntp_types.h" +#include "ntp_stdlib.h" + +int +atoint( + const char *str, + long *ival + ) +{ + register 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((int)*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 = -u; + else + *ival = u; + return 1; +} diff --git a/contrib/ntp/libntp/atolfp.c b/contrib/ntp/libntp/atolfp.c new file mode 100644 index 000000000000..ff50947f0c47 --- /dev/null +++ b/contrib/ntp/libntp/atolfp.c @@ -0,0 +1,118 @@ +/* + * atolfp - convert an ascii string to an l_fp number + */ +#include +#include + +#include "ntp_fp.h" +#include "ntp_string.h" + +/* + * Powers of 10 + */ +static u_long ten_to_the_n[10] = { + 0, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, +}; + + +int +atolfp( + 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 const 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((int)*cp)) + cp++; + + if (*cp == '-') { + cp++; + isneg = 1; + } + + if (*cp == '+') + cp++; + + if (*cp != '.' && !isdigit((int)*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((int)*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((int)*cp)) + cp++; + + if (*cp != '\0' && !isspace((int)*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/ntp/libntp/atouint.c b/contrib/ntp/libntp/atouint.c new file mode 100644 index 000000000000..c25e3a0c51a7 --- /dev/null +++ b/contrib/ntp/libntp/atouint.c @@ -0,0 +1,35 @@ +/* + * atouint - convert an ascii string to an unsigned long, with error checking + */ +#include +#include + +#include "ntp_types.h" +#include "ntp_stdlib.h" + +int +atouint( + 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((int)*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/ntp/libntp/authencrypt.c b/contrib/ntp/libntp/authencrypt.c new file mode 100644 index 000000000000..22f910c36691 --- /dev/null +++ b/contrib/ntp/libntp/authencrypt.c @@ -0,0 +1,97 @@ +/* + * DES interface for rsaref2.0 + * + * These routines implement an interface for the RSA Laboratories + * implementation of the Data Encryption Standard (DES) algorithm + * operating in Cipher-Block Chaining (CBC) mode. This algorithm is + * included in the rsaref2.0 package available from RSA in the US and + * foreign countries. Further information is available at www.rsa.com. + */ + +#include "ntp_machine.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef DES +#include "ntp_types.h" +#include "ntp_fp.h" +#include "ntp_string.h" +#include "global.h" +#include "des.h" +#include "ntp_stdlib.h" + +#define BLOCK_OCTETS 8 /* message digest size */ +#define MAXTPKT 128 /* max packet size */ + + +/* + * DESauthencrypt - generate DES-CBC message authenticator + * + * Returns length of authenticator field. + */ +int +DESauthencrypt( + u_char *key, /* key pointer */ + u_int32 *pkt, /* packet pointer */ + int length /* packet length */ + ) +{ + DES_CBC_CTX ctx; + u_int32 tpkt[MAXTPKT]; + u_int32 work[2]; + int i, j; + + /* + * DES-CBC with zero IV. Note the encrypted text is discarded. + */ + work[0] = work[1] = 0; + DES_CBCInit(&ctx, key, (u_char *)work, 1); + DES_CBCUpdate(&ctx, (u_char *)tpkt, (u_char *)pkt, + (u_int)length); + i = length / 4 + 1; + j = i - 3; + pkt[i++] = (u_int32)htonl(tpkt[j++]); + pkt[i] = (u_int32)htonl(tpkt[j]); + return (BLOCK_OCTETS + 4); +} + + +/* + * DESauthdecrypt - verify DES message authenticator + * + * Returns one if authenticator valid, zero if invalid. + */ +int +DESauthdecrypt( + u_char *key, /* key pointer */ + u_int32 *pkt, /* packet pointer */ + int length, /* packet length */ + int size /* size of MAC field */ + ) +{ + DES_CBC_CTX ctx; + u_int32 tpkt[MAXTPKT]; + u_int32 work[2]; + int i, j; + + /* + * DES-CBC with zero IV. Note the encrypted text is discarded. + */ + if (size != BLOCK_OCTETS + 4) + return (0); + work[0] = work[1] = 0; + DES_CBCInit (&ctx, key, (u_char *)work, 1); + DES_CBCUpdate (&ctx, (u_char *)tpkt, (u_char *)pkt, + (u_int)length); + i = length / 4 + 1; + j = i - 3; + if ((u_int32)ntohl(pkt[i++]) == tpkt[j++] && + (u_int32)ntohl(pkt[i]) == tpkt[j]) + return (1); + return (0); +} +#else +int authencrypt_bs; +#endif /* DES */ diff --git a/contrib/ntp/libntp/authkeys.c b/contrib/ntp/libntp/authkeys.c new file mode 100644 index 000000000000..39ca4938f3d4 --- /dev/null +++ b/contrib/ntp/libntp/authkeys.c @@ -0,0 +1,574 @@ +/* + * authkeys.c - routines to manage the storage of authentication keys + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "ntp_types.h" +#include "ntp_fp.h" +#include "ntp.h" +#include "ntpd.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 { + long bogon; /* Make sure nonempty */ +#ifdef DES + u_int32 DES_key[2]; /* DES key */ +#endif +#ifdef MD5 + u_char MD5_key[32]; /* MD5 key */ +#endif + } k; + u_long keyid; /* key identifier */ + u_short flags; /* flags that wave */ + u_long lifetime; /* remaining lifetime */ +#ifdef MD5 + int keylen; /* key length */ +#endif +}; + +#define KEY_TRUSTED 0x001 /* this key is trusted */ +#define KEY_DES 0x100 /* this is a DES type key */ +#define KEY_MD5 0x200 /* this is a MD5 type key */ + +/* + * 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; /* keys not found */ +u_long authkeylookups; /* calls to lookup keys */ +u_long authnumkeys; /* number of active keys */ +u_long authkeyexpired; /* key lifetime expirations */ +u_long authkeyuncached; /* cache misses */ +u_long authnokey; /* calls to encrypt with no key */ +u_long authencryptions; /* calls to encrypt */ +u_long authdecryptions; /* calls to decrypt */ + +/* + * 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 */ + +/* + * The key cache. We cache the last key we looked at here. + */ +u_long cache_keyid; /* key identifier */ +u_char *cache_key; /* key pointer */ +u_int cache_keylen; /* key length */ +u_short cache_flags; /* flags that wave */ + + +/* + * init_auth - initialize internal data + */ +void +init_auth(void) +{ + /* + * Initialize hash table and free list + */ + memset((char *)key_hash, 0, sizeof key_hash); +} + + +/* + * auth_findkey - find a key in the hash table + */ +struct savekey * +auth_findkey( + u_long keyno + ) +{ + 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 one if the key is known + */ +int +auth_havekey( + u_long keyno + ) +{ + struct savekey *sk; + + if (keyno == 0 || (keyno == cache_keyid)) + return (1); + + sk = key_hash[KEYHASH(keyno)]; + while (sk != 0) { + if (keyno == sk->keyid) + return (1); + + sk = sk->next; + } + return (0); +} + + +/* + * authhavekey - return one and cache the key, if known and trusted. + */ +int +authhavekey( + u_long keyno + ) +{ + struct savekey *sk; + + authkeylookups++; + if (keyno == 0 || keyno == cache_keyid) + return (1); + + authkeyuncached++; + sk = key_hash[KEYHASH(keyno)]; + while (sk != 0) { + if (keyno == sk->keyid) + break; + sk = sk->next; + } + if (sk == 0) { + authkeynotfound++; + return (0); + } else if (!(sk->flags & KEY_TRUSTED)) { + authnokey++; + return (0); + } + cache_keyid = sk->keyid; + cache_flags = sk->flags; +#ifdef MD5 + if (sk->flags & KEY_MD5) { + cache_key = sk->k.MD5_key; + cache_keylen = sk->keylen; + return (1); + } +#endif +#ifdef DES + if (sk->flags & KEY_DES) { + cache_key = (u_char *)sk->k.DES_key; + return (1); + } +#endif + return (0); +} + + +/* + * auth_moremem - get some more free key structures + */ +int +auth_moremem(void) +{ + struct savekey *sk; + 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( + u_long keyno, + int trust + ) +{ + struct savekey *sk; + +#ifdef DEBUG + if (debug > 1) + printf("authtrust: keyid %08lx life %d\n", (u_long)keyno, trust); +#endif + 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 = 0; + cache_keyid = 0; + } + + if (trust > 0) { + sk->flags |= KEY_TRUSTED; + if (trust > 1) + sk->lifetime = current_time + trust; + else + sk->lifetime = 0; + return; + } + + sk->flags &= ~KEY_TRUSTED; { + 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( + u_long keyno + ) +{ + 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) { + authkeynotfound++; + return (0); + } else if (!(sk->flags & KEY_TRUSTED)) { + authkeynotfound++; + return (0); + } + return (1); +} + + + +#ifdef DES +/* + * DESauth_setkey - set a key into the key array + */ +void +DESauth_setkey( + u_long keyno, + const u_int32 *key + ) +{ + 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_DES; + if (cache_keyid == keyno) + cache_flags = 0; + 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_DES; + sk->lifetime = 0; + sk->next = key_hash[KEYHASH(keyno)]; + key_hash[KEYHASH(keyno)] = sk; + authnumkeys++; + return; +} +#endif + +#ifdef MD5 +void +MD5auth_setkey( + u_long keyno, + const u_char *key, + const int len + ) +{ + 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((char *)sk->k.MD5_key, (const char *)key, + sizeof(sk->k.MD5_key)); + if ((sk->keylen = len) > sizeof(sk->k.MD5_key)) + sk->keylen = sizeof(sk->k.MD5_key); + + sk->flags |= KEY_MD5; + if (cache_keyid == keyno) { + cache_flags = 0; + 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((char *)sk->k.MD5_key, (const char *)key, + sizeof(sk->k.MD5_key)); + if ((sk->keylen = len) > sizeof(sk->k.MD5_key)) + sk->keylen = sizeof(sk->k.MD5_key); + + sk->keyid = keyno; + sk->flags = KEY_MD5; + sk->lifetime = 0; + 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(void) +{ + struct savekey *sk; + struct savekey **skp; + int i; + + for (i = 0; i < HASHSIZE; i++) { + skp = &(key_hash[i]); + sk = key_hash[i]; + /* + * Leave autokey keys alone. + */ + while (sk != 0 && sk->keyid <= NTP_MAXKEY) { + /* + * Don't loose info which keys are trusted. + */ + if (sk->flags & KEY_TRUSTED) { + memset(&sk->k, 0, sizeof(sk->k)); + sk->lifetime = 0; +#ifdef MD5 + sk->keylen = 0; +#endif + sk = sk->next; + } else { + *skp = sk->next; + authnumkeys--; + sk->next = authfreekeys; + authfreekeys = sk; + authnumfreekeys++; + sk = *skp; + } + } + } +} + +/* + * auth_agekeys - delete keys whose lifetimes have expired + */ +void +auth_agekeys(void) +{ + struct savekey *sk; + struct savekey *skp; + int i; + + for (i = 0; i < HASHSIZE; i++) { + sk = skp = key_hash[i]; + while (sk != 0) { + skp = sk->next; + if (sk->lifetime > 0 && current_time > + sk->lifetime) { + authtrust(sk->keyid, 0); + authkeyexpired++; + } + sk = skp; + } + } +#ifdef DEBUG + if (debug) + printf("auth_agekeys: at %lu keys %lu expired %lu\n", + current_time, authnumkeys, authkeyexpired); +#endif +} + +/* + * authencrypt - generate message authenticator + * + * Returns length of authenticator field, zero if key not found. + */ +int +authencrypt( + u_long keyno, + u_int32 *pkt, + int length + ) +{ + + /* + * A zero key identifier means the sender has not verified + * the last message was correctly authenticated. The MAC + * consists of a single word with value zero. + */ + authencryptions++; + pkt[length / 4] = (u_long)htonl(keyno); + if (keyno == 0) { + return (4); + } + if (!authhavekey(keyno)) + return (0); + +#ifdef DES + if (cache_flags & KEY_DES) + return (DESauthencrypt(cache_key, pkt, length)); +#endif + +#ifdef MD5 + if (cache_flags & KEY_MD5) + return (MD5authencrypt(cache_key, pkt, length)); +#endif + return (0); +} + +/* + * authdecrypt - verify message authenticator + * + * Returns one if authenticator valid, zero if invalid or key not found. + */ +int +authdecrypt( + u_long keyno, + u_int32 *pkt, + int length, + int size + ) +{ + + /* + * A zero key identifier means the sender has not verified + * the last message was correctly authenticated. Nevertheless, + * the authenticator itself is considered valid. + */ + authdecryptions++; + if (keyno == 0) + return (1); + + if (!authhavekey(keyno) || size < 4) + return (0); + +#ifdef DES + if (cache_flags & KEY_DES) + return (DESauthdecrypt(cache_key, pkt, length, size)); +#endif + +#ifdef MD5 + if (cache_flags & KEY_MD5) + return (MD5authdecrypt(cache_key, pkt, length, size)); +#endif + + return (0); +} diff --git a/contrib/ntp/libntp/authparity.c b/contrib/ntp/libntp/authparity.c new file mode 100644 index 000000000000..32fde586c00f --- /dev/null +++ b/contrib/ntp/libntp/authparity.c @@ -0,0 +1,57 @@ +/* + * auth_parity - set parity on a key/check for odd parity + */ +#include "ntp_stdlib.h" + +int +DESauth_parity( + u_int32 *key + ) +{ + u_int32 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/ntp/libntp/authreadkeys.c b/contrib/ntp/libntp/authreadkeys.c new file mode 100644 index 000000000000..18ac0dd15683 --- /dev/null +++ b/contrib/ntp/libntp/authreadkeys.c @@ -0,0 +1,205 @@ +/* + * authreadkeys.c - routines to support the reading of the key file + */ +#include +#include + +#include "ntp_fp.h" +#include "ntp.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 + +/* Forwards */ +static char *nexttok P((char **)); + +/* + * nexttok - basic internal tokenizing routine + */ +static char * +nexttok( + 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( + const char *file + ) +{ + FILE *fp; + char *line; + char *token; + u_long keyno; + int keytype; + char buf[512]; /* lots of room for line */ + + /* + * Open file. Complain and return if it can't be opened. + */ + fp = fopen(file, "r"); + if (fp == NULL) { + msyslog(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 = atoi(token); + if (keyno == 0) { + msyslog(LOG_ERR, + "cannot change keyid 0, key entry `%s' ignored", + token); + continue; + } + + if (keyno > NTP_MAXKEY) { + msyslog(LOG_ERR, + "keyid's > %d reserved for autokey, key entry `%s' ignored", + NTP_MAXKEY, token); + continue; + } + + /* + * Next is keytype. See if that is all right. + */ + token = nexttok(&line); + if (token == 0) { + msyslog(LOG_ERR, + "no key type for key number %ld, 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: + msyslog(LOG_ERR, + "invalid key type for key number %ld, entry ignored", + keyno); + continue; + } + + /* + * Finally, get key and insert it + */ + token = nexttok(&line); + if (token == 0) { + msyslog(LOG_ERR, + "no key for number %ld 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, + (u_char *)token)) + msyslog(LOG_ERR, + "format/parity error for DES key %ld, not used", + keyno); + break; +#endif +#ifdef MD5 + case KEY_TYPE_MD5: + if (!authusekey(keyno, keytype, + (u_char *)token)) + msyslog(LOG_ERR, + "format/parity error for MD5 key %ld, not used", + keyno); + break; +#endif + } + } + } + (void) fclose(fp); + return 1; +} diff --git a/contrib/ntp/libntp/authusekey.c b/contrib/ntp/libntp/authusekey.c new file mode 100644 index 000000000000..a399a48a13a0 --- /dev/null +++ b/contrib/ntp/libntp/authusekey.c @@ -0,0 +1,134 @@ +/* + * authusekey - decode a key from ascii and use it + */ +#include +#include + +#include "ntp_types.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" + +/* + * Types of ascii representations for keys. "Standard" means a 64 bit + * hex number in NBS format, i.e. with the low order bit of each byte + * a parity bit. "NTP" means a 64 bit key in NTP format, with the + * high order bit of each byte a parity bit. "Ascii" means a 1-to-8 + * character string whose ascii representation is used as the key. + */ +#ifdef DES +#define KEY_TYPE_STD 1 +#define KEY_TYPE_NTP 2 +#define KEY_TYPE_ASCII 3 + +#define STD_PARITY_BITS ((unsigned)0x01010101) + +#endif + +#ifdef MD5 +#define KEY_TYPE_MD5 4 +#endif + +int +authusekey( + u_long keyno, + int keytype, + const u_char *str + ) +{ +#ifdef DES + u_int32 key[2]; + u_char keybytes[8]; + char *xdigit; + int i; + static const char *hex = "0123456789abcdef"; +#endif + const u_char *cp; + int len; + + cp = str; + len = strlen((const char *)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_int32)(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_int32)keybytes[0] << 24 | (u_int32)keybytes[1] << 16 + | (u_int32)keybytes[2] << 8 | (u_int32)keybytes[3]; + key[1] = (u_int32)keybytes[4] << 24 | (u_int32)keybytes[5] << 16 + | (u_int32)keybytes[6] << 8 | (u_int32)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: + MD5auth_setkey(keyno, str, (int)strlen((const char *)str)); + break; +#endif + + default: + /* Oh, well */ + return 0; + } + + return 1; +} diff --git a/contrib/ntp/libntp/binio.c b/contrib/ntp/libntp/binio.c new file mode 100644 index 000000000000..cc3b408df9e8 --- /dev/null +++ b/contrib/ntp/libntp/binio.c @@ -0,0 +1,128 @@ +/* + * /src/NTP/ntp-4/libntp/binio.c,v 4.2 1999/02/21 12:17:34 kardel RELEASE_19990228_A + * + * $Created: Sun Jul 20 12:55:33 1997 $ + * + * Copyright (C) 1997, 1998 by Frank Kardel + */ + +#include "binio.h" + +long +get_lsb_short( + unsigned char **bufpp + ) +{ + long retval; + + retval = *((*bufpp)++); + retval |= *((*bufpp)++) << 8; + + return (retval & 0x8000) ? (~0xFFFF | retval) : retval; +} + +void +put_lsb_short( + unsigned char **bufpp, + long val + ) +{ + *((*bufpp)++) = val & 0xFF; + *((*bufpp)++) = (val >> 8) & 0xFF; +} + +long +get_lsb_long( + unsigned char **bufpp + ) +{ + long retval; + + retval = *((*bufpp)++); + retval |= *((*bufpp)++) << 8; + retval |= *((*bufpp)++) << 16; + retval |= *((*bufpp)++) << 24; + + return retval; +} + +void +put_lsb_long( + unsigned char **bufpp, + long val + ) +{ + *((*bufpp)++) = val & 0xFF; + *((*bufpp)++) = (val >> 8) & 0xFF; + *((*bufpp)++) = (val >> 16) & 0xFF; + *((*bufpp)++) = (val >> 24) & 0xFF; +} + +long +get_msb_short( + unsigned char **bufpp + ) +{ + long retval; + + retval = *((*bufpp)++) << 8; + retval |= *((*bufpp)++); + + return (retval & 0x8000) ? (~0xFFFF | retval) : retval; +} + +void +put_msb_short( + unsigned char **bufpp, + long val + ) +{ + *((*bufpp)++) = (val >> 8) & 0xFF; + *((*bufpp)++) = val & 0xFF; +} + +long +get_msb_long( + unsigned char **bufpp + ) +{ + long retval; + + retval = *((*bufpp)++) << 24; + retval |= *((*bufpp)++) << 16; + retval |= *((*bufpp)++) << 8; + retval |= *((*bufpp)++); + + return retval; +} + +void +put_msb_long( + unsigned char **bufpp, + long val + ) +{ + *((*bufpp)++) = (val >> 24) & 0xFF; + *((*bufpp)++) = (val >> 16) & 0xFF; + *((*bufpp)++) = (val >> 8 ) & 0xFF; + *((*bufpp)++) = val & 0xFF; +} + +/* + * binio.c,v + * Revision 4.2 1999/02/21 12:17:34 kardel + * 4.91f reconcilation + * + * Revision 4.1 1998/06/28 16:47:50 kardel + * added {get,put}_msb_{short,long} functions + * + * Revision 4.0 1998/04/10 19:46:16 kardel + * Start 4.0 release version numbering + * + * Revision 1.1 1998/04/10 19:27:46 kardel + * initial NTP VERSION 4 integration of PARSE with GPS166 binary support + * + * Revision 1.1 1997/10/06 21:05:46 kardel + * new parse structure + * + */ diff --git a/contrib/ntp/libntp/buftvtots.c b/contrib/ntp/libntp/buftvtots.c new file mode 100644 index 000000000000..96338bc1be59 --- /dev/null +++ b/contrib/ntp/libntp/buftvtots.c @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ntp_fp.h" +#include "ntp_unixtime.h" + +int +buftvtots( + const char *bufp, + l_fp *ts + ) +{ + register const u_char *bp; + register u_long sec; + register u_long usec; + +#ifdef WORDS_BIGENDIAN + bp = (const 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 = (const 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 + ts->l_ui = sec + (u_long)JAN_1970; + if (usec > 999999) + return 0; + TVUTOTSF(usec, ts->l_uf); + return 1; +} diff --git a/contrib/ntp/libntp/caljulian.c b/contrib/ntp/libntp/caljulian.c new file mode 100644 index 000000000000..948bb1c57dd8 --- /dev/null +++ b/contrib/ntp/libntp/caljulian.c @@ -0,0 +1,115 @@ +/* + * caljulian - determine the Julian date from an NTP time. + */ +#include + +#include "ntp_types.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * calmonthtab - days-in-the-month table + */ +static u_short calmonthtab[11] = { + JAN, + FEB, + MAR, + APR, + MAY, + JUN, + JUL, + AUG, + SEP, + OCT, + NOV +}; + +void +caljulian( + u_long ntptime, + register struct calendar *jt + ) +{ + u_long ntp_day; + u_long minutes; + /* + * Absolute, zero-adjusted Christian era day, starting from the + * mythical day 12/1/1 BC + */ + u_long acez_day; + + u_long d400; /* Days into a Gregorian cycle */ + u_long d100; /* Days into a normal century */ + u_long d4; /* Days into a 4-year cycle */ + u_long n400; /* # of Gregorian cycles */ + u_long n100; /* # of normal centuries */ + u_long n4; /* # of 4-year cycles */ + u_long n1; /* # of years into a leap year */ + /* cycle */ + + /* + * Do the easy stuff first: take care of hh:mm:ss, ignoring leap + * seconds + */ + jt->second = (u_char)(ntptime % SECSPERMIN); + minutes = ntptime / SECSPERMIN; + jt->minute = (u_char)(minutes % MINSPERHR); + jt->hour = (u_char)((minutes / MINSPERHR) % HRSPERDAY); + + /* + * Find the day past 1900/01/01 00:00 UTC + */ + ntp_day = ntptime / SECSPERDAY; + acez_day = DAY_NTP_STARTS + ntp_day - 1; + n400 = acez_day/GREGORIAN_CYCLE_DAYS; + d400 = acez_day%GREGORIAN_CYCLE_DAYS; + n100 = d400 / GREGORIAN_NORMAL_CENTURY_DAYS; + d100 = d400 % GREGORIAN_NORMAL_CENTURY_DAYS; + n4 = d100 / GREGORIAN_NORMAL_LEAP_CYCLE_DAYS; + d4 = d100 % GREGORIAN_NORMAL_LEAP_CYCLE_DAYS; + n1 = d4 / DAYSPERYEAR; + + /* + * Calculate the year and year-of-day + */ + jt->yearday = (u_short)(1 + d4%DAYSPERYEAR); + jt->year = (u_short)(400*n400 + 100*n100 + n4*4 + n1); + + if (n100 == 4 || n1 == 4) + { + /* + * If the cycle year ever comes out to 4, it must be December 31st + * of a leap year. + */ + jt->month = 12; + jt->monthday = 31; + jt->yearday = 366; + } + else + { + /* + * Else, search forwards through the months to get the right month + * and date. + */ + int monthday; + + jt->year++; + monthday = jt->yearday; + + for (jt->month=0;jt->month<11; jt->month++) + { + int t; + + t = monthday - calmonthtab[jt->month]; + if (jt->month == 1 && is_leapyear(jt->year)) + t--; + + if (t > 0) + monthday = t; + else + break; + } + jt->month++; + jt->monthday = monthday; + } +} diff --git a/contrib/ntp/libntp/calleapwhen.c b/contrib/ntp/libntp/calleapwhen.c new file mode 100644 index 000000000000..c9549010d57c --- /dev/null +++ b/contrib/ntp/libntp/calleapwhen.c @@ -0,0 +1,59 @@ +/* + * calleapwhen - determine the number of seconds to the next possible + * leap occurance. + */ +#include + +#include "ntp_types.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * calleaptab - leaps occur at the end of December and June + */ +long calleaptab[10] = { + -(JAN+FEBLEAP)*SECSPERDAY, /* leap previous to cycle */ + (MAR+APR+MAY+JUN)*SECSPERDAY, /* end of June */ + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC)*SECSPERDAY, /* end of Dec */ + (MAR+APR+MAY+JUN)*SECSPERDAY + SECSPERYEAR, + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC)*SECSPERDAY + SECSPERYEAR, + (MAR+APR+MAY+JUN)*SECSPERDAY + 2*SECSPERYEAR, + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC)*SECSPERDAY + 2*SECSPERYEAR, + (MAR+APR+MAY+JUN)*SECSPERDAY + 3*SECSPERYEAR, + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC)*SECSPERDAY + 3*SECSPERYEAR, + (MAR+APR+MAY+JUN+JUL+AUG+SEP+OCT+NOV+DEC+JAN+FEBLEAP+MAR+APR+MAY+JUN) + *SECSPERDAY + 3*SECSPERYEAR, /* next after current cycle */ +}; + +u_long +calleapwhen( + u_long ntpdate + ) +{ + 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. + */ + return (u_long)(calleaptab[i] - (long)dateincycle); +} diff --git a/contrib/ntp/libntp/caltontp.c b/contrib/ntp/libntp/caltontp.c new file mode 100644 index 000000000000..9ec106416dd0 --- /dev/null +++ b/contrib/ntp/libntp/caltontp.c @@ -0,0 +1,42 @@ +/* + * caltontp - convert a date to an NTP time + */ +#include + +#include "ntp_types.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +u_long +caltontp( + register const struct calendar *jt + ) +{ + u_long ace_days; /* absolute Christian Era days */ + u_long ntp_days; + int prior_years; + u_long ntp_time; + + /* + * First convert today's date to absolute days past 12/1/1 BC + */ + prior_years = jt->year-1; + ace_days = jt->yearday /* days this year */ + +(DAYSPERYEAR*prior_years) /* plus days in previous years */ + +(prior_years/4) /* plus prior years's leap days */ + -(prior_years/100) /* minus leapless century years */ + +(prior_years/400); /* plus leapful Gregorian yrs */ + + /* + * Subtract out 1/1/1900, the beginning of the NTP epoch + */ + ntp_days = ace_days - DAY_NTP_STARTS; + + /* + * Do the obvious: + */ + ntp_time = + ntp_days*SECSPERDAY+SECSPERMIN*(MINSPERHR*jt->hour + jt->minute); + + return ntp_time; +} diff --git a/contrib/ntp/libntp/calyearstart.c b/contrib/ntp/libntp/calyearstart.c new file mode 100644 index 000000000000..0f7ca4f9d065 --- /dev/null +++ b/contrib/ntp/libntp/calyearstart.c @@ -0,0 +1,22 @@ +/* + * calyearstart - determine the NTP time at midnight of January 1 in + * the year of the given date. + */ +#include + +#include "ntp_types.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +u_long +calyearstart(u_long ntp_time) +{ + struct calendar jt; + + caljulian(ntp_time,&jt); + jt.yearday = 1; + jt.monthday = 1; + jt.month = 1; + jt.hour = jt.minute = jt.second = 0; + return caltontp(&jt); +} diff --git a/contrib/ntp/libntp/clocktime.c b/contrib/ntp/libntp/clocktime.c new file mode 100644 index 000000000000..371859cda21c --- /dev/null +++ b/contrib/ntp/libntp/clocktime.c @@ -0,0 +1,132 @@ +/* + * 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( + int yday, + int hour, + int minute, + int second, + int tzoff, + u_long rec_ui, + u_long *yearstart, + u_int32 *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/ntp/libntp/clocktypes.c b/contrib/ntp/libntp/clocktypes.c new file mode 100644 index 000000000000..c9a67668aa6d --- /dev/null +++ b/contrib/ntp/libntp/clocktypes.c @@ -0,0 +1,98 @@ +/* + * Data for pretty printing clock types + */ +#include + +#include "ntp_fp.h" +#include "ntp.h" +#include "lib_strbuf.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +struct clktype clktypes[] = { + { REFCLK_NONE, "unspecified type (0)", + "UNKNOWN" }, + { REFCLK_LOCALCLOCK, "Undisciplined local clock (1)", + "LOCAL" }, + { REFCLK_GPS_TRAK, "TRAK 8810 GPS Receiver (2)", + "GPS_TRAK" }, + { REFCLK_WWV_PST, "PSTI/Traconex WWV/WWVH Receiver (3)", + "WWV_PST" }, + { REFCLK_WWVB_SPECTRACOM, "Spectracom WWVB Receiver (4)", + "WWVB_SPEC" }, + { REFCLK_TRUETIME, "TrueTime (generic) Receivers (5)", + "TRUETIME" }, + { REFCLK_IRIG_AUDIO, "IRIG Audio Decoder (6)", + "IRIG_AUDIO" }, + { REFCLK_CHU, "Scratchbuilt CHU Receiver (7)", + "CHU" }, + { REFCLK_PARSE, "Generic reference clock driver (8)", + "GENERIC" }, + { REFCLK_GPS_MX4200, "Magnavox MX4200 GPS Receiver (9)", + "GPS_MX4200" }, + { REFCLK_GPS_AS2201, "Austron 2201A GPS Receiver (10)", + "GPS_AS2201" }, + { REFCLK_GPS_ARBITER, "Arbiter 1088A/B GPS Receiver (11)", + "GPS_ARBITER" }, + { REFCLK_IRIG_TPRO, "KSI/Odetics TPRO/S IRIG Interface (12)", + "IRIG_TPRO" }, + { REFCLK_ATOM_LEITCH, "Leitch CSD 5300 Master Clock Controller (13)", + "ATOM_LEITCH" }, + { REFCLK_MSF_EES, "EES M201 MSF Receiver (14)", + "MSF_EES" }, + { REFCLK_GPSTM_TRUE, "TrueTime (old GPSTM driver) Receiver (15)", + "GPSTM_TRUE" }, + { REFCLK_IRIG_BANCOMM, "Bancomm GPS/IRIG Receiver (16)", + "GPS_BANC" }, + { REFCLK_GPS_DATUM, "Datum Precision Time System (17)", + "GPS_DATUM" }, + { REFCLK_NIST_ACTS, "NIST Automated Computer Time Service (18)", + "ACTS_NIST" }, + { REFCLK_WWV_HEATH, "Heath WWV/WWVH Receiver (19)", + "WWV_HEATH" }, + { REFCLK_GPS_NMEA, "Generic NMEA GPS Receiver (20)", + "GPS_NMEA" }, + { REFCLK_GPS_VME, "TrueTime GPS-VME Interface (21)", + "GPS_VME" }, + { REFCLK_ATOM_PPS, "PPS Clock Discipline (22)", + "PPS" }, + { REFCLK_PTB_ACTS, "PTB Automated Computer Time Service (23)", + "ACTS_PTB" }, + { REFCLK_USNO, "Naval Observatory dialup (24)", + "ACTS_USNO" }, + { REFCLK_TRUETIME, "TrueTime (generic) Receivers (25)", + "TRUETIME" }, + { REFCLK_GPS_HP, "HP 58503A GPS Time & Frequency Receiver (26)", + "GPS_HP" }, + { REFCLK_ARCRON_MSF, "ARCRON MSF (and DCF77) Receiver (27)", + "MSF_ARCRON" }, + { REFCLK_SHM, "Clock attached thru shared Memory (28)", + "SHM" }, + { REFCLK_PALISADE, "Trimble Navigation Palisade GPS (29)", + "GPS_PALISADE" }, + { REFCLK_ONCORE, "Motorola UT Oncore GPS (30)", + "GPS_ONCORE" }, + { REFCLK_GPS_JUPITER, "Rockwell Jupiter GPS (31)", + "GPS_JUPITER" }, + { REFCLK_CHRONOLOG, "Chrono-log K (32)", + "CHRONOLOG" }, + { REFCLK_DUMBCLOCK, "Dumb generic hh:mm:ss local clock", + "DUMBCLOCK" }, + { REFCLK_ULINK, "Ultralink M320 WWVB receiver", + "ULINK_M320"}, + { -1, "", "" } +}; + +const char * +clockname( + 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/ntp/libntp/decodenetnum.c b/contrib/ntp/libntp/decodenetnum.c new file mode 100644 index 000000000000..a24e4933af91 --- /dev/null +++ b/contrib/ntp/libntp/decodenetnum.c @@ -0,0 +1,59 @@ +/* + * decodenetnum - return a net number (this is crude, but careful) + */ +#include +#include +#include +#include + +#include "ntp_stdlib.h" + +int +decodenetnum( + const char *num, + u_int32 *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((int)*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/ntp/libntp/dofptoa.c b/contrib/ntp/libntp/dofptoa.c new file mode 100644 index 000000000000..caa099746145 --- /dev/null +++ b/contrib/ntp/libntp/dofptoa.c @@ -0,0 +1,118 @@ +/* + * dofptoa - do the grunge work to convert an fp number to ascii + */ +#include + +#include "ntp_fp.h" +#include "lib_strbuf.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" + +char * +dofptoa( + 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/ntp/libntp/dolfptoa.c b/contrib/ntp/libntp/dolfptoa.c new file mode 100644 index 000000000000..5602331ad945 --- /dev/null +++ b/contrib/ntp/libntp/dolfptoa.c @@ -0,0 +1,162 @@ +/* + * dolfptoa - do the grunge work of converting an l_fp number to decimal + */ +#include + +#include "ntp_fp.h" +#include "lib_strbuf.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" + +char * +dolfptoa( + u_long fpi, + u_long fpv, + int neg, + int ndec, + int msec + ) +{ + register u_char *cp, *cpend; + register u_long lwork; + 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]; + lwork = fpi; + if (lwork & 0xffff0000) { + register u_long lten = 10; + register u_long ltmp; + + do { + ltmp = lwork; + lwork /= lten; + ltmp -= (lwork << 3) + (lwork << 1); + *--cp = (u_char)ltmp; + } while (lwork & 0xffff0000); + } + if (lwork != 0) { + register u_short sten = 10; + register u_short stmp; + register u_short swork = (u_short)lwork; + + 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) { + l_fp work; + + work.l_ui = 0; + work.l_uf = fpv; + while (dec > 0) { + l_fp ftmp; + + 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.l_ui = 0; + L_LSHIFT(&work); + ftmp = work; + L_LSHIFT(&work); + L_LSHIFT(&work); + L_ADD(&work, &ftmp); + *cpend++ = (u_char)work.l_ui; + if (work.l_uf == 0) + break; + } + + /* + * Rounding is rotten + */ + if (work.l_uf & 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/ntp/libntp/emalloc.c b/contrib/ntp/libntp/emalloc.c new file mode 100644 index 000000000000..0918c9c7bf41 --- /dev/null +++ b/contrib/ntp/libntp/emalloc.c @@ -0,0 +1,48 @@ +/* + * 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" + +#if defined SYS_WINNT && defined DEBUG +#include +#endif + +#if defined SYS_WINNT && defined DEBUG + +void * +debug_emalloc( + u_int size, + char *filename, + int line + ) +{ + char *mem; + + if ((mem = (char *)_malloc_dbg(size, _NORMAL_BLOCK, filename, line)) == 0) { + msyslog(LOG_ERR, "No more memory!"); + exit(1); + } + return mem; +} + +#else + +void * +emalloc( + u_int size + ) +{ + char *mem; + + if ((mem = (char *)malloc(size)) == 0) { + msyslog(LOG_ERR, "No more memory!"); + exit(1); + } + return mem; +} + + +#endif diff --git a/contrib/ntp/libntp/findconfig.c b/contrib/ntp/libntp/findconfig.c new file mode 100644 index 000000000000..ecf6a4bc204c --- /dev/null +++ b/contrib/ntp/libntp/findconfig.c @@ -0,0 +1,72 @@ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef NEED_HPUX_FINDCONFIG +#include +#include +#include +#include +#include +#include + +const char * +FindConfig( + const 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 +#include "ntp_stdlib.h" + +const char * +FindConfig( + const char *base + ) +{ + return base; +} +#endif diff --git a/contrib/ntp/libntp/fptoa.c b/contrib/ntp/libntp/fptoa.c new file mode 100644 index 000000000000..f0247ddcdf86 --- /dev/null +++ b/contrib/ntp/libntp/fptoa.c @@ -0,0 +1,25 @@ +/* + * fptoa - return an asciized representation of an s_fp number + */ +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +char * +fptoa( + 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/ntp/libntp/fptoms.c b/contrib/ntp/libntp/fptoms.c new file mode 100644 index 000000000000..4d371aadef45 --- /dev/null +++ b/contrib/ntp/libntp/fptoms.c @@ -0,0 +1,24 @@ +/* + * fptoms - return an asciized s_fp number in milliseconds + */ +#include "ntp_fp.h" + +char * +fptoms( + 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/ntp/libntp/getopt.c b/contrib/ntp/libntp/getopt.c new file mode 100644 index 000000000000..7b344f0dc6f4 --- /dev/null +++ b/contrib/ntp/libntp/getopt.c @@ -0,0 +1,107 @@ +/* + * 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 + +#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 const char *prog = "amnesia"; + +/* + * Print message about a bad option. + */ +static int +badopt( + const 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( + int argc, + char *argv[], + const char *optstring + ) +{ + register char c; + register const 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/ntp/libntp/gpstolfp.c b/contrib/ntp/libntp/gpstolfp.c new file mode 100644 index 000000000000..cf7b80c25a26 --- /dev/null +++ b/contrib/ntp/libntp/gpstolfp.c @@ -0,0 +1,41 @@ +/* + * /src/NTP/ntp-4/libntp/gpstolfp.c,v 4.3 1999/02/28 11:42:44 kardel RELEASE_19990228_A + * + * $Created: Sun Jun 28 16:30:38 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#include "ntp_fp.h" + +#define GPSORIGIN (unsigned)(2524953600L) /* NTP origin - GPS origin in seconds */ +#define SECSPERWEEK (unsigned)(604800) /* seconds per week - GPS tells us about weeks */ +#define GPSWRAP 990 /* assume week count less than this in the previous epoch */ + +void +gpstolfp( + int weeks, + int days, + unsigned long seconds, + l_fp * lfp + ) +{ + if (weeks < GPSWRAP) + { + weeks += 1024; + } + + lfp->l_ui = weeks * SECSPERWEEK + days * 86400 + seconds + GPSORIGIN; /* convert to NTP time */ + lfp->l_uf = 0; +} + +/* + * gpstolfp.c,v + * Revision 4.3 1999/02/28 11:42:44 kardel + * (GPSWRAP): update GPS rollover to 990 weeks + * + * Revision 4.2 1998/07/11 10:05:25 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/28 16:47:15 kardel + * added gpstolfp() function + */ diff --git a/contrib/ntp/libntp/hextoint.c b/contrib/ntp/libntp/hextoint.c new file mode 100644 index 000000000000..0d774eb4ee3f --- /dev/null +++ b/contrib/ntp/libntp/hextoint.c @@ -0,0 +1,39 @@ +/* + * hextoint - convert an ascii string in hex to an unsigned + * long, with error checking + */ +#include + +#include "ntp_stdlib.h" + +int +hextoint( + 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((int)*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/ntp/libntp/hextolfp.c b/contrib/ntp/libntp/hextolfp.c new file mode 100644 index 000000000000..d0b624340d93 --- /dev/null +++ b/contrib/ntp/libntp/hextolfp.c @@ -0,0 +1,67 @@ +/* + * hextolfp - convert an ascii hex string to an l_fp number + */ +#include +#include + +#include "ntp_fp.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" + +int +hextolfp( + 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 const 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((int)*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((int)*cp)) + return 0; + + lfp->l_ui = dec_i; + lfp->l_uf = dec_f; + return 1; +} diff --git a/contrib/ntp/libntp/humandate.c b/contrib/ntp/libntp/humandate.c new file mode 100644 index 000000000000..f663c9ea256f --- /dev/null +++ b/contrib/ntp/libntp/humandate.c @@ -0,0 +1,62 @@ +/* + * humandate - convert an NTP (or the current) time to something readable + */ +#include +#include "time.h" +#include "ntp_fp.h" +#include "ntp_unixtime.h" /* includes */ +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +#ifdef TIME_WITH_SYS_TIME +#include +#endif + +static const char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; +static const char *days[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +char * +humandate( + u_long ntptime + ) +{ + char *bp; + struct tm *tm; + time_t sec; + + LIB_GETBUF(bp); + + sec = ntptime - JAN_1970; + tm = localtime(&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(void) +{ + 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/ntp/libntp/ieee754io.c b/contrib/ntp/libntp/ieee754io.c new file mode 100644 index 000000000000..4aa9920a3278 --- /dev/null +++ b/contrib/ntp/libntp/ieee754io.c @@ -0,0 +1,575 @@ +/* + * /src/NTP/ntp-4/libntp/ieee754io.c,v 4.8 1999/02/21 12:17:36 kardel RELEASE_19990228_A + * + * $Created: Sun Jul 13 09:12:02 1997 $ + * + * Copyright (C) 1997, 1998 by Frank Kardel + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "l_stdlib.h" +#include "ntp_stdlib.h" +#include "ntp_fp.h" +#include "ieee754io.h" + +static unsigned char get_byte P((unsigned char *, offsets_t, int *)); +#ifdef __not_yet__ +static void put_byte P((unsigned char *, offsets_t, int *, unsigned char)); +#endif + +#ifdef LIBDEBUG + +#include "lib_strbuf.h" + +static char * +fmt_blong( + unsigned long val, + int cnt + ) +{ + char *buf, *s; + int i = cnt; + + val <<= 32 - cnt; + LIB_GETBUF(buf); + s = buf; + + while (i--) + { + if (val & 0x80000000) + { + *s++ = '1'; + } + else + { + *s++ = '0'; + } + val <<= 1; + } + *s = '\0'; + return buf; +} + +static char * +fmt_flt( + unsigned int sign, + unsigned long mh, + unsigned long ml, + unsigned long ch + ) +{ + char *buf; + + LIB_GETBUF(buf); + sprintf(buf, "%c %s %s %s", sign ? '-' : '+', + fmt_blong(ch, 11), + fmt_blong(mh, 20), + fmt_blong(ml, 32)); + return buf; +} + +static char * +fmt_hex( + unsigned char *bufp, + int length + ) +{ + char *buf; + int i; + + LIB_GETBUF(buf); + for (i = 0; i < length; i++) + { + sprintf(buf+i*2, "%02x", bufp[i]); + } + return buf; +} + +#endif + +static unsigned char +get_byte( + unsigned char *bufp, + offsets_t offset, + int *fieldindex + ) +{ + unsigned char val; + + val = *(bufp + offset[*fieldindex]); +#ifdef LIBDEBUG + if (debug > 4) + printf("fetchieee754: getbyte(0x%08x, %d) = 0x%02x\n", (unsigned int)(bufp)+offset[*fieldindex], *fieldindex, val); +#endif + (*fieldindex)++; + return val; +} + +#ifdef __not_yet__ +static void +put_byte( + unsigned char *bufp, + offsets_t offsets, + int *fieldindex, + unsigned char val + ) +{ + *(bufp + offsets[*fieldindex]) = val; + (*fieldindex)++; +} +#endif + +/* + * make conversions to and from external IEEE754 formats and internal + * NTP FP format. + */ +int +fetch_ieee754( + unsigned char **buffpp, + int size, + l_fp *lfpp, + offsets_t offsets + ) +{ + unsigned char *bufp = *buffpp; + unsigned int sign; + unsigned int bias; + unsigned int maxexp; + unsigned int mbits; + u_long mantissa_low; + u_long mantissa_high; + u_long characteristic; + long exponent; +#ifdef LIBDEBUG + int length; +#endif + unsigned char val; + int fieldindex = 0; + + switch (size) + { + case IEEE_DOUBLE: +#ifdef LIBDEBUG + length = 8; +#endif + mbits = 52; + bias = 1023; + maxexp = 2047; + break; + + case IEEE_SINGLE: +#ifdef LIBDEBUG + length = 4; +#endif + mbits = 23; + bias = 127; + maxexp = 255; + break; + + default: + return IEEE_BADCALL; + } + + val = get_byte(bufp, offsets, &fieldindex); /* fetch sign byte & first part of characteristic */ + + sign = (val & 0x80) != 0; + characteristic = (val & 0x7F); + + val = get_byte(bufp, offsets, &fieldindex); /* fetch rest of characteristic and start of mantissa */ + + switch (size) + { + case IEEE_SINGLE: + characteristic <<= 1; + characteristic |= (val & 0x80) != 0; /* grab last characteristic bit */ + + mantissa_high = 0; + + mantissa_low = (val &0x7F) << 16; + mantissa_low |= get_byte(bufp, offsets, &fieldindex) << 8; + mantissa_low |= get_byte(bufp, offsets, &fieldindex); + break; + + case IEEE_DOUBLE: + characteristic <<= 4; + characteristic |= (val & 0xF0) >> 4; /* grab lower characteristic bits */ + + mantissa_high = (val & 0x0F) << 16; + mantissa_high |= get_byte(bufp, offsets, &fieldindex) << 8; + mantissa_high |= get_byte(bufp, offsets, &fieldindex); + + mantissa_low = get_byte(bufp, offsets, &fieldindex) << 24; + mantissa_low |= get_byte(bufp, offsets, &fieldindex) << 16; + mantissa_low |= get_byte(bufp, offsets, &fieldindex) << 8; + mantissa_low |= get_byte(bufp, offsets, &fieldindex); + break; + + default: + return IEEE_BADCALL; + } +#ifdef LIBDEBUG + if (debug > 4) + { + double d; + float f; + + if (size == IEEE_SINGLE) + { + int i; + + for (i = 0; i < length; i++) + { + *((unsigned char *)(&f)+i) = *(*buffpp + offsets[i]); + } + d = f; + } + else + { + int i; + + for (i = 0; i < length; i++) + { + *((unsigned char *)(&d)+i) = *(*buffpp + offsets[i]); + } + } + + printf("fetchieee754: FP: %s -> %s -> %e(=%s)\n", fmt_hex(*buffpp, length), + fmt_flt(sign, mantissa_high, mantissa_low, characteristic), + d, fmt_hex((unsigned char *)&d, length)); + } +#endif + + *buffpp += fieldindex; + + /* + * detect funny numbers + */ + if (characteristic == maxexp) + { + /* + * NaN or Infinity + */ + if (mantissa_low || mantissa_high) + { + /* + * NaN + */ + return IEEE_NAN; + } + else + { + /* + * +Inf or -Inf + */ + return sign ? IEEE_NEGINFINITY : IEEE_POSINFINITY; + } + } + else + { + /* + * collect real numbers + */ + + L_CLR(lfpp); + + /* + * check for overflows + */ + exponent = characteristic - bias; + + if (exponent > 31) /* sorry - hardcoded */ + { + /* + * overflow only in respect to NTP-FP representation + */ + return sign ? IEEE_NEGOVERFLOW : IEEE_POSOVERFLOW; + } + else + { + int frac_offset; /* where the fraction starts */ + + frac_offset = mbits - exponent; + + if (characteristic == 0) + { + /* + * de-normalized or tiny number - fits only as 0 + */ + return IEEE_OK; + } + else + { + /* + * adjust for implied 1 + */ + if (mbits > 31) + mantissa_high |= 1 << (mbits - 32); + else + mantissa_low |= 1 << mbits; + + /* + * take mantissa apart - if only all machine would support + * 64 bit operations 8-( + */ + if (frac_offset > mbits) + { + lfpp->l_ui = 0; /* only fractional number */ + frac_offset -= mbits + 1; /* will now contain right shift count - 1*/ + if (mbits > 31) + { + lfpp->l_uf = mantissa_high << (63 - mbits); + lfpp->l_uf |= mantissa_low >> (mbits - 33); + lfpp->l_uf >>= frac_offset; + } + else + { + lfpp->l_uf = mantissa_low >> frac_offset; + } + } + else + { + if (frac_offset > 32) + { + /* + * must split in high word + */ + lfpp->l_ui = mantissa_high >> (frac_offset - 32); + lfpp->l_uf = (mantissa_high & ((1 << (frac_offset - 32)) - 1)) << (64 - frac_offset); + lfpp->l_uf |= mantissa_low >> (frac_offset - 32); + } + else + { + /* + * must split in low word + */ + lfpp->l_ui = mantissa_high << (32 - frac_offset); + lfpp->l_ui |= (mantissa_low >> frac_offset) & ((1 << (32 - frac_offset)) - 1); + lfpp->l_uf = (mantissa_low & ((1 << frac_offset) - 1)) << (32 - frac_offset); + } + } + + /* + * adjust for sign + */ + if (sign) + { + L_NEG(lfpp); + } + + return IEEE_OK; + } + } + } +} + +int +put_ieee754( + unsigned char **bufpp, + int size, + l_fp *lfpp, + offsets_t offsets + ) +{ + l_fp outlfp; +#ifdef LIBDEBUG + unsigned int sign; + unsigned int bias; +#endif +/*unsigned int maxexp;*/ + int mbits; + int msb; + u_long mantissa_low = 0; + u_long mantissa_high = 0; +#ifdef LIBDEBUG + u_long characteristic = 0; + long exponent; +#endif +/*int length;*/ + unsigned long mask; + + outlfp = *lfpp; + + switch (size) + { + case IEEE_DOUBLE: + /*length = 8;*/ + mbits = 52; +#ifdef LIBDEBUG + bias = 1023; +#endif + /*maxexp = 2047;*/ + break; + + case IEEE_SINGLE: + /*length = 4;*/ + mbits = 23; +#ifdef LIBDEBUG + bias = 127; +#endif + /*maxexp = 255;*/ + break; + + default: + return IEEE_BADCALL; + } + + /* + * find sign + */ + if (L_ISNEG(&outlfp)) + { + L_NEG(&outlfp); +#ifdef LIBDEBUG + sign = 1; +#endif + } + else + { +#ifdef LIBDEBUG + sign = 0; +#endif + } + + if (L_ISZERO(&outlfp)) + { +#ifdef LIBDEBUG + exponent = mantissa_high = mantissa_low = 0; /* true zero */ +#endif + } + else + { + /* + * find number of significant integer bits + */ + mask = 0x80000000; + if (outlfp.l_ui) + { + msb = 63; + while (mask && ((outlfp.l_ui & mask) == 0)) + { + mask >>= 1; + msb--; + } + } + else + { + msb = 31; + while (mask && ((outlfp.l_uf & mask) == 0)) + { + mask >>= 1; + msb--; + } + } + + switch (size) + { + case IEEE_SINGLE: + mantissa_high = 0; + if (msb >= 32) + { + mantissa_low = (outlfp.l_ui & ((1 << (msb - 32)) - 1)) << (mbits - (msb - 32)); + mantissa_low |= outlfp.l_uf >> (mbits - (msb - 32)); + } + else + { + mantissa_low = (outlfp.l_uf << (mbits - msb)) & ((1 << mbits) - 1); + } + break; + + case IEEE_DOUBLE: + if (msb >= 32) + { + mantissa_high = (outlfp.l_ui << (mbits - msb)) & ((1 << (mbits - 32)) - 1); + mantissa_high |= outlfp.l_uf >> (32 - (mbits - msb)); + mantissa_low = (outlfp.l_ui & ((1 << (msb - mbits)) - 1)) << (32 - (msb - mbits)); + mantissa_low |= outlfp.l_uf >> (msb - mbits); + } + else + { + mantissa_high = outlfp.l_uf << (mbits - 32 - msb); + mantissa_low = outlfp.l_uf << (mbits - 32); + } + } + +#ifdef LIBDEBUG + exponent = msb - 32; + characteristic = exponent + bias; + + if (debug > 4) + printf("FP: %s\n", fmt_flt(sign, mantissa_high, mantissa_low, characteristic)); +#endif + } + return IEEE_OK; +} + + +#if defined(DEBUG) && defined(LIBDEBUG) +int main( + int argc, + char **argv + ) +{ + static offsets_t native_off = { 0, 1, 2, 3, 4, 5, 6, 7 }; + double f = 1.0; + double *f_p = &f; + l_fp fp; + + if (argc == 2) + { + if (sscanf(argv[1], "%lf", &f) != 1) + { + printf("cannot convert %s to a float\n", argv[1]); + return 1; + } + } + + printf("double: %s %s\n", fmt_blong(*(unsigned long *)&f, 32), fmt_blong(*(unsigned long *)((char *)(&f)+4), 32)); + printf("fetch from %f = %d\n", f, fetch_ieee754((void *)&f_p, IEEE_DOUBLE, &fp, native_off)); + printf("fp [%s %s] = %s\n", fmt_blong(fp.l_ui, 32), fmt_blong(fp.l_uf, 32), mfptoa(fp.l_ui, fp.l_uf, 15)); + f_p = &f; + put_ieee754((void *)&f_p, IEEE_DOUBLE, &fp, native_off); + + return 0; +} + +#endif +/* + * ieee754io.c,v + * Revision 4.8 1999/02/21 12:17:36 kardel + * 4.91f reconcilation + * + * Revision 4.7 1999/02/21 11:26:03 kardel + * renamed index to fieldindex to avoid index() name clash + * + * Revision 4.6 1998/11/15 20:27:52 kardel + * Release 4.0.73e13 reconcilation + * + * Revision 4.5 1998/08/16 19:01:51 kardel + * debug information only compile for LIBDEBUG case + * + * Revision 4.4 1998/08/09 09:39:28 kardel + * Release 4.0.73e2 reconcilation + * + * Revision 4.3 1998/06/13 11:56:19 kardel + * disabled putbute() for the time being + * + * Revision 4.2 1998/06/12 15:16:58 kardel + * ansi2knr compatibility + * + * Revision 4.1 1998/05/24 07:59:56 kardel + * conditional debug support + * + * Revision 4.0 1998/04/10 19:46:29 kardel + * Start 4.0 release version numbering + * + * Revision 1.1 1998/04/10 19:27:46 kardel + * initial NTP VERSION 4 integration of PARSE with GPS166 binary support + * + * Revision 1.1 1997/10/06 21:05:45 kardel + * new parse structure + * + */ diff --git a/contrib/ntp/libntp/inttoa.c b/contrib/ntp/libntp/inttoa.c new file mode 100644 index 000000000000..f27073339809 --- /dev/null +++ b/contrib/ntp/libntp/inttoa.c @@ -0,0 +1,20 @@ +/* + * inttoa - return an asciized signed integer + */ +#include + +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +inttoa( + long ival + ) +{ + register char *buf; + + LIB_GETBUF(buf); + + (void) sprintf(buf, "%ld", (long)ival); + return buf; +} diff --git a/contrib/ntp/libntp/iosignal.c b/contrib/ntp/libntp/iosignal.c new file mode 100644 index 000000000000..c8ec94961be8 --- /dev/null +++ b/contrib/ntp/libntp/iosignal.c @@ -0,0 +1,518 @@ +/* + * ntp_io.c - input/output routines for ntpd. The socket-opening code + * was shamelessly stolen from ntpd. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#ifdef HAVE_SYS_PARAM_H +# include +#endif /* HAVE_SYS_PARAM_H */ +#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance ) */ +# include +#endif +#include + +#if _BSDI_VERSION >= 199510 +# include +#endif +/* 98/06/01 */ +#include "ntp_machine.h" /* 98/06/01 */ +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" +#include "iosignal.h" + +#if defined(HAVE_SIGNALED_IO) +static int sigio_block_count = 0; +extern void input_handler P((l_fp *)); + +/* + * SIGPOLL and SIGIO ROUTINES. + */ + + /* + * Some systems (MOST) define SIGPOLL == SIGIO, others SIGIO == SIGPOLL, and + * a few have separate 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 initialization routines. + */ +int +init_clock_sig( + struct refclockio *rio + ) +{ +# ifdef USE_TTY_SIGPOLL + { + /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ + if (ioctl(rio->fd, I_SETSIG, S_INPUT) < 0) + { + msyslog(LOG_ERR, + "init_clock_sig: ioctl(I_SETSIG, S_INPUT) failed: %m"); + return 1; + } + return 0; + } +# else + /* + * Special cases first! + */ + /* Was: defined(SYS_HPUX) */ +# if defined(FIOSSAIOOWN) && defined(FIOSNBIO) && defined(FIOSSAIOSTAT) +#define CLOCK_DONE + { + int pgrp, on = 1; + + /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ + pgrp = getpid(); + if (ioctl(rio->fd, FIOSSAIOOWN, (char *)&pgrp) == -1) + { + msyslog(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) + { + msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails for clock I/O: %m"); + exit(1); + /*NOTREACHED*/ + } + + if (ioctl(rio->fd, FIOSSAIOSTAT, (char *)&on) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOSSAIOSTAT) fails for clock I/O: %m"); + exit(1); + /*NOTREACHED*/ + } + return 0; + } +# endif /* SYS_HPUX: FIOSSAIOOWN && FIOSNBIO && FIOSSAIOSTAT */ + /* Was: defined(SYS_AIX) && !defined(_BSD) */ +# if !defined(_BSD) && defined(_AIX) && defined(FIOASYNC) && defined(FIOSETOWN) + /* + * SYSV compatibility mode under AIX. + */ +#define CLOCK_DONE + { + int pgrp, on = 1; + + /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ + if (ioctl(rio->fd, FIOASYNC, (char *)&on) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOASYNC) fails for clock I/O: %m"); + return 1; + } + pgrp = -getpid(); + if (ioctl(rio->fd, FIOSETOWN, (char*)&pgrp) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails for clock I/O: %m"); + return 1; + } + + if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0) + { + msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m"); + return 1; + } + return 0; + } +# endif /* AIX && !BSD: !_BSD && FIOASYNC && FIOSETOWN */ +# ifndef CLOCK_DONE + { + /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ +# if defined(TIOCSCTTY) && defined(USE_FSETOWNCTTY) + /* + * there are, however, always exceptions to the rules + * one is, that OSF accepts SETOWN on TTY fd's only, iff they are + * CTTYs. SunOS and HPUX do not semm to have this restriction. + * another question is: how can you do multiple SIGIO from several + * ttys (as they all should be CTTYs), wondering... + * + * kd 95-07-16 + */ + if (ioctl(rio->fd, TIOCSCTTY, 0) == -1) + { + msyslog(LOG_ERR, "ioctl(TIOCSCTTY, 0) fails for clock I/O: %m"); + return 1; + } +# endif /* TIOCSCTTY && USE_FSETOWNCTTY */ + + if (fcntl(rio->fd, F_SETOWN, getpid()) == -1) + { + msyslog(LOG_ERR, "fcntl(F_SETOWN) fails for clock I/O: %m"); + return 1; + } + + if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0) + { + msyslog(LOG_ERR, + "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m"); + return 1; + } + return 0; + } +# endif /* CLOCK_DONE */ +# endif /* !USE_TTY_SIGPOLL */ +} + + + +void +init_socket_sig( + int fd + ) +{ +# ifdef USE_UDP_SIGPOLL + { + if (ioctl(fd, I_SETSIG, S_INPUT) < 0) + { + msyslog(LOG_ERR, + "init_socket_sig: ioctl(I_SETSIG, S_INPUT) failed: %m"); + exit(1); + } + } +# else /* USE_UDP_SIGPOLL */ + { + int pgrp; +# ifdef FIOASYNC + int on = 1; +# endif + +# if defined(FIOASYNC) + if (ioctl(fd, FIOASYNC, (char *)&on) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# elif defined(FASYNC) + { + int flags; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + { + msyslog(LOG_ERR, "fcntl(F_GETFL) fails: %m"); + exit(1); + /*NOTREACHED*/ + } + if (fcntl(fd, F_SETFL, flags|FASYNC) < 0) + { + msyslog(LOG_ERR, "fcntl(...|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } + } +# else +# include "Bletch: Need asynchronous I/O!" +# endif + +# ifdef UDP_BACKWARDS_SETOWN + pgrp = -getpid(); +# else + pgrp = getpid(); +# endif + +# if defined(SIOCSPGRP) + if (ioctl(fd, SIOCSPGRP, (char *)&pgrp) == -1) + { + msyslog(LOG_ERR, "ioctl(SIOCSPGRP) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# elif defined(FIOSETOWN) + if (ioctl(fd, FIOSETOWN, (char*)&pgrp) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# elif defined(F_SETOWN) + if (fcntl(fd, F_SETOWN, pgrp) == -1) + { + msyslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# else +# include "Bletch: Need to set process(group) to receive SIG(IO|POLL)" +# endif + } +# endif /* USE_UDP_SIGPOLL */ +} + +RETSIGTYPE +sigio_handler( + int sig + ) +{ + int saved_errno = errno; + l_fp ts; + + get_systime(&ts); + (void)input_handler(&ts); + errno = saved_errno; +} + +/* + * Signal support routines. + */ +# ifdef HAVE_SIGACTION +void +set_signal(void) +{ +# ifdef USE_SIGIO + (void) signal_no_reset(SIGIO, sigio_handler); +# endif +# ifdef USE_SIGPOLL + (void) signal_no_reset(SIGPOLL, sigio_handler); +# endif +} + +void +block_io_and_alarm(void) +{ + sigset_t set; + + if (sigemptyset(&set)) + msyslog(LOG_ERR, "block_io_and_alarm: sigemptyset() failed: %m"); +# if defined(USE_SIGIO) + if (sigaddset(&set, SIGIO)) + msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGIO) failed: %m"); +# endif +# if defined(USE_SIGPOLL) + if (sigaddset(&set, SIGPOLL)) + msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGPOLL) failed: %m"); +# endif + if (sigaddset(&set, SIGALRM)) + msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGALRM) failed: %m"); + + if (sigprocmask(SIG_BLOCK, &set, NULL)) + msyslog(LOG_ERR, "block_io_and_alarm: sigprocmask() failed: %m"); +} + +void +block_sigio(void) +{ + sigset_t set; + + ++sigio_block_count; + if (sigio_block_count > 1) + msyslog(LOG_INFO, "block_sigio: sigio_block_count > 1"); + if (sigio_block_count < 1) + msyslog(LOG_INFO, "block_sigio: sigio_block_count < 1"); + + if (sigemptyset(&set)) + msyslog(LOG_ERR, "block_sigio: sigemptyset() failed: %m"); +# if defined(USE_SIGIO) + if (sigaddset(&set, SIGIO)) + msyslog(LOG_ERR, "block_sigio: sigaddset(SIGIO) failed: %m"); +# endif +# if defined(USE_SIGPOLL) + if (sigaddset(&set, SIGPOLL)) + msyslog(LOG_ERR, "block_sigio: sigaddset(SIGPOLL) failed: %m"); +# endif + + if (sigprocmask(SIG_BLOCK, &set, NULL)) + msyslog(LOG_ERR, "block_sigio: sigprocmask() failed: %m"); +} + +void +unblock_io_and_alarm(void) +{ + sigset_t unset; + + if (sigemptyset(&unset)) + msyslog(LOG_ERR, "unblock_io_and_alarm: sigemptyset() failed: %m"); + +# if defined(USE_SIGIO) + if (sigaddset(&unset, SIGIO)) + msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGIO) failed: %m"); +# endif +# if defined(USE_SIGPOLL) + if (sigaddset(&unset, SIGPOLL)) + msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGPOLL) failed: %m"); +# endif + if (sigaddset(&unset, SIGALRM)) + msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGALRM) failed: %m"); + + if (sigprocmask(SIG_UNBLOCK, &unset, NULL)) + msyslog(LOG_ERR, "unblock_io_and_alarm: sigprocmask() failed: %m"); +} + +void +unblock_sigio(void) +{ + sigset_t unset; + + --sigio_block_count; + if (sigio_block_count > 0) + msyslog(LOG_INFO, "unblock_sigio: sigio_block_count > 0"); + if (sigio_block_count < 0) + msyslog(LOG_INFO, "unblock_sigio: sigio_block_count < 0"); + + if (sigemptyset(&unset)) + msyslog(LOG_ERR, "unblock_sigio: sigemptyset() failed: %m"); + +# if defined(USE_SIGIO) + if (sigaddset(&unset, SIGIO)) + msyslog(LOG_ERR, "unblock_sigio: sigaddset(SIGIO) failed: %m"); +# endif +# if defined(USE_SIGPOLL) + if (sigaddset(&unset, SIGPOLL)) + msyslog(LOG_ERR, "unblock_sigio: sigaddset(SIGPOLL) failed: %m"); +# endif + + if (sigprocmask(SIG_UNBLOCK, &unset, NULL)) + msyslog(LOG_ERR, "unblock_sigio: sigprocmask() failed: %m"); +} + +void +wait_for_signal(void) +{ + sigset_t old; + + if (sigprocmask(SIG_UNBLOCK, NULL, &old)) + msyslog(LOG_ERR, "wait_for_signal: sigprocmask() failed: %m"); + +# if defined(USE_SIGIO) + if (sigdelset(&old, SIGIO)) + msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGIO) failed: %m"); +# endif +# if defined(USE_SIGPOLL) + if (sigdelset(&old, SIGPOLL)) + msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGPOLL) failed: %m"); +# endif + if (sigdelset(&old, SIGALRM)) + msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGALRM) failed: %m"); + + if (sigsuspend(&old) && (errno != EINTR)) + msyslog(LOG_ERR, "wait_for_signal: sigsuspend() failed: %m"); +} + +# else /* !HAVE_SIGACTION */ +/* + * Must be an old bsd system. + * We assume there is no SIGPOLL. + */ + +void +block_io_and_alarm(void) +{ + int mask; + + mask = sigmask(SIGIO) | sigmask(SIGALRM); + if (sigblock(mask)) + msyslog(LOG_ERR, "block_io_and_alarm: sigblock() failed: %m"); +} + +void +block_sigio(void) +{ + int mask; + + ++sigio_block_count; + if (sigio_block_count > 1) + msyslog(LOG_INFO, "block_sigio: sigio_block_count > 1"); + if (sigio_block_count < 1) + msyslog(LOG_INFO, "block_sigio: sigio_block_count < 1"); + + mask = sigmask(SIGIO); + if (sigblock(mask)) + msyslog(LOG_ERR, "block_sigio: sigblock() failed: %m"); +} + +void +set_signal(void) +{ + (void) signal_no_reset(SIGIO, sigio_handler); +} + +void +unblock_io_and_alarm(void) +{ + int mask, omask; + + mask = sigmask(SIGIO) | sigmask(SIGALRM); + omask = sigblock(0); + omask &= ~mask; + (void) sigsetmask(omask); +} + +void +unblock_sigio(void) +{ + int mask, omask; + + --sigio_block_count; + if (sigio_block_count > 0) + msyslog(LOG_INFO, "unblock_sigio: sigio_block_count > 0"); + if (sigio_block_count < 0) + msyslog(LOG_INFO, "unblock_sigio: sigio_block_count < 0"); + mask = sigmask(SIGIO); + omask = sigblock(0); + omask &= ~mask; + (void) sigsetmask(omask); +} + +void +wait_for_signal(void) +{ + int mask, omask; + + mask = sigmask(SIGIO) | sigmask(SIGALRM); + omask = sigblock(0); + omask &= ~mask; + if (sigpause(omask) && (errno != EINTR)) + msyslog(LOG_ERR, "wait_for_signal: sigspause() failed: %m"); +} + +# endif /* HAVE_SIGACTION */ +#else +int NotAnEmptyCompilationUnit; +#endif diff --git a/contrib/ntp/libntp/lib_strbuf.c b/contrib/ntp/libntp/lib_strbuf.c new file mode 100644 index 000000000000..690f1ad28610 --- /dev/null +++ b/contrib/ntp/libntp/lib_strbuf.c @@ -0,0 +1,22 @@ +/* + * lib_strbuf - library string storage + */ + +#include "lib_strbuf.h" + +/* + * Storage declarations + */ +char lib_stringbuf[LIB_NUMBUFS][LIB_BUFLENGTH]; +int lib_nextbuf; +int lib_inited = 0; + +/* + * initialization routine. Might be needed if the code is ROMized. + */ +void +init_lib(void) +{ + lib_nextbuf = 0; + lib_inited = 1; +} diff --git a/contrib/ntp/libntp/lib_strbuf.h b/contrib/ntp/libntp/lib_strbuf.h new file mode 100644 index 000000000000..1a34034a8770 --- /dev/null +++ b/contrib/ntp/libntp/lib_strbuf.h @@ -0,0 +1,27 @@ +/* + * lib_strbuf.h - definitions for routines which use the common string buffers + */ + +#include + +/* + * 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 { \ + if (!lib_inited) \ + init_lib(); \ + 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; +extern int lib_inited; diff --git a/contrib/ntp/libntp/log.c b/contrib/ntp/libntp/log.c new file mode 100644 index 000000000000..e694361d5fe7 --- /dev/null +++ b/contrib/ntp/libntp/log.c @@ -0,0 +1,152 @@ +/* Microsoft Developer Support Copyright (c) 1993 Microsoft Corporation. */ + +#include +#include +#include +#include + +#include "messages.h" +#include "log.h" + +#define PERR(bSuccess, api) {if(!(bSuccess)) printf("%s: Error %d from %s \ + on line %d\n", __FILE__, GetLastError(), api, __LINE__);} + + +/********************************************************************* +* FUNCTION: addSourceToRegistry(void) * +* * +* PURPOSE: Add a source name key, message DLL name value, and * +* message type supported value to the registry * +* * +* INPUT: source name, path of message DLL * +* * +* RETURNS: none * +*********************************************************************/ + +void addSourceToRegistry(LPSTR pszAppname, LPSTR pszMsgDLL) +{ + HKEY hk; /* registry key handle */ + DWORD dwData; + BOOL bSuccess; + + /* When an application uses the RegisterEventSource or OpenEventLog + function to get a handle of an event log, the event loggging service + searches for the specified source name in the registry. You can add a + new source name to the registry by opening a new registry subkey + under the Application key and adding registry values to the new + subkey. */ + + /* Create a new key for our application */ + bSuccess = RegCreateKey(HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\NTP", &hk); + PERR(bSuccess == ERROR_SUCCESS, "RegCreateKey"); + + /* Add the Event-ID message-file name to the subkey. */ + bSuccess = RegSetValueEx(hk, /* subkey handle */ + "EventMessageFile", /* value name */ + 0, /* must be zero */ + REG_EXPAND_SZ, /* value type */ + (LPBYTE) pszMsgDLL, /* address of value data */ + strlen(pszMsgDLL) + 1); /* length of value data */ + PERR(bSuccess == ERROR_SUCCESS, "RegSetValueEx"); + + /* Set the supported types flags and addit to the subkey. */ + dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | + EVENTLOG_INFORMATION_TYPE; + bSuccess = RegSetValueEx(hk, /* subkey handle */ + "TypesSupported", /* value name */ + 0, /* must be zero */ + REG_DWORD, /* value type */ + (LPBYTE) &dwData, /* address of value data */ + sizeof(DWORD)); /* length of value data */ + PERR(bSuccess == ERROR_SUCCESS, "RegSetValueEx"); + RegCloseKey(hk); + return; +} + +/********************************************************************* +* FUNCTION: reportAnEvent(DWORD dwIdEvent, WORD cStrings, * +* LPTSTR *ppszStrings); * +* * +* PURPOSE: add the event to the event log * +* * +* INPUT: the event ID to report in the log, the number of insert * +* strings, and an array of null-terminated insert strings * +* * +* RETURNS: none * +*********************************************************************/ + +void reportAnIEvent(DWORD dwIdEvent, WORD cStrings, LPTSTR *pszStrings) +{ + HANDLE hAppLog; + BOOL bSuccess; + + /* Get a handle to the Application event log */ + hAppLog = RegisterEventSource(NULL, /* use local machine */ + "NTP"); /* source name */ + PERR(hAppLog, "RegisterEventSource"); + + /* Now report the event, which will add this event to the event log */ + bSuccess = ReportEvent(hAppLog, /* event-log handle */ + EVENTLOG_INFORMATION_TYPE, /* event type */ + 0, /* category zero */ + dwIdEvent, /* event ID */ + NULL, /* no user SID */ + cStrings, /* number of substitution strings */ + 0, /* no binary data */ + pszStrings, /* string array */ + NULL); /* address of data */ + PERR(bSuccess, "ReportEvent"); + DeregisterEventSource(hAppLog); + return; +} + +void reportAnWEvent(DWORD dwIdEvent, WORD cStrings, LPTSTR *pszStrings) +{ + HANDLE hAppLog; + BOOL bSuccess; + + /* Get a handle to the Application event log */ + hAppLog = RegisterEventSource(NULL, /* use local machine */ + "NTP"); /* source name */ + PERR(hAppLog, "RegisterEventSource"); + + /* Now report the event, which will add this event to the event log */ + bSuccess = ReportEvent(hAppLog, /* event-log handle */ + EVENTLOG_WARNING_TYPE, /* event type */ + 0, /* category zero */ + dwIdEvent, /* event ID */ + NULL, /* no user SID */ + cStrings, /* number of substitution strings */ + 0, /* no binary data */ + pszStrings, /* string array */ + NULL); /* address of data */ + PERR(bSuccess, "ReportEvent"); + DeregisterEventSource(hAppLog); + return; +} + +void reportAnEEvent(DWORD dwIdEvent, WORD cStrings, LPTSTR *pszStrings) +{ + HANDLE hAppLog; + BOOL bSuccess; + + /* Get a handle to the Application event log */ + hAppLog = RegisterEventSource(NULL, /* use local machine */ + "NTP"); /* source name */ + PERR(hAppLog, "RegisterEventSource"); + + /* Now report the event, which will add this event to the event log */ + bSuccess = ReportEvent(hAppLog, /* event-log handle */ + EVENTLOG_ERROR_TYPE, /* event type */ + 0, /* category zero */ + dwIdEvent, /* event ID */ + NULL, /* no user SID */ + cStrings, /* number of substitution strings */ + 0, /* no binary data */ + pszStrings, /* string array */ + NULL); /* address of data */ + PERR(bSuccess, "ReportEvent"); + DeregisterEventSource(hAppLog); + return; +} diff --git a/contrib/ntp/libntp/log.h b/contrib/ntp/libntp/log.h new file mode 100644 index 000000000000..99d0e72940ed --- /dev/null +++ b/contrib/ntp/libntp/log.h @@ -0,0 +1,21 @@ +/* + * log.h - Used only under Windows NT by msyslog.c + * + */ +#ifndef WINNT_LOG_H +#define WINNT_LOG_H + +#include + +/* function declarations */ + +void addSourceToRegistry(LPSTR pszAppname, LPSTR pszMsgDLL); +void reportAnIEvent(DWORD dwIdEvent, WORD cStrings, LPTSTR *pszStrings); +void reportAnWEvent(DWORD dwIdEvent, WORD cStrings, LPTSTR *pszStrings); +void reportAnEEvent(DWORD dwIdEvent, WORD cStrings, LPTSTR *pszStrings); + +#define MAX_MSG_LENGTH 1024 +#define MSG_ID_MASK 0x0000FFFF +#define MAX_INSERT_STRS 8 + +#endif /* WINNT_LOG_H */ diff --git a/contrib/ntp/libntp/machines.c b/contrib/ntp/libntp/machines.c new file mode 100644 index 000000000000..bbcfd54b9ca6 --- /dev/null +++ b/contrib/ntp/libntp/machines.c @@ -0,0 +1,218 @@ +/* machines.c - provide special support for peculiar architectures + * + * Real bummers unite ! + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ntp_machine.h" +#include "ntp_syslog.h" +#include "ntp_stdlib.h" +#include "ntp_unixtime.h" + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef SYS_WINNT +# include +#else + +#ifdef SYS_VXWORKS +#include "taskLib.h" +#include "sysLib.h" +#include "time.h" +#include "ntp_syslog.h" + +/* some translations to the world of vxWorkings -casey */ +/* first some netdb type things */ +#include "ioLib.h" +#include +int h_errno; + +struct hostent *gethostbyname(char *name) + { + struct hostent *host1; + h_errno = 0; /* we are always successful!!! */ + host1 = (struct hostent *) malloc (sizeof(struct hostent)); + host1->h_name = name; + host1->h_addrtype = AF_INET; + host1->h_aliases = name; + host1->h_length = 4; + host1->h_addr_list[0] = (char *)hostGetByName (name); + host1->h_addr_list[1] = NULL; + return host1; + } + +struct hostent *gethostbyaddr(char *name, int size, int addr_type) + { + struct hostent *host1; + h_errno = 0; /* we are always successful!!! */ + host1 = (struct hostent *) malloc (sizeof(struct hostent)); + host1->h_name = name; + host1->h_addrtype = AF_INET; + host1->h_aliases = name; + host1->h_length = 4; + host1->h_addr_list = NULL; + return host1; + } + +struct servent *getservbyname (char *name, char *type) + { + struct servent *serv1; + serv1 = (struct servent *) malloc (sizeof(struct servent)); + serv1->s_name = "ntp"; /* official service name */ + serv1->s_aliases = NULL; /* alias list */ + serv1->s_port = 123; /* port # */ + serv1->s_proto = "udp"; /* protocol to use */ + return serv1; + } + +/* second + * vxworks thinks it has insomnia + * we have to sleep for number of seconds + */ + +#define CLKRATE sysClkRateGet() + +/* I am not sure how valid the granularity is - it is from G. Eger's port */ +#define CLK_GRANULARITY 1 /* Granularity of system clock in usec */ + /* Used to round down # usecs/tick */ + /* On a VCOM-100, PIT gets 8 MHz clk, */ + /* & it prescales by 32, thus 4 usec */ + /* on mv167, granularity is 1usec anyway*/ + /* To defeat rounding, set to 1 */ +#define USECS_PER_SEC MILLION /* Microseconds per second */ +#define TICK (((USECS_PER_SEC / CLKRATE) / CLK_GRANULARITY) * CLK_GRANULARITY) + +/* emulate unix sleep + * casey + */ +void sleep(int seconds) + { + taskDelay(seconds*TICK); + } +/* emulate unix alarm + * that pauses and calls SIGALRM after the seconds are up... + * so ... taskDelay() fudged for seconds should amount to the same thing. + * casey + */ +void alarm (int seconds) + { + sleep(seconds); + } + +#endif /* SYS_VXWORKS */ + +#ifdef SYS_PTX /* Does PTX still need this? */ +/*#include */ +#include + +int +gettimeofday( + 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 /* SYS_PTX */ + +const char *set_tod_using = "UNKNOWN"; + +int +ntp_set_tod( + struct timeval *tvp, + void *tzp + ) +{ + int rc; + +#ifdef HAVE_CLOCK_SETTIME + { + struct timespec ts; + + /* Convert timeval to timespec */ + ts.tv_sec = tvp->tv_sec; + ts.tv_nsec = 1000 * tvp->tv_usec; + + rc = clock_settime(CLOCK_REALTIME, &ts); + if (!rc) + { + set_tod_using = "clock_settime"; + return rc; + } + } +#endif /* HAVE_CLOCK_SETTIME */ +#ifdef HAVE_SETTIMEOFDAY + { + rc = SETTIMEOFDAY(tvp, tzp); + if (!rc) + { + set_tod_using = "settimeofday"; + return rc; + } + } +#endif /* HAVE_SETTIMEOFDAY */ +#ifdef HAVE_STIME + { + long tp = tvp->tv_sec; + + rc = stime(&tp); /* lie as bad as SysVR4 */ + if (!rc) + { + set_tod_using = "stime"; + return rc; + } + } +#endif /* HAVE_STIME */ + set_tod_using = "Failed!"; + return -1; +} + +#endif /* not SYS_WINNT */ + +#if defined (SYS_WINNT) || defined (SYS_VXWORKS) +/* getpass is used in ntpq.c and ntpdc.c */ + +char * +getpass(const char * prompt) +{ + int c, i; + static char password[32]; +#ifdef DEBUG + fprintf(stderr, "%s", prompt); + fflush(stderr); +#endif + for (i=0; i 0) + *a++ = (char) x; +} +#endif /*POSIX*/ diff --git a/contrib/ntp/libntp/md5c.c b/contrib/ntp/libntp/md5c.c new file mode 100644 index 000000000000..00b3c6bb0b84 --- /dev/null +++ b/contrib/ntp/libntp/md5c.c @@ -0,0 +1,350 @@ +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. 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 "global.h" +#include "md5.h" + +/* Constants for MD5Transform routine. + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); +static void Encode PROTO_LIST + ((unsigned char *, UINT4 *, unsigned int)); +static void Decode PROTO_LIST + ((UINT4 *, unsigned char *, unsigned int)); +static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); +static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* 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. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* 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); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void +MD5Init( + MD5_CTX *context /* context */ + ) +{ + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. + */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void +MD5Update ( + MD5_CTX *context, /* context */ + unsigned char *input, /* input block */ + unsigned int inputLen /* length of input block */ + ) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. + */ + if (inputLen >= partLen) { + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void +MD5Final ( + unsigned char digest[16], /* message digest */ + MD5_CTX *context /* context */ + ) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. + */ + MD5_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void +MD5Transform ( + UINT4 state[4], + unsigned char block[64] + ) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. + */ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void +Encode ( + unsigned char *output, + UINT4 *input, + unsigned int len + ) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void +Decode ( + UINT4 *output, + unsigned char *input, + unsigned int len + ) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +/* Note: Replace "for loop" with standard memcpy if possible. + */ +static void +MD5_memcpy ( + POINTER output, + POINTER input, + unsigned int len + ) +{ + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void +MD5_memset ( + POINTER output, + int value, + unsigned int len + ) +{ + unsigned int i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} diff --git a/contrib/ntp/libntp/memmove.c b/contrib/ntp/libntp/memmove.c new file mode 100644 index 000000000000..b5d08687c17d --- /dev/null +++ b/contrib/ntp/libntp/memmove.c @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * 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, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may 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(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)bcopy.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifndef HAVE_MEMMOVE +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#include + +/* + * sizeof(word) MUST BE A POWER OF TWO + * SO THAT wmask BELOW IS ALL ONES + */ +typedef int word; /* "word" used for optimal copy speed */ + +#define wsize sizeof(word) +#define wmask (wsize - 1) + +/* + * Copy a block of memory, handling overlap. + * This is the routine that actually implements + * (the portable versions of) bcopy, memcpy, and memmove. + */ +void * +memmove( + void *dst0, + const void *src0, + register size_t length + ) +{ + register char *dst = dst0; + register const char *src = src0; + register size_t t; + + if (length == 0 || dst == src) /* nothing to do */ + goto done; + + /* + * Macros: loop-t-times; and loop-t-times, t>0 + */ +#define TLOOP(s) if (t) TLOOP1(s) +#define TLOOP1(s) do { s; } while (--t) + + if ((unsigned long)dst < (unsigned long)src) { + /* + * Copy forward. + */ + t = (int)src; /* only need low bits */ + if ((t | (int)dst) & wmask) { + /* + * Try to align operands. This cannot be done + * unless the low bits match. + */ + if ((t ^ (int)dst) & wmask || length < wsize) + t = length; + else + t = wsize - (t & wmask); + length -= t; + TLOOP1(*dst++ = *src++); + } + /* + * Copy whole words, then mop up any trailing bytes. + */ + t = length / wsize; + TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize); + t = length & wmask; + TLOOP(*dst++ = *src++); + } else { + /* + * Copy backwards. Otherwise essentially the same. + * Alignment works as before, except that it takes + * (t&wmask) bytes to align, not wsize-(t&wmask). + */ + src += length; + dst += length; + t = (int)src; + if ((t | (int)dst) & wmask) { + if ((t ^ (int)dst) & wmask || length <= wsize) + t = length; + else + t &= wmask; + length -= t; + TLOOP1(*--dst = *--src); + } + t = length / wsize; + TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src); + t = length & wmask; + TLOOP(*--dst = *--src); + } + done: + return (dst0); +} +#else +int memmove_bs; +#endif diff --git a/contrib/ntp/libntp/mexit.c b/contrib/ntp/libntp/mexit.c new file mode 100644 index 000000000000..6ae452ef3730 --- /dev/null +++ b/contrib/ntp/libntp/mexit.c @@ -0,0 +1,34 @@ +/* + * mexit - Used to exit the NTPD daemon + * + */ + +#ifdef SYS_WINNT +#include +#include + +HANDLE hServDoneEvent = NULL; + +void +service_exit( + int status + ) +{ + extern int debug; + + if (debug) /* did not become a service, simply exit */ + ExitThread((DWORD)status); + else { + /* service mode, need to have the service_main routine + * register with the service control manager that the + * service has stopped running, before exiting + */ + if ((status > 0) && (hServDoneEvent != NULL)) + SetEvent(hServDoneEvent); + ExitThread((DWORD)status); + } +} + +#else /* not SYS_WINNT */ +int mexit_bs; +#endif /* not SYS_WINNT */ diff --git a/contrib/ntp/libntp/mfp_mul.c b/contrib/ntp/libntp/mfp_mul.c new file mode 100644 index 000000000000..0c667f7bd60b --- /dev/null +++ b/contrib/ntp/libntp/mfp_mul.c @@ -0,0 +1,140 @@ +/* + * /src/NTP/ntp-4/libntp/mfp_mul.c,v 4.3 1999/02/21 12:17:37 kardel RELEASE_19990228_A + * + * $Created: Sat Aug 16 20:35:08 1997 $ + * + * Copyright (C) 1997, 1998 by Frank Kardel + */ +#include +#include "ntp_stdlib.h" +#include "ntp_types.h" +#include "ntp_fp.h" + +#define LOW_MASK (u_int32)((1<<(FRACTION_PREC/2))-1) +#define HIGH_MASK (u_int32)(LOW_MASK << (FRACTION_PREC/2)) + +void +mfp_mul( + int32 *o_i, + u_int32 *o_f, + int32 a_i, + u_int32 a_f, + int32 b_i, + u_int32 b_f + ) +{ + int32 i, j; + u_int32 f; + u_long a[4]; /* operand a */ + u_long b[4]; /* operand b */ + u_long c[4]; /* result c */ + + int neg = 0; + + if (a_i < 0) /* examine sign situation */ + { + neg = 1; + M_NEG(a_i, a_f); + } + + if (b_i < 0) /* examine sign situation */ + { + neg = !neg; + M_NEG(b_i, b_f); + } + + a[0] = a_f & LOW_MASK; /* prepare a operand */ + a[1] = (a_f & HIGH_MASK) >> (FRACTION_PREC/2); + a[2] = a_i & LOW_MASK; + a[3] = (a_i & HIGH_MASK) >> (FRACTION_PREC/2); + + b[0] = b_f & LOW_MASK; /* prepare b operand */ + b[1] = (b_f & HIGH_MASK) >> (FRACTION_PREC/2); + b[2] = b_i & LOW_MASK; + b[3] = (b_i & HIGH_MASK) >> (FRACTION_PREC/2); + + c[0] = c[1] = c[2] = c[3] = 0; + + for (i = 0; i < 4; i++) /* we do assume 32 * 32 = 64 bit multiplication */ + for (j = 0; j < 4; j++) + { + u_long result_low, result_high; + + result_low = (u_long)a[i] * (u_long)b[j]; /* partial product */ + + if ((i+j) & 1) /* splits across two result registers */ + { + result_high = result_low >> (FRACTION_PREC/2); + result_low <<= FRACTION_PREC/2; + } + else + { /* stays in a result register - except for overflows */ + result_high = 0; + } + + if (((c[(i+j)/2] >> 1) + (result_low >> 1)) & (u_int32)((unsigned)1<<(FRACTION_PREC - 1))) + result_high++; /* propagate overflows */ + + c[(i+j)/2] += result_low; /* add up partial products */ + + if (((c[(i+j+1)/2] >> 1) + (result_high >> 1)) & (u_int32)((unsigned)1<<(FRACTION_PREC - 1))) + c[1+(i+j)/2]++; /* propagate overflows */ + + c[(i+j+1)/2] += result_high; + } + +#ifdef DEBUG + if (debug > 6) + printf("mfp_mul: 0x%04lx%04lx%04lx%04lx * 0x%04lx%04lx%04lx%04lx = 0x%08lx%08lx%08lx%08lx\n", + a[3], a[2], a[1], a[0], b[3], b[2], b[1], b[0], c[3], c[2], c[1], c[0]); +#endif + + if (c[3]) /* overflow */ + { + i = ((unsigned)1 << (FRACTION_PREC-1)) - 1; + f = ~(unsigned)0; + } + else + { /* take produkt - discarding extra precision */ + i = c[2]; + f = c[1]; + } + + if (neg) /* recover sign */ + { + M_NEG(i, f); + } + + *o_i = i; + *o_f = f; + +#ifdef DEBUG + if (debug > 6) + printf("mfp_mul: %s * %s => %s\n", + mfptoa((u_long)a_i, a_f, 6), + mfptoa((u_long)b_i, b_f, 6), + mfptoa((u_long)i, f, 6)); +#endif +} + +/* + * mfp_mul.c,v + * Revision 4.3 1999/02/21 12:17:37 kardel + * 4.91f reconcilation + * + * Revision 4.2 1998/12/20 23:45:28 kardel + * fix types and warnings + * + * Revision 4.1 1998/05/24 07:59:57 kardel + * conditional debug support + * + * Revision 4.0 1998/04/10 19:46:38 kardel + * Start 4.0 release version numbering + * + * Revision 1.1 1998/04/10 19:27:47 kardel + * initial NTP VERSION 4 integration of PARSE with GPS166 binary support + * + * Revision 1.1 1997/10/06 21:05:46 kardel + * new parse structure + * + */ diff --git a/contrib/ntp/libntp/mfptoa.c b/contrib/ntp/libntp/mfptoa.c new file mode 100644 index 000000000000..8257b6c2a6bc --- /dev/null +++ b/contrib/ntp/libntp/mfptoa.c @@ -0,0 +1,23 @@ +/* + * mfptoa - Return an asciized representation of a signed long fp number + */ +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +char * +mfptoa( + 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/ntp/libntp/mfptoms.c b/contrib/ntp/libntp/mfptoms.c new file mode 100644 index 000000000000..10afb51bc5af --- /dev/null +++ b/contrib/ntp/libntp/mfptoms.c @@ -0,0 +1,23 @@ +/* + * mfptoms - Return an asciized signed long fp number in milliseconds + */ +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +char * +mfptoms( + 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/ntp/libntp/mktime.c b/contrib/ntp/libntp/mktime.c new file mode 100644 index 000000000000..c7526905b0ef --- /dev/null +++ b/contrib/ntp/libntp/mktime.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 1987, 1989 Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Arthur David Olson of the National Cancer Institute. + * + * 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, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may 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. */ + +/*static char *sccsid = "from: @(#)ctime.c 5.26 (Berkeley) 2/23/91";*/ +/*static char *rcsid = "mktime.c,v 1.1.1.3 1998/11/15 19:23:34 kardel RELEASE_19990228_A";*/ + +/* + * This implementation of mktime is lifted straight from the NetBSD (BSD 4.4) + * version. I modified it slightly to divorce it from the internals of the + * ctime library. Thus this version can't use details of the internal + * timezone state file to figure out strange unnormalized struct tm values, + * as might result from someone doing date math on the tm struct then passing + * it to mktime. + * + * It just does as well as it can at normalizing the tm input, then does a + * binary search of the time space using the system's localtime() function. + * + * The original binary search was defective in that it didn't consider the + * setting of tm_isdst when comparing tm values, causing the search to be + * flubbed for times near the dst/standard time changeover. The original + * code seems to make up for this by grubbing through the timezone info + * whenever the binary search barfed. Since I don't have that luxury in + * portable code, I have to take care of tm_isdst in the comparison routine. + * This requires knowing how many minutes offset dst is from standard time. + * + * So, if you live somewhere in the world where dst is not 60 minutes offset, + * and your vendor doesn't supply mktime(), you'll have to edit this variable + * by hand. Sorry about that. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef DSTMINUTES +#define DSTMINUTES 60 +#endif + +#define FALSE 0 +#define TRUE 1 + +/* some constants from tzfile.h */ +#define SECSPERMIN 60 +#define MINSPERHOUR 60 +#define HOURSPERDAY 24 +#define DAYSPERWEEK 7 +#define DAYSPERNYEAR 365 +#define DAYSPERLYEAR 366 +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) +#define MONSPERYEAR 12 +#define TM_YEAR_BASE 1900 +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#include + +extern time_t time(); + +static int mon_lengths[2][MONSPERYEAR] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +static int year_lengths[2] = { + DAYSPERNYEAR, DAYSPERLYEAR +}; + +/* +** Adapted from code provided by Robert Elz, who writes: +** The "best" way to do mktime I think is based on an idea of Bob +** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). +** It does a binary search of the time_t space. Since time_t's are +** just 32 bits, its a max of 32 iterations (even at 64 bits it +** would still be very reasonable). +*/ + +#ifndef WRONG +#define WRONG (-1) +#endif /* !defined WRONG */ + +static void +normalize( + int * tensptr, + int * unitsptr, + int base + ) +{ + if (*unitsptr >= base) { + *tensptr += *unitsptr / base; + *unitsptr %= base; + } else if (*unitsptr < 0) { + --*tensptr; + *unitsptr += base; + if (*unitsptr < 0) { + *tensptr -= 1 + (-*unitsptr) / base; + *unitsptr = base - (-*unitsptr) % base; + } + } +} + +static struct tm * +mkdst( + struct tm * tmp + ) +{ + /* jds */ + static struct tm tmbuf; + + tmbuf = *tmp; + tmbuf.tm_isdst = 1; + tmbuf.tm_min += DSTMINUTES; + normalize(&tmbuf.tm_hour, &tmbuf.tm_min, MINSPERHOUR); + return &tmbuf; +} + +static int +tmcomp( + register struct tm * atmp, + register struct tm * btmp + ) +{ + register int result; + + /* compare down to the same day */ + + if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && + (result = (atmp->tm_mon - btmp->tm_mon)) == 0) + result = (atmp->tm_mday - btmp->tm_mday); + + if(result != 0) + return result; + + /* get rid of one-sided dst bias */ + + if(atmp->tm_isdst == 1 && !btmp->tm_isdst) + btmp = mkdst(btmp); + else if(btmp->tm_isdst == 1 && !atmp->tm_isdst) + atmp = mkdst(atmp); + + /* compare the rest of the way */ + + if ((result = (atmp->tm_hour - btmp->tm_hour)) == 0 && + (result = (atmp->tm_min - btmp->tm_min)) == 0) + result = atmp->tm_sec - btmp->tm_sec; + return result; +} + + +static time_t +time2( + struct tm * tmp, + int * okayp + ) +{ + register int dir; + register int bits; + register int i; + register int saved_seconds; + time_t t; + struct tm yourtm, mytm; + + *okayp = FALSE; + yourtm = *tmp; + if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) + normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); + normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); + normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); + normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); + while (yourtm.tm_mday <= 0) { + --yourtm.tm_year; + yourtm.tm_mday += + year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)]; + } + for ( ; ; ) { + i = mon_lengths[isleap(yourtm.tm_year + + TM_YEAR_BASE)][yourtm.tm_mon]; + if (yourtm.tm_mday <= i) + break; + yourtm.tm_mday -= i; + if (++yourtm.tm_mon >= MONSPERYEAR) { + yourtm.tm_mon = 0; + ++yourtm.tm_year; + } + } + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = 0; + /* + ** Calculate the number of magnitude bits in a time_t + ** (this works regardless of whether time_t is + ** signed or unsigned, though lint complains if unsigned). + */ + for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) + ; + /* + ** If time_t is signed, then 0 is the median value, + ** if time_t is unsigned, then 1 << bits is median. + */ + t = (t < 0) ? 0 : ((time_t) 1 << bits); + for ( ; ; ) { + mytm = *localtime(&t); + dir = tmcomp(&mytm, &yourtm); + if (dir != 0) { + if (bits-- < 0) + return WRONG; + if (bits < 0) + --t; + else if (dir > 0) + t -= (time_t) 1 << bits; + else t += (time_t) 1 << bits; + continue; + } + if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) + break; + + return WRONG; + } + t += saved_seconds; + *tmp = *localtime(&t); + *okayp = TRUE; + return t; +} + +static time_t +time1( + struct tm * tmp + ) +{ + register time_t t; + int okay; + + if (tmp->tm_isdst > 1) + tmp->tm_isdst = 1; + t = time2(tmp, &okay); + if (okay || tmp->tm_isdst < 0) + return t; + + return WRONG; +} + +time_t +mktime( + struct tm * tmp + ) +{ + return time1(tmp); +} diff --git a/contrib/ntp/libntp/modetoa.c b/contrib/ntp/libntp/modetoa.c new file mode 100644 index 000000000000..405aef8550c1 --- /dev/null +++ b/contrib/ntp/libntp/modetoa.c @@ -0,0 +1,34 @@ +/* + * modetoa - return an asciized mode + */ +#include + +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +const char * +modetoa( + int mode + ) +{ + char *bp; + static const 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/ntp/libntp/mstolfp.c b/contrib/ntp/libntp/mstolfp.c new file mode 100644 index 000000000000..e4e909df7dbe --- /dev/null +++ b/contrib/ntp/libntp/mstolfp.c @@ -0,0 +1,100 @@ +/* + * mstolfp - convert an ascii string in milliseconds to an l_fp number + */ +#include +#include + +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +int +mstolfp( + 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((int)*cp)) + cp++; + + if (*cp == '-') { + *bp++ = '-'; + cp++; + } + + if (*cp != '.' && !isdigit((int)*cp)) + return 0; + + + /* + * Search forward for the decimal point or the end of the string. + */ + cpdec = cp; + while (isdigit((int)*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((int)*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((int)*cp)) + return 0; + return atolfp(buf, lfp); +} diff --git a/contrib/ntp/libntp/msutotsf.c b/contrib/ntp/libntp/msutotsf.c new file mode 100644 index 000000000000..eb3babe9cd1a --- /dev/null +++ b/contrib/ntp/libntp/msutotsf.c @@ -0,0 +1,35 @@ +/* + * msutotsf - tables for converting from a subsecond millisecond value + * to a time stamp fraction. + */ +#include + +#include "ntp_types.h" + +/* + * Index each of these tables with five bits of the (less than) 10 + * bit millisecond value. Note that the tables are rounded (not + * truncated). The error in the result will thus be +-1 low order + * bit in the time stamp fraction. + */ +u_long msutotsflo[32] = { + 0x00000000, 0x00418937, 0x0083126f, 0x00c49ba6, + 0x010624dd, 0x0147ae14, 0x0189374c, 0x01cac083, + 0x020c49ba, 0x024dd2f2, 0x028f5c29, 0x02d0e560, + 0x03126e98, 0x0353f7cf, 0x03958106, 0x03d70a3d, + 0x04189375, 0x045a1cac, 0x049ba5e3, 0x04dd2f1b, + 0x051eb852, 0x05604189, 0x05a1cac1, 0x05e353f8, + 0x0624dd2f, 0x06666666, 0x06a7ef9e, 0x06e978d5, + 0x072b020c, 0x076c8b44, 0x07ae147b, 0x07ef9db2 +}; + +u_long msutotsfhi[32] = { + 0x00000000, 0x083126e9, 0x10624dd3, 0x189374bc, + 0x20c49ba6, 0x28f5c28f, 0x3126e979, 0x39581062, + 0x4189374c, 0x49ba5e35, 0x51eb851f, 0x5a1cac08, + 0x624dd2f2, 0x6a7ef9db, 0x72b020c5, 0x7ae147ae, + 0x83126e98, 0x8b439581, 0x9374bc6a, 0x9ba5e354, + 0xa3d70a3d, 0xac083127, 0xb4395810, 0xbc6a7efa, + 0xc49ba5e3, 0xcccccccd, 0xd4fdf3b6, 0xdd2f1aa0, + 0xe5604189, 0xed916873, 0xf5c28f5c, 0xfdf3b646 +}; diff --git a/contrib/ntp/libntp/msyslog.c b/contrib/ntp/libntp/msyslog.c new file mode 100644 index 000000000000..dfb162713233 --- /dev/null +++ b/contrib/ntp/libntp/msyslog.c @@ -0,0 +1,170 @@ +/* + * msyslog - either send a message to the terminal or print it on + * the standard output. + * + * Converted to use varargs, much better ... jks + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include + +#include "ntp_types.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" +#include "ntp_syslog.h" + +#ifdef SYS_WINNT +# include "..\ports\winnt\libntp\log.h" +# include "..\ports\winnt\libntp\messages.h" +#endif + +int syslogit = 1; + +FILE *syslog_file = NULL; + +u_long ntp_syslogmask = ~ (u_long) 0; + +#ifdef SYS_WINNT +HANDLE hEventSource; +LPTSTR lpszStrings[1]; +static WORD event_type[] = { + EVENTLOG_ERROR_TYPE, EVENTLOG_ERROR_TYPE, EVENTLOG_ERROR_TYPE, EVENTLOG_ERROR_TYPE, + EVENTLOG_WARNING_TYPE, + EVENTLOG_INFORMATION_TYPE, EVENTLOG_INFORMATION_TYPE, EVENTLOG_INFORMATION_TYPE, +}; +#endif /* SYS_WINNT */ +extern char *progname; + +#if defined(__STDC__) || defined(HAVE_STDARG_H) +void msyslog(int level, const char *fmt, ...) +#else /* defined(__STDC__) || defined(HAVE_STDARG_H) */ + /*VARARGS*/ + void msyslog(va_alist) + va_dcl +#endif /* defined(__STDC__) || defined(HAVE_STDARG_H) */ +{ +#if defined(__STDC__) || defined(HAVE_STDARG_H) +#else + int level; + const char *fmt; +#endif + va_list ap; + char buf[1025], nfmt[256]; +#if !defined(VMS) + char xerr[50]; +#endif + register int c; + register char *n, *prog; + register const char *f; +#ifdef CHAR_SYS_ERRLIST + extern int sys_nerr; + extern char *sys_errlist[]; +#endif + int olderrno; + char *err; + +#if defined(__STDC__) || defined(HAVE_STDARG_H) + 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; + } + err = 0; +#if !defined(VMS) && !defined(SYS_WINNT) && !defined (SYS_VXWORKS) + if ((unsigned)olderrno > sys_nerr) + sprintf((char *)(err = xerr), "error %d", olderrno); + else + err = (char*)sys_errlist[olderrno]; +#elif defined(VMS) || defined (SYS_VXWORKS) + err = strerror(olderrno); +#else /* SYS_WINNT */ + err = xerr; + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + (LPTSTR) err, + sizeof(xerr), + NULL); + +#endif /* VMS && SYS_WINNT */ + if ((n + strlen(err)) < &nfmt[254]) { + strcpy(n, err); + n += strlen(err); + } + } +#if !defined(VMS) + if (!syslogit) +#endif /* VMS */ + *n++ = '\n'; + *n = '\0'; + + vsprintf(buf, nfmt, ap); +#if !defined(VMS) && !defined (SYS_VXWORKS) + if (syslogit) +#ifndef SYS_WINNT + syslog(level, "%s", buf); +#else + { + lpszStrings[0] = buf; + + switch (event_type[level]) + { + case EVENTLOG_ERROR_TYPE: + reportAnEEvent(NTP_ERROR,1,lpszStrings); + break; + case EVENTLOG_INFORMATION_TYPE: + reportAnIEvent(NTP_INFO,1,lpszStrings); + break; + case EVENTLOG_WARNING_TYPE: + reportAnWEvent(NTP_WARNING,1,lpszStrings); + break; + } /* switch end */ + + } +#endif /* SYS_WINNT */ + else +#endif /* VMS && SYS_VXWORKS*/ + { + 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[%d]: %s", prog, (int)getpid(), buf); + fflush (out_file); + } + va_end(ap); +} diff --git a/contrib/ntp/libntp/netof.c b/contrib/ntp/libntp/netof.c new file mode 100644 index 000000000000..df7657e4fd9e --- /dev/null +++ b/contrib/ntp/libntp/netof.c @@ -0,0 +1,25 @@ +/* + * netof - return the net address part of an ip address + * (zero out host part) + */ +#include + +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +u_int32 +netof( + u_int32 num + ) +{ + register u_int32 netnum; + + netnum = num; + if(IN_CLASSC(netnum)) + netnum &= IN_CLASSC_NET; + else if (IN_CLASSB(netnum)) + netnum &= IN_CLASSB_NET; + else /* treat all other like class A */ + netnum &= IN_CLASSA_NET; + return netnum; +} diff --git a/contrib/ntp/libntp/numtoa.c b/contrib/ntp/libntp/numtoa.c new file mode 100644 index 000000000000..de95118afe04 --- /dev/null +++ b/contrib/ntp/libntp/numtoa.c @@ -0,0 +1,24 @@ +/* + * numtoa - return asciized network numbers store in local array space + */ +#include + +#include "ntp_fp.h" +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +numtoa( + u_int32 num + ) +{ + register u_int32 netnum; + register char *buf; + + netnum = ntohl(num); + LIB_GETBUF(buf); + (void) sprintf(buf, "%lu.%lu.%lu.%lu", ((u_long)netnum >> 24) & 0xff, + ((u_long)netnum >> 16) & 0xff, ((u_long)netnum >> 8) & 0xff, + (u_long)netnum & 0xff); + return buf; +} diff --git a/contrib/ntp/libntp/numtohost.c b/contrib/ntp/libntp/numtohost.c new file mode 100644 index 000000000000..4e5309205e4f --- /dev/null +++ b/contrib/ntp/libntp/numtohost.c @@ -0,0 +1,39 @@ +/* + * numtohost - convert network number to host name. + */ +#include + +#include "ntp_fp.h" +#include "ntp_stdlib.h" +#include "lib_strbuf.h" + +#define LOOPBACKNET 0x7f000000 +#define LOOPBACKHOST 0x7f000001 +#define LOOPBACKNETMASK 0xff000000 + +char * +numtohost( + u_int32 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/ntp/libntp/octtoint.c b/contrib/ntp/libntp/octtoint.c new file mode 100644 index 000000000000..f792b2bd6184 --- /dev/null +++ b/contrib/ntp/libntp/octtoint.c @@ -0,0 +1,35 @@ +/* + * octtoint - convert an ascii string in octal to an unsigned + * long, with error checking + */ +#include +#include + +#include "ntp_stdlib.h" + +int +octtoint( + 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((int)*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/ntp/libntp/prettydate.c b/contrib/ntp/libntp/prettydate.c new file mode 100644 index 000000000000..291c17c2c11d --- /dev/null +++ b/contrib/ntp/libntp/prettydate.c @@ -0,0 +1,72 @@ +/* + * prettydate - convert a time stamp to something readable + */ +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" /* includes */ +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +#ifndef TM_IN_SYS_TIME +#include +#endif + +static const char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static const char *days[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +char * +prettydate( + l_fp *ts + ) +{ + char *bp; + struct tm *tm; + time_t sec; + u_long msec; + + LIB_GETBUF(bp); + + sec = ts->l_ui - JAN_1970; + msec = ts->l_uf / 4294967; /* fract / (2 ** 32 / 1000) */ + + tm = localtime(&sec); + + (void) sprintf(bp, "%08lx.%08lx %s, %s %2d %4d %2d:%02d:%02d.%03lu", + (u_long)ts->l_ui, (u_long)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; +} + +char * +gmprettydate( + l_fp *ts + ) +{ + char *bp; + struct tm *tm; + time_t sec; + u_long msec; + + LIB_GETBUF(bp); + + sec = ts->l_ui - JAN_1970; + msec = ts->l_uf / 4294967; /* fract / (2 ** 32 / 1000) */ + + tm = gmtime(&sec); + + (void) sprintf(bp, "%08lx.%08lx %s, %s %2d %4d %2d:%02d:%02d.%03lu UTC", + (u_long)ts->l_ui, (u_long)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/ntp/libntp/ranny.c b/contrib/ntp/libntp/ranny.c new file mode 100644 index 000000000000..fa555f565afa --- /dev/null +++ b/contrib/ntp/libntp/ranny.c @@ -0,0 +1,82 @@ +/* + * 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 ntp 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 time_t ran_y[55]; + +static time_t 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( + int m + ) +{ + time_t 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 (u_long)(r & ((1 << m ) - 1)); +} + +/* + * init_random - do initialization of random number routine + */ +void +init_random(void) +{ + 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((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/ntp/libntp/recvbuff.c b/contrib/ntp/libntp/recvbuff.c new file mode 100644 index 000000000000..37166a4a5c42 --- /dev/null +++ b/contrib/ntp/libntp/recvbuff.c @@ -0,0 +1,277 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "ntp_machine.h" +#include "ntp_fp.h" +#include "ntp_stdlib.h" +#include "ntp_syslog.h" +#include "ntp_io.h" +#include "recvbuff.h" +#include "iosignal.h" + +/* + * Memory allocation + */ +static u_long volatile full_recvbufs; /* number of recvbufs on fulllist */ +static u_long volatile free_recvbufs; /* number of recvbufs on freelist */ +static u_long volatile total_recvbufs; /* total recvbufs currently in use */ +static u_long volatile lowater_adds; /* number of times we have added memory */ + +static struct recvbuf *volatile freelist; /* free buffers */ +static struct recvbuf *volatile fulllist; /* lifo buffers with data */ +static struct recvbuf *volatile beginlist; /* fifo buffers with data */ + +#if defined(HAVE_IO_COMPLETION_PORT) +static HANDLE fulldatabufferevent; +static CRITICAL_SECTION RecvCritSection; +# define RECV_BLOCK_IO() EnterCriticalSection(&RecvCritSection) +# define RECV_UNBLOCK_IO() LeaveCriticalSection(&RecvCritSection) +#else +# define RECV_BLOCK_IO() +# define RECV_UNBLOCK_IO() +#endif + +u_long +free_recvbuffs (void) +{ + return free_recvbufs; +} + +u_long +full_recvbuffs (void) +{ + return free_recvbufs; +} + +u_long +total_recvbuffs (void) +{ + return free_recvbufs; +} + +u_long +lowater_additions(void) +{ + return lowater_adds; +} + +static void +initialise_buffer(struct recvbuf *buff) +{ + memset((char *) buff, 0, sizeof(struct recvbuf)); + +#if defined HAVE_IO_COMPLETION_PORT + buff->iocompletioninfo.overlapped.hEvent = CreateEvent(NULL, FALSE,FALSE, NULL); + buff->wsabuff.len = RX_BUFF_SIZE; + buff->wsabuff.buf = (char *) buff->recv_buffer; +#endif +} + +static void +create_buffers(void) +{ + register struct recvbuf *buf; + int i; + buf = (struct recvbuf *) + emalloc(RECV_INC*sizeof(struct recvbuf)); + for (i = 0; i < RECV_INC; i++) + { + initialise_buffer(buf); + buf->next = (struct recvbuf *) freelist; + freelist = buf; + buf++; + } + + free_recvbufs += RECV_INC; + total_recvbufs += RECV_INC; + lowater_adds++; +} + +void +init_recvbuff(int nbufs) +{ + register struct recvbuf *buf; + int i; + + /* + * Init buffer free list and stat counters + */ + freelist = 0; + + buf = (struct recvbuf *) + emalloc(nbufs*sizeof(struct recvbuf)); + for (i = 0; i < nbufs; i++) + { + initialise_buffer(buf); + buf->next = (struct recvbuf *) freelist; + freelist = buf; + buf++; + } + + fulllist = 0; + free_recvbufs = total_recvbufs = nbufs; + full_recvbufs = lowater_adds = 0; + +#if defined(HAVE_IO_COMPLETION_PORT) + InitializeCriticalSection(&RecvCritSection); + fulldatabufferevent = CreateEvent(NULL, FALSE,FALSE, NULL); +#endif + +} + +#if defined(HAVE_IO_COMPLETION_PORT) + +/* Return the new full buffer event handle . This handle is + * signalled when a recv buffer is placed in the full list. + */ +HANDLE +get_recv_buff_event() +{ + return fulldatabufferevent; +} +#endif + +/* + * getrecvbufs - get receive buffers which have data in them + * + * + */ + +struct recvbuf * +getrecvbufs(void) +{ + struct recvbuf *rb = NULL; /* nothing has arrived */; + + RECV_BLOCK_IO(); + if (full_recvbufs == 0) + { +#ifdef DEBUG + if (debug > 4) + printf("getrecvbufs called, no action here\n"); +#endif + } + else { + + /* + * Get the fulllist chain and mark it empty + */ +#ifdef DEBUG + if (debug > 4) + printf("getrecvbufs returning %ld 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) + { + if (total_recvbufs >= RECV_TOOMANY) + msyslog(LOG_ERR, "too many recvbufs allocated (%ld)", + total_recvbufs); + else + { + create_buffers(); + } + } + } + RECV_UNBLOCK_IO(); + + /* + * Return the chain + */ + return rb; +} + +/* + * freerecvbuf - make a single recvbuf available for reuse + */ +void +freerecvbuf( + struct recvbuf *rb + ) +{ + RECV_BLOCK_IO(); + BLOCKIO(); + rb->next = (struct recvbuf *) freelist; + freelist = rb; + free_recvbufs++; + UNBLOCKIO(); + RECV_UNBLOCK_IO(); +} + + +void +add_full_recv_buffer( + struct recvbuf *rb + ) +{ + RECV_BLOCK_IO(); + if (full_recvbufs == 0) + { + beginlist = rb; + rb->next = 0; + } + else + { + rb->next = fulllist->next; + fulllist->next = rb; + } + fulllist = rb; + full_recvbufs++; + +#if defined(HAVE_IO_COMPLETION_PORT) + if (!SetEvent(fulldatabufferevent)) { + msyslog(LOG_ERR, "Can't set receive buffer event"); + } +#endif + RECV_UNBLOCK_IO(); +} + +struct recvbuf * +get_free_recv_buffer(void) +{ + struct recvbuf * buffer = NULL; + RECV_BLOCK_IO(); + if (free_recvbufs <= RECV_LOWAT) + { + if (total_recvbufs >= RECV_TOOMANY) { + msyslog(LOG_ERR, "too many recvbufs allocated (%ld)", + total_recvbufs); + } + else + { + create_buffers(); + } + } + + if (free_recvbufs > 0) + { + buffer = freelist; + freelist = buffer->next; + buffer->next = NULL; + --free_recvbufs; + } + + RECV_UNBLOCK_IO(); + return buffer; +} + +struct recvbuf * +get_full_recv_buffer(void) +{ + struct recvbuf * buffer = NULL; + RECV_BLOCK_IO(); + if (full_recvbufs > 0) { + --full_recvbufs; + buffer = beginlist; + beginlist = buffer->next; + buffer->next = NULL; + } + RECV_UNBLOCK_IO(); + return buffer; +} diff --git a/contrib/ntp/libntp/refnumtoa.c b/contrib/ntp/libntp/refnumtoa.c new file mode 100644 index 000000000000..a1020150b7a1 --- /dev/null +++ b/contrib/ntp/libntp/refnumtoa.c @@ -0,0 +1,31 @@ +/* + * refnumtoa - return asciized refclock addresses stored in local array space + */ +#include + +#include "ntp_fp.h" +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +refnumtoa( + u_int32 num + ) +{ + register u_int32 netnum; + register char *buf; + register const char *rclock; + + netnum = ntohl(num); + + LIB_GETBUF(buf); + + rclock = clockname((int)((u_long)netnum >> 8) & 0xff); + + if (rclock != NULL) + (void)sprintf(buf, "%s(%lu)", rclock, (u_long)netnum & 0xff); + else + (void)sprintf(buf, "REFCLK(%lu,%lu)", + ((u_long)netnum >> 8) & 0xff, (u_long)netnum & 0xff); + return buf; +} diff --git a/contrib/ntp/libntp/statestr.c b/contrib/ntp/libntp/statestr.c new file mode 100644 index 000000000000..7dd600979904 --- /dev/null +++ b/contrib/ntp/libntp/statestr.c @@ -0,0 +1,271 @@ +/* + * pretty printing of status information + */ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include "ntp_stdlib.h" +#include "ntp_fp.h" +#include "ntp.h" +#include "lib_strbuf.h" +#include "ntp_refclock.h" +#include "ntp_control.h" +#include "ntp_string.h" + +/* + * Structure for turning various constants into a readable string. + */ +struct codestring { + int code; + const char *string; +}; + +/* + * Leap values + */ +static +struct codestring leap_codes[] = { + { LEAP_NOWARNING, "leap_none" }, + { LEAP_ADDSECOND, "leap_add_sec" }, + { LEAP_DELSECOND, "leap_del_sec" }, + { LEAP_NOTINSYNC, "sync_alarm" }, + { -1, "leap" } +}; + +/* + * Clock source + */ +static +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 + */ +static +struct codestring select_codes[] = { + { CTL_PST_SEL_REJECT, "selreject" }, + { CTL_PST_SEL_SANE, "sel_falsetick" }, + { CTL_PST_SEL_CORRECT, "sel_excess" }, + { CTL_PST_SEL_SELCAND, "sel_outlyer" }, + { CTL_PST_SEL_SYNCCAND, "sel_candidat" }, + { CTL_PST_SEL_DISTSYSPEER, "sel_selected" }, + { CTL_PST_SEL_SYSPEER, "sel_sys.peer" }, + { CTL_PST_SEL_PPS, "sel_pps.peer" }, + { -1, "sel" } +}; + + +/* + * Clock status + */ +static +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_badsignal" }, + { CTL_CLK_BADDATE, "clk_baddate" }, + { CTL_CLK_BADTIME, "clk_badtime" }, + { -1, "clk" } +}; + + +/* + * System Events + */ +static +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 + */ +static +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" }, + { EVNT_PEERCLOCK & ~PEER_EVENT, "event_peer_clock" }, +#if 0 + { EVNT_PEERSTRAT & ~PEER_EVENT, "event_stratum_chg" }, +#endif + { -1, "event" } +}; + +/* Forwards */ +static const char *getcode P((int, struct codestring *)); +static const char *getevents P((int)); + +/* + * getcode - return string corresponding to code + */ +static const char * +getcode( + 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; +} + +/* + * getevents - return a descriptive string for the event count + */ +static const char * +getevents( + 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 + */ +char * +statustoa( + int type, + int st + ) +{ + char *cb; + u_char pst; + + LIB_GETBUF(cb); + + 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) & ~CTL_SST_TS_PPS, sync_codes)); + if (CTL_SYS_SOURCE(st) & CTL_SST_TS_PPS) + (void)strcat(cb, "/PPS"); + (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 = (u_char) CTL_PEER_STATVAL(st); + if (!(pst & CTL_PST_REACH)) { + (void)strcpy(cb, "unreach"); + } else { + (void)strcpy(cb, "reach"); + + } + 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; +} + +const char * +eventstr( + int num + ) +{ + return getcode(num & ~PEER_EVENT, (num & PEER_EVENT) ? peer_codes : sys_codes); +} + +const char * +ceventstr( + int num + ) +{ + return getcode(num, clock_codes); +} + +const char * +sysstatstr( + int status + ) +{ + return statustoa(TYPE_SYS, status); +} + +const char * +peerstatstr( + int status + ) +{ + return statustoa(TYPE_PEER, status); +} + +const char * +clockstatstr( + int status + ) +{ + return statustoa(TYPE_CLOCK, status); +} diff --git a/contrib/ntp/libntp/strerror.c b/contrib/ntp/libntp/strerror.c new file mode 100644 index 000000000000..a07bcd65427b --- /dev/null +++ b/contrib/ntp/libntp/strerror.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)strerror.c 5.1 (Berkeley) 4/9/89"; +#endif /* LIBC_SCCS and not lint */ + +#include + +#include +#include + +char * +strerror( + int errnum + ) +{ + extern int sys_nerr; + extern char *sys_errlist[]; + static char ebuf[20]; + + if ((unsigned int)errnum < sys_nerr) + return(sys_errlist[errnum]); + (void)sprintf(ebuf, "Unknown error: %d", errnum); + return(ebuf); +} diff --git a/contrib/ntp/libntp/syssignal.c b/contrib/ntp/libntp/syssignal.c new file mode 100644 index 000000000000..50c65b7c3d11 --- /dev/null +++ b/contrib/ntp/libntp/syssignal.c @@ -0,0 +1,123 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "ntp_syslog.h" +#include "ntp_stdlib.h" + +#ifdef HAVE_SIGACTION + +void +signal_no_reset( +#if defined(__STDC__) || defined(HAVE_STDARG_H) + int sig, + void (*func) (int) +#else + sig, func +#endif + ) +#if defined(__STDC__) || defined(HAVE_STDARG_H) +#else + int sig; + void (*func) P((int)); +#endif +{ + int n; + struct sigaction vec; + + vec.sa_handler = func; + sigemptyset(&vec.sa_mask); +#if 0 +#ifdef SA_RESTART + vec.sa_flags = SA_RESTART; +#else + vec.sa_flags = 0; +#endif +#else + vec.sa_flags = 0; +#endif + + while (1) + { + struct sigaction ovec; + + n = sigaction(sig, &vec, &ovec); + if (n == -1 && errno == EINTR) continue; + if (ovec.sa_flags +#ifdef SA_RESTART + && ovec.sa_flags != SA_RESTART +#endif + ) + msyslog(LOG_DEBUG, "signal_no_reset: signal %d had flags %x", + sig, ovec.sa_flags); + break; + } + if (n == -1) { + perror("sigaction"); + exit(1); + } +} + +#elif HAVE_SIGVEC + +void +signal_no_reset( + int sig, + RETSIGTYPE (*func) (int) + ) +{ + struct sigvec sv; + int n; + + bzero((char *) &sv, sizeof(sv)); + sv.sv_handler = func; + n = sigvec(sig, &sv, (struct sigvec *)NULL); + if (n == -1) { + perror("sigvec"); + exit(1); + } +} + +#elif HAVE_SIGSET + +void +signal_no_reset( + int sig, + RETSIGTYPE (*func) (int) + ) +{ + int n; + + n = sigset(sig, func); + if (n == -1) { + perror("sigset"); + exit(1); + } +} + +#else + +/* Beware! This implementation resets the signal to SIG_DFL */ +void +signal_no_reset( + int sig, + RETSIGTYPE (*func) (int) + ) +{ +#ifdef SIG_ERR + if (SIG_ERR == signal(sig, func)) { +#else + int n; + n = signal(sig, func); + if (n == -1) { +#endif + perror("signal"); + exit(1); + } +} + +#endif diff --git a/contrib/ntp/libntp/systime.c b/contrib/ntp/libntp/systime.c new file mode 100644 index 000000000000..5e50fc52d6cd --- /dev/null +++ b/contrib/ntp/libntp/systime.c @@ -0,0 +1,404 @@ +/* + * systime -- routines to fiddle a UNIX clock. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_UTMP_H +# include +#endif /* HAVE_UTMP_H */ +#ifdef HAVE_UTMPX_H +# include +#endif /* HAVE_UTMPX_H */ + +#include "ntp_machine.h" +#include "ntp_fp.h" +#include "ntp_syslog.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +#if defined SYS_WINNT +#include "ntp_timer.h" +extern DWORD units_per_tick; +static long last_Adj = 0; +#endif + +int systime_10ms_ticks = 0; /* adj sysclock in 10ms increments */ + +#define MAXFREQ 500e-6 + +/* + * 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. + */ +double sys_residual = 0; /* residual from previous adjustment */ +double sys_maxfreq = MAXFREQ; /* max frequency correction */ + + +/* + * get_systime - return the system time in timestamp format biased by + * the current time offset. + */ +void +get_systime( + l_fp *now + ) +{ +#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) + struct timespec ts; +#else + struct timeval tv; +#endif + double dtemp; + + /* + * We use nanosecond time if we can get it. Watch out for + * rounding wiggles, which may overflow the fraction. + */ +#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) +# ifdef HAVE_CLOCK_GETTIME + (void) clock_gettime(CLOCK_REALTIME, &ts); +# else + (void) getclock(TIMEOFDAY, &ts); +# endif + now->l_i = ts.tv_sec + JAN_1970; + dtemp = ts.tv_nsec * FRAC / 1e9; + if (dtemp >= FRAC) + now->l_i++; + now->l_uf = (u_int32)dtemp; +#else /* HAVE_CLOCK_GETTIME */ + (void) GETTIMEOFDAY(&tv, (struct timezone *)0); + now->l_i = tv.tv_sec + JAN_1970; + + if (systime_10ms_ticks) { + /* fake better than 10ms resolution by interpolating + accumulated residual (in adj_systime(), see below) */ + dtemp = tv.tv_usec / 1e6; + if (sys_residual < 5000e-6 && sys_residual > -5000e-6) { + dtemp += sys_residual; + if (dtemp < 0) { + now->l_i--; + dtemp++; + } + } + dtemp *= FRAC; + } else { + dtemp = tv.tv_usec * FRAC / 1e6; + } + + if (dtemp >= FRAC) + now->l_i++; + now->l_uf = (u_int32)dtemp; +#endif /* HAVE_CLOCK_GETTIME */ + +} + + +/* + * adj_systime - called once every second to make system time adjustments. + * Returns 1 if okay, 0 if trouble. + */ +int +adj_systime( + double now + ) +{ + double dtemp; + struct timeval adjtv; + u_char isneg = 0; +#if !defined SYS_WINNT && !defined SYS_CYGWIN32 + struct timeval oadjtv; +#else + int rc; + long dwTimeAdjustment; +#endif + + /* + * Add the residual from the previous adjustment to the new + * adjustment, bound and round. + */ + dtemp = sys_residual + now; + sys_residual = 0; + if (dtemp < 0) { + isneg = 1; + dtemp = -dtemp; + } + + if (systime_10ms_ticks) { + /* accumulate changes until we have enough to adjust a tick */ + if (dtemp < 5000e-6) { + if (isneg) sys_residual = -dtemp; + else sys_residual = dtemp; + dtemp = 0; + } else { + if (isneg) sys_residual = 10000e-6 - dtemp; + else sys_residual = dtemp - 10000e-6; + dtemp = 10000e-6; + } + } else { + if (dtemp > sys_maxfreq) + dtemp = sys_maxfreq; + } + +#ifdef SYS_WINNT + dtemp = dtemp * 1000000.0; +#else + dtemp = dtemp * 1e6 + .5; +#endif + if (isneg) + dtemp = -dtemp; + adjtv.tv_sec = 0; + adjtv.tv_usec = (int32)dtemp; + +#if defined SYS_WINNT || defined SYS_CYGWIN32 + /* dtemp is in micro seconds. NT uses 100 ns units, + * so a unit change in dwTimeAdjustment corresponds + * to slewing 10 ppm. + * Calculate the number of 100ns units to add, + * and leave the remainder in dtemp */ + dwTimeAdjustment = dtemp / 10; + dtemp += (double) -dwTimeAdjustment * 10.0; + dwTimeAdjustment += units_per_tick; + + /* only adjust the clock if adjustment changes */ + if (last_Adj != dwTimeAdjustment) { + last_Adj = dwTimeAdjustment; +# ifdef DEBUG + if (debug > 1) + printf("SetSystemTimeAdjustment( %ld)\n", dwTimeAdjustment); +# endif + rc = !SetSystemTimeAdjustment(dwTimeAdjustment, FALSE); + } + else rc = 0; + if (rc) +#else + /* + * Here we do the actual adjustment. If for some reason the adjtime() + * call fails, like it is not implemented or something like that, + * we honk to the log. If the previous adjustment did not complete, + * we correct the residual offset. + */ + /* casey - we need a posix type thang here */ + if (adjtime(&adjtv, &oadjtv) < 0) +#endif /* SYS_WINNT */ + { + msyslog(LOG_ERR, "Can't adjust time: %m"); + return 0; + } + else { +#if !defined (SYS_WINNT) && !defined (SYS_CYGWIN32) + sys_residual += oadjtv.tv_usec / 1e6; +#else + sys_residual = dtemp / 1000000.0; +#endif /* SYS_WINNT */ + } +#ifdef DEBUG + if (debug > 6) + printf("adj_systime: adj %.9f -> remaining residual %.9f\n", now, sys_residual); +#endif + return 1; +} + + +/* + * step_systime - step the system clock. + */ +int +step_systime( + double now + ) +{ + struct timeval timetv, adjtv, oldtimetv; + int isneg = 0; + double dtemp; +#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) + struct timespec ts; +#endif + + dtemp = sys_residual + now; + if (dtemp < 0) { + isneg = 1; + dtemp = - dtemp; + adjtv.tv_sec = (int32)dtemp; + adjtv.tv_usec = (u_int32)((dtemp - (double)adjtv.tv_sec) * + 1e6 + .5); + } else { + adjtv.tv_sec = (int32)dtemp; + adjtv.tv_usec = (u_int32)((dtemp - (double)adjtv.tv_sec) * + 1e6 + .5); + } +#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) +#ifdef HAVE_CLOCK_GETTIME + (void) clock_gettime(CLOCK_REALTIME, &ts); +#else + (void) getclock(TIMEOFDAY, &ts); +#endif + timetv.tv_sec = ts.tv_sec; + timetv.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + (void) GETTIMEOFDAY(&timetv, (struct timezone *)0); +#endif /* not HAVE_GETCLOCK */ + + oldtimetv = timetv; + +#ifdef DEBUG + if (debug) + printf("step_systime: step %.6f residual %.6f\n", now, sys_residual); +#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 (ntp_set_tod(&timetv, (struct timezone *)0) != 0) { + msyslog(LOG_ERR, "Can't set time of day: %m"); + return (0); + } + sys_residual = 0; + +#ifdef NEED_HPUX_ADJTIME + /* + * CHECKME: is this correct when called by ntpdate????? + */ + _clear_adjtime(); +#endif + + /* + * FreeBSD, for example, has: + * struct utmp { + * char ut_line[UT_LINESIZE]; + * char ut_name[UT_NAMESIZE]; + * char ut_host[UT_HOSTSIZE]; + * long ut_time; + * }; + * and appends line="|", name="date", host="", time for the OLD + * and appends line="{", name="date", host="", time for the NEW + * to _PATH_WTMP . + * + * Some OSes have utmp, some have utmpx. + */ + + /* + * Write old and new time entries in utmp and wtmp if step adjustment + * is greater than one second. + * + * This might become even Uglier... + */ + if (oldtimetv.tv_sec != timetv.tv_sec) + { +#ifdef HAVE_UTMP_H + struct utmp ut; +#endif +#ifdef HAVE_UTMPX_H + struct utmpx utx; +#endif + +#ifdef HAVE_UTMP_H + memset((char *)&ut, 0, sizeof(ut)); +#endif +#ifdef HAVE_UTMPX_H + memset((char *)&utx, 0, sizeof(utx)); +#endif + + /* UTMP */ + +#ifdef UPDATE_UTMP +# ifdef HAVE_PUTUTLINE + ut.ut_type = OLD_TIME; + (void)strcpy(ut.ut_line, OTIME_MSG); + ut.ut_time = oldtimetv.tv_sec; + pututline(&ut); + setutent(); + ut.ut_type = NEW_TIME; + (void)strcpy(ut.ut_line, NTIME_MSG); + ut.ut_time = timetv.tv_sec; + pututline(&ut); + endutent(); +# else /* not HAVE_PUTUTLINE */ +# endif /* not HAVE_PUTUTLINE */ +#endif /* UPDATE_UTMP */ + + /* UTMPX */ + +#ifdef UPDATE_UTMPX +# ifdef HAVE_PUTUTXLINE + utx.ut_type = OLD_TIME; + (void)strcpy(utx.ut_line, OTIME_MSG); + utx.ut_tv = oldtimetv; + pututxline(&utx); + setutxent(); + utx.ut_type = NEW_TIME; + (void)strcpy(utx.ut_line, NTIME_MSG); + utx.ut_tv = timetv; + pututxline(&utx); + endutxent(); +# else /* not HAVE_PUTUTXLINE */ +# endif /* not HAVE_PUTUTXLINE */ +#endif /* UPDATE_UTMPX */ + + /* WTMP */ + +#ifdef UPDATE_WTMP +# ifdef HAVE_PUTUTLINE + utmpname(WTMP_FILE); + ut.ut_type = OLD_TIME; + (void)strcpy(ut.ut_line, OTIME_MSG); + ut.ut_time = oldtimetv.tv_sec; + pututline(&ut); + ut.ut_type = NEW_TIME; + (void)strcpy(ut.ut_line, NTIME_MSG); + ut.ut_time = timetv.tv_sec; + pututline(&ut); + endutent(); +# else /* not HAVE_PUTUTLINE */ +# endif /* not HAVE_PUTUTLINE */ +#endif /* UPDATE_WTMP */ + + /* WTMPX */ + +#ifdef UPDATE_WTMPX +# ifdef HAVE_PUTUTXLINE + utx.ut_type = OLD_TIME; + utx.ut_tv = oldtimetv; + (void)strcpy(utx.ut_line, OTIME_MSG); +# ifdef HAVE_UPDWTMPX + updwtmpx(WTMPX_FILE, &utx); +# else /* not HAVE_UPDWTMPX */ +# endif /* not HAVE_UPDWTMPX */ +# else /* not HAVE_PUTUTXLINE */ +# endif /* not HAVE_PUTUTXLINE */ +# ifdef HAVE_PUTUTXLINE + utx.ut_type = NEW_TIME; + utx.ut_tv = timetv; + (void)strcpy(utx.ut_line, NTIME_MSG); +# ifdef HAVE_UPDWTMPX + updwtmpx(WTMPX_FILE, &utx); +# else /* not HAVE_UPDWTMPX */ +# endif /* not HAVE_UPDWTMPX */ +# else /* not HAVE_PUTUTXLINE */ +# endif /* not HAVE_PUTUTXLINE */ +#endif /* UPDATE_WTMPX */ + + } + return (1); +} diff --git a/contrib/ntp/libntp/tsftomsu.c b/contrib/ntp/libntp/tsftomsu.c new file mode 100644 index 000000000000..5926aabc77a6 --- /dev/null +++ b/contrib/ntp/libntp/tsftomsu.c @@ -0,0 +1,38 @@ +/* + * tsftomsu - convert from a time stamp fraction to milliseconds + */ +#include "ntp_fp.h" +#include "ntp_stdlib.h" + +int +tsftomsu( + u_long tsf, + int round + ) +{ + register long val_ui, val_uf; + register 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/ntp/libntp/tstotv.c b/contrib/ntp/libntp/tstotv.c new file mode 100644 index 000000000000..be4bdd44155d --- /dev/null +++ b/contrib/ntp/libntp/tstotv.c @@ -0,0 +1,135 @@ +/* + * 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/ntp/libntp/tvtoa.c b/contrib/ntp/libntp/tvtoa.c new file mode 100644 index 000000000000..6bc72ac8d48f --- /dev/null +++ b/contrib/ntp/libntp/tvtoa.c @@ -0,0 +1,38 @@ +/* + * tvtoa - return an asciized representation of a struct timeval + */ +#include +#include + +#include "lib_strbuf.h" +#if defined(VMS) +#include "ntp_fp.h" +#endif /* VMS */ +#include "ntp_stdlib.h" +#include "ntp_unixtime.h" + +char * +tvtoa( + const 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/ntp/libntp/tvtots.c b/contrib/ntp/libntp/tvtots.c new file mode 100644 index 000000000000..0bd2b6911472 --- /dev/null +++ b/contrib/ntp/libntp/tvtots.c @@ -0,0 +1,159 @@ +/* + * tvtots - tables for converting from Unix struct timeval's to + * NTP time stamp format. + */ +#include + +#include "ntp_types.h" + +/* + * Tables to calculate time stamp fractions from usecs. The entries + * in these tables are offset into using each of the two low order + * bytes plus the next 4 bits in a usec value (from a struct timeval). + * These are summed to produce the time stamp fraction. + * + * Note that these tables are rounded (not truncated) to the nearest + * low order bit in the fraction. The timestamp computed should be + * +- 1.5 low order bits. + */ + +u_long ustotslo[256] = { + 0x00000000, 0x000010c7, 0x0000218e, 0x00003255, + 0x0000431c, 0x000053e3, 0x000064aa, 0x00007571, + 0x00008638, 0x000096ff, 0x0000a7c6, 0x0000b88d, + 0x0000c954, 0x0000da1b, 0x0000eae2, 0x0000fba9, + 0x00010c6f, 0x00011d36, 0x00012dfd, 0x00013ec4, + 0x00014f8b, 0x00016052, 0x00017119, 0x000181e0, + 0x000192a7, 0x0001a36e, 0x0001b435, 0x0001c4fc, + 0x0001d5c3, 0x0001e68a, 0x0001f751, 0x00020818, + 0x000218df, 0x000229a6, 0x00023a6d, 0x00024b34, + 0x00025bfb, 0x00026cc2, 0x00027d89, 0x00028e50, + 0x00029f17, 0x0002afde, 0x0002c0a5, 0x0002d16c, + 0x0002e233, 0x0002f2fa, 0x000303c0, 0x00031487, + 0x0003254e, 0x00033615, 0x000346dc, 0x000357a3, + 0x0003686a, 0x00037931, 0x000389f8, 0x00039abf, + 0x0003ab86, 0x0003bc4d, 0x0003cd14, 0x0003dddb, + 0x0003eea2, 0x0003ff69, 0x00041030, 0x000420f7, + 0x000431be, 0x00044285, 0x0004534c, 0x00046413, + 0x000474da, 0x000485a1, 0x00049668, 0x0004a72f, + 0x0004b7f6, 0x0004c8bd, 0x0004d984, 0x0004ea4b, + 0x0004fb12, 0x00050bd8, 0x00051c9f, 0x00052d66, + 0x00053e2d, 0x00054ef4, 0x00055fbb, 0x00057082, + 0x00058149, 0x00059210, 0x0005a2d7, 0x0005b39e, + 0x0005c465, 0x0005d52c, 0x0005e5f3, 0x0005f6ba, + 0x00060781, 0x00061848, 0x0006290f, 0x000639d6, + 0x00064a9d, 0x00065b64, 0x00066c2b, 0x00067cf2, + 0x00068db9, 0x00069e80, 0x0006af47, 0x0006c00e, + 0x0006d0d5, 0x0006e19c, 0x0006f263, 0x00070329, + 0x000713f0, 0x000724b7, 0x0007357e, 0x00074645, + 0x0007570c, 0x000767d3, 0x0007789a, 0x00078961, + 0x00079a28, 0x0007aaef, 0x0007bbb6, 0x0007cc7d, + 0x0007dd44, 0x0007ee0b, 0x0007fed2, 0x00080f99, + 0x00082060, 0x00083127, 0x000841ee, 0x000852b5, + 0x0008637c, 0x00087443, 0x0008850a, 0x000895d1, + 0x0008a698, 0x0008b75f, 0x0008c826, 0x0008d8ed, + 0x0008e9b4, 0x0008fa7b, 0x00090b41, 0x00091c08, + 0x00092ccf, 0x00093d96, 0x00094e5d, 0x00095f24, + 0x00096feb, 0x000980b2, 0x00099179, 0x0009a240, + 0x0009b307, 0x0009c3ce, 0x0009d495, 0x0009e55c, + 0x0009f623, 0x000a06ea, 0x000a17b1, 0x000a2878, + 0x000a393f, 0x000a4a06, 0x000a5acd, 0x000a6b94, + 0x000a7c5b, 0x000a8d22, 0x000a9de9, 0x000aaeb0, + 0x000abf77, 0x000ad03e, 0x000ae105, 0x000af1cc, + 0x000b0292, 0x000b1359, 0x000b2420, 0x000b34e7, + 0x000b45ae, 0x000b5675, 0x000b673c, 0x000b7803, + 0x000b88ca, 0x000b9991, 0x000baa58, 0x000bbb1f, + 0x000bcbe6, 0x000bdcad, 0x000bed74, 0x000bfe3b, + 0x000c0f02, 0x000c1fc9, 0x000c3090, 0x000c4157, + 0x000c521e, 0x000c62e5, 0x000c73ac, 0x000c8473, + 0x000c953a, 0x000ca601, 0x000cb6c8, 0x000cc78f, + 0x000cd856, 0x000ce91d, 0x000cf9e4, 0x000d0aaa, + 0x000d1b71, 0x000d2c38, 0x000d3cff, 0x000d4dc6, + 0x000d5e8d, 0x000d6f54, 0x000d801b, 0x000d90e2, + 0x000da1a9, 0x000db270, 0x000dc337, 0x000dd3fe, + 0x000de4c5, 0x000df58c, 0x000e0653, 0x000e171a, + 0x000e27e1, 0x000e38a8, 0x000e496f, 0x000e5a36, + 0x000e6afd, 0x000e7bc4, 0x000e8c8b, 0x000e9d52, + 0x000eae19, 0x000ebee0, 0x000ecfa7, 0x000ee06e, + 0x000ef135, 0x000f01fb, 0x000f12c2, 0x000f2389, + 0x000f3450, 0x000f4517, 0x000f55de, 0x000f66a5, + 0x000f776c, 0x000f8833, 0x000f98fa, 0x000fa9c1, + 0x000fba88, 0x000fcb4f, 0x000fdc16, 0x000fecdd, + 0x000ffda4, 0x00100e6b, 0x00101f32, 0x00102ff9, + 0x001040c0, 0x00105187, 0x0010624e, 0x00107315, + 0x001083dc, 0x001094a3, 0x0010a56a, 0x0010b631, +}; + +u_long ustotsmid[256] = { + 0x00000000, 0x0010c6f8, 0x00218def, 0x003254e7, + 0x00431bde, 0x0053e2d6, 0x0064a9ce, 0x007570c5, + 0x008637bd, 0x0096feb4, 0x00a7c5ac, 0x00b88ca4, + 0x00c9539b, 0x00da1a93, 0x00eae18a, 0x00fba882, + 0x010c6f7a, 0x011d3671, 0x012dfd69, 0x013ec460, + 0x014f8b58, 0x01605250, 0x01711947, 0x0181e03f, + 0x0192a736, 0x01a36e2e, 0x01b43526, 0x01c4fc1d, + 0x01d5c315, 0x01e68a0c, 0x01f75104, 0x020817fc, + 0x0218def3, 0x0229a5eb, 0x023a6ce3, 0x024b33da, + 0x025bfad2, 0x026cc1c9, 0x027d88c1, 0x028e4fb9, + 0x029f16b0, 0x02afdda8, 0x02c0a49f, 0x02d16b97, + 0x02e2328f, 0x02f2f986, 0x0303c07e, 0x03148775, + 0x03254e6d, 0x03361565, 0x0346dc5c, 0x0357a354, + 0x03686a4b, 0x03793143, 0x0389f83b, 0x039abf32, + 0x03ab862a, 0x03bc4d21, 0x03cd1419, 0x03dddb11, + 0x03eea208, 0x03ff6900, 0x04102ff7, 0x0420f6ef, + 0x0431bde7, 0x044284de, 0x04534bd6, 0x046412cd, + 0x0474d9c5, 0x0485a0bd, 0x049667b4, 0x04a72eac, + 0x04b7f5a3, 0x04c8bc9b, 0x04d98393, 0x04ea4a8a, + 0x04fb1182, 0x050bd879, 0x051c9f71, 0x052d6669, + 0x053e2d60, 0x054ef458, 0x055fbb4f, 0x05708247, + 0x0581493f, 0x05921036, 0x05a2d72e, 0x05b39e25, + 0x05c4651d, 0x05d52c15, 0x05e5f30c, 0x05f6ba04, + 0x060780fb, 0x061847f3, 0x06290eeb, 0x0639d5e2, + 0x064a9cda, 0x065b63d2, 0x066c2ac9, 0x067cf1c1, + 0x068db8b8, 0x069e7fb0, 0x06af46a8, 0x06c00d9f, + 0x06d0d497, 0x06e19b8e, 0x06f26286, 0x0703297e, + 0x0713f075, 0x0724b76d, 0x07357e64, 0x0746455c, + 0x07570c54, 0x0767d34b, 0x07789a43, 0x0789613a, + 0x079a2832, 0x07aaef2a, 0x07bbb621, 0x07cc7d19, + 0x07dd4410, 0x07ee0b08, 0x07fed200, 0x080f98f7, + 0x08205fef, 0x083126e6, 0x0841edde, 0x0852b4d6, + 0x08637bcd, 0x087442c5, 0x088509bc, 0x0895d0b4, + 0x08a697ac, 0x08b75ea3, 0x08c8259b, 0x08d8ec92, + 0x08e9b38a, 0x08fa7a82, 0x090b4179, 0x091c0871, + 0x092ccf68, 0x093d9660, 0x094e5d58, 0x095f244f, + 0x096feb47, 0x0980b23e, 0x09917936, 0x09a2402e, + 0x09b30725, 0x09c3ce1d, 0x09d49514, 0x09e55c0c, + 0x09f62304, 0x0a06e9fb, 0x0a17b0f3, 0x0a2877ea, + 0x0a393ee2, 0x0a4a05da, 0x0a5accd1, 0x0a6b93c9, + 0x0a7c5ac1, 0x0a8d21b8, 0x0a9de8b0, 0x0aaeafa7, + 0x0abf769f, 0x0ad03d97, 0x0ae1048e, 0x0af1cb86, + 0x0b02927d, 0x0b135975, 0x0b24206d, 0x0b34e764, + 0x0b45ae5c, 0x0b567553, 0x0b673c4b, 0x0b780343, + 0x0b88ca3a, 0x0b999132, 0x0baa5829, 0x0bbb1f21, + 0x0bcbe619, 0x0bdcad10, 0x0bed7408, 0x0bfe3aff, + 0x0c0f01f7, 0x0c1fc8ef, 0x0c308fe6, 0x0c4156de, + 0x0c521dd5, 0x0c62e4cd, 0x0c73abc5, 0x0c8472bc, + 0x0c9539b4, 0x0ca600ab, 0x0cb6c7a3, 0x0cc78e9b, + 0x0cd85592, 0x0ce91c8a, 0x0cf9e381, 0x0d0aaa79, + 0x0d1b7171, 0x0d2c3868, 0x0d3cff60, 0x0d4dc657, + 0x0d5e8d4f, 0x0d6f5447, 0x0d801b3e, 0x0d90e236, + 0x0da1a92d, 0x0db27025, 0x0dc3371d, 0x0dd3fe14, + 0x0de4c50c, 0x0df58c03, 0x0e0652fb, 0x0e1719f3, + 0x0e27e0ea, 0x0e38a7e2, 0x0e496ed9, 0x0e5a35d1, + 0x0e6afcc9, 0x0e7bc3c0, 0x0e8c8ab8, 0x0e9d51b0, + 0x0eae18a7, 0x0ebedf9f, 0x0ecfa696, 0x0ee06d8e, + 0x0ef13486, 0x0f01fb7d, 0x0f12c275, 0x0f23896c, + 0x0f345064, 0x0f45175c, 0x0f55de53, 0x0f66a54b, + 0x0f776c42, 0x0f88333a, 0x0f98fa32, 0x0fa9c129, + 0x0fba8821, 0x0fcb4f18, 0x0fdc1610, 0x0fecdd08, + 0x0ffda3ff, 0x100e6af7, 0x101f31ee, 0x102ff8e6, + 0x1040bfde, 0x105186d5, 0x10624dcd, 0x107314c4, + 0x1083dbbc, 0x1094a2b4, 0x10a569ab, 0x10b630a3, +}; + +u_long ustotshi[16] = { + 0x00000000, 0x10c6f79a, 0x218def35, 0x3254e6cf, + 0x431bde6a, 0x53e2d604, 0x64a9cd9f, 0x7570c539, + 0x8637bcd3, 0x96feb46e, 0xa7c5ac08, 0xb88ca3a3, + 0xc9539b3d, 0xda1a92d7, 0xeae18a72, 0xfba8820c, +}; diff --git a/contrib/ntp/libntp/uglydate.c b/contrib/ntp/libntp/uglydate.c new file mode 100644 index 000000000000..fcd3d9f5cf96 --- /dev/null +++ b/contrib/ntp/libntp/uglydate.c @@ -0,0 +1,50 @@ +/* + * uglydate - convert a time stamp to something barely readable + * The string returned is 37 characters long. + */ +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "lib_strbuf.h" +#include "ntp_stdlib.h" +#ifndef TM_IN_SYS_TIME +#include +#endif + +char * +uglydate( + l_fp *ts + ) +{ + char *bp; + char *timep; + struct tm *tm; + time_t sec; + 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(&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.%03ld", + timep, year, tm->tm_yday, tm->tm_hour, tm->tm_min, + tm->tm_sec, msec); + return bp; +} diff --git a/contrib/ntp/libntp/uinttoa.c b/contrib/ntp/libntp/uinttoa.c new file mode 100644 index 000000000000..be48ea5146a6 --- /dev/null +++ b/contrib/ntp/libntp/uinttoa.c @@ -0,0 +1,20 @@ +/* + * uinttoa - return an asciized unsigned integer + */ +#include + +#include "lib_strbuf.h" +#include "ntp_stdlib.h" + +char * +uinttoa( + u_long uval + ) +{ + register char *buf; + + LIB_GETBUF(buf); + + (void) sprintf(buf, "%lu", (u_long)uval); + return buf; +} diff --git a/contrib/ntp/libntp/utvtoa.c b/contrib/ntp/libntp/utvtoa.c new file mode 100644 index 000000000000..79d14ef048e6 --- /dev/null +++ b/contrib/ntp/libntp/utvtoa.c @@ -0,0 +1,26 @@ +/* + * utvtoa - return an asciized representation of an unsigned struct timeval + */ +#include +#include + +#include "lib_strbuf.h" +#if defined(VMS) +#include "ntp_fp.h" +#endif +#include "ntp_stdlib.h" +#include "ntp_unixtime.h" + +char * +utvtoa( + const 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/ntp/libntp/ymd2yd.c b/contrib/ntp/libntp/ymd2yd.c new file mode 100644 index 000000000000..796ce40948bd --- /dev/null +++ b/contrib/ntp/libntp/ymd2yd.c @@ -0,0 +1,37 @@ +/* + * ymd2yd - compute the date in the year from y/m/d + */ + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +/* + * Tables to compute the day of year from yyyymmdd timecode. + * Viva la leap. + */ +static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +int +ymd2yd( + int y, + int m, + int d + ) +{ + int i, *t; + + if (m < 1 || m > 12 || d < 1) + return (-1); + + if (((y%4 == 0) && (y%100 != 0)) || (y%400 == 0)) + t = day2tab; /* leap year */ + else + t = day1tab; /* not a leap year */ + if (d > t[m - 1]) + return (-1); + for (i = 0; i < m - 1; i++) + d += t[i]; + return d; +} diff --git a/contrib/ntp/libparse/Makefile.am b/contrib/ntp/libparse/Makefile.am new file mode 100644 index 000000000000..c0f838b798a3 --- /dev/null +++ b/contrib/ntp/libparse/Makefile.am @@ -0,0 +1,93 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +# +# this is sick - i want the source to be compile with +# two time with different flags resulting different +# objects - still need to find a way to communicate +# that to automake/autoconf +# +# Frank Kardel +# +AUTOMAKE_OPTIONS = ../util/ansi2knr +noinst_LIBRARIES = @MAKE_LIBPARSE@ @MAKE_LIBPARSE_KERNEL@ +EXTRA_LIBRARIES = libparse.a libparse_kernel.a +EXTRA_PROGRAMS = parsestreams parsesolaris +noinst_PROGRAMS = @MAKE_PARSEKMODULE@ +CLEANFILES = libparse.a libparse_kernel.a + +libparse_a_SOURCES = parse.c \ + parse_conf.c \ + clk_meinberg.c \ + clk_schmid.c \ + clk_rawdcf.c \ + clk_trimtsip.c \ + clk_dcf7000.c \ + clk_trimtaip.c \ + clk_rcc8000.c \ + clk_hopf6021.c \ + clk_computime.c \ + clk_wharton.c \ + clk_varitext.c \ + data_mbg.c \ + info_trimble.c \ + trim_info.c + +libparse_kernel_a_SOURCES = kparse.c \ + kparse_conf.c \ + kclk_meinberg.c \ + kclk_schmid.c \ + kclk_rawdcf.c \ + kclk_trimtsip.c \ + kclk_dcf7000.c \ + kclk_trimtaip.c \ + kclk_rcc8000.c \ + kclk_hopf6021.c \ + kclk_computime.c \ + kclk_wharton.c \ + kclk_varitext.c + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/kernel +ETAGS_ARGS = Makefile.am + +EXTRA_DIST = parsesolaris.c parsestreams.c mkinfo_scmd.sed mkinfo_rcmd.sed info_trimble.c + +# +# create info_trimble.c +# +info_trimble.c: $(top_srcdir)/include/trimble.h mkinfo_rcmd.sed mkinfo_scmd.sed + @rm -f info_trimble.c + sed -n -f mkinfo_scmd.sed $(top_srcdir)/include/trimble.h > info_trimble.c || rm -f info_trimble.c + sed -n -f mkinfo_rcmd.sed $(top_srcdir)/include/trimble.h >> info_trimble.c || rm -f info_trimble.c + +# +# HACK following below... +# +kparse_conf.o: parse_conf.c +kparse.o: parse.c +kclk_rawdcf.o: clk_rawdcf.c +kclk_trimtsip.o: clk_trimtsip.c +kclk_meinberg.o: clk_meinberg.c +kclk_schmid.o: clk_schmid.c +kclk_rawdcf.o: clk_rawdcf.c +kclk_trimtsip.o: clk_trimtsip.c +kclk_dcf7000.o: clk_dcf7000.c +kclk_trimtaip.o: clk_trimtaip.c +kclk_rcc8000.o: clk_rcc8000.c +kclk_hopf6021.o: clk_hopf6021.c +kclk_computime.o: clk_computime.c +kclk_wharton.o: clk_wharton.c +kclk_varitext.o: clk_varitext.c + +parsestreams.loadable_module.o: $(parsestreams_OBJECTS) libparse_kernel.a ../libntp/libntp.a + $(LD) -r -o $@ $(parsestreams_OBJECTS) libparse_kernel.a ../libntp/libntp.a + +parse: $(parsesolaris_OBJECTS) libparse_kernel.a ../libntp/libntp.a + $(LD) -r -o $@ $(parsesolaris_OBJECTS) libparse_kernel.a ../libntp/libntp.a + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +parsesolaris.o: sys/systm.h + +sys/systm.h: + mkdir sys && \ + sed -e 's/ffs(long)/ffs(int)/' < /usr/include/sys/systm.h > sys/systm.h diff --git a/contrib/ntp/libparse/Makefile.in b/contrib/ntp/libparse/Makefile.in new file mode 100644 index 000000000000..44f3174fb255 --- /dev/null +++ b/contrib/ntp/libparse/Makefile.in @@ -0,0 +1,598 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +# +# this is sick - i want the source to be compile with +# two time with different flags resulting different +# objects - still need to find a way to communicate +# that to automake/autoconf +# +# Frank Kardel +# + + +AUTOMAKE_OPTIONS = ../util/ansi2knr +noinst_LIBRARIES = @MAKE_LIBPARSE@ @MAKE_LIBPARSE_KERNEL@ +EXTRA_LIBRARIES = libparse.a libparse_kernel.a +EXTRA_PROGRAMS = parsestreams parsesolaris +noinst_PROGRAMS = @MAKE_PARSEKMODULE@ +CLEANFILES = libparse.a libparse_kernel.a + +libparse_a_SOURCES = parse.c \ + parse_conf.c \ + clk_meinberg.c \ + clk_schmid.c \ + clk_rawdcf.c \ + clk_trimtsip.c \ + clk_dcf7000.c \ + clk_trimtaip.c \ + clk_rcc8000.c \ + clk_hopf6021.c \ + clk_computime.c \ + clk_wharton.c \ + clk_varitext.c \ + data_mbg.c \ + info_trimble.c \ + trim_info.c + + +libparse_kernel_a_SOURCES = kparse.c \ + kparse_conf.c \ + kclk_meinberg.c \ + kclk_schmid.c \ + kclk_rawdcf.c \ + kclk_trimtsip.c \ + kclk_dcf7000.c \ + kclk_trimtaip.c \ + kclk_rcc8000.c \ + kclk_hopf6021.c \ + kclk_computime.c \ + kclk_wharton.c \ + kclk_varitext.c + + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/kernel +ETAGS_ARGS = Makefile.am + +EXTRA_DIST = parsesolaris.c parsestreams.c mkinfo_scmd.sed mkinfo_rcmd.sed info_trimble.c +subdir = libparse +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +ANSI2KNR = ../util/ansi2knr +libparse_a_LIBADD = +am_libparse_a_OBJECTS = parse$U.o parse_conf$U.o clk_meinberg$U.o \ +clk_schmid$U.o clk_rawdcf$U.o clk_trimtsip$U.o clk_dcf7000$U.o \ +clk_trimtaip$U.o clk_rcc8000$U.o clk_hopf6021$U.o clk_computime$U.o \ +clk_wharton$U.o clk_varitext$U.o data_mbg$U.o info_trimble$U.o \ +trim_info$U.o +libparse_a_OBJECTS = $(am_libparse_a_OBJECTS) +libparse_kernel_a_LIBADD = +am_libparse_kernel_a_OBJECTS = kparse$U.o kparse_conf$U.o \ +kclk_meinberg$U.o kclk_schmid$U.o kclk_rawdcf$U.o kclk_trimtsip$U.o \ +kclk_dcf7000$U.o kclk_trimtaip$U.o kclk_rcc8000$U.o kclk_hopf6021$U.o \ +kclk_computime$U.o kclk_wharton$U.o kclk_varitext$U.o +libparse_kernel_a_OBJECTS = $(am_libparse_kernel_a_OBJECTS) +AR = ar +PROGRAMS = $(noinst_PROGRAMS) + +parsesolaris_SOURCES = parsesolaris.c +parsesolaris_OBJECTS = parsesolaris$U.o +parsesolaris_LDADD = $(LDADD) +parsesolaris_DEPENDENCIES = +parsesolaris_LDFLAGS = +parsestreams_SOURCES = parsestreams.c +parsestreams_OBJECTS = parsestreams$U.o +parsestreams_LDADD = $(LDADD) +parsestreams_DEPENDENCIES = +parsestreams_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libparse_a_SOURCES) $(libparse_kernel_a_SOURCES) \ +parsesolaris.c parsestreams.c +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +SOURCES = $(libparse_a_SOURCES) $(libparse_kernel_a_SOURCES) parsesolaris.c parsestreams.c +OBJECTS = $(am_libparse_a_OBJECTS) $(am_libparse_kernel_a_OBJECTS) parsesolaris$U.o parsestreams$U.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps libparse/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: +../util/ansi2knr: ../util/ansi2knr.o + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr + +../util/ansi2knr.o: + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o + + +mostlyclean-kr: + -rm -f *_.c + +clean-kr: + +distclean-kr: + +maintainer-clean-kr: +parse$U.o: +parse_conf$U.o: +clk_meinberg$U.o: +clk_schmid$U.o: +clk_rawdcf$U.o: +clk_trimtsip$U.o: +clk_dcf7000$U.o: +clk_trimtaip$U.o: +clk_rcc8000$U.o: +clk_hopf6021$U.o: +clk_computime$U.o: +clk_wharton$U.o: +clk_varitext$U.o: +data_mbg$U.o: +info_trimble$U.o: +trim_info$U.o: + +libparse.a: $(libparse_a_OBJECTS) $(libparse_a_DEPENDENCIES) + -rm -f libparse.a + $(AR) cru libparse.a $(libparse_a_OBJECTS) $(libparse_a_LIBADD) + $(RANLIB) libparse.a +kparse$U.o: +kparse_conf$U.o: +kclk_meinberg$U.o: +kclk_schmid$U.o: +kclk_rawdcf$U.o: +kclk_trimtsip$U.o: +kclk_dcf7000$U.o: +kclk_trimtaip$U.o: +kclk_rcc8000$U.o: +kclk_hopf6021$U.o: +kclk_computime$U.o: +kclk_wharton$U.o: +kclk_varitext$U.o: + +libparse_kernel.a: $(libparse_kernel_a_OBJECTS) $(libparse_kernel_a_DEPENDENCIES) + -rm -f libparse_kernel.a + $(AR) cru libparse_kernel.a $(libparse_kernel_a_OBJECTS) $(libparse_kernel_a_LIBADD) + $(RANLIB) libparse_kernel.a + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: +parsesolaris$U.o: + +parsesolaris: $(parsesolaris_OBJECTS) $(parsesolaris_DEPENDENCIES) + @rm -f parsesolaris + $(LINK) $(parsesolaris_LDFLAGS) $(parsesolaris_OBJECTS) $(parsesolaris_LDADD) $(LIBS) +parsestreams$U.o: + +parsestreams: $(parsestreams_OBJECTS) $(parsestreams_DEPENDENCIES) + @rm -f parsestreams + $(LINK) $(parsestreams_LDFLAGS) $(parsestreams_OBJECTS) $(parsestreams_LDADD) $(LIBS) +clk_computime_.c: clk_computime.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_computime.c; then echo $(srcdir)/clk_computime.c; else echo clk_computime.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_computime_.c +clk_dcf7000_.c: clk_dcf7000.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_dcf7000.c; then echo $(srcdir)/clk_dcf7000.c; else echo clk_dcf7000.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_dcf7000_.c +clk_hopf6021_.c: clk_hopf6021.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_hopf6021.c; then echo $(srcdir)/clk_hopf6021.c; else echo clk_hopf6021.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_hopf6021_.c +clk_meinberg_.c: clk_meinberg.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_meinberg.c; then echo $(srcdir)/clk_meinberg.c; else echo clk_meinberg.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_meinberg_.c +clk_rawdcf_.c: clk_rawdcf.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_rawdcf.c; then echo $(srcdir)/clk_rawdcf.c; else echo clk_rawdcf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_rawdcf_.c +clk_rcc8000_.c: clk_rcc8000.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_rcc8000.c; then echo $(srcdir)/clk_rcc8000.c; else echo clk_rcc8000.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_rcc8000_.c +clk_schmid_.c: clk_schmid.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_schmid.c; then echo $(srcdir)/clk_schmid.c; else echo clk_schmid.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_schmid_.c +clk_trimtaip_.c: clk_trimtaip.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_trimtaip.c; then echo $(srcdir)/clk_trimtaip.c; else echo clk_trimtaip.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_trimtaip_.c +clk_trimtsip_.c: clk_trimtsip.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_trimtsip.c; then echo $(srcdir)/clk_trimtsip.c; else echo clk_trimtsip.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_trimtsip_.c +clk_varitext_.c: clk_varitext.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_varitext.c; then echo $(srcdir)/clk_varitext.c; else echo clk_varitext.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_varitext_.c +clk_wharton_.c: clk_wharton.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/clk_wharton.c; then echo $(srcdir)/clk_wharton.c; else echo clk_wharton.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > clk_wharton_.c +data_mbg_.c: data_mbg.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/data_mbg.c; then echo $(srcdir)/data_mbg.c; else echo data_mbg.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > data_mbg_.c +info_trimble_.c: info_trimble.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/info_trimble.c; then echo $(srcdir)/info_trimble.c; else echo info_trimble.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > info_trimble_.c +kclk_computime_.c: kclk_computime.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_computime.c; then echo $(srcdir)/kclk_computime.c; else echo kclk_computime.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_computime_.c +kclk_dcf7000_.c: kclk_dcf7000.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_dcf7000.c; then echo $(srcdir)/kclk_dcf7000.c; else echo kclk_dcf7000.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_dcf7000_.c +kclk_hopf6021_.c: kclk_hopf6021.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_hopf6021.c; then echo $(srcdir)/kclk_hopf6021.c; else echo kclk_hopf6021.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_hopf6021_.c +kclk_meinberg_.c: kclk_meinberg.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_meinberg.c; then echo $(srcdir)/kclk_meinberg.c; else echo kclk_meinberg.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_meinberg_.c +kclk_rawdcf_.c: kclk_rawdcf.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_rawdcf.c; then echo $(srcdir)/kclk_rawdcf.c; else echo kclk_rawdcf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_rawdcf_.c +kclk_rcc8000_.c: kclk_rcc8000.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_rcc8000.c; then echo $(srcdir)/kclk_rcc8000.c; else echo kclk_rcc8000.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_rcc8000_.c +kclk_schmid_.c: kclk_schmid.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_schmid.c; then echo $(srcdir)/kclk_schmid.c; else echo kclk_schmid.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_schmid_.c +kclk_trimtaip_.c: kclk_trimtaip.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_trimtaip.c; then echo $(srcdir)/kclk_trimtaip.c; else echo kclk_trimtaip.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_trimtaip_.c +kclk_trimtsip_.c: kclk_trimtsip.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_trimtsip.c; then echo $(srcdir)/kclk_trimtsip.c; else echo kclk_trimtsip.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_trimtsip_.c +kclk_varitext_.c: kclk_varitext.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_varitext.c; then echo $(srcdir)/kclk_varitext.c; else echo kclk_varitext.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_varitext_.c +kclk_wharton_.c: kclk_wharton.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kclk_wharton.c; then echo $(srcdir)/kclk_wharton.c; else echo kclk_wharton.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kclk_wharton_.c +kparse_.c: kparse.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kparse.c; then echo $(srcdir)/kparse.c; else echo kparse.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kparse_.c +kparse_conf_.c: kparse_conf.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kparse_conf.c; then echo $(srcdir)/kparse_conf.c; else echo kparse_conf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kparse_conf_.c +parse_.c: parse.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/parse.c; then echo $(srcdir)/parse.c; else echo parse.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > parse_.c +parse_conf_.c: parse_conf.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/parse_conf.c; then echo $(srcdir)/parse_conf.c; else echo parse_conf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > parse_conf_.c +parsesolaris_.c: parsesolaris.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/parsesolaris.c; then echo $(srcdir)/parsesolaris.c; else echo parsesolaris.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > parsesolaris_.c +parsestreams_.c: parsestreams.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/parsestreams.c; then echo $(srcdir)/parsestreams.c; else echo parsestreams.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > parsestreams_.c +trim_info_.c: trim_info.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/trim_info.c; then echo $(srcdir)/trim_info.c; else echo trim_info.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > trim_info_.c +clk_computime_.o clk_dcf7000_.o clk_hopf6021_.o clk_meinberg_.o \ +clk_rawdcf_.o clk_rcc8000_.o clk_schmid_.o clk_trimtaip_.o \ +clk_trimtsip_.o clk_varitext_.o clk_wharton_.o data_mbg_.o \ +info_trimble_.o kclk_computime_.o kclk_dcf7000_.o kclk_hopf6021_.o \ +kclk_meinberg_.o kclk_rawdcf_.o kclk_rcc8000_.o kclk_schmid_.o \ +kclk_trimtaip_.o kclk_trimtsip_.o kclk_varitext_.o kclk_wharton_.o \ +kparse_.o kparse_conf_.o parse_.o parse_conf_.o parsesolaris_.o \ +parsestreams_.o trim_info_.o : $(ANSI2KNR) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +clk_computime.o clk_computime.lo: clk_computime.c ../config.h +clk_dcf7000.o clk_dcf7000.lo: clk_dcf7000.c ../config.h +clk_hopf6021.o clk_hopf6021.lo: clk_hopf6021.c ../config.h +clk_meinberg.o clk_meinberg.lo: clk_meinberg.c ../config.h +clk_rawdcf.o clk_rawdcf.lo: clk_rawdcf.c ../config.h +clk_rcc8000.o clk_rcc8000.lo: clk_rcc8000.c ../config.h +clk_schmid.o clk_schmid.lo: clk_schmid.c ../config.h +clk_trimtaip.o clk_trimtaip.lo: clk_trimtaip.c ../config.h +clk_trimtsip.o clk_trimtsip.lo: clk_trimtsip.c ../config.h +clk_varitext.o clk_varitext.lo: clk_varitext.c ../config.h +clk_wharton.o clk_wharton.lo: clk_wharton.c ../config.h +data_mbg.o data_mbg.lo: data_mbg.c ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h ../include/ntp_fp.h \ + ../include/mbg_gps166.h ../include/binio.h \ + ../include/ieee754io.h +info_trimble.o info_trimble.lo: info_trimble.c ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntpd.h ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp.h ../include/ntp_malloc.h \ + ../include/ntp_refclock.h ../include/recvbuff.h \ + ../include/trimble.h +kclk_computime.o kclk_computime.lo: kclk_computime.c clk_computime.c \ + ../config.h +kclk_dcf7000.o kclk_dcf7000.lo: kclk_dcf7000.c clk_dcf7000.c ../config.h +kclk_hopf6021.o kclk_hopf6021.lo: kclk_hopf6021.c clk_hopf6021.c \ + ../config.h +kclk_meinberg.o kclk_meinberg.lo: kclk_meinberg.c clk_meinberg.c \ + ../config.h +kclk_rawdcf.o kclk_rawdcf.lo: kclk_rawdcf.c clk_rawdcf.c ../config.h +kclk_rcc8000.o kclk_rcc8000.lo: kclk_rcc8000.c clk_rcc8000.c ../config.h +kclk_schmid.o kclk_schmid.lo: kclk_schmid.c clk_schmid.c ../config.h +kclk_trimtaip.o kclk_trimtaip.lo: kclk_trimtaip.c clk_trimtaip.c \ + ../config.h +kclk_trimtsip.o kclk_trimtsip.lo: kclk_trimtsip.c clk_trimtsip.c \ + ../config.h +kclk_varitext.o kclk_varitext.lo: kclk_varitext.c clk_varitext.c \ + ../config.h +kclk_wharton.o kclk_wharton.lo: kclk_wharton.c clk_wharton.c ../config.h +kparse.o kparse.lo: kparse.c parse.c ../config.h +kparse_conf.o kparse_conf.lo: kparse_conf.c parse_conf.c ../config.h +parse.o parse.lo: parse.c ../config.h +parse_conf.o parse_conf.lo: parse_conf.c ../config.h +parsesolaris.o parsesolaris.lo: parsesolaris.c sys/systm.h \ + ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/parse.h ../include/parse_conf.h \ + ../kernel/sys/parsestreams.h ../kernel/sys/ppsclock.h \ + ../include/ntp_string.h + +trim_info.o trim_info.lo: trim_info.c ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/trimble.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-kr mostlyclean-noinstPROGRAMS \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-kr \ + clean-noinstPROGRAMS clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile distclean-kr \ + distclean-noinstPROGRAMS distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-kr \ + maintainer-clean-noinstPROGRAMS maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-kr distclean-kr clean-kr \ +maintainer-clean-kr mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS tags \ +mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \ +distdir info-am info dvi-am dvi check check-am installcheck-am \ +installcheck install-exec-am install-exec install-data-am install-data \ +install-am install uninstall-am uninstall all-redirect all-am all \ +install-strip installdirs mostlyclean-generic distclean-generic \ +clean-generic maintainer-clean-generic clean mostlyclean distclean \ +maintainer-clean + + +# +# create info_trimble.c +# +info_trimble.c: $(top_srcdir)/include/trimble.h mkinfo_rcmd.sed mkinfo_scmd.sed + @rm -f info_trimble.c + sed -n -f mkinfo_scmd.sed $(top_srcdir)/include/trimble.h > info_trimble.c || rm -f info_trimble.c + sed -n -f mkinfo_rcmd.sed $(top_srcdir)/include/trimble.h >> info_trimble.c || rm -f info_trimble.c + +# +# HACK following below... +# +kparse_conf.o: parse_conf.c +kparse.o: parse.c +kclk_rawdcf.o: clk_rawdcf.c +kclk_trimtsip.o: clk_trimtsip.c +kclk_meinberg.o: clk_meinberg.c +kclk_schmid.o: clk_schmid.c +kclk_rawdcf.o: clk_rawdcf.c +kclk_trimtsip.o: clk_trimtsip.c +kclk_dcf7000.o: clk_dcf7000.c +kclk_trimtaip.o: clk_trimtaip.c +kclk_rcc8000.o: clk_rcc8000.c +kclk_hopf6021.o: clk_hopf6021.c +kclk_computime.o: clk_computime.c +kclk_wharton.o: clk_wharton.c +kclk_varitext.o: clk_varitext.c + +parsestreams.loadable_module.o: $(parsestreams_OBJECTS) libparse_kernel.a ../libntp/libntp.a + $(LD) -r -o $@ $(parsestreams_OBJECTS) libparse_kernel.a ../libntp/libntp.a + +parse: $(parsesolaris_OBJECTS) libparse_kernel.a ../libntp/libntp.a + $(LD) -r -o $@ $(parsesolaris_OBJECTS) libparse_kernel.a ../libntp/libntp.a + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +parsesolaris.o: sys/systm.h + +sys/systm.h: + mkdir sys && \ + sed -e 's/ffs(long)/ffs(int)/' < /usr/include/sys/systm.h > sys/systm.h + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/libparse/README b/contrib/ntp/libparse/README new file mode 100644 index 000000000000..3484f9a935b3 --- /dev/null +++ b/contrib/ntp/libparse/README @@ -0,0 +1,96 @@ +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). + + SunOS4 (aka Solaris 1.x): + parsestreams.loadable_module.o - standard parse module for SunOS 4 + + Both modules can be loaded via modload . + + SunOS5 (aka Solaris 2.x): + parse - auto loadable streams module + + 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 the mode parameter. 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 + loopfilter. 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/ntp/libparse/clk_computime.c b/contrib/ntp/libparse/clk_computime.c new file mode 100644 index 000000000000..8e050c00fcad --- /dev/null +++ b/contrib/ntp/libparse/clk_computime.c @@ -0,0 +1,194 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_COMPUTIME) +/* + * /src/NTP/ntp-4/libparse/clk_computime.c,v 4.5 1998/06/14 21:09:34 kardel RELEASE_19990228_A + * + * clk_computime.c,v 4.5 1998/06/14 21:09:34 kardel RELEASE_19990228_A + * + * Supports Diem's Computime Radio Clock + * + * Used the Meinberg clock as a template for Diem's Computime Radio Clock + * + * adapted by Alois Camenzind + * + * Copyright (C) 1992-1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * 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 +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +#include "parse.h" + +#ifndef PARSESTREAM +#include +#else +#include "sys/parsestreams.h" +extern void printf P((const char *, ...)); +#endif + +/* + * The Computime receiver sends a datagram in the following format every minute + * + * Timestamp T:YY:MM:MD:WD:HH:MM:SSCRLF + * Pos 0123456789012345678901 2 3 + * 0000000000111111111122 2 2 + * Parse T: : : : : : : rn + * + * T Startcharacter "T" specifies start of the timestamp + * YY Year MM Month 1-12 + * MD Day of the month + * WD Day of week + * HH Hour + * MM Minute + * SS Second + * CR Carriage return + * LF Linefeed + * + */ + +static struct format computime_fmt = +{ + { + {8, 2}, {5, 2}, {2, 2}, /* day, month, year */ + {14, 2}, {17, 2}, {20, 2}, /* hour, minute, second */ + {11, 2}, /* dayofweek, */ + }, + (const unsigned char *)"T: : : : : : : \r\n", + 0 +}; + +static u_long cvt_computime P((unsigned char *, int, struct format *, clocktime_t *, void *)); +static unsigned long inp_computime P((parse_t *, unsigned int, timestamp_t *)); + +clockformat_t clock_computime = +{ + inp_computime, /* Computime input handling */ + cvt_computime, /* Computime conversion */ + 0, /* no PPS monitoring */ + (void *)&computime_fmt, /* conversion configuration */ + "Diem's Computime Radio Clock", /* Computime Radio Clock */ + 24, /* string buffer */ + 0 /* no private data (complete pakets) */ +}; + +/* + * cvt_computime + * + * convert simple type format + */ +static u_long +cvt_computime( + unsigned char *buffer, + int size, + struct format *format, + clocktime_t *clock_time, + void *local + ) +{ + + if (!Strok(buffer, format->fixed_string)) { + return CVT_NONE; + } else { + if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day, + format->field_offsets[O_DAY].length) || + Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month, + format->field_offsets[O_MONTH].length) || + Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year, + format->field_offsets[O_YEAR].length) || + Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour, + format->field_offsets[O_HOUR].length) || + Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute, + format->field_offsets[O_MIN].length) || + Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second, + format->field_offsets[O_SEC].length)) { + return CVT_FAIL | CVT_BADFMT; + } else { + + clock_time->flags = 0; + clock_time->utcoffset = 0; /* We have UTC time */ + + return CVT_OK; + } + } +} + +/* + * inp_computime + * + * grep data from input stream + */ +static u_long +inp_computime( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + unsigned int rtc; + + parseprintf(DD_PARSE, ("inp_computime(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + switch (ch) + { + case 'T': + parseprintf(DD_PARSE, ("inp_computime: START seen\n")); + + parseio->parse_index = 1; + parseio->parse_data[0] = ch; + parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ + return PARSE_INP_SKIP; + + case '\n': + parseprintf(DD_PARSE, ("inp_computime: END seen\n")); + if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) + return parse_end(parseio); + else + return rtc; + + default: + return parse_addchar(parseio, ch); + } +} + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_COMPUTIME) */ +int clk_computime_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_COMPUTIME) */ + +/* + * clk_computime.c,v + * Revision 4.5 1998/06/14 21:09:34 kardel + * Sun acc cleanup + * + * Revision 4.4 1998/06/13 12:00:38 kardel + * fix SYSV clock name clash + * + * Revision 4.3 1998/06/12 15:22:26 kardel + * fix prototypes + * + * Revision 4.2 1998/06/12 09:13:24 kardel + * conditional compile macros fixed + * printf prototype + * + * Revision 4.1 1998/05/24 09:39:51 kardel + * implementation of the new IO handling model + * + * Revision 4.0 1998/04/10 19:45:27 kardel + * Start 4.0 release version numbering + * + * from V3 1.8 log info deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/libparse/clk_dcf7000.c b/contrib/ntp/libparse/clk_dcf7000.c new file mode 100644 index 000000000000..845b46716d08 --- /dev/null +++ b/contrib/ntp/libparse/clk_dcf7000.c @@ -0,0 +1,188 @@ +/* + * /src/NTP/ntp-4/libparse/clk_dcf7000.c,v 4.5 1998/06/14 21:09:34 kardel RELEASE_19990228_A + * + * clk_dcf7000.c,v 4.5 1998/06/14 21:09:34 kardel RELEASE_19990228_A + * + * ELV DCF7000 module + * + * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_DCF7000) + +#include +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +#ifndef PARSESTREAM +#include "ntp_stdlib.h" +#include +#else +#include "sys/parsestreams.h" +extern void printf P((const char *, ...)); +#endif + +static struct format dcf7000_fmt = +{ /* ELV DCF7000 */ + { + { 6, 2}, { 3, 2}, { 0, 2}, + { 12, 2}, { 15, 2}, { 18, 2}, + { 9, 2}, { 21, 2}, + }, + (const unsigned char *)" - - - - - - - \r", + 0 +}; +static u_long cvt_dcf7000 P((unsigned char *, int, struct format *, clocktime_t *, void *)); +static unsigned long inp_dcf7000 P((parse_t *, unsigned int, timestamp_t *)); + +clockformat_t clock_dcf7000 = +{ + inp_dcf7000, /* DCF7000 input handling */ + cvt_dcf7000, /* ELV DCF77 conversion */ + 0, /* no direct PPS monitoring */ + (void *)&dcf7000_fmt, /* conversion configuration */ + "ELV DCF7000", /* ELV clock */ + 24, /* string buffer */ + 0 /* no private data (complete pakets) */ +}; + +/* + * cvt_dcf7000 + * + * convert dcf7000 type format + */ +static u_long +cvt_dcf7000( + unsigned char *buffer, + int size, + struct format *format, + clocktime_t *clock_time, + void *local + ) +{ + if (!Strok(buffer, format->fixed_string)) + { + return CVT_NONE; + } + else + { + if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day, + format->field_offsets[O_DAY].length) || + Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month, + format->field_offsets[O_MONTH].length) || + Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year, + format->field_offsets[O_YEAR].length) || + Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour, + format->field_offsets[O_HOUR].length) || + Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute, + format->field_offsets[O_MIN].length) || + Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second, + format->field_offsets[O_SEC].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + else + { + unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset]; + long flags; + + clock_time->flags = 0; + clock_time->usecond = 0; + + if (Stoi(f, &flags, format->field_offsets[O_FLAGS].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + else + { + if (flags & 0x1) + clock_time->utcoffset = -2*60*60; + else + clock_time->utcoffset = -1*60*60; + + if (flags & 0x2) + clock_time->flags |= PARSEB_ANNOUNCE; + + if (flags & 0x4) + clock_time->flags |= PARSEB_NOSYNC; + } + return CVT_OK; + } + } +} + +/* + * inp_dcf700 + * + * grep data from input stream + */ +static u_long +inp_dcf7000( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + unsigned int rtc; + + parseprintf(DD_PARSE, ("inp_dcf7000(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + switch (ch) + { + case '\r': + parseprintf(DD_PARSE, ("inp_dcf7000: EOL seen\n")); + parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ + if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) + return parse_end(parseio); + else + return rtc; + + default: + return parse_addchar(parseio, ch); + } +} + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_DCF7000) */ +int clk_dcf7000_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_DCF7000) */ + +/* + * History: + * + * clk_dcf7000.c,v + * Revision 4.5 1998/06/14 21:09:34 kardel + * Sun acc cleanup + * + * Revision 4.4 1998/06/13 12:01:59 kardel + * fix SYSV clock name clash + * + * Revision 4.3 1998/06/12 15:22:27 kardel + * fix prototypes + * + * Revision 4.2 1998/06/12 09:13:24 kardel + * conditional compile macros fixed + * printf prototype + * + * Revision 4.1 1998/05/24 09:39:51 kardel + * implementation of the new IO handling model + * + * Revision 4.0 1998/04/10 19:45:28 kardel + * Start 4.0 release version numbering + * + * from V3 3.18 log info deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/libparse/clk_hopf6021.c b/contrib/ntp/libparse/clk_hopf6021.c new file mode 100644 index 000000000000..06efc6ff6dc2 --- /dev/null +++ b/contrib/ntp/libparse/clk_hopf6021.c @@ -0,0 +1,280 @@ +/* + * /src/NTP/ntp-4/libparse/clk_hopf6021.c,v 4.6 1998/11/15 20:27:57 kardel RELEASE_19990228_A + * + * clk_hopf6021.c,v 4.6 1998/11/15 20:27:57 kardel RELEASE_19990228_A + * + * Radiocode Clocks HOPF Funkuhr 6021 mit serieller Schnittstelle + * base code version from 24th Nov 1995 - history at end + * + * Created by F.Schnekenbuehl from clk_rcc8000.c + * Nortel DASA Network Systems GmbH, Department: ND250 + * A Joint venture of Daimler-Benz Aerospace and Nortel + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_HOPF6021) + +#include +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" +#include "ascii.h" + +#include "parse.h" + +#ifndef PARSESTREAM +#include "ntp_stdlib.h" +#include +#else +#include "sys/parsestreams.h" +extern void printf P((const char *, ...)); +#endif + +/* + * hopf Funkuhr 6021 + * used with 9600,8N1, + * UTC ueber serielle Schnittstelle + * Sekundenvorlauf ON + * ETX zum Sekundenvorlauf ON + * Datenstring 6021 + * Ausgabe Uhrzeit und Datum + * Senden mit Steuerzeichen + * Senden sekuendlich + */ + +/* + * Type 6021 Serial Output format + * + * 000000000011111111 / char + * 012345678901234567 \ position + * sABHHMMSSDDMMYYnre Actual + * C4110046231195 Parse + * s enr Check + * + * s = STX (0x02), e = ETX (0x03) + * n = NL (0x0A), r = CR (0x0D) + * + * A B - Status and weekday + * + * A - Status + * + * 8 4 2 1 + * x x x 0 - no announcement + * x x x 1 - Summertime - wintertime - summertime announcement + * x x 0 x - Wintertime + * x x 1 x - Summertime + * 0 0 x x - Time/Date invalid + * 0 1 x x - Internal clock used + * 1 0 x x - Radio clock + * 1 1 x x - Radio clock highprecision + * + * B - 8 4 2 1 + * 0 x x x - MESZ/MEZ + * 1 x x x - UTC + * x 0 0 1 - Monday + * x 0 1 0 - Tuesday + * x 0 1 1 - Wednesday + * x 1 0 0 - Thursday + * x 1 0 1 - Friday + * x 1 1 0 - Saturday + * x 1 1 1 - Sunday + */ + +#define HOPF_DSTWARN 0x01 /* DST switch warning */ +#define HOPF_DST 0x02 /* DST in effect */ + +#define HOPF_MODE 0x0C /* operation mode mask */ +#define HOPF_INVALID 0x00 /* no time code available */ +#define HOPF_INTERNAL 0x04 /* internal clock */ +#define HOPF_RADIO 0x08 /* radio clock */ +#define HOPF_RADIOHP 0x0C /* high precision radio clock */ + +#define HOPF_UTC 0x08 /* time code in UTC */ +#define HOPF_WMASK 0x07 /* mask for weekday code */ + +static struct format hopf6021_fmt = +{ + { + { 9, 2 }, {11, 2}, { 13, 2}, /* Day, Month, Year */ + { 3, 2 }, { 5, 2}, { 7, 2}, /* Hour, Minute, Second */ + { 2, 1 }, { 1, 1}, { 0, 0}, /* Weekday, Flags, Zone */ + /* ... */ + }, + (const unsigned char *)"\002 \n\r\003", + 0 +}; + +#define OFFS(x) format->field_offsets[(x)].offset +#define STOI(x, y) Stoi(&buffer[OFFS(x)], y, format->field_offsets[(x)].length) +#define hexval(x) (('0' <= (x) && (x) <= '9') ? (x) - '0' : \ + ('a' <= (x) && (x) <= 'f') ? (x) - 'a' + 10 : \ + ('A' <= (x) && (x) <= 'F') ? (x) - 'A' + 10 : \ + -1) + +static unsigned long cvt_hopf6021 P((unsigned char *, int, struct format *, clocktime_t *, void *)); +static unsigned long inp_hopf6021 P((parse_t *, unsigned int, timestamp_t *)); + +clockformat_t clock_hopf6021 = +{ + inp_hopf6021, /* HOPF 6021 input handling */ + cvt_hopf6021, /* Radiocode clock conversion */ + 0, /* no direct PPS monitoring */ + (void *)&hopf6021_fmt, /* conversion configuration */ + "hopf Funkuhr 6021", /* clock format name */ + 19, /* string buffer */ + 0 /* private data length, no private data */ +}; + +static unsigned long +cvt_hopf6021( + unsigned char *buffer, + int size, + struct format *format, + clocktime_t *clock_time, + void *local + ) +{ + unsigned char status,weekday; + + if (!Strok(buffer, format->fixed_string)) + { + return CVT_NONE; + } + + if ( STOI(O_DAY, &clock_time->day) || + STOI(O_MONTH, &clock_time->month) || + STOI(O_YEAR, &clock_time->year) || + STOI(O_HOUR, &clock_time->hour) || + STOI(O_MIN, &clock_time->minute) || + STOI(O_SEC, &clock_time->second) + ) + { + return CVT_FAIL|CVT_BADFMT; + } + + clock_time->usecond = 0; + clock_time->utcoffset = 0; + + status = hexval(buffer[OFFS(O_FLAGS)]); + weekday= hexval(buffer[OFFS(O_WDAY)]); + + if ((status == 0xFF) || (weekday == 0xFF)) + { + return CVT_FAIL|CVT_BADFMT; + } + + clock_time->flags = 0; + + if (weekday & HOPF_UTC) + { + clock_time->flags |= PARSEB_UTC; + } + else + { + if (status & HOPF_DST) + { + clock_time->flags |= PARSEB_DST; + clock_time->utcoffset = -2*60*60; /* MET DST */ + } + else + { + clock_time->utcoffset = -1*60*60; /* MET */ + } + } + + clock_time->flags |= (status & HOPF_DSTWARN) ? PARSEB_ANNOUNCE : 0; + + switch (status & HOPF_MODE) + { + case HOPF_INVALID: /* Time/Date invalid */ + clock_time->flags |= PARSEB_POWERUP; + break; + + case HOPF_INTERNAL: /* internal clock */ + clock_time->flags |= PARSEB_NOSYNC; + break; + + case HOPF_RADIO: /* Radio clock */ + case HOPF_RADIOHP: /* Radio clock high precision */ + break; + + default: + return CVT_FAIL|CVT_BADFMT; + } + + return CVT_OK; +} + +/* + * inp_hopf6021 + * + * grep data from input stream + */ +static u_long +inp_hopf6021( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + unsigned int rtc; + + parseprintf(DD_PARSE, ("inp_hopf6021(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + switch (ch) + { + case ETX: + parseprintf(DD_PARSE, ("inp_hopf6021: EOL seen\n")); + parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ + if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) + return parse_end(parseio); + else + return rtc; + + default: + return parse_addchar(parseio, ch); + } +} + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_HOPF6021) */ +int clk_hopf6021_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_HOPF6021) */ + +/* + * History: + * + * clk_hopf6021.c,v + * Revision 4.6 1998/11/15 20:27:57 kardel + * Release 4.0.73e13 reconcilation + * + * Revision 4.5 1998/06/14 21:09:35 kardel + * Sun acc cleanup + * + * Revision 4.4 1998/06/13 12:02:38 kardel + * fix SYSV clock name clash + * + * Revision 4.3 1998/06/12 15:22:27 kardel + * fix prototypes + * + * Revision 4.2 1998/06/12 09:13:25 kardel + * conditional compile macros fixed + * printf prototype + * + * Revision 4.1 1998/05/24 09:39:52 kardel + * implementation of the new IO handling model + * + * Revision 4.0 1998/04/10 19:45:29 kardel + * Start 4.0 release version numbering + * + * from V3 3.6 log info deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/libparse/clk_meinberg.c b/contrib/ntp/libparse/clk_meinberg.c new file mode 100644 index 000000000000..fdffa1bf33c6 --- /dev/null +++ b/contrib/ntp/libparse/clk_meinberg.c @@ -0,0 +1,747 @@ +/* + * /src/NTP/ntp-4/libparse/clk_meinberg.c,v 4.7 1999/02/21 11:09:14 kardel RELEASE_19990228_A + * + * clk_meinberg.c,v 4.7 1999/02/21 11:09:14 kardel RELEASE_19990228_A + * + * Meinberg clock support + * + * Copyright (C) 1995-1999 by Frank Kardel + * Copyright (C) 1992-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_MEINBERG) + +#include +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "ntp_machine.h" + +#include "parse.h" + +#ifndef PARSESTREAM +#include +#else +#include "sys/parsestreams.h" +#endif + +#include "ntp_stdlib.h" + +#include "ntp_stdlib.h" + +#include "mbg_gps166.h" +#include "binio.h" +#include "ascii.h" + +/* + * The Meinberg receiver every second sends a datagram of the following form + * (Standard Format) + * + * D:
    ..;T:;U:::; + * pos: 0 00 00 0 00 0 11 111 1 111 12 2 22 2 22 2 2 2 3 3 3 + * 1 23 45 6 78 9 01 234 5 678 90 1 23 4 56 7 8 9 0 1 2 + * = '\002' ASCII start of text + * = '\003' ASCII end of text + *
    ,, = day, month, year(2 digits!!) + * = day of week (sunday= 0) + * ,, = hour, minute, second + * = '#' if never synced since powerup for DCF C51 + * = '#' if not PZF sychronisation available for PZF 535/509 + * = ' ' if ok + * = '*' if time comes from internal quartz + * = ' ' if completely synched + * = 'S' if daylight saving time is active + * = 'U' if time is represented in UTC + * = ' ' if no special condition exists + * = '!' during the hour preceeding an daylight saving time + * start/end change + * = 'A' leap second insert warning + * = ' ' if no special condition exists + * + * Extended data format (PZFUERL for PZF type clocks) + * + *
    ..; ; ::; + * pos: 0 00 0 00 0 00 11 1 11 11 1 11 2 22 22 2 2 2 2 2 3 3 3 + * 1 23 4 56 7 89 01 2 34 56 7 89 0 12 34 5 6 7 8 9 0 1 2 + * = '\002' ASCII start of text + * = '\003' ASCII end of text + *
    ,, = day, month, year(2 digits!!) + * = day of week (sunday= 0) + * ,, = hour, minute, second + * = 'U' UTC time display + * = '#' if never synced since powerup else ' ' for DCF C51 + * '#' if not PZF sychronisation available else ' ' for PZF 535/509 + * = '*' if time comes from internal quartz else ' ' + * = 'S' if daylight saving time is active else ' ' + * = '!' during the hour preceeding an daylight saving time + * start/end change + * = 'A' LEAP second announcement + * = 'R' alternate antenna + * + * Meinberg GPS166 receiver + * + * You must get the Uni-Erlangen firmware for the GPS receiver support + * to work to full satisfaction ! + * + *
    ..; ; ::; <+/-><00:00>; ; + * + * 000000000111111111122222222223333333333444444444455555555556666666 + * 123456789012345678901234567890123456789012345678901234567890123456 + * \x0209.07.93; 5; 08:48:26; +00:00; #*S!A L; 49.5736N 11.0280E 373m\x03 + * + * + * = '\002' ASCII start of text + * = '\003' ASCII end of text + *
    ,, = day, month, year(2 digits!!) + * = day of week (sunday= 0) + * ,, = hour, minute, second + * <+/->,<00:00> = offset to UTC + * = '#' if never synced since powerup else ' ' + * = '*' if position is not confirmed else ' ' + * = 'S' if daylight saving time is active else ' ' + * = '!' during the hour preceeding an daylight saving time + * start/end change + * = 'A' LEAP second announcement + * = 'R' alternate antenna (reminiscent of PZF535) usually ' ' + * = 'L' on 23:59:60 + * + * Binary messages have a lead in for a fixed header of SOH + */ + +/*--------------------------------------------------------------*/ +/* Name: csum() */ +/* */ +/* Purpose: Compute a checksum about a number of bytes */ +/* */ +/* Input: uchar *p address of the first byte */ +/* short n the number of bytes */ +/* */ +/* Output: -- */ +/* */ +/* Ret val: the checksum */ +/*+-------------------------------------------------------------*/ + +unsigned long +mbg_csum( + unsigned char *p, + unsigned int n + ) +{ + unsigned long sum = 0; + short i; + + for ( i = 0; i < n; i++ ) + sum += *p++; + + return( sum ); +} /* csum */ + +void +get_mbg_header( + unsigned char **bufpp, + GPS_MSG_HDR *headerp + ) +{ + headerp->gps_cmd = get_lsb_short(bufpp); + headerp->gps_len = get_lsb_short(bufpp); + headerp->gps_data_csum = get_lsb_short(bufpp); + headerp->gps_hdr_csum = get_lsb_short(bufpp); +} + +static struct format meinberg_fmt[] = +{ + { + { + { 3, 2}, { 6, 2}, { 9, 2}, + { 18, 2}, { 21, 2}, { 24, 2}, + { 14, 1}, { 27, 4}, { 29, 1}, + }, + (const unsigned char *)"\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}, + }, + (const unsigned char *)"\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, 7}, { 35, 1}, + { 25, 2}, { 28, 2}, { 24, 1} + }, + (const unsigned char *)"\2 . . ; ; : : ; : ; ; . . ", + 0 + } +}; + +static u_long cvt_meinberg P((unsigned char *, int, struct format *, clocktime_t *, void *)); +static u_long cvt_mgps P((unsigned char *, int, struct format *, clocktime_t *, void *)); +static u_long mbg_input P((parse_t *, unsigned int, timestamp_t *)); +static u_long gps_input P((parse_t *, unsigned int, timestamp_t *)); + +struct msg_buf +{ + unsigned short len; /* len to fill */ + unsigned short phase; /* current input phase */ +}; + +#define MBG_NONE 0 /* no data input */ +#define MBG_HEADER 1 /* receiving header */ +#define MBG_DATA 2 /* receiving data */ +#define MBG_STRING 3 /* receiving standard data message */ + +clockformat_t clock_meinberg[] = +{ + { + mbg_input, /* normal input handling */ + cvt_meinberg, /* Meinberg conversion */ + pps_one, /* easy PPS monitoring */ + 0, /* conversion configuration */ + "Meinberg Standard", /* Meinberg simple format - beware */ + 32, /* string buffer */ + 0 /* no private data (complete pakets) */ + }, + { + mbg_input, /* normal input handling */ + cvt_meinberg, /* Meinberg conversion */ + pps_one, /* easy PPS monitoring */ + 0, /* conversion configuration */ + "Meinberg Extended", /* Meinberg enhanced format */ + 32, /* string buffer */ + 0 /* no private data (complete pakets) */ + }, + { + gps_input, /* no input handling */ + cvt_mgps, /* Meinberg GPS166 conversion */ + pps_one, /* easy PPS monitoring */ + (void *)&meinberg_fmt[2], /* conversion configuration */ + "Meinberg GPS Extended", /* Meinberg FAU GPS format */ + 512, /* string buffer */ + sizeof(struct msg_buf) /* no private data (complete pakets) */ + } +}; + +/* + * cvt_meinberg + * + * convert simple type format + */ +static u_long +cvt_meinberg( + unsigned char *buffer, + int size, + struct format *unused, + clocktime_t *clock_time, + void *local + ) +{ + struct format *format; + + /* + * select automagically correct data format + */ + if (Strok(buffer, meinberg_fmt[0].fixed_string)) + { + format = &meinberg_fmt[0]; + } + else + { + if (Strok(buffer, meinberg_fmt[1].fixed_string)) + { + format = &meinberg_fmt[1]; + } + else + { + return CVT_FAIL|CVT_BADFMT; + } + } + + /* + * collect data + */ + if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day, + format->field_offsets[O_DAY].length) || + Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month, + format->field_offsets[O_MONTH].length) || + Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year, + format->field_offsets[O_YEAR].length) || + Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour, + format->field_offsets[O_HOUR].length) || + Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute, + format->field_offsets[O_MIN].length) || + Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second, + format->field_offsets[O_SEC].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + else + { + unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset]; + + clock_time->usecond = 0; + clock_time->flags = PARSEB_S_LEAP; + + if (clock_time->second == 60) + clock_time->flags |= PARSEB_LEAPSECOND; + + /* + * 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_time->utcoffset = 0; /* UTC */ + clock_time->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 *old* standard time code + * ROMS !!!! The new ROMS have 'U' at the ZONE field - good. + */ + switch (buffer[format->field_offsets[O_ZONE].offset]) + { + case ' ': + clock_time->utcoffset = -1*60*60; /* MET */ + break; + + case 'S': + clock_time->utcoffset = -2*60*60; /* MED */ + break; + + case 'U': + /* + * timecode is in UTC + */ + clock_time->utcoffset = 0; /* UTC */ + clock_time->flags |= PARSEB_UTC; + break; + + default: + return CVT_FAIL|CVT_BADFMT; + } + } + + /* + * gather status flags + */ + if (buffer[format->field_offsets[O_ZONE].offset] == 'S') + clock_time->flags |= PARSEB_DST; + + if (f[0] == '#') + clock_time->flags |= PARSEB_POWERUP; + + if (f[1] == '*') + clock_time->flags |= PARSEB_NOSYNC; + + if (f[3] == '!') + clock_time->flags |= PARSEB_ANNOUNCE; + + /* + * oncoming leap second + * 'a' code not confirmed - earth is not + * expected to speed up + */ + if (f[3] == 'A') + clock_time->flags |= PARSEB_LEAPADD; + + if (f[3] == 'a') + clock_time->flags |= PARSEB_LEAPDEL; + + + if (format->flags & MBG_EXTENDED) + { + clock_time->flags |= PARSEB_S_ANTENNA; + + /* + * DCF77 does not encode the direction - + * so we take the current default - + * earth slowing down + */ + clock_time->flags &= ~PARSEB_LEAPDEL; + + if (f[4] == 'A') + clock_time->flags |= PARSEB_LEAPADD; + + if (f[5] == 'R') + clock_time->flags |= PARSEB_ALTERNATE; + } + return CVT_OK; + } +} + + +/* + * mbg_input + * + * grep data from input stream + */ +static u_long +mbg_input( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + unsigned int rtc; + + parseprintf(DD_PARSE, ("mbg_input(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + switch (ch) + { + case STX: + parseprintf(DD_PARSE, ("mbg_input: STX seen\n")); + + parseio->parse_index = 1; + parseio->parse_data[0] = ch; + parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ + return PARSE_INP_SKIP; + + case ETX: + parseprintf(DD_PARSE, ("mbg_input: ETX seen\n")); + if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) + return parse_end(parseio); + else + return rtc; + + default: + return parse_addchar(parseio, ch); + } +} + + +/* + * cvt_mgps + * + * convert Meinberg GPS format + */ +static u_long +cvt_mgps( + unsigned char *buffer, + int size, + struct format *format, + clocktime_t *clock_time, + void *local + ) +{ + if (!Strok(buffer, format->fixed_string)) + { + return cvt_meinberg(buffer, size, format, clock_time, local); + } + else + { + if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day, + format->field_offsets[O_DAY].length) || + Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month, + format->field_offsets[O_MONTH].length) || + Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year, + format->field_offsets[O_YEAR].length) || + Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour, + format->field_offsets[O_HOUR].length) || + Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute, + format->field_offsets[O_MIN].length) || + Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second, + format->field_offsets[O_SEC].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + else + { + long h; + unsigned char *f = &buffer[format->field_offsets[O_FLAGS].offset]; + + clock_time->flags = PARSEB_S_LEAP|PARSEB_S_POSITION; + + clock_time->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_time->utcoffset, + format->field_offsets[O_UTCMOFFSET].length)) + { + return CVT_FAIL|CVT_BADFMT; + } + + clock_time->utcoffset += TIMES60(h); + clock_time->utcoffset = TIMES60(clock_time->utcoffset); + + if (buffer[format->field_offsets[O_UTCSOFFSET].offset] != '-') + { + clock_time->utcoffset = -clock_time->utcoffset; + } + } + + /* + * gather status flags + */ + if (buffer[format->field_offsets[O_ZONE].offset] == 'S') + clock_time->flags |= PARSEB_DST; + + if (clock_time->utcoffset == 0) + clock_time->flags |= PARSEB_UTC; + + /* + * no sv's seen - no time & position + */ + if (f[0] == '#') + clock_time->flags |= PARSEB_POWERUP; + + /* + * at least one sv seen - time (for last position) + */ + if (f[1] == '*') + clock_time->flags |= PARSEB_NOSYNC; + else + if (!(clock_time->flags & PARSEB_POWERUP)) + clock_time->flags |= PARSEB_POSITION; + + /* + * oncoming zone switch + */ + if (f[3] == '!') + clock_time->flags |= PARSEB_ANNOUNCE; + + /* + * oncoming leap second + * 'a' code not confirmed - earth is not + * expected to speed up + */ + if (f[4] == 'A') + clock_time->flags |= PARSEB_LEAPADD; + + if (f[4] == 'a') + clock_time->flags |= PARSEB_LEAPDEL; + + /* + * f[5] == ' ' + */ + + /* + * this is the leap second + */ + if ((f[6] == 'L') || (clock_time->second == 60)) + clock_time->flags |= PARSEB_LEAPSECOND; + + return CVT_OK; + } + } +} + +/* + * gps_input + * + * grep binary data from input stream + */ +static u_long +gps_input( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + CSUM calc_csum; /* used to compare the incoming csums */ + GPS_MSG_HDR header; + struct msg_buf *msg_buf; + + msg_buf = (struct msg_buf *)parseio->parse_pdata; + + parseprintf(DD_PARSE, ("gps_input(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + if (!msg_buf) + return PARSE_INP_SKIP; + + if ( msg_buf->phase == MBG_NONE ) + { /* not receiving yet */ + switch (ch) + { + case SOH: + parseprintf(DD_PARSE, ("gps_input: SOH seen\n")); + + msg_buf->len = sizeof( header ); /* prepare to receive msg header */ + msg_buf->phase = MBG_HEADER; /* receiving header */ + break; + + case STX: + parseprintf(DD_PARSE, ("gps_input: STX seen\n")); + + msg_buf->len = 0; + msg_buf->phase = MBG_STRING; /* prepare to receive ASCII ETX delimited message */ + parseio->parse_index = 1; + parseio->parse_data[0] = ch; + break; + + default: + return PARSE_INP_SKIP; /* keep searching */ + } + + parseio->parse_dtime.parse_msglen = 1; /* reset buffer pointer */ + parseio->parse_dtime.parse_msg[0] = ch; /* fill in first character */ + parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ + return PARSE_INP_SKIP; + } + + /* SOH/STX has already been received */ + + /* save incoming character in both buffers if needbe */ + if ((msg_buf->phase == MBG_STRING) && + (parseio->parse_index < parseio->parse_dsize)) + parseio->parse_data[parseio->parse_index++] = ch; + + parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch; + + if (parseio->parse_dtime.parse_msglen > sizeof(parseio->parse_dtime.parse_msg)) + { + msg_buf->phase = MBG_NONE; /* buffer overflow - discard */ + parseio->parse_data[parseio->parse_index] = '\0'; + memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1)); + parseio->parse_ldsize = parseio->parse_index+1; + return PARSE_INP_DATA; + } + + switch (msg_buf->phase) + { + case MBG_HEADER: + case MBG_DATA: + msg_buf->len--; + + if ( msg_buf->len ) /* transfer not complete */ + return PARSE_INP_SKIP; + + parseprintf(DD_PARSE, ("gps_input: %s complete\n", (msg_buf->phase == MBG_DATA) ? "data" : "header")); + + break; + + case MBG_STRING: + if ((ch == ETX) || (parseio->parse_index >= parseio->parse_dsize)) + { + msg_buf->phase = MBG_NONE; + parseprintf(DD_PARSE, ("gps_input: string complete\n")); + parseio->parse_data[parseio->parse_index] = '\0'; + memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1)); + parseio->parse_ldsize = parseio->parse_index+1; + parseio->parse_index = 0; + return PARSE_INP_TIME; + } + else + { + return PARSE_INP_SKIP; + } + } + + /* cnt == 0, so the header or the whole message is complete */ + + if ( msg_buf->phase == MBG_HEADER ) + { /* header complete now */ + unsigned char *datap = parseio->parse_dtime.parse_msg + 1; + + get_mbg_header(&datap, &header); + + parseprintf(DD_PARSE, ("gps_input: header: cmd 0x%x, len %d, dcsum 0x%x, hcsum 0x%x\n", + (int)header.gps_cmd, (int)header.gps_len, (int)header.gps_data_csum, + (int)header.gps_hdr_csum)); + + + calc_csum = mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg + 1, (unsigned short)6 ); + + if ( calc_csum != header.gps_hdr_csum ) + { + parseprintf(DD_PARSE, ("gps_input: header checksum mismatch expected 0x%x, got 0x%x\n", + (int)calc_csum, (int)mbg_csum( (unsigned char *) parseio->parse_dtime.parse_msg, (unsigned short)6 ))); + + msg_buf->phase = MBG_NONE; /* back to hunting mode */ + return PARSE_INP_DATA; /* invalid header checksum received - pass up for detection */ + } + + if ((header.gps_len == 0) || /* no data to wait for */ + (header.gps_len >= (sizeof (parseio->parse_dtime.parse_msg) - sizeof(header) - 1))) /* blows anything we have space for */ + { + msg_buf->phase = MBG_NONE; /* back to hunting mode */ + return (header.gps_len == 0) ? PARSE_INP_DATA : PARSE_INP_SKIP; /* message complete/throwaway */ + } + + parseprintf(DD_PARSE, ("gps_input: expecting %d bytes of data message\n", (int)header.gps_len)); + + msg_buf->len = header.gps_len;/* save number of bytes to wait for */ + msg_buf->phase = MBG_DATA; /* flag header already complete */ + return PARSE_INP_SKIP; + } + + parseprintf(DD_PARSE, ("gps_input: message data complete\n")); + + /* Header and data have been received. The header checksum has been */ + /* checked */ + + msg_buf->phase = MBG_NONE; /* back to hunting mode */ + return PARSE_INP_DATA; /* message complete, must be evaluated */ +} + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */ +int clk_meinberg_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_MEINBERG) */ + +/* + * History: + * + * clk_meinberg.c,v + * Revision 4.7 1999/02/21 11:09:14 kardel + * cleanup + * + * Revision 4.6 1998/06/14 21:09:36 kardel + * Sun acc cleanup + * + * Revision 4.5 1998/06/13 15:18:54 kardel + * fix mem*() to b*() function macro emulation + * + * Revision 4.4 1998/06/13 12:03:23 kardel + * fix SYSV clock name clash + * + * Revision 4.3 1998/06/12 15:22:28 kardel + * fix prototypes + * + * Revision 4.2 1998/05/24 16:14:42 kardel + * support current Meinberg standard data formats + * + * Revision 4.1 1998/05/24 09:39:52 kardel + * implementation of the new IO handling model + * + * Revision 4.0 1998/04/10 19:45:29 kardel + * Start 4.0 release version numbering + * + * from V3 3.23 - log info deleted 1998/04/11 kardel + * + */ diff --git a/contrib/ntp/libparse/clk_rawdcf.c b/contrib/ntp/libparse/clk_rawdcf.c new file mode 100644 index 000000000000..ac854c57b223 --- /dev/null +++ b/contrib/ntp/libparse/clk_rawdcf.c @@ -0,0 +1,581 @@ +/* + * /src/NTP/ntp-4/libparse/clk_rawdcf.c,v 4.6 1998/06/14 21:09:37 kardel RELEASE_19990228_A + * + * clk_rawdcf.c,v 4.6 1998/06/14 21:09:37 kardel RELEASE_19990228_A + * + * Raw DCF77 pulse clock support + * + * Copyright (C) 1992-1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_RAWDCF) + +#include +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" +#ifdef PARSESTREAM +# include +#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 u_long pps_rawdcf P((parse_t *, int, timestamp_t *)); +static u_long cvt_rawdcf P((unsigned char *, int, struct format *, clocktime_t *, void *)); +static u_long inp_rawdcf P((parse_t *, unsigned int, timestamp_t *)); + +clockformat_t clock_rawdcf = +{ + inp_rawdcf, /* DCF77 input handling */ + cvt_rawdcf, /* raw dcf input conversion */ + pps_rawdcf, /* examining PPS information */ + 0, /* no private configuration data */ + "RAW DCF77 Timecode", /* direct decoding / time synthesis */ + + 61, /* bit buffer */ + 0 /* no private data (currently in input buffer) */ +}; + +static struct dcfparam +{ + unsigned char onebits[60]; + unsigned char zerobits[60]; +} dcfparameter = +{ + "###############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 u_long +ext_bf( + register unsigned char *buf, + register int idx, + register unsigned char *zero + ) +{ + register u_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( + unsigned char *buf, + int idx, + unsigned char *zero + ) +{ + int i,last; + unsigned psum = 1; + + last = partab[idx+1].offset; + + for (i = partab[idx].offset; i < last; i++) + psum ^= (buf[i] != zero[i]); + + return psum; +} + +static u_long +convert_rawdcf( + unsigned char *buffer, + int size, + struct dcfparam *dcfprm, + clocktime_t *clock_time + ) +{ + register unsigned char *s = buffer; + register unsigned char *b = dcfprm->onebits; + register unsigned char *c = dcfprm->zerobits; + register int i; + + parseprintf(DD_RAWDCF,("parse: convert_rawdcf: \"%s\"\n", buffer)); + + if (size < 57) + { +#ifndef PARSEKERNEL + msyslog(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) + */ +#ifndef PARSEKERNEL + msyslog(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, dcfprm->zerobits) == 1) && + pcheck(buffer, DCF_P_P1, dcfprm->zerobits) && + pcheck(buffer, DCF_P_P2, dcfprm->zerobits) && + pcheck(buffer, DCF_P_P3, dcfprm->zerobits)) + { + /* + * buffer OK + */ + parseprintf(DD_RAWDCF,("parse: convert_rawdcf: parity check passed\n")); + + clock_time->flags = PARSEB_S_ANTENNA|PARSEB_S_LEAP; + clock_time->utctime= 0; + clock_time->usecond= 0; + clock_time->second = 0; + clock_time->minute = ext_bf(buffer, DCF_M10, dcfprm->zerobits); + clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1, dcfprm->zerobits); + clock_time->hour = ext_bf(buffer, DCF_H10, dcfprm->zerobits); + clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1, dcfprm->zerobits); + clock_time->day = ext_bf(buffer, DCF_D10, dcfprm->zerobits); + clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1, dcfprm->zerobits); + clock_time->month = ext_bf(buffer, DCF_MO0, dcfprm->zerobits); + clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO, dcfprm->zerobits); + clock_time->year = ext_bf(buffer, DCF_Y10, dcfprm->zerobits); + clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1, dcfprm->zerobits); + + switch (ext_bf(buffer, DCF_Z, dcfprm->zerobits)) + { + case DCF_Z_MET: + clock_time->utcoffset = -1*60*60; + break; + + case DCF_Z_MED: + clock_time->flags |= PARSEB_DST; + clock_time->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, dcfprm->zerobits)) + clock_time->flags |= PARSEB_ANNOUNCE; + + if (ext_bf(buffer, DCF_A2, dcfprm->zerobits)) + clock_time->flags |= PARSEB_LEAPADD; /* default: DCF77 data format deficiency */ + + if (ext_bf(buffer, DCF_R, dcfprm->zerobits)) + clock_time->flags |= PARSEB_ALTERNATE; + + parseprintf(DD_RAWDCF,("parse: convert_rawdcf: TIME CODE OK: %d:%d, %d.%d.%d, flags 0x%lx\n", + (int)clock_time->hour, (int)clock_time->minute, (int)clock_time->day, (int)clock_time->month,(int) clock_time->year, + (u_long)clock_time->flags)); + return CVT_OK; + } + else + { + /* + * bad format - not for us + */ +#ifndef PARSEKERNEL + msyslog(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 u_long +cvt_rawdcf( + unsigned char *buffer, + int size, + struct format *param, + clocktime_t *clock_time, + void *local + ) +{ + register unsigned char *s = (unsigned char *)buffer; + register unsigned char *e = s + size; + register unsigned char *b = dcfparameter.onebits; + register unsigned char *c = dcfparameter.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, (int)(s - (unsigned char *)buffer))); + *s = (unsigned char)~0; + rtc = CVT_FAIL|CVT_BADFMT; + } + s++; + } + + if (lowmax) + { + cutoff /= lowmax; + } + else + { + cutoff = 4; /* doesn't really matter - it'll fail anyway, but gives error output */ + } + + parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: average bit count: %d\n", cutoff)); + + lowmax = 0; + highmax = 0; + + parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: histogram:")); + for (i = 0; i <= cutoff; i++) + { + lowmax+=histbuf[i] * i; + highmax += histbuf[i]; + parseprintf(DD_RAWDCF,(" %d", histbuf[i])); + } + parseprintf(DD_RAWDCF, (" ")); + + lowmax += highmax / 2; + + if (highmax) + { + lowmax /= highmax; + } + else + { + lowmax = 0; + } + + highmax = 0; + cutoff = 0; + + for (; i < BITS; i++) + { + highmax+=histbuf[i] * i; + cutoff +=histbuf[i]; + parseprintf(DD_RAWDCF,(" %d", histbuf[i])); + } + parseprintf(DD_RAWDCF,("\n")); + + if (cutoff) + { + highmax /= cutoff; + } + else + { + highmax = BITS-1; + } + + span = cutoff = lowmax; + for (i = lowmax; i <= highmax; i++) + { + if (histbuf[cutoff] > histbuf[i]) + { + cutoff = i; + span = i; + } + else + if (histbuf[cutoff] == histbuf[i]) + { + span = i; + } + } + + cutoff = (cutoff + span) / 2; + + parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff)); + + s = (unsigned char *)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, &dcfparameter, clock_time) : rtc; +} + +/* + * pps_rawdcf + * + * currently a very stupid version - should be extended to decode + * also ones and zeros (which is easy) + */ +/*ARGSUSED*/ +static u_long +pps_rawdcf( + register parse_t *parseio, + register int status, + register timestamp_t *ptime + ) +{ + if (!status) /* negative edge for simpler wiring (Rx->DCD) */ + { + parseio->parse_dtime.parse_ptime = *ptime; + parseio->parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; + } + + return CVT_NONE; +} + +static u_long +snt_rawdcf( + register parse_t *parseio, + register timestamp_t *ptime + ) +{ + if ((parseio->parse_dtime.parse_status & CVT_MASK) == CVT_OK) + { + parseio->parse_dtime.parse_stime = *ptime; + +#ifdef PARSEKERNEL + parseio->parse_dtime.parse_time.tv.tv_sec++; +#else + parseio->parse_dtime.parse_time.fp.l_ui++; +#endif + + parseprintf(DD_RAWDCF,("parse: snt_rawdcf: time stamp synthesized offset %d seconds\n", parseio->parse_index - 1)); + + return updatetimeinfo(parseio, parseio->parse_lstate); + } + return CVT_NONE; +} + +/* + * inp_rawdcf + * + * grep DCF77 data from input stream + */ +static u_long +inp_rawdcf( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + static struct timeval timeout = { 1, 500000 }; /* 1.5 secongs denote second #60 */ + + parseprintf(DD_PARSE, ("inp_rawdcf(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ + + if (parse_timedout(parseio, tstamp, &timeout)) + { + parseprintf(DD_PARSE, ("inp_rawdcf: time out seen\n")); + + (void) parse_end(parseio); + (void) parse_addchar(parseio, ch); + return PARSE_INP_TIME; + } + else + { + unsigned int rtc; + + rtc = parse_addchar(parseio, ch); + if (rtc == PARSE_INP_SKIP) + { + if (snt_rawdcf(parseio, tstamp) == CVT_OK) + return PARSE_INP_SYNTH; + } + return rtc; + } +} + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_RAWDCF) */ +int clk_rawdcf_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_RAWDCF) */ + +/* + * History: + * + * clk_rawdcf.c,v + * Revision 4.6 1998/06/14 21:09:37 kardel + * Sun acc cleanup + * + * Revision 4.5 1998/06/13 12:04:16 kardel + * fix SYSV clock name clash + * + * Revision 4.4 1998/06/12 15:22:28 kardel + * fix prototypes + * + * Revision 4.3 1998/06/06 18:33:36 kardel + * simplified condidional compile expression + * + * Revision 4.2 1998/05/24 11:04:18 kardel + * triggering PPS on negative edge for simpler wiring (Rx->DCD) + * + * Revision 4.1 1998/05/24 09:39:53 kardel + * implementation of the new IO handling model + * + * Revision 4.0 1998/04/10 19:45:30 kardel + * Start 4.0 release version numbering + * + * from V3 3.24 log info deleted 1998/04/11 kardel + * + */ diff --git a/contrib/ntp/libparse/clk_rcc8000.c b/contrib/ntp/libparse/clk_rcc8000.c new file mode 100644 index 000000000000..09405c73d20e --- /dev/null +++ b/contrib/ntp/libparse/clk_rcc8000.c @@ -0,0 +1,195 @@ +/* + * /src/NTP/ntp-4/libparse/clk_rcc8000.c,v 4.5 1998/06/14 21:09:38 kardel RELEASE_19990228_A + * + * clk_rcc8000.c,v 4.5 1998/06/14 21:09:38 kardel RELEASE_19990228_A + * + * Radiocode Clocks Ltd RCC 8000 Intelligent Off-Air Master Clock support + * + * Created by R.E.Broughton from clk_trimtaip.c + * + * 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 HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_RCC8000) + +#include +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +#ifndef PARSESTREAM +#include "ntp_stdlib.h" +#include +#else +#include "sys/parsestreams.h" +extern void printf P((const char *, ...)); +#endif + +/* Type II Serial Output format + * + * 0000000000111111111122222222223 / char + * 0123456789012345678901234567890 \ posn + * HH:MM:SS.XYZ DD/MM/YY DDD W Prn Actual + * 33 44 55 666 00 11 22 7 Parse + * : : . / / rn Check + * "15:50:36.534 30/09/94 273 5 A\x0d\x0a" + * + * DDD - Day of year number + * W - Day of week number (Sunday is 0) + * P is the Status. See comment below for details. + */ + +#define O_USEC O_WDAY +static struct format rcc8000_fmt = +{ { { 13, 2 }, {16, 2}, { 19, 2}, /* Day, Month, Year */ + { 0, 2 }, { 3, 2}, { 6, 2}, /* Hour, Minute, Second */ + { 9, 3 }, {28, 1}, { 0, 0}, /* uSec, Status (Valid,Reject,BST,Leapyear) */ }, + (const unsigned char *)" : : . / / \r\n", + /*"15:50:36.534 30/09/94 273 5 A\x0d\x0a" */ + 0 +}; + +static unsigned long cvt_rcc8000 P((unsigned char *, int, struct format *, clocktime_t *, void *)); +static unsigned long inp_rcc8000 P((parse_t *, unsigned int, timestamp_t *)); + +clockformat_t clock_rcc8000 = +{ + inp_rcc8000, /* no input handling */ + cvt_rcc8000, /* Radiocode clock conversion */ + 0, /* no direct PPS monitoring */ + (void *)&rcc8000_fmt, /* conversion configuration */ + "Radiocode RCC8000", + 31, /* string buffer */ + 0 /* no private data */ +}; + +static unsigned long +cvt_rcc8000( + unsigned char *buffer, + int size, + struct format *format, + clocktime_t *clock_time, + void *local + ) +{ + 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_time->day) || + STOI(O_MONTH, &clock_time->month) || + STOI(O_YEAR, &clock_time->year) || + STOI(O_HOUR, &clock_time->hour) || + STOI(O_MIN, &clock_time->minute) || + STOI(O_SEC, &clock_time->second) || + STOI(O_USEC, &clock_time->usecond) + ) return CVT_FAIL|CVT_BADFMT; + clock_time->usecond *= 1000; + + clock_time->utcoffset = 0; + +#define RCCP buffer[28] + /* + * buffer[28] is the ASCII representation of a hex character ( 0 through F ) + * The four bits correspond to: + * 8 - Valid Time + * 4 - Reject Code + * 2 - British Summer Time (receiver set to emit GMT all year.) + * 1 - Leap year + */ +#define RCC8000_VALID 0x8 +#define RCC8000_REJECT 0x4 +#define RCC8000_BST 0x2 +#define RCC8000_LEAPY 0x1 + + clock_time->flags = 0; + + if ( (RCCP >= '0' && RCCP <= '9') || (RCCP >= 'A' && RCCP <= 'F') ) + { + register int flag; + + flag = (RCCP >= '0' && RCCP <= '9' ) ? RCCP - '0' : RCCP - 'A' + 10; + + if (!(flag & RCC8000_VALID)) + clock_time->flags |= PARSEB_POWERUP; + + clock_time->flags |= PARSEB_UTC; /* British special - guess why 8-) */ + + /* other flags not used */ + } + return CVT_OK; +} +/* + * inp_rcc8000 + * + * grep data from input stream + */ +static u_long +inp_rcc8000( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + unsigned int rtc; + + parseprintf(DD_PARSE, ("inp_rcc8000(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + switch (ch) + { + case '\n': + parseprintf(DD_PARSE, ("inp_rcc8000: EOL seen\n")); + if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) + return parse_end(parseio); + else + return rtc; + + + default: + if (parseio->parse_index == 0) /* take sample at start of message */ + { + parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ + } + return parse_addchar(parseio, ch); + } +} + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_RCC8000) */ +int clk_rcc8000_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_RCC8000) */ + +/* + * History: + * + * clk_rcc8000.c,v + * Revision 4.5 1998/06/14 21:09:38 kardel + * Sun acc cleanup + * + * Revision 4.4 1998/06/13 12:05:02 kardel + * fix SYSV clock name clash + * + * Revision 4.3 1998/06/12 15:22:29 kardel + * fix prototypes + * + * Revision 4.2 1998/06/12 09:13:25 kardel + * conditional compile macros fixed + * printf prototype + * + * Revision 4.1 1998/05/24 09:39:53 kardel + * implementation of the new IO handling model + * + * Revision 4.0 1998/04/10 19:45:30 kardel + * Start 4.0 release version numbering + * + * from V3 3.5 log info deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/libparse/clk_schmid.c b/contrib/ntp/libparse/clk_schmid.c new file mode 100644 index 000000000000..049b4e49c02d --- /dev/null +++ b/contrib/ntp/libparse/clk_schmid.c @@ -0,0 +1,231 @@ +/* + * /src/NTP/ntp-4/libparse/clk_schmid.c,v 4.4 1998/06/13 12:06:03 kardel RELEASE_19990228_A + * + * clk_schmid.c,v 4.4 1998/06/13 12:06:03 kardel RELEASE_19990228_A + * + * Schmid clock support + * + * Copyright (C) 1992-1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * 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 HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_SCHMID) + +#include +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +#ifndef PARSESTREAM +#include "ntp_stdlib.h" +#include +#else +#include "sys/parsestreams.h" +extern void printf P((const char *, ...)); +#endif + +/* + * 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 u_long cvt_schmid P((unsigned char *, int, struct format *, clocktime_t *, void *)); +static unsigned long inp_schmid P((parse_t *, unsigned int, timestamp_t *)); + +clockformat_t clock_schmid = +{ + inp_schmid, /* no input handling */ + cvt_schmid, /* Schmid conversion */ + 0, /* not direct PPS monitoring */ + 0, /* conversion configuration */ + "Schmid", /* Schmid receiver */ + 12, /* binary data buffer */ + 0, /* no private data (complete messages) */ +}; + + +static u_long +cvt_schmid( + unsigned char *buffer, + int size, + struct format *format, + clocktime_t *clock_time, + void *local + ) +{ + if ((size != 11) || (buffer[10] != (unsigned char)'\375')) + { + return CVT_NONE; + } + else + { + if (buffer[0] > 23 || buffer[1] > 59 || buffer[2] > 59 || buffer[3] > 9) /* Time */ + { + 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_time->hour = buffer[0]; + clock_time->minute = buffer[1]; + clock_time->second = buffer[2]; + clock_time->usecond = buffer[3] * 100000; + clock_time->day = buffer[4]; + clock_time->month = buffer[5]; + clock_time->year = buffer[6]; + + clock_time->flags = 0; + + switch (buffer[8] & WS_TZ) + { + case WS_MET: + clock_time->utcoffset = -1*60*60; + break; + + case WS_MEST: + clock_time->utcoffset = -2*60*60; + clock_time->flags |= PARSEB_DST; + break; + + default: + return CVT_FAIL|CVT_BADFMT; + } + + if (!(buffer[7] & WS_TIME)) + { + clock_time->flags |= PARSEB_POWERUP; + } + + if (!(buffer[7] & WS_SIGNAL)) + { + clock_time->flags |= PARSEB_NOSYNC; + } + + if (buffer[7] & WS_SIGNAL) + { + if (buffer[8] & WS_ALTERNATE) + { + clock_time->flags |= PARSEB_ALTERNATE; + } + + if (buffer[8] & WS_ANNOUNCE) + { + clock_time->flags |= PARSEB_ANNOUNCE; + } + + if (buffer[8] & WS_LEAP) + { + clock_time->flags |= PARSEB_LEAPADD; /* default: DCF77 data format deficiency */ + } + } + + clock_time->flags |= PARSEB_S_LEAP|PARSEB_S_ANTENNA; + + return CVT_OK; + } + } +} + +/* + * inp_schmid + * + * grep data from input stream + */ +static u_long +inp_schmid( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + unsigned int rtc; + + parseprintf(DD_PARSE, ("inp_schmid(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + switch (ch) + { + case 0xFD: /* */ + parseprintf(DD_PARSE, ("mbg_input: ETX seen\n")); + if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) + return parse_end(parseio); + else + return rtc; + + default: + return parse_addchar(parseio, ch); + } +} + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SCHMID) */ +int clk_schmid_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_SCHMID) */ + +/* + * History: + * + * clk_schmid.c,v + * Revision 4.4 1998/06/13 12:06:03 kardel + * fix SYSV clock name clash + * + * Revision 4.3 1998/06/12 15:22:29 kardel + * fix prototypes + * + * Revision 4.2 1998/06/12 09:13:26 kardel + * conditional compile macros fixed + * printf prototype + * + * Revision 4.1 1998/05/24 09:39:53 kardel + * implementation of the new IO handling model + * + * Revision 4.0 1998/04/10 19:45:31 kardel + * Start 4.0 release version numbering + * + * from V3 3.22 log info deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/libparse/clk_trimtaip.c b/contrib/ntp/libparse/clk_trimtaip.c new file mode 100644 index 000000000000..2fd1eab74694 --- /dev/null +++ b/contrib/ntp/libparse/clk_trimtaip.c @@ -0,0 +1,188 @@ +/* + * /src/NTP/ntp-4/libparse/clk_trimtaip.c,v 4.6 1998/08/16 18:46:27 kardel RELEASE_19990228_A + * + * clk_trimtaip.c,v 4.6 1998/08/16 18:46:27 kardel RELEASE_19990228_A + * + * Trimble SV6 clock support - several collected codepieces + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_TRIMTAIP) +#include +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +#ifndef PARSESTREAM +#include "ntp_stdlib.h" +#include +#else +#include "sys/parsestreams.h" +extern void printf P((const char *, ...)); +#endif + +/* 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) */ +}, + (const unsigned char *)">RTM 1 ;* <", + 0 +}; + +static unsigned long cvt_trimtaip P((unsigned char *, int, struct format *, clocktime_t *, void *)); +static unsigned long inp_trimtaip P((parse_t *, unsigned int, timestamp_t *)); + +clockformat_t clock_trimtaip = +{ + inp_trimtaip, /* no input handling */ + cvt_trimtaip, /* Trimble conversion */ + pps_one, /* easy PPS monitoring */ + (void *)&trimsv6_fmt, /* conversion configuration */ + "Trimble TAIP", + 37, /* string buffer */ + 0 /* no private data */ +}; + +static unsigned long +cvt_trimtaip( + unsigned char *buffer, + int size, + struct format *format, + clocktime_t *clock_time, + void *local + ) +{ + 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_time->day) || + STOI(O_MONTH, &clock_time->month) || + STOI(O_YEAR, &clock_time->year) || + STOI(O_HOUR, &clock_time->hour) || + STOI(O_MIN, &clock_time->minute) || + STOI(O_SEC, &clock_time->second) || + STOI(O_USEC, &clock_time->usecond)|| + STOI(O_GPSFIX, &gpsfix) + ) return CVT_FAIL|CVT_BADFMT; + + clock_time->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_time->utcoffset = 0; + + /* What should flags be set to ? */ + clock_time->flags = PARSEB_UTC; + + /* if the current GPS fix is 9 (unknown), reject */ + if (0 > gpsfix || gpsfix > 9) clock_time->flags |= PARSEB_POWERUP; + + return CVT_OK; +} + +/* + * inp_trimtaip + * + * grep data from input stream + */ +static u_long +inp_trimtaip( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + unsigned int rtc; + + parseprintf(DD_PARSE, ("inp_trimtaip(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + switch (ch) + { + case '>': + parseprintf(DD_PARSE, ("inp_trimptaip: START seen\n")); + + parseio->parse_index = 1; + parseio->parse_data[0] = ch; + parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ + return PARSE_INP_SKIP; + + case '<': + parseprintf(DD_PARSE, ("inp_trimtaip: END seen\n")); + if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) + return parse_end(parseio); + else + return rtc; + + + default: + return parse_addchar(parseio, ch); + } +} + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_TRIMTAIP) */ +int clk_trimtaip_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_TRIMTAIP) */ + +/* + * History: + * + * clk_trimtaip.c,v + * Revision 4.6 1998/08/16 18:46:27 kardel + * (clock_trimtaip =): changed format name + * + * Revision 4.5 1998/06/14 21:09:38 kardel + * Sun acc cleanup + * + * Revision 4.4 1998/06/13 12:06:57 kardel + * fix SYSV clock name clash + * + * Revision 4.3 1998/06/12 15:22:29 kardel + * fix prototypes + * + * Revision 4.2 1998/06/12 09:13:26 kardel + * conditional compile macros fixed + * printf prototype + * + * Revision 4.1 1998/05/24 09:39:54 kardel + * implementation of the new IO handling model + * + * Revision 4.0 1998/04/10 19:45:31 kardel + * Start 4.0 release version numbering + * + * from V3 1.4 log info deleted 1998/04/11 kardel + */ + diff --git a/contrib/ntp/libparse/clk_trimtsip.c b/contrib/ntp/libparse/clk_trimtsip.c new file mode 100644 index 000000000000..52a753649ea6 --- /dev/null +++ b/contrib/ntp/libparse/clk_trimtsip.c @@ -0,0 +1,421 @@ +/* + * /src/NTP/ntp-4/libparse/clk_trimtsip.c,v 4.12 1999/02/28 13:00:08 kardel RELEASE_19990228_A + * + * clk_trimtsip.c,v 4.12 1999/02/28 13:00:08 kardel RELEASE_19990228_A + * + * Trimble TSIP support - CURRENTLY VERY MUCH UNDER CONSTRUCTION + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_TRIMTSIP) + +#include +#include + +#include "ntp_syslog.h" +#include "ntp_types.h" +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" +#include "ntp_machine.h" +#include "ntp_stdlib.h" + +#include "parse.h" + +#ifndef PARSESTREAM +#include +#else +#include "sys/parsestreams.h" +# endif + +#include "ascii.h" +#include "binio.h" +#include "ieee754io.h" +#include "trimble.h" + +/* + * Trimble low level TSIP parser / time converter + * + * The receiver uses a serial message protocol called Trimble Standard + * Interface Protocol (it can support others but this driver only supports + * TSIP). Messages in this protocol have the following form: + * + * ... ... + * + * Any bytes within the portion of value 10 hex () are doubled + * on transmission and compressed back to one on reception. Otherwise + * the values of data bytes can be anything. The serial interface is RS-422 + * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits + * in total!), and 1 stop bit. The protocol supports byte, integer, single, + * and double datatypes. Integers are two bytes, sent most significant first. + * Singles are IEEE754 single precision floating point numbers (4 byte) sent + * sign & exponent first. Doubles are IEEE754 double precision floating point + * numbers (8 byte) sent sign & exponent first. + * The receiver supports a large set of messages, only a very small subset of + * which is used here. + * + * From this module the following are recognised: + * + * ID Description + * + * 41 GPS Time + * 46 Receiver health + * 4F UTC correction data (used to get leap second warnings) + * + * All others are accepted but ignored for time conversion - they are passed up to higher layers. + * + */ + +static offsets_t trim_offsets = { 0, 1, 2, 3, 4, 5, 6, 7 }; + +struct trimble +{ + u_char t_in_pkt; /* first DLE received */ + u_char t_dle; /* subsequent DLE received */ + u_short t_week; /* GPS week */ + u_short t_weekleap; /* GPS week of next/last week */ + u_short t_dayleap; /* day in week */ + u_short t_gpsutc; /* GPS - UTC offset */ + u_short t_gpsutcleap; /* offset at next/last leap */ + u_char t_operable; /* receiver feels OK */ + u_char t_mode; /* actual operating mode */ + u_char t_leap; /* possible leap warning */ + u_char t_utcknown; /* utc offset known */ +}; + +#define STATUS_BAD 0 /* BAD or UNINITIALIZED receiver status */ +#define STATUS_UNSAFE 1 /* not enough receivers for full precision */ +#define STATUS_SYNC 2 /* enough information for good operation */ + +static unsigned long inp_tsip P((parse_t *, unsigned int, timestamp_t *)); +static unsigned long cvt_trimtsip P((unsigned char *, int, struct format *, clocktime_t *, void *)); + +struct clockformat clock_trimtsip = +{ + inp_tsip, /* Trimble TSIP input handler */ + cvt_trimtsip, /* Trimble TSIP conversion */ + pps_one, /* easy PPS monitoring */ + 0, /* no configuration data */ + "Trimble TSIP", + 400, /* input buffer */ + sizeof(struct trimble) /* private data */ +}; + +#define ADDSECOND 0x01 +#define DELSECOND 0x02 + +static unsigned long +inp_tsip( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + struct trimble *t = (struct trimble *)parseio->parse_pdata; + + if (!t) + return PARSE_INP_SKIP; /* local data not allocated - sigh! */ + + if (!t->t_in_pkt && ch != DLE) { + /* wait for start of packet */ + return PARSE_INP_SKIP; + } + + if ((parseio->parse_index >= (parseio->parse_dsize - 2)) || + (parseio->parse_dtime.parse_msglen >= (sizeof(parseio->parse_dtime.parse_msg) - 2))) + { /* OVERFLOW - DROP! */ + t->t_in_pkt = t->t_dle = 0; + parseio->parse_index = 0; + parseio->parse_dtime.parse_msglen = 0; + return PARSE_INP_SKIP; + } + + switch (ch) { + case DLE: + if (!t->t_in_pkt) { + t->t_dle = 0; + t->t_in_pkt = 1; + parseio->parse_index = 0; + parseio->parse_data[parseio->parse_index++] = ch; + parseio->parse_dtime.parse_msglen = 0; + parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch; + parseio->parse_dtime.parse_stime = *tstamp; /* pick up time stamp at packet start */ + } else if (t->t_dle) { + /* Double DLE -> insert a DLE */ + t->t_dle = 0; + parseio->parse_data[parseio->parse_index++] = DLE; + parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = DLE; + } else + t->t_dle = 1; + break; + + case ETX: + if (t->t_dle) { + /* DLE,ETX -> end of packet */ + parseio->parse_data[parseio->parse_index++] = DLE; + parseio->parse_data[parseio->parse_index] = ch; + parseio->parse_ldsize = parseio->parse_index+1; + memcpy(parseio->parse_ldata, parseio->parse_data, parseio->parse_ldsize); + parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = DLE; + parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch; + t->t_in_pkt = t->t_dle = 0; + return PARSE_INP_TIME|PARSE_INP_DATA; + } + + default: /* collect data */ + t->t_dle = 0; + parseio->parse_data[parseio->parse_index++] = ch; + parseio->parse_dtime.parse_msg[parseio->parse_dtime.parse_msglen++] = ch; + } + + return PARSE_INP_SKIP; +} + +static int +getshort( + unsigned char *p + ) +{ + return get_msb_short(&p); +} + +/* + * cvt_trimtsip + * + * convert TSIP type format + */ +static unsigned long +cvt_trimtsip( + unsigned char *buffer, + int size, + struct format *format, + clocktime_t *clock_time, + void *local + ) +{ + register struct trimble *t = (struct trimble *)local; /* get local data space */ +#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ + register u_char cmd; + + clock_time->flags = 0; + + if (!t) { + return CVT_NONE; /* local data not allocated - sigh! */ + } + + if ((size < 4) || + (buffer[0] != DLE) || + (buffer[size-1] != ETX) || + (buffer[size-2] != DLE)) + { + printf("TRIMBLE BAD packet, size %d:\n", size); + return CVT_NONE; + } + else + { + unsigned char *bp; + cmd = buffer[1]; + + switch(cmd) + { + case CMD_RCURTIME: + { /* GPS time */ + l_fp secs; + int week = getshort((unsigned char *)&mb(4)); + l_fp utcoffset; + l_fp gpstime; + + bp = &mb(0); + if (fetch_ieee754(&bp, IEEE_SINGLE, &secs, trim_offsets) != IEEE_OK) + return CVT_FAIL|CVT_BADFMT; + + if ((secs.l_i <= 0) || + (t->t_utcknown == 0)) + { + clock_time->flags = PARSEB_POWERUP; + return CVT_OK; + } + if (week < 990) { + week += 1024; + } + + /* time OK */ + + /* fetch UTC offset */ + bp = &mb(6); + if (fetch_ieee754(&bp, IEEE_SINGLE, &utcoffset, trim_offsets) != IEEE_OK) + return CVT_FAIL|CVT_BADFMT; + + L_SUB(&secs, &utcoffset); /* adjust GPS time to UTC time */ + + gpstolfp((unsigned short)week, (unsigned short)0, + secs.l_ui, &gpstime); + + gpstime.l_uf = secs.l_uf; + + clock_time->utctime = gpstime.l_ui - JAN_1970; + + TSFTOTVU(gpstime.l_uf, clock_time->usecond); + + if (t->t_leap == ADDSECOND) + clock_time->flags |= PARSEB_LEAPADD; + + if (t->t_leap == DELSECOND) + clock_time->flags |= PARSEB_LEAPDEL; + + switch (t->t_operable) + { + case STATUS_SYNC: + clock_time->flags &= ~(PARSEB_POWERUP|PARSEB_NOSYNC); + break; + + case STATUS_UNSAFE: + clock_time->flags |= PARSEB_NOSYNC; + break; + + case STATUS_BAD: + clock_time->flags |= PARSEB_NOSYNC|PARSEB_POWERUP; + break; + } + + if (t->t_mode == 0) + clock_time->flags |= PARSEB_POSITION; + + clock_time->flags |= PARSEB_S_LEAP|PARSEB_S_POSITION; + + return CVT_OK; + + } /* case 0x41 */ + + case CMD_RRECVHEALTH: + { + /* TRIMBLE health */ + u_char status = mb(0); + + switch (status) + { + case 0x00: /* position fixes */ + t->t_operable = STATUS_SYNC; + break; + + case 0x09: /* 1 satellite */ + case 0x0A: /* 2 satellites */ + case 0x0B: /* 3 satellites */ + t->t_operable = STATUS_UNSAFE; + break; + + default: + t->t_operable = STATUS_BAD; + break; + } + t->t_mode = status; + } + break; + + case CMD_RUTCPARAM: + { + l_fp t0t; + unsigned char *lbp; + + /* UTC correction data - derive a leap warning */ + int tls = t->t_gpsutc = getshort((unsigned char *)&mb(12)); /* current leap correction (GPS-UTC) */ + int tlsf = t->t_gpsutcleap = getshort((unsigned char *)&mb(24)); /* new leap correction */ + + t->t_weekleap = getshort((unsigned char *)&mb(20)); /* week no of leap correction */ + if (t->t_weekleap < 990) + t->t_weekleap += 1024; + + t->t_dayleap = getshort((unsigned char *)&mb(22)); /* day in week of leap correction */ + t->t_week = getshort((unsigned char *)&mb(18)); /* current week no */ + if (t->t_week < 990) + t->t_week += 1024; + + lbp = (unsigned char *)&mb(14); /* last update time */ + if (fetch_ieee754(&lbp, IEEE_SINGLE, &t0t, trim_offsets) != IEEE_OK) + return CVT_FAIL|CVT_BADFMT; + + t->t_utcknown = t0t.l_ui != 0; + + if ((t->t_utcknown) && /* got UTC information */ + (tlsf != tls) && /* something will change */ + ((t->t_weekleap - t->t_week) < 5)) /* and close in the future */ + { + /* generate a leap warning */ + if (tlsf > tls) + t->t_leap = ADDSECOND; + else + t->t_leap = DELSECOND; + } + else + { + t->t_leap = 0; + } + } + break; + + default: + /* it's validly formed, but we don't care about it! */ + break; + } + } + return CVT_SKIP; +} + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_TRIMTSIP && !PARSESTREAM) */ +int clk_trimtsip_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_TRIMTSIP && !PARSESTREAM) */ + +/* + * History: + * + * clk_trimtsip.c,v + * Revision 4.12 1999/02/28 13:00:08 kardel + * *** empty log message *** + * + * Revision 4.11 1999/02/28 11:47:54 kardel + * (struct trimble): new member t_utcknown + * (cvt_trimtsip): fixed status monitoring, bad receiver states are + * now recognized + * + * Revision 4.10 1999/02/27 15:57:15 kardel + * use mmemcpy instead of bcopy + * + * Revision 4.9 1999/02/21 12:17:42 kardel + * 4.91f reconcilation + * + * Revision 4.8 1998/11/15 20:27:58 kardel + * Release 4.0.73e13 reconcilation + * + * Revision 4.7 1998/08/16 18:49:20 kardel + * (cvt_trimtsip): initial kernel capable version (no more floats) + * (clock_trimtsip =): new format name + * + * Revision 4.6 1998/08/09 22:26:05 kardel + * Trimble TSIP support + * + * Revision 4.5 1998/08/02 10:37:05 kardel + * working TSIP parser + * + * Revision 4.4 1998/06/28 16:50:40 kardel + * (getflt): fixed ENDIAN issue + * (getdbl): fixed ENDIAN issue + * (getint): use get_msb_short() + * (cvt_trimtsip): use gpstolfp() for conversion + * + * Revision 4.3 1998/06/13 12:07:31 kardel + * fix SYSV clock name clash + * + * Revision 4.2 1998/06/12 15:22:30 kardel + * fix prototypes + * + * Revision 4.1 1998/05/24 09:39:54 kardel + * implementation of the new IO handling model + * + * Revision 4.0 1998/04/10 19:45:32 kardel + * Start 4.0 release version numbering + * + * from V3 1.8 loginfo deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/libparse/clk_varitext.c b/contrib/ntp/libparse/clk_varitext.c new file mode 100644 index 000000000000..9236bb4b8c9a --- /dev/null +++ b/contrib/ntp/libparse/clk_varitext.c @@ -0,0 +1,239 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_VARITEXT) +/* + * clk_varitext.c,v 1.0 1997/01/19 A.McConnell + * + * Supports Varitext's Radio Clock + * + * Used the Meinberg/Computime clock as a template for Varitext Radio Clock + * + * Copyright (C) 1992-1996 by Frank Kardel + * Friedrich-Alexander Universitt Erlangen-Nrnberg, Germany + * + * 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 +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" + +#include "parse.h" + +#ifndef PARSESTREAM +#include "ntp_stdlib.h" +#include +#else +#include "sys/parsestreams.h" +extern void printf P((const char *, ...)); +#endif + +static const u_char VT_INITIALISED = 0x01; +static const u_char VT_SYNCHRONISED = 0x02; +static const u_char VT_ALARM_STATE = 0x04; +static const u_char VT_BST = 0x08; +static const u_char VT_SEASON_CHANGE = 0x10; +static const u_char VT_LAST_TELEGRAM_OK = 0x20; + +/* + * The Varitext receiver sends a datagram in the following format every minute + * + * Timestamp T:YY:MM:MD:WD:HH:MM:SSCRLFSTXXX + * Pos 0123456789012345678901 2 3 4567 + * 0000000000111111111122 2 2 2222 + * Parse T: : : : : : : \r\n + * + * T Startcharacter "T" specifies start of the timestamp + * YY Year MM Month 1-12 + * MD Day of the month + * WD Day of week + * HH Hour + * MM Minute + * SS Second + * CR Carriage return + * LF Linefeed + * ST Status character + * Bit 0 - Set= Initialised; Reset=Time Invalid (DO NOT USE) + * Bit 1 - Set= Synchronised; Reset= Unsynchronised + * Bit 2 - Set= Alarm state; Reset= No alarm + * Bit 3 - Set= BST; Reset= GMT + * Bit 4 - Set= Seasonal change in approx hour; Reset= No seasonal change expected + * Bit 5 - Set= Last MSF telegram was OK; Reset= Last telegram was in error; + * Bit 6 - Always set + * Bit 7 - Unused + * XXX Checksum calculated using Fletcher's method (ignored for now). + */ + +static struct format varitext_fmt = +{ + { + {8, 2}, {5, 2}, {2, 2}, /* day, month, year */ + {14, 2}, {17, 2}, {20, 2}, /* hour, minute, second */ + {11, 2}, {24, 1} /* dayofweek, status */ + }, + (const unsigned char*)"T: : : : : : : \r\n ", + 0 +}; + +static u_long cvt_varitext P((unsigned char *, int, struct format *, clocktime_t *, void *)); +static u_long inp_varitext P((parse_t *, unsigned int, timestamp_t *)); + +struct varitext { + unsigned char start_found; + unsigned char end_found; + unsigned char end_count; + unsigned char previous_ch; + timestamp_t tstamp; +}; + +clockformat_t clock_varitext = +{ + inp_varitext, /* Because of the strange format we need to parse it ourselves */ + cvt_varitext, /* Varitext conversion */ + 0, /* no PPS monitoring */ + (void *)&varitext_fmt, /* conversion configuration */ + "Varitext Radio Clock", /* Varitext Radio Clock */ + 30, /* string buffer */ + sizeof(struct varitext), /* Private data size required to hold current parse state */ +}; + +/* + * cvt_varitext + * + * convert simple type format + */ +static u_long +cvt_varitext( + unsigned char *buffer, + int size, + struct format *format, + clocktime_t *clock_time, + void *local + ) +{ + + if (!Strok(buffer, format->fixed_string)) { + return CVT_NONE; + } else { + if (Stoi(&buffer[format->field_offsets[O_DAY].offset], &clock_time->day, + format->field_offsets[O_DAY].length) || + Stoi(&buffer[format->field_offsets[O_MONTH].offset], &clock_time->month, + format->field_offsets[O_MONTH].length) || + Stoi(&buffer[format->field_offsets[O_YEAR].offset], &clock_time->year, + format->field_offsets[O_YEAR].length) || + Stoi(&buffer[format->field_offsets[O_HOUR].offset], &clock_time->hour, + format->field_offsets[O_HOUR].length) || + Stoi(&buffer[format->field_offsets[O_MIN].offset], &clock_time->minute, + format->field_offsets[O_MIN].length) || + Stoi(&buffer[format->field_offsets[O_SEC].offset], &clock_time->second, + format->field_offsets[O_SEC].length)) { + return CVT_FAIL | CVT_BADFMT; + } else { + u_char *f = (u_char*) &buffer[format->field_offsets[O_FLAGS].offset]; + + clock_time->flags = 0; + clock_time->utcoffset = 0; + + if (((*f) & VT_BST)) /* BST flag is set so set to indicate daylight saving time is active and utc offset */ + { + clock_time->utcoffset = -1*60*60; + clock_time->flags |= PARSEB_DST; + } + /* + if (!((*f) & VT_INITIALISED)) Clock not initialised + clock_time->flags |= PARSEB_POWERUP; + + if (!((*f) & VT_SYNCHRONISED)) Clock not synchronised + clock_time->flags |= PARSEB_NOSYNC; + + if (((*f) & VT_SEASON_CHANGE)) Seasonal change expected in the next hour + clock_time->flags |= PARSEB_ANNOUNCE; + */ + return CVT_OK; + } + } +} + +static u_long +inp_varitext( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + struct varitext *t = (struct varitext *)parseio->parse_pdata; + int rtc; + + parseprintf(DD_PARSE, ("inp_varitext(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + if (!t) + return PARSE_INP_SKIP; /* local data not allocated - sigh! */ + + if (ch == 'T') + t->tstamp = *tstamp; + + if ((t->previous_ch == 'T') && (ch == ':')) + { + parseprintf(DD_PARSE, ("inp_varitext: START seen\n")); + + parseio->parse_data[0] = 'T'; + parseio->parse_index=1; + parseio->parse_dtime.parse_stime = t->tstamp; /* Time stamp at packet start */ + t->start_found = 1; + t->end_found = 0; + t->end_count = 0; + } + + if (t->start_found) + { + if ((rtc = parse_addchar(parseio, ch)) != PARSE_INP_SKIP) + { + parseprintf(DD_PARSE, ("inp_varitext: ABORTED due to too many characters\n")); + + memset(t, 0, sizeof(struct varitext)); + return rtc; + } + + if (t->end_found) + { + if (++(t->end_count) == 4) /* Finally found the end of the message */ + { + parseprintf(DD_PARSE, ("inp_varitext: END seen\n")); + + memset(t, 0, sizeof(struct varitext)); + if ((rtc = parse_addchar(parseio, 0)) == PARSE_INP_SKIP) + return parse_end(parseio); + else + return rtc; + } + } + + if ((t->previous_ch == '\r') && (ch == '\n')) + { + t->end_found = 1; + } + + } + + t->previous_ch = ch; + + return PARSE_INP_SKIP; +} + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_VARITEXT) */ +int clk_varitext_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_VARITEXT) */ + +/* + * Revision 1.0 1997/06/02 13:16:30 McConnell + * File created + * + */ diff --git a/contrib/ntp/libparse/clk_wharton.c b/contrib/ntp/libparse/clk_wharton.c new file mode 100644 index 000000000000..2a243a5c114b --- /dev/null +++ b/contrib/ntp/libparse/clk_wharton.c @@ -0,0 +1,180 @@ +/* + * /src/NTP/ntp-4/libparse/clk_wharton.c,v 4.1 1999/02/28 15:27:24 kardel RELEASE_19990228_A + * + * clk_wharton.c,v 4.1 1999/02/28 15:27:24 kardel RELEASE_19990228_A + * + * From Philippe De Muyter , 1999 + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_WHARTON_400A) +/* + * Support for WHARTON 400A Series clock + 404.2 serial interface. + * + * Copyright (C) 1999 by Philippe De Muyter + * + * 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 "ntp_fp.h" +#include "ascii.h" +#include "parse.h" + +#ifndef PARSESTREAM +#include "ntp_stdlib.h" +#include +#else +#include "sys/parsestreams.h" +extern void printf P((const char *, ...)); +#endif + +/* + * In private e-mail alastair@wharton.co.uk said : + * "If you are going to use the 400A and 404.2 system [for ntp] I recommend + * that you set the 400A to output the message every second. The start of + * transmission of the first byte of the message is synchronised to the + * second edge." + * The WHARTON 400A Series is able to send date/time serial messages + * in 7 output formats. We use format 1 here because it is the shortest. + * For use with this driver, the WHARTON 400A Series clock must be set-up + * as follows : + * Programmable Selected + * Option No Option + * BST or CET display 3 9 or 11 + * No external controller 7 0 + * Serial Output Format 1 9 1 + * Baud rate 9600 bps 10 96 + * Bit length 8 bits 11 8 + * Parity even 12 E + * + * WHARTON 400A Series output format 1 is as follows : + * + * Timestamp STXssmmhhDDMMYYSETX + * Pos 0 12345678901234 + * 0 00000000011111 + * + * STX start transmission (ASCII 0x02) + * ETX end transmission (ASCII 0x03) + * ss Second expressed in reversed decimal (units then tens) + * mm Minute expressed in reversed decimal + * hh Hour expressed in reversed decimal + * DD Day of month expressed in reversed decimal + * MM Month expressed in reversed decimal (January is 1) + * YY Year (without century) expressed in reversed decimal + * S Status byte : 0x30 + + * bit 0 0 = MSF source 1 = DCF source + * bit 1 0 = Winter time 1 = Summer time + * bit 2 0 = not synchronised 1 = synchronised + * bit 3 0 = no early warning 1 = early warning + * + */ + +/* + * cvt_wharton_400a + * + * convert simple type format + */ +static u_long +cvt_wharton_400a( + unsigned char *buffer, + int size, + struct format *format, + clocktime_t *clock_time, + void *local + ) +{ + int i; + + /* The given `size' includes a terminating null-character. */ + if (size != 16 || buffer[0] != STX || buffer[14] != ETX) + return CVT_NONE; + for (i = 1; i < 14; i += 1) + if (buffer[i] < '0' || buffer[i] > '9') + return CVT_NONE; + clock_time->second = (buffer[2] - '0') * 10 + buffer[1] - '0'; + clock_time->minute = (buffer[4] - '0') * 10 + buffer[3] - '0'; + clock_time->hour = (buffer[6] - '0') * 10 + buffer[5] - '0'; + clock_time->day = (buffer[8] - '0') * 10 + buffer[7] - '0'; + clock_time->month = (buffer[10] - '0') * 10 + buffer[9] - '0'; + clock_time->year = (buffer[12] - '0') * 10 + buffer[11] - '0'; + clock_time->usecond = 0; + if (buffer[13] & 0x1) /* We have CET time */ + clock_time->utcoffset = -1*60*60; + else /* We have BST time */ + clock_time->utcoffset = 0; + if (buffer[13] & 0x2) { + clock_time->flags |= PARSEB_DST; + clock_time->utcoffset += -1*60*60; + } + if (!(buffer[13] & 0x4)) + clock_time->flags |= PARSEB_NOSYNC; + if (buffer[13] & 0x8) + clock_time->flags |= PARSEB_ANNOUNCE; + + return CVT_OK; +} + +/* + * inp_wharton_400a + * + * grep data from input stream + */ +static u_long +inp_wharton_400a( + parse_t *parseio, + unsigned int ch, + timestamp_t *tstamp + ) +{ + unsigned int rtc; + + parseprintf(DD_PARSE, ("inp_wharton_400a(0x%x, 0x%x, ...)\n", (int)parseio, (int)ch)); + + switch (ch) + { + case STX: + parseprintf(DD_PARSE, ("inp_wharton_400a: STX seen\n")); + + parseio->parse_index = 1; + parseio->parse_data[0] = ch; + parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */ + return PARSE_INP_SKIP; + + case ETX: + parseprintf(DD_PARSE, ("inp_wharton_400a: ETX seen\n")); + if ((rtc = parse_addchar(parseio, ch)) == PARSE_INP_SKIP) + return parse_end(parseio); + else + return rtc; + + default: + return parse_addchar(parseio, ch); + } +} + +clockformat_t clock_wharton_400a = +{ + inp_wharton_400a, /* input handling function */ + cvt_wharton_400a, /* conversion function */ + 0, /* no PPS monitoring */ + 0, /* conversion configuration */ + "WHARTON 400A Series clock Output Format 1", /* String format name */ + 15, /* string buffer */ + 0 /* no private data (complete pakets) */ +}; + +#else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_WHARTON_400A) */ +int clk_wharton_400a_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_WHARTON_400A) */ + +/* + * clk_wharton.c,v + * Revision 4.1 1999/02/28 15:27:24 kardel + * wharton clock integration + * + */ diff --git a/contrib/ntp/libparse/data_mbg.c b/contrib/ntp/libparse/data_mbg.c new file mode 100644 index 000000000000..af7987d0714a --- /dev/null +++ b/contrib/ntp/libparse/data_mbg.c @@ -0,0 +1,490 @@ +/* + * /src/NTP/ntp-4/libparse/data_mbg.c,v 4.3 1999/02/21 12:17:42 kardel RELEASE_19990228_A + * + * $Created: Sun Jul 20 12:08:14 1997 $ + * + * Copyright (C) 1997, 1998 by Frank Kardel + */ + +#ifdef PARSESTREAM +#define NEED_BOPS +#include "ntp_string.h" +#else +#include +#endif +#include "ntp_types.h" +#include "ntp_stdlib.h" +#include "ntp_fp.h" +#include "mbg_gps166.h" +#include "binio.h" +#include "ieee754io.h" + +static void get_mbg_tzname P((unsigned char **, char *)); +static void mbg_time_status_str P((unsigned char **, unsigned int)); + +#if 0 /* no actual floats on Meinberg binary interface */ +static offsets_t mbg_float = { 1, 0, 3, 2, 0, 0, 0, 0 }; /* byte order for meinberg floats */ +#endif +static offsets_t mbg_double = { 1, 0, 3, 2, 5, 4, 7, 6 }; /* byte order for meinberg doubles */ +static int32 rad2deg_i = 57; +static u_int32 rad2deg_f = 0x4BB834C7; /* 57.2957795131 == 180/PI */ + +void +put_mbg_header( + unsigned char **bufpp, + GPS_MSG_HDR *headerp + ) +{ + put_lsb_short(bufpp, headerp->gps_cmd); + put_lsb_short(bufpp, headerp->gps_len); + put_lsb_short(bufpp, headerp->gps_data_csum); + put_lsb_short(bufpp, headerp->gps_hdr_csum); +} + +void +get_mbg_sw_rev( + unsigned char **bufpp, + SW_REV *sw_revp + ) +{ + sw_revp->code = get_lsb_short(bufpp); + memcpy(sw_revp->name, *bufpp, sizeof(sw_revp->name)); + *bufpp += sizeof(sw_revp->name); +} + +void +get_mbg_ascii_msg( + unsigned char **bufpp, + ASCII_MSG *ascii_msgp + ) +{ + ascii_msgp->csum = get_lsb_short(bufpp); + ascii_msgp->valid = get_lsb_short(bufpp); + memcpy(ascii_msgp->s, *bufpp, sizeof(ascii_msgp->s)); + *bufpp += sizeof(ascii_msgp->s); +} + +void +get_mbg_svno( + unsigned char **bufpp, + SVNO *svnop + ) +{ + *svnop = get_lsb_short(bufpp); +} + +void +get_mbg_health( + unsigned char **bufpp, + HEALTH *healthp + ) +{ + *healthp = get_lsb_short(bufpp); +} + +void +get_mbg_cfg( + unsigned char **bufpp, + CFG *cfgp + ) +{ + *cfgp = get_lsb_short(bufpp); +} + +void +get_mbg_tgps( + unsigned char **bufpp, + T_GPS *tgpsp + ) +{ + tgpsp->wn = get_lsb_short(bufpp); + tgpsp->sec = get_lsb_long(bufpp); + tgpsp->tick = get_lsb_long(bufpp); +} + +void +get_mbg_tm( + unsigned char **buffpp, + TM *tmp + ) +{ + tmp->year = get_lsb_short(buffpp); + tmp->month = *(*buffpp)++; + tmp->mday = *(*buffpp)++; + tmp->yday = get_lsb_short(buffpp); + tmp->wday = *(*buffpp)++; + tmp->hour = *(*buffpp)++; + tmp->minute = *(*buffpp)++; + tmp->second = *(*buffpp)++; + tmp->frac = get_lsb_long(buffpp); + tmp->offs_from_utc = get_lsb_long(buffpp); + tmp->status= get_lsb_short(buffpp); +} + +void +get_mbg_ttm( + unsigned char **buffpp, + TTM *ttmp + ) +{ + ttmp->channel = get_lsb_short(buffpp); + get_mbg_tgps(buffpp, &ttmp->t); + get_mbg_tm(buffpp, &ttmp->tm); +} + +void +get_mbg_synth( + unsigned char **buffpp, + SYNTH *synthp + ) +{ + synthp->freq = get_lsb_short(buffpp); + synthp->range = get_lsb_short(buffpp); + synthp->phase = get_lsb_short(buffpp); +} + +static void +get_mbg_tzname( + unsigned char **buffpp, + char *tznamep + ) +{ + strncpy(tznamep, (char *)*buffpp, sizeof(TZ_NAME)); + *buffpp += sizeof(TZ_NAME); +} + +void +get_mbg_tzdl( + unsigned char **buffpp, + TZDL *tzdlp + ) +{ + tzdlp->offs = get_lsb_long(buffpp); + tzdlp->offs_dl = get_lsb_long(buffpp); + get_mbg_tm(buffpp, &tzdlp->tm_on); + get_mbg_tm(buffpp, &tzdlp->tm_off); + get_mbg_tzname(buffpp, (char *)tzdlp->name[0]); + get_mbg_tzname(buffpp, (char *)tzdlp->name[1]); +} + +void +get_mbg_antinfo( + unsigned char **buffpp, + ANT_INFO *antinfop + ) +{ + antinfop->status = get_lsb_short(buffpp); + get_mbg_tm(buffpp, &antinfop->tm_disconn); + get_mbg_tm(buffpp, &antinfop->tm_reconn); + antinfop->delta_t = get_lsb_long(buffpp); +} + +static void +mbg_time_status_str( + unsigned char **buffpp, + unsigned int status + ) +{ + static struct state + { + int flag; /* bit flag */ + const char *string; /* bit name */ + } states[] = + { + { TM_UTC, "UTC CORR" }, + { TM_LOCAL, "LOCAL TIME" }, + { TM_DL_ANN, "DST WARN" }, + { TM_DL_ENB, "DST" }, + { TM_LS_ANN, "LEAP WARN" }, + { TM_LS_ENB, "LEAP SEC" }, + { 0, "" } + }; + + if (status) + { + unsigned char *p; + struct state *s; + + p = *buffpp; + + for (s = states; s->flag; s++) + { + if (s->flag & status) + { + if (p != *buffpp) + { + *p++ = ','; + *p++ = ' '; + } + strcpy((char *)p, s->string); + p += strlen((char *)p); + } + } + *buffpp = p; + } +} + +void +mbg_tm_str( + unsigned char **buffpp, + TM *tmp + ) +{ + sprintf((char *)*buffpp, "%04d-%02d-%02d %02d:%02d:%02d.%07ld (%c%02d%02d) ", + tmp->year, tmp->month, tmp->mday, + tmp->hour, tmp->minute, tmp->second, tmp->frac, + (tmp->offs_from_utc < 0) ? '-' : '+', + abs(tmp->offs_from_utc) / 3600, + (abs(tmp->offs_from_utc) / 60) % 60); + *buffpp += strlen((char *)*buffpp); + mbg_time_status_str(buffpp, tmp->status); +} + +void +mbg_tgps_str( + unsigned char **buffpp, + T_GPS *tgpsp + ) +{ + sprintf((char *)*buffpp, "week %d + %ld days + %ld.%07ld sec", + tgpsp->wn, tgpsp->sec / 86400, + tgpsp->sec % 86400, tgpsp->tick); + *buffpp += strlen((char *)*buffpp); +} + +void +get_mbg_cfgh( + unsigned char **buffpp, + CFGH *cfghp + ) +{ + int i; + + cfghp->csum = get_lsb_short(buffpp); + cfghp->valid = get_lsb_short(buffpp); + get_mbg_tgps(buffpp, &cfghp->tot_51); + get_mbg_tgps(buffpp, &cfghp->tot_63); + get_mbg_tgps(buffpp, &cfghp->t0a); + + for (i = MIN_SVNO; i <= MAX_SVNO; i++) + { + get_mbg_cfg(buffpp, &cfghp->cfg[i]); + } + + for (i = MIN_SVNO; i <= MAX_SVNO; i++) + { + get_mbg_health(buffpp, &cfghp->health[i]); + } +} + +void +get_mbg_utc( + unsigned char **buffpp, + UTC *utcp + ) +{ + utcp->csum = get_lsb_short(buffpp); + utcp->valid = get_lsb_short(buffpp); + + get_mbg_tgps(buffpp, &utcp->t0t); + + if (fetch_ieee754(buffpp, IEEE_DOUBLE, &utcp->A0, mbg_double) != IEEE_OK) + { + L_CLR(&utcp->A0); + } + + if (fetch_ieee754(buffpp, IEEE_DOUBLE, &utcp->A1, mbg_double) != IEEE_OK) + { + L_CLR(&utcp->A1); + } + + utcp->WNlsf = get_lsb_short(buffpp); + utcp->DNt = get_lsb_short(buffpp); + utcp->delta_tls = *(*buffpp)++; + utcp->delta_tlsf = *(*buffpp)++; +} + +void +get_mbg_lla( + unsigned char **buffpp, + LLA lla + ) +{ + int i; + + for (i = LAT; i <= ALT; i++) + { + if (fetch_ieee754(buffpp, IEEE_DOUBLE, &lla[i], mbg_double) != IEEE_OK) + { + L_CLR(&lla[i]); + } + else + if (i != ALT) + { /* convert to degrees (* 180/PI) */ + mfp_mul(&lla[i].l_i, &lla[i].l_uf, lla[i].l_i, lla[i].l_uf, rad2deg_i, rad2deg_f); + } + } +} + +void +get_mbg_xyz( + unsigned char **buffpp, + XYZ xyz + ) +{ + int i; + + for (i = XP; i <= ZP; i++) + { + if (fetch_ieee754(buffpp, IEEE_DOUBLE, &xyz[i], mbg_double) != IEEE_OK) + { + L_CLR(&xyz[i]); + } + } +} + +static void +get_mbg_comparam( + unsigned char **buffpp, + COM_PARM *comparamp + ) +{ + int i; + + comparamp->baud_rate = get_lsb_long(buffpp); + for (i = 0; i < sizeof(comparamp->framing); i++) + { + comparamp->framing[i] = *(*buffpp)++; + } + comparamp->handshake = get_lsb_short(buffpp); +} + +void +get_mbg_portparam( + unsigned char **buffpp, + PORT_PARM *portparamp + ) +{ + int i; + + for (i = 0; i < N_COM; i++) + { + get_mbg_comparam(buffpp, &portparamp->com[i]); + } + for (i = 0; i < N_COM; i++) + { + portparamp->mode[i] = *(*buffpp)++; + } +} + +#define FETCH_DOUBLE(src, addr) \ + if (fetch_ieee754(src, IEEE_DOUBLE, addr, mbg_double) != IEEE_OK) \ + { \ + L_CLR(addr); \ + } + +void +get_mbg_eph( + unsigned char ** buffpp, + EPH *ephp + ) +{ + ephp->csum = get_lsb_short(buffpp); + ephp->valid = get_lsb_short(buffpp); + + ephp->health = get_lsb_short(buffpp); + ephp->IODC = get_lsb_short(buffpp); + ephp->IODE2 = get_lsb_short(buffpp); + ephp->IODE3 = get_lsb_short(buffpp); + + get_mbg_tgps(buffpp, &ephp->tt); + get_mbg_tgps(buffpp, &ephp->t0c); + get_mbg_tgps(buffpp, &ephp->t0e); + + FETCH_DOUBLE(buffpp, &ephp->sqrt_A); + FETCH_DOUBLE(buffpp, &ephp->e); + FETCH_DOUBLE(buffpp, &ephp->M0); + FETCH_DOUBLE(buffpp, &ephp->omega); + FETCH_DOUBLE(buffpp, &ephp->OMEGA0); + FETCH_DOUBLE(buffpp, &ephp->OMEGADOT); + FETCH_DOUBLE(buffpp, &ephp->deltan); + FETCH_DOUBLE(buffpp, &ephp->i0); + FETCH_DOUBLE(buffpp, &ephp->idot); + FETCH_DOUBLE(buffpp, &ephp->crc); + FETCH_DOUBLE(buffpp, &ephp->crs); + FETCH_DOUBLE(buffpp, &ephp->cuc); + FETCH_DOUBLE(buffpp, &ephp->cus); + FETCH_DOUBLE(buffpp, &ephp->cic); + FETCH_DOUBLE(buffpp, &ephp->cis); + + FETCH_DOUBLE(buffpp, &ephp->af0); + FETCH_DOUBLE(buffpp, &ephp->af1); + FETCH_DOUBLE(buffpp, &ephp->af2); + FETCH_DOUBLE(buffpp, &ephp->tgd); + + ephp->URA = get_lsb_short(buffpp); + + ephp->L2code = *(*buffpp)++; + ephp->L2flag = *(*buffpp)++; +} + +void +get_mbg_alm( + unsigned char **buffpp, + ALM *almp + ) +{ + almp->csum = get_lsb_short(buffpp); + almp->valid = get_lsb_short(buffpp); + + almp->health = get_lsb_short(buffpp); + get_mbg_tgps(buffpp, &almp->t0a); + + + FETCH_DOUBLE(buffpp, &almp->sqrt_A); + FETCH_DOUBLE(buffpp, &almp->e); + + FETCH_DOUBLE(buffpp, &almp->M0); + FETCH_DOUBLE(buffpp, &almp->omega); + FETCH_DOUBLE(buffpp, &almp->OMEGA0); + FETCH_DOUBLE(buffpp, &almp->OMEGADOT); + FETCH_DOUBLE(buffpp, &almp->deltai); + FETCH_DOUBLE(buffpp, &almp->af0); + FETCH_DOUBLE(buffpp, &almp->af1); +} + +void +get_mbg_iono( + unsigned char **buffpp, + IONO *ionop + ) +{ + ionop->csum = get_lsb_short(buffpp); + ionop->valid = get_lsb_short(buffpp); + + FETCH_DOUBLE(buffpp, &ionop->alpha_0); + FETCH_DOUBLE(buffpp, &ionop->alpha_1); + FETCH_DOUBLE(buffpp, &ionop->alpha_2); + FETCH_DOUBLE(buffpp, &ionop->alpha_3); + + FETCH_DOUBLE(buffpp, &ionop->beta_0); + FETCH_DOUBLE(buffpp, &ionop->beta_1); + FETCH_DOUBLE(buffpp, &ionop->beta_2); + FETCH_DOUBLE(buffpp, &ionop->beta_3); +} + +/* + * data_mbg.c,v + * Revision 4.3 1999/02/21 12:17:42 kardel + * 4.91f reconcilation + * + * Revision 4.2 1998/06/14 21:09:39 kardel + * Sun acc cleanup + * + * Revision 4.1 1998/05/24 08:02:06 kardel + * trimmed version log + * + * Revision 4.0 1998/04/10 19:45:33 kardel + * Start 4.0 release version numbering + */ + diff --git a/contrib/ntp/libparse/info_trimble.c b/contrib/ntp/libparse/info_trimble.c new file mode 100644 index 000000000000..af508582aa95 --- /dev/null +++ b/contrib/ntp/libparse/info_trimble.c @@ -0,0 +1,94 @@ +/* +* Automatically generated - do not modify +*/ + +#include "ntp_types.h" +#include "ntpd.h" +#include "trimble.h" + +cmd_info_t trimble_scmds[] = { + { CMD_CCLROSC, "CMD_CCLROSC", "clear oscillator offset (0x1D)", "", 0 }, + { CMD_CCLRRST, "CMD_CCLRRST", "clear battery backup and RESET (0x1E)", "", 0 }, + { CMD_CVERSION, "CMD_CVERSION", "return software version (0x1F)", "", 0 }, + { CMD_CALMANAC, "CMD_CALMANAC", "almanac (0x20)", "", 0 }, + { CMD_CCURTIME, "CMD_CCURTIME", "current time (0x21)", "", 0 }, + { CMD_CMODESEL, "CMD_CMODESEL", "mode select (2-d, 3-D, auto) (0x22)", "", 0 }, + { CMD_CINITPOS, "CMD_CINITPOS", "initial position (0x23)", "", 0 }, + { CMD_CRECVPOS, "CMD_CRECVPOS", "receiver position fix mode (0x24)", "", 0 }, + { CMD_CRESET, "CMD_CRESET", "soft reset & selftest (0x25)", "", 0 }, + { CMD_CRECVHEALTH, "CMD_CRECVHEALTH", "receiver health (0x26)", "", 0 }, + { CMD_CSIGNALLV, "CMD_CSIGNALLV", "signal levels (0x27)", "", 0 }, + { CMD_CMESSAGE, "CMD_CMESSAGE", "GPS system message (0x28)", "", 0 }, + { CMD_CALMAHEALTH, "CMD_CALMAHEALTH", "almanac healt page (0x29)", "", 0 }, + { CMD_C2DALTITUDE, "CMD_C2DALTITUDE", "altitude for 2-D mode (0x2A)", "", 0 }, + { CMD_CINITPOSLLA, "CMD_CINITPOSLLA", "initial position LLA (0x2B)", "", 0 }, + { CMD_COPERPARAM, "CMD_COPERPARAM", "operating parameters (0x2C)", "", 0 }, + { CMD_COSCOFFSET, "CMD_COSCOFFSET", "oscillator offset (0x2D)", "", 0 }, + { CMD_CSETGPSTIME, "CMD_CSETGPSTIME", "set GPS time (0x2E)", "", 0 }, + { CMD_CUTCPARAM, "CMD_CUTCPARAM", "UTC parameters (0x2F)", "", 0 }, + { CMD_CACCPOSXYZ, "CMD_CACCPOSXYZ", "accurate initial position (XYZ/ECEF) (0x31)", "", 0 }, + { CMD_CACCPOS, "CMD_CACCPOS", "accurate initial position (0x32)", "", 0 }, + { CMD_CANALOGDIG, "CMD_CANALOGDIG", "analog to digital (0x33)", "", 0 }, + { CMD_CSAT1SAT, "CMD_CSAT1SAT", "satellite for 1-Sat mode (0x34)", "", 0 }, + { CMD_CIOOPTIONS, "CMD_CIOOPTIONS", "I/O options (0x35)", "", 0 }, + { CMD_CVELOCAID, "CMD_CVELOCAID", "velocity aiding of acquisition (0x36)", "", 0 }, + { CMD_CSTATLSTPOS, "CMD_CSTATLSTPOS", "status and values of last pos. and vel. (0x37)", "", 0 }, + { CMD_CLOADSSATDT, "CMD_CLOADSSATDT", "load satellite system data (0x38)", "", 0 }, + { CMD_CSATDISABLE, "CMD_CSATDISABLE", "satellite disable (0x39)", "", 0 }, + { CMD_CLASTRAW, "CMD_CLASTRAW", "last raw measurement (0x3A)", "", 0 }, + { CMD_CSTATSATEPH, "CMD_CSTATSATEPH", "satellite ephemeris status (0x3B)", "", 0 }, + { CMD_CSTATTRACK, "CMD_CSTATTRACK", "tracking status (0x3C)", "", 0 }, + { CMD_CCHANADGPS, "CMD_CCHANADGPS", "configure channel A for differential GPS (0x3D)", "", 0 }, + { CMD_CADDITFIX, "CMD_CADDITFIX", "additional fix data (0x3E)", "", 0 }, + { CMD_CDGPSFIXMD, "CMD_CDGPSFIXMD", "set/request differential GPS position fix mode (0x62)", "", 0 }, + { CMD_CDGPSCORR, "CMD_CDGPSCORR", "differential correction status (0x65)", "", 0 }, + { CMD_CPOSFILT, "CMD_CPOSFILT", "position filter parameters (0x71)", "", 0 }, + { CMD_CHEIGHTFILT, "CMD_CHEIGHTFILT", "height filter control (0x73)", "", 0 }, + { CMD_CHIGH8CNT, "CMD_CHIGH8CNT", "high-8 (best 4) / high-6 (overdetermined) control (0x75)", "", 0 }, + { CMD_CMAXDGPSCOR, "CMD_CMAXDGPSCOR", "maximum rate of DGPS corrections (0x77)", "", 0 }, + { CMD_CSUPER, "CMD_CSUPER", "super paket (0x8E)", "", 0 }, +{ 0xFF, "", "" } +}; + + +cmd_info_t trimble_rcmds[] = { + { CMD_RDATAA, "CMD_RDATAA", "data channel A configuration (0x3D)", "trimble_channelA", RO }, + { CMD_RALMANAC, "CMD_RALMANAC", "almanac data for sat (0x40)", "gps_almanac", RO }, + { CMD_RCURTIME, "CMD_RCURTIME", "GPS time (0x41)", "gps_time", RO }, + { CMD_RSPOSXYZ, "CMD_RSPOSXYZ", "single precision XYZ position (0x42)", "gps_position(XYZ)", RO|DEF }, + { CMD_RVELOXYZ, "CMD_RVELOXYZ", "velocity fix (XYZ ECEF) (0x43)", "gps_velocity(XYZ)", RO|DEF }, + { CMD_RBEST4, "CMD_RBEST4", "best 4 satellite selection (0x44)", "trimble_best4", RO|DEF }, + { CMD_RVERSION, "CMD_RVERSION", "software version (0x45)", "trimble_version", RO|DEF }, + { CMD_RRECVHEALTH, "CMD_RRECVHEALTH", "receiver health (0x46)", "trimble_receiver_health", RO|DEF }, + { CMD_RSIGNALLV, "CMD_RSIGNALLV", "signal levels of all satellites (0x47)", "trimble_signal_levels", RO }, + { CMD_RMESSAGE, "CMD_RMESSAGE", "GPS system message (0x48)", "gps-message", RO|DEF }, + { CMD_RALMAHEALTH, "CMD_RALMAHEALTH", "almanac health page for all satellites (0x49)", "gps_almanac_health", RO }, + { CMD_RSLLAPOS, "CMD_RSLLAPOS", "single LLA position (0x4A)", "gps_position(LLA)", RO|DEF }, + { CMD_RMACHSTAT, "CMD_RMACHSTAT", "machine code / status (0x4B)", "trimble_status", RO|DEF }, + { CMD_ROPERPARAM, "CMD_ROPERPARAM", "operating parameters (0x4C)", "trimble_opparam", RO }, + { CMD_ROSCOFFSET, "CMD_ROSCOFFSET", "oscillator offset (0x4D)", "trimble_oscoffset", RO }, + { CMD_RSETGPSTIME, "CMD_RSETGPSTIME", "response to set GPS time (0x4E)", "trimble_setgpstime", RO }, + { CMD_RUTCPARAM, "CMD_RUTCPARAM", "UTC parameters (0x4F)", "gps_utc_correction", RO|DEF }, + { CMD_RANALOGDIG, "CMD_RANALOGDIG", "analog to digital (0x53)", "trimble_analogdigital", RO }, + { CMD_RSAT1BIAS, "CMD_RSAT1BIAS", "one-satellite bias & bias rate (0x54)", "trimble_sat1bias", RO }, + { CMD_RIOOPTIONS, "CMD_RIOOPTIONS", "I/O options (0x55)", "trimble_iooptions", RO }, + { CMD_RSTATLSTFIX, "CMD_RSTATLSTFIX", "status and values of last pos. and vel. (0x57)", "trimble_status_lastpos", RO }, + { CMD_RLOADSSATDT, "CMD_RLOADSSATDT", "response to load satellite system data (0x58)", "trimble_loaddata", RO }, + { CMD_RSATDISABLE, "CMD_RSATDISABLE", "satellite disable (0x59)", "trimble_satdisble", RO }, + { CMD_RLASTRAW, "CMD_RLASTRAW", "last raw measurement (0x5A)", "trimble_lastraw", RO }, + { CMD_RSTATSATEPH, "CMD_RSTATSATEPH", "satellite ephemeris status (0x5B)", "trimble_ephstatus", RO }, + { CMD_RSTATTRACK, "CMD_RSTATTRACK", "tracking status (0x5C)", "trimble_tracking_status", RO|DEF }, + { CMD_RADDITFIX, "CMD_RADDITFIX", "additional fix data (0x5E)", "trimble_addfix", RO }, + { CMD_RALLINVIEW, "CMD_RALLINVIEW", "all in view satellite selection (0x6D)", "trimble_satview", RO|DEF }, + { CMD_RPOSFILT, "CMD_RPOSFILT", "position filter parameters (0x72)", "trimble_posfilt", RO }, + { CMD_RHEIGHTFILT, "CMD_RHEIGHTFILT", "height filter control (0x74)", "trimble_heightfilt", RO }, + { CMD_RHIGH8CNT, "CMD_RHIGH8CNT", "high-8 (best 4) / high-6 (overdetermined) control (0x76)", "trimble_high8control", RO }, + { CMD_RMAXAGE, "CMD_RMAXAGE", "DC MaxAge (0x78)", "trimble_dgpsmaxage", RO }, + { CMD_RDGPSFIX, "CMD_RDGPSFIX", "differential position fix mode (0x82)", "trimble_dgpsfixmode", RO }, + { CMD_RDOUBLEXYZ, "CMD_RDOUBLEXYZ", "double precision XYZ (0x83)", "gps_position_ext(XYZ)", RO|DEF }, + { CMD_RDOUBLELLA, "CMD_RDOUBLELLA", "double precision LLA (0x84)", "gps_position_ext(LLA)", RO|DEF }, + { CMD_RDGPSSTAT, "CMD_RDGPSSTAT", "differential correction status (0x85)", "trimble_dgpsstatus", RO }, + { CMD_RSUPER, "CMD_RSUPER", "super paket (0x8F)", "", 0 }, +{ 0xFF, "", "" } +}; + diff --git a/contrib/ntp/libparse/kclk_computime.c b/contrib/ntp/libparse/kclk_computime.c new file mode 100644 index 000000000000..14707b98801f --- /dev/null +++ b/contrib/ntp/libparse/kclk_computime.c @@ -0,0 +1,17 @@ +/* + * /src/NTP/ntp-4/libparse/kclk_computime.c,v 4.2 1998/07/11 10:05:27 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 09:58:27 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_computime.c" +/* + * kclk_computime.c,v + * Revision 4.2 1998/07/11 10:05:27 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/13 12:09:27 kardel + * hack to compile the source for kernel/user-land + */ diff --git a/contrib/ntp/libparse/kclk_dcf7000.c b/contrib/ntp/libparse/kclk_dcf7000.c new file mode 100644 index 000000000000..e5d9436c565b --- /dev/null +++ b/contrib/ntp/libparse/kclk_dcf7000.c @@ -0,0 +1,17 @@ +/* + * /src/NTP/ntp-4/libparse/kclk_dcf7000.c,v 4.2 1998/07/11 10:05:27 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 09:59:11 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_dcf7000.c" +/* + * kclk_dcf7000.c,v + * Revision 4.2 1998/07/11 10:05:27 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/13 12:09:28 kardel + * hack to compile the source for kernel/user-land + */ diff --git a/contrib/ntp/libparse/kclk_hopf6021.c b/contrib/ntp/libparse/kclk_hopf6021.c new file mode 100644 index 000000000000..2d51788b625e --- /dev/null +++ b/contrib/ntp/libparse/kclk_hopf6021.c @@ -0,0 +1,17 @@ +/* + * /src/NTP/ntp-4/libparse/kclk_hopf6021.c,v 4.2 1998/07/11 10:05:28 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 09:59:57 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_hopf6021.c" +/* + * kclk_hopf6021.c,v + * Revision 4.2 1998/07/11 10:05:28 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/13 12:09:29 kardel + * hack to compile the source for kernel/user-land + */ diff --git a/contrib/ntp/libparse/kclk_meinberg.c b/contrib/ntp/libparse/kclk_meinberg.c new file mode 100644 index 000000000000..7cdb3e17093a --- /dev/null +++ b/contrib/ntp/libparse/kclk_meinberg.c @@ -0,0 +1,17 @@ +/* + * /src/NTP/ntp-4/libparse/kclk_meinberg.c,v 4.2 1998/07/11 10:05:28 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 10:00:28 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_meinberg.c" +/* + * kclk_meinberg.c,v + * Revision 4.2 1998/07/11 10:05:28 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/13 12:09:29 kardel + * hack to compile the source for kernel/user-land + */ diff --git a/contrib/ntp/libparse/kclk_rawdcf.c b/contrib/ntp/libparse/kclk_rawdcf.c new file mode 100644 index 000000000000..45ba743764f2 --- /dev/null +++ b/contrib/ntp/libparse/kclk_rawdcf.c @@ -0,0 +1,15 @@ +/* + * /src/NTP/ntp-4/libparse/kclk_rawdcf.c,v 4.1 1998/06/13 12:07:55 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 10:03:35 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_rawdcf.c" +/* + * kclk_rawdcf.c,v + * Revision 4.1 1998/06/13 12:07:55 kardel + * standard format + * + */ diff --git a/contrib/ntp/libparse/kclk_rcc8000.c b/contrib/ntp/libparse/kclk_rcc8000.c new file mode 100644 index 000000000000..67e6550b96c1 --- /dev/null +++ b/contrib/ntp/libparse/kclk_rcc8000.c @@ -0,0 +1,17 @@ +/* + * /src/NTP/ntp-4/libparse/kclk_rcc8000.c,v 4.2 1998/07/11 10:05:28 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 10:01:11 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_rcc8000.c" +/* + * kclk_rcc8000.c,v + * Revision 4.2 1998/07/11 10:05:28 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/13 12:09:29 kardel + * hack to compile the source for kernel/user-land + */ diff --git a/contrib/ntp/libparse/kclk_schmid.c b/contrib/ntp/libparse/kclk_schmid.c new file mode 100644 index 000000000000..ee87b7eed059 --- /dev/null +++ b/contrib/ntp/libparse/kclk_schmid.c @@ -0,0 +1,17 @@ +/* + * /src/NTP/ntp-4/libparse/kclk_schmid.c,v 4.2 1998/07/11 10:05:28 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 10:01:42 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_schmid.c" +/* + * kclk_schmid.c,v + * Revision 4.2 1998/07/11 10:05:28 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/13 12:09:30 kardel + * hack to compile the source for kernel/user-land + */ diff --git a/contrib/ntp/libparse/kclk_trimtaip.c b/contrib/ntp/libparse/kclk_trimtaip.c new file mode 100644 index 000000000000..20193f4e7b27 --- /dev/null +++ b/contrib/ntp/libparse/kclk_trimtaip.c @@ -0,0 +1,17 @@ +/* + * /src/NTP/ntp-4/libparse/kclk_trimtaip.c,v 4.2 1998/07/11 10:05:29 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 10:02:35 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_trimtaip.c" +/* + * kclk_trimtaip.c,v + * Revision 4.2 1998/07/11 10:05:29 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/13 12:09:30 kardel + * hack to compile the source for kernel/user-land + */ diff --git a/contrib/ntp/libparse/kclk_trimtsip.c b/contrib/ntp/libparse/kclk_trimtsip.c new file mode 100644 index 000000000000..1dcfec8029f8 --- /dev/null +++ b/contrib/ntp/libparse/kclk_trimtsip.c @@ -0,0 +1,17 @@ +/* + * /src/NTP/ntp-4/libparse/kclk_trimtsip.c,v 4.2 1998/07/11 10:05:29 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 10:04:12 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_trimtsip.c" +/* + * kclk_trimtsip.c,v + * Revision 4.2 1998/07/11 10:05:29 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/13 12:08:02 kardel + * standard format + */ diff --git a/contrib/ntp/libparse/kclk_varitext.c b/contrib/ntp/libparse/kclk_varitext.c new file mode 100644 index 000000000000..3ecc69dc228d --- /dev/null +++ b/contrib/ntp/libparse/kclk_varitext.c @@ -0,0 +1,28 @@ +/* + * $Header: /cvs/ntp/libparse/kclk_varitext.c,v 1.1 1999/07/25 09:21:16 stenn Exp $ + * + * $Created: Sat Jun 13 09:58:27 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_varitext.c" +/* + * $Log: kclk_varitext.c,v $ + * Revision 1.1 1999/07/25 09:21:16 stenn + * * configure.in: 4.0.94b + * + * * acconfig.h: + * * configure.in: + * * libparse/Makefile.am: + * * libparse/parse_conf.c: + * * libparse/clk_varitext.c: + * * libparse/kclk_varitext.c: + * * ntpd/refclock_parse.c: VARITEXT parse clock + * * ntpdate/ntpdate.c: bugfix + * From: Tony McConnell + * + * Revision 4.1 1998/06/13 12:09:27 kardel + * hack to compile the source for kernel/user-land + * + */ diff --git a/contrib/ntp/libparse/kclk_wharton.c b/contrib/ntp/libparse/kclk_wharton.c new file mode 100644 index 000000000000..0496f773d6d2 --- /dev/null +++ b/contrib/ntp/libparse/kclk_wharton.c @@ -0,0 +1,15 @@ +/* + * /src/NTP/ntp-4/libparse/kclk_wharton.c,v 4.1 1999/02/28 15:50:08 kardel RELEASE_19990228_A + * + * $Created: Sun Feb 28 16:46:14 MET 1999 $ + * + * Copyright (C) 1999 by Frank Kardel + */ +#define PARSESTREAM +#include "clk_wharton.c" +/* + * kclk_wharton.c,v + * Revision 4.1 1999/02/28 15:50:08 kardel + * new clock input machine + * + */ diff --git a/contrib/ntp/libparse/kparse.c b/contrib/ntp/libparse/kparse.c new file mode 100644 index 000000000000..a79943d76d81 --- /dev/null +++ b/contrib/ntp/libparse/kparse.c @@ -0,0 +1,17 @@ +/* + * /src/NTP/ntp-4/libparse/kparse.c,v 4.2 1998/07/11 10:05:29 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 10:04:47 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "parse.c" +/* + * kparse.c,v + * Revision 4.2 1998/07/11 10:05:29 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/13 12:08:12 kardel + * standard format + */ diff --git a/contrib/ntp/libparse/kparse_conf.c b/contrib/ntp/libparse/kparse_conf.c new file mode 100644 index 000000000000..be8628e3e179 --- /dev/null +++ b/contrib/ntp/libparse/kparse_conf.c @@ -0,0 +1,17 @@ +/* + * /src/NTP/ntp-4/libparse/kparse_conf.c,v 4.2 1998/07/11 10:05:30 kardel RELEASE_19990228_A + * + * $Created: Sat Jun 13 10:05:32 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#define PARSESTREAM +#include "parse_conf.c" +/* + * kparse_conf.c,v + * Revision 4.2 1998/07/11 10:05:30 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.1 1998/06/13 12:08:12 kardel + * standard format + */ diff --git a/contrib/ntp/libparse/mkinfo_rcmd.sed b/contrib/ntp/libparse/mkinfo_rcmd.sed new file mode 100644 index 000000000000..570c7a0b81e2 --- /dev/null +++ b/contrib/ntp/libparse/mkinfo_rcmd.sed @@ -0,0 +1,8 @@ +1i\ +\ +cmd_info_t trimble_rcmds[] = { +s!^#define[ ][ ]*\(CMD_R[^ ]*\)[ ][ ]*\([^ ]*\)[ ][ ]*/\*[ ][ ]*\(.*\)[ ]*:\([^:]*\):\([^:]*\)[ ][ ]*\*/! { \1, "\1", "\3 (\2)", "\4", \5 },!p +$a\ + { 0xFF, "", "" }\ +};\ + diff --git a/contrib/ntp/libparse/mkinfo_scmd.sed b/contrib/ntp/libparse/mkinfo_scmd.sed new file mode 100644 index 000000000000..cabe0654588d --- /dev/null +++ b/contrib/ntp/libparse/mkinfo_scmd.sed @@ -0,0 +1,16 @@ +1i\ +/*\ + * Automatically generated - do not modify\ + */\ +\ +#include "ntp_types.h"\ +#include "ntpd.h"\ +#include "trimble.h"\ +\ +cmd_info_t trimble_scmds[] = { +s!^#define[ ][ ]*\(CMD_C[^ ]*\)[ ][ ]*\([^ ]*\)[ ][ ]*/\*[ ][ ]*\(.*\)[ ][ ]*\*/! { \1, "\1", "\3 (\2)", "", 0 },!p +$a\ + { 0xFF, "", "" }\ +};\ + + diff --git a/contrib/ntp/libparse/parse.c b/contrib/ntp/libparse/parse.c new file mode 100644 index 000000000000..3d8485e14254 --- /dev/null +++ b/contrib/ntp/libparse/parse.c @@ -0,0 +1,917 @@ +/* + * /src/NTP/ntp-4/libparse/parse.c,v 4.13 1999/02/28 11:50:20 kardel RELEASE_19990228_A + * + * parse.c,v 4.13 1999/02/28 11:50:20 kardel RELEASE_19990228_A + * + * Parser module for reference clock + * + * PARSEKERNEL define switches between two personalities of the module + * if PARSEKERNEL is defined this module can be used + * as 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-1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) + +#if !(defined(lint) || defined(__GNUC__)) +static char rcsid[] = "parse.c,v 4.13 1999/02/28 11:50:20 kardel RELEASE_19990228_A"; +#endif + +#include +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" +#include "ntp_machine.h" +#include "ntp.h" /* (get Y2KFixes definitions) Y2KFixes */ + +#include "parse.h" + +#ifndef PARSESTREAM +#include +#else +#include "sys/parsestreams.h" +#endif + +extern clockformat_t *clockformats[]; +extern unsigned short nformats; + +static u_long timepacket P((parse_t *)); + +/* + * strings support usually not in kernel - duplicated, but what the heck + */ +static int +Strlen( + register const char *s + ) +{ + register int c; + + c = 0; + if (s) + { + while (*s++) + { + c++; + } + } + return c; +} + +static int +Strcmp( + register const char *s, + register const char *t + ) +{ + register int c = 0; + + if (!s || !t || (s == t)) + { + return 0; + } + + while (!(c = *s++ - *t++) && *s && *t) + /* empty loop */; + + return c; +} + +int +parse_timedout( + parse_t *parseio, + timestamp_t *tstamp, + struct timeval *del + ) +{ + struct timeval delta; + +#ifdef PARSEKERNEL + delta.tv_sec = tstamp->tv.tv_sec - parseio->parse_lastchar.tv.tv_sec; + delta.tv_usec = tstamp->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 = tstamp->fp; + L_SUB(&delt, &parseio->parse_lastchar.fp); + TSTOTV(&delt, &delta); +#endif + + if (timercmp(&delta, del, >)) + { + parseprintf(DD_PARSE, ("parse: timedout: TRUE\n")); + return 1; + } + else + { + parseprintf(DD_PARSE, ("parse: timedout: FALSE\n")); + return 0; + } +} + +/*ARGSUSED*/ +int +parse_ioinit( + register parse_t *parseio + ) +{ + parseprintf(DD_PARSE, ("parse_iostart\n")); + + parseio->parse_plen = 0; + parseio->parse_pdata = (void *)0; + + parseio->parse_data = 0; + parseio->parse_ldata = 0; + parseio->parse_dsize = 0; + + parseio->parse_badformat = 0; + parseio->parse_ioflags = PARSE_IO_CS7; /* usual unix default */ + parseio->parse_index = 0; + parseio->parse_ldsize = 0; + + return 1; +} + +/*ARGSUSED*/ +void +parse_ioend( + register parse_t *parseio + ) +{ + parseprintf(DD_PARSE, ("parse_ioend\n")); + + if (parseio->parse_pdata) + FREE(parseio->parse_pdata, parseio->parse_plen); + + if (parseio->parse_data) + FREE(parseio->parse_data, (unsigned)(parseio->parse_dsize * 2 + 2)); +} + +unsigned int +parse_restart( + parse_t *parseio, + unsigned int ch + ) +{ + unsigned int updated = PARSE_INP_SKIP; + + /* + * re-start packet - timeout - overflow - start symbol + */ + + if (parseio->parse_index) + { + /* + * filled buffer - thus not end character found + * do processing now + */ + parseio->parse_data[parseio->parse_index] = '\0'; + memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1)); + parseio->parse_ldsize = parseio->parse_index+1; + updated = PARSE_INP_TIME; + } + + parseio->parse_index = 1; + parseio->parse_data[0] = ch; + parseprintf(DD_PARSE, ("parse: parse_restart: buffer start (updated = %x)\n", updated)); + return updated; +} + +unsigned int +parse_addchar( + parse_t *parseio, + unsigned int ch + ) +{ + /* + * add to buffer + */ + if (parseio->parse_index < parseio->parse_dsize) + { + /* + * collect into buffer + */ + parseprintf(DD_PARSE, ("parse: parse_addchar: buffer[%d] = 0x%x\n", parseio->parse_index, ch)); + parseio->parse_data[parseio->parse_index++] = ch; + return PARSE_INP_SKIP; + } + else + /* + * buffer overflow - attempt to make the best of it + */ + return parse_restart(parseio, ch); +} + +unsigned int +parse_end( + parse_t *parseio + ) +{ + /* + * message complete processing + */ + parseio->parse_data[parseio->parse_index] = '\0'; + memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1)); + parseio->parse_ldsize = parseio->parse_index+1; + parseio->parse_index = 0; + parseprintf(DD_PARSE, ("parse: parse_end: buffer end\n")); + return PARSE_INP_TIME; +} + +/*ARGSUSED*/ +int +parse_ioread( + register parse_t *parseio, + register unsigned int ch, + register timestamp_t *tstamp + ) +{ + register unsigned updated = CVT_NONE; + /* + * 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: + ch &= 0xFF; + break; + } + + parseprintf(DD_PARSE, ("parse_ioread(0x%lx, char=0x%x, ..., ...)\n", (unsigned long)parseio, ch & 0xFF)); + + if (!clockformats[parseio->parse_lformat]->convert) + { + parseprintf(DD_PARSE, ("parse_ioread: input dropped.\n")); + return CVT_NONE; + } + + if (clockformats[parseio->parse_lformat]->input) + { + unsigned long input_status; + + input_status = clockformats[parseio->parse_lformat]->input(parseio, ch, tstamp); + + if (input_status & PARSE_INP_SYNTH) + { + updated = CVT_OK; + } + + if (input_status & PARSE_INP_TIME) /* time sample is available */ + { + updated = timepacket(parseio); + } + + if (input_status & PARSE_INP_DATA) /* got additional data */ + { + updated |= CVT_ADDITIONAL; + } + } + + + /* + * remember last character time + */ + parseio->parse_lastchar = *tstamp; + +#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) || + ((updated & CVT_ADDITIONAL) != 0)); +} + +/* + * 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( + 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 (clockformats[parseio->parse_lformat]->syncpps) + { + updated = clockformats[parseio->parse_lformat]->syncpps(parseio, status == SYNC_ONE, ptime); + parseprintf(DD_PARSE, ("parse_iopps: updated = 0x%x\n", updated)); + } + + return (updated & CVT_MASK) != CVT_NONE; +} + +/* + * parse_iodone + * + * clean up internal status for new round + */ +/*ARGSUSED*/ +void +parse_iodone( + register parse_t *parseio + ) +{ + /* + * we need to clean up certain flags for the next round + */ + parseprintf(DD_PARSE, ("parse_iodone: DONE\n")); + 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 days_per_year(x) ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366)) + +time_t +parse_to_unixtime( + register clocktime_t *clock_time, + register u_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_time->utctime) + return clock_time->utctime; /* if the conversion routine gets it right away - why not */ + + if ( clock_time->year < YEAR_PIVOT ) /* Y2KFixes [ */ + clock_time->year += 100; /* convert 20xx%100 to 20xx-1900 */ + if ( clock_time->year < YEAR_BREAK ) /* expand to full four-digits */ + clock_time->year += 1900; + + if (clock_time->year < 1970 ) /* Y2KFixes ] */ + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; + } + + /* + * sorry, slow section here - but it's not time critical anyway + */ + t = julian0(clock_time->year) - julian0(1970); /* Y2kFixes */ + /* month */ + if (clock_time->month <= 0 || clock_time->month > 12) + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; /* bad month */ + } + +#if 0 /* Y2KFixes */ + /* adjust leap year */ + if (clock_time->month < 3 && days_per_year(clock_time->year) == 366) + t--; +#else /* Y2KFixes [ */ + if ( clock_time->month >= 3 && isleap_4(clock_time->year) ) + t++; /* add one more if within leap year */ +#endif /* Y2KFixes ] */ + + for (i = 1; i < clock_time->month; i++) + { + t += days_of_month[i]; + } + /* day */ + if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ? + clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month])) + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; /* bad day */ + } + + t += clock_time->day - 1; + /* hour */ + if (clock_time->hour < 0 || clock_time->hour >= 24) + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad hour */ + } + + t = TIMES24(t) + clock_time->hour; + + /* min */ + if (clock_time->minute < 0 || clock_time->minute > 59) + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad min */ + } + + t = TIMES60(t) + clock_time->minute; + /* sec */ + + if (clock_time->second < 0 || clock_time->second > 60) /* allow for LEAPs */ + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad sec */ + } + + t = TIMES60(t) + clock_time->second; + + t += clock_time->utcoffset; /* warp to UTC */ + + /* done */ + + clock_time->utctime = t; /* documentray only */ + + return t; +} + +/*--------------- format conversion -----------------------------------*/ + +int +Stoi( + const unsigned char *s, + long *zp, + int cnt + ) +{ + char unsigned const *b = s; + int f,z,v; + char unsigned 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( + const unsigned char *s, + const unsigned char *m + ) +{ + if (!s || !m) + return 0; + + while(*s && *m) + { + if ((*m == ' ') ? 1 : (*s == *m)) + { + s++; + m++; + } + else + { + return 0; + } + } + return !*m; +} + +u_long +updatetimeinfo( + register parse_t *parseio, + register u_long flags + ) +{ +#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((unsigned int)s); + } +#endif + + +#ifdef PARSEKERNEL + parseprintf(DD_PARSE, ("updatetimeinfo status=0x%x, time=%x\n", parseio->parse_dtime.parse_state, + parseio->parse_dtime.parse_time.tv.tv_sec)); +#else + parseprintf(DD_PARSE, ("updatetimeinfo status=0x%lx, time=%x\n", (long)parseio->parse_dtime.parse_state, + parseio->parse_dtime.parse_time.fp.l_ui)); +#endif + + return CVT_OK; /* everything fine and dandy... */ +} + + +/* + * syn_simple + * + * handle a sync time stamp + */ +/*ARGSUSED*/ +void +syn_simple( + register parse_t *parseio, + register timestamp_t *ts, + register struct format *format, + register u_long why + ) +{ + parseio->parse_dtime.parse_stime = *ts; +} + +/* + * pps_simple + * + * handle a pps time stamp + */ +/*ARGSUSED*/ +u_long +pps_simple( + 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; +} + +/* + * pps_one + * + * handle a pps time stamp in ONE edge + */ +/*ARGSUSED*/ +u_long +pps_one( + register parse_t *parseio, + register int status, + register timestamp_t *ptime + ) +{ + if (status) + return pps_simple(parseio, status, ptime); + + return CVT_NONE; +} + +/* + * pps_zero + * + * handle a pps time stamp in ZERO edge + */ +/*ARGSUSED*/ +u_long +pps_zero( + register parse_t *parseio, + register int status, + register timestamp_t *ptime + ) +{ + if (!status) + return pps_simple(parseio, status, ptime); + + return CVT_NONE; +} + +/* + * timepacket + * + * process a data packet + */ +static u_long +timepacket( + register parse_t *parseio + ) +{ + register unsigned short format; + register time_t t; + u_long cvtrtc; /* current conversion result */ + clocktime_t clock_time; + + memset((char *)&clock_time, 0, sizeof clock_time); + format = parseio->parse_lformat; + + if (format == (unsigned short)~0) + return CVT_NONE; + + switch ((cvtrtc = clockformats[format]->convert ? + clockformats[format]->convert((unsigned char *)parseio->parse_ldata, parseio->parse_ldsize, (struct format *)(clockformats[format]->data), &clock_time, parseio->parse_pdata) : + CVT_NONE) & CVT_MASK) + { + case CVT_FAIL: + parseio->parse_badformat++; + break; + + case CVT_NONE: + /* + * too bad - pretend bad format + */ + parseio->parse_badformat++; + break; + + case CVT_OK: + break; + + case CVT_SKIP: + return CVT_NONE; + + default: + /* shouldn't happen */ +#ifndef PARSEKERNEL + msyslog(LOG_WARNING, "parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format]->name); +#endif + return CVT_FAIL|cvtrtc; + } + + if ((t = parse_to_unixtime(&clock_time, &cvtrtc)) == -1) + { + return CVT_FAIL|cvtrtc; + } + + /* + * time stamp + */ +#ifdef PARSEKERNEL + parseio->parse_dtime.parse_time.tv.tv_sec = t; + parseio->parse_dtime.parse_time.tv.tv_usec = clock_time.usecond; +#else + parseio->parse_dtime.parse_time.fp.l_ui = t + JAN_1970; + TVUTOTSF(clock_time.usecond, parseio->parse_dtime.parse_time.fp.l_uf); +#endif + + parseio->parse_dtime.parse_format = format; + + return updatetimeinfo(parseio, clock_time.flags); +} + +/*ARGSUSED*/ +int +parse_timecode( + 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; + memcpy(dct->parsegettc.parse_buffer, parse->parse_ldata, dct->parsegettc.parse_count); + return 1; + } + else + { + return 0; + } +} + + +/*ARGSUSED*/ +int +parse_setfmt( + 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)) + { + if (parse->parse_pdata) + FREE(parse->parse_pdata, parse->parse_plen); + parse->parse_pdata = 0; + + parse->parse_plen = clockformats[i]->plen; + + if (parse->parse_plen) + { + parse->parse_pdata = MALLOC(parse->parse_plen); + if (!parse->parse_pdata) + { + parseprintf(DD_PARSE, ("set format failed: malloc for private data area failed\n")); + return 0; + } + memset((char *)parse->parse_pdata, 0, parse->parse_plen); + } + + if (parse->parse_data) + FREE(parse->parse_data, (unsigned)(parse->parse_dsize * 2 + 2)); + parse->parse_ldata = parse->parse_data = 0; + + parse->parse_dsize = clockformats[i]->length; + + if (parse->parse_dsize) + { + parse->parse_data = (char*)MALLOC((unsigned)(parse->parse_dsize * 2 + 2)); + if (!parse->parse_data) + { + if (parse->parse_pdata) + FREE(parse->parse_pdata, parse->parse_plen); + parse->parse_pdata = 0; + + parseprintf(DD_PARSE, ("init failed: malloc for data area failed\n")); + return 0; + } + } + + + /* + * leave room for '\0' + */ + parse->parse_ldata = parse->parse_data + parse->parse_dsize + 1; + + parse->parse_lformat = i; + + return 1; + } + } + } + } + return 0; +} + +/*ARGSUSED*/ +int +parse_getfmt( + 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; + memcpy(dct->parseformat.parse_buffer, clockformats[dct->parseformat.parse_format]->name, dct->parseformat.parse_count); + return 1; + } + else + { + return 0; + } +} + +/*ARGSUSED*/ +int +parse_setcs( + parsectl_t *dct, + parse_t *parse + ) +{ + parse->parse_ioflags &= ~PARSE_IO_CSIZE; + parse->parse_ioflags |= dct->parsesetcs.parse_cs & PARSE_IO_CSIZE; + return 1; +} + +#else /* not (REFCLOCK && CLOCK_PARSE) */ +int parse_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE) */ + +/* + * History: + * + * parse.c,v + * Revision 4.13 1999/02/28 11:50:20 kardel + * (timepacket): removed unecessary code + * + * Revision 4.12 1999/02/21 12:17:44 kardel + * 4.91f reconcilation + * + * Revision 4.11 1999/02/21 11:09:47 kardel + * unified debug output + * + * Revision 4.10 1998/12/20 23:45:30 kardel + * fix types and warnings + * + * Revision 4.9 1998/08/09 22:26:06 kardel + * Trimble TSIP support + * + * Revision 4.8 1998/06/14 21:09:39 kardel + * Sun acc cleanup + * + * Revision 4.7 1998/06/13 15:19:13 kardel + * fix mem*() to b*() function macro emulation + * + * Revision 4.6 1998/06/13 13:24:13 kardel + * printf fmt + * + * Revision 4.5 1998/06/13 13:01:10 kardel + * printf fmt + * + * Revision 4.4 1998/06/13 12:12:10 kardel + * bcopy/memcpy cleanup + * fix SVSV name clash + * + * Revision 4.3 1998/06/12 15:22:30 kardel + * fix prototypes + * + * Revision 4.2 1998/06/12 09:13:27 kardel + * conditional compile macros fixed + * printf prototype + * + * Revision 4.1 1998/05/24 09:39:55 kardel + * implementation of the new IO handling model + * + * Revision 4.0 1998/04/10 19:45:36 kardel + * Start 4.0 release version numbering + * + * from V3 3.46 log info deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/libparse/parse_conf.c b/contrib/ntp/libparse/parse_conf.c new file mode 100644 index 000000000000..3333cd97d6e1 --- /dev/null +++ b/contrib/ntp/libparse/parse_conf.c @@ -0,0 +1,149 @@ +/* + * /src/NTP/ntp-4/libparse/parse_conf.c,v 4.4 1999/02/28 15:27:25 kardel RELEASE_19990228_A + * + * parse_conf.c,v 4.4 1999/02/28 15:27:25 kardel RELEASE_19990228_A + * + * 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) 1995-1998 by Frank Kardel + * Copyright (C) 1992-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) + +#include +#include + +#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_TRIMTAIP +extern clockformat_t clock_trimtaip; +#endif + +#ifdef CLOCK_TRIMTSIP +extern clockformat_t clock_trimtsip; +#endif + +#ifdef CLOCK_RCC8000 +extern clockformat_t clock_rcc8000; +#endif + +#ifdef CLOCK_HOPF6021 +extern clockformat_t clock_hopf6021; +#endif + +#ifdef CLOCK_COMPUTIME +extern clockformat_t clock_computime; +#endif + +#ifdef CLOCK_WHARTON_400A +extern clockformat_t clock_wharton_400a; +#endif + +#ifdef CLOCK_VARITEXT +extern clockformat_t clock_varitext; +#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_TRIMTAIP + &clock_trimtaip, +#endif +#ifdef CLOCK_TRIMTSIP + &clock_trimtsip, +#endif +#ifdef CLOCK_RCC8000 + &clock_rcc8000, +#endif +#ifdef CLOCK_HOPF6021 + &clock_hopf6021, +#endif +#ifdef CLOCK_COMPUTIME + &clock_computime, +#endif +#ifdef CLOCK_WHARTON_400A + &clock_wharton_400a, +#endif +#ifdef CLOCK_VARITEXT + &clock_varitext, +#endif + 0}; + +unsigned short nformats = sizeof(clockformats) / sizeof(clockformats[0]) - 1; + +#else /* not (REFCLOCK && CLOCK_PARSE) */ +int parse_conf_bs; +#endif /* not (REFCLOCK && CLOCK_PARSE) */ + +/* + * History: + * + * parse_conf.c,v + * Revision 4.4 1999/02/28 15:27:25 kardel + * wharton clock integration + * + * Revision 4.3 1998/08/16 18:52:15 kardel + * (clockformats): Trimble TSIP driver now also + * available for kernel operation + * + * Revision 4.2 1998/06/12 09:13:48 kardel + * conditional compile macros fixed + * + * Revision 4.1 1998/05/24 09:40:49 kardel + * adjustments of log messages + * + * + * from V3 3.24 log info deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/libparse/parsesolaris.c b/contrib/ntp/libparse/parsesolaris.c new file mode 100644 index 000000000000..e0e7c23bd382 --- /dev/null +++ b/contrib/ntp/libparse/parsesolaris.c @@ -0,0 +1,1173 @@ +/* + * /src/NTP/ntp-4/libparse/parsesolaris.c,v 4.6 1998/11/15 21:56:08 kardel RELEASE_19990228_A + * + * parsesolaris.c,v 4.6 1998/11/15 21:56:08 kardel RELEASE_19990228_A + * + * STREAMS module for reference clocks + * + * Copyright (C) 1993-1998 by Frank Kardel + * derived work from parsestreams.c ((c) 1991-1993, Frank Kardel) and + * dcf77sync.c((c) Frank Kardel) + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * 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. + * + */ + +#define _KERNEL /* it is a _KERNEL module */ + +#ifndef lint +static char rcsid[] = "parsesolaris.c,v 4.6 1998/11/15 21:56:08 kardel RELEASE_19990228_A"; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __GNUC__ /* makes it compile on Solaris 2.6 - acc doesn't like it -- GREAT! */ +#include +#endif + +#include "ntp_fp.h" +#include "parse.h" +#include + +/*--------------- loadable driver section -----------------------------*/ + +static struct streamtab parseinfo; + +static struct fmodsw fmod_templ = +{ + "parse", /* module name */ + &parseinfo, /* module information */ + D_NEW|D_MP|D_MTQPAIR, /* exclusive for q pair */ + /* 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 + } +}; + +/* + * module management routines + */ +/*ARGSUSED*/ +int +_init( + void + ) +{ + static char revision[] = "4.6"; + char *s, *S; + char *t; + +#ifndef lint + t = rcsid; +#endif + + /* + * 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, (unsigned)(S - s)); + } + } + return (mod_install(&modlinkage)); +} + +/*ARGSUSED*/ +int +_info( + struct modinfo *modinfop + ) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/*ARGSUSED*/ +int +_fini( + void + ) +{ + if (mod_remove(&modlinkage) != DDI_SUCCESS) + { + return EBUSY; + } + else + return DDI_SUCCESS; +} + +/*--------------- stream module definition ----------------------------*/ + +static int parseopen P((queue_t *, dev_t *, int, int, cred_t *)); +static int parseclose P((queue_t *, int)); +static int parsewput P((queue_t *, mblk_t *)); +static int parserput P((queue_t *, mblk_t *)); +static int parsersvc P((queue_t *)); + +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 */ + +#ifdef PARSEDEBUG +int parsedebug = ~0; +#else +int parsedebug = 0; +#endif + +/*--------------- 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) + +static int init_linemon P((queue_t *)); +static void close_linemon P((queue_t *, queue_t *)); + +#define M_PARSE 0x0001 +#define M_NOPARSE 0x0002 + +void +ntp_memset( + char *a, + int x, + int c + ) +{ + while (c-- > 0) + *a++ = x; +} + +static void +pprintf( + int lev, + const char *form, + ... + ) +{ + va_list ap; + + va_start(ap, form); + + if (lev & parsedebug) + vcmn_err(CE_CONT, (char *)form, ap); + + va_end(ap); +} + +static int +setup_stream( + queue_t *q, + int mode + ) +{ + register mblk_t *mp; + + pprintf(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|SO_ISNTTY; + 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(WR(q)->q_next, M_CTL, (mode == M_PARSE) ? MC_SERVICEIMM : + MC_SERVICEDEF); + } + else + { + pprintf(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 parsestream_t *parse; + static int notice = 0; + + pprintf(DD_OPEN, "parse: OPEN - q=%x\n", q); + + if (sflag != MODOPEN) + { /* open only for modules */ + pprintf(DD_OPEN, "parse: OPEN - FAILED - not MODOPEN\n"); + return EIO; + } + + if (q->q_ptr != (caddr_t)NULL) + { + pprintf(DD_OPEN, "parse: OPEN - FAILED - EXCLUSIVE ONLY\n"); + return EBUSY; + } + + q->q_ptr = (caddr_t)kmem_alloc(sizeof(parsestream_t), KM_SLEEP); + if (q->q_ptr == (caddr_t)0) + { + return ENOMEM; + } + + pprintf(DD_OPEN, "parse: OPEN - parse area q=%x, q->q_ptr=%x\n", q, q->q_ptr); + WR(q)->q_ptr = q->q_ptr; + pprintf(DD_OPEN, "parse: OPEN - WQ parse area q=%x, q->q_ptr=%x\n", WR(q), 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; + + qprocson(q); + + pprintf(DD_OPEN, "parse: OPEN - initializing io subsystem q=%x\n", q); + + if (!parse_ioinit(&parse->parse_io)) + { + /* + * ok guys - beat it + */ + qprocsoff(q); + + kmem_free((caddr_t)parse, sizeof(parsestream_t)); + + return EIO; + } + + pprintf(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 */ + pprintf(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) + { + cmn_err(CE_CONT, "?%s: Copyright (c) 1993-1998, Frank Kardel\n", modlstrmod.strmod_linkinfo); + notice = 1; + } + + return 0; + } + else + { + qprocsoff(q); + + kmem_free((caddr_t)parse, sizeof(parsestream_t)); + + return EIO; + } +} + +/*ARGSUSED*/ +static int +parseclose( + queue_t *q, + int flags + ) +{ + register parsestream_t *parse = (parsestream_t *)q->q_ptr; + register unsigned long s; + + pprintf(DD_CLOSE, "parse: CLOSE\n"); + + qprocsoff(q); + + 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; + + return 0; +} + +/* + * move unrecognized stuff upward + */ +static int +parsersvc( + queue_t *q + ) +{ + mblk_t *mp; + + while ((mp = getq(q))) + { + if (canputnext(q) || (mp->b_datap->db_type > QPCTL)) + { + putnext(q, mp); + pprintf(DD_RSVC, "parse: RSVC - putnext\n"); + } + else + { + putbq(q, mp); + pprintf(DD_RSVC, "parse: RSVC - flow control wait\n"); + break; + } + } + return 0; +} + +/* + * 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; + + pprintf(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: + pprintf(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 & (unsigned)~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_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_TIMECODE: + pprintf(DD_WPUT, "parse: parsewput - PARSEIOC_TIMECODE\n"); + ok = parse_timecode(dct, &parse->parse_io); + break; + + case PARSEIOC_SETFMT: + pprintf(DD_WPUT, "parse: parsewput - PARSEIOC_SETFMT\n"); + ok = parse_setfmt(dct, &parse->parse_io); + break; + + case PARSEIOC_GETFMT: + pprintf(DD_WPUT, "parse: parsewput - PARSEIOC_GETFMT\n"); + ok = parse_getfmt(dct, &parse->parse_io); + break; + + case PARSEIOC_SETCS: + pprintf(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; + } + pprintf(DD_WPUT, "parse: parsewput qreply - %s\n", (mp->b_datap->db_type == M_IOCNAK) ? "M_IOCNAK" : "M_IOCACK"); + qreply(q, mp); + break; + } + } + return 0; +} + +/* + * 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 (unsigned)~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 + */ + pprintf(DD_RPUT, "parse: parserput - forward type 0x%x\n", type); + + if (canputnext(q) || (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; + timespec_t hres_time; + + /* + * get time on packet delivery + */ + gethrestime(&hres_time); + ctime.tv.tv_sec = hres_time.tv_sec; + ctime.tv.tv_usec = hres_time.tv_nsec / 1000; + + if (!(parse->parse_status & PARSE_ENABLE)) + { + pprintf(DD_RPUT, "parse: parserput - parser disabled - forward type 0x%x\n", type); + if (canputnext(q) || (mp->b_datap->db_type > QPCTL)) + { + putnext(q, mp); + } + else + putq(q, mp); + } + else + { + pprintf(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, (unsigned int)ch, &ctime)) + { + /* + * up up and away (hopefully ...) + * don't press it if resources are tight or nobody wants it + */ + nmp = (mblk_t *)NULL; + if (canputnext(parse->parse_queue) && (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, (unsigned int)0, &ctime)) + { + /* + * up up and away (hopefully ...) + * don't press it if resources are tight or nobody wants it + */ + nmp = (mblk_t *)NULL; + if (canputnext(parse->parse_queue) && (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; + timespec_t hres_time; + register mblk_t *nmp; + register int status = cd_invert ^ (type == M_UNHANGUP); + + gethrestime(&hres_time); + ctime.tv.tv_sec = hres_time.tv_sec; + ctime.tv.tv_usec = hres_time.tv_nsec / 1000; + + pprintf(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 (canputnext(parse->parse_queue) && (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 (canputnext(q) || (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); + } + } + } + return 0; +} + +static int init_zs_linemon P((queue_t *, queue_t *)); /* handle line monitor for "zs" driver */ +static void close_zs_linemon P((queue_t *, queue_t *)); + +/*-------------------- CD isr status monitor ---------------*/ + +static int +init_linemon( + 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; + + pprintf(DD_INSTALL, "init_linemon: driver is \"%s\"\n", dname); + +#ifdef sun + if (dname && !strcmp(dname, "zs")) + { + return init_zs_linemon(dq, q); + } + else +#endif + { + pprintf(DD_INSTALL, "init_linemon: driver \"%s\" not suitable for CD monitoring\n", dname); + return 0; + } + } + pprintf(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; + } + pprintf(DD_INSTALL, "close_linemon: cannot find driver close routine for \"%s\"\n", dname); +#endif + } + pprintf(DD_INSTALL, "close_linemon: cannot find driver name\n"); +} + +#ifdef sun +#include +#include +#include +#include + +static void zs_xsisr P((struct zscom *)); /* zs external status interupt handler */ + +/* + * 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 + { + /* + * 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); + + if (szs == (struct savedzsops *)0) + { + pprintf(DD_INSTALL, "init_zs_linemon: CD monitor NOT installed - no memory\n"); + + return 0; + } + else + { + 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 (*) P((struct zscom *)))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 (*) P((struct zscom *)))zs_xsisr; + + mutex_exit(zs->zs_excl); + + pprintf(DD_INSTALL, "init_zs_linemon: CD monitor installed\n"); + + return 1; + } + } +} + +/* + * unregister our ISR routine - must call under splhigh() (or + * whatever block ZS status interrupts) + */ +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)); + + pprintf(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 const char *dname = "-UNKNOWN-"; + timespec_t hres_time; + + /* + * pick up current state + */ + zsstatus = SCC_READ0(); + + if (za->za_rr0 ^ (cdstate = zsstatus & ZSRR0_CD)) + { + timestamp_t cdevent; + register int status; + + /* + * time stamp + */ + gethrestime(&hres_time); + cdevent.tv.tv_sec = hres_time.tv_sec; + cdevent.tv.tv_usec = hres_time.tv_nsec / 1000; + + 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); + } + + pprintf(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"); + } + } + + if (cdstate) /* fake CARRIER status - XXX currently not coordinated */ + za->za_flags |= ZAS_CARR_ON; + else + za->za_flags &= ~ZAS_CARR_ON; + + /* + * 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; + } + } + + pprintf(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) P((struct zscom *)); + + /* + * 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"); + + pprintf(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 4.6 1998/11/15 21:56:08 kardel + * ntp_memset not necessary + * + * Revision 4.5 1998/11/15 21:23:37 kardel + * ntp_memset() replicated in Sun kernel files + * + * Revision 4.4 1998/06/14 21:09:40 kardel + * Sun acc cleanup + * + * Revision 4.3 1998/06/13 12:14:59 kardel + * more prototypes + * fix name clashes + * allow for ansi2knr + * + * Revision 4.2 1998/06/12 15:23:08 kardel + * fix prototypes + * adjust for ansi2knr + * + * Revision 4.1 1998/05/24 09:38:46 kardel + * streams initiated iopps calls (M_xHANGUP) are now consistent with the + * respective calls from zs_xsisr() + * simulation of CARRIER status to avoid unecessary M_xHANGUP messages + * + * Revision 4.0 1998/04/10 19:45:38 kardel + * Start 4.0 release version numbering + * + * from V3 3.28 log info deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/libparse/parsestreams.c b/contrib/ntp/libparse/parsestreams.c new file mode 100644 index 000000000000..1578229e19a8 --- /dev/null +++ b/contrib/ntp/libparse/parsestreams.c @@ -0,0 +1,1335 @@ +/* + * /src/NTP/ntp-4/libparse/parsestreams.c,v 4.6 1998/12/20 23:45:31 kardel RELEASE_19990228_A + * + * parsestreams.c,v 4.6 1998/12/20 23:45:31 kardel RELEASE_19990228_A + * + * STREAMS module for reference clocks + * (SunOS4.x) + * + * Copyright (c) 1989-1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * 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. + * + */ + +#define KERNEL /* MUST */ +#define VDDRV /* SHOULD */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef lint +static char rcsid[] = "parsestreams.c,v 4.6 1998/12/20 23:45:31 kardel RELEASE_19990228_A"; +#endif + +#ifndef KERNEL +#include "Bletch: MUST COMPILE WITH KERNEL DEFINE" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef VDDRV +#include +#endif + +#include "ntp_stdlib.h" +#include "ntp_fp.h" +/* + * just make checking compilers more silent + */ +extern int printf P((const char *, ...)); +extern int putctl1 P((queue_t *, int, int)); +extern int canput P((queue_t *)); +extern void putbq P((queue_t *, mblk_t *)); +extern void freeb P((mblk_t *)); +extern void qreply P((queue_t *, mblk_t *)); +extern void freemsg P((mblk_t *)); +extern void panic P((const char *, ...)); +extern void usec_delay P((int)); + +#include "parse.h" +#include "sys/parsestreams.h" + +/* + * use microtime instead of uniqtime if advised to + */ +#ifdef MICROTIME +#define uniqtime microtime +#endif + +#ifdef VDDRV +static unsigned int parsebusy = 0; + +/*--------------- loadable driver section -----------------------------*/ + +extern struct streamtab parseinfo; + + +#ifdef PPS_SYNC +static char mnam[] = "PARSEPPS "; /* name this baby - keep room for revision number */ +#else +static char mnam[] = "PARSE "; /* name this baby - keep room for revision number */ +#endif +struct vdldrv parsesync_vd = +{ + VDMAGIC_PSEUDO, /* nothing like a real driver - a STREAMS module */ + mnam, +}; + +/* + * strings support usually not in kernel + */ +static int +Strlen( + register const char *s + ) +{ + register int c; + + c = 0; + if (s) + { + while (*s++) + { + c++; + } + } + return c; +} + +static void +Strncpy( + register char *t, + register char *s, + register int c + ) +{ + if (s && t) + { + while ((c-- > 0) && (*t++ = *s++)) + ; + } +} + +static int +Strcmp( + register const char *s, + register const 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( + 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; +} + +void +ntp_memset( + char *a, + int x, + int c + ) +{ + while (c-- > 0) + *a++ = x; +} + +/* + * driver init routine + * since no mechanism gets us into and out of the fmodsw, we have to + * do it ourselves + */ +/*ARGSUSED*/ +int +xxxinit( + unsigned int fc, + struct vddrv *vdp, + addr_t vdin, + 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[] = "4.6"; + char *s, *S, *t; + + s = rcsid; /* NOOP - keep compilers happy */ + + 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 P((queue_t *, dev_t, int, int)); +static int parseclose P((queue_t *, int)); +static int parsewput P((queue_t *, mblk_t *)); +static int parserput P((queue_t *, mblk_t *)); +static int parsersvc P((queue_t *)); + +static char mn[] = "parse"; + +static struct module_info driverinfo = +{ + 0, /* module ID number */ + mn, /* 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 P((struct timeval *)); + +/*--------------- 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) + +static int init_linemon P((queue_t *)); +static void close_linemon P((queue_t *, queue_t *)); + +#define M_PARSE 0x0001 +#define M_NOPARSE 0x0002 + +static int +setup_stream( + queue_t *q, + int mode + ) +{ + mblk_t *mp; + + mp = allocb(sizeof(struct stroptions), BPRI_MED); + if (mp) + { + struct stroptions *str = (struct stroptions *)(void *)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( + queue_t *q, + dev_t dev, + int flag, + int sflag + ) +{ + 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)); + if (q->q_ptr == (caddr_t)0) + { + parseprintf(DD_OPEN,("parse: OPEN - FAILED - no memory\n")); +#ifdef VDDRV + parsebusy--; +#endif + return OPENFAIL; + } + WR(q)->q_ptr = q->q_ptr; + + parse = (parsestream_t *)(void *)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 */ + + 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) + { +#ifdef VDDRV + printf("%s: Copyright (C) 1991-1998, Frank Kardel\n", parsesync_vd.Drv_name); +#else + printf("%s: Copyright (C) 1991-1998, Frank Kardel\n", "parsestreams.c,v 4.6 1998/12/20 23:45:31 kardel RELEASE_19990228_A"); +#endif + notice = 1; + } + + return MODOPEN; + } + else + { + kmem_free((caddr_t)parse, sizeof(parsestream_t)); + +#ifdef VDDRV + parsebusy--; +#endif + return OPENFAIL; + } +} + +/*ARGSUSED*/ +static int +parseclose( + queue_t *q, + int flags + ) +{ + register parsestream_t *parse = (parsestream_t *)(void *)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 + return 0; +} + +/* + * move unrecognized stuff upward + */ +static int +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; + } + } + return 0; +} + +/* + * do ioctls and + * send stuff down - dont care about + * flow control + */ +static int +parsewput( + queue_t *q, + register mblk_t *mp + ) +{ + register int ok = 1; + register mblk_t *datap; + register struct iocblk *iocp; + parsestream_t *parse = (parsestream_t *)(void *)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 *)(void *)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 *)(void *)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 & (unsigned)~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_TIMECODE: + case PARSEIOC_SETFMT: + case PARSEIOC_GETFMT: + case PARSEIOC_SETCS: + if (iocp->ioc_count == sizeof(parsectl_t)) + { + parsectl_t *dct = (parsectl_t *)(void *)mp->b_cont->b_rptr; + + switch (iocp->ioc_cmd) + { + 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; + } + } + return 0; +} + +/* + * read characters from streams buffers + */ +static unsigned long +rdchar( + 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 (unsigned)~0; +} + +/* + * convert incoming data + */ +static int +parserput( + 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 *)(void *)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, (unsigned int)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, (unsigned int)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 *)(void *)q->q_ptr; + timestamp_t ctime; + register mblk_t *nmp; + register int status = cd_invert ^ (type == M_UNHANGUP); + + uniqtime(&ctime.tv); + + parseprintf(DD_RPUT,("parse: parserput - M_%sHANGUP\n", (type == M_HANGUP) ? "" : "UN")); + + if ((parse->parse_status & PARSE_ENABLE) && + parse_iopps(&parse->parse_io, (int)(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); + } + } + } + return 0; +} + +static int init_zs_linemon P((queue_t *, queue_t *)); /* handle line monitor for "zs" driver */ +static void close_zs_linemon P((queue_t *, queue_t *)); + +/*-------------------- CD isr status monitor ---------------*/ + +static int +init_linemon( + 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( + register queue_t *q, + register queue_t *my_q + ) +{ + /* + * find appropriate driver dependent routine + */ + if (q->q_qinfo && q->q_qinfo->qi_minfo) + { + register char *dname = q->q_qinfo->qi_minfo->mi_idname; + +#ifdef sun + if (dname && !Strcmp(dname, "zs")) + { + close_zs_linemon(q, my_q); + return; + } + parseprintf(DD_INSTALL, ("close_linemon: cannot find driver close routine for \"%s\"\n", dname)); +#endif + } + parseprintf(DD_INSTALL, ("close_linemon: cannot find driver name\n")); +} + +#ifdef sun + +#include +#include +#include + +static unsigned long cdmask = ZSRR0_CD; + +struct savedzsops +{ + struct zsops zsops; + struct zsops *oldzsops; +}; + +struct zsops *emergencyzs; +extern void zsopinit P((struct zscom *, struct zsops *)); +static int zs_xsisr P((struct zscom *)); /* zs external status interupt handler */ + +static int +init_zs_linemon( + register queue_t *q, + register queue_t *my_q + ) +{ + register struct zscom *zs; + register struct savedzsops *szs; + register parsestream_t *parsestream = (parsestream_t *)(void *)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 *)(void *)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 *)(void *)kmem_alloc(sizeof(struct savedzsops)); + + if (szs == (struct savedzsops *)0) + { + parseprintf(DD_INSTALL, ("init_zs_linemon: CD monitor NOT installed - no memory\n")); + + return 0; + } + else + { + parsestream->parse_data = (void *)szs; + + s = splhigh(); + + parsestream->parse_dqueue = q; /* remember driver */ + + szs->zsops = *zs->zs_ops; + szs->zsops.zsop_xsint = 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( + register queue_t *q, + register queue_t *my_q + ) +{ + register struct zscom *zs; + register parsestream_t *parsestream = (parsestream_t *)(void *)my_q->q_ptr; + + zs = ((struct zsaline *)(void *)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 */ + +#ifdef PPS_SYNC +extern void hardpps P((struct timeval *, long)); +#ifdef PPS_NEW +extern struct timeval timestamp; +#else +extern struct timeval pps_time; +#endif +#endif + +/* + * take external status interrupt (only CD interests us) + */ +static int +zs_xsisr( + struct zscom *zs + ) +{ + register struct zsaline *za = (struct zsaline *)(void *)zs->zs_priv; + register struct zscc_device *zsaddr = zs->zs_addr; + register queue_t *q; + register unsigned char zsstatus; + register int loopcheck; + register char *dname; +#ifdef PPS_SYNC + register unsigned int s; + register long usec; +#endif + + /* + * pick up current state + */ + zsstatus = zsaddr->zscc_control; + + if ((za->za_rr0 ^ zsstatus) & (cdmask)) + { + timestamp_t cdevent; + register int status; + + za->za_rr0 = (za->za_rr0 & ~(cdmask)) | (zsstatus & (cdmask)); + +#ifdef PPS_SYNC + s = splclock(); +#ifdef PPS_NEW + usec = timestamp.tv_usec; +#else + usec = pps_time.tv_usec; +#endif +#endif + /* + * time stamp + */ + uniqtime(&cdevent.tv); + +#ifdef PPS_SYNC + (void)splx(s); +#endif + + /* + * logical state + */ + status = cd_invert ? (zsstatus & cdmask) == 0 : (zsstatus & cdmask) != 0; + +#ifdef PPS_SYNC + if (status) + { + usec = cdevent.tv.tv_usec - usec; + if (usec < 0) + usec += 1000000; + + hardpps(&cdevent.tv, usec); + } +#endif + + q = za->za_ttycommon.t_readq; + + /* + * 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 *)(void *)q->q_ptr)->parse_status & PARSE_ENABLE) && + parse_iopps(&((parsestream_t *)(void *)q->q_ptr)->parse_io, (int)(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 *)(void *)q->q_ptr)->parse_io); + } + + if (status) + { + ((parsestream_t *)(void *)q->q_ptr)->parse_ppsclockev.tv = cdevent.tv; + ++(((parsestream_t *)(void *)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 + */ + ZSDELAY(2); + + if (!((za->za_rr0 ^ zsstatus) & ~(cdmask))) + { + /* + * all done - kill status indication and return + */ + zsaddr->zscc_control = ZSWR0_RESET_STATUS; /* might kill other conditions here */ + return 0; + } + } + + if (zsstatus & cdmask) /* fake CARRIER status */ + za->za_flags |= ZAS_CARR_ON; + else + za->za_flags &= ~ZAS_CARR_ON; + + /* + * 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 avoided 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) P((struct zscom *)); + + /* + * back home - phew (hopping along stream queues might + * prove dangerous to your health) + */ + if ((zsisr = ((struct savedzsops *)((parsestream_t *)(void *)q->q_ptr)->parse_data)->oldzsops->zsop_xsint)) + return 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 0; + } + } + + 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"); + return 0; +} +#endif /* sun */ + +/* + * History: + * + * parsestreams.c,v + * Revision 4.6 1998/12/20 23:45:31 kardel + * fix types and warnings + * + * Revision 4.5 1998/11/15 21:23:38 kardel + * ntp_memset() replicated in Sun kernel files + * + * Revision 4.4 1998/06/13 12:15:59 kardel + * superfluous variable removed + * + * Revision 4.3 1998/06/12 15:23:08 kardel + * fix prototypes + * adjust for ansi2knr + * + * Revision 4.2 1998/05/24 18:16:22 kardel + * moved copy of shadow status to the beginning + * + * Revision 4.1 1998/05/24 09:38:47 kardel + * streams initiated iopps calls (M_xHANGUP) are now consistent with the + * respective calls from zs_xsisr() + * simulation of CARRIER status to avoid unecessary M_xHANGUP messages + * + * Revision 4.0 1998/04/10 19:45:38 kardel + * Start 4.0 release version numbering + * + * from V3 3.37 log info deleted 1998/04/11 kardel + */ diff --git a/contrib/ntp/libparse/trim_info.c b/contrib/ntp/libparse/trim_info.c new file mode 100644 index 000000000000..ab2e1fe1ca55 --- /dev/null +++ b/contrib/ntp/libparse/trim_info.c @@ -0,0 +1,35 @@ +/* + * /src/NTP/ntp-4/libparse/trim_info.c,v 4.2 1998/12/20 23:45:31 kardel RELEASE_19990228_A + * + * $Created: Sun Aug 2 20:20:34 1998 $ + * + * Copyright (C) 1998 by Frank Kardel + */ +#include "ntp_types.h" +#include "trimble.h" + +cmd_info_t * +trimble_convert( + unsigned int cmd, + cmd_info_t *tbl + ) +{ + int i; + + for (i = 0; tbl[i].cmd != 0xFF; i++) + { + if (tbl[i].cmd == cmd) + return &tbl[i]; + } + return 0; +} + +/* + * trim_info.c,v + * Revision 4.2 1998/12/20 23:45:31 kardel + * fix types and warnings + * + * Revision 4.1 1998/08/09 22:27:48 kardel + * Trimble TSIP support + * + */ diff --git a/contrib/ntp/librsaref/Makefile.am b/contrib/ntp/librsaref/Makefile.am new file mode 100644 index 000000000000..32fd45768111 --- /dev/null +++ b/contrib/ntp/librsaref/Makefile.am @@ -0,0 +1,50 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +#AUTOMAKE_OPTIONS = ../util/ansi2knr +noinst_LIBRARIES = @MAKE_LIBRSAREF@ +EXTRA_LIBRARIES = librsaref.a +CLEANFILES = $(EXTRA_LIBRARIES) + +# NOTES: +# don't use RSAREF's global.h - we use ours. +# We already have a copy of des.h + +librsaref_a_SOURCES = \ + desc.c \ + digit.c \ + digit.h \ + md2.h \ + md2c.c \ + md5.h \ + md5c.c \ + nn.c \ + nn.h \ + prime.c \ + prime.h \ + r_dh.c \ + r_encode.c \ + r_enhanc.c \ + r_keygen.c \ + r_random.c \ + r_random.h \ + r_stdlib.c \ + rsa.c \ + rsa.h \ + rsaref.h + +BUILT_SOURCES = $(librsaref_a_SOURCES) +INCLUDES = -I$(top_srcdir)/include +ETAGS_ARGS = Makefile.am + +#EXTRA_DIST = + +$(librsaref_a_SOURCES): stamp-rsaref + for i in $(librsaref_a_SOURCES); do \ + case "@MAKE_LIBRSAREF@" in \ + '') touch $$i ;; \ + *) cmp -s $(srcdir)/$$i $(srcdir)/../rsaref2/source/$$i 2>/dev/null \ + || cp $(srcdir)/../rsaref2/source/$$i $(srcdir)/$$i ;; \ + esac ; \ + done + +stamp-rsaref: + touch stamp-rsaref diff --git a/contrib/ntp/librsaref/Makefile.in b/contrib/ntp/librsaref/Makefile.in new file mode 100644 index 000000000000..e2373e26ad42 --- /dev/null +++ b/contrib/ntp/librsaref/Makefile.in @@ -0,0 +1,346 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +#AUTOMAKE_OPTIONS = ../util/ansi2knr + + +noinst_LIBRARIES = @MAKE_LIBRSAREF@ +EXTRA_LIBRARIES = librsaref.a +CLEANFILES = $(EXTRA_LIBRARIES) + +# NOTES: +# don't use RSAREF's global.h - we use ours. +# We already have a copy of des.h + +librsaref_a_SOURCES = \ + desc.c \ + digit.c \ + digit.h \ + md2.h \ + md2c.c \ + md5.h \ + md5c.c \ + nn.c \ + nn.h \ + prime.c \ + prime.h \ + r_dh.c \ + r_encode.c \ + r_enhanc.c \ + r_keygen.c \ + r_random.c \ + r_random.h \ + r_stdlib.c \ + rsa.c \ + rsa.h \ + rsaref.h + + +BUILT_SOURCES = $(librsaref_a_SOURCES) +INCLUDES = -I$(top_srcdir)/include +ETAGS_ARGS = Makefile.am +subdir = librsaref +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +librsaref_a_LIBADD = +am_librsaref_a_OBJECTS = desc.o digit.o md2c.o md5c.o nn.o prime.o \ +r_dh.o r_encode.o r_enhanc.o r_keygen.o r_random.o r_stdlib.o rsa.o +librsaref_a_OBJECTS = $(am_librsaref_a_OBJECTS) +AR = ar +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(librsaref_a_SOURCES) +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +SOURCES = $(librsaref_a_SOURCES) +OBJECTS = $(am_librsaref_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps librsaref/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: +desc.o: +digit.o: +md2c.o: +md5c.o: +nn.o: +prime.o: +r_dh.o: +r_encode.o: +r_enhanc.o: +r_keygen.o: +r_random.o: +r_stdlib.o: +rsa.o: + +librsaref.a: $(librsaref_a_OBJECTS) $(librsaref_a_DEPENDENCIES) + -rm -f librsaref.a + $(AR) cru librsaref.a $(librsaref_a_OBJECTS) $(librsaref_a_LIBADD) + $(RANLIB) librsaref.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +#EXTRA_DIST = + +$(librsaref_a_SOURCES): stamp-rsaref + for i in $(librsaref_a_SOURCES); do \ + case "@MAKE_LIBRSAREF@" in \ + '') touch $$i ;; \ + *) cmp -s $(srcdir)/$$i $(srcdir)/../rsaref2/source/$$i 2>/dev/null \ + || cp $(srcdir)/../rsaref2/source/$$i $(srcdir)/$$i ;; \ + esac ; \ + done + +stamp-rsaref: + touch stamp-rsaref + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/missing b/contrib/ntp/missing new file mode 100755 index 000000000000..a6abd069801c --- /dev/null +++ b/contrib/ntp/missing @@ -0,0 +1,134 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard , 1996. + +# 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., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison touch file \`y.tab.c' + makeinfo touch the output file + yacc touch file \`y.tab.c'" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + touch config.h.in + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print \ + | sed 's/^\(.*\).am$/touch \1.in/' \ + | sh + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + touch y.tab.c + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/contrib/ntp/mkinstalldirs b/contrib/ntp/mkinstalldirs new file mode 100755 index 000000000000..91f6d04e17c2 --- /dev/null +++ b/contrib/ntp/mkinstalldirs @@ -0,0 +1,32 @@ +#!/bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Last modified: 1994-03-25 +# Public domain + +errstatus=0 + +for file in ${1+"$@"} ; do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d in ${1+"$@"} ; do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "$pathcomp" || errstatus=$? + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/contrib/ntp/ntpd/Makefile.am b/contrib/ntp/ntpd/Makefile.am new file mode 100644 index 000000000000..992668443255 --- /dev/null +++ b/contrib/ntp/ntpd/Makefile.am @@ -0,0 +1,45 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +bin_PROGRAMS = ntpd +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o @LIBPARSE@ ../libntp/libntp.a @LIBRSAREF@ +ntpd_LDADD = $(LDADD) -lm +DISTCLEANFILES = .version version.c +#EXTRA_DIST = ntpd.mak +ETAGS_ARGS = Makefile.am +### Y2Kfixes +check_PROGRAMS = @MAKE_CHECK_Y2K@ +EXTRA_PROGRAMS = check_y2k + +check-local: @MAKE_CHECK_Y2K@ + [ -z "@MAKE_CHECK_Y2K@" ] || ./@MAKE_CHECK_Y2K@ + +ntpd_SOURCES = map_vme.c ntp_config.c ntp_control.c ntp_io.c \ + ntp_loopfilter.c ntp_monitor.c ntp_peer.c ntp_proto.c \ + ntp_refclock.c ntp_request.c ntp_restrict.c ntp_timer.c \ + ntp_util.c ntp_intres.c ntp_filegen.c ntpd.c \ + refclock_conf.c refclock_chu.c refclock_local.c \ + refclock_pst.c refclock_wwvb.c refclock_mx4200.c \ + refclock_parse.c refclock_as2201.c refclock_bancomm.c \ + refclock_tpro.c refclock_leitch.c refclock_irig.c \ + refclock_msfees.c refclock_trak.c refclock_datum.c \ + refclock_acts.c refclock_heath.c refclock_nmea.c \ + refclock_atom.c refclock_ptbacts.c refclock_jupiter.c \ + refclock_usno.c refclock_true.c refclock_hpgps.c \ + refclock_shm.c refclock_gpsvme.c refclock_arbiter.c \ + refclock_arc.c refclock_palisade.c refclock_palisade.h \ + refclock_oncore.c refclock_chronolog.c refclock_dumbclock.c \ + refclock_ulink.c jupiter.h + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +../libparse/libparse.a: + cd ../libparse && $(MAKE) + +version.o: $(ntpd_OBJECTS) ../libntp/libntp.a @LIBPARSE@ @LIBRSAREF@ Makefile + $(top_builddir)/scripts/mkver ntpd + $(COMPILE) -c version.c diff --git a/contrib/ntp/ntpd/Makefile.in b/contrib/ntp/ntpd/Makefile.in new file mode 100644 index 000000000000..ac5e59191f96 --- /dev/null +++ b/contrib/ntp/ntpd/Makefile.in @@ -0,0 +1,907 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ../util/ansi2knr +bin_PROGRAMS = ntpd +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o @LIBPARSE@ ../libntp/libntp.a @LIBRSAREF@ +ntpd_LDADD = $(LDADD) -lm +DISTCLEANFILES = .version version.c +#EXTRA_DIST = ntpd.mak +ETAGS_ARGS = Makefile.am +### Y2Kfixes +check_PROGRAMS = @MAKE_CHECK_Y2K@ +EXTRA_PROGRAMS = check_y2k + +ntpd_SOURCES = map_vme.c ntp_config.c ntp_control.c ntp_io.c \ + ntp_loopfilter.c ntp_monitor.c ntp_peer.c ntp_proto.c \ + ntp_refclock.c ntp_request.c ntp_restrict.c ntp_timer.c \ + ntp_util.c ntp_intres.c ntp_filegen.c ntpd.c \ + refclock_conf.c refclock_chu.c refclock_local.c \ + refclock_pst.c refclock_wwvb.c refclock_mx4200.c \ + refclock_parse.c refclock_as2201.c refclock_bancomm.c \ + refclock_tpro.c refclock_leitch.c refclock_irig.c \ + refclock_msfees.c refclock_trak.c refclock_datum.c \ + refclock_acts.c refclock_heath.c refclock_nmea.c \ + refclock_atom.c refclock_ptbacts.c refclock_jupiter.c \ + refclock_usno.c refclock_true.c refclock_hpgps.c \ + refclock_shm.c refclock_gpsvme.c refclock_arbiter.c \ + refclock_arc.c refclock_palisade.c refclock_palisade.h \ + refclock_oncore.c refclock_chronolog.c refclock_dumbclock.c \ + refclock_ulink.c jupiter.h + +subdir = ntpd +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +ANSI2KNR = ../util/ansi2knr +check_y2k_SOURCES = check_y2k.c +check_y2k_OBJECTS = check_y2k$U.o +check_y2k_LDADD = $(LDADD) +check_y2k_DEPENDENCIES = version.o ../libntp/libntp.a +check_y2k_LDFLAGS = +am_ntpd_OBJECTS = map_vme$U.o ntp_config$U.o ntp_control$U.o ntp_io$U.o \ +ntp_loopfilter$U.o ntp_monitor$U.o ntp_peer$U.o ntp_proto$U.o \ +ntp_refclock$U.o ntp_request$U.o ntp_restrict$U.o ntp_timer$U.o \ +ntp_util$U.o ntp_intres$U.o ntp_filegen$U.o ntpd$U.o refclock_conf$U.o \ +refclock_chu$U.o refclock_local$U.o refclock_pst$U.o refclock_wwvb$U.o \ +refclock_mx4200$U.o refclock_parse$U.o refclock_as2201$U.o \ +refclock_bancomm$U.o refclock_tpro$U.o refclock_leitch$U.o \ +refclock_irig$U.o refclock_msfees$U.o refclock_trak$U.o \ +refclock_datum$U.o refclock_acts$U.o refclock_heath$U.o \ +refclock_nmea$U.o refclock_atom$U.o refclock_ptbacts$U.o \ +refclock_jupiter$U.o refclock_usno$U.o refclock_true$U.o \ +refclock_hpgps$U.o refclock_shm$U.o refclock_gpsvme$U.o \ +refclock_arbiter$U.o refclock_arc$U.o refclock_palisade$U.o \ +refclock_oncore$U.o refclock_chronolog$U.o refclock_dumbclock$U.o \ +refclock_ulink$U.o +ntpd_OBJECTS = $(am_ntpd_OBJECTS) +ntpd_DEPENDENCIES = version.o ../libntp/libntp.a +ntpd_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = check_y2k.c $(ntpd_SOURCES) +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +SOURCES = check_y2k.c $(ntpd_SOURCES) +OBJECTS = check_y2k$U.o $(am_ntpd_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ntpd/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +mostlyclean-checkPROGRAMS: + +clean-checkPROGRAMS: + -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS) + +distclean-checkPROGRAMS: + +maintainer-clean-checkPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: +../util/ansi2knr: ../util/ansi2knr.o + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr + +../util/ansi2knr.o: + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o + + +mostlyclean-kr: + -rm -f *_.c + +clean-kr: + +distclean-kr: + +maintainer-clean-kr: +check_y2k$U.o: + +check_y2k: $(check_y2k_OBJECTS) $(check_y2k_DEPENDENCIES) + @rm -f check_y2k + $(LINK) $(check_y2k_LDFLAGS) $(check_y2k_OBJECTS) $(check_y2k_LDADD) $(LIBS) +map_vme$U.o: +ntp_config$U.o: +ntp_control$U.o: +ntp_io$U.o: +ntp_loopfilter$U.o: +ntp_monitor$U.o: +ntp_peer$U.o: +ntp_proto$U.o: +ntp_refclock$U.o: +ntp_request$U.o: +ntp_restrict$U.o: +ntp_timer$U.o: +ntp_util$U.o: +ntp_intres$U.o: +ntp_filegen$U.o: +ntpd$U.o: +refclock_conf$U.o: +refclock_chu$U.o: +refclock_local$U.o: +refclock_pst$U.o: +refclock_wwvb$U.o: +refclock_mx4200$U.o: +refclock_parse$U.o: +refclock_as2201$U.o: +refclock_bancomm$U.o: +refclock_tpro$U.o: +refclock_leitch$U.o: +refclock_irig$U.o: +refclock_msfees$U.o: +refclock_trak$U.o: +refclock_datum$U.o: +refclock_acts$U.o: +refclock_heath$U.o: +refclock_nmea$U.o: +refclock_atom$U.o: +refclock_ptbacts$U.o: +refclock_jupiter$U.o: +refclock_usno$U.o: +refclock_true$U.o: +refclock_hpgps$U.o: +refclock_shm$U.o: +refclock_gpsvme$U.o: +refclock_arbiter$U.o: +refclock_arc$U.o: +refclock_palisade$U.o: +refclock_oncore$U.o: +refclock_chronolog$U.o: +refclock_dumbclock$U.o: +refclock_ulink$U.o: + +ntpd: $(ntpd_OBJECTS) $(ntpd_DEPENDENCIES) + @rm -f ntpd + $(LINK) $(ntpd_LDFLAGS) $(ntpd_OBJECTS) $(ntpd_LDADD) $(LIBS) +check_y2k_.c: check_y2k.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/check_y2k.c; then echo $(srcdir)/check_y2k.c; else echo check_y2k.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > check_y2k_.c +map_vme_.c: map_vme.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/map_vme.c; then echo $(srcdir)/map_vme.c; else echo map_vme.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > map_vme_.c +ntp_config_.c: ntp_config.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_config.c; then echo $(srcdir)/ntp_config.c; else echo ntp_config.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_config_.c +ntp_control_.c: ntp_control.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_control.c; then echo $(srcdir)/ntp_control.c; else echo ntp_control.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_control_.c +ntp_filegen_.c: ntp_filegen.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_filegen.c; then echo $(srcdir)/ntp_filegen.c; else echo ntp_filegen.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_filegen_.c +ntp_intres_.c: ntp_intres.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_intres.c; then echo $(srcdir)/ntp_intres.c; else echo ntp_intres.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_intres_.c +ntp_io_.c: ntp_io.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_io.c; then echo $(srcdir)/ntp_io.c; else echo ntp_io.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_io_.c +ntp_loopfilter_.c: ntp_loopfilter.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_loopfilter.c; then echo $(srcdir)/ntp_loopfilter.c; else echo ntp_loopfilter.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_loopfilter_.c +ntp_monitor_.c: ntp_monitor.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_monitor.c; then echo $(srcdir)/ntp_monitor.c; else echo ntp_monitor.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_monitor_.c +ntp_peer_.c: ntp_peer.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_peer.c; then echo $(srcdir)/ntp_peer.c; else echo ntp_peer.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_peer_.c +ntp_proto_.c: ntp_proto.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_proto.c; then echo $(srcdir)/ntp_proto.c; else echo ntp_proto.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_proto_.c +ntp_refclock_.c: ntp_refclock.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_refclock.c; then echo $(srcdir)/ntp_refclock.c; else echo ntp_refclock.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_refclock_.c +ntp_request_.c: ntp_request.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_request.c; then echo $(srcdir)/ntp_request.c; else echo ntp_request.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_request_.c +ntp_restrict_.c: ntp_restrict.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_restrict.c; then echo $(srcdir)/ntp_restrict.c; else echo ntp_restrict.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_restrict_.c +ntp_timer_.c: ntp_timer.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_timer.c; then echo $(srcdir)/ntp_timer.c; else echo ntp_timer.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_timer_.c +ntp_util_.c: ntp_util.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntp_util.c; then echo $(srcdir)/ntp_util.c; else echo ntp_util.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntp_util_.c +ntpd_.c: ntpd.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpd.c; then echo $(srcdir)/ntpd.c; else echo ntpd.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntpd_.c +refclock_acts_.c: refclock_acts.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_acts.c; then echo $(srcdir)/refclock_acts.c; else echo refclock_acts.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_acts_.c +refclock_arbiter_.c: refclock_arbiter.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_arbiter.c; then echo $(srcdir)/refclock_arbiter.c; else echo refclock_arbiter.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_arbiter_.c +refclock_arc_.c: refclock_arc.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_arc.c; then echo $(srcdir)/refclock_arc.c; else echo refclock_arc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_arc_.c +refclock_as2201_.c: refclock_as2201.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_as2201.c; then echo $(srcdir)/refclock_as2201.c; else echo refclock_as2201.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_as2201_.c +refclock_atom_.c: refclock_atom.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_atom.c; then echo $(srcdir)/refclock_atom.c; else echo refclock_atom.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_atom_.c +refclock_bancomm_.c: refclock_bancomm.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_bancomm.c; then echo $(srcdir)/refclock_bancomm.c; else echo refclock_bancomm.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_bancomm_.c +refclock_chronolog_.c: refclock_chronolog.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_chronolog.c; then echo $(srcdir)/refclock_chronolog.c; else echo refclock_chronolog.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_chronolog_.c +refclock_chu_.c: refclock_chu.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_chu.c; then echo $(srcdir)/refclock_chu.c; else echo refclock_chu.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_chu_.c +refclock_conf_.c: refclock_conf.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_conf.c; then echo $(srcdir)/refclock_conf.c; else echo refclock_conf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_conf_.c +refclock_datum_.c: refclock_datum.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_datum.c; then echo $(srcdir)/refclock_datum.c; else echo refclock_datum.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_datum_.c +refclock_dumbclock_.c: refclock_dumbclock.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_dumbclock.c; then echo $(srcdir)/refclock_dumbclock.c; else echo refclock_dumbclock.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_dumbclock_.c +refclock_gpsvme_.c: refclock_gpsvme.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_gpsvme.c; then echo $(srcdir)/refclock_gpsvme.c; else echo refclock_gpsvme.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_gpsvme_.c +refclock_heath_.c: refclock_heath.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_heath.c; then echo $(srcdir)/refclock_heath.c; else echo refclock_heath.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_heath_.c +refclock_hpgps_.c: refclock_hpgps.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_hpgps.c; then echo $(srcdir)/refclock_hpgps.c; else echo refclock_hpgps.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_hpgps_.c +refclock_irig_.c: refclock_irig.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_irig.c; then echo $(srcdir)/refclock_irig.c; else echo refclock_irig.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_irig_.c +refclock_jupiter_.c: refclock_jupiter.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_jupiter.c; then echo $(srcdir)/refclock_jupiter.c; else echo refclock_jupiter.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_jupiter_.c +refclock_leitch_.c: refclock_leitch.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_leitch.c; then echo $(srcdir)/refclock_leitch.c; else echo refclock_leitch.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_leitch_.c +refclock_local_.c: refclock_local.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_local.c; then echo $(srcdir)/refclock_local.c; else echo refclock_local.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_local_.c +refclock_msfees_.c: refclock_msfees.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_msfees.c; then echo $(srcdir)/refclock_msfees.c; else echo refclock_msfees.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_msfees_.c +refclock_mx4200_.c: refclock_mx4200.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_mx4200.c; then echo $(srcdir)/refclock_mx4200.c; else echo refclock_mx4200.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_mx4200_.c +refclock_nmea_.c: refclock_nmea.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_nmea.c; then echo $(srcdir)/refclock_nmea.c; else echo refclock_nmea.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_nmea_.c +refclock_oncore_.c: refclock_oncore.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_oncore.c; then echo $(srcdir)/refclock_oncore.c; else echo refclock_oncore.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_oncore_.c +refclock_palisade_.c: refclock_palisade.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_palisade.c; then echo $(srcdir)/refclock_palisade.c; else echo refclock_palisade.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_palisade_.c +refclock_parse_.c: refclock_parse.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_parse.c; then echo $(srcdir)/refclock_parse.c; else echo refclock_parse.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_parse_.c +refclock_pst_.c: refclock_pst.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_pst.c; then echo $(srcdir)/refclock_pst.c; else echo refclock_pst.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_pst_.c +refclock_ptbacts_.c: refclock_ptbacts.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ptbacts.c; then echo $(srcdir)/refclock_ptbacts.c; else echo refclock_ptbacts.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_ptbacts_.c +refclock_shm_.c: refclock_shm.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_shm.c; then echo $(srcdir)/refclock_shm.c; else echo refclock_shm.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_shm_.c +refclock_tpro_.c: refclock_tpro.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_tpro.c; then echo $(srcdir)/refclock_tpro.c; else echo refclock_tpro.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_tpro_.c +refclock_trak_.c: refclock_trak.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_trak.c; then echo $(srcdir)/refclock_trak.c; else echo refclock_trak.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_trak_.c +refclock_true_.c: refclock_true.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_true.c; then echo $(srcdir)/refclock_true.c; else echo refclock_true.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_true_.c +refclock_ulink_.c: refclock_ulink.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_ulink.c; then echo $(srcdir)/refclock_ulink.c; else echo refclock_ulink.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_ulink_.c +refclock_usno_.c: refclock_usno.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_usno.c; then echo $(srcdir)/refclock_usno.c; else echo refclock_usno.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_usno_.c +refclock_wwvb_.c: refclock_wwvb.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/refclock_wwvb.c; then echo $(srcdir)/refclock_wwvb.c; else echo refclock_wwvb.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > refclock_wwvb_.c +check_y2k_.o map_vme_.o ntp_config_.o ntp_control_.o ntp_filegen_.o \ +ntp_intres_.o ntp_io_.o ntp_loopfilter_.o ntp_monitor_.o ntp_peer_.o \ +ntp_proto_.o ntp_refclock_.o ntp_request_.o ntp_restrict_.o \ +ntp_timer_.o ntp_util_.o ntpd_.o refclock_acts_.o refclock_arbiter_.o \ +refclock_arc_.o refclock_as2201_.o refclock_atom_.o refclock_bancomm_.o \ +refclock_chronolog_.o refclock_chu_.o refclock_conf_.o \ +refclock_datum_.o refclock_dumbclock_.o refclock_gpsvme_.o \ +refclock_heath_.o refclock_hpgps_.o refclock_irig_.o \ +refclock_jupiter_.o refclock_leitch_.o refclock_local_.o \ +refclock_msfees_.o refclock_mx4200_.o refclock_nmea_.o \ +refclock_oncore_.o refclock_palisade_.o refclock_parse_.o \ +refclock_pst_.o refclock_ptbacts_.o refclock_shm_.o refclock_tpro_.o \ +refclock_trak_.o refclock_true_.o refclock_ulink_.o refclock_usno_.o \ +refclock_wwvb_.o : $(ANSI2KNR) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +check_y2k.o: check_y2k.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_malloc.h \ + ../include/ntp_refclock.h ../include/recvbuff.h \ + ../include/ntp_calendar.h ../include/parse.h \ + ../include/parse_conf.h +map_vme.o: map_vme.c ../config.h +ntp_config.o: ntp_config.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_filegen.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +ntp_control.o: ntp_control.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_control.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +ntp_filegen.o: ntp_filegen.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_string.h ../include/ntp_calendar.h \ + ../include/ntp_filegen.h ../include/ntp_stdlib.h \ + ../include/l_stdlib.h +ntp_intres.o: ntp_intres.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_request.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +ntp_io.o: ntp_io.c ../config.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h ../include/iosignal.h \ + ../include/ntp_if.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +ntp_loopfilter.o: ntp_loopfilter.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_syscall.h +ntp_monitor.o: ntp_monitor.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h ../include/ntp_if.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +ntp_peer.o: ntp_peer.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +ntp_proto.o: ntp_proto.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_unixtime.h ../include/ntp_control.h +ntp_refclock.o: ntp_refclock.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +ntp_request.o: ntp_request.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_request.h ../include/ntp_control.h \ + ../include/ntp_if.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_syscall.h +ntp_restrict.o: ntp_restrict.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_if.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +ntp_timer.o: ntp_timer.c ../config.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +ntp_util.o: ntp_util.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_filegen.h \ + ../include/ntp_if.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +ntpd.o: ntpd.c ../config.h ../include/ntpd.h ../include/ntp_syslog.h \ + ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../include/ntp_proto.h \ + ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +refclock_acts.o: refclock_acts.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_control.h +refclock_arbiter.o: refclock_arbiter.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +refclock_arc.o: refclock_arc.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +refclock_as2201.o: refclock_as2201.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_atom.o: refclock_atom.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_bancomm.o: refclock_bancomm.c ../config.h +refclock_chronolog.o: refclock_chronolog.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_calendar.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_chu.o: refclock_chu.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_calendar.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_conf.o: refclock_conf.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_datum.o: refclock_datum.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_dumbclock.o: refclock_dumbclock.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_calendar.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_gpsvme.o: refclock_gpsvme.c ../config.h +refclock_heath.o: refclock_heath.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +refclock_hpgps.o: refclock_hpgps.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +refclock_irig.o: refclock_irig.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_calendar.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_jupiter.o: refclock_jupiter.c ../config.h +refclock_leitch.o: refclock_leitch.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_local.o: refclock_local.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_syscall.h +refclock_msfees.o: refclock_msfees.c ../config.h +refclock_mx4200.o: refclock_mx4200.c ../config.h +refclock_nmea.o: refclock_nmea.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +refclock_oncore.o: refclock_oncore.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_palisade.o: refclock_palisade.c ../config.h refclock_palisade.h \ + ../include/ntpd.h ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_control.h ../include/ntp_unixtime.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +refclock_parse.o: refclock_parse.c ../config.h +refclock_pst.o: refclock_pst.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +refclock_ptbacts.o: refclock_ptbacts.c ../config.h refclock_acts.c \ + ../include/ntpd.h ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_control.h +refclock_shm.o: refclock_shm.c ../config.h +refclock_tpro.o: refclock_tpro.c ../config.h +refclock_trak.o: refclock_trak.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h ../include/ntp_unixtime.h +refclock_true.o: refclock_true.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_ulink.o: refclock_ulink.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_calendar.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +refclock_usno.o: refclock_usno.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h \ + ../include/ntp_control.h +refclock_wwvb.o: refclock_wwvb.c ../config.h ../include/ntpd.h \ + ../include/ntp_syslog.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_select.h \ + ../include/ntp_malloc.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_io.h \ + ../include/ntp_calendar.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-checkPROGRAMS \ + mostlyclean-compile mostlyclean-kr mostlyclean-tags \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-compile clean-kr \ + clean-tags clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-checkPROGRAMS \ + distclean-compile distclean-kr distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-checkPROGRAMS maintainer-clean-compile \ + maintainer-clean-kr maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-checkPROGRAMS distclean-checkPROGRAMS clean-checkPROGRAMS \ +maintainer-clean-checkPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile mostlyclean-kr distclean-kr \ +clean-kr maintainer-clean-kr tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi \ +check-local check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all install-strip \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +check-local: @MAKE_CHECK_Y2K@ + [ -z "@MAKE_CHECK_Y2K@" ] || ./@MAKE_CHECK_Y2K@ + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +../libparse/libparse.a: + cd ../libparse && $(MAKE) + +version.o: $(ntpd_OBJECTS) ../libntp/libntp.a @LIBPARSE@ @LIBRSAREF@ Makefile + $(top_builddir)/scripts/mkver ntpd + $(COMPILE) -c version.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/ntpd/check_y2k.c b/contrib/ntp/ntpd/check_y2k.c new file mode 100644 index 000000000000..3cc05fc0a65f --- /dev/null +++ b/contrib/ntp/ntpd/check_y2k.c @@ -0,0 +1,624 @@ +/* check_y2k.c -- test ntp code constructs for Y2K correctness Y2KFixes [*/ + + /* + Code invoked by `make check`. Not part of ntpd and not to be + installed. + + On any code I even wonder about, I've cut and pasted the code + here and ran it as a test case just to be sure. + + For code not in "ntpd" proper, we have tried to call most + repaired functions from herein to properly test them + (something never done before!). This has found several bugs, + not normal Y2K bugs, that will strike in Y2K so repair them + we did. + + Program exits with 0 on success, 1 on Y2K failure (stdout messages). + Exit of 2 indicates internal logic bug detected OR failure of + what should be our correct formulas. + + While "make check" should only check logic for source within that + specific directory, this check goes outside the scope of the local + directory. It's not a perfect world (besides, there is a lot of + interdependence here, and it really needs to be tested in + a controled order). + */ + +/* { definitions lifted from ntpd.c to allow us to complie with + "#include ntp.h". I have not taken the time to reduce the clutter. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#include +#include +#ifndef SYS_WINNT +# if !defined(VMS) /*wjm*/ +# include +# endif /* VMS */ +# include +# ifdef HAVE_SYS_IOCTL_H +# include +# endif /* HAVE_SYS_IOCTL_H */ +# include +# if !defined(VMS) /*wjm*/ +# include +# endif /* VMS */ +#else +# include +# include +# include +# include "../libntp/log.h" +#endif /* SYS_WINNT */ +#if defined(HAVE_RTPRIO) +# ifdef HAVE_SYS_RESOURCE_H +# include +# endif +# ifdef HAVE_SYS_LOCK_H +# include +# endif +# include +#else +# ifdef HAVE_PLOCK +# ifdef HAVE_SYS_LOCK_H +# include +# endif +# endif +#endif +#if defined(HAVE_SCHED_SETSCHEDULER) +# ifdef HAVE_SCHED_H +# include +# else +# ifdef HAVE_SYS_SCHED_H +# include +# endif +# endif +#endif +#if defined(HAVE_SYS_MMAN_H) +# include +#endif + +#ifdef HAVE_TERMIOS_H +# include +#endif + +#ifdef SYS_DOMAINOS +# include +#endif /* SYS_DOMAINOS */ + +#include "ntpd.h" + +/* } end definitions lifted from ntpd.c */ + +#include "ntp_calendar.h" +#include "parse.h" + +#define GoodLeap(Year) (((Year)%4 || (!((Year)%100) && (Year)%400)) ? 0 : 13 ) + +int debug = 0; /* debugging requests for parse stuff */ +char const *progname = "check_y2k"; + +long Days ( int Year ) /* return number of days since year "0" */ +{ + long Return; + /* this is a known to be good algorithm */ + Return = Year * 365; /* first aproximation to the value */ + if ( Year >= 1 ) + { /* see notes in libparse/parse.c if you want a PROPER + * **generic algorithm. */ + Return += (Year+3) / 4; /* add in (too many) leap days */ + Return -= (Year-1) / 100; /* reduce by (too many) centurys */ + Return += (Year-1) / 400; /* get final answer */ + } + + return Return; +} + +static int year0 = 1900; /* sarting year for NTP time */ +static int yearend; /* ending year we test for NTP time. + * 32-bit systems: through 2036, the + **year in which NTP time overflows. + * 64-bit systems: a reasonable upper + **limit (well, maybe somewhat beyond + **reasonable, but well before the + **max time, by which time the earth + **will be dead.) */ +static time_t Time; +static struct tm LocalTime; + +#define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \ + Warnings++; else Fatals++ + +int main( void ) +{ + int Fatals; + int Warnings; + int year; + + Time = time( (time_t *)NULL ) +#ifdef TESTTIMEOFFSET + + test_time_offset +#endif + ; + LocalTime = *localtime( &Time ); + + year = ( sizeof( u_long ) > 4 ) /* save max span using year as temp */ + ? ( 400 * 3 ) /* three greater gregorian cycles */ + : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/ + /* NOTE: will automacially expand test years on + * 64 bit machines.... this may cause some of the + * existing ntp logic to fail for years beyond + * 2036 (the current 32-bit limit). If all checks + * fail ONLY beyond year 2036 you may ignore such + * errors, at least for a decade or so. */ + yearend = year0 + year; + + puts( " internal self check" ); + { /* verify our own logic used to verify repairs */ + unsigned long days; + + if ( year0 >= yearend ) + { + fprintf( stdout, "year0=%d NOT LESS THAN yearend=%d (span=%d)\n", + (int)year0, (int)yearend, (int)year ); + exit(2); + } + + { + int save_year; + + save_year = LocalTime.tm_year; /* save current year */ + + year = 1980; + LocalTime.tm_year = year - 1900; + Fatals = Warnings = 0; + Error(year); /* should increment Fatals */ + if ( Fatals == 0 ) + { + fprintf( stdout, + "%4d: %s(%d): FATAL DID NOT INCREMENT (Fatals=%d Warnings=%d)\n", + (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings ); + exit(2); + } + + year = 2100; /* test year > limit but CURRENT year < limit */ + Fatals = Warnings = 0; + Error(year); /* should increment Fatals */ + if ( Warnings == 0 ) + { + fprintf( stdout, + "%4d: %s(%d): WARNING DID NOT INCREMENT (Fatals=%d Warnings=%d)\n", + (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings ); + exit(2); + } + Fatals = Warnings = 0; + LocalTime.tm_year = year - 1900; /* everything > limit */ + Error(1980); /* should increment Fatals */ + if ( Fatals == 0 ) + { + fprintf( stdout, + "%4d: %s(%d): FATALS DID NOT INCREMENT (Fatals=%d Warnings=%d)\n", + (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings ); + exit(2); + } + + LocalTime.tm_year = save_year; + } + + days = 365+1; /* days in year 0 + 1 more day */ + for ( year = 1; year <= 2500; year++ ) + { + long Test; + Test = Days( year ); + if ( days != Test ) + { + fprintf( stdout, "%04d: Days() DAY COUNT ERROR: s/b=%ld was=%ld\n", + year, (long)days, (long)Test ); + exit(2); /* would throw off many other tests */ + } + + Test = julian0(year); /* compare with julian0() macro */ + if ( days != Test ) + { + fprintf( stdout, "%04d: julian0() DAY COUNT ERROR: s/b=%ld was=%ld\n", + year, (long)days, (long)Test ); + exit(2); /* would throw off many other tests */ + } + + days += 365; + if ( isleap_4(year) ) days++; + } + + if ( isleap_4(1999) ) + { + fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" ); + exit(2); + } + if ( !isleap_4(2000) ) + { + fprintf( stdout, "isleap_4(2000) REPORTED FALSE\n" ); + exit(2); + } + if ( isleap_4(2001) ) + { + fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" ); + exit(2); + } + + if ( !isleap_tm(2000-1900) ) + { + fprintf( stdout, "isleap_tm(100) REPORTED FALSE\n" ); + exit(2); + } + } + + Fatals = Warnings = 0; + + puts( " include/ntp.h" ); + { /* test our new isleap_*() #define "functions" */ + + for ( year = 1400; year <= 2200; year++ ) + { + int LeapSw; + int IsLeapSw; + + LeapSw = GoodLeap(year); + IsLeapSw = isleap_4(year); + + if ( !!LeapSw != !!IsLeapSw ) + { + Error(year); + fprintf( stdout, + " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw ); + break; + } + + IsLeapSw = isleap_tm(year-1900); + + if ( !!LeapSw != !!IsLeapSw ) + { + Error(year); + fprintf( stdout, + " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw ); + break; + } + } + } + + puts( " include/ntp_calendar.h" ); + { /* I belive this is good, but just to be sure... */ + + /* we are testing this #define */ +#define is_leapyear(y) (y%4 == 0 && !(y%100 == 0 && !(y%400 == 0))) + + for ( year = 1400; year <= 2200; year++ ) + { + int LeapSw; + + LeapSw = GoodLeap(year); + + if ( !(!LeapSw) != !(!is_leapyear(year)) ) + { + Error(year); + fprintf( stdout, + " %4d %2d *** ERROR\n", year, LeapSw ); + break; + } + } + } + + + puts( " libparse/parse.c" ); + { + long Days1970; /* days from 1900 to 1970 */ + + struct ParseTime /* womp up a test structure to all cut/paste code */ + { + int year; + } Clock_Time, *clock_time; + + clock_time = &Clock_Time; + + /* first test this #define */ +#define days_per_year(x) ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366)) + + for ( year = 1400; year <= 2200; year++ ) + { + int LeapSw; + int DayCnt; + + LeapSw = GoodLeap(year); + DayCnt = (int)days_per_year(year); + + if ( ( LeapSw ? 366 : 365 ) != DayCnt ) + { + Error(year); + fprintf( stdout, + " days_per_year() %4d %2d %3d *** ERROR\n", + year, LeapSw, DayCnt ); + break; + } + } + + /* test (what is now julian0) calculations */ + + Days1970 = Days( 1970 ); /* get days since 1970 using a known good */ + + for ( year = 1970; year < yearend; year++ ) + { + unsigned long t; + long DaysYear ; + + clock_time->year = year; + + /* here is the code we are testing, cut and pasted out of the source */ +#if 0 /* old BUGGY code that has Y2K (and many other) failures */ + /* ghealton: this logic FAILED with great frequency when run + * over a period of time, including for year 2000. True, it + * had more successes than failures, but that's not really good + * enough for critical time distribution software. + * It is so awful I wonder if it has had a history of failure + * and fixes? */ + t = (clock_time->year - 1970) * 365; + t += (clock_time->year >> 2) - (1970 >> 2); + t -= clock_time->year / 100 - 1970 / 100; + t += clock_time->year / 400 - 1970 / 400; + + /* (immediate feare of rounding errors on integer + * **divisions proved well founded) */ + +#else + /* my replacement, based on Days() above */ + t = julian0(year) - julian0(1970); +#endif + + /* compare result in t against trusted calculations */ + DaysYear = Days( year ); /* get days to this year */ + if ( t != DaysYear - Days1970 ) + { + Error(year); + fprintf( stdout, + " %4d 1970=%-8ld %4d=%-8ld %-3ld t=%-8ld *** ERROR ***\n", + year, (long)Days1970, + year, + (long)DaysYear, + (long)(DaysYear - Days1970), + (long)t ); + } + } + +#if 1 /* { */ + { + debug = 1; /* enable debugging */ + for ( year = 1970; year < yearend; year++ ) + { /* (limited by theory unix 2038 related bug lives by, but + * ends in yearend) */ + clocktime_t ct; + time_t Observed; + time_t Expected; + u_long Flag; + unsigned long t; + + ct.day = 1; + ct.month = 1; + ct.year = year; + ct.hour = ct.minute = ct.second = ct.usecond = 0; + ct.utcoffset = 0; + ct.utctime = 0; + ct.flags = 0; + + Flag = 0; + Observed = parse_to_unixtime( &ct, &Flag ); + if ( ct.year != year ) + { + fprintf( stdout, + "%04d: parse_to_unixtime(,%d) CORRUPTED ct.year: was %d\n", + (int)year, (int)Flag, (int)ct.year ); + Error(year); + break; + } + t = julian0(year) - julian0(1970); /* Julian day from 1970 */ + Expected = t * 24 * 60 * 60; + if ( Observed != Expected || Flag ) + { /* time difference */ + fprintf( stdout, + "%04d: parse_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", + year, (int)Flag, + (unsigned long)Observed, (unsigned long)Expected, + ((long)Observed - (long)Expected) ); + Error(year); + break; + } + + if ( year >= YEAR_PIVOT+1900 ) + { + /* check year % 100 code we put into parse_to_unixtime() */ + ct.utctime = 0; + ct.year = year % 100; + Flag = 0; + + Observed = parse_to_unixtime( &ct, &Flag ); + + if ( Observed != Expected || Flag ) + { /* time difference */ + fprintf( stdout, +"%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", + year, (int)ct.year, (int)Flag, + (unsigned long)Observed, (unsigned long)Expected, + ((long)Observed - (long)Expected) ); + Error(year); + break; + } + + /* check year - 1900 code we put into parse_to_unixtime() */ + ct.utctime = 0; + ct.year = year - 1900; + Flag = 0; + + Observed = parse_to_unixtime( &ct, &Flag ); + + if ( Observed != Expected || Flag ) + { /* time difference */ + fprintf( stdout, +"%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", + year, (int)ct.year, (int)Flag, + (unsigned long)Observed, (unsigned long)Expected, + ((long)Observed - (long)Expected) ); + Error(year); + break; + } + + + } + } +#endif /* } */ + } + } + + puts( " libntp/caljulian.c" ); + { /* test caljulian() */ + struct calendar ot; + u_long ntp_time; /* NTP time */ + + year = year0; /* calculate the basic year */ + printf( " starting year %04d\n", (int)year0 ); + printf( " ending year %04d\n", (int)yearend ); + + + ntp_time = julian0( year0 ); /* NTP starts in 1900-01-01 */ +#if DAY_NTP_STARTS == 693596 + ntp_time -= 365; /* BIAS required for successful test */ +#endif + if ( DAY_NTP_STARTS != ntp_time ) + { + Error(year); + fprintf( stdout, + "%04d: DAY_NTP_STARTS (%ld) NOT TRUE VALUE OF %ld (%ld)\n", + (int)year0, + (long)DAY_NTP_STARTS, (long)ntp_time, + (long)DAY_NTP_STARTS - (long)ntp_time ); + } + + for ( ; year < yearend; year++ ) + { + + /* 01-01 for the current year */ + ntp_time = Days( year ) - Days( year0 ); /* days into NTP time */ + ntp_time *= 24 * 60 * 60; /* convert into seconds */ + caljulian( ntp_time, &ot ); /* convert January 1 */ + if ( ot.year != year + || ot.month != 1 + || ot.monthday != 1 ) + { + Error(year); + fprintf( stdout, "%lu: EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n", + (unsigned long)ntp_time, + year, + (int)ot.year, (int)ot.month, (int)ot.monthday ); + break; + } + + ntp_time += (31 + 28-1) * ( 24 * 60 * 60 ); /* advance to 02-28 */ + caljulian( ntp_time, &ot ); /* convert Feb 28 */ + if ( ot.year != year + || ot.month != 2 + || ot.monthday != 28 ) + { + Error(year); + fprintf( stdout, "%lu: EXPECTED %04d-02-28: FOUND %04d-%02d-%02d\n", + (unsigned long)ntp_time, + year, + (int)ot.year, (int)ot.month, (int)ot.monthday ); + break; + } + + { + int m; /* expected month */ + int d; /* expected day */ + + m = isleap_4(year) ? 2 : 3; + d = isleap_4(year) ? 29 : 1; + + ntp_time += ( 24 * 60 * 60 ); /* advance to the next day */ + caljulian( ntp_time, &ot ); /* convert this day */ + if ( ot.year != year + || ot.month != m + || ot.monthday != d ) + { + Error(year); + fprintf( stdout, "%lu: EXPECTED %04d-%02d-%02d: FOUND %04d-%02d-%02d\n", + (unsigned long)ntp_time, + year, m, d, + (int)ot.year, (int)ot.month, (int)ot.monthday ); + break; + } + + } + } + } + + puts( " libntp/caltontp.c" ); + { /* test caltontp() */ + struct calendar ot; + u_long ntp_time; /* NTP time */ + + year = year0; /* calculate the basic year */ + printf( " starting year %04d\n", (int)year0 ); + printf( " ending year %04d\n", (int)yearend ); + + + for ( ; year < yearend; year++ ) + { + u_long ObservedNtp; + + /* 01-01 for the current year */ + ot.year = year; + ot.month = ot.monthday = 1; /* unused, but set anyway JIC */ + ot.yearday = 1; /* this is the magic value used by caltontp() */ + ot.hour = ot.minute = ot.second = 0; + + ntp_time = Days( year ) - Days( year0 ); /* days into NTP time */ + ntp_time *= 24 * 60 * 60; /* convert into seconds */ + ObservedNtp = caltontp( &ot ); + if ( ntp_time != ObservedNtp ) + { + Error(year); + fprintf( stdout, "%d: EXPECTED %lu: FOUND %lu (%ld)\n", + (int)year, + (unsigned long)ntp_time, (unsigned long)ObservedNtp , + (long)ntp_time - (long)ObservedNtp ); + + break; + } + + /* now call caljulian as a type of failsafe supercheck */ + caljulian( ObservedNtp, &ot ); /* convert January 1 */ + if ( ot.year != year + || ot.month != 1 + || ot.monthday != 1 ) + { + Error(year); + fprintf( stdout, "%lu: caljulian FAILSAFE EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n", + (unsigned long)ObservedNtp, + year, + (int)ot.year, (int)ot.month, (int)ot.monthday ); + break; + } + } + } + + if ( Warnings > 0 ) + fprintf( stdout, "%d WARNINGS\n", Warnings ); + if ( Fatals > 0 ) + fprintf( stdout, "%d FATAL ERRORS\n", Fatals ); + return Fatals ? 1 : 0; +} + /* Y2KFixes ] */ diff --git a/contrib/ntp/ntpd/jupiter.h b/contrib/ntp/ntpd/jupiter.h new file mode 100644 index 000000000000..84b9a598cdce --- /dev/null +++ b/contrib/ntp/ntpd/jupiter.h @@ -0,0 +1,255 @@ +/* @(#) $Header: /cvs/ntp/ntpd/jupiter.h,v 1.1.1.1 1999/05/26 00:48:19 stenn Exp $ (LBL) */ + +/* + * Rockwell Jupiter GPS receiver definitions + * + * This is all based on the "Zodiac GPS Receiver Family Designer's + * Guide" (dated 12/96) + */ + +#define JUPITER_SYNC 0x81ff /* sync word (book says 0xff81 !?!?) */ +#define JUPITER_ALL 0xffff /* disable all output messages */ + +/* Output messages (sent by the Jupiter board) */ +#define JUPITER_O_GPOS 1000 /* geodetic position status */ +#define JUPITER_O_EPOS 1001 /* ECEF position status */ +#define JUPITER_O_CHAN 1002 /* channel summary */ +#define JUPITER_O_VIS 1003 /* visible satellites */ +#define JUPITER_O_DGPS 1005 /* differential GPS status */ +#define JUPITER_O_MEAS 1007 /* channel measurement */ +#define JUPITER_O_ID 1011 /* receiver id */ +#define JUPITER_O_USER 1012 /* user-settings output */ +#define JUPITER_O_TEST 1100 /* built-in test results */ +#define JUPITER_O_MARK 1102 /* measurement time mark */ +#define JUPITER_O_PULSE 1108 /* UTC time mark pulse output */ +#define JUPITER_O_PORT 1130 /* serial port com parameters in use */ +#define JUPITER_O_EUP 1135 /* EEPROM update */ +#define JUPITER_O_ESTAT 1136 /* EEPROM status */ + +/* Input messages (sent to the Jupiter board) */ +#define JUPITER_I_PVTINIT 1200 /* geodetic position and velocity */ +#define JUPITER_I_USER 1210 /* user-defined datum */ +#define JUPITER_I_MAPSEL 1211 /* map datum select */ +#define JUPITER_I_ELEV 1212 /* satellite elevation mask control */ +#define JUPITER_I_CAND 1213 /* satellite candidate select */ +#define JUPITER_I_DGPS 1214 /* differential GPS control */ +#define JUPITER_I_COLD 1216 /* cold start control */ +#define JUPITER_I_VALID 1217 /* solution validity criteria */ +#define JUPITER_I_ALT 1219 /* user-entered altitude input */ +#define JUPITER_I_PLAT 1220 /* application platform control */ +#define JUPITER_I_NAV 1221 /* nav configuration */ +#define JUPITER_I_TEST 1300 /* preform built-in test command */ +#define JUPITER_I_RESTART 1303 /* restart command */ +#define JUPITER_I_PORT 1330 /* serial port com parameters */ +#define JUPITER_I_PROTO 1331 /* message protocol control */ +#define JUPITER_I_RDGPS 1351 /* raw DGPS RTCM SC-104 data */ + +struct jheader { + u_short sync; /* (JUPITER_SYNC) */ + u_short id; /* message id */ + u_short len; /* number of data short wordss (w/o cksum) */ + u_char reqid; /* JUPITER_REQID_MASK bits available as id */ + u_char flags; /* flags */ + u_short hsum; /* header cksum */ +}; + +#define JUPITER_REQID_MASK 0x3f /* bits available as id */ +#define JUPITER_FLAG_NAK 0x01 /* negative acknowledgement */ +#define JUPITER_FLAG_ACK 0x02 /* acknowledgement */ +#define JUPITER_FLAG_REQUEST 0x04 /* request ACK or NAK */ +#define JUPITER_FLAG_QUERY 0x08 /* request one shot output message */ +#define JUPITER_FLAG_LOG 0x20 /* request periodic output message */ +#define JUPITER_FLAG_CONN 0x40 /* enable periodic message */ +#define JUPITER_FLAG_DISC 0x80 /* disable periodic message */ + +#define JUPITER_H_FLAG_BITS \ + "\020\1NAK\2ACK\3REQUEST\4QUERY\5MBZ\6LOG\7CONN\10DISC" + +/* Log request messages (data payload when using JUPITER_FLAG_LOG) */ +struct jrequest { + u_short trigger; /* if 0, trigger on time trigger on + update (e.g. new almanac) */ + u_short interval; /* frequency in seconds */ + u_short offset; /* offset into minute */ + u_short dsum; /* checksum */ +}; + +/* JUPITER_O_GPOS (1000) */ +struct jgpos { + u_short stime[2]; /* set time (10 ms ticks) */ + u_short seq; /* sequence number */ + u_short sseq; /* sat measurement sequence number */ + u_short navval; /* navigation soltuion validity */ + u_short navtype; /* navigation solution type */ + u_short nmeas; /* # of measurements used in solution */ + u_short polar; /* if 1 then polar navigation */ + u_short gweek; /* GPS week number */ + u_short sweek[2]; /* GPS seconds into week */ + u_short nsweek[2]; /* GPS nanoseconds into second */ + u_short utcday; /* 1 to 31 */ + u_short utcmon; /* 1 to 12 */ + u_short utcyear; /* 1980 to 2079 */ + u_short utchour; /* 0 to 23 */ + u_short utcmin; /* 0 to 59 */ + u_short utcsec; /* 0 to 59 */ + u_short utcnsec[2]; /* 0 to 999999999 */ + u_short lat[2]; /* latitude (radians) */ + u_short lon[2]; /* longitude (radians) */ + u_short height[2]; /* height (meters) */ + u_short gsep; /* geoidal separation */ + u_short speed[2]; /* ground speed (meters/sec) */ + u_short course; /* true course (radians) */ + u_short mvar; + u_short climb; + u_short mapd; + u_short herr[2]; + u_short verr[2]; + u_short terr[2]; + u_short hverr; + u_short bias[2]; + u_short biassd[2]; + u_short drift[2]; + u_short driftsd[2]; + u_short dsum; /* checksum */ +}; +#define JUPITER_O_GPOS_NAV_NOALT 0x01 /* altitude used */ +#define JUPITER_O_GPOS_NAV_NODGPS 0x02 /* no differential GPS */ +#define JUPITER_O_GPOS_NAV_NOSAT 0x04 /* not enough satellites */ +#define JUPITER_O_GPOS_NAV_MAXH 0x08 /* exceeded max EHPE */ +#define JUPITER_O_GPOS_NAV_MAXV 0x10 /* exceeded max EVPE */ + +/* JUPITER_O_CHAN (1002) */ +struct jchan { + u_short stime[2]; /* set time (10 ms ticks) */ + u_short seq; /* sequence number */ + u_short sseq; /* sat measurement sequence number */ + u_short gweek; /* GPS week number */ + u_short sweek[2]; /* GPS seconds into week */ + u_short gpsns[2]; /* GPS nanoseconds from epoch */ + struct jchan2 { + u_short flags; /* flags */ + u_short prn; /* satellite PRN */ + u_short chan; /* channel number */ + } sat[12]; + u_short dsum; +}; + +/* JUPITER_O_VIS (1003) */ +struct jvis { + u_short stime[2]; /* set time (10 ms ticks) */ + u_short seq; /* sequence number */ + u_short gdop; /* best possible GDOP */ + u_short pdop; /* best possible PDOP */ + u_short hdop; /* best possible HDOP */ + u_short vdop; /* best possible VDOP */ + u_short tdop; /* best possible TDOP */ + u_short nvis; /* number of visible satellites */ + struct jvis2 { + u_short prn; /* satellite PRN */ + u_short azi; /* satellite azimuth (radians) */ + u_short elev; /* satellite elevation (radians) */ + } sat[12]; + u_short dsum; /* checksum */ +}; + +/* JUPITER_O_ID (1011) */ +struct jid { + u_short stime[2]; /* set time (10 ms ticks) */ + u_short seq; /* sequence number */ + char chans[20]; /* number of channels (ascii) */ + char vers[20]; /* software version (ascii) */ + char date[20]; /* software date (ascii) */ + char opts[20]; /* software options (ascii) */ + char reserved[20]; + u_short dsum; /* checksum */ +}; + +/* JUPITER_O_USER (1012) */ +struct juser { + u_short stime[2]; /* set time (10 ms ticks) */ + u_short seq; /* sequence number */ + u_short status; /* operatinoal status */ + u_short coldtmo; /* cold start time-out */ + u_short dgpstmo; /* DGPS correction time-out*/ + u_short emask; /* elevation mask */ + u_short selcand[2]; /* selected candidate */ + u_short solflags; /* solution validity criteria */ + u_short nsat; /* number of satellites in track */ + u_short herr[2]; /* minimum expected horizontal error */ + u_short verr[2]; /* minimum expected vertical error */ + u_short platform; /* application platform */ + u_short dsum; /* checksum */ +}; + +/* JUPITER_O_PULSE (1108) */ +struct jpulse { + u_short stime[2]; /* set time (10 ms ticks) */ + u_short seq; /* sequence number */ + u_short reserved[5]; + u_short sweek[2]; /* GPS seconds into week */ + short offs; /* GPS to UTC time offset (seconds) */ + u_short offns[2]; /* GPS to UTC offset (nanoseconds) */ + u_short flags; /* flags */ + u_short dsum; /* checksum */ +}; +#define JUPITER_O_PULSE_VALID 0x1 /* time mark validity */ +#define JUPITER_O_PULSE_UTC 0x2 /* GPS/UTC sync */ + +/* JUPITER_O_EUP (1135) */ +struct jeup { + u_short stime[2]; /* set time (10 ms ticks) */ + u_short seq; /* sequence number */ + u_char dataid; /* data id */ + u_char prn; /* satellite PRN */ + u_short dsum; /* checksum */ +}; + +/* JUPITER_I_RESTART (1303) */ +struct jrestart { + u_short seq; /* sequence number */ + u_short flags; + u_short dsum; /* checksum */ +}; +#define JUPITER_I_RESTART_INVRAM 0x01 +#define JUPITER_I_RESTART_INVEEPROM 0x02 +#define JUPITER_I_RESTART_INVRTC 0x04 +#define JUPITER_I_RESTART_COLD 0x80 + +/* JUPITER_I_PVTINIT (1200) */ +struct jpvtinit { + u_short flags; + u_short gweek; /* GPS week number */ + u_short sweek[2]; /* GPS seconds into week */ + u_short utcday; /* 1 to 31 */ + u_short utcmon; /* 1 to 12 */ + u_short utcyear; /* 1980 to 2079 */ + u_short utchour; /* 0 to 23 */ + u_short utcmin; /* 0 to 59 */ + u_short utcsec; /* 0 to 59 */ + u_short lat[2]; /* latitude (radians) */ + u_short lon[2]; /* longitude (radians) */ + u_short height[2]; /* height (meters) */ + u_short speed[2]; /* ground speed (meters/sec) */ + u_short course; /* true course (radians) */ + u_short climb; + u_short dsum; +}; +#define JUPITER_I_PVTINIT_FORCE 0x01 +#define JUPITER_I_PVTINIT_GPSVAL 0x02 +#define JUPITER_I_PVTINIT_UTCVAL 0x04 +#define JUPITER_I_PVTINIT_POSVAL 0x08 +#define JUPITER_I_PVTINIT_ALTVAL 0x10 +#define JUPITER_I_PVTINIT_SPDVAL 0x12 +#define JUPITER_I_PVTINIT_MAGVAL 0x14 +#define JUPITER_I_PVTINIT_CLIMBVAL 0x18 + +/* JUPITER_I_PLAT (1220) */ +struct jplat { + u_short seq; /* sequence number */ + u_short platform; /* application platform */ + u_short dsum; +}; +#define JUPITER_I_PLAT_DEFAULT 0 /* default dynamics */ +#define JUPITER_I_PLAT_LOW 2 /* pedestrian */ +#define JUPITER_I_PLAT_MED 5 /* land (e.g. automobile) */ +#define JUPITER_I_PLAT_HIGH 6 /* air */ diff --git a/contrib/ntp/ntpd/map_vme.c b/contrib/ntp/ntpd/map_vme.c new file mode 100644 index 000000000000..3c161cc91450 --- /dev/null +++ b/contrib/ntp/ntpd/map_vme.c @@ -0,0 +1,135 @@ +/********************************************************/ +/* map_vme.c */ +/* VME control of TrueTime VME-SG sync gen card */ +/* and TrueTime GPS-VME receiver card */ +/* Version for 700 series HPUX 9.0 */ +/* Richard E.Schmidt, US Naval Observatory, Washington */ +/* 27 March 94 */ +/********************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_GPSVME) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for rtprio */ +#include /* for plock */ +#include "/etc/conf/machine/vme2.h" +#include "/etc/conf/h/io.h" +#include "gps.h" + +/* GLOBALS */ +void *gps_base; +unsigned short *greg[NREGS]; +struct vme2_map_addr ma; /* memory mapped structure */ +int fd; /* file descriptor for VME */ + +void unmap_vme (); + +caddr_t +map_vme ( + char *filename + ) +{ + int ret; + caddr_t base; + struct vme2_io_testx tx; + caddr_t cp; + +#define VME_START_ADDR 0x00000 /* Starting address in A16N VME Space */ +#define VMESIZE 0xFF /* 256 bytes of A16N space length */ + + /* + To create the HP9000/700 series device file, /dev/vme2: + mknod /dev/vme2 c 44 0x0; chmod 600 /dev/vme2 + + Then must create /etc/vme.CFG and run /etc/vme_config and reboot. + */ + if ((fd = open (filename, O_RDWR)) < 0) { + printf("ERROR: VME bus adapter open failed. errno:%d\n", + errno); + if(errno == ENODEV) { + printf("ENODEV. Is driver in kernel? vme2 in dfile?\n"); + } + exit(errno); + } + tx.card_type = VME_A16; + tx.vme_addr = VME_START_ADDR; + tx.width = SHORT_WIDE; + + if(ioctl(fd, VME2_IO_TESTR, &tx)) { + printf("ioctl to test VME space failed. Errno: %d\n", + errno); + exit(errno); + } + if(tx.error) + printf("io_testr failed internal error %d\n",tx.error); + if(tx.access_result <= 0) { + printf("io_testr failed\n"); + exit(2); + } + + /* If successful mmap the device */ + /* NOW MAP THE CARD */ + ma.card_type = VME_A16; + ma.vme_addr = VME_START_ADDR; + ma.size = VMESIZE; + + if(ioctl(fd, VME2_MAP_ADDR, &ma)) { + printf("ioctl to map VME space failed. Errno: %d\n", + errno); + exit(errno); + } + if(ma.error) { + printf("ioctl to map VME failed\n"); + exit(ENOMEM); + } + base = ma.user_addr; + return(base); +} + + +void +unmap_vme(void) +{ + if(ioctl(fd, VME2_UNMAP_ADDR, &ma)) + printf("ioctl to unmap VME space failed. Errno: %d\n", + errno); + close(fd); + return; +} + + +int +init_vme(boid) +{ + /* set up address offsets */ + + gps_base = map_vme (GPS_VME); + +/* offsets from base address: */ + + greg[0] = (unsigned short *)gps_base + GFRZ1; + greg[1] = (unsigned short *)gps_base + GUFRZ1; + greg[2] = (unsigned short *)gps_base + GREG1A; + greg[3] = (unsigned short *)gps_base + GREG1B; + greg[4] = (unsigned short *)gps_base + GREG1C; + greg[5] = (unsigned short *)gps_base + GREG1D; + greg[6] = (unsigned short *)gps_base + GREG1E; + + return (0); +} + +#else /* not (REFCLOCK && CLOCK_GPSVME) */ +int map_vme_bs; +#endif /* not (REFCLOCK && CLOCK_GPSVME) */ diff --git a/contrib/ntp/ntpd/ntp_config.c b/contrib/ntp/ntpd/ntp_config.c new file mode 100644 index 000000000000..e21f5b002ef5 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_config.c @@ -0,0 +1,2405 @@ +/* + * ntp_config.c - read and apply configuration information + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#ifndef SIGCHLD +#define SIGCHLD SIGCLD +#endif +#if !defined(VMS) +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#endif /* VMS */ +#include + +#ifdef HAVE_NETINFO +#include +#endif + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_refclock.h" +#include "ntp_filegen.h" +#include "ntp_stdlib.h" + +#ifdef SYS_WINNT +#include +extern HANDLE ResolverThreadHandle; +#endif /* SYS_WINNT */ + +/* + * 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 +# ifndef SYS_WINNT +# define CONFIG_FILE "/etc/ntp.conf" +# else /* SYS_WINNT */ +# define CONFIG_FILE "%windir%\\system32\\drivers\\etc\\ntp.conf" +# define ALT_CONFIG_FILE "%windir%\\ntp.conf" +# endif /* SYS_WINNT */ +#endif /* not CONFIG_FILE */ + +/* + * We understand the following configuration entries and defaults. + * + * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * server [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * broadcast [ addr ] [ version 3 ] [ key 0 ] [ ttl 1 ] + * broadcastclient + * multicastclient [ 224.0.1.1 ] + * manycastclient [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * manycastserver [ 224.0.1.1 ] + * broadcastdelay 0.0102 + * restrict [ addr ] [ 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 ] + * clientlimit [ n ] + * clientperiod [ 3600 ] + * trustedkey [ key ] + * requestkey [ key] + * controlkey [ key ] + * trap [ addr ] + * fudge [ addr ] [ stratum ] [ refid ] ... + * pidfile [ ] + * setvar [ ] + * logfile logfile + * logconfig [+|-|=][{sync|sys|peer|clock}{{,all}{info|statistics|events|status}}]... + * enable auth|bclient|pll|kernel|monitor|stats + * disable auth|bclient|pll|kernel|monitor|stats + * phone ... + * pps device [assert|clear] [hardpps] + */ + +/* + * Types of entries we understand. + */ +#define CONFIG_UNKNOWN 0 + +#define CONFIG_PEER 1 +#define CONFIG_SERVER 2 +#define CONFIG_AUTOMAX 3 +#define CONFIG_DRIFTFILE 4 +#define CONFIG_BROADCAST 5 +#define CONFIG_BROADCASTCLIENT 6 +#define CONFIG_AUTHENTICATE 7 +#define CONFIG_KEYS 8 +#define CONFIG_REVOKE 9 +#define CONFIG_PPS 10 +#define CONFIG_RESTRICT 11 +#define CONFIG_BDELAY 12 +#define CONFIG_TRUSTEDKEY 13 +#define CONFIG_REQUESTKEY 14 +#define CONFIG_CONTROLKEY 15 +#define CONFIG_TRAP 16 +#define CONFIG_FUDGE 17 +#define CONFIG_18 18 /* unused */ +#define CONFIG_STATSDIR 19 +#define CONFIG_FILEGEN 20 +#define CONFIG_STATISTICS 21 +#define CONFIG_PIDFILE 22 +#define CONFIG_SETVAR 23 +#define CONFIG_CLIENTLIMIT 24 +#define CONFIG_CLIENTPERIOD 25 +#define CONFIG_MULTICASTCLIENT 26 +#define CONFIG_ENABLE 27 +#define CONFIG_DISABLE 28 +#define CONFIG_PHONE 29 +#define CONFIG_LOGFILE 30 +#define CONFIG_LOGCONFIG 31 +#define CONFIG_MANYCASTCLIENT 32 +#define CONFIG_MANYCASTSERVER 33 + +#define CONF_MOD_VERSION 1 +#define CONF_MOD_KEY 2 +#define CONF_MOD_MINPOLL 3 +#define CONF_MOD_MAXPOLL 4 +#define CONF_MOD_PREFER 5 +#define CONF_MOD_BURST 6 +#define CONF_MOD_SKEY 7 +#define CONF_MOD_TTL 8 +#define CONF_MOD_MODE 9 +#define CONF_MOD_NOSELECT 10 + +#define CONF_RES_MASK 1 +#define CONF_RES_IGNORE 2 +#define CONF_RES_NOSERVE 3 +#define CONF_RES_NOTRUST 4 +#define CONF_RES_NOQUERY 5 +#define CONF_RES_NOMODIFY 6 +#define CONF_RES_NOPEER 7 +#define CONF_RES_NOTRAP 8 +#define CONF_RES_LPTRAP 9 +#define CONF_RES_NTPPORT 10 +#define CONF_RES_LIMITED 11 + +#define CONF_TRAP_PORT 1 +#define CONF_TRAP_INTERFACE 2 + +#define CONF_FDG_TIME1 1 +#define CONF_FDG_TIME2 2 +#define CONF_FDG_STRATUM 3 +#define CONF_FDG_REFID 4 +#define CONF_FDG_FLAG1 5 +#define CONF_FDG_FLAG2 6 +#define CONF_FDG_FLAG3 7 +#define CONF_FDG_FLAG4 8 + +#define CONF_FGEN_FILE 1 +#define CONF_FGEN_TYPE 2 +#define CONF_FGEN_FLAG_LINK 3 +#define CONF_FGEN_FLAG_NOLINK 4 +#define CONF_FGEN_FLAG_ENABLE 5 +#define CONF_FGEN_FLAG_DISABLE 6 + +#define CONF_PPS_ASSERT 1 +#define CONF_PPS_CLEAR 2 +#define CONF_PPS_HARDPPS 3 + +/* + * Translation table - keywords to function index + */ +struct keyword { + const char *text; + int keytype; +}; + +/* + * Command keywords + */ +static struct keyword keywords[] = { + { "peer", CONFIG_PEER }, + { "server", CONFIG_SERVER }, + { "driftfile", CONFIG_DRIFTFILE }, + { "broadcast", CONFIG_BROADCAST }, + { "broadcastclient", CONFIG_BROADCASTCLIENT }, + { "multicastclient", CONFIG_MULTICASTCLIENT }, + { "manycastclient", CONFIG_MANYCASTCLIENT }, + { "manycastserver", CONFIG_MANYCASTSERVER }, + { "authenticate", CONFIG_AUTHENTICATE }, + { "keys", CONFIG_KEYS }, + { "revoke", CONFIG_REVOKE }, + { "pps", CONFIG_PPS }, + { "automax", CONFIG_AUTOMAX }, + { "restrict", CONFIG_RESTRICT }, + { "broadcastdelay", CONFIG_BDELAY }, + { "trustedkey", CONFIG_TRUSTEDKEY }, + { "requestkey", CONFIG_REQUESTKEY }, + { "controlkey", CONFIG_CONTROLKEY }, + { "trap", CONFIG_TRAP }, + { "fudge", CONFIG_FUDGE }, + { "statsdir", CONFIG_STATSDIR }, + { "filegen", CONFIG_FILEGEN }, + { "statistics", CONFIG_STATISTICS }, + { "pidfile", CONFIG_PIDFILE }, + { "setvar", CONFIG_SETVAR }, + { "clientlimit", CONFIG_CLIENTLIMIT }, + { "clientperiod", CONFIG_CLIENTPERIOD }, + { "enable", CONFIG_ENABLE }, + { "disable", CONFIG_DISABLE }, + { "phone", CONFIG_PHONE }, + { "logfile", CONFIG_LOGFILE }, + { "logconfig", CONFIG_LOGCONFIG }, + { "", CONFIG_UNKNOWN } +}; + +/* + * "peer", "server", "broadcast" 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 }, + { "noselect", CONF_MOD_NOSELECT }, + { "burst", CONF_MOD_BURST }, + { "autokey", CONF_MOD_SKEY }, + { "mode", CONF_MOD_MODE }, /* reference clocks */ + { "ttl", CONF_MOD_TTL }, /* NTP peers */ + { "", CONFIG_UNKNOWN } +}; + +/* + * "restrict" modifier keywords + */ +static struct keyword res_keywords[] = { + { "mask", CONF_RES_MASK }, + { "ignore", CONF_RES_IGNORE }, + { "noserve", CONF_RES_NOSERVE }, + { "notrust", CONF_RES_NOTRUST }, + { "noquery", CONF_RES_NOQUERY }, + { "nomodify", CONF_RES_NOMODIFY }, + { "nopeer", CONF_RES_NOPEER }, + { "notrap", CONF_RES_NOTRAP }, + { "lowpriotrap", CONF_RES_LPTRAP }, + { "ntpport", CONF_RES_NTPPORT }, + { "limited", CONF_RES_LIMITED }, + { "", CONFIG_UNKNOWN } +}; + +/* + * "trap" modifier keywords + */ +static struct keyword trap_keywords[] = { + { "port", CONF_TRAP_PORT }, + { "interface", CONF_TRAP_INTERFACE }, + { "", CONFIG_UNKNOWN } +}; + + +/* + * "fudge" modifier keywords + */ +static struct keyword fudge_keywords[] = { + { "time1", CONF_FDG_TIME1 }, + { "time2", CONF_FDG_TIME2 }, + { "stratum", CONF_FDG_STRATUM }, + { "refid", CONF_FDG_REFID }, + { "flag1", CONF_FDG_FLAG1 }, + { "flag2", CONF_FDG_FLAG2 }, + { "flag3", CONF_FDG_FLAG3 }, + { "flag4", CONF_FDG_FLAG4 }, + { "", CONFIG_UNKNOWN } +}; + + +/* + * "filegen" modifier keywords + */ +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 } +}; + +/* + * "type" modifier keywords + */ +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} +}; + +/* + * "enable", "disable" modifier keywords + */ +static struct keyword flags_keywords[] = { + { "auth", PROTO_AUTHENTICATE }, + { "bclient", PROTO_BROADCLIENT }, + { "ntp", PROTO_NTP }, + { "kernel", PROTO_KERNEL }, + { "monitor", PROTO_MONITOR }, + { "stats", PROTO_FILEGEN }, + { "", CONFIG_UNKNOWN } +}; + +/* + * pps modifier keywords + */ +static struct keyword pps_keywords[] = { + { "assert", CONF_PPS_ASSERT }, + { "clear", CONF_PPS_CLEAR }, + { "hardpps", CONF_PPS_HARDPPS }, + { "", CONFIG_UNKNOWN } +}; + +/* + * "logconfig" building blocks + */ +struct masks { + const char *name; + unsigned long mask; +}; + +static struct masks logcfg_class[] = { + { "sys", NLOG_OSYS }, + { "peer", NLOG_OPEER }, + { "clock", NLOG_OCLOCK }, + { "sync", NLOG_OSYNC }, + { (char *)0, 0 } +}; + +static struct masks logcfg_item[] = { + { "info", NLOG_INFO }, + { "allinfo", NLOG_SYSINFO|NLOG_PEERINFO|NLOG_CLOCKINFO|NLOG_SYNCINFO }, + { "events", NLOG_EVENT }, + { "allevents", NLOG_SYSEVENT|NLOG_PEEREVENT|NLOG_CLOCKEVENT|NLOG_SYNCEVENT }, + { "status", NLOG_STATUS }, + { "allstatus", NLOG_SYSSTATUS|NLOG_PEERSTATUS|NLOG_CLOCKSTATUS|NLOG_SYNCSTATUS }, + { "statistics", NLOG_STATIST }, + { "allstatistics", NLOG_SYSSTATIST|NLOG_PEERSTATIST|NLOG_CLOCKSTATIST|NLOG_SYNCSTATIST }, + { "allclock", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<name) { + if (strncmp(*s, m->name, strlen(m->name)) == 0) { + *s += strlen(m->name); + return m->mask; + } else { + m++; + } + } + return 0; +} + +/* + * get_match - find logmask value + */ +static unsigned long +get_match( + char *s, + struct masks *m + ) +{ + while (m->name) { + if (strcmp(s, m->name) == 0) { + return m->mask; + } else { + m++; + } + } + return 0; +} + +/* + * get_logmask - build bitmask for ntp_syslogmask + */ +static unsigned long +get_logmask( + char *s + ) +{ + char *t; + unsigned long offset; + unsigned long mask; + + t = s; + offset = get_pfxmatch(&t, logcfg_class); + mask = get_match(t, logcfg_item); + + if (mask) + return mask << offset; + else + msyslog(LOG_ERR, "logconfig: illegal argument %s - ignored", s); + + return 0; +} + +/* + * getstartup - search through the options looking for a debugging flag + */ +void +getstartup( + int argc, + char *argv[] + ) +{ + int errflg; + int c; + +#ifdef DEBUG + debug = 0; /* no debugging by default */ +#endif + + /* + * This is a big hack. We don't really want to read command line + * configuration until everything else is initialized, since + * the ability to configure the system may depend on storage + * and the like having been initialized. Except that we also + * don't want to initialize anything until after detaching from + * the terminal, but we won't know to do that until we've + * parsed the command line. Do that now, crudely, and do it + * again later. Our ntp_getopt() is explicitly reusable, by the + * way. Your own mileage may vary. + * + * This hack is even called twice (to allow complete logging to file) + */ + errflg = 0; + progname = argv[0]; + + /* + * Decode argument list + */ + while ((c = ntp_getopt(argc, argv, ntp_options)) != EOF) + switch (c) { +#ifdef DEBUG + case 'd': + ++debug; + break; + case 'D': + debug = (int)atol(ntp_optarg); + printf("Debug1: %s -> %x = %d\n", ntp_optarg, debug, debug); + break; +#else + case 'd': + case 'D': + msyslog(LOG_ERR, "ntpd not compiled with -DDEBUG option - no DEBUG support"); + fprintf(stderr, "ntpd not compiled with -DDEBUG option - no DEBUG support"); + ++errflg; + break; +#endif + case 'L': + listen_to_virtual_ips = 1; + break; + case 'l': + { + FILE *new_file; + + new_file = fopen(ntp_optarg, "a"); + if (new_file != NULL) { + NLOG(NLOG_SYSINFO) + msyslog(LOG_NOTICE, "logging to file %s", ntp_optarg); + if (syslog_file != NULL && + fileno(syslog_file) != fileno(new_file)) + (void)fclose(syslog_file); + + syslog_file = new_file; + syslogit = 0; + } + else + msyslog(LOG_ERR, + "Cannot open log file %s", + ntp_optarg); + } + break; + + case 'n': + ++nofork; + break; + + case '?': + ++errflg; + break; + + default: + break; + } + + if (errflg || ntp_optind != argc) { + (void) fprintf(stderr, "usage: %s [ -abdgmnx ] [ -c config_file ] [ -e e_delay ]\n", progname); + (void) fprintf(stderr, "\t\t[ -f freq_file ] [ -k key_file ] [ -l log_file ]\n"); + (void) fprintf(stderr, "\t\t[ -p pid_file ] [ -r broad_delay ] [ -s statdir ]\n"); + (void) fprintf(stderr, "\t\t[ -t trust_key ] [ -v sys_var ] [ -V default_sysvar ]\n"); +#if defined(HAVE_SCHED_SETSCHEDULER) + (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); +#endif + exit(2); + } + ntp_optind = 0; /* reset ntp_optind to restart ntp_getopt */ + +#ifdef DEBUG + if (debug) { +#ifdef HAVE_SETVBUF + static char buf[BUFSIZ]; + setvbuf(stdout, buf, _IOLBF, BUFSIZ); +#else + setlinebuf(stdout); +#endif + } +#endif +} + +/* + * getconfig - get command line options and read the configuration file + */ +void +getconfig( + int argc, + char *argv[] + ) +{ + register int i; + int c; + int errflg; + int peerversion; + int minpoll; + int maxpoll; + int ttl; + u_long peerkey; + u_long lpeerkey; + int peerflags; + int hmode; + struct sockaddr_in peeraddr; + struct sockaddr_in maskaddr; + FILE *fp; + char line[MAXLINE]; + char *(tokens[MAXTOKENS]); + int ntokens; + int tok = CONFIG_UNKNOWN; + struct interface *localaddr; + const char *config_file; +#ifdef HAVE_NETINFO + struct netinfo_config_state *config_netinfo = NULL; + int check_netinfo = 1; +#endif /* HAVE_NETINFO */ +#ifdef SYS_WINNT + char *alt_config_file; + LPTSTR temp; + char config_file_storage[MAX_PATH]; + char alt_config_file_storage[MAX_PATH]; +#endif /* SYS_WINNT */ + struct refclockstat clock_stat; + FILEGEN *filegen; + + /* + * Initialize, initialize + */ + errflg = 0; +#ifdef DEBUG + debug = 0; +#endif /* DEBUG */ +#ifndef SYS_WINNT + config_file = CONFIG_FILE; +#else + temp = CONFIG_FILE; + if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n"); + exit(1); + } + config_file = config_file_storage; + + temp = ALT_CONFIG_FILE; + if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n"); + exit(1); + } + alt_config_file = alt_config_file_storage; + +#endif /* SYS_WINNT */ + progname = argv[0]; + res_fp = NULL; + memset((char *)sys_phone, 0, sizeof(sys_phone)); + ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */ + + /* + * install a non default variable with this daemon version + */ + (void) sprintf(line, "daemon_version=\"%s\"", Version); + set_sys_var(line, strlen(line)+1, RO); + + /* + * Say how we're setting the time of day + */ + (void) sprintf(line, "settimeofday=\"%s\"", set_tod_using); + set_sys_var(line, strlen(line)+1, RO); + + /* + * Initialize the loop. + */ + loop_config(LOOP_DRIFTINIT, 0.); + + /* + * Decode argument list + */ + while ((c = ntp_getopt(argc, argv, ntp_options)) != EOF) { + switch (c) { + case 'a': + proto_config(PROTO_AUTHENTICATE, 1, 0.); + break; + + case 'A': + proto_config(PROTO_AUTHENTICATE, 0, 0.); + break; + + case 'b': + proto_config(PROTO_BROADCLIENT, 1, 0.); + break; + + case 'c': + config_file = ntp_optarg; +#ifdef HAVE_NETINFO + check_netinfo = 0; +#endif + break; + + case 'd': +#ifdef DEBUG + debug++; +#else + errflg++; +#endif /* DEBUG */ + break; + + case 'D': +#ifdef DEBUG + debug = (int)atol(ntp_optarg); + printf("Debug2: %s -> %x = %d\n", ntp_optarg, debug, debug); +#else + errflg++; +#endif /* DEBUG */ + break; + + case 'f': + stats_config(STATS_FREQ_FILE, ntp_optarg); + break; + + case 'g': + correct_any = TRUE; + break; + + case 'k': + getauthkeys(ntp_optarg); + break; + + case 'L': /* already done at pre-scan */ + case 'l': /* already done at pre-scan */ + break; + + case 'm': + proto_config(PROTO_MULTICAST_ADD, htonl(INADDR_NTP), 0.); + sys_bclient = 1; + break; + + case 'n': /* already done at pre-scan */ + break; + + case 'p': + stats_config(STATS_PID_FILE, ntp_optarg); + break; + + case 'P': +#if defined(HAVE_SCHED_SETSCHEDULER) + config_priority = (int)atol(ntp_optarg); + config_priority_override = 1; +#else + errflg++; +#endif + break; + + case 'r': + do { + double tmp; + + if (sscanf(ntp_optarg, "%lf", &tmp) != 1) { + msyslog(LOG_ERR, + "command line broadcast delay value %s undecodable", + ntp_optarg); + } else { + proto_config(PROTO_BROADDELAY, 0, tmp); + } + } while (0); + break; + + case 's': + stats_config(STATS_STATSDIR, ntp_optarg); + break; + + case 't': + do { + u_long tkey; + + tkey = (int)atol(ntp_optarg); + if (tkey <= 0 || tkey > NTP_MAXKEY) { + msyslog(LOG_ERR, + "command line trusted key %s is invalid", + ntp_optarg); + } else { + authtrust(tkey, 1); + } + } while (0); + break; + + case 'v': + case 'V': + set_sys_var(ntp_optarg, strlen(ntp_optarg)+1, + RW | ((c == 'V') ? DEF : 0)); + break; + + case 'x': + allow_set_backward = FALSE; + break; + + default: + errflg++; + break; + } + } + + if (errflg || ntp_optind != argc) { + (void) fprintf(stderr, "usage: %s [ -abdgmnx ] [ -c config_file ] [ -e e_delay ]\n", progname); + (void) fprintf(stderr, "\t\t[ -f freq_file ] [ -k key_file ] [ -l log_file ]\n"); + (void) fprintf(stderr, "\t\t[ -p pid_file ] [ -r broad_delay ] [ -s statdir ]\n"); + (void) fprintf(stderr, "\t\t[ -t trust_key ] [ -v sys_var ] [ -V default_sysvar ]\n"); +#if defined(HAVE_SCHED_SETSCHEDULER) + (void) fprintf(stderr, "\t\t[ -P fixed_process_priority ]\n"); +#endif + exit(2); + } + + if ( + (fp = fopen(FindConfig(config_file), "r")) == NULL +#ifdef HAVE_NETINFO + /* If there is no config_file, try NetInfo. */ + && check_netinfo && !(config_netinfo = get_netinfo_config()) +#endif /* HAVE_NETINFO */ + ) { + fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file)); + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file)); +#ifdef SYS_WINNT + /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */ + + if ((fp = fopen(FindConfig(alt_config_file), "r")) == NULL) { + + /* + * Broadcast clients can sometimes run without + * a configuration file. + */ + + fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file)); + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file)); + return; + } +#else /* not SYS_WINNT */ + return; +#endif /* not SYS_WINNT */ + } + + for (;;) { + if (fp) + tok = gettokens(fp, line, tokens, &ntokens); +#ifdef HAVE_NETINFO + else + tok = gettokens_netinfo(config_netinfo, tokens, &ntokens); +#endif /* HAVE_NETINFO */ + + if (tok == CONFIG_UNKNOWN) break; + + switch(tok) { + case CONFIG_PEER: + case CONFIG_SERVER: + case CONFIG_MANYCASTCLIENT: + case CONFIG_BROADCAST: + if (tok == CONFIG_PEER) + hmode = MODE_ACTIVE; + else if (tok == CONFIG_SERVER) + hmode = MODE_CLIENT; + else if (tok == CONFIG_MANYCASTCLIENT) + hmode = MODE_CLIENT; + else + hmode = MODE_BROADCAST; + + if (ntokens < 2) { + msyslog(LOG_ERR, + "No address for %s, line ignored", + tokens[0]); + break; + } + + if (!getnetnum(tokens[1], &peeraddr, 0)) { + errflg = -1; + } else { + errflg = 0; + + if ( +#ifdef REFCLOCK + !ISREFCLOCKADR(&peeraddr) && +#endif + ISBADADR(&peeraddr)) { + msyslog(LOG_ERR, + "attempt to configure invalid address %s", + ntoa(&peeraddr)); + break; + } + /* + * Shouldn't be able to specify multicast + * address for server/peer! + * and unicast address for manycastclient! + */ + if (((tok == CONFIG_SERVER) || + (tok == CONFIG_PEER)) && +#ifdef REFCLOCK + !ISREFCLOCKADR(&peeraddr) && +#endif + IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr))) { + msyslog(LOG_ERR, + "attempt to configure invalid address %s", + ntoa(&peeraddr)); + break; + } + if ((tok == CONFIG_MANYCASTCLIENT) && + !IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr))) { + msyslog(LOG_ERR, + "attempt to configure invalid address %s", + ntoa(&peeraddr)); + break; + } + } + + peerversion = NTP_VERSION; + minpoll = NTP_MINDPOLL; + maxpoll = NTP_MAXDPOLL; + peerkey = 0; + peerflags = 0; + ttl = 0; + for (i = 2; i < ntokens; i++) + switch (matchkey(tokens[i], mod_keywords)) { + case CONF_MOD_VERSION: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "peer/server version requires an argument"); + errflg = 1; + break; + } + peerversion = atoi(tokens[++i]); + if ((u_char)peerversion > NTP_VERSION + || (u_char)peerversion < NTP_OLDVERSION) { + msyslog(LOG_ERR, + "inappropriate version number %s, line ignored", + tokens[i]); + errflg = 1; + } + break; + + case CONF_MOD_KEY: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "key: argument required"); + errflg = 1; + break; + } + peerkey = (int)atol(tokens[++i]); + peerflags |= FLAG_AUTHENABLE; + break; + + case CONF_MOD_MINPOLL: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "minpoll: argument required"); + errflg = 1; + break; + } + minpoll = atoi(tokens[++i]); + if (minpoll < NTP_MINPOLL) + minpoll = NTP_MINPOLL; + break; + + case CONF_MOD_MAXPOLL: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "maxpoll: argument required" + ); + errflg = 1; + break; + } + maxpoll = atoi(tokens[++i]); + if (maxpoll > NTP_MAXPOLL) + maxpoll = NTP_MAXPOLL; + break; + + case CONF_MOD_PREFER: + peerflags |= FLAG_PREFER; + break; + + case CONF_MOD_NOSELECT: + peerflags |= FLAG_NOSELECT; + break; + + case CONF_MOD_BURST: + peerflags |= FLAG_BURST; + break; + + case CONF_MOD_SKEY: + peerflags |= FLAG_SKEY | FLAG_AUTHENABLE; + break; + + case CONF_MOD_TTL: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "ttl: argument required"); + errflg = 1; + break; + } + ttl = atoi(tokens[++i]); + break; + + case CONF_MOD_MODE: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "mode: argument required"); + errflg = 1; + break; + } + ttl = atoi(tokens[++i]); + break; + + case CONFIG_UNKNOWN: + errflg = 1; + break; + } + if (minpoll > maxpoll) { + msyslog(LOG_ERR, "config error: minpoll > maxpoll"); + errflg = 1; + } + if (errflg == 0) { + if (peer_config(&peeraddr, + (struct interface *)0, hmode, + peerversion, minpoll, maxpoll, + peerflags, ttl, peerkey) + == 0) { + msyslog(LOG_ERR, + "configuration of %s failed", + ntoa(&peeraddr)); + } + } else if (errflg == -1) { + save_resolve(tokens[1], hmode, peerversion, + minpoll, maxpoll, peerflags, ttl, + peerkey); + } + 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: + if (ntokens >= 2) { + FILE *new_file; + new_file = fopen(tokens[1], "a"); + if (new_file != NULL) { + NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, "logging to file %s", tokens[1]); + if (syslog_file != NULL && + fileno(syslog_file) != fileno(new_file)) + (void)fclose(syslog_file); + + syslog_file = new_file; + syslogit = 0; + } + else + msyslog(LOG_ERR, + "Cannot open log file %s", + tokens[1]); + } + else + msyslog(LOG_ERR, "logfile needs one argument"); + break; + + case CONFIG_LOGCONFIG: + for (i = 1; i < ntokens; i++) + { + int add = 1; + int equals = 0; + char * s = &tokens[i][0]; + + switch (*s) { + case '+': + case '-': + case '=': + add = *s == '+'; + equals = *s == '='; + s++; + break; + + default: + break; + } + if (equals) { + ntp_syslogmask = get_logmask(s); + } else { + if (add) { + ntp_syslogmask |= get_logmask(s); + } else { + ntp_syslogmask &= ~get_logmask(s); + } + } +#ifdef DEBUG + if (debug) + printf("ntp_syslogmask = 0x%08lx (%s)\n", ntp_syslogmask, tokens[i]); +#endif + } + break; + + case CONFIG_BROADCASTCLIENT: + proto_config(PROTO_BROADCLIENT, 1, 0.); + break; + + case CONFIG_MULTICASTCLIENT: + case CONFIG_MANYCASTSERVER: + if (ntokens > 1) { + for (i = 1; i < ntokens; i++) { + if (getnetnum(tokens[i], &peeraddr, 1)) + proto_config(PROTO_MULTICAST_ADD, + peeraddr.sin_addr.s_addr, 0.); + } + } else + proto_config(PROTO_MULTICAST_ADD, + htonl(INADDR_NTP), 0.); + if (tok == CONFIG_MULTICASTCLIENT) { + sys_bclient = 1; +#ifdef DEBUG + if (debug) + printf("sys_bclient\n"); +#endif /* DEBUG */ + } + else if (tok == CONFIG_MANYCASTSERVER) { + sys_manycastserver = 1; +#ifdef DEBUG + if (debug) + printf("sys_manycastserver\n"); +#endif /* DEBUG */ + } + break; + + case CONFIG_AUTHENTICATE: + errflg = 0; + if (ntokens >= 2) { + if (STREQ(tokens[1], "yes")) + proto_config(PROTO_AUTHENTICATE, 1, 0.); + else if (STREQ(tokens[1], "no")) + proto_config(PROTO_AUTHENTICATE, 0, 0.); + else + errflg++; + } else { + errflg++; + } + + if (errflg) + msyslog(LOG_ERR, + "should be `authenticate yes|no'"); + break; + + case CONFIG_KEYS: + if (ntokens >= 2) { + getauthkeys(tokens[1]); + } + break; + + case CONFIG_REVOKE: + if (ntokens >= 2) { + sys_revoke = 1 << max(atoi(tokens[1]), 10); + } + break; + + case CONFIG_AUTOMAX: + if (ntokens >= 2) { + sys_automax = 1 << max(atoi(tokens[1]), 10); + } + break; + + case CONFIG_RESTRICT: + if (ntokens < 2) { + msyslog(LOG_ERR, "restrict requires an address"); + break; + } + if (STREQ(tokens[1], "default")) + peeraddr.sin_addr.s_addr = htonl(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 = ~(u_int32)0; + for (i = 2; i < ntokens; i++) { + switch (matchkey(tokens[i], res_keywords)) { + case CONF_RES_MASK: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "mask keyword needs argument"); + errflg++; + break; + } + i++; + if (!getnetnum(tokens[i], &maskaddr, 1)) + errflg++; + break; + + case CONF_RES_IGNORE: + peerversion |= RES_IGNORE; + break; + + case CONF_RES_NOSERVE: + peerversion |= RES_DONTSERVE; + break; + + case CONF_RES_NOTRUST: + peerversion |= RES_DONTTRUST; + break; + + case CONF_RES_NOQUERY: + peerversion |= RES_NOQUERY; + break; + + case CONF_RES_NOMODIFY: + peerversion |= RES_NOMODIFY; + break; + + case CONF_RES_NOPEER: + peerversion |= RES_NOPEER; + break; + + case CONF_RES_NOTRAP: + peerversion |= RES_NOTRAP; + break; + + case CONF_RES_LPTRAP: + peerversion |= RES_LPTRAP; + break; + + case CONF_RES_NTPPORT: + peerkey |= RESM_NTPONLY; + break; + + case CONF_RES_LIMITED: + peerversion |= RES_LIMITED; + break; + + case CONFIG_UNKNOWN: + errflg++; + break; + } + } + if (SRCADR(&peeraddr) == htonl(INADDR_ANY)) + maskaddr.sin_addr.s_addr = 0; + if (!errflg) + hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr, + (int)peerkey, peerversion); + break; + + case CONFIG_BDELAY: + if (ntokens >= 2) { + double tmp; + + if (sscanf(tokens[1], "%lf", &tmp) != 1) { + msyslog(LOG_ERR, + "broadcastdelay value %s undecodable", + tokens[1]); + } else { + proto_config(PROTO_BROADDELAY, 0, tmp); + } + } + break; + + case CONFIG_TRUSTEDKEY: + for (i = 1; i < ntokens; i++) { + u_long tkey; + + tkey = atol(tokens[i]); + if (tkey == 0) { + msyslog(LOG_ERR, + "trusted key %s unlikely", + tokens[i]); + } else { + authtrust(tkey, 1); + } + } + break; + + case CONFIG_REQUESTKEY: + if (ntokens >= 2) { + u_long rkey; + + if (!atouint(tokens[1], &rkey)) { + msyslog(LOG_ERR, + "%s is undecodable as request key", + tokens[1]); + } else if (rkey == 0) { + msyslog(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; + + ckey = atol(tokens[1]); + if (ckey == 0) { + msyslog(LOG_ERR, + "%s makes a poor control keyid", + tokens[1]); + } else { + ctl_auth_keyid = ckey; + } + } + break; + + case CONFIG_TRAP: + if (ntokens < 2) { + msyslog(LOG_ERR, + "no address for trap command, line ignored"); + break; + } + 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) { + msyslog(LOG_ERR, + "trap port requires an argument"); + errflg = 1; + break; + } + peerversion = atoi(tokens[++i]); + if (peerversion <= 0 + || peerversion > 32767) { + msyslog(LOG_ERR, + "invalid port number %s, trap ignored", + tokens[i]); + errflg = 1; + } + break; + + case CONF_TRAP_INTERFACE: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "trap interface requires an argument"); + errflg = 1; + break; + } + + if (!getnetnum(tokens[++i], + &maskaddr, 1)) { + errflg = 1; + break; + } + + localaddr = findinterface(&maskaddr); + if (localaddr == NULL) { + msyslog(LOG_ERR, + "can't find interface with address %s", + ntoa(&maskaddr)); + errflg = 1; + } + break; + + case CONFIG_UNKNOWN: + errflg++; + break; + } + + if (!errflg) { + if (peerversion != 0) + peeraddr.sin_port = htons( (u_short) peerversion); + else + peeraddr.sin_port = htons(TRAPPORT); + if (localaddr == NULL) + localaddr = any_interface; + if (!ctlsettrap(&peeraddr, localaddr, 0, + NTP_VERSION)) + msyslog(LOG_ERR, + "can't set trap for %s, no resources", + ntoa(&peeraddr)); + } + break; + + case CONFIG_FUDGE: + if (ntokens < 2) { + msyslog(LOG_ERR, + "no address for fudge command, line ignored"); + break; + } + if (!getnetnum(tokens[1], &peeraddr, 1)) + break; + + if (!ISREFCLOCKADR(&peeraddr)) { + msyslog(LOG_ERR, + "%s is inappropriate address for the fudge command, line ignored", + ntoa(&peeraddr)); + break; + } + + memset((void *)&clock_stat, 0, sizeof clock_stat); + errflg = 0; + for (i = 2; i < ntokens-1; i++) { + switch (c = matchkey(tokens[i], + fudge_keywords)) { + case CONF_FDG_TIME1: + if (sscanf(tokens[++i], "%lf", + &clock_stat.fudgetime1) != 1) { + msyslog(LOG_ERR, + "fudge %s time1 value in error", + ntoa(&peeraddr)); + errflg = i; + break; + } + clock_stat.haveflags |= CLK_HAVETIME1; + break; + + case CONF_FDG_TIME2: + if (sscanf(tokens[++i], "%lf", + &clock_stat.fudgetime2) != 1) { + msyslog(LOG_ERR, + "fudge %s time2 value in error", + ntoa(&peeraddr)); + errflg = i; + break; + } + clock_stat.haveflags |= CLK_HAVETIME2; + break; + + + case CONF_FDG_STRATUM: + /* HMS: the (long *)_ may be trouble */ + if (!atoint(tokens[++i], + (long *)&clock_stat.fudgeval1)) + { + msyslog(LOG_ERR, + "fudge %s stratum value in error", + ntoa(&peeraddr)); + errflg = i; + break; + } + clock_stat.haveflags |= CLK_HAVEVAL1; + break; + + case CONF_FDG_REFID: + /* HMS: Endianness and 0 bytes? */ + /* XXX */ + strncpy((char *)&clock_stat.fudgeval2, + tokens[++i], 4); + clock_stat.haveflags |= CLK_HAVEVAL2; + break; + + case CONF_FDG_FLAG1: + case CONF_FDG_FLAG2: + case CONF_FDG_FLAG3: + case CONF_FDG_FLAG4: + if (!atouint(tokens[++i], &lpeerkey) + || lpeerkey > 1) { + msyslog(LOG_ERR, + "fudge %s flag value in error", + ntoa(&peeraddr)); + peerkey = lpeerkey; + errflg = i; + break; + } + peerkey = lpeerkey; + switch(c) { + case CONF_FDG_FLAG1: + c = CLK_FLAG1; + clock_stat.haveflags|=CLK_HAVEFLAG1; + break; + case CONF_FDG_FLAG2: + c = CLK_FLAG2; + clock_stat.haveflags|=CLK_HAVEFLAG2; + break; + case CONF_FDG_FLAG3: + c = CLK_FLAG3; + clock_stat.haveflags|=CLK_HAVEFLAG3; + break; + case CONF_FDG_FLAG4: + c = CLK_FLAG4; + clock_stat.haveflags|=CLK_HAVEFLAG4; + break; + } + if (peerkey == 0) + clock_stat.flags &= ~c; + else + clock_stat.flags |= c; + break; + + case CONFIG_UNKNOWN: + errflg = -1; + break; + } + } + +#ifdef REFCLOCK + /* + * If reference clock support isn't defined the + * fudge line will still be accepted and syntax + * checked, but will essentially do nothing. + */ + if (!errflg) { + refclock_control(&peeraddr, &clock_stat, + (struct refclockstat *)0); + } +#endif + break; + + case CONFIG_STATSDIR: + if (ntokens >= 2) { + stats_config(STATS_STATSDIR,tokens[1]); + } + break; + + case CONFIG_STATISTICS: + for (i = 1; i < ntokens; i++) { + filegen = filegen_get(tokens[i]); + + if (filegen == NULL) { + msyslog(LOG_ERR, + "no statistics named %s available", + tokens[i]); + continue; + } +#ifdef DEBUG + if (debug > 3) + printf("enabling filegen for %s statistics \"%s%s\"\n", + tokens[i], filegen->prefix, filegen->basename); +#endif + filegen->flag |= FGEN_FLAG_ENABLED; + } + break; + + case CONFIG_FILEGEN: + if (ntokens < 2) { + msyslog(LOG_ERR, + "no id for filegen command, line ignored"); + break; + } + + filegen = filegen_get(tokens[1]); + if (filegen == NULL) { + msyslog(LOG_ERR, + "unknown filegen \"%s\" ignored", + tokens[1]); + break; + } + /* + * peerversion is (ab)used for filegen file (index) + * peerkey is (ab)used for filegen type + * peerflags is (ab)used for filegen flags + */ + peerversion = 0; + peerkey = filegen->type; + peerflags = filegen->flag; + errflg = 0; + + for (i = 2; i < ntokens; i++) { + switch (matchkey(tokens[i], filegen_keywords)) { + case CONF_FGEN_FILE: + if (i >= ntokens - 1) { + msyslog(LOG_ERR, + "filegen %s file requires argument", + tokens[1]); + errflg = i; + break; + } + peerversion = ++i; + break; + case CONF_FGEN_TYPE: + if (i >= ntokens -1) { + msyslog(LOG_ERR, + "filegen %s type requires argument", + tokens[1]); + errflg = i; + break; + } + peerkey = matchkey(tokens[++i], fgen_types); + if (peerkey == CONFIG_UNKNOWN) { + msyslog(LOG_ERR, + "filegen %s unknown type \"%s\"", + tokens[1], tokens[i]); + errflg = i; + break; + } + break; + + case CONF_FGEN_FLAG_LINK: + peerflags |= FGEN_FLAG_LINK; + break; + + case CONF_FGEN_FLAG_NOLINK: + peerflags &= ~FGEN_FLAG_LINK; + break; + + case CONF_FGEN_FLAG_ENABLE: + peerflags |= FGEN_FLAG_ENABLED; + break; + + case CONF_FGEN_FLAG_DISABLE: + peerflags &= ~FGEN_FLAG_ENABLED; + break; + } + } + if (!errflg) { + filegen_config(filegen, tokens[peerversion], + (u_char)peerkey, (u_char)peerflags); + } + break; + + case CONFIG_SETVAR: + if (ntokens < 2) { + msyslog(LOG_ERR, + "no value for setvar command - line ignored"); + } else { + set_sys_var(tokens[1], strlen(tokens[1])+1, + RW | + ((((ntokens > 2) + && !strcmp(tokens[2], + "default"))) + ? DEF + : 0)); + } + break; + + case CONFIG_CLIENTLIMIT: + if (ntokens < 2) { + msyslog(LOG_ERR, + "no value for clientlimit command - line ignored"); + } else { + u_long ui; + + if (!atouint(tokens[1], &ui) || !ui) { + msyslog(LOG_ERR, + "illegal value for clientlimit command - line ignored"); + } else { + char bp[80]; + +#ifdef DEBUG + if (debug) + sprintf(bp, "client_limit=%lu", ui); +#endif + set_sys_var(bp, strlen(bp)+1, RO); + client_limit = ui; + } + } + break; + + case CONFIG_CLIENTPERIOD: + if (ntokens < 2) { + msyslog(LOG_ERR, + "no value for clientperiod command - line ignored"); + } else { + u_long ui; + + if (!atouint(tokens[1], &ui) || ui < 64) { + msyslog(LOG_ERR, + "illegal value for clientperiod command - line ignored"); + } else { + char bp[80]; + + sprintf(bp, "client_limit_period=%ld", ui); + set_sys_var(bp, strlen(bp)+1, RO); + client_limit_period = ui; + } + } + break; + + case CONFIG_ENABLE: + for (i = 1; i < ntokens; i++) { + int flag; + + flag = matchkey(tokens[i], flags_keywords); + if (flag == CONFIG_UNKNOWN) { + msyslog(LOG_ERR, + "enable unknown flag %s", + tokens[i]); + errflg = 1; + break; + } + proto_config(flag, 1, 0.); + } + break; + + case CONFIG_DISABLE: + for (i = 1; i < ntokens; i++) { + int flag; + + flag = matchkey(tokens[i], flags_keywords); + if (flag == CONFIG_UNKNOWN) { + msyslog(LOG_ERR, + "disable unknown flag %s", + tokens[i]); + errflg = 1; + break; + } + proto_config(flag, 0, 0.); + } + break; + + case CONFIG_PHONE: + for (i = 1; i < ntokens && i < MAXPHONE; i++) { + (void)strncpy(sys_phone[i - 1], + tokens[i], MAXDIAL); + } + sys_phone[i - 1][0] = '\0'; + break; + + case CONFIG_PPS: + if (ntokens < 2) { + msyslog(LOG_ERR, + "pps missing device name"); + break; + } + (void)strncpy(pps_device, tokens[1], MAXPPS); + for (i = 2; i < ntokens; i++) { + int flag; + + flag = matchkey(tokens[i], pps_keywords); + switch(flag) { + case CONF_PPS_ASSERT: + pps_assert = 1; + break; + case CONF_PPS_CLEAR: + pps_assert = 0; + break; + case CONF_PPS_HARDPPS: + pps_hardpps = 1; + break; + default: + msyslog(LOG_ERR, + "pps unknown flag %s", + tokens[i]); + errflg = 1; + break; + } + if(errflg) + break; + } + break; + } + } + if (fp) (void)fclose(fp); +#ifdef HAVE_NETINFO + if (config_netinfo) free_netinfo_config(config_netinfo); +#endif /* HAVE_NETINFO */ + + if (res_fp != NULL) { + /* + * Need name resolution + */ + do_resolve_internal(); + } +} + + +#ifdef HAVE_NETINFO + +/* + * get_netinfo_config - find the nearest NetInfo domain with an ntp + * configuration and initialize the configuration state. + */ +static struct netinfo_config_state * +get_netinfo_config() +{ + ni_status status; + void *domain; + ni_id config_dir; + struct netinfo_config_state *config; + + if (ni_open(NULL, ".", &domain) != NI_OK) return NULL; + + while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) { + void *next_domain; + if (ni_open(domain, "..", &next_domain) != NI_OK) { + ni_free(next_domain); + break; + } + ni_free(domain); + domain = next_domain; + } + if (status != NI_OK) { + ni_free(domain); + return NULL; + } + + config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state)); + config->domain = domain; + config->config_dir = config_dir; + config->prop_index = 0; + config->val_index = 0; + config->val_list = NULL; + + return config; +} + + + +/* + * free_netinfo_config - release NetInfo configuration state + */ +static void +free_netinfo_config(struct netinfo_config_state *config) +{ + ni_free(config->domain); + free(config); +} + + + +/* + * gettokens_netinfo - return tokens from NetInfo + */ +static int +gettokens_netinfo ( + struct netinfo_config_state *config, + char **tokenlist, + int *ntokens + ) +{ + int prop_index = config->prop_index; + int val_index = config->val_index; + char **val_list = config->val_list; + + /* + * Iterate through each keyword and look for a property that matches it. + */ + again: + if (!val_list) { + for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++) + { + ni_namelist namelist; + struct keyword current_prop = keywords[prop_index]; + + /* + * For each value associated in the property, we're going to return + * a separate line. We squirrel away the values in the config state + * so the next time through, we don't need to do this lookup. + */ + NI_INIT(&namelist); + if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) { + ni_index index; + + /* Found the property, but it has no values */ + if (namelist.ni_namelist_len == 0) continue; + + if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1)))) + { msyslog(LOG_ERR, "out of memory while configuring"); break; } + + for (index = 0; index < namelist.ni_namelist_len; index++) { + char *value = namelist.ni_namelist_val[index]; + + if (! (val_list[index] = (char*)malloc(strlen(value+1)))) + { msyslog(LOG_ERR, "out of memory while configuring"); break; } + + strcpy(val_list[index], value); + } + val_list[index] = NULL; + + break; + } + ni_namelist_free(&namelist); + } + config->prop_index = prop_index; + } + + /* No list; we're done here. */ + if (!val_list) return CONFIG_UNKNOWN; + + /* + * We have a list of values for the current property. + * Iterate through them and return each in order. + */ + if (val_list[val_index]) + { + int ntok = 1; + int quoted = 0; + char *tokens = val_list[val_index]; + + msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]); + + (const char*)tokenlist[0] = keywords[prop_index].text; + for (ntok = 1; ntok < MAXTOKENS; ntok++) { + tokenlist[ntok] = tokens; + while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted)) + quoted ^= (*tokens++ == '"'); + + if (ISEOL(*tokens)) { + *tokens = '\0'; + break; + } else { /* must be space */ + *tokens++ = '\0'; + while (ISSPACE(*tokens)) tokens++; + if (ISEOL(*tokens)) break; + } + } + *ntokens = ntok + 1; + + config->val_index++; + + return keywords[prop_index].keytype; + } + + /* We're done with the current property. */ + prop_index = ++config->prop_index; + + /* Free val_list and reset counters. */ + for (val_index = 0; val_list[val_index]; val_index++) + free(val_list[val_index]); + free(val_list); val_list = config->val_list = NULL; val_index = config->val_index = 0; + + goto again; +} + +#endif /* HAVE_NETINFO */ + + +/* + * gettokens - read a line and return tokens + */ +static int +gettokens ( + FILE *fp, + char *line, + char **tokenlist, + int *ntokens + ) +{ + register char *cp; + register int ntok; + register int quoted = 0; + + /* + * Find start of first token + */ + again: + while ((cp = fgets(line, MAXLINE, fp)) != NULL) { + cp = line; + while (ISSPACE(*cp)) + cp++; + if (!ISEOL(*cp)) + break; + } + if (cp == NULL) { + *ntokens = 0; + return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */ + } + + /* + * Now separate out the tokens + */ + for (ntok = 0; ntok < MAXTOKENS; ntok++) { + tokenlist[ntok] = cp; + while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted)) + quoted ^= (*cp++ == '"'); + + if (ISEOL(*cp)) { + *cp = '\0'; + break; + } else { /* must be space */ + *cp++ = '\0'; + while (ISSPACE(*cp)) + cp++; + if (ISEOL(*cp)) + break; + } + } + + /* + * Return the match + */ + *ntokens = ntok + 1; + ntok = matchkey(tokenlist[0], keywords); + if (ntok == CONFIG_UNKNOWN) + goto again; + return ntok; +} + + + +/* + * matchkey - match a keyword to a list + */ +static int +matchkey( + register char *word, + register struct keyword *keys + ) +{ + for (;;) { + if (keys->keytype == CONFIG_UNKNOWN) { + msyslog(LOG_ERR, + "configure: keyword \"%s\" unknown, line ignored", + word); + return CONFIG_UNKNOWN; + } + if (STRSAME(word, keys->text)) + return keys->keytype; + keys++; + } +} + + +/* + * getnetnum - return a net number (this is crude, but careful) + */ +static int +getnetnum( + const char *num, + struct sockaddr_in *addr, + int complain + ) +{ + register const char *cp; + register char *bp; + register int i; + register int temp; + char buf[80]; /* will core dump on really stupid stuff */ + u_int32 netnum; + + /* XXX ELIMINATE replace with decodenetnum */ + cp = num; + netnum = 0; + for (i = 0; i < 4; i++) { + bp = buf; + while (isdigit((int)*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 %lu\n", + num, i, buf, temp, (u_long)netnum); +#endif + } + + if (i < 4) { + if (complain) + msyslog(LOG_ERR, + "getnetnum: \"%s\" invalid host number, line ignored", + num); +#ifdef DEBUG + if (debug > 3) + printf( + "getnetnum: \"%s\" invalid host number, line ignored\n", + num); +#endif + return 0; + } + + /* + * make up socket address. Clear it out for neatness. + */ + memset((void *)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 (%lx)\n", + num, ntoa(addr), (u_long)netnum); +#endif + return 1; +} + + +#if !defined(VMS) +/* + * catchchild - receive the resolver's exit status + */ +static RETSIGTYPE +catchchild( + int sig + ) +{ + /* + * We only start up one child, and if we're here + * it should have already exited. Hence the following + * shouldn't hang. If it does, please tell me. + */ +#if !defined (SYS_WINNT) && !defined(SYS_VXWORKS) + (void) wait(0); +#endif /* SYS_WINNT && VXWORKS*/ +} +#endif /* VMS */ + + +/* + * save_resolve - save configuration info into a file for later name resolution + */ +static void +save_resolve( + char *name, + int mode, + int version, + int minpoll, + int maxpoll, + int flags, + int ttl, + u_long keyid + ) +{ +#ifndef SYS_VXWORKS + if (res_fp == NULL) { +#ifndef SYS_WINNT + (void) strcpy(res_file, RES_TEMPFILE); +#else + /* no /tmp directory under NT */ + { + DWORD len; + if(!(len = GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) { + msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m"); + return; + } + (void) strcat(res_file, "ntpdXXXXXX"); + } +#endif /* SYS_WINNT */ +#ifdef HAVE_MKSTEMP + { + int fd; + + res_fp = NULL; + if ((fd = mkstemp(res_file)) != -1) + res_fp = fdopen(fd, "w"); + } +#else + (void) mktemp(res_file); + res_fp = fopen(res_file, "w"); +#endif + if (res_fp == NULL) { + msyslog(LOG_ERR, "open failed for %s: %m", res_file); + return; + } + } +#ifdef DEBUG + if (debug) { + printf("resolving %s\n", name); + } +#endif + + (void) fprintf(res_fp, "%s %d %d %d %d %d %d %lu\n", name, mode, + version, minpoll, maxpoll, flags, ttl, keyid); +#else /* SYS_VXWORKS */ + /* save resolve info to a struct */ +#endif /* SYS_VXWORKS */ +} + + +/* + * abort_resolve - terminate the resolver stuff and delete the file + */ +static void +abort_resolve(void) +{ + /* + * In an ideal world we would might reread the file and + * log the hosts which aren't getting configured. Since + * this is too much work, however, just close and delete + * the temp file. + */ + if (res_fp != NULL) + (void) fclose(res_fp); + res_fp = NULL; + +#ifndef SYS_VXWORKS /* we don't open the file to begin with */ +#if !defined(VMS) + (void) unlink(res_file); +#else + (void) delete(res_file); +#endif /* VMS */ +#endif /* SYS_VXWORKS */ +} + + +#define KEY_TYPE_MD5 4 + +/* + * do_resolve_internal - start up the resolver function (not program) + */ +/* + * On VMS, this routine will simply refuse to resolve anything. + * + * Possible implementation: keep `res_file' in memory, do async + * name resolution via QIO, update from within completion AST. + * I'm unlikely to find the time for doing this, though. -wjm + */ +static void +do_resolve_internal(void) +{ + int i; + + if (res_fp == NULL) { + /* belch */ + msyslog(LOG_ERR, + "internal error in do_resolve_internal: res_fp == NULL"); + exit(1); + } + + /* we are done with this now */ + (void) fclose(res_fp); + res_fp = NULL; + +#if !defined(VMS) && !defined (SYS_VXWORKS) + /* find a keyid */ + if (info_auth_keyid == 0) + req_keyid = 65535; + else + req_keyid = info_auth_keyid; + + /* if doesn't exist, make up one at random */ + if (!authhavekey(req_keyid)) { + char rankey[8]; + + for (i = 0; i < 8; i++) + rankey[i] = RANDOM & 0xff; + authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey); + authtrust(req_keyid, 1); + } + + /* save keyid so we will accept config requests with it */ + info_auth_keyid = req_keyid; + req_file = res_file; /* set up pointer to res file */ +#ifndef SYS_WINNT + (void) signal_no_reset(SIGCHLD, catchchild); + +#ifndef SYS_VXWORKS + i = fork(); + if (i == 0) { + /* + * this used to close everything + * I don't think this is necessary + */ + /* + * To the unknown commenter above: + * Well, I think it's better to clean up + * after oneself. I have had problems with + * refclock-io when intres was running - things + * where fine again when ntpintres was gone. + * So some systems react erratic at least. + * + * Frank Kardel + * + * 94-11-16: + * Further debugging has proven that the above is + * absolutely harmful. The internal resolver + * is still in the SIGIO process group and the lingering + * async io information causes it to process requests from + * all file decriptor causing a race between the NTP daemon + * and the resolver. which then eats data when it wins 8-(. + * It is absolutly necessary to kill ane io associations + * shared with the NTP daemon. I currently don't want + * + * we also block SIGIO (currently no portes means to + * disable the signal handle for IO). + * + * Thanks to wgstuken@informatik.uni-erlangen.de to notice + * that it is the ntp-resolver child running into trouble. + * + * THUS: + */ + + closelog(); + kill_asyncio(); + + (void) signal_no_reset(SIGCHLD, SIG_DFL); + +#ifdef DEBUG + if (0) + debug = 2; +#endif + +# ifndef LOG_DAEMON + openlog("ntpd_initres", LOG_PID); +# else /* LOG_DAEMON */ + +# ifndef LOG_NTP +# define LOG_NTP LOG_DAEMON +# endif + openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP); +#ifndef SYS_CYGWIN32 +# ifdef DEBUG + if (debug) + setlogmask(LOG_UPTO(LOG_DEBUG)); + else +# endif /* DEBUG */ + setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */ +# endif /* LOG_DAEMON */ +#endif + + ntp_intres(); + + /* + * If we got here, the intres code screwed up. + * Print something so we don't die without complaint + */ + msyslog(LOG_ERR, "call to ntp_intres lost"); + abort_resolve(); + exit(1); + } +#else + /* vxWorks spawns a thread... -casey */ + i = sp (ntp_intres); + /*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/ +#endif + if (i == -1) { + msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m"); + (void) signal_no_reset(SIGCHLD, SIG_DFL); + abort_resolve(); + } +#else /* SYS_WINNT */ + { + /* NT's equivalent of fork() is _spawn(), but the start point + * of the new process is an executable filename rather than + * a function name as desired here. + */ + DWORD dwThreadId; + fflush(stdout); + if (!(ResolverThreadHandle = CreateThread( + NULL, /* no security attributes */ + 0, /* use default stack size */ + (LPTHREAD_START_ROUTINE) ntp_intres, /* thread function */ + NULL, /* argument to thread function */ + 0, /* use default creation flags */ + &dwThreadId))) { /* returns the thread identifier */ + msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres"); + abort_resolve(); + } + } +#endif /* SYS_WINNT */ +#else /* VMS VX_WORKS */ + msyslog(LOG_ERR, + "Name resolution not implemented for VMS - use numeric addresses"); + abort_resolve(); +#endif /* VMS VX_WORKS */ +} diff --git a/contrib/ntp/ntpd/ntp_control.c b/contrib/ntp/ntpd/ntp_control.c new file mode 100644 index 000000000000..e63765f0d2b4 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_control.c @@ -0,0 +1,2652 @@ +/* + * ntp_control.c - respond to control messages and send async traps + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.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) P((struct recvbuf *, int)); /* 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((const char *, unsigned int, int)); +static void ctl_putstr P((const char *, const char *, unsigned int)); +static void ctl_putdbl P((const char *, double)); +static void ctl_putuint P((const char *, u_long)); +static void ctl_puthex P((const char *, u_long)); +static void ctl_putint P((const char *, long)); +static void ctl_putts P((const char *, l_fp *)); +static void ctl_putadr P((const char *, u_int32)); +static void ctl_putid P((const char *, char *)); +static void ctl_putarray P((const char *, double *, int)); +static void ctl_putsys P((int)); +static void ctl_putpeer P((int, struct peer *)); +#ifdef REFCLOCK +static void ctl_putclock P((int, struct refclockstat *, int)); +#endif /* REFCLOCK */ +static struct ctl_var *ctl_getitem P((struct ctl_var *, char **)); +static u_long count_var P((struct ctl_var *)); +static void control_unspec P((struct recvbuf *, int)); +static void read_status P((struct recvbuf *, int)); +static void read_variables P((struct recvbuf *, int)); +static void write_variables P((struct recvbuf *, int)); +static void read_clock_status P((struct recvbuf *, int)); +static void write_clock_status P((struct recvbuf *, int)); +static void set_trap P((struct recvbuf *, int)); +static void unset_trap P((struct recvbuf *, int)); +static struct ctl_trap *ctlfindtrap P((struct sockaddr_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_STATE, RO, "state" }, /* 10 */ + { CS_OFFSET, RO, "phase" }, /* 11 */ + { CS_DRIFT, RO, "frequency" }, /* 12 */ + { CS_COMPLIANCE, RO, "jitter" }, /* 13 */ + { CS_CLOCK, RO, "clock" }, /* 14 */ + { CS_PROCESSOR, RO, "processor" }, /* 15 */ + { CS_SYSTEM, RO, "system" }, /* 16 */ + { CS_STABIL, RO, "stability" }, /* 17 */ + { CS_VARLIST, RO, "sys_var_list" }, /* 18 */ + { 0, EOV, "" } +}; + +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_PROCESSOR, + CS_SYSTEM, + CS_LEAP, + CS_STRATUM, + CS_PRECISION, + CS_ROOTDELAY, + CS_ROOTDISPERSION, + CS_PEERID, + CS_REFID, + CS_REFTIME, + CS_POLL, + CS_CLOCK, + CS_STATE, + CS_OFFSET, + CS_DRIFT, + CS_COMPLIANCE, + CS_STABIL, + 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_JITTER, RO, "jitter" }, /* 26 */ + { CP_DISPERSION,RO, "dispersion" }, /* 27 */ + { CP_KEYID, RO, "keyid" }, /* 28 */ + { CP_FILTDELAY, RO, "filtdelay=" }, /* 29 */ + { CP_FILTOFFSET, RO, "filtoffset=" }, /* 30 */ + { CP_PMODE, RO, "pmode" }, /* 31 */ + { CP_RECEIVED, RO, "received"}, /* 32 */ + { CP_SENT, RO, "sent" }, /* 33 */ + { CP_FILTERROR, RO, "filtdisp=" }, /* 34 */ + { CP_FLASH, RO, "flash" }, /* 35 */ + { CP_DISP, PADDING,"" }, /* 36 */ + { CP_VARLIST, RO, "peer_var_list" }, /* 37 */ + { 0, EOV, "" } +}; + + +/* + * 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_JITTER, + 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, "stratum" }, /* 9 */ + { CC_FUDGEVAL2, RO, "refid" }, /* 10 */ + { CC_FLAGS, RO, "flags" }, /* 11 */ + { CC_DEVICE, RO, "device" }, /* 12 */ + { CC_VARLIST, RO, "clock_var_list" },/* 13 */ + { 0, EOV, "" } +}; + + +/* + * 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. + */ +#ifndef HAVE_UNAME +# ifndef STR_SYSTEM +# define STR_SYSTEM "UNIX" +# endif +# ifndef STR_PROCESSOR +# define STR_PROCESSOR "unknown" +# endif + +static char str_system[] = STR_SYSTEM; +static char str_processor[] = STR_PROCESSOR; +#else +# include +static struct utsname utsnamebuf; +#endif /* HAVE_UNAME */ + +/* + * Trap structures. We only allow a few of these, and send + * a copy of each async message to each live one. Traps time + * out after an hour, it is up to the trap receipient to + * keep resetting it to avoid being timed out. + */ +/* ntp_request.c */ +struct ctl_trap ctl_trap[CTL_MAXTRAPS]; +int num_ctl_traps; + +/* + * Type bits, for ctlsettrap() call. + */ +#define TRAP_TYPE_CONFIG 0 /* used by configuration code */ +#define TRAP_TYPE_PRIO 1 /* priority trap */ +#define TRAP_TYPE_NONPRIO 2 /* nonpriority trap */ + + +/* + * List relating reference clock types to control message time sources. + * Index by the reference clock type. + * This list will only be used iff the reference clock driver doesn't + * set peer->sstclktype to something different than CTL_SST_TS_UNSPEC. + */ +static u_char clocktypes[] = { + CTL_SST_TS_NTP, /* REFCLK_NONE (0) */ + CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */ + CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK (2) */ + CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */ + CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */ + CTL_SST_TS_UHF, /* REFCLK_TRUETIME (5) */ + CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) */ + CTL_SST_TS_HF, /* REFCLK_CHU (7) */ + CTL_SST_TS_LF, /* REFCLOCK_PARSE (default) (8) */ + CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */ + CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */ + CTL_SST_TS_UHF, /* REFCLK_GPS_ARBITER (11) */ + CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */ + CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */ + CTL_SST_TS_LF, /* REFCLK_MSF_EES (14) */ + CTL_SST_TS_UHF, /* REFCLK_TRUETIME (15) */ + CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */ + CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */ + CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACTS (18) */ + CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */ + CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */ + CTL_SST_TS_UHF, /* REFCLK_GPS_VME (21) */ + CTL_SST_TS_ATOM, /* REFCLK_ATOM_PPS (22) */ + CTL_SST_TS_TELEPHONE, /* REFCLK_PTB_ACTS (23) */ + CTL_SST_TS_TELEPHONE, /* REFCLK_USNO (24) */ + CTL_SST_TS_UHF, /* REFCLK_TRUETIME (25) */ + CTL_SST_TS_UHF, /* REFCLK_GPS_HP (26) */ + CTL_SST_TS_TELEPHONE, /* REFCLK_ARCRON_MSF (27) */ + CTL_SST_TS_TELEPHONE, /* REFCLK_SHM (28) */ + CTL_SST_TS_UHF, /* REFCLK_PALISADE (29) */ + CTL_SST_TS_UHF, /* REFCLK_ONCORE (30) */ + CTL_SST_TS_UHF, /* REFCLK_JUPITER (31) */ + CTL_SST_TS_LF, /* REFCLK_CHRONOLOG (32) */ + CTL_SST_TS_LF, /* REFCLK_DUMBCLOCK (32) */ + CTL_SST_TS_LF, /* REFCLK_ULINK (33) */ +}; + + +/* + * 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 */ + +/* + * 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(void) +{ + int i; + +#ifdef HAVE_UNAME + uname(&utsnamebuf); +#endif /* HAVE_UNAME */ + + ctl_clr_stats(); + + ctl_auth_keyid = 0; + ctl_sys_last_event = EVNT_UNSPEC; + ctl_sys_num_events = 0; + + num_ctl_traps = 0; + for (i = 0; i < CTL_MAXTRAPS; i++) + ctl_trap[i].tr_flags = 0; +} + + +/* + * ctl_error - send an error response for the current request + */ +static void +ctl_error( + int errcode + ) +{ +#ifdef DEBUG + if (debug >= 4) + printf("sending control error %d\n", errcode); +#endif + /* + * fill in the fields. We assume rpkt.sequence and rpkt.associd + * have already been filled in. + */ + rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode & CTL_OP_MASK)); + rpkt.status = htons((u_short) ((errcode<<8) & 0xff00)); + rpkt.count = 0; + + /* + * send packet and bump counters + */ + if (res_authenticate && sys_authenticate) { + int maclen; + + *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) + = htonl(res_keyid); + maclen = authencrypt(res_keyid, (u_int32 *)&rpkt, + CTL_HEADER_LEN); + sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt, + CTL_HEADER_LEN + maclen); + } else { + sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt, + CTL_HEADER_LEN); + } + numctlerrors++; +} + + +/* + * process_control - process an incoming control message + */ +void +process_control( + struct recvbuf *rbufp, + int restrict_mask + ) +{ + register struct ntp_control *pkt; + register int req_count; + register int req_data; + register struct ctl_proc *cc; + int properlen; + int maclen; + +#ifdef DEBUG + if (debug > 1) + printf("in process_control()\n"); +#endif + + /* + * Save the addresses for error responses + */ + numctlreq++; + rmt_addr = &rbufp->recv_srcadr; + lcl_inter = rbufp->dstadr; + pkt = (struct ntp_control *)&rbufp->recv_pkt; + + /* + * If the length is less than required for the header, or + * it is a response or a fragment, ignore this. + */ + if (rbufp->recv_length < CTL_HEADER_LEN + || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR) + || pkt->offset != 0) { +#ifdef DEBUG + if (debug) + printf("invalid format in control packet\n"); +#endif + if (rbufp->recv_length < CTL_HEADER_LEN) + numctltooshort++; + if (pkt->r_m_e_op & CTL_RESPONSE) + numctlinputresp++; + if (pkt->r_m_e_op & CTL_MORE) + numctlinputfrag++; + if (pkt->r_m_e_op & CTL_ERROR) + numctlinputerr++; + if (pkt->offset != 0) + numctlbadoffset++; + return; + } + res_version = PKT_VERSION(pkt->li_vn_mode); + if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) { +#ifdef DEBUG + if (debug) + printf("unknown version %d in control packet\n", + res_version); +#endif + numctlbadversion++; + return; + } + + /* + * Pull enough data from the packet to make intelligent responses + */ + rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version, MODE_CONTROL); + res_opcode = pkt->r_m_e_op; + rpkt.sequence = pkt->sequence; + rpkt.associd = pkt->associd; + rpkt.status = 0; + res_offset = 0; + res_associd = htons(pkt->associd); + res_async = 0; + res_authenticate = 0; + res_keyid = 0; + res_authokay = 0; + req_count = (int)htons(pkt->count); + datanotbinflag = 0; + datalinelen = 0; + datapt = rpkt.data; + dataend = &(rpkt.data[CTL_MAX_DATA_LEN]); + + /* + * We're set up now. Make sure we've got at least + * enough incoming data space to match the count. + */ + req_data = rbufp->recv_length - CTL_HEADER_LEN; + if (req_data < req_count || rbufp->recv_length & 0x3) { + ctl_error(CERR_BADFMT); + numctldatatooshort++; + return; + } + + properlen = req_count + CTL_HEADER_LEN; +#ifdef DEBUG + if (debug >= 2 && (rbufp->recv_length & 0x3) != 0) + printf("Packet length %d unrounded\n", rbufp->recv_length); +#endif + /* round up proper len to a 8 octet boundary */ + + properlen = (properlen + 7) & ~7; + maclen = rbufp->recv_length - properlen; + if ((rbufp->recv_length & (sizeof(u_long) - 1)) == 0 && + maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN && + sys_authenticate) { + res_authenticate = 1; + res_keyid = ntohl(*(u_int32 *)((u_char *)pkt + properlen)); + +#ifdef DEBUG + if (debug >= 3) + printf( + "recv_len %d, properlen %d, wants auth with keyid %ld, MAC length=%d\n", + rbufp->recv_length, properlen, res_keyid, maclen); +#endif + if (!authistrusted(res_keyid)) { +#ifdef DEBUG + if (debug >= 2) + printf("invalid keyid %lu\n", res_keyid); +#endif + } else if (authdecrypt(res_keyid, (u_int32 *)pkt, + rbufp->recv_length - maclen, 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_mask); + return; + } + } + + /* + * Can't find this one, return an error. + */ + numctlbadop++; + ctl_error(CERR_BADOP); + return; +} + + +/* + * ctlpeerstatus - return a status word for this peer + */ +u_short +ctlpeerstatus( + register struct peer *peer + ) +{ + register u_short status; + + status = peer->status; + if (peer->flags & FLAG_CONFIG) + status |= CTL_PST_CONFIG; + if (peer->flags & FLAG_AUTHENABLE) + status |= CTL_PST_AUTHENABLE; + if (peer->flags & FLAG_AUTHENTIC) + status |= CTL_PST_AUTHENTIC; + if (peer->reach != 0) + status |= CTL_PST_REACH; + return (u_short)CTL_PEER_STATUS(status, peer->num_events, + peer->last_event); +} + + +/* + * ctlclkstatus - return a status word for this clock + */ +static u_short +ctlclkstatus( + struct refclockstat *this_clock + ) +{ + return ((u_short)(this_clock->currentstatus) << 8) + | (u_short)(this_clock->lastevent); +} + + + +/* + * ctlsysstatus - return the system status word + */ +u_short +ctlsysstatus(void) +{ + register u_char this_clock; + + this_clock = CTL_SST_TS_UNSPEC; + if (sys_peer != 0) { + if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) { + this_clock = sys_peer->sstclktype; + if (pps_control) + this_clock |= CTL_SST_TS_PPS; + } else { + if (sys_peer->refclktype < sizeof(clocktypes)) + this_clock = clocktypes[sys_peer->refclktype]; + if (pps_control) + this_clock |= CTL_SST_TS_PPS; + } + } + return (u_short)CTL_SYS_STATUS(sys_leap, this_clock, + ctl_sys_num_events, ctl_sys_last_event); +} + + + +/* + * ctl_flushpkt - write out the current packet and prepare + * another if necessary. + */ +static void +ctl_flushpkt( + int more + ) +{ + int dlen; + int sendlen; + + if (!more && datanotbinflag) { + /* + * Big hack, output a trailing \r\n + */ + *datapt++ = '\r'; + *datapt++ = '\n'; + } + dlen = datapt - (u_char *)rpkt.data; + sendlen = dlen + CTL_HEADER_LEN; + + /* + * Pad to a multiple of 32 bits + */ + while (sendlen & 0x3) { + *datapt++ = '\0'; + sendlen++; + } + + /* + * Fill in the packet with the current info + */ + rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode & CTL_OP_MASK)); + rpkt.count = htons((u_short) dlen); + rpkt.offset = htons( (u_short) res_offset); + if (res_async) { + register int i; + + for (i = 0; i < CTL_MAXTRAPS; i++) { + if (ctl_trap[i].tr_flags & TRAP_INUSE) { + rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, + ctl_trap[i].tr_version, MODE_CONTROL); + rpkt.sequence = htons(ctl_trap[i].tr_sequence); + sendpkt(&ctl_trap[i].tr_addr, + ctl_trap[i].tr_localaddr, + -4, + (struct pkt *)&rpkt, sendlen); + if (!more) + ctl_trap[i].tr_sequence++; + numasyncmsgs++; + } + } + } else { + if (res_authenticate && sys_authenticate) { + int maclen; + int totlen = sendlen; + u_long keyid = htonl(res_keyid); + + /* + * If we are going to authenticate, then there is + * an additional requirement that the MAC begin on + * a 64 bit boundary. + */ + while (totlen & 7) { + *datapt++ = '\0'; + totlen++; + } + memcpy(datapt, &keyid, sizeof keyid); + maclen = authencrypt(res_keyid, (u_int32 *)&rpkt, + totlen); + sendpkt(rmt_addr, lcl_inter, -5, (struct pkt *)&rpkt, + totlen + maclen); + } else { + sendpkt(rmt_addr, lcl_inter, -6, (struct pkt *)&rpkt, + sendlen); + } + if (more) + numctlfrags++; + else + numctlresponses++; + } + + /* + * Set us up for another go around. + */ + res_offset += dlen; + datapt = (u_char *)rpkt.data; +} + + +/* + * ctl_putdata - write data into the packet, fragmenting and + * starting another if this one is full. + */ +static void +ctl_putdata( + const char *dp, + unsigned int dlen, + int bin /* set to 1 when data is binary */ + ) +{ + int overhead; + + overhead = 0; + if (!bin) { + datanotbinflag = 1; + overhead = 3; + if (datapt != rpkt.data) { + *datapt++ = ','; + datalinelen++; + if ((dlen + datalinelen + 1) >= MAXDATALINELEN) { + *datapt++ = '\r'; + *datapt++ = '\n'; + datalinelen = 0; + } else { + *datapt++ = ' '; + datalinelen++; + } + } + } + + /* + * Save room for trailing junk + */ + if (dlen + overhead + datapt > dataend) { + /* + * Not enough room in this one, flush it out. + */ + ctl_flushpkt(CTL_MORE); + } + + memmove((char *)datapt, dp, (unsigned)dlen); + datapt += dlen; + datalinelen += dlen; +} + + +/* + * ctl_putstr - write a tagged string into the response packet + */ +static void +ctl_putstr( + const char *tag, + const char *data, + unsigned int len + ) +{ + register char *cp; + register const char *cq; + char buffer[400]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + if (len > 0) { + *cp++ = '='; + *cp++ = '"'; + if (len > (int) (sizeof(buffer) - (cp - buffer) - 1)) + len = sizeof(buffer) - (cp - buffer) - 1; + memmove(cp, data, (unsigned)len); + cp += len; + *cp++ = '"'; + } + + ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); +} + + +/* + * ctl_putdbl - write a tagged, signed double into the response packet + */ +static void +ctl_putdbl( + const char *tag, + double ts + ) +{ + register char *cp; + register const char *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + *cp++ = '='; + (void)sprintf(cp, "%.3f", ts); + while (*cp != '\0') + cp++; + ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); +} + +/* + * ctl_putuint - write a tagged unsigned integer into the response + */ +static void +ctl_putuint( + const char *tag, + u_long uval + ) +{ + register char *cp; + register const char *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + (void) sprintf(cp, "%lu", uval); + while (*cp != '\0') + cp++; + + ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); +} + + +/* + * ctl_puthex - write a tagged unsigned integer, in hex, into the response + */ +static void +ctl_puthex( + const char *tag, + u_long uval + ) +{ + register char *cp; + register const char *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + (void) sprintf(cp, "0x%lx", uval); + while (*cp != '\0') + cp++; + + ctl_putdata(buffer,(unsigned)( cp - buffer ), 0); +} + + +/* + * ctl_putint - write a tagged signed integer into the response + */ +static void +ctl_putint( + const char *tag, + long ival + ) +{ + register char *cp; + register const char *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + (void) sprintf(cp, "%ld", ival); + while (*cp != '\0') + cp++; + + ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); +} + + +/* + * ctl_putts - write a tagged timestamp, in hex, into the response + */ +static void +ctl_putts( + const char *tag, + l_fp *ts + ) +{ + register char *cp; + register const char *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + (void) sprintf(cp, "0x%08lx.%08lx", ts->l_ui & 0xffffffffL, + ts->l_uf & 0xffffffffL); + while (*cp != '\0') + cp++; + + ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); +} + + +/* + * ctl_putadr - write a dotted quad IP address into the response + */ +static void +ctl_putadr( + const char *tag, + u_int32 addr + ) +{ + register char *cp; + register const char *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, (unsigned)( cp - buffer ), 0); +} + + +/* + * ctl_putid - write a tagged clock ID into the response + */ +static void +ctl_putid( + const char *tag, + char *id + ) +{ + register char *cp; + register const char *cq; + char buffer[200]; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + + *cp++ = '='; + cq = id; + while (*cq != '\0' && (cq - id) < 4) + *cp++ = *cq++; + + ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); +} + + +/* + * ctl_putarray - write a tagged eight element double array into the response + */ +static void +ctl_putarray( + const char *tag, + double *arr, + int start + ) +{ + register char *cp; + register const char *cq; + char buffer[200]; + int i; + + cp = buffer; + cq = tag; + while (*cq != '\0') + *cp++ = *cq++; + i = start; + do { + if (i == 0) + i = NTP_SHIFT; + i--; + (void)sprintf(cp, " %.2f", arr[i] * 1e3); + while (*cp != '\0') + cp++; + } while(i != start); + ctl_putdata(buffer, (unsigned)(cp - buffer), 0); +} + + +/* + * ctl_putsys - output a system variable + */ +static void +ctl_putsys( + int varid + ) +{ + l_fp tmp; +#ifdef HAVE_UNAME + char str[50]; +#endif + + switch (varid) { + case CS_LEAP: + ctl_putuint(sys_var[CS_LEAP].text, sys_leap); + break; + case CS_STRATUM: + ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum); + break; + case CS_PRECISION: + ctl_putint(sys_var[CS_PRECISION].text, sys_precision); + break; + case CS_ROOTDELAY: + ctl_putdbl(sys_var[CS_ROOTDELAY].text, sys_rootdelay * 1e3); + break; + case CS_ROOTDISPERSION: + ctl_putdbl(sys_var[CS_ROOTDISPERSION].text, + sys_rootdispersion * 1e3); + break; + case CS_REFID: + if (sys_stratum > 1) + ctl_putadr(sys_var[CS_REFID].text, sys_refid); + else + ctl_putid(sys_var[CS_REFID].text, (char *)&sys_refid); + break; + case CS_REFTIME: + ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime); + break; + case CS_POLL: + ctl_putuint(sys_var[CS_POLL].text, sys_poll); + break; + case CS_PEERID: + if (sys_peer == NULL) + ctl_putuint(sys_var[CS_PEERID].text, 0); + else + ctl_putuint(sys_var[CS_PEERID].text, + sys_peer->associd); + break; + case CS_STATE: + ctl_putuint(sys_var[CS_STATE].text, (unsigned)state); + break; + case CS_OFFSET: + ctl_putdbl(sys_var[CS_OFFSET].text, last_offset * 1e3); + break; + case CS_DRIFT: + ctl_putdbl(sys_var[CS_DRIFT].text, drift_comp * 1e6); + break; + case CS_COMPLIANCE: + ctl_putdbl(sys_var[CS_COMPLIANCE].text, sys_error * 1e3); + break; + case CS_CLOCK: + get_systime(&tmp); + ctl_putts(sys_var[CS_CLOCK].text, &tmp); + break; + case CS_PROCESSOR: +#ifndef HAVE_UNAME + ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor, + sizeof(str_processor) - 1); +#else + ctl_putstr(sys_var[CS_PROCESSOR].text, utsnamebuf.machine, + strlen(utsnamebuf.machine)); +#endif /* HAVE_UNAME */ + break; + case CS_SYSTEM: +#ifndef HAVE_UNAME + ctl_putstr(sys_var[CS_SYSTEM].text, str_system, + sizeof(str_system) - 1); +#else + (void)strcpy(str, utsnamebuf.sysname); + (void)strcat(str, utsnamebuf.release); + ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str)); +#endif /* HAVE_UNAME */ + break; + case CS_STABIL: + ctl_putdbl(sys_var[CS_STABIL].text, clock_stability * 1e6); + break; + case CS_VARLIST: + { + char buf[CTL_MAX_DATA_LEN]; + register char *s, *t, *be; + register const char *ss; + register int i; + register struct ctl_var *k; + + s = buf; + be = buf + sizeof(buf) - strlen(sys_var[CS_VARLIST].text) - 4; + if (s > be) + break; /* really long var name 8-( - Killer */ + + strcpy(s, sys_var[CS_VARLIST].text); + strcat(s, "=\""); + s += strlen(s); + t = s; + + for (k = sys_var; !(k->flags &EOV); k++) + { + if (k->flags & PADDING) + continue; + + i = strlen(k->text); + if (s+i+1 >= be) + break; + if (s != t) + *s++ = ','; + strcpy(s, k->text); + s += i; + } + + for (k = ext_sys_var; k && !(k->flags &EOV); k++) + { + if (k->flags & PADDING) + continue; + + ss = k->text; + if (!ss) + continue; + + while (*ss && *ss != '=') + ss++; + + i = ss - k->text; + if (s+i+1 >= be) + break; + if (s != t) + *s++ = ','; + strncpy(s, k->text, (unsigned)i); + s += i; + } + + if (s+2 >= be) + break; + + *s++ = '"'; + *s = '\0'; + + ctl_putdata(buf, (unsigned)( s - buf ), 0); + } + break; + } +} + + +/* + * ctl_putpeer - output a peer variable + */ +static void +ctl_putpeer( + int varid, + struct peer *peer + ) +{ + switch (varid) { + case CP_CONFIG: + ctl_putuint(peer_var[CP_CONFIG].text, + (unsigned)((peer->flags & FLAG_CONFIG) != 0)); + break; + case CP_AUTHENABLE: + ctl_putuint(peer_var[CP_AUTHENABLE].text, + (unsigned)((peer->flags & FLAG_AUTHENABLE) != 0)); + break; + case CP_AUTHENTIC: + ctl_putuint(peer_var[CP_AUTHENTIC].text, + (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0)); + break; + case CP_SRCADR: + ctl_putadr(peer_var[CP_SRCADR].text, + peer->srcadr.sin_addr.s_addr); + break; + case CP_SRCPORT: + ctl_putuint(peer_var[CP_SRCPORT].text, + ntohs(peer->srcadr.sin_port)); + break; + case CP_DSTADR: + ctl_putadr(peer_var[CP_DSTADR].text, + peer->processed ? + peer->cast_flags & MDF_BCAST ? + peer->dstadr->bcast.sin_addr.s_addr: + peer->cast_flags ? + peer->dstadr->sin.sin_addr.s_addr ? + peer->dstadr->sin.sin_addr.s_addr: + peer->dstadr->bcast.sin_addr.s_addr: + 8 : 12); + break; + case CP_DSTPORT: + ctl_putuint(peer_var[CP_DSTPORT].text, + (u_long)(peer->dstadr + ? ntohs(peer->dstadr->sin.sin_port) + : 0 + ) + ); + break; + case CP_LEAP: + ctl_putuint(peer_var[CP_LEAP].text, peer->leap); + break; + case CP_HMODE: + ctl_putuint(peer_var[CP_HMODE].text, peer->hmode); + break; + case CP_STRATUM: + ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum); + break; + case CP_PPOLL: + ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll); + break; + case CP_HPOLL: + ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll); + break; + case CP_PRECISION: + ctl_putint(peer_var[CP_PRECISION].text, peer->precision); + break; + case CP_ROOTDELAY: + ctl_putdbl(peer_var[CP_ROOTDELAY].text, peer->rootdelay * 1e3); + break; + case CP_ROOTDISPERSION: + ctl_putdbl(peer_var[CP_ROOTDISPERSION].text, + peer->rootdispersion * 1e3); + break; + case CP_REFID: + if (peer->stratum > 1) + { + if (peer->flags & FLAG_REFCLOCK) + ctl_putadr(peer_var[CP_REFID].text, + peer->srcadr.sin_addr.s_addr); + else + 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, peer->reach); + break; + case CP_FLASH: + ctl_puthex(peer_var[CP_FLASH].text, peer->flash); + break; + case CP_VALID: + ctl_putuint(peer_var[CP_VALID].text, peer->valid); + break; + case CP_TIMER: + ctl_putuint(peer_var[CP_TIMER].text, + peer->nextdate - current_time); + break; + case CP_DELAY: + ctl_putdbl(peer_var[CP_DELAY].text, peer->delay * 1e3); + break; + case CP_OFFSET: + ctl_putdbl(peer_var[CP_OFFSET].text, peer->offset * 1e3); + break; + case CP_JITTER: + ctl_putdbl(peer_var[CP_JITTER].text, + SQRT(peer->variance) * 1e3); + break; + case CP_DISPERSION: + ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp * 1e3); + break; + case CP_KEYID: + ctl_putuint(peer_var[CP_KEYID].text, peer->keyid); + break; + case CP_FILTDELAY: + ctl_putarray(peer_var[CP_FILTDELAY].text, + peer->filter_delay, (int)peer->filter_nextpt); + break; + case CP_FILTOFFSET: + ctl_putarray(peer_var[CP_FILTOFFSET].text, + peer->filter_offset, (int)peer->filter_nextpt); + break; + case CP_FILTERROR: + ctl_putarray(peer_var[CP_FILTERROR].text, + peer->filter_disp, (int)peer->filter_nextpt); + break; + case CP_PMODE: + ctl_putuint(peer_var[CP_PMODE].text, peer->pmode); + break; + case CP_RECEIVED: + ctl_putuint(peer_var[CP_RECEIVED].text, peer->received); + break; + case CP_SENT: + ctl_putuint(peer_var[CP_SENT].text, peer->sent); + break; + case CP_VARLIST: + { + char buf[CTL_MAX_DATA_LEN]; + register char *s, *t, *be; + register int i; + register struct ctl_var *k; + + s = buf; + be = buf + sizeof(buf) - strlen(peer_var[CP_VARLIST].text) - 4; + if (s > be) + break; /* really long var name 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, (unsigned)(s - buf), 0); + } + break; + } +} + + +#ifdef REFCLOCK +/* + * ctl_putclock - output clock variables + */ +static void +ctl_putclock( + int varid, + struct refclockstat *clock_stat, + int mustput + ) +{ + switch(varid) { + case CC_TYPE: + if (mustput || clock_stat->clockdesc == NULL + || *(clock_stat->clockdesc) == '\0') { + ctl_putuint(clock_var[CC_TYPE].text, clock_stat->type); + } + break; + case CC_TIMECODE: + ctl_putstr(clock_var[CC_TIMECODE].text, clock_stat->p_lastcode, + (unsigned)clock_stat->lencode); + break; + case CC_POLL: + ctl_putuint(clock_var[CC_POLL].text, clock_stat->polls); + break; + case CC_NOREPLY: + ctl_putuint(clock_var[CC_NOREPLY].text, clock_stat->noresponse); + break; + case CC_BADFORMAT: + ctl_putuint(clock_var[CC_BADFORMAT].text, clock_stat->badformat); + break; + case CC_BADDATA: + ctl_putuint(clock_var[CC_BADDATA].text, clock_stat->baddata); + break; + case CC_FUDGETIME1: + if (mustput || (clock_stat->haveflags & CLK_HAVETIME1)) { + ctl_putdbl(clock_var[CC_FUDGETIME1].text, + clock_stat->fudgetime1 * 1e3); + } + break; + case CC_FUDGETIME2: + if (mustput || (clock_stat->haveflags & CLK_HAVETIME2)) { + ctl_putdbl(clock_var[CC_FUDGETIME2].text, + clock_stat->fudgetime2 * 1e3); + } + break; + case CC_FUDGEVAL1: + if (mustput || (clock_stat->haveflags & CLK_HAVEVAL1)) + ctl_putint(clock_var[CC_FUDGEVAL1].text, + clock_stat->fudgeval1); + break; + case CC_FUDGEVAL2: + if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) { + if (clock_stat->fudgeval1 > 1) + ctl_putadr(clock_var[CC_FUDGEVAL2].text, + (u_int32)clock_stat->fudgeval2); + else + ctl_putid(clock_var[CC_FUDGEVAL2].text, + (char *)&clock_stat->fudgeval2); + } + break; + case CC_FLAGS: + if (mustput || (clock_stat->haveflags & + (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))) + ctl_putuint(clock_var[CC_FLAGS].text, clock_stat->flags); + break; + case CC_DEVICE: + if (clock_stat->clockdesc == NULL || *(clock_stat->clockdesc) == '\0') { + if (mustput) + ctl_putstr(clock_var[CC_DEVICE].text, "", 0); + } else { + ctl_putstr(clock_var[CC_DEVICE].text, clock_stat->clockdesc, + strlen(clock_stat->clockdesc)); + } + break; + case CC_VARLIST: + { + char buf[CTL_MAX_DATA_LEN]; + register char *s, *t, *be; + register const char *ss; + register int i; + register struct ctl_var *k; + + s = buf; + be = buf + sizeof(buf); + if (s + strlen(clock_var[CC_VARLIST].text) + 4 > be) + break; /* really long var name 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_stat->kv_list; k && !(k->flags &EOV); k++) + { + if (k->flags & PADDING) + continue; + + ss = k->text; + if (!ss) + continue; + + while (*ss && *ss != '=') + ss++; + + i = ss - k->text; + if (s+i+1 >= be) + break; + if (s != t) + *s++ = ','; + strncpy(s, k->text, (unsigned)i); + s += i; + *s = '\0'; + } + + if (s+2 >= be) + break; + + *s++ = '"'; + *s = '\0'; + + ctl_putdata(buf, (unsigned)( s - buf ), 0); + } + break; + } +} +#endif + + + +/* + * ctl_getitem - get the next data item from the incoming packet + */ +static struct ctl_var * +ctl_getitem( + struct ctl_var *var_list, + char **data + ) +{ + register struct ctl_var *v; + register char *cp; + register char *tp; + static struct ctl_var eol = { 0, EOV, }; + static char buf[128]; + + /* + * Delete leading commas and white space + */ + while (reqpt < reqend && (*reqpt == ',' || isspace((int)*reqpt))) { + reqpt++; + } + + if (reqpt >= reqend) + return 0; + + if (var_list == (struct ctl_var *)0) + return &eol; + + /* + * Look for a first character match on the tag. If we find + * one, see if it is a full match. + */ + v = var_list; + cp = reqpt; + while (!(v->flags & EOV)) { + if (!(v->flags & PADDING) && *cp == *(v->text)) { + tp = v->text; + while (*tp != '\0' && *tp != '=' && cp < reqend && *cp == *tp) { + cp++; + tp++; + } + if ((*tp == '\0') || (*tp == '=')) { + while (cp < reqend && isspace((int)*cp)) + cp++; + if (cp == reqend || *cp == ',') { + buf[0] = '\0'; + *data = buf; + if (cp < reqend) + cp++; + reqpt = cp; + return v; + } + if (*cp == '=') { + cp++; + tp = buf; + while (cp < reqend && isspace((int)*cp)) + cp++; + while (cp < reqend && *cp != ',') + *tp++ = *cp++; + if (cp < reqend) + cp++; + *tp = '\0'; + while (isspace((int)(*(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( + struct recvbuf *rbufp, + int restrict_mask + ) +{ + struct peer *peer; + + /* + * What is an appropriate response to an unspecified op-code? + * I return no errors and no data, unless a specified assocation + * doesn't exist. + */ + if (res_associd != 0) { + if ((peer = findpeerbyassoc((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( + struct recvbuf *rbufp, + int restrict_mask + ) +{ + register int i; + register struct peer *peer; + u_short ass_stat[CTL_MAX_DATA_LEN/sizeof(u_short)]; + +#ifdef DEBUG + if (debug >= 2) + printf("read_status: ID %d\n", res_associd); +#endif + /* + * Two choices here. If the specified association ID is + * zero we return all known assocation ID's. Otherwise + * we return a bunch of stuff about the particular peer. + */ + if (res_associd == 0) { + register int n; + + n = 0; + rpkt.status = htons(ctlsysstatus()); + for (i = 0; i < HASH_SIZE; i++) { + for (peer = assoc_hash[i]; peer != 0; + peer = peer->ass_next) { + ass_stat[n++] = htons(peer->associd); + ass_stat[n++] = htons(ctlpeerstatus(peer)); + if (n == CTL_MAX_DATA_LEN/sizeof(u_short)) { + ctl_putdata((char *)ass_stat, + n * sizeof(u_short), 1); + n = 0; + } + } + } + + if (n != 0) + ctl_putdata((char *)ass_stat, n * sizeof(u_short), 1); + ctl_flushpkt(0); + } else { + peer = findpeerbyassoc((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( + struct recvbuf *rbufp, + int restrict_mask + ) +{ + register struct ctl_var *v; + register int i; + char *valuep; + u_char *wants; + unsigned int gotvar = (CS_MAXCODE>CP_MAXCODE) ? (CS_MAXCODE+1) : (CP_MAXCODE+1); + + if (res_associd == 0) { + /* + * Wants system variables. Figure out which he wants + * and give them to him. + */ + rpkt.status = htons(ctlsysstatus()); + if (res_authokay) + ctl_sys_num_events = 0; + gotvar += count_var(ext_sys_var); + wants = (u_char *)emalloc(gotvar); + memset((char *)wants, 0, gotvar); + gotvar = 0; + while ((v = ctl_getitem(sys_var, &valuep)) != 0) { + if (v->flags & EOV) { + if ((v = ctl_getitem(ext_sys_var, &valuep)) != 0) { + if (v->flags & EOV) { + ctl_error(CERR_UNKNOWNVAR); + free((char *)wants); + return; + } + wants[CS_MAXCODE+1+v->code] = 1; + gotvar = 1; + continue; + } else { + break; /* shouldn't happen ! */ + } + } + wants[v->code] = 1; + gotvar = 1; + } + if (gotvar) { + for (i = 1; i <= CS_MAXCODE; i++) + if (wants[i]) + ctl_putsys(i); + for (i = 0; ext_sys_var && !(ext_sys_var[i].flags & EOV); i++) + if (wants[i+CS_MAXCODE+1]) + ctl_putdata(ext_sys_var[i].text, + strlen(ext_sys_var[i].text), 0); + } else { + register u_char *cs; + register struct ctl_var *kv; + + for (cs = def_sys_var; *cs != 0; cs++) + ctl_putsys((int)*cs); + for (kv = ext_sys_var; kv && !(kv->flags & EOV); kv++) + if (kv->flags & DEF) + ctl_putdata(kv->text, strlen(kv->text), 0); + } + free((char *)wants); + } else { + register struct peer *peer; + + /* + * Wants info for a particular peer. See if we know + * the guy. + */ + peer = findpeerbyassoc((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( + struct recvbuf *rbufp, + int restrict_mask + ) +{ + register struct ctl_var *v; + register int ext_var; + char *valuep; + long val; + /*int 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 = ~0; + leapwarn = ~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 = (char *)emalloc(strlen(v->text)+strlen(valuep)+2); + const char *t; + char *tt = s; + + t = v->text; + while (*t && *t != '=') + *tt++ = *t++; + + *tt++ = '='; + strcat(tt, valuep); + + set_sys_var(s, strlen(s)+1, v->flags); + free(s); + } else { + /* + * This one seems sane. Save it. + */ + switch(v->code) { + case CS_LEAP: + default: + ctl_error(CERR_UNSPEC); /* our fault, really */ + return; + } + } + } + + /* + * If we got anything, do it. + */ + /* + if (leapind != ~0 || leapwarn != ~0) { + if (!leap_setleap((int)leapind, (int)leapwarn)) { + ctl_error(CERR_PERMISSION); + return; + } + } + */ + ctl_flushpkt(0); +} + + +/* + * read_clock_status - return clock radio status + */ +/*ARGSUSED*/ +static void +read_clock_status( + struct recvbuf *rbufp, + int restrict_mask + ) +{ +#ifndef REFCLOCK + /* + * If no refclock support, no data to return + */ + ctl_error(CERR_BADASSOC); +#else + register struct ctl_var *v; + register int i; + register struct peer *peer; + char *valuep; + u_char *wants; + unsigned int gotvar; + struct refclockstat clock_stat; + + if (res_associd == 0) { + /* + * Find a clock for this jerk. If the system peer + * is a clock use it, else search the hash tables + * for one. + */ + if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK)) { + peer = sys_peer; + } else { + peer = 0; + for (i = 0; peer == 0 && i < HASH_SIZE; i++) { + for (peer = assoc_hash[i]; peer != 0; + peer = peer->ass_next) { + if (peer->flags & FLAG_REFCLOCK) + break; + } + } + if (peer == 0) { + ctl_error(CERR_BADASSOC); + return; + } + } + } else { + peer = findpeerbyassoc((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_stat.kv_list = (struct ctl_var *)0; + + refclock_control(&peer->srcadr, (struct refclockstat *)0, &clock_stat); + + /* + * Look for variables in the packet. + */ + rpkt.status = htons(ctlclkstatus(&clock_stat)); + gotvar = CC_MAXCODE+1+count_var(clock_stat.kv_list); + wants = (u_char *)emalloc(gotvar); + memset((char*)wants, 0, gotvar); + gotvar = 0; + while ((v = ctl_getitem(clock_var, &valuep)) != 0) { + if (v->flags & EOV) { + if ((v = ctl_getitem(clock_stat.kv_list, &valuep)) != 0) { + if (v->flags & EOV) { + ctl_error(CERR_UNKNOWNVAR); + free((char*)wants); + free_varlist(clock_stat.kv_list); + return; + } + wants[CC_MAXCODE+1+v->code] = 1; + gotvar = 1; + continue; + } else { + break; /* shouldn't happen ! */ + } + } + wants[v->code] = 1; + gotvar = 1; + } + + if (gotvar) { + for (i = 1; i <= CC_MAXCODE; i++) + if (wants[i]) + ctl_putclock(i, &clock_stat, 1); + for (i = 0; clock_stat.kv_list && !(clock_stat.kv_list[i].flags & EOV); i++) + if (wants[i+CC_MAXCODE+1]) + ctl_putdata(clock_stat.kv_list[i].text, + strlen(clock_stat.kv_list[i].text), 0); + } else { + register u_char *cc; + register struct ctl_var *kv; + + for (cc = def_clock_var; *cc != 0; cc++) + ctl_putclock((int)*cc, &clock_stat, 0); + for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV); kv++) + if (kv->flags & DEF) + ctl_putdata(kv->text, strlen(kv->text), 0); + } + + free((char*)wants); + free_varlist(clock_stat.kv_list); + + ctl_flushpkt(0); +#endif +} + + +/* + * write_clock_status - we don't do this + */ +/*ARGSUSED*/ +static void +write_clock_status( + struct recvbuf *rbufp, + int restrict_mask + ) +{ + ctl_error(CERR_PERMISSION); +} + +/* + * Trap support from here on down. We send async trap messages when the + * upper levels report trouble. Traps can by set either by control + * messages or by configuration. + */ + +/* + * set_trap - set a trap in response to a control message + */ +static void +set_trap( + struct recvbuf *rbufp, + int restrict_mask + ) +{ + int traptype; + + /* + * See if this guy is allowed + */ + if (restrict_mask & RES_NOTRAP) { + ctl_error(CERR_PERMISSION); + return; + } + + /* + * Determine his allowed trap type. + */ + traptype = TRAP_TYPE_PRIO; + if (restrict_mask & RES_LPTRAP) + traptype = TRAP_TYPE_NONPRIO; + + /* + * Call ctlsettrap() to do the work. Return + * an error if it can't assign the trap. + */ + if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype, + (int)res_version)) + ctl_error(CERR_NORESOURCE); + ctl_flushpkt(0); +} + + +/* + * unset_trap - unset a trap in response to a control message + */ +static void +unset_trap( + struct recvbuf *rbufp, + int restrict_mask + ) +{ + int traptype; + + /* + * We don't prevent anyone from removing his own + * trap unless the trap is configured. Note we also + * must be aware of the possibility that restriction + * flags were changed since this guy last set his trap. + * Set the trap type based on this. + */ + traptype = TRAP_TYPE_PRIO; + if (restrict_mask & RES_LPTRAP) + traptype = TRAP_TYPE_NONPRIO; + + /* + * Call ctlclrtrap() to clear this out. + */ + if (!ctlclrtrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype)) + ctl_error(CERR_BADASSOC); + ctl_flushpkt(0); +} + + +/* + * ctlsettrap - called to set a trap + */ +int +ctlsettrap( + struct sockaddr_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( + 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( + 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( + 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) { + NLOG(NLOG_SYSEVENT) + msyslog(LOG_INFO, "system event '%s' (0x%02x) status '%s' (0x%02x)", + eventstr(err), err, + sysstatstr(ctlsysstatus()), ctlsysstatus()); +#ifdef DEBUG + if (debug) + printf("report_event: system event '%s' (0x%02x) status '%s' (0x%02x)\n", + eventstr(err), err, + sysstatstr(ctlsysstatus()), ctlsysstatus()); +#endif + ctl_sys_last_event = (u_char)err; + } + } else if (peer != 0) { + char *src; + +#ifdef REFCLOCK + if (ISREFCLOCKADR(&peer->srcadr)) + src = refnumtoa(peer->srcadr.sin_addr.s_addr); + else +#endif + src = ntoa(&peer->srcadr); + + peer->last_event = (u_char)(err & ~PEER_EVENT); + if (peer->num_events < CTL_PEER_MAXEVENTS) + peer->num_events++; + NLOG(NLOG_PEEREVENT) + msyslog(LOG_INFO, "peer %s event '%s' (0x%02x) status '%s' (0x%02x)", + src, eventstr(err), err, + peerstatstr(ctlpeerstatus(peer)), ctlpeerstatus(peer)); +#ifdef DEBUG + if (debug) + printf( "peer %s event '%s' (0x%02x) status '%s' (0x%02x)\n", + src, eventstr(err), err, + peerstatstr(ctlpeerstatus(peer)), ctlpeerstatus(peer)); +#endif + } else { + msyslog(LOG_ERR, "report_event: err '%s' (0x%02x), no peer", eventstr(err), err); +#ifdef DEBUG + printf("report_event: peer event '%s' (0x%02x), no peer\n", eventstr(err), err); +#endif + return; + } + + /* + * If no trappers, return. + */ + if (num_ctl_traps <= 0) + return; + + /* + * Set up the outgoing packet variables + */ + res_opcode = CTL_OP_ASYNCMSG; + res_offset = 0; + res_async = 1; + res_authenticate = 0; + datapt = rpkt.data; + dataend = &(rpkt.data[CTL_MAX_DATA_LEN]); + + if (!(err & PEER_EVENT)) { + rpkt.associd = 0; + rpkt.status = htons(ctlsysstatus()); + + /* + * For now, put everything we know about system + * variables. 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_stat; + struct ctl_var *kv; + + clock_stat.kv_list = (struct ctl_var *)0; + + refclock_control(&peer->srcadr, + (struct refclockstat *)0, &clock_stat); + ctl_puthex("refclockstatus", ctlclkstatus(&clock_stat)); + + for (i = 1; i <= CC_MAXCODE; i++) + ctl_putclock(i, &clock_stat, 0); + for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV); kv++) + if (kv->flags & DEF) + ctl_putdata(kv->text, strlen(kv->text), 0); + + free_varlist(clock_stat.kv_list); + } +#endif /*REFCLOCK*/ + } else { + rpkt.associd = htons(peer->associd); + rpkt.status = htons(ctlpeerstatus(peer)); + + /* + * Dump it all. Later, maybe less. + */ + for (i = 1; i <= CP_MAXCODE; i++) + ctl_putpeer(i, peer); +#ifdef REFCLOCK + /* + * for clock exception events: + * add clock variables to reflect info on exception + */ + if (err == EVNT_PEERCLOCK) { + struct refclockstat clock_stat; + struct ctl_var *kv; + + clock_stat.kv_list = (struct ctl_var *)0; + + refclock_control(&peer->srcadr, + (struct refclockstat *)0, + &clock_stat); + + ctl_puthex("refclockstatus", + ctlclkstatus(&clock_stat)); + + for (i = 1; i <= CC_MAXCODE; i++) + ctl_putclock(i, &clock_stat, 0); + for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV); kv++) + if (kv->flags & DEF) + ctl_putdata(kv->text, strlen(kv->text), 0); + + free_varlist(clock_stat.kv_list); + } +#endif /*REFCLOCK*/ + } + + /* + * We're done, return. + */ + ctl_flushpkt(0); +} + + +/* + * ctl_clr_stats - clear stat counters + */ +void +ctl_clr_stats(void) +{ + ctltimereset = current_time; + numctlreq = 0; + numctlbadpkts = 0; + numctlresponses = 0; + numctlfrags = 0; + numctlerrors = 0; + numctlfrags = 0; + numctltooshort = 0; + numctlinputresp = 0; + numctlinputfrag = 0; + numctlinputerr = 0; + numctlbadoffset = 0; + numctlbadversion = 0; + numctldatatooshort = 0; + numctlbadop = 0; + numasyncmsgs = 0; +} + +static u_long +count_var( + struct ctl_var *k + ) +{ + register u_long c; + + if (!k) + return 0; + + c = 0; + + while (!(k++->flags & EOV)) + c++; + + return c; +} + +char * +add_var( + struct ctl_var **kv, + u_long size, + int def + ) +{ + register u_long c; + register struct ctl_var *k; + + c = count_var(*kv); + + k = *kv; + *kv = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var)); + if (k) + { + memmove((char *)*kv, (char *)k, sizeof(struct ctl_var)*c); + free((char *)k); + } + + (*kv)[c].code = (u_short) c; + (*kv)[c].text = (char *)emalloc(size); + (*kv)[c].flags = def; + (*kv)[c+1].code = 0; + (*kv)[c+1].text = (char *)0; + (*kv)[c+1].flags = EOV; + return (char *)(*kv)[c].text; +} + +void +set_var( + struct ctl_var **kv, + const char *data, + u_long size, + int def + ) +{ + register struct ctl_var *k; + register const char *s; + register const char *t; + char *td; + + 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((void *)k->text); + td = (char *)emalloc(size); + memmove(td, data, size); + k->text =td; + k->flags = def; + return; + } + } + else + { + td = (char *)emalloc(size); + memmove(td, data, size); + k->text = td; + k->flags = def; + return; + } + k++; + } + } + td = add_var(kv, size, def); + memmove(td, data, size); +} + +void +set_sys_var( + char *data, + u_long size, + int def + ) +{ + set_var(&ext_sys_var, data, size, def); +} + +void +free_varlist( + struct ctl_var *kv + ) +{ + struct ctl_var *k; + if (kv) + { + for (k = kv; !(k->flags & EOV); k++) + free((void *)k->text); + free((void *)kv); + } +} diff --git a/contrib/ntp/ntpd/ntp_filegen.c b/contrib/ntp/ntpd/ntp_filegen.c new file mode 100644 index 000000000000..bcf3f9c19cd1 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_filegen.c @@ -0,0 +1,547 @@ +/* + * ntp_filegen.c,v 3.12 1994/01/25 19:06:11 kardel Exp + * + * implements file generations support for NTP + * logfiles and statistic files + * + * + * Copyright (C) 1992, 1996 by Rainer Pruy + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * This code may be modified and used freely + * provided credits remain intact. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_string.h" +#include "ntp_calendar.h" +#include "ntp_filegen.h" +#include "ntp_stdlib.h" + +/* + * NTP is intended to run long periods of time without restart. + * Thus log and statistic files generated by NTP will grow large. + * + * this set of routines provides a central interface + * to generating files using file generations + * + * the generation of a file is changed according to file generation type + */ + + +/* + * redefine this if your system dislikes filename suffixes like + * X.19910101 or X.1992W50 or .... + */ +#define SUFFIX_SEP '.' + +/* + * other constants + */ +#define FGEN_AGE_SECS (24*60*60) /* life time of FILEGEN_AGE in seconds */ + +static void filegen_open P((FILEGEN *, u_long)); +static int valid_fileref P((char *, char *)); +#ifdef UNUSED +static FILEGEN *filegen_unregister P((char *)); +#endif /* UNUSED */ + +/* + * open a file generation according to the current settings of gen + * will also provide a link to basename if requested to do so + */ + +static void +filegen_open( + FILEGEN *gen, + u_long newid + ) +{ + char *filename; + char *basename; + u_int len; + FILE *fp; + struct calendar cal; + + len = strlen(gen->prefix) + strlen(gen->basename) + 1; + basename = (char*)emalloc(len); + sprintf(basename, "%s%s", gen->prefix, gen->basename); + + switch(gen->type) { + default: + msyslog(LOG_ERR, "unsupported file generations type %d for \"%s\" - reverting to FILEGEN_NONE", + gen->type, basename); + gen->type = FILEGEN_NONE; + + /*FALLTHROUGH*/ + case FILEGEN_NONE: + filename = (char*)emalloc(len); + sprintf(filename,"%s", basename); + break; + + case FILEGEN_PID: + filename = (char*)emalloc(len + 1 + 1 + 10); + sprintf(filename,"%s%c#%ld", basename, SUFFIX_SEP, newid); + break; + + case FILEGEN_DAY: + /* You can argue here in favor of using MJD, but + * I would assume it to be easier for humans to interpret dates + * in a format they are used to in everyday life. + */ + caljulian(newid,&cal); + filename = (char*)emalloc(len + 1 + 4 + 2 + 2); + sprintf(filename, "%s%c%04d%02d%02d", + basename, SUFFIX_SEP, cal.year, cal.month, cal.monthday); + break; + + case FILEGEN_WEEK: + /* + * This is still a hack + * - the term week is not correlated to week as it is used + * normally - it just refers to a period of 7 days + * starting at Jan 1 - 'weeks' are counted starting from zero + */ + caljulian(newid,&cal); + filename = (char*)emalloc(len + 1 + 4 + 1 + 2); + sprintf(filename, "%s%c%04dw%02d", + basename, SUFFIX_SEP, cal.year, cal.yearday / 7); + break; + + case FILEGEN_MONTH: + caljulian(newid,&cal); + filename = (char*)emalloc(len + 1 + 4 + 2); + sprintf(filename, "%s%c%04d%02d", + basename, SUFFIX_SEP, cal.year, cal.month); + break; + + case FILEGEN_YEAR: + caljulian(newid,&cal); + filename = (char*)emalloc(len + 1 + 4); + sprintf(filename, "%s%c%04d", basename, SUFFIX_SEP, cal.year); + break; + + case FILEGEN_AGE: + filename = (char*)emalloc(len + 1 + 2 + 10); + sprintf(filename, "%s%ca%08ld", basename, SUFFIX_SEP, newid); + break; + } + + if (gen->type != FILEGEN_NONE) { + /* + * check for existence of a file with name 'basename' + * as we disallow such a file + * if FGEN_FLAG_LINK is set create a link + */ + struct stat stats; + /* + * try to resolve name collisions + */ + static u_long conflicts = 0; + +#ifndef S_ISREG +#define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG) +#endif + if (stat(basename, &stats) == 0) { + /* Hm, file exists... */ + if (S_ISREG(stats.st_mode)) { + if (stats.st_nlink <= 1) { + /* + * Oh, it is not linked - try to save it + */ + char *savename = (char*)emalloc(len + 1 + 1 + 10 + 10); + sprintf(savename, "%s%c%dC%lu", + basename, + SUFFIX_SEP, + (int) getpid(), + (u_long)conflicts++); + if (rename(basename, savename) != 0) + msyslog(LOG_ERR," couldn't save %s: %m", basename); + free(savename); + } else { + /* + * there is at least a second link tpo this file + * just remove the conflicting one + */ + if ( +#if !defined(VMS) + unlink(basename) != 0 +#else + delete(basename) != 0 +#endif + ) + msyslog(LOG_ERR, "couldn't unlink %s: %m", basename); + } + } else { + /* + * Ehh? Not a regular file ?? strange !!!! + */ + msyslog(LOG_ERR, "expected regular file for %s (found mode 0%lo)", + basename, (unsigned long)stats.st_mode); + } + } else { + /* + * stat(..) failed, but it is absolutely correct for + * 'basename' not to exist + */ + if (errno != ENOENT) + msyslog(LOG_ERR,"stat(%s) failed: %m", basename); + } + } + + /* + * now, try to open new file generation... + */ + fp = fopen(filename, "a"); + +#ifdef DEBUG + if (debug > 3) + printf("opening filegen (type=%d/id=%lu) \"%s\"\n", + gen->type, (u_long)newid, filename); +#endif + + if (fp == NULL) { + /* open failed -- keep previous state + * + * If the file was open before keep the previous generation. + * This will cause output to end up in the 'wrong' file, + * but I think this is still better than loosing output + * + * ignore errors due to missing directories + */ + + if (errno != ENOENT) + msyslog(LOG_ERR, "can't open %s: %m", filename); + } else { + if (gen->fp != NULL) { + fclose(gen->fp); + } + gen->fp = fp; + gen->id = newid; + + if (gen->flag & FGEN_FLAG_LINK) { + /* + * need to link file to basename + * have to use hardlink for now as I want to allow + * gen->basename spanning directory levels + * this would make it more complex to get the correct + * filename for symlink + * + * Ok, it would just mean taking the part following + * the last '/' in the name.... Should add it later.... + */ + + /* Windows NT does not support file links -Greg Schueman 1/18/97 */ + +#if defined SYS_WINNT || defined SYS_VXWORKS + SetLastError(0); /* On WinNT, don't support FGEN_FLAG_LINK */ +#elif defined(VMS) + errno = 0; /* On VMS, don't support FGEN_FLAG_LINK */ +#else /* not (VMS) / VXWORKS / WINNT ; DO THE LINK) */ + if (link(filename, basename) != 0) + if (errno != EEXIST) + msyslog(LOG_ERR, "can't link(%s, %s): %m", filename, basename); +#endif /* SYS_WINNT || VXWORKS */ + } /* flags & FGEN_FLAG_LINK */ + } /* else fp == NULL */ + + free(basename); + free(filename); + return; +} + +/* + * this function sets up gen->fp to point to the correct + * generation of the file for the time specified by 'now' + * + * 'now' usually is interpreted as second part of a l_fp as is in the cal... + * library routines + */ + +void +filegen_setup( + FILEGEN *gen, + u_long now + ) +{ + u_long new_gen = ~ (u_long) 0; + struct calendar cal; + + if (!(gen->flag & FGEN_FLAG_ENABLED)) { + if (gen->fp != NULL) + fclose(gen->fp); + return; + } + + switch (gen->type) { + case FILEGEN_NONE: + if (gen->fp != NULL) return; /* file already open */ + break; + + case FILEGEN_PID: + new_gen = getpid(); + break; + + case FILEGEN_DAY: + caljulian(now, &cal); + cal.hour = cal.minute = cal.second = 0; + new_gen = caltontp(&cal); + break; + + case FILEGEN_WEEK: + /* Would be nice to have a calweekstart() routine */ + /* so just use a hack ... */ + /* just round time to integral 7 day period for actual year */ + new_gen = now - (now - calyearstart(now)) % TIMES7(SECSPERDAY) + + 60; + /* + * just to be sure - + * the computation above would fail in the presence of leap seconds + * so at least carry the date to the next day (+60 (seconds)) + * and go back to the start of the day via calendar computations + */ + caljulian(new_gen, &cal); + cal.hour = cal.minute = cal.second = 0; + new_gen = caltontp(&cal); + break; + + case FILEGEN_MONTH: + caljulian(now, &cal); + cal.yearday -= cal.monthday - 1; + cal.monthday = 1; + cal.hour = cal.minute = cal.second = 0; + new_gen = caltontp(&cal); + break; + + case FILEGEN_YEAR: + new_gen = calyearstart(now); + break; + + case FILEGEN_AGE: + new_gen = current_time - (current_time % FGEN_AGE_SECS); + break; + } + /* + * try to open file if not yet open + * reopen new file generation file on change of generation id + */ + if (gen->fp == NULL || gen->id != new_gen) { + filegen_open(gen, new_gen); + } +} + + +/* + * change settings for filegen files + */ +void +filegen_config( + FILEGEN *gen, + char *basename, + u_int type, + u_int flag + ) +{ + /* + * if nothing would be changed... + */ + if ((basename == gen->basename || strcmp(basename,gen->basename) == 0) && + type == gen->type && + flag == gen->flag) + return; + + /* + * validate parameters + */ + if (!valid_fileref(gen->prefix,basename)) + return; + + if (gen->fp != NULL) + fclose(gen->fp); + +#ifdef DEBUG + if (debug > 2) + printf("configuring filegen:\n\tprefix:\t%s\n\tbasename:\t%s -> %s\n\ttype:\t%d -> %d\n\tflag: %x -> %x\n", + gen->prefix, gen->basename, basename, gen->type, type, gen->flag, flag); +#endif + if (gen->basename != basename || strcmp(gen->basename, basename) != 0) { + free(gen->basename); + gen->basename = (char*)emalloc(strlen(basename) + 1); + strcpy(gen->basename, basename); + } + gen->type = 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; + + get_systime(&now); + filegen_setup(gen, now.l_ui); + } +} + + +/* + * check whether concatenating prefix and basename + * yields a legal filename + */ +static int +valid_fileref( + char *prefix, + char *basename + ) +{ + /* + * prefix cannot be changed dynamically + * (within the context of filegen) + * so just reject basenames containing '..' + * + * ASSUMPTION: + * file system parts 'below' prefix may be + * specified without infringement of security + * + * restricing prefix to legal values + * has to be ensured by other means + * (however, it would be possible to perform some checks here...) + */ + register char *p = basename; + + /* + * Just to catch, dumb errors opening up the world... + */ + if (prefix == NULL || *prefix == '\0') + return 0; + + if (basename == NULL) + return 0; + + for (p = basename; p; p = strchr(p, '/')) { + if (*p == '.' && *(p+1) == '.' && (*(p+2) == '\0' || *(p+2) == '/')) + return 0; + } + + return 1; +} + + +/* + * filegen registry + */ + +static struct filegen_entry { + char *name; + FILEGEN *filegen; + struct filegen_entry *next; +} *filegen_registry = NULL; + + +FILEGEN * +filegen_get( + char *name + ) +{ + struct filegen_entry *f = filegen_registry; + + while(f) { + if (f->name == name || strcmp(name, f->name) == 0) { +#ifdef XXX /* this gives the Alpha compiler fits */ + if (debug > 3) + printf("filegen_get(\"%s\") = %x\n", name, + (u_int)f->filegen); +#endif + return f->filegen; + } + f = f->next; + } +#ifdef DEBUG + if (debug > 3) + printf("filegen_get(\"%s\") = NULL\n", name); +#endif + return NULL; +} + +void +filegen_register( + const char *name, + FILEGEN *filegen + ) +{ + struct filegen_entry **f = &filegen_registry; + +#ifdef XXX /* this gives the Alpha compiler fits */ + if (debug > 3) + printf("filegen_register(\"%s\",%x)\n", name, (u_int)filegen); +#endif + while (*f) { + if ((*f)->name == name || strcmp(name, (*f)->name) == 0) { +#ifdef XXX /* this gives the Alpha compiler fits */ + if (debug > 4) { + printf("replacing filegen %x\n", (u_int)(*f)->filegen); + } +#endif + (*f)->filegen = filegen; + return; + } + f = &((*f)->next); + } + + *f = (struct filegen_entry *) emalloc(sizeof(struct filegen_entry)); + if (*f) { + (*f)->next = NULL; + (*f)->name = (char*)emalloc(strlen(name) + 1); + strcpy((*f)->name, name); + (*f)->filegen = filegen; +#ifdef DEBUG + if (debug > 5) { + printf("adding new filegen\n"); + } +#endif + } + + return; +} + +#ifdef UNUSED +static FILEGEN * +filegen_unregister( + char *name + ) +{ + struct filegen_entry **f = &filegen_registry; + +#ifdef DEBUG + if (debug > 3) + printf("filegen_unregister(\"%s\")\n", name); +#endif + + while (*f) { + if (strcmp((*f)->name,name) == 0) { + struct filegen_entry *ff = *f; + FILEGEN *fg; + + *f = (*f)->next; + fg = ff->filegen; + free(ff->name); + free(ff); + return fg; + } + f = &((*f)->next); + } + return NULL; +} +#endif /* UNUSED */ diff --git a/contrib/ntp/ntpd/ntp_intres.c b/contrib/ntp/ntpd/ntp_intres.c new file mode 100644 index 000000000000..182991464875 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_intres.c @@ -0,0 +1,970 @@ +/* + * ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92 + * routine callable from ntpd, rather than separate program + * also, key info passed in via a global, so no key file needed. + */ + +/* + * ntpres - process configuration entries which require use of the resolver + * + * This is meant to be run by ntpd on the fly. It is not guaranteed + * to work properly if run by hand. This is actually a quick hack to + * stave off violence from people who hate using numbers in the + * configuration file (at least I hope the rest of the daemon is + * better than this). Also might provide some ideas about how one + * might go about autoconfiguring an NTP distribution network. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "ntpd.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_ttl ce_config.ttl +#define ce_keyid ce_config.keyid + +/* + * confentries is a pointer to the list of configuration entries + * we have left to do. + */ +static struct conf_entry *confentries = NULL; + +/* + * We take an interrupt every thirty seconds, at which time we decrement + * config_timer and resolve_timer. The former is set to 2, so we retry + * unsucessful reconfigurations every minute. The latter is set to + * an exponentially increasing value which starts at 2 and increases to + * 32. When this expires we retry failed name resolutions. + * + * We sleep SLEEPTIME seconds before doing anything, to give the server + * time to arrange itself. + */ +#define MINRESOLVE 2 +#define MAXRESOLVE 32 +#define CONFIG_TIME 2 +#define ALARM_TIME 30 + +#define SLEEPTIME 2 + +static volatile int config_timer = 0; +static volatile int resolve_timer = 0; + +static int resolve_value; /* next value of resolve timer */ + +/* + * Big hack attack + */ +#define LOCALHOST 0x7f000001 /* 127.0.0.1, in hex, of course */ +#define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */ + +/* + * Select time out. Set to 2 seconds. The server is on the local machine, + * after all. + */ +#define TIMEOUT_SEC 2 +#define TIMEOUT_USEC 0 + + +/* + * Input processing. The data on each line in the configuration file + * is supposed to consist of entries in the following order + */ +#define TOK_HOSTNAME 0 +#define TOK_HMODE 1 +#define TOK_VERSION 2 +#define TOK_MINPOLL 3 +#define TOK_MAXPOLL 4 +#define TOK_FLAGS 5 +#define TOK_TTL 6 +#define TOK_KEYID 7 +#define NUMTOK 8 + +#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 */ + + +static RETSIGTYPE bong P((int)); +static void checkparent P((void)); +static void removeentry P((struct conf_entry *)); +static void addentry P((char *, int, int, int, int, int, int, u_long)); +static 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(void) +{ + FILE *in; +#ifdef HAVE_SIGSUSPEND + sigset_t set; + + sigemptyset(&set); +#endif /* NTP_POSIX_SOURCE */ + +#ifdef DEBUG + if (debug) { + msyslog(LOG_INFO, "NTP_INTRES running"); + } +#endif + + /* check out auth stuff */ + if (sys_authenticate) { + if (!authistrusted(req_keyid)) { + msyslog(LOG_ERR, "invalid request keyid %lu", + req_keyid ); + exit(1); + } + } + + /* + * Read the configuration info + * {this is bogus, since we are forked, but it is easier + * to keep this code - gdt} + */ + if ((in = fopen(req_file, "r")) == NULL) { + msyslog(LOG_ERR, "can't open configuration file %s: %m", + req_file); + exit(1); + } + readconf(in, req_file); + (void) fclose(in); + + if (!debug ) + (void) unlink(req_file); + + /* + * Sleep a little to make sure the server is completely up + */ + + sleep(SLEEPTIME); + + /* + * Make a first cut at resolving the bunch + */ + doconfigure(1); + if (confentries == NULL) +#if defined SYS_WINNT + ExitThread(0); /* Don't want to kill whole NT process */ +#else + exit(0); /* done that quick */ +#endif + + /* + * Here we've got some problem children. Set up the timer + * and wait for it. + */ + resolve_value = resolve_timer = MINRESOLVE; + config_timer = CONFIG_TIME; +#ifndef SYS_WINNT + (void) signal_no_reset(SIGALRM, bong); + alarm(ALARM_TIME); +#endif /* SYS_WINNT */ + + for (;;) { + if (confentries == NULL) + exit(0); + + checkparent(); + + if (resolve_timer == 0) { + if (resolve_value < MAXRESOLVE) + resolve_value <<= 1; + resolve_timer = resolve_value; +#ifdef DEBUG + msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer); +#endif + config_timer = CONFIG_TIME; + doconfigure(1); + continue; + } else if (config_timer == 0) { + config_timer = CONFIG_TIME; +#ifdef DEBUG + msyslog(LOG_INFO, "config_timer: 0->%d", config_timer); +#endif + doconfigure(0); + continue; + } +#ifndef SYS_WINNT + /* + * There is a race in here. Is okay, though, since + * all it does is delay things by 30 seconds. + */ +#ifdef HAVE_SIGSUSPEND + sigsuspend(&set); +#else + sigpause(0); +#endif /* HAVE_SIGSUSPEND */ +#else + if (config_timer > 0) + config_timer--; + if (resolve_timer > 0) + resolve_timer--; + sleep(ALARM_TIME); +#endif /* SYS_WINNT */ + } +} + + +#ifndef SYS_WINNT +/* + * bong - service and reschedule an alarm() interrupt + */ +static RETSIGTYPE +bong( + int sig + ) +{ + if (config_timer > 0) + config_timer--; + if (resolve_timer > 0) + resolve_timer--; + alarm(ALARM_TIME); +} +#endif /* SYS_WINNT */ + +/* + * checkparent - see if our parent process is still running + * + * No need to worry in the Windows NT environment whether the + * main thread is still running, because if it goes + * down it takes the whole process down with it (in + * which case we won't be running this thread either) + * Turn function into NOP; + */ + +static void +checkparent(void) +{ +#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) + + /* + * If our parent (the server) has died we will have been + * inherited by init. If so, exit. + */ + if (getppid() == 1) { + msyslog(LOG_INFO, "parent died before we finished, exiting"); + exit(0); + } +#endif /* SYS_WINNT && SYS_VXWORKS*/ +} + + + +/* + * removeentry - we are done with an entry, remove it from the list + */ +static void +removeentry( + struct conf_entry *entry + ) +{ + register struct conf_entry *ce; + + ce = confentries; + if (ce == entry) { + confentries = ce->ce_next; + return; + } + + while (ce != NULL) { + if (ce->ce_next == entry) { + ce->ce_next = entry->ce_next; + return; + } + ce = ce->ce_next; + } +} + + +/* + * addentry - add an entry to the configuration list + */ +static void +addentry( + char *name, + int mode, + int version, + int minpoll, + int maxpoll, + int flags, + int ttl, + u_long keyid + ) +{ + register char *cp; + register struct conf_entry *ce; + unsigned int len; + + len = strlen(name) + 1; + cp = (char*)emalloc(len); + memmove(cp, name, len); + + ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry)); + ce->ce_name = cp; + ce->ce_peeraddr = 0; + ce->ce_hmode = (u_char)mode; + ce->ce_version = (u_char)version; + ce->ce_minpoll = (u_char)minpoll; + ce->ce_maxpoll = (u_char)maxpoll; + ce->ce_flags = (u_char)flags; + ce->ce_ttl = (u_char)ttl; + ce->ce_keyid = keyid; + 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( + 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. + */ + 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(void) +{ + struct sockaddr_in saddr; + + if (sockfd >= 0) + return; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) { + msyslog(LOG_ERR, "socket() failed: %m"); + exit(1); + } + + memset((char *)&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(NTP_PORT); /* trash */ + saddr.sin_addr.s_addr = htonl(LOCALHOST); /* garbage */ + + /* + * Make the socket non-blocking. We'll wait with select() + */ +#ifndef SYS_WINNT +#if defined(O_NONBLOCK) + if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) { + msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m"); + exit(1); + } +#else +#if defined(FNDELAY) + if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) { + msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m"); + exit(1); + } +#else +# include "Bletch: NEED NON BLOCKING IO" +#endif /* FNDDELAY */ +#endif /* O_NONBLOCK */ +#else /* SYS_WINNT */ + { + int on=1; + if (ioctlsocket(sockfd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) { + msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m"); + exit(1); /* Windows NT - set socket in non-blocking mode */ + } + } +#endif /* SYS_WINNT */ + + + if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { + msyslog(LOG_ERR, "connect() failed: %m"); + exit(1); + } +} + + +/* + * request - send a configuration request to the server, wait for a response + */ +static int +request( + struct conf_peer *conf + ) +{ + fd_set fdset; + struct timeval tvout; + struct req_pkt reqpkt; + l_fp ts; + int n; +#ifdef SYS_WINNT + HANDLE hReadWriteEvent = NULL; + BOOL ret; + DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait; + OVERLAPPED overlap; +#endif /* SYS_WINNT */ + + checkparent(); /* make sure our guy is still running */ + + if (sockfd < 0) + openntp(); + +#ifdef SYS_WINNT + hReadWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL); +#endif /* SYS_WINNT */ + + /* + * Try to clear out any previously received traffic so it + * doesn't fool us. Note the socket is nonblocking. + */ + tvout.tv_sec = 0; + tvout.tv_usec = 0; + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) > + 0) { + recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0); + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + } + + /* + * Make up a request packet with the configuration info + */ + memset((char *)&reqpkt, 0, sizeof(reqpkt)); + + reqpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0); + reqpkt.auth_seq = AUTH_SEQ(1, 0); /* authenticated, no seq */ + reqpkt.implementation = IMPL_XNTPD; /* local implementation */ + reqpkt.request = REQ_CONFIG; /* configure a new peer */ + reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */ + reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct conf_peer)); + memmove(reqpkt.data, (char *)conf, sizeof(struct conf_peer)); + reqpkt.keyid = htonl(req_keyid); + + get_systime(&ts); + L_ADDUF(&ts, SKEWTIME); + HTONL_FP(&ts, &reqpkt.tstamp); + n = 0; + if (sys_authenticate) + n = authencrypt(req_keyid, (u_int32 *)&reqpkt, REQ_LEN_NOMAC); + + /* + * Done. Send it. + */ +#ifndef SYS_WINNT + n = send(sockfd, (char *)&reqpkt, (unsigned)(REQ_LEN_NOMAC + n), 0); + if (n < 0) { + msyslog(LOG_ERR, "send to NTP server failed: %m"); + return 0; /* maybe should exit */ + } +#else + /* In the NT world, documentation seems to indicate that there + * exist _write and _read routines that can be used to so blocking + * I/O on sockets. Problem is these routines require a socket + * handle obtained through the _open_osf_handle C run-time API + * of which there is no explanation in the documentation. We need + * nonblocking write's and read's anyway for our purpose here. + * We're therefore forced to deviate a little bit from the Unix + * model here and use the ReadFile and WriteFile Win32 I/O API's + * on the socket + */ + overlap.Offset = overlap.OffsetHigh = (DWORD)0; + overlap.hEvent = hReadWriteEvent; + ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n, + (LPDWORD)&NumberOfBytesWritten, (LPOVERLAPPED)&overlap); + if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) { + msyslog(LOG_ERR, "send to NTP server failed: %m"); + return 0; + } + dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000); + if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) { + if (dwWait == WAIT_FAILED) + msyslog(LOG_ERR, "WaitForSingleObject failed: %m"); + return 0; + } +#endif /* SYS_WINNT */ + + + /* + * Wait for a response. A weakness of the mode 7 protocol used + * is that there is no way to associate a response with a + * particular request, i.e. the response to this configuration + * request is indistinguishable from that to any other. I should + * fix this some day. In any event, the time out is fairly + * pessimistic to make sure that if an answer is coming back + * at all, we get it. + */ + for (;;) { + FD_ZERO(&fdset); + FD_SET(sockfd, &fdset); + tvout.tv_sec = TIMEOUT_SEC; + tvout.tv_usec = TIMEOUT_USEC; + + n = select(sockfd + 1, &fdset, (fd_set *)0, + (fd_set *)0, &tvout); + + if (n < 0) + { + msyslog(LOG_ERR, "select() fails: %m"); + return 0; + } + else if (n == 0) + { + if(debug) + msyslog(LOG_DEBUG, "select() returned 0."); + return 0; + } + +#ifndef SYS_WINNT + n = recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0); + if (n <= 0) { + if (n < 0) { + msyslog(LOG_ERR, "recv() fails: %m"); + return 0; + } + continue; + } +#else /* Overlapped I/O used on non-blocking sockets on Windows NT */ + ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, (DWORD)REQ_LEN_MAC, + (LPDWORD)&NumberOfBytesRead, (LPOVERLAPPED)&overlap); + if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) { + msyslog(LOG_ERR, "ReadFile() fails: %m"); + return 0; + } + dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000); + if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) { + if (dwWait == WAIT_FAILED) { + msyslog(LOG_ERR, "WaitForSingleObject fails: %m"); + return 0; + } + continue; + } + n = NumberOfBytesRead; +#endif /* SYS_WINNT */ + + /* + * Got one. Check through to make sure it is what + * we expect. + */ + if (n < RESP_HEADER_SIZE) { + msyslog(LOG_ERR, "received runt response (%d octets)", + n); + continue; + } + + if (!ISRESPONSE(reqpkt.rm_vn_mode)) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, "received non-response packet"); +#endif + continue; + } + + if (ISMORE(reqpkt.rm_vn_mode)) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, "received fragmented packet"); +#endif + continue; + } + + if ( ( (INFO_VERSION(reqpkt.rm_vn_mode) < 2) + || (INFO_VERSION(reqpkt.rm_vn_mode) > NTP_VERSION)) + || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "version (%d/%d) or mode (%d/%d) incorrect", + INFO_VERSION(reqpkt.rm_vn_mode), + NTP_VERSION, + INFO_MODE(reqpkt.rm_vn_mode), + MODE_PRIVATE); +#endif + continue; + } + + if (INFO_SEQ(reqpkt.auth_seq) != 0) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "nonzero sequence number (%d)", + INFO_SEQ(reqpkt.auth_seq)); +#endif + continue; + } + + if (reqpkt.implementation != IMPL_XNTPD || + reqpkt.request != REQ_CONFIG) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "implementation (%d) or request (%d) incorrect", + reqpkt.implementation, reqpkt.request); +#endif + continue; + } + + if (INFO_NITEMS(reqpkt.err_nitems) != 0 || + INFO_MBZ(reqpkt.mbz_itemsize) != 0 || + INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, + "nitems (%d) mbz (%d) or itemsize (%d) nonzero", + INFO_NITEMS(reqpkt.err_nitems), + INFO_MBZ(reqpkt.mbz_itemsize), + INFO_ITEMSIZE(reqpkt.mbz_itemsize)); +#endif + continue; + } + + n = INFO_ERR(reqpkt.err_nitems); + switch (n) { + case INFO_OKAY: + /* success */ + return 1; + + case INFO_ERR_IMPL: + msyslog(LOG_ERR, + "server reports implementation mismatch!!"); + return 0; + + case INFO_ERR_REQ: + msyslog(LOG_ERR, + "server claims configuration request is unknown"); + return 0; + + case INFO_ERR_FMT: + msyslog(LOG_ERR, + "server indicates a format error occurred(!!)"); + return 0; + + case INFO_ERR_NODATA: + msyslog(LOG_ERR, + "server indicates no data available (shouldn't happen)"); + return 0; + + case INFO_ERR_AUTH: + msyslog(LOG_ERR, + "server returns a permission denied error"); + return 0; + + default: + msyslog(LOG_ERR, + "server returns unknown error code %d", n); + return 0; + } + } +} + + +/* + * nexttoken - return the next token from a line + */ +static char * +nexttoken( + char **lptr + ) +{ + register char *cp; + register char *tstart; + + cp = *lptr; + + /* + * Skip leading white space + */ + while (*cp == ' ' || *cp == '\t') + cp++; + + /* + * If this is the end of the line, return nothing. + */ + if (*cp == '\n' || *cp == '\0') { + *lptr = cp; + return NULL; + } + + /* + * Must be the start of a token. Record the pointer and look + * for the end. + */ + tstart = cp++; + while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0') + cp++; + + /* + * Terminate the token with a \0. If this isn't the end of the + * line, space to the next character. + */ + if (*cp == '\n' || *cp == '\0') + *cp = '\0'; + else + *cp++ = '\0'; + + *lptr = cp; + return tstart; +} + + +/* + * readconf - read the configuration information out of the file we + * were passed. Note that since the file is supposed to be + * machine generated, we bail out at the first sign of trouble. + */ +static void +readconf( + FILE *fp, + char *name + ) +{ + register int i; + char *token[NUMTOK]; + u_long intval[NUMTOK]; + int flags; + char buf[MAXLINESIZE]; + char *bp; + + while (fgets(buf, MAXLINESIZE, fp) != NULL) { + + bp = buf; + for (i = 0; i < NUMTOK; i++) { + if ((token[i] = nexttoken(&bp)) == NULL) { + msyslog(LOG_ERR, + "tokenizing error in file `%s', quitting", + name); + exit(1); + } + } + + for (i = 1; i < NUMTOK; i++) { + if (!atouint(token[i], &intval[i])) { + msyslog(LOG_ERR, + "format error for integer token `%s', file `%s', quitting", + token[i], name); + exit(1); + } + } + + if (intval[TOK_HMODE] != MODE_ACTIVE && + intval[TOK_HMODE] != MODE_CLIENT && + intval[TOK_HMODE] != MODE_BROADCAST) { + msyslog(LOG_ERR, "invalid mode (%ld) in file %s", + intval[TOK_HMODE], name); + exit(1); + } + + if (intval[TOK_VERSION] > NTP_VERSION || + intval[TOK_VERSION] < NTP_OLDVERSION) { + msyslog(LOG_ERR, "invalid version (%ld) in file %s", + intval[TOK_VERSION], name); + exit(1); + } + if (intval[TOK_MINPOLL] < NTP_MINPOLL || + intval[TOK_MINPOLL] > NTP_MAXPOLL) { + msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s", + intval[TOK_MINPOLL], name); + exit(1); + } + + if (intval[TOK_MAXPOLL] < NTP_MINPOLL || + intval[TOK_MAXPOLL] > NTP_MAXPOLL) { + msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s", + intval[TOK_MAXPOLL], name); + exit(1); + } + + if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE | FLAG_PREFER | + FLAG_NOSELECT | FLAG_BURST | FLAG_SKEY)) + != 0) { + msyslog(LOG_ERR, "invalid flags (%ld) in file %s", + intval[TOK_FLAGS], name); + exit(1); + } + + flags = 0; + if (intval[TOK_FLAGS] & FLAG_AUTHENABLE) + flags |= CONF_FLAG_AUTHENABLE; + if (intval[TOK_FLAGS] & FLAG_PREFER) + flags |= CONF_FLAG_PREFER; + if (intval[TOK_FLAGS] & FLAG_NOSELECT) + flags |= CONF_FLAG_NOSELECT; + if (intval[TOK_FLAGS] & FLAG_BURST) + flags |= CONF_FLAG_BURST; + if (intval[TOK_FLAGS] & FLAG_SKEY) + flags |= CONF_FLAG_SKEY; + + /* + * This is as good as we can check it. Add it in. + */ + addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE], + (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL], + (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL], + intval[TOK_KEYID]); + } +} + + +/* + * doconfigure - attempt to resolve names and configure the server + */ +static void +doconfigure( + int dores + ) +{ + register struct conf_entry *ce; + register struct conf_entry *ceremove; + +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, "doconfigure(%d)", dores); +#endif + + ce = confentries; + while (ce != NULL) { +#ifdef DEBUG + if (debug > 1) + msyslog(LOG_INFO, "doconfigure: <%s> has peeraddr %#x", + ce->ce_name, ce->ce_peeraddr); +#endif + if (dores && ce->ce_peeraddr == 0) { + if (!findhostaddr(ce)) { + msyslog(LOG_ERR, + "couldn't resolve `%s', giving up on it", + ce->ce_name); + ceremove = ce; + ce = ceremove->ce_next; + removeentry(ceremove); + continue; + } +#ifdef DEBUG + if (debug > 1) { + msyslog(LOG_INFO, + "doconfigure:findhostaddr() worked"); + } +#endif + } + + if (ce->ce_peeraddr != 0) { +#ifdef DEBUG + if (debug > 1) { + msyslog(LOG_INFO, + "doconfigure: calling request()"); + } +#endif + if (request(&ce->ce_config)) { +#ifdef DEBUG + if (debug > 1) { + msyslog(LOG_INFO, + "doconfigure: request() OK, removing this entry"); + } +#endif + ceremove = ce; + ce = ceremove->ce_next; + removeentry(ceremove); + continue; + } +#ifdef DEBUG + if (debug > 1) { + msyslog(LOG_INFO, + "doconfigure: request() FAILED, maybe next time."); + } +#endif + } + ce = ce->ce_next; + } +} diff --git a/contrib/ntp/ntpd/ntp_io.c b/contrib/ntp/ntpd/ntp_io.c new file mode 100644 index 000000000000..e9202491fe7d --- /dev/null +++ b/contrib/ntp/ntpd/ntp_io.c @@ -0,0 +1,1754 @@ +/* + * ntp_io.c - input/output routines for ntpd. The socket-opening code + * was shamelessly stolen from ntpd. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#ifdef HAVE_SYS_PARAM_H +# include +#endif /* HAVE_SYS_PARAM_H */ +#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_SYS_SOCKIO_H /* UXPV: SIOC* #defines (Frank Vance ) */ +# include +#endif +#include + +#if _BSDI_VERSION >= 199510 +# include +#endif + +#include "ntp_machine.h" +#include "ntpd.h" +#include "ntp_io.h" +#include "iosignal.h" +#include "ntp_refclock.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" + +#if defined(VMS) /* most likely UCX-specific */ + +#include + +/* "un*x"-compatible names for some items in UCX$INETDEF.H */ +#define ifreq IFREQDEF +#define ifr_name IFR$T_NAME +#define ifr_addr IFR$R_DUMMY.IFR$T_ADDR +#define ifr_broadaddr IFR$R_DUMMY.IFR$T_BROADADDR +#define ifr_flags IFR$R_DUMMY.IFR$R_DUMMY_1_OVRL.IFR$W_FLAGS +#define IFF_UP IFR$M_IFF_UP +#define IFF_BROADCAST IFR$M_IFF_BROADCAST +#define IFF_LOOPBACK IFR$M_IFF_LOOPBACK + +#endif /* VMS */ + + +#if defined(VMS) || defined(SYS_WINNT) +/* structure used in SIOCGIFCONF request (after [KSR] OSF/1) */ +struct ifconf { + int ifc_len; /* size of buffer */ + union { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ + +#endif /* VMS */ + +#if defined(USE_TTY_SIGPOLL) || defined(USE_UDP_SIGPOLL) +# if defined(SYS_AIX) && defined(_IO) /* XXX Identify AIX some other way */ +# undef _IO +# endif +# include +#endif + +/* + * We do asynchronous input using the SIGIO facility. A number of + * recvbuf buffers are preallocated for input. In the signal + * handler we poll to see which sockets are ready and read the + * packets from them into the recvbuf's along with a time stamp and + * an indication of the source host and the interface it was received + * through. This allows us to get as accurate receive time stamps + * as possible independent of other processing going on. + * + * We watch the number of recvbufs available to the signal handler + * and allocate more when this number drops below the low water + * mark. If the signal handler should run out of buffers in the + * interim it will drop incoming frames, the idea being that it is + * better to drop a packet than to be inaccurate. + */ + + +/* + * Other statistics of possible interest + */ +volatile u_long packets_dropped; /* total number of packets dropped on reception */ +volatile u_long packets_ignored; /* packets received on wild card interface */ +volatile u_long packets_received; /* total number of packets received */ +u_long packets_sent; /* total number of packets sent */ +u_long packets_notsent; /* total number of packets which couldn't be sent */ + +volatile u_long handler_calls; /* number of calls to interrupt handler */ +volatile u_long handler_pkts; /* number of pkts received by handler */ +u_long io_timereset; /* time counters were reset */ + +/* + * Interface stuff + */ +struct interface *any_interface; /* 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 /* REFCLOCK */ + +/* + * File descriptor masks etc. for call to select + */ +fd_set activefds; +int maxactivefd; + +static int create_sockets P((u_int)); +static int open_socket P((struct sockaddr_in *, int, int)); +static void close_socket P((int)); +static void close_file P((int)); +static char * fdbits P((int, fd_set *)); + +/* + * init_io - initialize I/O data structures and call socket creation routine + */ +void +init_io(void) +{ +#ifdef SYS_WINNT + WORD wVersionRequested; + WSADATA wsaData; + init_transmitbuff(); +#endif /* SYS_WINNT */ + + /* + * Init buffer free list and stat counters + */ + init_recvbuff(RECV_INIT); + + packets_dropped = packets_received = 0; + packets_ignored = 0; + packets_sent = packets_notsent = 0; + handler_calls = handler_pkts = 0; + io_timereset = 0; + loopback_interface = 0; + +#ifdef REFCLOCK + refio = 0; +#endif + +#if defined(HAVE_SIGNALED_IO) + (void) set_signal(); +#endif + +#ifdef SYS_WINNT + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) + { + msyslog(LOG_ERR, "No useable winsock.dll: %m"); + exit(1); + } +#endif /* SYS_WINNT */ + + /* + * 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( + u_int port + ) +{ +#if _BSDI_VERSION >= 199510 + int i, j; + struct ifaddrs *ifaddrs, *ifap; + struct sockaddr_in resmask; +#if _BSDI_VERSION < 199701 + struct ifaddrs *lp; + int num_if; +#endif +#else /* _BSDI_VERSION >= 199510 */ +# 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 = 0; + struct sockaddr_in resmask; +#endif /* _BSDI_VERSION >= 199510 */ + +#ifdef DEBUG + if (debug) + printf("create_sockets(%d)\n", ntohs( (u_short) 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 = htonl(INADDR_ANY); + (void) strncpy(inter_list[0].name, "wildcard", + sizeof(inter_list[0].name)); + inter_list[0].mask.sin_addr.s_addr = htonl(~ (u_int32)0); + inter_list[0].received = 0; + inter_list[0].sent = 0; + inter_list[0].notsent = 0; + inter_list[0].flags = INT_BROADCAST; + +#if _BSDI_VERSION >= 199510 +#if _BSDI_VERSION >= 199701 + if (getifaddrs(&ifaddrs) < 0) + { + msyslog(LOG_ERR, "getifaddrs: %m"); + exit(1); + } + i = 1; + for (ifap = ifaddrs; ifap != NULL; ifap = ifap->ifa_next) +#else + if (getifaddrs(&ifaddrs, &num_if) < 0) + { + msyslog(LOG_ERR, "create_sockets: getifaddrs() failed: %m"); + exit(1); + } + + i = 1; + + for (ifap = ifaddrs, lp = ifap + num_if; ifap < lp; ifap++) +#endif + { + struct sockaddr_in *sin; + + if (!ifap->ifa_addr) + continue; + + if (ifap->ifa_addr->sa_family != AF_INET) + continue; + + if ((ifap->ifa_flags & IFF_UP) == 0) + continue; + + if (ifap->ifa_flags & IFF_LOOPBACK) + { + sin = (struct sockaddr_in *)ifap->ifa_addr; + if (ntohl(sin->sin_addr.s_addr) != 0x7f000001) + { + continue; + } + } + + inter_list[i].flags = 0; + if (ifap->ifa_flags & IFF_BROADCAST) + inter_list[i].flags |= INT_BROADCAST; + + (void)strcpy(inter_list[i].name, ifap->ifa_name); + + sin = (struct sockaddr_in *)ifap->ifa_addr; + inter_list[i].sin = *sin; + inter_list[i].sin.sin_port = port; + + if (ifap->ifa_flags & IFF_LOOPBACK) + { + inter_list[i].flags = INT_LOOPBACK; + if (loopback_interface == NULL + || ntohl(sin->sin_addr.s_addr) != 0x7f000001) + loopback_interface = &inter_list[i]; + } + + if (inter_list[i].flags & INT_BROADCAST) + { + sin = (struct sockaddr_in *)ifap->ifa_broadaddr; + inter_list[i].bcast = *sin; + inter_list[i].bcast.sin_port = port; + } + + if (ifap->ifa_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) + { + inter_list[i].mask.sin_addr.s_addr = 0xffffffff; + } + else + { + sin = (struct sockaddr_in *)ifap->ifa_netmask; + inter_list[i].mask = *sin; + } + inter_list[i].mask.sin_family = AF_INET; + inter_list[i].mask.sin_len = sizeof *sin; + + /* + * 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. + * + * A second problem exists if we have two addresses on + * the same network (via "ifconfig alias ..."). Don't + * make two xntp interfaces for the two aliases on the + * one physical interface. -wsr + */ + for (j=0; j < i; j++) + if (inter_list[j].sin.sin_addr.s_addr & + inter_list[j].mask.sin_addr.s_addr == + inter_list[i].sin.sin_addr.s_addr & + inter_list[i].mask.sin_addr.s_addr) + { + if (inter_list[j].flags & INT_LOOPBACK) + inter_list[j] = inter_list[i]; + break; + } + if (j == i) + i++; + if (i > MAXINTERFACES) + break; + } + free(ifaddrs); +#else /* _BSDI_VERSION >= 199510 */ +# ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG + if ((vs = open("/dev/ip", O_RDONLY)) < 0) + { + msyslog(LOG_ERR, "create_sockets: open(/dev/ip) failed: %m"); + exit(1); + } +# else /* not USE_STREAMS_DEVICE_FOR_IF_CONFIG */ + if ( + (vs = socket(AF_INET, SOCK_DGRAM, 0)) +# ifndef SYS_WINNT + < 0 +# else /* SYS_WINNT */ + == INVALID_SOCKET +# endif /* SYS_WINNT */ + ) { + msyslog(LOG_ERR, "create_sockets: socket(AF_INET, SOCK_DGRAM) failed: %m"); + exit(1); + } +# endif /* not USE_STREAMS_DEVICE_FOR_IF_CONFIG */ + + i = 1; +# if !defined(SYS_WINNT) + ifc.ifc_len = sizeof(buf); +# endif +# 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)) + { + msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFCONF) failed: %m - exiting"); + exit(1); + } +# ifdef SIZE_RETURNED_IN_BUFFER + ifc.ifc_len = ioc.ic_len - sizeof(int); + ifc.ifc_buf = buf + sizeof(int); +# else /* not SIZE_RETURNED_IN_BUFFER */ + ifc.ifc_len = ioc.ic_len; + ifc.ifc_buf = buf; +# endif /* not SIZE_RETURNED_IN_BUFFER */ + +# else /* not STREAMS_TLI */ + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; +# ifndef SYS_WINNT + if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) +# else + if (WSAIoctl(vs, SIO_GET_INTERFACE_LIST, 0, 0, ifc.ifc_buf, ifc.ifc_len, &ifc.ifc_len, 0, 0) == SOCKET_ERROR) +# endif /* SYS_WINNT */ +{ + msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFCONF) failed: %m - exiting"); + exit(1); +} + +# endif /* not STREAMS_TLI */ + + for(n = ifc.ifc_len, ifr = ifc.ifc_req; n > 0; + ifr = (struct ifreq *)((char *)ifr + size)) + { + extern int listen_to_virtual_ips; + + size = sizeof(*ifr); + +# ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR + if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr)) + size += ifr->ifr_addr.sa_len - sizeof(struct sockaddr); +# endif + n -= size; + +# if !defined(SYS_WINNT) + /* Exclude logical interfaces (indicated by ':' in the interface name) */ + if (debug) + printf("interface <%s> ", ifr->ifr_name); + if ((listen_to_virtual_ips == 0) + && (strchr(ifr->ifr_name, (int)':') != NULL)) { + if (debug) + printf("ignored\n"); + continue; + } + if (debug) + printf("OK\n"); + + if ( +# ifdef VMS /* VMS+UCX */ + (((struct sockaddr *)&(ifr->ifr_addr))->sa_family != AF_INET) +# else + (ifr->ifr_addr.sa_family != AF_INET) +# endif /* VMS+UCX */ + ) { + if (debug) + printf("ignoring %s - not AF_INET\n", + ifr->ifr_name); + continue; + } +# endif /* SYS_WINNT */ + ifreq = *ifr; + inter_list[i].flags = 0; + /* is it broadcast capable? */ +# ifndef SYS_WINNT +# 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)) { + msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFFLAGS) failed: %m"); + continue; + } +# else /* not STREAMS_TLI */ + if (ioctl(vs, SIOCGIFFLAGS, (char *)&ifreq) < 0) { + if (errno != ENXIO) + msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFFLAGS) failed: %m"); + continue; + } +# endif /* not STREAMS_TLI */ + if ((ifreq.ifr_flags & IFF_UP) == 0) { + if (debug) + printf("ignoring %s - interface not UP\n", + ifr->ifr_name); + continue; + } + inter_list[i].flags = 0; + if (ifreq.ifr_flags & IFF_BROADCAST) + inter_list[i].flags |= INT_BROADCAST; +# endif /* not SYS_WINNT */ +# if !defined(SUN_3_3_STINKS) + if ( +# if defined(IFF_LOCAL_LOOPBACK) /* defined(SYS_HPUX) && (SYS_HPUX < 8) */ + (ifreq.ifr_flags & IFF_LOCAL_LOOPBACK) +# elif defined(IFF_LOOPBACK) + (ifreq.ifr_flags & IFF_LOOPBACK) +# else /* not IFF_LOCAL_LOOPBACK and not IFF_LOOPBACK */ + /* test against 127.0.0.1 (yuck!!) */ + (inter_list[i].sin.sin_addr.s_addr == inet_addr("127.0.0.1")) +# endif /* not IFF_LOCAL_LOOPBACK and not IFF_LOOPBACK */ + ) + { +# ifndef SYS_WINNT + inter_list[i].flags |= INT_LOOPBACK; +# endif /* not SYS_WINNT */ + if (loopback_interface == 0) + { + loopback_interface = &inter_list[i]; + } + } +# endif /* not SUN_3_3_STINKS */ + +#if 0 +# ifndef SYS_WINNT +# 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)) + { + msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFADDR) failed: %m"); + continue; + } +# else /* not STREAMS_TLI */ + if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) + { + if (errno != ENXIO) + msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFADDR) failed: %m"); + continue; + } +# endif /* not STREAMS_TLI */ +# endif /* not SYS_WINNT */ +#endif /* 0 */ +# if defined(SYS_WINNT) + {int TODO_FillInTheNameWithSomeThingReasonble;} +# else + (void)strncpy(inter_list[i].name, ifreq.ifr_name, + sizeof(inter_list[i].name)); +# endif + inter_list[i].sin = *(struct sockaddr_in *)&ifr->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 /* SUN_3_3_STINKS */ +# if !defined SYS_WINNT && !defined SYS_CYGWIN32 /* no interface flags on NT */ + 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)) { + msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFBRDADDR) failed: %m"); + exit(1); + } +# else /* not STREAMS_TLI */ + if (ioctl(vs, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { + msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFBRDADDR) failed: %m"); + exit(1); + } +# endif /* not STREAMS_TLI */ + +# 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 /* ifr_broadaddr */ + 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)) { + msyslog(LOG_ERR, "create_sockets: ioctl(I_STR:SIOCGIFNETMASK) failed: %m"); + exit(1); + } +# else /* not STREAMS_TLI */ + if (ioctl(vs, SIOCGIFNETMASK, (char *)&ifreq) < 0) { + msyslog(LOG_ERR, "create_sockets: ioctl(SIOCGIFNETMASK) failed: %m"); + exit(1); + } +# endif /* not STREAMS_TLI */ + inter_list[i].mask = *(struct sockaddr_in *)&ifreq.ifr_addr; +# else + /* winnt here */ + inter_list[i].bcast = ifreq.ifr_broadaddr; + inter_list[i].bcast.sin_family = AF_INET; + inter_list[i].bcast.sin_port = port; + inter_list[i].mask = ifreq.ifr_mask; +# endif /* not SYS_WINNT */ + + /* + * 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++; + if (i > MAXINTERFACES) + break; + } + closesocket(vs); +#endif /* _BSDI_VERSION >= 199510 */ + + 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, 0); + } + + /* + * Now that we have opened all the sockets, turn off the reuse flag for + * security. + */ + for (i = 0; i < ninterfaces; i++) { + int off = 0; + + /* + * if inter_list[ n ].fd is -1, we might have a adapter + * configured but not present + */ + if ( inter_list[ i ].fd != -1 ) { + if (setsockopt(inter_list[i].fd, SOL_SOCKET, + SO_REUSEADDR, (char *)&off, + sizeof(off))) { + msyslog(LOG_ERR, "create_sockets: setsockopt(SO_REUSEADDR,off) failed: %m"); + } + } + } + +#if defined(MCAST) + /* + * enable possible multicast reception on the broadcast socket + */ + inter_list[0].bcast.sin_addr.s_addr = htonl(INADDR_ANY); + inter_list[0].bcast.sin_family = AF_INET; + inter_list[0].bcast.sin_port = port; +#endif /* MCAST */ + + /* + * Blacklist all bound interface addresses + */ + resmask.sin_addr.s_addr = ~ (u_int32)0; + for (i = 1; i < ninterfaces; i++) + hack_restrict(RESTRICT_FLAGS, &inter_list[i].sin, &resmask, + RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE); + + any_interface = &inter_list[0]; +#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 +#if defined (HAVE_IO_COMPLETION_PORT) + for (i = 0; i < ninterfaces; i++) { + io_completion_port_add_socket(&inter_list[i]); + } +#endif + return ninterfaces; +} + +/* + * io_setbclient - open the broadcast client sockets + */ +void +io_setbclient(void) +{ + 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 SYS_SOLARIS + inter_list[i].bcast.sin_addr.s_addr = htonl(INADDR_ANY); +#endif +#ifdef OPEN_BCAST_SOCKET /* Was: !SYS_DOMAINOS && !SYS_LINUX */ + inter_list[i].bfd = open_socket(&inter_list[i].bcast, INT_BROADCAST, 1); + inter_list[i].flags |= INT_BCASTOPEN; +#endif + } +} + + +/* + * io_multicast_add() - add multicast group address + */ +void +io_multicast_add( + u_int32 addr + ) +{ +#ifdef MCAST + struct ip_mreq mreq; + int i = ninterfaces; /* Use the next interface */ + u_int32 haddr = ntohl(addr); + struct in_addr iaddr; + int s; + struct sockaddr_in *sinp; + + iaddr.s_addr = addr; + + if (!IN_CLASSD(haddr)) + { + msyslog(LOG_ERR, + "cannot add multicast address %s as it is not class D", + inet_ntoa(iaddr)); + return; + } + + for (i = 0; i < ninterfaces; i++) + { + /* Already have this address */ + if (inter_list[i].sin.sin_addr.s_addr == addr) return; + /* found a free slot */ + if (inter_list[i].sin.sin_addr.s_addr == 0 && + inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 && + inter_list[i].flags == 0) break; + } + sinp = &(inter_list[i].sin); + + memset((char *)&mreq, 0, sizeof(mreq)); + memset((char *)&inter_list[i], 0, sizeof inter_list[0]); + sinp->sin_family = AF_INET; + sinp->sin_addr = iaddr; + sinp->sin_port = htons(123); + + s = open_socket(sinp, 0, 1); + /* Try opening a socket for the specified class D address */ + /* This works under SunOS 4.x, but not OSF1 .. :-( */ + if (s < 0) + { + memset((char *)&inter_list[i], 0, sizeof inter_list[0]); + i = 0; + /* HACK ! -- stuff in an address */ + inter_list[i].bcast.sin_addr.s_addr = addr; + msyslog(LOG_ERR, "...multicast address %s using wildcard socket", + inet_ntoa(iaddr)); + } + else + { + inter_list[i].fd = s; + inter_list[i].bfd = -1; + (void) strncpy(inter_list[i].name, "multicast", + sizeof(inter_list[i].name)); + inter_list[i].mask.sin_addr.s_addr = htonl(~(u_int32)0); + } + + /* + * enable reception of multicast packets + */ + mreq.imr_multiaddr = iaddr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) == -1) + msyslog(LOG_ERR, + "setsockopt IP_ADD_MEMBERSHIP fails: %m for %x / %x (%s)", + mreq.imr_multiaddr.s_addr, mreq.imr_interface.s_addr, + inet_ntoa(iaddr)); + inter_list[i].flags |= INT_MULTICAST; + if (i >= ninterfaces) ninterfaces = i+1; +#else /* MCAST */ + struct in_addr iaddr; + + iaddr.s_addr = addr; + msyslog(LOG_ERR, "cannot add multicast address %s as no MCAST support", + inet_ntoa(iaddr)); +#endif /* MCAST */ +} + +/* + * io_unsetbclient - close the broadcast client sockets + */ +void +io_unsetbclient(void) +{ + 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].bfd = -1; + inter_list[i].flags &= ~INT_BCASTOPEN; + } +} + + +/* + * io_multicast_del() - delete multicast group address + */ +void +io_multicast_del( + u_int32 addr + ) +{ +#ifdef MCAST + int i; + struct ip_mreq mreq; + u_int32 haddr = ntohl(addr); + struct sockaddr_in sinaddr; + + if (!IN_CLASSD(haddr)) + { + sinaddr.sin_addr.s_addr = addr; + msyslog(LOG_ERR, + "invalid multicast address %s", ntoa(&sinaddr)); + return; + } + + /* + * Disable reception of multicast packets + */ + mreq.imr_multiaddr.s_addr = addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + for (i = 0; i < ninterfaces; i++) + { + if (!(inter_list[i].flags & INT_MULTICAST)) + continue; + if (!(inter_list[i].fd < 0)) + continue; + if (addr != inter_list[i].sin.sin_addr.s_addr) + continue; + if (i != 0) + { + /* we have an explicit fd, so we can close it */ + close_socket(inter_list[i].fd); + memset((char *)&inter_list[i], 0, sizeof inter_list[0]); + inter_list[i].fd = -1; + inter_list[i].bfd = -1; + } + else + { + /* We are sharing "any address" port :-( Don't close it! */ + if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) == -1) + msyslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails: %m"); + /* This is **WRONG** -- there may be others ! */ + /* There should be a count of users ... */ + inter_list[i].flags &= ~INT_MULTICAST; + } + } +#else /* not MCAST */ + msyslog(LOG_ERR, "this function requires multicast kernel"); +#endif /* not MCAST */ +} + + +/* + * open_socket - open a socket, returning the file descriptor + */ +static int +open_socket( + struct sockaddr_in *addr, + int flags, + int turn_off_reuse + ) +{ + int fd; + int on = 1, off = 0; + + /* create a datagram (UDP) socket */ + if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) +#ifndef SYS_WINNT + < 0 +#else + == INVALID_SOCKET +#endif /* SYS_WINNT */ + ) + { + msyslog(LOG_ERR, "socket(AF_INET, SOCK_DGRAM, 0) failed: %m"); + exit(1); + /*NOTREACHED*/ + } + + /* 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))) + { + msyslog(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 %s, in_classd=%d flags=%d fails: %%m", + fd, addr->sin_family, (int)ntohs(addr->sin_port), + ntoa(addr), + IN_CLASSD(ntohl(addr->sin_addr.s_addr)), flags); + msyslog(LOG_ERR, buff); + closesocket(fd); + + /* + * soft fail if opening a class D address + */ + if (IN_CLASSD(ntohl(addr->sin_addr.s_addr))) + return -1; +#if 0 + exit(1); +#else + return -1; +#endif + } +#ifdef DEBUG + if (debug) + printf("bind() fd %d, family %d, port %d, addr %s, flags=%d\n", + fd, + addr->sin_family, + (int)ntohs(addr->sin_port), + ntoa(addr), + flags); +#endif + if (fd > maxactivefd) + maxactivefd = fd; + FD_SET(fd, &activefds); + + /* + * set non-blocking, + */ + +#ifdef USE_FIONBIO + /* in vxWorks we use FIONBIO, but the others are defined for old systems, so + * all hell breaks loose if we leave them defined + */ +#undef O_NONBLOCK +#undef FNDELAY +#undef O_NDELAY +#endif + +#if defined(O_NONBLOCK) /* POSIX */ + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + { + msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FNDELAY) + if (fcntl(fd, F_SETFL, FNDELAY) < 0) + { + msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(O_NDELAY) /* generally the same as FNDELAY */ + if (fcntl(fd, F_SETFL, O_NDELAY) < 0) + { + msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FIONBIO) + if ( +# if defined(VMS) + (ioctl(fd,FIONBIO,&1) < 0) +# elif defined(SYS_WINNT) + (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) +# else + (ioctl(fd,FIONBIO,&on) < 0) +# endif + ) + { + msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FIOSNBIO) + if (ioctl(fd,FIOSNBIO,&on) < 0) + { + msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#else +# include "Bletch: Need non-blocking I/O!" +#endif + +#ifdef HAVE_SIGNALED_IO + init_socket_sig(fd); +#endif /* not HAVE_SIGNALED_IO */ + + /* + * Turn off the SO_REUSEADDR socket option. It apparently + * causes heartburn on systems with multicast IP installed. + * On normal systems it only gets looked at when the address + * is being bound anyway.. + */ + if (turn_off_reuse) + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (char *)&off, sizeof(off))) + { + msyslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m"); + } + +#ifdef SO_BROADCAST + /* if this interface can support broadcast, set SO_BROADCAST */ + if (flags & INT_BROADCAST) + { + if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, + (char *)&on, sizeof(on))) + { + msyslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m"); + } + } +#endif /* SO_BROADCAST */ + +#if !defined(SYS_WINNT) && !defined(VMS) +# ifdef DEBUG + if (debug > 1) + printf("flags for fd %d: 0%o\n", fd, + fcntl(fd, F_GETFL, 0)); +# endif +#endif /* SYS_WINNT || VMS */ + + return fd; +} + + +/* + * close_socket - close a socket and remove from the activefd list + */ +static void +close_socket( + int fd + ) +{ + int i, newmax; + + (void) closesocket(fd); + FD_CLR( (u_int) fd, &activefds); + + if (fd >= maxactivefd) + { + newmax = 0; + for (i = 0; i < maxactivefd; i++) + if (FD_ISSET(i, &activefds)) + newmax = i; + maxactivefd = newmax; + } +} + + +/* + * close_file - close a file and remove from the activefd list + * added 1/31/1997 Greg Schueman for Windows NT portability + */ +static void +close_file( + int fd + ) +{ + int i, newmax; + + (void) close(fd); + FD_CLR( (u_int) fd, &activefds); + + if (fd >= maxactivefd) + { + newmax = 0; + for (i = 0; i < maxactivefd; i++) + if (FD_ISSET(i, &activefds)) + newmax = i; + maxactivefd = newmax; + } +} + + +/* + * findbcastinter - find broadcast interface corresponding to address + */ +struct interface * +findbcastinter( + struct sockaddr_in *addr + ) +{ +#if defined(SIOCGIFCONF) || defined(SYS_WINNT) + register int i; + register u_int32 netnum; + + netnum = NSRCADR(addr); + for (i = 1; i < ninterfaces; i++) + { + if (!(inter_list[i].flags & INT_BROADCAST)) + continue; + if (NSRCADR(&inter_list[i].bcast) == netnum) + return &inter_list[i]; + if ((NSRCADR(&inter_list[i].sin) & NSRCADR(&inter_list[i].mask)) + == (netnum & NSRCADR(&inter_list[i].mask))) + return &inter_list[i]; + } +#endif /* SIOCGIFCONF */ + return any_interface; +} + + +/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ +/* + * sendpkt - send a packet to the specified destination. Maintain a + * send error cache so that only the first consecutive error for a + * destination is logged. + */ +void +sendpkt( + struct sockaddr_in *dest, + struct interface *inter, + int ttl, + struct pkt *pkt, + int len + ) +{ + int cc, slot; +#ifdef SYS_WINNT + DWORD err; +#endif /* SYS_WINNT */ + + /* + * 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 + + /* + * check if the source address is a multicast address - replace + * interface with any-interface if so. + */ + if (IN_MULTICAST(ntohl(inter->sin.sin_addr.s_addr))) + inter = any_interface; +#ifdef DEBUG + if (debug > 1) + printf("%ssendpkt(fd=%d dst=%s, src=%s, ttl=%d, len=%d)\n", + (ttl >= 0) ? "\tMCAST\t*****" : "", + inter->fd, ntoa(dest), + ntoa(&inter->sin), ttl, len); +#endif + +#ifdef MCAST + /* for the moment we use the bcast option to set multicast ttl */ + if (ttl >= 0 && ttl != inter->last_ttl) + { + char mttl = ttl; + + /* set the multicast ttl for outgoing packets */ + if (setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL, + &mttl, sizeof(mttl)) == -1) + { + msyslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails: %m"); + } + else inter->last_ttl = ttl; + } +#endif /* MCAST */ + + for (slot = ERRORCACHESIZE; --slot >= 0; ) + if (badaddrs[slot].port == dest->sin_port && + badaddrs[slot].addr.s_addr == dest->sin_addr.s_addr) + break; + +#if defined(HAVE_IO_COMPLETION_PORT) + err = io_completion_port_sendto(inter, pkt, len, dest); + if (err != ERROR_SUCCESS) +#else + cc = sendto(inter->fd, (char *)pkt, len, 0, (struct sockaddr *)dest, + sizeof(struct sockaddr_in)); + if (cc == -1) +#endif + { + inter->notsent++; + packets_notsent++; +#if defined(HAVE_IO_COMPLETION_PORT) + if (err != WSAEWOULDBLOCK && err != WSAENOBUFS && slot < 0) +#else + if (errno != EWOULDBLOCK && errno != ENOBUFS && slot < 0) +#endif + { + /* + * 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; + } + msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + } + } + else + { + inter->sent++; + packets_sent++; + /* + * He's not bad any more + */ + if (slot >= 0) + { + msyslog(LOG_INFO, "Connection re-established to %s", ntoa(dest)); + badaddrs[slot].port = 0; + } + } +} + +#if !defined(HAVE_IO_COMPLETION_PORT) +/* + * fdbits - generate ascii representation of fd_set (FAU debug support) + * HFDF format - highest fd first. + */ +static char * +fdbits( + int count, + fd_set *set + ) +{ + static char buffer[256]; + char * buf = buffer; + + count = (count < 256) ? count : 255; + + while (count >= 0) + { + *buf++ = FD_ISSET(count, set) ? '#' : '-'; + count--; + } + *buf = '\0'; + + return buffer; +} + +/* + * input_handler - receive packets asynchronously + */ +extern void +input_handler( + 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; /* Timestamp at BOselect() gob */ + l_fp ts_e; /* Timestamp at EOselect() gob */ + fd_set fds; + int select_count = 0; + static int handler_count = 0; + + ++handler_count; + if (handler_count != 1) + msyslog(LOG_ERR, "input_handler: handler_count is %d!", handler_count); + handler_calls++; + ts = *cts; + + for (;;) + { + /* + * Do a poll to see who has data + */ + + fds = activefds; + tvzero.tv_sec = tvzero.tv_usec = 0; + + /* + * If we have something to do, freeze a timestamp. + * See below for the other cases (nothing (left) to do or error) + */ + while (0 < (n = select(maxactivefd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero))) + { + ++select_count; + ++handler_pkts; + +#ifdef REFCLOCK + /* + * Check out the reference clocks first, if any + */ + if (refio != 0) + { + register struct refclockio *rp; + + for (rp = refio; rp != 0 && n > 0; rp = rp->next) + { + fd = rp->fd; + if (FD_ISSET(fd, &fds)) + { + n--; + if (free_recvbuffs() == 0) + { + char buf[RX_BUFF_SIZE]; + +#ifndef SYS_WINNT + (void) read(fd, buf, sizeof buf); +#else + (void) ReadFile((HANDLE)fd, buf, (DWORD)sizeof buf, NULL, NULL); +#endif /* SYS_WINNT */ + packets_dropped++; + goto select_again; + } + + rb = get_free_recv_buffer(); + + i = (rp->datalen == 0 + || rp->datalen > sizeof(rb->recv_space)) + ? sizeof(rb->recv_space) : rp->datalen; +#ifndef SYS_WINNT + rb->recv_length = + read(fd, (char *)&rb->recv_space, (unsigned)i) +#else /* SYS_WINNT */ + ReadFile((HANDLE)fd, (char *)&rb->recv_space, (DWORD)i, + (LPDWORD)&(rb->recv_length), NULL) +#endif /* SYS_WINNT */ + ; + + if (rb->recv_length == -1) + { + msyslog(LOG_ERR, "clock read fd %d: %m", fd); + freerecvbuf(rb); + goto select_again; + } + + /* + * Got one. Mark how and when it got here, + * put it on the full list and do bookkeeping. + */ + rb->recv_srcclock = rp->srcclock; + rb->dstadr = 0; + rb->fd = fd; + rb->recv_time = ts; + rb->receiver = rp->clock_recv; + + if (rp->io_input) + { + /* + * have direct input routine for refclocks + */ + if (rp->io_input(rb) == 0) + { + /* + * data was consumed - nothing to pass up + * into block input machine + */ + freerecvbuf(rb); +#if 1 + goto select_again; +#else + continue; +#endif + } + } + + add_full_recv_buffer(rb); + + rp->recvcount++; + packets_received++; + } + } + } +#endif /* REFCLOCK */ + + /* + * Loop through the interfaces looking for data to read. + */ + for (i = ninterfaces - 1; (i >= 0) && (n > 0); i--) + { + for (doing = 0; (doing < 2) && (n > 0); doing++) + { + if (doing == 0) + { + fd = inter_list[i].fd; + } + else + { + if (!(inter_list[i].flags & INT_BCASTOPEN)) + break; + fd = inter_list[i].bfd; + } + if (fd < 0) continue; + if (FD_ISSET(fd, &fds)) + { + n--; + + /* + * Get a buffer and read the frame. If we + * haven't got a buffer, or this is received + * on the wild card socket, just dump the + * packet. + */ + if ( +#ifdef UDP_WILDCARD_DELIVERY + /* + * these guys manage to put properly addressed + * packets into the wildcard queue + */ + (free_recvbuffs() == 0) +#else + ((i == 0) || (free_recvbuffs() == 0)) +#endif + ) + { + char buf[RX_BUFF_SIZE]; + struct sockaddr from; + + fromlen = sizeof from; + (void) recvfrom(fd, buf, sizeof(buf), 0, &from, &fromlen); +#ifdef DEBUG + if (debug) + printf("%s on %d(%lu) fd=%d from %s\n", + (i) ? "drop" : "ignore", + i, free_recvbuffs(), fd, + inet_ntoa(((struct sockaddr_in *) &from)->sin_addr)); +#endif + if (i == 0) + packets_ignored++; + else + packets_dropped++; + goto select_again; + } + + rb = get_free_recv_buffer(); + + 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 == 0 +#ifdef EWOULDBLOCK + || errno==EWOULDBLOCK +#endif +#ifdef EAGAIN + || errno==EAGAIN +#endif + ) { + freerecvbuf(rb); + continue; + } + else if (rb->recv_length < 0) + { + msyslog(LOG_ERR, "recvfrom() fd=%d: %m", fd); +#ifdef DEBUG + if (debug) + printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd); +#endif + freerecvbuf(rb); + continue; + } +#ifdef DEBUG + if (debug > 2) + printf("input_handler: fd=%d length %d from %08lx %s\n", + fd, rb->recv_length, + (u_long)ntohl(rb->recv_srcadr.sin_addr.s_addr) & + 0x00000000ffffffff, + inet_ntoa(rb->recv_srcadr.sin_addr)); +#endif + + /* + * Got one. Mark how and when it got here, + * put it on the full list and do bookkeeping. + */ + rb->dstadr = &inter_list[i]; + rb->fd = fd; + rb->recv_time = ts; + rb->receiver = receive; + + add_full_recv_buffer(rb); + + inter_list[i].received++; + packets_received++; + goto select_again; + } + /* Check more interfaces */ + } + } + select_again:; + /* + * Done everything from that select. Poll again. + */ + } + + /* + * If nothing more to do, try again. + * If nothing to do, just return. + * If an error occurred, complain and return. + */ + if (n == 0) + { + if (select_count == 0) /* We really had nothing to do */ + { + if (debug) + msyslog(LOG_DEBUG, "input_handler: select() returned 0"); + --handler_count; + return; + } + /* We've done our work */ + get_systime(&ts_e); + /* + * (ts_e - ts) is the amount of time we spent processing + * this gob of file descriptors. Log it. + */ + L_SUB(&ts_e, &ts); + if (debug > 3) + msyslog(LOG_INFO, "input_handler: Processed a gob of fd's in %s msec", lfptoms(&ts_e, 6)); + + /* just bail. */ + --handler_count; + return; + } + else if (n == -1) + { +#ifndef SYS_WINNT + int err = errno; +#else + DWORD err = WSAGetLastError(); +#endif /* SYS_WINNT */ + + /* + * extended FAU debugging output + */ + msyslog(LOG_ERR, "select(%d, %s, 0L, 0L, &0.000000) error: %m", + maxactivefd+1, fdbits(maxactivefd, &activefds)); + if ( +#ifndef SYS_WINNT + (err == EBADF) +#else + (err == WSAEBADF) +#endif /* SYS_WINNT */ + ) + { + int j, b; + + fds = activefds; + for (j = 0; j <= maxactivefd; j++) + if ( +#ifndef SYS_WINNT + (FD_ISSET(j, &fds) && (read(j, &b, 0) == -1)) +#else + (FD_ISSET(j, &fds) && (!ReadFile((HANDLE)j, &b, 0, NULL, NULL))) +#endif /* SYS_WINNT */ + ) + msyslog(LOG_ERR, "Bad file descriptor %d", j); + } + --handler_count; + return; + } + } + msyslog(LOG_ERR, "input_handler: fell out of infinite for(;;) loop!"); + --handler_count; + return; +} + +#endif + +/* + * findinterface - utility used by other modules to find an interface + * given an address. + */ +struct interface * +findinterface( + struct sockaddr_in *addr + ) +{ + register int i; + register u_int32 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(void) +{ + packets_dropped = 0; + packets_ignored = 0; + packets_received = 0; + packets_sent = 0; + packets_notsent = 0; + + handler_calls = 0; + handler_pkts = 0; + io_timereset = current_time; +} + + +#ifdef REFCLOCK +/* + * This is a hack so that I don't have to fool with these ioctls in the + * pps driver ... we are already non-blocking and turn on SIGIO thru + * another mechanisim + */ +int +io_addclock_simple( + struct refclockio *rio + ) +{ + BLOCKIO(); + /* + * Stuff the I/O structure in the list and mark the descriptor + * in use. There is a harmless (I hope) race condition here. + */ + rio->next = refio; + refio = rio; + + 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( + struct refclockio *rio + ) +{ + BLOCKIO(); + /* + * Stuff the I/O structure in the list and mark the descriptor + * in use. There is a harmless (I hope) race condition here. + */ + rio->next = refio; + refio = rio; + +# ifdef HAVE_SIGNALED_IO + if (init_clock_sig(rio)) + { + refio = rio->next; + UNBLOCKIO(); + return 0; + } +# elif defined(HAVE_IO_COMPLETION_PORT) + if (io_completion_port_add_clock_io(rio)) + { + refio = rio->next; + 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( + struct refclockio *rio + ) +{ + /* + * Remove structure from the list + */ + if (refio == rio) + { + refio = rio->next; + } + else + { + register struct refclockio *rp; + + for (rp = refio; rp != 0; rp = rp->next) + if (rp->next == rio) + { + rp->next = rio->next; + break; + } + + if (rp == 0) + { + /* + * Internal error. Report it. + */ + msyslog(LOG_ERR, + "internal error: refclockio structure not found"); + return; + } + } + + /* + * Close the descriptor. + */ + close_file(rio->fd); +} +#endif /* REFCLOCK */ + +void +kill_asyncio(void) +{ + int i; + + BLOCKIO(); + for (i = 0; i <= maxactivefd; i++) + (void)close_socket(i); +} diff --git a/contrib/ntp/ntpd/ntp_loopfilter.c b/contrib/ntp/ntpd/ntp_loopfilter.c new file mode 100644 index 000000000000..6e0e134af921 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_loopfilter.c @@ -0,0 +1,847 @@ +/* + * ntp_loopfilter.c - implements the NTP loop filter algorithm + * + */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + + +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +#if defined(VMS) && defined(VMS_LOCALUNIT) /*wjm*/ +#include "ntp_refclock.h" +#endif /* VMS */ + +#ifdef KERNEL_PLL +#include "ntp_syscall.h" +#endif /* KERNEL_PLL */ + +/* + * This is an implementation of the clock discipline algorithm described + * in UDel TR 97-4-3, as amended. It operates as an adaptive parameter, + * hybrid phase/frequency-lock loop. A number of sanity checks are + * included to protect against timewarps, timespikes and general mayhem. + * All units are in s and s/s, unless noted otherwise. + */ +#define CLOCK_MAX .128 /* default max offset (s) */ +#define CLOCK_PANIC 1000. /* default panic offset (s) */ +#define CLOCK_MAXSTAB 2e-6 /* max frequency stability */ +#define CLOCK_MAXERR 1e-2 /* max phase jitter (s) */ +#define SHIFT_PLL 4 /* PLL loop gain (shift) */ +#define CLOCK_AVG 4. /* FLL loop gain */ +#define CLOCK_MINSEC 256. /* min FLL update interval (s) */ +#define CLOCK_MINSTEP 900. /* step-change timeout (s) */ +#define CLOCK_DAY 86400. /* one day of seconds */ +#define CLOCK_LIMIT 30 /* poll-adjust threshold */ +#define CLOCK_PGATE 4. /* poll-adjust gate */ +#define CLOCK_ALLAN 1024. /* min Allan intercept (s) */ +#define CLOCK_ADF 1e11 /* Allan deviation factor */ + +/* + * Clock discipline state machine. This is used to control the + * synchronization behavior during initialization and following a + * timewarp. + */ +#define S_NSET 0 /* clock never set */ +#define S_FSET 1 /* frequency set from the drift file */ +#define S_TSET 2 /* time set */ +#define S_FREQ 3 /* frequency mode */ +#define S_SYNC 4 /* clock synchronized */ +#define S_SPIK 5 /* spike detected */ + +/* + * Kernel PLL/PPS state machine. This is used with the kernel PLL + * modifications described in the README.kernel file. + * + * If kernel support for the ntp_adjtime() system call is available, the + * ntp_control flag is set. The ntp_enable and kern_enable flags can be + * set at configuration time or run time using ntpdc. If ntp_enable is + * false, the discipline loop is unlocked and no correctios of any kind + * are made. If both ntp_control and kern_enable are set, the kernel + * support is used as described above; if false, the kernel is bypassed + * entirely and the daemon PLL used instead. + * + * Each update to a prefer peer sets pps_update if it survives the + * intersection algorithm and its time is within range. The PPS time + * discipline is enabled (STA_PPSTIME bit set in the status word) when + * pps_update is true and the PPS frequency discipline is enabled. If + * the PPS time discipline is enabled and the kernel reports a PPS + * signal is present, the pps_control variable is set to the current + * time. If the current time is later than pps_control by PPS_MAXAGE + * (120 s), this variable is set to zero. + * + * If an external clock is present, the clock driver sets STA_CLK in the + * status word. When the local clock driver sees this bit, it updates + * via this routine, which then calls ntp_adjtime() with the STA_PLL bit + * set to zero, in which case the system clock is not adjusted. This is + * also a signal for the external clock driver to discipline the system + * clock. + */ +#define PPS_MAXAGE 120 /* kernel pps signal timeout (s) */ + +/* + * Program variables + */ +static double clock_offset; /* clock offset adjustment (s) */ +double drift_comp; /* clock frequency (ppm) */ +double clock_stability; /* clock stability (ppm) */ +double clock_max = CLOCK_MAX; /* max offset allowed before step (s) */ +static double clock_panic = CLOCK_PANIC; /* max offset allowed before panic */ +u_long pps_control; /* last pps sample time */ +static void rstclock P((int)); /* state transition function */ + +#ifdef KERNEL_PLL +int pll_status; /* status bits for kernel pll */ +#endif /* KERNEL_PLL */ + +/* + * Clock state machine control flags + */ +int ntp_enable; /* clock discipline enabled */ +int pll_control; /* kernel support available */ +int kern_enable; /* kernel support enabled */ +int ext_enable; /* external clock enabled */ +int pps_update; /* pps update valid */ +int allow_set_backward = TRUE; /* step corrections allowed */ +int correct_any = FALSE; /* corrections > 1000 s allowed */ + +#ifdef STA_NANO +int pll_nano; /* nanosecond kernel switch */ +#endif /* STA_NANO */ + +/* + * Clock state machine variables + */ +u_char sys_poll; /* log2 of system poll interval */ +int state; /* clock discipline state */ +int tc_counter; /* poll-adjust counter */ +u_long last_time; /* time of last clock update (s) */ +double last_offset; /* last clock offset (s) */ +double allan_xpt; /* Allan intercept (s) */ +double sys_error; /* system standard error (s) */ + +#if defined(KERNEL_PLL) +/* Emacs cc-mode goes nuts if we split the next line... */ +#define MOD_BITS (MOD_OFFSET | MOD_MAXERROR | MOD_ESTERROR | \ + MOD_STATUS | MOD_TIMECONST) +static void pll_trap P((int)); /* configuration trap */ +#ifdef SIGSYS +static struct sigaction sigsys; /* current sigaction status */ +static struct sigaction newsigsys; /* new sigaction status */ +static sigjmp_buf env; /* environment var. for pll_trap() */ +#endif /* SIGSYS */ +#endif /* KERNEL_PLL */ + +/* + * init_loopfilter - initialize loop filter data + */ +void +init_loopfilter(void) +{ + /* + * Initialize state variables. Initially, we expect no drift + * file, so set the state to S_NSET. + */ + rstclock(S_NSET); +} + +/* + * 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( + struct peer *peer, /* synch source peer structure */ + double fp_offset, /* clock offset (s) */ + double epsil /* jittter (square s*s) */ + ) +{ + double mu; /* interval since last update (s) */ + double oerror; /* previous error estimate */ + double flladj; /* FLL frequency adjustment (ppm) */ + double plladj; /* PLL frequency adjustment (ppm) */ + double clock_frequency; /* clock frequency adjustment (ppm) */ + double dtemp, etemp; /* double temps */ + int retval; /* return value */ + +#if defined(KERNEL_PLL) + struct timex ntv; /* kernel interface structure */ +#endif /* KERNEL_PLL */ + +#ifdef DEBUG + if (debug) + printf( + "local_clock: offset %.6f jitter %.6f state %d\n", + fp_offset, SQRT(epsil), state); +#endif + if (!ntp_enable) + return(0); + + /* + * If the clock is way off, don't tempt fate by correcting it. + */ +#ifndef SYS_WINNT + if (fabs(fp_offset) >= clock_panic && !correct_any) { + msyslog(LOG_ERR, + "time error %.0f over %d seconds; set clock manually)", + fp_offset, (int)clock_panic); + return (-1); + } +#endif + /* + * If the clock has never been set, set it and initialize the + * discipline parameters. We then switch to frequency mode to + * speed the inital convergence process. If lucky, after an hour + * the ntp.drift file is created and initialized and we don't + * get here again. + */ + if (state == S_NSET) { + step_systime(fp_offset); + NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) + msyslog(LOG_NOTICE, "time set %.6f s", fp_offset); + rstclock(S_TSET); + rstclock(S_FREQ); + return (1); + } + + /* + * Update the jitter estimate. + */ + oerror = sys_error; + dtemp = SQUARE(sys_error); + sys_error = SQRT(dtemp + (epsil - dtemp) / CLOCK_AVG); + + /* + * Clock state machine transition function. This is where the + * action is and defines how the system reacts to large phase + * and frequency errors. There are two main regimes: when the + * phase error exceeds the maximum allowed for ordinary tracking + * and otherwise when it does not. + */ + retval = 0; + clock_frequency = flladj = plladj = 0; + mu = current_time - last_time; + if (fabs(fp_offset) > clock_max) { + switch (state) { + + /* + * In S_TSET state the time has been set at the last + * valid update and the offset at that time set to zero. + * If following that we cruise outside the capture + * range, assume a really bad frequency error and switch + * to S_FREQ state. + */ + case S_TSET: + rstclock(S_FREQ); + last_offset = clock_offset = fp_offset; + return (0); + + /* + * In S_SYNC state we ignore outlyers. At the first + * outlyer after CLOCK_MINSTEP (900 s), switch to S_SPIK + * state. + */ + case S_SYNC: + if (mu < CLOCK_MINSTEP) + return (0); + rstclock(S_SPIK); + return (0); + + /* + * In S_FREQ state we ignore outlyers. At the first + * outlyer after CLOCK_MINSTEP (900 s), compute the + * apparent phase and frequency correction. + */ + case S_FREQ: + if (mu < CLOCK_MINSTEP) + return (0); + clock_frequency = (fp_offset - clock_offset) / + mu; + /* fall through to default */ + + /* + * In S_SPIK state a large correction is necessary. + * Since the outlyer may be due to a large frequency + * error, compute the apparent frequency correction. + */ + case S_SPIK: + clock_frequency = (fp_offset - clock_offset) / + mu; + /* fall through to default */ + + /* + * We get here directly in S_FSET state and indirectly + * from S_FREQ and S_SPIK states. The clock is either + * reset or shaken, but never stirred. + */ + default: + if (allow_set_backward) { + step_systime(fp_offset); + NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) + msyslog(LOG_NOTICE, "time reset %.6f s", + fp_offset); + rstclock(S_TSET); + retval = 1; + } else { + NLOG(NLOG_SYNCEVENT|NLOG_SYSEVENT) + msyslog(LOG_NOTICE, "time slew %.6f s", + fp_offset); + rstclock(S_FREQ); + last_offset = clock_offset = fp_offset; + return (0); + } + break; + } + } else { + switch (state) { + + /* + * If this is the first update, initialize the + * discipline parameters and pretend we had just set the + * clock. We don't want to step the clock unless we have + * to. + */ + case S_FSET: + rstclock(S_TSET); + last_offset = clock_offset = fp_offset; + return (0); + + /* + * In S_FREQ state we ignore updates until CLOCK_MINSTEP + * (900 s). After that, correct the phase and frequency + * and switch to S_SYNC state. + */ + case S_FREQ: + if (mu < CLOCK_MINSTEP) + return (0); + clock_frequency = (fp_offset - clock_offset) / + mu; + clock_offset = fp_offset; + rstclock(S_SYNC); + break; + + /* + * Either the clock has just been set or the previous + * update was a spike and ignored. Since this update is + * not an outlyer, fold the tent and resume life. + */ + case S_TSET: + case S_SPIK: + rstclock(S_SYNC); + /* fall through to default */ + + /* + * We come here in the normal case for linear phase and + * frequency adjustments. If the offset exceeds the + * previous time error estimate by CLOCK_SGATE and the + * interval since the last update is less than twice the + * poll interval, consider the update a popcorn spike + * and ignore it. + */ + default: + if (fabs(fp_offset - last_offset) > + CLOCK_SGATE * oerror && mu < + ULOGTOD(sys_poll + 1)) { +#ifdef DEBUG + if (debug) + printf("local_clock: popcorn %.6f %.6f\n", + fp_offset, last_offset); +#endif + last_offset = fp_offset; + return (0); + } + + /* + * Compute the FLL and PLL frequency adjustments + * conditioned on two weighting factors, one + * which limits the time constant determined + * from the Allan intercept, the other which + * limits the gain factor as a function of + * update interval. The net effect is to favor + * the PLL adjustments at the smaller update + * intervals and the FLL adjustments at the + * larger ones. + */ + dtemp = max(mu, allan_xpt); + etemp = min(max(0, mu - CLOCK_MINSEC) / + CLOCK_ALLAN, 1.); + flladj = fp_offset * etemp / (dtemp * + CLOCK_AVG); + dtemp = ULOGTOD(SHIFT_PLL + 2 + sys_poll); + plladj = fp_offset * mu / (dtemp * dtemp); + clock_offset = fp_offset; + break; + } + } + + /* + * This code segment works when clock adjustments are made using + * precision time kernel support and the ntp_adjtime() system + * call. This support is available in Solaris 2.6 and later, + * Digital Unix 4.0 and later, FreeBSD, Linux and specially + * modified kernels for HP-UX 9 and Ultrix 4. In the case of the + * DECstation 5000/240 and Alpha AXP, additional kernel + * modifications provide a true microsecond clock and nanosecond + * clock, respectively. + */ +#if defined(KERNEL_PLL) + if (pll_control && kern_enable) { + + /* + * We initialize the structure for the ntp_adjtime() + * system call. We have to convert everything to + * microseconds or nanoseconds first. Do not update the + * system variables if the ext_enable flag is set. In + * this case, the external clock driver will update the + * variables, which will be read later by the local + * clock driver. Afterwards, remember the time and + * frequency offsets for jitter and stability values and + * to update the drift file. + */ + memset((char *)&ntv, 0, sizeof ntv); + if (ext_enable) { + ntv.modes = MOD_STATUS; + } else { + ntv.modes = MOD_BITS; + if (clock_offset < 0) + dtemp = -.5; + else + dtemp = .5; +#ifdef STA_NANO + if (pll_nano) + ntv.offset = (int32)(clock_offset * + 1e9 + dtemp); + else +#endif /* STA_NANO */ + ntv.offset = (int32)(clock_offset * + 1e6 + dtemp); + if (clock_frequency != 0) { + ntv.modes |= MOD_FREQUENCY; + ntv.freq = (int32)((clock_frequency + + drift_comp) * 65536e6); + } +#ifdef STA_NANO + ntv.constant = sys_poll; +#else + ntv.constant = sys_poll - 4; +#endif /* STA_NANO */ + ntv.esterror = (u_int32)(sys_error * 1e6); + ntv.maxerror = (u_int32)((sys_rootdelay / 2 + + sys_rootdispersion) * 1e6); + ntv.status = STA_PLL; + + /* + * Set the leap bits in the status word. + */ + if (sys_leap == LEAP_NOTINSYNC) { + ntv.status |= STA_UNSYNC; + } else if (calleapwhen(sys_reftime.l_ui) < + CLOCK_DAY) { + if (sys_leap & LEAP_ADDSECOND) + ntv.status |= STA_INS; + else if (sys_leap & LEAP_DELSECOND) + ntv.status |= STA_DEL; + } + + /* + * Switch to FLL mode if the poll interval is + * greater than MAXDPOLL, so that the kernel + * loop behaves as the daemon loop; viz., + * selects the FLL when necessary, etc. For + * legacy only. + */ + if (sys_poll > NTP_MAXDPOLL) + ntv.status |= STA_FLL; + } + + /* + * Wiggle the PPS bits according to the health of the + * prefer peer. + */ + if (pll_status & STA_PPSSIGNAL) + ntv.status |= STA_PPSFREQ; + if (pll_status & STA_PPSFREQ && pps_update) + ntv.status |= STA_PPSTIME; + + /* + * Update the offset and frequency from the kernel + * variables. + */ + if (ntp_adjtime(&ntv) == TIME_ERROR) { + if (ntv.status != pll_status) + msyslog(LOG_ERR, + "kernel pll status change %x", + ntv.status); + } + pll_status = ntv.status; +#ifdef STA_NANO + if (pll_nano) + clock_offset = ntv.offset / 1e9; + else +#endif /* STA_NANO */ + clock_offset = ntv.offset / 1e6; +#ifdef STA_NANO + sys_poll = ntv.constant; +#else + sys_poll = ntv.constant + 4; +#endif /* STA_NANO */ + clock_frequency = ntv.freq / 65536e6 - drift_comp; + flladj = plladj = 0; + + /* + * If the kernel pps discipline is working, monitor its + * performance. + */ + if (ntv.status & STA_PPSTIME) { + if (!pps_control) + NLOG(NLOG_SYSEVENT)msyslog(LOG_INFO, + "pps sync enabled"); + pps_control = current_time; +#ifdef STA_NANO + if (pll_nano) + record_peer_stats( + &loopback_interface->sin, + ctlsysstatus(), ntv.offset / 1e9, + 0., ntv.jitter / 1e9, 0.); + else +#endif /* STA_NANO */ + record_peer_stats( + &loopback_interface->sin, + ctlsysstatus(), ntv.offset / 1e6, + 0., ntv.jitter / 1e6, 0.); + } + } +#endif /* KERNEL_PLL */ + + /* + * Adjust the clock frequency and calculate the stability. If + * kernel support is available, we use the results of the kernel + * discipline instead of the PLL/FLL discipline. In this case, + * drift_comp is a sham and used only for updating the drift + * file and for billboard eye candy. + */ + etemp = clock_frequency + flladj + plladj; + drift_comp += etemp; + if (drift_comp > sys_maxfreq) + drift_comp = sys_maxfreq; + else if (drift_comp <= -sys_maxfreq) + drift_comp = -sys_maxfreq; + dtemp = SQUARE(clock_stability); + etemp = SQUARE(etemp) - dtemp; + clock_stability = SQRT(dtemp + etemp / CLOCK_AVG); + allan_xpt = max(CLOCK_ALLAN, clock_stability * CLOCK_ADF); + + /* + * In SYNC state, adjust the poll interval. + */ + if (state == S_SYNC) { + if (clock_stability < CLOCK_MAXSTAB && + fabs(clock_offset) < CLOCK_PGATE * sys_error) { + tc_counter += sys_poll; + if (tc_counter > CLOCK_LIMIT) { + tc_counter = CLOCK_LIMIT; + if (sys_poll < peer->maxpoll) { + tc_counter = 0; + sys_poll++; + } + } + } else { + tc_counter -= sys_poll << 1; + if (tc_counter < -CLOCK_LIMIT) { + tc_counter = -CLOCK_LIMIT; + if (sys_poll > peer->minpoll) { + tc_counter = 0; + sys_poll--; + } + } + } + } + + /* + * Update the system time variables. + */ + last_time = current_time; + last_offset = clock_offset; + dtemp = peer->disp + SQRT(peer->variance + SQUARE(sys_error)); + if ((peer->flags & FLAG_REFCLOCK) == 0 && dtemp < MINDISPERSE) + dtemp = MINDISPERSE; + sys_rootdispersion = peer->rootdispersion + dtemp; + (void)record_loop_stats(); +#ifdef DEBUG + if (debug) + printf( + "local_clock: mu %.0f allan %.0f fadj %.3f fll %.3f pll %.3f\n", + mu, allan_xpt, clock_frequency * 1e6, flladj * 1e6, + plladj * 1e6); +#endif /* DEBUG */ +#ifdef DEBUG + if (debug) + printf( + "local_clock: jitter %.6f freq %.3f stab %.3f poll %d count %d\n", + sys_error, drift_comp * 1e6, clock_stability * 1e6, + sys_poll, tc_counter); +#endif /* DEBUG */ + return (retval); +} + + +/* + * adj_host_clock - Called once every second to update the local clock. + */ +void +adj_host_clock( + void + ) +{ + double adjustment; + + /* + * Update the dispersion since the last update. In contrast to + * NTPv3, NTPv4 does not declare unsynchronized after one day, + * since the dispersion check serves this function. Also, + * since the poll interval can exceed one day, the old test + * would be counterproductive. Note we do this even with + * external clocks, since the clock driver will recompute the + * maximum error and the local clock driver will pick it up and + * pass to the common refclock routines. Very elegant. + */ + sys_rootdispersion += CLOCK_PHI; + + /* + * Declare PPS kernel unsync if the pps signal has not been + * heard for a few minutes. + */ + if (pps_control && current_time - pps_control > PPS_MAXAGE) { + if (pps_control) + NLOG(NLOG_SYSEVENT) /* conditional if clause */ + msyslog(LOG_INFO, "pps sync disabled"); + pps_control = 0; + } + if (!ntp_enable) + return; + + /* + * If the phase-lock loop is implemented in the kernel, we + * have no business going further. + */ + if (pll_control && kern_enable) + return; + + /* + * Intricate wrinkle for legacy only. If the local clock driver + * is in use and selected for synchronization, somebody else may + * tinker the adjtime() syscall. If this is the case, the driver + * is marked prefer and we have to avoid calling adjtime(), + * since that may truncate the other guy's requests. + */ + if (sys_peer != 0) { + if (sys_peer->refclktype == REFCLK_LOCALCLOCK && + sys_peer->flags & FLAG_PREFER) + return; + } + adjustment = clock_offset / ULOGTOD(SHIFT_PLL + sys_poll); + clock_offset -= adjustment; + adj_systime(adjustment + drift_comp); +} + + +/* + * Clock state machine. Enter new state and set state variables. + */ +static void +rstclock( + int trans /* new state */ + ) +{ + state = trans; + switch (state) { + + /* + * Frequency mode. The clock has ben set, but the frequency has + * not yet been determined. Note that the Allan intercept is set + * insure the clock filter considers only the most recent + * measurements. + */ + case S_FREQ: + sys_poll = NTP_MINDPOLL; + allan_xpt = CLOCK_ALLAN; + last_time = current_time; + break; + + /* + * Synchronized mode. Discipline the poll interval. + */ + case S_SYNC: + sys_poll = NTP_MINDPOLL; + allan_xpt = CLOCK_ALLAN; + tc_counter = 0; + break; + + /* + * Don't do anything in S_SPIK state; just continue from S_SYNC + * state. + */ + case S_SPIK: + break; + + /* + * S_NSET, S_FSET and S_TSET states. These transient states set + * the time reference for future frequency updates. + */ + default: + sys_poll = NTP_MINDPOLL; + allan_xpt = CLOCK_ALLAN; + last_time = current_time; + last_offset = clock_offset = 0; + break; + } +} + + +/* + * loop_config - configure the loop filter + */ +void +loop_config( + int item, + double freq + ) +{ +#if defined(KERNEL_PLL) + struct timex ntv; +#endif /* KERNEL_PLL */ + +#ifdef DEBUG + if (debug) + printf("loop_config: state %d freq %.3f\n", item, freq * + 1e6); +#endif + switch (item) { + + case LOOP_DRIFTINIT: + case LOOP_DRIFTCOMP: + + /* + * The drift file is present and the initial frequency + * is available, so set the state to S_FSET + */ + rstclock(S_FSET); + drift_comp = freq; + if (drift_comp > sys_maxfreq) + drift_comp = sys_maxfreq; + if (drift_comp < -sys_maxfreq) + drift_comp = -sys_maxfreq; +#ifdef KERNEL_PLL + /* + * If the phase-lock code is implemented in the kernel, + * give the time_constant and saved frequency offset to + * the kernel. If not, no harm is done. Note the initial + * time constant is zero, but the first clock update + * will fix that. + */ + memset((char *)&ntv, 0, sizeof ntv); + pll_control = 1; +#ifdef MOD_NANO + ntv.modes = MOD_NANO; +#endif /* MOD_NANO */ +#ifdef SIGSYS + newsigsys.sa_handler = pll_trap; + newsigsys.sa_flags = 0; + if (sigaction(SIGSYS, &newsigsys, &sigsys)) { + msyslog(LOG_ERR, + "sigaction() fails to save SIGSYS trap: %m"); + pll_control = 0; + return; + } + + /* + * Use sigsetjmp() to save state and then call + * ntp_adjtime(); if it fails, then siglongjmp() is used + * to return control + */ + if (sigsetjmp(env, 1) == 0) + (void)ntp_adjtime(&ntv); + if ((sigaction(SIGSYS, &sigsys, + (struct sigaction *)NULL))) { + msyslog(LOG_ERR, + "sigaction() fails to restore SIGSYS trap: %m"); + pll_control = 0; + return; + } +#else /* SIGSYS */ + if (ntp_adjtime(&ntv) < 0) { + msyslog(LOG_ERR, + "loop_config: ntp_adjtime() failed: %m"); + pll_control = 0; + } +#endif /* SIGSYS */ + + /* + * If the kernel support is available and enabled, + * initialize the parameters, but only if the external + * clock is not present. + */ + if (pll_control && kern_enable) { + msyslog(LOG_NOTICE, + "using kernel phase-lock loop %04x", + ntv.status); +#ifdef STA_NANO + if (ntv.status & STA_NANO) + pll_nano = 1; +#endif /* STA_NANO */ +#ifdef STA_CLK + + if (ntv.status & STA_CLK) { + ext_enable = 1; + } else { + ntv.modes = MOD_BITS | MOD_FREQUENCY; + ntv.freq = (int32)(drift_comp * + 65536e6); + ntv.maxerror = MAXDISPERSE; + ntv.esterror = MAXDISPERSE; + ntv.status = STA_UNSYNC | STA_PLL; + (void)ntp_adjtime(&ntv); + } +#else + ntv.modes = MOD_BITS | MOD_FREQUENCY; + ntv.freq = (int32)(drift_comp * 65536e6); + ntv.maxerror = MAXDISPERSE; + ntv.esterror = MAXDISPERSE; + ntv.status = STA_UNSYNC | STA_PLL; + (void)ntp_adjtime(&ntv); +#endif /* STA_CLK */ + } +#endif /* KERNEL_PLL */ + } +} + + +#if defined(KERNEL_PLL) && defined(SIGSYS) +/* + * _trap - trap processor for undefined syscalls + * + * This nugget is called by the kernel when the SYS_ntp_adjtime() + * syscall bombs because the silly thing has not been implemented in + * the kernel. In this case the phase-lock loop is emulated by + * the stock adjtime() syscall and a lot of indelicate abuse. + */ +static RETSIGTYPE +pll_trap( + int arg + ) +{ + pll_control = 0; + siglongjmp(env, 1); +} +#endif /* KERNEL_PLL && SIGSYS */ diff --git a/contrib/ntp/ntpd/ntp_monitor.c b/contrib/ntp/ntpd/ntp_monitor.c new file mode 100644 index 000000000000..64dfb3ee1542 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_monitor.c @@ -0,0 +1,354 @@ +/* + * ntp_monitor.c - monitor who is using the ntpd server + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +# ifdef HAVE_SYS_IOCTL_H +# include +# endif +# include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" + +/* + * I'm still not sure I like what I've done here. It certainly consumes + * memory like it is going out of style, and also may not be as low + * overhead as I'd imagined. + * + * Anyway, we record statistics based on source address, mode and version + * (for now, anyway. Check the code). The receive procedure calls us with + * the incoming rbufp before it does anything else. + * + * Each entry is doubly linked into two lists, a hash table and a + * most-recently-used list. When a packet arrives it is looked up + * in the hash table. If found, the statistics are updated and the + * entry relinked at the head of the MRU list. If not found, a new + * entry is allocated, initialized and linked into both the hash + * table and at the head of the MRU list. + * + * Memory is usually allocated by grabbing a big chunk of new memory + * and cutting it up into littler pieces. The exception to this when we + * hit the memory limit. Then we free memory by grabbing entries off + * the tail for the MRU list, unlinking from the hash table, and + * reinitializing. + * + * trimmed back memory consumption ... jdg 8/94 + */ + +/* + * Limits on the number of structures allocated. This limit is picked + * with the illicit knowlege that we can only return somewhat less + * than 8K bytes in a mode 7 response packet, and that each structure + * will require about 20 bytes of space in the response. + * + * ... I don't believe the above is true anymore ... jdg + */ +#ifndef MAXMONMEM +#define MAXMONMEM 600 /* we allocate up to 600 structures */ +#endif +#ifndef MONMEMINC +#define MONMEMINC 40 /* allocate them 40 at a time */ +#endif + +/* + * Hashing stuff + */ +#define MON_HASH_SIZE 128 +#define MON_HASH_MASK (MON_HASH_SIZE-1) +#define MON_HASH(addr) ((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[MON_HASH_SIZE]; /* array of list ptrs */ +struct mon_data mon_mru_list; +struct mon_data mon_fifo_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; /* the free list or null if none */ + +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; + +static void mon_getmoremem P((void)); +static void remove_from_hash P((struct mon_data *)); + +/* + * init_mon - initialize monitoring global data + */ +void +init_mon(void) +{ + /* + * Don't do much of anything here. We don't allocate memory + * until someone explicitly starts us. + */ + mon_enabled = MON_OFF; + mon_have_memory = 0; + + mon_total_mem = 0; + mon_mem_increments = 0; + mon_free = NULL; + memset((char *)&mon_hash[0], 0, sizeof mon_hash); + memset((char *)&mon_mru_list, 0, sizeof mon_mru_list); + memset((char *)&mon_fifo_list, 0, sizeof mon_fifo_list); +} + + +/* + * mon_start - start up the monitoring software + */ +void +mon_start( + int mode + ) +{ + + if (mon_enabled != MON_OFF) { + mon_enabled |= mode; + return; + } + if (mode == MON_OFF) + return; /* Ooops.. */ + + if (!mon_have_memory) { + mon_total_mem = 0; + mon_mem_increments = 0; + mon_free = NULL; + mon_getmoremem(); + mon_have_memory = 1; + } + + mon_mru_list.mru_next = &mon_mru_list; + mon_mru_list.mru_prev = &mon_mru_list; + + mon_fifo_list.fifo_next = &mon_fifo_list; + mon_fifo_list.fifo_prev = &mon_fifo_list; + + mon_enabled = mode; +} + + +/* + * mon_stop - stop the monitoring software + */ +void +mon_stop( + int mode + ) +{ + register struct mon_data *md, *md_next; + register int i; + + if (mon_enabled == MON_OFF) + return; + if ((mon_enabled & mode) == 0 || mode == MON_OFF) + return; + + mon_enabled &= ~mode; + if (mon_enabled != MON_OFF) + return; + + /* + * Put everything back on the free list + */ + for (i = 0; i < MON_HASH_SIZE; i++) { + md = mon_hash[i]; /* get next list */ + mon_hash[i] = NULL; /* zero the list head */ + while (md != NULL) { + md_next = md->hash_next; + md->hash_next = mon_free; + mon_free = md; + md = md_next; + } + } + + mon_mru_list.mru_next = &mon_mru_list; + mon_mru_list.mru_prev = &mon_mru_list; + + mon_fifo_list.fifo_next = &mon_fifo_list; + mon_fifo_list.fifo_prev = &mon_fifo_list; +} + + +/* + * ntp_monitor - record stats about this packet + */ +void +ntp_monitor( + struct recvbuf *rbufp + ) +{ + register struct pkt *pkt; + register struct mon_data *md; + register u_long netnum; + register int hash; + register int mode; + + if (mon_enabled == MON_OFF) + 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]; + while (md != NULL) { + if (md->rmtadr == netnum && + /* ?? md->interface == rbufp->dstadr && ?? */ + 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 == NULL && 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; + + remove_from_hash(md); + + /* + * Get it from FIFO list + */ + md->fifo_prev->fifo_next = md->fifo_next; + md->fifo_next->fifo_prev = md->fifo_prev; + + } else { + if (mon_free == NULL) /* if free list empty */ + mon_getmoremem(); /* then get more */ + md = mon_free; + mon_free = md->hash_next; + } + + /* + * Got one, initialize it + */ + md->lasttime = md->firsttime = current_time; + md->lastdrop = 0; + 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); + md->interface = rbufp->dstadr; + md->cast_flags = ((rbufp->dstadr->flags & INT_MULTICAST) && + rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd == + md->interface->bfd ? MDF_BCAST : MDF_UCAST; + + /* + * Drop him into front of the hash table. + * Also put him on top of the MRU list + * and at bottom of FIFO list + */ + + md->hash_next = mon_hash[hash]; + mon_hash[hash] = md; + + md->mru_next = mon_mru_list.mru_next; + md->mru_prev = &mon_mru_list; + mon_mru_list.mru_next->mru_prev = md; + mon_mru_list.mru_next = md; + + md->fifo_prev = mon_fifo_list.fifo_prev; + md->fifo_next = &mon_fifo_list; + mon_fifo_list.fifo_prev->fifo_next = md; + mon_fifo_list.fifo_prev = md; +} + + +/* + * mon_getmoremem - get more memory and put it on the free list + */ +static void +mon_getmoremem(void) +{ + register struct mon_data *md; + register int i; + struct mon_data *freedata; /* 'old' free list (null) */ + + md = (struct mon_data *)emalloc(MONMEMINC * sizeof(struct mon_data)); + freedata = mon_free; + mon_free = md; + + for (i = 0; i < (MONMEMINC-1); i++) { + md->hash_next = (md + 1); + md++; + } + + /* + * md now points at the last. Link in the rest of the chain. + */ + md->hash_next = freedata; + + mon_total_mem += MONMEMINC; + mon_mem_increments++; +} + +static void +remove_from_hash( + struct mon_data *md + ) +{ + register int hash; + register struct mon_data *md_prev; + + hash = MON_HASH(md->rmtadr); + if (mon_hash[hash] == md) { + mon_hash[hash] = md->hash_next; + } else { + md_prev = mon_hash[hash]; + while (md_prev->hash_next != md) { + md_prev = md_prev->hash_next; + if (md_prev == NULL) { + /* logic error */ + return; + } + } + md_prev->hash_next = md->hash_next; + } +} diff --git a/contrib/ntp/ntpd/ntp_peer.c b/contrib/ntp/ntpd/ntp_peer.c new file mode 100644 index 000000000000..90646abcfac7 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_peer.c @@ -0,0 +1,795 @@ +/* + * ntp_peer.c - management of data maintained for peer associations + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "ntpd.h" +#include "ntp_stdlib.h" + +/* + * Table of valid association combinations + * --------------------------------------- + * + * packet->mode + * peer->mode | UNSPEC ACTIVE PASSIVE CLIENT SERVER BCAST + * ---------- | --------------------------------------------- + * NO_PEER | e 1 e 1 1 1 + * ACTIVE | e 1 1 0 0 0 + * PASSIVE | e 1 e 0 0 0 + * CLIENT | e 0 0 0 1 1 + * SERVER | e 0 0 0 0 0 + * BCAST | e 0 0 0 0 0 + * CONTROL | e 0 0 0 0 0 + * PRIVATE | e 0 0 0 0 0 + * BCLIENT | e 0 0 0 e 1 + * MCLIENT | e 0 0 0 0 0 + * + * One point to note here: + * a packet in BCAST mode can potentially match a peer in CLIENT + * mode, but we that is a special case and we check for that early + * in the decision process. This avoids having to keep track of + * what kind of associations are possible etc... We actually + * circumvent that problem by requiring that the first b(m)roadcast + * received after the change back to BCLIENT mode sets the clock. + */ + +int AM[AM_MODES][AM_MODES] = { +/* { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */ + +/*NONE*/{ AM_ERR, AM_NEWPASS, AM_ERR, AM_FXMIT, AM_MANYCAST, AM_NEWBCL}, + +/*A*/ { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, + +/*P*/ { AM_ERR, AM_PROCPKT, AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, + +/*C*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT, AM_POSSBCL}, + +/*S*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, + +/*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, + +/*CNTL*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, + +/*PRIV*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, + +/*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_ERR, AM_PROCPKT}, + +/*MCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH} +}; + +#define MATCH_ASSOC(x,y) AM[(x)][(y)] + +/* + * These routines manage the allocation of memory to peer structures + * and the maintenance of the peer hash table. The two main entry + * points are findpeer(), which looks for corresponding peer data + * in the peer list, newpeer(), which allocates a new peer structure + * and adds it to the list, and unpeer(), which demobilizes the association + * and 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. + */ +static 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. + */ +static 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 */ +int peer_associations; /* number of active associations */ + +/* + * Our initial allocation of peer space + */ +static struct peer init_peer_alloc[INIT_PEER_ALLOC]; + +/* + * Initialization data. When configuring peers at initialization time, + * we try to get their poll update timers initialized to different values + * to prevent us from sending big clumps of data all at once. + */ +/* static u_long init_peer_starttime; */ + +static void getmorepeermem P((void)); +static void key_expire P((struct peer *)); + +/* + * init_peer - initialize peer data structures and counters + * + * N.B. We use the random number routine in here. It had better be + * initialized prior to getting here. + */ +void +init_peer(void) +{ + register int i; + + /* + * Clear hash table and counters. + */ + for (i = 0; i < HASH_SIZE; i++) { + peer_hash[i] = 0; + peer_hash_count[i] = 0; + assoc_hash[i] = 0; + assoc_hash_count[i] = 0; + } + + /* + * Clear stat counters + */ + findpeer_calls = peer_allocations = 0; + assocpeer_calls = peer_demobilizations = 0; + + /* + * 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(void) +{ + register int i; + register struct peer *peer; + + peer = (struct peer *)emalloc(INC_PEER_ALLOC*sizeof(struct peer)); + for (i = 0; i < INC_PEER_ALLOC; i++) { + peer->next = peer_free; + peer_free = peer; + peer++; + } + + total_peer_structs += INC_PEER_ALLOC; + peer_free_count += INC_PEER_ALLOC; +} + + + +/* + * findexistingpeer - return a pointer to a peer in the hash table + */ +struct peer * +findexistingpeer( + struct sockaddr_in *addr, + struct peer *start_peer, + int mode + ) +{ + register struct peer *peer; + + /* + * start_peer is included so we can locate instances of the + * same peer through different interfaces in the hash table. + */ + if (start_peer == 0) + peer = peer_hash[HASH_ADDR(addr)]; + else + peer = start_peer->next; + + while (peer != 0) { + if (NSRCADR(addr) == NSRCADR(&peer->srcadr) + && NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) { + if (mode == -1) + return peer; + else if (peer->hmode == mode) + break; + } + peer = peer->next; + } + + return peer; +} + + +/* + * findpeer - find and return a peer in the hash table. + */ +struct peer * +findpeer( + struct sockaddr_in *srcadr, + struct interface *dstadr, + int fd, + int pkt_mode, + int *action + ) +{ + register struct peer *peer; + int hash; + + findpeer_calls++; + hash = HASH_ADDR(srcadr); + for (peer = peer_hash[hash]; peer != 0; peer = peer->next) { + if (NSRCADR(srcadr) == NSRCADR(&peer->srcadr) + && NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) { + /* + * if the association matching rules determine that + * this is not a valid combination, then look for + * the next valid peer association. + */ + *action = MATCH_ASSOC(peer->hmode, pkt_mode); + + /* + * Sigh! Check if BCLIENT peer in client + * server mode, else return error + */ + if ((*action == AM_POSSBCL) && + !(peer->cast_flags & FLAG_MCAST1)) { + *action = AM_ERR; + } + + /* if an error was returned, exit back right here */ + if (*action == AM_ERR) + return (struct peer *)0; + + /* if a match is found, we stop our search */ + if (*action != AM_NOMATCH) + break; + } + } + +#ifdef DEBUG + if (debug > 1) + printf("pkt_mode %d action %d\n", pkt_mode, *action); +#endif + /* if no matching association is found */ + if (peer == 0) { + *action = MATCH_ASSOC(NO_PEER, pkt_mode); +#ifdef DEBUG + if (debug > 1) + printf("pkt_mode %d action %d\n", pkt_mode, *action); +#endif + return (struct peer *)0; + } + + /* reset the default interface to something more meaningful */ + if ((peer->dstadr == any_interface)) + peer->dstadr = dstadr; + return peer; +} + +/* + * findpeerbyassocid - find and return a peer using his association ID + */ +struct peer * +findpeerbyassoc( + 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; +} + +/* + * findmanycastpeer - find and return an manycast peer if it exists + * + * + * the current implementation loops across all hash-buckets + * + * *** THERE IS AN URGENT NEED TO CHANGE THIS *** + */ +struct peer * +findmanycastpeer( + l_fp *p_org + ) +{ + register struct peer *peer; + register struct peer *manycast_peer = 0; + int i = 0; + + for (i = 0; i < HASH_SIZE; i++) { + if (peer_hash_count[i] == 0) + continue; + + for (peer = peer_hash[i]; peer != 0; peer = peer->next) { + if (peer->cast_flags & MDF_ACAST && + peer->flags & FLAG_CONFIG) { + if (L_ISEQU(&peer->xmt, p_org)) + return peer; /* got it */ + else + manycast_peer = peer; + } + } + } + + /* + * Out of luck. Return the manycastpeer for what it is worth. + */ + return manycast_peer; +} + +/* + * key_expire - garbage collect keys + */ +static void +key_expire( + struct peer *peer + ) +{ + int i; + + if (peer->keylist != 0) { + for (i = 0; i <= peer->keynumber; i++) + authtrust(peer->keylist[i], 0); + free(peer->keylist); + peer->keylist = 0; + } + if (peer->keyid > NTP_MAXKEY) { + authtrust(peer->keyid, 0); + peer->keyid = 0; + } +} + +/* + * key_rekey - expire all keys and roll a new private value. Note the + * 32-bit mask is necessary for 64-bit u_longs. + */ +void +key_expire_all( + ) +{ + struct peer *peer, *next_peer; + int n; + + for (n = 0; n < HASH_SIZE; n++) { + for (peer = peer_hash[n]; peer != 0; peer = next_peer) { + next_peer = peer->next; + key_expire(peer); + } + } + sys_private = (u_long)RANDOM & 0xffffffff; +#ifdef DEBUG + if (debug) + printf("key_expire_all: at %lu private %08lx\n", + current_time, sys_private); +#endif +} +/* + * unpeer - remove peer structure from hash table and free structure + */ +void +unpeer( + struct peer *peer_to_remove + ) +{ + int hash; + +#ifdef DEBUG + if (debug > 1) + printf("demobilize %u\n", peer_to_remove->associd); +#endif + key_expire(peer_to_remove); + hash = HASH_ADDR(&peer_to_remove->srcadr); + peer_hash_count[hash]--; + peer_demobilizations++; + peer_associations--; + +#ifdef REFCLOCK + /* + * If this peer is actually a clock, shut it down first + */ + if (peer_to_remove->flags & FLAG_REFCLOCK) + refclock_unpeer(peer_to_remove); +#endif + peer_to_remove->action = 0; /* disable timeout actions */ + if (peer_hash[hash] == peer_to_remove) + peer_hash[hash] = peer_to_remove->next; + else { + register struct peer *peer; + + peer = peer_hash[hash]; + while (peer != 0 && peer->next != peer_to_remove) + peer = peer->next; + + if (peer == 0) { + peer_hash_count[hash]++; + msyslog(LOG_ERR, "peer struct for %s not in table!", + 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]++; + msyslog(LOG_ERR, + "peer struct for %s not in association table!", + ntoa(&peer->srcadr)); + } else { + peer->ass_next = peer_to_remove->ass_next; + } + } + peer_to_remove->next = peer_free; + peer_free = peer_to_remove; + peer_free_count++; +} + + +/* + * peer_config - configure a new peer + */ +struct peer * +peer_config( + struct sockaddr_in *srcadr, + struct interface *dstadr, + int hmode, + int version, + int minpoll, + int maxpoll, + int flags, + int ttl, + u_long key + ) +{ + register struct peer *peer; + + /* + * See if we have this guy in the tables already. If + * so just mark him configured. + */ + peer = findexistingpeer(srcadr, (struct peer *)0, hmode); + if (dstadr != 0) { + while (peer != 0) { + if (peer->dstadr == dstadr) + break; + peer = findexistingpeer(srcadr, peer, hmode); + } + } + + /* + * 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 = flags | FLAG_CONFIG | + (peer->flags & FLAG_REFCLOCK); + peer->cast_flags = (hmode == MODE_BROADCAST) ? + IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)) ? MDF_MCAST : MDF_BCAST : MDF_UCAST; + peer->ttl = (u_char)ttl; + peer->keyid = key; + peer->keynumber = 0; + 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, + ttl, key); + if (peer != 0) { + peer->flags |= flags | FLAG_CONFIG; +#ifdef DEBUG + if (debug) + printf("peer_config: %s mode %d vers %d min %d max %d flags 0x%04x ttl %d key %lu\n", + ntoa(&peer->srcadr), peer->hmode, peer->version, + peer->minpoll, peer->maxpoll, peer->flags, + peer->ttl, peer->keyid); +#endif + } + return peer; +} + + +/* + * newpeer - initialize a new peer association + */ +struct peer * +newpeer( + struct sockaddr_in *srcadr, + struct interface *dstadr, + int hmode, + int version, + int minpoll, + int maxpoll, + int ttl, + u_long key + ) +{ + register struct peer *peer; + register int i; + + /* + * Some dirt here. Some of the initialization requires + * knowlege of our system state. + */ + if (peer_free_count == 0) + getmorepeermem(); + + peer = peer_free; + peer_free = peer->next; + peer_free_count--; + peer_associations++; + + /* + * 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->cast_flags = (hmode == MODE_BROADCAST) ? + (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr))) ? MDF_MCAST : + MDF_BCAST : (hmode == MODE_BCLIENT || hmode == MODE_MCLIENT) ? + (peer->dstadr->flags & INT_MULTICAST) ? MDF_MCAST : MDF_BCAST : + MDF_UCAST; + /* Set manycast flags if appropriate */ + if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)) && hmode == MODE_CLIENT) + peer->cast_flags = MDF_ACAST; + peer->hmode = (u_char)hmode; + peer->keyid = key; + peer->version = (u_char)version; + peer->minpoll = (u_char)minpoll; + peer->maxpoll = (u_char)maxpoll; + peer->hpoll = peer->minpoll; + peer->ppoll = peer->minpoll; + peer->ttl = ttl; + peer->leap = LEAP_NOTINSYNC; + peer->precision = sys_precision; + peer->variance = MAXDISPERSE; + peer->epoch = current_time; + peer->stratum = STRATUM_UNSPEC; + peer_clear(peer); + peer->update = peer->outdate = current_time; + peer->nextdate = peer->outdate + RANDPOLL(NTP_MINPOLL); + if (peer->flags & FLAG_BURST) + peer->burst = NTP_SHIFT; + + /* + * 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; + } + } +#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]++; +#ifdef DEBUG + if (debug > 1) + printf("mobilize %u next %lu\n", peer->associd, + peer->nextdate - peer->outdate); +#endif + return peer; +} + + +/* + * peer_unconfig - remove the configuration bit from a peer + */ +int +peer_unconfig( + struct sockaddr_in *srcadr, + struct interface *dstadr, + int mode + ) +{ + register struct peer *peer; + int num_found; + + num_found = 0; + peer = findexistingpeer(srcadr, (struct peer *)0, mode); + while (peer != 0) { + if (peer->flags & FLAG_CONFIG + && (dstadr == 0 || peer->dstadr == dstadr)) { + num_found++; + /* + * Tricky stuff here. If the peer is polling us + * in active mode, turn off the configuration bit + * and make the mode passive. This allows us to + * avoid dumping a lot of history for peers we + * might choose to keep track of in passive mode. + * The protocol will eventually terminate undesirables + * on its own. + */ + if (peer->hmode == MODE_ACTIVE + && peer->pmode == MODE_ACTIVE) { + peer->hmode = MODE_PASSIVE; + peer->flags &= ~FLAG_CONFIG; + } else { + unpeer(peer); + peer = 0; + } + } + peer = findexistingpeer(srcadr, peer, mode); + } + return num_found; +} + +/* + * peer_copy_manycast - copy manycast peer variables to new association + * (right now it simply copies the transmit timestamp) + */ +void +peer_config_manycast( + struct peer *peer1, + struct peer *peer2 + ) +{ + peer2->cast_flags = MDF_ACAST; + peer2->xmt = peer1->xmt; +} + +/* + * peer_clr_stats - clear peer module stat counters + */ +void +peer_clr_stats(void) +{ + findpeer_calls = 0; + assocpeer_calls = 0; + peer_allocations = 0; + peer_demobilizations = 0; + peer_timereset = current_time; +} + +/* + * peer_reset - reset stat counters in a peer structure + */ +void +peer_reset( + struct peer *peer + ) +{ + if (peer == 0) + return; + peer->sent = 0; + peer->received = 0; + peer->processed = 0; + peer->badauth = 0; + peer->bogusorg = 0; + peer->oldpkt = 0; + peer->seldisptoolarge = 0; + peer->selbroken = 0; + peer->seltooold = 0; + peer->timereset = current_time; +} + + +/* + * peer_all_reset - reset all peer stat counters + */ +void +peer_all_reset(void) +{ + struct peer *peer; + int hash; + + for (hash = 0; hash < HASH_SIZE; hash++) + for (peer = peer_hash[hash]; peer != 0; peer = peer->next) + peer_reset(peer); +} diff --git a/contrib/ntp/ntpd/ntp_proto.c b/contrib/ntp/ntpd/ntp_proto.c new file mode 100644 index 000000000000..6d5429144b47 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_proto.c @@ -0,0 +1,2165 @@ +/* + * ntp_proto.c - NTP version 4 protocol machinery + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_stdlib.h" +#include "ntp_unixtime.h" +#include "ntp_control.h" +#include "ntp_string.h" + +#if defined(VMS) && defined(VMS_LOCALUNIT) /*wjm*/ +#include "ntp_refclock.h" +#endif + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif + +/* + * System variables are declared here. See Section 3.2 of the + * specification. + */ +u_char sys_leap; /* system leap indicator */ +u_char sys_stratum; /* stratum of system */ +s_char sys_precision; /* local clock precision */ +double sys_rootdelay; /* distance to current sync source */ +double sys_rootdispersion; /* dispersion of system clock */ +u_int32 sys_refid; /* reference source for local clock */ +static double sys_offset; /* current local clock offset */ +l_fp sys_reftime; /* time we were last updated */ +struct peer *sys_peer; /* our current peer */ +u_long sys_automax; /* maximum session key lifetime */ + +/* + * Nonspecified system state variables. + */ +int sys_bclient; /* we set our time to broadcasts */ +double sys_bdelay; /* broadcast client default delay */ +int sys_authenticate; /* requre authentication for config */ +l_fp sys_authdelay; /* authentication delay */ +static u_long sys_authdly[2]; /* authentication delay shift reg */ +static u_char leap_consensus; /* consensus of survivor leap bits */ +static double sys_maxd; /* select error (squares) */ +static double sys_epsil; /* system error (squares) */ +u_long sys_private; /* private value for session seed */ +int sys_manycastserver; /* 1 => respond to manycast client pkts */ + +/* + * Statistics counters + */ +u_long sys_stattime; /* time when we started recording */ +u_long sys_badstratum; /* packets with invalid 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 auth */ +u_long sys_limitrejected; /* pkts rejected due to client count per net */ + +static double root_distance P((struct peer *)); +static double clock_combine P((struct peer **, int)); +static void peer_xmit P((struct peer *)); +static void fast_xmit P((struct recvbuf *, int, u_long)); +static void clock_update P((void)); +#ifdef MD5 +static void make_keylist P((struct peer *)); +#endif /* MD5 */ + +/* + * transmit - Transmit Procedure. See Section 3.4.2 of the + * specification. + */ +void +transmit( + struct peer *peer /* peer structure pointer */ + ) +{ + int hpoll; + + hpoll = peer->hpoll; + if (peer->burst == 0) { + u_char oreach; + + /* + * Determine reachability and diddle things if we + * haven't heard from the host for a while. If the peer + * is not configured and not likely to stay around, + * we exhaust it. + */ + oreach = peer->reach; + if (oreach & 0x01) + peer->valid++; + if (oreach & 0x80) + peer->valid--; + if (!(peer->flags & FLAG_CONFIG) && + peer->valid > NTP_SHIFT / 2 && (peer->reach & 0x80) && + peer->status < CTL_PST_SEL_SYNCCAND) + peer->reach = 0; + peer->reach <<= 1; + if (peer->reach == 0) { + + /* + * If this is an uncofigured association and + * has become unreachable, demobilize it. + */ + if (oreach != 0) { + report_event(EVNT_UNREACH, peer); + peer->timereachable = current_time; + peer_clear(peer); + if (!(peer->flags & FLAG_CONFIG)) { + unpeer(peer); + return; + } + } + + /* + * We would like to respond quickly when the + * peer comes back to life. If the probes since + * becoming unreachable are less than + * NTP_UNREACH, clamp the poll interval to the + * minimum. In order to minimize the network + * traffic, the interval gradually ramps up the + * the maximum after that. + */ + peer->ppoll = peer->maxpoll; + if (peer->unreach < NTP_UNREACH) { + if (peer->hmode == MODE_CLIENT) + peer->unreach++; + hpoll = peer->minpoll; + } else { + hpoll++; + } + if (peer->flags & FLAG_BURST) + peer->burst = 2; + + } else { + + /* + * Here the peer is reachable. If there is no + * system peer or if the stratum of the system + * peer is greater than this peer, clamp the + * poll interval to the minimum. If less than + * two samples are in the reachability register, + * reduce the interval; if more than six samples + * are in the register, increase the interval. + */ + peer->unreach = 0; + if (sys_peer == 0) + hpoll = peer->minpoll; + else if (sys_peer->stratum > peer->stratum) + hpoll = peer->minpoll; + if ((peer->reach & 0x03) == 0) { + clock_filter(peer, 0., 0., MAXDISPERSE); + clock_select(); + } + if (peer->valid <= 2) + hpoll--; + else if (peer->valid >= NTP_SHIFT - 2) + hpoll++; + if (peer->flags & FLAG_BURST) + peer->burst = NTP_SHIFT; + } + } else { + peer->burst--; + if (peer->burst == 0) { + if (peer->flags & FLAG_MCAST2) { + peer->flags &= ~FLAG_BURST; + peer->hmode = MODE_BCLIENT; + } + clock_select(); + poll_update(peer, hpoll); + return; + } + } + + /* + * We need to be very careful about honking uncivilized time. If + * not operating in broadcast mode, honk in all except broadcast + * client mode. If operating in broadcast mode and synchronized + * to a real source, honk except when the peer is the local- + * clock driver and the prefer flag is not set. In other words, + * in broadcast mode we never honk unless known to be + * synchronized to real time. + */ + if (peer->hmode != MODE_BROADCAST) { + if (peer->hmode != MODE_BCLIENT) + peer_xmit(peer); + } else if (sys_peer != 0 && sys_leap != LEAP_NOTINSYNC) { + if (!(sys_peer->refclktype == REFCLK_LOCALCLOCK && + !(sys_peer->flags & FLAG_PREFER))) + peer_xmit(peer); + } + peer->outdate = current_time; + poll_update(peer, hpoll); +} + +/* + * receive - Receive Procedure. See section 3.4.3 in the specification. + */ +void +receive( + struct recvbuf *rbufp + ) +{ + register struct peer *peer; + register struct pkt *pkt; + int hismode; + int oflags; + int restrict_mask; + int has_mac; /* has MAC field */ + int authlen; /* length of MAC field */ + int is_authentic; /* cryptosum ok */ + int is_mystic; /* session key exists */ + int is_error; /* parse error */ +/* u_long pkeyid; */ + u_long skeyid, tkeyid; + struct peer *peer2; + int retcode = AM_NOMATCH; + + /* + * Monitor the packet and get restrictions + */ + ntp_monitor(rbufp); + restrict_mask = restrictions(&rbufp->recv_srcadr); +#ifdef DEBUG + if (debug > 1) + printf("receive: from %s restrict %02x\n", + ntoa(&rbufp->recv_srcadr), restrict_mask); +#endif + if (restrict_mask & RES_IGNORE) + return; + + /* + * Discard packets with invalid version number. + */ + pkt = &rbufp->recv_pkt; + if (PKT_VERSION(pkt->li_vn_mode) >= NTP_VERSION) + sys_newversionpkt++; + else if (PKT_VERSION(pkt->li_vn_mode) >= NTP_OLDVERSION) + sys_oldversionpkt++; + else { + sys_unknownversion++; + return; + } + + /* + * Restrict control/private mode packets. Note that packet + * length has to be checked in the control/private mode protocol + * module. + */ + if (PKT_MODE(pkt->li_vn_mode) == MODE_PRIVATE) { + if (restrict_mask & RES_NOQUERY) + return; + process_private(rbufp, ((restrict_mask & RES_NOMODIFY) == + 0)); + return; + } + if (PKT_MODE(pkt->li_vn_mode) == MODE_CONTROL) { + if (restrict_mask & RES_NOQUERY) + return; + process_control(rbufp, restrict_mask); + return; + } + + /* + * Restrict revenue packets. + */ + if (restrict_mask & RES_DONTSERVE) + return; + + /* + * See if we only accept limited number of clients from the net + * this guy is from. Note: the flag is determined dynamically + * within restrictions() + */ + if (restrict_mask & RES_LIMITED) { + sys_limitrejected++; + return; + } + + /* + * If we are not a broadcast client, ignore broadcast packets. + */ + if ((PKT_MODE(pkt->li_vn_mode) == MODE_BROADCAST && !sys_bclient)) + return; + + /* + * This is really awful ugly. We figure out whether an extension + * field is present and then measure the MAC size. If the number + * of words following the packet header is less than or equal to + * 5, no extension field is present and these words constitute the + * MAC. If the number of words is greater than 5, an extension + * field is present and the first word contains the length of + * the extension field and the MAC follows that. + */ + has_mac = 0; +/* pkeyid = 0; */ + skeyid = tkeyid = 0; + authlen = LEN_PKT_NOMAC; + has_mac = rbufp->recv_length - authlen; + if (has_mac <= 5 * sizeof(u_int32)) { + skeyid = (u_long)ntohl(pkt->keyid1) & 0xffffffff; + } else { + authlen += (u_long)ntohl(pkt->keyid1) & 0xffffffff; + has_mac = rbufp->recv_length - authlen; + if (authlen <= 0) { + sys_badlength++; + return; + } + + /* + * Note that keyid3 is actually the key ident of the + * MAC itself. + */ +/* pkeyid = (u_long)ntohl(pkt->keyid2) & 0xffffffff; */ + skeyid = tkeyid = (u_long)ntohl(pkt->keyid3) & 0xffffffff; + } + + /* + * Figure out his mode and validate it. + */ + hismode = (int)PKT_MODE(pkt->li_vn_mode); + if (PKT_VERSION(pkt->li_vn_mode) == NTP_OLDVERSION && hismode == + 0) { + /* + * Easy. If it is from the NTP port it is + * a sym act, else client. + */ + if (SRCPORT(&rbufp->recv_srcadr) == NTP_PORT) + hismode = MODE_ACTIVE; + else + hismode = MODE_CLIENT; + } else { + if (hismode != MODE_ACTIVE && hismode != MODE_PASSIVE && + hismode != MODE_SERVER && hismode != MODE_CLIENT && + hismode != MODE_BROADCAST) + return; + } + + /* + * If he included a mac field, decrypt it to see if it is + * authentic. + */ + is_authentic = is_mystic = 0; + if (has_mac == 0) { +#ifdef DEBUG + if (debug) + printf("receive: at %ld from %s mode %d\n", + current_time, ntoa(&rbufp->recv_srcadr), + hismode); +#endif + } else { + is_mystic = authistrusted(skeyid); +#ifdef MD5 + if (skeyid > NTP_MAXKEY && !is_mystic) { + + /* + * For multicast mode, generate the session key + * and install in the key cache. For client mode, + * generate the session key for the unicast + * address. For server mode, the session key should + * already be in the key cache, since it was + * generated when the last request was sent. + */ + if (hismode == MODE_BROADCAST) { + tkeyid = session_key( + ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), + ntohl(rbufp->dstadr->bcast.sin_addr.s_addr), + skeyid, (u_long)(4 * (1 << pkt->ppoll))); + } else if (hismode != MODE_SERVER) { + tkeyid = session_key( + ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), + ntohl(rbufp->dstadr->sin.sin_addr.s_addr), + skeyid, (u_long)(4 * (1 << pkt->ppoll))); + } + + } +#endif /* MD5 */ + + /* + * Compute the cryptosum. Note a clogging attack may + * succceed in bloating the key cache. + */ + if (authdecrypt(skeyid, (u_int32 *)pkt, authlen, has_mac)) + is_authentic = 1; + else + sys_badauth++; +#ifdef DEBUG + if (debug) + printf( + "receive: at %ld %s mode %d keyid %08lx mac %d auth %d\n", + current_time, ntoa(&rbufp->recv_srcadr), + hismode, skeyid, has_mac, is_authentic); +#endif + } + + /* + * Find the peer. This will return a null if this guy isn't in + * the database. + */ + peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr, rbufp->fd, + hismode, &retcode); + /* + * The new association matching rules are driven by a table specified + * in ntp.h. We have replaced the *default* behaviour of replying + * to bogus packets in server mode in this version. + * A packet must now match an association in order to be processed. + * In the event that no association exists, then an association is + * mobilized if need be. Two different associations can be mobilized + * a) passive associations + * b) client associations due to broadcasts or manycasts. + */ + is_error = 0; + switch (retcode) { + case AM_FXMIT: + /* + * If the client is configured purely as a broadcast client and + * not as an manycast server, it has no business being a server. + * Simply go home. Otherwise, send a MODE_SERVER response and go + * home. Note that we don't do a authentication check here, + * since we can't set the system clock; but, we do set the + * key ID to zero to tell the caller about this. + */ + if (!sys_bclient || sys_manycastserver) { + if (is_authentic) + fast_xmit(rbufp, MODE_SERVER, skeyid); + else + fast_xmit(rbufp, MODE_SERVER, 0); + } + + /* + * We can't get here if an association is mobilized, so just + * toss the key, if appropriate. + */ + if (!is_mystic && skeyid > NTP_MAXKEY) + authtrust(skeyid, 0); + return; + + case AM_MANYCAST: + /* + * This could be in response to a multicast packet sent by + * the "manycast" mode association. Find peer based on the + * originate timestamp in the packet. Note that we don't + * mobilize a new association, unless the packet is properly + * authenticated. The response must be properly authenticated + * and it's darn funny of the manycaster isn't around now. + */ + if ((sys_authenticate && !is_authentic)) { + is_error = 1; + break; + } + peer2 = (struct peer *)findmanycastpeer(&pkt->org); + if (peer2 == 0) { + is_error = 1; + break; + } + + /* + * Create a new association and copy the peer variables to it. + * If something goes wrong, carefully pry the new association + * away and return its marbles to the candy store. + */ + peer = newpeer(&rbufp->recv_srcadr, + rbufp->dstadr, MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode), + NTP_MINDPOLL, NTP_MAXDPOLL, 0, skeyid); + if (peer == 0) { + is_error = 1; + break; + } + peer_config_manycast(peer2, peer); + break; + + case AM_ERR: + /* + * Something bad happened. Dirty floor will be mopped by the + * code at the end of this adventure. + */ + is_error = 1; + break; + + case AM_NEWPASS: + /* + * Okay, we're going to keep him around. Allocate him some + * memory. But, don't do that unless the packet is properly + * authenticated. + */ + if ((sys_authenticate && !is_authentic)) { + is_error = 1; + break; + } + peer = newpeer(&rbufp->recv_srcadr, + rbufp->dstadr, MODE_PASSIVE, PKT_VERSION(pkt->li_vn_mode), + NTP_MINDPOLL, NTP_MAXDPOLL, 0, skeyid); + break; + + case AM_NEWBCL: + /* + * Broadcast client being set up now. Do this only if the + * packet is properly authenticated. + */ + if ((restrict_mask & RES_NOPEER) || !sys_bclient || + (sys_authenticate && !is_authentic)) { + is_error = 1; + break; + } + peer = newpeer(&rbufp->recv_srcadr, + rbufp->dstadr, MODE_MCLIENT, PKT_VERSION(pkt->li_vn_mode), + NTP_MINDPOLL, NTP_MAXDPOLL, 0, skeyid); + if (peer == 0) + break; + peer->flags |= FLAG_MCAST1 | FLAG_MCAST2 | FLAG_BURST; + peer->hmode = MODE_CLIENT; + break; + + case AM_POSSBCL: + case AM_PROCPKT: + /* + * It seems like it is okay to process the packet now + */ + break; + + default: + /* + * shouldn't be getting here, but simply return anyway! + */ + is_error = 1; + } + if (is_error) { + + /* + * Error stub. If we get here, something broke. We scuttle + * the autokey if necessary and sink the ship. This can + * occur only upon mobilization, so we can throw the + * structure away without fear of breaking anything. + */ + if (!is_mystic && skeyid > NTP_MAXKEY) + authtrust(skeyid, 0); + if (peer != 0) + if (!(peer->flags & FLAG_CONFIG)) + unpeer(peer); +#ifdef DEBUG + if (debug) + printf("match error code %d assoc %d\n", retcode, + peer_associations); +#endif + return; + } + + /* + * If the peer isn't configured, set his keyid and authenable + * status based on the packet. + */ + oflags = peer->flags; + peer->timereceived = current_time; + if (!(peer->flags & FLAG_CONFIG) && has_mac) { + peer->flags |= FLAG_AUTHENABLE; + if (skeyid > NTP_MAXKEY) { + if (peer->flags & FLAG_MCAST2) + peer->keyid = skeyid; + else + peer->flags |= FLAG_SKEY; + } + } + + /* + * Determine if this guy is basically trustable. If not, flush + * the bugger. If this is the first packet that is authenticated, + * flush the clock filter. This is to foil clogging attacks that + * might starve the poor dear. + */ + peer->flash = 0; + if (is_authentic) + peer->flags |= FLAG_AUTHENTIC; + else + peer->flags &= ~FLAG_AUTHENTIC; + if (peer->hmode == MODE_BROADCAST && (restrict_mask & RES_DONTTRUST)) + peer->flash |= TEST10; /* access denied */ + if (peer->flags & FLAG_AUTHENABLE) { + if (!(peer->flags & FLAG_AUTHENTIC)) + peer->flash |= TEST5; /* authentication failed */ + else if (skeyid == 0) + peer->flash |= TEST9; /* peer not authenticated */ + else if (!(oflags & FLAG_AUTHENABLE)) { + peer_clear(peer); + report_event(EVNT_PEERAUTH, peer); + } + } + if ((peer->flash & ~(u_int)TEST9) != 0) { + + /* + * The packet is bogus, so we throw it away before becoming + * a denial-of-service hazard. We don't throw the current + * association away if it is configured or if it has prior + * reachable friends. + */ + if (!is_mystic && skeyid > NTP_MAXKEY) + authtrust(skeyid, 0); + if (!(peer->flags & FLAG_CONFIG) && peer->reach == 0) + unpeer(peer); +#ifdef DEBUG + if (debug) + printf( + "invalid packet 0x%02x code %d assoc %d\n", + peer->flash, retcode, peer_associations); +#endif + return; + } + +#ifdef MD5 + /* + * The autokey dance. The cha-cha requires that the hash of the + * current session key matches the previous key identifier. Heaps + * of trouble if the steps falter. + */ + if (skeyid > NTP_MAXKEY) { + int i; + + /* + * In the case of a new autokey, verify the hash matches + * one of the previous four hashes. If not, raise the + * authentication flasher and hope the next one works. + */ + if (hismode == MODE_SERVER) { + peer->pkeyid = peer->keyid; + } else if (peer->flags & FLAG_MCAST2) { + if (peer->pkeyid > NTP_MAXKEY) + authtrust(peer->pkeyid, 0); + for (i = 0; i < 4 && tkeyid != peer->pkeyid; i++) { + tkeyid = session_key( + ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), + ntohl(rbufp->dstadr->bcast.sin_addr.s_addr), + tkeyid, 0); + } + } else { + if (peer->pkeyid > NTP_MAXKEY) + authtrust(peer->pkeyid, 0); + for (i = 0; i < 4 && tkeyid != peer->pkeyid; i++) { + tkeyid = session_key( + ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), + ntohl(rbufp->dstadr->sin.sin_addr.s_addr), + tkeyid, 0); + } + } +#ifdef XXX /* temp until certificate code is mplemented */ + if (tkeyid != peer->pkeyid) + peer->flash |= TEST9; /* peer not authentic */ +#endif + peer->pkeyid = skeyid; + } +#endif /* MD5 */ + + /* + * Gawdz, it's come to this. Process the dang packet. If something + * breaks and the association doesn't deserve to live, toss it. + * Be careful in active mode and return a packet anyway. + */ + process_packet(peer, pkt, &(rbufp->recv_time)); + if (!(peer->flags & FLAG_CONFIG) && peer->reach == 0) { + if (peer->hmode == MODE_PASSIVE) { + if (is_authentic) + fast_xmit(rbufp, MODE_PASSIVE, skeyid); + else + fast_xmit(rbufp, MODE_PASSIVE, 0); + } + unpeer(peer); + } +} + + +/* + * process_packet - Packet Procedure, a la Section 3.4.4 of the + * specification. Or almost, at least. If we're in here we have a + * reasonable expectation that we will be having a long term + * relationship with this host. + */ +int +process_packet( + register struct peer *peer, + register struct pkt *pkt, + l_fp *recv_ts + ) +{ + l_fp t10, t23; + double p_offset, p_del, p_disp; + double dtemp; + l_fp p_rec, p_xmt, p_org, p_reftime; + l_fp ci; + int pmode; + + /* + * Swap header fields and keep the books. + */ + sys_processed++; + peer->processed++; + p_del = FPTOD(NTOHS_FP(pkt->rootdelay)); + p_disp = FPTOD(NTOHS_FP(pkt->rootdispersion)); + NTOHL_FP(&pkt->reftime, &p_reftime); + NTOHL_FP(&pkt->rec, &p_rec); + NTOHL_FP(&pkt->xmt, &p_xmt); + if (PKT_MODE(pkt->li_vn_mode) != MODE_BROADCAST) + NTOHL_FP(&pkt->org, &p_org); + else + p_org = peer->rec; + peer->rec = *recv_ts; + peer->ppoll = pkt->ppoll; + pmode = PKT_MODE(pkt->li_vn_mode); + + /* + * Test for old or duplicate packets (tests 1 through 3). + */ + if (L_ISHIS(&peer->org, &p_xmt)) /* count old packets */ + peer->oldpkt++; + if (L_ISEQU(&peer->org, &p_xmt)) /* test 1 */ + peer->flash |= TEST1; /* duplicate packet */ + if (PKT_MODE(pkt->li_vn_mode) != MODE_BROADCAST) { + if (!L_ISEQU(&peer->xmt, &p_org)) { /* test 2 */ + peer->bogusorg++; + peer->flash |= TEST2; /* bogus packet */ + } + if (L_ISZERO(&p_rec) || L_ISZERO(&p_org)) + peer->flash |= TEST3; /* unsynchronized */ + } else { + if (L_ISZERO(&p_org)) + peer->flash |= TEST3; /* unsynchronized */ + } + peer->org = p_xmt; + + /* + * Test for valid header (tests 5 through 10) + */ + ci = p_xmt; + L_SUB(&ci, &p_reftime); + LFPTOD(&ci, dtemp); + if (PKT_LEAP(pkt->li_vn_mode) == LEAP_NOTINSYNC || /* test 6 */ + PKT_TO_STRATUM(pkt->stratum) >= NTP_MAXSTRATUM || + dtemp < 0) + peer->flash |= TEST6; /* peer clock unsynchronized */ + if (!(peer->flags & FLAG_CONFIG) && sys_peer != 0) { /* test 7 */ + if (PKT_TO_STRATUM(pkt->stratum) > sys_stratum) { + peer->flash |= TEST7; /* peer stratum too high */ + sys_badstratum++; + } + } + if (fabs(p_del) >= MAXDISPERSE /* test 8 */ + || p_disp >= MAXDISPERSE) + peer->flash |= TEST8; /* delay/dispersion too high */ + + /* + * If the packet header is invalid (tests 5 through 10), exit. + * XXX we let TEST9 sneak by until the certificate code is + * implemented, but only to mobilize the association. + */ + if (peer->flash & (TEST5 | TEST6 | TEST7 | TEST8 | TEST10)) { +#ifdef DEBUG + if (debug) + printf( + "invalid packet header 0x%02x mode %d\n", + peer->flash, pmode); +#endif + return (0); + } + + /* + * Valid header; update our state. + */ + record_raw_stats(&peer->srcadr, &peer->dstadr->sin, + &p_org, &p_rec, &p_xmt, &peer->rec); + + peer->leap = PKT_LEAP(pkt->li_vn_mode); + peer->pmode = pmode; /* unspec */ + peer->stratum = PKT_TO_STRATUM(pkt->stratum); + peer->precision = pkt->precision; + peer->rootdelay = p_del; + peer->rootdispersion = p_disp; + peer->refid = pkt->refid; + peer->reftime = p_reftime; + if (peer->reach == 0) { + report_event(EVNT_REACH, peer); + peer->timereachable = current_time; + } + peer->reach |= 1; + poll_update(peer, peer->hpoll); + + /* + * If running in a client/server association, calculate the + * clock offset c, roundtrip delay d and dispersion e. We use + * the equations (reordered from those in the spec). Note that, + * in a broadcast association, org has been set to the time of + * last reception. Note the computation of dispersion includes + * the system precision plus that due to the frequency error + * since the originate time. + * + * c = ((t2 - t3) + (t1 - t0)) / 2 + * d = (t2 - t3) - (t1 - t0) + * e = (org - rec) (seconds only) + */ + t10 = p_xmt; /* compute t1 - t0 */ + L_SUB(&t10, &peer->rec); + t23 = p_rec; /* compute t2 - t3 */ + L_SUB(&t23, &p_org); + ci = t10; + p_disp = CLOCK_PHI * (peer->rec.l_ui - p_org.l_ui); + + /* + * If running in a broadcast association, the clock offset is (t1 + * - t0) corrected by the one-way delay, but we can't measure + * that directly; therefore, we start up in client/server mode, + * calculate the clock offset, using the engineered refinement + * algorithms, while also receiving broadcasts. When a broadcast + * is received in client/server mode, we calculate a correction + * factor to use after switching back to broadcast mode. We know + * NTP_SKEWFACTOR == 16, which accounts for the simplified ei + * calculation. + * + * If FLAG_MCAST2 is set, we are a broadcast/multicast client. + * If FLAG_MCAST1 is set, we haven't calculated the propagation + * delay. If hmode is MODE_CLIENT, we haven't set the local + * clock in client/server mode. Initially, we come up + * MODE_CLIENT. When the clock is first updated and FLAG_MCAST2 + * is set, we switch from MODE_CLIENT to MODE_BCLIENT. + */ + if (pmode == MODE_BROADCAST) { + if (peer->flags & FLAG_MCAST1) { + if (peer->hmode == MODE_BCLIENT) + peer->flags &= ~FLAG_MCAST1; + LFPTOD(&ci, p_offset); + peer->estbdelay = peer->offset - p_offset; + return (1); + + } + DTOLFP(peer->estbdelay, &t10); + L_ADD(&ci, &t10); + p_del = peer->delay; + } else { + L_ADD(&ci, &t23); + L_RSHIFT(&ci); + L_SUB(&t23, &t10); + LFPTOD(&t23, p_del); + } + LFPTOD(&ci, p_offset); + if (fabs(p_del) >= MAXDISPERSE || p_disp >= MAXDISPERSE) /* test 4 */ + peer->flash |= TEST4; /* delay/dispersion too big */ + + /* + * If the packet data are invalid (tests 1 through 4), exit. + */ + if (peer->flash) { +#ifdef DEBUG + if (debug) + printf("invalid packet data 0x%02x mode %d\n", + peer->flash, pmode); +#endif + return(1); + } + + + /* + * This one is valid. Mark it so, give it to clock_filter(). + */ + clock_filter(peer, p_offset, p_del, fabs(p_disp)); + clock_select(); + record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), + peer->offset, peer->delay, peer->disp, SQRT(peer->variance)); + return(1); +} + + +/* + * clock_update - Called at system process update intervals. + */ +static void +clock_update(void) +{ + u_char oleap; + u_char ostratum; + int i; + struct peer *peer; + + /* + * Reset/adjust the system clock. Do this only if there is a + * system peer and we haven't seen that peer lately. Watch for + * timewarps here. + */ + if (sys_peer == 0) + return; + if (sys_peer->pollsw == FALSE || sys_peer->burst > 0) + return; + sys_peer->pollsw = FALSE; +#ifdef DEBUG + if (debug) + printf("clock_update: at %ld assoc %d \n", current_time, + peer_associations); +#endif + oleap = sys_leap; + ostratum = sys_stratum; + switch (local_clock(sys_peer, sys_offset, sys_epsil)) { + + case -1: + /* + * Clock is too screwed up. Just exit for now. + */ + report_event(EVNT_SYSFAULT, (struct peer *)0); + exit(1); + /*NOTREACHED*/ + + case 1: + /* + * Clock was stepped. Clear filter registers + * of all peers. + */ + for (i = 0; i < HASH_SIZE; i++) { + for (peer = peer_hash[i]; peer != 0; + peer =peer->next) + peer_clear(peer); + } + NLOG(NLOG_SYNCSTATUS) + msyslog(LOG_INFO, "synchronisation lost"); + sys_peer = 0; + sys_stratum = STRATUM_UNSPEC; + report_event(EVNT_CLOCKRESET, (struct peer *)0); + break; + + default: + /* + * Update the system stratum, leap bits, root delay, + * root dispersion, reference ID and reference time. We + * also update select dispersion and max frequency + * error. + */ + sys_stratum = sys_peer->stratum + 1; + if (sys_stratum == 1) + sys_refid = sys_peer->refid; + else + sys_refid = sys_peer->srcadr.sin_addr.s_addr; + sys_reftime = sys_peer->rec; + sys_rootdelay = sys_peer->rootdelay + fabs(sys_peer->delay); + sys_leap = leap_consensus; + } + if (oleap != sys_leap) + report_event(EVNT_SYNCCHG, (struct peer *)0); + if (ostratum != sys_stratum) + report_event(EVNT_PEERSTCHG, (struct peer *)0); +} + + +/* + * poll_update - update peer poll interval. See Section 3.4.9 of the + * spec. + */ +void +poll_update( + struct peer *peer, + int hpoll + ) +{ + long update; + + /* + * The wiggle-the-poll-interval dance. Broadcasters dance only + * the minpoll beat. Reference clock partners sit this one out. + * Dancers surviving the clustering algorithm beat to the system + * clock. Broadcast clients are usually lead by their broadcast + * partner, but faster in the initial mating dance. + */ + if (peer->hmode == MODE_BROADCAST) { + peer->hpoll = peer->minpoll; + } else if (peer->flags & FLAG_SYSPEER) { + peer->hpoll = sys_poll; + } else { + if (hpoll > peer->maxpoll) + peer->hpoll = peer->maxpoll; + else if (hpoll < peer->minpoll) + peer->hpoll = peer->minpoll; + else + peer->hpoll = hpoll; + } + if (peer->burst > 0) { + if (peer->nextdate != current_time) + return; + if (peer->flags & FLAG_REFCLOCK) + peer->nextdate++; + else if (peer->reach & 0x1) + peer->nextdate += RANDPOLL(BURST_INTERVAL2); + else + peer->nextdate += RANDPOLL(BURST_INTERVAL1); + } else { + update = max(min(peer->ppoll, peer->hpoll), peer->minpoll); + peer->nextdate = peer->outdate + RANDPOLL(update); + } +#ifdef DEBUG + if (debug > 1) + printf("poll_update: at %lu %s poll %d burst %d last %lu next %lu\n", + current_time, ntoa(&peer->srcadr), hpoll, peer->burst, + peer->outdate, peer->nextdate); +#endif +} + + +/* + * clear - clear peer filter registers. See Section 3.4.8 of the spec. + */ +void +peer_clear( + register struct peer *peer + ) +{ + register int i; + + memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO); + peer->estbdelay = sys_bdelay; + peer->hpoll = peer->minpoll; + peer->pollsw = FALSE; + peer->variance = MAXDISPERSE; + peer->epoch = current_time; + for (i = 0; i < NTP_SHIFT; i++) { + peer->filter_order[i] = i; + peer->filter_disp[i] = MAXDISPERSE; + peer->filter_epoch[i] = current_time; + } + poll_update(peer, peer->minpoll); + + /* + * Since we have a chance to correct possible funniness in + * our selection of interfaces on a multihomed host, do so + * by setting us to no particular interface. + * WARNING: do so only in non-broadcast mode! + */ + if (peer->hmode != MODE_BROADCAST) + 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( + register struct peer *peer, + double sample_offset, + double sample_delay, + double sample_disp + ) +{ + register int i, j, k, n = 0; + register u_char *ord; + double distance[NTP_SHIFT]; + double x, y, z, off; + + /* + * Update error bounds and calculate distances. Also initialize + * sort index vector. + */ + x = CLOCK_PHI * (current_time - peer->update); + peer->update = current_time; + ord = peer->filter_order; + j = peer->filter_nextpt; + for (i = 0; i < NTP_SHIFT; i++) { + peer->filter_disp[j] += x; + if (peer->filter_disp[j] > MAXDISPERSE) + peer->filter_disp[j] = MAXDISPERSE; + distance[i] = fabs(peer->filter_delay[j]) / 2 + + peer->filter_disp[j]; + ord[i] = j; + if (--j < 0) + j += NTP_SHIFT; + } + + /* + * Insert the new sample at the beginning of the register. + */ + peer->filter_offset[peer->filter_nextpt] = sample_offset; + peer->filter_delay[peer->filter_nextpt] = sample_delay; + x = LOGTOD(peer->precision) + LOGTOD(sys_precision) + sample_disp; + peer->filter_disp[peer->filter_nextpt] = min(x, MAXDISPERSE); + peer->filter_epoch[peer->filter_nextpt] = current_time; + distance[0] = min(x + fabs(sample_delay) / 2, MAXDISTANCE); + peer->filter_nextpt++; + if (peer->filter_nextpt >= NTP_SHIFT) + peer->filter_nextpt = 0; + + /* + * Sort the samples in the register by distance. The winning + * sample will be in ord[0]. Sort the samples only if they + * are younger than the Allen intercept. + */ + y = min(allan_xpt, NTP_SHIFT * ULOGTOD(sys_poll)); + for (n = 0; n < NTP_SHIFT && current_time - + peer->filter_epoch[ord[n]] <= y; n++) { + for (j = 0; j < n; j++) { + if (distance[j] > distance[n]) { + x = distance[j]; + k = ord[j]; + distance[j] = distance[n]; + ord[j] = ord[n]; + distance[n] = x; + ord[n] = k; + } + } + } + + /* + * Compute the error bound and standard error. + */ + x = y = z = off = 0.; + for (i = NTP_SHIFT - 1; i >= 0; i--) { + x = NTP_FWEIGHT * (x + peer->filter_disp[ord[i]]); + if (i < n) { + z += 1. / distance[i]; + off += peer->filter_offset[ord[i]] / distance[i]; + y += DIFF(peer->filter_offset[ord[i]], + peer->filter_offset[ord[0]]); + } + } + peer->delay = peer->filter_delay[ord[0]]; + peer->variance = min(y / n, MAXDISPERSE); + peer->disp = min(x, MAXDISPERSE); + peer->epoch = current_time; + x = peer->offset; + if (peer->flags & FLAG_BURST) + peer->offset = off / z; + else + peer->offset = peer->filter_offset[ord[0]]; + + /* + * A new sample is useful only if it is younger than the last + * one used. + */ + if (peer->filter_epoch[ord[0]] > peer->epoch) { +#ifdef DEBUG + if (debug) + printf("clock_filter: discard %lu\n", + peer->filter_epoch[ord[0]] - peer->epoch); +#endif + return; + } + + /* + * If the offset exceeds the dispersion by CLOCK_SGATE and the + * interval since the last update is less than twice the system + * poll interval, consider the update a popcorn spike and ignore + * it. + */ + if (fabs(x - peer->offset) > CLOCK_SGATE && + peer->filter_epoch[ord[0]] - peer->epoch < (1 << + (sys_poll + 1))) { +#ifdef DEBUG + if (debug) + printf("clock_filter: popcorn spike %.6f\n", x); +#endif + return; + } + peer->epoch = peer->filter_epoch[ord[0]]; + peer->pollsw = TRUE; +#ifdef DEBUG + if (debug) + printf( + "clock_filter: offset %.6f delay %.6f disp %.6f std %.6f, age %lu\n", + peer->offset, peer->delay, peer->disp, + SQRT(peer->variance), current_time - peer->epoch); +#endif +} + + +/* + * clock_select - find the pick-of-the-litter clock + */ +void +clock_select(void) +{ + register struct peer *peer; + int i; + int nlist, nl3; + double d, e, f; + int j; + int n; + int allow, found, k; + double high, low; + double synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK]; + struct peer *osys_peer; + struct peer *typeacts = 0; + struct peer *typelocal = 0; + struct peer *typepps = 0; + struct peer *typeprefer = 0; + struct peer *typesystem = 0; + + static int list_alloc = 0; + static struct endpoint *endpoint = NULL; + static int *index = NULL; + static struct peer **peer_list = NULL; + static u_int endpoint_size = 0; + static u_int index_size = 0; + static u_int peer_list_size = 0; + + /* + * Initialize. If a prefer peer does not survive this thing, + * the pps_update switch will remain zero. + */ + pps_update = 0; + nlist = 0; + low = 1e9; + high = -1e9; + 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 peers which are most likely + * to succeed. We run through the list doing the sanity checks + * and trying to insert anyone who looks okay. + */ + nlist = nl3 = 0; /* none yet */ + for (n = 0; n < HASH_SIZE; n++) { + for (peer = peer_hash[n]; peer != 0; peer = peer->next) { + peer->flags &= ~FLAG_SYSPEER; + peer->status = CTL_PST_SEL_REJECT; + if (peer->flags & FLAG_NOSELECT) + continue; /* noselect (survey only) */ + if (peer->reach == 0) + continue; /* unreachable */ + if (peer->stratum > 1 && peer->refid == + peer->dstadr->sin.sin_addr.s_addr) + continue; /* sync loop */ + if (root_distance(peer) >= MAXDISTANCE + 2 * + CLOCK_PHI * ULOGTOD(sys_poll)) { + peer->seldisptoolarge++; + continue; /* too noisy or broken */ + } + + /* + * Don't allow the local-clock or acts drivers + * in the kitchen at this point, unless the + * prefer peer. Do that later, but only if + * nobody else is around. + */ + if (peer->refclktype == REFCLK_LOCALCLOCK +#if defined(VMS) && defined(VMS_LOCALUNIT) + /* wjm: local unit VMS_LOCALUNIT taken seriously */ + && REFCLOCKUNIT(&peer->srcadr) != VMS_LOCALUNIT +#endif /* VMS && VMS_LOCALUNIT */ + ) { + typelocal = peer; + if (!(peer->flags & FLAG_PREFER)) + continue; /* no local clock */ + } + if (peer->sstclktype == CTL_SST_TS_TELEPHONE) { + typeacts = peer; + if (!(peer->flags & FLAG_PREFER)) + continue; /* no acts */ + } + + /* + * If we get this far, we assume the peer is + * acceptable. + */ + peer->status = CTL_PST_SEL_SANE; + peer_list[nlist++] = peer; + + /* + * Insert each interval endpoint on the sorted + * list. + */ + e = peer->offset; /* Upper end */ + f = root_distance(peer); + e = e + f; + for (i = nl3 - 1; i >= 0; i--) { + if (e >= endpoint[index[i]].val) + break; + index[i + 3] = index[i]; + } + index[i + 3] = nl3; + endpoint[nl3].type = 1; + endpoint[nl3++].val = e; + + e = e - f; /* Center point */ + for ( ; i >= 0; i--) { + if (e >= endpoint[index[i]].val) + break; + index[i + 2] = index[i]; + } + index[i + 2] = nl3; + endpoint[nl3].type = 0; + endpoint[nl3++].val = e; + + e = e - f; /* Lower end */ + for ( ; i >= 0; i--) { + if (e >= endpoint[index[i]].val) + break; + index[i + 1] = index[i]; + } + index[i + 1] = nl3; + endpoint[nl3].type = -1; + endpoint[nl3++].val = e; + } + } +#ifdef DEBUG + if (debug > 1) + for (i = 0; i < nl3; i++) + printf("select: endpoint %2d %.6f\n", + endpoint[index[i]].type, endpoint[index[i]].val); +#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 no survivors remain at this point, check if the acts or + * local clock drivers have been found. If so, nominate one of + * them as the only survivor. Otherwise, give up and declare us + * unsynchronized. + */ + if ((allow << 1) >= nlist) { + if (typeacts != 0) { + typeacts->status = CTL_PST_SEL_SANE; + peer_list[0] = typeacts; + nlist = 1; + } else if (typelocal != 0) { + typelocal->status = CTL_PST_SEL_SANE; + peer_list[0] = typelocal; + nlist = 1; + } else { + if (sys_peer != 0) { + report_event(EVNT_PEERSTCHG, + (struct peer *)0); + NLOG(NLOG_SYNCSTATUS) + msyslog(LOG_INFO, "synchronisation lost"); + } + sys_peer = 0; + return; + } + } +#ifdef DEBUG + if (debug > 1) + printf("select: low %.6f high %.6f\n", low, high); +#endif + + /* + * Clustering algorithm. Process intersection list to discard + * outlyers. Construct candidate list in cluster order + * determined by the sum of peer synchronization distance plus + * scaled stratum. We must find at least one peer. + */ + j = 0; + for (i = 0; i < nlist; i++) { + peer = peer_list[i]; + if (nlist > 1 && (low >= peer->offset || + peer->offset >= high)) + continue; + peer->status = CTL_PST_SEL_CORRECT; + d = root_distance(peer) + peer->stratum * MAXDISPERSE; + 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 > 1) + for (i = 0; i < nlist; i++) + printf("select: %s distance %.6f\n", + ntoa(&peer_list[i]->srcadr), synch[i]); +#endif + + /* + * Now, prune outlyers by root dispersion. Continue as long as + * there are more than NTP_MINCLOCK survivors and the minimum + * select dispersion is greater than the maximum peer + * dispersion. Stop if we are about to discard a prefer peer. + */ + for (i = 0; i < nlist; i++) { + peer = peer_list[i]; + error[i] = peer->variance; + if (i < NTP_CANCLOCK) + peer->status = CTL_PST_SEL_SELCAND; + else + peer->status = CTL_PST_SEL_DISTSYSPEER; + } + while (1) { + sys_maxd = 0; + d = error[0]; + for (k = i = nlist - 1; i >= 0; i--) { + double sdisp = 0; + + for (j = nlist - 1; j > 0; j--) { + sdisp = NTP_SWEIGHT * (sdisp + + DIFF(peer_list[i]->offset, + peer_list[j]->offset)); + } + if (sdisp > sys_maxd) { + sys_maxd = sdisp; + k = i; + } + if (error[i] < d) + d = error[i]; + } + +#ifdef DEBUG + if (debug > 1) + printf( + "select: survivors %d select %.6f peer %.6f\n", + nlist, SQRT(sys_maxd), SQRT(d)); +#endif + if (nlist <= NTP_MINCLOCK || sys_maxd <= d || + 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: %s offset %.6f, distance %.6f poll %d\n", + ntoa(&peer_list[i]->srcadr), peer_list[i]->offset, + synch[i], peer_list[i]->pollsw); + } +#endif + + /* + * What remains is a list of not greater than NTP_MINCLOCK + * peers. We want only a peer at the lowest stratum to become + * the system peer, although all survivors are eligible for the + * combining algorithm. First record their order, diddle the + * flags and clamp the poll intervals. Then, consider the peers + * at the lowest stratum. Of these, OR the leap bits on the + * assumption that, if some of them honk nonzero bits, they must + * know what they are doing. Also, check for prefer and pps + * peers. If a prefer peer is found within clock_max, update the + * pps switch. Of the other peers not at the lowest stratum, + * check if the system peer is among them and, if found, zap + * him. We note that the head of the list is at the lowest + * stratum and that unsynchronized peers cannot survive this + * far. + */ + leap_consensus = 0; + for (i = nlist - 1; i >= 0; i--) { + peer_list[i]->status = CTL_PST_SEL_SYNCCAND; + peer_list[i]->flags |= FLAG_SYSPEER; + poll_update(peer_list[i], peer_list[i]->hpoll); + if (peer_list[i]->stratum == peer_list[0]->stratum) { + leap_consensus |= peer_list[i]->leap; + if (peer_list[i]->refclktype == REFCLK_ATOM_PPS) + typepps = peer_list[i]; + if (peer_list[i] == sys_peer) + typesystem = peer_list[i]; + if (peer_list[i]->flags & FLAG_PREFER) { + typeprefer = peer_list[i]; + if (fabs(typeprefer->offset) < clock_max) + pps_update = 1; + } + } else { + if (peer_list[i] == sys_peer) + sys_peer = 0; + } + } + + /* + * Mitigation rules of the game. There are several types of + * peers that make a difference here: (1) prefer local peers + * (type REFCLK_LOCALCLOCK with FLAG_PREFER) or prefer modem + * peers (type REFCLK_NIST_ATOM etc with FLAG_PREFER), (2) pps peers + * (type REFCLK_ATOM_PPS), (3) remaining prefer peers (flag + * FLAG_PREFER), (4) the existing system peer, if any, (5) the + * head of the survivor list. Note that only one peer can be + * declared prefer. The order of preference is in the order + * stated. Note that all of these must be at the lowest stratum, + * i.e., the stratum of the head of the survivor list. + */ + osys_peer = sys_peer; + if (typeprefer && (typeprefer->refclktype == REFCLK_LOCALCLOCK || + typeprefer->sstclktype == CTL_SST_TS_TELEPHONE || !typepps)) { + sys_peer = typeprefer; + sys_peer->status = CTL_PST_SEL_SYSPEER; + sys_offset = sys_peer->offset; + sys_epsil = sys_peer->variance; +#ifdef DEBUG + if (debug > 1) + printf("select: prefer offset %.6f\n", sys_offset); +#endif + } else if (typepps && pps_update) { + sys_peer = typepps; + sys_peer->status = CTL_PST_SEL_PPS; + sys_offset = sys_peer->offset; + sys_epsil = sys_peer->variance; + if (!pps_control) + NLOG(NLOG_SYSEVENT) /* conditional syslog */ + msyslog(LOG_INFO, "pps sync enabled"); + pps_control = current_time; +#ifdef DEBUG + if (debug > 1) + printf("select: pps offset %.6f\n", sys_offset); +#endif + } else { + if (!typesystem) + sys_peer = peer_list[0]; + sys_peer->status = CTL_PST_SEL_SYSPEER; + sys_offset = clock_combine(peer_list, nlist); + sys_epsil = sys_peer->variance + sys_maxd; +#ifdef DEBUG + if (debug > 1) + printf("select: combine offset %.6f\n", + sys_offset); +#endif + } + if (osys_peer != sys_peer) + report_event(EVNT_PEERSTCHG, (struct peer *)0); + clock_update(); +} + +/* + * clock_combine - combine offsets from selected peers + */ +static double +clock_combine( + struct peer **peers, + int npeers + ) +{ + int i; + double x, y, z; + y = z = 0; + for (i = 0; i < npeers; i++) { + x = root_distance(peers[i]); + y += 1. / x; + z += peers[i]->offset / x; + } + return (z / y); +} + +/* + * root_distance - compute synchronization distance from peer to root + */ +static double +root_distance( + struct peer *peer + ) +{ + return ((fabs(peer->delay) + peer->rootdelay) / 2 + + peer->rootdispersion + peer->disp + + SQRT(peer->variance) + CLOCK_PHI * (current_time - + peer->update)); +} + +/* + * peer_xmit - send packet for persistent association. + */ +static void +peer_xmit( + struct peer *peer /* peer structure pointer */ + ) +{ + struct pkt xpkt; + int find_rtt = (peer->cast_flags & MDF_MCAST) && + peer->hmode != MODE_BROADCAST; + int sendlen; + + /* + * Initialize protocol fields. + */ + xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, + peer->version, peer->hmode); + xpkt.stratum = STRATUM_TO_PKT(sys_stratum); + xpkt.ppoll = peer->hpoll; + xpkt.precision = sys_precision; + xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); + xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion + + LOGTOD(sys_precision))); + xpkt.refid = sys_refid; + HTONL_FP(&sys_reftime, &xpkt.reftime); + HTONL_FP(&peer->org, &xpkt.org); + HTONL_FP(&peer->rec, &xpkt.rec); + + /* + * Authenticate the packet if enabled and either configured or + * the previous packet was authenticated. If for some reason the + * key associated with the key identifier is not in the key + * cache, then honk key zero. + */ + sendlen = LEN_PKT_NOMAC; + if (peer->flags & FLAG_AUTHENABLE) { + u_long xkeyid; + l_fp xmt_tx; + + /* + * Transmit encrypted packet compensated for the + * encryption delay. + */ +#ifdef MD5 + if (peer->flags & FLAG_SKEY) { + + /* + * In SKEY mode, allocate and initialize a key list if + * not already done. Then, use the list in inverse + * order, discarding keys once used. Keep the latest + * key around until the next one, so clients can use + * client/server packets to compute propagation delay. + * Note we have to wait until the receive side of the + * socket is bound and the server address confirmed. + */ + if (ntohl(peer->dstadr->sin.sin_addr.s_addr) == 0 && + ntohl(peer->dstadr->bcast.sin_addr.s_addr) == 0) + peer->keyid = 0; + else { + if (peer->keylist == 0) { + make_keylist(peer); + } else { + authtrust(peer->keylist[peer->keynumber], 0); + if (peer->keynumber == 0) + make_keylist(peer); + else { + peer->keynumber--; + xkeyid = peer->keylist[peer->keynumber]; + if (!authistrusted(xkeyid)) + make_keylist(peer); + } + } + peer->keyid = peer->keylist[peer->keynumber]; + xpkt.keyid1 = htonl(2 * sizeof(u_int32)); + xpkt.keyid2 = htonl(sys_private); + sendlen += 2 * sizeof(u_int32); + } + } +#endif /* MD5 */ + xkeyid = peer->keyid; + get_systime(&peer->xmt); + L_ADD(&peer->xmt, &sys_authdelay); + HTONL_FP(&peer->xmt, &xpkt.xmt); + sendlen += authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen); + get_systime(&xmt_tx); + sendpkt(&peer->srcadr, find_rtt ? any_interface : + peer->dstadr, + ((peer->cast_flags & MDF_MCAST) && !find_rtt) ? + ((peer->cast_flags & MDF_ACAST) ? -7 : peer->ttl) : -7, + &xpkt, sendlen); + + /* + * Calculate the encryption delay. Keep the minimum over + * the latest two samples. + */ + L_SUB(&xmt_tx, &peer->xmt); + L_ADD(&xmt_tx, &sys_authdelay); + sys_authdly[1] = sys_authdly[0]; + sys_authdly[0] = xmt_tx.l_uf; + if (sys_authdly[0] < sys_authdly[1]) + sys_authdelay.l_uf = sys_authdly[0]; + else + sys_authdelay.l_uf = sys_authdly[1]; + peer->sent++; +#ifdef DEBUG + if (debug) + printf( + "transmit: at %ld to %s mode %d keyid %08lx index %d\n", + current_time, ntoa(&peer->srcadr), + peer->hmode, xkeyid, peer->keynumber); +#endif + } else { + /* + * Transmit non-authenticated packet. + */ + get_systime(&(peer->xmt)); + HTONL_FP(&peer->xmt, &xpkt.xmt); + sendpkt(&(peer->srcadr), find_rtt ? any_interface : + peer->dstadr, + ((peer->cast_flags & MDF_MCAST) && !find_rtt) ? + ((peer->cast_flags & MDF_ACAST) ? -7 : peer->ttl) : -8, + &xpkt, sendlen); + peer->sent++; +#ifdef DEBUG + if (debug) + printf("transmit: at %ld to %s mode %d\n", + current_time, ntoa(&peer->srcadr), + peer->hmode); +#endif + } +} + +/* + * fast_xmit - Send packet for nonpersistent association. + */ +static void +fast_xmit( + struct recvbuf *rbufp, /* receive packet pointer */ + int xmode, /* transmit mode */ + u_long xkeyid /* transmit key ID */ + ) +{ + struct pkt xpkt; + struct pkt *rpkt; + int sendlen; + l_fp xmt_ts; + + /* + * Initialize transmit packet header fields in the receive + * buffer provided. We leave some fields intact as received. + */ + rpkt = &rbufp->recv_pkt; + xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, + PKT_VERSION(rpkt->li_vn_mode), xmode); + xpkt.stratum = STRATUM_TO_PKT(sys_stratum); + xpkt.ppoll = rpkt->ppoll; + xpkt.precision = sys_precision; + xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); + xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion + + LOGTOD(sys_precision))); + xpkt.refid = sys_refid; + HTONL_FP(&sys_reftime, &xpkt.reftime); + xpkt.org = rpkt->xmt; + HTONL_FP(&rbufp->recv_time, &xpkt.rec); + sendlen = LEN_PKT_NOMAC; + if (rbufp->recv_length > sendlen) { + l_fp xmt_tx; + + /* + * Transmit encrypted packet compensated for the + * encryption delay. + */ + if (xkeyid > NTP_MAXKEY) { + xpkt.keyid1 = htonl(2 * sizeof(u_int32)); + xpkt.keyid2 = htonl(sys_private); + sendlen += 2 * sizeof(u_int32); + } + get_systime(&xmt_ts); + L_ADD(&xmt_ts, &sys_authdelay); + HTONL_FP(&xmt_ts, &xpkt.xmt); + sendlen += authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen); + get_systime(&xmt_tx); + sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, -9, &xpkt, + sendlen); + + /* + * Calculate the encryption delay. Keep the minimum over + * the latest two samples. + */ + L_SUB(&xmt_tx, &xmt_ts); + L_ADD(&xmt_tx, &sys_authdelay); + sys_authdly[1] = sys_authdly[0]; + sys_authdly[0] = xmt_tx.l_uf; + if (sys_authdly[0] < sys_authdly[1]) + sys_authdelay.l_uf = sys_authdly[0]; + else + sys_authdelay.l_uf = sys_authdly[1]; +#ifdef DEBUG + if (debug) + printf( + "transmit: at %ld to %s mode %d keyid %08lx\n", + current_time, ntoa(&rbufp->recv_srcadr), + xmode, xkeyid); +#endif + } else { + + /* + * Transmit non-authenticated packet. + */ + get_systime(&xmt_ts); + HTONL_FP(&xmt_ts, &xpkt.xmt); + sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, -10, &xpkt, + sendlen); +#ifdef DEBUG + if (debug) + printf("transmit: at %ld to %s mode %d\n", + current_time, ntoa(&rbufp->recv_srcadr), + xmode); +#endif + } +} + +#ifdef MD5 +/* + * Compute key list + */ +static void +make_keylist( + struct peer *peer + ) +{ + int i; + u_long keyid; + u_long ltemp; + + /* + * Allocate the key list if necessary. + */ + if (peer->keylist == 0) + peer->keylist = (u_long *)emalloc(sizeof(u_long) * + NTP_MAXSESSION); + + /* + * Generate an initial key ID which is unique and greater than + * NTP_MAXKEY. + */ + while (1) { + keyid = (u_long)RANDOM & 0xffffffff; + if (keyid <= NTP_MAXKEY) + continue; + if (authhavekey(keyid)) + continue; + break; + } + + /* + * Generate up to NTP_MAXSESSION session keys. Stop if the + * next one would not be unique or not a session key ID or if + * it would expire before the next poll. + */ + ltemp = sys_automax; + for (i = 0; i < NTP_MAXSESSION; i++) { + peer->keylist[i] = keyid; + peer->keynumber = i; + keyid = session_key( + ntohl(peer->dstadr->sin.sin_addr.s_addr), + (peer->hmode == MODE_BROADCAST || (peer->flags & + FLAG_MCAST2)) ? + ntohl(peer->dstadr->bcast.sin_addr.s_addr): + ntohl(peer->srcadr.sin_addr.s_addr), + keyid, ltemp); + ltemp -= 1 << peer->hpoll; + if (auth_havekey(keyid) || keyid <= NTP_MAXKEY || + ltemp <= (1 << (peer->hpoll + 1))) + break; + } +} +#endif /* MD5 */ + +/* + * Find the precision of this particular machine + */ +#define DUSECS 1000000 /* us in a s */ +#define HUSECS (1 << 20) /* approx DUSECS for shifting etc */ +#define MINSTEP 5 /* minimum clock increment (us) */ +#define MAXSTEP 20000 /* maximum clock increment (us) */ +#define MINLOOPS 5 /* minimum number of step samples */ + +/* + * This routine calculates the differences between successive calls to + * gettimeofday(). If a difference is less than zero, the us field + * has rolled over to the next second, so we add a second in us. If + * the difference is greater than zero and less than MINSTEP, the + * clock has been advanced by a small amount to avoid standing still. + * If the clock has advanced by a greater amount, then a timer interrupt + * has occurred and this amount represents the precision of the clock. + * In order to guard against spurious values, which could occur if we + * happen to hit a fat interrupt, we do this for MINLOOPS times and + * keep the minimum value obtained. + */ +int +default_get_precision(void) +{ + struct timeval tp; +#if !defined(SYS_WINNT) && !defined(VMS) && !defined(_SEQUENT_) + struct timezone tzp; +#elif defined(VMS) || defined(_SEQUENT_) + struct timezone { + int tz_minuteswest; + int tz_dsttime; + } tzp; +#endif /* defined(VMS) || defined(_SEQUENT_) */ + long last; + int i; + long diff; + long val; + long usec; +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + u_long freq; + int j; + + /* Try to see if we can find the frequency of of the counter + * which drives our timekeeping + */ + j = sizeof freq; + i = sysctlbyname("kern.timecounter.frequency", + &freq, &j , 0, 0); + if (i) + i = sysctlbyname("machdep.tsc_freq", + &freq, &j , 0, 0); + if (i) + i = sysctlbyname("machdep.i586_freq", + &freq, &j , 0, 0); + if (i) + i = sysctlbyname("machdep.i8254_freq", + &freq, &j , 0, 0); + if (!i) { + for (i = 1; freq ; i--) + freq >>= 1; + return (i); + } +#endif + usec = 0; + val = MAXSTEP; +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tp.tv_sec = ts.tv_sec; + tp.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tp, &tzp); +#endif /* not HAVE_GETCLOCK */ + last = tp.tv_usec; + for (i = 0; i < MINLOOPS && usec < HUSECS;) { +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tp.tv_sec = ts.tv_sec; + tp.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tp, &tzp); +#endif /* not HAVE_GETCLOCK */ + diff = tp.tv_usec - last; + last = tp.tv_usec; + if (diff < 0) + diff += DUSECS; + usec += diff; + if (diff > MINSTEP) { + i++; + if (diff < val) + val = diff; + } + } + NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_INFO, "precision = %ld usec", val); + if (usec >= HUSECS) + val = MINSTEP; /* val <= MINSTEP; fast machine */ + diff = HUSECS; + for (i = 0; diff > val; i--) + diff >>= 1; + return (i); +} + +/* + * init_proto - initialize the protocol module's data + */ +void +init_proto(void) +{ + l_fp dummy; + + /* + * Fill in the sys_* stuff. Default is don't listen to + * broadcasting, 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; + L_CLR(&sys_reftime); + sys_peer = 0; + get_systime(&dummy); + sys_bclient = 0; + sys_bdelay = DEFBROADDELAY; +#if defined(DES) || defined(MD5) + sys_authenticate = 1; +#else + sys_authenticate = 0; +#endif + L_CLR(&sys_authdelay); + sys_authdly[0] = sys_authdly[1] = 0; + sys_stattime = 0; + sys_badstratum = 0; + sys_oldversionpkt = 0; + sys_newversionpkt = 0; + sys_badlength = 0; + sys_unknownversion = 0; + sys_processed = 0; + sys_badauth = 0; + sys_manycastserver = 0; + sys_automax = 1 << NTP_AUTOMAX; + + /* + * Default these to enable + */ + ntp_enable = 1; +#ifndef KERNEL_FLL_BUG + kern_enable = 1; +#endif + msyslog(LOG_DEBUG, "kern_enable is %d", kern_enable); + stats_control = 1; + + /* + * Some system clocks should only be adjusted in 10ms increments. + */ +#if defined RELIANTUNIX_CLOCK + systime_10ms_ticks = 1; /* Reliant UNIX */ +#elif defined SCO5_CLOCK + if (sys_precision >= (s_char)-10) /* pre- SCO OpenServer 5.0.6 */ + systime_10ms_ticks = 1; +#endif + if (systime_10ms_ticks) + msyslog(LOG_INFO, "using 10ms tick adjustments"); +} + + +/* + * proto_config - configure the protocol module + */ +void +proto_config( + int item, + u_long value, + double dvalue + ) +{ + /* + * Figure out what he wants to change, then do it + */ + switch (item) { + case PROTO_KERNEL: + /* + * Turn on/off kernel discipline + */ + kern_enable = (int)value; + break; + + case PROTO_NTP: + /* + * Turn on/off clock discipline + */ + ntp_enable = (int)value; + break; + + case PROTO_MONITOR: + /* + * Turn on/off monitoring + */ + if (value) + mon_start(MON_ON); + else + mon_stop(MON_ON); + break; + + case PROTO_FILEGEN: + /* + * Turn on/off statistics + */ + stats_control = (int)value; + break; + + case PROTO_BROADCLIENT: + /* + * Turn on/off facility to listen to broadcasts + */ + sys_bclient = (int)value; + if (value) + io_setbclient(); + else + io_unsetbclient(); + break; + + case PROTO_MULTICAST_ADD: + /* + * Add muliticast group address + */ + io_multicast_add(value); + break; + + case PROTO_MULTICAST_DEL: + /* + * Delete multicast group address + */ + io_multicast_del(value); + break; + + case PROTO_BROADDELAY: + /* + * Set default broadcast delay + */ + sys_bdelay = dvalue; + break; + + case PROTO_AUTHENTICATE: + /* + * Specify the use of authenticated data + */ + sys_authenticate = (int)value; + break; + + default: + /* + * Log this error + */ + msyslog(LOG_ERR, "proto_config: illegal item %d, value %ld", + item, value); + break; + } +} + + +/* + * proto_clr_stats - clear protocol stat counters + */ +void +proto_clr_stats(void) +{ + sys_badstratum = 0; + sys_oldversionpkt = 0; + sys_newversionpkt = 0; + sys_unknownversion = 0; + sys_badlength = 0; + sys_processed = 0; + sys_badauth = 0; + sys_stattime = current_time; + sys_limitrejected = 0; +} diff --git a/contrib/ntp/ntpd/ntp_refclock.c b/contrib/ntp/ntpd/ntp_refclock.c new file mode 100644 index 000000000000..c7b9166973de --- /dev/null +++ b/contrib/ntp/ntpd/ntp_refclock.c @@ -0,0 +1,1322 @@ +/* + * ntp_refclock - processing support for reference clocks + */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#ifdef HAVE_SYS_IOCTL_H +# include +#endif /* HAVE_SYS_IOCTL_H */ + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +#ifdef REFCLOCK + +#ifdef TTYCLK +# ifdef SCO5_CLOCK +# include +# else +# include +# endif +#endif /* TTYCLK */ + +#ifdef HAVE_PPSCLOCK_H +#include +#endif /* HAVE_PPSCLOCK_H */ + +#ifdef HAVE_PPSAPI +#include +#endif /* HAVE_PPSAPI */ + +/* + * Reference clock support is provided here by maintaining the fiction + * that the clock is actually a peer. As no packets are exchanged with a + * reference clock, however, we replace the transmit, receive and packet + * procedures with separate code to simulate them. Routines + * refclock_transmit() and refclock_receive() maintain the peer + * variables in a state analogous to an actual peer and pass reference + * clock data on through the filters. Routines refclock_peer() and + * refclock_unpeer() are called to initialize and terminate reference + * clock associations. A set of utility routines is included to open + * serial devices, process sample data, edit input lines to extract + * embedded timestamps and to peform various debugging functions. + * + * The main interface used by these routines is the refclockproc + * structure, which contains for most drivers the decimal equivalants of + * the year, day, month, hour, second and millisecond/microsecond + * decoded from the ASCII timecode. Additional information includes the + * receive timestamp, exception report, statistics tallies, etc. In + * addition, there may be a driver-specific unit structure used for + * local control of the device. + * + * The support routines are passed a pointer to the peer structure, + * which is used for all peer-specific processing and contains a pointer + * to the refclockproc structure, which in turn containes a pointer to + * the unit structure, if used. The peer structure is identified by an + * interface address in the dotted quad form 127.127.t.u, where t is the + * clock type and u the unit. Some legacy drivers derive the + * refclockproc structure pointer from the table typeunit[type][unit]. + * This interface is strongly discouraged and may be abandoned in + * future. + * + * The routines include support for the 1-pps signal provided by some + * radios and connected via a level converted described in the gadget + * directory. The signal is captured using a serial port and one of + * three STREAMS modules described in the refclock_atom.c file. For the + * highest precision, the signal is captured using the carrier-detect + * line of a serial port and either the ppsclock or ppsapi streams + * module or some devilish ioctl() folks keep slipping in as a patch. Be + * advised ALL support for other than the duly standardized ppsapi + * interface will eventually be withdrawn. + */ +#define MAXUNIT 4 /* max units */ + +#if defined(PPS) || defined(HAVE_PPSAPI) +int fdpps; /* pps file descriptor */ +#endif /* PPS HAVE_PPSAPI */ + +#define FUDGEFAC .1 /* fudge correction factor */ + +/* + * Type/unit peer index. Used to find the peer structure for control and + * debugging. When all clock drivers have been converted to new style, + * this dissapears. + */ +static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT]; + +/* + * Forward declarations + */ +#ifdef QSORT_USES_VOID_P +static int refclock_cmpl_fp P((const void *, const void *)); +#else +static int refclock_cmpl_fp P((const double *, const double *)); +#endif /* QSORT_USES_VOID_P */ +static int refclock_sample P((struct refclockproc *)); + +#ifdef HAVE_PPSAPI +extern int pps_assert; /* capture edge 1:assert, 0:clear */ +extern int pps_hardpps; /* PPS kernel 1:on, 0:off */ +#endif /* HAVE_PPSAPI */ + +/* + * refclock_report - note the occurance of an event + * + * This routine presently just remembers the report and logs it, but + * does nothing heroic for the trap handler. It tries to be a good + * citizen and bothers the system log only if things change. + */ +void +refclock_report( + struct peer *peer, + int code + ) +{ + struct refclockproc *pp; + + if (!(pp = peer->procptr)) + return; + if (code == CEVNT_BADREPLY) + pp->badformat++; + if (code == CEVNT_BADTIME) + pp->baddata++; + if (code == CEVNT_TIMEOUT) + pp->noreply++; + if (pp->currentstatus != code) { + pp->currentstatus = code; + pp->lastevent = code; + if (code == CEVNT_FAULT) + msyslog(LOG_ERR, + "clock %s event '%s' (0x%02x)", + refnumtoa(peer->srcadr.sin_addr.s_addr), + ceventstr(code), code); + else { + NLOG(NLOG_CLOCKEVENT) + msyslog(LOG_INFO, + "clock %s event '%s' (0x%02x)", + refnumtoa(peer->srcadr.sin_addr.s_addr), + ceventstr(code), code); + } + } +#ifdef DEBUG + if (debug) + printf("clock %s event '%s' (0x%02x)\n", + refnumtoa(peer->srcadr.sin_addr.s_addr), + ceventstr(code), code); +#endif +} + + +/* + * init_refclock - initialize the reference clock drivers + * + * This routine calls each of the drivers in turn to initialize internal + * variables, if necessary. Most drivers have nothing to say at this + * point. + */ +void +init_refclock(void) +{ + int i, j; + + for (i = 0; i < (int)num_refclock_conf; i++) { + if (refclock_conf[i]->clock_init != noentry) + (refclock_conf[i]->clock_init)(); + for (j = 0; j < MAXUNIT; j++) + typeunit[i][j] = 0; + } +} + + +/* + * refclock_newpeer - initialize and start a reference clock + * + * This routine allocates and initializes the interface structure which + * supports a reference clock in the form of an ordinary NTP peer. A + * driver-specific support routine completes the initialization, if + * used. Default peer variables which identify the clock and establish + * its reference ID and stratum are set here. It returns one if success + * and zero if the clock address is invalid or already running, + * insufficient resources are available or the driver declares a bum + * rap. + */ +int +refclock_newpeer( + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + u_char clktype; + int unit; + + /* + * Check for valid clock address. If already running, shut it + * down first. + */ + if (!ISREFCLOCKADR(&peer->srcadr)) { + msyslog(LOG_ERR, + "refclock_newpeer: clock address %s invalid", + ntoa(&peer->srcadr)); + return (0); + } + clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); + unit = REFCLOCKUNIT(&peer->srcadr); + if (clktype >= num_refclock_conf || unit >= MAXUNIT || + refclock_conf[clktype]->clock_start == noentry) { + msyslog(LOG_ERR, + "refclock_newpeer: clock type %d invalid\n", + clktype); + return (0); + } + refclock_unpeer(peer); + + /* + * Allocate and initialize interface structure + */ + if (!(pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc)))) + return (0); + memset((char *)pp, 0, sizeof(struct refclockproc)); + typeunit[clktype][unit] = peer; + peer->procptr = pp; + + /* + * Initialize structures + */ + peer->refclktype = clktype; + peer->refclkunit = unit; + peer->flags |= FLAG_REFCLOCK; + peer->stratum = STRATUM_REFCLOCK; + peer->refid = peer->srcadr.sin_addr.s_addr; + peer->maxpoll = peer->minpoll; + + pp->type = clktype; + pp->timestarted = current_time; + + /* + * If the interface has been set to any_interface, set it to the + * loopback address if we have one. This is so that peers which + * are unreachable are easy to see in the peer display. + */ + if (peer->dstadr == any_interface && loopback_interface != 0) + peer->dstadr = loopback_interface; + + /* + * Set peer.pmode based on the hmode. For appearances only. + */ + switch (peer->hmode) { + + case MODE_ACTIVE: + peer->pmode = MODE_PASSIVE; + break; + + default: + peer->pmode = MODE_SERVER; + break; + } + + /* + * Do driver dependent initialization. The above defaults + * can be wiggled, then finish up for consistency. + */ + if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { + free(pp); + return (0); + } + peer->hpoll = peer->minpoll; + peer->ppoll = peer->maxpoll; + if (peer->stratum <= 1) + peer->refid = pp->refid; + else + peer->refid = peer->srcadr.sin_addr.s_addr; + return (1); +} + + +/* + * refclock_unpeer - shut down a clock + */ +void +refclock_unpeer( + struct peer *peer /* peer structure pointer */ + ) +{ + u_char clktype; + int unit; + + /* + * Wiggle the driver to release its resources, then give back + * the interface structure. + */ + if (!peer->procptr) + return; + clktype = peer->refclktype; + unit = peer->refclkunit; + if (refclock_conf[clktype]->clock_shutdown != noentry) + (refclock_conf[clktype]->clock_shutdown)(unit, peer); + free(peer->procptr); + peer->procptr = 0; +} + + +/* + * refclock_transmit - simulate the transmit procedure + * + * This routine implements the NTP transmit procedure for a reference + * clock. This provides a mechanism to call the driver at the NTP poll + * interval, as well as provides a reachability mechanism to detect a + * broken radio or other madness. + */ +void +refclock_transmit( + struct peer *peer /* peer structure pointer */ + ) +{ + u_char clktype; + int unit; + int hpoll; + u_long next; + + clktype = peer->refclktype; + unit = peer->refclkunit; + peer->sent++; + + /* + * This is a ripoff of the peer transmit routine, but + * specialized for reference clocks. We do a little less + * protocol here and call the driver-specific transmit routine. + */ + hpoll = peer->hpoll; + next = peer->outdate; + if (peer->burst == 0) { + u_char oreach; +#ifdef DEBUG + if (debug) + printf("refclock_transmit: at %ld %s\n", + current_time, ntoa(&(peer->srcadr))); +#endif + + /* + * Update reachability and poll variables like the + * network code. + */ + oreach = peer->reach; + if (oreach & 0x01) + peer->valid++; + if (oreach & 0x80) + peer->valid--; + peer->reach <<= 1; + if (peer->reach == 0) { + if (oreach != 0) { + report_event(EVNT_UNREACH, peer); + peer->timereachable = current_time; + peer_clear(peer); + } + } else { + if ((oreach & 0x03) == 0) { + clock_filter(peer, 0., 0., MAXDISPERSE); + clock_select(); + } + if (peer->valid <= 2) { + hpoll--; + } else if (peer->valid > NTP_SHIFT - 2) + hpoll++; + if (peer->flags & FLAG_BURST) + peer->burst = NSTAGE; + } + next = current_time; + } + get_systime(&peer->xmt); + if (refclock_conf[clktype]->clock_poll != noentry) + (refclock_conf[clktype]->clock_poll)(unit, peer); + peer->outdate = next; + poll_update(peer, hpoll); + if (peer->burst > 0) + peer->burst--; + poll_update(peer, hpoll); +} + + +/* + * Compare two doubles - used with qsort() + */ +#ifdef QSORT_USES_VOID_P +static int +refclock_cmpl_fp( + const void *p1, + const void *p2 + ) +{ + const double *dp1 = (const double *)p1; + const double *dp2 = (const double *)p2; + + if (*dp1 < *dp2) + return (-1); + if (*dp1 > *dp2) + return (1); + return (0); +} +#else +static int +refclock_cmpl_fp( + const double *dp1, + const double *dp2 + ) +{ + if (*dp1 < *dp2) + return (-1); + if (*dp1 > *dp2) + return (1); + return (0); +} +#endif /* QSORT_USES_VOID_P */ + + +/* + * refclock_process_offset - update median filter + * + * This routine uses the given offset and timestamps to construct a new entry in the median filter circular buffer. Samples that overflow the filter are quietly discarded. + */ +void +refclock_process_offset( + struct refclockproc *pp, + l_fp offset, + l_fp lastrec, + double fudge + ) +{ + double doffset; + + pp->lastref = offset; + pp->lastrec = lastrec; + pp->variance = 0; + L_SUB(&offset, &lastrec); + LFPTOD(&offset, doffset); + SAMPLE(doffset + fudge); +} + +/* + * refclock_process - process a sample from the clock + * + * This routine converts the timecode in the form days, hours, minutes, + * seconds and milliseconds/microseconds to internal timestamp format, + * then constructs a new entry in the median filter circular buffer. + * Return success (1) if the data are correct and consistent with the + * converntional calendar. +*/ +int +refclock_process( + struct refclockproc *pp + ) +{ + l_fp offset; + + /* + * Compute the timecode timestamp from the days, hours, minutes, + * seconds and milliseconds/microseconds of the timecode. Use + * clocktime() for the aggregate seconds and the msec/usec for + * the fraction, when present. Note that this code relies on the + * filesystem time for the years and does not use the years of + * the timecode. + */ + if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, + pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) + return (0); + if (pp->usec) { + TVUTOTSF(pp->usec, offset.l_uf); + } else { + MSUTOTSF(pp->msec, offset.l_uf); + } + refclock_process_offset(pp, offset, pp->lastrec, + pp->fudgetime1); + return (1); +} + +/* + * refclock_sample - process a pile of samples from the clock + * + * This routine implements a recursive median filter to suppress spikes + * in the data, as well as determine a performance statistic. It + * calculates the mean offset and mean-square variance. A time + * adjustment fudgetime1 can be added to the final offset to compensate + * for various systematic errors. The routine returns the number of + * samples processed, which could be 0. + */ +static int +refclock_sample( + struct refclockproc *pp + ) +{ + int i, j, k, n; + double offset, disp; + double off[MAXSTAGE]; + + /* + * Copy the raw offsets and sort into ascending order. Don't do + * anything if the buffer is empty. + */ + if (pp->codeproc == pp->coderecv) + return (0); + n = 0; + while (pp->codeproc != pp->coderecv) + off[n++] = pp->filter[pp->codeproc++ % MAXSTAGE]; + if (n > 1) + qsort((char *)off, n, sizeof(double), refclock_cmpl_fp); + + /* + * Reject the furthest from the median of the samples until + * approximately 60 percent of the samples remain. + */ + i = 0; j = n; + k = n - (n * 2) / NSTAGE; + while ((j - i) > k) { + offset = off[(j + i) / 2]; + if (off[j - 1] - offset < offset - off[i]) + i++; /* reject low end */ + else + j--; /* reject high end */ + } + + /* + * Determine the offset and variance. + */ + offset = disp = 0; + for (; i < j; i++) { + offset += off[i]; + disp += SQUARE(off[i]); + } + offset /= k; + pp->offset = offset; + pp->variance += disp / k - SQUARE(offset); +#ifdef DEBUG + if (debug) + printf( + "refclock_sample: n %d offset %.6f disp %.6f std %.6f\n", + n, pp->offset, pp->disp, SQRT(pp->variance)); +#endif + return (n); +} + + +/* + * refclock_receive - simulate the receive and packet procedures + * + * This routine simulates the NTP receive and packet procedures for a + * reference clock. This provides a mechanism in which the ordinary NTP + * filter, selection and combining algorithms can be used to suppress + * misbehaving radios and to mitigate between them when more than one is + * available for backup. + */ +void +refclock_receive( + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + +#ifdef DEBUG + if (debug) + printf("refclock_receive: at %lu %s\n", + current_time, ntoa(&peer->srcadr)); +#endif + + /* + * Do a little sanity dance and update the peer structure. Groom + * the median filter samples and give the data to the clock + * filter. + */ + peer->received++; + pp = peer->procptr; + peer->processed++; + peer->timereceived = current_time; + peer->leap = pp->leap; + if (peer->leap == LEAP_NOTINSYNC) { + refclock_report(peer, CEVNT_FAULT); + return; + } + if (peer->reach == 0) + report_event(EVNT_REACH, peer); + peer->reach |= 1; + peer->reftime = peer->org = pp->lastrec; + peer->rootdispersion = pp->disp + SQRT(pp->variance); + get_systime(&peer->rec); + if (!refclock_sample(pp)) + return; + clock_filter(peer, pp->offset, 0., 0.); + clock_select(); + record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), + peer->offset, peer->delay, CLOCK_PHI * (current_time - + peer->epoch), SQRT(peer->variance)); + if (pps_control && pp->sloppyclockflag & CLK_FLAG1) + pp->fudgetime1 -= pp->offset * FUDGEFAC; +} + +/* + * refclock_gtlin - groom next input line and extract timestamp + * + * This routine processes the timecode received from the clock and + * removes the parity bit and control characters. If a timestamp is + * present in the timecode, as produced by the tty_clk STREAMS module, + * it returns that as the timestamp; otherwise, it returns the buffer + * timestamp. The routine return code is the number of characters in + * the line. + */ +int +refclock_gtlin( + struct recvbuf *rbufp, /* receive buffer pointer */ + char *lineptr, /* current line pointer */ + int bmax, /* remaining characters in line */ + l_fp *tsptr /* pointer to timestamp returned */ + ) +{ + char *dpt, *dpend, *dp; + int i; + l_fp trtmp, tstmp; + char c; +#ifdef TIOCDCDTIMESTAMP + struct timeval dcd_time; +#endif /* TIOCDCDTIMESTAMP */ +#ifdef HAVE_PPSAPI + pps_info_t pi; + struct timespec timeout, *tsp; + double a; +#endif /* HAVE_PPSAPI */ + + /* + * Check for the presence of a timestamp left by the tty_clock + * module and, if present, use that instead of the buffer + * timestamp captured by the I/O routines. We recognize a + * timestamp by noting its value is earlier than the buffer + * timestamp, but not more than one second earlier. + */ + dpt = (char *)&rbufp->recv_space; + dpend = dpt + rbufp->recv_length; + trtmp = rbufp->recv_time; + +#ifdef HAVE_PPSAPI + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + if ((rbufp->fd == fdpps) && + (time_pps_fetch(fdpps, PPS_TSFMT_TSPEC, &pi, &timeout) >= 0)) { + if(pps_assert) + tsp = &pi.assert_timestamp; + else + tsp = &pi.clear_timestamp; + a = tsp->tv_nsec; + a /= 1e9; + tstmp.l_uf = a * 4294967296.0; + tstmp.l_ui = tsp->tv_sec; + tstmp.l_ui += JAN_1970; + L_SUB(&trtmp, &tstmp); + if (trtmp.l_ui == 0) { +#ifdef DEBUG + if (debug > 1) { + printf( + "refclock_gtlin: fd %d time_pps_fetch %s", + fdpps, lfptoa(&tstmp, 6)); + printf(" sigio %s\n", lfptoa(&trtmp, 6)); + } +#endif + trtmp = tstmp; + goto gotit; + } else + trtmp = rbufp->recv_time; + } +#endif /* HAVE_PPSAPI */ +#ifdef TIOCDCDTIMESTAMP + if(ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1) { + TVTOTS(&dcd_time, &tstmp); + tstmp.l_ui += JAN_1970; + L_SUB(&trtmp, &tstmp); + if (trtmp.l_ui == 0) { +#ifdef DEBUG + if (debug > 1) { + printf( + "refclock_gtlin: fd %d DCDTIMESTAMP %s", + rbufp->fd, lfptoa(&tstmp, 6)); + printf(" sigio %s\n", lfptoa(&trtmp, 6)); + } +#endif + trtmp = tstmp; + goto gotit; + } else + trtmp = rbufp->recv_time; + } + else + /* XXX fallback to old method if kernel refuses TIOCDCDTIMESTAMP */ +#endif /* TIOCDCDTIMESTAMP */ + if (dpend >= dpt + 8) { + if (buftvtots(dpend - 8, &tstmp)) { + L_SUB(&trtmp, &tstmp); + if (trtmp.l_ui == 0) { +#ifdef DEBUG + if (debug > 1) { + printf( + "refclock_gtlin: fd %d ldisc %s", + rbufp->fd, lfptoa(&trtmp, 6)); + get_systime(&trtmp); + L_SUB(&trtmp, &tstmp); + printf(" sigio %s\n", lfptoa(&trtmp, 6)); + } +#endif + dpend -= 8; + trtmp = tstmp; + } else + trtmp = rbufp->recv_time; + } + } + +#if defined(HAVE_PPSAPI) || defined(TIOCDCDTIMESTAMP) +gotit: +#endif + /* + * Edit timecode to remove control chars. Don't monkey with the + * line buffer if the input buffer contains no ASCII printing + * characters. + */ + if (dpend - dpt > bmax - 1) + dpend = dpt + bmax - 1; + for (dp = lineptr; dpt < dpend; dpt++) { + c = *dpt & 0x7f; + if (c >= ' ') + *dp++ = c; + } + i = dp - lineptr; + if (i > 0) + *dp = '\0'; +#ifdef DEBUG + if (debug > 1 && i > 0) + printf("refclock_gtlin: fd %d time %s timecode %d %s\n", + rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr); +#endif + *tsptr = trtmp; + return (i); +} + +/* + * The following code does not apply to WINNT & VMS ... + */ +#if !defined SYS_VXWORKS && !defined SYS_WINNT +#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) + +/* + * refclock_open - open serial port for reference clock + * + * This routine opens a serial port for I/O and sets default options. It + * returns the file descriptor if success and zero if failure. + */ +int +refclock_open( + char *dev, /* device name pointer */ + int speed, /* serial port speed (code) */ + int flags /* line discipline flags */ + ) +{ + int fd, i; +#ifdef HAVE_TERMIOS + struct termios ttyb, *ttyp; +#endif /* HAVE_TERMIOS */ +#ifdef HAVE_SYSV_TTYS + struct termio ttyb, *ttyp; +#endif /* HAVE_SYSV_TTYS */ +#ifdef HAVE_BSD_TTYS + struct sgttyb ttyb, *ttyp; +#endif /* HAVE_BSD_TTYS */ +#ifdef TIOCMGET + u_long ltemp; +#endif /* TIOCMGET */ + + /* + * Open serial port and set default options + */ +#ifdef O_NONBLOCK + fd = open(dev, O_RDWR | O_NONBLOCK, 0777); +#else + fd = open(dev, O_RDWR, 0777); +#endif /* O_NONBLOCK */ + if (fd == -1) { + msyslog(LOG_ERR, "refclock_open: %s: %m", dev); + return (0); + } + + /* + * The following sections initialize the serial line port in + * canonical (line-oriented) mode and set the specified line + * speed, 8 bits and no parity. The modem control, break, erase + * and kill functions are normally disabled. There is a + * different section for each terminal interface, as selected at + * compile time. + */ + ttyp = &ttyb; + +#ifdef HAVE_TERMIOS + /* + * POSIX serial line parameters (termios interface) + */ + if (tcgetattr(fd, ttyp) < 0) { + msyslog(LOG_ERR, + "refclock_open: fd %d tcgetattr: %m", fd); + return (0); + } + + /* + * Set canonical mode and local connection; set specified speed, + * 8 bits and no parity; map CR to NL; ignore break. + */ + ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; + ttyp->c_oflag = 0; + ttyp->c_cflag = CS8 | CLOCAL | CREAD; + (void)cfsetispeed(&ttyb, (u_int)speed); + (void)cfsetospeed(&ttyb, (u_int)speed); + ttyp->c_lflag = ICANON; + for (i = 0; i < NCCS; ++i) + { + ttyp->c_cc[i] = '\0'; + } + + /* + * Some special cases + */ + if (flags & LDISC_RAW) { + ttyp->c_iflag = 0; + ttyp->c_lflag = 0; + ttyp->c_cc[VMIN] = 1; + } +#if defined(TIOCMGET) && !defined(SCO5_CLOCK) + /* + * If we have modem control, check to see if modem leads are + * active; if so, set remote connection. This is necessary for + * the kernel pps mods to work. + */ + ltemp = 0; + if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) + msyslog(LOG_ERR, + "refclock_open: fd %d TIOCMGET failed: %m", fd); +#ifdef DEBUG + if (debug) + printf("refclock_open: fd %d modem status 0x%lx\n", + fd, ltemp); +#endif + if (ltemp & TIOCM_DSR) + ttyp->c_cflag &= ~CLOCAL; +#endif /* TIOCMGET */ + if (tcsetattr(fd, TCSANOW, ttyp) < 0) { + msyslog(LOG_ERR, + "refclock_open: fd %d TCSANOW failed: %m", fd); + return (0); + } + if (tcflush(fd, TCIOFLUSH) < 0) { + msyslog(LOG_ERR, + "refclock_open: fd %d TCIOFLUSH failed: %m", fd); + return (0); + } +#endif /* HAVE_TERMIOS */ + +#ifdef HAVE_SYSV_TTYS + + /* + * System V serial line parameters (termio interface) + * + */ + if (ioctl(fd, TCGETA, ttyp) < 0) { + msyslog(LOG_ERR, + "refclock_open: fd %d TCGETA failed: %m", fd); + return (0); + } + + /* + * Set canonical mode and local connection; set specified speed, + * 8 bits and no parity; map CR to NL; ignore break. + */ + ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; + ttyp->c_oflag = 0; + ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD; + ttyp->c_lflag = ICANON; + ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; + + /* + * Some special cases + */ + if (flags & LDISC_RAW) { + ttyp->c_iflag = 0; + ttyp->c_lflag = 0; + } +#ifdef TIOCMGET + /* + * If we have modem control, check to see if modem leads are + * active; if so, set remote connection. This is necessary for + * the kernel pps mods to work. + */ + ltemp = 0; + if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) + msyslog(LOG_ERR, + "refclock_open: fd %d TIOCMGET failed: %m", fd); +#ifdef DEBUG + if (debug) + printf("refclock_open: fd %d modem status %lx\n", + fd, ltemp); +#endif + if (ltemp & TIOCM_DSR) + ttyp->c_cflag &= ~CLOCAL; +#endif /* TIOCMGET */ + if (ioctl(fd, TCSETA, ttyp) < 0) { + msyslog(LOG_ERR, + "refclock_open: fd %d TCSETA failed: %m", fd); + return (0); + } +#endif /* HAVE_SYSV_TTYS */ + +#ifdef HAVE_BSD_TTYS + + /* + * 4.3bsd serial line parameters (sgttyb interface) + */ + if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) { + msyslog(LOG_ERR, + "refclock_open: fd %d TIOCGETP %m", fd); + return (0); + } + ttyp->sg_ispeed = ttyp->sg_ospeed = speed; + ttyp->sg_flags = EVENP | ODDP | CRMOD; + if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { + msyslog(LOG_ERR, + "refclock_open: TIOCSETP failed: %m"); + return (0); + } +#endif /* HAVE_BSD_TTYS */ + if (!refclock_ioctl(fd, flags)) { + (void)close(fd); + msyslog(LOG_ERR, + "refclock_open: fd %d ioctl failed: %m", fd); + return (0); + } + + /* + * If this is the PPS device, so say and initialize the thing. + */ + if (strcmp(dev, pps_device) == 0) + (void)refclock_ioctl(fd, LDISC_PPS); + return (fd); +} +#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ +#endif /* SYS_VXWORKS SYS_WINNT */ + +/* + * refclock_ioctl - set serial port control functions + * + * This routine attempts to hide the internal, system-specific details + * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD + * (sgtty) interfaces with varying degrees of success. The routine sets + * up optional features such as tty_clk, ppsclock and ppsapi, as well as + * their many other variants. The routine returns 1 if success and 0 if + * failure. + */ +int +refclock_ioctl( + int fd, /* file descriptor */ + int flags /* line discipline flags */ + ) +{ + /* simply return 1 if no UNIX line discipline is supported */ +#if !defined SYS_VXWORKS && !defined SYS_WINNT +#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) + +#ifdef TTYCLK +#ifdef HAVE_TERMIOS + struct termios ttyb, *ttyp; +#endif /* HAVE_TERMIOS */ +#ifdef HAVE_SYSV_TTYS + struct termio ttyb, *ttyp; +#endif /* HAVE_SYSV_TTYS */ +#ifdef HAVE_BSD_TTYS + struct sgttyb ttyb, *ttyp; +#endif /* HAVE_BSD_TTYS */ +#endif /* TTYCLK */ + +#ifdef DEBUG + if (debug) + printf("refclock_ioctl: fd %d flags 0x%x\n", fd, flags); +#endif + + /* + * The following sections select optional features, such as + * modem control, PPS capture and so forth. Some require + * specific operating system support in the form of STREAMS + * modules, which can be loaded and unloaded at run time without + * rebooting the kernel. The STREAMS modules require System + * V STREAMS support. The checking frenzy is attenuated here, + * since the device is already open. + * + * Note that the tty_clk and ppsclock modules are optional; if + * configured and unavailable, the dang thing still works, but + * the accuracy improvement using them will not be available. + * The only known implmentations of these moldules are specific + * to SunOS 4.x. Use the ppsclock module ONLY with Sun baseboard + * ttya or ttyb. Using it with the SPIF multipexor crashes the + * kernel. + * + * The preferred way to capture PPS timestamps is using the + * ppsapi interface, which is machine independent. The SunOS 4.x + * and Digital Unix 4.x interfaces use STREAMS modules and + * support both the ppsapi specification and ppsclock + * functionality, but other systems may vary widely. + */ + if (flags == 0) + return (1); +#if !(defined(HAVE_TERMIOS) || defined(HAVE_BSD_TTYS)) + if (flags & (LDISC_CLK | LDISC_PPS | LDISC_ACTS)) { + msyslog(LOG_ERR, + "refclock_ioctl: unsupported terminal interface"); + return (0); + } +#endif /* HAVE_TERMIOS HAVE_BSD_TTYS */ +#ifdef TTYCLK + ttyp = &ttyb; +#endif /* TTYCLK */ + + /* + * The following features may or may not require System V + * STREAMS support, depending on the particular implementation. + */ +#if defined(TTYCLK) + /* + * The TTYCLK option provides timestamping at the driver level. + * It requires the tty_clk streams module and System V STREAMS + * support. If not available, don't complain. + */ + if (flags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) { + int rval = 0; + + if (ioctl(fd, I_PUSH, "clk") < 0) { + msyslog(LOG_NOTICE, + "refclock_ioctl: I_PUSH clk failed: %m"); + } else { + char *str; + + if (flags & LDISC_CLKPPS) + str = "\377"; + else if (flags & LDISC_ACTS) + str = "*"; + else + str = "\n"; +#ifdef CLK_SETSTR + if ((rval = ioctl(fd, CLK_SETSTR, str)) < 0) + msyslog(LOG_ERR, + "refclock_ioctl: CLK_SETSTR failed: %m"); + if (debug) + printf("refclock_ioctl: fd %d CLK_SETSTR %d str %s\n", + fd, rval, str); +#endif + } + } +#endif /* TTYCLK */ + +#if defined(PPS) && !defined(HAVE_PPSAPI) + /* + * The PPS option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires the ppsclock streams module and System V STREAMS + * support. This option has been superseded by the ppsapi + * option and may be withdrawn in future. + */ + if (flags & LDISC_PPS) { + int rval = 0; +#ifdef HAVE_TIOCSPPS /* Solaris */ + int one = 1; +#endif /* HAVE_TIOCSPPS */ + + if (fdpps > 0) { + msyslog(LOG_ERR, + "refclock_ioctl: PPS already configured"); + return (0); + } +#ifdef HAVE_TIOCSPPS /* Solaris */ + if (ioctl(fd, TIOCSPPS, &one) < 0) { + msyslog(LOG_NOTICE, + "refclock_ioctl: TIOCSPPS failed: %m"); + return (0); + } + if (debug) + printf("refclock_ioctl: fd %d TIOCSPPS %d\n", + fd, rval); +#else + if (ioctl(fd, I_PUSH, "ppsclock") < 0) { + msyslog(LOG_NOTICE, + "refclock_ioctl: I_PUSH ppsclock failed: %m"); + return (0); + } + if (debug) + printf("refclock_ioctl: fd %d ppsclock %d\n", + fd, rval); +#endif /* not HAVE_TIOCSPPS */ + fdpps = fd; + } +#endif /* PPS HAVE_PPSAPI */ + +#ifdef HAVE_PPSAPI + /* + * The PPSAPI option provides timestamping at the driver level. + * It uses a 1-pps signal and level converter (gadget box) and + * requires ppsapi compiled into the kernel on non STREAMS + * systems. This is the preferred way to capture PPS timestamps + * and is expected to become an IETF cross-platform standard. + */ + if (flags & (LDISC_PPS | LDISC_CLKPPS)) { + pps_params_t pp; + int mode, temp; + pps_handle_t handle; + + memset((char *)&pp, 0, sizeof(pp)); + if (fdpps > 0) { + msyslog(LOG_ERR, + "refclock_ioctl: ppsapi already configured"); + return (0); + } + if (time_pps_create(fd, &handle) < 0) { + msyslog(LOG_ERR, + "refclock_ioctl: time_pps_create failed: %m"); + return (0); + } + if (time_pps_getcap(handle, &mode) < 0) { + msyslog(LOG_ERR, + "refclock_ioctl: time_pps_getcap failed: %m"); + return (0); + } + pp.mode = mode & PPS_CAPTUREBOTH; + if (time_pps_setparams(handle, &pp) < 0) { + msyslog(LOG_ERR, + "refclock_ioctl: time_pps_setparams failed: %m"); + return (0); + } + if (!pps_hardpps) + temp = 0; + else if (pps_assert) + temp = mode & PPS_CAPTUREASSERT; + else + temp = mode & PPS_CAPTURECLEAR; + if (time_pps_kcbind(handle, PPS_KC_HARDPPS, temp, + PPS_TSFMT_TSPEC) < 0) { + msyslog(LOG_ERR, + "refclock_ioctl: time_pps_kcbind failed: %m"); + return (0); + } + (void)time_pps_getparams(handle, &pp); + fdpps = (int)handle; + if (debug) + printf( + "refclock_ioctl: fd %d ppsapi vers %d mode 0x%x cap 0x%x\n", + fdpps, pp.api_version, pp.mode, mode); + } +#endif /* HAVE_PPSAPI */ +#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ +#endif /* SYS_VXWORKS SYS_WINNT */ + return (1); +} + +/* + * refclock_control - set and/or return clock values + * + * This routine is used mainly for debugging. It returns designated + * values from the interface structure that can be displayed using + * ntpdc and the clockstat command. It can also be used to initialize + * configuration variables, such as fudgetimes, fudgevalues, reference + * ID and stratum. + */ +void +refclock_control( + struct sockaddr_in *srcadr, + struct refclockstat *in, + struct refclockstat *out + ) +{ + struct peer *peer; + struct refclockproc *pp; + u_char clktype; + int unit; + + /* + * Check for valid address and running peer + */ + if (!ISREFCLOCKADR(srcadr)) + return; + clktype = (u_char)REFCLOCKTYPE(srcadr); + unit = REFCLOCKUNIT(srcadr); + if (clktype >= num_refclock_conf || unit >= MAXUNIT) + return; + if (!(peer = typeunit[clktype][unit])) + return; + pp = peer->procptr; + + /* + * Initialize requested data + */ + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + pp->fudgetime1 = in->fudgetime1; + if (in->haveflags & CLK_HAVETIME2) + pp->fudgetime2 = in->fudgetime2; + if (in->haveflags & CLK_HAVEVAL1) + peer->stratum = (u_char) in->fudgeval1; + if (in->haveflags & CLK_HAVEVAL2) + pp->refid = in->fudgeval2; + if (peer->stratum <= 1) + peer->refid = pp->refid; + else + peer->refid = peer->srcadr.sin_addr.s_addr; + if (in->haveflags & CLK_HAVEFLAG1) { + pp->sloppyclockflag &= ~CLK_FLAG1; + pp->sloppyclockflag |= in->flags & CLK_FLAG1; + } + if (in->haveflags & CLK_HAVEFLAG2) { + pp->sloppyclockflag &= ~CLK_FLAG2; + pp->sloppyclockflag |= in->flags & CLK_FLAG2; + } + if (in->haveflags & CLK_HAVEFLAG3) { + pp->sloppyclockflag &= ~CLK_FLAG3; + pp->sloppyclockflag |= in->flags & CLK_FLAG3; + } + if (in->haveflags & CLK_HAVEFLAG4) { + pp->sloppyclockflag &= ~CLK_FLAG4; + pp->sloppyclockflag |= in->flags & CLK_FLAG4; + } + } + + /* + * Readback requested data + */ + if (out != 0) { + out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 | + CLK_HAVEVAL2 | CLK_HAVEFLAG4; + out->fudgetime1 = pp->fudgetime1; + out->fudgetime2 = pp->fudgetime2; + out->fudgeval1 = peer->stratum; + out->fudgeval2 = pp->refid; + out->flags = (u_char) pp->sloppyclockflag; + + out->timereset = current_time - pp->timestarted; + out->polls = pp->polls; + out->noresponse = pp->noreply; + out->badformat = pp->badformat; + out->baddata = pp->baddata; + + out->lastevent = pp->lastevent; + out->currentstatus = pp->currentstatus; + out->type = pp->type; + out->clockdesc = pp->clockdesc; + out->lencode = pp->lencode; + out->p_lastcode = pp->a_lastcode; + } + + /* + * Give the stuff to the clock + */ + if (refclock_conf[clktype]->clock_control != noentry) + (refclock_conf[clktype]->clock_control)(unit, in, out, peer); +} + + +/* + * refclock_buginfo - return debugging info + * + * This routine is used mainly for debugging. It returns designated + * values from the interface structure that can be displayed using + * ntpdc and the clkbug command. + */ +void +refclock_buginfo( + struct sockaddr_in *srcadr, /* clock address */ + struct refclockbug *bug /* output structure */ + ) +{ + struct peer *peer; + struct refclockproc *pp; + u_char clktype; + int unit; + int i; + + /* + * Check for valid address and peer structure + */ + if (!ISREFCLOCKADR(srcadr)) + return; + clktype = (u_char) REFCLOCKTYPE(srcadr); + unit = REFCLOCKUNIT(srcadr); + if (clktype >= num_refclock_conf || unit >= MAXUNIT) + return; + if (!(peer = typeunit[clktype][unit])) + return; + pp = peer->procptr; + + /* + * Copy structure values + */ + bug->nvalues = 8; + bug->svalues = 0x0000003f; + bug->values[0] = pp->year; + bug->values[1] = pp->day; + bug->values[2] = pp->hour; + bug->values[3] = pp->minute; + bug->values[4] = pp->second; + bug->values[5] = pp->msec; + bug->values[6] = pp->yearstart; + bug->values[7] = pp->coderecv; + bug->stimes = 0xfffffffc; + bug->times[0] = pp->lastref; + bug->times[1] = pp->lastrec; + for (i = 2; i < (int)bug->ntimes; i++) + DTOLFP(pp->filter[i - 2], &bug->times[i]); + + /* + * Give the stuff to the clock + */ + if (refclock_conf[clktype]->clock_buginfo != noentry) + (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); +} + +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/ntp_request.c b/contrib/ntp/ntpd/ntp_request.c new file mode 100644 index 000000000000..3743118f3eb8 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_request.c @@ -0,0 +1,2334 @@ +/* + * ntp_request.c - respond to information requests + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_request.h" +#include "ntp_control.h" +#include "ntp_refclock.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" +#include "recvbuff.h" + +#ifdef KERNEL_PLL +#include "ntp_syscall.h" +#endif /* KERNEL_PLL */ + +/* + * Structure to hold request procedure information + */ +#define NOAUTH 0 +#define AUTH 1 + +#define NO_REQUEST (-1) + +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) P((struct sockaddr_in *, struct interface *, + struct req_pkt *)); /* routine to handle request */ +}; + +/* + * Universal request codes + */ +static struct req_proc univ_codes[] = { + { NO_REQUEST, NOAUTH, 0, 0 } +}; + +static void req_ack P((struct sockaddr_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 *, u_long)); +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_0 P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +static void mon_getlist_1 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 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 *)); +#ifdef KERNEL_PLL +static void get_kernel_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +#endif /* KERNEL_PLL */ +#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 */ +#ifdef REFCLOCK +static void get_clkbug_info P((struct sockaddr_in *, struct interface *, struct req_pkt *)); +#endif /* REFCLOCK */ + +/* + * ntpd request codes + */ +static struct req_proc ntp_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_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_0 }, + { REQ_MON_GETLIST_1, NOAUTH, 0, mon_getlist_1 }, + { 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_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 }, +#ifdef KERNEL_PLL + { REQ_GET_KERNEL, NOAUTH, 0, get_kernel_info }, +#endif +#ifdef REFCLOCK + { REQ_GET_CLOCKINFO, NOAUTH, sizeof(u_int32), get_clock_info }, + { REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge), set_clock_fudge }, + { REQ_GET_CLKBUGINFO, NOAUTH, sizeof(u_int32), 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 */ + +/* + * A hack. To keep the authentication module clear of ntp-ism's, we + * include a time reset variable for its stats here. + */ +static u_long auth_timereset; + +/* + * Response packet used by these routines. Also some state information + * so that we can handle packet formatting within a common set of + * subroutines. Note we try to enter data in place whenever possible, + * but the need to set the more bit correctly means we occasionally + * use the extra buffer and copy. + */ +static struct resp_pkt rpkt; +static int reqver; +static int seqno; +static int nitems; +static int itemsize; +static int databytes; +static char exbuf[RESP_DATA_SIZE]; +static int usingexbuf; +static struct sockaddr_in *toaddr; +static struct interface *frominter; + +/* + * init_request - initialize request data + */ +void +init_request (void) +{ + int i; + + numrequests = 0; + numresppkts = 0; + auth_timereset = 0; + info_auth_keyid = 0; /* by default, can't do this */ + + for (i = 0; i < sizeof(errorcounter)/sizeof(errorcounter[0]); i++) + errorcounter[i] = 0; +} + + +/* + * req_ack - acknowledge request with no data + */ +static void +req_ack( + struct sockaddr_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, reqver); + rpkt.auth_seq = AUTH_SEQ(0, 0); + rpkt.implementation = inpkt->implementation; + rpkt.request = inpkt->request; + rpkt.err_nitems = ERR_NITEMS(errcode, 0); + rpkt.mbz_itemsize = MBZ_ITEMSIZE(0); + + /* + * send packet and bump counters + */ + sendpkt(srcadr, inter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE); + errorcounter[errcode]++; +} + + +/* + * prepare_pkt - prepare response packet for transmission, return pointer + * to storage for data item. + */ +static char * +prepare_pkt( + struct sockaddr_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(void) +{ + /* + * If we were using the extra buffer, send the packet. + */ + if (usingexbuf) { +#ifdef DEBUG + if (debug > 2) + printf("request: sending pkt\n"); +#endif + rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT, reqver); + rpkt.auth_seq = AUTH_SEQ(0, seqno); + rpkt.err_nitems = htons((u_short)nitems); + sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt, + RESP_HEADER_SIZE+databytes); + numresppkts++; + + /* + * Copy data out of exbuf into the packet. + */ + memmove(&rpkt.data[0], exbuf, (unsigned)itemsize); + seqno++; + databytes = 0; + nitems = 0; + usingexbuf = 0; + } + + databytes += itemsize; + nitems++; + if (databytes + itemsize <= RESP_DATA_SIZE) { +#ifdef DEBUG + if (debug > 3) + printf("request: giving him more data\n"); +#endif + /* + * More room in packet. Give him the + * next address. + */ + return &rpkt.data[databytes]; + } else { + /* + * No room in packet. Give him the extra + * buffer unless this was the last in the sequence. + */ +#ifdef DEBUG + if (debug > 3) + printf("request: into extra buffer\n"); +#endif + if (seqno == MAXSEQ) + return (char *)0; + else { + usingexbuf = 1; + return exbuf; + } + } +} + + +/* + * flush_pkt - we're done, return remaining information. + */ +static void +flush_pkt(void) +{ +#ifdef DEBUG + if (debug > 2) + printf("request: flushing packet, %d items\n", nitems); +#endif + /* + * Must send the last packet. If nothing in here and nothing + * has been sent, send an error saying no data to be found. + */ + if (seqno == 0 && nitems == 0) + req_ack(toaddr, frominter, (struct req_pkt *)&rpkt, + INFO_ERR_NODATA); + else { + rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver); + rpkt.auth_seq = AUTH_SEQ(0, seqno); + rpkt.err_nitems = htons((u_short)nitems); + sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt, + RESP_HEADER_SIZE+databytes); + numresppkts++; + } +} + + + +/* + * process_private - process private mode (7) packets + */ +void +process_private( + struct recvbuf *rbufp, + int mod_okay + ) +{ + struct req_pkt *inpkt; + struct 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; + } + + reqver = INFO_VERSION(inpkt->rm_vn_mode); + + /* + * Get the appropriate procedure list to search. + */ + if (inpkt->implementation == IMPL_UNIV) + proc = univ_codes; + else if (inpkt->implementation == IMPL_XNTPD) + proc = ntp_codes; + else { + req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL); + return; + } + + + /* + * Search the list for the request codes. If it isn't one + * we know, return an error. + */ + while (proc->request_code != NO_REQUEST) { + if (proc->request_code == (short) inpkt->request) + break; + proc++; + } + if (proc->request_code == NO_REQUEST) { + req_ack(srcadr, inter, inpkt, INFO_ERR_REQ); + return; + } + +#ifdef DEBUG + if (debug > 3) + printf("found request in tables\n"); +#endif + + /* + * If we need to authenticate, do so. Note that an + * authenticatable packet must include a mac field, must + * have used key info_auth_keyid and must have included + * a time stamp in the appropriate field. The time stamp + * must be within INFO_TS_MAXSKEW of the receive + * time stamp. + */ + if (proc->needs_auth && sys_authenticate) { + l_fp ftmp; + double dtemp; + + /* + * If 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 %lu pkt keyid %lu\n", + INFO_IS_AUTH(inpkt->auth_seq), + (u_long)info_auth_keyid, + (u_long)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("bad pkt length %d\n", + rbufp->recv_length); +#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. + */ + NTOHL_FP(&inpkt->tstamp, &ftmp); + L_SUB(&ftmp, &rbufp->recv_time); + LFPTOD(&ftmp, dtemp); + if (fabs(dtemp) >= INFO_TS_MAXSKEW) { + /* + * 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_int32 *)inpkt, + REQ_LEN_NOMAC, (int)(rbufp->recv_length - 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( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + register struct info_peer_list *ip; + register struct peer *pp; + register int i; + + 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->status == CTL_PST_SEL_SYNCCAND) + ip->flags |= INFO_FLAG_SEL_CANDIDATE; + if (pp->status >= CTL_PST_SEL_SYSPEER) + ip->flags |= INFO_FLAG_SHORTLIST; + ip = (struct info_peer_list *)more_pkt(); + pp = pp->next; + } + } + flush_pkt(); +} + + +/* + * peer_list_sum - return extended peer list + */ +static void +peer_list_sum( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + register struct info_peer_summary *ips; + register struct peer *pp; + register int i; + l_fp ltmp; + +#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 + ips->dstadr = (pp->processed) ? + pp->cast_flags == MDF_BCAST ? + pp->dstadr->bcast.sin_addr.s_addr: + pp->cast_flags ? + pp->dstadr->sin.sin_addr.s_addr ? + pp->dstadr->sin.sin_addr.s_addr: + pp->dstadr->bcast.sin_addr.s_addr: + 1 : 5; + ips->srcadr = pp->srcadr.sin_addr.s_addr; + ips->srcport = pp->srcadr.sin_port; + ips->stratum = pp->stratum; + ips->hpoll = pp->hpoll; + ips->ppoll = pp->ppoll; + ips->reach = pp->reach; + ips->flags = 0; + if (pp == sys_peer) + ips->flags |= INFO_FLAG_SYSPEER; + if (pp->flags & FLAG_CONFIG) + ips->flags |= INFO_FLAG_CONFIG; + if (pp->flags & FLAG_REFCLOCK) + ips->flags |= INFO_FLAG_REFCLOCK; + if (pp->flags & FLAG_AUTHENABLE) + ips->flags |= INFO_FLAG_AUTHENABLE; + if (pp->flags & FLAG_PREFER) + ips->flags |= INFO_FLAG_PREFER; + if (pp->flags & FLAG_BURST) + ips->flags |= INFO_FLAG_BURST; + if (pp->status == CTL_PST_SEL_SYNCCAND) + ips->flags |= INFO_FLAG_SEL_CANDIDATE; + if (pp->status >= CTL_PST_SEL_SYSPEER) + ips->flags |= INFO_FLAG_SHORTLIST; + ips->hmode = pp->hmode; + ips->delay = HTONS_FP(DTOFP(pp->delay)); + DTOLFP(pp->offset, <mp); + HTONL_FP(<mp, &ips->offset); + ips->dispersion = HTONS_FP(DTOUFP(pp->disp)); + + pp = pp->next; + ips = (struct info_peer_summary *)more_pkt(); + } + } + flush_pkt(); +} + + +/* + * peer_info - send information for one or more peers + */ +static void +peer_info ( + struct sockaddr_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; + l_fp ltmp; + + 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, -1)) == 0) + continue; + ip->dstadr = (pp->processed) ? + pp->cast_flags == MDF_BCAST ? + pp->dstadr->bcast.sin_addr.s_addr: + pp->cast_flags ? + pp->dstadr->sin.sin_addr.s_addr ? + pp->dstadr->sin.sin_addr.s_addr: + pp->dstadr->bcast.sin_addr.s_addr: + 2 : 6; + ip->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->flags & FLAG_BURST) + ip->flags |= INFO_FLAG_BURST; + if (pp->status == CTL_PST_SEL_SYNCCAND) + ip->flags |= INFO_FLAG_SEL_CANDIDATE; + if (pp->status >= CTL_PST_SEL_SYSPEER) + ip->flags |= INFO_FLAG_SHORTLIST; + ip->leap = pp->leap; + ip->hmode = pp->hmode; + ip->keyid = pp->keyid; + ip->stratum = pp->stratum; + ip->ppoll = pp->ppoll; + ip->hpoll = pp->hpoll; + ip->precision = pp->precision; + ip->version = pp->version; + ip->valid = pp->valid; + ip->reach = pp->reach; + ip->unreach = pp->unreach; + ip->flash = (u_char)pp->flash; + ip->flash2 = pp->flash; + ip->estbdelay = HTONS_FP(DTOFP(pp->estbdelay)); + ip->ttl = pp->ttl; + ip->associd = htons(pp->associd); + ip->rootdelay = HTONS_FP(DTOUFP(pp->rootdelay)); + ip->rootdispersion = HTONS_FP(DTOUFP(pp->rootdispersion)); + ip->refid = pp->refid; + HTONL_FP(&pp->reftime, &ip->reftime); + HTONL_FP(&pp->org, &ip->org); + HTONL_FP(&pp->rec, &ip->rec); + HTONL_FP(&pp->xmt, &ip->xmt); + j = pp->filter_nextpt - 1; + for (i = 0; i < NTP_SHIFT; i++, j--) { + if (j < 0) + j = NTP_SHIFT-1; + ip->filtdelay[i] = HTONS_FP(DTOFP(pp->filter_delay[j])); + DTOLFP(pp->filter_offset[j], <mp); + HTONL_FP(<mp, &ip->filtoffset[i]); + ip->order[i] = (pp->filter_nextpt+NTP_SHIFT-1) + - pp->filter_order[i]; + if (ip->order[i] >= NTP_SHIFT) + ip->order[i] -= NTP_SHIFT; + } + DTOLFP(pp->offset, <mp); + HTONL_FP(<mp, &ip->offset); + ip->delay = HTONS_FP(DTOFP(pp->delay)); + ip->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp))); + ip->selectdisp = HTONS_FP(DTOUFP(SQRT(pp->variance))); + ip = (struct info_peer *)more_pkt(); + } + flush_pkt(); +} + + +/* + * peer_stats - send statistics for one or more peers + */ +static void +peer_stats ( + 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, -1)) == 0) + continue; + ip->dstadr = (pp->processed) ? + pp->cast_flags == MDF_BCAST ? + pp->dstadr->bcast.sin_addr.s_addr: + pp->cast_flags ? + pp->dstadr->sin.sin_addr.s_addr ? + pp->dstadr->sin.sin_addr.s_addr: + pp->dstadr->bcast.sin_addr.s_addr: + 3 : 7; + ip->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->flags & FLAG_BURST) + ip->flags |= INFO_FLAG_BURST; + if (pp->status == CTL_PST_SEL_SYNCCAND) + ip->flags |= INFO_FLAG_SEL_CANDIDATE; + if (pp->status >= CTL_PST_SEL_SYSPEER) + ip->flags |= INFO_FLAG_SHORTLIST; + ip->timereceived = htonl((u_int32)(current_time - pp->timereceived)); + ip->timetosend = htonl(pp->nextdate - current_time); + ip->timereachable = htonl((u_int32)(current_time - pp->timereachable)); + ip->sent = htonl((u_int32)(pp->sent)); + ip->processed = htonl((u_int32)(pp->processed)); + ip->badauth = htonl((u_int32)(pp->badauth)); + ip->bogusorg = htonl((u_int32)(pp->bogusorg)); + ip->oldpkt = htonl((u_int32)(pp->oldpkt)); + ip->seldisp = htonl((u_int32)(pp->seldisptoolarge)); + ip->selbroken = htonl((u_int32)(pp->selbroken)); + ip->candidate = pp->status; + ip = (struct info_peer_stats *)more_pkt(); + } + flush_pkt(); +} + + +/* + * sys_info - return system info + */ +static void +sys_info( + struct sockaddr_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 double sys_rootdelay; + extern double sys_rootdispersion; + extern u_int32 sys_refid; + extern l_fp sys_reftime; + extern u_char sys_poll; + extern struct peer *sys_peer; + extern int sys_bclient; + extern double sys_bdelay; + extern l_fp sys_authdelay; + extern double clock_stability; + extern double sys_error; + + 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(DTOFP(sys_rootdelay)); + is->rootdispersion = htonl(DTOUFP(sys_rootdispersion)); + is->frequency = htonl(DTOFP(sys_error)); + is->stability = htonl(DTOUFP(clock_stability * 1e6)); + is->refid = sys_refid; + HTONL_FP(&sys_reftime, &is->reftime); + + is->poll = sys_poll; + + is->flags = 0; + if (sys_bclient) + is->flags |= INFO_FLAG_BCLIENT; + if (sys_authenticate) + is->flags |= INFO_FLAG_AUTHENTICATE; + if (kern_enable) + is->flags |= INFO_FLAG_KERNEL; + if (ntp_enable) + is->flags |= INFO_FLAG_NTP; + if (pll_control) + is->flags |= INFO_FLAG_PLL_SYNC; + if (pps_control) + is->flags |= INFO_FLAG_PPS_SYNC; + if (mon_enabled != MON_OFF) + is->flags |= INFO_FLAG_MONITOR; + if (stats_control) + is->flags |= INFO_FLAG_FILEGEN; + is->bdelay = HTONS_FP(DTOFP(sys_bdelay)); + HTONL_UF(sys_authdelay.l_f, &is->authdelay); + + (void) more_pkt(); + flush_pkt(); +} + + +/* + * sys_stats - return system statistics + */ +static void +sys_stats( + struct sockaddr_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_limitrejected; + + ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_sys_stats)); + + ss->timeup = htonl((u_int32)current_time); + ss->timereset = htonl((u_int32)(current_time - sys_stattime)); + ss->badstratum = htonl((u_int32)sys_badstratum); + ss->oldversionpkt = htonl((u_int32)sys_oldversionpkt); + ss->newversionpkt = htonl((u_int32)sys_newversionpkt); + ss->unknownversion = htonl((u_int32)sys_unknownversion); + ss->badlength = htonl((u_int32)sys_badlength); + ss->processed = htonl((u_int32)sys_processed); + ss->badauth = htonl((u_int32)sys_badauth); + ss->limitrejected = htonl((u_int32)sys_limitrejected); + (void) more_pkt(); + flush_pkt(); +} + + +/* + * mem_stats - return memory statistics + */ +static void +mem_stats( + 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((u_int32)(current_time - peer_timereset)); + ms->totalpeermem = htons((u_short)total_peer_structs); + ms->freepeermem = htons((u_short)peer_free_count); + ms->findpeer_calls = htonl((u_int32)findpeer_calls); + ms->allocations = htonl((u_int32)peer_allocations); + ms->demobilizations = htonl((u_int32)peer_demobilizations); + + for (i = 0; i < HASH_SIZE; i++) { + if (peer_hash_count[i] > 255) + ms->hashcount[i] = 255; + else + ms->hashcount[i] = (u_char)peer_hash_count[i]; + } + + (void) more_pkt(); + flush_pkt(); +} + + +/* + * io_stats - return io statistics + */ +static void +io_stats( + struct sockaddr_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; + + io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_io_stats)); + + io->timereset = htonl((u_int32)(current_time - io_timereset)); + io->totalrecvbufs = htons((u_short) total_recvbuffs()); + io->freerecvbufs = htons((u_short) free_recvbuffs()); + io->fullrecvbufs = htons((u_short) full_recvbuffs()); + io->lowwater = htons((u_short) lowater_additions()); + io->dropped = htonl((u_int32)packets_dropped); + io->ignored = htonl((u_int32)packets_ignored); + io->received = htonl((u_int32)packets_received); + io->sent = htonl((u_int32)packets_sent); + io->notsent = htonl((u_int32)packets_notsent); + io->interrupts = htonl((u_int32)handler_calls); + io->int_received = htonl((u_int32)handler_pkts); + + (void) more_pkt(); + flush_pkt(); +} + + +/* + * timer_stats - return timer statistics + */ +static void +timer_stats( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + register struct info_timer_stats *ts; + + /* + * Importations from the timer module + */ + extern u_long timer_timereset; + extern u_long timer_overflows; + extern u_long timer_xmtcalls; + + ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_timer_stats)); + + ts->timereset = htonl((u_int32)(current_time - timer_timereset)); + ts->alarms = htonl((u_int32)alarm_overflow); + ts->overflows = htonl((u_int32)timer_overflows); + ts->xmtcalls = htonl((u_int32)timer_xmtcalls); + + (void) more_pkt(); + flush_pkt(); +} + + +/* + * loop_info - return the current state of the loop filter + */ +static void +loop_info( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + register struct info_loop *li; + l_fp ltmp; + + /* + * Importations from the loop filter module + */ + extern double last_offset; + extern double drift_comp; + extern int tc_counter; + extern u_long last_time; + + li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_loop)); + + DTOLFP(last_offset, <mp); + HTONL_FP(<mp, &li->last_offset); + DTOLFP(drift_comp * 1e6, <mp); + HTONL_FP(<mp, &li->drift_comp); + li->compliance = htonl((u_int32)(tc_counter)); + li->watchdog_timer = htonl((u_int32)(current_time - last_time)); + + (void) more_pkt(); + flush_pkt(); +} + + +/* + * do_conf - add a peer to the configuration list + */ +static void +do_conf( + struct sockaddr_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 + | CONF_FLAG_NOSELECT | CONF_FLAG_BURST | CONF_FLAG_SKEY)) + 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 + */ + if ( +#ifdef REFCLOCK + !ISREFCLOCKADR(&peeraddr) && +#endif + ISBADADR(&peeraddr)) { + 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; + if (cp->flags & CONF_FLAG_NOSELECT) + fl |= FLAG_NOSELECT; + if (cp->flags & CONF_FLAG_BURST) + fl |= FLAG_BURST; + if (cp->flags & CONF_FLAG_SKEY) + fl |= FLAG_SKEY; + peeraddr.sin_addr.s_addr = cp->peeraddr; + /* XXX W2DO? minpoll/maxpoll arguments ??? */ + if (peer_config(&peeraddr, (struct interface *)0, + cp->hmode, cp->version, cp->minpoll, cp->maxpoll, + fl, cp->ttl, cp->keyid) == 0) { + 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( + 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, -1); + 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, -1); + cp++; + } + + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * set_sys_flag - set system flags + */ +static void +set_sys_flag( + 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( + 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( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt, + u_long 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 | + SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR | + SYS_FLAG_FILEGEN)) { + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + if (flags & SYS_FLAG_BCLIENT) + proto_config(PROTO_BROADCLIENT, set, 0.); + if (flags & SYS_FLAG_AUTHENTICATE) + proto_config(PROTO_AUTHENTICATE, set, 0.); + if (flags & SYS_FLAG_NTP) + proto_config(PROTO_NTP, set, 0.); + if (flags & SYS_FLAG_KERNEL) + proto_config(PROTO_KERNEL, set, 0.); + if (flags & SYS_FLAG_MONITOR) + proto_config(PROTO_MONITOR, set, 0.); + if (flags & SYS_FLAG_FILEGEN) + proto_config(PROTO_FILEGEN, set, 0.); + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * list_restrict - return the restrict list + */ +static void +list_restrict( + 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((u_int32)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( + 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( + 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( + 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( + 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 == htonl(INADDR_ANY) && cr->mask != htonl(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; + hack_restrict(op, &matchaddr, &matchmask, cr->mflags, + cr->flags); + cr++; + } + + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * mon_getlist - return monitor data + */ +static void +mon_getlist_0( + struct sockaddr_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 0 list\n"); +#endif + if (!mon_enabled) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + im = (struct info_monitor *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_monitor)); + for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0; + md = md->mru_next) { + im->lasttime = htonl((u_int32)(current_time - md->lasttime)); + im->firsttime = htonl((u_int32)(current_time - md->firsttime)); + if (md->lastdrop) + im->lastdrop = htonl((u_int32)(current_time - md->lastdrop)); + else + im->lastdrop = 0; + im->count = htonl((u_int32)(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(); +} + +/* + * mon_getlist - return monitor data + */ +static void +mon_getlist_1( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + register struct info_monitor_1 *im; + register struct mon_data *md; + extern struct mon_data mon_mru_list; + extern int mon_enabled; + +#ifdef DEBUG + if (debug > 2) + printf("wants monitor 1 list\n"); +#endif + if (!mon_enabled) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + im = (struct info_monitor_1 *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_monitor_1)); + for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0; + md = md->mru_next) { + im->lasttime = htonl((u_int32)(current_time - md->lasttime)); + im->firsttime = htonl((u_int32)(current_time - md->firsttime)); + if (md->lastdrop) + im->lastdrop = htonl((u_int32)(current_time - md->lastdrop)); + else + im->lastdrop = 0; + im->count = htonl((u_int32)md->count); + im->addr = md->rmtadr; + im->daddr = + (md->cast_flags == MDF_BCAST) + ? md->interface->bcast.sin_addr.s_addr + : (md->cast_flags + ? (md->interface->sin.sin_addr.s_addr + ? md->interface->sin.sin_addr.s_addr + : md->interface->bcast.sin_addr.s_addr + ) + : 4); + im->flags = md->cast_flags; + im->port = md->rmtport; + im->mode = md->mode; + im->version = md->version; + im = (struct info_monitor_1 *)more_pkt(); + } + flush_pkt(); +} + +/* + * Module entry points and the flags they correspond with + */ +struct reset_entry { + int flag; /* flag this corresponds to */ + void (*handler) P((void)); /* routine to handle request */ +}; + +struct reset_entry reset_entries[] = { + { RESET_FLAG_ALLPEERS, peer_all_reset }, + { RESET_FLAG_IO, io_clr_stats }, + { RESET_FLAG_SYS, proto_clr_stats }, + { RESET_FLAG_MEM, peer_clr_stats }, + { RESET_FLAG_TIMER, timer_clr_stats }, + { RESET_FLAG_AUTH, reset_auth_stats }, + { RESET_FLAG_CTL, ctl_clr_stats }, + { 0, 0 } +}; + +/* + * reset_stats - reset statistic counters here and there + */ +static void +reset_stats( + struct sockaddr_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( + 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, -1); + 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, -1); + while (peer != 0) { + peer_reset(peer); + peer = findexistingpeer(&peeraddr, (struct peer *)peer, -1); + } + cp++; + } + + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * do_key_reread - reread the encryption key file + */ +static void +do_key_reread( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + rereadkeys(); + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + +/* + * trust_key - make one or more keys trusted + */ +static void +trust_key( + struct sockaddr_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( + 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( + 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( + 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 int authnumfreekeys; + extern u_long authkeylookups; + extern u_long authkeynotfound; + extern u_long authencryptions; + extern u_long authdecryptions; + extern u_long authkeyuncached; + extern u_long authkeyexpired; + + ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_auth)); + + ia->numkeys = htonl((u_int32)authnumkeys); + ia->numfreekeys = htonl((u_int32)authnumfreekeys); + ia->keylookups = htonl((u_int32)authkeylookups); + ia->keynotfound = htonl((u_int32)authkeynotfound); + ia->encryptions = htonl((u_int32)authencryptions); + ia->decryptions = htonl((u_int32)authdecryptions); + ia->keyuncached = htonl((u_int32)authkeyuncached); + ia->expired = htonl((u_int32)authkeyexpired); + ia->timereset = htonl((u_int32)(current_time - auth_timereset)); + + (void) more_pkt(); + flush_pkt(); +} + + + +/* + * reset_auth_stats - reset the authentication stat counters. Done here + * to keep ntp-isms out of the authentication module + */ +static void +reset_auth_stats(void) +{ + /* + * Importations from the authentication module + */ + extern u_long authkeylookups; + extern u_long authkeynotfound; + extern u_long authencryptions; + extern u_long authdecryptions; + extern u_long authkeyuncached; + + authkeylookups = 0; + authkeynotfound = 0; + authencryptions = 0; + authdecryptions = 0; + authkeyuncached = 0; + auth_timereset = current_time; +} + + +/* + * req_get_traps - return information about current trap holders + */ +static void +req_get_traps( + struct sockaddr_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((u_int32)(current_time - tr->tr_settime)); + it->origtime = htonl((u_int32)(current_time - tr->tr_origtime)); + it->resets = htonl((u_int32)tr->tr_resets); + it->flags = htonl((u_int32)tr->tr_flags); + it = (struct info_trap *)more_pkt(); + } + } + flush_pkt(); +} + + +/* + * req_set_trap - configure a trap + */ +static void +req_set_trap( + struct sockaddr_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( + 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( + 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( + 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_int32 *)(inpkt->data))); + info_auth_keyid = keyid; + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + + +/* + * set_control_keyid - set the keyid used to authenticate requests + */ +static void +set_control_keyid( + struct sockaddr_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_int32 *)(inpkt->data))); + ctl_auth_keyid = keyid; + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} + + + +/* + * get_ctl_stats - return some stats concerning the control message module + */ +static void +get_ctl_stats( + struct sockaddr_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((u_int32)(current_time - ctltimereset)); + ic->numctlreq = htonl((u_int32)numctlreq); + ic->numctlbadpkts = htonl((u_int32)numctlbadpkts); + ic->numctlresponses = htonl((u_int32)numctlresponses); + ic->numctlfrags = htonl((u_int32)numctlfrags); + ic->numctlerrors = htonl((u_int32)numctlerrors); + ic->numctltooshort = htonl((u_int32)numctltooshort); + ic->numctlinputresp = htonl((u_int32)numctlinputresp); + ic->numctlinputfrag = htonl((u_int32)numctlinputfrag); + ic->numctlinputerr = htonl((u_int32)numctlinputerr); + ic->numctlbadoffset = htonl((u_int32)numctlbadoffset); + ic->numctlbadversion = htonl((u_int32)numctlbadversion); + ic->numctldatatooshort = htonl((u_int32)numctldatatooshort); + ic->numctlbadop = htonl((u_int32)numctlbadop); + ic->numasyncmsgs = htonl((u_int32)numasyncmsgs); + + (void) more_pkt(); + flush_pkt(); +} + + +#ifdef KERNEL_PLL +/* + * get_kernel_info - get kernel pll/pps information + */ +static void +get_kernel_info( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + register struct info_kernel *ik; + struct timex ntx; + + if (!pll_control) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + memset((char *)&ntx, 0, sizeof(ntx)); + if (ntp_adjtime(&ntx) < 0) + msyslog(LOG_ERR, "get_kernel_info: ntp_adjtime() failed: %m"); + ik = (struct info_kernel *)prepare_pkt(srcadr, inter, inpkt, + sizeof(struct info_kernel)); + + /* + * pll variables + */ + ik->offset = htonl((u_int32)ntx.offset); + ik->freq = htonl((u_int32)ntx.freq); + ik->maxerror = htonl((u_int32)ntx.maxerror); + ik->esterror = htonl((u_int32)ntx.esterror); + ik->status = htons(ntx.status); + ik->constant = htonl((u_int32)ntx.constant); + ik->precision = htonl((u_int32)ntx.precision); + ik->tolerance = htonl((u_int32)ntx.tolerance); + + /* + * pps variables + */ + ik->ppsfreq = htonl((u_int32)ntx.ppsfreq); + ik->jitter = htonl((u_int32)ntx.jitter); + ik->shift = htons(ntx.shift); + ik->stabil = htonl((u_int32)ntx.stabil); + ik->jitcnt = htonl((u_int32)ntx.jitcnt); + ik->calcnt = htonl((u_int32)ntx.calcnt); + ik->errcnt = htonl((u_int32)ntx.errcnt); + ik->stbcnt = htonl((u_int32)ntx.stbcnt); + + (void) more_pkt(); + flush_pkt(); +} +#endif /* KERNEL_PLL */ + + +#ifdef REFCLOCK +/* + * get_clock_info - get info about a clock + */ +static void +get_clock_info( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + register struct info_clock *ic; + register u_int32 *clkaddr; + register int items; + struct refclockstat clock_stat; + struct sockaddr_in addr; + l_fp ltmp; + + 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_int32 *) 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, -1) == 0) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + clock_stat.kv_list = (struct ctl_var *)0; + + refclock_control(&addr, (struct refclockstat *)0, &clock_stat); + + ic->clockadr = addr.sin_addr.s_addr; + ic->type = clock_stat.type; + ic->flags = clock_stat.flags; + ic->lastevent = clock_stat.lastevent; + ic->currentstatus = clock_stat.currentstatus; + ic->polls = htonl((u_int32)clock_stat.polls); + ic->noresponse = htonl((u_int32)clock_stat.noresponse); + ic->badformat = htonl((u_int32)clock_stat.badformat); + ic->baddata = htonl((u_int32)clock_stat.baddata); + ic->timestarted = htonl((u_int32)clock_stat.timereset); + DTOLFP(clock_stat.fudgetime1, <mp); + HTONL_FP(<mp, &ic->fudgetime1); + DTOLFP(clock_stat.fudgetime1, <mp); + HTONL_FP(<mp, &ic->fudgetime2); + ic->fudgeval1 = htonl((u_int32)clock_stat.fudgeval1); + ic->fudgeval2 = htonl((u_int32)clock_stat.fudgeval2); + + free_varlist(clock_stat.kv_list); + + ic = (struct info_clock *)more_pkt(); + } + flush_pkt(); +} + + + +/* + * set_clock_fudge - get a clock's fudge factors + */ +static void +set_clock_fudge( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + register struct conf_fudge *cf; + register int items; + struct refclockstat clock_stat; + struct sockaddr_in addr; + l_fp ltmp; + + memset((char *)&addr, 0, sizeof addr); + memset((char *)&clock_stat, 0, sizeof clock_stat); + 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, -1) == 0) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + switch(ntohl(cf->which)) { + case FUDGE_TIME1: + NTOHL_FP(&cf->fudgetime, <mp); + LFPTOD(<mp, clock_stat.fudgetime1); + clock_stat.haveflags = CLK_HAVETIME1; + break; + case FUDGE_TIME2: + NTOHL_FP(&cf->fudgetime, <mp); + LFPTOD(<mp, clock_stat.fudgetime2); + clock_stat.haveflags = CLK_HAVETIME2; + break; + case FUDGE_VAL1: + clock_stat.fudgeval1 = ntohl(cf->fudgeval_flags); + clock_stat.haveflags = CLK_HAVEVAL1; + break; + case FUDGE_VAL2: + clock_stat.fudgeval2 = ntohl(cf->fudgeval_flags); + clock_stat.haveflags = CLK_HAVEVAL2; + break; + case FUDGE_FLAGS: + clock_stat.flags = (u_char) ntohl(cf->fudgeval_flags) & 0xf; + clock_stat.haveflags = + (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4); + break; + default: + req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); + return; + } + + refclock_control(&addr, &clock_stat, (struct refclockstat *)0); + } + + req_ack(srcadr, inter, inpkt, INFO_OKAY); +} +#endif + +#ifdef REFCLOCK +/* + * get_clkbug_info - get debugging info about a clock + */ +static void +get_clkbug_info( + struct sockaddr_in *srcadr, + struct interface *inter, + struct req_pkt *inpkt + ) +{ + register int i; + register struct info_clkbug *ic; + register u_int32 *clkaddr; + register int items; + struct refclockbug bug; + struct sockaddr_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_int32 *) 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, -1) == 0) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + memset((char *)&bug, 0, sizeof bug); + refclock_buginfo(&addr, &bug); + if (bug.nvalues == 0 && bug.ntimes == 0) { + req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); + return; + } + + ic->clockadr = addr.sin_addr.s_addr; + i = bug.nvalues; + if (i > NUMCBUGVALUES) + i = NUMCBUGVALUES; + ic->nvalues = (u_char)i; + ic->svalues = htons((u_short) (bug.svalues & ((1<= 0) + ic->values[i] = htonl(bug.values[i]); + + i = bug.ntimes; + if (i > NUMCBUGTIMES) + i = NUMCBUGTIMES; + ic->ntimes = (u_char)i; + ic->stimes = htonl(bug.stimes); + while (--i >= 0) { + HTONL_FP(&bug.times[i], &ic->times[i]); + } + + ic = (struct info_clkbug *)more_pkt(); + } + flush_pkt(); +} +#endif diff --git a/contrib/ntp/ntpd/ntp_restrict.c b/contrib/ntp/ntpd/ntp_restrict.c new file mode 100644 index 000000000000..0e5b9dc264ac --- /dev/null +++ b/contrib/ntp/ntpd/ntp_restrict.c @@ -0,0 +1,460 @@ +/* + * ntp_restrict.c - find out what restrictions this host is running under + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "ntpd.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" + +/* + * This code keeps a simple address-and-mask list of hosts we want + * to place restrictions on (or remove them from). The restrictions + * are implemented as a set of flags which tell you what the host + * can't do. There is a subroutine entry to return the flags. The + * list is kept sorted to reduce the average number of comparisons + * and make sure you get the set of restrictions most specific to + * the address. + * + * The algorithm is that, when looking up a host, it is first assumed + * that the default set of restrictions will apply. It then searches + * down through the list. Whenever it finds a match it adopts the match's + * flags instead. When you hit the point where the sorted address is + * greater than the target, you return with the last set of flags you + * found. Because of the ordering of the list, the most specific match + * will provide the final set of flags. + * + * This was originally intended to restrict you from sync'ing to your + * own broadcasts when you are doing that, by restricting yourself + * from your own interfaces. It was also thought it would sometimes + * be useful to keep a misbehaving host or two from abusing your primary + * clock. It has been expanded, however, to suit the needs of those + * with more restrictive access policies. + */ + +/* + * Memory allocation parameters. We allocate INITRESLIST entries + * initially, and add INCRESLIST entries to the free list whenever + * we run out. + */ +#define INITRESLIST 10 +#define INCRESLIST 5 + +/* + * The restriction list + */ +struct restrictlist *restrictlist; +static int restrictcount; /* count of entries in the restriction list */ + +/* + * The free list and associated counters. Also some uninteresting + * stat counters. + */ +static struct restrictlist *resfree; +static int numresfree; /* number of structures on free list */ + +static u_long res_calls; +static u_long res_found; +static u_long res_not_found; +/* static u_long res_timereset; */ + +/* + * Parameters of the RES_LIMITED restriction option. + * client_limit is the number of hosts allowed per source net + * client_limit_period is the number of seconds after which an entry + * is no longer considered for client limit determination + */ +u_long client_limit; +u_long client_limit_period; +/* + * count number of restriction entries referring to RES_LIMITED + * controls activation/deactivation of monitoring + * (with respect to RES_LIMITED control) + */ +static u_long res_limited_refcnt; + +/* + * Our initial allocation of list entries. + */ +static struct restrictlist resinit[INITRESLIST]; + +/* + * init_restrict - initialize the restriction data structures + */ +void +init_restrict(void) +{ + register int i; + char bp[80]; + + /* + * 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 = htonl(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; */ + + /* + * set default values for RES_LIMIT functionality + */ + client_limit = 3; + client_limit_period = 3600; + res_limited_refcnt = 0; + + sprintf(bp, "client_limit=%ld", client_limit); + set_sys_var(bp, strlen(bp)+1, RO); + sprintf(bp, "client_limit_period=%ld", client_limit_period); + set_sys_var(bp, strlen(bp)+1, RO); +} + + +/* + * restrictions - return restrictions for this host + */ +int +restrictions( + struct sockaddr_in *srcadr + ) +{ + register struct restrictlist *rl; + register struct restrictlist *match; + register u_int32 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); + + /* + * Ignore any packets with a multicast source address + * (this should be done early in the receive process, later!) + */ + if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr))) + return (int)RES_IGNORE; + + /* + * Set match to first entry, which is default entry. Work our + * way down from there. + */ + match = restrictlist; + + for (rl = match->next; rl != 0 && rl->addr <= hostaddr; rl = rl->next) + if ((hostaddr & rl->mask) == rl->addr) { + if ((rl->mflags & RESM_NTPONLY) && !isntpport) + continue; + match = rl; + } + + match->count++; + if (match == restrictlist) + res_not_found++; + else + res_found++; + + /* + * The following implements limiting the number of clients + * accepted from a given network. The notion of "same network" + * is determined by the mask and addr fields of the restrict + * list entry. The monitor mechanism has to be enabled for + * collecting info on current clients. + * + * The policy is as follows: + * - take the list of clients recorded + * from the given "network" seen within the last + * client_limit_period seconds + * - if there are at most client_limit entries: + * --> access allowed + * - otherwise sort by time first seen + * - current client among the first client_limit seen + * hosts? + * if yes: access allowed + * else: eccess denied + */ + if (match->flags & RES_LIMITED) { + int lcnt; + struct mon_data *md, *this_client; + +#ifdef DEBUG + if (debug > 2) + printf("limited clients check: %ld clients, period %ld seconds, net is 0x%lX\n", + client_limit, client_limit_period, + (u_long)netof(hostaddr)); +#endif /*DEBUG*/ + if (mon_enabled == MON_OFF) { +#ifdef DEBUG + if (debug > 4) + printf("no limit - monitoring is off\n"); +#endif + return (int)(match->flags & ~RES_LIMITED); + } + + /* + * How nice, MRU list provides our current client as the + * first entry in the list. + * Monitoring was verified to be active above, thus we + * know an entry for our client must exist, or some + * brain dead set the memory limit for mon entries to ZERO!!! + */ + this_client = mon_mru_list.mru_next; + + for (md = mon_fifo_list.fifo_next,lcnt = 0; + md != &mon_fifo_list; + md = md->fifo_next) { + if ((current_time - md->lasttime) + > client_limit_period) { +#ifdef DEBUG + if (debug > 5) + printf("checking: %s: ignore: too old: %ld\n", + numtoa(md->rmtadr), + current_time - md->lasttime); +#endif + continue; + } + if (md->mode == MODE_BROADCAST || + md->mode == MODE_CONTROL || + md->mode == MODE_PRIVATE) { +#ifdef DEBUG + if (debug > 5) + printf("checking: %s: ignore mode %d\n", + numtoa(md->rmtadr), + md->mode); +#endif + continue; + } + if (netof(md->rmtadr) != + netof(hostaddr)) { +#ifdef DEBUG + if (debug > 5) + printf("checking: %s: different net 0x%lX\n", + numtoa(md->rmtadr), + (u_long)netof(md->rmtadr)); +#endif + continue; + } + lcnt++; + if (lcnt > (int) client_limit || + md->rmtadr == hostaddr) { +#ifdef DEBUG + if (debug > 5) + printf("considering %s: found host\n", + numtoa(md->rmtadr)); +#endif + break; + } +#ifdef DEBUG + else { + if (debug > 5) + printf("considering %s: same net\n", + numtoa(md->rmtadr)); + } +#endif + + } +#ifdef DEBUG + if (debug > 4) + printf("this one is rank %d in list, limit is %lu: %s\n", + lcnt, client_limit, + (lcnt <= (int) client_limit) ? "ALLOW" : "REJECT"); +#endif + if (lcnt <= (int) client_limit) { + this_client->lastdrop = 0; + return (int)(match->flags & ~RES_LIMITED); + } else { + this_client->lastdrop = current_time; + } + } + return (int)match->flags; +} + + +/* + * hack_restrict - add/subtract/manipulate entries on the restrict list + */ +void +hack_restrict( + int op, + struct sockaddr_in *resaddr, + struct sockaddr_in *resmask, + int mflags, + int flags + ) +{ + register u_int32 addr; + register u_int32 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 == htonl(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++; + } + if ((rl->flags ^ (u_short)flags) & RES_LIMITED) { + res_limited_refcnt++; + mon_start(MON_RES); /* ensure data gets collected */ + } + rl->flags |= (u_short)flags; + break; + + case RESTRICT_UNFLAG: + /* + * Remove some bits from the flags. If we didn't + * find this one, just return. + */ + if (rl != 0) { + if ((rl->flags ^ (u_short)flags) & RES_LIMITED) { + res_limited_refcnt--; + if (res_limited_refcnt == 0) + mon_stop(MON_RES); + } + rl->flags &= (u_short)~flags; + } + break; + + case RESTRICT_REMOVE: + /* + * Remove an entry from the table entirely if we found one. + * Don't remove the default entry and don't remove an + * interface entry. + */ + if (rl != 0 + && rl->addr != htonl(INADDR_ANY) + && !(rl->mflags & RESM_INTERFACE)) { + rlprev->next = rl->next; + restrictcount--; + if (rl->flags & RES_LIMITED) { + res_limited_refcnt--; + if (res_limited_refcnt == 0) + mon_stop(MON_RES); + } + memset((char *)rl, 0, sizeof(struct restrictlist)); + + rl->next = resfree; + resfree = rl; + numresfree++; + } + break; + + default: + /* Oh, well */ + break; + } + + /* done! */ +} diff --git a/contrib/ntp/ntpd/ntp_timer.c b/contrib/ntp/ntpd/ntp_timer.c new file mode 100644 index 000000000000..0e2dc88cbe95 --- /dev/null +++ b/contrib/ntp/ntpd/ntp_timer.c @@ -0,0 +1,308 @@ +/* + * ntp_timer.c - event timer support routines + */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "ntp_machine.h" +#include "ntpd.h" +#include "ntp_stdlib.h" +#if defined(HAVE_IO_COMPLETION_PORT) +# include "ntp_iocompletionport.h" +# include "ntp_timer.h" +#endif + +/* + * These routines provide support for the event timer. The timer is + * implemented by an interrupt routine which sets a flag once every + * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which + * is called when the mainline code gets around to seeing the flag. + * The timer routine dispatches the clock adjustment code if its time + * has come, then searches the timer queue for expiries which are + * dispatched to the transmit procedure. Finally, we call the hourly + * procedure to do cleanup and print a message. + */ + +/* + * Alarm flag. The mainline code imports this. + */ +volatile int alarm_flag; + +/* + * The counters + */ +static u_long adjust_timer; /* second timer */ +static u_long keys_timer; /* minute timer */ +static u_long hourly_timer; /* hour timer */ +static u_long revoke_timer; /* keys revoke timer */ +u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout */ + +/* + * Statistics counter for the interested. + */ +volatile u_long alarm_overflow; + +#define MINUTE 60 +#define HOUR (60*60) + +u_long current_time; + +/* + * Stats. Number of overflows and number of calls to transmit(). + */ +u_long timer_timereset; +u_long timer_overflows; +u_long timer_xmtcalls; + +#if defined(VMS) +static int vmstimer[2]; /* time for next timer AST */ +static int vmsinc[2]; /* timer increment */ +#endif /* VMS */ + +#if defined SYS_WINNT +static HANDLE WaitableTimerHandle = NULL; +#else +static RETSIGTYPE alarming P((int)); +#endif /* SYS_WINNT */ + + +/* + * init_timer - initialize the timer data structures + */ +void +init_timer(void) +{ +#if !defined(VMS) +# if !defined SYS_WINNT || defined(SYS_CYGWIN32) +# ifndef HAVE_TIMER_SETTIME + struct itimerval itimer; +# else + static timer_t ntpd_timerid; /* should be global if we ever want */ + /* to kill timer without rebooting ... */ + struct itimerspec itimer; +# endif /* HAVE_TIMER_SETTIME */ +# else /* SYS_WINNT */ + HANDLE hToken; + TOKEN_PRIVILEGES tkp; +# endif /* SYS_WINNT */ +#endif /* !VMS */ + + /* + * Initialize... + */ + alarm_flag = 0; + alarm_overflow = 0; + adjust_timer = 1; + hourly_timer = HOUR; + current_time = 0; + timer_overflows = 0; + timer_xmtcalls = 0; + timer_timereset = 0; + +#if !defined(SYS_WINNT) + /* + * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT + * seconds from now and they continue on every 2**EVENT_TIMEOUT + * seconds. + */ +# if !defined(VMS) +# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) + if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) == +# ifdef SYS_VXWORKS + ERROR +# else + -1 +# endif + ) + { + fprintf (stderr, "timer create FAILED\n"); + exit (0); + } + (void) signal_no_reset(SIGALRM, alarming); + itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<next; + if (peer->action && peer->nextaction <= current_time) + peer->action(peer); + if (peer->nextdate <= current_time) { +#ifdef REFCLOCK + if (peer->flags & FLAG_REFCLOCK) + refclock_transmit(peer); + else + transmit(peer); +#else /* REFCLOCK */ + transmit(peer); +#endif /* REFCLOCK */ + } + } + } + + /* + * Garbage collect expired keys. + */ + if (keys_timer <= current_time) { + keys_timer += MINUTE; + auth_agekeys(); + } + + /* + * Garbage collect revoked keys + */ + if (revoke_timer <= current_time) { + revoke_timer += RANDPOLL(sys_revoke); + key_expire_all(); + } + + /* + * Finally, call the hourly routine. + */ + if (hourly_timer <= current_time) { + hourly_timer += HOUR; + hourly_stats(); + } +} + + +#ifndef SYS_WINNT +/* + * alarming - tell the world we've been alarmed + */ +static RETSIGTYPE +alarming( + int sig + ) +{ +#if !defined(VMS) + if (initializing) + return; + if (alarm_flag) + alarm_overflow++; + else + alarm_flag++; +#else /* VMS AST routine */ + if (!initializing) { + if (alarm_flag) alarm_overflow++; + else alarm_flag = 1; /* increment is no good */ + } + lib$addx(&vmsinc,&vmstimer,&vmstimer); + sys$setimr(0,&vmstimer,alarming,alarming,0); +#endif /* VMS */ +} +#endif /* SYS_WINNT */ + + +/* + * timer_clr_stats - clear timer module stat counters + */ +void +timer_clr_stats(void) +{ + timer_overflows = 0; + timer_xmtcalls = 0; + timer_timereset = current_time; +} + diff --git a/contrib/ntp/ntpd/ntp_util.c b/contrib/ntp/ntpd/ntp_util.c new file mode 100644 index 000000000000..c53255a0a62b --- /dev/null +++ b/contrib/ntp/ntpd/ntp_util.c @@ -0,0 +1,640 @@ +/* + * ntp_util.c - stuff I didn't have any other place for + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +# ifdef HAVE_SYS_IOCTL_H +# include +# endif +# include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_filegen.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" + +#ifdef DOSYNCTODR +#if !defined(VMS) +#include +#endif /* VMS */ +#endif + +#if defined(VMS) +#include +#endif /* VMS */ + +/* + * This contains odds and ends. Right now the only thing you'll find + * in here is the hourly stats printer and some code to support rereading + * the keys file, but I may eventually put other things in here such as + * code to do something with the leap bits. + */ + +/* + * Name of the keys file + */ +static char *key_file_name; + +/* + * The name of the drift_comp file and the temporary. + */ +static char *stats_drift_file; +static char *stats_temp_file; + +/* + * Statistics file stuff + */ +#ifndef NTP_VAR +#ifndef SYS_WINNT +#define NTP_VAR "/var/NTP/" /* NOTE the trailing '/' */ +#else +#define NTP_VAR "c:\\var\\ntp\\" /* NOTE the trailing '\\' */ +#endif /* SYS_WINNT */ +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 256 +#endif + +static char statsdir[MAXPATHLEN] = NTP_VAR; + +static FILEGEN peerstats; +static FILEGEN loopstats; +static FILEGEN clockstats; +static FILEGEN rawstats; + +/* + * This controls whether stats are written to the fileset. Provided + * so that ntpdc can turn off stats when the file system fills up. + */ +int stats_control; + +/* + * init_util - initialize the utilities + */ +void +init_util(void) +{ + stats_drift_file = 0; + stats_temp_file = 0; + key_file_name = 0; + +#define PEERNAME "peerstats" +#define LOOPNAME "loopstats" +#define CLOCKNAME "clockstats" +#define RAWNAME "rawstats" + peerstats.fp = NULL; + peerstats.prefix = &statsdir[0]; + peerstats.basename = (char*)emalloc(strlen(PEERNAME)+1); + strcpy(peerstats.basename, PEERNAME); + peerstats.id = 0; + peerstats.type = FILEGEN_DAY; + peerstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ + filegen_register("peerstats", &peerstats); + + loopstats.fp = NULL; + loopstats.prefix = &statsdir[0]; + loopstats.basename = (char*)emalloc(strlen(LOOPNAME)+1); + strcpy(loopstats.basename, LOOPNAME); + loopstats.id = 0; + loopstats.type = FILEGEN_DAY; + loopstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ + filegen_register("loopstats", &loopstats); + + clockstats.fp = NULL; + clockstats.prefix = &statsdir[0]; + clockstats.basename = (char*)emalloc(strlen(CLOCKNAME)+1); + strcpy(clockstats.basename, CLOCKNAME); + clockstats.id = 0; + clockstats.type = FILEGEN_DAY; + clockstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ + filegen_register("clockstats", &clockstats); + + rawstats.fp = NULL; + rawstats.prefix = &statsdir[0]; + rawstats.basename = (char*)emalloc(strlen(RAWNAME)+1); + strcpy(rawstats.basename, RAWNAME); + rawstats.id = 0; + rawstats.type = FILEGEN_DAY; + rawstats.flag = FGEN_FLAG_LINK; /* not yet enabled !!*/ + filegen_register("rawstats", &rawstats); + +#undef PEERNAME +#undef LOOPNAME +#undef CLOCKNAME +#undef RAWNAME + +} + + +/* + * hourly_stats - print some interesting stats + */ +void +hourly_stats(void) +{ + FILE *fp; + +#ifdef DOSYNCTODR + struct timeval tv; +#if !defined(VMS) + int prio_set; +#endif +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif + int o_prio; + + /* + * Sometimes having a Sun can be a drag. + * + * The kernel variable dosynctodr controls whether the system's + * soft clock is kept in sync with the battery clock. If it + * is zero, then the soft clock is not synced, and the battery + * clock is simply left to rot. That means that when the system + * reboots, the battery clock (which has probably gone wacky) + * sets the soft clock. That means ntpd starts off with a very + * confused idea of what time it is. It then takes a large + * amount of time to figure out just how wacky the battery clock + * has made things drift, etc, etc. The solution is to make the + * battery clock sync up to system time. The way to do THAT is + * to simply set the time of day to the current time of day, but + * as quickly as possible. This may, or may not be a sensible + * thing to do. + * + * CAVEAT: settimeofday() steps the sun clock by about 800 us, + * so setting DOSYNCTODR seems a bad idea in the + * case of us resolution + */ + +#if !defined(VMS) + /* (prr) getpriority returns -1 on error, but -1 is also a valid + * return value (!), so instead we have to zero errno before the call + * and check it for non-zero afterwards. + */ + + errno = 0; + prio_set = 0; + o_prio = getpriority(PRIO_PROCESS,0); /* Save setting */ + + /* (prr) if getpriority succeeded, call setpriority to raise + * scheduling priority as high as possible. If that succeeds + * as well, set the prio_set flag so we remember to reset + * priority to its previous value below. Note that on Solaris 2.6 + * (and beyond?), both getpriority and setpriority will fail with + * ESRCH, because sched_setscheduler (called from main) put us in + * the real-time scheduling class which setpriority doesn't know about. + * Being in the real-time class is better than anything setpriority + * can do, anyhow, so this error is silently ignored. + */ + + if ((errno == 0) && (setpriority(PRIO_PROCESS,0,-20) == 0)) + prio_set = 1; /* overdrive */ +#endif /* VMS */ +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tv,(struct timezone *)NULL); +#endif /* not HAVE_GETCLOCK */ + if (ntp_set_tod(&tv,(struct timezone *)NULL) != 0) + { + msyslog(LOG_ERR, "can't sync battery time: %m"); + } +#if !defined(VMS) + if (prio_set) + setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */ +#endif /* VMS */ +#endif /* DOSYNCTODR */ + + NLOG(NLOG_SYSSTATIST) + msyslog(LOG_INFO, + "offset %.6f sec freq %.3f ppm error %.6f poll %d", + last_offset, drift_comp * 1e6, sys_error, sys_poll); + + if (stats_drift_file != 0) { + if ((fp = fopen(stats_temp_file, "w")) == NULL) { + msyslog(LOG_ERR, "can't open %s: %m", + stats_temp_file); + return; + } + fprintf(fp, "%.3f\n", drift_comp * 1e6); + (void)fclose(fp); + /* atomic */ +#ifdef SYS_WINNT + (void) unlink(stats_drift_file); /* rename semantics differ under NT */ +#endif /* SYS_WINNT */ + +#ifndef NO_RENAME + (void) rename(stats_temp_file, stats_drift_file); +#else + /* we have no rename NFS of ftp in use*/ + if ((fp = fopen(stats_drift_file, "w")) == NULL) { + msyslog(LOG_ERR, "can't open %s: %m", + stats_drift_file); + return; + } + +#endif + +#if defined(VMS) + /* PURGE */ + { + $DESCRIPTOR(oldvers,";-1"); + struct dsc$descriptor driftdsc = { + strlen(stats_drift_file),0,0,stats_drift_file }; + + while(lib$delete_file(&oldvers,&driftdsc) & 1) ; + } +#endif + } +} + + +/* + * stats_config - configure the stats operation + */ +void +stats_config( + int item, + char *invalue /* only one type so far */ + ) +{ + FILE *fp; + char *value; + double old_drift; + int len; + + /* Expand environment strings under Windows NT, since the command + * interpreter doesn't do this, the program must. + */ +#ifdef SYS_WINNT + char newvalue[MAX_PATH], parameter[MAX_PATH]; + + if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) + { + switch(item) { + case STATS_FREQ_FILE: + strcpy(parameter,"STATS_FREQ_FILE"); + break; + case STATS_STATSDIR: + strcpy(parameter,"STATS_STATSDIR"); + break; + case STATS_PID_FILE: + strcpy(parameter,"STATS_PID_FILE"); + break; + default: + strcpy(parameter,"UNKNOWN"); + break; + } + value = invalue; + + msyslog(LOG_ERR, + "ExpandEnvironmentStrings(%s) failed: %m\n", parameter); + } + else + value = newvalue; +#else + value = invalue; +#endif /* SYS_WINNT */ + + + + switch(item) { + case STATS_FREQ_FILE: + if (stats_drift_file != 0) { + (void) free(stats_drift_file); + (void) free(stats_temp_file); + stats_drift_file = 0; + stats_temp_file = 0; + } + + if (value == 0 || (len = strlen(value)) == 0) + break; + + stats_drift_file = (char*)emalloc((u_int)(len + 1)); +#if !defined(VMS) + stats_temp_file = (char*)emalloc((u_int)(len + sizeof(".TEMP"))); +#else + stats_temp_file = (char*)emalloc((u_int)(len + sizeof("-TEMP"))); +#endif /* VMS */ + memmove(stats_drift_file, value, (unsigned)(len+1)); + memmove(stats_temp_file, value, (unsigned)len); +#if !defined(VMS) + memmove(stats_temp_file + len, ".TEMP", sizeof(".TEMP")); +#else + memmove(stats_temp_file + len, "-TEMP", sizeof("-TEMP")); +#endif /* VMS */ + + /* + * Open drift file and read frequency + */ + if ((fp = fopen(stats_drift_file, "r")) == NULL) { + break; + } + if (fscanf(fp, "%lf", &old_drift) != 1) { + msyslog(LOG_ERR, "invalid frequency from %s", + stats_drift_file); + (void) fclose(fp); + break; + } + (void) fclose(fp); + msyslog(LOG_INFO, "frequency initialized %.3f from %s", + old_drift, stats_drift_file); + loop_config(LOOP_DRIFTCOMP, old_drift / 1e6); + break; + + case STATS_STATSDIR: + if (strlen(value) >= sizeof(statsdir)) { + msyslog(LOG_ERR, + "value for statsdir too long (>%d, sigh)", + (int)sizeof(statsdir)-1); + } else { + l_fp now; + + get_systime(&now); + strcpy(statsdir,value); + if(peerstats.prefix == &statsdir[0] && + peerstats.fp != NULL) { + fclose(peerstats.fp); + peerstats.fp = NULL; + filegen_setup(&peerstats, now.l_ui); + } + if(loopstats.prefix == &statsdir[0] && + loopstats.fp != NULL) { + fclose(loopstats.fp); + loopstats.fp = NULL; + filegen_setup(&loopstats, now.l_ui); + } + if(clockstats.prefix == &statsdir[0] && + clockstats.fp != NULL) { + fclose(clockstats.fp); + clockstats.fp = NULL; + filegen_setup(&clockstats, now.l_ui); + } + if(rawstats.prefix == &statsdir[0] && + rawstats.fp != NULL) { + fclose(rawstats.fp); + rawstats.fp = NULL; + filegen_setup(&rawstats, now.l_ui); + } + } + break; + + case STATS_PID_FILE: + if ((fp = fopen(value, "w")) == NULL) { + msyslog(LOG_ERR, "Can't open %s: %m", value); + break; + } + fprintf(fp, "%d", (int) getpid()); + fclose(fp);; + break; + + default: + /* oh well */ + break; + } +} + +/* + * record_peer_stats - write peer statistics to file + * + * file format: + * day (mjd) + * time (s past UTC midnight) + * peer (ip address) + * peer status word (hex) + * peer offset (s) + * peer delay (s) + * peer error bound (s) + * peer error (s) +*/ +void +record_peer_stats( + struct sockaddr_in *addr, + int status, + double offset, + double delay, + double dispersion, + double skew + ) +{ + struct timeval tv; +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif + u_long day, sec, msec; + + if (!stats_control) + return; +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tv, (struct timezone *)NULL); +#endif /* not HAVE_GETCLOCK */ + day = tv.tv_sec / 86400 + MJD_1970; + sec = tv.tv_sec % 86400; + msec = 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 %.9f %.9f %.9f %.9f\n", + day, sec, msec, ntoa(addr), status, offset, + delay, dispersion, skew); + fflush(peerstats.fp); + } +} +/* + * record_loop_stats - write loop filter statistics to file + * + * file format: + * day (mjd) + * time (s past midnight) + * offset (s) + * frequency (approx ppm) + * time constant (log base 2) + */ +void +record_loop_stats(void) +{ + struct timeval tv; +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif + u_long day, sec, msec; + + if (!stats_control) + return; +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tv, (struct timezone *)NULL); +#endif /* not HAVE_GETCLOCK */ + day = tv.tv_sec / 86400 + MJD_1970; + sec = tv.tv_sec % 86400; + msec = tv.tv_usec / 1000; + + filegen_setup(&loopstats, (u_long)(tv.tv_sec + JAN_1970)); + if (loopstats.fp != NULL) { + fprintf(loopstats.fp, "%lu %lu.%03lu %.9f %.6f %.9f %.6f %d\n", + day, sec, msec, last_offset, drift_comp * 1e6, + sys_error, clock_stability * 1e6, sys_poll); + fflush(loopstats.fp); + } +} + +/* + * record_clock_stats - write clock statistics to file + * + * file format: + * day (mjd) + * time (s past midnight) + * peer (ip address) + * text message + */ +void +record_clock_stats( + struct sockaddr_in *addr, + const char *text + ) +{ + struct timeval tv; +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif + u_long day, sec, msec; + + if (!stats_control) + return; +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tv, (struct timezone *)NULL); +#endif /* not HAVE_GETCLOCK */ + day = tv.tv_sec / 86400 + MJD_1970; + sec = tv.tv_sec % 86400; + msec = 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); + } +} + +/* + * record_raw_stats - write raw timestamps to file + * + * + * file format + * time (s past midnight) + * peer ip address + * local ip address + * t1 t2 t3 t4 timestamps + */ +void +record_raw_stats( + struct sockaddr_in *srcadr, + struct sockaddr_in *dstadr, + l_fp *t1, + l_fp *t2, + l_fp *t3, + l_fp *t4 + ) +{ + struct timeval tv; +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif + u_long day, sec, msec; + + if (!stats_control) + return; +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tv, (struct timezone *)NULL); +#endif /* not HAVE_GETCLOCK */ + day = tv.tv_sec / 86400 + MJD_1970; + sec = tv.tv_sec % 86400; + msec = tv.tv_usec / 1000; + + filegen_setup(&rawstats, (u_long)(tv.tv_sec + JAN_1970)); + if (rawstats.fp != NULL) { + fprintf(rawstats.fp, "%lu %lu.%03lu %s %s %s %s %s %s\n", + day, sec, msec, ntoa(srcadr), ntoa(dstadr), + ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9), + ulfptoa(t4, 9)); + fflush(rawstats.fp); + } +} + +/* + * getauthkeys - read the authentication keys from the specified file + */ +void +getauthkeys( + char *keyfile + ) +{ + int len; + + len = strlen(keyfile); + if (len == 0) + return; + + if (key_file_name != 0) { + if (len > (int)strlen(key_file_name)) { + (void) free(key_file_name); + key_file_name = 0; + } + } + + if (key_file_name == 0) { +#ifndef SYS_WINNT + key_file_name = (char*)emalloc((u_int) (len + 1)); +#else + key_file_name = (char*)emalloc((u_int) (MAXPATHLEN)); +#endif + } +#ifndef SYS_WINNT + memmove(key_file_name, keyfile, (unsigned)(len+1)); +#else + if (!ExpandEnvironmentStrings(keyfile, key_file_name, MAXPATHLEN)) + { + msyslog(LOG_ERR, + "ExpandEnvironmentStrings(KEY_FILE) failed: %m\n"); + } +#endif /* SYS_WINNT */ + + authreadkeys(key_file_name); +} + + +/* + * rereadkeys - read the authentication key file over again. + */ +void +rereadkeys(void) +{ + if (key_file_name != 0) + authreadkeys(key_file_name); +} diff --git a/contrib/ntp/ntpd/ntpd.c b/contrib/ntp/ntpd/ntpd.c new file mode 100644 index 000000000000..923b1f702653 --- /dev/null +++ b/contrib/ntp/ntpd/ntpd.c @@ -0,0 +1,1121 @@ +/* + * ntpd.c - main program for the fixed point NTP daemon + */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#include +#ifndef SYS_WINNT +# if !defined(VMS) /*wjm*/ +# include +# endif /* VMS */ +# include +# ifdef HAVE_SYS_IOCTL_H +# include +# endif /* HAVE_SYS_IOCTL_H */ +# include +# ifdef HAVE_SYS_RESOURCE_H +# include +# endif /* HAVE_SYS_RESOURCE_H */ +#else +# include +# include +# include +# include "../libntp/log.h" +# include +#endif /* SYS_WINNT */ +#if defined(HAVE_RTPRIO) +# ifdef HAVE_SYS_RESOURCE_H +# include +# endif +# ifdef HAVE_SYS_LOCK_H +# include +# endif +# include +#else +# ifdef HAVE_PLOCK +# ifdef HAVE_SYS_LOCK_H +# include +# endif +# endif +#endif +#if defined(HAVE_SCHED_SETSCHEDULER) +# ifdef HAVE_SCHED_H +# include +# else +# ifdef HAVE_SYS_SCHED_H +# include +# endif +# endif +#endif +#if defined(HAVE_SYS_MMAN_H) +# include +#endif + +#ifdef HAVE_TERMIOS_H +# include +#endif + +#ifdef SYS_DOMAINOS +# include +#endif /* SYS_DOMAINOS */ + +#include "ntpd.h" +#include "ntp_io.h" + +#include "ntp_stdlib.h" +#include "recvbuff.h" + +#if 0 /* HMS: I don't think we need this. 961223 */ +#ifdef LOCK_PROCESS +# ifdef SYS_SOLARIS +# include +# else +# include +# endif +#endif +#endif + +#ifdef _AIX +#include +#endif /* _AIX */ + +#ifdef SCO5_CLOCK +#include +#endif + +/* + * Signals we catch for debugging. If not debugging we ignore them. + */ +#define MOREDEBUGSIG SIGUSR1 +#define LESSDEBUGSIG SIGUSR2 + +/* + * Signals which terminate us gracefully. + */ +#ifndef SYS_WINNT +#define SIGDIE1 SIGHUP +#define SIGDIE3 SIGQUIT +#define SIGDIE2 SIGINT +#define SIGDIE4 SIGTERM +#endif /* SYS_WINNT */ + +#if defined SYS_WINNT || defined SYS_CYGWIN32 +/* handles for various threads, process, and objects */ +HANDLE ResolverThreadHandle = NULL; +/* variables used to inform the Service Control Manager of our current state */ +SERVICE_STATUS ssStatus; +SERVICE_STATUS_HANDLE sshStatusHandle; +HANDLE WaitHandles[3] = { NULL, NULL, NULL }; +char szMsgPath[255]; +static BOOL WINAPI OnConsoleEvent(DWORD dwCtrlType); +#endif /* SYS_WINNT */ + +/* + * Scheduling priority we run at + */ +#if !defined SYS_WINNT +# define NTPD_PRIO (-12) +#else +# define NTPD_PRIO REALTIME_PRIORITY_CLASS +#endif + +/* + * Debugging flag + */ +volatile int debug; + +/* + * No-fork flag. If set, we do not become a background daemon. + */ +int nofork; + +/* + * Initializing flag. All async routines watch this and only do their + * thing when it is clear. + */ +int initializing; + +/* + * Version declaration + */ +extern const char *Version; + +int was_alarmed; + +#ifdef DECL_SYSCALL +/* + * We put this here, since the argument profile is syscall-specific + */ +extern int syscall P((int, ...)); +#endif /* DECL_SYSCALL */ + + +#ifdef SIGDIE2 +static RETSIGTYPE finish P((int)); +#endif /* SIGDIE2 */ + +#ifdef DEBUG +static RETSIGTYPE moredebug P((int)); +static RETSIGTYPE lessdebug P((int)); +#else /* not DEBUG */ +static RETSIGTYPE no_debug P((int)); +#endif /* not DEBUG */ + +int ntpdmain P((int, char **)); +static void set_process_priority P((void)); + + +#ifdef NO_MAIN_ALLOWED +CALL(ntpd,"ntpd",ntpdmain); +#else +int +main( + int argc, + char *argv[] + ) +{ + return ntpdmain(argc, argv); +} +#endif + +#ifdef _AIX +/* + * OK. AIX is different than solaris in how it implements plock(). + * If you do NOT adjust the stack limit, you will get the MAXIMUM + * stack size allocated and PINNED with you program. To check the + * value, use ulimit -a. + * + * To fix this, we create an automatic variable and set our stack limit + * to that PLUS 32KB of extra space (we need some headroom). + * + * This subroutine gets the stack address. + * + * Grover Davidson and Matt Ladendorf + * + */ +static char * +get_aix_stack(void) +{ + char ch; + return (&ch); +} + +/* + * Signal handler for SIGDANGER. + */ +static void +catch_danger(int signo) +{ + msyslog(LOG_INFO, "ntpd: setpgid(): %m"); + /* Make the system believe we'll free something, but don't do it! */ + return; +} +#endif /* _AIX */ + +/* + * Set the process priority + */ +static void +set_process_priority(void) +{ + int done = 0; + +#ifdef SYS_WINNT + if (!SetPriorityClass(GetCurrentProcess(), (DWORD) REALTIME_PRIORITY_CLASS)) + msyslog(LOG_ERR, "SetPriorityClass: %m"); + else + ++done; +#else /* not SYS_WINNT */ +# if defined(HAVE_SCHED_SETSCHEDULER) + + if (!done) { + extern int config_priority_override, config_priority; + int pmax, pmin; + struct sched_param sched; + + pmax = sched_get_priority_max(SCHED_FIFO); + sched.sched_priority = pmax; + if ( config_priority_override ) { + pmin = sched_get_priority_min(SCHED_FIFO); + if ( config_priority > pmax ) + sched.sched_priority = pmax; + else if ( config_priority < pmin ) + sched.sched_priority = pmin; + else + sched.sched_priority = config_priority; + } + if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 ) + msyslog(LOG_ERR, "sched_setscheduler(): %m"); + else + ++done; + } +# endif /* HAVE_SCHED_SETSCHEDULER */ +# if defined(HAVE_RTPRIO) +# ifdef RTP_SET + if (!done) { + struct rtprio srtp; + + srtp.type = RTP_PRIO_REALTIME; /* was: RTP_PRIO_NORMAL */ + srtp.prio = 0; /* 0 (hi) -> RTP_PRIO_MAX (31,lo) */ + + if (rtprio(RTP_SET, getpid(), &srtp) < 0) + msyslog(LOG_ERR, "rtprio() error: %m"); + else + ++done; + } +# else /* not RTP_SET */ + if (!done) { + if (rtprio(0, 120) < 0) + msyslog(LOG_ERR, "rtprio() error: %m"); + else + ++done; + } +# endif /* not RTP_SET */ +# endif /* HAVE_RTPRIO */ +# if defined(NTPD_PRIO) && NTPD_PRIO != 0 +# ifdef HAVE_ATT_NICE + if (!done) { + errno = 0; + if (-1 == nice (NTPD_PRIO) && errno != 0) + msyslog(LOG_ERR, "nice() error: %m"); + else + ++done; + } +# endif /* HAVE_ATT_NICE */ +# ifdef HAVE_BSD_NICE + if (!done) { + if (-1 == setpriority(PRIO_PROCESS, 0, NTPD_PRIO)) + msyslog(LOG_ERR, "setpriority() error: %m"); + else + ++done; + } +# endif /* HAVE_BSD_NICE */ +# endif /* NTPD_PRIO && NTPD_PRIO != 0 */ +#endif /* not SYS_WINNT */ + if (!done) + msyslog(LOG_ERR, "set_process_priority: No way found to improve our priority"); +} + +/* + * Main program. Initialize us, disconnect us from the tty if necessary, + * and loop waiting for I/O and/or timer expiries. + */ +int +ntpdmain( + int argc, + char *argv[] + ) +{ + l_fp now; + char *cp; + struct recvbuf *rbuflist; + struct recvbuf *rbuf; +#ifdef _AIX /* HMS: ifdef SIGDANGER? */ + struct sigaction sa; +#endif + + initializing = 1; /* mark that we are initializing */ + debug = 0; /* no debugging by default */ + nofork = 0; /* will fork by default */ + +#ifdef HAVE_UMASK + { + unsigned int uv; + + uv = umask(0); + if(uv) + (void) umask(uv); + else + (void) umask(022); + } +#endif + +#ifdef HAVE_GETUID + { + uid_t uid; + + uid = getuid(); + if (uid) + { + msyslog(LOG_ERR, "ntpd: must be run as root, not uid %ld", (long)uid); + exit(1); + } + } +#endif + +#ifdef SYS_WINNT + /* Set the Event-ID message-file name. */ + if (!GetModuleFileName(NULL, szMsgPath, sizeof(szMsgPath))) { + msyslog(LOG_ERR, "GetModuleFileName(PGM_EXE_FILE) failed: %m\n"); + exit(1); + } + addSourceToRegistry("NTP", szMsgPath); +#endif + + get_systime(&now); + SRANDOM((int)(now.l_i * now.l_uf)); + getstartup(argc, argv); /* startup configuration, may set debug */ + +#if !defined(VMS) +# ifndef NODETACH + /* + * Detach us from the terminal. May need an #ifndef GIZMO. + */ +# ifdef DEBUG + if (!debug && !nofork) +# else /* DEBUG */ + if (!nofork) +# endif /* DEBUG */ + { +# ifndef SYS_WINNT +# ifdef HAVE_DAEMON + daemon(0, 0); +# else /* not HAVE_DAEMON */ + if (fork()) /* HMS: What about a -1? */ + exit(0); + + { +#if !defined(F_CLOSEM) + u_long s; + int max_fd; +#endif /* not F_CLOSEM */ + + /* + * From 'Writing Reliable AIX Daemons,' SG24-4946-00, + * by Eric Agar (saves us from doing 32767 system + * calls) + */ +#if defined(F_CLOSEM) + if (fcntl(0, F_CLOSEM, 0) == -1) + msyslog(LOG_ERR, "ntpd: failed to close open files(): %m"); +#else /* not F_CLOSEM */ + +#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) + max_fd = sysconf(_SC_OPEN_MAX); +#else /* HAVE_SYSCONF && _SC_OPEN_MAX */ + max_fd = getdtablesize(); +#endif /* HAVE_SYSCONF && _SC_OPEN_MAX */ + for (s = 0; s < max_fd; s++) + (void) close((int)s); +#endif /* not F_CLOSEM */ + (void) open("/", 0); + (void) dup2(0, 1); + (void) dup2(0, 2); +#ifdef SYS_DOMAINOS + { + uid_$t puid; + status_$t st; + + proc2_$who_am_i(&puid); + proc2_$make_server(&puid, &st); + } +#endif /* SYS_DOMAINOS */ +#if defined(HAVE_SETPGID) || defined(HAVE_SETSID) +# ifdef HAVE_SETSID + if (setsid() == (pid_t)-1) + msyslog(LOG_ERR, "ntpd: setsid(): %m"); +# else + if (setpgid(0, 0) == -1) + msyslog(LOG_ERR, "ntpd: setpgid(): %m"); +# endif +#else /* HAVE_SETPGID || HAVE_SETSID */ + { +# if defined(TIOCNOTTY) + int fid; + + fid = open("/dev/tty", 2); + if (fid >= 0) + { + (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0); + (void) close(fid); + } +# endif /* defined(TIOCNOTTY) */ +# ifdef HAVE_SETPGRP_0 + (void) setpgrp(); +# else /* HAVE_SETPGRP_0 */ + (void) setpgrp(0, getpid()); +# endif /* HAVE_SETPGRP_0 */ + } +#endif /* HAVE_SETPGID || HAVE_SETSID */ +#ifdef _AIX + /* Don't get killed by low-on-memory signal. */ + sa.sa_handler = catch_danger; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + (void) sigaction(SIGDANGER, &sa, NULL); +#endif /* _AIX */ + } +#endif /* not HAVE_DAEMON */ +#else /* SYS_WINNT */ + + { + SERVICE_TABLE_ENTRY dispatchTable[] = { + { TEXT("NetworkTimeProtocol"), (LPSERVICE_MAIN_FUNCTION)service_main }, + { NULL, NULL } + }; + + /* daemonize */ + if (!StartServiceCtrlDispatcher(dispatchTable)) + { + msyslog(LOG_ERR, "StartServiceCtrlDispatcher: %m"); + ExitProcess(2); + } + } +#endif /* SYS_WINNT */ + } +#endif /* NODETACH */ +#if defined(SYS_WINNT) && !defined(NODETACH) + else + service_main(argc, argv); + return 0; /* must return a value */ +} /* end main */ + +/* + * If this runs as a service under NT, the main thread will block at + * StartServiceCtrlDispatcher() and another thread will be started by the + * Service Control Dispatcher which will begin execution at the routine + * specified in that call (viz. service_main) + */ +void +service_main( + DWORD argc, + LPTSTR *argv + ) +{ + char *cp; + struct recvbuf *rbuflist; + struct recvbuf *rbuf; + + if(!debug) + { + /* register our service control handler */ + if (!(sshStatusHandle = RegisterServiceCtrlHandler( TEXT("NetworkTimeProtocol"), + (LPHANDLER_FUNCTION)service_ctrl))) + { + msyslog(LOG_ERR, "RegisterServiceCtrlHandler failed: %m"); + return; + } + + /* report pending status to Service Control Manager */ + ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ssStatus.dwCurrentState = SERVICE_START_PENDING; + ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + ssStatus.dwWin32ExitCode = NO_ERROR; + ssStatus.dwServiceSpecificExitCode = 0; + ssStatus.dwCheckPoint = 1; + ssStatus.dwWaitHint = 5000; + if (!SetServiceStatus(sshStatusHandle, &ssStatus)) + { + msyslog(LOG_ERR, "SetServiceStatus: %m"); + ssStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(sshStatusHandle, &ssStatus); + return; + } + + } /* debug */ +#endif /* defined(SYS_WINNT) && !defined(NODETACH) */ +#endif /* VMS */ + + /* + * Logging. This may actually work on the gizmo board. Find a name + * to log with by using the basename of argv[0] + */ + cp = strrchr(argv[0], '/'); + if (cp == 0) + cp = argv[0]; + else + cp++; + + debug = 0; /* will be immediately re-initialized 8-( */ + getstartup(argc, argv); /* startup configuration, catch logfile this time */ + +#if !defined(SYS_WINNT) && !defined(VMS) + +# ifndef LOG_DAEMON + openlog(cp, LOG_PID); +# else /* LOG_DAEMON */ + +# ifndef LOG_NTP +# define LOG_NTP LOG_DAEMON +# endif + openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP); +#ifndef SYS_CYGWIN32 +# ifdef DEBUG + if (debug) + setlogmask(LOG_UPTO(LOG_DEBUG)); + else +# endif /* DEBUG */ + setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */ +# endif /* LOG_DAEMON */ +#endif + +#endif /* !SYS_WINNT && !VMS */ + + NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, "%s", Version); + +#ifdef SYS_WINNT + /* GMS 1/18/1997 + * TODO: lock the process in memory using SetProcessWorkingSetSize() and VirtualLock() functions + * + process_handle = GetCurrentProcess(); + if (SetProcessWorkingSetSize(process_handle, 2097152 , 4194304 ) == TRUE) { + if (VirtualLock(0 , 4194304) == FALSE) + msyslog(LOG_ERR, "VirtualLock() failed: %m"); + } else { + msyslog(LOG_ERR, "SetProcessWorkingSetSize() failed: %m"); + } + */ +#endif /* SYS_WINNT */ + +#ifdef SCO5_CLOCK + /* + * SCO OpenServer's system clock offers much more precise timekeeping + * on the base CPU than the other CPUs (for multiprocessor systems), + * so we must lock to the base CPU. + */ + { + int fd = open("/dev/at1", O_RDONLY); + if (fd >= 0) { + int zero = 0; + if (ioctl(fd, ACPU_LOCK, &zero) < 0) + msyslog(LOG_ERR, "cannot lock to base CPU: %m\n"); + close( fd ); + } /* else ... + * If we can't open the device, this probably just isn't + * a multiprocessor system, so we're A-OK. + */ + } +#endif + +#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && defined(MCL_FUTURE) + /* + * lock the process into memory + */ + if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) + msyslog(LOG_ERR, "mlockall(): %m"); +#else /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */ +# ifdef HAVE_PLOCK +# ifdef PROCLOCK +# ifdef _AIX + /* + * set the stack limit for AIX for plock(). + * see get_aix_stack for more info. + */ + if (ulimit(SET_STACKLIM, (get_aix_stack() - 8*4096)) < 0) + { + msyslog(LOG_ERR,"Cannot adjust stack limit for plock on AIX: %m"); + } +# endif /* _AIX */ + /* + * lock the process into memory + */ + if (plock(PROCLOCK) < 0) + msyslog(LOG_ERR, "plock(PROCLOCK): %m"); +# else /* not PROCLOCK */ +# ifdef TXTLOCK + /* + * Lock text into ram + */ + if (plock(TXTLOCK) < 0) + msyslog(LOG_ERR, "plock(TXTLOCK) error: %m"); +# else /* not TXTLOCK */ + msyslog(LOG_ERR, "plock() - don't know what to lock!"); +# endif /* not TXTLOCK */ +# endif /* not PROCLOCK */ +# endif /* HAVE_PLOCK */ +#endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */ + + /* + * Set up signals we pay attention to locally. + */ +#ifdef SIGDIE1 + (void) signal_no_reset(SIGDIE1, finish); +#endif /* SIGDIE1 */ +#ifdef SIGDIE2 + (void) signal_no_reset(SIGDIE2, finish); +#endif /* SIGDIE2 */ +#ifdef SIGDIE3 + (void) signal_no_reset(SIGDIE3, finish); +#endif /* SIGDIE3 */ +#ifdef SIGDIE4 + (void) signal_no_reset(SIGDIE4, finish); +#endif /* SIGDIE4 */ + +#ifdef SIGBUS + (void) signal_no_reset(SIGBUS, finish); +#endif /* SIGBUS */ + +#if !defined(SYS_WINNT) && !defined(VMS) +# ifdef DEBUG + (void) signal_no_reset(MOREDEBUGSIG, moredebug); + (void) signal_no_reset(LESSDEBUGSIG, lessdebug); +# else + (void) signal_no_reset(MOREDEBUGSIG, no_debug); + (void) signal_no_reset(LESSDEBUGSIG, no_debug); +# endif /* DEBUG */ +#endif /* !SYS_WINNT && !VMS */ + + /* + * Set up signals we should never pay attention to. + */ +#if defined SIGPIPE && !defined SYS_CYGWIN32 + (void) signal_no_reset(SIGPIPE, SIG_IGN); +#endif /* SIGPIPE */ + +#if defined SYS_WINNT + if (!SetConsoleCtrlHandler(OnConsoleEvent, TRUE)) { + msyslog(LOG_ERR, "Can't set console control handler: %m"); + } +#endif + + /* + * Call the init_ routines to initialize the data structures. + */ +#if defined (HAVE_IO_COMPLETION_PORT) + init_io_completion_port(); + init_winnt_time(); +#endif + init_auth(); + init_util(); + init_restrict(); + init_mon(); + init_timer(); + init_lib(); + init_random(); + init_request(); + init_control(); + init_peer(); +#ifdef REFCLOCK + init_refclock(); +#endif + set_process_priority(); + init_proto(); + init_io(); + init_loopfilter(); + + mon_start(MON_ON); /* monitor on by default now */ + /* turn off in config if unwanted */ + + /* + * Get configuration. This (including argument list parsing) is + * done in a separate module since this will definitely be different + * for the gizmo board. + */ + getconfig(argc, argv); + + initializing = 0; + +#if defined(SYS_WINNT) && !defined(NODETACH) +# if defined(DEBUG) + if(!debug) + { +#endif + /* report to the service control manager that the service is running */ + ssStatus.dwCurrentState = SERVICE_RUNNING; + ssStatus.dwWin32ExitCode = NO_ERROR; + if (!SetServiceStatus(sshStatusHandle, &ssStatus)) + { + msyslog(LOG_ERR, "SetServiceStatus: %m"); + if (ResolverThreadHandle != NULL) + CloseHandle(ResolverThreadHandle); + ssStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(sshStatusHandle, &ssStatus); + return; + } +# if defined(DEBUG) + } +#endif +#endif + + /* + * Report that we're up to any trappers + */ + report_event(EVNT_SYSRESTART, (struct peer *)0); + + /* + * Use select() on all on all input fd's for unlimited + * time. select() will terminate on SIGALARM or on the + * reception of input. Using select() means we can't do + * robust signal handling and we get a potential race + * between checking for alarms and doing the select(). + * Mostly harmless, I think. + */ + /* On VMS, I suspect that select() can't be interrupted + * by a "signal" either, so I take the easy way out and + * have select() time out after one second. + * System clock updates really aren't time-critical, + * and - lacking a hardware reference clock - I have + * yet to learn about anything else that is. + */ +# if defined(HAVE_IO_COMPLETION_PORT) + { + WaitHandles[0] = CreateEvent(NULL, FALSE, FALSE, NULL); /* exit reques */ + WaitHandles[1] = get_recv_buff_event(); + WaitHandles[2] = get_timer_handle(); + + for (;;) { + DWORD Index = MsgWaitForMultipleObjectsEx(sizeof(WaitHandles)/sizeof(WaitHandles[0]), WaitHandles, INFINITE, QS_ALLEVENTS, MWMO_ALERTABLE); + switch (Index) { + case WAIT_OBJECT_0 + 0 : /* exit request */ + exit(0); + break; + + case WAIT_OBJECT_0 + 1 : {/* recv buffer */ + if (NULL != (rbuf = get_full_recv_buffer())) { + if (rbuf->receiver != NULL) { + rbuf->receiver(rbuf); + } + freerecvbuf(rbuf); + } + } + break; + + case WAIT_OBJECT_0 + 2 : /* 1 second timer */ + timer(); + break; + + case WAIT_OBJECT_0 + 3 : { /* Windows message */ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + exit(0); + } + DispatchMessage(&msg); + } + } + break; + + case WAIT_IO_COMPLETION : /* loop */ + case WAIT_TIMEOUT : + break; + + } + + } + } +# else /* normal I/O */ + + was_alarmed = 0; + rbuflist = (struct recvbuf *)0; + for (;;) + { +# if !defined(HAVE_SIGNALED_IO) + extern fd_set activefds; + extern int maxactivefd; + + fd_set rdfdes; + int nfound; +# elif defined(HAVE_SIGNALED_IO) + block_io_and_alarm(); +# endif + + rbuflist = getrecvbufs(); /* get received buffers */ + if (alarm_flag) /* alarmed? */ + { + was_alarmed = 1; + alarm_flag = 0; + } + + if (!was_alarmed && rbuflist == (struct recvbuf *)0) + { + /* + * Nothing to do. Wait for something. + */ +#ifndef HAVE_SIGNALED_IO + rdfdes = activefds; +# if defined(VMS) || defined(SYS_VXWORKS) + /* make select() wake up after one second */ + { + struct timeval t1; + + t1.tv_sec = 1; t1.tv_usec = 0; + nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, &t1); + } +# else + nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, (struct timeval *)0); +# endif /* VMS */ + if (nfound > 0) + { + l_fp ts; + + get_systime(&ts); + + (void)input_handler(&ts); + } + else if (nfound == -1 && errno != EINTR) + msyslog(LOG_ERR, "select() error: %m"); + else if (debug) { +# if !defined SYS_VXWORKS && !defined SYS_CYGWIN32 && !defined SCO5_CLOCK /* to unclutter log */ + msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound); +# endif + } +# else /* HAVE_SIGNALED_IO */ + + wait_for_signal(); +# endif /* HAVE_SIGNALED_IO */ + if (alarm_flag) /* alarmed? */ + { + was_alarmed = 1; + alarm_flag = 0; + } + rbuflist = getrecvbufs(); /* get received buffers */ + } +# ifdef HAVE_SIGNALED_IO + unblock_io_and_alarm(); +# endif /* HAVE_SIGNALED_IO */ + + /* + * Out here, signals are unblocked. Call timer routine + * to process expiry. + */ + if (was_alarmed) + { + timer(); + was_alarmed = 0; + } + + /* + * Call the data procedure to handle each received + * packet. + */ + while (rbuflist != (struct recvbuf *)0) + { + rbuf = rbuflist; + rbuflist = rbuf->next; + (rbuf->receiver)(rbuf); + freerecvbuf(rbuf); + } +# if defined DEBUG && defined SYS_WINNT + if (debug > 4) + printf("getrecvbufs: %ld handler interrupts, %ld frames\n", + handler_calls, handler_pkts); +# endif + + /* + * Go around again + */ + } +# endif /* HAVE_IO_COMPLETION_PORT */ + exit(1); /* unreachable */ + return 1; /* DEC OSF cc braindamage */ +} + + +#ifdef SIGDIE2 +/* + * finish - exit gracefully + */ +static RETSIGTYPE +finish( + int sig + ) +{ + + msyslog(LOG_NOTICE, "ntpd exiting on signal %d", sig); + + switch (sig) + { +#ifdef SIGBUS + case SIGBUS: + printf("\nfinish(SIGBUS)\n"); + exit(0); +#endif + case 0: /* Should never happen... */ + return; + default: + exit(0); + } +} +#endif /* SIGDIE2 */ + + +#ifdef DEBUG +/* + * moredebug - increase debugging verbosity + */ +static RETSIGTYPE +moredebug( + int sig + ) +{ + int saved_errno = errno; + + if (debug < 255) + { + debug++; + msyslog(LOG_DEBUG, "debug raised to %d", debug); + } + errno = saved_errno; +} + +/* + * lessdebug - decrease debugging verbosity + */ +static RETSIGTYPE +lessdebug( + int sig + ) +{ + int saved_errno = errno; + + if (debug > 0) + { + debug--; + msyslog(LOG_DEBUG, "debug lowered to %d", debug); + } + errno = saved_errno; +} +#else /* not DEBUG */ +/* + * no_debug - We don't do the debug here. + */ +static RETSIGTYPE +no_debug( + int sig + ) +{ + int saved_errno = errno; + + msyslog(LOG_DEBUG, "ntpd not compiled for debugging (signal %d)", sig); + errno = saved_errno; +} +#endif /* not DEBUG */ + +#ifdef SYS_WINNT +/* service_ctrl - control handler for NTP service + * signals the service_main routine of start/stop requests + * from the control panel or other applications making + * win32API calls + */ +void +service_ctrl( + DWORD dwCtrlCode + ) +{ + DWORD dwState = SERVICE_RUNNING; + + /* Handle the requested control code */ + switch(dwCtrlCode) + { + case SERVICE_CONTROL_PAUSE: + /* see no reason to support this */ + break; + + case SERVICE_CONTROL_CONTINUE: + /* see no reason to support this */ + break; + + case SERVICE_CONTROL_STOP: + dwState = SERVICE_STOP_PENDING; + /* + * Report the status, specifying the checkpoint and waithint, + * before setting the termination event. + */ + ssStatus.dwCurrentState = dwState; + ssStatus.dwWin32ExitCode = NO_ERROR; + ssStatus.dwWaitHint = 3000; + if (!SetServiceStatus(sshStatusHandle, &ssStatus)) + { + msyslog(LOG_ERR, "SetServiceStatus: %m"); + } + if (WaitHandles[0] != NULL) { + SetEvent(WaitHandles[0]); + } + return; + + case SERVICE_CONTROL_INTERROGATE: + /* Update the service status */ + break; + + default: + /* invalid control code */ + break; + + } + + ssStatus.dwCurrentState = dwState; + ssStatus.dwWin32ExitCode = NO_ERROR; + if (!SetServiceStatus(sshStatusHandle, &ssStatus)) + { + msyslog(LOG_ERR, "SetServiceStatus: %m"); + } +} + +static BOOL WINAPI +OnConsoleEvent( + DWORD dwCtrlType + ) +{ + switch (dwCtrlType) { + case CTRL_BREAK_EVENT : + if (debug > 0) { + debug <<= 1; + } + else { + debug = 1; + } + if (debug > 8) { + debug = 0; + } + printf("debug level %d\n", debug); + break ; + + case CTRL_C_EVENT : + case CTRL_CLOSE_EVENT : + case CTRL_SHUTDOWN_EVENT : + if (WaitHandles[0] != NULL) { + SetEvent(WaitHandles[0]); + } + break; + + default : + return FALSE; + + + } + return TRUE;; +} + + +/* + * NT version of exit() - all calls to exit() should be routed to + * this function. + */ +void +service_exit( + int status + ) +{ + if (!debug) { /* did not become a service, simply exit */ + /* service mode, need to have the service_main routine + * register with the service control manager that the + * service has stopped running, before exiting + */ + ssStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(sshStatusHandle, &ssStatus); + + } + uninit_io_completion_port(); + reset_winnt_time(); + +# if defined _MSC_VER + _CrtDumpMemoryLeaks(); +# endif +#undef exit + exit(status); +} + +#endif /* SYS_WINNT */ diff --git a/contrib/ntp/ntpd/refclock_acts.c b/contrib/ntp/ntpd/refclock_acts.c new file mode 100644 index 000000000000..9c367b52abe8 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_acts.c @@ -0,0 +1,981 @@ +/* + * refclock_acts - clock driver for the NIST/PTB Automated Computer Time + * Service aka Amalgamated Containerized Trash Service (ACTS) + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && (defined(CLOCK_ACTS) || defined(CLOCK_PTBACTS)) + +#include +#include +#include +#ifdef HAVE_SYS_IOCTL_H +# include +#endif /* HAVE_SYS_IOCTL_H */ + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" +#include "ntp_control.h" + +/* MUST BE AFTER LAST #include !!! */ + +#if defined(CLOCK_ACTS) && defined(CLOCK_PTBACTS) +# if defined(KEEPPTBACTS) +# undef CLOCK_ACTS +# else /* not KEEPPTBACTS */ +# undef CLOCK_PTBACTS +# endif /* not KEEPPTBACTS */ +#endif /* CLOCK_ACTS && CLOCK_PTBACTS */ + +/* + * This driver supports the NIST Automated Computer Time Service (ACTS). + * It periodically dials a prespecified telephone number, receives the + * NIST timecode data and calculates the local clock correction. It is + * designed primarily for use as a backup when neither a radio clock nor + * connectivity to Internet time servers is available. For the best + * accuracy, the individual telephone line/modem delay needs to be + * calibrated using outside sources. + * + * The ACTS is located at NIST Boulder, CO, telephone 303 494 4774. A + * toll call from a residence telephone in Newark, DE, costs between 14 + * and 27 cents, depending on time of day, and from a campus telephone + * between 3 and 4 cents, although it is not clear what carrier and time + * of day discounts apply in this case. The modem dial string will + * differ depending on local telephone configuration, etc., and is + * specified by the phone command in the configuration file. The + * argument to this command is an AT command for a Hayes compatible + * modem. + * + * The accuracy produced by this driver should be in the range of a + * millisecond or two, but may need correction due to the delay + * characteristics of the individual modem involved. For undetermined + * reasons, some modems work with the ACTS echo-delay measurement scheme + * and some don't. This driver tries to do the best it can with what it + * gets. Initial experiments with a Practical Peripherals 9600SA modem + * here in Delaware suggest an accuracy of a millisecond or two can be + * achieved without the scheme by using a fudge time1 value of 65.0 ms. + * In either case, the dispersion for a single call involving ten + * samples is about 1.3 ms. + * + * The driver can operate in either of three modes, as determined by + * the mode parameter in the server configuration command. In mode 0 + * (automatic) the driver operates continuously at intervals depending + * on the prediction error, as measured by the driver, usually in the + * order of several hours. In mode 1 (backup) the driver is enabled in + * automatic mode only when no other source of synchronization is + * available and when more than MAXOUTAGE (3600 s) have elapsed since + * last synchronized by other sources. In mode 2 (manual) the driver + * operates only when enabled using a fudge flags switch, as described + * below. + * + * For reliable call management, this driver requires a 1200-bps modem + * with a Hayes-compatible command set and control over the modem data + * terminal ready (DTR) control line. Present restrictions require the + * use of a POSIX-compatible programming interface, although other + * interfaces may work as well. The modem setup string is hard-coded in + * the driver and may require changes for nonstandard modems or special + * circumstances. + * + * Further information can be found in the README.refclock file in the + * ntp - Version 3 distribution. + * + * Fudge Factors + * + * Ordinarily, the propagation time correction is computed automatically + * by ACTS and the driver. When this is not possible or erratic due to + * individual modem characteristics, the fudge flag2 switch should be + * set to disable the ACTS echo-delay scheme. In any case, the fudge + * time1 parameter can be used to adjust the propagation delay as + * required. + * + * The ACTS call interval is determined in one of three ways. In manual + * mode a call is initiated by setting fudge flag1 using ntpdc, either + * manually or via a cron job. In AUTO mode this flag is set by the peer + * timer, which is controlled by the sys_poll variable in response to + * measured errors. In backup mode the driver is ordinarily asleep, but + * awakes (in auto mode) if all other synchronization sources are lost. + * In either auto or backup modes, the call interval increases as long + * as the measured errors do not exceed the value of the fudge time2 + * parameter. + * + * When the fudge flag1 is set, the ACTS calling program is activated. + * This program dials each number listed in the phones command of the + * configuration file in turn. If a call attempt fails, the next number + * in the list is dialed. The fudge flag1 and counter are reset and the + * calling program terminated if (a) a valid clock update has been + * determined, (b) no more numbers remain in the list, (c) a device + * fault or timeout occurs or (d) fudge flag1 is reset manually using + * ntpdc. + * + * In automatic and backup modes, the driver determines the call + * interval using a procedure depending on the measured prediction + * error and the fudge time2 parameter. If the error exceeds time2 for a + * number of times depending on the current interval, the interval is + * decreased, but not less than about 1000 s. If the error is less than + * time2 for some number of times, the interval is increased, but not + * more than about 18 h. With the default value of zero for fudge time2, + * the interval will increase from 1000 s to the 4000-8000-s range, in + * which the expected accuracy should be in the 1-2-ms range. Setting + * fudge time2 to a large value, like 0.1 s, may result in errors of + * that order, but increase the call interval to the maximum. The exact + * value for each configuration will depend on the modem and operating + * system involved, so some experimentation may be necessary. + */ + +/* + * DESCRIPTION OF THE AUTOMATED COMPUTER TELEPHONE SERVICE (ACTS) + * (reformatted from ACTS on-line computer help information) + * + * The following is transmitted (at 1200 baud) following completion of + * the telephone connection. + * + * National Institute of Standards and Technology + * Telephone Time Service, Generator 3B + * Enter question mark "?" for HELP + * D L D + * MJD YR MO DA H M S ST S UT1 msADV + * 47999 90-04-18 21:39:15 50 0 +.1 045.0 UTC(NIST) * + * 47999 90-04-18 21:39:16 50 0 +.1 045.0 UTC(NIST) * + * 47999 90-04-18 21:39:17 50 0 +.1 045.0 UTC(NIST) * + * 47999 90-04-18 21:39:18 50 0 +.1 045.0 UTC(NIST) * + * 47999 90-04-18 21:39:19 50 0 +.1 037.6 UTC(NIST) # + * 47999 90-04-18 21:39:20 50 0 +.1 037.6 UTC(NIST) # + * etc..etc...etc....... + * + * UTC = Universal Time Coordinated, the official world time referred to + * the zero meridian. + * + * DST Daylight savings time characters, valid for the continental + * U.S., are set as follows: + * + * 00 We are on standard time (ST). + * 01-49 Now on DST, go to ST when your local time is 2:00 am and + * the count is 01. The count is decremented daily at 00 + * (UTC). + * 50 We are on DST. + * 51-99 Now on ST, go to DST when your local time is 2:00 am and + * the count is 51. The count is decremented daily at 00 + * (UTC). + * + * The two DST characters provide up to 48 days advance notice of a + * change in time. The count remains at 00 or 50 at other times. + * + * LS Leap second flag is set to "1" to indicate that a leap second is + * to be added as 23:59:60 (UTC) on the last day of the current UTC + * month. The LS flag will be reset to "0" starting with 23:59:60 + * (UTC). The flag will remain on for the entire month before the + * second is added. Leap seconds are added as needed at the end of + * any month. Usually June and/or December are chosen. + * + * The leap second flag will be set to a "2" to indicate that a + * leap second is to be deleted at 23:59:58--00:00:00 on the last + * day of the current month. (This latter provision is included per + * international recommendation, however it is not likely to be + * required in the near future.) + * + * DUT1 Approximate difference between earth rotation time (UT1) and + * UTC, in steps of 0.1 second: DUT1 = UT1 - UTC. + * + * MJD Modified Julian Date, often used to tag certain scientific data. + * + * The full time format is sent at 1200 baud, 8 bit, 1 stop, no parity. + * The format at 300 Baud is also 8 bit, 1 stop, no parity. At 300 Baud + * the MJD and DUT1 values are deleted and the time is transmitted only + * on even seconds. + * + * Maximum on line time will be 56 seconds. If all lines are busy at any + * time, the oldest call will be terminated if it has been on line more + * than 28 seconds, otherwise, the call that first reaches 28 seconds + * will be terminated. + * + * Current time is valid at the "on-time" marker (OTM), either "*" or + * "#". The nominal on-time marker (*) will be transmitted 45 ms early + * to account for the 8 ms required to send 1 character at 1200 Baud, + * plus an additional 7 ms for delay from NIST to the user, and + * approximately 30 ms "scrambler" delay inherent in 1200 Baud modems. + * If the caller echoes all characters, NIST will measure the round trip + * delay and advance the on-time marker so that the midpoint of the stop + * bit arrives at the user on time. The amount of msADV will reflect the + * actual required advance in milliseconds and the OTM will be a "#". + * + * (The NIST system requires 4 or 5 consecutive delay measurements which + * are consistent before switching from "*" to "#". If the user has a + * 1200 Baud modem with the same internal delay as that used by NIST, + * then the "#" OTM should arrive at the user within +-2 ms of the + * correct time. + * + * However, NIST has studied different brands of 1200 Baud modems and + * found internal delays from 24 ms to 40 ms and offsets of the "#" OTM + * of +-10 ms. For many computer users, +-10 ms accuracy should be more + * than adequate since many computer internal clocks can only be set + * with granularity of 20 to 50 ms. In any case, the repeatability of + * the offset for the "#" OTM should be within +-2 ms, if the dial-up + * path is reciprocal and the user doesn't change the brand or model of + * modem used. + * + * This should be true even if the dial-up path on one day is a land- + * line of less than 40 ms (one way) and on the next day is a satellite + * link of 260 to 300 ms. In the rare event that the path is one way by + * satellite and the other way by land line with a round trip + * measurement in the range of 90 to 260 ms, the OTM will remain a "*" + * indicating 45 ms advance. + * + * For user comments write: + * NIST-ACTS + * Time and Frequency Division + * Mail Stop 847 + * 325 Broadway + * Boulder, CO 80303 + * + * Software for setting (PC)DOS compatable machines is available on a + * 360-kbyte diskette for $35.00 from: NIST Office of Standard Reference + * Materials B311-Chemistry Bldg, NIST, Gaithersburg, MD, 20899, (301) + * 975-6776 + * + * PTB timecode service (+49 531 512038) + * The Physikalisch-Technische Bundesanstalt (Germany) + * also supports a modem time service + * as the data formats are very similar this driver can also be compiled for + * utilizing the PTB time code service. + * + * Data format + * 0000000000111111111122222222223333333333444444444455555555556666666666777777777 7 + * 0123456789012345678901234567890123456789012345678901234567890123456789012345678 9 + * 1995-01-23 20:58:51 MEZ 10402303260219950123195849740+40000500 * + * A B C D EF G H IJ K L M N O P Q R S T U V W XY Z + * + * A year + * B month + * C day + * D hour + * E : normally + * A for DST to ST switch first hour + * B for DST to ST switch second hour if not marked in H + * F minute + * G second + * H timezone + * I day of week + * J week of year + * K day of year + * L month for next ST/DST changes + * M day + * N hour + * O UTC year + * P UTC month + * Q UTC day + * R UTC hour + * S UTC minute + * T modified julian day (MJD) + * U DUT1 + * V direction and month if leap second + * W signal delay (assumed/measured) + * X sequence number for additional text line in Y + * Y additional text + * Z on time marker (* - assumed delay / # measured delay) + * ! ! is second change ! + * + * This format is also used by the National Physical Laboratory (NPL)'s + * TRUETIME service in the UK. In this case the timezone field is + * UTC+0 or UTC+1 for standard and daylight saving time. The phone + * number for this service (a premium rate number) is 0891 516 333. + * It is not clear whether the echo check is implemented. + * + * For more detail, see http://www.npl.co.uk/npl/cetm/taf/truetime.html. + */ + +/* + * Interface definitions + */ +#define SPEED232 B1200 /* uart speed (1200 cowardly baud) */ +#define PRECISION (-10) /* precision assumed (about 1 ms) */ +#ifdef CLOCK_ACTS +# define REFID "ACTS" /* reference ID */ +# define DESCRIPTION "NIST Automated Computer Time Service" /* WRU */ +# define LENCODE 50 /* length of valid timecode string */ +# define DEVICE "/dev/acts%d" /* device name and unit */ +# define REF_ENTRY refclock_acts +#else /* not CLOCK_ACTS */ +# define REFID "TPTB" /* reference ID */ +# define DESCRIPTION "PTB Automated Computer Time Service" +# define LENCODE 78 /* length of valid timecode string */ +# define DEVICE "/dev/ptb%d" /* device name and unit */ +# define REF_ENTRY refclock_ptb +#endif /* not CLOCK_ACTS */ +#define MODE_AUTO 0 /* automatic mode */ +#define MODE_BACKUP 1 /* backup mode */ +#define MODE_MANUAL 2 /* manual mode */ + +#define MSGCNT 10 /* we need this many ACTS messages */ +#define SMAX 80 /* max token string length */ +#define ACTS_MINPOLL 10 /* log2 min poll interval (1024 s) */ +#define ACTS_MAXPOLL 18 /* log2 max poll interval (16384 s) */ +#define MAXOUTAGE 3600 /* max before ACTS kicks in (s) */ + +/* + * Modem control strings. These may have to be changed for some modems. + * + * AT command prefix + * B1 initiate call negotiation using Bell 212A + * &C1 enable carrier detect + * &D2 hang up and return to command mode on DTR transition + * E0 modem command echo disabled + * l1 set modem speaker volume to low level + * M1 speaker enabled untill carrier detect + * Q0 return result codes + * V1 return result codes as English words + */ +#define MODEM_SETUP "ATB1&C1&D2E0L1M1Q0V1" /* modem setup */ +#define MODEM_HANGUP "ATH" /* modem disconnect */ + +/* + * Timeouts + */ +#define IDLE 60 /* idle timeout (s) */ +#define WAIT 2 /* wait timeout (s) */ +#define ANSWER 30 /* answer timeout (s) */ +#define CONNECT 10 /* connect timeout (s) */ +#define TIMECODE 15 /* timecode timeout (s) */ + +/* + * Tables to compute the ddd of year form icky dd/mm timecode. Viva la + * leap. + */ +static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* + * Unit control structure + */ +struct actsunit { + int pollcnt; /* poll message counter */ + int state; /* the first one was Delaware */ + int run; /* call program run switch */ + int msgcnt; /* count of ACTS messages received */ + long redial; /* interval to next automatic call */ + double msADV; /* millisecond advance of last message */ +}; + +/* + * Function prototypes + */ +static int acts_start P((int, struct peer *)); +static void acts_shutdown P((int, struct peer *)); +static void acts_receive P((struct recvbuf *)); +static void acts_poll P((int, struct peer *)); +static void acts_timeout P((struct peer *)); +static void acts_disc P((struct peer *)); +static int acts_write P((struct peer *, const char *)); + +/* + * Transfer vector (conditional structure name) + */ +struct refclock REF_ENTRY = { + acts_start, /* start up driver */ + acts_shutdown, /* shut down driver */ + acts_poll, /* transmit poll message */ + noentry, /* not used (old acts_control) */ + noentry, /* not used (old acts_init) */ + noentry, /* not used (old acts_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * acts_start - open the devices and initialize data for processing + */ + +static int +acts_start ( + int unit, + struct peer *peer + ) +{ + register struct actsunit *up; + struct refclockproc *pp; + int fd; + char device[20]; + int dtr = TIOCM_DTR; + + /* + * Open serial port. Use ACTS line discipline, if available. It + * pumps a timestamp into the data stream at every on-time + * character '*' found. Note: the port must have modem control + * or deep pockets for the phone bill. HP-UX 9.03 users should + * have very deep pockets. + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED232, LDISC_ACTS))) + return (0); + if (ioctl(fd, TIOCMBIS, (char *)&dtr) < 0) { + msyslog(LOG_ERR, "clock %s ACTS no modem control", + ntoa(&peer->srcadr)); + return (0); + } + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct actsunit *) + emalloc(sizeof(struct actsunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct actsunit)); + pp = peer->procptr; + pp->io.clock_recv = acts_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + peer->minpoll = ACTS_MINPOLL; + peer->maxpoll = ACTS_MAXPOLL; + peer->sstclktype = CTL_SST_TS_TELEPHONE; + + /* + * Initialize modem and kill DTR. We skedaddle if this comes + * bum. + */ + if (!acts_write(peer, MODEM_SETUP)) { + (void) close(fd); + free(up); + return (0); + } + + /* + * Set up the driver timeout + */ + peer->nextdate = current_time + WAIT; + return (1); +} + + +/* + * acts_shutdown - shut down the clock + */ +static void +acts_shutdown ( + int unit, + struct peer *peer + ) +{ + register struct actsunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct actsunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * acts_receive - receive data from the serial interface + */ +static void +acts_receive ( + struct recvbuf *rbufp + ) +{ + register struct actsunit *up; + struct refclockproc *pp; + struct peer *peer; + char str[SMAX]; + int i; + char hangup = '%'; /* ACTS hangup */ + int day; /* day of the month */ + int month; /* month of the year */ + u_long mjd; /* Modified Julian Day */ + double dut1; /* DUT adjustment */ + double msADV; /* ACTS transmit advance (ms) */ + char flag; /* calibration flag */ +#ifndef CLOCK_PTBACTS + char utc[10]; /* this is NIST and you're not */ + u_int dst; /* daylight/standard time indicator */ + u_int leap; /* leap-second indicator */ +#else + char leapdir; /* leap direction */ + u_int leapmonth; /* month of leap */ +#endif + /* + * Initialize pointers and read the timecode and timestamp. If + * the OK modem status code, leave it where folks can find it. + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct actsunit *)pp->unitptr; + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, + &pp->lastrec); + if (pp->lencode == 0) { + if (strcmp(pp->a_lastcode, "OK") == 0) + pp->lencode = 2; + return; + } +#ifdef DEBUG + if (debug) + printf("acts: state %d timecode %d %*s\n", up->state, + pp->lencode, pp->lencode, pp->a_lastcode); +#endif + + switch (up->state) { + + case 0: + + /* + * State 0. We are not expecting anything. Probably + * modem disconnect noise. Go back to sleep. + */ + return; + + case 1: + + /* + * State 1. We are waiting for the call to be answered. + * All we care about here is CONNECT as the first token + * in the string. If the modem signals BUSY, ERROR, NO + * ANSWER, NO CARRIER or NO DIALTONE, we immediately + * hang up the phone. If CONNECT doesn't happen after + * ANSWER seconds, hang up the phone. If everything is + * okay, start the connect timeout and slide into state + * 2. + */ + if( strcmp(pp->a_lastcode, " ") == 0) { + acts_disc(peer); + return; + } + if( strcmp(sys_phone[0],"DIRECT") != 0 ) { + (void)strncpy(str, strtok(pp->a_lastcode, " "), SMAX); + if (strcmp(str, "BUSY") == 0 || strcmp(str, "ERROR") == + 0 || strcmp(str, "NO") == 0) { + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, + "clock %s ACTS modem status %s", + ntoa(&peer->srcadr), pp->a_lastcode); + acts_disc(peer); + } else if (strcmp(str, "CONNECT") == 0) { + peer->nextdate = current_time + CONNECT; + up->msgcnt = 0; + up->state++; + } + } else { + (void) strncpy(str,"CONNECT",7); + peer->nextdate = current_time + CONNECT; + up->msgcnt = 0; + up->state++; + } + return; + + case 2: + + /* + * State 2. The call has been answered and we are + * waiting for the first ACTS message. If this doesn't + * happen within the timecode timeout, hang up the + * phone. We probably got a wrong number or ACTS is + * down. + */ + peer->nextdate = current_time + TIMECODE; + up->state++; + } + + /* + * Real yucky things here. Ignore everything except timecode + * messages, as determined by the message length. We told the + * terminal routines to end the line with '*' and the line + * discipline to strike a timestamp on that character. However, + * when the ACTS echo-delay scheme works, the '*' eventually + * becomes a '#'. In this case the message is ended by the + * that comes about 200 ms after the '#' and the '#' cannot be + * echoed at the proper time. But, this may not be a lose, since + * we already have good data from prior messages and only need + * the millisecond advance calculated by ACTS. So, if the + * message is long enough and has an on-time character at the + * right place, we consider the message (but not neccesarily the + * timestmap) to be valid. + */ + if (pp->lencode != LENCODE) + return; + +#ifndef CLOCK_PTBACTS + /* + * We apparently have a valid timecode message, so dismember it + * with sscan(). This routine does a good job in spotting syntax + * errors without becoming overly pedantic. + * + * D L D + * MJD YR MO DA H M S ST S UT1 msADV OTM + * 47222 88-03-02 21:39:15 83 0 +.3 045.0 UTC(NBS) * + */ + if (sscanf(pp->a_lastcode, + "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %s %c", + &mjd, &pp->year, &month, &day, &pp->hour, &pp->minute, + &pp->second, &dst, &leap, &dut1, &msADV, utc, &flag) != 13) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } +#else + /* + * Data format + * 0000000000111111111122222222223333333333444444444455555555556666666666777777777 7 + * 0123456789012345678901234567890123456789012345678901234567890123456789012345678 9 + * 1995-01-23 20:58:51 MEZ 10402303260219950123195849740+40000500 * + */ + if (sscanf(pp->a_lastcode, + "%*4d-%*2d-%*2d %*2d:%*2d:%2d %*5c%*12c%4d%2d%2d%2d%2d%5ld%2lf%c%2d%3lf%*15c%c", + &pp->second, &pp->year, &month, &day, &pp->hour, &pp->minute, &mjd, &dut1, &leapdir, &leapmonth, &msADV, &flag) != 12) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } +#endif + /* + * Some modems can't be trusted (the Practical Peripherals + * 9600SA comes to mind) and, even if they manage to unstick + * ACTS, the millisecond advance is wrong, so we use CLK_FLAG2 + * to disable echoes, if neccessary. + */ + if ((flag == '*' || flag == '#') && !(pp->sloppyclockflag & + CLK_FLAG2)) + (void)write(pp->io.fd, &flag, 1); + + /* + * Yes, I know this code incorrectly thinks that 2000 is a leap + * year. The ACTS timecode format croaks then anyway. Life is + * short. Would only the timecode mavens resist the urge to + * express months of the year and days of the month in favor of + * days of the year. + * NOTE: year 2000 IS a leap year!!! ghealton Y2KFixes + */ + if (month < 1 || month > 12 || day < 1) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + if ( pp->year <= YEAR_PIVOT ) pp->year += 100; /* Y2KFixes */ + if ( !isleap_tm(pp->year) ) { /* Y2KFixes */ + if (day > day1tab[month - 1]) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + for (i = 0; i < month - 1; i++) + day += day1tab[i]; + } else { + if (day > day2tab[month - 1]) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + for (i = 0; i < month - 1; i++) + day += day2tab[i]; + } + pp->day = day; + +#ifndef CLOCK_PTBACTS + if (leap == 1) + pp->leap = LEAP_ADDSECOND; + else if (pp->leap == 2) + pp->leap = LEAP_DELSECOND; +#else + if (leapmonth == month) { + if (leapdir == '+') + pp->leap = LEAP_ADDSECOND; + else if (leapdir == '-') + pp->leap = LEAP_DELSECOND; + } +#endif + + /* + * Colossal hack here. We process each sample in a trimmed-mean + * filter and determine the reference clock offset and + * dispersion. The fudge time1 value is added to each sample as + * received. If we collect MSGCNT samples before the '#' on-time + * character, we use the results of the filter as is. If the '#' + * is found before that, the adjusted msADV is used to correct + * the propagation delay. + */ + up->msgcnt++; + if (flag == '#') { + pp->offset += (msADV - up->msADV) * 1000 * 1e-6; + } else { + up->msADV = msADV; + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } else if (up->msgcnt < MSGCNT) + return; + } + + /* + * We have a filtered sample offset ready for peer processing. + * We use lastrec as both the reference time and receive time in + * order to avoid being cute, like setting the reference time + * later than the receive time, which may cause a paranoid + * protocol module to chuck out the data. Finaly, we unhook the + * timeout, arm for the next call, fold the tent and go home. + * The little dance with the '%' character is an undocumented + * ACTS feature that hangs up the phone real quick without + * waiting for carrier loss or long-space disconnect, but we do + * these clumsy things anyway. + */ + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + pp->sloppyclockflag &= ~CLK_FLAG1; + up->pollcnt = 0; + (void)write(pp->io.fd, &hangup, 1); + up->state = 0; + acts_disc(peer); +} + + +/* + * acts_poll - called by the transmit routine + */ +static void +acts_poll ( + int unit, + struct peer *peer + ) +{ + register struct actsunit *up; + struct refclockproc *pp; + + /* + * If the driver is running, we set the enable flag (fudge + * flag1), which causes the driver timeout routine to initiate a + * call to ACTS. If not, the enable flag can be set using + * ntpdc. If this is the sustem peer, then follow the system + * poll interval. + */ + pp = peer->procptr; + up = (struct actsunit *)pp->unitptr; + + if (up->run) { + pp->sloppyclockflag |= CLK_FLAG1; + if (peer == sys_peer) + peer->hpoll = sys_poll; + else + peer->hpoll = peer->minpoll; + } + acts_timeout (peer); + return; +} + + +/* + * acts_timeout - called by the timer interrupt + */ +static void +acts_timeout ( + struct peer *peer + ) +{ + register struct actsunit *up; + struct refclockproc *pp; + int dtr = TIOCM_DTR; + + /* + * If a timeout occurs in other than state 0, the call has + * failed. If in state 0, we just see if there is other work to + * do. + */ + pp = peer->procptr; + up = (struct actsunit *)pp->unitptr; + if (up->state) { + acts_disc(peer); + return; + } + switch (peer->ttl) { + + /* + * In manual mode the ACTS calling program is activated + * by the ntpdc program using the enable flag (fudge + * flag1), either manually or by a cron job. + */ + case MODE_MANUAL: + up->run = 0; + break; + + /* + * In automatic mode the ACTS calling program runs + * continuously at intervals determined by the sys_poll + * variable. + */ + case MODE_AUTO: + if (!up->run) + pp->sloppyclockflag |= CLK_FLAG1; + up->run = 1; + break; + + /* + * In backup mode the ACTS calling program is disabled, + * unless no system peer has been selected for MAXOUTAGE + * (3600 s). Once enabled, it runs until some other NTP + * peer shows up. + */ + case MODE_BACKUP: + if (!up->run && sys_peer == 0) { + if (current_time - last_time > MAXOUTAGE) { + up->run = 1; + peer->hpoll = peer->minpoll; + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, + "clock %s ACTS backup started ", + ntoa(&peer->srcadr)); + } + } else if (up->run && sys_peer->sstclktype != CTL_SST_TS_TELEPHONE) { + peer->hpoll = peer->minpoll; + up->run = 0; + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, + "clock %s ACTS backup stopped", + ntoa(&peer->srcadr)); + } + break; + + default: + msyslog(LOG_ERR, + "clock %s ACTS invalid mode", ntoa(&peer->srcadr)); + } + + /* + * The fudge flag1 is used as an enable/disable; if set either + * by the code or via ntpdc, the ACTS calling program is + * started; if reset, the phones stop ringing. + */ + if (!(pp->sloppyclockflag & CLK_FLAG1)) { + up->pollcnt = 0; + peer->nextdate = current_time + IDLE; + return; + } + + /* + * Initiate a call to the ACTS service. If we wind up here in + * other than state 0, a successful call could not be completed + * within minpoll seconds. We advance to the next modem dial + * string. If none are left, we log a notice and clear the + * enable flag. For future enhancement: call the site RP and + * leave an obscene message in his voicemail. + */ + if (sys_phone[up->pollcnt][0] == '\0') { + refclock_report(peer, CEVNT_TIMEOUT); + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, + "clock %s ACTS calling program terminated", + ntoa(&peer->srcadr)); + pp->sloppyclockflag &= ~CLK_FLAG1; +#ifdef DEBUG + if (debug) + printf("acts: calling program terminated\n"); +#endif + up->pollcnt = 0; + peer->nextdate = current_time + IDLE; + return; + } + + /* + * Raise DTR, call ACTS and start the answer timeout. We think + * it strange if the OK status has not been received from the + * modem, but plow ahead anyway. + */ + if (strcmp(pp->a_lastcode, "OK") != 0) + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, "clock %s ACTS no modem status", + ntoa(&peer->srcadr)); + (void)ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr); + (void)acts_write(peer, sys_phone[up->pollcnt]); + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, "clock %s ACTS calling %s\n", + ntoa(&peer->srcadr), sys_phone[up->pollcnt]); + up->state = 1; + up->pollcnt++; + pp->polls++; + peer->nextdate = current_time + ANSWER; + return; +} + + +/* + * acts_disc - disconnect the call and wait for the ruckus to cool + */ +static void +acts_disc ( + struct peer *peer + ) +{ + register struct actsunit *up; + struct refclockproc *pp; + int dtr = TIOCM_DTR; + + /* + * We should never get here other than in state 0, unless a call + * has timed out. We drop DTR, which will reliably get the modem + * off the air, even while ACTS is hammering away full tilt. + */ + pp = peer->procptr; + up = (struct actsunit *)pp->unitptr; + (void)ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr); + if (up->state > 0) { + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, "clock %s ACTS call failed %d", + ntoa(&peer->srcadr), up->state); +#ifdef DEBUG + if (debug) + printf("acts: call failed %d\n", up->state); +#endif + up->state = 0; + } + peer->nextdate = current_time + WAIT; +} + + +/* + * acts_write - write a message to the serial port + */ +static int +acts_write ( + struct peer *peer, + const char *str + ) +{ + register struct actsunit *up; + struct refclockproc *pp; + int len; + int code; + char cr = '\r'; + + /* + * Not much to do here, other than send the message, handle + * debug and report faults. + */ + pp = peer->procptr; + up = (struct actsunit *)pp->unitptr; + len = strlen(str); +#ifdef DEBUG + if (debug) + printf("acts: state %d send %d %s\n", up->state, len, + str); +#endif + code = write(pp->io.fd, str, (unsigned)len) == len; + code &= write(pp->io.fd, &cr, 1) == 1; + if (!code) + refclock_report(peer, CEVNT_FAULT); + return (code); +} + +#else +int refclock_acts_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_arbiter.c b/contrib/ntp/ntpd/refclock_arbiter.c new file mode 100644 index 000000000000..045a93a1b773 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_arbiter.c @@ -0,0 +1,429 @@ +/* + * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite + * Controlled Clock + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_ARBITER) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +/* + * This driver supports the Arbiter 1088A/B Satellite Controlled Clock. + * The claimed accuracy of this clock is 100 ns relative to the PPS + * output when receiving four or more satellites. + * + * The receiver should be configured before starting the NTP daemon, in + * order to establish reliable position and operating conditions. It + * does not initiate surveying or hold mode. For use with NTP, the + * daylight savings time feature should be disables (D0 command) and the + * broadcast mode set to operate in UTC (BU command). + * + * The timecode format supported by this driver is selected by the poll + * sequence "B5", which initiates a line in the following format to be + * repeated once per second until turned off by the "B0" poll sequence. + * + * Format B5 (24 ASCII printing characters): + * + * i yy ddd hh:mm:ss.000bbb + * + * on-time = + * i = synchronization flag (' ' = locked, '?' = unlocked) + * yy = year of century + * ddd = day of year + * hh:mm:ss = hours, minutes, seconds + * .000 = fraction of second (not used) + * bbb = tailing spaces for fill + * + * The alarm condition is indicated by a '?' at i, which indicates the + * receiver is not synchronized. In normal operation, a line consisting + * of the timecode followed by the time quality character (TQ) followed + * by the receiver status string (SR) is written to the clockstats file. + * The time quality character is encoded in IEEE P1344 standard: + * + * Format TQ (IEEE P1344 estimated worst-case time quality) + * + * 0 clock locked, maximum accuracy + * F clock failure, time not reliable + * 4 clock unlocked, accuracy < 1 us + * 5 clock unlocked, accuracy < 10 us + * 6 clock unlocked, accuracy < 100 us + * 7 clock unlocked, accuracy < 1 ms + * 8 clock unlocked, accuracy < 10 ms + * 9 clock unlocked, accuracy < 100 ms + * A clock unlocked, accuracy < 1 s + * B clock unlocked, accuracy < 10 s + * + * The status string is encoded as follows: + * + * Format SR (25 ASCII printing characters) + * + * V=vv S=ss T=t P=pdop E=ee + * + * vv = satellites visible + * ss = relative signal strength + * t = satellites tracked + * pdop = position dilution of precision (meters) + * ee = hardware errors + * + * If flag4 is set, an additional line consisting of the receiver + * latitude (LA), longitude (LO) and elevation (LH) (meters) is written + * to this file. If channel B is enabled for deviation mode and connected + * to a 1-PPS signal, the last two numbers on the line are the deviation + * and standard deviation averaged over the last 15 seconds. + */ + +/* + * Interface definitions + */ +#define DEVICE "/dev/gps%d" /* device name and unit */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ +#define PRECISION (-20) /* precision assumed (about 1 us) */ +#define REFID "GPS " /* reference ID */ +#define DESCRIPTION "Arbiter 1088A/B GPS Receiver" /* WRU */ + +#define LENARB 24 /* format B5 timecode length */ +#define MAXSTA 30 /* max length of status string */ +#define MAXPOS 70 /* max length of position string */ + +/* + * ARB unit control structure + */ +struct arbunit { + l_fp laststamp; /* last receive timestamp */ + int tcswitch; /* timecode switch/counter */ + char qualchar; /* IEEE P1344 quality (TQ command) */ + char status[MAXSTA]; /* receiver status (SR command) */ + char latlon[MAXPOS]; /* receiver position (lat/lon/alt) */ +}; + +/* + * Function prototypes + */ +static int arb_start P((int, struct peer *)); +static void arb_shutdown P((int, struct peer *)); +static void arb_receive P((struct recvbuf *)); +static void arb_poll P((int, struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_arbiter = { + arb_start, /* start up driver */ + arb_shutdown, /* shut down driver */ + arb_poll, /* transmit poll message */ + noentry, /* not used (old arb_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old arb_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * arb_start - open the devices and initialize data for processing + */ +static int +arb_start( + int unit, + struct peer *peer + ) +{ + register struct arbunit *up; + struct refclockproc *pp; + int fd; + char device[20]; + + /* + * Open serial port. Use CLK line discipline, if available. + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct arbunit *)emalloc(sizeof(struct arbunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct arbunit)); + pp = peer->procptr; + pp->io.clock_recv = arb_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + write(pp->io.fd, "B0", 2); + return (1); +} + + +/* + * arb_shutdown - shut down the clock + */ +static void +arb_shutdown( + int unit, + struct peer *peer + ) +{ + register struct arbunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct arbunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * arb_receive - receive data from the serial interface + */ +static void +arb_receive( + struct recvbuf *rbufp + ) +{ + register struct arbunit *up; + struct refclockproc *pp; + struct peer *peer; + l_fp trtmp; + int temp; + u_char syncchar; /* synchronization indicator */ + + /* + * Initialize pointers and read the timecode and timestamp + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct arbunit *)pp->unitptr; + temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); + + /* + * Note we get a buffer and timestamp for both a and , + * but only the timestamp is retained. The program first + * sends a TQ and expects the echo followed by the time quality + * character. It then sends a B5 starting the timecode broadcast + * and expects the echo followed some time later by the on-time + * character and then the beginning the timecode + * itself. Finally, at the beginning the next timecode at + * the next second, the program sends a B0 shutting down the + * timecode broadcast. + * + * If flag4 is set, the program snatches the latitude, longitude + * and elevation and writes it to the clockstats file. + */ + if (temp == 0) + return; + pp->lastrec = up->laststamp; + up->laststamp = trtmp; + if (temp < 3) + return; + if (up->tcswitch == 0) { + + /* + * Collect statistics. If nothing is recogized, just + * ignore; sometimes the clock doesn't stop spewing + * timecodes for awhile after the B0 commant. + */ + if (!strncmp(pp->a_lastcode, "TQ", 2)) { + up->qualchar = pp->a_lastcode[2]; + write(pp->io.fd, "SR", 2); + } else if (!strncmp(pp->a_lastcode, "SR", 2)) { + strcpy(up->status, pp->a_lastcode + 2); + if (pp->sloppyclockflag & CLK_FLAG4) + write(pp->io.fd, "LA", 2); + else { + write(pp->io.fd, "B5", 2); + up->tcswitch++; + } + } else if (!strncmp(pp->a_lastcode, "LA", 2)) { + strcpy(up->latlon, pp->a_lastcode + 2); + write(pp->io.fd, "LO", 2); + } else if (!strncmp(pp->a_lastcode, "LO", 2)) { + strcat(up->latlon, " "); + strcat(up->latlon, pp->a_lastcode + 2); + write(pp->io.fd, "LH", 2); + } else if (!strncmp(pp->a_lastcode, "LH", 2)) { + strcat(up->latlon, " "); + strcat(up->latlon, pp->a_lastcode + 2); + write(pp->io.fd, "DB", 2); + } else if (!strncmp(pp->a_lastcode, "DB", 2)) { + strcat(up->latlon, " "); + strcat(up->latlon, pp->a_lastcode + 2); + record_clock_stats(&peer->srcadr, up->latlon); + write(pp->io.fd, "B5", 2); + up->tcswitch++; + } + return; + } + pp->lencode = temp; + + /* + * We get down to business, check the timecode format and decode + * its contents. If the timecode has valid length, but not in + * proper format, we declare bad format and exit. If the + * timecode has invalid length, which sometimes occurs when the + * B0 amputates the broadcast, we just quietly steal away. Note + * that the time quality character and receiver status string is + * tacked on the end for clockstats display. + */ + if (pp->lencode == LENARB) { + /* + * Timecode format B5: "i yy ddd hh:mm:ss.000 " + */ + pp->a_lastcode[LENARB - 2] = up->qualchar; + strcat(pp->a_lastcode, up->status); + syncchar = ' '; + if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d", + &syncchar, &pp->year, &pp->day, &pp->hour, + &pp->minute, &pp->second) != 6) { + refclock_report(peer, CEVNT_BADREPLY); + write(pp->io.fd, "B0", 2); + return; + } + } else { + write(pp->io.fd, "B0", 2); + return; + } + up->tcswitch++; + + /* + * We decode the clock dispersion from the time quality + * character. + */ + switch (up->qualchar) { + + case '0': /* locked, max accuracy */ + pp->disp = 1e-7; + break; + + case '4': /* unlock accuracy < 1 us */ + pp->disp = 1e-6; + break; + + case '5': /* unlock accuracy < 10 us */ + pp->disp = 1e-5; + break; + + case '6': /* unlock accuracy < 100 us */ + pp->disp = 1e-4; + break; + + case '7': /* unlock accuracy < 1 ms */ + pp->disp = .001; + break; + + case '8': /* unlock accuracy < 10 ms */ + pp->disp = .01; + break; + + case '9': /* unlock accuracy < 100 ms */ + pp->disp = .1; + break; + + case 'A': /* unlock accuracy < 1 s */ + pp->disp = 1; + break; + + case 'B': /* unlock accuracy < 10 s */ + pp->disp = 10; + break; + + case 'F': /* clock failure */ + pp->disp = MAXDISPERSE; + refclock_report(peer, CEVNT_FAULT); + write(pp->io.fd, "B0", 2); + return; + + default: + pp->disp = MAXDISPERSE; + refclock_report(peer, CEVNT_BADREPLY); + write(pp->io.fd, "B0", 2); + return; + } + if (syncchar != ' ') + pp->leap = LEAP_NOTINSYNC; + else + pp->leap = LEAP_NOWARNING; +#ifdef DEBUG + if (debug) + printf("arbiter: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + if (up->tcswitch >= NSTAGE) + write(pp->io.fd, "B0", 2); + + /* + * Process the new sample in the median filter and determine the + * timecode timestamp. + */ + if (!refclock_process(pp)) + refclock_report(peer, CEVNT_BADTIME); +} + + +/* + * arb_poll - called by the transmit procedure + */ +static void +arb_poll( + int unit, + struct peer *peer + ) +{ + register struct arbunit *up; + struct refclockproc *pp; + + /* + * Time to poll the clock. The Arbiter clock responds to a "B5" + * by returning a timecode in the format specified above. + * Transmission occurs once per second, unless turned off by a + * "B0". Note there is no checking on state, since this may not + * be the only customer reading the clock. Only one customer + * need poll the clock; all others just listen in. If nothing is + * heard from the clock for two polls, declare a timeout and + * keep going. + */ + pp = peer->procptr; + up = (struct arbunit *)pp->unitptr; + up->tcswitch = 0; + if (write(pp->io.fd, "TQ", 2) != 2) { + refclock_report(peer, CEVNT_FAULT); + } else + pp->polls++; + if (pp->coderecv == pp->codeproc) { + refclock_report(peer, CEVNT_TIMEOUT); + return; + } + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); +} + +#else +int refclock_arbiter_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_arc.c b/contrib/ntp/ntpd/refclock_arc.c new file mode 100644 index 000000000000..1db8a9a51241 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_arc.c @@ -0,0 +1,1323 @@ +/* + * refclock_arc - clock driver for ARCRON MSF receivers + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_ARCRON_MSF) +static const char arc_version[] = { "V1.1 1997/06/23" }; + +#undef ARCRON_DEBUG /* Define only while in development... */ + +#ifndef ARCRON_NOT_KEEN +#define ARCRON_KEEN 1 /* Be keen, and trusting of the clock, if defined. */ +#endif + +#ifndef ARCRON_NOT_MULTIPLE_SAMPLES +#define ARCRON_MULTIPLE_SAMPLES 1 /* Use all timestamp bytes as samples. */ +#endif + +#ifndef ARCRON_NOT_LEAPSECOND_KEEN +#ifndef ARCRON_LEAPSECOND_KEEN +#undef ARCRON_LEAPSECOND_KEEN /* Respond quickly to leap seconds: doesn't work yet. */ +#endif +#endif + +/* +Code by Derek Mulcahy, , 1997. +Modifications by Damon Hart-Davis, , 1997. + +THIS CODE IS SUPPLIED AS IS, WITH NO WARRANTY OF ANY KIND. USE AT +YOUR OWN RISK. + +Orginally developed and used with ntp3-5.85 by Derek Mulcahy. + +Built against ntp3-5.90 on Solaris 2.5 using gcc 2.7.2. + +This code may be freely copied and used and incorporated in other +systems providing the disclaimer and notice of authorship are +reproduced. + +------------------------------------------------------------------------------- + +Author's original note: + +I enclose my ntp driver for the Galleon Systems Arc MSF receiver. + +It works (after a fashion) on both Solaris-1 and Solaris-2. + +I am currently using ntp3-5.85. I have been running the code for +about 7 months without any problems. Even coped with the change to BST! + +I had to do some funky things to read from the clock because it uses the +power from the receive lines to drive the transmit lines. This makes the +code look a bit stupid but it works. I also had to put in some delays to +allow for the turnaround time from receive to transmit. These delays +are between characters when requesting a time stamp so that shouldn't affect +the results too drastically. + +... + +The bottom line is that it works but could easily be improved. You are +free to do what you will with the code. I haven't been able to determine +how good the clock is. I think that this requires a known good clock +to compare it against. + +------------------------------------------------------------------------------- + +Damon's notes for adjustments: + +MAJOR CHANGES SINCE V1.0 +======================== + 1) Removal of pollcnt variable that made the clock go permanently + off-line once two time polls failed to gain responses. + + 2) Avoiding (at least on Solaris-2) terminal becoming the controlling + terminal of the process when we do a low-level open(). + + 3) Additional logic (conditional on ARCRON_LEAPSECOND_KEEN being + defined) to try to resync quickly after a potential leap-second + insertion or deletion. + + 4) Code significantly slimmer at run-time than V1.0. + + +GENERAL +======= + + 1) The C preprocessor symbol to have the clock built has been changed + from ARC to ARCRON_MSF to CLOCK_ARCRON_MSF to minimise the + possiblity of clashes with other symbols in the future. + + 2) PRECISION should be -4/-5 (63ms/31ms) for the following reasons: + + a) The ARC documentation claims the internal clock is (only) + accurate to about 20ms relative to Rugby (plus there must be + noticable drift and delay in the ms range due to transmission + delays and changing atmospheric effects). This clock is not + designed for ms accuracy as NTP has spoilt us all to expect. + + b) The clock oscillator looks like a simple uncompensated quartz + crystal of the sort used in digital watches (ie 32768Hz) which + can have large temperature coefficients and drifts; it is not + clear if this oscillator is properly disciplined to the MSF + transmission, but as the default is to resync only once per + *day*, we can imagine that it is not, and is free-running. We + can minimise drift by resyncing more often (at the cost of + reduced battery life), but drift/wander may still be + significant. + + c) Note that the bit time of 3.3ms adds to the potential error in + the the clock timestamp, since the bit clock of the serial link + may effectively be free-running with respect to the host clock + and the MSF clock. Actually, the error is probably 1/16th of + the above, since the input data is probably sampled at at least + 16x the bit rate. + + By keeping the clock marked as not very precise, it will have a + fairly large dispersion, and thus will tend to be used as a + `backup' time source and sanity checker, which this clock is + probably ideal for. For an isolated network without other time + sources, this clock can probably be expected to provide *much* + better than 1s accuracy, which will be fine. + + By default, PRECISION is set to -4, but experience, especially at a + particular geographic location with a particular clock, may allow + this to be altered to -5. (Note that skews of +/- 10ms are to be + expected from the clock from time-to-time.) This improvement of + reported precision can be instigated by setting flag3 to 1, though + the PRECISION will revert to the normal value while the clock + signal quality is unknown whatever the flag3 setting. + + IN ANY CASE, BE SURE TO SET AN APPROPRIATE FUDGE FACTOR TO REMOVE + ANY RESIDUAL SKEW, eg: + + server 127.127.27.0 # ARCRON MSF radio clock unit 0. + # Fudge timestamps by about 20ms. + fudge 127.127.27.0 time1 0.020 + + You will need to observe your system's behaviour, assuming you have + some other NTP source to compare it with, to work out what the + fudge factor should be. For my Sun SS1 running SunOS 4.1.3_U1 with + my MSF clock with my distance from the MSF transmitter, +20ms + seemed about right, after some observation. + + 3) REFID has been made "MSFa" to reflect the MSF time source and the + ARCRON receiver. + + 4) DEFAULT_RESYNC_TIME is the time in seconds (by default) before + forcing a resync since the last attempt. This is picked to give a + little less than an hour between resyncs and to try to avoid + clashing with any regular event at a regular time-past-the-hour + which might cause systematic errors. + + The INITIAL_RESYNC_DELAY is to avoid bothering the clock and + running down its batteries unnecesarily if ntpd is going to crash + or be killed or reconfigured quickly. If ARCRON_KEEN is defined + then this period is long enough for (with normal polling rates) + enough time samples to have been taken to allow ntpd to sync to + the clock before the interruption for the clock to resync to MSF. + This avoids ntpd syncing to another peer first and then + almost immediately hopping to the MSF clock. + + The RETRY_RESYNC_TIME is used before rescheduling a resync after a + resync failed to reveal a statisfatory signal quality (too low or + unknown). + + 5) The clock seems quite jittery, so I have increased the + median-filter size from the typical (previous) value of 3. I + discard up to half the results in the filter. It looks like maybe + 1 sample in 10 or so (maybe less) is a spike, so allow the median + filter to discard at least 10% of its entries or 1 entry, whichever + is greater. + + 6) Sleeping *before* each character sent to the unit to allow required + inter-character time but without introducting jitter and delay in + handling the response if possible. + + 7) If the flag ARCRON_KEEN is defined, take time samples whenever + possible, even while resyncing, etc. We rely, in this case, on the + clock always giving us a reasonable time or else telling us in the + status byte at the end of the timestamp that it failed to sync to + MSF---thus we should never end up syncing to completely the wrong + time. + + 8) If the flag ARCRON_OWN_FILTER is defined, use own versions of + refclock median-filter routines to get round small bug in 3-5.90 + code which does not return the median offset. XXX Removed this + bit due NTP Version 4 upgrade - dlm. + + 9) We would appear to have a year-2000 problem with this clock since + it returns only the two least-significant digits of the year. But + ntpd ignores the year and uses the local-system year instead, so + this is in fact not a problem. Nevertheless, we attempt to do a + sensible thing with the dates, wrapping them into a 100-year + window. + + 10)Logs stats information that can be used by Derek's Tcl/Tk utility + to show the status of the clock. + + 11)The clock documentation insists that the number of bits per + character to be sent to the clock, and sent by it, is 11, including + one start bit and two stop bits. The data format is either 7+even + or 8+none. + + +TO-DO LIST +========== + + * Eliminate use of scanf(), and maybe sprintf(). + + * Allow user setting of resync interval to trade battery life for + accuracy; maybe could be done via fudge factor or unit number. + + * Possibly note the time since the last resync of the MSF clock to + MSF as the age of the last reference timestamp, ie trust the + clock's oscillator not very much... + + * Add very slow auto-adjustment up to a value of +/- time2 to correct + for long-term errors in the clock value (time2 defaults to 0 so the + correction would be disabled by default). + + * Consider trying to use the tty_clk/ppsclock support. + + * Possibly use average or maximum signal quality reported during + resync, rather than just the last one, which may be atypical. + +*/ + + +/* Notes for HKW Elektronik GmBH Radio clock driver */ +/* Author Lyndon David, Sentinet Ltd, Feb 1997 */ +/* These notes seem also to apply usefully to the ARCRON clock. */ + +/* The HKW clock module is a radio receiver tuned into the Rugby */ +/* MSF time signal tranmitted on 60 kHz. The clock module connects */ +/* to the computer via a serial line and transmits the time encoded */ +/* in 15 bytes at 300 baud 7 bits two stop bits even parity */ + +/* Clock communications, from the datasheet */ +/* All characters sent to the clock are echoed back to the controlling */ +/* device. */ +/* Transmit time/date information */ +/* syntax ASCII o */ +/* Character o may be replaced if neccesary by a character whose code */ +/* contains the lowest four bits f(hex) eg */ +/* syntax binary: xxxx1111 00001101 */ + +/* DHD note: +You have to wait for character echo + 10ms before sending next character. +*/ + +/* The clock replies to this command with a sequence of 15 characters */ +/* which contain the complete time and a final making 16 characters */ +/* in total. */ +/* The RC computer clock will not reply immediately to this command because */ +/* the start bit edge of the first reply character marks the beginning of */ +/* the second. So the RC Computer Clock will reply to this command at the */ +/* start of the next second */ +/* The characters have the following meaning */ +/* 1. hours tens */ +/* 2. hours units */ +/* 3. minutes tens */ +/* 4. minutes units */ +/* 5. seconds tens */ +/* 6. seconds units */ +/* 7. day of week 1-monday 7-sunday */ +/* 8. day of month tens */ +/* 9. day of month units */ +/* 10. month tens */ +/* 11. month units */ +/* 12. year tens */ +/* 13. year units */ +/* 14. BST/UTC status */ +/* bit 7 parity */ +/* bit 6 always 0 */ +/* bit 5 always 1 */ +/* bit 4 always 1 */ +/* bit 3 always 0 */ +/* bit 2 =1 if UTC is in effect, complementary to the BST bit */ +/* bit 1 =1 if BST is in effect, according to the BST bit */ +/* bit 0 BST/UTC change impending bit=1 in case of change impending */ +/* 15. status */ +/* bit 7 parity */ +/* bit 6 always 0 */ +/* bit 5 always 1 */ +/* bit 4 always 1 */ +/* bit 3 =1 if low battery is detected */ +/* bit 2 =1 if the very last reception attempt failed and a valid */ +/* time information already exists (bit0=1) */ +/* =0 if the last reception attempt was successful */ +/* bit 1 =1 if at least one reception since 2:30 am was successful */ +/* =0 if no reception attempt since 2:30 am was successful */ +/* bit 0 =1 if the RC Computer Clock contains valid time information */ +/* This bit is zero after reset and one after the first */ +/* successful reception attempt */ + +/* DHD note: +Also note g command which confirms that a resync is in progress, and +if so what signal quality (0--5) is available. +Also note h command which starts a resync to MSF signal. +*/ + + + +#include +#include +#include + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(HAVE_TERMIOS) +#include +#endif + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +/* + * This driver supports the ARCRON MSF Radio Controlled Clock + */ + +/* + * Interface definitions + */ +#define DEVICE "/dev/arc%d" /* Device name and unit. */ +#define SPEED B300 /* UART speed (300 baud) */ +#define PRECISION (-4) /* Precision (~63 ms). */ +#define HIGHPRECISION (-5) /* If things are going well... */ +#define REFID "MSFa" /* Reference ID. */ +#define DESCRIPTION "ARCRON MSF Receiver" + +#define NSAMPLESLONG 8 /* Stages of long filter. */ + +#define LENARC 16 /* Format `o' timecode length. */ + +#define BITSPERCHAR 11 /* Bits per character. */ +#define BITTIME 0x0DA740E /* Time for 1 bit at 300bps. */ +#define CHARTIME10 0x8888888 /* Time for 10-bit char at 300bps. */ +#define CHARTIME11 0x962FC96 /* Time for 11-bit char at 300bps. */ +#define CHARTIME /* Time for char at 300bps. */ \ +( (BITSPERCHAR == 11) ? CHARTIME11 : ( (BITSPERCHAR == 10) ? CHARTIME10 : \ + (BITSPERCHAR * BITTIME) ) ) + + /* Allow for UART to accept char half-way through final stop bit. */ +#define INITIALOFFSET (u_int32)(-BITTIME/2) + + /* + charoffsets[x] is the time after the start of the second that byte + x (with the first byte being byte 1) is received by the UART, + assuming that the initial edge of the start bit of the first byte + is on-time. The values are represented as the fractional part of + an l_fp. + + We store enough values to have the offset of each byte including + the trailing \r, on the assumption that the bytes follow one + another without gaps. + */ + static const u_int32 charoffsets[LENARC+1] = { +#if BITSPERCHAR == 11 /* Usual case. */ + /* Offsets computed as accurately as possible... */ + 0, + INITIALOFFSET + 0x0962fc96, /* 1 chars, 11 bits */ + INITIALOFFSET + 0x12c5f92c, /* 2 chars, 22 bits */ + INITIALOFFSET + 0x1c28f5c3, /* 3 chars, 33 bits */ + INITIALOFFSET + 0x258bf259, /* 4 chars, 44 bits */ + INITIALOFFSET + 0x2eeeeeef, /* 5 chars, 55 bits */ + INITIALOFFSET + 0x3851eb85, /* 6 chars, 66 bits */ + INITIALOFFSET + 0x41b4e81b, /* 7 chars, 77 bits */ + INITIALOFFSET + 0x4b17e4b1, /* 8 chars, 88 bits */ + INITIALOFFSET + 0x547ae148, /* 9 chars, 99 bits */ + INITIALOFFSET + 0x5dddddde, /* 10 chars, 110 bits */ + INITIALOFFSET + 0x6740da74, /* 11 chars, 121 bits */ + INITIALOFFSET + 0x70a3d70a, /* 12 chars, 132 bits */ + INITIALOFFSET + 0x7a06d3a0, /* 13 chars, 143 bits */ + INITIALOFFSET + 0x8369d037, /* 14 chars, 154 bits */ + INITIALOFFSET + 0x8ccccccd, /* 15 chars, 165 bits */ + INITIALOFFSET + 0x962fc963 /* 16 chars, 176 bits */ +#else + /* Offsets computed with a small rounding error... */ + 0, + INITIALOFFSET + 1 * CHARTIME, + INITIALOFFSET + 2 * CHARTIME, + INITIALOFFSET + 3 * CHARTIME, + INITIALOFFSET + 4 * CHARTIME, + INITIALOFFSET + 5 * CHARTIME, + INITIALOFFSET + 6 * CHARTIME, + INITIALOFFSET + 7 * CHARTIME, + INITIALOFFSET + 8 * CHARTIME, + INITIALOFFSET + 9 * CHARTIME, + INITIALOFFSET + 10 * CHARTIME, + INITIALOFFSET + 11 * CHARTIME, + INITIALOFFSET + 12 * CHARTIME, + INITIALOFFSET + 13 * CHARTIME, + INITIALOFFSET + 14 * CHARTIME, + INITIALOFFSET + 15 * CHARTIME, + INITIALOFFSET + 16 * CHARTIME +#endif + }; + +/* Chose filter length dependent on fudge flag 4. */ +#define CHOSENSAMPLES(pp) \ +(((pp)->sloppyclockflag & CLK_FLAG4) ? NSAMPLESLONG : NSAMPLES) + /* +Chose how many filter samples to keep. Several factors are in play. + + 1) Discard at least one sample to allow a spike value to be + discarded. + + 2) Discard about 1-in-8 to 1-in-30 samples to handle spikes. + + 3) Keep an odd number of samples to avoid median value being biased + high or low. +*/ +#define NKEEP(pp) ((CHOSENSAMPLES(pp) - 1 - (CHOSENSAMPLES(pp)>>3)) | 1) + +#define DEFAULT_RESYNC_TIME (57*60) /* Gap between resync attempts (s). */ +#define RETRY_RESYNC_TIME (27*60) /* Gap to emergency resync attempt. */ +#ifdef ARCRON_KEEN +#define INITIAL_RESYNC_DELAY 500 /* Delay before first resync. */ +#else +#define INITIAL_RESYNC_DELAY 50 /* Delay before first resync. */ +#endif + + static const int moff[12] = +{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; +/* Flags for a raw open() of the clock serial device. */ +#ifdef O_NOCTTY /* Good, we can avoid tty becoming controlling tty. */ +#define OPEN_FLAGS (O_RDWR | O_NOCTTY) +#else /* Oh well, it may not matter... */ +#define OPEN_FLAGS (O_RDWR) +#endif + + +/* Length of queue of command bytes to be sent. */ +#define CMDQUEUELEN 4 /* Enough for two cmds + each \r. */ +/* Queue tick time; interval in seconds between chars taken off queue. */ +/* Must be >= 2 to allow o\r response to come back uninterrupted. */ +#define QUEUETICK 2 /* Allow o\r reply to finish. */ + +/* + * ARC unit control structure + */ +struct arcunit { + l_fp lastrec; /* Time tag for the receive time (system). */ + int status; /* Clock status. */ + + int quality; /* Quality of reception 0--5 for unit. */ + /* We may also use the values -1 or 6 internally. */ + + u_long next_resync; /* Next resync time (s) compared to current_time. */ + int resyncing; /* Resync in progress if true. */ + + /* In the outgoing queue, cmdqueue[0] is next to be sent. */ + char cmdqueue[CMDQUEUELEN+1]; /* Queue of outgoing commands + \0. */ + + u_long saved_flags; /* Saved fudge flags. */ +}; +#ifdef ARCRON_LEAPSECOND_KEEN +/* The flag `possible_leap' is set non-zero when any MSF unit + thinks a leap-second may have happened. + + Set whenever we receive a valid time sample in the first hour of + the first day of the first/seventh months. + + Outside the special hour this value is unconditionally set + to zero by the receive routine. + + On finding itself in this timeslot, as long as the value is + non-negative, the receive routine sets it to a positive value to + indicate a resync to MSF should be performed. + + In the poll routine, if this value is positive and we are not + already resyncing (eg from a sync that started just before + midnight), start resyncing and set this value negative to + indicate that a leap-triggered resync has been started. Having + set this negative prevents the receive routine setting it + positive and thus prevents multiple resyncs during the witching + hour. + */ +static int possible_leap = 0; /* No resync required by default. */ +#endif + +#if 0 +static void dummy_event_handler P((struct peer *)); +static void arc_event_handler P((struct peer *)); +#endif /* 0 */ + +#define QUALITY_UNKNOWN -1 /* Indicates unknown clock quality. */ +#define MIN_CLOCK_QUALITY 0 /* Min quality clock will return. */ +#define MIN_CLOCK_QUALITY_OK 3 /* Min quality for OK reception. */ +#define MAX_CLOCK_QUALITY 5 /* Max quality clock will return. */ + +/* + * Function prototypes + */ +static int arc_start P((int, struct peer *)); +static void arc_shutdown P((int, struct peer *)); +static void arc_receive P((struct recvbuf *)); +static void arc_poll P((int, struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_arc = { + arc_start, /* start up driver */ + arc_shutdown, /* shut down driver */ + arc_poll, /* transmit poll message */ + noentry, /* not used (old arc_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old arc_buginfo) */ + NOFLAGS /* not used */ +}; + +/* Queue us up for the next tick. */ +#define ENQUEUE(up) \ + do { \ + if((up)->ev.next != 0) { break; } /* WHOOPS! */ \ + peer->nextdate = current_time + QUEUETICK; \ + } while(0) + +#if 0 +/* Placeholder event handler---does nothing safely---soaks up lose tick. */ +static void +dummy_event_handler( + struct peer *peer + ) +{ +#ifdef ARCRON_DEBUG + if(debug) { printf("arc: dummy_event_handler() called.\n"); } +#endif +} + +/* +Normal event handler. + +Take first character off queue and send to clock if not a null. + +Shift characters down and put a null on the end. + +We assume that there is no parallelism so no race condition, but even +if there is nothing bad will happen except that we might send some bad +data to the clock once in a while. +*/ +static void +arc_event_handler( + struct peer *peer + ) +{ + struct refclockproc *pp = peer->procptr; + register struct arcunit *up = (struct arcunit *)pp->unitptr; + int i; + char c; +#ifdef ARCRON_DEBUG + if(debug > 2) { printf("arc: arc_event_handler() called.\n"); } +#endif + + c = up->cmdqueue[0]; /* Next char to be sent. */ + /* Shift down characters, shifting trailing \0 in at end. */ + for(i = 0; i < CMDQUEUELEN; ++i) + { up->cmdqueue[i] = up->cmdqueue[i+1]; } + + /* Don't send '\0' characters. */ + if(c != '\0') { + if(write(pp->io.fd, &c, 1) != 1) { + msyslog(LOG_NOTICE, "ARCRON: write to fd %d failed", pp->io.fd); + } +#ifdef ARCRON_DEBUG + else if(debug) { printf("arc: sent `%2.2x', fd %d.\n", c, pp->io.fd); } +#endif + } +} +#endif /* 0 */ + +/* + * arc_start - open the devices and initialize data for processing + */ +static int +arc_start( + int unit, + struct peer *peer + ) +{ + register struct arcunit *up; + struct refclockproc *pp; + int fd; + char device[20]; +#ifdef HAVE_TERMIOS + struct termios arg; +#endif + + msyslog(LOG_NOTICE, "ARCRON: %s: opening unit %d", arc_version, unit); +#ifdef ARCRON_DEBUG + if(debug) { + printf("arc: %s: attempt to open unit %d.\n", arc_version, unit); + } +#endif + + /* Prevent a ridiculous device number causing overflow of device[]. */ + if((unit < 0) || (unit > 255)) { return(0); } + + /* + * Open serial port. Use CLK line discipline, if available. + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED, LDISC_CLK))) + return(0); +#ifdef ARCRON_DEBUG + if(debug) { printf("arc: unit %d using open().\n", unit); } +#endif + fd = open(device, OPEN_FLAGS); + if(fd < 0) { +#ifdef DEBUG + if(debug) { printf("arc: failed [open()] to open %s.\n", device); } +#endif + return(0); + } + + fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */ +#ifdef ARCRON_DEBUG + if(debug) + { printf("Opened RS232 port with file descriptor %d.\n", fd); } +#endif + +#ifdef HAVE_TERMIOS + + arg.c_iflag = IGNBRK | ISTRIP; + arg.c_oflag = 0; + arg.c_cflag = B300 | CS8 | CREAD | CLOCAL | CSTOPB; + arg.c_lflag = 0; + arg.c_cc[VMIN] = 1; + arg.c_cc[VTIME] = 0; + + tcsetattr(fd, TCSANOW, &arg); + +#else + + msyslog(LOG_ERR, "ARCRON: termios not supported in this driver"); + (void)close(fd); + + return 0; + +#endif + + up = (struct arcunit *) emalloc(sizeof(struct arcunit)); + if(!up) { (void) close(fd); return(0); } + /* Set structure to all zeros... */ + memset((char *)up, 0, sizeof(struct arcunit)); + pp = peer->procptr; + pp->io.clock_recv = arc_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if(!io_addclock(&pp->io)) { (void) close(fd); free(up); return(0); } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + peer->stratum = 2; /* Default to stratum 2 not 0. */ + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + /* Spread out resyncs so that they should remain separated. */ + up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009; + +#if 0 /* Not needed because of zeroing of arcunit structure... */ + up->resyncing = 0; /* Not resyncing yet. */ + up->saved_flags = 0; /* Default is all flags off. */ + /* Clear send buffer out... */ + { + int i; + for(i = CMDQUEUELEN; i >= 0; --i) { up->cmdqueue[i] = '\0'; } + } +#endif + +#ifdef ARCRON_KEEN + up->quality = QUALITY_UNKNOWN; /* Trust the clock immediately. */ +#else + up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */ +#endif + return(1); +} + + +/* + * arc_shutdown - shut down the clock + */ +static void +arc_shutdown( + int unit, + struct peer *peer + ) +{ + register struct arcunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct arcunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + +/* +Compute space left in output buffer. +*/ +static int +space_left( + register struct arcunit *up + ) +{ + int spaceleft; + + /* Compute space left in buffer after any pending output. */ + for(spaceleft = 0; spaceleft < CMDQUEUELEN; ++spaceleft) + { if(up->cmdqueue[CMDQUEUELEN - 1 - spaceleft] != '\0') { break; } } + return(spaceleft); +} + +/* +Send command by copying into command buffer as far forward as possible, +after any pending output. + +Indicate an error by returning 0 if there is not space for the command. +*/ +static int +send_slow( + register struct arcunit *up, + int fd, + const char *s + ) +{ + int sl = strlen(s); + int spaceleft = space_left(up); + +#ifdef ARCRON_DEBUG + if(debug > 1) { printf("arc: spaceleft = %d.\n", spaceleft); } +#endif + if(spaceleft < sl) { /* Should not normally happen... */ +#ifdef ARCRON_DEBUG + msyslog(LOG_NOTICE, "ARCRON: send-buffer overrun (%d/%d)", + sl, spaceleft); +#endif + return(0); /* FAILED! */ + } + + /* Copy in the command to be sent. */ + while(*s) { up->cmdqueue[CMDQUEUELEN - spaceleft--] = *s++; } + + return(1); +} + + +/* Macro indicating action we will take for different quality values. */ +#define quality_action(q) \ +(((q) == QUALITY_UNKNOWN) ? "UNKNOWN, will use clock anyway" : \ + (((q) < MIN_CLOCK_QUALITY_OK) ? "TOO POOR, will not use clock" : \ + "OK, will use clock")) + + /* + * arc_receive - receive data from the serial interface + */ + static void +arc_receive( + struct recvbuf *rbufp + ) +{ + register struct arcunit *up; + struct refclockproc *pp; + struct peer *peer; + char c; + int i, n, wday, month, bst, status; + int arc_last_offset; + + /* + * Initialize pointers and read the timecode and timestamp + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct arcunit *)pp->unitptr; + + + /* + If the command buffer is empty, and we are resyncing, insert a + g\r quality request into it to poll for signal quality again. + */ + if((up->resyncing) && (space_left(up) == CMDQUEUELEN)) { +#ifdef DEBUG + if(debug > 1) { printf("arc: inserting signal-quality poll.\n"); } +#endif + send_slow(up, pp->io.fd, "g\r"); + } + + /* + The `arc_last_offset' is the offset in lastcode[] of the last byte + received, and which we assume actually received the input + timestamp. + + (When we get round to using tty_clk and it is available, we + assume that we will receive the whole timecode with the + trailing \r, and that that \r will be timestamped. But this + assumption also works if receive the characters one-by-one.) + */ + arc_last_offset = pp->lencode+rbufp->recv_length - 1; + + /* + We catch a timestamp iff: + + * The command code is `o' for a timestamp. + + * If ARCRON_MULTIPLE_SAMPLES is undefined then we must have + exactly char in the buffer (the command code) so that we + only sample the first character of the timecode as our + `on-time' character. + + * The first character in the buffer is not the echoed `\r' + from the `o` command (so if we are to timestamp an `\r' it + must not be first in the receive buffer with lencode==1. + (Even if we had other characters following it, we probably + would have a premature timestamp on the '\r'.) + + * We have received at least one character (I cannot imagine + how it could be otherwise, but anyway...). + */ + c = rbufp->recv_buffer[0]; + if((pp->a_lastcode[0] == 'o') && +#ifndef ARCRON_MULTIPLE_SAMPLES + (pp->lencode == 1) && +#endif + ((pp->lencode != 1) || (c != '\r')) && + (arc_last_offset >= 1)) { + /* Note that the timestamp should be corrected if >1 char rcvd. */ + l_fp timestamp; + timestamp = rbufp->recv_time; +#ifdef DEBUG + if(debug) { /* Show \r as `R', other non-printing char as `?'. */ + printf("arc: stamp -->%c<-- (%d chars rcvd)\n", + ((c == '\r') ? 'R' : (isgraph((int)c) ? c : '?')), + rbufp->recv_length); + } +#endif + + /* + Now correct timestamp by offset of last byte received---we + subtract from the receive time the delay implied by the + extra characters received. + + Reject the input if the resulting code is too long, but + allow for the trailing \r, normally not used but a good + handle for tty_clk or somesuch kernel timestamper. + */ + if(arc_last_offset > LENARC) { +#ifdef ARCRON_DEBUG + if(debug) { + printf("arc: input code too long (%d cf %d); rejected.\n", + arc_last_offset, LENARC); + } +#endif + pp->lencode = 0; + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + L_SUBUF(×tamp, charoffsets[arc_last_offset]); +#ifdef ARCRON_DEBUG + if(debug > 1) { + printf( + "arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n", + ((rbufp->recv_length > 1) ? "*** " : ""), + rbufp->recv_length, + arc_last_offset, + mfptoms((unsigned long)0, + charoffsets[arc_last_offset], + 1)); + } +#endif + +#ifdef ARCRON_MULTIPLE_SAMPLES + /* + If taking multiple samples, capture the current adjusted + sample iff: + + * No timestamp has yet been captured (it is zero), OR + + * This adjusted timestamp is earlier than the one already + captured, on the grounds that this one suffered less + delay in being delivered to us and is more accurate. + + */ + if(L_ISZERO(&(up->lastrec)) || + L_ISGEQ(&(up->lastrec), ×tamp)) +#endif + { +#ifdef ARCRON_DEBUG + if(debug > 1) { + printf("arc: system timestamp captured.\n"); +#ifdef ARCRON_MULTIPLE_SAMPLES + if(!L_ISZERO(&(up->lastrec))) { + l_fp diff; + diff = up->lastrec; + L_SUB(&diff, ×tamp); + printf("arc: adjusted timestamp by -%sms.\n", + mfptoms(diff.l_i, diff.l_f, 3)); + } +#endif + } +#endif + up->lastrec = timestamp; + } + + } + + /* Just in case we still have lots of rubbish in the buffer... */ + /* ...and to avoid the same timestamp being reused by mistake, */ + /* eg on receipt of the \r coming in on its own after the */ + /* timecode. */ + if(pp->lencode >= LENARC) { +#ifdef ARCRON_DEBUG + if(debug && (rbufp->recv_buffer[0] != '\r')) + { printf("arc: rubbish in pp->a_lastcode[].\n"); } +#endif + pp->lencode = 0; + return; + } + + /* Append input to code buffer, avoiding overflow. */ + for(i = 0; i < rbufp->recv_length; i++) { + if(pp->lencode >= LENARC) { break; } /* Avoid overflow... */ + c = rbufp->recv_buffer[i]; + + /* Drop trailing '\r's and drop `h' command echo totally. */ + if(c != '\r' && c != 'h') { pp->a_lastcode[pp->lencode++] = c; } + + /* + If we've just put an `o' in the lastcode[0], clear the + timestamp in anticipation of a timecode arriving soon. + + We would expect to get to process this before any of the + timecode arrives. + */ + if((c == 'o') && (pp->lencode == 1)) { + L_CLR(&(up->lastrec)); +#ifdef ARCRON_DEBUG + if(debug > 1) { printf("arc: clearing timestamp.\n"); } +#endif + } + } + + /* Handle a quality message. */ + if(pp->a_lastcode[0] == 'g') { + int r, q; + + if(pp->lencode < 3) { return; } /* Need more data... */ + r = (pp->a_lastcode[1] & 0x7f); /* Strip parity. */ + q = (pp->a_lastcode[2] & 0x7f); /* Strip parity. */ + if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) || + ((r & 0x70) != 0x30)) { + /* Badly formatted response. */ +#ifdef ARCRON_DEBUG + if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); } +#endif + return; + } + if(r == '3') { /* Only use quality value whilst sync in progress. */ + up->quality = (q & 0xf); +#ifdef DEBUG + if(debug) { printf("arc: signal quality %d.\n", up->quality); } +#endif + } else if( /* (r == '2') && */ up->resyncing) { +#ifdef DEBUG + if(debug) + { + printf("arc: sync finished, signal quality %d: %s\n", + up->quality, + quality_action(up->quality)); + } +#endif + msyslog(LOG_NOTICE, + "ARCRON: sync finished, signal quality %d: %s", + up->quality, + quality_action(up->quality)); + up->resyncing = 0; /* Resync is over. */ + +#ifdef ARCRON_KEEN + /* Clock quality dubious; resync earlier than usual. */ + if((up->quality == QUALITY_UNKNOWN) || + (up->quality < MIN_CLOCK_QUALITY_OK)) + { up->next_resync = current_time + RETRY_RESYNC_TIME; } +#endif + } + pp->lencode = 0; + return; + } + + /* Stop now if this is not a timecode message. */ + if(pp->a_lastcode[0] != 'o') { + pp->lencode = 0; + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* If we don't have enough data, wait for more... */ + if(pp->lencode < LENARC) { return; } + + + /* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */ +#ifdef ARCRON_DEBUG + if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); } +#endif + + /* But check that we actually captured a system timestamp on it. */ + if(L_ISZERO(&(up->lastrec))) { +#ifdef ARCRON_DEBUG + if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); } +#endif + pp->lencode = 0; + refclock_report(peer, CEVNT_BADREPLY); + return; + } + /* + Append a mark of the clock's received signal quality for the + benefit of Derek Mulcahy's Tcl/Tk utility (we map the `unknown' + quality value to `6' for his s/w) and terminate the string for + sure. This should not go off the buffer end. + */ + pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ? + '6' : ('0' + up->quality)); + pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */ + record_clock_stats(&peer->srcadr, pp->a_lastcode); + + /* We don't use the micro-/milli- second part... */ + pp->usec = 0; + pp->msec = 0; + + n = sscanf(pp->a_lastcode, "o%2d%2d%2d%1d%2d%2d%2d%1d%1d", + &pp->hour, &pp->minute, &pp->second, + &wday, &pp->day, &month, &pp->year, &bst, &status); + + /* Validate format and numbers. */ + if(n != 9) { +#ifdef ARCRON_DEBUG + /* Would expect to have caught major problems already... */ + if(debug) { printf("arc: badly formatted data.\n"); } +#endif + refclock_report(peer, CEVNT_BADREPLY); + return; + } + /* + Validate received values at least enough to prevent internal + array-bounds problems, etc. + */ + if((pp->hour < 0) || (pp->hour > 23) || + (pp->minute < 0) || (pp->minute > 59) || + (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || + (wday < 1) || (wday > 7) || + (pp->day < 1) || (pp->day > 31) || + (month < 1) || (month > 12) || + (pp->year < 0) || (pp->year > 99)) { + /* Data out of range. */ + refclock_report(peer, CEVNT_BADREPLY); + return; + } + /* Check that BST/UTC bits are the complement of one another. */ + if(!(bst & 2) == !(bst & 4)) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); } + + /* Year-2000 alert! */ + /* Attempt to wrap 2-digit date into sensible window. */ + if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* Y2KFixes */ + pp->year += 1900; /* use full four-digit year */ /* Y2KFixes */ + /* + Attempt to do the right thing by screaming that the code will + soon break when we get to the end of its useful life. What a + hero I am... PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X! + */ + if(pp->year >= YEAR_PIVOT+2000-2 ) { /* Y2KFixes */ + /*This should get attention B^> */ + msyslog(LOG_NOTICE, + "ARCRON: fix me! EITHER YOUR DATE IS BADLY WRONG or else I will break soon!"); + } +#ifdef DEBUG + if(debug) { + printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n", + n, + pp->hour, pp->minute, pp->second, + pp->day, month, pp->year, bst, status); + } +#endif + + /* + The status value tested for is not strictly supported by the + clock spec since the value of bit 2 (0x4) is claimed to be + undefined for MSF, yet does seem to indicate if the last resync + was successful or not. + */ + pp->leap = LEAP_NOWARNING; + status &= 0x7; + if(status == 0x3) { + if(status != up->status) + { msyslog(LOG_NOTICE, "ARCRON: signal acquired"); } + } else { + if(status != up->status) { + msyslog(LOG_NOTICE, "ARCRON: signal lost"); + pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */ + up->status = status; + refclock_report(peer, CEVNT_FAULT); + return; + } + } + up->status = status; + + pp->day += moff[month - 1]; + + if(isleap_4(pp->year) && month > 2) { pp->day++; } /* Y2KFixes */ + + /* Convert to UTC if required */ + if(bst & 2) { + pp->hour--; + if (pp->hour < 0) { + pp->hour = 23; + pp->day--; + /* If we try to wrap round the year (BST on 1st Jan), reject.*/ + if(pp->day < 0) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + } + } + + /* If clock signal quality is unknown, revert to default PRECISION...*/ + if(up->quality == QUALITY_UNKNOWN) { peer->precision = PRECISION; } + /* ...else improve precision if flag3 is set... */ + else { + peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? + HIGHPRECISION : PRECISION); + } + + /* Notice and log any change (eg from initial defaults) for flags. */ + if(up->saved_flags != pp->sloppyclockflag) { +#ifdef ARCRON_DEBUG + msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s", + ((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."), + ((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."), + ((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."), + ((pp->sloppyclockflag & CLK_FLAG4) ? "4" : ".")); + /* Note effects of flags changing... */ + if(debug) { + printf("arc: CHOSENSAMPLES(pp) = %d.\n", CHOSENSAMPLES(pp)); + printf("arc: NKEEP(pp) = %d.\n", NKEEP(pp)); + printf("arc: PRECISION = %d.\n", peer->precision); + } +#endif + up->saved_flags = pp->sloppyclockflag; + } + + /* Note time of last believable timestamp. */ + pp->lastrec = up->lastrec; + +#ifdef ARCRON_LEAPSECOND_KEEN + /* Find out if a leap-second might just have happened... + (ie is this the first hour of the first day of Jan or Jul?) + */ + if((pp->hour == 0) && + (pp->day == 1) && + ((month == 1) || (month == 7))) { + if(possible_leap >= 0) { + /* A leap may have happened, and no resync has started yet...*/ + possible_leap = 1; + } + } else { + /* Definitely not leap-second territory... */ + possible_leap = 0; + } +#endif + + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + refclock_receive(peer); +} + + +/* request_time() sends a time request to the clock with given peer. */ +/* This automatically reports a fault if necessary. */ +/* No data should be sent after this until arc_poll() returns. */ +static void request_time P((int, struct peer *)); +static void +request_time( + int unit, + struct peer *peer + ) +{ + struct refclockproc *pp = peer->procptr; + register struct arcunit *up = (struct arcunit *)pp->unitptr; +#ifdef DEBUG + if(debug) { printf("arc: unit %d: requesting time.\n", unit); } +#endif + if (!send_slow(up, pp->io.fd, "o\r")) { +#ifdef ARCRON_DEBUG + msyslog(LOG_NOTICE, "ARCRON: unit %d: problem sending", unit); +#endif + refclock_report(peer, CEVNT_FAULT); + return; + } + pp->polls++; +} + +/* + * arc_poll - called by the transmit procedure + */ +static void +arc_poll( + int unit, + struct peer *peer + ) +{ + register struct arcunit *up; + struct refclockproc *pp; + int resync_needed; /* Should we start a resync? */ + + pp = peer->procptr; + up = (struct arcunit *)pp->unitptr; + pp->lencode = 0; + memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode)); + +#if 0 + /* Flush input. */ + tcflush(pp->io.fd, TCIFLUSH); +#endif + + /* Resync if our next scheduled resync time is here or has passed. */ + resync_needed = (up->next_resync <= current_time); + +#ifdef ARCRON_LEAPSECOND_KEEN + /* + Try to catch a potential leap-second insertion or deletion quickly. + + In addition to the normal NTP fun of clocks that don't report + leap-seconds spooking their hosts, this clock does not even + sample the radio sugnal the whole time, so may miss a + leap-second insertion or deletion for up to a whole sample + time. + + To try to minimise this effect, if in the first few minutes of + the day immediately following a leap-second-insertion point + (ie in the first hour of the first day of the first and sixth + months), and if the last resync was in the previous day, and a + resync is not already in progress, resync the clock + immediately. + + */ + if((possible_leap > 0) && /* Must be 00:XX 01/0{1,7}/XXXX. */ + (!up->resyncing)) { /* No resync in progress yet. */ + resync_needed = 1; + possible_leap = -1; /* Prevent multiple resyncs. */ + msyslog(LOG_NOTICE,"ARCRON: unit %d: checking for leap second",unit); + } +#endif + + /* Do a resync if required... */ + if(resync_needed) { + /* First, reset quality value to `unknown' so we can detect */ + /* when a quality message has been responded to by this */ + /* being set to some other value. */ + up->quality = QUALITY_UNKNOWN; + + /* Note that we are resyncing... */ + up->resyncing = 1; + + /* Now actually send the resync command and an immediate poll. */ +#ifdef DEBUG + if(debug) { printf("arc: sending resync command (h\\r).\n"); } +#endif + msyslog(LOG_NOTICE, "ARCRON: unit %d: sending resync command", unit); + send_slow(up, pp->io.fd, "h\r"); + + /* Schedule our next resync... */ + up->next_resync = current_time + DEFAULT_RESYNC_TIME; + + /* Drop through to request time if appropriate. */ + } + + /* If clock quality is too poor to trust, indicate a fault. */ + /* If quality is QUALITY_UNKNOWN and ARCRON_KEEN is defined,*/ + /* we'll cross our fingers and just hope that the thing */ + /* synced so quickly we did not catch it---we'll */ + /* double-check the clock is OK elsewhere. */ + if( +#ifdef ARCRON_KEEN + (up->quality != QUALITY_UNKNOWN) && +#else + (up->quality == QUALITY_UNKNOWN) || +#endif + (up->quality < MIN_CLOCK_QUALITY_OK)) { +#ifdef DEBUG + if(debug) { + printf("arc: clock quality %d too poor.\n", up->quality); + } +#endif + refclock_report(peer, CEVNT_FAULT); + return; + } + /* This is the normal case: request a timestamp. */ + request_time(unit, peer); +} + +#else +int refclock_arc_bs; +#endif diff --git a/contrib/ntp/ntpd/refclock_as2201.c b/contrib/ntp/ntpd/refclock_as2201.c new file mode 100644 index 000000000000..2c104402f098 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_as2201.c @@ -0,0 +1,388 @@ +/* + * refclock_as2201 - clock driver for the Austron 2201A GPS + * Timing Receiver + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_AS2201) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#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. If flag4 of the fudge configuration command is set to + * 1, the statistics data are written to the clockstats file for later + * processing. + * + * In order for this code to work, the radio must be placed in non- + * interactive mode using the "off" command and with a single + * response using the "term cr" command. The setting of the "echo" + * and "df" commands does not matter. The radio should select UTC + * timescale using the "ts utc" command. + * + * There are two modes of operation for this driver. The first with + * default configuration is used with stock kernels and serial-line + * drivers and works with almost any machine. In this mode the driver + * assumes the radio captures a timestamp upon receipt of the "*" that + * begins the driver query. Accuracies in this mode are in the order of + * a millisecond or two and the receiver can be connected to only one + * host. + * + * The second mode of operation can be used for SunOS kernels that have + * been modified with the ppsclock streams module included in this + * distribution. The mode is enabled if flag3 of the fudge configuration + * command has been set to 1. In this mode a precise timestamp is + * available using a gadget box and 1-pps signal from the receiver. This + * improves the accuracy to the order of a few tens of microseconds. In + * addition, the serial output and 1-pps signal can be bussed to more + * than one hosts, but only one of them should be connected to the + * radio input data line. + */ + +/* + * GPS Definitions + */ +#define SMAX 200 /* statistics buffer length */ +#define DEVICE "/dev/gps%d" /* device name and unit */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ +#define PRECISION (-20) /* precision assumed (about 1 us) */ +#define REFID "GPS\0" /* reference ID */ +#define DESCRIPTION "Austron 2201A GPS Receiver" /* WRU */ + +#define LENTOC 19 /* yy:ddd:hh:mm:ss.mmm timecode lngth */ + +/* + * AS2201 unit control structure. + */ +struct as2201unit { + char *lastptr; /* statistics buffer pointer */ + char stats[SMAX]; /* statistics buffer */ + int linect; /* count of lines remaining */ + int index; /* current statistics command */ +}; + +/* + * Radio commands to extract statitistics + * + * A command consists of an ASCII string terminated by a (\r). The + * command list consist of a sequence of commands terminated by a null + * string ("\0"). One command from the list is sent immediately + * following each received timecode (*toc\r command) and the ASCII + * strings received from the radio are saved along with the timecode in + * the clockstats file. Subsequent commands are sent at each timecode, + * with the last one in the list followed by the first one. The data + * received from the radio consist of ASCII strings, each terminated by + * a (\r) character. The number of strings for each command is + * specified as the first line of output as an ASCII-encode number. Note + * that the ETF command requires the Input Buffer Module and the LORAN + * commands require the LORAN Assist Module. However, if these modules + * are not installed, the radio and this driver will continue to operate + * successfuly, but no data will be captured for these commands. + */ +static char stat_command[][30] = { + "ITF\r", /* internal time/frequency */ + "ETF\r", /* external time/frequency */ + "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */ + "LORAN TDATA\r", /* LORAN signal data */ + "ID;OPT;VER\r", /* model; options; software version */ + + "ITF\r", /* internal time/frequency */ + "ETF\r", /* external time/frequency */ + "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */ + "TRSTAT\r", /* satellite tracking status */ + "POS;PPS;PPSOFF\r", /* position, pps source, offsets */ + + "ITF\r", /* internal time/frequency */ + "ETF\r", /* external time/frequency */ + "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */ + "LORAN TDATA\r", /* LORAN signal data */ + "UTC\r", /* UTC leap info */ + + "ITF\r", /* internal time/frequency */ + "ETF\r", /* external time/frequency */ + "LORAN ENSEMBLE\r", /* GPS/LORAN ensemble statistics */ + "TRSTAT\r", /* satellite tracking status */ + "OSC;ET;TEMP\r", /* osc type; tune volts; oven temp */ + "\0" /* end of table */ +}; + +/* + * Function prototypes + */ +static int as2201_start P((int, struct peer *)); +static void as2201_shutdown P((int, struct peer *)); +static void as2201_receive P((struct recvbuf *)); +static void as2201_poll P((int, struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_as2201 = { + as2201_start, /* start up driver */ + as2201_shutdown, /* shut down driver */ + as2201_poll, /* transmit poll message */ + noentry, /* not used (old as2201_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old as2201_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * as2201_start - open the devices and initialize data for processing + */ +static int +as2201_start( + int unit, + struct peer *peer + ) +{ + register struct as2201unit *up; + struct refclockproc *pp; + int fd; + char gpsdev[20]; + + /* + * Open serial port. Use CLK line discipline, if available. + */ + (void)sprintf(gpsdev, DEVICE, unit); + if (!(fd = refclock_open(gpsdev, SPEED232, LDISC_CLK))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct as2201unit *) + emalloc(sizeof(struct as2201unit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct as2201unit)); + pp = peer->procptr; + pp->io.clock_recv = as2201_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + peer->burst = NSTAGE; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + up->lastptr = up->stats; + up->index = 0; + return (1); +} + + +/* + * as2201_shutdown - shut down the clock + */ +static void +as2201_shutdown( + int unit, + struct peer *peer + ) +{ + register struct as2201unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct as2201unit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * as2201__receive - receive data from the serial interface + */ +static void +as2201_receive( + struct recvbuf *rbufp + ) +{ + register struct as2201unit *up; + struct refclockproc *pp; + struct peer *peer; + l_fp trtmp; + + /* + * Initialize pointers and read the timecode and timestamp. + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct as2201unit *)pp->unitptr; + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); +#ifdef DEBUG + if (debug) + printf("gps: timecode %d %d %s\n", + up->linect, pp->lencode, pp->a_lastcode); +#endif + if (pp->lencode == 0) + return; + + /* + * If linect is greater than zero, we must be in the middle of a + * statistics operation, so simply tack the received data at the + * end of the statistics string. If not, we could either have + * just received the timecode itself or a decimal number + * indicating the number of following lines of the statistics + * reply. In the former case, write the accumulated statistics + * data to the clockstats file and continue onward to process + * the timecode; in the later case, save the number of lines and + * quietly return. + */ + if (pp->sloppyclockflag & CLK_FLAG2) + pp->lastrec = trtmp; + if (up->linect > 0) { + up->linect--; + if ((int)(up->lastptr - up->stats + pp->lencode) > SMAX - 2) + return; + *up->lastptr++ = ' '; + (void)strcpy(up->lastptr, pp->a_lastcode); + up->lastptr += pp->lencode; + return; + } else { + if (pp->lencode == 1) { + up->linect = atoi(pp->a_lastcode); + return; + } else { + record_clock_stats(&peer->srcadr, up->stats); +#ifdef DEBUG + if (debug) + printf("gps: stat %s\n", up->stats); +#endif + } + } + up->lastptr = up->stats; + *up->lastptr = '\0'; + + /* + * We get down to business, check the timecode format and decode + * its contents. If the timecode has invalid length or is not in + * proper format, we declare bad format and exit. + */ + if (pp->lencode < LENTOC) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Timecode format: "yy:ddd:hh:mm:ss.mmm" + */ + if (sscanf(pp->a_lastcode, "%2d:%3d:%2d:%2d:%2d.%3d", &pp->year, + &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->msec) + != 6) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Test for synchronization (this is a temporary crock). + */ + if (pp->a_lastcode[2] != ':') + pp->leap = LEAP_NOTINSYNC; + else + pp->leap = LEAP_NOWARNING; + + /* + * Process the new sample in the median filter and determine the + * timecode timestamp. + */ + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + + /* + * If CLK_FLAG4 is set, initialize the statistics buffer and + * send the next command. If not, simply write the timecode to + * the clockstats file. + */ + (void)strcpy(up->lastptr, pp->a_lastcode); + up->lastptr += pp->lencode; + if (pp->sloppyclockflag & CLK_FLAG4) { + *up->lastptr++ = ' '; + (void)strcpy(up->lastptr, stat_command[up->index]); + up->lastptr += strlen(stat_command[up->index]); + up->lastptr--; + *up->lastptr = '\0'; + (void)write(pp->io.fd, stat_command[up->index], + strlen(stat_command[up->index])); + up->index++; + if (*stat_command[up->index] == '\0') + up->index = 0; + } +} + + +/* + * as2201_poll - called by the transmit procedure + * + * We go to great pains to avoid changing state here, since there may be + * more than one eavesdropper receiving the same timecode. + */ +static void +as2201_poll( + int unit, + struct peer *peer + ) +{ + struct refclockproc *pp; + + /* + * Send a "\r*toc\r" to get things going. We go to great pains + * to avoid changing state, since there may be more than one + * eavesdropper watching the radio. + */ + pp = peer->procptr; + if (write(pp->io.fd, "\r*toc\r", 6) != 6) { + refclock_report(peer, CEVNT_FAULT); + } else { + pp->polls++; + if (!(pp->sloppyclockflag & CLK_FLAG2)) + get_systime(&pp->lastrec); + } + if (peer->burst > 0) + return; + if (pp->coderecv == pp->codeproc) { + refclock_report(peer, CEVNT_TIMEOUT); + return; + } + refclock_receive(peer); + peer->burst = NSTAGE; +} + +#else +int refclock_as2201_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_atom.c b/contrib/ntp/ntpd/refclock_atom.c new file mode 100644 index 000000000000..63e17c1f6c04 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_atom.c @@ -0,0 +1,488 @@ +/* + * refclock_atom - clock driver for 1-pps signals + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_ATOM) + +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_SYS_TERMIOS_H +# include +#endif +#ifdef HAVE_SYS_PPSCLOCK_H +# include +#endif +#ifdef HAVE_PPSAPI +#include +#endif /* HAVE_PPSAPI */ + +/* + * This driver furnishes an interface for pulse-per-second (PPS) signals + * produced by a cesium clock, timing receiver or related equipment. It + * can be used to remove accumulated jitter and retime a secondary + * server when synchronized to a primary server over a congested, wide- + * area network and before redistributing the time to local clients. + * + * In order for this driver 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 flopflop and RS232 level converter. + * Conntection is either via the carrier detect (DCD) lead or via the + * receive data (RD) lead. The incidental jitter using the DCD lead is + * essentially the interrupt latency. The incidental jitter using the RD + * lead has an additional component due to the line sampling clock. When + * operated at 38.4 kbps, this arrangement has a worst-case jitter less + * than 26 us. + * + * There are four ways in which this driver can be used. They are + * described in decreasing order of merit below. The first way uses the + * ppsapi STREAMS module and the LDISC_PPS line discipline, while the + * second way uses the ppsclock STREAMS module and the LDISC_PPS line + * discipline. Either of these works only for the baseboard serial ports + * of the Sun SPARC IPC and clones. However, the ppsapi uses the + * proposed IETF interface expected to become standard for PPS signals. + * The serial port to be used is specified by the pps command in the + * configuration file. This driver reads the timestamp directly by a + * designated ioctl() system call. + * + * The third way uses the LDISC_CLKPPS line discipline and works for + * any architecture supporting a serial port. If after a few seconds + * this driver finds no ppsclock module configured, it attempts to open + * a serial port device /dev/pps%d, where %d is the unit number, and + * assign the LDISC_CLKPPS line discipline to it. If the line discipline + * fails, no harm is done except the accuracy is reduced somewhat. The + * pulse generator in the gadget box is adjusted to produce a start bit + * of length 26 usec at 38400 bps. Used with the LDISC_CLKPPS line + * discipline, this produces an ASCII DEL character ('\377') followed by + * a timestamp at each seconds epoch. + * + * The fourth way involves an auxiliary radio clock driver which calls + * the PPS driver with a timestamp captured by that driver. This use is + * documented in the source code for the driver(s) involved. Note that + * some drivers collect the sample information themselves before calling + * pps_sample(), and others call knowing only that they are running + * shortly after an on-time tick and they expect to retrieve the PPS + * offset, fudge their result, and insert it into the timestream. + * + * Fudge Factors + * + * There are no special fudge factors other than the generic. The fudge + * time1 parameter can be used to compensate for miscellaneous UART and + * OS delays. Allow about 247 us for uart delays at 38400 bps and about + * 1 ms for STREAMS nonsense with older workstations. Velocities may + * vary with modern workstations. + */ +/* + * Interface definitions + */ +#ifdef HAVE_PPSAPI +extern int pps_assert; +#endif /* HAVE_PPSAPI */ +#ifdef TTYCLK +#define DEVICE "/dev/pps%d" /* device name and unit */ +#ifdef B38400 +#define SPEED232 B38400 /* uart speed (38400 baud) */ +#else +#define SPEED232 EXTB /* as above */ +#endif +#endif /* TTYCLK */ + +#define PRECISION (-20) /* precision assumed (about 1 us) */ +#define REFID "PPS\0" /* reference ID */ +#define DESCRIPTION "PPS Clock Discipline" /* WRU */ + +#define FLAG_TTY 0x01 /* tty_clk heard from */ +#define FLAG_PPS 0x02 /* ppsclock heard from */ +#define FLAG_AUX 0x04 /* auxiliary PPS source */ + +static struct peer *pps_peer; /* atom driver for auxiliary PPS sources */ + +#ifdef TTYCLK +static void atom_receive P((struct recvbuf *)); +#endif /* TTYCLK */ + +/* + * Unit control structure + */ +struct atomunit { +#ifdef HAVE_PPSAPI + pps_info_t pps_info; /* pps_info control */ +#endif /* HAVE_PPSAPI */ +#ifdef PPS + struct ppsclockev ev; /* ppsclock control */ +#endif /* PPS */ + int flags; /* flags that wave */ +}; + +/* + * Function prototypes + */ +static int atom_start P((int, struct peer *)); +static void atom_shutdown P((int, struct peer *)); +static void atom_poll P((int, struct peer *)); +#if defined(PPS) || defined(HAVE_PPSAPI) +static int atom_pps P((struct peer *)); +#endif /* PPS || HAVE_PPSAPI */ + +/* + * Transfer vector + */ +struct refclock refclock_atom = { + atom_start, /* start up driver */ + atom_shutdown, /* shut down driver */ + atom_poll, /* transmit poll message */ + noentry, /* not used (old atom_control) */ + noentry, /* initialize driver */ + noentry, /* not used (old atom_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * atom_start - initialize data for processing + */ +static int +atom_start( + int unit, + struct peer *peer + ) +{ + register struct atomunit *up; + struct refclockproc *pp; + int flags; +#ifdef TTYCLK + int fd = 0; + char device[20]; + int ldisc = LDISC_CLKPPS; +#endif /* TTYCLK */ + + pps_peer = peer; + flags = 0; + +#ifdef TTYCLK +# if defined(SCO5_CLOCK) + ldisc = LDISC_RAW; /* DCD timestamps without any line discipline */ +# endif + /* + * Open serial port. Use LDISC_CLKPPS line discipline only + * if the LDISC_PPS line discipline is not availble, + */ +# if defined(PPS) || defined(HAVE_PPSAPI) + if (fdpps <= 0) +# endif + { + (void)sprintf(device, DEVICE, unit); + if ((fd = refclock_open(device, SPEED232, ldisc)) != 0) + flags |= FLAG_TTY; + } +#endif /* TTYCLK */ + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct atomunit *)emalloc(sizeof(struct atomunit)))) { +#ifdef TTYCLK + if (flags & FLAG_TTY) + (void) close(fd); +#endif /* TTYCLK */ + return (0); + } + memset((char *)up, 0, sizeof(struct atomunit)); + pp = peer->procptr; + pp->unitptr = (caddr_t)up; +#ifdef TTYCLK + if (flags & FLAG_TTY) { + pp->io.clock_recv = atom_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + } +#endif /* TTYCLK */ + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + up->flags = flags; + return (1); +} + + +/* + * atom_shutdown - shut down the clock + */ +static void +atom_shutdown( + int unit, + struct peer *peer + ) +{ + register struct atomunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct atomunit *)pp->unitptr; +#ifdef TTYCLK + if (up->flags & FLAG_TTY) + io_closeclock(&pp->io); +#endif /* TTYCLK */ + if (pps_peer == peer) + pps_peer = 0; + free(up); +} + + +#if defined(PPS) || defined(HAVE_PPSAPI) +/* + * atom_pps - receive data from the LDISC_PPS discipline + */ +static int +atom_pps( + struct peer *peer + ) +{ + register struct atomunit *up; + struct refclockproc *pp; +#ifdef HAVE_PPSAPI + struct timespec timeout; +# ifdef HAVE_TIMESPEC + struct timespec ts; +# else + struct timeval ts; +# endif /* HAVE_TIMESPEC */ +#endif /* HAVE_PPSAPI */ + l_fp lftmp; + double doffset; + int i; +#if !defined(HAVE_PPSAPI) + int request = +# ifdef HAVE_CIOGETEV + CIOGETEV +# endif +# ifdef HAVE_TIOCGPPSEV + TIOCGPPSEV +# endif + ; +#endif /* HAVE_PPSAPI */ + + /* + * This routine is called once per second when the LDISC_PPS + * discipline is present. It snatches the pps timestamp from the + * kernel and saves the sign-extended fraction in a circular + * buffer for processing at the next poll event. + */ + pp = peer->procptr; + up = (struct atomunit *)pp->unitptr; + + /* + * Convert the timeval to l_fp and save for billboards. Sign- + * extend the fraction and stash in the buffer. No harm is done + * if previous data are overwritten. If the discipline comes bum + * or the data grow stale, just forget it. Round the nanoseconds + * to microseconds with great care. + */ + if (fdpps <= 0) + return (1); +#ifdef HAVE_PPSAPI + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + i = up->pps_info.assert_sequence; + if (time_pps_fetch(fdpps, PPS_TSFMT_TSPEC, &up->pps_info, &timeout) + < 0) + return (2); + if (i == up->pps_info.assert_sequence) + return (3); + if (pps_assert) + ts = up->pps_info.assert_timestamp; + else + ts = up->pps_info.clear_timestamp; + pp->lastrec.l_ui = ts.tv_sec + JAN_1970; + ts.tv_nsec = (ts.tv_nsec + 500) / 1000; + if (ts.tv_nsec > 1000000) { + ts.tv_nsec -= 1000000; + ts.tv_sec++; + } + TVUTOTSF(ts.tv_nsec, pp->lastrec.l_uf); +#else + i = up->ev.serial; + if (ioctl(fdpps, request, (caddr_t)&up->ev) < 0) + return (2); + if (i == up->ev.serial) + return (3); + pp->lastrec.l_ui = up->ev.tv.tv_sec + JAN_1970; + TVUTOTSF(up->ev.tv.tv_usec, pp->lastrec.l_uf); +#endif /* HAVE_PPSAPI */ + up->flags |= FLAG_PPS; + L_CLR(&lftmp); + L_ADDF(&lftmp, pp->lastrec.l_f); + LFPTOD(&lftmp, doffset); + SAMPLE(-doffset + pp->fudgetime1); + return (0); +} +#endif /* PPS || HAVE_PPSAPI */ + +#ifdef TTYCLK +/* + * atom_receive - receive data from the LDISC_CLK discipline + */ +static void +atom_receive( + struct recvbuf *rbufp + ) +{ + register struct atomunit *up; + struct refclockproc *pp; + struct peer *peer; + l_fp lftmp; + double doffset; + + /* + * This routine is called once per second when the serial + * interface is in use. It snatches the timestamp from the + * buffer and saves the sign-extended fraction in a circular + * buffer for processing at the next poll event. + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct atomunit *)pp->unitptr; + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, + &pp->lastrec); + + /* + * Save the timestamp for billboards. Sign-extend the fraction + * and stash in the buffer. No harm is done if previous data are + * overwritten. Do this only if the ppsclock gizmo is not + * working. + */ + if (up->flags & FLAG_PPS) + return; + L_CLR(&lftmp); + L_ADDF(&lftmp, pp->lastrec.l_f); + LFPTOD(&lftmp, doffset); + SAMPLE(-doffset + pp->fudgetime1); +} +#endif /* TTYCLK */ + +/* + * pps_sample - receive PPS data from some other clock driver + */ +int +pps_sample( + l_fp *offset + ) +{ + register struct peer *peer; + register struct atomunit *up; + struct refclockproc *pp; + l_fp lftmp; + double doffset; + + /* + * This routine is called once per second when the external + * clock driver processes PPS information. It processes the pps + * timestamp and saves the sign-extended fraction in a circular + * buffer for processing at the next poll event. + */ + peer = pps_peer; + if (peer == 0) /* nobody home */ + return 1; + pp = peer->procptr; + up = (struct atomunit *)pp->unitptr; + + /* + * Convert the timeval to l_fp and save for billboards. Sign- + * extend the fraction and stash in the buffer. No harm is done + * if previous data are overwritten. If the discipline comes bum + * or the data grow stale, just forget it. + */ + up->flags |= FLAG_AUX; + pp->lastrec = *offset; + L_CLR(&lftmp); + L_ADDF(&lftmp, pp->lastrec.l_f); + LFPTOD(&lftmp, doffset); + SAMPLE(-doffset + pp->fudgetime1); + return (0); +} + +/* + * atom_poll - called by the transmit procedure + */ +static void +atom_poll( + int unit, + struct peer *peer + ) +{ +#if defined(PPS) || defined(HAVE_PPSAPI) + register struct atomunit *up; +#endif /* PPS || HAVE_PPSAPI */ + struct refclockproc *pp; + + /* + * Accumulate samples in the median filter. At the end of each + * poll interval, do a little bookeeping and process the + * samples. + */ + pp = peer->procptr; +#if defined(PPS) || defined(HAVE_PPSAPI) + up = (struct atomunit *)pp->unitptr; + if (!(up->flags & !(FLAG_AUX | FLAG_TTY))) { + int err; + + err = atom_pps(peer); + if (err > 0) { + refclock_report(peer, CEVNT_FAULT); + return; + } + } +#endif /* PPS || HAVE_PPSAPI */ + pp->polls++; + if (peer->burst > 0) + return; + if (pp->coderecv == pp->codeproc) { + refclock_report(peer, CEVNT_TIMEOUT); + return; + } + + /* + * Valid time (leap bits zero) is returned only if the prefer + * peer has survived the intersection algorithm and within + * clock_max of local time and not too long ago. This ensures + * the pps time is within +-0.5 s of the local time and the + * seconds numbering is unambiguous. + */ + if (pps_update) { + pp->leap = LEAP_NOWARNING; + } else { + pp->leap = LEAP_NOTINSYNC; + return; + } + pp->variance = 0; + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + peer->burst = MAXSTAGE; +} + +#else +int refclock_atom_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_bancomm.c b/contrib/ntp/ntpd/refclock_bancomm.c new file mode 100644 index 000000000000..95c211b15fc2 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_bancomm.c @@ -0,0 +1,483 @@ +/* refclock_bancomm.c - clock driver for the Datum/Bancomm bc635VME + * Time and Frequency Processor. It requires the BANCOMM bc635VME/ + * bc350VXI Time and Frequency Processor Module Driver for SunOS4.x + * and SunOS5.x UNIX Systems. It has been tested on a UltraSparc + * IIi-cEngine running Solaris 2.6. + * + * Author(s): Ganesh Ramasivan & Gary Cliff, Computing Devices Canada, + * Ottawa, Canada + * + * Date: July 1999 + * + * Note(s): The refclock type has been defined as 16. + * + * This program has been modelled after the Bancomm driver + * originally written by R. Schmidt of Time Service, U.S. + * Naval Observatory for a HP-UX machine. Since the original + * authors no longer plan to maintain this code, all + * references to the HP-UX vme2 driver subsystem bave been + * removed. Functions vme_report_event(), vme_receive(), + * vme_control() and vme_buginfo() have been deleted because + * they are no longer being used. + * + * The time on the bc635 TFP must be set to GMT due to the + * fact that NTP makes use of GMT for all its calculations. + * + * Installation of the Datum/Bancomm driver creates the + * device file /dev/btfp0 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_BANC) +#include +#include +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +/* STUFF BY RES */ +struct btfp_time /* Structure for reading 5 time words */ + /* in one ioctl(2) operation. */ +{ + unsigned short btfp_time[5]; /* Time words 0,1,2,3, and 4. (16bit)*/ +}; + +/* SunOS5 ioctl commands definitions.*/ +#define BTFPIOC ( 'b'<< 8 ) +#define IOCIO( l, n ) ( BTFPIOC | n ) +#define IOCIOR( l, n, s ) ( BTFPIOC | n ) +#define IOCIORN( l, n, s ) ( BTFPIOC | n ) +#define IOCIOWN( l, n, s ) ( BTFPIOC | n ) + +/***** Simple ioctl commands *****/ +#define RUNLOCK IOCIOR(b, 19, int ) /* Release Capture Lockout */ +#define RCR0 IOCIOR(b, 22, int ) /* Read control register zero.*/ +#define WCR0 IOCIOWN(b, 23, int) /* Write control register zero*/ + +/***** Compound ioctl commands *****/ + +/* Read all 5 time words in one call. */ +#define READTIME IOCIORN(b, 32, sizeof( struct btfp_time )) +#define VMEFD "/dev/btfp0" + +struct vmedate { /* structure returned by get_vmetime.c */ + unsigned short year; + unsigned short day; + unsigned short hr; + unsigned short mn; + unsigned short sec; + unsigned long frac; + unsigned short status; +}; + +/* END OF STUFF FROM RES */ + +/* + * Definitions + */ +#define MAXUNITS 2 /* max number of VME units */ + +/* + * VME interface parameters. + */ +#define VMEPRECISION (-21) /* precision assumed (1 us) */ +#define USNOREFID "BTFP" /* or whatever */ +#define VMEREFID "BTFP" /* reference id */ +#define VMEDESCRIPTION "Bancomm bc635 TFP" /* who we are */ +#define VMEHSREFID 0x7f7f1000 /* 127.127.16.00 refid hi strata */ +/* clock type 16 is used here */ +#define GMT 0 /* hour offset from Greenwich */ + +/* + * Imported from ntp_timer module + */ +extern u_long current_time; /* current time(s) */ + +/* + * Imported from ntpd module + */ +extern int debug; /* global debug flag */ + +/* + * VME unit control structure. + * Changes made to vmeunit structure. Most members are now available in the + * new refclockproc structure in ntp_refclock.h - 07/99 - Ganesh Ramasivan + */ +struct vmeunit { + struct vmedate vmedata; /* data returned from vme read */ + u_long lasttime; /* last time clock heard from */ +}; + +/* + * Keep the fudge factors separately so they can be set even + * when no clock is configured. + */ +static double fudgefactor[MAXUNITS]; +static u_char stratumtouse[MAXUNITS]; +static u_char sloppyclockflag[MAXUNITS]; + +/* + * Function prototypes + */ +static void vme_init (void); +static int vme_start (int, struct peer *); +static void vme_shutdown (int, struct peer *); +static void vme_receive (struct recvbuf *); +static void vme_poll (int unit, struct peer *); +struct vmedate *get_datumtime(struct vmedate *); + +/* + * Transfer vector + */ +struct refclock refclock_bancomm = { + vme_start, + vme_shutdown, + vme_poll, + noentry, /* not used (old vme_control) */ + vme_init, + noentry, /* not used (old vme_buginfo) */ + NOFLAGS +}; + +int fd_vme; /* file descriptor for ioctls */ +int regvalue; + +/* + * vme_init - initialize internal vme driver data + */ +static void +vme_init(void) +{ + register int i; + + /* + * Initialize fudge factors to default. + */ + for (i = 0; i < MAXUNITS; i++) { + fudgefactor[i] = 0.0; + stratumtouse[i] = 0; + sloppyclockflag[i] = 0; + } +} + +/* + * vme_start - open the VME device and initialize data for processing + */ +static int +vme_start( + int unit, + struct peer *peer + ) +{ + register struct vmeunit *vme; + struct refclockproc *pp; + int dummy; + char vmedev[20]; + + /* + * Check configuration info. + */ + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, "vme_start: unit %d invalid", unit); + return (0); + } + + /* + * Open VME device + */ +#ifdef DEBUG + + printf("Opening DATUM VME DEVICE \n"); +#endif + if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) { + msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev); + return (0); + } + else { /* Release capture lockout in case it was set from before. */ + if( ioctl( fd_vme, RUNLOCK, &dummy ) ) + msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m"); + + regvalue = 0; /* More esoteric stuff to do... */ + if( ioctl( fd_vme, WCR0, ®value ) ) + msyslog(LOG_ERR, "vme_start: WCR0 failed %m"); + } + + /* + * Allocate unit structure + */ + vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit)); + bzero((char *)vme, sizeof(struct vmeunit)); + + + /* + * Set up the structures + */ + pp = peer->procptr; + pp->unitptr = (caddr_t) vme; + pp->timestarted = current_time; + + pp->io.clock_recv = vme_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd_vme; + + /* + * All done. Initialize a few random peer variables, then + * return success. Note that root delay and root dispersion are + * always zero for this clock. + */ + pp->leap = LEAP_NOWARNING; + peer->precision = VMEPRECISION; + peer->stratum = stratumtouse[unit]; + memcpy( (char *)&peer->refid, USNOREFID,4); + + peer->refid = htonl(VMEHSREFID); + + return (1); +} + + +/* + * vme_shutdown - shut down a VME clock + */ +static void +vme_shutdown( + int unit, + struct peer *peer + ) +{ + register struct vmeunit *vme; + struct refclockproc *pp; + + pp = peer->procptr; + + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, "vme_shutdown: unit %d invalid", unit); + return; + } + + /* + * Tell the I/O module to turn us off. We're history. + */ + vme = (struct vmeunit *)pp->unitptr; + io_closeclock(&pp->io); + pp->unitptr = NULL; + free(vme); +} + + +/* + * vme_receive - receive data from the VME device. + * + * Note: This interface would be interrupt-driven. We don't use that + * now, but include a dummy routine for possible future adventures. + */ +static void +vme_receive( + struct recvbuf *rbufp + ) +{ +} + + +/* + * vme_poll - called by the transmit procedure + */ +static void +vme_poll( + int unit, + struct peer *peer + ) +{ + struct vmedate *tptr; + struct vmeunit *vme; + struct refclockproc *pp; + time_t tloc; + struct tm *tadr; + + pp = peer->procptr; + vme = (struct vmeunit *)pp->unitptr; /* Here is the structure */ + + tptr = &vme->vmedata; + if ((tptr = get_datumtime(tptr)) == NULL ) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + get_systime(&pp->lastrec); + pp->polls++; + vme->lasttime = current_time; + + /* + * Get VME time and convert to timestamp format. + * The year must come from the system clock. + */ + + time(&tloc); + tadr = gmtime(&tloc); + tptr->year = (unsigned short)(tadr->tm_year + 1900); + + + sprintf(pp->a_lastcode, + "%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d", + tptr->day, + tptr->hr, + tptr->mn, + tptr->sec, + tptr->frac, + tptr->status); + + pp->lencode = (u_short) strlen(pp->a_lastcode); + + pp->day = tptr->day; + pp->hour = tptr->hr; + pp->minute = tptr->mn; + pp->second = tptr->sec; + pp->usec = tptr->frac; + +#ifdef DEBUG + if (debug) + printf("pp: %3d %02d:%02d:%02d.%06ld %1x\n", + pp->day, pp->hour, pp->minute, pp->second, + pp->usec, tptr->status); +#endif + if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */ + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Now, compute the reference time value. Use the heavy + * machinery for the seconds and the millisecond field for the + * fraction when present. If an error in conversion to internal + * format is found, the program declares bad data and exits. + * Note that this code does not yet know how to do the years and + * relies on the clock-calendar chip for sanity. + */ + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); +} + +struct vmedate * +get_datumtime(struct vmedate *time_vme) +{ + unsigned short status; + char cbuf[7]; + struct btfp_time vts; + + if ( time_vme == (struct vmedate *)NULL) { + time_vme = (struct vmedate *)malloc(sizeof(struct vmedate )); + } + + if( ioctl(fd_vme, READTIME, &vts)) + msyslog(LOG_ERR, "get_datumtime error: %m"); + + /* if you want to actually check the validity of these registers, do a + define of CHECK above this. I didn't find it necessary. - RES + */ + +#ifdef CHECK + + /* Get day */ + sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) + + ((vts.btfp_time[ 1 ] & 0xff00) >> 8)); + + if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) ) + time_vme->day = (unsigned short)atoi(cbuf); + else + time_vme->day = (unsigned short) 0; + + /* Get hour */ + sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff); + + if (isdigit(cbuf[0]) && isdigit(cbuf[1])) + time_vme->hr = (unsigned short)atoi(cbuf); + else + time_vme->hr = (unsigned short) 0; + + /* Get minutes */ + sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8); + if (isdigit(cbuf[0]) && isdigit(cbuf[1])) + time_vme->mn = (unsigned short)atoi(cbuf); + else + time_vme->mn = (unsigned short) 0; + + /* Get seconds */ + sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff); + + if (isdigit(cbuf[0]) && isdigit(cbuf[1])) + time_vme->sec = (unsigned short)atoi(cbuf); + else + time_vme->sec = (unsigned short) 0; + + /* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can + use the TVTOTSF function later on...*/ + + sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ], + vts.btfp_time[ 4 ]>>8); + + if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) + && isdigit(cbuf[3]) && isdigit(cbuf[4]) && isdigit(cbuf[5])) + time_vme->frac = (u_long) atoi(cbuf); + else + time_vme->frac = (u_long) 0; +#else + + /* DONT CHECK just trust the card */ + + /* Get day */ + sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) + + ((vts.btfp_time[ 1 ] & 0xff00) >> 8)); + time_vme->day = (unsigned short)atoi(cbuf); + + /* Get hour */ + sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff); + + time_vme->hr = (unsigned short)atoi(cbuf); + + /* Get minutes */ + sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8); + time_vme->mn = (unsigned short)atoi(cbuf); + + /* Get seconds */ + sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff); + time_vme->sec = (unsigned short)atoi(cbuf); + + /* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can + use the TVTOTSF function later on...*/ + + sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ], + vts.btfp_time[ 4 ]>>8); + + time_vme->frac = (u_long) atoi(cbuf); + +#endif /* CHECK */ + + /* Get status bit */ + status = (vts.btfp_time[0] & 0x0010) >>4; + time_vme->status = status; /* Status=0 if locked to ref. */ + /* Status=1 if flywheeling */ + if (status) { /* lost lock ? */ + return ((void *)NULL); + } + else + return (time_vme); +} + +#else +int refclock_bancomm_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_chronolog.c b/contrib/ntp/ntpd/refclock_chronolog.c new file mode 100644 index 000000000000..2982ecc9843a --- /dev/null +++ b/contrib/ntp/ntpd/refclock_chronolog.c @@ -0,0 +1,343 @@ +/* + * refclock_chronolog - clock driver for Chronolog K-series WWVB receiver. + */ + +/* + * Must interpolate back to local time. Very annoying. + */ +#define GET_LOCALTIME + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_CHRONOLOG) + +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * This driver supports the Chronolog K-series WWVB receiver. + * + * Input format: + * + * Y YY/MM/DD + * Z hh:mm:ss + * + * YY/MM/DD -- what you'd expect. This arrives a few seconds before the + * timestamp. + * hh:mm:ss -- what you'd expect. We take time on the . + * + * Our Chronolog writes time out at 2400 bps 8/N/1, but it can be configured + * otherwise. The clock seems to appear every 60 seconds, which doesn't make + * for good statistics collection. + * + * The original source of this module was the WWVB module. + */ + +/* + * Interface definitions + */ +#define DEVICE "/dev/chronolog%d" /* device name and unit */ +#define SPEED232 B2400 /* uart speed (2400 baud) */ +#define PRECISION (-13) /* precision assumed (about 100 us) */ +#define REFID "chronolog" /* reference ID */ +#define DESCRIPTION "Chrono-log K" /* WRU */ + +#define MONLIN 15 /* number of monitoring lines */ + +/* + * Chrono-log unit control structure + */ +struct chronolog_unit { + u_char tcswitch; /* timecode switch */ + l_fp laststamp; /* last receive timestamp */ + u_char lasthour; /* last hour (for monitor) */ + int year; /* Y2K-adjusted year */ + int day; /* day-of-month */ + int month; /* month-of-year */ +}; + +/* + * Function prototypes + */ +static int chronolog_start P((int, struct peer *)); +static void chronolog_shutdown P((int, struct peer *)); +static void chronolog_receive P((struct recvbuf *)); +static void chronolog_poll P((int, struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_chronolog = { + chronolog_start, /* start up driver */ + chronolog_shutdown, /* shut down driver */ + chronolog_poll, /* poll the driver -- a nice fabrication */ + noentry, /* not used */ + noentry, /* not used */ + noentry, /* not used */ + NOFLAGS /* not used */ +}; + + +/* + * chronolog_start - open the devices and initialize data for processing + */ +static int +chronolog_start( + int unit, + struct peer *peer + ) +{ + register struct chronolog_unit *up; + struct refclockproc *pp; + int fd; + char device[20]; + + /* + * Open serial port. Don't bother with CLK line discipline, since + * it's not available. + */ + (void)sprintf(device, DEVICE, unit); +#ifdef DEBUG + if (debug) + printf ("starting Chronolog with device %s\n",device); +#endif + if (!(fd = refclock_open(device, SPEED232, 0))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct chronolog_unit *) + emalloc(sizeof(struct chronolog_unit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct chronolog_unit)); + pp = peer->procptr; + pp->unitptr = (caddr_t)up; + pp->io.clock_recv = chronolog_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + return (1); +} + + +/* + * chronolog_shutdown - shut down the clock + */ +static void +chronolog_shutdown( + int unit, + struct peer *peer + ) +{ + register struct chronolog_unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct chronolog_unit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * chronolog_receive - receive data from the serial interface + */ +static void +chronolog_receive( + struct recvbuf *rbufp + ) +{ + struct chronolog_unit *up; + struct refclockproc *pp; + struct peer *peer; + + l_fp trtmp; /* arrival timestamp */ + int hours; /* hour-of-day */ + int minutes; /* minutes-past-the-hour */ + int seconds; /* seconds */ + int temp; /* int temp */ + int got_good; /* got a good time flag */ + + /* + * Initialize pointers and read the timecode and timestamp + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct chronolog_unit *)pp->unitptr; + temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); + + if (temp == 0) { + if (up->tcswitch == 0) { + up->tcswitch = 1; + up->laststamp = trtmp; + } else + up->tcswitch = 0; + return; + } + pp->lencode = temp; + pp->lastrec = up->laststamp; + up->laststamp = trtmp; + up->tcswitch = 1; + +#ifdef DEBUG + if (debug) + printf("chronolog: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + + /* + * We get down to business. Check the timecode format and decode + * its contents. This code uses the first character to see whether + * we're looking at a date or a time. We store data data across + * calls since it is transmitted a few seconds ahead of the + * timestamp. + */ + pp->msec = 0; + got_good=0; + if (sscanf(pp->a_lastcode, "Y %d/%d/%d", &up->year,&up->month,&up->day)) + { + /* + * Y2K convert the 2-digit year + */ + up->year = up->year >= 69 ? up->year : up->year + 100; + return; + } + if (sscanf(pp->a_lastcode,"Z %02d:%02d:%02d", + &hours,&minutes,&seconds) == 3) + { +#ifdef GET_LOCALTIME + struct tm local; + struct tm *gmtp; + time_t unixtime; + int adjyear; + int adjmon; + + /* + * Convert to GMT for sites that distribute localtime. This + * means we have to do Y2K conversion on the 2-digit year; + * otherwise, we get the time wrong. + */ + + local.tm_year = up->year; + local.tm_mon = up->month-1; + local.tm_mday = up->day; + local.tm_hour = hours; + local.tm_min = minutes; + local.tm_sec = seconds; + local.tm_isdst = -1; + + unixtime = mktime (&local); + if ((gmtp = gmtime (&unixtime)) == NULL) + { + refclock_report (peer, CEVNT_FAULT); + return; + } + adjyear = gmtp->tm_year+1900; + adjmon = gmtp->tm_mon+1; + pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday); + pp->hour = gmtp->tm_hour; + pp->minute = gmtp->tm_min; + pp->second = gmtp->tm_sec; +#ifdef DEBUG + if (debug) + printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", + adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute, + pp->second); +#endif + +#else + /* + * For more rational sites distributing UTC + */ + pp->day = ymd2yd(year+1900,month,day); + pp->hour = hours; + pp->minute = minutes; + pp->second = seconds; + +#endif + got_good=1; + } + + if (!got_good) + return; + + + /* + * Process the new sample in the median filter and determine the + * timecode timestamp. + */ + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + up->lasthour = pp->hour; +} + + +/* + * chronolog_poll - called by the transmit procedure + */ +static void +chronolog_poll( + int unit, + struct peer *peer + ) +{ + /* + * Time to poll the clock. The Chrono-log clock is supposed to + * respond to a 'T' by returning a timecode in the format(s) + * specified above. Ours does (can?) not, but this seems to be + * an installation-specific problem. This code is dyked out, + * but may be re-enabled if anyone ever finds a Chrono-log that + * actually listens to this command. + */ +#if 0 + register struct chronolog_unit *up; + struct refclockproc *pp; + char pollchar; + + pp = peer->procptr; + up = (struct chronolog_unit *)pp->unitptr; + if (peer->burst == 0 && peer->reach == 0) + refclock_report(peer, CEVNT_TIMEOUT); + if (up->linect > 0) + pollchar = 'R'; + else + pollchar = 'T'; + if (write(pp->io.fd, &pollchar, 1) != 1) + refclock_report(peer, CEVNT_FAULT); + else + pp->polls++; +#endif +} + +#else +int refclock_chronolog_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_chu.c b/contrib/ntp/ntpd/refclock_chu.c new file mode 100644 index 000000000000..0b2ae78e1b73 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_chu.c @@ -0,0 +1,1464 @@ +/* + * refclock_chu - clock driver for Canadian radio CHU receivers + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_CHU) + +/* #define AUDIO_CHUa */ + +#include +#include +#include +#include +#include + +#ifdef AUDIO_CHU +#ifdef HAVE_SYS_AUDIOIO_H +#include +#endif /* HAVE_SYS_AUDIOIO_H */ +#ifdef HAVE_SUN_AUDIOIO_H +#include +#endif /* HAVE_SUN_AUDIOIO_H */ +#endif /* AUDIO_CHU */ + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * Clock driver for Canadian radio CHU receivers + * + * This driver synchronizes the computer time using data encoded in + * radio transmissions from Canadian time/frequency station CHU in + * Ottawa, Ontario. Transmissions are made continuously on 3330 kHz, + * 7335 kHz and 14670 kHz in upper sideband, compatible AM mode. An + * ordinary shortwave receiver can be tuned manually to one of these + * frequencies or, in the case of ICOM receivers, the receiver can be + * tuned automatically using the minimuf and icom programs as + * propagation conditions change throughout the day and night. + * + * The driver can be compiled to use a Bell 103 compatible modem or + * modem chip to receive the radio signal and demodulate the data. + * Alternatively, the driver can be compiled to use the audio codec of + * the Sun workstation or another with compatible audio drivers. In the + * latter case, the driver implements the modem using DSP routines, so + * the radio can be connected directly to either the microphone on line + * input port. In either case, the driver decodes the data using a + * maximum likelihood technique which exploits the considerable degree + * of redundancy available to maximize accuracy and minimize errors. + * + * The CHU time broadcast includes an audio signal compatible with the + * Bell 103 modem standard (mark = 2225 Hz, space = 2025 Hz). It consist + * of nine, ten-character bursts transmitted at 300 bps and beginning + * each second from second 31 to second 39 of the minute. Each character + * consists of eight data bits plus one start bit and two stop bits to + * encode two hex digits. The burst data consist of five characters (ten + * hex digits) followed by a repeat of these characters. In format A, + * the characters are repeated in the same polarity; in format B, the + * characters are repeated in the opposite polarity. + * + * Format A bursts are sent at seconds 32 through 39 of the minute in + * hex digits + * + * 6dddhhmmss6dddhhmmss + * + * The first ten digits encode a frame marker (6) followed by the day + * (ddd), hour (hh in UTC), minute (mm) and the second (ss). Since + * format A bursts are sent during the third decade of seconds the tens + * digit of ss is always 3. The driver uses this to determine correct + * burst synchronization. These digits are then repeated with the same + * polarity. + * + * Format B bursts are sent at second 31 of the minute in hex digits + * + * xdyyyyttaaxdyyyyttaa + * + * The first ten digits encode a code (x described below) followed by + * the DUT1 (d in deciseconds), Gregorian year (yyyy), difference TAI - + * UTC (tt) and daylight time indicator (aa) peculiar to Canada. These + * digits are then repeated with inverted polarity. + * + * The x is coded + * + * 1 Sign of DUT (0 = +) + * 2 Leap second warning. One second will be added. + * 4 Leap second warning. One second will be subtracted. + * 8 Even parity bit for this nibble. + * + * By design, the last stop bit of the last character in the burst + * coincides with 0.5 second. Since characters have 11 bits and are + * transmitted at 300 bps, the last stop bit of the first character + * coincides with 0.5 - 10 * 11/300 = 0.133 second. Depending on the + * UART, character interrupts can vary somewhere between the beginning + * of bit 9 and end of bit 11. These eccentricities can be corrected + * along with the radio propagation delay using fudge time 1. + * + * Debugging aids + * + * The timecode format used for debugging and data recording includes + * data helpful in diagnosing problems with the radio signal and serial + * connections. With debugging enabled (-d -d -d on the ntpd command + * line), the driver produces one line for each burst in two formats + * corresponding to format A and B. Following is format A: + * + * n b f s m code + * + * where n is the number of characters in the burst (0-11), b the burst + * distance (0-40), f the field alignment (-1, 0, 1), s the + * synchronization distance (0-16), m the burst number (2-9) and code + * the burst characters as received. Note that the hex digits in each + * character are reversed, so the burst + * + * 10 38 0 16 9 06851292930685129293 + * + * is interpreted as containing 11 characters with burst distance 38, + * field alignment 0, synchronization distance 16 and burst number 9. + * The nibble-swapped timecode shows day 58, hour 21, minute 29 and + * second 39. + * + * When the audio driver is compiled, format A is preceded by + * the current gain (0-255) and relative signal level (0-9999). The + * receiver folume control should be set so that the gain is somewhere + * near the middle of the range 0-255, which results in a signal level + * near 1000. + * + * Following is format B: + * + * n b s code + * + * where n is the number of characters in the burst (0-11), b the burst + * distance (0-40), s the synchronization distance (0-40) and code the + * burst characters as received. Note that the hex digits in each + * character are reversed and the last ten digits inverted, so the burst + * + * 11 40 1091891300ef6e76ecff + * + * is interpreted as containing 11 characters with burst distance 40. + * The nibble-swapped timecode shows DUT1 +0.1 second, year 1998 and TAI + * - UTC 31 seconds. + * + * In addition to the above, the reference timecode is updated and + * written to the clockstats file and debug score after the last burst + * received in the minute. The format is + * + * qq yyyy ddd hh:mm:ss nn dd tt + * + * where qq are the error flags, as described below, yyyy is the year, + * ddd the day, hh:mm:ss the time of day, nn the number of format A + * bursts received during the previous minute, dd the decoding distance + * and tt the number of timestamps. The error flags are cleared after + * every update. + * + * Fudge factors + * + * For accuracies better than the low millisceconds, fudge time1 can be + * set to the radio propagation delay from CHU to the receiver. This can + * be done conviently using the minimuf program. When the modem driver + * is compiled, fudge flag3 enables the ppsclock line discipline. Fudge + * flag4 causes the dubugging output described above to be recorded in + * the clockstats file. + * + * When the audio driver is compiled, fudge flag2 selects the audio + * input port, where 0 is the mike port (default) and 1 is the line-in + * port. It does not seem useful to select the compact disc player port. + * Fudge flag3 enables audio monitoring of the input signal. For this + * purpose, the speaker volume must be set before the driver is started. + */ + +/* + * Interface definitions + */ +#define SPEED232 B300 /* uart speed (300 baud) */ +#define PRECISION (-10) /* precision assumed (about 1 ms) */ +#define REFID "CHU" /* reference ID */ +#ifdef AUDIO_CHU +#define DESCRIPTION "CHU Modem Receiver" /* WRU */ + +/* + * Audio demodulator definitions + */ +#define AUDIO_BUFSIZ 160 /* codec buffer size (Solaris only) */ +#define SAMPLE 8000 /* nominal sample rate (Hz) */ +#define BAUD 300 /* modulation rate (bps) */ +#define OFFSET 128 /* companded sample offset */ +#define SIZE 256 /* decompanding table size */ +#define MAXSIG 6000. /* maximum signal level */ +#define DRPOUT 100. /* dropout signal level */ +#define LIMIT 1000. /* soft limiter threshold */ +#define AGAIN 6. /* baseband gain */ +#define LAG 10 /* discriminator lag */ +#else +#define DEVICE "/dev/chu%d" /* device name and unit */ +#define SPEED232 B300 /* UART speed (300 baud) */ +#define DESCRIPTION "CHU Audio Receiver" /* WRU */ +#endif /* AUDIO_CHU */ + +/* + * Decoder definitions + */ +#define CHAR (11. / 300.) /* character time (s) */ +#define FUDGE .185 /* offset to first stop bit (s) */ +#define BURST 11 /* max characters per burst */ +#define MINCHAR 9 /* min characters per burst */ +#define MINDIST 28 /* min burst distance (of 40) */ +#define MINSYNC 8 /* min sync distance (of 16) */ +#define MINDEC .5 /* decoder majority rule (of 1.) */ +#define MINSTAMP 20 /* min timestamps (of 60) */ + +/* + * Hex extension codes (>= 16) + */ +#define HEX_MISS 16 /* miss */ +#define HEX_SOFT 17 /* soft error */ +#define HEX_HARD 18 /* hard error */ + +/* + * Error flags (up->errflg) + */ +#define CHU_ERR_RUNT 0x001 /* runt burst */ +#define CHU_ERR_NOISE 0x002 /* noise burst */ +#define CHU_ERR_BFRAME 0x004 /* invalid format B frame sync */ +#define CHU_ERR_BFORMAT 0x008 /* invalid format B data */ +#define CHU_ERR_AFRAME 0x010 /* invalid format A frame sync */ +#define CHU_ERR_DECODE 0x020 /* invalid data decode */ +#define CHU_ERR_STAMP 0x040 /* too few timestamps */ +#define CHU_ERR_AFORMAT 0x080 /* invalid format A data */ +#ifdef AUDIO_CHU +#define CHU_ERR_ERROR 0x100 /* codec error (overrun) */ +#endif /* AUDIO_CHU */ + +#ifdef AUDIO_CHU +struct surv { + double shift[12]; /* mark register */ + double max, min; /* max/min envelope signals */ + double dist; /* sample distance */ + int uart; /* decoded character */ +}; +#endif /* AUDIO_CHU */ + +/* + * CHU unit control structure + */ +struct chuunit { + u_char decode[20][16]; /* maximum likelihood decoding matrix */ + l_fp cstamp[BURST]; /* character timestamps */ + l_fp tstamp[MAXSTAGE]; /* timestamp samples */ + l_fp timestamp; /* current buffer timestamp */ + l_fp laststamp; /* last buffer timestamp */ + l_fp charstamp; /* character time as a l_fp */ + int errflg; /* error flags */ + int bufptr; /* buffer index pointer */ + int pollcnt; /* poll message counter */ + + /* + * Character burst variables + */ + int cbuf[BURST]; /* character buffer */ + int ntstamp; /* number of timestamp samples */ + int ndx; /* buffer start index */ + int prevsec; /* previous burst second */ + int burdist; /* burst distance */ + int syndist; /* sync distance */ + int burstcnt; /* format A bursts this minute */ + +#ifdef AUDIO_CHU + /* + * Audio codec variables + */ + double comp[SIZE]; /* decompanding table */ + int port; /* codec port */ + int gain; /* codec gain */ + int bufcnt; /* samples in buffer */ + int clipcnt; /* sample clip count */ + int seccnt; /* second interval counter */ + + /* + * Modem variables + */ + l_fp tick; /* audio sample increment */ + double bpf[9]; /* IIR bandpass filter */ + double disc[LAG]; /* discriminator shift register */ + double lpf[27]; /* FIR lowpass filter */ + double monitor; /* audio monitor */ + double maxsignal; /* signal level */ + int discptr; /* discriminator pointer */ + + /* + * Maximum likelihood UART variables + */ + double baud; /* baud interval */ + struct surv surv[8]; /* UART survivor structures */ + int decptr; /* decode pointer */ + int dbrk; /* holdoff counter */ +#endif /* AUDIO_CHU */ +}; + +/* + * Function prototypes + */ +static int chu_start P((int, struct peer *)); +static void chu_shutdown P((int, struct peer *)); +static void chu_receive P((struct recvbuf *)); +static void chu_poll P((int, struct peer *)); + +/* + * More function prototypes + */ +static void chu_decode P((struct peer *, int)); +static void chu_burst P((struct peer *)); +static void chu_clear P((struct peer *)); +static void chu_update P((struct peer *, int)); +static void chu_year P((struct peer *, int)); +static int chu_dist P((int, int)); +#ifdef AUDIO_CHU +static void chu_uart P((struct surv *, double)); +static void chu_rf P((struct peer *, double)); +static void chu_gain P((struct peer *)); +static int chu_audio P((void)); +static void chu_debug P((void)); +#endif /* AUDIO_CHU */ + +/* + * Global variables + */ +static char hexchar[] = "0123456789abcdef_-="; +#ifdef AUDIO_CHU +#ifdef HAVE_SYS_AUDIOIO_H +struct audio_device device; /* audio device ident */ +#endif /* HAVE_SYS_AUDIOIO_H */ +static struct audio_info info; /* audio device info */ +static int chu_ctl_fd; /* audio control file descriptor */ +#endif /* AUDIO_CHU */ + +/* + * Transfer vector + */ +struct refclock refclock_chu = { + chu_start, /* start up driver */ + chu_shutdown, /* shut down driver */ + chu_poll, /* transmit poll message */ + noentry, /* not used (old chu_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old chu_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * chu_start - open the devices and initialize data for processing + */ +static int +chu_start( + int unit, /* instance number (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct chuunit *up; + struct refclockproc *pp; + + /* + * Local variables + */ + int fd; /* file descriptor */ +#ifdef AUDIO_CHU + int i; /* index */ + double step; /* codec adjustment */ + + /* + * Open audio device + */ + fd = open("/dev/audio", O_RDWR | O_NONBLOCK, 0777); + if (fd == -1) { + perror("chu: audio"); + return (0); + } +#else + char device[20]; /* device name */ + + /* + * Open serial port. Use RAW line discipline (required). + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED232, LDISC_RAW))) { + return (0); + } +#endif /* AUDIO_CHU */ + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct chuunit *) + emalloc(sizeof(struct chuunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct chuunit)); + pp = peer->procptr; + pp->unitptr = (caddr_t)up; + pp->io.clock_recv = chu_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void)close(fd); + free(up); + return (0); + } + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + DTOLFP(CHAR, &up->charstamp); + up->pollcnt = 2; +#ifdef AUDIO_CHU + up->gain = (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN) / 2; + if (chu_audio() < 0) { + io_closeclock(&pp->io); + free(up); + return (0); + } + + /* + * The companded samples are encoded sign-magnitude. The table + * contains all the 256 values in the interest of speed. + */ + up->comp[0] = up->comp[OFFSET] = 0.; + up->comp[1] = 1; up->comp[OFFSET + 1] = -1.; + up->comp[2] = 3; up->comp[OFFSET + 2] = -3.; + step = 2.; + for (i = 3; i < OFFSET; i++) { + up->comp[i] = up->comp[i - 1] + step; + up->comp[OFFSET + i] = -up->comp[i]; + if (i % 16 == 0) + step *= 2.; + } + DTOLFP(1. / SAMPLE, &up->tick); +#endif /* AUDIO_CHU */ + return (1); +} + + +/* + * chu_shutdown - shut down the clock + */ +static void +chu_shutdown( + int unit, /* instance number (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct chuunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + +#ifdef AUDIO_CHU + +/* + * chu_receive - receive data from the audio device + */ +static void +chu_receive( + struct recvbuf *rbufp /* receive buffer structure pointer */ + ) +{ + struct chuunit *up; + struct refclockproc *pp; + struct peer *peer; + + /* + * Local variables + */ + double sample; /* codec sample */ + u_char *dpt; /* buffer pointer */ + l_fp ltemp; /* l_fp temp */ + double dtemp; /* double temp */ + int isneg; /* parity flag */ + int i, j; /* index temps */ + + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + + /* + * Main loop - read until there ain't no more. Note codec + * samples are bit-inverted. + */ + up->timestamp = rbufp->recv_time; + up->bufcnt = rbufp->recv_length; + DTOLFP(up->bufcnt * 1. / SAMPLE, <emp); + L_SUB(&up->timestamp, <emp); + dpt = (u_char *)&rbufp->recv_space; + for (up->bufptr = 0; up->bufptr < up->bufcnt; up->bufptr++) { + sample = up->comp[~*dpt & 0xff]; + + /* + * Clip noise spikes greater than MAXSIG. If no clips, + * increase the gain a tad; if the clips are too high, + * decrease a tad. + */ + if (sample > MAXSIG) { + sample = MAXSIG; + up->clipcnt++; + } else if (sample < -MAXSIG) { + sample = -MAXSIG; + up->clipcnt++; + } + up->seccnt = (up->seccnt + 1) % SAMPLE; + if (up->seccnt == 0) { + if (pp->sloppyclockflag & CLK_FLAG2) + up->port = AUDIO_LINE_IN; + else + up->port = AUDIO_MICROPHONE; + chu_gain(peer); + up->clipcnt = 0; + } + chu_rf(peer, sample); + + /* + * During development, it is handy to have an audio + * monitor that can be switched to various signals. This + * code converts the linear signal left in up->monitor + * to codec format. If we can get the grass out of this + * thing and improve modem performance, this expensive + * code will be permanently nixed. + */ + isneg = 0; + dtemp = up->monitor; + if (sample < 0) { + isneg = 1; + dtemp-= dtemp; + } + i = 0; + j = OFFSET >> 1; + while (j != 0) { + if (dtemp > up->comp[i]) + i += j; + else if (dtemp < up->comp[i]) + i -= j; + else + break; + j >>= 1; + } + if (isneg) + *dpt = ~(i + OFFSET); + else + *dpt = ~i; + dpt++; + L_ADD(&up->timestamp, &up->tick); + } + + /* + * Squawk to the monitor speaker if enabled. + */ + if (pp->sloppyclockflag & CLK_FLAG3) + if (write(pp->io.fd, (u_char *)&rbufp->recv_space, + (u_int)up->bufcnt) < 0) + perror("chu:"); +} + + +/* + * chu_rf - filter and demodulate the FSK signal + * + * This routine implements a 300-baud Bell 103 modem with mark 2225 Hz + * and space 2025 Hz. It uses a bandpass filter followed by a soft + * limiter, FM discriminator and lowpass filter. A maximum likelihood + * decoder samples the baseband signal at eight times the baud rate and + * detects the start bit of each character. + * + * The filters are built for speed, which explains the rather clumsy + * code. Hopefully, the compiler will efficiently implement the move- + * and-muiltiply-and-add operations. + */ +void +chu_rf( + struct peer *peer, /* peer structure pointer */ + double sample /* analog sample */ + ) +{ + struct refclockproc *pp; + struct chuunit *up; + struct surv *sp; + + /* + * Local variables + */ + double signal; /* bandpass signal */ + double limit; /* limiter signal */ + double disc; /* discriminator signal */ + double lpf; /* lowpass signal */ + double span; /* UART signal span */ + double dist; /* UART signal distance */ + int i, j; /* index temps */ + + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + /* + * Bandpass filter. 4th-order elliptic, 500-Hz bandpass centered + * at 2125 Hz. Passband ripple 0.3 dB, stopband ripple 50 dB. + */ + signal = (up->bpf[8] = up->bpf[7]) * 5.844676e-01; + signal += (up->bpf[7] = up->bpf[6]) * 4.884860e-01; + signal += (up->bpf[6] = up->bpf[5]) * 2.704384e+00; + signal += (up->bpf[5] = up->bpf[4]) * 1.645032e+00; + signal += (up->bpf[4] = up->bpf[3]) * 4.644557e+00; + signal += (up->bpf[3] = up->bpf[2]) * 1.879165e+00; + signal += (up->bpf[2] = up->bpf[1]) * 3.522634e+00; + signal += (up->bpf[1] = up->bpf[0]) * 7.315738e-01; + up->bpf[0] = sample - signal; + signal = up->bpf[0] * 6.176213e-03 + + up->bpf[1] * 3.156599e-03 + + up->bpf[2] * 7.567487e-03 + + up->bpf[3] * 4.344580e-03 + + up->bpf[4] * 1.190128e-02 + + up->bpf[5] * 4.344580e-03 + + up->bpf[6] * 7.567487e-03 + + up->bpf[7] * 3.156599e-03 + + up->bpf[8] * 6.176213e-03; + + up->monitor = signal / 4.; /* note monitor after filter */ + + /* + * Soft limiter/discriminator. The 11-sample discriminator lag + * interval corresponds to three cycles of 2125 Hz, which + * requires the sample frequency to be 2125 * 11 / 3 = 7791.7 + * Hz. The discriminator output varies +-0.5 interval for input + * frequency 2025-2225 Hz. However, we don't get to sample at + * this frequency, so the discriminator output is biased. Life + * at 8000 Hz sucks. + */ + limit = signal; + if (limit > LIMIT) + limit = LIMIT; + else if (limit < -LIMIT) + limit = -LIMIT; + disc = up->disc[up->discptr] * -limit; + up->disc[up->discptr] = limit; + up->discptr = (up->discptr + 1 ) % LAG; + if (disc >= 0) + disc = sqrt(disc); + else + disc = -sqrt(-disc); + + /* + * Lowpass filter. Raised cosine, Ts = 1 / 300, beta = 0.1. + */ + lpf = (up->lpf[26] = up->lpf[25]) * 2.538771e-02; + lpf += (up->lpf[25] = up->lpf[24]) * 1.084671e-01; + lpf += (up->lpf[24] = up->lpf[23]) * 2.003159e-01; + lpf += (up->lpf[23] = up->lpf[22]) * 2.985303e-01; + lpf += (up->lpf[22] = up->lpf[21]) * 4.003697e-01; + lpf += (up->lpf[21] = up->lpf[20]) * 5.028552e-01; + lpf += (up->lpf[20] = up->lpf[19]) * 6.028795e-01; + lpf += (up->lpf[19] = up->lpf[18]) * 6.973249e-01; + lpf += (up->lpf[18] = up->lpf[17]) * 7.831828e-01; + lpf += (up->lpf[17] = up->lpf[16]) * 8.576717e-01; + lpf += (up->lpf[16] = up->lpf[15]) * 9.183463e-01; + lpf += (up->lpf[15] = up->lpf[14]) * 9.631951e-01; + lpf += (up->lpf[14] = up->lpf[13]) * 9.907208e-01; + lpf += (up->lpf[13] = up->lpf[12]) * 1.000000e+00; + lpf += (up->lpf[12] = up->lpf[11]) * 9.907208e-01; + lpf += (up->lpf[11] = up->lpf[10]) * 9.631951e-01; + lpf += (up->lpf[10] = up->lpf[9]) * 9.183463e-01; + lpf += (up->lpf[9] = up->lpf[8]) * 8.576717e-01; + lpf += (up->lpf[8] = up->lpf[7]) * 7.831828e-01; + lpf += (up->lpf[7] = up->lpf[6]) * 6.973249e-01; + lpf += (up->lpf[6] = up->lpf[5]) * 6.028795e-01; + lpf += (up->lpf[5] = up->lpf[4]) * 5.028552e-01; + lpf += (up->lpf[4] = up->lpf[3]) * 4.003697e-01; + lpf += (up->lpf[3] = up->lpf[2]) * 2.985303e-01; + lpf += (up->lpf[2] = up->lpf[1]) * 2.003159e-01; + lpf += (up->lpf[1] = up->lpf[0]) * 1.084671e-01; + lpf += up->lpf[0] = disc * 2.538771e-02; +/* +printf("%8.3f %8.3f\n", disc, lpf); +return; +*/ + /* + * Maximum likelihood decoder. The UART updates each of the + * eight survivors and determines the span, slice level and + * tentative decoded character. Valid 11-bit characters are + * framed so that bit 1 and bit 11 (stop bits) are mark and bit + * 2 (start bit) is space. When a valid character is found, the + * survivor with maximum distance determines the final decoded + * character. + */ + up->baud += 1. / SAMPLE; + if (up->baud > 1. / (BAUD * 8.)) { + up->baud -= 1. / (BAUD * 8.); + sp = &up->surv[up->decptr]; + span = sp->max - sp->min; + up->maxsignal += (span - up->maxsignal) / 80.; + if (up->dbrk > 0) { + up->dbrk--; + } else if ((sp->uart & 0x403) == 0x401 && span > 1000.) + { + dist = 0; + j = 0; + for (i = 0; i < 8; i++) { + if (up->surv[i].dist > dist) { + dist = up->surv[i].dist; + j = i; + } + } + chu_decode(peer, (up->surv[j].uart >> 2) & + 0xff); + up->dbrk = 80; + } + up->decptr = (up->decptr + 1) % 8; + chu_uart(sp, -lpf * AGAIN); + } +} + + +/* + * chu_uart - maximum likelihood UART + * + * This routine updates a shift register holding the last 11 envelope + * samples. It then computes the slice level and span over these samples + * and determines the tentative data bits and distance. The calling + * program selects over the last eight survivors the one with maximum + * distance to determine the decoded character. + */ +void +chu_uart( + struct surv *sp, /* survivor structure pointer */ + double sample /* baseband signal */ + ) +{ + /* + * Local variables + */ + double max, min; /* max/min envelope */ + double slice; /* slice level */ + double dist; /* distance */ + double dtemp; /* double temp */ + int i; /* index temp */ + + /* + * Save the sample and shift right. At the same time, measure + * the maximum and minimum over all eleven samples. + */ + max = -1e6; + min = 1e6; + sp->shift[0] = sample; + for (i = 11; i > 0; i--) { + sp->shift[i] = sp->shift[i - 1]; + if (sp->shift[i] > max) + max = sp->shift[i]; + if (sp->shift[i] < min) + min = sp->shift[i]; + } + + /* + * Determine the slice level midway beteen the maximum and + * minimum and the span as the maximum less the minimum. Compute + * the distance on the assumption the first and last bits must + * be mark, the second space and the rest either mark or space. + */ + slice = (max + min) / 2.; + dist = 0; + sp->uart = 0; + for (i = 1; i < 12; i++) { + sp->uart <<= 1; + dtemp = sp->shift[i]; + if (dtemp > slice) + sp->uart |= 0x1; + if (i == 1 || i == 11) { + dist += dtemp - min; + } else if (i == 10) { + dist += max - dtemp; + } else { + if (dtemp > slice) + dist += dtemp - min; + else + dist += max - dtemp; + } + } + sp->max = max; + sp->min = min; + sp->dist = dist / (11 * (max - min)); +} + + +#else /* AUDIO_CHU */ +/* + * chu_receive - receive data from the serial interface + */ +static void +chu_receive( + struct recvbuf *rbufp /* receive buffer structure pointer */ + ) +{ + struct chuunit *up; + struct refclockproc *pp; + struct peer *peer; + + u_char *dpt; /* receive buffer pointer */ + + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + + /* + * Initialize pointers and read the timecode and timestamp. + */ + up->timestamp = rbufp->recv_time; + dpt = (u_char *)&rbufp->recv_space; + chu_decode(peer, *dpt); +} +#endif /* AUDIO_CHU */ + + +/* + * chu_decode - decode the data + */ +static void +chu_decode( + struct peer *peer, /* peer structure pointer */ + int hexhex /* data character */ + ) +{ + struct refclockproc *pp; + struct chuunit *up; + + /* + * Local variables + */ + l_fp tstmp; /* timestamp temp */ + double dtemp; /* double temp */ + + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + + /* + * If the interval since the last character is greater than the + * longest burst, process the last burst and start a new one. If + * the interval is less than this but greater than two + * characters, consider this a noise burst and reject it. + */ + tstmp = up->timestamp; + if (L_ISZERO(&up->laststamp)) + up->laststamp = up->timestamp; + L_SUB(&tstmp, &up->laststamp); + up->laststamp = up->timestamp; + LFPTOD(&tstmp, dtemp); + if (dtemp > BURST * CHAR) { + chu_burst(peer); + up->ndx = 0; + } else if (dtemp > 2.5 * CHAR) { + up->ndx = 0; + } + + /* + * Append the character to the current burst and append the + * timestamp to the timestamp list. + */ + if (up->ndx < BURST) { + up->cbuf[up->ndx] = hexhex & 0xff; + up->cstamp[up->ndx] = up->timestamp; + up->ndx++; + + } +} + + +/* + * chu_burst - search for valid burst format + */ +static void +chu_burst( + struct peer *peer + ) +{ + struct chuunit *up; + struct refclockproc *pp; + + /* + * Local variables + */ + int i; /* index temp */ + + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + + /* + * Correlate a block of five characters with the next block of + * five characters. The burst distance is defined as the number + * of bits that match in the two blocks for format A and that + * match the inverse for format B. + */ + if (up->ndx < MINCHAR) { + up->errflg |= CHU_ERR_RUNT; + return; + } + up->burdist = 0; + for (i = 0; i < 5 && i < up->ndx - 5; i++) + up->burdist += chu_dist(up->cbuf[i], up->cbuf[i + 5]); + + /* + * If the burst distance is at least MINDIST, this must be a + * format A burst; if the value is not greater than -MINDIST, it + * must be a format B burst; otherwise, it is a noise burst and + * of no use to anybody. + */ + if (up->burdist >= MINDIST) { + chu_update(peer, up->ndx); + } else if (up->burdist <= -MINDIST) { + chu_year(peer, up->ndx); + } else { + up->errflg |= CHU_ERR_NOISE; + return; + } + + /* + * If this is a valid burst, wait a guard time of ten seconds to + * allow for more bursts, then arm the poll update routine to + * process the minute. Don't do this if this is called from the + * timer interrupt routine. + */ + if (peer->outdate == current_time) + up->pollcnt = 2; + else + peer->nextdate = current_time + 10; +} + + +/* + * chu_year - decode format B burst + */ +static void +chu_year( + struct peer *peer, + int nchar + ) +{ + struct refclockproc *pp; + struct chuunit *up; + + /* + * Local variables + */ + u_char code[11]; /* decoded timecode */ + l_fp offset; /* timestamp offset */ + int leap; /* leap/dut code */ + int dut; /* UTC1 correction */ + int tai; /* TAI - UTC correction */ + int dst; /* Canadian DST code */ + int i; /* index temp */ + + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + + /* + * In a format B burst, a character is considered valid only if + * the first occurrence matches the last occurrence. The burst + * is considered valid only if all characters are valid; that + * is, only if the distance is 40. + */ + sprintf(pp->a_lastcode, "%2d %2d ", nchar, -up->burdist); + for (i = 0; i < nchar; i++) + sprintf(&pp->a_lastcode[strlen(pp->a_lastcode)], "%02x", + up->cbuf[i]); + pp->lencode = strlen(pp->a_lastcode); + if (pp->sloppyclockflag & CLK_FLAG4) + record_clock_stats(&peer->srcadr, pp->a_lastcode); +#ifdef DEBUG + if (debug > 2) + printf("chu: %s\n", pp->a_lastcode); +#endif + if (-up->burdist < 40) { + up->errflg |= CHU_ERR_BFRAME; + return; + } + + /* + * Convert the burst data to internal format. If this succeeds, + * save the timestamps for later. The leap, dut, tai and dst are + * presently unused. + */ + for (i = 0; i < 5; i++) { + code[2 * i] = hexchar[up->cbuf[i] & 0xf]; + code[2 * i + 1] = hexchar[(up->cbuf[i] >> + 4) & 0xf]; + } + if (sscanf((char *)code, "%1x%1d%4d%2d%2x", &leap, &dut, + &pp->year, &tai, &dst) != 5) { + up->errflg |= CHU_ERR_BFORMAT; + return; + } + offset.l_ui = 31; + offset.l_f = 0; + for (i = 0; i < nchar && i < 10; i++) { + up->tstamp[up->ntstamp] = up->cstamp[i]; + L_SUB(&up->tstamp[up->ntstamp], &offset); + L_ADD(&offset, &up->charstamp); + if (up->ntstamp < MAXSTAGE) + up->ntstamp++; + } +} + + +/* + * chu_update - decode format A burst + */ +static void +chu_update( + struct peer *peer, + int nchar + ) +{ + struct refclockproc *pp; + struct chuunit *up; + + /* + * Local variables + */ + l_fp offset; /* timestamp offset */ + int val; /* distance */ + int temp; /* common temp */ + int i, j, k; /* index temps */ + + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + + /* + * Determine correct burst phase. There are three cases + * corresponding to in-phase, one character early or one + * character late. These cases are distinguished by the position + * of the framing digits x6 at positions 0 and 5 and x3 at + * positions 4 and 9. The correct phase is when the distance + * relative to the framing digits is maximum. The burst is valid + * only if the maximum distance is at least MINSYNC. + */ + up->syndist = k = 0; + val = -16; + for (i = -1; i < 2; i++) { + temp = up->cbuf[i + 4] & 0xf; + if (i >= 0) + temp |= (up->cbuf[i] & 0xf) << 4; + val = chu_dist(temp, 0x63); + temp = (up->cbuf[i + 5] & 0xf) << 4; + if (i + 9 < nchar) + temp |= up->cbuf[i + 9] & 0xf; + val += chu_dist(temp, 0x63); + if (val > up->syndist) { + up->syndist = val; + k = i; + } + } + + temp = (up->cbuf[k + 4] >> 4) & 0xf; + if (temp > 9 || k + 9 >= nchar || temp != ((up->cbuf[k + 9] >> + 4) & 0xf)) + temp = 0; +#ifdef AUDIO_CHU + sprintf(pp->a_lastcode, "%3d %4.0f %2d %2d %2d %2d %1d ", + up->gain, up->maxsignal, nchar, up->burdist, k, up->syndist, + temp); +#else + sprintf(pp->a_lastcode, "%2d %2d %2d %2d %1d ", nchar, + up->burdist, k, up->syndist, temp); +#endif /* AUDIO_CHU */ + for (i = 0; i < nchar; i++) + sprintf(&pp->a_lastcode[strlen(pp->a_lastcode)], "%02x", + up->cbuf[i]); + pp->lencode = strlen(pp->a_lastcode); + if (pp->sloppyclockflag & CLK_FLAG4) + record_clock_stats(&peer->srcadr, pp->a_lastcode); +#ifdef DEBUG + if (debug > 2) + printf("chu: %s\n", pp->a_lastcode); +#endif + if (up->syndist < MINSYNC) { + up->errflg |= CHU_ERR_AFRAME; + return; + } + + /* + * A valid burst requires the first seconds number to match the + * last seconds number. If so, the burst timestamps are + * corrected to the current minute and saved for later + * processing. In addition, the seconds decode is advanced from + * the previous burst to the current one. + */ + if (temp != 0) { + offset.l_ui = 30 + temp; + offset.l_f = 0; + i = 0; + if (k < 0) + offset = up->charstamp; + else if (k > 0) + i = 1; + for (; i < nchar && i < k + 10; i++) { + up->tstamp[up->ntstamp] = up->cstamp[i]; + L_SUB(&up->tstamp[up->ntstamp], &offset); + L_ADD(&offset, &up->charstamp); + if (up->ntstamp < MAXSTAGE) + up->ntstamp++; + } + while (temp > up->prevsec) { + for (j = 15; j > 0; j--) { + up->decode[9][j] = up->decode[9][j - 1]; + up->decode[19][j] = + up->decode[19][j - 1]; + } + up->decode[9][j] = up->decode[19][j] = 0; + up->prevsec++; + } + } + i = -(2 * k); + for (j = 0; j < nchar; j++) { + if (i < 0 || i > 19) { + i += 2; + continue; + } + up->decode[i++][up->cbuf[j] & 0xf]++; + up->decode[i++][(up->cbuf[j] >> 4) & 0xf]++; + } + up->burstcnt++; +} + + +/* + * chu_poll - called by the transmit procedure + */ +static void +chu_poll( + int unit, + struct peer *peer + ) +{ + struct refclockproc *pp; + struct chuunit *up; + + /* + * Local variables + */ + u_char code[11]; /* decoded timecode */ + l_fp toffset, offset; /* l_fp temps */ + int mindist; /* minimum distance */ + int val1, val2; /* maximum distance */ + int synchar; /* should be a 6 in traffic */ + double dtemp; /* double temp */ + int temp; /* common temp */ + int i, j, k; /* index temps */ + + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + + /* + * Process the last burst, if still in the burst buffer. + * Don't mess with anything if nothing has been heard. + */ + chu_burst(peer); + if (up->pollcnt == 0) + refclock_report(peer, CEVNT_TIMEOUT); + else + up->pollcnt--; + if (up->burstcnt == 0) { + chu_clear(peer); + return; + } + + /* + * Majority decoder. Select the character with the most + * occurrences for each burst position. The distance for the + * character is this number of occurrences. If no occurrences + * are found, assume a miss '_'; if only a single occurrence is + * found, assume a soft error '-'; if two different characters + * with the same distance are found, assume a hard error '='. + * The decoding distance is defined as the minimum of the + * character distances. + */ + mindist = 16; + for (i = 0; i < 10; i++) { + val1 = val2 = 0; + k = 0; + for (j = 0; j < 16; j++) { + temp = up->decode[i][j] + up->decode[i + 10][j]; + if (temp > val1) { + val2 = val1; + val1 = temp; + k = j; + } + } + if (val1 > 0 && val1 == val2) + code[i] = HEX_HARD; + else if (val1 < 2) + code[i] = HEX_SOFT; + else + code[i] = k; + if (val1 < mindist) + mindist = val1; + code[i] = hexchar[code[i]]; + } + code[i] = 0; + if (mindist < up->burstcnt * 2 * MINDEC) + up->errflg |= CHU_ERR_DECODE; + if (up->ntstamp < MINSTAMP) + up->errflg |= CHU_ERR_STAMP; + + /* + * Compute the timecode timestamp from the days, hours and + * minutes of the timecode. Use clocktime() for the aggregate + * minutes and the minute offset computed from the burst + * seconds. Note that this code relies on the filesystem time + * for the years and does not use the years of the timecode. + */ + if (sscanf((char *)code, "%1x%3d%2d%2d", &synchar, &pp->day, &pp->hour, + &pp->minute) != 4) + up->errflg |= CHU_ERR_AFORMAT; + sprintf(pp->a_lastcode, + "%02x %4d %3d %02d:%02d:%02d %2d %2d %2d", + up->errflg, pp->year, pp->day, pp->hour, pp->minute, + pp->second, up->burstcnt, mindist, up->ntstamp); + pp->lencode = strlen(pp->a_lastcode); + record_clock_stats(&peer->srcadr, pp->a_lastcode); +#ifdef DEBUG + if (debug > 2) + printf("chu: %s\n", pp->a_lastcode); +#endif + if (up->errflg & (CHU_ERR_DECODE | CHU_ERR_STAMP | + CHU_ERR_AFORMAT)) { + refclock_report(peer, CEVNT_BADREPLY); + chu_clear(peer); + return; + } + L_CLR(&offset); + if (!clocktime(pp->day, pp->hour, pp->minute, 0, GMT, + up->tstamp[0].l_ui, &pp->yearstart, &offset.l_ui)) { + refclock_report(peer, CEVNT_BADTIME); + chu_clear(peer); + return; + } + pp->polls++; + pp->leap = LEAP_NOWARNING; + pp->lastref = offset; + pp->variance = 0; + for (i = 0; i < up->ntstamp; i++) { + toffset = offset; + L_SUB(&toffset, &up->tstamp[i]); + LFPTOD(&toffset, dtemp); + SAMPLE(dtemp + FUDGE + pp->fudgetime1); + } + if (i > 0) + refclock_receive(peer); + chu_clear(peer); +} + + +/* + * chu_clear - clear decoding matrix + */ +static void +chu_clear( + struct peer *peer + ) +{ + struct refclockproc *pp; + struct chuunit *up; + + /* + * Local variables + */ + int i, j; /* index temps */ + + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + + /* + * Clear stuff for following minute. + */ + up->ndx = up->ntstamp = up->prevsec = 0; + up->errflg = 0; + up->burstcnt = 0; + for (i = 0; i < 20; i++) { + for (j = 0; j < 16; j++) + up->decode[i][j] = 0; + } +} + + +/* + * chu_dist - determine the distance of two octet arguments + */ +static int +chu_dist( + int x, /* an octet of bits */ + int y /* another octet of bits */ + ) +{ + /* + * Local variables + */ + int val; /* bit count */ + int temp; /* misc temporary */ + int i; /* index temporary */ + + /* + * The distance is determined as the weight of the exclusive OR + * of the two arguments. The weight is determined by the number + * of one bits in the result. Each one bit increases the weight, + * while each zero bit decreases it. + */ + temp = x ^ y; + val = 0; + for (i = 0; i < 8; i++) { + if ((temp & 0x1) == 0) + val++; + else + val--; + temp >>= 1; + } + return (val); +} + + +#ifdef AUDIO_CHU +/* + * chu_gain - adjust codec gain + * + * This routine is called once each second. If the signal envelope + * amplitude is too low, the codec gain is bumped up by four units; if + * too high, it is bumped down. The decoder is relatively insensitive to + * amplitude, so this crudity works just fine. The input port is set and + * the error flag is cleared, mostly to be ornery. + */ +static void +chu_gain( + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + struct chuunit *up; + + pp = peer->procptr; + up = (struct chuunit *)pp->unitptr; + + /* + * Apparently, the codec uses only the high order bits of the + * gain control field. Thus, it may take awhile for changes to + * wiggle the hardware bits. Set the new bits in the structure + * and call AUDIO_SETINFO. Upon return, the old bits are in the + * structure. + */ + if (up->clipcnt == 0) { + up->gain += 4; + if (up->gain > AUDIO_MAX_GAIN) + up->gain = AUDIO_MAX_GAIN; + } else if (up->clipcnt > SAMPLE / 100) { + up->gain -= 4; + if (up->gain < AUDIO_MIN_GAIN) + up->gain = AUDIO_MIN_GAIN; + } + AUDIO_INITINFO(&info); + info.record.port = up->port; + info.record.gain = up->gain; + info.record.error = 0; + ioctl(chu_ctl_fd, (int)AUDIO_SETINFO, &info); + if (info.record.error) + up->errflg |= CHU_ERR_ERROR; +} + + +/* + * chu_audio - initialize audio device + * + * This code works with SunOS 4.1.3 and Solaris 2.6; however, it is + * believed generic and applicable to other systems with a minor twid + * or two. All it does is open the device, set the buffer size (Solaris + * only), preset the gain and set the input port. It assumes that the + * codec sample rate (8000 Hz), precision (8 bits), number of channels + * (1) and encoding (ITU-T G.711 mu-law companded) have been set by + * default. + */ +static int +chu_audio( + ) +{ + /* + * Open audio control device + */ + if ((chu_ctl_fd = open("/dev/audioctl", O_RDWR)) < 0) { + perror("audioctl"); + return(-1); + } +#ifdef HAVE_SYS_AUDIOIO_H + /* + * Set audio device parameters. + */ + AUDIO_INITINFO(&info); + info.record.buffer_size = AUDIO_BUFSIZ; + if (ioctl(chu_ctl_fd, (int)AUDIO_SETINFO, &info) < 0) { + perror("AUDIO_SETINFO"); + close(chu_ctl_fd); + return(-1); + } +#endif /* HAVE_SYS_AUDIOIO_H */ +#ifdef DEBUG + chu_debug(); +#endif /* DEBUG */ + return(0); +} + + +#ifdef DEBUG +/* + * chu_debug - display audio parameters + * + * This code doesn't really do anything, except satisfy curiousity and + * verify the ioctl's work. + */ +static void +chu_debug( + ) +{ + if (debug == 0) + return; +#ifdef HAVE_SYS_AUDIOIO_H + ioctl(chu_ctl_fd, (int)AUDIO_GETDEV, &device); + printf("chu: name %s, version %s, config %s\n", + device.name, device.version, device.config); +#endif /* HAVE_SYS_AUDIOIO_H */ + ioctl(chu_ctl_fd, (int)AUDIO_GETINFO, &info); + printf( + "chu: samples %d, channels %d, precision %d, encoding %d\n", + info.record.sample_rate, info.record.channels, + info.record.precision, info.record.encoding); +#ifdef HAVE_SYS_AUDIOIO_H + printf("chu: gain %d, port %d, buffer %d\n", + info.record.gain, info.record.port, + info.record.buffer_size); +#else /* HAVE_SYS_AUDIOIO_H */ + printf("chu: gain %d, port %d\n", + info.record.gain, info.record.port); +#endif /* HAVE_SYS_AUDIOIO_H */ + printf( + "chu: samples %d, eof %d, pause %d, error %d, waiting %d, balance %d\n", + info.record.samples, info.record.eof, + info.record.pause, info.record.error, + info.record.waiting, info.record.balance); + printf("chu: monitor %d, muted %d\n", + info.monitor_gain, info.output_muted); +} +#endif /* DEBUG */ +#endif /* AUDIO_CHU */ + +#else +int refclock_chu_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_conf.c b/contrib/ntp/ntpd/refclock_conf.c new file mode 100644 index 000000000000..d203dd7c22ff --- /dev/null +++ b/contrib/ntp/ntpd/refclock_conf.c @@ -0,0 +1,262 @@ +/* + * refclock_conf.c - reference clock configuration + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "ntpd.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +#ifdef REFCLOCK + +static struct refclock refclock_none = { + noentry, noentry, noentry, noentry, noentry, noentry, NOFLAGS +}; + +#ifdef CLOCK_LOCAL +extern struct refclock refclock_local; +#else +#define refclock_local refclock_none +#endif + +#ifdef CLOCK_TRAK +extern struct refclock refclock_trak; +#else +#define refclock_trak refclock_none +#endif + +#ifdef CLOCK_PST +extern struct refclock refclock_pst; +#else +#define refclock_pst refclock_none +#endif + +#ifdef CLOCK_CHU +extern struct refclock refclock_chu; +#else +#define refclock_chu refclock_none +#endif + +#ifdef CLOCK_WWVB +extern struct refclock refclock_wwvb; +#else +#define refclock_wwvb refclock_none +#endif + +#ifdef CLOCK_PARSE +extern struct refclock refclock_parse; +#else +#define refclock_parse refclock_none +#endif + +#if defined(CLOCK_MX4200) && defined(PPS) +extern struct refclock refclock_mx4200; +#else +#define refclock_mx4200 refclock_none +#endif + +#ifdef CLOCK_AS2201 +extern struct refclock refclock_as2201; +#else +#define refclock_as2201 refclock_none +#endif + +#ifdef CLOCK_ARBITER +extern struct refclock refclock_arbiter; +#else +#define refclock_arbiter refclock_none +#endif + +#ifdef CLOCK_TPRO +extern struct refclock refclock_tpro; +#else +#define refclock_tpro refclock_none +#endif + +#ifdef CLOCK_LEITCH +extern struct refclock refclock_leitch; +#else +#define refclock_leitch refclock_none +#endif + +#ifdef CLOCK_IRIG +extern struct refclock refclock_irig; +#else +#define refclock_irig refclock_none +#endif + +#if defined(CLOCK_MSFEES) && defined(PPS) +extern struct refclock refclock_msfees; +#else +#define refclock_msfees refclock_none +#endif + +#ifdef CLOCK_BANC +extern struct refclock refclock_bancomm; +#else +#define refclock_bancomm refclock_none +#endif + +#ifdef CLOCK_TRUETIME +extern struct refclock refclock_true; +#else +#define refclock_true refclock_none +#endif + +#ifdef CLOCK_DATUM +extern struct refclock refclock_datum; +#else +#define refclock_datum refclock_none +#endif + +#ifdef CLOCK_ACTS +extern struct refclock refclock_acts; +#else +#define refclock_acts refclock_none +#endif + +#ifdef CLOCK_HEATH +extern struct refclock refclock_heath; +#else +#define refclock_heath refclock_none +#endif + +#ifdef CLOCK_NMEA +extern struct refclock refclock_nmea; +#else +#define refclock_nmea refclock_none +#endif + +#ifdef CLOCK_ATOM +extern struct refclock refclock_atom; +#else +#define refclock_atom refclock_none +#endif + +#ifdef CLOCK_PTBACTS +extern struct refclock refclock_ptb; +#else +#define refclock_ptb refclock_none +#endif + +#ifdef CLOCK_USNO +extern struct refclock refclock_usno; +#else +#define refclock_usno refclock_none +#endif + +#ifdef CLOCK_HPGPS +extern struct refclock refclock_hpgps; +#else +#define refclock_hpgps refclock_none +#endif + +#ifdef CLOCK_GPSVME +extern struct refclock refclock_gpsvme; +#else +#define refclock_gpsvme refclock_none +#endif + +#ifdef CLOCK_ARCRON_MSF +extern struct refclock refclock_arc; +#else +#define refclock_arc refclock_none +#endif + +#ifdef SHM +extern struct refclock refclock_shm; +#else +#define refclock_shm refclock_none +#endif + +#ifdef CLOCK_PALISADE +extern struct refclock refclock_palisade; +#else +#define refclock_palisade refclock_none +#endif + +#ifdef CLOCK_ONCORE +extern struct refclock refclock_oncore; +#else +#define refclock_oncore refclock_none +#endif + +#if defined(CLOCK_JUPITER) && defined(PPS) +extern struct refclock refclock_jupiter; +#else +#define refclock_jupiter refclock_none +#endif + +#if defined(CLOCK_CHRONOLOG) +extern struct refclock refclock_chronolog; +#else +#define refclock_chronolog refclock_none +#endif + +#if defined(CLOCK_DUMBCLOCK) +extern struct refclock refclock_dumbclock; +#else +#define refclock_dumbclock refclock_none +#endif + +#ifdef CLOCK_ULINK +extern struct refclock refclock_ulink; +#else +#define refclock_ulink refclock_none +#endif + + +/* + * Order is clock_start(), clock_shutdown(), clock_poll(), + * clock_control(), clock_init(), clock_buginfo, clock_flags; + * + * Types are defined in ntp.h. The index must match this. + */ +struct refclock *refclock_conf[] = { + &refclock_none, /* 0 REFCLK_NONE */ + &refclock_local, /* 1 REFCLK_LOCAL */ + &refclock_trak, /* 2 REFCLK_GPS_TRAK */ + &refclock_pst, /* 3 REFCLK_WWV_PST */ + &refclock_wwvb, /* 4 REFCLK_WWVB_SPECTRACOM */ + &refclock_true, /* 5 REFCLK_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_arbiter, /* 11 REFCLK_GPS_ARBITER */ + &refclock_tpro, /* 12 REFCLK_IRIG_TPRO */ + &refclock_leitch, /* 13 REFCLK_ATOM_LEITCH */ + &refclock_msfees, /* 14 REFCLK_MSF_EES */ + &refclock_true, /* 15 alias for REFCLK_TRUETIME */ + &refclock_bancomm, /* 16 REFCLK_IRIG_BANCOMM */ + &refclock_datum, /* 17 REFCLK_GPS_DATUM */ + &refclock_acts, /* 18 REFCLK_NIST_ACTS */ + &refclock_heath, /* 19 REFCLK_WWV_HEATH */ + &refclock_nmea, /* 20 REFCLK_GPS_NMEA */ + &refclock_gpsvme, /* 21 REFCLK_GPS_VME */ + &refclock_atom, /* 22 REFCLK_ATOM_PPS */ + &refclock_ptb, /* 23 REFCLK_PTB_ACTS */ + &refclock_usno, /* 24 REFCLK_USNO */ + &refclock_true, /* 25 alias for REFCLK_TRUETIME */ + &refclock_hpgps, /* 26 REFCLK_GPS_HP */ + &refclock_arc, /* 27 REFCLK_ARCRON_MSF */ + &refclock_shm, /* 28 REFCLK_SHM */ + &refclock_palisade, /* 29 REFCLK_PALISADE */ + &refclock_oncore, /* 30 REFCLK_ONCORE */ + &refclock_jupiter, /* 31 REFCLK_GPS_JUPITER */ + &refclock_chronolog, /* 32 REFCLK_CHRONOLOG */ + &refclock_dumbclock, /* 33 REFCLK_DUMBCLOCK */ + &refclock_ulink, /* 34 REFCLOCK_ULINK */ +}; + +u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *); + +#else +int refclock_conf_bs; +#endif diff --git a/contrib/ntp/ntpd/refclock_datum.c b/contrib/ntp/ntpd/refclock_datum.c new file mode 100644 index 000000000000..74a37dbbc575 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_datum.c @@ -0,0 +1,873 @@ +/* +** refclock_datum - clock driver for the Datum Programmable Time Server +** +** Important note: This driver assumes that you have termios. If you have +** a system that does not have termios, you will have to modify this driver. +** +** Sorry, I have only tested this driver on SUN and HP platforms. +*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_DATUM) + +/* +** Include Files +*/ + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ + +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ + +#if defined(HAVE_TERMIOS) +#include +#endif +#if defined(STREAM) +#include +#if defined(WWVBCLK) +#include +#endif /* WWVBCLK */ +#endif /* STREAM */ + +#if defined (WWVBPPS) +#include +#endif /* WWVBPPS */ + +#include "ntp_stdlib.h" + +/* +** This driver supports the Datum Programmable Time System (PTS) clock. +** The clock works in very straight forward manner. When it receives a +** time code request (e.g., the ascii string "//k/mn"), it responds with +** a seven byte BCD time code. This clock only responds with a +** time code after it first receives the "//k/mn" message. It does not +** periodically send time codes back at some rate once it is started. +** the returned time code can be broken down into the following fields. +** +** _______________________________ +** Bit Index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +** =============================== +** byte 0: | - - - - | H D | +** =============================== +** byte 1: | T D | U D | +** =============================== +** byte 2: | - - | T H | U H | +** =============================== +** byte 3: | - | T M | U M | +** =============================== +** byte 4: | - | T S | U S | +** =============================== +** byte 5: | t S | h S | +** =============================== +** byte 6: | m S | - - - - | +** =============================== +** +** In the table above: +** +** "-" means don't care +** "H D", "T D", and "U D" means Hundreds, Tens, and Units of Days +** "T H", and "UH" means Tens and Units of Hours +** "T M", and "U M" means Tens and Units of Minutes +** "T S", and "U S" means Tens and Units of Seconds +** "t S", "h S", and "m S" means tenths, hundredths, and thousandths +** of seconds +** +** The Datum PTS communicates throught the RS232 port on your machine. +** Right now, it assumes that you have termios. This driver has been tested +** on SUN and HP workstations. The Datum PTS supports various IRIG and +** NASA input codes. This driver assumes that the name of the device is +** /dev/datum. You will need to make a soft link to your RS232 device or +** create a new driver to use this refclock. +*/ + +/* +** Datum PTS defines +*/ + +/* +** Note that if GMT is defined, then the Datum PTS must use Greenwich +** time. Otherwise, this driver allows the Datum PTS to use the current +** wall clock for its time. It determines the time zone offset by minimizing +** the error after trying several time zone offsets. If the Datum PTS +** time is Greenwich time and GMT is not defined, everything should still +** work since the time zone will be found to be 0. What this really means +** is that your system time (at least to start with) must be within the +** correct time by less than +- 30 minutes. The default is for GMT to not +** defined. If you really want to force GMT without the funny +- 30 minute +** stuff then you must define (uncomment) GMT below. +*/ + +/* +#define GMT +#define DEBUG_DATUM_PTC +#define LOG_TIME_ERRORS +*/ + + +#define PTSPRECISION (-10) /* precision assumed 1/1024 ms */ +#define DATMREFID "DATM" /* reference id */ +#define DATUM_DISPERSION 0 /* fixed dispersion = 0 ms */ +#define DATUM_MAX_ERROR 0.100 /* limits on sigma squared */ + +#define DATUM_MAX_ERROR2 (DATUM_MAX_ERROR*DATUM_MAX_ERROR) + +/* +** The Datum PTS structure +*/ + +/* +** I don't use a fixed array of MAXUNITS like everyone else just because +** I don't like to program that way. Sorry if this bothers anyone. I assume +** that you can use any id for your unit and I will search for it in a +** dynamic array of units until I find it. I was worried that users might +** enter a bad id in their configuration file (larger than MAXUNITS) and +** besides, it is just cleaner not to have to assume that you have a fixed +** number of anything in a program. +*/ + +struct datum_pts_unit { + struct peer *peer; /* peer used by ntp */ + struct refclockio io; /* io structure used by ntp */ + int PTS_fd; /* file descriptor for PTS */ + u_int unit; /* id for unit */ + u_long timestarted; /* time started */ + l_fp lastrec; /* time tag for the receive time (system) */ + l_fp lastref; /* reference time (Datum time) */ + u_long yearstart; /* the year that this clock started */ + int coderecv; /* number of time codes received */ + int day; /* day */ + int hour; /* hour */ + int minute; /* minutes */ + int second; /* seconds */ + int msec; /* miliseconds */ + int usec; /* miliseconds */ + u_char leap; /* funny leap character code */ + char retbuf[8]; /* returned time from the datum pts */ + char nbytes; /* number of bytes received from datum pts */ + double sigma2; /* average squared error (roughly) */ + int tzoff; /* time zone offest from GMT */ +}; + +/* +** PTS static constant variables for internal use +*/ + +static char TIME_REQUEST[6]; /* request message sent to datum for time */ +static int nunits; /* number of active units */ +static struct datum_pts_unit +**datum_pts_unit; /* dynamic array of datum PTS structures */ + +/* +** Callback function prototypes that ntpd needs to know about. +*/ + +static int datum_pts_start P((int, struct peer *)); +static void datum_pts_shutdown P((int, struct peer *)); +static void datum_pts_poll P((int, struct peer *)); +static void datum_pts_control P((int, struct refclockstat *, + struct refclockstat *, struct peer *)); +static void datum_pts_init P((void)); +static void datum_pts_buginfo P((int, struct refclockbug *, struct peer *)); + +/* +** This is the call back function structure that ntpd actually uses for +** this refclock. +*/ + +struct refclock refclock_datum = { + datum_pts_start, /* start up a new Datum refclock */ + datum_pts_shutdown, /* shutdown a Datum refclock */ + datum_pts_poll, /* sends out the time request */ + datum_pts_control, /* not used */ + datum_pts_init, /* initialization (called first) */ + datum_pts_buginfo, /* not used */ + NOFLAGS /* we are not setting any special flags */ +}; + +/* +** The datum_pts_receive callback function is handled differently from the +** rest. It is passed to the ntpd io data structure. Basically, every +** 64 seconds, the datum_pts_poll() routine is called. It sends out the time +** request message to the Datum Programmable Time System. Then, ntpd +** waits on a select() call to receive data back. The datum_pts_receive() +** function is called as data comes back. We expect a seven byte time +** code to be returned but the datum_pts_receive() function may only get +** a few bytes passed to it at a time. In other words, this routine may +** get called by the io stuff in ntpd a few times before we get all seven +** bytes. Once the last byte is received, we process it and then pass the +** new time measurement to ntpd for updating the system time. For now, +** there is no 3 state filtering done on the time measurements. The +** jitter may be a little high but at least for its current use, it is not +** a problem. We have tried to keep things as simple as possible. This +** clock should not jitter more than 1 or 2 mseconds at the most once +** things settle down. It is important to get the right drift calibrated +** in the ntpd.drift file as well as getting the right tick set up right +** using tickadj for SUNs. Tickadj is not used for the HP but you need to +** remember to bring up the adjtime daemon because HP does not support +** the adjtime() call. +*/ + +static void datum_pts_receive P((struct recvbuf *)); + +/*......................................................................*/ +/* datum_pts_start - start up the datum PTS. This means open the */ +/* RS232 device and set up the data structure for my unit. */ +/*......................................................................*/ + +static int +datum_pts_start( + int unit, + struct peer *peer + ) +{ + struct datum_pts_unit **temp_datum_pts_unit; + struct datum_pts_unit *datum_pts; + +#ifdef HAVE_TERMIOS + struct termios arg; +#endif + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Starting Datum PTS unit %d\n", unit); +#endif + + /* + ** Create the memory for the new unit + */ + + temp_datum_pts_unit = (struct datum_pts_unit **) + malloc((nunits+1)*sizeof(struct datum_pts_unit *)); + if (nunits > 0) memcpy(temp_datum_pts_unit, datum_pts_unit, + nunits*sizeof(struct datum_pts_unit *)); + free(datum_pts_unit); + datum_pts_unit = temp_datum_pts_unit; + datum_pts_unit[nunits] = (struct datum_pts_unit *) + malloc(sizeof(struct datum_pts_unit)); + datum_pts = datum_pts_unit[nunits]; + + datum_pts->unit = unit; /* set my unit id */ + datum_pts->yearstart = 0; /* initialize the yearstart to 0 */ + datum_pts->sigma2 = 0.0; /* initialize the sigma2 to 0 */ + + /* + ** Open the Datum PTS device + */ + + datum_pts->PTS_fd = open("/dev/datum",O_RDWR); + + fcntl(datum_pts->PTS_fd, F_SETFL, 0); /* clear the descriptor flags */ + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Opening RS232 port with file descriptor %d\n", + datum_pts->PTS_fd); +#endif + + /* + ** Set up the RS232 terminal device information. Note that we assume that + ** we have termios. This code has only been tested on SUNs and HPs. If your + ** machine does not have termios this driver cannot be initialized. You can change this + ** if you want by editing this source. Please give the changes back to the + ** ntp folks so that it can become part of their regular distribution. + */ + +#ifdef HAVE_TERMIOS + + arg.c_iflag = IGNBRK; + arg.c_oflag = 0; + arg.c_cflag = B9600 | CS8 | CREAD | PARENB | CLOCAL; + arg.c_lflag = 0; + arg.c_cc[VMIN] = 0; /* start timeout timer right away (not used) */ + arg.c_cc[VTIME] = 30; /* 3 second timout on reads (not used) */ + + tcsetattr(datum_pts->PTS_fd, TCSANOW, &arg); + +#else + + msyslog(LOG_ERR, "Datum_PTS: Termios not supported in this driver"); + (void)close(datum_pts->PTS_fd); + + return 0; + +#endif + + /* + ** Initialize the ntpd IO structure + */ + + datum_pts->peer = peer; + datum_pts->io.clock_recv = datum_pts_receive; + datum_pts->io.srcclock = (caddr_t)datum_pts; + datum_pts->io.datalen = 0; + datum_pts->io.fd = datum_pts->PTS_fd; + + if (!io_addclock(&(datum_pts->io))) { + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Problem adding clock\n"); +#endif + + msyslog(LOG_ERR, "Datum_PTS: Problem adding clock"); + (void)close(datum_pts->PTS_fd); + + return 0; + } + + peer->precision = PTSPRECISION; + peer->stratum = 0; + memcpy((char *)&peer->refid, DATMREFID, 4); + + /* + ** Now add one to the number of units and return a successful code + */ + + nunits++; + return 1; + +} + + +/*......................................................................*/ +/* datum_pts_shutdown - this routine shuts doen the device and */ +/* removes the memory for the unit. */ +/*......................................................................*/ + +static void +datum_pts_shutdown( + int unit, + struct peer *peer + ) +{ + int i,j; + struct datum_pts_unit **temp_datum_pts_unit; + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Shutdown Datum PTS\n"); +#endif + + msyslog(LOG_ERR, "Datum_PTS: Shutdown Datum PTS"); + + /* + ** First we have to find the right unit (i.e., the one with the same id). + ** We do this by looping through the dynamic array of units intil we find + ** it. Note, that I don't simply use an array with a maximimum number of + ** Datum PTS units. Everything is completely dynamic. + */ + + for (i=0; iunit == unit) { + + /* + ** We found the unit so close the file descriptor and free up the memory used + ** by the structure. + */ + + io_closeclock(&datum_pts_unit[i]->io); + close(datum_pts_unit[i]->PTS_fd); + free(datum_pts_unit[i]); + + /* + ** Now clean up the datum_pts_unit dynamic array so that there are no holes. + ** This may mean moving pointers around, etc., to keep things compact. + */ + + if (nunits > 1) { + + temp_datum_pts_unit = (struct datum_pts_unit **) + malloc((nunits-1)*sizeof(struct datum_pts_unit *)); + if (i!= 0) memcpy(temp_datum_pts_unit, datum_pts_unit, + i*sizeof(struct datum_pts_unit *)); + + for (j=i+1; junit == unit) { + index = i; + datum_pts = datum_pts_unit[i]; + error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6); + if (error_code != 6) perror("TIME_REQUEST"); + datum_pts->nbytes = 0; + break; + } + } + + /* + ** Print out an error message if we could not find the right unit. + */ + + if (index == -1) { + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Error, could not poll unit %d\n",unit); +#endif + + msyslog(LOG_ERR, "Datum_PTS: Could not poll unit %d",unit); + return; + + } + +} + + +/*......................................................................*/ +/* datum_pts_control - not used */ +/*......................................................................*/ + +static void +datum_pts_control( + int unit, + struct refclockstat *in, + struct refclockstat *out, + struct peer *peer + ) +{ + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Control Datum PTS\n"); +#endif + +} + + +/*......................................................................*/ +/* datum_pts_init - initializes things for all possible Datum */ +/* time code generators that might be used. In practice, this is */ +/* only called once at the beginning before anything else is */ +/* called. */ +/*......................................................................*/ + +static void +datum_pts_init(void) +{ + + /* */ + /*...... open up the log file if we are debugging ......................*/ + /* */ + + /* + ** Open up the log file if we are debugging. For now, send data out to the + ** screen (stdout). + */ + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Init Datum PTS\n"); +#endif + + /* + ** Initialize the time request command string. This is the only message + ** that we ever have to send to the Datum PTS (although others are defined). + */ + + memcpy(TIME_REQUEST, "//k/mn",6); + + /* + ** Initialize the number of units to 0 and set the dynamic array of units to + ** NULL since there are no units defined yet. + */ + + datum_pts_unit = NULL; + nunits = 0; + +} + + +/*......................................................................*/ +/* datum_pts_buginfo - not used */ +/*......................................................................*/ + +static void +datum_pts_buginfo( + int unit, + register struct refclockbug *bug, + register struct peer *peer + ) +{ + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Buginfo Datum PTS\n"); +#endif + +} + + +/*......................................................................*/ +/* datum_pts_receive - receive the time buffer that was read in */ +/* by the ntpd io handling routines. When 7 bytes have been */ +/* received (it may take several tries before all 7 bytes are */ +/* received), then the time code must be unpacked and sent to */ +/* the ntpd clock_receive() routine which causes the systems */ +/* clock to be updated (several layers down). */ +/*......................................................................*/ + +static void +datum_pts_receive( + struct recvbuf *rbufp + ) +{ + int i; + l_fp tstmp; + struct datum_pts_unit *datum_pts; + char *dpt; + int dpend; + int tzoff; + int timerr; + double ftimerr, abserr; +#ifdef DEBUG_DATUM_PTC + double dispersion; +#endif + int goodtime; + /*double doffset;*/ + + /* + ** Get the time code (maybe partial) message out of the rbufp buffer. + */ + + datum_pts = (struct datum_pts_unit *)rbufp->recv_srcclock; + dpt = (char *)&rbufp->recv_space; + dpend = rbufp->recv_length; + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Receive Datum PTS: %d bytes\n", dpend); +#endif + + /* */ + /*...... save the ntp system time when the first byte is received ......*/ + /* */ + + /* + ** Save the ntp system time when the first byte is received. Note that + ** because it may take several calls to this routine before all seven + ** bytes of our return message are finally received by the io handlers in + ** ntpd, we really do want to use the time tag when the first byte is + ** received to reduce the jitter. + */ + + if (datum_pts->nbytes == 0) { + datum_pts->lastrec = rbufp->recv_time; + } + + /* + ** Increment our count to the number of bytes received so far. Return if we + ** haven't gotten all seven bytes yet. + */ + + for (i=0; iretbuf[datum_pts->nbytes+i] = dpt[i]; + } + + datum_pts->nbytes += dpend; + + if (datum_pts->nbytes != 7) { + return; + } + + /* + ** Convert the seven bytes received in our time buffer to day, hour, minute, + ** second, and msecond values. The usec value is not used for anything + ** currently. It is just the fractional part of the time stored in units + ** of microseconds. + */ + + datum_pts->day = 100*(datum_pts->retbuf[0] & 0x0f) + + 10*((datum_pts->retbuf[1] & 0xf0)>>4) + + (datum_pts->retbuf[1] & 0x0f); + + datum_pts->hour = 10*((datum_pts->retbuf[2] & 0x30)>>4) + + (datum_pts->retbuf[2] & 0x0f); + + datum_pts->minute = 10*((datum_pts->retbuf[3] & 0x70)>>4) + + (datum_pts->retbuf[3] & 0x0f); + + datum_pts->second = 10*((datum_pts->retbuf[4] & 0x70)>>4) + + (datum_pts->retbuf[4] & 0x0f); + + datum_pts->msec = 100*((datum_pts->retbuf[5] & 0xf0) >> 4) + + 10*(datum_pts->retbuf[5] & 0x0f) + + ((datum_pts->retbuf[6] & 0xf0)>>4); + + datum_pts->usec = 1000*datum_pts->msec; + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("day %d, hour %d, minute %d, second %d, msec %d\n", + datum_pts->day, + datum_pts->hour, + datum_pts->minute, + datum_pts->second, + datum_pts->msec); +#endif + + /* + ** Get the GMT time zone offset. Note that GMT should be zero if the Datum + ** reference time is using GMT as its time base. Otherwise we have to + ** determine the offset if the Datum PTS is using time of day as its time + ** base. + */ + + goodtime = 0; /* We are not sure about the time and offset yet */ + +#ifdef GMT + + /* + ** This is the case where the Datum PTS is using GMT so there is no time + ** zone offset. + */ + + tzoff = 0; /* set time zone offset to 0 */ + +#else + + /* + ** This is the case where the Datum PTS is using regular time of day for its + ** time so we must compute the time zone offset. The way we do it is kind of + ** funny but it works. We loop through different time zones (0 to 24) and + ** pick the one that gives the smallest error (+- one half hour). The time + ** zone offset is stored in the datum_pts structure for future use. Normally, + ** the clocktime() routine is only called once (unless the time zone offset + ** changes due to daylight savings) since the goodtime flag is set when a + ** good time is found (with a good offset). Note that even if the Datum + ** PTS is using GMT, this mechanism will still work since it should come up + ** with a value for tzoff = 0 (assuming that your system clock is within + ** a half hour of the Datum time (even with time zone differences). + */ + + for (tzoff=0; tzoff<24; tzoff++) { + if (clocktime( datum_pts->day, + datum_pts->hour, + datum_pts->minute, + datum_pts->second, + (tzoff + datum_pts->tzoff) % 24, + datum_pts->lastrec.l_ui, + &datum_pts->yearstart, + &datum_pts->lastref.l_ui) ) { + + error = datum_pts->lastref.l_ui - datum_pts->lastrec.l_ui; + +#ifdef DEBUG_DATUM_PTC + printf("Time Zone (clocktime method) = %d, error = %d\n", tzoff, error); +#endif + + if ((error < 1799) && (error > -1799)) { + tzoff = (tzoff + datum_pts->tzoff) % 24; + datum_pts->tzoff = tzoff; + goodtime = 1; + +#ifdef DEBUG_DATUM_PTC + printf("Time Zone found (clocktime method) = %d\n",tzoff); +#endif + + break; + } + + } + } + +#endif + + /* + ** Make sure that we have a good time from the Datum PTS. Clocktime() also + ** sets yearstart and lastref.l_ui. We will have to set astref.l_uf (i.e., + ** the fraction of a second) stuff later. + */ + + if (!goodtime) { + + if (!clocktime( datum_pts->day, + datum_pts->hour, + datum_pts->minute, + datum_pts->second, + tzoff, + datum_pts->lastrec.l_ui, + &datum_pts->yearstart, + &datum_pts->lastref.l_ui) ) { + +#ifdef DEBUG_DATUM_PTC + if (debug) + { + printf("Error: bad clocktime\n"); + printf("GMT %d, lastrec %d, yearstart %d, lastref %d\n", + tzoff, + datum_pts->lastrec.l_ui, + datum_pts->yearstart, + datum_pts->lastref.l_ui); + } +#endif + + msyslog(LOG_ERR, "Datum_PTS: Bad clocktime"); + + return; + + }else{ + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Good clocktime\n"); +#endif + + } + + } + + /* + ** We have datum_pts->lastref.l_ui set (which is the integer part of the + ** time. Now set the microseconds field. + */ + + TVUTOTSF(datum_pts->usec, datum_pts->lastref.l_uf); + + /* + ** Compute the time correction as the difference between the reference + ** time (i.e., the Datum time) minus the receive time (system time). + */ + + tstmp = datum_pts->lastref; /* tstmp is the datum ntp time */ + L_SUB(&tstmp, &datum_pts->lastrec); /* tstmp is now the correction */ + datum_pts->coderecv++; /* increment a counter */ + +#ifdef DEBUG_DATUM_PTC + dispersion = DATUM_DISPERSION; /* set the dispersion to 0 */ + ftimerr = dispersion; + ftimerr /= (1024.0 * 64.0); + if (debug) + printf("dispersion = %d, %f\n", dispersion, ftimerr); +#endif + + /* + ** Pass the new time to ntpd through the refclock_receive function. Note + ** that we are not trying to make any corrections due to the time it takes + ** for the Datum PTS to send the message back. I am (erroneously) assuming + ** that the time for the Datum PTS to send the time back to us is negligable. + ** I suspect that this time delay may be as much as 15 ms or so (but probably + ** less). For our needs at JPL, this kind of error is ok so it is not + ** necessary to use fudge factors in the ntp.conf file. Maybe later we will. + */ + /*LFPTOD(&tstmp, doffset);*/ + refclock_receive(datum_pts->peer); + + /* + ** Compute sigma squared (not used currently). Maybe later, this could be + ** used for the dispersion estimate. The problem is that ntpd does not link + ** in the math library so sqrt() is not available. Anyway, this is useful + ** for debugging. Maybe later I will just use absolute values for the time + ** error to come up with my dispersion estimate. Anyway, for now my dispersion + ** is set to 0. + */ + + timerr = tstmp.l_ui<<20; + timerr |= (tstmp.l_uf>>12) & 0x000fffff; + ftimerr = timerr; + ftimerr /= 1024*1024; + abserr = ftimerr; + if (ftimerr < 0.0) abserr = -ftimerr; + + if (datum_pts->sigma2 == 0.0) { + if (abserr < DATUM_MAX_ERROR) { + datum_pts->sigma2 = abserr*abserr; + }else{ + datum_pts->sigma2 = DATUM_MAX_ERROR2; + } + }else{ + if (abserr < DATUM_MAX_ERROR) { + datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*abserr*abserr; + }else{ + datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*DATUM_MAX_ERROR2; + } + } + +#ifdef DEBUG_DATUM_PTC + if (debug) + printf("Time error = %f seconds\n", ftimerr); +#endif + +#if defined(DEBUG_DATUM_PTC) || defined(LOG_TIME_ERRORS) + if (debug) + printf("PTS: day %d, hour %d, minute %d, second %d, msec %d, Time Error %f\n", + datum_pts->day, + datum_pts->hour, + datum_pts->minute, + datum_pts->second, + datum_pts->msec, + ftimerr); +#endif + +} +#else +int refclock_datum_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_dumbclock.c b/contrib/ntp/ntpd/refclock_dumbclock.c new file mode 100644 index 000000000000..8138d9e66bf7 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_dumbclock.c @@ -0,0 +1,381 @@ +/* + * refclock_dumbclock - clock driver for a unknown time distribution system + * that only provides hh:mm:ss (in local time, yet!). + */ + +/* + * Must interpolate back to local time. Very annoying. + */ +#define GET_LOCALTIME + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK) + +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * This driver supports a generic dumb clock that only outputs hh:mm:ss, + * in local time, no less. + * + * Input format: + * + * hh:mm:ss + * + * hh:mm:ss -- what you'd expect, with a 24 hour clock. (Heck, that's the only + * way it could get stupider.) We take time on the . + * + * The original source of this module was the WWVB module. + */ + +/* + * Interface definitions + */ +#define DEVICE "/dev/dumbclock%d" /* device name and unit */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ +#define PRECISION (-13) /* precision assumed (about 100 us) */ +#define REFID "dumbclock" /* reference ID */ +#define DESCRIPTION "Dumb clock" /* WRU */ + + +/* + * Insanity check. Since the time is local, we need to make sure that during midnight + * transitions, we can convert back to Unix time. If the conversion results in some number + * worse than this number of seconds away, assume the next day and retry. + */ +#define INSANE_SECONDS 3600 + +/* + * Dumb clock control structure + */ +struct dumbclock_unit { + u_char tcswitch; /* timecode switch */ + l_fp laststamp; /* last receive timestamp */ + u_char lasthour; /* last hour (for monitor) */ + u_char linect; /* count ignored lines (for monitor */ + struct tm ymd; /* struct tm for y/m/d only */ +}; + +/* + * Function prototypes + */ +static int dumbclock_start P((int, struct peer *)); +static void dumbclock_shutdown P((int, struct peer *)); +static void dumbclock_receive P((struct recvbuf *)); +#if 0 +static void dumbclock_poll P((int, struct peer *)); +#endif + +/* + * Transfer vector + */ +struct refclock refclock_dumbclock = { + dumbclock_start, /* start up driver */ + dumbclock_shutdown, /* shut down driver */ + noentry, /* poll the driver -- a nice fabrication */ + noentry, /* not used */ + noentry, /* not used */ + noentry, /* not used */ + NOFLAGS /* not used */ +}; + + +/* + * dumbclock_start - open the devices and initialize data for processing + */ +static int +dumbclock_start( + int unit, + struct peer *peer + ) +{ + register struct dumbclock_unit *up; + struct refclockproc *pp; + int fd; + char device[20]; + struct tm *tm_time_p; + time_t now; + + /* + * Open serial port. Don't bother with CLK line discipline, since + * it's not available. + */ + (void)sprintf(device, DEVICE, unit); +#ifdef DEBUG + if (debug) + printf ("starting Dumbclock with device %s\n",device); +#endif + if (!(fd = refclock_open(device, SPEED232, 0))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct dumbclock_unit *) + emalloc(sizeof(struct dumbclock_unit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct dumbclock_unit)); + pp = peer->procptr; + pp->unitptr = (caddr_t)up; + pp->io.clock_recv = dumbclock_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + + + time(&now); +#ifdef GET_LOCALTIME + tm_time_p = localtime(&now); +#else + tm_time_p = gmtime(&now); +#endif + if (tm_time_p) + { + up->ymd = *tm_time_p; + } + else + { + return 0; + } + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + return (1); +} + + +/* + * dumbclock_shutdown - shut down the clock + */ +static void +dumbclock_shutdown( + int unit, + struct peer *peer + ) +{ + register struct dumbclock_unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct dumbclock_unit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * dumbclock_receive - receive data from the serial interface + */ +static void +dumbclock_receive( + struct recvbuf *rbufp + ) +{ + struct dumbclock_unit *up; + struct refclockproc *pp; + struct peer *peer; + + l_fp trtmp; /* arrival timestamp */ + int hours; /* hour-of-day */ + int minutes; /* minutes-past-the-hour */ + int seconds; /* seconds */ + int temp; /* int temp */ + int got_good; /* got a good time flag */ + + /* + * Initialize pointers and read the timecode and timestamp + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct dumbclock_unit *)pp->unitptr; + temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); + + if (temp == 0) { + if (up->tcswitch == 0) { + up->tcswitch = 1; + up->laststamp = trtmp; + } else + up->tcswitch = 0; + return; + } + pp->lencode = temp; + pp->lastrec = up->laststamp; + up->laststamp = trtmp; + up->tcswitch = 1; + +#ifdef DEBUG + if (debug) + printf("dumbclock: timecode %d %s\n", + pp->lencode, pp->a_lastcode); +#endif + + /* + * We get down to business. Check the timecode format... + */ + pp->msec = 0; + got_good=0; + if (sscanf(pp->a_lastcode,"%02d:%02d:%02d", + &hours,&minutes,&seconds) == 3) + { + struct tm *gmtp; + struct tm *lt_p; + time_t asserted_time; /* the SPM time based on the composite time+date */ + struct tm asserted_tm; /* the struct tm of the same */ + int adjyear; + int adjmon; + int reality_delta; + time_t now; + + + /* + * Convert to GMT for sites that distribute localtime. This + * means we have to figure out what day it is. Easier said + * than done... + */ + + asserted_tm.tm_year = up->ymd.tm_year; + asserted_tm.tm_mon = up->ymd.tm_mon; + asserted_tm.tm_mday = up->ymd.tm_mday; + asserted_tm.tm_hour = hours; + asserted_tm.tm_min = minutes; + asserted_tm.tm_sec = seconds; + asserted_tm.tm_isdst = -1; + +#ifdef GET_LOCALTIME + asserted_time = mktime (&asserted_tm); + time(&now); +#else +#include "GMT unsupported for dumbclock!" +#endif + reality_delta = asserted_time - now; + + /* + * We assume that if the time is grossly wrong, it's because we got the + * year/month/day wrong. + */ + if (reality_delta > INSANE_SECONDS) + { + asserted_time -= SECSPERDAY; /* local clock behind real time */ + } + else if (-reality_delta > INSANE_SECONDS) + { + asserted_time += SECSPERDAY; /* local clock ahead of real time */ + } + lt_p = localtime(&asserted_time); + if (lt_p) + { + up->ymd = *lt_p; + } + else + { + refclock_report (peer, CEVNT_FAULT); + return; + } + + if ((gmtp = gmtime (&asserted_time)) == NULL) + { + refclock_report (peer, CEVNT_FAULT); + return; + } + adjyear = gmtp->tm_year+1900; + adjmon = gmtp->tm_mon+1; + pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday); + pp->hour = gmtp->tm_hour; + pp->minute = gmtp->tm_min; + pp->second = gmtp->tm_sec; +#ifdef DEBUG + if (debug) + printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", + adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute, + pp->second); +#endif + + got_good=1; + } + + if (!got_good) + { + if (up->linect > 0) + up->linect--; + else + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Process the new sample in the median filter and determine the + * timecode timestamp. + */ + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + up->lasthour = pp->hour; +} + +#if 0 +/* + * dumbclock_poll - called by the transmit procedure + */ +static void +dumbclock_poll( + int unit, + struct peer *peer + ) +{ + register struct dumbclock_unit *up; + struct refclockproc *pp; + char pollchar; + + /* + * Time to poll the clock. The Chrono-log clock is supposed to + * respond to a 'T' by returning a timecode in the format(s) + * specified above. Ours does (can?) not, but this seems to be + * an installation-specific problem. This code is dyked out, + * but may be re-enabled if anyone ever finds a Chrono-log that + * actually listens to this command. + */ +#if 0 + pp = peer->procptr; + up = (struct dumbclock_unit *)pp->unitptr; + if (peer->reach == 0) + refclock_report(peer, CEVNT_TIMEOUT); + if (up->linect > 0) + pollchar = 'R'; + else + pollchar = 'T'; + if (write(pp->io.fd, &pollchar, 1) != 1) + refclock_report(peer, CEVNT_FAULT); + else + pp->polls++; +#endif +} +#endif + +#else +int refclock_dumbclock_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_gpsvme.c b/contrib/ntp/ntpd/refclock_gpsvme.c new file mode 100644 index 000000000000..a7c6d23d3a4f --- /dev/null +++ b/contrib/ntp/ntpd/refclock_gpsvme.c @@ -0,0 +1,613 @@ +/* + * refclock_gpsvme.c NTP clock driver for the TrueTime GPS-VME + * R. Schmidt, Time Service, US Naval Obs. res@tuttle.usno.navy.mil + * + * The refclock type has been defined as 16 (until new id assigned). + * These DEFS are included in the Makefile: + * DEFS= -DHAVE_TERMIOS -DSYS_HPUX=9 + * DEFS_LOCAL= -DREFCLOCK + * CLOCKDEFS= -DGPSVME + * The file map_vme.c does the VME memory mapping, and includes vme_init(). + * map_vme.c is HP-UX specific, because HPUX cannot mmap() device files! Boo! + * The file gps.h provides TrueTime register info. + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_GPSVME) +#include +#include +#include +#include +#include +#include + +#include "gps.h" +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" +#include "/etc/conf/h/io.h" + +/* GLOBAL STUFF BY RES */ + +#include + +#define PRIO 120 /* set the realtime priority */ +#define NREGS 7 /* number of registers we will use */ + +extern int init_vme(); /* This is just a call to map_vme() */ + /* It doesn't have to be extern */ +unsigned short *greg[NREGS]; /* GPS registers defined in gps.h */ +void *gps_base; /* Base address of GPS VME card returned by */ + /* the map_vme() call */ +extern caddr_t map_vme (); +extern void unmap_vme(); /* Unmaps the VME space */ + +struct vmedate { /* structure needed by ntp */ + unsigned short year; /* *tptr is a pointer to this */ + unsigned short doy; + unsigned short hr; + unsigned short mn; + unsigned short sec; + unsigned long frac; + unsigned short status; +}; + +struct vmedate *get_gpsvme_time(); + +/* END OF STUFF FROM RES */ + +/* + * Definitions + */ +#define MAXUNITS 2 /* max number of VME units */ +#define BMAX 50 /* timecode buffer length */ + +/* + * VME interface parameters. + */ +#define VMEPRECISION (-21) /* precision assumed (1 us) */ +#define USNOREFID "USNO\0" /* Or whatever? */ +#define VMEREFID "GPS" /* reference id */ +#define VMEDESCRIPTION "GPS" /* who we are */ +#define VMEHSREFID 0x7f7f1001 /* 127.127.16.01 refid hi strata */ + +/* I'm using clock type 16 until one is assigned */ +/* This is set also in vme_control, below */ + + +#define GMT 0 /* hour offset from Greenwich */ + +/* + * VME unit control structure. + */ +struct vmeunit { + struct peer *peer; /* associated peer structure */ + struct refclockio io; /* given to the I/O handler */ + struct vmedate vmedata; /* data returned from vme read */ + l_fp lastrec; /* last local time */ + l_fp lastref; /* last timecode time */ + char lastcode[BMAX]; /* last timecode received */ + u_short lencode; /* length of last timecode */ + u_long lasttime; /* last time clock heard from */ + u_short unit; /* unit number for this guy */ + u_short status; /* clock status */ + u_short lastevent; /* last clock event */ + u_short year; /* year of eternity */ + u_short day; /* day of year */ + u_short hour; /* hour of day */ + u_short minute; /* minute of hour */ + u_short second; /* seconds of minute */ + u_long usec; /* microsecond of second */ + u_long yearstart; /* start of current year */ + u_short leap; /* leap indicators */ + /* + * Status tallies + */ + u_long polls; /* polls sent */ + u_long noreply; /* no replies to polls */ + u_long coderecv; /* timecodes received */ + u_long badformat; /* bad format */ + u_long baddata; /* bad data */ + u_long timestarted; /* time we started this */ +}; + +/* + * Data space for the unit structures. Note that we allocate these on + * the fly, but never give them back. + */ +static struct vmeunit *vmeunits[MAXUNITS]; +static u_char unitinuse[MAXUNITS]; + +/* + * Keep the fudge factors separately so they can be set even + * when no clock is configured. + */ +static l_fp fudgefactor[MAXUNITS]; +static u_char stratumtouse[MAXUNITS]; +static u_char sloppyclockflag[MAXUNITS]; + +/* + * Function prototypes + */ +static void vme_init (void); +static int vme_start (u_int, struct peer *); +static void vme_shutdown (int); +static void vme_report_event (struct vmeunit *, int); +static void vme_receive (struct recvbuf *); +static void vme_poll (int unit, struct peer *); +static void vme_control (u_int, struct refclockstat *, struct refclockstat *); +static void vme_buginfo (int, struct refclockbug *); + +/* + * Transfer vector + */ +struct refclock refclock_gpsvme = { + vme_start, vme_shutdown, vme_poll, + vme_control, vme_init, vme_buginfo, NOFLAGS +}; + +int fd_vme; /* file descriptor for ioctls */ +int regvalue; + +/* + * vme_init - initialize internal vme driver data + */ +static void +vme_init(void) +{ + register int i; + /* + * Just zero the data arrays + */ + /* + bzero((char *)vmeunits, sizeof vmeunits); + bzero((char *)unitinuse, sizeof unitinuse); + */ + + /* + * Initialize fudge factors to default. + */ + for (i = 0; i < MAXUNITS; i++) { + fudgefactor[i].l_ui = 0; + fudgefactor[i].l_uf = 0; + stratumtouse[i] = 0; + sloppyclockflag[i] = 0; + } +} + +/* + * vme_start - open the VME device and initialize data for processing + */ +static int +vme_start( + u_int unit, + struct peer *peer + ) +{ + register struct vmeunit *vme; + register int i; + int dummy; + char vmedev[20]; + + /* + * Check configuration info. + */ + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, "vme_start: unit %d invalid", unit); + return (0); + } + if (unitinuse[unit]) { + msyslog(LOG_ERR, "vme_start: unit %d in use", unit); + return (0); + } + + /* + * Open VME device + */ +#ifdef DEBUG + + printf("Opening VME DEVICE \n"); +#endif + init_vme(); /* This is in the map_vme.c external file */ + + /* + * Allocate unit structure + */ + if (vmeunits[unit] != 0) { + vme = vmeunits[unit]; /* The one we want is okay */ + } else { + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && vmeunits[i] != 0) + break; + } + if (i < MAXUNITS) { + /* + * Reclaim this one + */ + vme = vmeunits[i]; + vmeunits[i] = 0; + } else { + vme = (struct vmeunit *) + emalloc(sizeof(struct vmeunit)); + } + } + bzero((char *)vme, sizeof(struct vmeunit)); + vmeunits[unit] = vme; + + /* + * Set up the structures + */ + vme->peer = peer; + vme->unit = (u_short)unit; + vme->timestarted = current_time; + + vme->io.clock_recv = vme_receive; + vme->io.srcclock = (caddr_t)vme; + vme->io.datalen = 0; + vme->io.fd = fd_vme; + + /* + * All done. Initialize a few random peer variables, then + * return success. + */ + peer->precision = VMEPRECISION; + peer->stratum = stratumtouse[unit]; + memcpy( (char *)&peer->refid, USNOREFID,4); + + /* peer->refid = htonl(VMEHSREFID); */ + + unitinuse[unit] = 1; + return (1); +} + + +/* + * vme_shutdown - shut down a VME clock + */ +static void +vme_shutdown( + int unit + ) +{ + register struct vmeunit *vme; + + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, "vme_shutdown: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + msyslog(LOG_ERR, "vme_shutdown: unit %d not in use", unit); + return; + } + + /* + * Tell the I/O module to turn us off. We're history. + */ + unmap_vme(); + vme = vmeunits[unit]; + io_closeclock(&vme->io); + unitinuse[unit] = 0; +} + +/* + * vme_report_event - note the occurance of an event + * + * This routine presently just remembers the report and logs it, but + * does nothing heroic for the trap handler. + */ +static void +vme_report_event( + struct vmeunit *vme, + int code + ) +{ + struct peer *peer; + + peer = vme->peer; + if (vme->status != (u_short)code) { + vme->status = (u_short)code; + if (code != CEVNT_NOMINAL) + vme->lastevent = (u_short)code; + msyslog(LOG_INFO, + "clock %s event %x", ntoa(&peer->srcadr), code); + } +} + + +/* + * vme_receive - receive data from the VME device. + * + * Note: This interface would be interrupt-driven. We don't use that + * now, but include a dummy routine for possible future adventures. + */ +static void +vme_receive( + struct recvbuf *rbufp + ) +{ +} + +/* + * vme_poll - called by the transmit procedure + */ +static void +vme_poll( + int unit, + struct peer *peer + ) +{ + struct vmedate *tptr; + struct vmeunit *vme; + l_fp tstmp; + time_t tloc; + struct tm *tadr; + + + vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit *)); + tptr = (struct vmedate *)emalloc(sizeof(struct vmedate *)); + + + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, "vme_poll: unit %d invalid", unit); + return; + } + if (!unitinuse[unit]) { + msyslog(LOG_ERR, "vme_poll: unit %d not in use", unit); + return; + } + vme = vmeunits[unit]; /* Here is the structure */ + vme->polls++; + + tptr = &vme->vmedata; + + if ((tptr = get_gpsvme_time()) == NULL ) { + vme_report_event(vme, CEVNT_BADREPLY); + return; + } + + get_systime(&vme->lastrec); + vme->lasttime = current_time; + + /* + * Get VME time and convert to timestamp format. + * The year must come from the system clock. + */ + /* + time(&tloc); + tadr = gmtime(&tloc); + tptr->year = (unsigned short)(tadr->tm_year + 1900); + */ + + sprintf(vme->lastcode, + "%3.3d %2.2d:%2.2d:%2.2d.%.6d %1d\0", + tptr->doy, tptr->hr, tptr->mn, + tptr->sec, tptr->frac, tptr->status); + + record_clock_stats(&(vme->peer->srcadr), vme->lastcode); + vme->lencode = (u_short) strlen(vme->lastcode); + + vme->day = tptr->doy; + vme->hour = tptr->hr; + vme->minute = tptr->mn; + vme->second = tptr->sec; + vme->usec = tptr->frac; + +#ifdef DEBUG + if (debug) + printf("vme: %3d %02d:%02d:%02d.%06ld %1x\n", + vme->day, vme->hour, vme->minute, vme->second, + vme->usec, tptr->status); +#endif + if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */ + vme_report_event(vme, CEVNT_BADREPLY); + return; + } + + /* + * Now, compute the reference time value. Use the heavy + * machinery for the seconds and the millisecond field for the + * fraction when present. If an error in conversion to internal + * format is found, the program declares bad data and exits. + * Note that this code does not yet know how to do the years and + * relies on the clock-calendar chip for sanity. + */ + if (!clocktime(vme->day, vme->hour, vme->minute, + vme->second, GMT, vme->lastrec.l_ui, + &vme->yearstart, &vme->lastref.l_ui)) { + vme->baddata++; + vme_report_event(vme, CEVNT_BADTIME); + msyslog(LOG_ERR, "refclock_gpsvme: bad data!!"); + return; + } + TVUTOTSF(vme->usec, vme->lastref.l_uf); + tstmp = vme->lastref; + + L_SUB(&tstmp, &vme->lastrec); + vme->coderecv++; + + L_ADD(&tstmp, &(fudgefactor[vme->unit])); + + refclock_receive(vme->peer); +} + +/* + * vme_control - set fudge factors, return statistics + */ +static void +vme_control( + u_int unit, + struct refclockstat *in, + struct refclockstat *out + ) +{ + register struct vmeunit *vme; + + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, "vme_control: unit %d invalid)", unit); + return; + } + + if (in != 0) { + if (in->haveflags & CLK_HAVETIME1) + 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 + */ + vme = vmeunits[unit]; + peer = vme->peer; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) + memcpy( (char *)&peer->refid, USNOREFID,4); + else + peer->refid = htonl(VMEHSREFID); + } + } + if (in->haveflags & CLK_HAVEFLAG1) { + sloppyclockflag[unit] = in->flags & CLK_FLAG1; + } + } + + if (out != 0) { + out->type = 16; /*set by RES SHOULD BE CHANGED */ + out->haveflags + = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1; + out->clockdesc = VMEDESCRIPTION; + 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]) { + vme = vmeunits[unit]; + out->lencode = vme->lencode; + out->lastcode = vme->lastcode; + out->timereset = current_time - vme->timestarted; + out->polls = vme->polls; + out->noresponse = vme->noreply; + out->badformat = vme->badformat; + out->baddata = vme->baddata; + out->lastevent = vme->lastevent; + out->currentstatus = vme->status; + } else { + out->lencode = 0; + out->lastcode = ""; + out->polls = out->noresponse = 0; + out->badformat = out->baddata = 0; + out->timereset = 0; + out->currentstatus = out->lastevent = CEVNT_NOMINAL; + } + } +} + +/* + * vme_buginfo - return clock dependent debugging info + */ +static void +vme_buginfo( + int unit, + register struct refclockbug *bug + ) +{ + register struct vmeunit *vme; + + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, "vme_buginfo: unit %d invalid)", unit); + return; + } + + if (!unitinuse[unit]) + return; + vme = vmeunits[unit]; + + bug->nvalues = 11; + bug->ntimes = 5; + if (vme->lasttime != 0) + bug->values[0] = current_time - vme->lasttime; + else + bug->values[0] = 0; + bug->values[2] = (u_long)vme->year; + bug->values[3] = (u_long)vme->day; + bug->values[4] = (u_long)vme->hour; + bug->values[5] = (u_long)vme->minute; + bug->values[6] = (u_long)vme->second; + bug->values[7] = (u_long)vme->usec; + bug->values[9] = vme->yearstart; + bug->stimes = 0x1c; + bug->times[0] = vme->lastref; + bug->times[1] = vme->lastrec; +} +/* -------------------------------------------------------*/ +/* get_gpsvme_time() */ +/* R. Schmidt, USNO, 1995 */ +/* It's ugly, but hey, it works and its free */ + +#include "gps.h" /* defines for TrueTime GPS-VME */ + +#define PBIAS 193 /* 193 microsecs to read the GPS experimentally found */ + +struct vmedate * +get_gpsvme_time(void) +{ + struct vmedate *time_vme; + unsigned short set, hr, min, sec, ums, hms, status; + int ret; + char ti[3]; + + long tloc ; + time_t mktime(),time(); + struct tm *gmtime(), *gmt; + char *gpsmicro; + gpsmicro = (char *) malloc(7); + + time_vme = (struct vmedate *)malloc(sizeof(struct vmedate )); + *greg = (unsigned short *)malloc(sizeof(short) * NREGS); + + + /* reference the freeze command address general register 1 */ + set = *greg[0]; + /* read the registers : */ + /* get year */ + time_vme->year = (unsigned short) *greg[6]; + /* Get doy */ + time_vme->doy = (unsigned short) (*greg[5] & MASKDAY); + /* Get hour */ + time_vme->hr = (unsigned short) ((*greg[4] & MASKHI) >>8); + /* Get minutes */ + time_vme->mn = (unsigned short) (*greg[4] & MASKLO); + /* Get seconds */ + time_vme->sec = (unsigned short) (*greg[3] & MASKHI) >>8; + /* get microseconds in 2 parts and put together */ + ums = *greg[2]; + hms = *greg[3] & MASKLO; + + time_vme->status = (unsigned short) *greg[5] >>13; + + /* reference the unfreeze command address general register 1 */ + set = *greg[1]; + + sprintf(gpsmicro,"%2.2x%4.4x\0", hms, ums); + time_vme->frac = (u_long) gpsmicro; + + /* unmap_vme(); */ + + if (!status) { + return ((void *)NULL); + } + else + return (time_vme); +} + +#else +int refclock_gpsvme_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_heath.c b/contrib/ntp/ntpd/refclock_heath.c new file mode 100644 index 000000000000..9d297d1f877b --- /dev/null +++ b/contrib/ntp/ntpd/refclock_heath.c @@ -0,0 +1,487 @@ +/* + * refclock_heath - clock driver for Heath GC-1000 Most Accurate Clock + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_HEATH) + +#include +#include +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef TM_IN_SYS_TIME +# include +# else +# include +# endif +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif /* not HAVE_SYS_IOCTL_H */ + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +/* + * This driver supports the Heath GC-1000 Most Accurate Clock, with + * RS232C Output Accessory. This is a WWV/WWVH receiver somewhat less + * robust than other supported receivers. Its claimed accuracy is 100 ms + * when actually synchronized to the broadcast signal, but this doesn't + * happen even most of the time, due to propagation conditions, ambient + * noise sources, etc. When not synchronized, the accuracy is at the + * whim of the internal clock oscillator, which can wander into the + * sunset without warning. Since the indicated precision is 100 ms, + * expect a host synchronized only to this thing to wander to and fro, + * occasionally being rudely stepped when the offset exceeds the default + * clock_max of 128 ms. + * + * The internal DIPswitches should be set to operate at 1200 baud in + * MANUAL mode and the current year. The external DIPswitches should be + * set to GMT and 24-hour format, or to the host local time zone (with + * DST) and 12-hour format. It is very important that the year be + * set correctly in the DIPswitches. Otherwise, the day of year will be + * incorrect after 28 April[?] of a normal or leap year. In 12-hour mode + * with DST selected the clock will be incorrect by an hour for an + * indeterminate amount of time between 0000Z and 0200 on the day DST + * changes. + * + * In MANUAL mode the clock responds to a rising edge of the request to + * send (RTS) modem control line by sending the timecode. Therefore, it + * is necessary that the operating system implement the TIOCMBIC and + * TIOCMBIS ioctl system calls and TIOCM_RTS control bit. Present + * restrictions require the use of a POSIX-compatible programming + * interface, although other interfaces may work as well. + * + * A simple hardware modification to the clock can be made which + * prevents the clock hearing the request to send (RTS) if the HI SPEC + * lamp is out. Route the HISPEC signal to the tone decoder board pin + * 19, from the display, pin 19. Isolate pin 19 of the decoder board + * first, but maintain connection with pin 10. Also isolate pin 38 of + * the CPU on the tone board, and use half an added 7400 to gate the + * original signal to pin 38 with that from pin 19. + * + * The clock message consists of 23 ASCII printing characters in the + * following format: + * + * hh:mm:ss.f AM dd/mm/yr + * + * hh:mm:ss.f = hours, minutes, seconds + * f = deciseconds ('?' when out of spec) + * AM/PM/bb = blank in 24-hour mode + * dd/mm/yr = day, month, year + * + * The alarm condition is indicated by '?', rather than a digit, at f. + * Note that 0?:??:??.? is displayed before synchronization is first + * established and hh:mm:ss.? once synchronization is established and + * then lost again for about a day. + * + * Fudge Factors + * + * A fudge time1 value of .04 s appears to center the clock offset + * residuals. The fudge time2 parameter is the local time offset east of + * Greenwich, which depends on DST. Sorry about that, but the clock + * gives no hint on what the DIPswitches say. + */ + +/* + * Interface definitions + */ +#define DEVICE "/dev/heath%d" /* device name and unit */ +#define SPEED232 B1200 /* uart speed (1200 baud) */ +#define PRECISION (-4) /* precision assumed (about 100 ms) */ +#define REFID "WWV\0" /* reference ID */ +#define DESCRIPTION "Heath GC-1000 Most Accurate Clock" /* WRU */ + +#define LENHEATH 23 /* min timecode length */ + +/* + * Tables to compute the ddd of year form icky dd/mm timecode. Viva la + * leap. + */ +static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* + * Unit control structure + */ +struct heathunit { + int pollcnt; /* poll message counter */ + l_fp tstamp; /* timestamp of last poll */ +}; + +/* + * Function prototypes + */ +static int heath_start P((int, struct peer *)); +static void heath_shutdown P((int, struct peer *)); +static void heath_receive P((struct recvbuf *)); +static void heath_poll P((int, struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_heath = { + heath_start, /* start up driver */ + heath_shutdown, /* shut down driver */ + heath_poll, /* transmit poll message */ + noentry, /* not used (old heath_control) */ + noentry, /* initialize driver */ + noentry, /* not used (old heath_buginfo) */ + NOFLAGS /* not used */ +}; + +#if 0 +/* + * Gee, Unix so thoughfully omitted code to convert from a struct tm to + * a long, so I'll just have to ferret out the inverse myself, the hard way. + * (Newton's method.) + */ +#define timelocal(x) invert(x, localtime) +/* + * comparetm compares two tm structures and returns -1 if the first + * is less than the second, 0 if they are equal, and +1 if the first + * is greater than the second. Only the year, month, day, hour, minute + * and second are compared. The yearday (Julian), day of week, and isdst + * are not compared. + */ + +static int +comparetm( + struct tm *a, + struct tm *b + ) +{ + if (a->tm_year < b->tm_year ) return -1; + if (a->tm_year > b->tm_year ) return 1; + if (a->tm_mon < b->tm_mon ) return -1; + if (a->tm_mon > b->tm_mon ) return 1; + if (a->tm_mday < b->tm_mday ) return -1; + if (a->tm_mday > b->tm_mday ) return 1; + if (a->tm_hour < b->tm_hour ) return -1; + if (a->tm_hour > b->tm_hour ) return 1; + if (a->tm_min < b->tm_min ) return -1; + if (a->tm_min > b->tm_min ) return 1; + if (a->tm_sec < b->tm_sec ) return -1; + if (a->tm_sec > b->tm_sec ) return 1; + return 0; +} + +static long +invert ( + struct tm *x, + struct tm *(*func)() + ) +{ + struct tm *y; + int result; + long trial; + long lower=0L; + long upper=(long)((unsigned long)(~lower) >> 1); + + do { + trial = (upper + lower) / 2L; + y = (*func)(&trial); + result = comparetm(x, y); + if (result < 0) upper = trial; + if (result > 0) lower = trial; + } while (result != 0); + return trial; +} +#endif /* 0 */ + + +/* + * heath_start - open the devices and initialize data for processing + */ +static int +heath_start( + int unit, + struct peer *peer + ) +{ + register struct heathunit *up; + struct refclockproc *pp; + int fd; + char device[20]; + + /* + * Open serial port + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED232, 0))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct heathunit *) + emalloc(sizeof(struct heathunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct heathunit)); + pp = peer->procptr; + pp->io.clock_recv = heath_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + peer->burst = NSTAGE; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + up->pollcnt = 2; + return (1); +} + + +/* + * heath_shutdown - shut down the clock + */ +static void +heath_shutdown( + int unit, + struct peer *peer + ) +{ + register struct heathunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct heathunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * heath_receive - receive data from the serial interface + */ +static void +heath_receive( + struct recvbuf *rbufp + ) +{ + register struct heathunit *up; + struct refclockproc *pp; + struct peer *peer; + l_fp trtmp; + int month, day; + int i; + char dsec, a[5]; + + /* + * Initialize pointers and read the timecode and timestamp + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct heathunit *)pp->unitptr; + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); + + /* + * We get a buffer and timestamp for each ; however, we use + * the timestamp captured at the RTS modem control line toggle + * on the assumption that's what the radio bases the timecode + * on. Apparently, the radio takes about a second to make up its + * mind to send a timecode, so the receive timestamp is + * worthless. + */ + pp->lastrec = up->tstamp; + up->pollcnt = 2; +#ifdef DEBUG + if (debug) + printf("heath: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + + /* + * We get down to business, check the timecode format and decode + * its contents. If the timecode has invalid length or is not in + * proper format, we declare bad format and exit. + */ + if (pp->lencode < LENHEATH) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Timecode format: "hh:mm:ss.f AM mm/dd/yy" + */ + if (sscanf(pp->a_lastcode, "%2d:%2d:%2d.%c%5c%2d/%2d/%2d", + &pp->hour, &pp->minute, &pp->second, &dsec, a, &month, &day, + &pp->year) != 8) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * If AM or PM is received, assume the clock is displaying local + * time. First, convert to 24-hour format. + */ + + switch (a[1]) { + case 'P': + if (12 > pp->hour) + pp->hour += 12; + break; + + case 'A': + if (12 == pp->hour) + pp->hour -= 12; + break; + } + + /* + * Now make a struct tm out of it, convert to UTC, and + * repopulate pp-> + */ + + if (' ' != a[1]) { + struct tm t, *q; + time_t l; + + t.tm_sec = pp->second; + t.tm_min = pp->minute; + t.tm_hour = pp->hour; + t.tm_mday = day; /* not converted to yday yet */ + t.tm_mon = month-1; /* ditto */ + t.tm_year = pp->year; + if ( t.tm_year < YEAR_PIVOT ) t.tm_year += 100; /* Y2KFixes */ + + t.tm_wday = -1; /* who knows? */ + t.tm_yday = -1; /* who knows? */ + t.tm_isdst = -1; /* who knows? */ + + l = mktime(&t); + if (l == -1) { + /* HMS: do we want to do this? */ + refclock_report(peer, CEVNT_BADTIME); + return; + } + q = gmtime(&l); + + pp->year = q->tm_year; + month = q->tm_mon+1; + day = q->tm_mday; /* still not converted */ + pp->hour = q->tm_hour; + /* pp->minute = q->tm_min; GC-1000 cannot adjust timezone */ + /* pp->second = q->tm_sec; by other than hour increments */ + } + + + + /* + * We determine the day of the year from the DIPswitches. This + * should be fixed, since somebody might forget to set them. + * Someday this hazard will be fixed by a fiendish scheme that + * looks at the timecode and year the radio shows, then computes + * the residue of the seconds mod the seconds in a leap cycle. + * If in the third year of that cycle and the third and later + * months of that year, add one to the day. Then, correct the + * timecode accordingly. Icky pooh. This bit of nonsense could + * be avoided if the engineers had been required to write a + * device driver before finalizing the timecode format. + * + * Yes, I know this code incorrectly thinks that 2000 is a leap + * year; but, the latest year that can be set by the DIPswitches + * is 1997 anyay. Life is short. + * Hey! Year 2000 IS a leap year! Y2KFixes + */ + if (month < 1 || month > 12 || day < 1) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + if (pp->year % 4) { + if (day > day1tab[month - 1]) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + for (i = 0; i < month - 1; i++) + day += day1tab[i]; + } else { + if (day > day2tab[month - 1]) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + for (i = 0; i < month - 1; i++) + day += day2tab[i]; + } + pp->day = day; + + /* + * Determine synchronization and last update + */ + if (!isdigit((int)dsec)) + pp->leap = LEAP_NOTINSYNC; + else { + pp->msec = (dsec - '0') * 100; + pp->leap = LEAP_NOWARNING; + } + if (!refclock_process(pp)) + refclock_report(peer, CEVNT_BADTIME); +} + + +/* + * heath_poll - called by the transmit procedure + */ +static void +heath_poll( + int unit, + struct peer *peer + ) +{ + register struct heathunit *up; + struct refclockproc *pp; + int bits = TIOCM_RTS; + + /* + * At each poll we check for timeout and toggle the RTS modem + * control line, then take a timestamp. Presumably, this is the + * event the radio captures to generate the timecode. + */ + pp = peer->procptr; + up = (struct heathunit *)pp->unitptr; + pp->polls++; + + /* + * We toggle the RTS modem control lead to kick a timecode loose + * from the radio. This code works only for POSIX and SYSV + * interfaces. With bsd you are on your own. We take a timestamp + * between the up and down edges to lengthen the pulse, which + * should be about 50 usec on a Sun IPC. With hotshot CPUs, the + * pulse might get too short. Later. + */ + if (ioctl(pp->io.fd, TIOCMBIC, (char *)&bits) < 0) + refclock_report(peer, CEVNT_FAULT); + get_systime(&up->tstamp); + ioctl(pp->io.fd, TIOCMBIS, (char *)&bits); + if (peer->burst > 0) + return; + if (pp->coderecv == pp->codeproc) { + refclock_report(peer, CEVNT_TIMEOUT); + return; + } + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + peer->burst = NSTAGE; +} + +#else +int refclock_heath_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_hpgps.c b/contrib/ntp/ntpd/refclock_hpgps.c new file mode 100644 index 000000000000..30aa49406842 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_hpgps.c @@ -0,0 +1,603 @@ +/* + * refclock_hpgps - clock driver for HP 58503A GPS receiver + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_HPGPS) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +/* Version 0.1 April 1, 1995 + * 0.2 April 25, 1995 + * tolerant of missing timecode response prompt and sends + * clear status if prompt indicates error; + * can use either local time or UTC from receiver; + * can get receiver status screen via flag4 + * + * WARNING!: This driver is UNDER CONSTRUCTION + * Everything in here should be treated with suspicion. + * If it looks wrong, it probably is. + * + * Comments and/or questions to: Dave Vitanye + * Hewlett Packard Company + * dave@scd.hp.com + * (408) 553-2856 + * + * Thanks to the author of the PST driver, which was the starting point for + * this one. + * + * This driver supports the HP 58503A Time and Frequency Reference Receiver. + * This receiver uses HP SmartClock (TM) to implement an Enhanced GPS receiver. + * The receiver accuracy when locked to GPS in normal operation is better + * than 1 usec. The accuracy when operating in holdover is typically better + * than 10 usec. per day. + * + * The receiver should be operated with factory default settings. + * Initial driver operation: expects the receiver to be already locked + * to GPS, configured and able to output timecode format 2 messages. + * + * The driver uses the poll sequence :PTIME:TCODE? to get a response from + * the receiver. The receiver responds with a timecode string of ASCII + * printing characters, followed by a , followed by a prompt string + * issued by the receiver, in the following format: + * T#yyyymmddhhmmssMFLRVccscpi > + * + * The driver processes the response at the and , so what the + * driver sees is the prompt from the previous poll, followed by this + * timecode. The prompt from the current poll is (usually) left unread until + * the next poll. So (except on the very first poll) the driver sees this: + * + * scpi > T#yyyymmddhhmmssMFLRVcc + * + * The T is the on-time character, at 980 msec. before the next 1PPS edge. + * The # is the timecode format type. We look for format 2. + * Without any of the CLK or PPS stuff, then, the receiver buffer timestamp + * at the is 24 characters later, which is about 25 msec. at 9600 bps, + * so the first approximation for fudge time1 is nominally -0.955 seconds. + * This number probably needs adjusting for each machine / OS type, so far: + * -0.955000 on an HP 9000 Model 712/80 HP-UX 9.05 + * -0.953175 on an HP 9000 Model 370 HP-UX 9.10 + * + * This receiver also provides a 1PPS signal, but I haven't figured out + * how to deal with any of the CLK or PPS stuff yet. Stay tuned. + * + */ + +/* + * Fudge Factors + * + * Fudge time1 is used to accomodate the timecode serial interface adjustment. + * Fudge flag4 can be set to request a receiver status screen summary, which + * is recorded in the clockstats file. + */ + +/* + * Interface definitions + */ +#define DEVICE "/dev/hpgps%d" /* device name and unit */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ +#define PRECISION (-10) /* precision assumed (about 1 ms) */ +#define REFID "GPS\0" /* reference ID */ +#define DESCRIPTION "HP 58503A GPS Time and Frequency Reference Receiver" + +#define SMAX 23*80+1 /* for :SYSTEM:PRINT? status screen response */ + +#define MTZONE 2 /* number of fields in timezone reply */ +#define MTCODET2 12 /* number of fields in timecode format T2 */ +#define NTCODET2 21 /* number of chars to checksum in format T2 */ + +/* + * Tables to compute the day of year from yyyymmdd timecode. + * Viva la leap. + */ +static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* + * Unit control structure + */ +struct hpgpsunit { + int pollcnt; /* poll message counter */ + int tzhour; /* timezone offset, hours */ + int tzminute; /* timezone offset, minutes */ + int linecnt; /* set for expected multiple line responses */ + char *lastptr; /* pointer to receiver response data */ + char statscrn[SMAX]; /* receiver status screen buffer */ +}; + +/* + * Function prototypes + */ +static int hpgps_start P((int, struct peer *)); +static void hpgps_shutdown P((int, struct peer *)); +static void hpgps_receive P((struct recvbuf *)); +static void hpgps_poll P((int, struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_hpgps = { + hpgps_start, /* start up driver */ + hpgps_shutdown, /* shut down driver */ + hpgps_poll, /* transmit poll message */ + noentry, /* not used (old hpgps_control) */ + noentry, /* initialize driver */ + noentry, /* not used (old hpgps_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * hpgps_start - open the devices and initialize data for processing + */ +static int +hpgps_start( + int unit, + struct peer *peer + ) +{ + register struct hpgpsunit *up; + struct refclockproc *pp; + int fd; + char device[20]; + + /* + * Open serial port. Use CLK line discipline, if available. + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct hpgpsunit *) + emalloc(sizeof(struct hpgpsunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct hpgpsunit)); + pp = peer->procptr; + pp->io.clock_recv = hpgps_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + up->tzhour = 0; + up->tzminute = 0; + + *up->statscrn = '\0'; + up->lastptr = up->statscrn; + up->pollcnt = 2; + + /* + * Get the identifier string, which is logged but otherwise ignored, + * and get the local timezone information + */ + up->linecnt = 1; + if (write(pp->io.fd, "*IDN?\r:PTIME:TZONE?\r", 20) != 20) + refclock_report(peer, CEVNT_FAULT); + + return (1); +} + + +/* + * hpgps_shutdown - shut down the clock + */ +static void +hpgps_shutdown( + int unit, + struct peer *peer + ) +{ + register struct hpgpsunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct hpgpsunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * hpgps_receive - receive data from the serial interface + */ +static void +hpgps_receive( + struct recvbuf *rbufp + ) +{ + register struct hpgpsunit *up; + struct refclockproc *pp; + struct peer *peer; + l_fp trtmp; + char tcodechar1; /* identifies timecode format */ + char tcodechar2; /* identifies timecode format */ + char timequal; /* time figure of merit: 0-9 */ + char freqqual; /* frequency figure of merit: 0-3 */ + char leapchar; /* leapsecond: + or 0 or - */ + char servchar; /* request for service: 0 = no, 1 = yes */ + char syncchar; /* time info is invalid: 0 = no, 1 = yes */ + short expectedsm; /* expected timecode byte checksum */ + short tcodechksm; /* computed timecode byte checksum */ + int i,m,n; + int month, day, lastday; + char *tcp; /* timecode pointer (skips over the prompt) */ + char prompt[BMAX]; /* prompt in response from receiver */ + + /* + * Initialize pointers and read the receiver response + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct hpgpsunit *)pp->unitptr; + *pp->a_lastcode = '\0'; + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); + +#ifdef DEBUG + if (debug) + printf("hpgps: lencode: %d timecode:%s\n", + pp->lencode, pp->a_lastcode); +#endif + + /* + * If there's no characters in the reply, we can quit now + */ + if (pp->lencode == 0) + return; + + /* + * If linecnt is greater than zero, we are getting information only, + * such as the receiver identification string or the receiver status + * screen, so put the receiver response at the end of the status + * screen buffer. When we have the last line, write the buffer to + * the clockstats file and return without further processing. + * + * If linecnt is zero, we are expecting either the timezone + * or a timecode. At this point, also write the response + * to the clockstats file, and go on to process the prompt (if any), + * timezone, or timecode and timestamp. + */ + + + if (up->linecnt-- > 0) { + if ((int)(pp->lencode + 2) <= (SMAX - (up->lastptr - up->statscrn))) { + *up->lastptr++ = '\n'; + (void)strcpy(up->lastptr, pp->a_lastcode); + up->lastptr += pp->lencode; + } + if (up->linecnt == 0) + record_clock_stats(&peer->srcadr, up->statscrn); + + return; + } + + record_clock_stats(&peer->srcadr, pp->a_lastcode); + pp->lastrec = trtmp; + + up->lastptr = up->statscrn; + *up->lastptr = '\0'; + up->pollcnt = 2; + + /* + * We get down to business: get a prompt if one is there, issue + * a clear status command if it contains an error indication. + * Next, check for either the timezone reply or the timecode reply + * and decode it. If we don't recognize the reply, or don't get the + * proper number of decoded fields, or get an out of range timezone, + * or if the timecode checksum is bad, then we declare bad format + * and exit. + * + * Timezone format (including nominal prompt): + * scpi > -H,-M + * + * Timecode format (including nominal prompt): + * scpi > T2yyyymmddhhmmssMFLRVcc + * + */ + + (void)strcpy(prompt,pp->a_lastcode); + tcp = strrchr(pp->a_lastcode,'>'); + if (tcp == NULL) + tcp = pp->a_lastcode; + else + tcp++; + prompt[tcp - pp->a_lastcode] = '\0'; + while ((*tcp == ' ') || (*tcp == '\t')) tcp++; + + /* + * deal with an error indication in the prompt here + */ + if (strrchr(prompt,'E') > strrchr(prompt,'s')){ +#ifdef DEBUG + if (debug) + printf("hpgps: error indicated in prompt: %s\n", prompt); +#endif + if (write(pp->io.fd, "*CLS\r\r", 6) != 6) + refclock_report(peer, CEVNT_FAULT); + } + + /* + * make sure we got a timezone or timecode format and + * then process accordingly + */ + m = sscanf(tcp,"%c%c", &tcodechar1, &tcodechar2); + + if (m != 2){ +#ifdef DEBUG + if (debug) + printf("hpgps: no format indicator\n"); +#endif + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + switch (tcodechar1) { + + case '+': + case '-': + m = sscanf(tcp,"%d,%d", &up->tzhour, &up->tzminute); + if (m != MTZONE) { +#ifdef DEBUG + if (debug) + printf("hpgps: only %d fields recognized in timezone\n", m); +#endif + refclock_report(peer, CEVNT_BADREPLY); + return; + } + if ((up->tzhour < -12) || (up->tzhour > 13) || + (up->tzminute < -59) || (up->tzminute > 59)){ +#ifdef DEBUG + if (debug) + printf("hpgps: timezone %d, %d out of range\n", + up->tzhour, up->tzminute); +#endif + refclock_report(peer, CEVNT_BADREPLY); + return; + } + return; + + case 'T': + break; + + default: +#ifdef DEBUG + if (debug) + printf("hpgps: unrecognized reply format %c%c\n", + tcodechar1, tcodechar2); +#endif + refclock_report(peer, CEVNT_BADREPLY); + return; + } /* end of tcodechar1 switch */ + + + switch (tcodechar2) { + + case '2': + m = sscanf(tcp,"%*c%*c%4d%2d%2d%2d%2d%2d%c%c%c%c%c%2hx", + &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second, + &timequal, &freqqual, &leapchar, &servchar, &syncchar, + &expectedsm); + n = NTCODET2; + + if (m != MTCODET2){ +#ifdef DEBUG + if (debug) + printf("hpgps: only %d fields recognized in timecode\n", m); +#endif + refclock_report(peer, CEVNT_BADREPLY); + return; + } + break; + + default: +#ifdef DEBUG + if (debug) + printf("hpgps: unrecognized timecode format %c%c\n", + tcodechar1, tcodechar2); +#endif + refclock_report(peer, CEVNT_BADREPLY); + return; + } /* end of tcodechar2 format switch */ + + /* + * Compute and verify the checksum. + * Characters are summed starting at tcodechar1, ending at just + * before the expected checksum. Bail out if incorrect. + */ + tcodechksm = 0; + while (n-- > 0) tcodechksm += *tcp++; + tcodechksm &= 0x00ff; + + if (tcodechksm != expectedsm) { +#ifdef DEBUG + if (debug) + printf("hpgps: checksum %2hX doesn't match %2hX expected\n", + tcodechksm, expectedsm); +#endif + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Compute the day of year from the yyyymmdd format. + */ + if (month < 1 || month > 12 || day < 1) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + + if ( ! isleap_4(pp->year) ) { /* Y2KFixes */ + /* not a leap year */ + if (day > day1tab[month - 1]) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + for (i = 0; i < month - 1; i++) day += day1tab[i]; + lastday = 365; + } else { + /* a leap year */ + if (day > day2tab[month - 1]) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + for (i = 0; i < month - 1; i++) day += day2tab[i]; + lastday = 366; + } + + /* + * Deal with the timezone offset here. The receiver timecode is in + * local time = UTC + :PTIME:TZONE, so SUBTRACT the timezone values. + * For example, Pacific Standard Time is -8 hours , 0 minutes. + * Deal with the underflows and overflows. + */ + pp->minute -= up->tzminute; + pp->hour -= up->tzhour; + + if (pp->minute < 0) { + pp->minute += 60; + pp->hour--; + } + if (pp->minute > 59) { + pp->minute -= 60; + pp->hour++; + } + if (pp->hour < 0) { + pp->hour += 24; + day--; + if (day < 1) { + pp->year--; + if ( isleap_4(pp->year) ) /* Y2KFixes */ + day = 366; + else + day = 365; + } + } + + if (pp->hour > 23) { + pp->hour -= 24; + day++; + if (day > lastday) { + pp->year++; + day = 1; + } + } + + pp->day = day; + + /* + * Decode the MFLRV indicators. + * NEED TO FIGURE OUT how to deal with the request for service, + * time quality, and frequency quality indicators some day. + */ + if (syncchar != '0') { + pp->leap = LEAP_NOTINSYNC; + } + else { + switch (leapchar) { + + case '+': + pp->leap = LEAP_ADDSECOND; + break; + + case '0': + pp->leap = LEAP_NOWARNING; + break; + + case '-': + pp->leap = LEAP_DELSECOND; + break; + + default: +#ifdef DEBUG + if (debug) + printf("hpgps: unrecognized leap indicator: %c\n", + leapchar); +#endif + refclock_report(peer, CEVNT_BADTIME); + return; + } /* end of leapchar switch */ + } + + /* + * Process the new sample in the median filter and determine the + * reference clock offset and dispersion. We use lastrec as both + * the reference time and receive time in order to avoid being + * cute, like setting the reference time later than the receive + * time, which may cause a paranoid protocol module to chuck out + * the data. + */ + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + refclock_receive(peer); + + /* + * If CLK_FLAG4 is set, ask for the status screen response. + */ + if (pp->sloppyclockflag & CLK_FLAG4){ + up->linecnt = 22; + if (write(pp->io.fd, ":SYSTEM:PRINT?\r", 15) != 15) + refclock_report(peer, CEVNT_FAULT); + } +} + + +/* + * hpgps_poll - called by the transmit procedure + */ +static void +hpgps_poll( + int unit, + struct peer *peer + ) +{ + register struct hpgpsunit *up; + struct refclockproc *pp; + + /* + * Time to poll the clock. The HP 58503A responds to a + * ":PTIME:TCODE?" by returning a timecode in the format specified + * above. If nothing is heard from the clock for two polls, + * declare a timeout and keep going. + */ + pp = peer->procptr; + up = (struct hpgpsunit *)pp->unitptr; + if (up->pollcnt == 0) + refclock_report(peer, CEVNT_TIMEOUT); + else + up->pollcnt--; + if (write(pp->io.fd, ":PTIME:TCODE?\r", 14) != 14) { + refclock_report(peer, CEVNT_FAULT); + } + else + pp->polls++; +} + +#else +int refclock_hpgps_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_irig.c b/contrib/ntp/ntpd/refclock_irig.c new file mode 100644 index 000000000000..eccbda81cfdf --- /dev/null +++ b/contrib/ntp/ntpd/refclock_irig.c @@ -0,0 +1,1079 @@ +/* + * refclock_irig - audio IRIG-B/E demodulator/decoder + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_IRIG) + +#include +#include +#include +#include +#ifdef HAVE_SYS_AUDIOIO_H +#include +#endif /* HAVE_SYS_AUDIOIO_H */ +#ifdef HAVE_SUN_AUDIOIO_H +#include +#endif /* HAVE_SUN_AUDIOIO_H */ +#ifdef HAVE_SYS_IOCTL_H +#include +#endif /* HAVE_SYS_IOCTL_H */ + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * Audio IRIG-B/E demodulator/decoder + * + * This driver receives, demodulates and decodes IRIG-B/E signals when + * connected to the audio codec /dev/audio. The IRIG signal format is an + * amplitude-modulated carrier with pulse-width modulated data bits. For + * IRIG-B, the carrier frequency is 1000 Hz and bit rate 100 b/s; for + * IRIG-E, the carrier frequenchy is 100 Hz and bit rate 10 b/s. The + * driver automatically recognizes which format is in use. + * + * The program processes 8000-Hz mu-law companded samples using separate + * signal filters for IRIG-B and IRIG-E, a comb filter, envelope + * detector and automatic threshold corrector. Cycle crossings relative + * to the corrected slice level determine the width of each pulse and + * its value - zero, one or position identifier. The data encode 20 BCD + * digits which determine the second, minute, hour and day of the year + * and sometimes the year and synchronization condition. The comb filter + * exponentially averages the corresponding samples of successive baud + * intervals in order to reliably identify the reference carrier cycle. + * A type-II phase-lock loop (PLL) performs additional integration and + * interpolation to accurately determine the zero crossing of that + * cycle, which determines the reference timestamp. A pulse-width + * discriminator demodulates the data pulses, which are then encoded as + * the BCD digits of the timecode. + * + * The timecode and reference timestamp are updated once each second + * with IRIG-B (ten seconds with IRIG-E) and local clock offset samples + * saved for later processing. At poll intervals of 64 s, the saved + * samples are processed by a trimmed-mean filter and used to update the + * system clock. + * + * An automatic gain control feature provides protection against + * overdriven or underdriven input signal amplitudes. It is designed to + * maintain adequate demodulator signal amplitude while avoiding + * occasional noise spikes. In order to assure reliable capture, the + * decompanded input signal amplitude must be greater than 100 units and + * the codec sample frequency error less than 250 PPM (.025 percent). + * + * The program performs a number of error checks to protect against + * overdriven or underdriven input signal levels, incorrect signal + * format or improper hardware configuration. Specifically, if any of + * the following errors occur for a time measurement, the data are + * rejected. + * + * o The peak carrier amplitude is less than DRPOUT (100). This usually + * means dead IRIG signal source, broken cable or wrong input port. + * + * o The frequency error is greater than MAXFREQ +-250 PPM (.025%). This + * usually means broken codec hardware or wrong codec configuration. + * + * o The modulation index is less than MODMIN (0.5). This usually means + * overdriven IRIG signal or wrong IRIG format. + * + * o A frame synchronization error has occurred. This usually means wrong + * IRIG signal format or the IRIG signal source has lost + * synchronization (signature control). + * + * o A data decoding error has occurred. This usually means wrong IRIG + * signal format. + * + * o The current second of the day is not exactly one greater than the + * previous one. This usually means a very noisy IRIG signal or + * insufficient CPU resources. + * + * o An audio codec error (overrun) occurred. This usually means + * insufficient CPU resources, as sometimes happens with Sun SPARC + * IPCs when doing something useful. + * + * Note that additional checks are done elsewhere in the reference clock + * interface routines. + * + * Debugging aids + * + * The timecode format used for debugging and data recording includes + * data helpful in diagnosing problems with the IRIG signal and codec + * connections. With debugging enabled (-d -d -d on the ntpd command + * line), the driver produces one line for each timecode in the + * following format: + * + * 00 1 98 23 19:26:52 721 143 0.694 47 20 0.083 66.5 3094572411.00027 + * + * The most recent line is also written to the clockstats file at 64-s + * intervals. + * + * The first field contains the error flags in hex, where the hex bits + * are interpreted as below. This is followed by the IRIG status + * indicator, year of century, day of year and time of day. The status + * indicator and year are not produced by some IRIG devices. Following + * these fields are the signal amplitude (0-8100), codec gain (0-255), + * field phase (0-79), time constant (2-20), modulation index (0-1), + * carrier phase error (0+-0.5) and carrier frequency error (PPM). The + * last field is the on-time timestamp in NTP format. + * + * The fraction part of the on-time timestamp is a good indicator of how + * well the driver is doing. With an UltrSPARC 30, this thing can keep + * the clock within a few tens of microseconds relative to the IRIG-B + * signal. Accuracy with IRIG-E is about ten times worse. + * + * Unlike other drivers, which can have multiple instantiations, this + * one supports only one. It does not seem likely that more than one + * audio codec would be useful in a single machine. More than one would + * probably chew up too much CPU time anyway. + * + * Fudge factors + * + * Fudge flag2 selects the audio input port, where 0 is the mike port + * (default) and 1 is the line-in port. It does not seem useful to + * select the compact disc player port. Fudge flag3 enables audio + * monitoring of the input signal. For this purpose, the speaker volume + * must be set before the driver is started. Fudge flag4 causes the + * debugging output described above to be recorded in the clockstats + * file. Any of these flags can be changed during operation with the + * ntpdc program. + */ + +/* + * Interface definitions + */ +#define PRECISION (-17) /* precision assumed (about 10 us) */ +#define REFID "IRIG" /* reference ID */ +#define DESCRIPTION "Generic IRIG Audio Driver" /* WRU */ + +#define AUDIO_BUFSIZ 160 /* codec buffer size (Solaris only) */ +#define SAMPLES 8000 /* nominal sample rate (Hz) */ +#define BAUD 80 /* samples per baud interval */ +#define OFFSET 128 /* companded sample offset */ +#define SIZE 256 /* decompanding table size */ +#define CYCLE 8 /* samples per carrier cycle */ +#define SUBFLD 10 /* bits per subfield */ +#define FIELD 10 /* subfields per field */ +#define MINTC 2 /* min PLL time constant */ +#define MAXTC 20 /* max PLL time constant max */ +#define MAXSIG 6000. /* maximum signal level */ +#define DRPOUT 100. /* dropout signal level */ +#define MODMIN 0.5 /* minimum modulation index */ +#define MAXFREQ (250e-6 * SAMPLES) /* freq tolerance (.025%) */ +#define PI 3.1415926535 /* the real thing */ + +/* + * Experimentally determined fudge factors + */ +#define IRIG_B .0019 /* IRIG-B phase delay */ +#define IRIG_E .0019 /* IRIG-E phase delay */ + +/* + * Data bit definitions + */ +#define BIT0 0 /* zero */ +#define BIT1 1 /* one */ +#define BITP 2 /* position identifier */ + +/* + * Error flags (up->errflg) + */ +#define IRIG_ERR_AMP 0x01 /* low carrier amplitude */ +#define IRIG_ERR_FREQ 0x02 /* frequency tolerance exceeded */ +#define IRIG_ERR_MOD 0x04 /* low modulation index */ +#define IRIG_ERR_SYNCH 0x08 /* frame synch error */ +#define IRIG_ERR_DECODE 0x10 /* frame decoding error */ +#define IRIG_ERR_CHECK 0x20 /* second numbering discrepancy */ +#define IRIG_ERR_ERROR 0x40 /* codec error (overrun) */ + +/* + * IRIG unit control structure + */ +struct irigunit { + u_char timecode[21]; /* timecode string */ + l_fp timestamp; /* audio sample timestamp */ + l_fp tick; /* audio sample increment */ + double comp[SIZE]; /* decompanding table */ + double integ[BAUD]; /* baud integrator */ + double phase, freq; /* logical clock phase and frequency */ + double zxing; /* phase detector integrator */ + double yxing; /* phase detector display */ + double modndx; /* modulation index */ + double irig_b; /* IRIG-B signal amplitude */ + double irig_e; /* IRIG-E signal amplitude */ + int errflg; /* error flags */ + int bufcnt; /* samples in buffer */ + int bufptr; /* buffer index pointer */ + int pollcnt; /* poll counter */ + int port; /* codec port */ + int gain; /* codec gain */ + int clipcnt; /* sample clipped count */ + int seccnt; /* second interval counter */ + int decim; /* sample decimation factor */ + + /* + * RF variables + */ + double hpf[5]; /* IRIG-B filter shift register */ + double lpf[5]; /* IRIG-E filter shift register */ + double intmin, intmax; /* integrated envelope min and max */ + double envmax; /* peak amplitude */ + double envmin; /* noise amplitude */ + double maxsignal; /* integrated peak amplitude */ + double noise; /* integrated noise amplitude */ + double lastenv[CYCLE]; /* last cycle amplitudes */ + double lastint[CYCLE]; /* last integrated cycle amplitudes */ + double lastsig; /* last carrier sample */ + double xxing; /* phase detector interpolated output */ + double fdelay; /* filter delay */ + int envphase; /* envelope phase */ + int envptr; /* envelope phase pointer */ + int carphase; /* carrier phase */ + int envsw; /* envelope state */ + int envxing; /* envelope slice crossing */ + int tc; /* time constant */ + int tcount; /* time constant counter */ + int badcnt; /* decimation interval counter */ + + /* + * Decoder variables + */ + l_fp montime; /* reference timestamp for eyeball */ + int timecnt; /* timecode counter */ + int pulse; /* cycle counter */ + int cycles; /* carrier cycles */ + int dcycles; /* data cycles */ + int xptr; /* translate table pointer */ + int lastbit; /* last code element length */ + int second; /* previous second */ + int fieldcnt; /* subfield count in field */ + int bits; /* demodulated bits */ + int bitcnt; /* bit count in subfield */ +}; + +/* + * Function prototypes + */ +static int irig_start P((int, struct peer *)); +static void irig_shutdown P((int, struct peer *)); +static void irig_receive P((struct recvbuf *)); +static void irig_poll P((int, struct peer *)); + +/* + * More function prototypes + */ +static void irig_base P((struct peer *, double)); +static void irig_rf P((struct peer *, double)); +static void irig_decode P((struct peer *, int)); +static void irig_gain P((struct peer *)); +static int irig_audio P((void)); +static void irig_debug P((void)); + +/* + * Transfer vector + */ +struct refclock refclock_irig = { + irig_start, /* start up driver */ + irig_shutdown, /* shut down driver */ + irig_poll, /* transmit poll message */ + noentry, /* not used (old irig_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old irig_buginfo) */ + NOFLAGS /* not used */ +}; + +/* + * Global variables + */ +#ifdef HAVE_SYS_AUDIOIO_H +struct audio_device device; /* audio device ident */ +#endif /* HAVE_SYS_AUDIOIO_H */ +static struct audio_info info; /* audio device info */ +static int irig_ctl_fd; /* audio control file descriptor */ +static char hexchar[] = { /* really quick decoding table */ + '0', '8', '4', 'c', /* 0000 0001 0010 0011 */ + '2', 'a', '6', 'e', /* 0100 0101 0110 0111 */ + '1', '9', '5', 'd', /* 1000 1001 1010 1011 */ + '3', 'b', '7', 'f' /* 1100 1101 1110 1111 */ +}; + + +/* + * irig_start - open the devices and initialize data for processing + */ +static int +irig_start( + int unit, /* instance number (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + struct irigunit *up; + + /* + * Local variables + */ + int fd; /* file descriptor */ + int i; /* index */ + double step; /* codec adjustment */ + + /* + * Open audio device + */ + fd = open("/dev/audio", O_RDWR | O_NONBLOCK, 0777); + if (fd == -1) { + perror("audio"); + return (0); + } + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct irigunit *) + emalloc(sizeof(struct irigunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct irigunit)); + pp = peer->procptr; + pp->unitptr = (caddr_t)up; + pp->io.clock_recv = irig_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void)close(fd); + free(up); + return (0); + } + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + up->tc = MINTC; + up->decim = 1; + up->fdelay = IRIG_B; + up->gain = (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN) / 2; + if (irig_audio() < 0) { + io_closeclock(&pp->io); + return(0); + } + up->pollcnt = 2; + + /* + * The companded samples are encoded sign-magnitude. The table + * contains all the 256 values in the interest of speed. + */ + up->comp[0] = up->comp[OFFSET] = 0.; + up->comp[1] = 1; up->comp[OFFSET + 1] = -1.; + up->comp[2] = 3; up->comp[OFFSET + 2] = -3.; + step = 2.; + for (i = 3; i < OFFSET; i++) { + up->comp[i] = up->comp[i - 1] + step; + up->comp[OFFSET + i] = -up->comp[i]; + if (i % 16 == 0) + step *= 2.; + } + DTOLFP(1. / SAMPLES, &up->tick); + return (1); +} + + +/* + * irig_shutdown - shut down the clock + */ +static void +irig_shutdown( + int unit, /* instance number (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + struct irigunit *up; + + pp = peer->procptr; + up = (struct irigunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * irig_receive - receive data from the audio device + * + * This routine reads input samples and adjusts the logical clock to + * track the irig clock by dropping or duplicating codec samples. + */ +static void +irig_receive( + struct recvbuf *rbufp /* receive buffer structure pointer */ + ) +{ + struct peer *peer; + struct refclockproc *pp; + struct irigunit *up; + + /* + * Local variables + */ + double sample; /* codec sample */ + u_char *dpt; /* buffer pointer */ + l_fp ltemp; /* l_fp temp */ + + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct irigunit *)pp->unitptr; + + /* + * Main loop - read until there ain't no more. Note codec + * samples are bit-inverted. + */ + up->timestamp = rbufp->recv_time; + up->bufcnt = rbufp->recv_length; + DTOLFP((double)up->bufcnt / SAMPLES, <emp); + L_SUB(&up->timestamp, <emp); + dpt = rbufp->recv_buffer; + for (up->bufptr = 0; up->bufptr < up->bufcnt; up->bufptr++) { + sample = up->comp[~*dpt++ & 0xff]; + + /* + * Clip noise spikes greater than MAXSIG. If no clips, + * increase the gain a tad; if the clips are too high, + * decrease a tad. Choose either IRIG-B or IRIG-E + * according to the energy at the respective filter + * output. + */ + if (sample > MAXSIG) { + sample = MAXSIG; + up->clipcnt++; + } else if (sample < -MAXSIG) { + sample = -MAXSIG; + up->clipcnt++; + } + + /* + * Variable frequency oscillator. A phase change of one + * unit produces a change of 360 degrees; a frequency + * change of one unit produces a change of 1 Hz. + */ + up->phase += up->freq / SAMPLES; + if (up->phase >= .5) { + up->phase -= 1.; + } else if (up->phase < -.5) { + up->phase += 1.; + irig_rf(peer, sample); + irig_rf(peer, sample); + } else { + irig_rf(peer, sample); + } + L_ADD(&up->timestamp, &up->tick); + + /* + * Once each second, determine the IRIG format, codec + * port and gain. + */ + up->seccnt = (up->seccnt + 1) % SAMPLES; + if (up->seccnt == 0) { + if (up->irig_b > up->irig_e) { + up->decim = 1; + up->fdelay = IRIG_B; + } else { + up->decim = 10; + up->fdelay = IRIG_E; + } + if (pp->sloppyclockflag & CLK_FLAG2) + up->port = AUDIO_LINE_IN; + else + up->port = AUDIO_MICROPHONE; + irig_gain(peer); + up->clipcnt = 0; + up->irig_b = up->irig_e = 0; + } + } + + /* + * Squawk to the monitor speaker if enabled. + */ + if (pp->sloppyclockflag & CLK_FLAG3) + if (write(pp->io.fd, (u_char *)&rbufp->recv_space, + (u_int)up->bufcnt) < 0) + perror("irig:"); +} + +/* + * irig_rf - RF processing + * + * This routine filters the RF signal using a highpass filter for IRIG-B + * and a lowpass filter for IRIG-E. In case of IRIG-E, the samples are + * decimated by a factor of ten. The lowpass filter functions also as a + * decimation filter in this case. Note that the codec filters function + * as roofing filters to attenuate both the high and low ends of the + * passband. IIR filter coefficients were determined using Matlab Signal + * Processing Toolkit. + */ +static void +irig_rf( + struct peer *peer, /* peer structure pointer */ + double sample /* current signal sample */ + ) +{ + struct refclockproc *pp; + struct irigunit *up; + + /* + * Local variables + */ + double irig_b, irig_e; /* irig filter outputs */ + + pp = peer->procptr; + up = (struct irigunit *)pp->unitptr; + + /* + * IRIG-B filter. 4th-order elliptic, 800-Hz highpass, 0.3 dB + * passband ripple, -50 dB stopband ripple, phase delay -.0022 + * s) + */ + irig_b = (up->hpf[4] = up->hpf[3]) * 2.322484e-01; + irig_b += (up->hpf[3] = up->hpf[2]) * -1.103929e+00; + irig_b += (up->hpf[2] = up->hpf[1]) * 2.351081e+00; + irig_b += (up->hpf[1] = up->hpf[0]) * -2.335036e+00; + up->hpf[0] = sample - irig_b; + irig_b = up->hpf[0] * 4.335855e-01 + + up->hpf[1] * -1.695859e+00 + + up->hpf[2] * 2.525004e+00 + + up->hpf[3] * -1.695859e+00 + + up->hpf[4] * 4.335855e-01; + up->irig_b += irig_b * irig_b; + + /* + * IRIG-E filter. 4th-order elliptic, 130-Hz lowpass, 0.3 dB + * passband ripple, -50 dB stopband ripple, phase delay .0219 s. + */ + irig_e = (up->lpf[4] = up->lpf[3]) * 8.694604e-01; + irig_e += (up->lpf[3] = up->lpf[2]) * -3.589893e+00; + irig_e += (up->lpf[2] = up->lpf[1]) * 5.570154e+00; + irig_e += (up->lpf[1] = up->lpf[0]) * -3.849667e+00; + up->lpf[0] = sample - irig_e; + irig_e = up->lpf[0] * 3.215696e-03 + + up->lpf[1] * -1.174951e-02 + + up->lpf[2] * 1.712074e-02 + + up->lpf[3] * -1.174951e-02 + + up->lpf[4] * 3.215696e-03; + up->irig_e += irig_e * irig_e; + + /* + * Decimate by a factor of either 1 (IRIG-B) or 10 (IRIG-E). + */ + up->badcnt = (up->badcnt + 1) % up->decim; + if (up->badcnt == 0) { + if (up->decim == 1) + irig_base(peer, irig_b); + else + irig_base(peer, irig_e); + } +} + +/* + * irig_base - baseband processing + * + * This routine processes the baseband signal and demodulates the AM + * carrier using a synchronous detector. It then synchronizes to the + * data frame at the baud rate and decodes the data pulses. + */ +static void +irig_base( + struct peer *peer, /* peer structure pointer */ + double sample /* current signal sample */ + ) +{ + struct refclockproc *pp; + struct irigunit *up; + + /* + * Local variables + */ + double lope; /* integrator output */ + double env; /* envelope detector output */ + double dtemp; /* double temp */ + int i; /* index temp */ + + pp = peer->procptr; + up = (struct irigunit *)pp->unitptr; + + /* + * Synchronous baud integrator. Corresponding samples of current + * and past baud intervals are integrated to refine the envelope + * amplitude and phase estimate. We keep one cycle of both the + * raw and integrated data for later use. + */ + up->envphase = (up->envphase + 1) % BAUD; + up->carphase = (up->carphase + 1) % CYCLE; + up->integ[up->envphase] += (sample - up->integ[up->envphase]) / + (5 * up->tc); + lope = up->integ[up->envphase]; + up->lastenv[up->carphase] = sample; + up->lastint[up->carphase] = lope; + + /* + * Phase detector. Sample amplitudes are integrated over the + * baud interval. Cycle phase is determined from these + * amplitudes using an eight-sample cyclic buffer. A phase + * change of 360 degrees produces an output change of one unit. + */ + if (up->lastsig > 0 && lope <= 0) { + up->xxing = lope / (up->lastsig - lope); + up->zxing += (up->carphase - 4 + up->xxing) / 8.; + } + up->lastsig = lope; + + /* + * Update signal/noise estimates and PLL phase/frequency. + */ + if (up->envphase == 0) { + + /* + * Update envelope signal and noise estimates and mess + * with error bits. + */ + up->maxsignal = up->intmax; + up->noise = up->intmin; + if (up->maxsignal < DRPOUT) + up->errflg |= IRIG_ERR_AMP; + if (up->intmax > 0) + up->modndx = (up->intmax - up->intmin) / up->intmax; + else + up->modndx = 0; + if (up->modndx < MODMIN) + up->errflg |= IRIG_ERR_MOD; + up->intmin = 1e6; up->intmax = 0; + if (up->errflg & (IRIG_ERR_AMP | IRIG_ERR_FREQ | + IRIG_ERR_MOD | IRIG_ERR_SYNCH)) { + up->tc = MINTC; + up->tcount = 0; + } + + /* + * Update PLL phase and frequency. The PLL time constant + * is set initially to stabilize the frequency within a + * minute or two, then increases to the maximum. The + * frequency is clamped so that the PLL capture range + * cannot be exceeded. + */ + dtemp = up->zxing * up->decim / BAUD; + up->yxing = dtemp; + up->zxing = 0.; + up->phase += dtemp / up->tc; + up->freq += dtemp / (4. * up->tc * up->tc); + if (up->freq > MAXFREQ) { + up->freq = MAXFREQ; + up->errflg |= IRIG_ERR_FREQ; + } else if (up->freq < -MAXFREQ) { + up->freq = -MAXFREQ; + up->errflg |= IRIG_ERR_FREQ; + } + } + + /* + * Synchronous demodulator. There are eight samples in the cycle + * and ten cycles in the baud interval. The amplitude of each + * cycle is determined at the last sample in the cycle. The + * beginning of the data pulse is determined from the integrated + * samples, while the end of the pulse is determined from the + * raw samples. The raw data bits are demodulated relative to + * the slice level and left-shifted in the decoding register. + */ + if (up->carphase != 7) + return; + env = (up->lastenv[2] - up->lastenv[6]) / 2.; + lope = (up->lastint[2] - up->lastint[6]) / 2.; + if (lope > up->intmax) + up->intmax = lope; + if (lope < up->intmin) + up->intmin = lope; + + /* + * Pulse code demodulator and reference timestamp. The decoder + * looks for a sequence of ten bits; the first two bits must be + * one, the last two bits must be zero. Frame synch is asserted + * when three correct frames have been found. + */ + up->pulse = (up->pulse + 1) % 10; + if (up->pulse == 1) + up->envmax = env; + else if (up->pulse == 9) + up->envmin = env; + up->dcycles <<= 1; + if (env >= (up->envmax + up->envmin) / 2.) + up->dcycles |= 1; + up->cycles <<= 1; + if (lope >= (up->maxsignal + up->noise) / 2.) + up->cycles |= 1; + if ((up->cycles & 0x303c0f03) == 0x300c0300) { + l_fp ltemp; + int bitz; + + /* + * The PLL time constant starts out small, in order to + * sustain a frequency tolerance of 250 PPM. It + * gradually increases as the loop settles down. Note + * that small wiggles are not believed, unless they + * persist for lots of samples. + */ + if (up->pulse != 9) + up->errflg |= IRIG_ERR_SYNCH; + up->pulse = 9; + dtemp = BAUD - up->zxing; + i = up->envxing - up->envphase; + if (i < 0) + i -= i; + if (i <= 1) { + up->tcount++; + if (up->tcount > 50 * up->tc) { + up->tc++; + if (up->tc > MAXTC) + up->tc = MAXTC; + up->tcount = 0; + up->envxing = up->envphase; + } else { + dtemp -= up->envxing - up->envphase; + } + } else { + up->tcount = 0; + up->envxing = up->envphase; + } + + /* + * Determine a reference timestamp, accounting for the + * codec delay and filter delay. Note the timestamp is + * for the previous frame, so we have to backtrack for + * this plus the delay since the last carrier positive + * zero crossing. + */ + DTOLFP(up->decim * (dtemp / SAMPLES + 1.) + up->fdelay, + <emp); + pp->lastrec = up->timestamp; + L_SUB(&pp->lastrec, <emp); + + /* + * The data bits are collected in ten-bit frames. The + * first two and last two bits are determined by frame + * sync and ignored here; the resulting patterns + * represent zero (0-1 bits), one (2-4 bits) and + * position identifier (5-6 bits). The remaining + * patterns represent errors and are treated as zeros. + */ + bitz = up->dcycles & 0xfc; + switch(bitz) { + + case 0x00: + case 0x80: + irig_decode(peer, BIT0); + break; + + case 0xc0: + case 0xe0: + case 0xf0: + irig_decode(peer, BIT1); + break; + + case 0xf8: + case 0xfc: + irig_decode(peer, BITP); + break; + + default: + irig_decode(peer, 0); + up->errflg |= IRIG_ERR_DECODE; + } + } +} + + +/* + * irig_decode - decode the data + * + * This routine assembles bits into digits, digits into subfields and + * subfields into the timecode field. Bits can have values of zero, one + * or position identifier. There are four bits per digit, two digits per + * subfield and ten subfields per field. The last bit in every subfield + * and the first bit in the first subfield are position identifiers. + */ +static void +irig_decode( + struct peer *peer, /* peer structure pointer */ + int bit /* data bit (0, 1 or 2) */ + ) +{ + struct refclockproc *pp; + struct irigunit *up; + + /* + * Local variables + */ + char syncchar; /* sync character (Spectracom only) */ + char sbs[6]; /* binary seconds since 0h */ + char spare[2]; /* mulligan digits */ + + pp = peer->procptr; + up = (struct irigunit *)pp->unitptr; + + /* + * Assemble subfield bits. + */ + up->bits <<= 1; + if (bit == BIT1) { + up->bits |= 1; + } else if (bit == BITP && up->lastbit == BITP) { + + /* + * Frame sync - two adjacent position identifiers. + * Monitor the reference timestamp and wiggle the + * clock, but only if no errors have occurred. + */ + up->bitcnt = 1; + up->fieldcnt = 0; + up->lastbit = 0; + up->montime = pp->lastrec; + if (up->errflg == 0) { + up->timecnt++; + refclock_process(pp); + } + if (up->timecnt >= MAXSTAGE) { + refclock_receive(peer); + up->timecnt = 0; + up->pollcnt = 2; + } + up->errflg = 0; + } + up->bitcnt = (up->bitcnt + 1) % SUBFLD; + if (up->bitcnt == 0) { + + /* + * End of subfield. Encode two hexadecimal digits in + * little-endian timecode field. + */ + if (up->fieldcnt == 0) + up->bits <<= 1; + if (up->xptr < 2) + up->xptr = 2 * FIELD; + up->timecode[--up->xptr] = hexchar[(up->bits >> 5) & + 0xf]; + up->timecode[--up->xptr] = hexchar[up->bits & 0xf]; + up->fieldcnt = (up->fieldcnt + 1) % FIELD; + if (up->fieldcnt == 0) { + + /* + * End of field. Decode the timecode, adjust the + * gain and set the input port. Set the port + * here on the assumption somebody might even + * change it on-wing. + */ + up->xptr = 2 * FIELD; + if (sscanf((char *)up->timecode, + "%6s%2d%c%2s%3d%2d%2d%2d", + sbs, &pp->year, &syncchar, spare, &pp->day, + &pp->hour, &pp->minute, &pp->second) != 8) + pp->leap = LEAP_NOTINSYNC; + else + pp->leap = LEAP_NOWARNING; + up->second = (up->second + up->decim) % 60; + if (pp->second != up->second) + up->errflg |= IRIG_ERR_CHECK; + up->second = pp->second; + sprintf(pp->a_lastcode, + "%02x %c %2d %3d %02d:%02d:%02d %4.0f %3d %6.3f %2d %2d %6.3f %6.1f %s", + up->errflg, syncchar, pp->year, pp->day, + pp->hour, pp->minute, pp->second, + up->maxsignal, info.record.gain, up->modndx, + up->envxing, up->tc, up->yxing, up->freq * + 1e6 / SAMPLES, ulfptoa(&up->montime, 6)); + pp->lencode = strlen(pp->a_lastcode); + if (up->timecnt == 0 || pp->sloppyclockflag & + CLK_FLAG4) + record_clock_stats(&peer->srcadr, + pp->a_lastcode); +#ifdef DEBUG + if (debug > 2) + printf("irig: %s\n", pp->a_lastcode); +#endif /* DEBUG */ + } + } + up->lastbit = bit; +} + + +/* + * irig_poll - called by the transmit procedure + * + * This routine keeps track of status. If nothing is heard for two + * successive poll intervals, a timeout event is declared and any + * orphaned timecode updates are sent to foster care. + */ +static void +irig_poll( + int unit, /* instance number (not used) */ + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + struct irigunit *up; + + pp = peer->procptr; + up = (struct irigunit *)pp->unitptr; + + /* + * Keep book for tattletales + */ + if (up->pollcnt == 0) { + refclock_report(peer, CEVNT_TIMEOUT); + up->timecnt = 0; + return; + } + up->pollcnt--; + pp->polls++; + +} + + +/* + * irig_gain - adjust codec gain + * + * This routine is called once each second. If the signal envelope + * amplitude is too low, the codec gain is bumped up by four units; if + * too high, it is bumped down. The decoder is relatively insensitive to + * amplitude, so this crudity works just fine. The input port is set and + * the error flag is cleared, mostly to be ornery. + */ +static void +irig_gain( + struct peer *peer /* peer structure pointer */ + ) +{ + struct refclockproc *pp; + struct irigunit *up; + + pp = peer->procptr; + up = (struct irigunit *)pp->unitptr; + + /* + * Apparently, the codec uses only the high order bits of the + * gain control field. Thus, it may take awhile for changes to + * wiggle the hardware bits. Set the new bits in the structure + * and call AUDIO_SETINFO. Upon return, the old bits are in the + * structure. + */ + if (up->clipcnt == 0) { + up->gain += 4; + if (up->gain > AUDIO_MAX_GAIN) + up->gain = AUDIO_MAX_GAIN; + } else if (up->clipcnt > SAMPLES / 100) { + up->gain -= 4; + if (up->gain < AUDIO_MIN_GAIN) + up->gain = AUDIO_MIN_GAIN; + } + AUDIO_INITINFO(&info); + info.record.port = up->port; + info.record.gain = up->gain; + info.record.error = 0; + ioctl(irig_ctl_fd, (int)AUDIO_SETINFO, &info); + if (info.record.error) + up->errflg |= IRIG_ERR_ERROR; +} + + +/* + * irig_audio - initialize audio device + * + * This code works with SunOS 4.1.3 and Solaris 2.6; however, it is + * believed generic and applicable to other systems with a minor twid + * or two. All it does is open the device, set the buffer size (Solaris + * only), preset the gain and set the input port. It assumes that the + * codec sample rate (8000 Hz), precision (8 bits), number of channels + * (1) and encoding (ITU-T G.711 mu-law companded) have been set by + * default. + */ +static int +irig_audio( + ) +{ + /* + * Open audio control device + */ + if ((irig_ctl_fd = open("/dev/audioctl", O_RDWR)) < 0) { + perror("audioctl"); + return(-1); + } +#ifdef HAVE_SYS_AUDIOIO_H + /* + * Set audio device parameters. + */ + AUDIO_INITINFO(&info); + info.record.buffer_size = AUDIO_BUFSIZ; + if (ioctl(irig_ctl_fd, (int)AUDIO_SETINFO, &info) < 0) { + perror("AUDIO_SETINFO"); + close(irig_ctl_fd); + return(-1); + } +#endif /* HAVE_SYS_AUDIOIO_H */ +#ifdef DEBUG + irig_debug(); +#endif /* DEBUG */ + return(0); +} + + +#ifdef DEBUG +/* + * irig_debug - display audio parameters + * + * This code doesn't really do anything, except satisfy curiousity and + * verify the ioctl's work. + */ +static void +irig_debug( + ) +{ + if (debug == 0) + return; +#ifdef HAVE_SYS_AUDIOIO_H + ioctl(irig_ctl_fd, (int)AUDIO_GETDEV, &device); + printf("irig: name %s, version %s, config %s\n", + device.name, device.version, device.config); +#endif /* HAVE_SYS_AUDIOIO_H */ + ioctl(irig_ctl_fd, (int)AUDIO_GETINFO, &info); + printf( + "irig: samples %d, channels %d, precision %d, encoding %d\n", + info.record.sample_rate, info.record.channels, + info.record.precision, info.record.encoding); +#ifdef HAVE_SYS_AUDIOIO_H + printf("irig: gain %d, port %d, buffer %d\n", + info.record.gain, info.record.port, + info.record.buffer_size); +#else /* HAVE_SYS_AUDIOIO_H */ + printf("irig: gain %d, port %d\n", + info.record.gain, info.record.port); +#endif /* HAVE_SYS_AUDIOIO_H */ + printf( + "irig: samples %d, eof %d, pause %d, error %d, waiting %d, balance %d\n", + info.record.samples, info.record.eof, + info.record.pause, info.record.error, + info.record.waiting, info.record.balance); +#ifdef __NetBSD__ + printf("irig: monitor %d, blocksize %d, hiwat %d, lowat %d, mode %d\n", + info.monitor_gain, info.blocksize, info.hiwat, info.lowat, info.mode); +#else /* __NetBSD__ */ + printf("irig: monitor %d, muted %d\n", + info.monitor_gain, info.output_muted); +#endif /* __NetBSD__ */ +} +#endif /* DEBUG */ + +#else +int refclock_irig_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_jupiter.c b/contrib/ntp/ntpd/refclock_jupiter.c new file mode 100644 index 000000000000..f22714bdf792 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_jupiter.c @@ -0,0 +1,1262 @@ +/* + * Copyright (c) 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * 4. The name of the University may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_JUPITER) && defined(PPS) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" +#include "ntp_calendar.h" + +#include "jupiter.h" + +#include + +#ifdef XNTP_BIG_ENDIAN +#define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) +#define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) +#else +#define getshort(s) (s) +#define putshort(s) (s) +#endif + +/* XXX */ +#ifdef sun +char *strerror(int); +#endif + +/* + * This driver supports the Rockwell Jupiter GPS Receiver board + * adapted to precision timing applications. It requires the + * ppsclock line discipline or streams module described in the + * Line Disciplines and Streams Drivers page. It also requires a + * gadget box and 1-PPS level converter, such as described in the + * Pulse-per-second (PPS) Signal Interfacing page. + * + * It may work (with minor modifications) with other Rockwell GPS + * receivers such as the CityTracker. + */ + +/* + * GPS Definitions + */ +#define DEVICE "/dev/gps%d" /* device name and unit */ +#define SPEED232 B9600 /* baud */ + +/* + * The number of raw samples which we acquire to derive a single estimate. + * NSAMPLES ideally should not exceed the default poll interval 64. + * NKEEP must be a power of 2 to simplify the averaging process. + */ +#define NSAMPLES 64 +#define NKEEP 8 +#define REFCLOCKMAXDISPERSE .25 /* max sample dispersion */ + +/* + * Radio interface parameters + */ +#define PRECISION (-18) /* precision assumed (about 4 us) */ +#define REFID "GPS\0" /* reference id */ +#define DESCRIPTION "Rockwell Jupiter GPS Receiver" /* who we are */ +#define DEFFUDGETIME 0 /* default fudge time (ms) */ + +/* Unix timestamp for the GPS epoch: January 6, 1980 */ +#define GPS_EPOCH 315964800 + +/* Double short to unsigned int */ +#define DS2UI(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) + +/* Double short to signed int */ +#define DS2I(p) ((getshort((p)[1]) << 16) | getshort((p)[0])) + +/* One week's worth of seconds */ +#define WEEKSECS (7 * 24 * 60 * 60) + +/* + * Jupiter unit control structure. + */ +struct jupiterunit { + u_int pollcnt; /* poll message counter */ + u_int polled; /* Hand in a time sample? */ + u_int lastserial; /* last pps serial number */ + struct ppsclockev ppsev; /* PPS control structure */ + u_int gweek; /* current GPS week number */ + u_int32 lastsweek; /* last seconds into GPS week */ + u_int32 timecode; /* current ntp timecode */ + u_int32 stime; /* used to detect firmware bug */ + int wantid; /* don't reconfig on channel id msg */ + u_int moving; /* mobile platform? */ + u_long sloppyclockflag; /* fudge flags */ + u_int known; /* position known yet? */ + int coderecv; /* total received samples */ + int nkeep; /* number of samples to preserve */ + int rshift; /* number of rshifts for division */ + l_fp filter[NSAMPLES]; /* offset filter */ + l_fp lastref; /* last reference timestamp */ + u_short sbuf[512]; /* local input buffer */ + int ssize; /* space used in sbuf */ +}; + +/* + * Function prototypes + */ +static void jupiter_canmsg P((struct peer *, u_int)); +static u_short jupiter_cksum P((u_short *, u_int)); +#ifdef QSORT_USES_VOID_P + int jupiter_cmpl_fp P((const void *, const void *)); +#else + int jupiter_cmpl_fp P((const l_fp *, const l_fp *)); +#endif /* not QSORT_USES_VOID_P */ +static void jupiter_config P((struct peer *)); +static void jupiter_debug P((struct peer *, char *, ...)) + __attribute__ ((format (printf, 2, 3))); +static char * jupiter_offset P((struct peer *)); +static char * jupiter_parse_t P((struct peer *, u_short *)); +static void jupiter_platform P((struct peer *, u_int)); +static void jupiter_poll P((int, struct peer *)); +static int jupiter_pps P((struct peer *)); +static char * jupiter_process P((struct peer *)); +static int jupiter_recv P((struct peer *)); +static void jupiter_receive P((register struct recvbuf *rbufp)); +static void jupiter_reqmsg P((struct peer *, u_int, u_int)); +static void jupiter_reqonemsg P((struct peer *, u_int)); +static char * jupiter_send P((struct peer *, struct jheader *)); +static void jupiter_shutdown P((int, struct peer *)); +static int jupiter_start P((int, struct peer *)); +static int jupiter_ttyinit P((struct peer *, int)); + +/* + * Transfer vector + */ +struct refclock refclock_jupiter = { + jupiter_start, /* start up driver */ + jupiter_shutdown, /* shut down driver */ + jupiter_poll, /* transmit poll message */ + noentry, /* (clock control) */ + noentry, /* (clock init) */ + noentry, /* (clock buginfo) */ + NOFLAGS /* not used */ +}; + +/* + * jupiter_start - open the devices and initialize data for processing + */ +static int +jupiter_start( + register int unit, + register struct peer *peer + ) +{ + struct refclockproc *pp; + register struct jupiterunit *up; + register int fd; + char gpsdev[20]; + + /* + * Open serial port + */ + (void)sprintf(gpsdev, DEVICE, unit); + fd = open(gpsdev, O_RDWR +#ifdef O_NONBLOCK + | O_NONBLOCK +#endif + , 0); + if (fd < 0) { + jupiter_debug(peer, "jupiter_start: open %s: %s\n", + gpsdev, strerror(errno)); + return (0); + } + if (!jupiter_ttyinit(peer, fd)) + return (0); + + /* Allocate unit structure */ + if ((up = (struct jupiterunit *) + emalloc(sizeof(struct jupiterunit))) == NULL) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct jupiterunit)); + pp = peer->procptr; + pp->io.clock_recv = jupiter_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + + + /* Ensure the receiver is properly configured */ + jupiter_config(peer); + + /* Turn on pulse gathering by requesting the first sample */ + if (ioctl(fd, CIOGETEV, (caddr_t)&up->ppsev) < 0) { + jupiter_debug(peer, "jupiter_ttyinit: CIOGETEV: %s\n", + strerror(errno)); + (void) close(fd); + free(up); + return (0); + } + up->lastserial = up->ppsev.serial; + memset(&up->ppsev, 0, sizeof(up->ppsev)); + return (1); +} + +/* + * jupiter_shutdown - shut down the clock + */ +static void +jupiter_shutdown(register int unit, register struct peer *peer) +{ + register struct jupiterunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct jupiterunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + +/* + * jupiter_config - Configure the receiver + */ +static void +jupiter_config(register struct peer *peer) +{ + register int i; + register struct jupiterunit *up; + register struct refclockproc *pp; + + pp = peer->procptr; + up = (struct jupiterunit *)pp->unitptr; + + /* + * Initialize the unit variables + * + * STRANGE BEHAVIOUR WARNING: The fudge flags are not available + * at the time jupiter_start is called. These are set later, + * and so the code must be prepared to handle changing flags. + */ + up->sloppyclockflag = pp->sloppyclockflag; + if (pp->sloppyclockflag & CLK_FLAG2) { + up->moving = 1; /* Receiver on mobile platform */ + msyslog(LOG_DEBUG, "jupiter_config: mobile platform"); + } else { + up->moving = 0; /* Static Installation */ + } + + /* XXX fludge flags don't make the trip from the config to here... */ +#ifdef notdef + /* Configure for trailing edge triggers */ +#ifdef CIOSETTET + i = ((pp->sloppyclockflag & CLK_FLAG3) != 0); + jupiter_debug(peer, "jupiter_configure: (sloppyclockflag 0x%lx)\n", + pp->sloppyclockflag); + if (ioctl(pp->io.fd, CIOSETTET, (char *)&i) < 0) + msyslog(LOG_DEBUG, "jupiter_configure: CIOSETTET %d: %m", i); +#else + if (pp->sloppyclockflag & CLK_FLAG3) + msyslog(LOG_DEBUG, "jupiter_configure: \ +No kernel support for trailing edge trigger"); +#endif +#endif + + up->pollcnt = 2; + up->polled = 0; + up->known = 0; + up->gweek = 0; + up->lastsweek = 2 * WEEKSECS; + up->timecode = 0; + up->stime = 0; + up->ssize = 0; + up->coderecv = 0; + up->nkeep = NKEEP; + if (up->nkeep > NSAMPLES) + up->nkeep = NSAMPLES; + if (up->nkeep >= 1) + up->rshift = 0; + if (up->nkeep >= 2) + up->rshift = 1; + if (up->nkeep >= 4) + up->rshift = 2; + if (up->nkeep >= 8) + up->rshift = 3; + if (up->nkeep >= 16) + up->rshift = 4; + if (up->nkeep >= 32) + up->rshift = 5; + if (up->nkeep >= 64) + up->rshift = 6; + up->nkeep = 1; + i = up->rshift; + while (i > 0) { + up->nkeep *= 2; + i--; + } + + /* Stop outputting all messages */ + jupiter_canmsg(peer, JUPITER_ALL); + + /* Request the receiver id so we can syslog the firmware version */ + jupiter_reqonemsg(peer, JUPITER_O_ID); + + /* Flag that this the id was requested (so we don't get called again) */ + up->wantid = 1; + + /* Request perodic time mark pulse messages */ + jupiter_reqmsg(peer, JUPITER_O_PULSE, 1); + + /* Set application platform type */ + if (up->moving) + jupiter_platform(peer, JUPITER_I_PLAT_MED); + else + jupiter_platform(peer, JUPITER_I_PLAT_LOW); +} + +/* + * jupiter_poll - jupiter watchdog routine + */ +static void +jupiter_poll(register int unit, register struct peer *peer) +{ + register struct jupiterunit *up; + register struct refclockproc *pp; + + pp = peer->procptr; + up = (struct jupiterunit *)pp->unitptr; + + /* + * You don't need to poll this clock. It puts out timecodes + * once per second. If asked for a timestamp, take note. + * The next time a timecode comes in, it will be fed back. + */ + + /* + * If we haven't had a response in a while, reset the receiver. + */ + if (up->pollcnt > 0) { + up->pollcnt--; + } else { + refclock_report(peer, CEVNT_TIMEOUT); + + /* Request the receiver id to trigger a reconfig */ + jupiter_reqonemsg(peer, JUPITER_O_ID); + up->wantid = 0; + } + + /* + * polled every 64 seconds. Ask jupiter_receive to hand in + * a timestamp. + */ + up->polled = 1; + pp->polls++; +} + +/* + * jupiter_receive - receive gps data + * Gag me! + */ +static void +jupiter_receive(register struct recvbuf *rbufp) +{ + register int bpcnt, cc, size, ppsret; + register u_int32 last_timecode, laststime; + register char *cp; + register u_char *bp; + register u_short *sp; + register u_long sloppyclockflag; + register struct jupiterunit *up; + register struct jid *ip; + register struct jheader *hp; + register struct refclockproc *pp; + register struct peer *peer; + + /* Initialize pointers and read the timecode and timestamp */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct jupiterunit *)pp->unitptr; + + /* + * If operating mode has been changed, then reinitialize the receiver + * before doing anything else. + */ +/* XXX Sloppy clock flags are broken!! */ + sloppyclockflag = up->sloppyclockflag; + up->sloppyclockflag = pp->sloppyclockflag; + if ((pp->sloppyclockflag & CLK_FLAG2) != + (sloppyclockflag & CLK_FLAG2)) { + jupiter_debug(peer, + "jupiter_receive: mode switch: reset receiver\n"); + jupiter_config(peer); + return; + } + + up->pollcnt = 2; + + bp = (u_char *)rbufp->recv_buffer; + bpcnt = rbufp->recv_length; + + /* This shouldn't happen */ + if (bpcnt > sizeof(up->sbuf) - up->ssize) + bpcnt = sizeof(up->sbuf) - up->ssize; + + /* Append to input buffer */ + memcpy((u_char *)up->sbuf + up->ssize, bp, bpcnt); + up->ssize += bpcnt; + + /* While there's at least a header and we parse a intact message */ + while (up->ssize > sizeof(*hp) && (cc = jupiter_recv(peer)) > 0) { + hp = (struct jheader *)up->sbuf; + sp = (u_short *)(hp + 1); + size = cc - sizeof(*hp); + switch (getshort(hp->id)) { + + case JUPITER_O_PULSE: + if (size != sizeof(struct jpulse)) { + jupiter_debug(peer, + "jupiter_receive: pulse: len %d != %u\n", + size, (int)sizeof(struct jpulse)); + refclock_report(peer, CEVNT_BADREPLY); + break; + } + + /* + * There appears to be a firmware bug related + * to the pulse message; in addition to the one + * per second messages, we get an extra pulse + * message once an hour (on the anniversary of + * the cold start). It seems to come 200 ms + * after the one requested. So if we've seen a + * pulse message in the last 210 ms, we skip + * this one. + */ + laststime = up->stime; + up->stime = DS2UI(((struct jpulse *)sp)->stime); + if (laststime != 0 && up->stime - laststime <= 21) { + jupiter_debug(peer, "jupiter_receive: \ +avoided firmware bug (stime %.2f, laststime %.2f)\n", + (double)up->stime * 0.01, (double)laststime * 0.01); + break; + } + + /* Retrieve pps timestamp */ + ppsret = jupiter_pps(peer); + + /* Parse timecode (even when there's no pps) */ + last_timecode = up->timecode; + if ((cp = jupiter_parse_t(peer, sp)) != NULL) { + jupiter_debug(peer, + "jupiter_receive: pulse: %s\n", cp); + break; + } + + /* Bail if we didn't get a pps timestamp */ + if (ppsret) + break; + + /* Bail if we don't have the last timecode yet */ + if (last_timecode == 0) + break; + + /* Add the new sample to a median filter */ + if ((cp = jupiter_offset(peer)) != NULL) { + jupiter_debug(peer, + "jupiter_receive: offset: %s\n", cp); + refclock_report(peer, CEVNT_BADTIME); + break; + } + + /* + * The clock will blurt a timecode every second + * but we only want one when polled. If we + * havn't been polled, bail out. + */ + if (!up->polled) + break; + + /* + * It's a live one! Remember this time. + */ + pp->lasttime = current_time; + + /* + * Determine the reference clock offset and + * dispersion. NKEEP of NSAMPLE offsets are + * passed through a median filter. + * Save the (filtered) offset and dispersion in + * pp->offset and pp->disp. + */ + if ((cp = jupiter_process(peer)) != NULL) { + jupiter_debug(peer, + "jupiter_receive: process: %s\n", cp); + refclock_report(peer, CEVNT_BADTIME); + break; + } + /* + * Return offset and dispersion to control + * module. We use lastrec as both the reference + * time and receive time in order to avoid + * being cute, like setting the reference time + * later than the receive time, which may cause + * a paranoid protocol module to chuck out the + * data. + */ + jupiter_debug(peer, + "jupiter_receive: process time: \ +%4d-%03d %02d:%02d:%02d at %s, %s\n", + pp->year, pp->day, + pp->hour, pp->minute, pp->second, + prettydate(&pp->lastrec), lfptoa(&pp->offset, 6)); + + refclock_receive(peer); + + /* + * We have succeeded in answering the poll. + * Turn off the flag and return + */ + up->polled = 0; + break; + + case JUPITER_O_ID: + if (size != sizeof(struct jid)) { + jupiter_debug(peer, + "jupiter_receive: id: len %d != %u\n", + size, (int)sizeof(struct jid)); + refclock_report(peer, CEVNT_BADREPLY); + break; + } + /* + * If we got this message because the Jupiter + * just powered up, it needs to be reconfigured. + */ + ip = (struct jid *)sp; + jupiter_debug(peer, + "jupiter_receive: >> %s chan ver %s, %s (%s)\n", + ip->chans, ip->vers, ip->date, ip->opts); + msyslog(LOG_DEBUG, + "jupiter_receive: %s chan ver %s, %s (%s)\n", + ip->chans, ip->vers, ip->date, ip->opts); + if (up->wantid) + up->wantid = 0; + else { + jupiter_debug(peer, + "jupiter_receive: reset receiver\n"); + jupiter_config(peer); + /* Rese since jupiter_config() just zeroed it */ + up->ssize = cc; + } + break; + + default: + jupiter_debug(peer, + "jupiter_receive: >> unknown message id %d\n", + getshort(hp->id)); + break; + } + up->ssize -= cc; + if (up->ssize < 0) { + fprintf(stderr, "jupiter_recv: negative ssize!\n"); + abort(); + } else if (up->ssize > 0) + memcpy(up->sbuf, (u_char *)up->sbuf + cc, up->ssize); + } + record_clock_stats(&peer->srcadr, ""); +} + +/* + * jupiter_offset - Calculate the offset, and add to the rolling filter. + */ +static char * +jupiter_offset(register struct peer *peer) +{ + register struct jupiterunit *up; + register struct refclockproc *pp; + register int i; + l_fp offset; + + pp = peer->procptr; + up = (struct jupiterunit *)pp->unitptr; + + /* + * Calculate the offset + */ + if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, + pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) { + return ("jupiter_process: clocktime failed"); + } + if (pp->usec) { + TVUTOTSF(pp->usec, offset.l_uf); + } else { + MSUTOTSF(pp->msec, offset.l_uf); + } + L_ADD(&offset, &pp->fudgetime1); + up->lastref = offset; /* save last reference time */ + L_SUB(&offset, &pp->lastrec); /* form true offset */ + + /* + * A rolling filter. Initialize first time around. + */ + i = ((up->coderecv)) % NSAMPLES; + + up->filter[i] = offset; + if (up->coderecv == 0) + for (i = 1; (u_int) i < NSAMPLES; i++) + up->filter[i] = up->filter[0]; + up->coderecv++; + + return (NULL); +} + +/* + * jupiter_process - process the sample from the clock, + * passing it through a median filter and optionally averaging + * the samples. Returns offset and dispersion in "up" structure. + */ +static char * +jupiter_process(register struct peer *peer) +{ + register struct jupiterunit *up; + register struct refclockproc *pp; + register int i, n; + register int j, k; + l_fp offset, median, lftmp; + u_fp disp; + l_fp off[NSAMPLES]; + + pp = peer->procptr; + up = (struct jupiterunit *)pp->unitptr; + + /* + * Copy the raw offsets and sort into ascending order + */ + for (i = 0; i < NSAMPLES; i++) + off[i] = up->filter[i]; + qsort((char *)off, NSAMPLES, sizeof(l_fp), jupiter_cmpl_fp); + + /* + * Reject the furthest from the median of NSAMPLES samples until + * NKEEP samples remain. + */ + i = 0; + n = NSAMPLES; + while ((n - i) > up->nkeep) { + lftmp = off[n - 1]; + median = off[(n + i) / 2]; + L_SUB(&lftmp, &median); + L_SUB(&median, &off[i]); + if (L_ISHIS(&median, &lftmp)) { + /* reject low end */ + i++; + } else { + /* reject high end */ + n--; + } + } + + /* + * Copy key values to the billboard to measure performance. + */ + pp->lastref = up->lastref; + pp->coderecv = up->coderecv; + pp->filter[0] = off[0]; /* smallest offset */ + pp->filter[1] = off[NSAMPLES-1]; /* largest offset */ + for (j = 2, k = i; k < n; j++, k++) + pp->filter[j] = off[k]; /* offsets actually examined */ + + /* + * Compute the dispersion based on the difference between the + * extremes of the remaining offsets. Add to this the time since + * the last clock update, which represents the dispersion + * increase with time. We know that NTP_MAXSKEW is 16. If the + * sum is greater than the allowed sample dispersion, bail out. + * If the loop is unlocked, return the most recent offset; + * otherwise, return the median offset. + */ + lftmp = off[n - 1]; + L_SUB(&lftmp, &off[i]); + disp = LFPTOFP(&lftmp); + if (disp > REFCLOCKMAXDISPERSE) + return ("Maximum dispersion exceeded"); + + /* + * Now compute the offset estimate. If fudge flag 1 + * is set, average the remainder, otherwise pick the + * median. + */ + if (pp->sloppyclockflag & CLK_FLAG1) { + L_CLR(&lftmp); + while (i < n) { + L_ADD(&lftmp, &off[i]); + i++; + } + i = up->rshift; + while (i > 0) { + L_RSHIFT(&lftmp); + i--; + } + offset = lftmp; + } else { + i = (n + i) / 2; + offset = off[i]; + } + + /* + * The payload: filtered offset and dispersion. + */ + + pp->offset = offset; + pp->disp = disp; + + return (NULL); + +} + +/* Compare two l_fp's, used with qsort() */ +int +#ifdef QSORT_USES_VOID_P +jupiter_cmpl_fp(register const void *p1, register const void *p2) +#else +jupiter_cmpl_fp(register const l_fp *fp1, register const l_fp *fp2) +#endif +{ +#ifdef QSORT_USES_VOID_P + register const l_fp *fp1 = (const l_fp *)p1; + register const l_fp *fp2 = (const l_fp *)p2; +#endif + + if (!L_ISGEQ(fp1, fp2)) + return (-1); + if (L_ISEQU(fp1, fp2)) + return (0); + return (1); +} + +static char * +jupiter_parse_t(register struct peer *peer, register u_short *sp) +{ + register struct refclockproc *pp; + register struct jupiterunit *up; + register struct tm *tm; + register char *cp; + register struct jpulse *jp; + register struct calendar *jt; + register u_int32 sweek; + register u_int32 last_timecode; + register u_short flags; + time_t t; + struct calendar cal; + + pp = peer->procptr; + up = (struct jupiterunit *)pp->unitptr; + jp = (struct jpulse *)sp; + + /* The timecode is presented as seconds into the current GPS week */ + sweek = DS2UI(jp->sweek); + + /* + * If we don't know the current GPS week, calculate it from the + * current time. (It's too bad they didn't include this + * important value in the pulse message). We'd like to pick it + * up from one of the other messages like gpos or chan but they + * don't appear to be synchronous with time keeping and changes + * too soon (something like 10 seconds before the new GPS + * week). + * + * If we already know the current GPS week, increment it when + * we wrap into a new week. + */ + if (up->gweek == 0) + up->gweek = (time(NULL) - GPS_EPOCH) / WEEKSECS; + else if (sweek == 0 && up->lastsweek == WEEKSECS - 1) { + ++up->gweek; + jupiter_debug(peer, + "jupiter_parse_t: NEW gps week %u\n", up->gweek); + } + + /* + * See if the sweek stayed the same (this happens when there is + * no pps pulse). + * + * Otherwise, look for time warps: + * + * - we have stored at least one lastsweek and + * - the sweek didn't increase by one and + * - we didn't wrap to a new GPS week + * + * Then we warped. + */ + if (up->lastsweek == sweek) + jupiter_debug(peer, + "jupiter_parse_t: gps sweek not incrementing (%d)\n", + sweek); + else if (up->lastsweek != 2 * WEEKSECS && + up->lastsweek + 1 != sweek && + !(sweek == 0 && up->lastsweek == WEEKSECS - 1)) + jupiter_debug(peer, + "jupiter_parse_t: gps sweek jumped (was %d, now %d)\n", + up->lastsweek, sweek); + up->lastsweek = sweek; + + /* This timecode describes next pulse */ + last_timecode = up->timecode; + up->timecode = (u_int32)JAN_1970 + + GPS_EPOCH + (up->gweek * WEEKSECS) + sweek; + + if (last_timecode == 0) + /* XXX debugging */ + jupiter_debug(peer, + "jupiter_parse_t: UTC (gweek/sweek %u/%u)\n", + up->gweek, sweek); + else { + /* XXX debugging */ + t = last_timecode - (u_int32)JAN_1970; + tm = gmtime(&t); + cp = asctime(tm); + + jupiter_debug(peer, + "jupiter_parse_t: UTC %.24s (gweek/sweek %u/%u)\n", + cp, up->gweek, sweek); + + /* Billboard last_timecode (which is now the current time) */ + jt = &cal; + caljulian(last_timecode, jt); + pp = peer->procptr; + pp->year = jt->year; + pp->day = jt->yearday; + pp->hour = jt->hour; + pp->minute = jt->minute; + pp->second = jt->second; + pp->msec = 0; + pp->usec = 0; + } + + /* XXX debugging */ + tm = gmtime(&up->ppsev.tv.tv_sec); + cp = asctime(tm); + flags = getshort(jp->flags); + jupiter_debug(peer, + "jupiter_parse_t: PPS %.19s.%06lu %.4s (serial %u)%s\n", + cp, up->ppsev.tv.tv_usec, cp + 20, up->ppsev.serial, + (flags & JUPITER_O_PULSE_VALID) == 0 ? + " NOT VALID" : ""); + + /* Toss if not designated "valid" by the gps */ + if ((flags & JUPITER_O_PULSE_VALID) == 0) { + refclock_report(peer, CEVNT_BADTIME); + return ("time mark not valid"); + } + + /* We better be sync'ed to UTC... */ + if ((flags & JUPITER_O_PULSE_UTC) == 0) { + refclock_report(peer, CEVNT_BADTIME); + return ("time mark not sync'ed to UTC"); + } + + return (NULL); +} + +/* + * Process a PPS signal, returning a timestamp. + */ +static int +jupiter_pps(register struct peer *peer) +{ + register struct refclockproc *pp; + register struct jupiterunit *up; + register int firsttime; + struct timeval ntp_tv; + + pp = peer->procptr; + up = (struct jupiterunit *)pp->unitptr; + + /* + * Grab the timestamp of the PPS signal. + */ + firsttime = (up->ppsev.tv.tv_sec == 0); + if (ioctl(pp->io.fd, CIOGETEV, (caddr_t)&up->ppsev) < 0) { + /* XXX Actually, if this fails, we're pretty much screwed */ + jupiter_debug(peer, "jupiter_pps: CIOGETEV: %s\n", + strerror(errno)); + refclock_report(peer, CEVNT_FAULT); + return (1); + } + + /* + * Check pps serial number against last one + */ + if (!firsttime && up->lastserial + 1 != up->ppsev.serial) { + if (up->ppsev.serial == up->lastserial) + jupiter_debug(peer, "jupiter_pps: no new pps event\n"); + else + jupiter_debug(peer, + "jupiter_pps: missed %d pps events\n", + up->ppsev.serial - up->lastserial - 1); + up->lastserial = up->ppsev.serial; + refclock_report(peer, CEVNT_FAULT); + return (1); + } + up->lastserial = up->ppsev.serial; + + /* + * Return the timestamp in pp->lastrec + */ + ntp_tv = up->ppsev.tv; + ntp_tv.tv_sec += (u_int32)JAN_1970; + TVTOTS(&ntp_tv, &pp->lastrec); + + return (0); +} + +/* + * jupiter_debug - print debug messages + */ +#if __STDC__ +static void +jupiter_debug(struct peer *peer, char *fmt, ...) +#else +static void +jupiter_debug(peer, fmt, va_alist) + struct peer *peer; + char *fmt; +#endif +{ + va_list ap; + + if (debug) { + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + /* + * Print debug message to stdout + * In the future, we may want to get get more creative... + */ + vfprintf(stderr, fmt, ap); + + va_end(ap); + } +} + +/* Checksum and transmit a message to the Jupiter */ +static char * +jupiter_send(register struct peer *peer, register struct jheader *hp) +{ + register u_int len, size; + register int cc; + register u_short *sp; + static char errstr[132]; + + size = sizeof(*hp); + hp->hsum = putshort(jupiter_cksum((u_short *)hp, + (size / sizeof(u_short)) - 1)); + len = getshort(hp->len); + if (len > 0) { + sp = (u_short *)(hp + 1); + sp[len] = putshort(jupiter_cksum(sp, len)); + size += (len + 1) * sizeof(u_short); + } + + if ((cc = write(peer->procptr->io.fd, (char *)hp, size)) < 0) { + (void)sprintf(errstr, "write: %s", strerror(errno)); + return (errstr); + } else if (cc != size) { + (void)sprintf(errstr, "short write (%d != %d)", cc, size); + return (errstr); + } + return (NULL); +} + +/* Request periodic message output */ +static struct { + struct jheader jheader; + struct jrequest jrequest; +} reqmsg = { + { putshort(JUPITER_SYNC), 0, + putshort((sizeof(struct jrequest) / sizeof(u_short)) - 1), + 0, putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | + JUPITER_FLAG_CONN | JUPITER_FLAG_LOG), 0 }, + { 0, 0, 0, 0 } +}; + +/* An interval of zero means to output on trigger */ +static void +jupiter_reqmsg(register struct peer *peer, register u_int id, + register u_int interval) +{ + register struct jheader *hp; + register struct jrequest *rp; + register char *cp; + + hp = &reqmsg.jheader; + hp->id = putshort(id); + rp = &reqmsg.jrequest; + rp->trigger = putshort(interval == 0); + rp->interval = putshort(interval); + if ((cp = jupiter_send(peer, hp)) != NULL) + jupiter_debug(peer, "jupiter_reqmsg: %u: %s\n", id, cp); +} + +/* Cancel periodic message output */ +static struct jheader canmsg = { + putshort(JUPITER_SYNC), 0, 0, 0, + putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_DISC), + 0 +}; + +static void +jupiter_canmsg(register struct peer *peer, register u_int id) +{ + register struct jheader *hp; + register char *cp; + + hp = &canmsg; + hp->id = putshort(id); + if ((cp = jupiter_send(peer, hp)) != NULL) + jupiter_debug(peer, "jupiter_canmsg: %u: %s\n", id, cp); +} + +/* Request a single message output */ +static struct jheader reqonemsg = { + putshort(JUPITER_SYNC), 0, 0, 0, + putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK | JUPITER_FLAG_QUERY), + 0 +}; + +static void +jupiter_reqonemsg(register struct peer *peer, register u_int id) +{ + register struct jheader *hp; + register char *cp; + + hp = &reqonemsg; + hp->id = putshort(id); + if ((cp = jupiter_send(peer, hp)) != NULL) + jupiter_debug(peer, "jupiter_reqonemsg: %u: %s\n", id, cp); +} + +/* Set the platform dynamics */ +static struct { + struct jheader jheader; + struct jplat jplat; +} platmsg = { + { putshort(JUPITER_SYNC), putshort(JUPITER_I_PLAT), + putshort((sizeof(struct jplat) / sizeof(u_short)) - 1), 0, + putshort(JUPITER_FLAG_REQUEST | JUPITER_FLAG_NAK), 0 }, + { 0, 0, 0 } +}; + +static void +jupiter_platform(register struct peer *peer, register u_int platform) +{ + register struct jheader *hp; + register struct jplat *pp; + register char *cp; + + hp = &platmsg.jheader; + pp = &platmsg.jplat; + pp->platform = putshort(platform); + if ((cp = jupiter_send(peer, hp)) != NULL) + jupiter_debug(peer, "jupiter_platform: %u: %s\n", platform, cp); +} + +/* Checksum "len" shorts */ +static u_short +jupiter_cksum(register u_short *sp, register u_int len) +{ + register u_short sum, x; + + sum = 0; + while (len-- > 0) { + x = *sp++; + sum += getshort(x); + } + return (~sum + 1); +} + +/* Return the size of the next message (or zero if we don't have it all yet) */ +static int +jupiter_recv(register struct peer *peer) +{ + register int n, len, size, cc; + register struct refclockproc *pp; + register struct jupiterunit *up; + register struct jheader *hp; + register u_char *bp; + register u_short *sp; + + pp = peer->procptr; + up = (struct jupiterunit *)pp->unitptr; + + /* Must have at least a header's worth */ + cc = sizeof(*hp); + size = up->ssize; + if (size < cc) + return (0); + + /* Search for the sync short if missing */ + sp = up->sbuf; + hp = (struct jheader *)sp; + if (getshort(hp->sync) != JUPITER_SYNC) { + /* Wasn't at the front, sync up */ + jupiter_debug(peer, "syncing"); + bp = (u_char *)sp; + n = size; + while (n >= 2) { + if (bp[0] != (JUPITER_SYNC & 0xff)) { + jupiter_debug(peer, "{0x%x}", bp[0]); + ++bp; + --n; + continue; + } + if (bp[1] == ((JUPITER_SYNC >> 8) & 0xff)) + break; + jupiter_debug(peer, "{0x%x 0x%x}", bp[0], bp[1]); + bp += 2; + n -= 2; + } + jupiter_debug(peer, "\n"); + /* Shuffle data to front of input buffer */ + if (n > 0) + memcpy(sp, bp, n); + size = n; + up->ssize = size; + if (size < cc || hp->sync != JUPITER_SYNC) + return (0); + } + + if (jupiter_cksum(sp, (cc / sizeof(u_short) - 1)) != + getshort(hp->hsum)) { + jupiter_debug(peer, "jupiter_recv: bad header checksum!\n"); + /* This is drastic but checksum errors should be rare */ + up->ssize = 0; + return (0); + } + + /* Check for a payload */ + len = getshort(hp->len); + if (len > 0) { + n = (len + 1) * sizeof(u_short); + /* Not enough data yet */ + if (size < cc + n) + return (0); + + /* Check payload checksum */ + sp = (u_short *)(hp + 1); + if (jupiter_cksum(sp, len) != getshort(sp[len])) { + jupiter_debug(peer, + "jupiter_recv: bad payload checksum!\n"); + /* This is drastic but checksum errors should be rare */ + up->ssize = 0; + return (0); + } + cc += n; + } + return (cc); +} + +static int +jupiter_ttyinit(register struct peer *peer, register int fd) +{ + struct termios termios; + + memset((char *)&termios, 0, sizeof(termios)); + if (cfsetispeed(&termios, B9600) < 0 || + cfsetospeed(&termios, B9600) < 0) { + jupiter_debug(peer, + "jupiter_ttyinit: cfsetispeed/cfgetospeed: %s\n", + strerror(errno)); + return (0); + } +#ifdef HAVE_CFMAKERAW + cfmakeraw(&termios); +#else + termios.c_iflag &= ~(IMAXBEL | IXOFF | INPCK | BRKINT | PARMRK | + ISTRIP | INLCR | IGNCR | ICRNL | IXON | IGNPAR); + termios.c_iflag |= IGNBRK; + termios.c_oflag &= ~OPOST; + termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON | ISIG | + IEXTEN | NOFLSH | TOSTOP | PENDIN); + termios.c_cflag &= ~(CSIZE | PARENB); + termios.c_cflag |= CS8 | CREAD; + termios.c_cc[VMIN] = 1; +#endif + termios.c_cflag |= CLOCAL; + if (tcsetattr(fd, TCSANOW, &termios) < 0) { + jupiter_debug(peer, "jupiter_ttyinit: tcsetattr: %s\n", + strerror(errno)); + return (0); + } + +#ifdef TIOCSPPS + if (ioctl(fd, TIOCSPPS, (char *)&fdpps) < 0) { + jupiter_debug(peer, "jupiter_ttyinit: TIOCSPPS: %s\n", + strerror(errno)); + return (0); + } +#endif +#ifdef I_PUSH + if (ioctl(fd, I_PUSH, "ppsclock") < 0) { + jupiter_debug(peer, "jupiter_ttyinit: push ppsclock: %s\n", + strerror(errno)); + return (0); + } +#endif + + return (1); +} + +#else /* not (REFCLOCK && CLOCK_JUPITER && PPS) */ +int refclock_jupiter_bs; +#endif /* not (REFCLOCK && CLOCK_JUPITER && PPS) */ diff --git a/contrib/ntp/ntpd/refclock_leitch.c b/contrib/ntp/ntpd/refclock_leitch.c new file mode 100644 index 000000000000..edee3f805cef --- /dev/null +++ b/contrib/ntp/ntpd/refclock_leitch.c @@ -0,0 +1,619 @@ +/* + * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_LEITCH) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" + +#ifdef STREAM +#include +#if defined(LEITCHCLK) +#include +#endif /* LEITCHCLK */ +#endif /* STREAM */ + +#include "ntp_stdlib.h" + + +/* + * Driver for Leitch CSD-5300 Master Clock System + * + * COMMANDS: + * DATE: D + * TIME: T + * STATUS: S + * LOOP: L + * + * FORMAT: + * DATE: YYMMDD + * TIME: /HHMMSS /HHMMSS /HHMMSS / + * second bondaried on the stop bit of the + * second boundaries at '/' above. + * STATUS: G (good), D (diag fail), T (time not provided) or + * P (last phone update failed) + */ +#define MAXUNITS 1 /* max number of LEITCH units */ +#define LEITCHREFID "ATOM" /* reference id */ +#define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver" +#define LEITCH232 "/dev/leitch%d" /* name of radio device */ +#define SPEED232 B300 /* uart speed (300 baud) */ +#define leitch_send(A,M) \ +if (debug) fprintf(stderr,"write leitch %s\n",M); \ +if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\ + if (debug) \ + fprintf(stderr, "leitch_send: unit %d send failed\n", A->unit); \ + else \ + msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);} + +#define STATE_IDLE 0 +#define STATE_DATE 1 +#define STATE_TIME1 2 +#define STATE_TIME2 3 +#define STATE_TIME3 4 + +/* + * LEITCH unit control structure + */ +struct leitchunit { + struct peer *peer; + struct refclockio leitchio; + u_char unit; + short year; + short yearday; + short month; + short day; + short hour; + short second; + short minute; + short state; + u_short fudge1; + l_fp reftime1; + l_fp reftime2; + l_fp reftime3; + l_fp codetime1; + l_fp codetime2; + l_fp codetime3; + u_long yearstart; +}; + +/* + * Function prototypes + */ +static void leitch_init P((void)); +static int leitch_start P((int, struct peer *)); +static void leitch_shutdown P((int, struct peer *)); +static void leitch_poll P((int, struct peer *)); +static void leitch_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); +#define leitch_buginfo noentry +static void leitch_receive P((struct recvbuf *)); +static void leitch_process P((struct leitchunit *)); +#if 0 +static void leitch_timeout P((struct peer *)); +#endif +static int leitch_get_date P((struct recvbuf *, struct leitchunit *)); +static int leitch_get_time P((struct recvbuf *, struct leitchunit *, int)); +static int days_per_year P((int)); + +static struct leitchunit leitchunits[MAXUNITS]; +static u_char unitinuse[MAXUNITS]; +static u_char stratumtouse[MAXUNITS]; +static u_int32 refid[MAXUNITS]; + +static char days_in_month [] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +/* + * Transfer vector + */ +struct refclock refclock_leitch = { + leitch_start, leitch_shutdown, leitch_poll, + leitch_control, leitch_init, leitch_buginfo, NOFLAGS +}; + +/* + * leitch_init - initialize internal leitch driver data + */ +static void +leitch_init(void) +{ + int i; + + memset((char*)leitchunits, 0, sizeof(leitchunits)); + memset((char*)unitinuse, 0, sizeof(unitinuse)); + for (i = 0; i < MAXUNITS; i++) + memcpy((char *)&refid[i], LEITCHREFID, 4); +} + +/* + * leitch_shutdown - shut down a LEITCH clock + */ +static void +leitch_shutdown( + int unit, + struct peer *peer + ) +{ +#ifdef DEBUG + if (debug) + fprintf(stderr, "leitch_shutdown()\n"); +#endif +} + +/* + * leitch_poll - called by the transmit procedure + */ +static void +leitch_poll( + int unit, + struct peer *peer + ) +{ + struct leitchunit *leitch; + + /* start the state machine rolling */ + +#ifdef DEBUG + if (debug) + fprintf(stderr, "leitch_poll()\n"); +#endif + if (unit > MAXUNITS) { + /* XXXX syslog it */ + return; + } + + leitch = &leitchunits[unit]; + + if (leitch->state != STATE_IDLE) { + /* reset and wait for next poll */ + /* XXXX syslog it */ + leitch->state = STATE_IDLE; + } else { + leitch_send(leitch,"D\r"); + leitch->state = STATE_DATE; + } +} + +static void +leitch_control( + int unit, + struct refclockstat *in, + struct refclockstat *out, + struct peer *passed_peer + ) +{ + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, + "leitch_control: unit %d invalid", unit); + return; + } + + if (in) { + if (in->haveflags & CLK_HAVEVAL1) + stratumtouse[unit] = (u_char)(in->fudgeval1); + if (in->haveflags & CLK_HAVEVAL2) + refid[unit] = in->fudgeval2; + if (unitinuse[unit]) { + struct peer *peer; + + peer = (&leitchunits[unit])->peer; + peer->stratum = stratumtouse[unit]; + peer->refid = refid[unit]; + } + } + + if (out) { + memset((char *)out, 0, sizeof (struct refclockstat)); + out->type = REFCLK_ATOM_LEITCH; + out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2; + out->fudgeval1 = (int32)stratumtouse[unit]; + out->fudgeval2 = refid[unit]; + out->p_lastcode = ""; + out->clockdesc = LEITCH_DESCRIPTION; + } +} + +/* + * leitch_start - open the LEITCH devices and initialize data for processing + */ +static int +leitch_start( + int unit, + struct peer *peer + ) +{ + struct leitchunit *leitch; + int fd232; + char leitchdev[20]; + + /* + * Check configuration info. + */ + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, "leitch_start: unit %d invalid", unit); + return (0); + } + + if (unitinuse[unit]) { + msyslog(LOG_ERR, "leitch_start: unit %d in use", unit); + return (0); + } + + /* + * Open serial port. + */ + (void) sprintf(leitchdev, LEITCH232, unit); + fd232 = open(leitchdev, O_RDWR, 0777); + if (fd232 == -1) { + msyslog(LOG_ERR, + "leitch_start: open of %s: %m", leitchdev); + return (0); + } + + leitch = &leitchunits[unit]; + memset((char*)leitch, 0, sizeof(*leitch)); + +#if defined(HAVE_SYSV_TTYS) + /* + * System V serial line parameters (termio interface) + * + */ + { struct termio ttyb; + if (ioctl(fd232, TCGETA, &ttyb) < 0) { + msyslog(LOG_ERR, + "leitch_start: ioctl(%s, TCGETA): %m", leitchdev); + goto screwed; + } + ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL; + ttyb.c_oflag = 0; + ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD; + ttyb.c_lflag = ICANON; + ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0'; + if (ioctl(fd232, TCSETA, &ttyb) < 0) { + msyslog(LOG_ERR, + "leitch_start: ioctl(%s, TCSETA): %m", leitchdev); + goto screwed; + } + } +#endif /* HAVE_SYSV_TTYS */ +#if defined(HAVE_TERMIOS) + /* + * POSIX serial line parameters (termios interface) + * + * The LEITCHCLK option provides timestamping at the driver level. + * It requires the tty_clk streams module. + */ + { struct termios ttyb, *ttyp; + + ttyp = &ttyb; + if (tcgetattr(fd232, ttyp) < 0) { + msyslog(LOG_ERR, + "leitch_start: tcgetattr(%s): %m", leitchdev); + goto screwed; + } + ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL; + ttyp->c_oflag = 0; + ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD; + ttyp->c_lflag = ICANON; + ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; + if (tcsetattr(fd232, TCSANOW, ttyp) < 0) { + msyslog(LOG_ERR, + "leitch_start: tcsetattr(%s): %m", leitchdev); + goto screwed; + } + if (tcflush(fd232, TCIOFLUSH) < 0) { + msyslog(LOG_ERR, + "leitch_start: tcflush(%s): %m", leitchdev); + goto screwed; + } + } +#endif /* HAVE_TERMIOS */ +#ifdef STREAM +#if defined(LEITCHCLK) + if (ioctl(fd232, I_PUSH, "clk") < 0) + msyslog(LOG_ERR, + "leitch_start: ioctl(%s, I_PUSH, clk): %m", leitchdev); + if (ioctl(fd232, CLK_SETSTR, "\n") < 0) + msyslog(LOG_ERR, + "leitch_start: ioctl(%s, CLK_SETSTR): %m", leitchdev); +#endif /* LEITCHCLK */ +#endif /* STREAM */ +#if defined(HAVE_BSD_TTYS) + /* + * 4.3bsd serial line parameters (sgttyb interface) + * + * The LEITCHCLK option provides timestamping at the driver level. + * It requires the tty_clk line discipline and 4.3bsd or later. + */ + { struct sgttyb ttyb; +#if defined(LEITCHCLK) + int ldisc = CLKLDISC; +#endif /* LEITCHCLK */ + + if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { + msyslog(LOG_ERR, + "leitch_start: ioctl(%s, TIOCGETP): %m", leitchdev); + goto screwed; + } + ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; +#if defined(LEITCHCLK) + ttyb.sg_erase = ttyb.sg_kill = '\r'; + ttyb.sg_flags = RAW; +#else + ttyb.sg_erase = ttyb.sg_kill = '\0'; + ttyb.sg_flags = EVENP|ODDP|CRMOD; +#endif /* LEITCHCLK */ + if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { + msyslog(LOG_ERR, + "leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev); + goto screwed; + } +#if defined(LEITCHCLK) + if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { + msyslog(LOG_ERR, + "leitch_start: ioctl(%s, TIOCSETD): %m",leitchdev); + goto screwed; + } +#endif /* LEITCHCLK */ + } +#endif /* HAVE_BSD_TTYS */ + + /* + * Set up the structures + */ + leitch->peer = peer; + leitch->unit = unit; + leitch->state = STATE_IDLE; + leitch->fudge1 = 15; /* 15ms */ + + leitch->leitchio.clock_recv = leitch_receive; + leitch->leitchio.srcclock = (caddr_t) leitch; + leitch->leitchio.datalen = 0; + leitch->leitchio.fd = fd232; + if (!io_addclock(&leitch->leitchio)) { + goto screwed; + } + + /* + * All done. Initialize a few random peer variables, then + * return success. + */ + peer->precision = 0; + peer->stratum = stratumtouse[unit]; + peer->refid = refid[unit]; + unitinuse[unit] = 1; + return(1); + + /* + * Something broke; abandon ship. + */ + screwed: + close(fd232); + return(0); +} + +/* + * leitch_receive - receive data from the serial interface on a leitch + * clock + */ +static void +leitch_receive( + struct recvbuf *rbufp + ) +{ + struct leitchunit *leitch = (struct leitchunit *)rbufp->recv_srcclock; + +#ifdef DEBUG + if (debug) + fprintf(stderr, "leitch_recieve(%*.*s)\n", + rbufp->recv_length, rbufp->recv_length, + rbufp->recv_buffer); +#endif + if (rbufp->recv_length != 7) + return; /* The date is return with a trailing newline, + discard it. */ + + switch (leitch->state) { + case STATE_IDLE: /* unexpected, discard and resync */ + return; + case STATE_DATE: + if (!leitch_get_date(rbufp,leitch)) { + leitch->state = STATE_IDLE; + break; + } + leitch_send(leitch,"T\r"); +#ifdef DEBUG + if (debug) + fprintf(stderr, "%u\n",leitch->yearday); +#endif + leitch->state = STATE_TIME1; + break; + case STATE_TIME1: + if (!leitch_get_time(rbufp,leitch,1)) { + } + if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, + leitch->second, 1, rbufp->recv_time.l_ui, + &leitch->yearstart, &leitch->reftime1.l_ui)) { + leitch->state = STATE_IDLE; + break; + } +#ifdef DEBUG + if (debug) + fprintf(stderr, "%lu\n", (u_long)leitch->reftime1.l_ui); +#endif + MSUTOTSF(leitch->fudge1, leitch->reftime1.l_uf); + leitch->codetime1 = rbufp->recv_time; + leitch->state = STATE_TIME2; + break; + case STATE_TIME2: + if (!leitch_get_time(rbufp,leitch,2)) { + } + if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, + leitch->second, 1, rbufp->recv_time.l_ui, + &leitch->yearstart, &leitch->reftime2.l_ui)) { + leitch->state = STATE_IDLE; + break; + } +#ifdef DEBUG + if (debug) + fprintf(stderr, "%lu\n", (u_long)leitch->reftime2.l_ui); +#endif + MSUTOTSF(leitch->fudge1, leitch->reftime2.l_uf); + leitch->codetime2 = rbufp->recv_time; + leitch->state = STATE_TIME3; + break; + case STATE_TIME3: + if (!leitch_get_time(rbufp,leitch,3)) { + } + if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, + leitch->second, GMT, rbufp->recv_time.l_ui, + &leitch->yearstart, &leitch->reftime3.l_ui)) { + leitch->state = STATE_IDLE; + break; + } +#ifdef DEBUG + if (debug) + fprintf(stderr, "%lu\n", (u_long)leitch->reftime3.l_ui); +#endif + MSUTOTSF(leitch->fudge1, leitch->reftime3.l_uf); + leitch->codetime3 = rbufp->recv_time; + leitch_process(leitch); + leitch->state = STATE_IDLE; + break; + default: + msyslog(LOG_ERR, + "leitech_receive: invalid state %d unit %d", + leitch->state, leitch->unit); + } +} + +/* + * leitch_process - process a pile of samples from the clock + * + * This routine uses a three-stage median filter to calculate offset and + * dispersion. reduce jitter. The dispersion is calculated as the span + * of the filter (max - min), unless the quality character (format 2) is + * non-blank, in which case the dispersion is calculated on the basis of + * the inherent tolerance of the internal radio oscillator, which is + * +-2e-5 according to the radio specifications. + */ +static void +leitch_process( + struct leitchunit *leitch + ) +{ + l_fp off; + l_fp tmp_fp; + /*double doffset;*/ + + off = leitch->reftime1; + L_SUB(&off,&leitch->codetime1); + tmp_fp = leitch->reftime2; + L_SUB(&tmp_fp,&leitch->codetime2); + if (L_ISGEQ(&off,&tmp_fp)) + off = tmp_fp; + tmp_fp = leitch->reftime3; + L_SUB(&tmp_fp,&leitch->codetime3); + + if (L_ISGEQ(&off,&tmp_fp)) + off = tmp_fp; + /*LFPTOD(&off, doffset);*/ + refclock_receive(leitch->peer); +} + +/* + * days_per_year + */ +static int +days_per_year( + int year + ) +{ + if (year%4) { /* not a potential leap year */ + return (365); + } else { + if (year % 100) { /* is a leap year */ + return (366); + } else { + if (year % 400) { + return (365); + } else { + return (366); + } + } + } +} + +static int +leitch_get_date( + struct recvbuf *rbufp, + struct leitchunit *leitch + ) +{ + int i; + + if (rbufp->recv_length < 6) + return(0); +#undef BAD /* confict: defined as (-1) in AIX sys/param.h */ +#define BAD(A) (rbufp->recv_buffer[A] < '0') || (rbufp->recv_buffer[A] > '9') + if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5)) + return(0); +#define ATOB(A) ((rbufp->recv_buffer[A])-'0') + leitch->year = ATOB(0)*10 + ATOB(1); + leitch->month = ATOB(2)*10 + ATOB(3); + leitch->day = ATOB(4)*10 + ATOB(5); + + /* sanity checks */ + if (leitch->month > 12) + return(0); + if (leitch->day > days_in_month[leitch->month-1]) + return(0); + + /* calculate yearday */ + i = 0; + leitch->yearday = leitch->day; + + while ( i < (leitch->month-1) ) + leitch->yearday += days_in_month[i++]; + + if ((days_per_year((leitch->year>90?1900:2000)+leitch->year)==365) && + leitch->month > 2) + leitch->yearday--; + + return(1); +} + +/* + * leitch_get_time + */ +static int +leitch_get_time( + struct recvbuf *rbufp, + struct leitchunit *leitch, + int which + ) +{ + if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5)) + return(0); + leitch->hour = ATOB(0)*10 +ATOB(1); + leitch->minute = ATOB(2)*10 +ATOB(3); + leitch->second = ATOB(4)*10 +ATOB(5); + + if ((leitch->hour > 23) || (leitch->minute > 60) || + (leitch->second > 60)) + return(0); + return(1); +} + +#else +int refclock_leitch_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_local.c b/contrib/ntp/ntpd/refclock_local.c new file mode 100644 index 000000000000..12184dbc97cd --- /dev/null +++ b/contrib/ntp/ntpd/refclock_local.c @@ -0,0 +1,258 @@ +/* wjm 17-aug-1995: add a hook for special treatment of VMS_LOCALUNIT */ + +/* + * refclock_local - local pseudo-clock driver + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef REFCLOCK +#include +#include +#include + +#include "ntpd.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +#ifdef KERNEL_PLL +#include "ntp_syscall.h" +#endif + +/* + * This is a hack to allow a machine to use its own system clock as a + * reference clock, i.e., to free-run using no outside clock discipline + * source. This is useful if you want to use NTP in an isolated + * environment with no radio clock or NIST modem available. Pick a + * machine that you figure has a good clock oscillator and configure it + * with this driver. Set the clock using the best means available, like + * eyeball-and-wristwatch. Then, point all the other machines at this + * one or use broadcast (not multicast) mode to distribute time. + * + * Another application for this driver is if you want to use a + * particular server's clock as the clock of last resort when all other + * normal synchronization sources have gone away. This is especially + * useful if that server has an ovenized oscillator. For this you would + * configure this driver at a higher stratum (say 3 or 4) to prevent the + * server's stratum from falling below that. + * + * A third application for this driver is when an external discipline + * source is available, such as the NIST "lockclock" program, which + * synchronizes the local clock via a telephone modem and the NIST + * Automated Computer Time Service (ACTS), or the Digital Time + * Synchronization Service (DTSS), which runs on DCE machines. In this + * case the stratum should be set at zero, indicating a bona fide + * stratum-1 source. Exercise some caution with this, since there is no + * easy way to telegraph via NTP that something might be wrong in the + * discipline source itself. In the case of DTSS, the local clock can + * have a rather large jitter, depending on the interval between + * corrections and the intrinsic frequency error of the clock + * oscillator. In extreme cases, this can cause clients to exceed the + * 128-ms slew window and drop off the NTP subnet. + * + * THis driver includes provisions to telegraph synchronization state + * and related variables by means of kernel variables with specially + * modified kernels. This is done using the ntp_adjtime() syscall. + * In the cases where another protocol or device synchronizes the local + * host, the data given to the kernel can be slurped up by this driver + * and distributed to clients by ordinary NTP messaging. + * + * In the default mode the behavior of the clock selection algorithm is + * modified when this driver is in use. The algorithm is designed so + * that this driver will never be selected unless no other discipline + * source is available. This can be overriden with the prefer keyword of + * the server configuration command, in which case only this driver will + * be selected for synchronization and all other discipline sources will + * be ignored. This behavior is intended for use when an external + * discipline source controls the system clock. + * + * Fudge Factors + * + * The stratum for this driver set at 3 by default, but it can be changed + * by the fudge command and/or the ntpdc utility. The reference ID is + * "LCL" by default, but can be changed using the same mechanism. *NEVER* + * configure this driver to operate at a stratum which might possibly + * disrupt a client with access to a bona fide primary server, unless the + * local clock oscillator is reliably disciplined by another source. + * *NEVER NEVER* configure a server which might devolve to an undisciplined + * local clock to use multicast mode. Always remember that an improperly + * configured local clock driver let loose in the Internet can cause + * very serious disruption. This is why most of us who care about good + * time use cryptographic authentication. + * + * This driver provides a mechanism to trim the local clock in both time + * and frequency, as well as a way to manipulate the leap bits. The + * fudge time1 parameter adjusts the time, in seconds, and the fudge + * time2 parameter adjusts the frequency, in ppm. The fudge time1 parameter + * is additive; that is, it adds an increment to the current time. The + * fudge time2 parameter directly sets the frequency. + */ + +/* + * Local interface definitions + */ +#define PRECISION (-7) /* about 10 ms precision */ +#define REFID "LCL\0" /* reference ID */ +#define DESCRIPTION "Undisciplined local clock" /* WRU */ + +#define STRATUM 3 /* default stratum */ +#define DISPERSION .01 /* default dispersion (10 ms) */ + +/* + * Imported from the timer module + */ +extern u_long current_time; + +/* + * Imported from ntp_proto + */ +extern s_char sys_precision; + +#ifdef KERNEL_PLL +/* + * Imported from ntp_loopfilter + */ +extern int pll_control; /* kernel pll control */ +extern int kern_enable; /* kernel pll enabled */ +extern int ext_enable; /* external clock enable */ +#endif /* KERNEL_PLL */ + +/* + * Function prototypes + */ +static int local_start P((int, struct peer *)); +static void local_poll P((int, struct peer *)); + +/* + * Local variables + */ +static u_long poll_time; /* last time polled */ + +/* + * Transfer vector + */ +struct refclock refclock_local = { + local_start, /* start up driver */ + noentry, /* shut down driver (not used) */ + local_poll, /* transmit poll message */ + noentry, /* not used (old lcl_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old lcl_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * local_start - start up the clock + */ +static int +local_start( + int unit, + struct peer *peer + ) +{ + struct refclockproc *pp; + + pp = peer->procptr; + + /* + * Initialize miscellaneous variables + */ + peer->precision = sys_precision; + peer->stratum = STRATUM; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); +#if defined(VMS) && defined(VMS_LOCALUNIT) + /* provide a non-standard REFID */ + if(unit == VMS_LOCALUNIT) + memcpy((char *)&pp->refid,"LCLv",4); +#endif /* VMS && VMS_LOCALUNIT */ + poll_time = current_time; + return (1); +} + + +/* + * local_poll - called by the transmit procedure + */ +static void +local_poll( + int unit, + struct peer *peer + ) +{ + struct refclockproc *pp; +#if defined(KERNEL_PLL) && defined(STA_CLK) + struct timex ntv; + int retval; +#endif /* KERNEL_PLL STA_CLK */ + +#if defined(VMS) && defined(VMS_LOCALUNIT) + if(unit == VMS_LOCALUNIT) { + extern void vms_local_poll(struct peer *); + + vms_local_poll(peer); + return; + } +#endif /* VMS && VMS_LOCALUNIT */ + pp = peer->procptr; + pp->polls++; + + /* + * Ramble through the usual filtering and grooming code, which + * is essentially a no-op and included mostly for pretty + * billboards. We allow a one-time time adjustment using fudge + * time1 (s) and a continuous frequency adjustment using fudge + * time 2 (ppm). + */ + get_systime(&pp->lastrec); + pp->fudgetime1 += pp->fudgetime2 * 1e-6 * (current_time - + poll_time); + poll_time = current_time; + refclock_process_offset(pp, pp->lastrec, pp->lastrec, pp->fudgetime1); + pp->leap = LEAP_NOWARNING; + pp->disp = DISPERSION; + pp->variance = 0; +#if defined(KERNEL_PLL) && defined(STA_CLK) + + /* + * If the kernel pll code is up and running, somebody else + * may come diddle the clock. If so, they better use ntp_adjtime(), + * and set the STA_CLK bit in the status word. In this case, the + * performance information is read from the kernel and becomes the + * variables presented to the clock mitigation process. + */ + if (pll_control && kern_enable && (peer->flags & FLAG_PREFER)) { + memset((char *)&ntv, 0, sizeof ntv); + retval = ntp_adjtime(&ntv); + if (ntv.status & STA_CLK) { + ext_enable = 1; + switch(retval) { + + case TIME_OK: + pp->leap = LEAP_NOWARNING; + break; + + case TIME_INS: + pp->leap = LEAP_ADDSECOND; + break; + + case TIME_DEL: + pp->leap = LEAP_DELSECOND; + break; + + case TIME_ERROR: + pp->leap = LEAP_NOTINSYNC; + } + pp->disp = ntv.maxerror / 1e6; + pp->variance = SQUARE(ntv.esterror / 1e6); + } + } else { + ext_enable = 0; + } +#endif /* KERNEL_PLL STA_CLK */ + refclock_receive(peer); + pp->fudgetime1 = 0; +} +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_msfees.c b/contrib/ntp/ntpd/refclock_msfees.c new file mode 100644 index 000000000000..01fe27fb1375 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_msfees.c @@ -0,0 +1,1444 @@ +/* refclock_ees - clock driver for the EES M201 receiver */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_MSFEES) && defined(PPS) + +/* Currently REQUIRES STREAM and PPSCD. CLK and CBREAK modes + * were removed as the code was overly hairy, they weren't in use + * (hence probably didn't work). Still in RCS file at cl.cam.ac.uk + */ + +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" +#if defined(HAVE_BSD_TTYS) +#include +#endif /* HAVE_BSD_TTYS */ +#if defined(HAVE_SYSV_TTYS) +#include +#endif /* HAVE_SYSV_TTYS */ +#if defined(HAVE_TERMIOS) +#include +#endif +#if defined(STREAM) +#include +#endif + +#ifdef HAVE_SYS_TERMIOS_H +# include +#endif +#ifdef HAVE_SYS_PPSCLOCK_H +# include +#endif + +#include "ntp_stdlib.h" + +/* + fudgefactor = fudgetime1; + os_delay = fudgetime2; + offset_fudge = os_delay + fudgefactor + inherent_delay; + stratumtouse = fudgeval1 & 0xf + debug = fudgeval2; + sloppyclockflag = flags & CLK_FLAG1; + 1 log smoothing summary when processing sample + 4 dump the buffer from the clock + 8 EIOGETKD the last n uS time stamps + if (flags & CLK_FLAG2 && unitinuse) ees->leaphold = 0; + ees->dump_vals = flags & CLK_FLAG3; + ees->usealldata = flags & CLK_FLAG4; + + + bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0; + bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0; + bug->values[2] = (u_long)ees->status; + bug->values[3] = (u_long)ees->lastevent; + bug->values[4] = (u_long)ees->reason; + bug->values[5] = (u_long)ees->nsamples; + bug->values[6] = (u_long)ees->codestate; + bug->values[7] = (u_long)ees->day; + bug->values[8] = (u_long)ees->hour; + bug->values[9] = (u_long)ees->minute; + bug->values[10] = (u_long)ees->second; + bug->values[11] = (u_long)ees->tz; + bug->values[12] = ees->yearstart; + bug->values[13] = (ees->leaphold > current_time) ? + ees->leaphold - current_time : 0; + bug->values[14] = inherent_delay[unit].l_uf; + bug->values[15] = offset_fudge[unit].l_uf; + + bug->times[0] = ees->reftime; + bug->times[1] = ees->arrvtime; + bug->times[2] = ees->lastsampletime; + bug->times[3] = ees->offset; + bug->times[4] = ees->lowoffset; + bug->times[5] = ees->highoffset; + bug->times[6] = inherent_delay[unit]; + bug->times[8] = os_delay[unit]; + bug->times[7] = fudgefactor[unit]; + bug->times[9] = offset_fudge[unit]; + bug->times[10]= ees->yearstart, 0; + */ + +/* This should support the use of an EES M201 receiver with RS232 + * output (modified to transmit time once per second). + * + * For the format of the message sent by the clock, see the EESM_ + * definitions below. + * + * It appears to run free for an integral number of minutes, until the error + * reaches 4mS, at which point it steps at second = 01. + * It appears that sometimes it steps 4mS (say at 7 min interval), + * then the next minute it decides that it was an error, so steps back. + * On the next minute it steps forward again :-( + * This is typically 16.5uS/S then 3975uS at the 4min re-sync, + * or 9.5uS/S then 3990.5uS at a 7min re-sync, + * at which point it may 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 "ppsclocd\0<-- patch space for module name1 -->" +#endif +#ifndef STREAM_PP2 +#define STREAM_PP2 "ppsclock\0<-- patch space for module name2 -->" +#endif + + /* Offsets of the bytes of the serial line code. The clock gives + * local time with a GMT/BST indication. The EESM_ definitions + * give offsets into ees->lastcode. + */ +#define EESM_CSEC 0 /* centiseconds - always zero in our clock */ +#define EESM_SEC 1 /* seconds in BCD */ +#define EESM_MIN 2 /* minutes in BCD */ +#define EESM_HOUR 3 /* hours in BCD */ +#define EESM_DAYWK 4 /* day of week (Sun = 0 etc) */ +#define EESM_DAY 5 /* day of month in BCD */ +#define EESM_MON 6 /* month in BCD */ +#define EESM_YEAR 7 /* year MOD 100 in BCD */ +#define EESM_LEAP 8 /* 0x0f if leap year, otherwise zero */ +#define EESM_BST 9 /* 0x03 if BST, 0x00 if GMT */ +#define EESM_MSFOK 10 /* 0x3f if radio good, otherwise zero */ + /* followed by a frame alignment byte (0xff) / + / which is not put into the lastcode buffer*/ + +/* Length of the serial time code, in characters. The first length + * is less the frame alignment byte. + */ +#define LENEESPRT (EESM_MSFOK+1) +#define LENEESCODE (LENEESPRT+1) + + /* Code state. */ +#define EESCS_WAIT 0 /* waiting for start of timecode */ +#define EESCS_GOTSOME 1 /* have an incomplete time code buffered */ + + /* Default fudge factor and character to receive */ +#define DEFFUDGETIME 0 /* Default user supplied fudge factor */ +#ifndef DEFOSTIME +#define DEFOSTIME 0 /* Default OS delay -- passed by Make ? */ +#endif +#define DEFINHTIME INH_DELAY_PPS /* inherent delay due to sample point*/ + + /* Limits on things. Reduce the number of samples to SAMPLEREDUCE by median + * elimination. If we're running with an accurate clock, chose the BESTSAMPLE + * as the estimated offset, otherwise average the remainder. + */ +#define FULLSHIFT 6 /* NCODES root 2 */ +#define NCODES (1<< FULLSHIFT) /* 64 */ +#define REDUCESHIFT (FULLSHIFT -1) /* SAMPLEREDUCE root 2 */ + + /* Towards the high ( Why ?) end of half */ +#define BESTSAMPLE ((samplereduce * 3) /4) /* 24 */ + + /* Leap hold time. After a leap second the clock will no longer be + * reliable until it resynchronizes. Hope 40 minutes is enough. */ +#define EESLEAPHOLD (40 * 60) + +#define EES_STEP_F (1 << 24) /* the receiver steps in units of about 4ms */ +#define EES_STEP_F_GRACE (EES_STEP_F/8) /*Allow for slop of 1/8 which is .5ms*/ +#define EES_STEP_NOTE (1 << 21)/* Log any unexpected jumps, say .5 ms .... */ +#define EES_STEP_NOTES 50 /* Only do a limited number */ +#define MAX_STEP 16 /* Max number of steps to remember */ + + /* debug is a bit mask of debugging that is wanted */ +#define DB_SYSLOG_SMPLI 0x0001 +#define DB_SYSLOG_SMPLE 0x0002 +#define DB_SYSLOG_SMTHI 0x0004 +#define DB_SYSLOG_NSMTHE 0x0008 +#define DB_SYSLOG_NSMTHI 0x0010 +#define DB_SYSLOG_SMTHE 0x0020 +#define DB_PRINT_EV 0x0040 +#define DB_PRINT_CDT 0x0080 +#define DB_PRINT_CDTC 0x0100 +#define DB_SYSLOG_KEEPD 0x0800 +#define DB_SYSLOG_KEEPE 0x1000 +#define DB_LOG_DELTAS 0x2000 +#define DB_PRINT_DELTAS 0x4000 +#define DB_LOG_AWAITMORE 0x8000 +#define DB_LOG_SAMPLES 0x10000 +#define DB_NO_PPS 0x20000 +#define DB_INC_PPS 0x40000 +#define DB_DUMP_DELTAS 0x80000 + + struct eesunit { /* EES unit control structure. */ + struct peer *peer; /* associated peer structure */ + struct refclockio io; /* given to the I/O handler */ + l_fp reftime; /* reference time */ + l_fp lastsampletime; /* time as in txt from last EES msg */ + l_fp arrvtime; /* Time at which pkt arrived */ + l_fp codeoffsets[NCODES]; /* the time of arrival of 232 codes */ + l_fp offset; /* chosen offset (for clkbug) */ + l_fp lowoffset; /* lowest sample offset (for clkbug) */ + l_fp highoffset; /* highest " " (for clkbug) */ + char lastcode[LENEESCODE+6]; /* last time code we received */ + u_long lasttime; /* last time clock heard from */ + u_long clocklastgood; /* last time good radio seen */ + u_char lencode; /* length of code in buffer */ + u_char nsamples; /* number of samples we've collected */ + u_char codestate; /* state of 232 code reception */ + u_char unit; /* unit number for this guy */ + u_char status; /* clock status */ + u_char lastevent; /* last clock event */ + u_char reason; /* reason for last abort */ + u_char hour; /* hour of day */ + u_char minute; /* minute of hour */ + u_char second; /* seconds of minute */ + char tz; /* timezone from clock */ + u_char ttytype; /* method used */ + u_char dump_vals; /* Should clock values be dumped */ + u_char usealldata; /* Use ALL samples */ + u_short day; /* day of year from last code */ + u_long yearstart; /* start of current year */ + u_long leaphold; /* time of leap hold expiry */ + u_long badformat; /* number of bad format codes */ + u_long baddata; /* number of invalid time codes */ + u_long timestarted; /* time we started this */ + long last_pps_no; /* The serial # of the last PPS */ + char fix_pending; /* Is a "sync to time" pending ? */ + /* Fine tuning - compensate for 4 mS ramping .... */ + l_fp last_l; /* last time stamp */ + u_char last_steps[MAX_STEP]; /* Most recent n steps */ + int best_av_step; /* Best guess at average step */ + char best_av_step_count; /* # of steps over used above */ + char this_step; /* Current pos in buffer */ + int last_step_late; /* How late the last step was (0-59) */ + long jump_fsecs; /* # of fractions of a sec last jump */ + u_long last_step; /* time of last step */ + int last_step_secs; /* Number of seconds in last step */ + int using_ramp; /* 1 -> noemal, -1 -> over stepped */ + }; +#define last_sec last_l.l_ui +#define last_sfsec last_l.l_f +#define this_uisec ((ees->arrvtime).l_ui) +#define this_sfsec ((ees->arrvtime).l_f) +#define msec(x) ((x) / (1<<22)) +#define LAST_STEPS (sizeof ees->last_steps / sizeof ees->last_steps[0]) +#define subms(x) ((((((x < 0) ? (-(x)) : (x)) % (1<<22))/2) * 625) / (1<<(22 -5))) + +/* Bitmask for what methods to try to use -- currently only PPS enabled */ +#define T_CBREAK 1 +#define T_PPS 8 +/* macros to test above */ +#define is_cbreak(x) ((x)->ttytype & T_CBREAK) +#define is_pps(x) ((x)->ttytype & T_PPS) +#define is_any(x) ((x)->ttytype) + +#define CODEREASON 20 /* reason codes */ + +/* Data space for the unit structures. Note that we allocate these on + * the fly, but never give them back. */ +static struct eesunit *eesunits[MAXUNITS]; +static u_char unitinuse[MAXUNITS]; + +/* Keep the fudge factors separately so they can be set even + * when no clock is configured. */ +static l_fp inherent_delay[MAXUNITS]; /* when time stamp is taken */ +static l_fp fudgefactor[MAXUNITS]; /* fudgetime1 */ +static l_fp os_delay[MAXUNITS]; /* fudgetime2 */ +static l_fp offset_fudge[MAXUNITS]; /* Sum of above */ +static u_char stratumtouse[MAXUNITS]; +static u_char sloppyclockflag[MAXUNITS]; + +static int deltas[60]; + +static l_fp acceptable_slop; /* = { 0, 1 << (FRACTION_PREC -2) }; */ +static l_fp onesec; /* = { 1, 0 }; */ + +#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) + +/* + * Function prototypes + */ + +static int msfees_start P((int unit, struct peer *peer)); +static void msfees_shutdown P((int unit, struct peer *peer)); +static void msfees_poll P((int unit, struct peer *peer)); +static void msfees_init P((void)); +static void dump_buf P((l_fp *coffs, int from, int to, char *text)); +static void ees_report_event P((struct eesunit *ees, int code)); +static void ees_receive P((struct recvbuf *rbufp)); +static int offcompare P((l_fp *a, l_fp *b)); +static void ees_process P((struct eesunit *ees)); + +/* + * Transfer vector + */ +struct refclock refclock_msfees = { + msfees_start, /* start up driver */ + msfees_shutdown, /* shut down driver */ + msfees_poll, /* transmit poll message */ + noentry, /* not used */ + msfees_init, /* initialize driver */ + noentry, /* not used */ + NOFLAGS /* not used */ +}; + + +static void +dump_buf( + l_fp *coffs, + int from, + int to, + char *text + ) +{ + char buff[DUMP_BUF_SIZE + 80]; + int i; + register char *ptr = buff; + + sprintf(ptr, text); + for (i=from; i DUMP_BUF_SIZE) msyslog(LOG_DEBUG, "D: %s", ptr=buff); + sprintf(ptr, " %06d", ((int)coffs[i].l_f) / 4295); + } + msyslog(LOG_DEBUG, "D: %s", buff); +} + +/* msfees_init - initialize internal ees driver data */ +static void +msfees_init(void) +{ + register int i; + /* Just zero the data arrays */ + memset((char *)eesunits, 0, sizeof eesunits); + memset((char *)unitinuse, 0, sizeof unitinuse); + + acceptable_slop.l_ui = 0; + acceptable_slop.l_uf = 1 << (FRACTION_PREC -2); + + onesec.l_ui = 1; + onesec.l_uf = 0; + + /* Initialize fudge factors to default. */ + for (i = 0; i < MAXUNITS; i++) { + fudgefactor[i].l_ui = 0; + fudgefactor[i].l_uf = DEFFUDGETIME; + os_delay[i].l_ui = 0; + os_delay[i].l_uf = DEFOSTIME; + inherent_delay[i].l_ui = 0; + inherent_delay[i].l_uf = DEFINHTIME; + offset_fudge[i] = os_delay[i]; + L_ADD(&offset_fudge[i], &fudgefactor[i]); + L_ADD(&offset_fudge[i], &inherent_delay[i]); + stratumtouse[i] = 0; + sloppyclockflag[i] = 0; + } +} + + +/* msfees_start - open the EES devices and initialize data for processing */ +static int +msfees_start( + int unit, + struct peer *peer + ) +{ + register struct eesunit *ees; + register int i; + int fd232 = -1; + char eesdev[20]; + struct termios ttyb, *ttyp; + struct refclockproc *pp; + pp = peer->procptr; + + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)", + unit, MAXUNITS-1); + return 0; + } + if (unitinuse[unit]) { + msyslog(LOG_ERR, "ees clock: unit number %d in use", unit); + return 0; + } + + /* Unit okay, attempt to open the devices. We do them both at + * once to make sure we can */ + (void) sprintf(eesdev, EES232, unit); + + fd232 = open(eesdev, O_RDWR, 0777); + if (fd232 == -1) { + msyslog(LOG_ERR, "ees clock: open of %s failed: %m", eesdev); + return 0; + } + +#ifdef TIOCEXCL + /* Set for exclusive use */ + if (ioctl(fd232, TIOCEXCL, (char *)0) < 0) { + msyslog(LOG_ERR, "ees clock: ioctl(%s, TIOCEXCL): %m", eesdev); + goto screwed; + } +#endif + + /* STRIPPED DOWN VERSION: Only PPS CD is supported at the moment */ + + /* Set port characteristics. If we don't have a STREAMS module or + * a clock line discipline, cooked mode is just usable, even though it + * strips the top bit. The only EES byte which uses the top + * bit is the year, and we don't use that anyway. If we do + * have the line discipline, we choose raw mode, and the + * line discipline code will block up the messages. + */ + + /* STIPPED DOWN VERSION: Only PPS CD is supported at the moment */ + + ttyp = &ttyb; + if (tcgetattr(fd232, ttyp) < 0) { + msyslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev); + goto screwed; + } + + ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL; + ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD; + ttyp->c_oflag = 0; + ttyp->c_lflag = ICANON; + ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; + if (tcsetattr(fd232, TCSANOW, ttyp) < 0) { + msyslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev); + goto screwed; + } + + if (tcflush(fd232, TCIOFLUSH) < 0) { + msyslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev); + goto screwed; + } + + inherent_delay[unit].l_uf = INH_DELAY_PPS; + + /* offset fudge (how *late* the timestamp is) = fudge + os delays */ + offset_fudge[unit] = os_delay[unit]; + L_ADD(&offset_fudge[unit], &fudgefactor[unit]); + L_ADD(&offset_fudge[unit], &inherent_delay[unit]); + + /* Looks like this might succeed. Find memory for the structure. + * Look to see if there are any unused ones, if not we malloc() one. + */ + if (eesunits[unit] != 0) /* The one we want is okay */ + ees = eesunits[unit]; + else { + /* Look for an unused, but allocated struct */ + for (i = 0; i < MAXUNITS; i++) { + if (!unitinuse[i] && eesunits[i] != 0) + break; + } + + if (i < MAXUNITS) { /* Reclaim this one */ + ees = eesunits[i]; + eesunits[i] = 0; + } /* no spare -- make a new one */ + else ees = (struct eesunit *) emalloc(sizeof(struct eesunit)); + } + memset((char *)ees, 0, sizeof(struct eesunit)); + eesunits[unit] = ees; + + /* Set up the structures */ + ees->peer = peer; + ees->unit = (u_char)unit; + ees->timestarted= current_time; + ees->ttytype = 0; + ees->io.clock_recv= ees_receive; + ees->io.srcclock= (caddr_t)ees; + ees->io.datalen = 0; + ees->io.fd = fd232; + + /* Okay. Push one of the two (linked into the kernel, or dynamically + * loaded) STREAMS module, and give it to the I/O code to start + * receiving stuff. + */ + +#ifdef STREAM + { + int rc1; + /* Pop any existing onews first ... */ + while (ioctl(fd232, I_POP, 0 ) >= 0) ; + + /* Now try pushing either of the possible modules */ + if ((rc1=ioctl(fd232, I_PUSH, STREAM_PP1)) < 0 && + ioctl(fd232, I_PUSH, STREAM_PP2) < 0) { + msyslog(LOG_ERR, + "ees clock: Push of `%s' and `%s' to %s failed %m", + STREAM_PP1, STREAM_PP2, eesdev); + goto screwed; + } + else { + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_INFO, "I: ees clock: PUSHed %s on %s", + (rc1 >= 0) ? STREAM_PP1 : STREAM_PP2, eesdev); + ees->ttytype |= T_PPS; + } + } +#endif /* STREAM */ + + /* Add the clock */ + if (!io_addclock(&ees->io)) { + /* Oh shit. Just close and return. */ + msyslog(LOG_ERR, "ees clock: io_addclock(%s): %m", eesdev); + goto screwed; + } + + + /* All done. Initialize a few random peer variables, then + * return success. */ + peer->precision = sys_precision; + peer->stratum = stratumtouse[unit]; + if (stratumtouse[unit] <= 1) { + memcpy((char *)&pp->refid, EESREFID, 4); + if (unit > 0 && unit < 10) + ((char *)&pp->refid)[3] = '0' + unit; + } else { + peer->refid = htonl(EESHSREFID); + } + unitinuse[unit] = 1; + pp->unitptr = (caddr_t) &eesunits[unit]; + pp->clockdesc = EESDESCRIPTION; + msyslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit); + return (1); + + screwed: + if (fd232 != -1) + (void) close(fd232); + return (0); +} + + +/* msfees_shutdown - shut down a EES clock */ +static void +msfees_shutdown( + int unit, + struct peer *peer + ) +{ + register struct eesunit *ees; + + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, + "ees clock: INTERNAL ERROR, unit number %d invalid (max %d)", + unit, MAXUNITS); + return; + } + if (!unitinuse[unit]) { + msyslog(LOG_ERR, + "ees clock: INTERNAL ERROR, unit number %d not in use", unit); + return; + } + + /* Tell the I/O module to turn us off. We're history. */ + ees = eesunits[unit]; + io_closeclock(&ees->io); + unitinuse[unit] = 0; +} + + +/* ees_report_event - note the occurance of an event */ +static void +ees_report_event( + struct eesunit *ees, + int code + ) +{ + if (ees->status != (u_char)code) { + ees->status = (u_char)code; + if (code != CEVNT_NOMINAL) + ees->lastevent = (u_char)code; + /* Should report event to trap handler in here. + * Soon... + */ + } +} + + +/* ees_receive - receive data from the serial interface on an EES clock */ +static void +ees_receive( + struct recvbuf *rbufp + ) +{ + register int n_sample; + register int day; + register struct eesunit *ees; + register u_char *dpt; /* Data PoinTeR: move along ... */ + register u_char *dpend; /* Points just *after* last data char */ + register char *cp; + l_fp tmp; + int call_pps_sample = 0; + l_fp pps_arrvstamp; + int sincelast; + int pps_step = 0; + int suspect_4ms_step = 0; + struct ppsclockev ppsclockev; + long *ptr = (long *) &ppsclockev; + int rc; + int request; +#ifdef HAVE_CIOGETEV + request = CIOGETEV; +#endif +#ifdef HAVE_TIOCGPPSEV + request = TIOCGPPSEV; +#endif + + /* Get the clock this applies to and a pointer to the data */ + ees = (struct eesunit *)rbufp->recv_srcclock; + dpt = (u_char *)&rbufp->recv_space; + dpend = dpt + rbufp->recv_length; + if ((debug & DB_LOG_AWAITMORE) && (rbufp->recv_length != LENEESCODE)) + printf("[%d] ", rbufp->recv_length); + + /* Check out our state and process appropriately */ + switch (ees->codestate) { + case EESCS_WAIT: + /* Set an initial guess at the timestamp as the recv time. + * If just running in CBREAK mode, we can't improve this. + * If we have the CLOCK Line Discipline, PPSCD, or sime such, + * then we will do better later .... + */ + ees->arrvtime = rbufp->recv_time; + ees->codestate = EESCS_GOTSOME; + ees->lencode = 0; + /*FALLSTHROUGH*/ + + case EESCS_GOTSOME: + cp = &(ees->lastcode[ees->lencode]); + + /* Gobble the bytes until the final (possibly stripped) 0xff */ + while (dpt < dpend && (*dpt & 0x7f) != 0x7f) { + *cp++ = (char)*dpt++; + ees->lencode++; + /* Oh dear -- too many bytes .. */ + if (ees->lencode > LENEESPRT) { + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_INFO, + "I: ees clock: %d + %d > %d [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]", + ees->lencode, dpend - dpt, LENEESPRT, +#define D(x) (ees->lastcode[x]) + D(0), D(1), D(2), D(3), D(4), D(5), D(6), + D(7), D(8), D(9), D(10), D(11), D(12)); +#undef D + ees->badformat++; + ees->reason = CODEREASON + 1; + ees_event(ees, CEVNT_BADREPLY); + ees_reset(ees); + return; + } + } + /* Gave up because it was end of the buffer, rather than ff */ + if (dpt == dpend) { + /* Incomplete. Wait for more. */ + if (debug & DB_LOG_AWAITMORE) + msyslog(LOG_INFO, + "I: ees clock %d: %x == %x: await more", + ees->unit, dpt, dpend); + return; + } + + /* This shouldn't happen ... ! */ + if ((*dpt & 0x7f) != 0x7f) { + msyslog(LOG_INFO, "I: ees clock: %0x & 0x7f != 0x7f", *dpt); + ees->badformat++; + ees->reason = CODEREASON + 2; + ees_event(ees, CEVNT_BADREPLY); + ees_reset(ees); + return; + } + + /* Skip the 0xff */ + dpt++; + + /* Finally, got a complete buffer. Mainline code will + * continue on. */ + cp = ees->lastcode; + break; + + default: + msyslog(LOG_ERR, "ees clock: INTERNAL ERROR: %d state %d", + ees->unit, ees->codestate); + ees->reason = CODEREASON + 5; + ees_event(ees, CEVNT_FAULT); + ees_reset(ees); + return; + } + + /* Boy! After all that crap, the lastcode buffer now contains + * something we hope will be a valid time code. Do length + * checks and sanity checks on constant data. + */ + ees->codestate = EESCS_WAIT; + ees->lasttime = current_time; + if (ees->lencode != LENEESPRT) { + ees->badformat++; + ees->reason = CODEREASON + 6; + ees_event(ees, CEVNT_BADREPLY); + ees_reset(ees); + return; + } + + cp = ees->lastcode; + + /* Check that centisecond is zero */ + if (cp[EESM_CSEC] != 0) { + ees->baddata++; + ees->reason = CODEREASON + 7; + ees_event(ees, CEVNT_BADREPLY); + ees_reset(ees); + return; + } + + /* Check flag formats */ + if (cp[EESM_LEAP] != 0 && cp[EESM_LEAP] != 0x0f) { + ees->badformat++; + ees->reason = CODEREASON + 8; + ees_event(ees, CEVNT_BADREPLY); + ees_reset(ees); + return; + } + + if (cp[EESM_BST] != 0 && cp[EESM_BST] != 0x03) { + ees->badformat++; + ees->reason = CODEREASON + 9; + ees_event(ees, CEVNT_BADREPLY); + ees_reset(ees); + return; + } + + if (cp[EESM_MSFOK] != 0 && cp[EESM_MSFOK] != 0x3f) { + ees->badformat++; + ees->reason = CODEREASON + 10; + ees_event(ees, CEVNT_BADREPLY); + ees_reset(ees); + return; + } + + /* So far, so good. Compute day, hours, minutes, seconds, + * time zone. Do range checks on these. + */ + +#define bcdunpack(val) ( (((val)>>4) & 0x0f) * 10 + ((val) & 0x0f) ) +#define istrue(x) ((x)?1:0) + + ees->second = bcdunpack(cp[EESM_SEC]); /* second */ + ees->minute = bcdunpack(cp[EESM_MIN]); /* minute */ + ees->hour = bcdunpack(cp[EESM_HOUR]); /* hour */ + + day = bcdunpack(cp[EESM_DAY]); /* day of month */ + + switch (bcdunpack(cp[EESM_MON])) { /* month */ + + /* Add in lengths of all previous months. Add one more + if it is a leap year and after February. + */ + case 12: day += NOV; /*FALLSTHROUGH*/ + case 11: day += OCT; /*FALLSTHROUGH*/ + case 10: day += SEP; /*FALLSTHROUGH*/ + case 9: day += AUG; /*FALLSTHROUGH*/ + case 8: day += JUL; /*FALLSTHROUGH*/ + case 7: day += JUN; /*FALLSTHROUGH*/ + case 6: day += MAY; /*FALLSTHROUGH*/ + case 5: day += APR; /*FALLSTHROUGH*/ + case 4: day += MAR; /*FALLSTHROUGH*/ + case 3: day += FEB; + if (istrue(cp[EESM_LEAP])) day++; /*FALLSTHROUGH*/ + case 2: day += JAN; /*FALLSTHROUGH*/ + case 1: break; + default: ees->baddata++; + ees->reason = CODEREASON + 11; + ees_event(ees, CEVNT_BADDATE); + ees_reset(ees); + return; + } + + ees->day = day; + + /* Get timezone. The clocktime routine wants the number + * of hours to add to the delivered time to get UT. + * Currently -1 if BST flag set, 0 otherwise. This + * is the place to tweak things if double summer time + * ever happens. + */ + ees->tz = istrue(cp[EESM_BST]) ? -1 : 0; + + if (ees->day > 366 || ees->day < 1 || + ees->hour > 23 || ees->minute > 59 || ees->second > 59) { + ees->baddata++; + ees->reason = CODEREASON + 12; + ees_event(ees, CEVNT_BADDATE); + ees_reset(ees); + return; + } + + n_sample = ees->nsamples; + + /* Now, compute the reference time value: text -> tmp.l_ui */ + if (!clocktime(ees->day, ees->hour, ees->minute, ees->second, + ees->tz, rbufp->recv_time.l_ui, &ees->yearstart, + &tmp.l_ui)) { + ees->baddata++; + ees->reason = CODEREASON + 13; + ees_event(ees, CEVNT_BADDATE); + ees_reset(ees); + return; + } + tmp.l_uf = 0; + + /* DON'T use ees->arrvtime -- it may be < reftime */ + ees->lastsampletime = tmp; + + /* If we are synchronised to the radio, update the reference time. + * Also keep a note of when clock was last good. + */ + if (istrue(cp[EESM_MSFOK])) { + ees->reftime = tmp; + ees->clocklastgood = current_time; + } + + + /* Compute the offset. For the fractional part of the + * offset we use the expected delay for the message. + */ + ees->codeoffsets[n_sample].l_ui = tmp.l_ui; + ees->codeoffsets[n_sample].l_uf = 0; + + /* Number of seconds since the last step */ + sincelast = this_uisec - ees->last_step; + + memset((char *) &ppsclockev, 0, sizeof ppsclockev); + + rc = ioctl(ees->io.fd, request, (char *) &ppsclockev); + if (debug & DB_PRINT_EV) fprintf(stderr, + "[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08lx %08lx %ld\n", + DB_PRINT_EV, ees->unit, ees->io.fd, request, is_pps(ees), + rc, errno, ptr[0], ptr[1], ptr[2]); + + /* If we managed to get the time of arrival, process the info */ + if (rc >= 0) { + int conv = -1; + pps_step = ppsclockev.serial - ees->last_pps_no; + + /* Possible that PPS triggered, but text message didn't */ + if (pps_step == 2) msyslog(LOG_ERR, "pps step = 2 @ %02d", ees->second); + if (pps_step == 2 && ees->second == 1) suspect_4ms_step |= 1; + if (pps_step == 2 && ees->second == 2) suspect_4ms_step |= 4; + + /* allow for single loss of PPS only */ + if (pps_step != 1 && pps_step != 2) + fprintf(stderr, "PPS step: %d too far off %ld (%d)\n", + ppsclockev.serial, ees->last_pps_no, pps_step); + else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp)) + fprintf(stderr, "buftvtots failed\n"); + else { /* if ((ABS(time difference) - 0.25) < 0) + * then believe it ... + */ + l_fp diff; + diff = pps_arrvstamp; + conv = 0; + L_SUB(&diff, &ees->arrvtime); + if (debug & DB_PRINT_CDT) + printf("[%x] Have %lx.%08lx and %lx.%08lx -> %lx.%08lx @ %s", + DB_PRINT_CDT, (long)ees->arrvtime.l_ui, (long)ees->arrvtime.l_uf, + (long)pps_arrvstamp.l_ui, (long)pps_arrvstamp.l_uf, + (long)diff.l_ui, (long)diff.l_uf, + ctime(&(ppsclockev.tv.tv_sec))); + if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf); + L_SUB(&diff, &acceptable_slop); + if (L_ISNEG(&diff)) { /* AOK -- pps_sample */ + ees->arrvtime = pps_arrvstamp; + conv++; + call_pps_sample++; + } + /* Some loss of some signals around sec = 1 */ + else if (ees->second == 1) { + diff = pps_arrvstamp; + L_ADD(&diff, &onesec); + L_SUB(&diff, &ees->arrvtime); + if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf); + L_SUB(&diff, &acceptable_slop); + msyslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s", + pps_arrvstamp.l_ui - ees->arrvtime.l_ui, + pps_arrvstamp.l_uf, + ees->arrvtime.l_uf, + diff.l_ui, diff.l_uf, + (int)ppsclockev.tv.tv_usec, + ctime(&(ppsclockev.tv.tv_sec))); + if (L_ISNEG(&diff)) { /* AOK -- pps_sample */ + suspect_4ms_step |= 2; + ees->arrvtime = pps_arrvstamp; + L_ADD(&ees->arrvtime, &onesec); + conv++; + call_pps_sample++; + } + } + } + ees->last_pps_no = ppsclockev.serial; + if (debug & DB_PRINT_CDTC) + printf( + "[%x] %08lx %08lx %d u%d (%d %d)\n", + DB_PRINT_CDTC, (long)pps_arrvstamp.l_ui, + (long)pps_arrvstamp.l_uf, conv, ees->unit, + call_pps_sample, pps_step); + } + + /* See if there has been a 4ms jump at a minute boundry */ + { l_fp delta; +#define delta_isec delta.l_ui +#define delta_ssec delta.l_i +#define delta_sfsec delta.l_f + long delta_f_abs; + + delta.l_i = ees->arrvtime.l_i; + delta.l_f = ees->arrvtime.l_f; + + L_SUB(&delta, &ees->last_l); + delta_f_abs = delta_sfsec; + if (delta_f_abs < 0) delta_f_abs = -delta_f_abs; + + /* Dump the deltas each minute */ + if (debug & DB_DUMP_DELTAS) + { if (/*0 <= ees->second && */ + ees->second < ((sizeof deltas) / (sizeof deltas[0]))) deltas[ees->second] = delta_sfsec; + /* Dump on second 1, as second 0 sometimes missed */ + if (ees->second == 1) { + char text[16 * ((sizeof deltas) / (sizeof deltas[0]))]; + char *cptr=text; + int i; + for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) { + sprintf(cptr, " %d.%04d", + msec(deltas[i]), subms(deltas[i])); + while (*cptr) cptr++; + } + msyslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s", + msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE), + msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE), + text+1); + for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) deltas[i] = 0; + } + } + + /* Lets see if we have a 4 mS step at a minute boundaary */ + if ( ((EES_STEP_F - EES_STEP_F_GRACE) < delta_f_abs) && + (delta_f_abs < (EES_STEP_F + EES_STEP_F_GRACE)) && + (ees->second == 0 || ees->second == 1 || ees->second == 2) && + (sincelast < 0 || sincelast > 122) + ) { /* 4ms jump at min boundry */ + int old_sincelast; + int count=0; + int sum = 0; + /* Yes -- so compute the ramp time */ + if (ees->last_step == 0) sincelast = 0; + old_sincelast = sincelast; + + /* First time in, just set "ees->last_step" */ + if(ees->last_step) { + int other_step = 0; + int third_step = 0; + int this_step = (sincelast + (60 /2)) / 60; + int p_step = ees->this_step; + int p; + ees->last_steps[p_step] = this_step; + p= p_step; + p_step++; + if (p_step >= LAST_STEPS) p_step = 0; + ees->this_step = p_step; + /* Find the "average" interval */ + while (p != p_step) { + int this = ees->last_steps[p]; + if (this == 0) break; + if (this != this_step) { + if (other_step == 0 && ( + this== (this_step +2) || + this== (this_step -2) || + this== (this_step +1) || + this== (this_step -1))) + other_step = this; + if (other_step != this) { + int idelta = (this_step - other_step); + if (idelta < 0) idelta = - idelta; + if (third_step == 0 && ( + (idelta == 1) ? ( + this == (other_step +1) || + this == (other_step -1) || + this == (this_step +1) || + this == (this_step -1)) + : + ( + this == (this_step + other_step)/2 + ) + )) third_step = this; + if (third_step != this) break; + } + } + sum += this; + p--; + if (p < 0) p += LAST_STEPS; + count++; + } + msyslog(LOG_ERR, "MSF%d: %d: This=%d (%d), other=%d/%d, sum=%d, count=%d, pps_step=%d, suspect=%x", ees->unit, p, ees->last_steps[p], this_step, other_step, third_step, sum, count, pps_step, suspect_4ms_step); + if (count != 0) sum = ((sum * 60) + (count /2)) / count; +#define SV(x) (ees->last_steps[(x + p_step) % LAST_STEPS]) + msyslog(LOG_ERR, "MSF%d: %x steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", + ees->unit, suspect_4ms_step, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6), + SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15)); + printf("MSF%d: steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", + ees->unit, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6), + SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15)); +#undef SV + ees->jump_fsecs = delta_sfsec; + ees->using_ramp = 1; + if (sincelast > 170) + ees->last_step_late += sincelast - ((sum) ? sum : ees->last_step_secs); + else ees->last_step_late = 30; + if (ees->last_step_late < -60 || ees->last_step_late > 120) ees->last_step_late = 30; + if (ees->last_step_late < 0) ees->last_step_late = 0; + if (ees->last_step_late >= 60) ees->last_step_late = 59; + sincelast = 0; + } + else { /* First time in -- just save info */ + ees->last_step_late = 30; + ees->jump_fsecs = delta_sfsec; + ees->using_ramp = 1; + sum = 4 * 60; + } + ees->last_step = this_uisec; + printf("MSF%d: d=%3ld.%04ld@%d :%d:%d:$%d:%d:%d\n", + ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec), + ees->second, old_sincelast, ees->last_step_late, count, sum, + ees->last_step_secs); + msyslog(LOG_ERR, "MSF%d: d=%3d.%04d@%d :%d:%d:%d:%d:%d", + ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, + old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs); + if (sum) ees->last_step_secs = sum; + } + /* OK, so not a 4ms step at a minute boundry */ + else { + if (suspect_4ms_step) msyslog(LOG_ERR, + "MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]", + ees->unit, suspect_4ms_step, msec(delta_sfsec), subms(delta_sfsec), + msec(EES_STEP_F - EES_STEP_F_GRACE), + subms(EES_STEP_F - EES_STEP_F_GRACE), + (int)msec(delta_f_abs), + (int)subms(delta_f_abs), + msec(EES_STEP_F + EES_STEP_F_GRACE), + subms(EES_STEP_F + EES_STEP_F_GRACE), + ees->second, + sincelast); + if ((delta_f_abs > EES_STEP_NOTE) && ees->last_l.l_i) { + static int ees_step_notes = EES_STEP_NOTES; + if (ees_step_notes > 0) { + ees_step_notes--; + printf("MSF%d: D=%3ld.%04ld@%02d :%d%s\n", + ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec), + ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !"); + msyslog(LOG_ERR, "MSF%d: D=%3d.%04d@%02d :%d%s", + ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step) ? sincelast : -1, ees_step_notes ? "" : " -- NO MORE !"); + } + } + } + } + ees->last_l = ees->arrvtime; + + /* IF we have found that it's ramping + * && it's within twice the expected ramp period + * && there is a non zero step size (avoid /0 !) + * THEN we twiddle things + */ + if (ees->using_ramp && + sincelast < (ees->last_step_secs)*2 && + ees->last_step_secs) + { long sec_of_ramp = sincelast + ees->last_step_late; + long fsecs; + l_fp inc; + + /* Ramp time may vary, so may ramp for longer than last time */ + if (sec_of_ramp > (ees->last_step_secs + 120)) + sec_of_ramp = ees->last_step_secs; + + /* sec_of_ramp * ees->jump_fsecs may overflow 2**32 */ + fsecs = sec_of_ramp * (ees->jump_fsecs / ees->last_step_secs); + + if (debug & DB_LOG_DELTAS) msyslog(LOG_ERR, + "[%x] MSF%d: %3ld/%03d -> d=%11ld (%d|%ld)", + DB_LOG_DELTAS, + ees->unit, sec_of_ramp, ees->last_step_secs, fsecs, + pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs); + if (debug & DB_PRINT_DELTAS) printf( + "MSF%d: %3ld/%03d -> d=%11ld (%ld|%ld)\n", + ees->unit, sec_of_ramp, ees->last_step_secs, fsecs, + (long)pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs); + + /* Must sign extend the result */ + inc.l_i = (fsecs < 0) ? -1 : 0; + inc.l_f = fsecs; + if (debug & DB_INC_PPS) + { L_SUB(&pps_arrvstamp, &inc); + L_SUB(&ees->arrvtime, &inc); + } + else + { L_ADD(&pps_arrvstamp, &inc); + L_ADD(&ees->arrvtime, &inc); + } + } + else { + if (debug & DB_LOG_DELTAS) msyslog(LOG_ERR, + "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x", + DB_LOG_DELTAS, + ees->unit, ees->using_ramp, + sincelast, + (ees->last_step_secs)*2, + ees->last_step_secs); + if (debug & DB_PRINT_DELTAS) printf( + "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x\n", + DB_LOG_DELTAS, + ees->unit, ees->using_ramp, + sincelast, + (ees->last_step_secs)*2, + ees->last_step_secs); + } + + L_SUB(&ees->arrvtime, &offset_fudge[ees->unit]); + L_SUB(&pps_arrvstamp, &offset_fudge[ees->unit]); + + if (call_pps_sample && !(debug & DB_NO_PPS)) { + /* Sigh -- it expects its args negated */ + L_NEG(&pps_arrvstamp); + /* + * I had to disable this here, since it appears there is no pointer to the + * peer structure. + * + (void) pps_sample(peer, &pps_arrvstamp); + */ + } + + /* Subtract off the local clock time stamp */ + L_SUB(&ees->codeoffsets[n_sample], &ees->arrvtime); + if (debug & DB_LOG_SAMPLES) msyslog(LOG_ERR, + "MSF%d: [%x] %d (ees: %d %d) (pps: %d %d)%s", + ees->unit, DB_LOG_DELTAS, n_sample, + ees->codeoffsets[n_sample].l_f, + ees->codeoffsets[n_sample].l_f / 4295, + pps_arrvstamp.l_f, + pps_arrvstamp.l_f /4295, + (debug & DB_NO_PPS) ? " [no PPS]" : ""); + + if (ees->nsamples++ == NCODES-1) ees_process(ees); + + /* Done! */ +} + + +/* offcompare - auxiliary comparison routine for offset sort */ + +static int +offcompare( + l_fp *a, + l_fp *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( + struct eesunit *ees + ) +{ + static int last_samples = -1; + register int i, j; + register int noff; + register l_fp *coffs = ees->codeoffsets; + l_fp offset, tmp; + double dispersion; /* ++++ */ + int lostsync, isinsync; + int samples = ees->nsamples; + int samplelog = 0; /* keep "gcc -Wall" happy ! */ + int samplereduce = (samples + 1) / 2; + double doffset; + + /* Reset things to zero so we don't have to worry later */ + ees_reset(ees); + + if (sloppyclockflag[ees->unit]) { + samplelog = (samples < 2) ? 0 : + (samples < 5) ? 1 : + (samples < 9) ? 2 : + (samples < 17) ? 3 : + (samples < 33) ? 4 : 5; + samplereduce = (1 << samplelog); + } + + if (samples != last_samples && + ((samples != (last_samples-1)) || samples < 3)) { + msyslog(LOG_ERR, "Samples=%d (%d), samplereduce=%d ....", + samples, last_samples, samplereduce); + last_samples = samples; + } + if (samples < 1) return; + + /* If requested, dump the raw data we have in the buffer */ + if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw data is:"); + + /* Sort the offsets, trim off the extremes, then choose one. */ + qsort((char *) coffs, (u_int)samples, sizeof(l_fp), offcompare); + + noff = samples; + i = 0; + while ((noff - i) > samplereduce) { + /* Trim off the sample which is further away + * from the median. We work this out by doubling + * the median, subtracting off the end samples, and + * looking at the sign of the answer, using the + * identity (c-b)-(b-a) == 2*b-a-c + */ + tmp = coffs[(noff + i)/2]; + L_ADD(&tmp, &tmp); + L_SUB(&tmp, &coffs[i]); + L_SUB(&tmp, &coffs[noff-1]); + if (L_ISNEG(&tmp)) noff--; else i++; + } + + /* If requested, dump the reduce data we have in the buffer */ + if (ees->dump_vals) dump_buf(coffs, i, noff, "Reduced to:"); + + /* What we do next depends on the setting of the sloppy clock flag. + * If it is on, average the remainder to derive our estimate. + * Otherwise, just pick a representative value from the remaining stuff + */ + if (sloppyclockflag[ees->unit]) { + offset.l_ui = offset.l_uf = 0; + for (j = i; j < noff; j++) + L_ADD(&offset, &coffs[j]); + for (j = samplelog; j > 0; j--) + L_RSHIFTU(&offset); + } + else offset = coffs[i+BESTSAMPLE]; + + /* Compute the dispersion as the difference between the + * lowest and highest offsets that remain in the + * consideration list. + * + * It looks like MOST clocks have MOD (max error), so halve it ! + */ + tmp = coffs[noff-1]; + L_SUB(&tmp, &coffs[i]); +#define FRACT_SEC(n) ((1 << 30) / (n/2)) + dispersion = LFPTOFP(&tmp) / 2; /* ++++ */ + if (debug & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE)) msyslog( + (debug & DB_SYSLOG_SMPLE) ? LOG_ERR : LOG_INFO, + "I: [%x] Offset=%06d (%d), disp=%f%s [%d], %d %d=%d %d:%d %d=%d %d", + debug & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE), + offset.l_f / 4295, offset.l_f, + (dispersion * 1526) / 100, + (sloppyclockflag[ees->unit]) ? " by averaging" : "", + FRACT_SEC(10) / 4295, + (coffs[0].l_f) / 4295, + i, + (coffs[i].l_f) / 4295, + (coffs[samples/2].l_f) / 4295, + (coffs[i+BESTSAMPLE].l_f) / 4295, + noff-1, + (coffs[noff-1].l_f) / 4295, + (coffs[samples-1].l_f) / 4295); + + /* Are we playing silly wotsits ? + * If we are using all data, see if there is a "small" delta, + * and if so, blurr this with 3/4 of the delta from the last value + */ + if (ees->usealldata && ees->offset.l_uf) { + long diff = (long) (ees->offset.l_uf - offset.l_uf); + + /* is the delta small enough ? */ + if ((- FRACT_SEC(100)) < diff && diff < FRACT_SEC(100)) { + int samd = (64 * 4) / samples; + long new; + if (samd < 2) samd = 2; + new = offset.l_uf + ((diff * (samd -1)) / samd); + + /* Sign change -> need to fix up int part */ + if ((new & (1 << 31)) != + (((long) offset.l_uf) & ( 1 << 31))) + { NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_INFO, "I: %lx != %lx (%lx %lx), 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)) msyslog( + (debug & DB_SYSLOG_SMTHE) ? LOG_ERR : LOG_INFO, + "I: [%x] Smooth data: %ld -> %ld, dispersion now %f", + debug & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE), + ((long) offset.l_uf) / 4295, new / 4295, + (dispersion * 1526) / 100); + offset.l_uf = (unsigned long) new; + } + else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog( + (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO, + "[%x] No smooth as delta not %d < %ld < %d", + debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE), + - FRACT_SEC(100), diff, FRACT_SEC(100)); + } + else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog( + (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO, + "I: [%x] No smooth as flag=%x and old=%x=%d (%d:%d)", + debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE), + ees->usealldata, ees->offset.l_f, ees->offset.l_uf, + offset.l_f, ees->offset.l_f - offset.l_f); + + /* Collect offset info for debugging info */ + ees->offset = offset; + ees->lowoffset = coffs[i]; + ees->highoffset = coffs[noff-1]; + + /* Determine synchronization status. Can be unsync'd either + * by a report from the clock or by a leap hold. + * + * Loss of the radio signal for a short time does not cause + * us to go unsynchronised, since the receiver keeps quite + * good time on its own. The spec says 20ms in 4 hours; the + * observed drift in our clock (Cambridge) is about a second + * a day, but even that keeps us within the inherent tolerance + * of the clock for about 15 minutes. Observation shows that + * the typical "short" outage is 3 minutes, so to allow us + * to ride out those, we will give it 5 minutes. + */ + lostsync = current_time - ees->clocklastgood > 300 ? 1 : 0; + isinsync = (lostsync || ees->leaphold > current_time) ? 0 : 1; + + /* Done. Use time of last good, synchronised code as the + * reference time, and lastsampletime as the receive time. + */ + if (ees->fix_pending) { + msyslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x\n", + ees->fix_pending, ees->unit, offset.l_i, offset.l_f); + ees->fix_pending = 0; + } + LFPTOD(&offset, doffset); + refclock_receive(ees->peer); + ees_event(ees, lostsync ? CEVNT_PROP : CEVNT_NOMINAL); +} + +/* msfees_poll - called by the transmit procedure */ +static void +msfees_poll( + int unit, + struct peer *peer + ) +{ + if (unit >= MAXUNITS) { + msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d invalid", + unit); + return; + } + if (!unitinuse[unit]) { + msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d unused", + unit); + return; + } + + ees_process(eesunits[unit]); + + if ((current_time - eesunits[unit]->lasttime) > 150) + ees_event(eesunits[unit], CEVNT_FAULT); +} + + +#else +int refclock_msfees_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_mx4200.c b/contrib/ntp/ntpd/refclock_mx4200.c new file mode 100644 index 000000000000..28f563f8a809 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_mx4200.c @@ -0,0 +1,1774 @@ +/* + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66. + * + * Copyright (c) 1992 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * 4. The name of the University may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Modified: Marc Brett Sept, 1999. + * + * 1. Added support for alternate PPS schemes, with code mostly + * copied from the Oncore driver (Thanks, Poul-Henning Kamp). + * This code runs on SunOS 4.1.3 with ppsclock-1.6a1 and Solaris 7. + */ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_MX4200) && defined(PPS) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +#include "mx4200.h" + +#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_SYS_TERMIOS_H +# include +#endif +#ifdef HAVE_SYS_PPSCLOCK_H +# include +#endif + +#ifndef HAVE_STRUCT_PPSCLOCKEV +struct ppsclockev { +# ifdef HAVE_TIMESPEC + struct timespec tv; +# else + struct timeval tv; +# endif + u_int serial; +}; +#endif /* ! HAVE_STRUCT_PPSCLOCKEV */ + +/* + * This driver supports the Magnavox Model MX 4200 GPS Receiver + * adapted to precision timing applications. It requires the + * ppsclock line discipline or streams module described in the + * Line Disciplines and Streams Drivers page. It also requires a + * gadget box and 1-PPS level converter, such as described in the + * Pulse-per-second (PPS) Signal Interfacing page. + * + * It's likely that other compatible Magnavox receivers such as the + * MX 4200D, MX 9212, MX 9012R, MX 9112 will be supported by this code. + */ + +/* + * Check this every time you edit the code! + */ +#define YEAR_RIGHT_NOW 1998 + +/* + * GPS Definitions + */ +#define DEVICE "/dev/gps%d" /* device name and unit */ +#define SPEED232 B4800 /* baud */ + +/* + * Radio interface parameters + */ +#define PRECISION (-18) /* precision assumed (about 4 us) */ +#define REFID "GPS\0" /* reference id */ +#define DESCRIPTION "Magnavox MX4200 GPS Receiver" /* who we are */ +#define DEFFUDGETIME 0 /* default fudge time (ms) */ + +#define SLEEPTIME 32 /* seconds to wait for reconfig to complete */ + +/* + * Position Averaging. + * Reference: Dr. Thomas A. Clark's Totally Accurate Clock (TAC) files at + * ftp://aleph.gsfc.nasa.gov/GPS/totally.accurate.clock/ + * For a 6-channel Motorola Oncore, he indicates that good nominal + * HDOP and VDOP are 1.50 and 2.00 respectively. Given the relationship + * HDOP^2 = NDOP^2 + EDOP^2 and assuming EDOP and NDOP are equal, we + * have a nominal NDOP = EDOP = sqrt((HDOP*HDOP)/2). An 8-channel + * Oncore does well with HDOP=1.20 and VDOP=1.70. + */ +#define INTERVAL 1 /* Interval between position measurements (s) */ +#define AVGING_TIME 24 /* Number of hours to average */ +#define USUAL_EDOP 1.06066 /* used for normalizing EDOP */ +#define USUAL_NDOP 1.06066 /* used for normalizing NDOP */ +#define USUAL_VDOP 2.00 /* used for normalizing VDOP */ +#define NOT_INITIALIZED -9999. /* initial pivot longitude */ + +/* + * MX4200 unit control structure. + */ +struct mx4200unit { + u_int pollcnt; /* poll message counter */ + u_int polled; /* Hand in a time sample? */ + u_int lastserial; /* last pps serial number */ + struct ppsclockev ppsev; /* PPS control structure */ + double avg_lat; /* average latitude */ + double avg_lon; /* average longitude */ + double avg_alt; /* average height */ + double central_meridian; /* central meridian */ + double filt_lat; /* latitude filter length */ + double filt_lon; /* longitude filter length */ + double filt_alt; /* height filter length */ + double edop; /* EDOP (east DOP) */ + double ndop; /* NDOP (north DOP) */ + double vdop; /* VDOP (vertical DOP) */ + int last_leap; /* leap second warning */ + u_int moving; /* mobile platform? */ + u_long sloppyclockflag; /* fudge flags */ + u_int known; /* position known yet? */ + u_long clamp_time; /* when to stop postion averaging */ + u_long log_time; /* when to print receiver status */ +}; + +static char pmvxg[] = "PMVXG"; + +/* XXX should be somewhere else */ +#ifdef __GNUC__ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +#ifndef __attribute__ +#define __attribute__(args) +#endif +#endif +#else +#ifndef __attribute__ +#define __attribute__(args) +#endif +#endif +/* XXX end */ + +/* + * Function prototypes + */ +static int mx4200_start P((int, struct peer *)); +static void mx4200_shutdown P((int, struct peer *)); +static void mx4200_receive P((struct recvbuf *)); +static void mx4200_poll P((int, struct peer *)); + +static char * mx4200_parse_t P((struct peer *)); +static char * mx4200_parse_p P((struct peer *)); +static char * mx4200_parse_d P((struct peer *)); +static char * mx4200_parse_s P((struct peer *)); +#ifdef QSORT_USES_VOID_P +int mx4200_cmpl_fp P((const void *, const void *)); +#else +int mx4200_cmpl_fp P((const l_fp *, const l_fp *)); +#endif /* not QSORT_USES_VOID_P */ +static void mx4200_config P((struct peer *)); +static void mx4200_ref P((struct peer *)); +static void mx4200_send P((struct peer *, char *, ...)) + __attribute__ ((format (printf, 2, 3))); +static u_char mx4200_cksum P((char *, int)); +static int mx4200_jday P((int, int, int)); +static void mx4200_debug P((struct peer *, char *, ...)) + __attribute__ ((format (printf, 2, 3))); +static int mx4200_pps P((struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_mx4200 = { + mx4200_start, /* start up driver */ + mx4200_shutdown, /* shut down driver */ + mx4200_poll, /* transmit poll message */ + noentry, /* not used (old mx4200_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old mx4200_buginfo) */ + NOFLAGS /* not used */ +}; + + + +/* + * mx4200_start - open the devices and initialize data for processing + */ +static int +mx4200_start( + int unit, + struct peer *peer + ) +{ + register struct mx4200unit *up; + struct refclockproc *pp; + int fd; + char gpsdev[20]; + +#ifdef HAVE_TIOCGPPSEV +#ifdef HAVE_TERMIOS + struct termios ttyb; +#endif /* HAVE_TERMIOS */ +#ifdef HAVE_SYSV_TTYS + struct termio ttyb; +#endif /* HAVE_SYSV_TTYS */ +#ifdef HAVE_BSD_TTYS + struct sgttyb ttyb; +#endif /* HAVE_BSD_TTYS */ +#endif /* HAVE_TIOCGPPSEV */ + + /* + * Open serial port + */ + (void)sprintf(gpsdev, DEVICE, unit); + if (!(fd = refclock_open(gpsdev, SPEED232, LDISC_PPS))) { + return (0); + } +#ifdef HAVE_TIOCGPPSEV + if (fdpps > 0) { + /* + * Truly nasty hack in order to get this to work on Solaris 7. + * Really, refclock_open() should set the port properly, but + * it doesn't work (as of ntp-4.0.98a) - almost 99% dropped + * PPS signals with "Interrupted system call". Even this + * still gives a 5% error rate. + */ + ttyb.c_iflag = IGNCR; + ttyb.c_oflag = 0; + ttyb.c_cflag = CS8 | CREAD | CLOCAL; + ttyb.c_lflag = ICANON; + if (tcsetattr(fdpps, TCSAFLUSH, &ttyb) < 0) { + return (0); + } + } +#endif /* HAVE_TIOCGPPSEV */ + + /* + * Allocate unit structure + */ + if (!(up = (struct mx4200unit *) emalloc(sizeof(struct mx4200unit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct mx4200unit)); + pp = peer->procptr; + pp->io.clock_recv = mx4200_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + + /* Ensure the receiver is properly configured */ + mx4200_config(peer); + return (1); +} + + +/* + * mx4200_shutdown - shut down the clock + */ +static void +mx4200_shutdown( + int unit, + struct peer *peer + ) +{ + register struct mx4200unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * mx4200_config - Configure the receiver + */ +static void +mx4200_config( + struct peer *peer + ) +{ + char tr_mode; + int add_mode; + register struct mx4200unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + /* + * Initialize the unit variables + * + * STRANGE BEHAVIOUR WARNING: The fudge flags are not available + * at the time mx4200_start is called. These are set later, + * and so the code must be prepared to handle changing flags. + */ + up->sloppyclockflag = pp->sloppyclockflag; + if (pp->sloppyclockflag & CLK_FLAG2) { + up->moving = 1; /* Receiver on mobile platform */ + msyslog(LOG_DEBUG, "mx4200_config: mobile platform"); + } else { + up->moving = 0; /* Static Installation */ + } + up->pollcnt = 2; + up->polled = 0; + up->known = 0; + up->avg_lat = 0.0; + up->avg_lon = 0.0; + up->avg_alt = 0.0; + up->central_meridian = NOT_INITIALIZED; + up->filt_lat = 0.0; + up->filt_lon = 0.0; + up->filt_alt = 0.0; + up->edop = USUAL_EDOP; + up->ndop = USUAL_NDOP; + up->vdop = USUAL_VDOP; + up->last_leap = 0; /* LEAP_NOWARNING */ + up->clamp_time = current_time + (AVGING_TIME * 60 * 60); + up->log_time = current_time + SLEEPTIME; + + /* + * "007" Control Port Configuration + * Zero the output list (do it twice to flush possible junk) + */ + mx4200_send(peer, "%s,%03d,,%d,,,,,,", pmvxg, + PMVXG_S_PORTCONF, + /* control port output block Label */ + 1); /* clear current output control list (1=yes) */ + /* add/delete sentences from list */ + /* must be null */ + /* sentence output rate (sec) */ + /* precision for position output */ + /* nmea version for cga & gll output */ + /* pass-through control */ + mx4200_send(peer, "%s,%03d,,%d,,,,,,", pmvxg, + PMVXG_S_PORTCONF, 1); + + /* + * Request software configuration so we can syslog the firmware version + */ + mx4200_send(peer, "%s,%03d", "CDGPQ", PMVXG_D_SOFTCONF); + + /* + * "001" Initialization/Mode Control, Part A + * Where ARE we? + */ + mx4200_send(peer, "%s,%03d,,,,,,,,,,", pmvxg, + PMVXG_S_INITMODEA); + /* day of month */ + /* month of year */ + /* year */ + /* gmt */ + /* latitude DDMM.MMMM */ + /* north/south */ + /* longitude DDDMM.MMMM */ + /* east/west */ + /* height */ + /* Altitude Reference 1=MSL */ + + /* + * "001" Initialization/Mode Control, Part B + * Start off in 2d/3d coast mode, holding altitude to last known + * value if only 3 satellites available. + */ + mx4200_send(peer, "%s,%03d,%d,,%.1f,%.1f,%d,%d,%d,%c,%d", + pmvxg, PMVXG_S_INITMODEB, + 3, /* 2d/3d coast */ + /* reserved */ + 0.1, /* hor accel fact as per Steve (m/s**2) */ + 0.1, /* ver accel fact as per Steve (m/s**2) */ + 10, /* vdop */ + 10, /* hdop limit as per Steve */ + 5, /* elevation limit as per Steve (deg) */ + 'U', /* time output mode (UTC) */ + 0); /* local time offset from gmt (HHHMM) */ + + /* + * "023" Time Recovery Configuration + * Get UTC time from a stationary receiver. + * (Set field 1 'D' == dynamic if we are on a moving platform). + * (Set field 1 'S' == static if we are not moving). + * (Set field 1 'K' == known position if we can initialize lat/lon/alt). + */ + + if (pp->sloppyclockflag & CLK_FLAG2) + up->moving = 1; /* Receiver on mobile platform */ + else + up->moving = 0; /* Static Installation */ + + up->pollcnt = 2; + if (up->moving) { + /* dynamic: solve for pos, alt, time, while moving */ + tr_mode = 'D'; + } else { + /* static: solve for pos, alt, time, while stationary */ + tr_mode = 'S'; + } + mx4200_send(peer, "%s,%03d,%c,%c,%c,%d,%d,%d,", pmvxg, + PMVXG_S_TRECOVCONF, + tr_mode, /* time recovery mode (see above ) */ + 'U', /* synchronize to UTC */ + 'A', /* always output a time pulse */ + 500, /* max time error in ns */ + 0, /* user bias in ns */ + 1); /* output "830" sentences to control port */ + /* Multi-satellite mode */ + + /* + * Output position information (to calculate fixed installation + * location) only if we are not moving + */ + if (up->moving) { + add_mode = 2; /* delete from list */ + } else { + add_mode = 1; /* add to list */ + } + + /* + * "007" Control Port Configuration + * Output "022" DOPs + */ + mx4200_send(peer, "%s,%03d,%03d,%d,%d,,%d,,,", pmvxg, + PMVXG_S_PORTCONF, + PMVXG_D_DOPS, /* control port output block Label */ + 0, /* clear current output control list (0=no) */ + add_mode, /* add/delete sentences from list (1=add, 2=del) */ + /* must be null */ + INTERVAL); /* sentence output rate (sec) */ + /* precision for position output */ + /* nmea version for cga & gll output */ + /* pass-through control */ + + + /* + * "007" Control Port Configuration + * Output "021" position, height, velocity reports + */ + mx4200_send(peer, "%s,%03d,%03d,%d,%d,,%d,,,", pmvxg, + PMVXG_S_PORTCONF, + PMVXG_D_PHV, /* control port output block Label */ + 0, /* clear current output control list (0=no) */ + add_mode, /* add/delete sentences from list (1=add, 2=del) */ + /* must be null */ + INTERVAL); /* sentence output rate (sec) */ + /* precision for position output */ + /* nmea version for cga & gll output */ + /* pass-through control */ +} + +/* + * mx4200_ref - Reconfigure unit as a reference station at a known position. + */ +static void +mx4200_ref( + struct peer *peer + ) +{ + register struct mx4200unit *up; + struct refclockproc *pp; + double minute, lat, lon, alt; + char lats[16], lons[16]; + char nsc, ewc; + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + /* Should never happen! */ + if (up->moving) return; + + /* + * Set up to output status information in the near future + */ + up->log_time = current_time + SLEEPTIME; + + /* + * "007" Control Port Configuration + * Stop outputting "022" DOPs + */ + mx4200_send(peer, "%s,%03d,%03d,%d,%d,,,,,", pmvxg, + PMVXG_S_PORTCONF, + PMVXG_D_DOPS, /* control port output block Label */ + 0, /* clear current output control list (0=no) */ + 2); /* add/delete sentences from list (2=delete) */ + /* must be null */ + /* sentence output rate (sec) */ + /* precision for position output */ + /* nmea version for cga & gll output */ + /* pass-through control */ + + /* + * "007" Control Port Configuration + * Stop outputting "021" position, height, velocity reports + */ + mx4200_send(peer, "%s,%03d,%03d,%d,%d,,,,,", pmvxg, + PMVXG_S_PORTCONF, + PMVXG_D_PHV, /* control port output block Label */ + 0, /* clear current output control list (0=no) */ + 2); /* add/delete sentences from list (2=delete) */ + /* must be null */ + /* sentence output rate (sec) */ + /* precision for position output */ + /* nmea version for cga & gll output */ + /* pass-through control */ + + /* + * "001" Initialization/Mode Control, Part B + * Put receiver in fully-constrained 2d nav mode + */ + mx4200_send(peer, "%s,%03d,%d,,%.1f,%.1f,%d,%d,%d,%c,%d", + pmvxg, PMVXG_S_INITMODEB, + 2, /* 2d nav */ + /* reserved */ + 0.1, /* hor accel fact as per Steve (m/s**2) */ + 0.1, /* ver accel fact as per Steve (m/s**2) */ + 10, /* vdop */ + 10, /* hdop limit as per Steve */ + 5, /* elevation limit as per Steve (deg) */ + 'U', /* time output mode (UTC) */ + 0); /* local time offset from gmt (HHHMM) */ + + /* + * "023" Time Recovery Configuration + * Get UTC time from a stationary receiver. Solve for time only. + * This should improve the time resolution dramatically. + */ + mx4200_send(peer, "%s,%03d,%c,%c,%c,%d,%d,%d,", pmvxg, + PMVXG_S_TRECOVCONF, + 'K', /* known position: solve for time only */ + 'U', /* synchronize to UTC */ + 'A', /* always output a time pulse */ + 500, /* max time error in ns */ + 0, /* user bias in ns */ + 1); /* output "830" sentences to control port */ + /* Multi-satellite mode */ + + /* + * "000" Initialization/Mode Control - Part A + * Fix to our averaged position. + */ + if (up->central_meridian != NOT_INITIALIZED) { + up->avg_lon += up->central_meridian; + if (up->avg_lon < -180.0) up->avg_lon += 360.0; + if (up->avg_lon > 180.0) up->avg_lon -= 360.0; + } + + if (up->avg_lat >= 0.0) { + lat = up->avg_lat; + nsc = 'N'; + } else { + lat = up->avg_lat * (-1.0); + nsc = 'S'; + } + if (up->avg_lon >= 0.0) { + lon = up->avg_lon; + ewc = 'E'; + } else { + lon = up->avg_lon * (-1.0); + ewc = 'W'; + } + alt = up->avg_alt; + minute = (lat - (double)(int)lat) * 60.0; + sprintf(lats,"%02d%02.4f", (int)lat, minute); + minute = (lon - (double)(int)lon) * 60.0; + sprintf(lons,"%03d%02.4f", (int)lon, minute); + + mx4200_send(peer, "%s,%03d,,,,,%s,%c,%s,%c,%.2f,", pmvxg, + PMVXG_S_INITMODEA, + /* day of month */ + /* month of year */ + /* year */ + /* gmt */ + lats, /* latitude DDMM.MMMM */ + nsc, /* north/south */ + lons, /* longitude DDDMM.MMMM */ + ewc, /* east/west */ + alt); /* Altitude */ + /* Altitude Reference */ + + msyslog(LOG_DEBUG, + "mx4200: reconfig to fixed location: %s %c, %s %c, %.2f m", + lats, nsc, lons, ewc, alt ); + +} + +/* + * mx4200_poll - mx4200 watchdog routine + */ +static void +mx4200_poll( + int unit, + struct peer *peer + ) +{ + register struct mx4200unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + /* + * You don't need to poll this clock. It puts out timecodes + * once per second. If asked for a timestamp, take note. + * The next time a timecode comes in, it will be fed back. + */ + + /* + * If we haven't had a response in a while, reset the receiver. + */ + if (up->pollcnt > 0) { + up->pollcnt--; + } else { + refclock_report(peer, CEVNT_TIMEOUT); + + /* + * Request a "000" status message which should trigger a + * reconfig + */ + mx4200_send(peer, "%s,%03d", + "CDGPQ", /* query from CDU to GPS */ + PMVXG_D_STATUS); /* label of desired sentence */ + } + + /* + * polled every 64 seconds. Ask mx4200_receive to hand in + * a timestamp. + */ + up->polled = 1; + pp->polls++; + + /* + * Output receiver status information. + */ + if ((up->log_time > 0) && (current_time > up->log_time)) { + up->log_time = 0; + /* + * Output the following messages once, for debugging. + * "004" Mode Data + * "523" Time Recovery Parameters + */ + mx4200_send(peer, "%s,%03d", "CDGPQ", PMVXG_D_MODEDATA); + mx4200_send(peer, "%s,%03d", "CDGPQ", PMVXG_D_TRECOVUSEAGE); + } +} + +static char char2hex[] = "0123456789ABCDEF"; + +/* + * mx4200_receive - receive gps data + */ +static void +mx4200_receive( + struct recvbuf *rbufp + ) +{ + register struct mx4200unit *up; + struct refclockproc *pp; + struct peer *peer; + char *cp; + int sentence_type; + u_char ck; + + /* + * Initialize pointers and read the timecode and timestamp. + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + /* + * If operating mode has been changed, then reinitialize the receiver + * before doing anything else. + */ + if ((pp->sloppyclockflag & CLK_FLAG2) != + (up->sloppyclockflag & CLK_FLAG2)) { + up->sloppyclockflag = pp->sloppyclockflag; + mx4200_debug(peer, + "mx4200_receive: mode switch: reset receiver\n"); + mx4200_config(peer); + return; + } + up->sloppyclockflag = pp->sloppyclockflag; + + /* + * Read clock output. Automatically handles STREAMS, CLKLDISC. + */ + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); + + /* + * There is a case where generates 2 timestamps. + */ + if (pp->lencode == 0) + return; + + up->pollcnt = 2; + pp->a_lastcode[pp->lencode] = '\0'; + record_clock_stats(&peer->srcadr, pp->a_lastcode); + mx4200_debug(peer, "mx4200_receive: %d %s\n", + pp->lencode, pp->a_lastcode); + + /* + * The structure of the control port sentences is based on the + * NMEA-0183 Standard for interfacing Marine Electronics + * Navigation Devices (Version 1.5) + * + * $PMVXG,XXX, ....................*CK + * + * $ Sentence Start Identifier (reserved char) + * (Start-of-Sentence Identifier) + * P Special ID (Proprietary) + * MVX Originator ID (Magnavox) + * G Interface ID (GPS) + * , Field Delimiters (reserved char) + * XXX Sentence Type + * ...... Data + * * Checksum Field Delimiter (reserved char) + * CK Checksum + * Carriage-Return/Line Feed (reserved chars) + * (End-of-Sentence Identifier) + * + * Reject if any important landmarks are missing. + */ + cp = pp->a_lastcode + pp->lencode - 3; + if (cp < pp->a_lastcode || *pp->a_lastcode != '$' || cp[0] != '*' ) { + mx4200_debug(peer, "mx4200_receive: bad format\n"); + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Check and discard the checksum + */ + ck = mx4200_cksum(&pp->a_lastcode[1], pp->lencode - 4); + if (char2hex[ck >> 4] != cp[1] || char2hex[ck & 0xf] != cp[2]) { + mx4200_debug(peer, "mx4200_receive: bad checksum\n"); + refclock_report(peer, CEVNT_BADREPLY); + return; + } + *cp = '\0'; + + /* + * Get the sentence type. + */ + sentence_type = 0; + if ((cp = strchr(pp->a_lastcode, ',')) == NULL) { + mx4200_debug(peer, "mx4200_receive: no sentence\n"); + refclock_report(peer, CEVNT_BADREPLY); + return; + } + cp++; + sentence_type = strtol(cp, &cp, 10); + + /* + * "000" Status message + */ + + if (sentence_type == PMVXG_D_STATUS) { + /* + * XXX + * Since we configure the receiver to not give us status + * messages and since the receiver outputs status messages by + * default after being reset to factory defaults when sent the + * "$PMVXG,018,C\r\n" message, any status message we get + * indicates the reciever needs to be initialized; thus, it is + * not necessary to decode the status message. + */ + if ((cp = mx4200_parse_s(peer)) != NULL) { + mx4200_debug(peer, + "mx4200_receive: status: %s\n", cp); + } + mx4200_debug(peer, "mx4200_receive: reset receiver\n"); + mx4200_config(peer); + return; + } + + /* + * "021" Position, Height, Velocity message, + * if we are still averaging our position + */ + if (sentence_type == PMVXG_D_PHV && !up->known) { + /* + * Parse the message, calculating our averaged position. + */ + if ((cp = mx4200_parse_p(peer)) != NULL) { + mx4200_debug(peer, "mx4200_receive: pos: %s\n", cp); + return; + } + mx4200_debug(peer, + "mx4200_receive: position avg %.9f %.9f %.4f\n", + up->avg_lat, up->avg_lon, up->avg_alt); + mx4200_debug(peer, + "mx4200_receive: position len %.4f %.4f %.4f\n", + up->filt_lat, up->filt_lon, up->filt_alt); + mx4200_debug(peer, + "mx4200_receive: position dop %.1f %.1f %.1f\n", + up->ndop, up->edop, up->vdop); + /* + * Reinitialize as a reference station + * if position is well known. + */ + if (current_time > up->clamp_time) { + up->known++; + mx4200_debug(peer, "mx4200_receive: reconfiguring!\n"); + mx4200_ref(peer); + } + return; + } + + /* + * "022" DOPs, if we are still averaging our position + */ + if (sentence_type == PMVXG_D_DOPS && !up->known) { + if ((cp = mx4200_parse_d(peer)) != NULL) { + mx4200_debug(peer, "mx4200_receive: dop: %s\n", cp); + return; + } + return; + } + + /* + * Print to the syslog: + * "004" Mode Data + * "030" Software Configuration + * "523" Time Recovery Parameters Currently in Use + */ + if (sentence_type == PMVXG_D_MODEDATA || + sentence_type == PMVXG_D_SOFTCONF || + sentence_type == PMVXG_D_TRECOVUSEAGE ) { + if ((cp = mx4200_parse_s(peer)) != NULL) { + mx4200_debug(peer, + "mx4200_receive: multi-record: %s\n", cp); + return; + } + return; + } + + /* + * "830" Time Recovery Results message + */ + if (sentence_type == PMVXG_D_TRECOVOUT) { + + /* + * Capture the last PPS signal. + * Precision timestamp is returned in pp->lastrec + */ + if (mx4200_pps(peer) != NULL) { + mx4200_debug(peer, "mx4200_receive: pps failure\n"); + refclock_report(peer, CEVNT_FAULT); + return; + } + + + /* + * Parse the time recovery message, and keep the info + * to print the pretty billboards. + */ + if ((cp = mx4200_parse_t(peer)) != NULL) { + mx4200_debug(peer, "mx4200_receive: time: %s\n", cp); + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Add the new sample to a median filter. + */ + if (!refclock_process(pp)) { + mx4200_debug(peer,"mx4200_receive: offset: %.6f\n", + pp->offset); + refclock_report(peer, CEVNT_BADTIME); + return; + } + + /* + * The clock will blurt a timecode every second but we only + * want one when polled. If we havn't been polled, bail out. + */ + if (!up->polled) + return; + + /* + * Return offset and dispersion to control module. We use + * lastrec as both the reference time and receive time in + * order to avoid being cute, like setting the reference time + * later than the receive time, which may cause a paranoid + * protocol module to chuck out the data. + */ + mx4200_debug(peer, "mx4200_receive: process time: "); + mx4200_debug(peer, "%4d-%03d %02d:%02d:%02d at %s, %.6f\n", + pp->year, pp->day, pp->hour, pp->minute, pp->second, + prettydate(&pp->lastrec), pp->offset); + + refclock_receive(peer); + + /* + * We have succeeded in answering the poll. + * Turn off the flag and return + */ + up->polled = 0; + return; + } + + /* + * Ignore all other sentence types + */ + return; +} + + +/* + * Parse a mx4200 time recovery message. Returns a string if error. + * + * A typical message looks like this. Checksum has already been stripped. + * + * $PMVXG,830,T,YYYY,MM,DD,HH:MM:SS,U,S,FFFFFF,PPPPP,BBBBBB,LL + * + * Field Field Contents + * ----- -------------- + * Block Label: $PMVXG + * Sentence Type: 830=Time Recovery Results + * This sentence is output approximately 1 second + * preceding the 1PPS output. It indicates the + * exact time of the next pulse, whether or not the + * time mark will be valid (based on operator-specified + * error tolerance), the time to which the pulse is + * synchronized, the receiver operating mode, + * and the time error of the *last* 1PPS output. + * 1 char Time Mark Valid: T=Valid, F=Not Valid + * 2 int Year: 1993- + * 3 int Month of Year: 1-12 + * 4 int Day of Month: 1-31 + * 5 int Time of Day: HH:MM:SS + * 6 char Time Synchronization: U=UTC, G=GPS + * 7 char Time Recovery Mode: D=Dynamic, S=Static, + * K=Known Position, N=No Time Recovery + * 8 int Oscillator Offset: The filter's estimate of the oscillator + * frequency error, in parts per billion (ppb). + * 9 int Time Mark Error: The computed error of the *last* pulse + * output, in nanoseconds. + * 10 int User Time Bias: Operator specified bias, in nanoseconds + * 11 int Leap Second Flag: Indicates that a leap second will + * occur. This value is usually zero, except during + * the week prior to the leap second occurence, when + * this value will be set to +1 or -1. A value of + * +1 indicates that GPS time will be 1 second + * further ahead of UTC time. + * + */ +static char * +mx4200_parse_t( + struct peer *peer + ) +{ + struct refclockproc *pp; + struct mx4200unit *up; + char time_mark_valid, time_sync, op_mode; + int sentence_type, valid; + int year, day_of_year, month, day_of_month, hour, minute, second, leapsec; + int oscillator_offset, time_mark_error, time_bias; + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + leapsec = 0; /* Not all receivers output leap second warnings (!) */ + sscanf(pp->a_lastcode, "$PMVXG,%d,%c,%d,%d,%d,%d:%d:%d,%c,%c,%d,%d,%d,%d", + &sentence_type, &time_mark_valid, &year, &month, &day_of_month, + &hour, &minute, &second, &time_sync, &op_mode, &oscillator_offset, + &time_mark_error, &time_bias, &leapsec); + + if (sentence_type != PMVXG_D_TRECOVOUT) + return ("wrong rec-type"); + + switch (time_mark_valid) { + case 'T': + valid = 1; + break; + case 'F': + valid = 0; + break; + default: + return ("bad pulse-valid"); + } + + switch (time_sync) { + case 'G': + return ("synchronized to GPS; should be UTC"); + case 'U': + break; /* UTC -> ok */ + default: + return ("not synchronized to UTC"); + } + + /* + * Check for insane time (allow for possible leap seconds) + */ + if (second > 60 || minute > 59 || hour > 23 || + second < 0 || minute < 0 || hour < 0) { + mx4200_debug(peer, + "mx4200_parse_t: bad time %02d:%02d:%02d", + hour, minute, second); + if (leapsec != 0) + mx4200_debug(peer, " (leap %+d\n)", leapsec); + mx4200_debug(peer, "\n"); + refclock_report(peer, CEVNT_BADTIME); + return ("bad time"); + } + if ( second == 60 ) { + msyslog(LOG_DEBUG, + "mx4200: leap second! %02d:%02d:%02d", + hour, minute, second); + } + + /* + * Check for insane date + * (Certainly can't be any year before this code was last altered!) + */ + if (day_of_month > 31 || month > 12 || + day_of_month < 1 || month < 1 || year < YEAR_RIGHT_NOW) { + mx4200_debug(peer, + "mx4200_parse_t: bad date (%4d-%02d-%02d)\n", + year, month, day_of_month); + refclock_report(peer, CEVNT_BADDATE); + return ("bad date"); + } + + /* + * Silly Hack for MX4200: + * ASCII message is for *next* 1PPS signal, but we have the + * timestamp for the *last* 1PPS signal. So we have to subtract + * a second. Discard if we are on a month boundary to avoid + * possible leap seconds and leap days. + */ + second--; + if (second < 0) { + second = 59; + minute--; + if (minute < 0) { + minute = 59; + hour--; + if (hour < 0) { + hour = 23; + day_of_month--; + if (day_of_month < 1) { + return ("sorry, month boundary"); + } + } + } + } + + /* + * Calculate Julian date + */ + if (!(day_of_year = mx4200_jday(year, month, day_of_month))) { + mx4200_debug(peer, + "mx4200_parse_t: bad julian date %d (%4d-%02d-%02d)\n", + day_of_year, year, month, day_of_month); + refclock_report(peer, CEVNT_BADDATE); + return("invalid julian date"); + } + + /* + * Setup leap second indicator + */ + switch (leapsec) { + case 0: + pp->leap = LEAP_NOWARNING; + break; + case 1: + pp->leap = LEAP_ADDSECOND; + break; + case -1: + pp->leap = LEAP_DELSECOND; + break; + default: + pp->leap = LEAP_NOTINSYNC; + } + + /* + * Any change to the leap second warning status? + */ + if (leapsec != up->last_leap ) { + msyslog(LOG_DEBUG, + "mx4200: leap second warning: %d to %d (%d)", + up->last_leap, leapsec, pp->leap); + } + up->last_leap = leapsec; + + /* + * Copy time data for billboard monitoring. + */ + + pp->year = year; + pp->day = day_of_year; + pp->hour = hour; + pp->minute = minute; + pp->second = second; + pp->msec = 0; + pp->usec = 0; + + /* + * Toss if sentence is marked invalid + */ + if (!valid || pp->leap == LEAP_NOTINSYNC) { + mx4200_debug(peer, "mx4200_parse_t: time mark not valid\n"); + refclock_report(peer, CEVNT_BADTIME); + return ("pulse invalid"); + } + + return (NULL); +} + +/* + * Calculate the checksum + */ +static u_char +mx4200_cksum( + register char *cp, + register int n + ) +{ + register u_char ck; + + for (ck = 0; n-- > 0; cp++) + ck ^= *cp; + return (ck); +} + +/* + * Tables to compute the day of year. Viva la leap. + */ +static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* + * Calculate the the Julian Day + */ +static int +mx4200_jday( + int year, + int month, + int day_of_month + ) +{ + register int day, i; + int leap_year; + + /* + * Is this a leap year ? + */ + if (year % 4) { + leap_year = 0; /* FALSE */ + } else { + if (year % 100) { + leap_year = 1; /* TRUE */ + } else { + if (year % 400) { + leap_year = 0; /* FALSE */ + } else { + leap_year = 1; /* TRUE */ + } + } + } + + /* + * Calculate the Julian Date + */ + day = day_of_month; + + if (leap_year) { + /* a leap year */ + if (day > day2tab[month - 1]) { + return (0); + } + for (i = 0; i < month - 1; i++) + day += day2tab[i]; + } else { + /* not a leap year */ + if (day > day1tab[month - 1]) { + return (0); + } + for (i = 0; i < month - 1; i++) + day += day1tab[i]; + } + return (day); +} + +/* + * Parse a mx4200 position/height/velocity sentence. + * + * A typical message looks like this. Checksum has already been stripped. + * + * $PMVXG,021,SSSSSS.SS,DDMM.MMMM,N,DDDMM.MMMM,E,HHHHH.H,GGGG.G,EEEE.E,WWWW.W,MM + * + * Field Field Contents + * ----- -------------- + * Block Label: $PMVXG + * Sentence Type: 021=Position, Height Velocity Data + * This sentence gives the receiver position, height, + * navigation mode, and velocity north/east. + * *This sentence is intended for post-analysis + * applications.* + * 1 float UTC measurement time (seconds into week) + * 2 float WGS-84 Lattitude (degrees, minutes) + * 3 char N=North, S=South + * 4 float WGS-84 Longitude (degrees, minutes) + * 5 char E=East, W=West + * 6 float Altitude (meters above mean sea level) + * 7 float Geoidal height (meters) + * 8 float East velocity (m/sec) + * 9 float West Velocity (m/sec) + * 10 int Navigation Mode + * Mode if navigating: + * 1 = Position from remote device + * 2 = 2-D position + * 3 = 3-D position + * 4 = 2-D differential position + * 5 = 3-D differential position + * 6 = Static + * 8 = Position known -- reference station + * 9 = Position known -- Navigator + * Mode if not navigating: + * 51 = Too few satellites + * 52 = DOPs too large + * 53 = Position STD too large + * 54 = Velocity STD too large + * 55 = Too many iterations for velocity + * 56 = Too many iterations for position + * 57 = 3 sat startup failed + * 58 = Command abort + */ +static char * +mx4200_parse_p( + struct peer *peer + ) +{ + struct refclockproc *pp; + struct mx4200unit *up; + int sentence_type, mode; + double mtime, lat, lon, alt, geoid, vele, veln, weight; + char north_south, east_west; + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + /* Should never happen! */ + if (up->moving) return ("mobile platform - no pos!"); + + sscanf ( pp->a_lastcode, "$PMVXG,%d,%lf,%lf,%c,%lf,%c,%lf,%lf,%lf,%lf,%d", + &sentence_type, &mtime, &lat, &north_south, &lon, &east_west, &alt, + &geoid, &vele, &veln, &mode); + + /* Sentence type */ + if (sentence_type != PMVXG_D_PHV) + return ("wrong rec-type"); + + /* + * return if not navigating + */ + if (mode > 10) + return ("not navigating"); + if (mode != 3 && mode != 5) + return ("not navigating in 3D"); + + /* Latitude (always +ve) and convert DDMM.MMMM to decimal */ + if (lat < 0.0) return ("negative latitude"); + if (lat > 9000.0) lat = 9000.0; + lat *= 0.01; + lat = ((int)lat) + (((lat - (int)lat)) * 1.6666666666666666); + + /* North/South */ + switch (north_south) { + case 'N': + break; + case 'S': + lat *= -1.0; + break; + default: + return ("invalid north/south indicator"); + } + + /* Longitude (always +ve) and convert DDDMM.MMMM to decimal */ + if (lon < 0.0) return ("negative longitude"); + if (lon > 180.0) lon = 180.0; + lon *= 0.01; + lon = ((int)lon) + (((lon - (int)lon)) * 1.6666666666666666); + + /* East/West */ + switch (east_west) { + case 'E': + break; + case 'W': + lon *= -1.0; + break; + default: + return ("invalid east/west indicator"); + } + + /* + * Normalize longitude to near 0 degrees. + * Assume all data are clustered around first reading. + */ + if (up->central_meridian == NOT_INITIALIZED) { + up->central_meridian = lon; + mx4200_debug(peer, + "mx4200_receive: central meridian = %.9f \n", + up->central_meridian); + } + lon -= up->central_meridian; + if (lon < -180.0) lon += 360.0; + if (lon > 180.0) lon -= 360.0; + + /* + * Calculate running weighted averages + */ + weight = USUAL_EDOP / up->edop; + weight *= weight; + up->avg_lon = (up->filt_lon * up->avg_lon) + (weight * lon); + up->filt_lon += weight; + up->avg_lon = up->avg_lon / up->filt_lon; + + weight = USUAL_NDOP / up->ndop; + weight *= weight; + up->avg_lat = (up->filt_lat * up->avg_lat) + (weight * lat); + up->filt_lat += weight; + up->avg_lat = up->avg_lat / up->filt_lat; + + weight = USUAL_VDOP / up->vdop; + weight *= weight; + up->avg_alt = (up->filt_alt * up->avg_alt) + (weight * alt); + up->filt_alt += weight; + up->avg_alt = up->avg_alt / up->filt_alt; + + mx4200_debug(peer, + "mx4200_receive: position rdg %.9f %.9f %.4f (CM=%.9f)\n", + lat, lon, alt, up->central_meridian); + + return (NULL); +} + +/* + * Parse a mx4200 DOP sentence. + * + * A typical message looks like this. Checksum has already been stripped. + * + * $PMVXG,022,SSSSSS.SSEE.E,NN.N,VV.V,XX,XX,XX,XX,XX,XX + * + * Field Field Contents + * ----- -------------- + * Block Label: $PMVXG + * Sentence Type: 022=DOPs. The DOP values in this sentence + * correspond to the satellites listed. The PRNs in + * the message are listed in receiver channel number order + * 1 UTC measurement time (seconds into week) + * 2 EDOP (east DOP) + * 3 NDOP (north DOP) + * 4 VDOP (vertical DOP) + * 5 PRN on channel 1 + * 6 PRN on channel 2 + * 7 PRN on channel 3 + * 8 PRN on channel 4 + * 9 PRN on channel 5 + * 10 PRN on channel 6 + * 11 PRN on channel 7 (12-channel receivers only) + * 12 PRN on channel 8 (12-channel receivers only) + * 13 PRN on channel 9 (12-channel receivers only) + * 14 PRN on channel 10 (12-channel receivers only) + * 15 PRN on channel 11 (12-channel receivers only) + * 16 PRN on channel 12 (12-channel receivers only) + */ +static char * +mx4200_parse_d( + struct peer *peer + ) +{ + struct refclockproc *pp; + struct mx4200unit *up; + int sentence_type; + double mtime, edop, ndop, vdop; + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + /* Should never happen! */ + if (up->moving) return ("mobile platform - no dop!"); + + sscanf ( pp->a_lastcode, "$PMVXG,%d,%lf,%lf,%lf,%lf", + &sentence_type, &mtime, &edop, &ndop, &vdop); + + /* Sentence type */ + if (sentence_type != PMVXG_D_DOPS) + return ("wrong rec-type"); + + /* Update values */ + if (edop <= 0.0 || ndop <= 0.0 || vdop <= 0.0) + return ("nonpositive dop"); + up->edop = edop; + up->ndop = ndop; + up->vdop = vdop; + + return (NULL); +} + +/* + * Parse a mx4200 Status sentence + * Parse a mx4200 Mode Data sentence + * Parse a mx4200 Software Configuration sentence + * Parse a mx4200 Time Recovery Parameters Currently in Use sentence + * (used only for logging raw strings) + * + * A typical message looks like this. Checksum has already been stripped. + * + * $PMVXG,000,XXX,XX,X,HHMM,X + * + * Field Field Contents + * ----- -------------- + * Block Label: $PMVXG + * Sentence Type: 000=Status. + * Returns status of the receiver to the controller. + * 1 Current Receiver Status: + * ACQ = Satellite re-acquisition + * ALT = Constellation selection + * COR = Providing corrections (for reference stations only) + * IAC = Initial acquisition + * IDL = Idle, no satellites + * NAV = Navigation + * STS = Search the Sky (no almanac available) + * TRK = Tracking + * 2 Number of satellites that should be visible + * 3 Number of satellites being tracked + * 4 Time since last navigation status if not currently navigating + * (hours, minutes) + * 5 Initialization status: + * 0 = Waiting for initialization parameters + * 1 = Initialization completed + * + * A typical message looks like this. Checksum has already been stripped. + * + * $PMVXG,004,C,R,D,H.HH,V.VV,TT,HHHH,VVVV,T + * + * Field Field Contents + * ----- -------------- + * Block Label: $PMVXG + * Sentence Type: 004=Software Configuration. + * Defines the navigation mode and criteria for + * acceptable navigation for the receiver. + * 1 Constrain Altitude Mode: + * 0 = Auto. Constrain altitude (2-D solution) and use + * manual altitude input when 3 sats avalable. Do + * not constrain altitude (3-D solution) when 4 sats + * available. + * 1 = Always constrain altitude (2-D solution). + * 2 = Never constrain altitude (3-D solution). + * 3 = Coast. Constrain altitude (2-D solution) and use + * last GPS altitude calculation when 3 sats avalable. + * Do not constrain altitude (3-D solution) when 4 sats + * available. + * 2 Altitude Reference: (always 0 for MX4200) + * 0 = Ellipsoid + * 1 = Geoid (MSL) + * 3 Differential Navigation Control: + * 0 = Disabled + * 1 = Enabled + * 4 Horizontal Acceleration Constant (m/sec**2) + * 5 Vertical Acceleration Constant (m/sec**2) (0 for MX4200) + * 6 Tracking Elevation Limit (degrees) + * 7 HDOP Limit + * 8 VDOP Limit + * 9 Time Output Mode: + * U = UTC + * L = Local time + * 10 Local Time Offset (minutes) (absent on MX4200) + * + * A typical message looks like this. Checksum has already been stripped. + * + * $PMVXG,030,NNNN,FFF + * + * Field Field Contents + * ----- -------------- + * Block Label: $PMVXG + * Sentence Type: 030=Software Configuration. + * This sentence contains the navigation processor + * and baseband firmware version numbers. + * 1 Nav Processor Version Number + * 2 Baseband Firmware Version Number + * + * A typical message looks like this. Checksum has already been stripped. + * + * $PMVXG,523,M,S,M,EEEE,BBBBBB,C,R + * + * Field Field Contents + * ----- -------------- + * Block Label: $PMVXG + * Sentence Type: 523=Time Recovery Parameters Currently in Use. + * This sentence contains the configuration of the + * time recovery feature of the receiver. + * 1 Time Recovery Mode: + * D = Dynamic; solve for position and time while moving + * S = Static; solve for position and time while stationary + * K = Known position input, solve for time only + * N = No time recovery + * 2 Time Synchronization: + * U = UTC time + * G = GPS time + * 3 Time Mark Mode: + * A = Always output a time pulse + * V = Only output time pulse if time is valid (as determined + * by Maximum Time Error) + * 4 Maximum Time Error - the maximum error (in nanoseconds) for + * which a time mark will be considered valid. + * 5 User Time Bias - external bias in nanoseconds + * 6 Time Message Control: + * 0 = Do not output the time recovery message + * 1 = Output the time recovery message (record 830) to + * Control port + * 2 = Output the time recovery message (record 830) to + * Equipment port + * 7 Reserved + * 8 Position Known PRN (absent on MX 4200) + * + */ +static char * +mx4200_parse_s( + struct peer *peer + ) +{ + struct refclockproc *pp; + struct mx4200unit *up; + int sentence_type; + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + sscanf ( pp->a_lastcode, "$PMVXG,%d", &sentence_type); + + /* Sentence type */ + switch (sentence_type) { + + case PMVXG_D_STATUS: + msyslog(LOG_DEBUG, + "mx4200: status: %s", pp->a_lastcode); + break; + case PMVXG_D_MODEDATA: + msyslog(LOG_DEBUG, + "mx4200: mode data: %s", pp->a_lastcode); + break; + case PMVXG_D_SOFTCONF: + msyslog(LOG_DEBUG, + "mx4200: firmware configuration: %s", pp->a_lastcode); + break; + case PMVXG_D_TRECOVUSEAGE: + msyslog(LOG_DEBUG, + "mx4200: time recovery parms: %s", pp->a_lastcode); + break; + default: + return ("wrong rec-type"); + } + + return (NULL); +} + +/* + * Process a PPS signal, returning a timestamp. + */ +static int +mx4200_pps( + struct peer *peer + ) +{ + int temp_serial; + struct refclockproc *pp; + struct mx4200unit *up; + + int request; +#ifdef HAVE_CIOGETEV + request = CIOGETEV; +#endif +#ifdef HAVE_TIOCGPPSEV + request = TIOCGPPSEV; +#endif + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + /* + * Grab the timestamp of the PPS signal. + */ + temp_serial = up->ppsev.serial; + if (ioctl(fdpps, request, (caddr_t)&up->ppsev) < 0) { + /* XXX Actually, if this fails, we're pretty much screwed */ + mx4200_debug(peer, + "mx4200_pps: CIOGETEV/TIOCGPPSEV: serial=%d, fdpps=%d, %s\n", + up->ppsev.serial, fdpps, strerror(errno)); + refclock_report(peer, CEVNT_FAULT); + return(1); + } + if (temp_serial == up->ppsev.serial) { + mx4200_debug(peer, + "mx4200_pps: ppsev serial not incrementing: %d\n", + up->ppsev.serial); + refclock_report(peer, CEVNT_FAULT); + return(1); + } + + /* + * Check pps serial number against last one + */ + if (up->lastserial + 1 != up->ppsev.serial && up->lastserial != 0) { + if (up->ppsev.serial == up->lastserial) + mx4200_debug(peer, "mx4200_pps: no new pps event\n"); + else + mx4200_debug(peer, "mx4200_pps: missed %d pps events\n", + up->ppsev.serial - up->lastserial - 1); + refclock_report(peer, CEVNT_FAULT); + } + up->lastserial = up->ppsev.serial; + + /* + * Return the timestamp in pp->lastrec + */ + up->ppsev.tv.tv_sec += (u_int32) JAN_1970; + TVTOTS(&up->ppsev.tv,&pp->lastrec); + + return(0); +} + +/* + * mx4200_debug - print debug messages + */ +#if __STDC__ +static void +mx4200_debug(struct peer *peer, char *fmt, ...) +#else + static void +mx4200_debug(peer, fmt, va_alist) + struct peer *peer; + char *fmt; +#endif +{ + va_list ap; + struct refclockproc *pp; + struct mx4200unit *up; + + if (debug) { + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + + /* + * Print debug message to stdout + * In the future, we may want to get get more creative... + */ + vprintf(fmt, ap); + + va_end(ap); + } +} + +/* + * Send a character string to the receiver. Checksum is appended here. + */ +static void +#if __STDC__ +mx4200_send(struct peer *peer, char *fmt, ...) +#else + mx4200_send(peer, fmt, va_alist) + struct peer *peer; + char *fmt; + va_dcl +#endif /* __STDC__ */ +{ + struct refclockproc *pp; + struct mx4200unit *up; + + register char *cp; + register int n, m; + va_list ap; + char buf[1024]; + u_char ck; + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif /* __STDC__ */ + + pp = peer->procptr; + up = (struct mx4200unit *)pp->unitptr; + + 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 /* notdef */ + ck = mx4200_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 /* notdef */ + + m = write(pp->io.fd, buf, (unsigned)n); + if (m < 0) + msyslog(LOG_ERR, "mx4200_send: write: %m (%s)", buf); + mx4200_debug(peer, "mx4200_send: %d %s\n", m, buf); + va_end(ap); +} + +#else +int refclock_mx4200_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_nmea.c b/contrib/ntp/ntpd/refclock_nmea.c new file mode 100644 index 000000000000..211d01e3d6ad --- /dev/null +++ b/contrib/ntp/ntpd/refclock_nmea.c @@ -0,0 +1,411 @@ +/* + * refclock_nmea.c - clock driver for an NMEA GPS CLOCK + * Michael Petry Jun 20, 1994 + * based on refclock_heathn.c + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_NMEA) + +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +/* + * This driver supports the NMEA GPS Receiver with + * + * Protype was refclock_trak.c, Thanks a lot. + * + * The receiver used spits out the NMEA sentences for boat navigation. + * And you thought it was an information superhighway. Try a raging river + * filled with rapids and whirlpools that rip away your data and warp time. + */ + +/* + * Definitions + */ +#define DEVICE "/dev/gps%d" /* name of radio device */ +#define SPEED232 B4800 /* uart speed (4800 bps) */ +#define PRECISION (-9) /* precision assumed (about 2 ms) */ +#define DCD_PRECISION (-20) /* precision assumed (about 1 us) */ +#define REFID "GPS\0" /* reference id */ +#define DESCRIPTION "NMEA GPS Clock" /* who we are */ + +#define LENNMEA 75 /* min timecode length */ + +/* + * Tables to compute the ddd of year form icky dd/mm timecode. Viva la + * leap. + */ +static int day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +static int day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* + * Unit control structure + */ +struct nmeaunit { + int pollcnt; /* poll message counter */ + int polled; /* Hand in a sample? */ + l_fp tstamp; /* timestamp of last poll */ +}; + +/* + * Function prototypes + */ +static int nmea_start P((int, struct peer *)); +static void nmea_shutdown P((int, struct peer *)); +static void nmea_receive P((struct recvbuf *)); +static void nmea_poll P((int, struct peer *)); +static void gps_send P((int, const char *, struct peer *)); +static char *field_parse P((char *, int)); + +/* + * Transfer vector + */ +struct refclock refclock_nmea = { + nmea_start, /* start up driver */ + nmea_shutdown, /* shut down driver */ + nmea_poll, /* transmit poll message */ + noentry, /* handle control */ + noentry, /* initialize driver */ + noentry, /* buginfo */ + NOFLAGS /* not used */ +}; + +/* + * nmea_start - open the GPS devices and initialize data for processing + */ +static int +nmea_start( + int unit, + struct peer *peer + ) +{ + register struct nmeaunit *up; + struct refclockproc *pp; + int fd; + char device[20]; + + /* + * Open serial port. Use CLK line discipline, if available. + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct nmeaunit *) + emalloc(sizeof(struct nmeaunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct nmeaunit)); + pp = peer->procptr; + pp->io.clock_recv = nmea_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = DCD_PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + up->pollcnt = 2; + gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer); + + return (1); +} + +/* + * nmea_shutdown - shut down a GPS clock + */ +static void +nmea_shutdown( + int unit, + struct peer *peer + ) +{ + register struct nmeaunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct nmeaunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + +/* + * nmea_receive - receive data from the serial interface + */ +static void +nmea_receive( + struct recvbuf *rbufp + ) +{ + register struct nmeaunit *up; + struct refclockproc *pp; + struct peer *peer; + l_fp trtmp; + int month, day; + int i; + char *cp, *dp; + int cmdtype; + + /* + * Initialize pointers and read the timecode and timestamp + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct nmeaunit *)pp->unitptr; + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); + + /* + * There is a case that a gives back a "blank" line + */ + if (pp->lencode == 0) + return; + + /* + * We get a buffer and timestamp for each . + */ + pp->lastrec = up->tstamp = trtmp; + up->pollcnt = 2; +#ifdef DEBUG + if (debug) + printf("nmea: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + + /* + * We check the timecode format and decode its contents. The + * we only care about a few of them. The most important being + * the $GPRMC format + * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC + * $GPGGA,162617.0,4548.339,N,00837.719,E,1,07,0.97,00262,M,048,M,,*5D + */ +#define GPRMC 0 +#define GPXXX 1 +#define GPGCA 2 + cp = pp->a_lastcode; + cmdtype=0; + if(strncmp(cp,"$GPRMC",6)==0) { + cmdtype=GPRMC; + } + else if(strncmp(cp,"$GPGGA",6)==0) { + cmdtype=GPGCA; + } + else if(strncmp(cp,"$GPXXX",6)==0) { + cmdtype=GPXXX; + } + else + return; + + switch( cmdtype ) { + case GPRMC: + case GPGCA: + /* + * Check time code format of NMEA + */ + + dp = field_parse(cp,1); + if( !isdigit((int)dp[0]) || + !isdigit((int)dp[1]) || + !isdigit((int)dp[2]) || + !isdigit((int)dp[3]) || + !isdigit((int)dp[4]) || + !isdigit((int)dp[5]) + ) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Test for synchronization. Check for quality byte. + */ + dp = field_parse(cp,2); + if( dp[0] != 'A') { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + break; + case GPXXX: + return; + default: + return; + + } + + if (cmdtype ==GPGCA) { + /* only time */ + time_t tt = time(NULL); + struct tm * t = gmtime(&tt); + day = t->tm_mday; + month = t->tm_mon + 1; + pp->year= t->tm_year; + } else { + dp = field_parse(cp,9); + /* + * Convert date and check values. + */ + day = dp[0] - '0'; + day = (day * 10) + dp[1] - '0'; + month = dp[2] - '0'; + month = (month * 10) + dp[3] - '0'; + pp->year = dp[4] - '0'; + pp->year = (pp->year * 10) + dp[5] - '0'; + } + + if (month < 1 || month > 12 || day < 1) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + + if (pp->year % 4) { + if (day > day1tab[month - 1]) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + for (i = 0; i < month - 1; i++) + day += day1tab[i]; + } else { + if (day > day2tab[month - 1]) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + for (i = 0; i < month - 1; i++) + day += day2tab[i]; + } + pp->day = day; + + dp = field_parse(cp,1); + /* + * Convert time and check values. + */ + pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0'; + pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0'; + pp->second = ((dp[4] - '0') * 10) + dp[5] - '0'; + pp->msec = 0; + + if (pp->hour > 23 || pp->minute > 59 || pp->second > 59) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + + /* + * Process the new sample in the median filter and determine the + * reference clock offset and dispersion. We use lastrec as both + * the reference time and receive time, in order to avoid being + * cute, like setting the reference time later than the receive + * time, which may cause a paranoid protocol module to chuck out + * the data. + */ + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + + /* + * Only go on if we had been polled. + */ + if (!up->polled) + return; + up->polled = 0; + + refclock_receive(peer); + + record_clock_stats(&peer->srcadr, pp->a_lastcode); +} + +/* + * nmea_poll - called by the transmit procedure + * + * We go to great pains to avoid changing state here, since there may be + * more than one eavesdropper receiving the same timecode. + */ +static void +nmea_poll( + int unit, + struct peer *peer + ) +{ + register struct nmeaunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct nmeaunit *)pp->unitptr; + if (up->pollcnt == 0) + refclock_report(peer, CEVNT_TIMEOUT); + else + up->pollcnt--; + pp->polls++; + up->polled = 1; + + /* + * usually nmea_receive can get a timestamp every second + */ + + gps_send(pp->io.fd,"$PMOTG,RMC,0000*1D\r\n", peer); +} + +/* + * + * gps_send(fd,cmd, peer) Sends a command to the GPS receiver. + * as gps_send(fd,"rqts,u\r", peer); + * + * We don't currently send any data, but would like to send + * RTCM SC104 messages for differential positioning. It should + * also give us better time. Without a PPS output, we're + * Just fooling ourselves because of the serial code paths + * + */ +static void +gps_send( + int fd, + const char *cmd, + struct peer *peer + ) +{ + + if (write(fd, cmd, strlen(cmd)) == -1) { + refclock_report(peer, CEVNT_FAULT); + } +} + +static char * +field_parse( + char *cp, + int fn + ) +{ + char *tp; + int i = fn; + + for (tp = cp; *tp != '\0'; tp++) { + if (*tp == ',') + i--; + if (i == 0) + break; + } + return (++tp); +} +#else +int refclock_nmea_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_oncore.c b/contrib/ntp/ntpd/refclock_oncore.c new file mode 100644 index 000000000000..9ff3d2383636 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_oncore.c @@ -0,0 +1,1660 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * refclock_oncore.c + * + * Driver for some of the various the Motorola Oncore GPS receivers. + * + * Tested with: + * + * (UT) (VP) + * COPYRIGHT 1991-1997 MOTOROLA INC. COPYRIGHT 1991-1996 MOTOROLA INC. + * SFTW P/N # 98-P36848P SFTW P/N # 98-P36830P + * SOFTWARE VER # 2 SOFTWARE VER # 8 + * SOFTWARE REV # 2 SOFTWARE REV # 8 + * SOFTWARE DATE APR 24 1998 SOFTWARE DATE 06 Aug 1996 + * MODEL # R1121N1114 MODEL # B4121P1155 + * HWDR P/N # 1 HDWR P/N # _ + * SERIAL # R0010A SERIAL # SSG0226478 + * MANUFACTUR DATE 6H07 MANUFACTUR DATE 7E02 + * OPTIONS LIST IB + * + * -------------------------------------------------------------------------- + * This code uses the two devices + * /dev/oncore.serial.n + * /dev/oncore.pps.n + * which may be linked to the same device. + * and can read initialization data from the file + * /etc/ntp.oncoreN (where n and N are the unit number, viz 127.127.30.N) + * or /etc/ntp.oncore + * -------------------------------------------------------------------------- + * Reg.Clemens Sep98. + * Original code written for FreeBSD. + * With these mods it works on SunOS, Solaris (untested) and Linux + * (RedHat 5.1 2.0.35 + PPSKit, 2.1.126 + changes). + * + * Lat,Long,Ht, cable-delay, offset, and the ReceiverID (along with the + * state machine state) are printed to CLOCKSTATS if that file is enabled + * in /etc/ntp.conf. + * + * -------------------------------------------------------------------------- + */ + +/* + * According to the ONCORE manual (TRM0003, Rev 3.2, June 1998, page 3.13) + * doing an average of 10000 valid 2D and 3D fixes is what the automatic + * site survey mode does. Looking at the output from the receiver + * it seems like it is only using 3D fixes. + * When we do it ourselves, take 10000 3D fixes. + */ + +#define POS_HOLD_AVERAGE 10000 /* nb, 10000s ~= 2h45m */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_ONCORE) + +#include +#include +#include +#include +#include + +#ifdef HAVE_PPSAPI +# ifdef HAVE_TIMEPPS_H +# include +# else +# ifdef HAVE_SYS_TIMEPPS_H +# include +# endif +# endif +#endif + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +#ifdef HAVE_SYS_TERMIOS_H +#include +#endif + +#ifdef HAVE_SYS_PPSCLOCK_H +# include +#endif + +#ifndef HAVE_STRUCT_PPSCLOCKEV +struct ppsclockev { +# ifdef HAVE_TIMESPEC + struct timespec tv; +# else + struct timeval tv; +# endif + u_int serial; +}; +#endif /* not HAVE_STRUCT_PPSCLOCKEV */ + +enum receive_state { + ONCORE_NO_IDEA, + ONCORE_RESET_SENT, + ONCORE_TEST_SENT, + ONCORE_ID_SENT, + ONCORE_ALMANAC, + ONCORE_RUN +}; + +enum site_survey_state { + ONCORE_SS_UNKNOWN, + ONCORE_SS_HW, + ONCORE_SS_SW, + ONCORE_SS_DONE +}; + +struct instance { + int unit; /* 127.127.30.unit */ + int ttyfd; /* TTY file descriptor */ + int ppsfd; /* PPS file descriptor */ +#ifdef HAVE_PPSAPI + pps_handle_t pps_h; + pps_params_t pps_p; +#endif + enum receive_state o_state; /* Receive state */ + + enum site_survey_state site_survey; /* Site Survey state */ + + struct refclockproc *pp; + struct peer *peer; + + int Bj_day; + int assert; + + long delay; /* ns */ + long offset; /* ns */ + + double ss_lat; + double ss_long; + double ss_ht; + int ss_count; + u_char ss_ht_type; + int posn_set; + + int printed; + int pollcnt; + int polled; + u_int ev_serial; + int Rcvptr; + u_char Rcvbuf[500]; + u_char Ea[77]; + u_char En[70]; + u_char Cj[300]; + u_char As; + u_char Ay; + u_char Az; + u_char init_type; + s_char saw_tooth; +}; + +#define rcvbuf instance->Rcvbuf +#define rcvptr instance->Rcvptr + +static void oncore_consume P((struct instance *)); +static void oncore_poll P((int, struct peer *)); +static void oncore_read_config P((struct instance *)); +static void oncore_receive P((struct recvbuf *)); +static void oncore_sendmsg P((int fd, u_char *, u_int)); +static void oncore_shutdown P((int, struct peer *)); +static int oncore_start P((int, struct peer *)); +static void oncore_stats P((struct instance *)); + +static void oncore_msg_any P((struct instance *, u_char *, u_int, int)); +static void oncore_msg_As P((struct instance *, u_char *, u_int)); +static void oncore_msg_At P((struct instance *, u_char *, u_int)); +static void oncore_msg_Ay P((struct instance *, u_char *, u_int)); +static void oncore_msg_Az P((struct instance *, u_char *, u_int)); +static void oncore_msg_Bj P((struct instance *, u_char *, u_int)); +static void oncore_msg_Cf P((struct instance *, u_char *, u_int)); +static void oncore_msg_Cj P((struct instance *, u_char *, u_int)); +static void oncore_msg_Ea P((struct instance *, u_char *, u_int)); +static void oncore_msg_En P((struct instance *, u_char *, u_int)); +static void oncore_msg_Fa P((struct instance *, u_char *, u_int)); + +struct refclock refclock_oncore = { + oncore_start, /* start up driver */ + oncore_shutdown, /* shut down driver */ + oncore_poll, /* transmit poll message */ + noentry, /* not used */ + noentry, /* not used */ + noentry, /* not used */ + NOFLAGS /* not used */ +}; + +/* + * Understanding the next bit here is not easy unless you have a manual + * for the the UT or VP Oncore. + */ + +static struct { + const char flag[3]; + const int len; + void (*handler) P((struct instance *, u_char *, u_int)); + const char *fmt; +} oncore_messages[] = { + /* Ea and En first since they're most common */ + { "Ea", 76, oncore_msg_Ea, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" }, + { "En", 69, oncore_msg_En, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" }, + { "Ab", 10, 0, "" }, + { "Ac", 11, 0, "" }, + { "Ad", 11, 0, "" }, + { "Ae", 11, 0, "" }, + { "Af", 15, 0, "" }, + { "As", 20, oncore_msg_As, "" }, + { "At", 8, oncore_msg_At, "" }, + { "Aw", 8, 0, "" }, + { "Ay", 11, oncore_msg_Ay, "" }, + { "Az", 11, oncore_msg_Az, "" }, + { "AB", 8, 0, "" }, + { "Bb", 92, 0, "" }, + { "Bj", 8, oncore_msg_Bj, "" }, + { "Cb", 33, 0, "" }, + { "Cf", 7, oncore_msg_Cf, "" }, + { "Cg", 8, 0, "" }, + { "Ch", 9, 0, "" }, + { "Cj", 294, oncore_msg_Cj, "" }, + { "Ek", 71, 0, "" }, + { "Fa", 9, oncore_msg_Fa, "" }, + { "Sz", 8, 0, "" }, + { {0}, 7, 0, ""} +}; + + +/* + * Position Set. + */ +u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 }; +u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 }; +u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 }; + +/* + * Position-Hold Mode + * Start automatic site survey + */ +static u_char oncore_cmd_At[] = { 'A', 't', 2 }; + +/* + * Position-Hold Position + */ +u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 }; +u_char oncore_cmd_Asx[]= { 'A', 's', 0x7f, 0xff, 0xff, 0xff, + 0x7f, 0xff, 0xff, 0xff, + 0x7f, 0xff, 0xff, 0xff, 0xff }; + +/* + * Set to UTC time (not GPS). + */ +u_char oncore_cmd_Aw[] = { 'A', 'w', 1 }; + +/* + * Read back PPS Offset for Output + */ +u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 }; +u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff }; + +/* + * Read back Cable Delay for Output + */ +u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 }; +u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff }; + +/* + * Application type = static. + */ +u_char oncore_cmd_AB[] = { 'A', 'B', 4 }; + +/* + * Visible Satellite Status Msg. + */ +u_char oncore_cmd_Bb[] = { 'B', 'b', 0 }; /* just turn off */ + +/* + * Leap Second Pending Message + * Request message once + */ +u_char oncore_cmd_Bj[] = { 'B', 'j', 0 }; + +/* + * Set to Defaults + */ +static u_char oncore_cmd_Cf[] = { 'C', 'f' }; + +/* + * Set to Position Fix mode (only needed on VP). + */ +u_char oncore_cmd_Cg[] = { 'C', 'g', 1 }; + +/* + * Receiver Id + */ +static u_char oncore_cmd_Cj[] = { 'C', 'j' }; + +/* + * Position/Status/Data message + * Send once per second + */ +static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 }; + +/* + * Position/Status Extension Msg + */ +u_char oncore_cmd_Ek[] = { 'E', 'k', 0 }; /* just turn off */ + +/* + * Time Raim Setup & Status Message + * Send once per second + * Time-RAIM on + * Alarm limit 1us + * PPS on when we have the first sat + */ +static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* + * Self-test + */ +static u_char oncore_cmd_Fa[] = { 'F', 'a' }; + +#define DEVICE1 "/dev/oncore.serial.%d" /* name of serial device */ +#define DEVICE2 "/dev/oncore.pps.%d" /* name of pps device */ +#define INIT_FILE "/etc/ntp.oncore" /* optional init file */ + +#define SPEED B9600 /* Oncore Binary speed (9600 bps) */ + +/* + * Assemble and disassemble 32bit signed quantities from a buffer. + * + */ + + /* to buffer, int w, u_char *buf */ +#define w32_buf(buf,w) { unsigned int i_tmp; \ + i_tmp = (w<0) ? (~(-w)+1) : (w); \ + (buf)[0] = (i_tmp >> 24) & 0xff; \ + (buf)[1] = (i_tmp >> 16) & 0xff; \ + (buf)[2] = (i_tmp >> 8) & 0xff; \ + (buf)[3] = (i_tmp ) & 0xff; \ + } + +#define w32(buf) (((buf)[0]&0xff) << 24 | \ + ((buf)[1]&0xff) << 16 | \ + ((buf)[2]&0xff) << 8 | \ + ((buf)[3]&0xff) ) + + /* from buffer, char *buf, result to an int */ +#define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf)) + +/* + * oncore_start - initialize data for processing + */ +static int +oncore_start( + int unit, + struct peer *peer + ) +{ + register struct instance *instance; + struct refclockproc *pp; + int fd1, fd2, mode; + char device1[30], device2[30]; + const char *cp; + struct stat stat1, stat2; + + /* OPEN DEVICES */ + /* opening different devices for fd1 and fd2 presents no problems */ + /* opening the SAME device twice, seems to be OS dependent. + (a) on Linux (no streams) no problem + (b) on SunOS (and possibly Solaris, untested), (streams) + never see the line discipline. + Since things ALWAYS work if we only open the device once, we check + to see if the two devices are in fact the same, then proceed to + do one open or two. + */ + + (void)sprintf(device1, DEVICE1, unit); + (void)sprintf(device2, DEVICE2, unit); + + if (stat(device1, &stat1)) { + perror("ONCORE: stat fd1"); + exit(1); + } + + if (stat(device2, &stat2)) { + perror("ONCORE: stat fd2"); + exit(1); + } + + if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) { + /* same device here */ + if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW +#ifdef HAVE_PPSAPI +#else + | LDISC_PPS +#endif + ))) { + perror("ONCORE: fd1"); + exit(1); + } + fd2 = fd1; + } else { /* different devices here */ + if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) { + perror("ONCORE: fd1"); + exit(1); + } + if ((fd2=open(device2, O_RDWR)) < 0) { + perror("ONCORE: fd2"); + exit(1); + } + } + + /* Devices now open, initialize instance structure */ + + if (!(instance = (struct instance *)emalloc(sizeof *instance))) { + perror("malloc"); + close(fd1); + return (0); + } + memset((char *) instance, 0, sizeof *instance); + pp = peer->procptr; + pp->unitptr = (caddr_t)instance; + instance->unit = unit; + instance->ttyfd = fd1; + instance->ppsfd = fd2; + + instance->Bj_day = -1; + instance->assert = 1; + + /* go read any input data in /etc/ntp.oncoreX */ + + oncore_read_config(instance); + +#ifdef HAVE_PPSAPI + if (time_pps_create(fd2, &instance->pps_h) < 0) { + perror("time_pps_create"); + exit(1); + } + + if (instance->assert) { + instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT; + instance->pps_p.assert_offset.tv_sec = 0; + instance->pps_p.assert_offset.tv_nsec = 0; + } else { + instance->pps_p.mode = PPS_CAPTURECLEAR | PPS_OFFSETCLEAR; + instance->pps_p.clear_offset.tv_sec = 0; + instance->pps_p.clear_offset.tv_nsec = 0; + } + instance->pps_p.mode |= PPS_TSFMT_TSPEC; + if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) { + perror("time_pps_setparams"); + exit(1); + } + if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, + instance->pps_p.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR), + PPS_TSFMT_TSPEC) < 0) { + perror("time_pps_kcbind"); + } +#endif + instance->pp = pp; + instance->peer = peer; + instance->o_state = ONCORE_NO_IDEA; + cp = "state = ONCORE_NO_IDEA"; + record_clock_stats(&(instance->peer->srcadr), cp); + + /* + * Initialize miscellaneous variables + */ + + peer->precision = -26; + peer->minpoll = 4; + peer->maxpoll = 4; + pp->clockdesc = "Motorola UT/VP Oncore GPS Receiver"; + memcpy((char *)&pp->refid, "GPS\0", 4); + + pp->io.clock_recv = oncore_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd1; + if (!io_addclock(&pp->io)) { + perror("io_addclock"); + (void) close(fd1); + free(instance); + return (0); + } + pp->unitptr = (caddr_t)instance; + + /* + * This will start the Oncore receiver. + * We send info from config to Oncore later. + */ + + mode = instance->init_type; + if (mode == 3 || mode == 4) { + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof oncore_cmd_Cf); + instance->o_state = ONCORE_RESET_SENT; + cp = "state = ONCORE_RESET_SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + } else { + oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa); + instance->o_state = ONCORE_TEST_SENT; + cp = "state = ONCORE_TEST_SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + } + + instance->pollcnt = 2; + + return (1); +} + +/* + * Read Input file if it exists. + */ +static void +oncore_read_config( + struct instance *instance + ) +{ +/* + * First we try to open the configuration file /etc/ntp.oncoreN, where + * N is the unit number viz 127.127.30.N. + * If we don't find it, then we try the file /etc/ntp.oncore. + * + * If we find NEITHER then we don't have the cable delay or PPS offset + * and we choose MODE (4) below. + * + * Five Choices for MODE + * (0) ONCORE is preinitialized, don't do anything to change it. + * nb, DON'T set 0D mode, DON'T set Delay, position... + * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode. + * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position, + * lock this in, go to 0D mode. + * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode. + * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position, + * lock this in, go to 0D mode. + * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY] + * then this position is set as the INITIAL position of the ONCORE. + * This can reduce the time to first fix. + * ------------------------------------------------------------------------------- + * Note that an Oncore UT without a battery backup retains NO information if it is + * power cycled, with a Battery Backup it remembers the almanac, etc. + * For an Oncore VP, there is an eeprom that will contain this data, along with the + * option of Battery Backup. + * So a UT without Battery Backup is equivalent to doing a HARD RESET on each + * power cycle, since there is nowhere to store the data. + * ------------------------------------------------------------------------------- + * + * If we open one or the other of the files, we read it looking for + * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET + * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must + * be present or mode reverts to (2,4). + * + * Read input file. + * + * # is comment to end of line + * = allowed between 1st and 2nd fields. + * + * Expect to see one line with 'MODE' as first field, followed by an integer + * in the range 0-4 (default = 4). + * + * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields. + * All numbers are floating point. + * DDD.ddd + * DDD MMM.mmm + * DDD MMM SSS.sss + * + * Expect to see one line with 'HT' (or 'HTMSL' or 'HTGPS') as first field. + * followed by 1-2 fields. First is a number, the second is 'FT' or 'M'. + * for feet or meters. HT is the same as HTGPS. + * HTMSL = HT above mean_sea_level, + * HTGPS = HT above GPS ellipse. + * + * There are two optional lines, starting with DELAY and OFFSET, followed + * by 1 or two fields. The first is a number (a time) the second is + * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. + * DELAY is cable delay, typically a few tens of ns. + * OFFSET is the offset of the PPS pulse from 0. (only fully implemented + * with the PPSAPI, we need to be able to tell the Kernel about this + * offset if the Kernel PLL is in use, but can only do this presently + * when using the PPSAPI interface. If not using the Kernel PLL, + * then there is no problem. + * + * There is another optional line, with either ASSERT or CLEAR on it, which + * determine which transition of the PPS signal is used for timing by the + * PPSAPI. If neither is present, then ASSERT is assumed. + * + * So acceptable input would be + * # these are my coordinates (RWC) + * LON -106 34.610 + * LAT 35 08.999 + * HT 1589 # could equally well say HT 5215 FT + * DELAY 60 ns + */ + + FILE *fd; + char *cp, line[100], units[2], device[20]; + int i, j, sign, lat_flg, long_flg, ht_flg, mode; + double f1, f2, f3; + + + sprintf(device, "%s%d", INIT_FILE, instance->unit); + if ((fd=fopen(device, "r")) == NULL) + if ((fd=fopen(INIT_FILE, "r")) == NULL) { + instance->init_type = 4; + return; + } + + mode = 0; + lat_flg = long_flg = ht_flg = 0; + while (fgets(line, 100, fd)) { + if ((cp=strchr(line, '#'))) + *cp = '\0'; + i = strlen(line); + for (j=0; jss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ + lat_flg++; + } else if (!strncmp(&line[j], "LON", 3)) { + j += 3; + f1 = f2 = f3 = 0; + sscanf(&line[j], "%lf %lf %lf", &f1, &f2, &f3); + sign = 1; + if (f1 < 0) { + f1 = -f1; + sign = -1; + } + instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1)); /*miliseconds*/ + long_flg++; + } else if (!strncmp(&line[j], "HT", 2)) { + instance->ss_ht_type = 0; + if (!strncmp(&line[j], "HTGPS", 5)) { + instance->ss_ht_type = 0; + j +=3; + } + if (!strncmp(&line[j], "HTMSL", 5)) { + instance->ss_ht_type = 1; + j +=3; + } + j += 2; + f1 = 0; + units[0] = '\0'; + sscanf(&line[j], "%lf %1s", &f1, units); + if (units[0] == 'F') + f1 = 0.3048 * f1; + instance->ss_ht = 100 * f1; /* cm */ + ht_flg++; + } else if (!strncmp(&line[j], "DELAY", 5)) { + j += 5; + f1 = 0; + units[0] = '\0'; + sscanf(&line[j], "%lf %1s", &f1, units); + if (units[0] == 'N') + ; + else if (units[0] == 'U') + f1 = 1000 * f1; + else if (units[0] == 'M') + f1 = 1000000 * f1; + else + f1 = 1000000000 * f1; + if (f1 < 0 || f1 > 1.e9) + f1 = 0; + instance->delay = f1; /* delay in ns */ + } else if (!strncmp(&line[j], "OFFSET", 6)) { + j += 6; + f1 = 0; + units[0] = '\0'; + sscanf(&line[j], "%lf %1s", &f1, units); + if (units[0] == 'N') + ; + else if (units[0] == 'U') + f1 = 1000 * f1; + else if (units[0] == 'M') + f1 = 1000000 * f1; + else + f1 = 1000000000 * f1; + if (f1 < 0 || f1 > 1.e9) + f1 = 0; + instance->offset = f1; /* offset in ns */ + } else if (!strncmp(&line[j], "MODE", 4)) { + j += 4; + sscanf(&line[j], "%d", &mode); + if (mode < 0 || mode > 4) + mode = 4; + instance->init_type = mode; + } else if (!strncmp(&line[j], "ASSERT", 6)) { + instance->assert = 1; + } else if (!strncmp(&line[j], "CLEAR", 5)) { + instance->assert = 0; + } + } + fclose(fd); + + /* + * OK, have read all of data file, and extracted the good stuff. + * If lat/long/ht specified they ALL must be specified for mode = (1,3). + */ + + instance->posn_set = 1; + if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) { + printf("ONCORE: incomplete data on %s\n", INIT_FILE); + instance->posn_set = 0; + if (mode == 1 || mode == 3) + instance->init_type++; + } +} + + + +/* + * oncore_shutdown - shut down the clock + */ +static void +oncore_shutdown( + int unit, + struct peer *peer + ) +{ + register struct instance *instance; + struct refclockproc *pp; + + pp = peer->procptr; + instance = (struct instance *) pp->unitptr; + free(instance); +} + + + +/* + * oncore_poll - called by the transmit procedure + */ +static void +oncore_poll( + int unit, + struct peer *peer + ) +{ + struct instance *instance; + + instance = (struct instance *) peer->procptr->unitptr; + if (!instance->pollcnt) + refclock_report(peer, CEVNT_TIMEOUT); + else + instance->pollcnt--; + peer->procptr->polls++; + instance->polled = 1; +} + + + +/* + * move dta from NTP to buffer (toss in unlikely case it wont fit) + */ +static void +oncore_receive( + struct recvbuf *rbufp + ) +{ + u_int i; + u_char *p; + struct peer *peer; + struct instance *instance; + + peer = (struct peer *)rbufp->recv_srcclock; + instance = (struct instance *) peer->procptr->unitptr; + p = (u_char *) &rbufp->recv_space; + +#if 0 + if (debug > 4) { + int i; + printf("ONCORE: >>>"); + for(i=0; irecv_length; i++) + printf("%02x ", p[i]); + printf("\n"); + printf("ONCORE: >>>"); + for(i=0; irecv_length; i++) + printf("%03o ", p[i]); + printf("\n"); + } +#endif + + i = rbufp->recv_length; + if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf]) + i = sizeof(rcvbuf) - rcvptr; /* and some char will be lost */ + memcpy(rcvbuf+rcvptr, p, i); + rcvptr += i; + oncore_consume(instance); +} + + + +/* + * Deal with any complete messages + */ +static void +oncore_consume( + struct instance *instance + ) +{ + int i, l, j, m; + + while (rcvptr >= 7) { + if (rcvbuf[0] != '@' || rcvbuf[1] != '@') { + /* We're not in sync, lets try to get there */ + for (i=1; i < rcvptr-1; i++) + if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@') + break; + if (debug > 4) + printf("ONCORE: >>> skipping %d chars\n", i); + if (i != rcvptr) + memcpy(rcvbuf, rcvbuf+i, (unsigned)(rcvptr-i)); + rcvptr -= i; + } + + /* Ok, we have a header now */ + l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1; + for(m=0; m 3) + printf("ONCORE: GOT: %c%c %d of %d entry %d\n", rcvbuf[2], rcvbuf[3], rcvptr, l, m); +#endif + /* Got the entire message ? */ + + if (rcvptr < l) + return; + + /* Check the checksum */ + + j = 0; + for (i = 2; i < l-3; i++) + j ^= rcvbuf[i]; + if (j == rcvbuf[l-3]) { + oncore_msg_any(instance, rcvbuf, (unsigned) (l-3), m); + if (oncore_messages[m].handler) + oncore_messages[m].handler(instance, rcvbuf, (unsigned) (l-3)); + } else if (debug) { + printf("ONCORE: Checksum mismatch! calc %o is %o\n", j, rcvbuf[l-3]); + printf("ONCORE: @@%c%c ", rcvbuf[2], rcvbuf[3]); + for (i=4; i 3) { + GETTIMEOFDAY(&tv, 0); + printf("ONCORE: %ld.%06ld\n", (long) tv.tv_sec, (long) tv.tv_usec); + + if (!*fmt) { + printf(">>@@%c%c ", buf[2], buf[3]); + for(i=2; i < len && i < 2400 ; i++) + printf("%02x", buf[i]); + printf("\n"); + return; + } else { + printf("##"); + for (p = fmt; *p; p++) { + putchar(*p); + putchar('_'); + } + printf("\n%c%c", buf[2], buf[3]); + i = 4; + for (p = fmt; *p; p++) { + printf("%02x", buf[i++]); + } + printf("\n"); + } + } +} + + + +/* + * Set to Factory Defaults (Reasonable for UT w/ no Battery Backup + * not so for VP (eeprom) or UT with battery + */ +static void +oncore_msg_Cf( + struct instance *instance, + u_char *buf, + u_int len + ) +{ + const char *cp; + + if (instance->o_state == ONCORE_RESET_SENT) { + oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof oncore_cmd_Fa); + instance->o_state = ONCORE_TEST_SENT; + cp = "state = ONCORE_TEST_SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + } +} + + + +static void +oncore_msg_Fa( + struct instance *instance, + u_char *buf, + u_int len + ) +{ + const char *cp; + + if (instance->o_state == ONCORE_TEST_SENT) { + if (debug > 2) + printf("ONCORE: >>@@Fa %x %x\n", buf[4], buf[5]); + if (buf[4] || buf[5]) { + printf("ONCORE: SELF TEST FAILED\n"); + exit(1); + } + + /* sometimes the @@Cj request does not produce any output + PERHAPS the ONCORE is still busy from the selftest??? + try a 2 second sleep here to see if it makes any difference + */ + + sleep(2); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof oncore_cmd_Cj); + instance->o_state = ONCORE_ID_SENT; + cp = "state = ONCORE_ID_SENT"; + record_clock_stats(&(instance->peer->srcadr), cp); + } +} + + + +/* + * preliminaries out of the way, this is the REAL start of initialization + */ +static void +oncore_msg_Cj( + struct instance *instance, + u_char *buf, + u_int len + ) +{ + const char *cp; + int mode; + + if (instance->o_state != ONCORE_ID_SENT) + return; + + memcpy(instance->Cj, buf, len); + + oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof oncore_cmd_Cg); /* Set Posn Fix mode (not Idle (VP)) */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof oncore_cmd_Bb); /* turn off */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof oncore_cmd_Ek); /* turn off */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof oncore_cmd_Aw); /* UTC time */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof oncore_cmd_AB); /* Appl type static */ + + mode = instance->init_type; + if (debug) + printf("ONCORE: INIT mode = %d\n", mode); + + /* If there is Position input in the Config file + * and mode = (1,3) set it as posn hold posn, goto 0D mode. + * or mode = (2,4) set it as INITIAL position, and Site Survey. + */ + + switch (mode) { + case 0: /* NO initialization, don't change anything */ + instance->site_survey = ONCORE_SS_DONE; + break; + + case 1: + case 3: + w32_buf(&oncore_cmd_As[2], (int) instance->ss_lat); + w32_buf(&oncore_cmd_As[6], (int) instance->ss_long); + w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht); + oncore_cmd_As[14] = instance->ss_ht_type; + oncore_sendmsg(instance->ttyfd, oncore_cmd_As, sizeof oncore_cmd_As); + + instance->site_survey = ONCORE_SS_DONE; + oncore_cmd_At[2] = 1; + oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); + record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); + break; + + case 2: + case 4: + if (instance->posn_set) { + w32_buf(&oncore_cmd_Ad[2], (int) instance->ss_lat); + w32_buf(&oncore_cmd_Ae[2], (int) instance->ss_long); + w32_buf(&oncore_cmd_Af[2], (int) instance->ss_ht); + oncore_cmd_Af[6] = instance->ss_ht_type; + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ad, sizeof oncore_cmd_Ad); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ae, sizeof oncore_cmd_Ae); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Af, sizeof oncore_cmd_Af); + } + instance->site_survey = ONCORE_SS_UNKNOWN; + oncore_cmd_At[2] = 2; + oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); + break; + } + + if (mode != 0) { + /* cable delay in ns */ + w32_buf(&oncore_cmd_Az[2], instance->delay); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Az, sizeof oncore_cmd_Az); + + /* PPS offset in ns */ + w32_buf(&oncore_cmd_Ay[2], instance->offset); + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ay, sizeof oncore_cmd_Ay); + } + + /* 8chan - Position/Status/Data Output Message, 1/s */ + + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof oncore_cmd_Ea); + + instance->o_state = ONCORE_ALMANAC; + cp = "state = ONCORE_ALMANAC"; + record_clock_stats(&(instance->peer->srcadr), cp); +} + + + +static void +oncore_msg_Ea( + struct instance *instance, + u_char *buf, + u_int len + ) +{ + const char *cp; + + if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN) + return; + + memcpy(instance->Ea, buf, len); + + /* When we have an almanac, start the En messages */ + + if (instance->o_state == ONCORE_ALMANAC) { + if ((instance->Ea[72] & 1)) { + if (debug) + printf("ONCORE: waiting for almanac\n"); + return; + } else { + oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof oncore_cmd_En); + instance->o_state = ONCORE_RUN; + cp = "state = ONCORE_RUN"; + record_clock_stats(&(instance->peer->srcadr), cp); + } + } + + /* must be ONCORE_RUN if we are here */ + /* First check if Hardware SiteSurvey has Finished */ + + if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) { + instance->site_survey = ONCORE_SS_DONE; + record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); + } + + if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) { /* will print to clockstat when all */ + instance->printed = 1; /* three messages respond */ + /* Read back Position Hold Params */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof oncore_cmd_Asx); + /* Read back PPS Offset for Output */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof oncore_cmd_Ayx); + /* Read back Cable Delay for Output */ + oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof oncore_cmd_Azx); + } + + /* Check the leap second status once per day */ + + /* + * The following additional check, checking for June/December, is a + * workaround for incorrect ONCORE firmware. The oncore starts + * reporting the leap second when the GPS satellite data message + * (page 18, subframe 4) is updated to a date in the future, which + * which can be several months before the leap second. WWV and other + * services seem to wait until the month of the event to turn + * on their indicators (which are usually a single bit). + */ + + if ((buf[4] == 6) || (buf[4] == 12)) { + if (instance->Bj_day != buf[5]) { /* do this 1/day */ + instance->Bj_day = buf[5]; + oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof oncore_cmd_Bj); + } + } + instance->pp->year = buf[6]*256+buf[7]; + instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]); + instance->pp->hour = buf[8]; + instance->pp->minute = buf[9]; + instance->pp->second = buf[10]; + + if (instance->site_survey != ONCORE_SS_SW) + return; + + /* + * We have to average our own position for the Position Hold Mode + */ + + /* We only take PDOP/3D fixes */ + + if (instance->Ea[37] & 1) + return; + + /* Not if poor geometry or less than 3 sats */ + + if (instance->Ea[72] & 0x52) + return; + + /* Only 3D fix */ + + if (!(instance->Ea[72] & 0x20)) + return; + + instance->ss_lat += buf_w32(&instance->Ea[15]); + instance->ss_long += buf_w32(&instance->Ea[19]); + instance->ss_ht += buf_w32(&instance->Ea[23]); /* GPS ellipse */ + instance->ss_count++; + + if (debug) + printf("ONCORE: AVG %d %d %d %d\n", + instance->ss_count, + (unsigned) (instance->ss_lat / instance->ss_count), + (unsigned) (instance->ss_long / instance->ss_count), + (unsigned) (instance->ss_ht / instance->ss_count) + ); + + if (instance->ss_count != POS_HOLD_AVERAGE) + return; + + instance->ss_lat /= POS_HOLD_AVERAGE; + instance->ss_long /= POS_HOLD_AVERAGE; + instance->ss_ht /= POS_HOLD_AVERAGE; + + w32_buf(&oncore_cmd_As[2], (int) instance->ss_lat); + w32_buf(&oncore_cmd_As[6], (int) instance->ss_long); + w32_buf(&oncore_cmd_As[10], (int) instance->ss_ht); + oncore_cmd_As[14] = 0; + oncore_sendmsg(instance->ttyfd, oncore_cmd_As, sizeof oncore_cmd_As); + + oncore_cmd_At[2] = 1; + oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); + record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode"); + instance->site_survey = ONCORE_SS_DONE; +} + + + +static void +oncore_msg_En( + struct instance *instance, + u_char *buf, + u_int len + ) +{ + int j; + l_fp ts, ts_tmp; + double dmy; +#ifdef HAVE_TIMESPEC + struct timespec *tsp = 0; +#else + struct timeval *tsp = 0; +#endif +#ifdef HAVE_PPSAPI + struct timespec timeout; + pps_info_t pps_i; +#else /* ! HAVE_PPSAPI */ +#ifdef HAVE_CIOGETEV + struct ppsclockev ev; + int r = CIOGETEV; +#endif +#ifdef HAVE_TIOCGPPSEV + struct ppsclockev ev; + int r = TIOCGPPSEV; +#endif +#endif /* ! HAVE_PPS_API */ + + if (instance->o_state != ONCORE_RUN) + return; + + memcpy(instance->En, buf, len); + + /* Don't do anything without an almanac to define the GPS->UTC delta */ + + if (instance->Ea[72] & 1) + return; + + /* If Time RAIM doesn't like it, don't trust it */ + + if (instance->En[21]) + return; + +#ifdef HAVE_PPSAPI + j = instance->ev_serial; + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i, + &timeout) < 0) { + printf("ONCORE: time_pps_fetch failed\n"); + return; + } + + if (instance->assert) { + tsp = &pps_i.assert_timestamp; + + if (debug > 2) + printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", + pps_i.assert_sequence, j, tsp->tv_sec, tsp->tv_nsec); + + if (pps_i.assert_sequence == j) { + printf("ONCORE: oncore_msg_En, error serial pps\n"); + return; + } + instance->ev_serial = pps_i.assert_sequence; + } else { + tsp = &pps_i.clear_timestamp; + + if (debug > 2) + printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n", + pps_i.clear_sequence, j, tsp->tv_sec, tsp->tv_nsec); + + if (pps_i.clear_sequence == j) { + printf("ONCORE: oncore_msg_En, error serial pps\n"); + return; + } + instance->ev_serial = pps_i.clear_sequence; + } + + /* convert timespec -> ntp l_fp */ + + dmy = tsp->tv_nsec; + dmy /= 1e9; + ts.l_uf = dmy * 4294967296.0; + ts.l_ui = tsp->tv_sec; +#if 0 + alternate code for previous 4 lines is + dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ + DTOLFP(dmy, &ts); + dmy = tsp->tv_sec; /* integer part */ + DTOLFP(dmy, &ts_tmp); + L_ADD(&ts, &ts_tmp); + or more simply + dmy = 1.0e-9*tsp->tv_nsec; /* fractional part */ + DTOLFP(dmy, &ts); + ts.l_ui = tsp->tv_sec; +#endif /* 0 */ +#else /* ! HAVE_PPSAPI */ + j = instance->ev_serial; + if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) { + perror("ONCORE: IOCTL:"); + return; + } + + tsp = &ev.tv; + + if (debug > 2) + printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n", + ev.serial, j, tsp->tv_sec, tsp->tv_usec); + + if (ev.serial == j) { + printf("ONCORE: oncore_msg_En, error serial pps\n"); + return; + } + instance->ev_serial = ev.serial; + + /* convert timeval -> ntp l_fp */ + + TVTOTS(tsp, &ts); +#endif + /* now have timestamp in ts */ + /* add in saw_tooth and offset */ + + /* saw_tooth not really necessary if using TIMEVAL */ + /* since its only precise to us, but do it anyway. */ + + /* offset in ns, and is positive (late), we subtract */ + /* to put the PPS time transition back where it belongs */ + + j = instance->saw_tooth + instance->offset; + instance->saw_tooth = (s_char) buf[25]; /* update for next time */ +#ifdef HAVE_PPSAPI + /* must hand this offset off to the Kernel to do the addition */ + /* so that the Kernel PLL sees the offset too */ + + if (instance->assert) { + instance->pps_p.assert_offset.tv_nsec = + -(instance->saw_tooth + instance->offset); + } else { + instance->pps_p.clear_offset.tv_nsec = + -(instance->saw_tooth + instance->offset); + } + + if (time_pps_setparams(instance->pps_h, &instance->pps_p)) + perror("time_pps_setparams"); +#else + /* if not PPSAPI, no way to inform kernel of OFFSET, just do it */ + + dmy = -1.0e-9*j; + DTOLFP(dmy, &ts_tmp); + L_ADD(&ts, &ts_tmp); +#endif + /* have time from UNIX origin, convert to NTP origin. */ + + ts.l_ui += JAN_1970; + instance->pp->lastrec = ts; + instance->pp->msec = 0; + + ts_tmp = ts; + ts_tmp.l_ui = 0; /* zero integer part */ + LFPTOD(&ts_tmp, dmy); /* convert fractional part to a double */ + j = 1.0e9*dmy; /* then to integer ns */ + sprintf(instance->pp->a_lastcode, + "%u.%09u %d %d %2d %2d %2d %2ld rstat %02x dop %d nsat %2d,%d raim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d", + ts.l_ui, j, + instance->pp->year, instance->pp->day, + instance->pp->hour, instance->pp->minute, instance->pp->second, + (long) tsp->tv_sec % 60, + + instance->Ea[72], instance->Ea[37], instance->Ea[38], instance->Ea[39], instance->En[21], + /*rstat dop nsat visible, nsat tracked, raim */ + instance->En[23]*256+instance->En[24], (s_char) buf[25], + /* sigma neg-sawtooth */ + /*sat*/ instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53], + instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69] + ); + + if (debug > 2) { + int i; + i = strlen(instance->pp->a_lastcode); + printf("ONCORE: len = %d %s\n", i, instance->pp->a_lastcode); + } + + if (!refclock_process(instance->pp)) { + refclock_report(instance->peer, CEVNT_BADTIME); + return; + } + + record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode); + instance->pollcnt = 2; + + if (instance->polled) { + instance->polled = 0; +/* + instance->pp->dispersion = instance->pp->skew = 0; +*/ + refclock_receive(instance->peer); + } +} + + + +/* + * Try to use Oncore UT+ Auto Survey Feature + * If its not there (VP), set flag to do it ourselves. + */ +static void +oncore_msg_At( + struct instance *instance, + u_char *buf, + u_int len + ) +{ + + if (instance->site_survey != ONCORE_SS_UNKNOWN) + return; + + if (buf[4] == 2) + instance->site_survey = ONCORE_SS_HW; + else { + instance->site_survey = ONCORE_SS_SW; + + /* + * Probably a VP or an older UT which can't do site-survey. + * We will have to do it ourselves + */ + oncore_cmd_At[2] = 0; + instance->ss_lat = instance->ss_long = instance->ss_ht = 0; + oncore_sendmsg(instance->ttyfd, oncore_cmd_At, sizeof oncore_cmd_At); + } +} + + + +/* get leap-second warning message */ + +/* + * @@Bj does NOT behave as documented in current Oncore firmware. + * It turns on the LEAP indicator when the data is set, and does not, + * as documented, wait until the beginning of the month when the + * leap second will occur. + * Until this firmware bug is fixed, @@Bj is only called in June/December. + */ + +static void +oncore_msg_Bj( + struct instance *instance, + u_char *buf, + u_int len + ) +{ + const char *cp; + + switch(buf[4]) { + case 1: + instance->peer->leap = LEAP_ADDSECOND; + cp = "Set peer.leap to LEAP_ADDSECOND"; + break; + case 2: + instance->peer->leap = LEAP_DELSECOND; + cp = "Set peer.leap to LEAP_DELSECOND"; + break; + case 0: + default: + instance->peer->leap = LEAP_NOWARNING; + cp = "Set peer.leap to LEAP_NOWARNING"; + break; + } + record_clock_stats(&(instance->peer->srcadr), cp); +} + + + +/* + * get Position hold position + */ +static void +oncore_msg_As( + struct instance *instance, + u_char *buf, + u_int len + ) +{ + int lat, lon, ht; + + if (!instance->printed || instance->As) + return; + + instance->As = 1; + + lat = buf_w32(&buf[4]); + instance->ss_lat = lat; + + lon = buf_w32(&buf[8]); + instance->ss_long = lon; + + ht = buf_w32(&buf[12]); + instance->ss_ht = ht; + + instance->ss_ht_type = buf[16]; + + if (instance->Ay && instance->Az) + oncore_stats(instance); +} + + + +/* + * get PPS Offset + */ +static void +oncore_msg_Ay( + struct instance *instance, + u_char *buf, + u_int len + ) +{ + if (!instance->printed || instance->Ay) + return; + + instance->Ay = 1; + + instance->offset = buf_w32(&buf[4]); + + if (instance->As && instance->Az) + oncore_stats(instance); +} + + + +/* + * get Cable Delay + */ +static void +oncore_msg_Az( + struct instance *instance, + u_char *buf, + u_int len + ) +{ + if (!instance->printed || instance->Az) + return; + + instance->Az = 1; + + instance->delay = buf_w32(&buf[4]); + + if (instance->As && instance->Ay) + oncore_stats(instance); +} + + + +/* + * print init data in ONCORE to clockstats file + */ +static void +oncore_stats( + struct instance *instance + ) +{ + char Msg[120], ew, ns, *cp, *cp1; + const char *Ht; + double xd, xm, xs, yd, ym, ys, hm, hft; + int idx, idy, is, imx, imy; + long lat, lon; + + /* First, Receiver ID */ + + instance->Cj[294] = '\0'; + for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) { + cp1 = strchr(cp, '\r'); + if (!cp1) + cp1 = (char *)&instance->Cj[294]; + *cp1 = '\0'; + record_clock_stats(&(instance->peer->srcadr), cp); + *cp1 = '\r'; + cp = cp1+2; + } + + /* Next Position */ + + record_clock_stats(&(instance->peer->srcadr), "Posn:"); + ew = 'E'; + lon = instance->ss_long; + if (lon < 0) { + ew = 'W'; + lon = -lon; + } + + ns = 'N'; + lat = instance->ss_lat; + if (lat < 0) { + ns = 'S'; + lat = -lat; + } + + hm = instance->ss_ht/100.; + hft= hm/0.3048; + Ht = instance->ss_ht_type ? "MSL" : "GPS"; + + xd = lat/3600000.; /* lat, lon in int msec arc, ht in cm. */ + yd = lon/3600000.; + sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) %s", ns, xd, ew, yd, hm, hft, Ht); + record_clock_stats(&(instance->peer->srcadr), Msg); + + idx = xd; + idy = yd; + imx = lat%3600000; + imy = lon%3600000; + xm = imx/60000.; + ym = imy/60000.; + sprintf(Msg, "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %5.2fm (%5.2fft) %s", ns, idx, xm, ew, idy, ym, hm, hft, Ht); + record_clock_stats(&(instance->peer->srcadr), Msg); + + imx = xm; + imy = ym; + is = lat%60000; + xs = is/1000.; + is = lon%60000; + ys = is/1000.; + sprintf(Msg, "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %5.2fm (%5.2fft) %s", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft, Ht); + record_clock_stats(&(instance->peer->srcadr), Msg); + + /* finally, cable delay and PPS offset */ + + sprintf(Msg, "Cable delay is set to %ld ns", instance->delay); + record_clock_stats(&(instance->peer->srcadr), Msg); + + sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset); + record_clock_stats(&(instance->peer->srcadr), Msg); + +#ifdef HAVE_PPSAPI + if (instance->assert) + cp = "Timing on Assert."; + else + cp = "Timing on Clear."; + record_clock_stats(&(instance->peer->srcadr), cp); +#endif +} + +#else +int refclock_oncore_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_palisade.c b/contrib/ntp/ntpd/refclock_palisade.c new file mode 100644 index 000000000000..b9a0e2ac9b62 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_palisade.c @@ -0,0 +1,880 @@ +/* + * This software was developed by the Software and Component Technologies + * group of Trimble Navigation, Ltd. + * + * Copyright (c) 1997, 1998, 1999 Trimble Navigation Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Trimble Navigation, Ltd. + * 4. The name of Trimble Navigation Ltd. may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * refclock_palisade - clock driver for the Trimble Palisade GPS + * timing receiver + * + * For detailed information on this program, please refer to the html + * Refclock 29 page accompanying the NTP distribution. + * + * for questions / bugs / comments, contact: + * sven_dietrich@trimble.com + * + * Sven-Thorsten Dietrich + * 645 North Mary Avenue + * Post Office Box 3642 + * Sunnyvale, CA 94088-3642 + * + * Version 2.45; July 14, 1999 + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(REFCLOCK) && (defined(PALISADE) || defined(CLOCK_PALISADE)) + +#include "refclock_palisade.h" +/* Table to get from month to day of the year */ +const int days_of_year [12] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +#ifdef DEBUG +const char * Tracking_Status[15][15] = { + { "Doing Fixes\0" }, { "Good 1SV\0" }, { "Approx. 1SV\0" }, + {"Need Time\0" }, { "Need INIT\0" }, { "PDOP too High\0" }, + { "Bad 1SV\0" }, { "0SV Usable\0" }, { "1SV Usable\0" }, + { "2SV Usable\0" }, { "3SV Usable\0" }, { "No Integrity\0" }, + { "Diff Corr\0" }, { "Overdet Clock\0" }, { "Invalid\0" } }; +#endif + +/* + * Transfer vector + */ +struct refclock refclock_palisade = { + palisade_start, /* start up driver */ + palisade_shutdown, /* shut down driver */ + palisade_poll, /* transmit poll message */ + noentry, /* not used */ + noentry, /* initialize driver (not used) */ + noentry, /* not used */ + NOFLAGS /* not used */ +}; + + +/* + * palisade_start - open the devices and initialize data for processing + */ +static int +palisade_start ( +#ifdef PALISADE + unit, peer + ) + int unit; + struct peer *peer; +#else /* ANSI */ + int unit, + struct peer *peer + ) +#endif +{ + struct palisade_unit *up; + struct refclockproc *pp; + int fd; + char gpsdev[20]; + + struct termios tio; +#ifdef SYS_WINNT + (void) sprintf(gpsdev, "COM%d:", unit); +#else + (void) sprintf(gpsdev, DEVICE, unit); +#endif + /* + * Open serial port. + */ +#if defined PALISADE + fd = open(gpsdev, O_RDWR +#ifdef O_NONBLOCK + | O_NONBLOCK +#endif + ); +#else /* NTP 4.x */ + fd = refclock_open(gpsdev, SPEED232, LDISC_RAW); +#endif + if (fd <= 0) { +#ifdef DEBUG + printf("Palisade(%d) start: open %s failed\n", unit, gpsdev); +#endif + return 0; + } + + msyslog(LOG_NOTICE, "Palisade(%d) fd: %d dev: %s", unit, fd, + gpsdev); + +#if defined PALISADE + tio.c_cflag = (CS8|CLOCAL|CREAD|PARENB|PARODD); + tio.c_iflag = (IGNBRK); + tio.c_oflag = (0); + tio.c_lflag = (0); + + if (cfsetispeed(&tio, SPEED232) == -1) { + msyslog(LOG_ERR,"Palisade(%d) cfsetispeed(fd, &tio): %m",unit); +#ifdef DEBUG + printf("Palisade(%d) cfsetispeed(fd, &tio)\n",unit); +#endif + return 0; + } + if (cfsetospeed(&tio, SPEED232) == -1) { +#ifdef DEBUG + printf("Palisade(%d) cfsetospeed(fd, &tio)\n",unit); +#endif + msyslog(LOG_ERR,"Palisade(%d) cfsetospeed(fd, &tio): %m",unit); + return 0; + } +#else /* NTP 4.x */ + if (tcgetattr(fd, &tio) < 0) { + msyslog(LOG_ERR, + "Palisade(%d) tcgetattr(fd, &tio): %m",unit); +#ifdef DEBUG + printf("Palisade(%d) tcgetattr(fd, &tio)\n",unit); +#endif + return (0); + } + + tio.c_cflag |= (PARENB|PARODD); + tio.c_iflag &= ~ICRNL; +#endif /* NTP 4.x */ + + if (tcsetattr(fd, TCSANOW, &tio) == -1) { + msyslog(LOG_ERR, "Palisade(%d) tcsetattr(fd, &tio): %m",unit); +#ifdef DEBUG + printf("Palisade(%d) tcsetattr(fd, &tio)\n",unit); +#endif + return 0; + } + + /* + * Allocate and initialize unit structure + */ + up = (struct palisade_unit *) emalloc(sizeof(struct palisade_unit)); + + if (!(up)) { + msyslog(LOG_ERR, "Palisade(%d) emalloc: %m",unit); +#ifdef DEBUG + printf("Palisade(%d) emalloc\n",unit); +#endif + (void) close(fd); + return (0); + } + + memset((char *)up, 0, sizeof(struct palisade_unit)); + + pp = peer->procptr; + pp->io.clock_recv = palisade_io; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { +#ifdef DEBUG + printf("Palisade(%d) io_addclock\n",unit); +#endif + (void) close(fd); + free(up); + return (0); + } + + /* + * Initialize miscellaneous variables + */ + pp->unitptr = (caddr_t)up; + pp->clockdesc = DESCRIPTION; + + peer->precision = PRECISION; + peer->sstclktype = CTL_SST_TS_UHF; + peer->minpoll = TRMB_MINPOLL; + peer->maxpoll = TRMB_MAXPOLL; + memcpy((char *)&pp->refid, REFID, 4); + + up->leap_status = 0; + up->unit = (short) unit; + up->rpt_status = TSIP_PARSED_EMPTY; + up->rpt_cnt = 0; + + return 1; +} + + +/* + * palisade_shutdown - shut down the clock + */ +static void +palisade_shutdown ( +#ifdef PALISADE + unit, peer + ) + int unit; + struct peer *peer; +#else /* ANSI */ + int unit, + struct peer *peer + ) +#endif +{ + struct palisade_unit *up; + struct refclockproc *pp; + pp = peer->procptr; + up = (struct palisade_unit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + + +/* + * unpack_date - get day and year from date + */ +int +day_of_year ( +#ifdef PALISADE + dt + ) + char * dt; +#else + char * dt + ) +#endif +{ + int day, mon, year; + + mon = dt[1]; + /* Check month is inside array bounds */ + if ((mon < 1) || (mon > 12)) + return -1; + + day = dt[0] + days_of_year[mon - 1]; + year = getint((u_char *) (dt + 2)); + + if ( !(year % 4) && ((year % 100) || + (!(year % 100) && !(year%400))) + &&(mon > 2)) + day ++; /* leap year and March or later */ + + return day; +} + + +/* + * TSIP_decode - decode the TSIP data packets + */ +int +TSIP_decode ( +#ifdef PALISADE + peer + ) + struct peer *peer; +#else + struct peer *peer + ) +#endif +{ + int st; + long secint; + double secs; + double secfrac; + unsigned short event = 0; + + struct palisade_unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct palisade_unit *)pp->unitptr; + + /* + * Check the time packet, decode its contents. + * If the timecode has invalid length or is not in + * proper format, declare bad format and exit. + */ + + if ((up->rpt_buf[0] == (char) 0x41) || + (up->rpt_buf[0] == (char) 0x46) || + (up->rpt_buf[0] == (char) 0x54) || + (up->rpt_buf[0] == (char) 0x4B) || + (up->rpt_buf[0] == (char) 0x6D)) { + + /* standard time packet - GPS time and GPS week number */ +#ifdef DEBUG + printf("Palisade Port B packets detected. Connect to Port A\n"); +#endif + + return 0; + } + + if (up->rpt_buf[0] == (char) 0x8f) { + /* + * Superpackets + */ + event = (unsigned short) (getint((u_char *) &mb(1)) & 0xffff); + if (!((pp->sloppyclockflag & CLK_FLAG2) || event)) + /* Ignore Packet */ + return 0; + + switch (mb(0) & 0xff) { + int GPS_UTC_Offset; + case PACKET_8F0B: + + if (up->polled <= 0) + return 0; + + if (up->rpt_cnt != LENCODE_8F0B) /* check length */ + break; + +#ifdef DEBUG +if (debug > 1) { + int ts; + double lat, lon, alt; + lat = getdbl((u_char *) &mb(42)) * R2D; + lon = getdbl((u_char *) &mb(50)) * R2D; + alt = getdbl((u_char *) &mb(58)); + + printf("TSIP_decode: unit %d: Latitude: %03.4f Longitude: %03.4f Alt: %05.2f m\n", + up->unit, lat,lon,alt); + printf("TSIP_decode: unit %d: Sats:", up->unit); + for (st = 66, ts = 0; st <= 73; st++) if (mb(st)) { + if (mb(st) > 0) ts++; + printf(" %02d", mb(st)); + } + printf(" : Tracking %d\n", ts); + } +#endif + + GPS_UTC_Offset = getint((u_char *) &mb(16)); + if (GPS_UTC_Offset == 0) { /* Check UTC offset */ +#ifdef DEBUG + printf("TSIP_decode: UTC Offset Unknown\n"); +#endif + break; + } + + secs = getdbl((u_char *) &mb(3)); + secint = (long) secs; + secfrac = secs - secint; /* 0.0 <= secfrac < 1.0 */ + + pp->usec = (long) (secfrac * 1000000); + + secint %= 86400; /* Only care about today */ + pp->hour = secint / 3600; + secint %= 3600; + pp->minute = secint / 60; + secint %= 60; + pp->second = secint % 60; + + if ((pp->day = day_of_year(&mb(11))) < 0) break; + + pp->year = getint((u_char *) &mb(13)); + +#ifdef DEBUG + if (debug > 1) + printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02d\n", + up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, + pp->second, pp->usec, mb(12), mb(11), pp->year, GPS_UTC_Offset); +#endif + /* Only use this packet when no + * 8F-AD's are being received + */ + + if (up->leap_status) { + up->leap_status = 0; + return 0; + } + + return 2; + break; + + case PACKET_NTP: + /* Palisade-NTP Packet */ + + if (up->rpt_cnt != LENCODE_NTP) /* check length */ + break; + + up->leap_status = mb(19); + + if (up->polled <= 0) + return 0; + + /* Check Tracking Status */ + st = mb(18); + if (st < 0 || st > 14) st = 14; + if ((st >= 2 && st <= 7) || st == 11 || st == 12) { +#ifdef DEBUG + printf("TSIP_decode: Not Tracking Sats : %s\n", + *Tracking_Status[st]); +#endif + refclock_report(peer, CEVNT_BADTIME); + up->polled = -1; + return 0; + break; + } + + if (up->leap_status & PALISADE_LEAP_PENDING) { + if (up->leap_status & PALISADE_UTC_TIME) + pp->leap = LEAP_ADDSECOND; + else + pp->leap = LEAP_DELSECOND; + } + else if (up->leap_status) + pp->leap = LEAP_NOWARNING; + + else { /* UTC flag is not set: + * Receiver may have been reset, and lost + * its UTC almanac data */ + pp->leap = LEAP_NOTINSYNC; +#ifdef DEBUG + printf("TSIP_decode: UTC Almanac unavailable: %d\n", + mb(19)); +#endif + refclock_report(peer, CEVNT_BADTIME); + up->polled = -1; + return 0; + } + + pp->usec = (long) (getdbl((u_char *) &mb(3)) * 1000000); + + if ((pp->day = day_of_year(&mb(14))) < 0) + break; + pp->year = getint((u_char *) &mb(16)); + pp->hour = mb(11); + pp->minute = mb(12); + pp->second = mb(13); + +#ifdef DEBUG + if (debug > 1) +printf("TSIP_decode: unit %d: %02X #%d %02d:%02d:%02d.%06ld %02d/%02d/%04d UTC %02x %s\n", + up->unit, mb(0) & 0xff, event, pp->hour, pp->minute, + pp->second, pp->usec, mb(15), mb(14), pp->year, + mb(19), *Tracking_Status[st]); +#endif + return 1; + break; + + default: + /* Ignore Packet */ + return 0; + } /* switch */ + }/* if 8F packets */ + + refclock_report(peer, CEVNT_BADREPLY); + up->polled = -1; +#ifdef DEBUG + printf("TSIP_decode: unit %d: bad packet %02x-%02x event %d len %d\n", + up->unit, up->rpt_buf[0] & 0xff, mb(0) & 0xff, + event, up->rpt_cnt); +#endif + return 0; +} + +/* + * palisade__receive - receive data from the serial interface + */ + +static void +palisade_receive ( +#ifdef PALISADE + peer + ) + struct peer * peer; +#else /* ANSI */ + struct peer * peer + ) +#endif +{ + struct palisade_unit *up; + struct refclockproc *pp; + + /* + * Initialize pointers and read the timecode and timestamp. + */ + pp = peer->procptr; + up = (struct palisade_unit *)pp->unitptr; + + if (! TSIP_decode(peer)) return; + + if (up->polled <= 0) + return; /* no poll pending, already received or timeout */ + + up->polled = 0; /* Poll reply received */ + pp->lencode = 0; /* clear time code */ +#ifdef DEBUG + if (debug) + printf( + "palisade_receive: unit %d: %4d %03d %02d:%02d:%02d.%06ld\n", + up->unit, pp->year, pp->day, pp->hour, pp->minute, + pp->second, pp->usec); +#endif + + /* + * Process the sample + * Generate timecode: YYYY DoY HH:MM:SS.microsec + * report and process + */ + + (void) sprintf(pp->a_lastcode,"%4d %03d %02d:%02d:%02d.%06ld", + pp->year,pp->day,pp->hour,pp->minute, pp->second,pp->usec); + pp->lencode = 24; + +#ifdef PALISADE + pp->lasttime = current_time; +#endif + if (!refclock_process(pp +#ifdef PALISADE + , PALISADE_SAMPLES, PALISADE_SAMPLES * 3 / 5 +#endif + )) { + refclock_report(peer, CEVNT_BADTIME); + +#ifdef DEBUG + printf("palisade_receive: unit %d: refclock_process failed!\n", + up->unit); +#endif + return; + } + + record_clock_stats(&peer->srcadr, pp->a_lastcode); + +#ifdef DEBUG + if (debug) + printf("palisade_receive: unit %d: %s\n", + up->unit, prettydate(&pp->lastrec)); +#endif + + refclock_receive(peer +#ifdef PALISADE + , &pp->offset, 0, pp->dispersion, + &pp->lastrec, &pp->lastrec, pp->leap +#endif + ); +} + + +/* + * palisade_poll - called by the transmit procedure + * + */ +static void +palisade_poll ( +#ifdef PALISADE + unit, peer + ) + int unit; + struct peer *peer; +#else + int unit, + struct peer *peer + ) +#endif +{ + struct palisade_unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct palisade_unit *)pp->unitptr; + + pp->polls++; + if (up->polled > 0) /* last reply never arrived or error */ + refclock_report(peer, CEVNT_TIMEOUT); + + up->polled = 2; /* synchronous packet + 1 event */ + +#ifdef DEBUG + if (debug) + printf("palisade_poll: unit %d: polling %s\n", unit, + (pp->sloppyclockflag & CLK_FLAG2) ? + "synchronous packet" : "event"); +#endif + + if (pp->sloppyclockflag & CLK_FLAG2) + return; /* using synchronous packet input */ + + if (HW_poll(pp) < 0) + refclock_report(peer, CEVNT_FAULT); +} + + +static void +palisade_io ( +#ifdef PALISADE + rbufp + ) + struct recvbuf *rbufp; +#else /* ANSI */ + struct recvbuf *rbufp + ) +#endif +{ + /* + * Initialize pointers and read the timecode and timestamp. + */ + struct palisade_unit *up; + struct refclockproc *pp; + struct peer *peer; + + char * c, * d; + + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct palisade_unit *)pp->unitptr; + + c = (char *) &rbufp->recv_space; + d = c + rbufp->recv_length; + + while (c != d) { + + /* Build time packet */ + switch (up->rpt_status) { + + case TSIP_PARSED_DLE_1: + switch (*c) + { + case 0: + case DLE: + case ETX: + up->rpt_status = TSIP_PARSED_EMPTY; + break; + + default: + up->rpt_status = TSIP_PARSED_DATA; + /* save packet ID */ + up->rpt_buf[0] = *c; + break; + } + break; + + case TSIP_PARSED_DATA: + if (*c == DLE) + up->rpt_status = TSIP_PARSED_DLE_2; + else + mb(up->rpt_cnt++) = *c; + break; + + case TSIP_PARSED_DLE_2: + if (*c == DLE) { + up->rpt_status = TSIP_PARSED_DATA; + mb(up->rpt_cnt++) = + *c; + } + else if (*c == ETX) + up->rpt_status = TSIP_PARSED_FULL; + else { + /* error: start new report packet */ + up->rpt_status = TSIP_PARSED_DLE_1; + up->rpt_buf[0] = *c; + } + break; + + case TSIP_PARSED_FULL: + case TSIP_PARSED_EMPTY: + default: + if ( *c != DLE) + up->rpt_status = TSIP_PARSED_EMPTY; + else + up->rpt_status = TSIP_PARSED_DLE_1; + break; + } + + c++; + + if (up->rpt_status == TSIP_PARSED_DLE_1) { + up->rpt_cnt = 0; + if (pp->sloppyclockflag & CLK_FLAG2) + /* stamp it */ + get_systime(&pp->lastrec); + } + else if (up->rpt_status == TSIP_PARSED_EMPTY) + up->rpt_cnt = 0; + + else if (up->rpt_cnt > BMAX) + up->rpt_status =TSIP_PARSED_EMPTY; + + if (up->rpt_status == TSIP_PARSED_FULL) + palisade_receive(peer); + + } /* while chars in buffer */ +} + + +/* + * Trigger the Palisade's event input, which is driven off the RTS + * + * Take a system time stamp to match the GPS time stamp. + * + */ +long +HW_poll ( +#ifdef PALISADE + pp /* pointer to unit structure */ + ) + struct refclockproc * pp; /* pointer to unit structure */ +#else + struct refclockproc * pp /* pointer to unit structure */ + ) +#endif +{ + int x; /* state before & after RTS set */ + struct palisade_unit *up; + + up = (struct palisade_unit *) pp->unitptr; + + /* read the current status, so we put things back right */ + if (ioctl(pp->io.fd, TIOCMGET, &x) < 0) { +#ifdef DEBUG + if (debug) + printf("Palisade HW_poll: unit %d: GET %s\n", up->unit, strerror(errno)); +#endif + msyslog(LOG_ERR, "Palisade(%d) HW_poll: ioctl(fd,GET): %m", + up->unit); + return -1; + } + + x |= TIOCM_RTS; /* turn on RTS */ + + /* Edge trigger */ + if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) { +#ifdef DEBUG + if (debug) + printf("Palisade HW_poll: unit %d: SET \n", up->unit); +#endif + msyslog(LOG_ERR, + "Palisade(%d) HW_poll: ioctl(fd, SET, RTS_on): %m", + up->unit); + return -1; + } + + x &= ~TIOCM_RTS; /* turn off RTS */ + + /* poll timestamp */ + get_systime(&pp->lastrec); + + if (ioctl(pp->io.fd, TIOCMSET, &x) == -1) { +#ifdef DEBUG + if (debug) + printf("Palisade HW_poll: unit %d: UNSET \n", up->unit); +#endif + msyslog(LOG_ERR, + "Palisade(%d) HW_poll: ioctl(fd, UNSET, RTS_off): %m", + up->unit); + return -1; + } + + return 0; +} + +#if 0 /* unused */ +/* + * this 'casts' a character array into a float + */ +float +getfloat ( +#ifdef PALISADE + bp + ) + u_char *bp; +#else + u_char *bp + ) +#endif +{ + float sval; +#ifdef WORDS_BIGENDIAN + ((char *) &sval)[0] = *bp++; + ((char *) &sval)[1] = *bp++; + ((char *) &sval)[2] = *bp++; + ((char *) &sval)[3] = *bp++; +#else + ((char *) &sval)[3] = *bp++; + ((char *) &sval)[2] = *bp++; + ((char *) &sval)[1] = *bp++; + ((char *) &sval)[0] = *bp; +#endif /* ! XNTP_BIG_ENDIAN */ + return sval; +} +#endif + +/* + * this 'casts' a character array into a double + */ +double +getdbl ( +#ifdef PALISADE + bp + ) + u_char *bp; +#else + u_char *bp + ) +#endif +{ + double dval; +#ifdef WORDS_BIGENDIAN + ((char *) &dval)[0] = *bp++; + ((char *) &dval)[1] = *bp++; + ((char *) &dval)[2] = *bp++; + ((char *) &dval)[3] = *bp++; + ((char *) &dval)[4] = *bp++; + ((char *) &dval)[5] = *bp++; + ((char *) &dval)[6] = *bp++; + ((char *) &dval)[7] = *bp; +#else + ((char *) &dval)[7] = *bp++; + ((char *) &dval)[6] = *bp++; + ((char *) &dval)[5] = *bp++; + ((char *) &dval)[4] = *bp++; + ((char *) &dval)[3] = *bp++; + ((char *) &dval)[2] = *bp++; + ((char *) &dval)[1] = *bp++; + ((char *) &dval)[0] = *bp; +#endif /* ! XNTP_BIG_ENDIAN */ + return dval; +} + +/* + * cast a 16 bit character array into a short (16 bit) int + */ +short +getint ( +#ifdef PALISADE + bp + ) + u_char *bp; +#else + u_char *bp + ) +#endif +{ +return (short) (bp[1] + (bp[0] << 8)); +} + +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_palisade.h b/contrib/ntp/ntpd/refclock_palisade.h new file mode 100644 index 000000000000..b78d9880b883 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_palisade.h @@ -0,0 +1,167 @@ +/* + * This software was developed by the Software and Component Technologies + * group of Trimble Navigation, Ltd. + * + * Copyright (c) 1997, 1998, 1999 Trimble Navigation Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Trimble Navigation, Ltd. + * 4. The name of Trimble Navigation Ltd. may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY TRIMBLE NAVIGATION LTD. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL TRIMBLE NAVIGATION LTD. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * refclock_palisade - clock driver for the Trimble Palisade GPS + * timing receiver + * + * For detailed information on this program, please refer to the html + * Refclock 29 page accompanying the NTP distribution. + * + * for questions / bugs / comments, contact: + * sven_dietrich@trimble.com + * + * Sven-Thorsten Dietrich + * 645 North Mary Avenue + * Post Office Box 3642 + * Sunnyvale, CA 94088-3642 + * + */ + +#ifndef _REFCLOCK_PALISADE_H +#define _REFCLOCK_PALISADE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined HAVE_SYS_MODEM_H +#include +#define TIOCMSET MCSETA +#define TIOCMGET MCGETA +#define TIOCM_RTS MRTS +#endif + +#ifdef HAVE_TERMIOS_H +# ifdef TERMIOS_NEEDS__SVID3 +# define _SVID3 +# endif +# include +# ifdef TERMIOS_NEEDS__SVID3 +# undef _SVID3 +# endif +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_control.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +/* + * GPS Definitions + */ +#define DESCRIPTION "Trimble Palisade GPS" /* Long name */ +#define PRECISION (-20) /* precision assumed (about 1 us) */ +#define REFID "GPS\0" /* reference ID */ +#define TRMB_MINPOLL 5 /* 16 seconds */ +#define TRMB_MAXPOLL 7 /* 64 seconds */ + +/* + * I/O Definitions + */ +#define DEVICE "/dev/palisade%d" /* device name and unit */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ + +/* + * TSIP Report Definitions + */ +#define LENCODE_8F0B 74 /* Length of TSIP 8F-0B Packet & header */ +#define LENCODE_NTP 22 /* Length of Palisade NTP Packet */ + +/* Allowed Sub-Packet ID's */ +#define PACKET_8F0B 0x0B +#define PACKET_NTP 0xAD + +#define DLE 0x10 +#define ETX 0x03 + +/* parse states */ +#define TSIP_PARSED_EMPTY 0 +#define TSIP_PARSED_FULL 1 +#define TSIP_PARSED_DLE_1 2 +#define TSIP_PARSED_DATA 3 +#define TSIP_PARSED_DLE_2 4 + +/* + * Leap-Insert and Leap-Delete are encoded as follows: + * PALISADE_UTC_TIME set and PALISADE_LEAP_PENDING set: INSERT leap + */ + +#define PALISADE_LEAP_INPROGRESS 0x08 /* This is the leap flag */ +#define PALISADE_LEAP_WARNING 0x04 /* GPS Leap Warning (see ICD-200) */ +#define PALISADE_LEAP_PENDING 0x02 /* Leap Pending (24 hours) */ +#define PALISADE_UTC_TIME 0x01 /* UTC time available */ + +#define mb(_X_) (up->rpt_buf[(_X_ + 1)]) /* shortcut for buffer access */ + +/* Conversion Definitions */ +#define GPS_PI (3.1415926535898) +#define R2D (180.0/GPS_PI) + +/* + * Palisade unit control structure. + */ +struct palisade_unit { + short unit; /* NTP refclock unit number */ + int polled; /* flag to detect noreplies */ + char leap_status; /* leap second flag */ + char rpt_status; /* TSIP Parser State */ + short rpt_cnt; /* TSIP packet length so far */ + char rpt_buf[BMAX]; /* packet assembly buffer */ +}; + +/* + * Function prototypes + */ + +static int palisade_start P((int, struct peer *)); +static void palisade_shutdown P((int, struct peer *)); +static void palisade_receive P((struct peer *)); +static void palisade_poll P((int, struct peer *)); +static void palisade_io P((struct recvbuf *)); +int palisade_configure P((int, struct peer *)); +int TSIP_decode P((struct peer *)); +long HW_poll P((struct refclockproc *)); +float getfloat P((u_char *)); +double getdbl P((u_char *)); +short getint P((u_char *)); + +#endif /* PALISADE_H */ diff --git a/contrib/ntp/ntpd/refclock_parse.c b/contrib/ntp/ntpd/refclock_parse.c new file mode 100644 index 000000000000..6771a139ed10 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_parse.c @@ -0,0 +1,5340 @@ +/* + * /src/NTP/ntp-4/ntpd/refclock_parse.c,v 4.29 1999/02/28 19:58:23 kardel RELEASE_19990228_A + * + * refclock_parse.c,v 4.29 1999/02/28 19:58:23 kardel RELEASE_19990228_A + * + * generic reference clock driver for receivers + * + * optionally make use of a STREAMS module for input processing where + * available and configured. Currently the STREAMS module + * is only available for Suns running SunOS 4.x and SunOS5.x + * + * the STREAMS module is not required for operation and may be omitted + * at the cost of reduced accuracy. As new kernel interfaces emerger this + * restriction may be lifted in future. + * + * Copyright (c) 1995-1999 by Frank Kardel + * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * This software may not be sold for profit without a written consent + * from the author. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PARSE) + +/* + * This driver currently provides the support for + * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF) + * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF) + * - Meinberg receiver DCF77 PZF 509 (DCF) + * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF) + * - IGEL CLOCK (DCF) + * - ELV DCF7000 (DCF) + * - Schmid clock (DCF) + * - Conrad DCF77 receiver module (DCF) + * - FAU DCF77 NTP receiver (TimeBrick) (DCF) + * + * - Meinberg GPS166/GPS167 (GPS) + * - Trimble (TSIP and TAIP protocol) (GPS) + * + * - RCC8000 MSF Receiver (MSF) + * - WHARTON 400A Series clock (DCF) + * - VARITEXT clock (MSF) + */ + +/* + * Meinberg receivers are usually connected via a + * 9600 baud serial line + * + * The Meinberg GPS receivers also have a special NTP time stamp + * format. The firmware release is Uni-Erlangen. + * + * Meinberg generic receiver setup: + * output time code every second + * Baud rate 9600 7E2S + * + * Meinberg GPS16x setup: + * output time code every second + * Baudrate 19200 8N1 + * + * This software supports the standard data formats used + * in Meinberg receivers. + * + * Special software versions are only sensible for the + * GPS 16x family of receivers. + * + * Meinberg can be reached via: http://www.meinberg.de/ + */ + +#include "ntpd.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" /* includes */ +#include "ntp_control.h" + +#include +#include +#ifndef TM_IN_SYS_TIME +# include +#endif + +#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS) +# include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}" +#endif + +#ifdef STREAM +# include +# include +#endif + +#ifdef HAVE_TERMIOS +# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) +# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) +# undef HAVE_SYSV_TTYS +#endif + +#ifdef HAVE_SYSV_TTYS +# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) +# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) +#endif + +#ifdef HAVE_BSD_TTYS +/* #error CURRENTLY NO BSD TTY SUPPORT */ +# include "Bletch: BSD TTY not currently supported" +#endif + +#ifdef HAVE_SYS_IOCTL_H +# include +#endif + +#ifdef PPS +#ifdef HAVE_SYS_PPSCLOCK_H +#include +#endif +#ifdef HAVE_TIO_SERIAL_STUFF +#include +#endif +#endif + +#include "ntp_io.h" +#include "ntp_stdlib.h" + +#include "parse.h" +#include "mbg_gps166.h" +#include "trimble.h" +#include "binio.h" +#include "ascii.h" +#include "ieee754io.h" + +static char rcsid[]="refclock_parse.c,v 4.29 1999/02/28 19:58:23 kardel RELEASE_19990228_A"; + +/**=========================================================================== + ** external interface to ntp mechanism + **/ + +static void parse_init P((void)); +static int parse_start P((int, struct peer *)); +static void parse_shutdown P((int, struct peer *)); +static void parse_poll P((int, struct peer *)); +static void parse_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); + +#define parse_buginfo noentry + +struct refclock refclock_parse = { + parse_start, + parse_shutdown, + parse_poll, + parse_control, + parse_init, + parse_buginfo, + NOFLAGS +}; + +/* + * Definitions + */ +#define MAXUNITS 4 /* maximum number of "PARSE" units permitted */ +#define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */ + +#undef ABS +#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_)) + +/**=========================================================================== + ** function vector for dynamically binding io handling mechanism + **/ + +struct parseunit; /* to keep inquiring minds happy */ + +typedef struct bind +{ + const char *bd_description; /* name of type of binding */ + int (*bd_init) P((struct parseunit *)); /* initialize */ + void (*bd_end) P((struct parseunit *)); /* end */ + int (*bd_setcs) P((struct parseunit *, parsectl_t *)); /* set character size */ + int (*bd_disable) P((struct parseunit *)); /* disable */ + int (*bd_enable) P((struct parseunit *)); /* enable */ + int (*bd_getfmt) P((struct parseunit *, parsectl_t *)); /* get format */ + int (*bd_setfmt) P((struct parseunit *, parsectl_t *)); /* setfmt */ + int (*bd_timecode) P((struct parseunit *, parsectl_t *)); /* get time code */ + void (*bd_receive) P((struct recvbuf *)); /* receive operation */ + int (*bd_io_input) P((struct recvbuf *)); /* input operation */ +} bind_t; + +#define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_) +#define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_) +#define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_) +#define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_) +#define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_) +#define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_) +#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_) + +/* + * io modes + */ +#define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */ +#define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */ + + +/**=========================================================================== + ** error message regression handling + ** + ** there are quite a few errors that can occur in rapid succession such as + ** noisy input data or no data at all. in order to reduce the amount of + ** syslog messages in such case, we are using a backoff algorithm. We limit + ** the number of error messages of a certain class to 1 per time unit. if a + ** configurable number of messages is displayed that way, we move on to the + ** next time unit / count for that class. a count of messages that have been + ** suppressed is held and displayed whenever a corresponding message is + ** displayed. the time units for a message class will also be displayed. + ** whenever an error condition clears we reset the error message state, + ** thus we would still generate much output on pathological conditions + ** where the system oscillates between OK and NOT OK states. coping + ** with that condition is currently considered too complicated. + **/ + +#define ERR_ALL (unsigned)~0 /* "all" errors */ +#define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */ +#define ERR_NODATA (unsigned)1 /* no input data */ +#define ERR_BADIO (unsigned)2 /* read/write/select errors */ +#define ERR_BADSTATUS (unsigned)3 /* unsync states */ +#define ERR_BADEVENT (unsigned)4 /* non nominal events */ +#define ERR_INTERNAL (unsigned)5 /* internal error */ +#define ERR_CNT (unsigned)(ERR_INTERNAL+1) + +#define ERR(_X_) if (list_err(parse, (_X_))) + +struct errorregression +{ + u_long err_count; /* number of repititions per class */ + u_long err_delay; /* minimum delay between messages */ +}; + +static struct errorregression +err_baddata[] = /* error messages for bad input data */ +{ + { 1, 0 }, /* output first message immediately */ + { 5, 60 }, /* output next five messages in 60 second intervals */ + { 3, 3600 }, /* output next 3 messages in hour intervals */ + { 0, 12*3600 } /* repeat messages only every 12 hours */ +}; + +static struct errorregression +err_nodata[] = /* error messages for missing input data */ +{ + { 1, 0 }, /* output first message immediately */ + { 5, 60 }, /* output next five messages in 60 second intervals */ + { 3, 3600 }, /* output next 3 messages in hour intervals */ + { 0, 12*3600 } /* repeat messages only every 12 hours */ +}; + +static struct errorregression +err_badstatus[] = /* unsynchronized state messages */ +{ + { 1, 0 }, /* output first message immediately */ + { 5, 60 }, /* output next five messages in 60 second intervals */ + { 3, 3600 }, /* output next 3 messages in hour intervals */ + { 0, 12*3600 } /* repeat messages only every 12 hours */ +}; + +static struct errorregression +err_badio[] = /* io failures (bad reads, selects, ...) */ +{ + { 1, 0 }, /* output first message immediately */ + { 5, 60 }, /* output next five messages in 60 second intervals */ + { 5, 3600 }, /* output next 3 messages in hour intervals */ + { 0, 12*3600 } /* repeat messages only every 12 hours */ +}; + +static struct errorregression +err_badevent[] = /* non nominal events */ +{ + { 20, 0 }, /* output first message immediately */ + { 6, 60 }, /* output next five messages in 60 second intervals */ + { 5, 3600 }, /* output next 3 messages in hour intervals */ + { 0, 12*3600 } /* repeat messages only every 12 hours */ +}; + +static struct errorregression +err_internal[] = /* really bad things - basically coding/OS errors */ +{ + { 0, 0 }, /* output all messages immediately */ +}; + +static struct errorregression * +err_tbl[] = +{ + err_baddata, + err_nodata, + err_badio, + err_badstatus, + err_badevent, + err_internal +}; + +struct errorinfo +{ + u_long err_started; /* begin time (ntp) of error condition */ + u_long err_last; /* last time (ntp) error occurred */ + u_long err_cnt; /* number of error repititions */ + u_long err_suppressed; /* number of suppressed messages */ + struct errorregression *err_stage; /* current error stage */ +}; + +/**=========================================================================== + ** refclock instance data + **/ + +struct parseunit +{ + /* + * NTP management + */ + struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */ + struct refclockproc *generic; /* backlink to refclockproc structure */ + + /* + * PARSE io + */ + bind_t *binding; /* io handling binding */ + + /* + * parse state + */ + parse_t parseio; /* io handling structure (user level parsing) */ + + /* + * type specific parameters + */ + struct parse_clockinfo *parse_type; /* link to clock description */ + + /* + * clock state handling/reporting + */ + u_char flags; /* flags (leap_control) */ + u_long lastchange; /* time (ntp) when last state change accured */ + u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */ + u_char pollneeddata; /* 1 for receive sample expected in PPS mode */ + u_short lastformat; /* last format used */ + u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */ + u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */ + u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */ + parsetime_t time; /* last (parse module) data */ + void *localdata; /* optional local, receiver-specific data */ + unsigned long localstate; /* private local state */ + struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */ + struct ctl_var *kv; /* additional pseudo variables */ + u_long laststatistic; /* time when staticstics where output */ +}; + + +/**=========================================================================== + ** Clockinfo section all parameter for specific clock types + ** includes NTP parameters, TTY parameters and IO handling parameters + **/ + +static void poll_dpoll P((struct parseunit *)); +static void poll_poll P((struct peer *)); +static int poll_init P((struct parseunit *)); + +typedef struct poll_info +{ + u_long rate; /* poll rate - once every "rate" seconds - 0 off */ + const char *string; /* string to send for polling */ + u_long count; /* number of characters in string */ +} poll_info_t; + +#define NO_CL_FLAGS 0 +#define NO_POLL 0 +#define NO_INIT 0 +#define NO_END 0 +#define NO_EVENT 0 +#define NO_DATA 0 +#define NO_MESSAGE 0 +#define NO_PPSDELAY 0 + +#define DCF_ID "DCF" /* generic DCF */ +#define DCF_A_ID "DCFa" /* AM demodulation */ +#define DCF_P_ID "DCFp" /* psuedo random phase shift */ +#define GPS_ID "GPS" /* GPS receiver */ + +#define NOCLOCK_ROOTDELAY 0.0 +#define NOCLOCK_BASEDELAY 0.0 +#define NOCLOCK_DESCRIPTION 0 +#define NOCLOCK_MAXUNSYNC 0 +#define NOCLOCK_CFLAG 0 +#define NOCLOCK_IFLAG 0 +#define NOCLOCK_OFLAG 0 +#define NOCLOCK_LFLAG 0 +#define NOCLOCK_ID "TILT" +#define NOCLOCK_POLL NO_POLL +#define NOCLOCK_INIT NO_INIT +#define NOCLOCK_END NO_END +#define NOCLOCK_DATA NO_DATA +#define NOCLOCK_FORMAT "" +#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC +#define NOCLOCK_SAMPLES 0 +#define NOCLOCK_KEEP 0 + +#define DCF_TYPE CTL_SST_TS_LF +#define GPS_TYPE CTL_SST_TS_UHF + +/* + * receiver specific constants + */ +#define MBG_SPEED (B9600) +#define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL) +#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP) +#define MBG_OFLAG 0 +#define MBG_LFLAG 0 +#define MBG_FLAGS PARSE_F_PPSONSECOND + +/* + * Meinberg DCF77 receivers + */ +#define DCFUA31_ROOTDELAY 0.0 /* 0 */ +#define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */ +#define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible" +#define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */ +#define DCFUA31_SPEED MBG_SPEED +#define DCFUA31_CFLAG MBG_CFLAG +#define DCFUA31_IFLAG MBG_IFLAG +#define DCFUA31_OFLAG MBG_OFLAG +#define DCFUA31_LFLAG MBG_LFLAG +#define DCFUA31_SAMPLES 5 +#define DCFUA31_KEEP 3 +#define DCFUA31_FORMAT "Meinberg Standard" + +/* + * Meinberg DCF PZF535/TCXO (FM/PZF) receiver + */ +#define DCFPZF535_ROOTDELAY 0.0 +#define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ +#define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO" +#define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours + * @ 5e-8df/f we have accumulated + * at most 2.16 ms (thus we move to + * NTP synchronisation */ +#define DCFPZF535_SPEED MBG_SPEED +#define DCFPZF535_CFLAG MBG_CFLAG +#define DCFPZF535_IFLAG MBG_IFLAG +#define DCFPZF535_OFLAG MBG_OFLAG +#define DCFPZF535_LFLAG MBG_LFLAG +#define DCFPZF535_SAMPLES 5 +#define DCFPZF535_KEEP 3 +#define DCFPZF535_FORMAT "Meinberg Standard" + +/* + * Meinberg DCF PZF535/OCXO receiver + */ +#define DCFPZF535OCXO_ROOTDELAY 0.0 +#define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ +#define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO" +#define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days + * @ 5e-9df/f we have accumulated + * at most an error of 1.73 ms + * (thus we move to NTP synchronisation) */ +#define DCFPZF535OCXO_SPEED MBG_SPEED +#define DCFPZF535OCXO_CFLAG MBG_CFLAG +#define DCFPZF535OCXO_IFLAG MBG_IFLAG +#define DCFPZF535OCXO_OFLAG MBG_OFLAG +#define DCFPZF535OCXO_LFLAG MBG_LFLAG +#define DCFPZF535OCXO_SAMPLES 5 +#define DCFPZF535OCXO_KEEP 3 +#define DCFPZF535OCXO_FORMAT "Meinberg Standard" + +/* + * Meinberg GPS16X receiver + */ +static void gps16x_message P((struct parseunit *, parsetime_t *)); +static int gps16x_poll_init P((struct parseunit *)); + +#define GPS16X_ROOTDELAY 0.0 /* nothing here */ +#define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ +#define GPS16X_DESCRIPTION "Meinberg GPS16x receiver" +#define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days + * @ 5e-9df/f we have accumulated + * at most an error of 1.73 ms + * (thus we move to NTP synchronisation) */ +#define GPS16X_SPEED B19200 +#define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL) +#define GPS16X_IFLAG (IGNBRK|IGNPAR) +#define GPS16X_OFLAG MBG_OFLAG +#define GPS16X_LFLAG MBG_LFLAG +#define GPS16X_POLLRATE 6 +#define GPS16X_POLLCMD "" +#define GPS16X_CMDSIZE 0 + +static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE }; + +#define GPS16X_INIT gps16x_poll_init +#define GPS16X_POLL 0 +#define GPS16X_END 0 +#define GPS16X_DATA ((void *)(&gps16x_pollinfo)) +#define GPS16X_MESSAGE gps16x_message +#define GPS16X_ID GPS_ID +#define GPS16X_FORMAT "Meinberg GPS Extended" +#define GPS16X_SAMPLES 5 +#define GPS16X_KEEP 3 + +/* + * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit) + * + * This is really not the hottest clock - but before you have nothing ... + */ +#define DCF7000_ROOTDELAY 0.0 /* 0 */ +#define DCF7000_BASEDELAY 0.405 /* slow blow */ +#define DCF7000_DESCRIPTION "ELV DCF7000" +#define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */ +#define DCF7000_SPEED (B9600) +#define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL) +#define DCF7000_IFLAG (IGNBRK) +#define DCF7000_OFLAG 0 +#define DCF7000_LFLAG 0 +#define DCF7000_SAMPLES 5 +#define DCF7000_KEEP 3 +#define DCF7000_FORMAT "ELV DCF7000" + +/* + * Schmid DCF Receiver Kit + * + * When the WSDCF clock is operating optimally we want the primary clock + * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer + * structure is set to 290 ms and we compute delays which are at least + * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format + */ +#define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */ +#define WS_POLLCMD "\163" +#define WS_CMDSIZE 1 + +static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE }; + +#define WSDCF_INIT poll_init +#define WSDCF_POLL poll_dpoll +#define WSDCF_END 0 +#define WSDCF_DATA ((void *)(&wsdcf_pollinfo)) +#define WSDCF_ROOTDELAY 0.0 /* 0 */ +#define WSDCF_BASEDELAY 0.010 /* ~ 10ms */ +#define WSDCF_DESCRIPTION "WS/DCF Receiver" +#define WSDCF_FORMAT "Schmid" +#define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */ +#define WSDCF_SPEED (B1200) +#define WSDCF_CFLAG (CS8|CREAD|CLOCAL) +#define WSDCF_IFLAG 0 +#define WSDCF_OFLAG 0 +#define WSDCF_LFLAG 0 +#define WSDCF_SAMPLES 5 +#define WSDCF_KEEP 3 + +/* + * RAW DCF77 - input of DCF marks via RS232 - many variants + */ +#define RAWDCF_FLAGS 0 +#define RAWDCF_ROOTDELAY 0.0 /* 0 */ +#define RAWDCF_BASEDELAY 0.258 +#define RAWDCF_FORMAT "RAW DCF77 Timecode" +#define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */ +#define RAWDCF_SPEED (B50) +#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */ +/* somehow doesn't grok PARENB & IGNPAR (mj) */ +# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL) +#else +# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB) +#endif +#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */ +# define RAWDCF_IFLAG 0 +#else +# define RAWDCF_IFLAG (IGNPAR) +#endif +#define RAWDCF_OFLAG 0 +#define RAWDCF_LFLAG 0 +#define RAWDCF_SAMPLES 20 +#define RAWDCF_KEEP 12 +#define RAWDCF_INIT 0 + +/* + * RAW DCF variants + */ +/* + * Conrad receiver + * + * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad + * (~40DM - roughly $30 ) followed by a level converter for RS232 + */ +#define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */ +#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)" + +/* + * TimeBrick receiver + */ +#define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */ +#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)" + +/* + * IGEL:clock receiver + */ +#define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */ +#define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)" +#define IGELCLOCK_SPEED (B1200) +#define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL) + +/* + * RAWDCF receivers that need to be powered from DTR + * (like Expert mouse clock) + */ +static int rawdcfdtr_init P((struct parseunit *)); +#define RAWDCFDTR_DESCRIPTION "RAW DCF77 CODE (DTR OPTION)" +#define RAWDCFDTR_INIT rawdcfdtr_init + +/* + * RAWDCF receivers that need to be powered from RTS + */ +static int rawdcfrts_init P((struct parseunit *)); +#define RAWDCFRTS_DESCRIPTION "RAW DCF77 CODE (RTS OPTION)" +#define RAWDCFRTS_INIT rawdcfrts_init + +/* + * Trimble GPS receivers (TAIP and TSIP protocols) + */ +#ifndef TRIM_POLLRATE +#define TRIM_POLLRATE 0 /* only true direct polling */ +#endif + +#define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<" +#define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1) + +static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE }; +static int trimbletaip_init P((struct parseunit *)); +static void trimbletaip_event P((struct parseunit *, int)); + +/* query time & UTC correction data */ +static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX }; + +static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) }; +static int trimbletsip_init P((struct parseunit *)); +static void trimbletsip_end P((struct parseunit *)); +static void trimbletsip_message P((struct parseunit *, parsetime_t *)); +static void trimbletsip_event P((struct parseunit *, int)); + +#define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */ + +#define TRIMBLETAIP_SPEED (B4800) +#define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL) +#define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON) +#define TRIMBLETAIP_OFLAG (OPOST|ONLCR) +#define TRIMBLETAIP_LFLAG (0) + +#define TRIMBLETSIP_SPEED (B9600) +#define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD) +#define TRIMBLETSIP_IFLAG (IGNBRK) +#define TRIMBLETSIP_OFLAG (0) +#define TRIMBLETSIP_LFLAG (ICANON) + +#define TRIMBLETSIP_SAMPLES 5 +#define TRIMBLETSIP_KEEP 3 +#define TRIMBLETAIP_SAMPLES 5 +#define TRIMBLETAIP_KEEP 3 + +#define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND) +#define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS) + +#define TRIMBLETAIP_POLL poll_dpoll +#define TRIMBLETSIP_POLL poll_dpoll + +#define TRIMBLETAIP_INIT trimbletaip_init +#define TRIMBLETSIP_INIT trimbletsip_init + +#define TRIMBLETAIP_EVENT trimbletaip_event + +#define TRIMBLETSIP_EVENT trimbletsip_event +#define TRIMBLETSIP_MESSAGE trimbletsip_message + +#define TRIMBLETAIP_END 0 +#define TRIMBLETSIP_END trimbletsip_end + +#define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo)) +#define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo)) + +#define TRIMBLETAIP_ID GPS_ID +#define TRIMBLETSIP_ID GPS_ID + +#define TRIMBLETAIP_FORMAT "Trimble TAIP" +#define TRIMBLETSIP_FORMAT "Trimble TSIP" + +#define TRIMBLETAIP_ROOTDELAY 0x0 +#define TRIMBLETSIP_ROOTDELAY 0x0 + +#define TRIMBLETAIP_BASEDELAY 0.0 +#define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */ + +#define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver" +#define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver" + +#define TRIMBLETAIP_MAXUNSYNC 0 +#define TRIMBLETSIP_MAXUNSYNC 0 + +#define TRIMBLETAIP_EOL '<' + +/* + * RadioCode Clocks RCC 800 receiver + */ +#define RCC_POLLRATE 0 /* only true direct polling */ +#define RCC_POLLCMD "\r" +#define RCC_CMDSIZE 1 + +static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }; +#define RCC8000_FLAGS 0 +#define RCC8000_POLL poll_dpoll +#define RCC8000_INIT poll_init +#define RCC8000_END 0 +#define RCC8000_DATA ((void *)(&rcc8000_pollinfo)) +#define RCC8000_ROOTDELAY 0.0 +#define RCC8000_BASEDELAY 0.0 +#define RCC8000_ID "MSF" +#define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver" +#define RCC8000_FORMAT "Radiocode RCC8000" +#define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */ +#define RCC8000_SPEED (B2400) +#define RCC8000_CFLAG (CS8|CREAD|CLOCAL) +#define RCC8000_IFLAG (IGNBRK|IGNPAR) +#define RCC8000_OFLAG 0 +#define RCC8000_LFLAG 0 +#define RCC8000_SAMPLES 5 +#define RCC8000_KEEP 3 + +/* + * Hopf Radio clock 6021 Format + * + */ +#define HOPF6021_ROOTDELAY 0.0 +#define HOPF6021_BASEDELAY 0.0 +#define HOPF6021_DESCRIPTION "HOPF 6021" +#define HOPF6021_FORMAT "hopf Funkuhr 6021" +#define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */ +#define HOPF6021_SPEED (B9600) +#define HOPF6021_CFLAG (CS8|CREAD|CLOCAL) +#define HOPF6021_IFLAG (IGNBRK|ISTRIP) +#define HOPF6021_OFLAG 0 +#define HOPF6021_LFLAG 0 +#define HOPF6021_FLAGS 0 +#define HOPF6021_SAMPLES 5 +#define HOPF6021_KEEP 3 + +/* + * Diem's Computime Radio Clock Receiver + */ +#define COMPUTIME_FLAGS 0 +#define COMPUTIME_ROOTDELAY 0.0 +#define COMPUTIME_BASEDELAY 0.0 +#define COMPUTIME_ID DCF_ID +#define COMPUTIME_DESCRIPTION "Diem's Computime receiver" +#define COMPUTIME_FORMAT "Diem's Computime Radio Clock" +#define COMPUTIME_TYPE DCF_TYPE +#define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ +#define COMPUTIME_SPEED (B9600) +#define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL) +#define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP) +#define COMPUTIME_OFLAG 0 +#define COMPUTIME_LFLAG 0 +#define COMPUTIME_SAMPLES 5 +#define COMPUTIME_KEEP 3 + +/* + * Varitext Radio Clock Receiver + */ +#define VARITEXT_FLAGS 0 +#define VARITEXT_ROOTDELAY 0.0 +#define VARITEXT_BASEDELAY 0.0 +#define VARITEXT_ID "MSF" +#define VARITEXT_DESCRIPTION "Varitext receiver" +#define VARITEXT_FORMAT "Varitext Radio Clock" +#define VARITEXT_TYPE DCF_TYPE +#define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ +#define VARITEXT_SPEED (B9600) +#define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD) +#define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/ +#define VARITEXT_OFLAG 0 +#define VARITEXT_LFLAG 0 +#define VARITEXT_SAMPLES 32 +#define VARITEXT_KEEP 20 + +static struct parse_clockinfo +{ + u_long cl_flags; /* operation flags (io modes) */ + void (*cl_poll) P((struct parseunit *)); /* active poll routine */ + int (*cl_init) P((struct parseunit *)); /* active poll init routine */ + void (*cl_event) P((struct parseunit *, int)); /* special event handling (e.g. reset clock) */ + void (*cl_end) P((struct parseunit *)); /* active poll end routine */ + void (*cl_message) P((struct parseunit *, parsetime_t *)); /* process a lower layer message */ + void *cl_data; /* local data area for "poll" mechanism */ + double cl_rootdelay; /* rootdelay */ + double cl_basedelay; /* current offset by which the RS232 + time code is delayed from the actual time */ + const char *cl_id; /* ID code */ + const char *cl_description; /* device name */ + const char *cl_format; /* fixed format */ + u_char cl_type; /* clock type (ntp control) */ + u_long cl_maxunsync; /* time to trust oscillator after loosing synch */ + u_long cl_speed; /* terminal input & output baudrate */ + u_long cl_cflag; /* terminal control flags */ + u_long cl_iflag; /* terminal input flags */ + u_long cl_oflag; /* terminal output flags */ + u_long cl_lflag; /* terminal local flags */ + u_long cl_samples; /* samples for median filter */ + u_long cl_keep; /* samples for median filter to keep */ +} parse_clockinfo[] = +{ + { /* mode 0 */ + MBG_FLAGS, + NO_POLL, + NO_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + DCFPZF535_ROOTDELAY, + DCFPZF535_BASEDELAY, + DCF_P_ID, + DCFPZF535_DESCRIPTION, + DCFPZF535_FORMAT, + DCF_TYPE, + DCFPZF535_MAXUNSYNC, + DCFPZF535_SPEED, + DCFPZF535_CFLAG, + DCFPZF535_IFLAG, + DCFPZF535_OFLAG, + DCFPZF535_LFLAG, + DCFPZF535_SAMPLES, + DCFPZF535_KEEP + }, + { /* mode 1 */ + MBG_FLAGS, + NO_POLL, + NO_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + DCFPZF535OCXO_ROOTDELAY, + DCFPZF535OCXO_BASEDELAY, + DCF_P_ID, + DCFPZF535OCXO_DESCRIPTION, + DCFPZF535OCXO_FORMAT, + DCF_TYPE, + DCFPZF535OCXO_MAXUNSYNC, + DCFPZF535OCXO_SPEED, + DCFPZF535OCXO_CFLAG, + DCFPZF535OCXO_IFLAG, + DCFPZF535OCXO_OFLAG, + DCFPZF535OCXO_LFLAG, + DCFPZF535OCXO_SAMPLES, + DCFPZF535OCXO_KEEP + }, + { /* mode 2 */ + MBG_FLAGS, + NO_POLL, + NO_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + DCFUA31_ROOTDELAY, + DCFUA31_BASEDELAY, + DCF_A_ID, + DCFUA31_DESCRIPTION, + DCFUA31_FORMAT, + DCF_TYPE, + DCFUA31_MAXUNSYNC, + DCFUA31_SPEED, + DCFUA31_CFLAG, + DCFUA31_IFLAG, + DCFUA31_OFLAG, + DCFUA31_LFLAG, + DCFUA31_SAMPLES, + DCFUA31_KEEP + }, + { /* mode 3 */ + MBG_FLAGS, + NO_POLL, + NO_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + DCF7000_ROOTDELAY, + DCF7000_BASEDELAY, + DCF_A_ID, + DCF7000_DESCRIPTION, + DCF7000_FORMAT, + DCF_TYPE, + DCF7000_MAXUNSYNC, + DCF7000_SPEED, + DCF7000_CFLAG, + DCF7000_IFLAG, + DCF7000_OFLAG, + DCF7000_LFLAG, + DCF7000_SAMPLES, + DCF7000_KEEP + }, + { /* mode 4 */ + NO_CL_FLAGS, + WSDCF_POLL, + WSDCF_INIT, + NO_EVENT, + WSDCF_END, + NO_MESSAGE, + WSDCF_DATA, + WSDCF_ROOTDELAY, + WSDCF_BASEDELAY, + DCF_A_ID, + WSDCF_DESCRIPTION, + WSDCF_FORMAT, + DCF_TYPE, + WSDCF_MAXUNSYNC, + WSDCF_SPEED, + WSDCF_CFLAG, + WSDCF_IFLAG, + WSDCF_OFLAG, + WSDCF_LFLAG, + WSDCF_SAMPLES, + WSDCF_KEEP + }, + { /* mode 5 */ + RAWDCF_FLAGS, + NO_POLL, + RAWDCF_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + RAWDCF_ROOTDELAY, + CONRAD_BASEDELAY, + DCF_A_ID, + CONRAD_DESCRIPTION, + RAWDCF_FORMAT, + DCF_TYPE, + RAWDCF_MAXUNSYNC, + RAWDCF_SPEED, + RAWDCF_CFLAG, + RAWDCF_IFLAG, + RAWDCF_OFLAG, + RAWDCF_LFLAG, + RAWDCF_SAMPLES, + RAWDCF_KEEP + }, + { /* mode 6 */ + RAWDCF_FLAGS, + NO_POLL, + RAWDCF_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + RAWDCF_ROOTDELAY, + TIMEBRICK_BASEDELAY, + DCF_A_ID, + TIMEBRICK_DESCRIPTION, + RAWDCF_FORMAT, + DCF_TYPE, + RAWDCF_MAXUNSYNC, + RAWDCF_SPEED, + RAWDCF_CFLAG, + RAWDCF_IFLAG, + RAWDCF_OFLAG, + RAWDCF_LFLAG, + RAWDCF_SAMPLES, + RAWDCF_KEEP + }, + { /* mode 7 */ + MBG_FLAGS, + GPS16X_POLL, + GPS16X_INIT, + NO_EVENT, + GPS16X_END, + GPS16X_MESSAGE, + GPS16X_DATA, + GPS16X_ROOTDELAY, + GPS16X_BASEDELAY, + GPS16X_ID, + GPS16X_DESCRIPTION, + GPS16X_FORMAT, + GPS_TYPE, + GPS16X_MAXUNSYNC, + GPS16X_SPEED, + GPS16X_CFLAG, + GPS16X_IFLAG, + GPS16X_OFLAG, + GPS16X_LFLAG, + GPS16X_SAMPLES, + GPS16X_KEEP + }, + { /* mode 8 */ + RAWDCF_FLAGS, + NO_POLL, + NO_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + RAWDCF_ROOTDELAY, + IGELCLOCK_BASEDELAY, + DCF_A_ID, + IGELCLOCK_DESCRIPTION, + RAWDCF_FORMAT, + DCF_TYPE, + RAWDCF_MAXUNSYNC, + IGELCLOCK_SPEED, + IGELCLOCK_CFLAG, + RAWDCF_IFLAG, + RAWDCF_OFLAG, + RAWDCF_LFLAG, + RAWDCF_SAMPLES, + RAWDCF_KEEP + }, + { /* mode 9 */ + TRIMBLETAIP_FLAGS, +#if TRIM_POLLRATE /* DHD940515: Allow user config */ + NO_POLL, +#else + TRIMBLETAIP_POLL, +#endif + TRIMBLETAIP_INIT, + TRIMBLETAIP_EVENT, + TRIMBLETAIP_END, + NO_MESSAGE, + TRIMBLETAIP_DATA, + TRIMBLETAIP_ROOTDELAY, + TRIMBLETAIP_BASEDELAY, + TRIMBLETAIP_ID, + TRIMBLETAIP_DESCRIPTION, + TRIMBLETAIP_FORMAT, + GPS_TYPE, + TRIMBLETAIP_MAXUNSYNC, + TRIMBLETAIP_SPEED, + TRIMBLETAIP_CFLAG, + TRIMBLETAIP_IFLAG, + TRIMBLETAIP_OFLAG, + TRIMBLETAIP_LFLAG, + TRIMBLETAIP_SAMPLES, + TRIMBLETAIP_KEEP + }, + { /* mode 10 */ + TRIMBLETSIP_FLAGS, +#if TRIM_POLLRATE /* DHD940515: Allow user config */ + NO_POLL, +#else + TRIMBLETSIP_POLL, +#endif + TRIMBLETSIP_INIT, + TRIMBLETSIP_EVENT, + TRIMBLETSIP_END, + TRIMBLETSIP_MESSAGE, + TRIMBLETSIP_DATA, + TRIMBLETSIP_ROOTDELAY, + TRIMBLETSIP_BASEDELAY, + TRIMBLETSIP_ID, + TRIMBLETSIP_DESCRIPTION, + TRIMBLETSIP_FORMAT, + GPS_TYPE, + TRIMBLETSIP_MAXUNSYNC, + TRIMBLETSIP_SPEED, + TRIMBLETSIP_CFLAG, + TRIMBLETSIP_IFLAG, + TRIMBLETSIP_OFLAG, + TRIMBLETSIP_LFLAG, + TRIMBLETSIP_SAMPLES, + TRIMBLETSIP_KEEP + }, + { /* mode 11 */ + NO_CL_FLAGS, + RCC8000_POLL, + RCC8000_INIT, + NO_EVENT, + RCC8000_END, + NO_MESSAGE, + RCC8000_DATA, + RCC8000_ROOTDELAY, + RCC8000_BASEDELAY, + RCC8000_ID, + RCC8000_DESCRIPTION, + RCC8000_FORMAT, + DCF_TYPE, + RCC8000_MAXUNSYNC, + RCC8000_SPEED, + RCC8000_CFLAG, + RCC8000_IFLAG, + RCC8000_OFLAG, + RCC8000_LFLAG, + RCC8000_SAMPLES, + RCC8000_KEEP + }, + { /* mode 12 */ + HOPF6021_FLAGS, + NO_POLL, + NO_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + HOPF6021_ROOTDELAY, + HOPF6021_BASEDELAY, + DCF_ID, + HOPF6021_DESCRIPTION, + HOPF6021_FORMAT, + DCF_TYPE, + HOPF6021_MAXUNSYNC, + HOPF6021_SPEED, + HOPF6021_CFLAG, + HOPF6021_IFLAG, + HOPF6021_OFLAG, + HOPF6021_LFLAG, + HOPF6021_SAMPLES, + HOPF6021_KEEP + }, + { /* mode 13 */ + COMPUTIME_FLAGS, + NO_POLL, + NO_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + COMPUTIME_ROOTDELAY, + COMPUTIME_BASEDELAY, + COMPUTIME_ID, + COMPUTIME_DESCRIPTION, + COMPUTIME_FORMAT, + COMPUTIME_TYPE, + COMPUTIME_MAXUNSYNC, + COMPUTIME_SPEED, + COMPUTIME_CFLAG, + COMPUTIME_IFLAG, + COMPUTIME_OFLAG, + COMPUTIME_LFLAG, + COMPUTIME_SAMPLES, + COMPUTIME_KEEP + }, + { /* mode 14 */ + RAWDCF_FLAGS, + NO_POLL, + RAWDCFDTR_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + RAWDCF_ROOTDELAY, + RAWDCF_BASEDELAY, + DCF_A_ID, + RAWDCFDTR_DESCRIPTION, + RAWDCF_FORMAT, + DCF_TYPE, + RAWDCF_MAXUNSYNC, + RAWDCF_SPEED, + RAWDCF_CFLAG, + RAWDCF_IFLAG, + RAWDCF_OFLAG, + RAWDCF_LFLAG, + RAWDCF_SAMPLES, + RAWDCF_KEEP + }, + { /* mode 15 */ + 0, /* operation flags (io modes) */ + NO_POLL, /* active poll routine */ + NO_INIT, /* active poll init routine */ + NO_EVENT, /* special event handling (e.g. reset clock) */ + NO_END, /* active poll end routine */ + NO_MESSAGE, /* process a lower layer message */ + NO_DATA, /* local data area for "poll" mechanism */ + 0, /* rootdelay */ + 11.0 /* bits */ / 9600, /* current offset by which the RS232 + time code is delayed from the actual time */ + DCF_ID, /* ID code */ + "WHARTON 400A Series clock", /* device name */ + "WHARTON 400A Series clock Output Format 1", /* fixed format */ + /* Must match a format-name in a libparse/clk_xxx.c file */ + DCF_TYPE, /* clock type (ntp control) */ + (1*60*60)/*?*/, /* time to trust oscillator after loosing synch */ + B9600, /* terminal input & output baudrate */ + (CS8|CREAD|PARENB|CLOCAL|HUPCL), /* terminal control flags */ + 0, /* terminal input flags */ + 0, /* terminal output flags */ + 0, /* terminal local flags */ + 5/*?*/, /* samples for median filter */ + 3/*?*/, /* samples for median filter to keep */ + }, + { /* mode 16 */ + VARITEXT_FLAGS, + NO_POLL, + NO_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + VARITEXT_ROOTDELAY, + VARITEXT_BASEDELAY, + VARITEXT_ID, + VARITEXT_DESCRIPTION, + VARITEXT_FORMAT, + VARITEXT_TYPE, + VARITEXT_MAXUNSYNC, + VARITEXT_SPEED, + VARITEXT_CFLAG, + VARITEXT_IFLAG, + VARITEXT_OFLAG, + VARITEXT_LFLAG, + VARITEXT_SAMPLES, + VARITEXT_KEEP + }, + { /* mode 17 */ + RAWDCF_FLAGS, + NO_POLL, + RAWDCFRTS_INIT, + NO_EVENT, + NO_END, + NO_MESSAGE, + NO_DATA, + RAWDCF_ROOTDELAY, + RAWDCF_BASEDELAY, + DCF_A_ID, + RAWDCFRTS_DESCRIPTION, + RAWDCF_FORMAT, + DCF_TYPE, + RAWDCF_MAXUNSYNC, + RAWDCF_SPEED, + RAWDCF_CFLAG, + RAWDCF_IFLAG, + RAWDCF_OFLAG, + RAWDCF_LFLAG, + RAWDCF_SAMPLES, + RAWDCF_KEEP + }, +}; + +static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); + +#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) +#define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x)) +#define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr)) +#define CLK_PPS(x) (((x)->ttl) & 0x80) + +/* + * Other constant stuff + */ +#define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */ + +#define PARSESTATISTICS (60*60) /* output state statistics every hour */ + +static struct parseunit *parseunits[MAXUNITS]; + +static int notice = 0; + +#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i]) + +static void parse_event P((struct parseunit *, int)); +static void parse_process P((struct parseunit *, parsetime_t *)); +static void clear_err P((struct parseunit *, u_long)); +static int list_err P((struct parseunit *, u_long)); +static char * l_mktime P((u_long)); + +/**=========================================================================== + ** implementation error message regression module + **/ +static void +clear_err( + struct parseunit *parse, + u_long lstate + ) +{ + if (lstate == ERR_ALL) + { + int i; + + for (i = 0; i < ERR_CNT; i++) + { + parse->errors[i].err_stage = err_tbl[i]; + parse->errors[i].err_cnt = 0; + parse->errors[i].err_last = 0; + parse->errors[i].err_started = 0; + parse->errors[i].err_suppressed = 0; + } + } + else + { + parse->errors[lstate].err_stage = err_tbl[lstate]; + parse->errors[lstate].err_cnt = 0; + parse->errors[lstate].err_last = 0; + parse->errors[lstate].err_started = 0; + parse->errors[lstate].err_suppressed = 0; + } +} + +static int +list_err( + struct parseunit *parse, + u_long lstate + ) +{ + int do_it; + struct errorinfo *err = &parse->errors[lstate]; + + if (err->err_started == 0) + { + err->err_started = current_time; + } + + do_it = (current_time - err->err_last) >= err->err_stage->err_delay; + + if (do_it) + err->err_cnt++; + + if (err->err_stage->err_count && + (err->err_cnt >= err->err_stage->err_count)) + { + err->err_stage++; + err->err_cnt = 0; + } + + if (!err->err_cnt && do_it) + msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s", + CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay)); + + if (!do_it) + err->err_suppressed++; + else + err->err_last = current_time; + + if (do_it && err->err_suppressed) + { + msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s", + CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where", + l_mktime(current_time - err->err_started)); + err->err_suppressed = 0; + } + + return do_it; +} + +/*-------------------------------------------------- + * mkreadable - make a printable ascii string (without + * embedded quotes so that the ntpq protocol isn't + * fooled + */ +#ifndef isprint +#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F)) +#endif + +static char * +mkreadable( + char *buffer, + long blen, + const char *src, + u_long srclen, + int hex + ) +{ + char *b = buffer; + char *endb = (char *)0; + + if (blen < 4) + return (char *)0; /* don't bother with mini buffers */ + + endb = buffer + blen - 4; + + blen--; /* account for '\0' */ + + while (blen && srclen--) + { + if (!hex && /* no binary only */ + (*src != '\\') && /* no plain \ */ + (*src != '"') && /* no " */ + isprint((int)*src)) /* only printables */ + { /* they are easy... */ + *buffer++ = *src++; + blen--; + } + else + { + if (blen < 4) + { + while (blen--) + { + *buffer++ = '.'; + } + *buffer = '\0'; + return b; + } + else + { + if (*src == '\\') + { + strcpy(buffer,"\\\\"); + buffer += 2; + blen -= 2; + src++; + } + else + { + sprintf(buffer, "\\x%02x", *src++); + blen -= 4; + buffer += 4; + } + } + } + if (srclen && !blen && endb) /* overflow - set last chars to ... */ + strcpy(endb, "..."); + } + + *buffer = '\0'; + return b; +} + + +/*-------------------------------------------------- + * mkascii - make a printable ascii string + * assumes (unless defined better) 7-bit ASCII + */ +static char * +mkascii( + char *buffer, + long blen, + const char *src, + u_long srclen + ) +{ + return mkreadable(buffer, blen, src, srclen, 0); +} + +/**=========================================================================== + ** implementation of i/o handling methods + ** (all STREAM, partial STREAM, user level) + **/ + +/* + * define possible io handling methods + */ +#ifdef STREAM +static int ppsclock_init P((struct parseunit *)); +static int stream_init P((struct parseunit *)); +static void stream_end P((struct parseunit *)); +static int stream_enable P((struct parseunit *)); +static int stream_disable P((struct parseunit *)); +static int stream_setcs P((struct parseunit *, parsectl_t *)); +static int stream_getfmt P((struct parseunit *, parsectl_t *)); +static int stream_setfmt P((struct parseunit *, parsectl_t *)); +static int stream_timecode P((struct parseunit *, parsectl_t *)); +static void stream_receive P((struct recvbuf *)); +#endif + +static int local_init P((struct parseunit *)); +static void local_end P((struct parseunit *)); +static int local_nop P((struct parseunit *)); +static int local_setcs P((struct parseunit *, parsectl_t *)); +static int local_getfmt P((struct parseunit *, parsectl_t *)); +static int local_setfmt P((struct parseunit *, parsectl_t *)); +static int local_timecode P((struct parseunit *, parsectl_t *)); +static void local_receive P((struct recvbuf *)); +static int local_input P((struct recvbuf *)); + +static bind_t io_bindings[] = +{ +#ifdef STREAM + { + "parse STREAM", + stream_init, + stream_end, + stream_setcs, + stream_disable, + stream_enable, + stream_getfmt, + stream_setfmt, + stream_timecode, + stream_receive, + 0, + }, + { + "ppsclock STREAM", + ppsclock_init, + local_end, + local_setcs, + local_nop, + local_nop, + local_getfmt, + local_setfmt, + local_timecode, + local_receive, + local_input, + }, +#endif + { + "normal", + local_init, + local_end, + local_setcs, + local_nop, + local_nop, + local_getfmt, + local_setfmt, + local_timecode, + local_receive, + local_input, + }, + { + (char *)0, + } +}; + +#ifdef STREAM + +#define fix_ts(_X_) \ + if ((&(_X_))->tv.tv_usec >= 1000000) \ + { \ + (&(_X_))->tv.tv_usec -= 1000000; \ + (&(_X_))->tv.tv_sec += 1; \ + } + +#define cvt_ts(_X_, _Y_) \ + { \ + l_fp ts; \ + fix_ts((_X_)); \ + if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \ + { \ + ERR(ERR_BADDATA) \ + msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\ + return; \ + } \ + else \ + { \ + (&(_X_))->fp = ts; \ + } \ + } + +/*-------------------------------------------------- + * ppsclock STREAM init + */ +static int +ppsclock_init( + struct parseunit *parse + ) +{ + static char m1[] = "ppsclocd"; + static char m2[] = "ppsclock"; + + /* + * now push the parse streams module + * it will ensure exclusive access to the device + */ + if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1 && + ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m2) == -1) + { + if (errno != EINVAL) + { + msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", + CLK_UNIT(parse->peer)); + } + return 0; + } + if (!local_init(parse)) + { + (void)ioctl(parse->generic->io.fd, I_POP, (caddr_t)0); + return 0; + } + + parse->flags |= PARSE_PPSCLOCK; + return 1; +} + +/*-------------------------------------------------- + * parse STREAM init + */ +static int +stream_init( + struct parseunit *parse + ) +{ + static char m1[] = "parse"; + /* + * now push the parse streams module + * to test whether it is there (neat interface 8-( ) + */ + if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) + { + if (errno != EINVAL) /* accept non-existence */ + { + msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); + } + return 0; + } + else + { + while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) + /* empty loop */; + + /* + * now push it a second time after we have removed all + * module garbage + */ + if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); + return 0; + } + else + { + return 1; + } + } +} + +/*-------------------------------------------------- + * parse STREAM end + */ +static void +stream_end( + struct parseunit *parse + ) +{ + while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) + /* empty loop */; +} + +/*-------------------------------------------------- + * STREAM setcs + */ +static int +stream_setcs( + struct parseunit *parse, + parsectl_t *tcl + ) +{ + struct strioctl strioc; + + strioc.ic_cmd = PARSEIOC_SETCS; + strioc.ic_timout = 0; + strioc.ic_dp = (char *)tcl; + strioc.ic_len = sizeof (*tcl); + + if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer)); + return 0; + } + return 1; +} + +/*-------------------------------------------------- + * STREAM enable + */ +static int +stream_enable( + struct parseunit *parse + ) +{ + struct strioctl strioc; + + strioc.ic_cmd = PARSEIOC_ENABLE; + strioc.ic_timout = 0; + strioc.ic_dp = (char *)0; + strioc.ic_len = 0; + + if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer)); + return 0; + } + parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */ + return 1; +} + +/*-------------------------------------------------- + * STREAM disable + */ +static int +stream_disable( + struct parseunit *parse + ) +{ + struct strioctl strioc; + + strioc.ic_cmd = PARSEIOC_DISABLE; + strioc.ic_timout = 0; + strioc.ic_dp = (char *)0; + strioc.ic_len = 0; + + if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer)); + return 0; + } + parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */ + return 1; +} + +/*-------------------------------------------------- + * STREAM getfmt + */ +static int +stream_getfmt( + struct parseunit *parse, + parsectl_t *tcl + ) +{ + struct strioctl strioc; + + strioc.ic_cmd = PARSEIOC_GETFMT; + strioc.ic_timout = 0; + strioc.ic_dp = (char *)tcl; + strioc.ic_len = sizeof (*tcl); + if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer)); + return 0; + } + return 1; +} + +/*-------------------------------------------------- + * STREAM setfmt + */ +static int +stream_setfmt( + struct parseunit *parse, + parsectl_t *tcl + ) +{ + struct strioctl strioc; + + strioc.ic_cmd = PARSEIOC_SETFMT; + strioc.ic_timout = 0; + strioc.ic_dp = (char *)tcl; + strioc.ic_len = sizeof (*tcl); + + if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer)); + return 0; + } + return 1; +} + + +/*-------------------------------------------------- + * STREAM timecode + */ +static int +stream_timecode( + struct parseunit *parse, + parsectl_t *tcl + ) +{ + struct strioctl strioc; + + strioc.ic_cmd = PARSEIOC_TIMECODE; + strioc.ic_timout = 0; + strioc.ic_dp = (char *)tcl; + strioc.ic_len = sizeof (*tcl); + + if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) + { + ERR(ERR_INTERNAL) + msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer)); + return 0; + } + clear_err(parse, ERR_INTERNAL); + return 1; +} + +/*-------------------------------------------------- + * STREAM receive + */ +static void +stream_receive( + struct recvbuf *rbufp + ) +{ + struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); + parsetime_t parsetime; + + if (!parse->peer) + return; + + if (rbufp->recv_length != sizeof(parsetime_t)) + { + ERR(ERR_BADIO) + msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)", + CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); + parse->generic->baddata++; + parse_event(parse, CEVNT_BADREPLY); + return; + } + clear_err(parse, ERR_BADIO); + + memmove((caddr_t)&parsetime, + (caddr_t)rbufp->recv_buffer, + sizeof(parsetime_t)); + +#ifdef DEBUG + if (debug > 3) + { + printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", + CLK_UNIT(parse->peer), + (unsigned int)parsetime.parse_status, + (unsigned int)parsetime.parse_state, + (long)parsetime.parse_time.tv.tv_sec, + (long)parsetime.parse_time.tv.tv_usec, + (long)parsetime.parse_stime.tv.tv_sec, + (long)parsetime.parse_stime.tv.tv_usec, + (long)parsetime.parse_ptime.tv.tv_sec, + (long)parsetime.parse_ptime.tv.tv_usec); + } +#endif + + /* + * switch time stamp world - be sure to normalize small usec field + * errors. + */ + + cvt_ts(parsetime.parse_stime, "parse_stime"); + + if (PARSE_TIMECODE(parsetime.parse_state)) + { + cvt_ts(parsetime.parse_time, "parse_time"); + } + + if (PARSE_PPS(parsetime.parse_state)) + cvt_ts(parsetime.parse_ptime, "parse_ptime"); + + parse_process(parse, &parsetime); +} +#endif + +/*-------------------------------------------------- + * local init + */ +static int +local_init( + struct parseunit *parse + ) +{ + return parse_ioinit(&parse->parseio); +} + +/*-------------------------------------------------- + * local end + */ +static void +local_end( + struct parseunit *parse + ) +{ + parse_ioend(&parse->parseio); +} + + +/*-------------------------------------------------- + * local nop + */ +static int +local_nop( + struct parseunit *parse + ) +{ + return 1; +} + +/*-------------------------------------------------- + * local setcs + */ +static int +local_setcs( + struct parseunit *parse, + parsectl_t *tcl + ) +{ + return parse_setcs(tcl, &parse->parseio); +} + +/*-------------------------------------------------- + * local getfmt + */ +static int +local_getfmt( + struct parseunit *parse, + parsectl_t *tcl + ) +{ + return parse_getfmt(tcl, &parse->parseio); +} + +/*-------------------------------------------------- + * local setfmt + */ +static int +local_setfmt( + struct parseunit *parse, + parsectl_t *tcl + ) +{ + return parse_setfmt(tcl, &parse->parseio); +} + +/*-------------------------------------------------- + * local timecode + */ +static int +local_timecode( + struct parseunit *parse, + parsectl_t *tcl + ) +{ + return parse_timecode(tcl, &parse->parseio); +} + + +/*-------------------------------------------------- + * local input + */ +static int +local_input( + struct recvbuf *rbufp + ) +{ + struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); + int count; + unsigned char *s; + timestamp_t ts; + + if (!parse->peer) + return 0; + + /* + * eat all characters, parsing then and feeding complete samples + */ + count = rbufp->recv_length; + s = (unsigned char *)rbufp->recv_buffer; + ts.fp = rbufp->recv_time; + + while (count--) + { + if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts)) + { + struct recvbuf buf; + + /* + * got something good to eat + */ + if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state)) + { +#ifdef TIOCDCDTIMESTAMP + struct timeval dcd_time; + + if (ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1) + { + l_fp tstmp; + + TVTOTS(&dcd_time, &tstmp); + tstmp.l_ui += JAN_1970; + L_SUB(&ts.fp, &tstmp); + if (ts.fp.l_ui == 0) + { +#ifdef DEBUG + if (debug) + { + printf( + "parse: local_receive: fd %d DCDTIMESTAMP %s\n", + rbufp->fd, + lfptoa(&tstmp, 6)); + printf(" sigio %s\n", + lfptoa(&ts.fp, 6)); + } +#endif + parse->parseio.parse_dtime.parse_ptime.fp = tstmp; + parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; + } + } +#else /* TIOCDCDTIMESTAMP */ +#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) + if (parse->flags & PARSE_PPSCLOCK) + { + l_fp tts; + struct ppsclockev ev; + +#ifdef HAVE_CIOGETEV + if (ioctl(parse->generic->io.fd, CIOGETEV, (caddr_t)&ev) == 0) +#endif +#ifdef HAVE_TIOCGPPSEV + if (ioctl(parse->generic->io.fd, TIOCGPPSEV, (caddr_t)&ev) == 0) +#endif + { + if (ev.serial != parse->ppsserial) + { + /* + * add PPS time stamp if available via ppsclock module + * and not supplied already. + */ + if (!buftvtots((const char *)&ev.tv, &tts)) + { + ERR(ERR_BADDATA) + msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); + } + else + { + parse->parseio.parse_dtime.parse_ptime.fp = tts; + parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; + } + } + parse->ppsserial = ev.serial; + } + } +#endif +#endif /* TIOCDCDTIMESTAMP */ + } + if (count) + { /* simulate receive */ + memmove((caddr_t)buf.recv_buffer, + (caddr_t)&parse->parseio.parse_dtime, + sizeof(parsetime_t)); + parse_iodone(&parse->parseio); + buf.recv_length = sizeof(parsetime_t); + buf.recv_time = rbufp->recv_time; + buf.srcadr = rbufp->srcadr; + buf.dstadr = rbufp->dstadr; + buf.fd = rbufp->fd; + buf.next = 0; + buf.X_from_where = rbufp->X_from_where; + rbufp->receiver(&buf); + } + else + { + memmove((caddr_t)rbufp->recv_buffer, + (caddr_t)&parse->parseio.parse_dtime, + sizeof(parsetime_t)); + parse_iodone(&parse->parseio); + rbufp->recv_length = sizeof(parsetime_t); + return 1; /* got something & in place return */ + } + } + } + return 0; /* nothing to pass up */ +} + +/*-------------------------------------------------- + * local receive + */ +static void +local_receive( + struct recvbuf *rbufp + ) +{ + struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); + parsetime_t parsetime; + + if (!parse->peer) + return; + + if (rbufp->recv_length != sizeof(parsetime_t)) + { + ERR(ERR_BADIO) + msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)", + CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); + parse->generic->baddata++; + parse_event(parse, CEVNT_BADREPLY); + return; + } + clear_err(parse, ERR_BADIO); + + memmove((caddr_t)&parsetime, + (caddr_t)rbufp->recv_buffer, + sizeof(parsetime_t)); + +#ifdef DEBUG + if (debug > 3) + { + printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", + CLK_UNIT(parse->peer), + (unsigned int)parsetime.parse_status, + (unsigned int)parsetime.parse_state, + (long)parsetime.parse_time.tv.tv_sec, + (long)parsetime.parse_time.tv.tv_usec, + (long)parsetime.parse_stime.tv.tv_sec, + (long)parsetime.parse_stime.tv.tv_usec, + (long)parsetime.parse_ptime.tv.tv_sec, + (long)parsetime.parse_ptime.tv.tv_usec); + } +#endif + + parse_process(parse, &parsetime); +} + +/*-------------------------------------------------- + * init_iobinding - find and initialize lower layers + */ +static bind_t * +init_iobinding( + struct parseunit *parse + ) +{ + bind_t *b = io_bindings; + + while (b->bd_description != (char *)0) + { + if ((*b->bd_init)(parse)) + { + return b; + } + b++; + } + return (bind_t *)0; +} + +/**=========================================================================== + ** support routines + **/ + +/*-------------------------------------------------- + * convert a flag field to a string + */ +static char * +parsestate( + u_long lstate, + char *buffer + ) +{ + static struct bits + { + u_long bit; + const char *name; + } flagstrings[] = + { + { PARSEB_ANNOUNCE, "DST SWITCH WARNING" }, + { PARSEB_POWERUP, "NOT SYNCHRONIZED" }, + { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" }, + { PARSEB_DST, "DST" }, + { PARSEB_UTC, "UTC DISPLAY" }, + { PARSEB_LEAPADD, "LEAP ADD WARNING" }, + { PARSEB_LEAPDEL, "LEAP DELETE WARNING" }, + { PARSEB_LEAPSECOND, "LEAP SECOND" }, + { PARSEB_ALTERNATE,"ALTERNATE ANTENNA" }, + { PARSEB_TIMECODE, "TIME CODE" }, + { PARSEB_PPS, "PPS" }, + { PARSEB_POSITION, "POSITION" }, + { 0 } + }; + + static struct sbits + { + u_long bit; + const char *name; + } sflagstrings[] = + { + { PARSEB_S_LEAP, "LEAP INDICATION" }, + { PARSEB_S_PPS, "PPS SIGNAL" }, + { PARSEB_S_ANTENNA, "ANTENNA" }, + { PARSEB_S_POSITION, "POSITION" }, + { 0 } + }; + int i; + + *buffer = '\0'; + + i = 0; + while (flagstrings[i].bit) + { + if (flagstrings[i].bit & lstate) + { + if (buffer[0]) + strcat(buffer, "; "); + strcat(buffer, flagstrings[i].name); + } + i++; + } + + if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION)) + { + char *s, *t; + + if (buffer[0]) + strcat(buffer, "; "); + + strcat(buffer, "("); + + t = s = buffer + strlen(buffer); + + i = 0; + while (sflagstrings[i].bit) + { + if (sflagstrings[i].bit & lstate) + { + if (t != s) + { + strcpy(t, "; "); + t += 2; + } + + strcpy(t, sflagstrings[i].name); + t += strlen(t); + } + i++; + } + strcpy(t, ")"); + } + return buffer; +} + +/*-------------------------------------------------- + * convert a status flag field to a string + */ +static char * +parsestatus( + u_long lstate, + char *buffer + ) +{ + static struct bits + { + u_long bit; + const char *name; + } flagstrings[] = + { + { CVT_OK, "CONVERSION SUCCESSFUL" }, + { CVT_NONE, "NO CONVERSION" }, + { CVT_FAIL, "CONVERSION FAILED" }, + { CVT_BADFMT, "ILLEGAL FORMAT" }, + { CVT_BADDATE, "DATE ILLEGAL" }, + { CVT_BADTIME, "TIME ILLEGAL" }, + { CVT_ADDITIONAL, "ADDITIONAL DATA" }, + { 0 } + }; + int i; + + *buffer = '\0'; + + i = 0; + while (flagstrings[i].bit) + { + if (flagstrings[i].bit & lstate) + { + if (buffer[0]) + strcat(buffer, "; "); + strcat(buffer, flagstrings[i].name); + } + i++; + } + + return buffer; +} + +/*-------------------------------------------------- + * convert a clock status flag field to a string + */ +static const char * +clockstatus( + u_long lstate + ) +{ + static char buffer[20]; + static struct status + { + u_long value; + const char *name; + } flagstrings[] = + { + { CEVNT_NOMINAL, "NOMINAL" }, + { CEVNT_TIMEOUT, "NO RESPONSE" }, + { CEVNT_BADREPLY,"BAD FORMAT" }, + { CEVNT_FAULT, "FAULT" }, + { CEVNT_PROP, "PROPAGATION DELAY" }, + { CEVNT_BADDATE, "ILLEGAL DATE" }, + { CEVNT_BADTIME, "ILLEGAL TIME" }, + { (unsigned)~0L } + }; + int i; + + i = 0; + while (flagstrings[i].value != ~0) + { + if (flagstrings[i].value == lstate) + { + return flagstrings[i].name; + } + i++; + } + + sprintf(buffer, "unknown #%ld", (u_long)lstate); + + return buffer; +} + + +/*-------------------------------------------------- + * l_mktime - make representation of a relative time + */ +static char * +l_mktime( + u_long delta + ) +{ + u_long tmp, m, s; + static char buffer[40]; + + buffer[0] = '\0'; + + if ((tmp = delta / (60*60*24)) != 0) + { + sprintf(buffer, "%ldd+", (u_long)tmp); + delta -= tmp * 60*60*24; + } + + s = delta % 60; + delta /= 60; + m = delta % 60; + delta /= 60; + + sprintf(buffer+strlen(buffer), "%02d:%02d:%02d", + (int)delta, (int)m, (int)s); + + return buffer; +} + + +/*-------------------------------------------------- + * parse_statistics - list summary of clock states + */ +static void +parse_statistics( + struct parseunit *parse + ) +{ + int i; + + NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */ + { + msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s", + CLK_UNIT(parse->peer), + l_mktime(current_time - parse->generic->timestarted)); + + msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s", + CLK_UNIT(parse->peer), + clockstatus(parse->generic->currentstatus)); + + for (i = 0; i <= CEVNT_MAX; i++) + { + u_long s_time; + u_long percent, d = current_time - parse->generic->timestarted; + + percent = s_time = PARSE_STATETIME(parse, i); + + while (((u_long)(~0) / 10000) < percent) + { + percent /= 10; + d /= 10; + } + + if (d) + percent = (percent * 10000) / d; + else + percent = 10000; + + if (s_time) + msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)", + CLK_UNIT(parse->peer), + clockstatus((unsigned int)i), + l_mktime(s_time), + percent / 100, percent % 100); + } + } +} + +/*-------------------------------------------------- + * cparse_statistics - wrapper for statistics call + */ +static void +cparse_statistics( + register struct parseunit *parse + ) +{ + if (parse->laststatistic + PARSESTATISTICS < current_time) + parse_statistics(parse); + parse->laststatistic = current_time; +} + +/**=========================================================================== + ** ntp interface routines + **/ + +/*-------------------------------------------------- + * parse_init - initialize internal parse driver data + */ +static void +parse_init(void) +{ + memset((caddr_t)parseunits, 0, sizeof parseunits); +} + + +/*-------------------------------------------------- + * parse_shutdown - shut down a PARSE clock + */ +static void +parse_shutdown( + int unit, + struct peer *peer + ) +{ + struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; + + if (parse && !parse->peer) + { + msyslog(LOG_ERR, + "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit not in use", unit); + return; + } + + /* + * print statistics a last time and + * stop statistics machine + */ + parse_statistics(parse); + + if (parse->parse_type->cl_end) + { + parse->parse_type->cl_end(parse); + } + + if (parse->binding) + PARSE_END(parse); + + /* + * Tell the I/O module to turn us off. We're history. + */ + io_closeclock(&parse->generic->io); + + free_varlist(parse->kv); + + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", + CLK_UNIT(parse->peer), parse->parse_type->cl_description); + + parse->peer = (struct peer *)0; /* unused now */ + free(parse); +} + +/*-------------------------------------------------- + * parse_start - open the PARSE devices and initialize data for processing + */ +static int +parse_start( + int sysunit, + struct peer *peer + ) +{ + u_int unit; + int fd232; +#ifdef HAVE_TERMIOS + struct termios tio; /* NEEDED FOR A LONG TIME ! */ +#endif +#ifdef HAVE_SYSV_TTYS + struct termio tio; /* NEEDED FOR A LONG TIME ! */ +#endif + struct parseunit * parse; + char parsedev[sizeof(PARSEDEVICE)+20]; + parsectl_t tmp_ctl; + u_int type; + + type = CLK_TYPE(peer); + unit = CLK_UNIT(peer); + + if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0)) + { + msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", + unit, CLK_REALTYPE(peer), ncltypes-1); + return 0; + } + + /* + * Unit okay, attempt to open the device. + */ + (void) sprintf(parsedev, PARSEDEVICE, unit); + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + + fd232 = open(parsedev, O_RDWR | O_NOCTTY +#ifdef O_NONBLOCK + | O_NONBLOCK +#endif + , 0777); + + if (fd232 == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); + return 0; + } + + parse = (struct parseunit *)emalloc(sizeof(struct parseunit)); + + memset((char *)parse, 0, sizeof(struct parseunit)); + + parse->generic = peer->procptr; /* link up */ + parse->generic->unitptr = (caddr_t)parse; /* link down */ + + /* + * Set up the structures + */ + parse->generic->timestarted = current_time; + parse->lastchange = current_time; + + parse->generic->currentstatus = CEVNT_TIMEOUT; /* expect the worst */ + + parse->flags = 0; + parse->pollneeddata = 0; + parse->laststatistic = current_time; + parse->lastformat = (unsigned short)~0; /* assume no format known */ + parse->time.parse_status = (unsigned short)~0; /* be sure to mark initial status change */ + parse->lastmissed = 0; /* assume got everything */ + parse->ppsserial = 0; + parse->localdata = (void *)0; + parse->localstate = 0; + parse->kv = (struct ctl_var *)0; + + clear_err(parse, ERR_ALL); + + parse->parse_type = &parse_clockinfo[type]; + + parse->generic->fudgetime1 = parse->parse_type->cl_basedelay; + + parse->generic->fudgetime2 = 0.0; + + parse->generic->clockdesc = parse->parse_type->cl_description; + + peer->rootdelay = parse->parse_type->cl_rootdelay; + peer->sstclktype = parse->parse_type->cl_type; + peer->precision = sys_precision; + + peer->burst = NTP_SHIFT; + peer->flags |= FLAG_BURST; + + peer->stratum = STRATUM_REFCLOCK; + if (peer->stratum <= 1) + memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); + else + parse->generic->refid = htonl(PARSEHSREFID); + + parse->generic->io.fd = fd232; + + parse->peer = peer; /* marks it also as busy */ + + /* + * configure terminal line + */ + if (TTY_GETATTR(fd232, &tio) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); + parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ + return 0; + } + else + { +#ifndef _PC_VDISABLE + memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); +#else + int disablec; + errno = 0; /* pathconf can deliver -1 without changing errno ! */ + + disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); + if (disablec == -1 && errno) + { + msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); + memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ + } + else + if (disablec != -1) + memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); +#endif + +#if defined (VMIN) || defined(VTIME) + if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) + { +#ifdef VMIN + tio.c_cc[VMIN] = 1; +#endif +#ifdef VTIME + tio.c_cc[VTIME] = 0; +#endif + } +#endif + + tio.c_cflag = parse_clockinfo[type].cl_cflag; + tio.c_iflag = parse_clockinfo[type].cl_iflag; + tio.c_oflag = parse_clockinfo[type].cl_oflag; + tio.c_lflag = parse_clockinfo[type].cl_lflag; + + +#ifdef HAVE_TERMIOS + if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) || + (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1)) + { + msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); + parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ + return 0; + } +#else + tio.c_cflag |= parse_clockinfo[type].cl_speed; +#endif + +#if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ + { + struct serial_struct ss; + if (ioctl(fd232, TIOCGSERIAL, &ss) < 0 || + ( +#ifdef ASYNC_LOW_LATENCY + ss.flags |= ASYNC_LOW_LATENCY, +#endif +#ifdef ASYNC_PPS_CD_NEG + ss.flags |= ASYNC_PPS_CD_NEG, +#endif + ioctl(fd232, TIOCSSERIAL, &ss)) < 0) { + msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", fd232); + msyslog(LOG_NOTICE, + "refclock_parse: optional PPS processing not available"); + } else { + parse->flags |= PARSE_PPSCLOCK; + msyslog(LOG_INFO, + "refclock_parse: PPS detection on"); + } + } +#endif +#ifdef HAVE_TIOCSPPS /* SUN PPS support */ + if (CLK_PPS(parse->peer)) + { + int i = 1; + + if (ioctl(fd232, TIOCSPPS, (caddr_t)&i) == 0) + { + parse->flags |= PARSE_PPSCLOCK; + } + } +#endif + + if (TTY_SETATTR(fd232, &tio) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); + parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ + return 0; + } + } + + /* + * Insert in async io device list. + */ + parse->generic->io.srcclock = (caddr_t)parse; + parse->generic->io.datalen = 0; + + if (!io_addclock(&parse->generic->io)) + { + msyslog(LOG_ERR, + "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); + parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ + return 0; + } + + parse->binding = init_iobinding(parse); + parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ + parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ + + if (parse->binding == (bind_t *)0) + { + msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); + parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ + return 0; /* well, ok - special initialisation broke */ + } + + /* + * as we always(?) get 8 bit chars we want to be + * sure, that the upper bits are zero for less + * than 8 bit I/O - so we pass that information on. + * note that there can be only one bit count format + * per file descriptor + */ + + switch (tio.c_cflag & CSIZE) + { + case CS5: + tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; + break; + + case CS6: + tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; + break; + + case CS7: + tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; + break; + + case CS8: + tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; + break; + } + + if (!PARSE_SETCS(parse, &tmp_ctl)) + { + msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); + parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ + return 0; /* well, ok - special initialisation broke */ + } + + strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format); + tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer); + + if (!PARSE_SETFMT(parse, &tmp_ctl)) + { + msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); + parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ + return 0; /* well, ok - special initialisation broke */ + } + + /* + * get rid of all IO accumulated so far + */ +#ifdef HAVE_TERMIOS + (void) tcflush(parse->generic->io.fd, TCIOFLUSH); +#else +#ifdef TCFLSH + { +#ifndef TCIOFLUSH +#define TCIOFLUSH 2 +#endif + int flshcmd = TCIOFLUSH; + + (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); + } +#endif +#endif + + /* + * try to do any special initializations + */ + if (parse->parse_type->cl_init) + { + if (parse->parse_type->cl_init(parse)) + { + parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ + return 0; /* well, ok - special initialisation broke */ + } + } + + /* + * get out Copyright information once + */ + if (!notice) + { + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1999, Frank Kardel"); + notice = 1; + } + + /* + * print out configuration + */ + NLOG(NLOG_CLOCKINFO) + { + /* conditional if clause for conditional syslog */ + msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added", + CLK_UNIT(parse->peer), + parse->parse_type->cl_description, parsedev); + + msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, %sPPS support, trust time %s, precision %d", + CLK_UNIT(parse->peer), + parse->peer->stratum, CLK_PPS(parse->peer) ? "" : "no ", + l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision); + + msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phaseadjust %.6f s, %s IO handling", + CLK_UNIT(parse->peer), + parse->parse_type->cl_rootdelay, + parse->generic->fudgetime1, + parse->binding->bd_description); + + msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), + parse->parse_type->cl_format); +#ifdef PPS + msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS ioctl support", CLK_UNIT(parse->peer), + (parse->flags & PARSE_PPSCLOCK) ? "" : "NO "); +#endif + } + + return 1; +} + +/*-------------------------------------------------- + * parse_poll - called by the transmit procedure + */ +static void +parse_poll( + int unit, + struct peer *peer + ) +{ + struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; + + if (peer != parse->peer) + { + msyslog(LOG_ERR, + "PARSE receiver #%d: poll: INTERNAL: peer incorrect", + unit); + return; + } + + /* + * Update clock stat counters + */ + parse->generic->polls++; + + if (parse->pollneeddata) + { + /* + * bad news - didn't get a response last time + */ + parse->generic->noreply++; + parse->lastmissed = current_time; + parse_event(parse, CEVNT_TIMEOUT); + + ERR(ERR_NODATA) + msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / cableling)", CLK_UNIT(parse->peer)); + } + + /* + * we just mark that we want the next sample for the clock filter + */ + parse->pollneeddata = 1; + + if (parse->parse_type->cl_poll) + { + parse->parse_type->cl_poll(parse); + } + + cparse_statistics(parse); + + return; +} + +#define LEN_STATES 300 /* length of state string */ + +/*-------------------------------------------------- + * parse_control - set fudge factors, return statistics + */ +static void +parse_control( + int unit, + struct refclockstat *in, + struct refclockstat *out, + struct peer *peer + ) +{ + register struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; + parsectl_t tmpctl; + + static char outstatus[400]; /* status output buffer */ + + if (out) + { + out->lencode = 0; + out->p_lastcode = 0; + out->kv_list = (struct ctl_var *)0; + } + + if (!parse || !parse->peer) + { + msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", + unit); + return; + } + + unit = CLK_UNIT(parse->peer); + + if (in) + { + if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) + { + parse->flags = in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4); + } + } + + if (out) + { + u_long sum = 0; + char *t, *tt, *start; + int i; + + outstatus[0] = '\0'; + + out->type = REFCLK_PARSE; + out->haveflags |= CLK_HAVETIME2; + + /* + * figure out skew between PPS and RS232 - just for informational + * purposes - returned in time2 value + */ + if (PARSE_SYNC(parse->time.parse_state)) + { + if (PARSE_PPS(parse->time.parse_state) && PARSE_TIMECODE(parse->time.parse_state)) + { + l_fp off; + + /* + * we have a PPS and RS232 signal - calculate the skew + * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) + */ + off = parse->time.parse_stime.fp; + L_SUB(&off, &parse->time.parse_ptime.fp); /* true offset */ + tt = add_var(&out->kv_list, 80, RO); + sprintf(tt, "refclock_ppsskew=%s", lfptoms(&off, 6)); + } + } + + if (PARSE_PPS(parse->time.parse_state)) + { + tt = add_var(&out->kv_list, 80, RO|DEF); + sprintf(tt, "refclock_ppstime=\"%s\"", gmprettydate(&parse->time.parse_ptime.fp)); + } + + tt = add_var(&out->kv_list, 128, RO|DEF); + sprintf(tt, "refclock_time=\""); + tt += strlen(tt); + + if (parse->time.parse_time.fp.l_ui == 0) + { + strcpy(tt, "\""); + } + else + { + sprintf(tt, "%s\"", gmprettydate(&parse->time.parse_time.fp)); + t = tt + strlen(tt); + } + + if (!PARSE_GETTIMECODE(parse, &tmpctl)) + { + ERR(ERR_INTERNAL) + msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); + } + else + { + tt = add_var(&out->kv_list, 512, RO|DEF); + sprintf(tt, "refclock_status=\""); + tt += strlen(tt); + + /* + * copy PPS flags from last read transaction (informational only) + */ + tmpctl.parsegettc.parse_state |= parse->time.parse_state & + (PARSEB_PPS|PARSEB_S_PPS); + + (void) parsestate(tmpctl.parsegettc.parse_state, tt); + + strcat(tt, "\""); + + if (tmpctl.parsegettc.parse_count) + mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1), + tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)); + + parse->generic->badformat += tmpctl.parsegettc.parse_badformat; + } + + tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; + + if (!PARSE_GETFMT(parse, &tmpctl)) + { + ERR(ERR_INTERNAL) + msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); + } + else + { + tt = add_var(&out->kv_list, 80, RO|DEF); + sprintf(tt, "refclock_format=\""); + + strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count); + strcat(tt,"\""); + } + + /* + * gather state statistics + */ + + start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); + strcpy(tt, "refclock_states=\""); + tt += strlen(tt); + + for (i = 0; i <= CEVNT_MAX; i++) + { + u_long s_time; + u_long d = current_time - parse->generic->timestarted; + u_long percent; + + percent = s_time = PARSE_STATETIME(parse, i); + + while (((u_long)(~0) / 10000) < percent) + { + percent /= 10; + d /= 10; + } + + if (d) + percent = (percent * 10000) / d; + else + percent = 10000; + + if (s_time) + { + char item[80]; + int count; + + sprintf(item, "%s%s%s: %s (%d.%02d%%)", + sum ? "; " : "", + (parse->generic->currentstatus == i) ? "*" : "", + clockstatus((unsigned int)i), + l_mktime(s_time), + (int)(percent / 100), (int)(percent % 100)); + if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start))) + { + strcpy(tt, item); + tt += count; + } + sum += s_time; + } + } + + sprintf(tt, "; running time: %s\"", l_mktime(sum)); + + tt = add_var(&out->kv_list, 32, RO); + sprintf(tt, "refclock_id=\"%s\"", parse->parse_type->cl_id); + + tt = add_var(&out->kv_list, 80, RO); + sprintf(tt, "refclock_iomode=\"%s\"", parse->binding->bd_description); + + tt = add_var(&out->kv_list, 128, RO); + sprintf(tt, "refclock_driver_version=\"%s\"", rcsid); + + { + struct ctl_var *k; + + k = parse->kv; + while (k && !(k->flags & EOV)) + { + set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); + k++; + } + } + + out->lencode = strlen(outstatus); + out->p_lastcode = outstatus; + } +} + +/**=========================================================================== + ** processing routines + **/ + +/*-------------------------------------------------- + * event handling - note that nominal events will also be posted + */ +static void +parse_event( + struct parseunit *parse, + int event + ) +{ + if (parse->generic->currentstatus != (u_char) event) + { + parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; + parse->lastchange = current_time; + + parse->generic->currentstatus = (u_char)event; + + if (parse->parse_type->cl_event) + parse->parse_type->cl_event(parse, event); + + if (event != CEVNT_NOMINAL) + { + parse->generic->lastevent = parse->generic->currentstatus; + } + else + { + NLOG(NLOG_CLOCKSTATUS) + msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", + CLK_UNIT(parse->peer)); + } + + if (event == CEVNT_FAULT) + { + NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */ + ERR(ERR_BADEVENT) + msyslog(LOG_ERR, + "clock %s fault '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event), + (u_int)event); + } + else + { + NLOG(NLOG_CLOCKEVENT) /* conditional if clause for conditional syslog */ + if (event == CEVNT_NOMINAL || list_err(parse, ERR_BADEVENT)) + msyslog(LOG_INFO, + "clock %s event '%s' (0x%02x)", refnumtoa(parse->peer->srcadr.sin_addr.s_addr), ceventstr(event), + (u_int)event); + } + + report_event(EVNT_PEERCLOCK, parse->peer); + report_event(EVNT_CLOCKEXCPT, parse->peer); + } +} + +/*-------------------------------------------------- + * process a PARSE time sample + */ +static void +parse_process( + struct parseunit *parse, + parsetime_t *parsetime + ) +{ + l_fp off, rectime, reftime; + double fudge; + + /* + * check for changes in conversion status + * (only one for each new status !) + */ + if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && + ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && + (parse->time.parse_status != parsetime->parse_status)) + { + char buffer[400]; + + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", + CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer)); + + if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) + { + /* + * tell more about the story - list time code + * there is a slight change for a race condition and + * the time code might be overwritten by the next packet + */ + parsectl_t tmpctl; + + if (!PARSE_GETTIMECODE(parse, &tmpctl)) + { + ERR(ERR_INTERNAL) + msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); + } + else + { + ERR(ERR_BADDATA) + msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / cableling)", + CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1))); + parse->generic->badformat += tmpctl.parsegettc.parse_badformat; + } + } + } + + /* + * examine status and post appropriate events + */ + if ((parsetime->parse_status & CVT_MASK) != CVT_OK) + { + /* + * got bad data - tell the rest of the system + */ + switch (parsetime->parse_status & CVT_MASK) + { + case CVT_NONE: + if ((parsetime->parse_status & CVT_ADDITIONAL) && + parse->parse_type->cl_message) + parse->parse_type->cl_message(parse, parsetime); + break; /* well, still waiting - timeout is handled at higher levels */ + + case CVT_FAIL: + parse->generic->badformat++; + if (parsetime->parse_status & CVT_BADFMT) + { + parse_event(parse, CEVNT_BADREPLY); + } + else + if (parsetime->parse_status & CVT_BADDATE) + { + parse_event(parse, CEVNT_BADDATE); + } + else + if (parsetime->parse_status & CVT_BADTIME) + { + parse_event(parse, CEVNT_BADTIME); + } + else + { + parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ + } + } + return; /* skip the rest - useless */ + } + + /* + * check for format changes + * (in case somebody has swapped clocks 8-) + */ + if (parse->lastformat != parsetime->parse_format) + { + parsectl_t tmpctl; + + tmpctl.parseformat.parse_format = parsetime->parse_format; + + if (!PARSE_GETFMT(parse, &tmpctl)) + { + ERR(ERR_INTERNAL) + msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); + } + else + { + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", + CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); + } + parse->lastformat = parsetime->parse_format; + } + + /* + * now, any changes ? + */ + if (parse->time.parse_state != parsetime->parse_state) + { + char tmp1[200]; + char tmp2[200]; + /* + * something happend + */ + + (void) parsestate(parsetime->parse_state, tmp1); + (void) parsestate(parse->time.parse_state, tmp2); + + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", + CLK_UNIT(parse->peer), tmp2, tmp1); + } + + /* + * remember for future + */ + parse->time = *parsetime; + + /* + * check to see, whether the clock did a complete powerup or lost PZF signal + * and post correct events for current condition + */ + if (PARSE_POWERUP(parsetime->parse_state)) + { + /* + * this is bad, as we have completely lost synchronisation + * well this is a problem with the receiver here + * for PARSE Meinberg DCF77 receivers the lost synchronisation + * is true as it is the powerup state and the time is taken + * from a crude real time clock chip + * for the PZF series this is only partly true, as + * PARSE_POWERUP only means that the pseudo random + * phase shift sequence cannot be found. this is only + * bad, if we have never seen the clock in the SYNC + * state, where the PHASE and EPOCH are correct. + * for reporting events the above business does not + * really matter, but we can use the time code + * even in the POWERUP state after having seen + * the clock in the synchronized state (PZF class + * receivers) unless we have had a telegram disruption + * after having seen the clock in the SYNC state. we + * thus require having seen the clock in SYNC state + * *after* having missed telegrams (noresponse) from + * the clock. one problem remains: we might use erroneously + * POWERUP data if the disruption is shorter than 1 polling + * interval. fortunately powerdowns last usually longer than 64 + * seconds and the receiver is at least 2 minutes in the + * POWERUP or NOSYNC state before switching to SYNC + */ + parse_event(parse, CEVNT_FAULT); + NLOG(NLOG_CLOCKSTATUS) + ERR(ERR_BADSTATUS) + msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED", + CLK_UNIT(parse->peer)); + } + else + { + /* + * we have two states left + * + * SYNC: + * this state means that the EPOCH (timecode) and PHASE + * information has be read correctly (at least two + * successive PARSE timecodes were received correctly) + * this is the best possible state - full trust + * + * NOSYNC: + * The clock should be on phase with respect to the second + * signal, but the timecode has not been received correctly within + * at least the last two minutes. this is a sort of half baked state + * for PARSE Meinberg DCF77 clocks this is bad news (clock running + * without timecode confirmation) + * PZF 535 has also no time confirmation, but the phase should be + * very precise as the PZF signal can be decoded + */ + + if (PARSE_SYNC(parsetime->parse_state)) + { + /* + * currently completely synchronized - best possible state + */ + parse->lastsync = current_time; + clear_err(parse, ERR_BADSTATUS); + } + else + { + /* + * we have had some problems receiving the time code + */ + parse_event(parse, CEVNT_PROP); + NLOG(NLOG_CLOCKSTATUS) + ERR(ERR_BADSTATUS) + msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", + CLK_UNIT(parse->peer)); + } + } + + fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ + + if (PARSE_TIMECODE(parsetime->parse_state)) + { + rectime = parsetime->parse_stime.fp; + off = reftime = parsetime->parse_time.fp; + + L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ + +#ifdef DEBUG + if (debug > 3) + printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", + CLK_UNIT(parse->peer), + prettydate(&reftime), + prettydate(&rectime), + lfptoa(&off,6)); +#endif + } + + if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) + { + l_fp offset; + + /* + * we have a PPS signal - much better than the RS232 stuff (we hope) + */ + offset = parsetime->parse_ptime.fp; + +#ifdef DEBUG + if (debug > 3) + printf("PARSE receiver #%d: PPStime %s\n", + CLK_UNIT(parse->peer), + prettydate(&offset)); +#endif + if (PARSE_TIMECODE(parsetime->parse_state)) + { + if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) && + M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f)) + { + fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */ + + /* + * RS232 offsets within [-0.5..0.5[ - take PPS offsets + */ + + if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) + { + reftime = off = offset; + if (reftime.l_uf & (unsigned)0x80000000) + reftime.l_ui++; + reftime.l_uf = 0; + + + /* + * implied on second offset + */ + off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ + off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ + } + else + { + /* + * time code describes pulse + */ + reftime = off = parsetime->parse_time.fp; + + L_SUB(&off, &offset); /* true offset */ + } + } + /* + * take RS232 offset when PPS when out of bounds + */ + } + else + { + fudge = parse->generic->fudgetime2; /* pick PPS fudge factor */ + /* + * Well, no time code to guide us - assume on second pulse + * and pray, that we are within [-0.5..0.5[ + */ + off = offset; + reftime = offset; + if (reftime.l_uf & (unsigned)0x80000000) + reftime.l_ui++; + reftime.l_uf = 0; + /* + * implied on second offset + */ + off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ + off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ + } + } + else + { + if (!PARSE_TIMECODE(parsetime->parse_state)) + { + /* + * Well, no PPS, no TIMECODE, no more work ... + */ + if ((parsetime->parse_status & CVT_ADDITIONAL) && + parse->parse_type->cl_message) + parse->parse_type->cl_message(parse, parsetime); + return; + } + } + +#ifdef DEBUG + if (debug > 3) + printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", + CLK_UNIT(parse->peer), + prettydate(&reftime), + prettydate(&rectime), + lfptoa(&off,6)); +#endif + + + rectime = reftime; + L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ + +#ifdef DEBUG + if (debug > 3) + printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", + CLK_UNIT(parse->peer), + prettydate(&reftime), + prettydate(&rectime)); +#endif + + if ((parsetime->parse_status & CVT_ADDITIONAL) && + parse->parse_type->cl_message) + parse->parse_type->cl_message(parse, parsetime); + + if (PARSE_SYNC(parsetime->parse_state)) + { + /* + * log OK status + */ + parse_event(parse, CEVNT_NOMINAL); + } + + clear_err(parse, ERR_BADIO); + clear_err(parse, ERR_BADDATA); + clear_err(parse, ERR_NODATA); + clear_err(parse, ERR_INTERNAL); + +#ifdef DEBUG + if (debug > 2) + { + printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", + CLK_UNIT(parse->peer), + prettydate(&reftime), + prettydate(&rectime), + fudge); + } +#endif + + refclock_process_offset(parse->generic, reftime, rectime, fudge); + if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) + { + (void) pps_sample(&parse->time.parse_ptime.fp); + } + + + /* + * and now stick it into the clock machine + * samples are only valid iff lastsync is not too old and + * we have seen the clock in sync at least once + * after the last time we didn't see an expected data telegram + * see the clock states section above for more reasoning + */ + if (((current_time - parse->lastsync) > parse->parse_type->cl_maxunsync) || + (parse->lastsync <= parse->lastmissed)) + { + parse->generic->leap = LEAP_NOTINSYNC; + } + else + { + if (PARSE_LEAPADD(parsetime->parse_state)) + { + /* + * we pick this state also for time code that pass leap warnings + * without direction information (as earth is currently slowing + * down). + */ + parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; + } + else + if (PARSE_LEAPDEL(parsetime->parse_state)) + { + parse->generic->leap = LEAP_DELSECOND; + } + else + { + parse->generic->leap = LEAP_NOWARNING; + } + } + + /* + * ready, unless the machine wants a sample + */ + if (!parse->pollneeddata) + return; + + parse->pollneeddata = 0; + + refclock_receive(parse->peer); +} + +/**=========================================================================== + ** special code for special clocks + **/ + +static void +mk_utcinfo( + char *t, + int wnt, + int wnlsf, + int dn, + int dtls, + int dtlsf + ) +{ + l_fp leapdate; + + sprintf(t, "current correction %d sec", dtls); + t += strlen(t); + + if (wnlsf < 990) + wnlsf += 1024; + + if (wnt < 990) + wnt += 1024; + + gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate); + + if ((dtlsf != dtls) && + ((wnlsf - wnt) < 52)) + { + sprintf(t, ", next correction %d sec on %s, new GPS-UTC offset %d", + dtlsf - dtls, gmprettydate(&leapdate), dtlsf); + } + else + { + sprintf(t, ", last correction on %s", + gmprettydate(&leapdate)); + } +} + +#ifdef CLOCK_MEINBERG +/**=========================================================================== + ** Meinberg GPS166/GPS167 support + **/ + +/*------------------------------------------------------------ + * gps16x_message - process GPS16x messages + */ +static void +gps16x_message( + struct parseunit *parse, + parsetime_t *parsetime + ) +{ + if (parse->time.parse_msglen && parsetime->parse_msg[0] == SOH) + { + GPS_MSG_HDR header; + unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; + +#ifdef DEBUG + if (debug > 2) + { + char msgbuffer[600]; + + mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); + printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", + CLK_UNIT(parse->peer), + parsetime->parse_msglen, + msgbuffer); + } +#endif + get_mbg_header(&bufp, &header); + if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && + (header.gps_len == 0 || + (header.gps_len < sizeof(parsetime->parse_msg) && + header.gps_data_csum == mbg_csum(bufp, header.gps_len)))) + { + /* + * clean message + */ + switch (header.gps_cmd) + { + case GPS_SW_REV: + { + char buffer[64]; + SW_REV gps_sw_rev; + + get_mbg_sw_rev(&bufp, &gps_sw_rev); + sprintf(buffer, "meinberg_gps_version=\"%x.%02x%s%s\"", + (gps_sw_rev.code >> 8) & 0xFF, + gps_sw_rev.code & 0xFF, + gps_sw_rev.name[0] ? " " : "", + gps_sw_rev.name); + set_var(&parse->kv, buffer, 64, RO|DEF); + } + break; + + case GPS_STAT: + { + static struct state + { + unsigned short flag; /* status flag */ + unsigned const char *string; /* bit name */ + } states[] = + { + { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" }, + { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" }, + { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" }, + { TM_NO_POS, (const unsigned char *)"NO POSITION" }, + { 0, (const unsigned char *)"" } + }; + unsigned short status; + struct state *s = states; + char buffer[512]; + char *p, *b; + + status = get_lsb_short(&bufp); + sprintf(buffer, "meinberg_gps_status=\"[0x%04x] ", status); + + if (status) + { + p = b = buffer + strlen(buffer); + while (s->flag) + { + if (status & s->flag) + { + if (p != b) + { + *p++ = ','; + *p++ = ' '; + } + + strcat(p, (const char *)s->string); + } + s++; + } + + *p++ = '"'; + *p = '\0'; + } + else + { + strcat(buffer, "\""); + } + + set_var(&parse->kv, buffer, 64, RO|DEF); + } + break; + + case GPS_POS_XYZ: + { + XYZ xyz; + char buffer[256]; + + get_mbg_xyz(&bufp, xyz); + sprintf(buffer, "gps_position(XYZ)=\"%s m, %s m, %s m\"", + mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), + mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), + mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); + + set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); + } + break; + + case GPS_POS_LLA: + { + LLA lla; + char buffer[256]; + + get_mbg_lla(&bufp, lla); + + sprintf(buffer, "gps_position(LLA)=\"%s deg, %s deg, %s m\"", + mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), + mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), + mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); + + set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); + } + break; + + case GPS_TZDL: + break; + + case GPS_PORT_PARM: + break; + + case GPS_SYNTH: + break; + + case GPS_ANT_INFO: + { + ANT_INFO antinfo; + char buffer[512]; + char *p; + + get_mbg_antinfo(&bufp, &antinfo); + sprintf((char *)buffer, "meinberg_antenna_status=\""); + p = buffer + strlen(buffer); + + switch (antinfo.status) + { + case ANT_INVALID: + strcat(p, ""); + p += strlen(p); + break; + + case ANT_DISCONN: + strcat(p, "DISCONNECTED since "); + NLOG(NLOG_CLOCKSTATUS) + ERR(ERR_BADSTATUS) + msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", + CLK_UNIT(parse->peer), p); + + p += strlen(p); + mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn); + *p = '\0'; + break; + + case ANT_RECONN: + strcat(p, "RECONNECTED on "); + p += strlen(p); + mbg_tm_str((unsigned char **)&p, &antinfo.tm_reconn); + sprintf(p, ", reconnect clockoffset %c%ld.%07ld s, disconnect time ", + (antinfo.delta_t < 0) ? '-' : '+', + ABS(antinfo.delta_t) / 10000, + ABS(antinfo.delta_t) % 10000); + p += strlen(p); + mbg_tm_str((unsigned char **)&p, &antinfo.tm_disconn); + *p = '\0'; + break; + + default: + sprintf(p, "bad status 0x%04x", antinfo.status); + p += strlen(p); + break; + } + + *p++ = '"'; + *p = '\0'; + + set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); + } + break; + + case GPS_UCAP: + break; + + case GPS_CFGH: + { + CFGH cfgh; + char buffer[512]; + char *p; + + get_mbg_cfgh(&bufp, &cfgh); + if (cfgh.valid) + { + int i; + + p = buffer; + strcpy(buffer, "gps_tot_51=\""); + p += strlen(p); + mbg_tgps_str((unsigned char **)&p, &cfgh.tot_51); + *p++ = '"'; + *p = '\0'; + set_var(&parse->kv, buffer, sizeof(buffer), RO); + + p = buffer; + strcpy(buffer, "gps_tot_63=\""); + p += strlen(p); + mbg_tgps_str((unsigned char **)&p, &cfgh.tot_63); + *p++ = '"'; + *p = '\0'; + set_var(&parse->kv, buffer, sizeof(buffer), RO); + + p = buffer; + strcpy(buffer, "gps_t0a=\""); + p += strlen(p); + mbg_tgps_str((unsigned char **)&p, &cfgh.t0a); + *p++ = '"'; + *p = '\0'; + set_var(&parse->kv, buffer, sizeof(buffer), RO); + + for (i = MIN_SVNO; i <= MAX_SVNO; i++) + { + p = buffer; + sprintf(p, "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]); + p += strlen(p); + switch (cfgh.cfg[i] & 0x7) + { + case 0: + strcpy(p, "BLOCK I"); + break; + case 1: + strcpy(p, "BLOCK II"); + break; + default: + sprintf(p, "bad CFG"); + break; + } + strcat(p, "\""); + set_var(&parse->kv, buffer, sizeof(buffer), RO); + + p = buffer; + sprintf(p, "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]); + p += strlen(p); + switch ((cfgh.health[i] >> 5) & 0x7 ) + { + case 0: + strcpy(p, "OK;"); + break; + case 1: + strcpy(p, "PARITY;"); + break; + case 2: + strcpy(p, "TLM/HOW;"); + break; + case 3: + strcpy(p, "Z-COUNT;"); + break; + case 4: + strcpy(p, "SUBFRAME 1,2,3;"); + break; + case 5: + strcpy(p, "SUBFRAME 4,5;"); + break; + case 6: + strcpy(p, "UPLOAD BAD;"); + break; + case 7: + strcpy(p, "DATA BAD;"); + break; + } + + p += strlen(p); + + switch (cfgh.health[i] & 0x1F) + { + case 0: + strcpy(p, "SIGNAL OK"); + break; + case 0x1C: + strcpy(p, "SV TEMP OUT"); + break; + case 0x1D: + strcpy(p, "SV WILL BE TEMP OUT"); + break; + case 0x1E: + break; + case 0x1F: + strcpy(p, "MULTIPLE ERRS"); + break; + default: + strcpy(p, "TRANSMISSION PROBLEMS"); + break; + } + + strcat(p, "\""); + set_var(&parse->kv, buffer, sizeof(buffer), RO); + } + } + } + break; + + case GPS_ALM: + break; + + case GPS_EPH: + break; + + case GPS_UTC: + { + UTC utc; + char buffer[512]; + char *p; + + p = buffer; + + get_mbg_utc(&bufp, &utc); + + if (utc.valid) + { + strcpy(p, "gps_utc_correction=\""); + p += strlen(p); + mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf); + strcat(p, "\""); + } + else + { + strcpy(p, "gps_utc_correction=\"\""); + } + set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); + } + break; + + case GPS_IONO: + break; + + case GPS_ASCII_MSG: + { + ASCII_MSG gps_ascii_msg; + char buffer[128]; + + get_mbg_ascii_msg(&bufp, &gps_ascii_msg); + + if (gps_ascii_msg.valid) + { + char buffer1[128]; + mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); + + sprintf(buffer, "gps_message=\"%s\"", buffer1); + } + else + strcpy(buffer, "gps_message="); + + set_var(&parse->kv, buffer, 128, RO|DEF); + } + + break; + + default: + break; + } + } + else + { + msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)", + CLK_UNIT(parse->peer), + header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), + header.gps_len, + header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0))); + } + } + + return; +} + +/*------------------------------------------------------------ + * gps16x_poll - query the reciver peridically + */ +static void +gps16x_poll( + struct peer *peer + ) +{ + struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; + + static GPS_MSG_HDR sequence[] = + { + { GPS_SW_REV, 0, 0, 0 }, + { GPS_STAT, 0, 0, 0 }, + { GPS_UTC, 0, 0, 0 }, + { GPS_ASCII_MSG, 0, 0, 0 }, + { GPS_ANT_INFO, 0, 0, 0 }, + { GPS_CFGH, 0, 0, 0 }, + { GPS_POS_XYZ, 0, 0, 0 }, + { GPS_POS_LLA, 0, 0, 0 }, + { (unsigned short)~0, 0, 0, 0 } + }; + + int rtc; + unsigned char cmd_buffer[64]; + unsigned char *outp = cmd_buffer; + GPS_MSG_HDR *header; + + if (((poll_info_t *)parse->parse_type->cl_data)->rate) + { + parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; + } + + if (sequence[parse->localstate].gps_cmd == (unsigned short)~0) + parse->localstate = 0; + + header = sequence + parse->localstate++; + + *outp++ = SOH; /* start command */ + + put_mbg_header(&outp, header); + outp = cmd_buffer + 1; + + header->gps_hdr_csum = (short)mbg_csum(outp, 6); + put_mbg_header(&outp, header); + +#ifdef DEBUG + if (debug > 2) + { + char buffer[128]; + + mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); + printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", + CLK_UNIT(parse->peer), + parse->localstate - 1, + (int)(outp - cmd_buffer), + buffer); + } +#endif + + rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); + + if (rtc < 0) + { + ERR(ERR_BADIO) + msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); + } + else + if (rtc != outp - cmd_buffer) + { + ERR(ERR_BADIO) + msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, (int)(outp - cmd_buffer)); + } + + clear_err(parse, ERR_BADIO); + return; +} + +/*-------------------------------------------------- + * init routine - setup timer + */ +static int +gps16x_poll_init( + struct parseunit *parse + ) +{ + if (((poll_info_t *)parse->parse_type->cl_data)->rate) + { + parse->peer->action = gps16x_poll; + gps16x_poll(parse->peer); + } + + return 0; +} + +#else +static void +gps16x_message( + struct parseunit *parse, + parsetime_t *parsetime + ) +{} +static int +gps16x_poll_init( + struct parseunit *parse + ) +{ + return 1; +} +#endif /* CLOCK_MEINBERG */ + +/**=========================================================================== + ** clock polling support + **/ + +/*-------------------------------------------------- + * direct poll routine + */ +static void +poll_dpoll( + struct parseunit *parse + ) +{ + int rtc; + const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; + int ct = ((poll_info_t *)parse->parse_type->cl_data)->count; + + rtc = write(parse->generic->io.fd, ps, (unsigned long)ct); + if (rtc < 0) + { + ERR(ERR_BADIO) + msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); + } + else + if (rtc != ct) + { + ERR(ERR_BADIO) + msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct); + } + clear_err(parse, ERR_BADIO); +} + +/*-------------------------------------------------- + * periodic poll routine + */ +static void +poll_poll( + struct peer *peer + ) +{ + struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; + + if (parse->parse_type->cl_poll) + parse->parse_type->cl_poll(parse); + + if (((poll_info_t *)parse->parse_type->cl_data)->rate) + { + parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; + } +} + +/*-------------------------------------------------- + * init routine - setup timer + */ +static int +poll_init( + struct parseunit *parse + ) +{ + if (((poll_info_t *)parse->parse_type->cl_data)->rate) + { + parse->peer->action = poll_poll; + poll_poll(parse->peer); + } + + return 0; +} + +/**=========================================================================== + ** Trimble support + **/ + +/*------------------------------------------------------------- + * trimble TAIP init routine - setup EOL and then do poll_init. + */ +static int +trimbletaip_init( + struct parseunit *parse + ) +{ +#ifdef HAVE_TERMIOS + struct termios tio; +#endif +#ifdef HAVE_SYSV_TTYS + struct termio tio; +#endif + /* + * configure terminal line for trimble receiver + */ + if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); + return 0; + } + else + { + tio.c_cc[VEOL] = TRIMBLETAIP_EOL; + + if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); + return 0; + } + } + return poll_init(parse); +} + +/*-------------------------------------------------- + * trimble TAIP event routine - reset receiver upon data format trouble + */ +static const char *taipinit[] = { + ">FPV00000000<", + ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", + ">FTM00020001<", + (char *)0 +}; + +static void +trimbletaip_event( + struct parseunit *parse, + int event + ) +{ + switch (event) + { + case CEVNT_BADREPLY: /* reset on garbled input */ + case CEVNT_TIMEOUT: /* reset on no input */ + { + const char **iv; + + iv = taipinit; + while (*iv) + { + int rtc = write(parse->generic->io.fd, *iv, strlen(*iv)); + if (rtc < 0) + { + msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); + return; + } + else + { + if (rtc != strlen(*iv)) + { + msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", + CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); + return; + } + } + iv++; + } + + NLOG(NLOG_CLOCKINFO) + ERR(ERR_BADIO) + msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", + CLK_UNIT(parse->peer)); + } + break; + + default: /* ignore */ + break; + } +} + +/* + * This driver supports the Trimble SVee Six Plus GPS receiver module. + * It should support other Trimble receivers which use the Trimble Standard + * Interface Protocol (see below). + * + * The module has a serial I/O port for command/data and a 1 pulse-per-second + * output, about 1 microsecond wide. The leading edge of the pulse is + * coincident with the change of the GPS second. This is the same as + * the change of the UTC second +/- ~1 microsecond. Some other clocks + * specifically use a feature in the data message as a timing reference, but + * the SVee Six Plus does not do this. In fact there is considerable jitter + * on the timing of the messages, so this driver only supports the use + * of the PPS pulse for accurate timing. Where it is determined that + * the offset is way off, when first starting up ntpd for example, + * the timing of the data stream is used until the offset becomes low enough + * (|offset| < clock_max), at which point the pps offset is used. + * + * It can use either option for receiving PPS information - the 'ppsclock' + * stream pushed onto the serial data interface to timestamp the Carrier + * Detect interrupts, where the 1PPS connects to the CD line. This only + * works on SunOS 4.1.x currently. To select this, define PPSPPS in + * Config.local. The other option is to use a pulse-stretcher/level-converter + * to convert the PPS pulse into a RS232 start pulse & feed this into another + * tty port. To use this option, define PPSCLK in Config.local. The pps input, + * by whichever method, is handled in ntp_loopfilter.c + * + * The receiver uses a serial message protocol called Trimble Standard + * Interface Protocol (it can support others but this driver only supports + * TSIP). Messages in this protocol have the following form: + * + * ... ... + * + * Any bytes within the portion of value 10 hex () are doubled + * on transmission and compressed back to one on reception. Otherwise + * the values of data bytes can be anything. The serial interface is RS-422 + * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits + * in total!), and 1 stop bit. The protocol supports byte, integer, single, + * and double datatypes. Integers are two bytes, sent most significant first. + * Singles are IEEE754 single precision floating point numbers (4 byte) sent + * sign & exponent first. Doubles are IEEE754 double precision floating point + * numbers (8 byte) sent sign & exponent first. + * The receiver supports a large set of messages, only a small subset of + * which are used here. From driver to receiver the following are used: + * + * ID Description + * + * 21 Request current time + * 22 Mode Select + * 2C Set/Request operating parameters + * 2F Request UTC info + * 35 Set/Request I/O options + + * From receiver to driver the following are recognised: + * + * ID Description + * + * 41 GPS Time + * 44 Satellite selection, PDOP, mode + * 46 Receiver health + * 4B Machine code/status + * 4C Report operating parameters (debug only) + * 4F UTC correction data (used to get leap second warnings) + * 55 I/O options (debug only) + * + * All others are accepted but ignored. + * + */ + +#define PI 3.1415926535898 /* lots of sig figs */ +#define D2R PI/180.0 + +/*------------------------------------------------------------------- + * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command + * interface to the receiver. + * + * CAVEAT: the sendflt, sendint routines are byte order dependend and + * float implementation dependend - these must be converted to portable + * versions ! + * + * CURRENT LIMITATION: float implementation. This runs only on systems + * with IEEE754 floats as native floats + */ + +typedef struct trimble +{ + u_long last_msg; /* last message received */ + u_char qtracking; /* query tracking status */ + u_long ctrack; /* current tracking set */ + u_long ltrack; /* last tracking set */ +} trimble_t; + +union uval { + u_char bd[8]; + int iv; + float fv; + double dv; +}; + +struct txbuf +{ + short idx; /* index to first unused byte */ + u_char *txt; /* pointer to actual data buffer */ +}; + +void +sendcmd( + struct txbuf *buf, + int c + ) +{ + buf->txt[0] = DLE; + buf->txt[1] = (u_char)c; + buf->idx = 2; +} + +void +sendbyte( + struct txbuf *buf, + int b + ) +{ + if (b == DLE) + buf->txt[buf->idx++] = DLE; + buf->txt[buf->idx++] = (u_char)b; +} + +void +sendetx( + struct txbuf *buf, + struct parseunit *parse + ) +{ + buf->txt[buf->idx++] = DLE; + buf->txt[buf->idx++] = ETX; + + if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) + { + ERR(ERR_BADIO) + msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); + } + else + { +#ifdef DEBUG + if (debug > 2) + { + char buffer[256]; + + mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); + printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", + CLK_UNIT(parse->peer), + buf->idx, buffer); + } +#endif + clear_err(parse, ERR_BADIO); + } +} + +void +sendint( + struct txbuf *buf, + int a + ) +{ + /* send 16bit int, msbyte first */ + sendbyte(buf, (u_char)((a>>8) & 0xff)); + sendbyte(buf, (u_char)(a & 0xff)); +} + +void +sendflt( + struct txbuf *buf, + double a + ) +{ + int i; + union uval uval; + + uval.fv = a; +#ifdef WORDS_BIGENDIAN + for (i=0; i<=3; i++) +#else + for (i=3; i>=0; i--) +#endif + sendbyte(buf, uval.bd[i]); +} + +#define TRIM_POS_OPT 0x13 /* output position with high precision */ +#define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ + +/*-------------------------------------------------- + * trimble TSIP setup routine + */ +static int +trimbletsip_setup( + struct parseunit *parse, + const char *reason + ) +{ + u_char buffer[256]; + struct txbuf buf; + + buf.txt = buffer; + + sendcmd(&buf, CMD_CVERSION); /* request software versions */ + sendetx(&buf, parse); + + sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ + sendbyte(&buf, 4); /* static */ + sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ + sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ + sendflt(&buf, 12.0); /* PDOP mask = 12 */ + sendflt(&buf, 8.0); /* PDOP switch level = 8 */ + sendetx(&buf, parse); + + sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ + sendbyte(&buf, 0); /* automatic */ + sendetx(&buf, parse); + + sendcmd(&buf, CMD_CMESSAGE); /* request system message */ + sendetx(&buf, parse); + + sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ + sendbyte(&buf, 0x2); /* binary mode */ + sendetx(&buf, parse); + + sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ + sendbyte(&buf, TRIM_POS_OPT); /* position output */ + sendbyte(&buf, 0x00); /* no velocity output */ + sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ + sendbyte(&buf, 0x00); /* no raw measurements */ + sendetx(&buf, parse); + + sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ + sendetx(&buf, parse); + + NLOG(NLOG_CLOCKINFO) + ERR(ERR_BADIO) + msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); + + return 0; +} + +/*-------------------------------------------------- + * TRIMBLE TSIP check routine + */ +static void +trimble_check( + struct peer *peer + ) +{ + struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; + trimble_t *t = parse->localdata; + u_char buffer[256]; + struct txbuf buf; + buf.txt = buffer; + + if (t) + { + if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) + (void)trimbletsip_setup(parse, "message timeout"); + } + poll_poll(parse->peer); /* emit query string and re-arm timer */ + + if (t->qtracking) + { + u_long oldsats = t->ltrack & ~t->ctrack; + + t->qtracking = 0; + t->ltrack = t->ctrack; + + if (oldsats) + { + int i; + + for (i = 0; oldsats; i++) + if (oldsats & (1 << i)) + { + sendcmd(&buf, CMD_CSTATTRACK); + sendbyte(&buf, i+1); /* old sat */ + sendetx(&buf, parse); + } + oldsats &= ~(1 << i); + } + + sendcmd(&buf, CMD_CSTATTRACK); + sendbyte(&buf, 0x00); /* current tracking set */ + sendetx(&buf, parse); + } +} + +/*-------------------------------------------------- + * TRIMBLE TSIP end routine + */ +static void +trimbletsip_end( + struct parseunit *parse + ) +{ trimble_t *t = parse->localdata; + + if (t) + { + free(t); + parse->localdata = (void *)0; + } + parse->peer->nextaction = 0; + parse->peer->action = (void (*) P((struct peer *)))0; +} + +/*-------------------------------------------------- + * TRIMBLE TSIP init routine + */ +static int +trimbletsip_init( + struct parseunit *parse + ) +{ +#if defined(VEOL) || defined(VEOL2) +#ifdef HAVE_TERMIOS + struct termios tio; /* NEEDED FOR A LONG TIME ! */ +#endif +#ifdef HAVE_SYSV_TTYS + struct termio tio; /* NEEDED FOR A LONG TIME ! */ +#endif + /* + * allocate local data area + */ + if (!parse->localdata) + { + trimble_t *t; + + t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); + + if (t) + { + memset((char *)t, 0, sizeof(trimble_t)); + t->last_msg = current_time; + } + } + + parse->peer->action = trimble_check; + parse->peer->nextaction = current_time; + + /* + * configure terminal line for ICANON mode with VEOL characters + */ + if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); + return 0; + } + else + { + if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) + { +#ifdef VEOL + tio.c_cc[VEOL] = ETX; +#endif +#ifdef VEOL2 + tio.c_cc[VEOL2] = DLE; +#endif +} + + if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) + { + msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); + return 0; + } + } +#endif + return trimbletsip_setup(parse, "initial startup"); +} + +/*------------------------------------------------------------ + * trimbletsip_event - handle Trimble events + * simple evente handler - attempt to re-initialize receiver + */ +static void +trimbletsip_event( + struct parseunit *parse, + int event + ) +{ + switch (event) + { + case CEVNT_BADREPLY: /* reset on garbled input */ + case CEVNT_TIMEOUT: /* reset on no input */ + (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); + break; + + default: /* ignore */ + break; + } +} + +/* + * getflt, getint convert fields in the incoming data into the + * appropriate type of item + * + * CAVEAT: these routines are currently definitely byte order dependent + * and assume Representation(float) == IEEE754 + * These functions MUST be converted to portable versions (especially + * converting the float representation into ntp_fp formats in order + * to avoid floating point operations at all! + */ + +static float +getflt( + u_char *bp + ) +{ + union uval uval; + +#ifdef WORDS_BIGENDIAN + uval.bd[0] = *bp++; + uval.bd[1] = *bp++; + uval.bd[2] = *bp++; + uval.bd[3] = *bp; +#else /* ! WORDS_BIGENDIAN */ + uval.bd[3] = *bp++; + uval.bd[2] = *bp++; + uval.bd[1] = *bp++; + uval.bd[0] = *bp; +#endif /* ! WORDS_BIGENDIAN */ + return uval.fv; +} + +static double +getdbl( + u_char *bp + ) +{ + union uval uval; + +#ifdef WORDS_BIGENDIAN + uval.bd[0] = *bp++; + uval.bd[1] = *bp++; + uval.bd[2] = *bp++; + uval.bd[3] = *bp++; + uval.bd[4] = *bp++; + uval.bd[5] = *bp++; + uval.bd[6] = *bp++; + uval.bd[7] = *bp; +#else /* ! WORDS_BIGENDIAN */ + uval.bd[7] = *bp++; + uval.bd[6] = *bp++; + uval.bd[5] = *bp++; + uval.bd[4] = *bp++; + uval.bd[3] = *bp++; + uval.bd[2] = *bp++; + uval.bd[1] = *bp++; + uval.bd[0] = *bp; +#endif /* ! WORDS_BIGENDIAN */ + return uval.dv; +} + +static int +getshort( + unsigned char *p + ) +{ + return get_msb_short(&p); +} + +/*-------------------------------------------------- + * trimbletsip_message - process trimble messages + */ +#define RTOD (180.0 / 3.1415926535898) +#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ + +static void +trimbletsip_message( + struct parseunit *parse, + parsetime_t *parsetime + ) +{ + unsigned char *buffer = parsetime->parse_msg; + unsigned int size = parsetime->parse_msglen; + + if ((size < 4) || + (buffer[0] != DLE) || + (buffer[size-1] != ETX) || + (buffer[size-2] != DLE)) + { +#ifdef DEBUG + if (debug > 2) { + int i; + + printf("TRIMBLE BAD packet, size %d:\n ", size); + for (i = 0; i < size; i++) { + printf ("%2.2x, ", buffer[i]&0xff); + if (i%16 == 15) printf("\n\t"); + } + printf("\n"); + } +#endif + return; + } + else + { + int var_flag; + trimble_t *tr = parse->localdata; + unsigned int cmd = buffer[1]; + char pbuffer[200]; + char *t = pbuffer; + cmd_info_t *s; + +#ifdef DEBUG + if (debug > 3) { + int i; + + printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); + for (i = 0; i < size; i++) { + printf ("%2.2x, ", buffer[i]&0xff); + if (i%16 == 15) printf("\n\t"); + } + printf("\n"); + } +#endif + + if (tr) + tr->last_msg = current_time; + + s = trimble_convert(cmd, trimble_rcmds); + + if (s) + { + sprintf(t, "%s=\"", s->varname); + } + else + { + printf("TRIMBLE unknown command 0x%02x\n", cmd); + return; + } + + var_flag = s->varmode; + + t += strlen(t); + + switch(cmd) + { + case CMD_RCURTIME: + sprintf(t, "%f, %d, %f", + getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), + getflt((unsigned char *)&mb(6))); + break; + + case CMD_RBEST4: + strcpy(t, "mode: "); + t += strlen(t); + switch (mb(0) & 0xF) + { + default: + sprintf(t, "0x%x", mb(0) & 0x7); + break; + + case 1: + strcat(t, "0D"); + break; + + case 3: + strcat(t, "2D"); + break; + + case 4: + strcat(t, "3D"); + break; + } + t += strlen(t); + if (mb(0) & 0x10) + strcpy(t, "-MANUAL, "); + else + strcpy(t, "-AUTO, "); + t += strlen(t); + + sprintf(t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", + mb(1), mb(2), mb(3), mb(4), + getflt((unsigned char *)&mb(5)), + getflt((unsigned char *)&mb(9)), + getflt((unsigned char *)&mb(13)), + getflt((unsigned char *)&mb(17))); + + break; + + case CMD_RVERSION: + sprintf(t, "%d.%d (%d/%d/%d)", + mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); + break; + + case CMD_RRECVHEALTH: + { + static const char *msgs[] = + { + "Battery backup failed", + "Signal processor error", + "Alignment error, channel or chip 1", + "Alignment error, channel or chip 2", + "Antenna feed line fault", + "Excessive ref freq. error", + "", + "" + }; + + int i, bits; + + switch (mb(0) & 0xFF) + { + default: + sprintf(t, "illegal value 0x%02x", mb(0) & 0xFF); + break; + case 0x00: + strcpy(t, "doing position fixes"); + break; + case 0x01: + strcpy(t, "no GPS time yet"); + break; + case 0x03: + strcpy(t, "PDOP too high"); + break; + case 0x08: + strcpy(t, "no usable satellites"); + break; + case 0x09: + strcpy(t, "only ONE usable satellite"); + break; + case 0x0A: + strcpy(t, "only TWO usable satellites"); + break; + case 0x0B: + strcpy(t, "only THREE usable satellites"); + break; + case 0x0C: + strcpy(t, "the chosen satellite is unusable"); + break; + } + + t += strlen(t); + + bits = mb(1) & 0xFF; + + for (i = 0; i < 8; i++) + if (bits & (0x1<", + "", + "" + }; + + int i, bits; + + sprintf(t, "machine id 0x%02x", mb(0) & 0xFF); + t += strlen(t); + + bits = mb(1) & 0xFF; + + for (i = 0; i < 8; i++) + if (bits & (0x1<"); + } + } + break; + + case CMD_RSAT1BIAS: + sprintf(t, "%.1fm %.2fm/s at %.1fs", + getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); + break; + + case CMD_RIOOPTIONS: + { + sprintf(t, "%02x %02x %02x %02x", + mb(0), mb(1), mb(2), mb(3)); + if (mb(0) != TRIM_POS_OPT || + mb(2) != TRIM_TIME_OPT) + { + (void)trimbletsip_setup(parse, "bad io options"); + } + } + break; + + case CMD_RSPOSXYZ: + { + double x = getflt((unsigned char *)&mb(0)); + double y = getflt((unsigned char *)&mb(4)); + double z = getflt((unsigned char *)&mb(8)); + double f = getflt((unsigned char *)&mb(12)); + + if (f > 0.0) + sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", + x, y, z, + f); + else + return; + } + break; + + case CMD_RSLLAPOS: + { + double lat = getflt((unsigned char *)&mb(0)); + double lng = getflt((unsigned char *)&mb(4)); + double f = getflt((unsigned char *)&mb(12)); + + if (f > 0.0) + sprintf(t, "lat %f %c, long %f %c, alt %.2fm", + ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), + ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), + getflt((unsigned char *)&mb(8))); + else + return; + } + break; + + case CMD_RDOUBLEXYZ: + { + double x = getdbl((unsigned char *)&mb(0)); + double y = getdbl((unsigned char *)&mb(8)); + double z = getdbl((unsigned char *)&mb(16)); + sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm", + x, y, z); + } + break; + + case CMD_RDOUBLELLA: + { + double lat = getdbl((unsigned char *)&mb(0)); + double lng = getdbl((unsigned char *)&mb(8)); + sprintf(t, "lat %f %c, lon %f %c, alt %.2fm", + ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), + ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), + getdbl((unsigned char *)&mb(16))); + } + break; + + case CMD_RALLINVIEW: + { + int i, sats; + + strcpy(t, "mode: "); + t += strlen(t); + switch (mb(0) & 0x7) + { + default: + sprintf(t, "0x%x", mb(0) & 0x7); + break; + + case 3: + strcat(t, "2D"); + break; + + case 4: + strcat(t, "3D"); + break; + } + t += strlen(t); + if (mb(0) & 0x8) + strcpy(t, "-MANUAL, "); + else + strcpy(t, "-AUTO, "); + t += strlen(t); + + sats = (mb(0)>>4) & 0xF; + + sprintf(t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", + getflt((unsigned char *)&mb(1)), + getflt((unsigned char *)&mb(5)), + getflt((unsigned char *)&mb(9)), + getflt((unsigned char *)&mb(13)), + sats, (sats == 1) ? "" : "s"); + t += strlen(t); + + for (i=0; i < sats; i++) + { + sprintf(t, "%s%02d", i ? ", " : "", mb(17+i)); + t += strlen(t); + if (tr) + tr->ctrack |= (1 << (mb(17+i)-1)); + } + + if (tr) + { /* mark for tracking status query */ + tr->qtracking = 1; + } + } + break; + + case CMD_RSTATTRACK: + { + sprintf(t-2, "[%02d]=\"", mb(0)); /* add index to var name */ + t += strlen(t); + + if (getflt((unsigned char *)&mb(4)) < 0.0) + { + strcpy(t, ""); + var_flag &= ~DEF; + } + else + { + sprintf(t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", + (mb(1) & 0xFF)>>3, + mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", + mb(3), + getflt((unsigned char *)&mb(4)), + getflt((unsigned char *)&mb(12)) * RTOD, + getflt((unsigned char *)&mb(16)) * RTOD); + t += strlen(t); + if (mb(20)) + { + var_flag &= ~DEF; + strcpy(t, ", OLD"); + } + t += strlen(t); + if (mb(22)) + { + if (mb(22) == 1) + strcpy(t, ", BAD PARITY"); + else + if (mb(22) == 2) + strcpy(t, ", BAD EPH HEALTH"); + } + t += strlen(t); + if (mb(23)) + strcpy(t, ", collecting data"); + } + } + break; + + default: + strcpy(t, ""); + break; + } + strcat(t,"\""); + set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); + } +} + + +/**============================================================ + ** RAWDCF support + **/ + +/*-------------------------------------------------- + * rawdcfdtr_init - set up modem lines for RAWDCF receivers + */ +#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) +static int +rawdcfdtr_init( + struct parseunit *parse + ) +{ + /* + * You can use the RS232 to supply the power for a DCF77 receiver. + * Here a voltage between the DTR and the RTS line is used. Unfortunately + * the name has changed from CIOCM_DTR to TIOCM_DTR recently. + */ + +#ifdef TIOCM_DTR + int sl232 = TIOCM_DTR; /* turn on DTR for power supply */ +#else + int sl232 = CIOCM_DTR; /* turn on DTR for power supply */ +#endif + + if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) + { + msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); + } + return 0; +} +#else +static int +rawdcfdtr_init( + struct parseunit *parse + ) +{ + msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); + return 0; +} +#endif /* DTR initialisation type */ + +/*-------------------------------------------------- + * rawdcfrts_init - set up modem lines for RAWDCF receivers + */ +#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) +static int +rawdcfrts_init( + struct parseunit *parse + ) +{ + /* + * You can use the RS232 to supply the power for a DCF77 receiver. + * Here a voltage between the RTS and the DTR line is used. + */ + +#ifdef TIOCM_RTS + int sl232 = TIOCM_RTS; /* turn on RTS for power supply */ +#else + int sl232 = CIOCM_RTS; /* turn on RTS for power supply */ +#endif + + if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) + { + msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); + } + return 0; +} +#else +static int +rawdcfrts_init( + struct parseunit *parse + ) +{ + msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); + return 0; +} +#endif /* RTS initialisation type */ + +#else /* defined(REFCLOCK) && defined(PARSE) */ +int refclock_parse_bs; +#endif /* defined(REFCLOCK) && defined(PARSE) */ + +/* + * History: + * + * refclock_parse.c,v + * Revision 4.29 1999/02/28 19:58:23 kardel + * updated copyright information + * + * Revision 4.28 1999/02/28 19:01:50 kardel + * improved debug out on sent Meinberg messages + * + * Revision 4.27 1999/02/28 18:05:55 kardel + * no linux/ppsclock.h stuff + * + * Revision 4.26 1999/02/28 15:27:27 kardel + * wharton clock integration + * + * Revision 4.25 1999/02/28 14:04:46 kardel + * added missing double quotes to UTC information string + * + * Revision 4.24 1999/02/28 12:06:50 kardel + * (parse_control): using gmprettydate instead of prettydate() + * (mk_utcinfo): new function for formatting GPS derived UTC information + * (gps16x_message): changed to use mk_utcinfo() + * (trimbletsip_message): changed to use mk_utcinfo() + * ignoring position information in unsynchronized mode + * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY + * + * Revision 4.23 1999/02/23 19:47:53 kardel + * fixed #endifs + * (stream_receive): fixed formats + * + * Revision 4.22 1999/02/22 06:21:02 kardel + * use new autoconfig symbols + * + * Revision 4.21 1999/02/21 12:18:13 kardel + * 4.91f reconcilation + * + * Revision 4.20 1999/02/21 10:53:36 kardel + * initial Linux PPSkit version + * + * Revision 4.19 1999/02/07 09:10:45 kardel + * clarify STREAMS mitigation rules in comment + * + * Revision 4.18 1998/12/20 23:45:34 kardel + * fix types and warnings + * + * Revision 4.17 1998/11/15 21:24:51 kardel + * cannot access mbg_ routines when CLOCK_MEINBERG + * is not defined + * + * Revision 4.16 1998/11/15 20:28:17 kardel + * Release 4.0.73e13 reconcilation + * + * Revision 4.15 1998/08/22 21:56:08 kardel + * fixed IO handling for non-STREAM IO + * + * Revision 4.14 1998/08/16 19:00:48 kardel + * (gps16x_message): reduced UTC parameter information (dropped A0,A1) + * made uval a local variable (killed one of the last globals) + * (sendetx): added logging of messages when in debug mode + * (trimble_check): added periodic checks to facilitate re-initialization + * (trimbletsip_init): made use of EOL character if in non-kernel operation + * (trimbletsip_message): extended message interpretation + * (getdbl): fixed data conversion + * + * Revision 4.13 1998/08/09 22:29:13 kardel + * Trimble TSIP support + * + * Revision 4.12 1998/07/11 10:05:34 kardel + * Release 4.0.73d reconcilation + * + * Revision 4.11 1998/06/14 21:09:42 kardel + * Sun acc cleanup + * + * Revision 4.10 1998/06/13 12:36:45 kardel + * signed/unsigned, name clashes + * + * Revision 4.9 1998/06/12 15:30:00 kardel + * prototype fixes + * + * Revision 4.8 1998/06/12 11:19:42 kardel + * added direct input processing routine for refclocks in + * order to avaiod that single character io gobbles up all + * receive buffers and drops input data. (Problem started + * with fast machines so a character a buffer was possible + * one of the few cases where faster machines break existing + * allocation algorithms) + * + * Revision 4.7 1998/06/06 18:35:20 kardel + * (parse_start): added BURST mode initialisation + * + * Revision 4.6 1998/05/27 06:12:46 kardel + * RAWDCF_BASEDELAY default added + * old comment removed + * casts for ioctl() + * + * Revision 4.5 1998/05/25 22:05:09 kardel + * RAWDCF_SETDTR option removed + * clock type 14 attempts to set DTR for + * power supply of RAWDCF receivers + * + * Revision 4.4 1998/05/24 16:20:47 kardel + * updated comments referencing Meinberg clocks + * added RAWDCF clock with DTR set option as type 14 + * + * Revision 4.3 1998/05/24 10:48:33 kardel + * calibrated CONRAD RAWDCF default fudge factor + * + * Revision 4.2 1998/05/24 09:59:35 kardel + * corrected version information (ntpq support) + * + * Revision 4.1 1998/05/24 09:52:31 kardel + * use fixed format only (new IO model) + * output debug to stdout instead of msyslog() + * don't include >"< in ASCII output in order not to confuse + * ntpq parsing + * + * Revision 4.0 1998/04/10 19:52:11 kardel + * Start 4.0 release version numbering + * + * Revision 1.2 1998/04/10 19:28:04 kardel + * initial NTP VERSION 4 integration of PARSE with GPS166 binary support + * derived from 3.105.1.2 from V3 tree + * + * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel + * + */ diff --git a/contrib/ntp/ntpd/refclock_pst.c b/contrib/ntp/ntpd/refclock_pst.c new file mode 100644 index 000000000000..6af43824795a --- /dev/null +++ b/contrib/ntp/ntpd/refclock_pst.c @@ -0,0 +1,318 @@ +/* + * refclock_pst - clock driver for PSTI/Traconex WWV/WWVH receivers + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PST) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +/* + * This driver supports the PSTI 1010 and Traconex 1020 WWV/WWVH + * Receivers. No specific claim of accuracy is made for these receiver, + * but actual experience suggests that 10 ms would be a conservative + * assumption. + * + * The DIPswitches should be set for 9600 bps line speed, 24-hour day- + * of-year format and UTC time zone. Automatic correction for DST should + * be disabled. It is very important that the year be set correctly in + * the DIPswitches; otherwise, the day of year will be incorrect after + * 28 April of a normal or leap year. The propagation delay DIPswitches + * should be set according to the distance from the transmitter for both + * WWV and WWVH, as described in the instructions. While the delay can + * be set only to within 11 ms, the fudge time1 parameter can be used + * for vernier corrections. + * + * Using the poll sequence QTQDQM, the response timecode is in three + * sections totalling 50 ASCII printing characters, as concatenated by + * the driver, in the following format: + * + * ahh:mm:ss.fffs yy/dd/mm/ddd frdzycchhSSFTttttuuxx + * + * on-time = first + * hh:mm:ss.fff = hours, minutes, seconds, milliseconds + * a = AM/PM indicator (' ' for 24-hour mode) + * yy = year (from internal switches) + * dd/mm/ddd = day of month, month, day of year + * s = daylight-saving indicator (' ' for 24-hour mode) + * f = frequency enable (O = all frequencies enabled) + * r = baud rate (3 = 1200, 6 = 9600) + * d = features indicator (@ = month/day display enabled) + * z = time zone (0 = UTC) + * y = year (5 = 91) + * cc = WWV propagation delay (52 = 22 ms) + * hh = WWVH propagation delay (81 = 33 ms) + * SS = status (80 or 82 = operating correctly) + * F = current receive frequency (4 = 15 MHz) + * T = transmitter (C = WWV, H = WWVH) + * tttt = time since last update (0000 = minutes) + * uu = flush character (03 = ^c) + * xx = 94 (unknown) + * + * The alarm condition is indicated by other than '8' at A, which occurs + * during initial synchronization and when received signal is lost for + * an extended period; unlock condition is indicated by other than + * "0000" in the tttt subfield at Q. + * + * Fudge Factors + * + * There are no special fudge factors other than the generic. + */ + +/* + * Interface definitions + */ +#define DEVICE "/dev/pst%d" /* device name and unit */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ +#define PRECISION (-10) /* precision assumed (about 1 ms) */ +#define WWVREFID "WWV\0" /* WWV reference ID */ +#define WWVHREFID "WWVH" /* WWVH reference ID */ +#define DESCRIPTION "PSTI/Traconex WWV/WWVH Receiver" /* WRU */ +#define PST_PHI (10e-6) /* max clock oscillator offset */ +#define LENPST 46 /* min timecode length */ + +/* + * Unit control structure + */ +struct pstunit { + u_char tcswitch; /* timecode switch */ + char *lastptr; /* pointer to timecode data */ +}; + +/* + * Function prototypes + */ +static int pst_start P((int, struct peer *)); +static void pst_shutdown P((int, struct peer *)); +static void pst_receive P((struct recvbuf *)); +static void pst_poll P((int, struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_pst = { + pst_start, /* start up driver */ + pst_shutdown, /* shut down driver */ + pst_poll, /* transmit poll message */ + noentry, /* not used (old pst_control) */ + noentry, /* initialize driver */ + noentry, /* not used (old pst_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * pst_start - open the devices and initialize data for processing + */ +static int +pst_start( + int unit, + struct peer *peer + ) +{ + register struct pstunit *up; + struct refclockproc *pp; + int fd; + char device[20]; + + /* + * Open serial port. Use CLK line discipline, if available. + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct pstunit *)emalloc(sizeof(struct pstunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct pstunit)); + pp = peer->procptr; + pp->io.clock_recv = pst_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + peer->burst = NSTAGE; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, WWVREFID, 4); + return (1); +} + + +/* + * pst_shutdown - shut down the clock + */ +static void +pst_shutdown( + int unit, + struct peer *peer + ) +{ + register struct pstunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct pstunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * pst_receive - receive data from the serial interface + */ +static void +pst_receive( + struct recvbuf *rbufp + ) +{ + register struct pstunit *up; + struct refclockproc *pp; + struct peer *peer; + l_fp trtmp; + u_long ltemp; + char ampmchar; /* AM/PM indicator */ + char daychar; /* standard/daylight indicator */ + char junque[10]; /* "yy/dd/mm/" discard */ + char info[14]; /* "frdzycchhSSFT" clock info */ + + /* + * Initialize pointers and read the timecode and timestamp + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct pstunit *)pp->unitptr; + up->lastptr += refclock_gtlin(rbufp, up->lastptr, pp->a_lastcode + + BMAX - 2 - up->lastptr, &trtmp); + *up->lastptr++ = ' '; + *up->lastptr = '\0'; + + /* + * Note we get a buffer and timestamp for each , but only + * the first timestamp is retained. + */ + if (!up->tcswitch) + pp->lastrec = trtmp; + up->tcswitch++; + pp->lencode = up->lastptr - pp->a_lastcode; + if (up->tcswitch < 3) + return; +#ifdef DEBUG + if (debug) + printf("pst: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + + /* + * We get down to business, check the timecode format and decode + * its contents. If the timecode has invalid length or is not in + * proper format, we declare bad format and exit. + */ + if (pp->lencode < LENPST) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Timecode format: + * "ahh:mm:ss.fffs yy/dd/mm/ddd frdzycchhSSFTttttuuxx" + */ + if (sscanf(pp->a_lastcode, "%c%2d:%2d:%2d.%3d%c %9s%3d%13s%4ld", + &mchar, &pp->hour, &pp->minute, &pp->second, + &pp->msec, &daychar, junque, &pp->day, + info, <emp) != 10) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Decode synchronization, quality and last update. If + * unsynchronized, set the leap bits accordingly and exit. Once + * synchronized, the dispersion depends only on when the clock + * was last heard, which depends on the time since last update, + * as reported by the clock. + */ + if (info[9] != '8') + pp->leap = LEAP_NOTINSYNC; + if (info[12] == 'H') + memcpy((char *)&pp->refid, WWVHREFID, 4); + else + memcpy((char *)&pp->refid, WWVREFID, 4); + if (peer->stratum <= 1) + peer->refid = pp->refid; + pp->disp = PST_PHI * ltemp; + + /* + * Process the new sample in the median filter and determine the + * timecode timestamp. + */ + if (!refclock_process(pp)) + refclock_report(peer, CEVNT_BADTIME); + +} + + +/* + * pst_poll - called by the transmit procedure + */ +static void +pst_poll( + int unit, + struct peer *peer + ) +{ + register struct pstunit *up; + struct refclockproc *pp; + + /* + * Time to poll the clock. The PSTI/Traconex clock responds to a + * "QTQDQMT" by returning a timecode in the format specified + * above. If nothing is heard from the clock for two polls, + * declare a timeout and keep going. + */ + pp = peer->procptr; + up = (struct pstunit *)pp->unitptr; + up->tcswitch = 0; + up->lastptr = pp->a_lastcode; + if (write(pp->io.fd, "QTQDQMT", 6) != 6) + refclock_report(peer, CEVNT_FAULT); + else + pp->polls++; + if (peer->burst > 0) + return; + if (pp->coderecv == pp->codeproc) { + refclock_report(peer, CEVNT_TIMEOUT); + return; + } + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + peer->burst = NSTAGE; +} + +#else +int refclock_pst_int; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_ptbacts.c b/contrib/ntp/ntpd/refclock_ptbacts.c new file mode 100644 index 000000000000..09d7bf4c2203 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_ptbacts.c @@ -0,0 +1,16 @@ +/* + * crude hack to avoid hard links in distribution + * and keep only one ACTS type source for different + * ACTS refclocks + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_PTBACTS) +# define KEEPPTBACTS +# include "refclock_acts.c" +#else /* not (REFCLOCK && CLOCK_PTBACTS) */ +int refclock_ptbacts_bs; +#endif /* not (REFCLOCK && CLOCK_PTBACTS) */ diff --git a/contrib/ntp/ntpd/refclock_shm.c b/contrib/ntp/ntpd/refclock_shm.c new file mode 100644 index 000000000000..fe05b02f7137 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_shm.c @@ -0,0 +1,320 @@ +/* + * refclock_shm - clock driver for utc via shared memory + * - under construction - + * To add new modes: Extend or union the shmTime-struct. Do not + * extend/shrink size, because otherwise existing implementations + * will specify wrong size of shared memory-segment + * PB 18.3.97 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_SHM) + +#undef fileno +#include +#undef fileno +#include +#undef fileno + +#include "ntpd.h" +#undef fileno +#include "ntp_io.h" +#undef fileno +#include "ntp_refclock.h" +#undef fileno +#include "ntp_unixtime.h" +#undef fileno +#include "ntp_stdlib.h" + +#ifndef SYS_WINNT +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +/* + * This driver supports a reference clock attached thru shared memory + */ + +/* + * SHM interface definitions + */ +#define PRECISION (-1) /* precision assumed (0.5 s) */ +#define REFID "SHM" /* reference ID */ +#define DESCRIPTION "SHM/Shared memory interface" + +#define NSAMPLES 3 /* stages of median filter */ + +/* + * Function prototypes + */ +static int shm_start (int, struct peer *); +static void shm_shutdown (int, struct peer *); +static void shm_poll (int unit, struct peer *); + +/* + * Transfer vector + */ +struct refclock refclock_shm = { + shm_start, /* start up driver */ + shm_shutdown, /* shut down driver */ + shm_poll, /* transmit poll message */ + noentry, /* not used */ + noentry, /* initialize driver (not used) */ + noentry, /* not used */ + NOFLAGS /* not used */ +}; +struct shmTime { + int mode; /* 0 - if valid set + * use values, + * clear valid + * 1 - if valid set + * if count before and after read of values is equal, + * use values + * clear valid + */ + int count; + time_t clockTimeStampSec; + int clockTimeStampUSec; + time_t receiveTimeStampSec; + int receiveTimeStampUSec; + int leap; + int precision; + int nsamples; + int valid; + int dummy[10]; +}; +struct shmTime *getShmTime (int unit) { +#ifndef SYS_WINNT + extern char *sys_errlist[ ]; + extern int sys_nerr; + int shmid=0; + + assert (unit<10); /* MAXUNIT is 4, so should never happen */ + shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), + IPC_CREAT|(unit<2?0700:0777)); + if (shmid==-1) { /*error */ + char buf[20]; + char *pe=buf; + if (errno=2) { /* world access */ + if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { + msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit); + return 0; + } + if (!SetSecurityDescriptorDacl(&sd,1,0,0)) { + msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit); + return 0; + } + sa.nLength=sizeof (SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor=&sd; + sa.bInheritHandle=0; + psec=&sa; + } + shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE, + 0, sizeof (struct shmTime),buf); + if (!shmid) { /*error*/ + char buf[1000]; + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, + 0, GetLastError (), 0, buf, sizeof (buf), 0); + msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf); + return 0; + } + else { + struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid, + FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime)); + if (p==0) { /*error*/ + char buf[1000]; + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, + 0, GetLastError (), 0, buf, sizeof (buf), 0); + msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf); + return 0; + } + return p; + } +#endif + return 0; +} +/* + * shm_start - attach to shared memory + */ +static int +shm_start( + int unit, + struct peer *peer + ) +{ + struct refclockproc *pp; + pp = peer->procptr; + pp->io.clock_recv = noentry; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = -1; + pp->unitptr = (caddr_t)getShmTime(unit); + + /* + * Initialize miscellaneous peer variables + */ + memcpy((char *)&pp->refid, REFID, 4); + if (pp->unitptr!=0) { + ((struct shmTime*)pp->unitptr)->precision=PRECISION; + peer->precision = ((struct shmTime*)pp->unitptr)->precision; + ((struct shmTime*)pp->unitptr)->valid=0; + ((struct shmTime*)pp->unitptr)->nsamples=NSAMPLES; + pp->clockdesc = DESCRIPTION; + return (1); + } + else { + return 0; + } +} + + +/* + * shm_shutdown - shut down the clock + */ +static void +shm_shutdown( + int unit, + struct peer *peer + ) +{ + register struct shmTime *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct shmTime *)pp->unitptr; +#ifndef SYS_WINNT + shmdt (up); +#else + UnmapViewOfFile (up); +#endif +} + + +/* + * shm_poll - called by the transmit procedure + */ +static void +shm_poll( + int unit, + struct peer *peer + ) +{ + register struct shmTime *up; + struct refclockproc *pp; + + /* + * This is the main routine. It snatches the time from the shm + * board and tacks on a local timestamp. + */ + pp = peer->procptr; + up = (struct shmTime*)pp->unitptr; + if (up==0) { /* try to map again - this may succeed if meanwhile some- + body has ipcrm'ed the old (unaccessible) shared mem + segment */ + pp->unitptr = (caddr_t)getShmTime(unit); + up = (struct shmTime*)pp->unitptr; + } + if (up==0) { + refclock_report(peer, CEVNT_FAULT); + return; + } + if (up->valid) { + struct timeval tvr; + struct timeval tvt; + struct tm *t; + int ok=1; + switch (up->mode) { + case 0: { + tvr.tv_sec=up->receiveTimeStampSec-172800; + tvr.tv_usec=up->receiveTimeStampUSec; + tvt.tv_sec=up->clockTimeStampSec; + tvt.tv_usec=up->clockTimeStampUSec; + } + break; + case 1: { + int cnt=up->count; + tvr.tv_sec=up->receiveTimeStampSec-172800; + tvr.tv_usec=up->receiveTimeStampUSec; + tvt.tv_sec=up->clockTimeStampSec; + tvt.tv_usec=up->clockTimeStampUSec; + ok=(cnt==up->count); + } + break; + default: + msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",up->mode); + } + /*msyslog(LOG_NOTICE,"poll2a tvr.s %d tvr.u %d tvt.s %d tvt.u %d",tvr.tv_sec,tvr.tv_usec,tvt.tv_sec,tvt.tv_usec);*/ + up->valid=0; + if (ok) { + TVTOTS(&tvr,&pp->lastrec); + /* pp->lasttime = current_time; */ + pp->polls++; + t=gmtime (&tvt.tv_sec); + pp->day=t->tm_yday;/*+2; */ + pp->hour=t->tm_hour; + pp->minute=t->tm_min; + pp->second=t->tm_sec; + pp->usec=tvt.tv_usec; + peer->precision=up->precision; + pp->leap=up->leap; + } + else { + refclock_report(peer, CEVNT_FAULT); + msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); + return; + } + } + else { + refclock_report(peer, CEVNT_TIMEOUT); + msyslog (LOG_NOTICE, "SHM: no new value found in shared memory"); + return; + } + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + refclock_receive(peer); +} + +#else +int refclock_shm_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_tpro.c b/contrib/ntp/ntpd/refclock_tpro.c new file mode 100644 index 000000000000..a29383a222b2 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_tpro.c @@ -0,0 +1,209 @@ +/* + * refclock_tpro - clock driver for the KSI/Odetics TPRO-S IRIG-B reader + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_TPRO) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "sys/tpro.h" +#include "ntp_stdlib.h" + +/* + * This driver supports the KSI/Odetecs TPRO-S IRIG-B reader and TPRO- + * SAT GPS receiver for the Sun Microsystems SBus. It requires that the + * tpro.o device driver be installed and loaded. + */ + +/* + * TPRO interface definitions + */ +#define DEVICE "/dev/tpro%d" /* device name and unit */ +#define PRECISION (-20) /* precision assumed (1 us) */ +#define REFID "IRIG" /* reference ID */ +#define DESCRIPTION "KSI/Odetics TPRO/S IRIG Interface" /* WRU */ + +/* + * Unit control structure + */ +struct tprounit { + struct tproval tprodata; /* data returned from tpro read */ +}; + +/* + * Function prototypes + */ +static int tpro_start P((int, struct peer *)); +static void tpro_shutdown P((int, struct peer *)); +static void tpro_poll P((int unit, struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_tpro = { + tpro_start, /* start up driver */ + tpro_shutdown, /* shut down driver */ + tpro_poll, /* transmit poll message */ + noentry, /* not used (old tpro_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old tpro_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * tpro_start - open the TPRO device and initialize data for processing + */ +static int +tpro_start( + int unit, + struct peer *peer + ) +{ + register struct tprounit *up; + struct refclockproc *pp; + char device[20]; + int fd; + + /* + * Open TPRO device + */ + (void)sprintf(device, DEVICE, unit); + fd = open(device, O_RDONLY | O_NDELAY, 0777); + if (fd == -1) { + msyslog(LOG_ERR, "tpro_start: open of %s: %m", device); + return (0); + } + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct tprounit *) emalloc(sizeof(struct tprounit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct tprounit)); + pp = peer->procptr; + pp->io.clock_recv = noentry; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous peer variables + */ + peer->precision = PRECISION; + peer->burst = NSTAGE; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + return (1); +} + + +/* + * tpro_shutdown - shut down the clock + */ +static void +tpro_shutdown( + int unit, + struct peer *peer + ) +{ + register struct tprounit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct tprounit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * tpro_poll - called by the transmit procedure + */ +static void +tpro_poll( + int unit, + struct peer *peer + ) +{ + register struct tprounit *up; + struct refclockproc *pp; + struct tproval *tp; + + /* + * This is the main routine. It snatches the time from the TPRO + * board and tacks on a local timestamp. + */ + pp = peer->procptr; + up = (struct tprounit *)pp->unitptr; + + tp = &up->tprodata; + if (read(pp->io.fd, (char *)tp, sizeof(struct tproval)) < 0) { + refclock_report(peer, CEVNT_FAULT); + return; + } + get_systime(&pp->lastrec); + pp->polls++; + + /* + * We get down to business, check the timecode format and decode + * its contents. If the timecode has invalid length or is not in + * proper format, we declare bad format and exit. Note: we + * can't use the sec/usec conversion produced by the driver, + * since the year may be suspect. All format error checking is + * done by the sprintf() and sscanf() routines. + */ + sprintf(pp->a_lastcode, + "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x", + tp->day100, tp->day10, tp->day1, tp->hour10, tp->hour1, + tp->min10, tp->min1, tp->sec10, tp->sec1, tp->ms100, + tp->ms10, tp->ms1, tp->usec100, tp->usec10, tp->usec1, + tp->status); + pp->lencode = strlen(pp->a_lastcode); +#ifdef DEBUG + if (debug) + printf("tpro: time %s timecode %d %s\n", + ulfptoa(&pp->lastrec, 6), pp->lencode, + pp->a_lastcode); +#endif + if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", &pp->day, + &pp->hour, &pp->minute, &pp->second, &pp->usec) + != 5) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + if (!tp->status & 0x3) + pp->leap = LEAP_NOTINSYNC; + else + pp->leap = LEAP_NOWARNING; + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + if (peer->burst > 0) + return; + if (pp->coderecv == pp->codeproc) { + refclock_report(peer, CEVNT_TIMEOUT); + return; + } + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + peer->burst = NSTAGE; +} + +#else +int refclock_tpro_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_trak.c b/contrib/ntp/ntpd/refclock_trak.c new file mode 100644 index 000000000000..e7833af7db1f --- /dev/null +++ b/contrib/ntp/ntpd/refclock_trak.c @@ -0,0 +1,361 @@ +/* + * refclock_trak - clock driver for the TRAK 8810 GPS Station Clock + * + * Tomoaki TSURUOKA + * original version Dec, 1993 + * revised version Sep, 1994 for ntp3.4e or later + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_TRAK) + +#include +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" +#include "ntp_unixtime.h" + +#ifdef HAVE_SYS_TERMIOS_H +# include +#endif +#ifdef HAVE_SYS_PPSCLOCK_H +# include +#endif + +/* + * This driver supports the TRAK 8810/8820 GPS Station Clock. The claimed + * accuracy at the 1-pps output is 200-300 ns relative to the broadcast + * signal; however, in most cases the actual accuracy is limited by the + * precision of the timecode and the latencies of the serial interface + * and operating system. + * + * For best accuracy, this radio requires the LDISC_ACTS line + * discipline, which captures a timestamp at the '*' on-time character + * of the timecode. Using this discipline the jitter is in the order of + * 1 ms and systematic error about 0.5 ms. If unavailable, the buffer + * timestamp is used, which is captured at the \r ending the timecode + * message. This introduces a systematic error of 23 character times, or + * about 24 ms at 9600 bps, together with a jitter well over 8 ms on Sun + * IPC-class machines. + * + * Using the memus, the radio should be set for 9600 bps, one stop bit + * and no parity. It should be set to operate in computer (no echo) + * mode. The timecode format includes neither the year nor leap-second + * warning. No provisions are included in this preliminary version of + * the driver to read and record detailed internal radio status. + * + * In operation, this driver sends a RQTS\r request to the radio at + * initialization in order to put it in continuous time output mode. The + * radio then sends the following message once each second: + * + * *RQTS U,ddd:hh:mm:ss.0,q + * + * on-time = '*' * ddd = day of year + * hh:mm:ss = hours, minutes, seconds + * q = quality indicator (phase error), 0-6: + * 0 > 20 us + * 6 > 10 us + * 5 > 1 us + * 4 > 100 ns + * 3 > 10 ns + * 2 < 10 ns + * + * The alarm condition is indicated by '0' at Q, which means the radio + * has a phase error than 20 usec relative to the broadcast time. The + * absence of year, DST and leap-second warning in this format is also + * alarming. + * + * The continuous time mode is disabled using the RQTX request, + * following which the radio sends a RQTX DONE response. In the + * normal mode, other control and status requests are effective, + * including the leap-second status request RQLS. The radio responds + * wtih RQLS yy,mm,dd, where yy,mm,dd are the year, month and + * day. Presumably, this gives the epoch of the next leap second, + * RQLS 00,00,00 if none is specified in the GPS message. Specified in + * this form, the information is generally useless and is ignored by + * the driver. + * + * Fudge Factors + * + * There are no special fudge factors other than the generic. + */ + +/* + * Interface definitions + */ +#define DEVICE "/dev/trak%d" /* device name and unit */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ +#define PRECISION (-20) /* precision assumed (about 1 us) */ +#define REFID "GPS\0" /* reference ID */ +#define DESCRIPTION "TRACK 8810/8820 Station Clock" /* WRU */ + +#define LENTRAK 24 /* timecode length */ +#define C_CTO "RQTS\r" /* start continuous time output */ + +/* + * Unit control structure + */ +struct trakunit { + int polled; /* poll message flag */ + l_fp tstamp; /* timestamp of last poll */ +}; + +/* + * Function prototypes + */ +static int trak_start P((int, struct peer *)); +static void trak_shutdown P((int, struct peer *)); +static void trak_receive P((struct recvbuf *)); +static void trak_poll P((int, struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_trak = { + trak_start, /* start up driver */ + trak_shutdown, /* shut down driver */ + trak_poll, /* transmit poll message */ + noentry, /* not used (old trak_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old trak_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * trak_start - open the devices and initialize data for processing + */ +static int +trak_start( + int unit, + struct peer *peer + ) +{ + register struct trakunit *up; + struct refclockproc *pp; + int fd; + char device[20]; + + /* + * Open serial port. The LDISC_ACTS line discipline inserts a + * timestamp following the "*" on-time character of the + * timecode. + */ + (void)sprintf(device, DEVICE, unit); + if ( +#ifdef PPS + !(fd = refclock_open(device, SPEED232, LDISC_CLK)) +#else + !(fd = refclock_open(device, SPEED232, 0)) +#endif /* PPS */ + ) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct trakunit *) + emalloc(sizeof(struct trakunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct trakunit)); + pp = peer->procptr; + pp->io.clock_recv = trak_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + up->polled = 0; + + /* + * Start continuous time output. If something breaks, fold the + * tent and go home. + */ + if (write(pp->io.fd, C_CTO, sizeof(C_CTO)) != sizeof(C_CTO)) { + refclock_report(peer, CEVNT_FAULT); + (void) close(fd); + free(up); + return (0); + } + return (1); +} + + +/* + * trak_shutdown - shut down the clock + */ +static void +trak_shutdown( + int unit, + struct peer *peer + ) +{ + register struct trakunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct trakunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * trak_receive - receive data from the serial interface + */ +static void +trak_receive( + struct recvbuf *rbufp + ) +{ + register struct trakunit *up; + struct refclockproc *pp; + struct peer *peer; + l_fp trtmp; + char *dpt, *dpend; + char qchar; +#ifdef PPS + struct ppsclockev ppsev; + int request; +#ifdef HAVE_CIOGETEV + request = CIOGETEV; +#endif +#ifdef HAVE_TIOCGPPSEV + request = TIOCGPPSEV; +#endif +#endif /* PPS */ + + /* + * Initialize pointers and read the timecode and timestamp. We + * then chuck out everything, including runts, except one + * message each poll interval. + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct trakunit *)pp->unitptr; + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, + &pp->lastrec); + + /* + * We get a buffer and timestamp following the '*' on-time + * character. If a valid timestamp, we use that in place of the + * buffer timestamp and edit out the timestamp for prettyprint + * billboards. + */ + dpt = pp->a_lastcode; + dpend = dpt + pp->lencode; + if (*dpt == '*' && buftvtots(dpt + 1, &trtmp)) { + if (trtmp.l_i == pp->lastrec.l_i || trtmp.l_i == + pp->lastrec.l_i + 1) { + pp->lastrec = trtmp; + dpt += 9; + while (dpt < dpend) { + *(dpt - 8) = *dpt; + ++dpt; + } + } + } + if (up->polled == 0) return; + up->polled = 0; +#ifndef PPS + get_systime(&up->tstamp); +#endif + record_clock_stats(&peer->srcadr, pp->a_lastcode); +#ifdef DEBUG + if (debug) + printf("trak: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + + /* + * We get down to business, check the timecode format and decode + * its contents. If the timecode has invalid length or is not in + * proper format, we declare bad format and exit. + */ + if (pp->lencode < LENTRAK) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Timecode format: "*RQTS U,ddd:hh:mm:ss.0,q" + */ + if (sscanf(pp->a_lastcode, "*RQTS U,%3d:%2d:%2d:%2d.0,%c", + &pp->day, &pp->hour, &pp->minute, &pp->second, &qchar) != 5) { + refclock_report(peer, CEVNT_BADREPLY); + return; + } + + /* + * Decode quality and leap characters. If unsynchronized, set + * the leap bits accordingly and exit. + */ + if (qchar == '0') { + pp->leap = LEAP_NOTINSYNC; + return; + } +#ifdef PPS + if(ioctl(fdpps,request,(caddr_t) &ppsev) >=0) { + ppsev.tv.tv_sec += (u_int32) JAN_1970; + TVTOTS(&ppsev.tv,&up->tstamp); + } +#endif /* PPS */ + /* record the last ppsclock event time stamp */ + pp->lastrec = up->tstamp; + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + refclock_receive(peer); +} + + +/* + * trak_poll - called by the transmit procedure + */ +static void +trak_poll( + int unit, + struct peer *peer + ) +{ + register struct trakunit *up; + struct refclockproc *pp; + + /* + * We don't really do anything here, except arm the receiving + * side to capture a sample and check for timeouts. + */ + pp = peer->procptr; + up = (struct trakunit *)pp->unitptr; + if (up->polled) + refclock_report(peer, CEVNT_TIMEOUT); + pp->polls++; + up->polled = 1; +} + +#else +int refclock_trak_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_true.c b/contrib/ntp/ntpd/refclock_true.c new file mode 100644 index 000000000000..b841f72589b9 --- /dev/null +++ b/contrib/ntp/ntpd/refclock_true.c @@ -0,0 +1,852 @@ +/* + * refclock_true - clock driver for the Kinemetrics Truetime receivers + * Receiver Version 3.0C - tested plain, with CLKLDISC + * Developement work being done: + * - Properly handle varying satellite positions (more acurately) + * - Integrate GPSTM and/or OMEGA and/or TRAK and/or ??? drivers + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_TRUETIME) + +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_unixtime.h" +#include "ntp_stdlib.h" + +/* This should be an atom clock but those are very hard to build. + * + * The PCL720 from P C Labs has an Intel 8253 lookalike, as well as a bunch + * of TTL input and output pins, all brought out to the back panel. If you + * wire a PPS signal (such as the TTL PPS coming out of a GOES or other + * Kinemetrics/Truetime clock) to the 8253's GATE0, and then also wire the + * 8253's OUT0 to the PCL720's INPUT3.BIT0, then we can read CTR0 to get the + * number of uSecs since the last PPS upward swing, mediated by reading OUT0 + * to find out if the counter has wrapped around (this happens if more than + * 65535us (65ms) elapses between the PPS event and our being called.) + */ +#ifdef CLOCK_PPS720 +# undef min /* XXX */ +# undef max /* XXX */ +# include +# include +# include +# define PCL720_IOB 0x2a0 /* XXX */ +# define PCL720_CTR 0 /* XXX */ +#endif + +/* + * Support for Kinemetrics Truetime Receivers + * GOES + * GPS/TM-TMD + * XL-DC (a 151-602-210, reported by the driver as a GPS/TM-TMD) + * GPS-800 TCU (an 805-957 with the RS232 Talker/Listener module) + * OM-DC: getting stale ("OMEGA") + * + * Most of this code is originally from refclock_wwvb.c with thanks. + * It has been so mangled that wwvb is not a recognizable ancestor. + * + * Timcode format: ADDD:HH:MM:SSQCL + * A - control A (this is stripped before we see it) + * Q - Quality indication (see below) + * C - Carriage return + * L - Line feed + * + * Quality codes indicate possible error of + * 468-DC GOES Receiver: + * GPS-TM/TMD Receiver: + * ? +/- 500 milliseconds # +/- 50 milliseconds + * * +/- 5 milliseconds . +/- 1 millisecond + * space less than 1 millisecond + * OM-DC OMEGA Receiver: + * > >+- 5 seconds + * ? >+/- 500 milliseconds # >+/- 50 milliseconds + * * >+/- 5 milliseconds . >+/- 1 millisecond + * A-H less than 1 millisecond. Character indicates which station + * is being received as follows: + * A = Norway, B = Liberia, C = Hawaii, D = North Dakota, + * E = La Reunion, F = Argentina, G = Australia, H = Japan. + * + * The carriage return start bit begins on 0 seconds and extends to 1 bit time. + * + * Notes on 468-DC and OMEGA receiver: + * + * Send the clock a 'R' or 'C' and once per second a timestamp will + * appear. Send a 'P' to get the satellite position once (GOES only.) + * + * Notes on the 468-DC receiver: + * + * Since the old east/west satellite locations are only historical, you can't + * set your clock propagation delay settings correctly and still use + * automatic mode. The manual says to use a compromise when setting the + * switches. This results in significant errors. The solution; use fudge + * time1 and time2 to incorporate corrections. If your clock is set for + * 50 and it should be 58 for using the west and 46 for using the east, + * use the line + * + * fudge 127.127.5.0 time1 +0.008 time2 -0.004 + * + * This corrects the 4 milliseconds advance and 8 milliseconds retard + * needed. The software will ask the clock which satellite it sees. + * + * Ntp.conf parameters: + * time1 - offset applied to samples when reading WEST satellite (default = 0) + * time2 - offset applied to samples when reading EAST satellite (default = 0) + * val1 - stratum to assign to this clock (default = 0) + * val2 - refid assigned to this clock (default = "TRUE", see below) + * flag1 - will silence the clock side of ntpd, just reading the clock + * without trying to write to it. (default = 0) + * flag2 - generate a debug file /tmp/true%d. + * flag3 - enable ppsclock streams module + * flag4 - use the PCL-720 (BSD/OS only) + */ + +/* + * Definitions + */ +#define DEVICE "/dev/true%d" +#define SPEED232 B9600 /* 9600 baud */ + +/* + * Radio interface parameters + */ +#define PRECISION (-10) /* precision assumed (about 1 ms) */ +#define REFID "TRUE" /* reference id */ +#define DESCRIPTION "Kinemetrics/TrueTime Receiver" + +/* + * Tags which station (satellite) we see + */ +#define GOES_WEST 0 /* Default to WEST satellite and apply time1 */ +#define GOES_EAST 1 /* until you discover otherwise */ + +/* + * used by the state machine + */ +enum true_event {e_Init, e_Huh, e_F18, e_F50, e_F51, e_Satellite, + e_Poll, e_Location, e_TS, e_Max}; +const char *events[] = {"Init", "Huh", "F18", "F50", "F51", "Satellite", + "Poll", "Location", "TS"}; +#define eventStr(x) (((int)x<(int)e_Max) ? events[(int)x] : "?") + +enum true_state {s_Base, s_InqTM, s_InqTCU, s_InqOmega, s_InqGOES, + s_Init, s_F18, s_F50, s_Start, s_Auto, s_Max}; +const char *states[] = {"Base", "InqTM", "InqTCU", "InqOmega", "InqGOES", + "Init", "F18", "F50", "Start", "Auto"}; +#define stateStr(x) (((int)x<(int)s_Max) ? states[(int)x] : "?") + +enum true_type {t_unknown, t_goes, t_tm, t_tcu, t_omega, t_Max}; +const char *types[] = {"unknown", "goes", "tm", "tcu", "omega"}; +#define typeStr(x) (((int)x<(int)t_Max) ? types[(int)x] : "?") + +/* + * unit control structure + */ +struct true_unit { + unsigned int pollcnt; /* poll message counter */ + unsigned int station; /* which station we are on */ + unsigned int polled; /* Hand in a time sample? */ + enum true_state state; /* state machine */ + enum true_type type; /* what kind of clock is it? */ + int unit; /* save an extra copy of this */ + FILE *debug; /* debug logging file */ +#ifdef CLOCK_PPS720 + int pcl720init; /* init flag for PCL 720 */ +#endif +}; + +/* + * Function prototypes + */ +static int true_start P((int, struct peer *)); +static void true_shutdown P((int, struct peer *)); +static void true_receive P((struct recvbuf *)); +static void true_poll P((int, struct peer *)); +static void true_send P((struct peer *, const char *)); +static void true_doevent P((struct peer *, enum true_event)); + +#ifdef CLOCK_PPS720 +static u_long true_sample720 P((void)); +#endif + +/* + * Transfer vector + */ +struct refclock refclock_true = { + true_start, /* start up driver */ + true_shutdown, /* shut down driver */ + true_poll, /* transmit poll message */ + noentry, /* not used (old true_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old true_buginfo) */ + NOFLAGS /* not used */ +}; + + +#if !defined(__STDC__) +# define true_debug (void) +#else +static void +true_debug(struct peer *peer, const char *fmt, ...) +{ + va_list ap; + int want_debugging, now_debugging; + struct refclockproc *pp; + struct true_unit *up; + + va_start(ap, fmt); + pp = peer->procptr; + up = (struct true_unit *)pp->unitptr; + + want_debugging = (pp->sloppyclockflag & CLK_FLAG2) != 0; + now_debugging = (up->debug != NULL); + if (want_debugging != now_debugging) + { + if (want_debugging) { + char filename[20]; + + sprintf(filename, "/tmp/true%d.debug", up->unit); + up->debug = fopen(filename, "w"); + if (up->debug) { +#ifdef HAVE_SETVBUF + static char buf[BUFSIZ]; + setvbuf(up->debug, buf, _IOLBF, BUFSIZ); +#else + setlinebuf(up->debug); +#endif + } + } else { + fclose(up->debug); + up->debug = NULL; + } + } + + if (up->debug) { + fprintf(up->debug, "true%d: ", up->unit); + vfprintf(up->debug, fmt, ap); + } +} +#endif /*STDC*/ + +/* + * true_start - open the devices and initialize data for processing + */ +static int +true_start( + int unit, + struct peer *peer + ) +{ + register struct true_unit *up; + struct refclockproc *pp; + char device[20]; + int fd; + + /* + * Open serial port + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct true_unit *) + emalloc(sizeof(struct true_unit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct true_unit)); + pp = peer->procptr; + pp->io.clock_recv = true_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + pp->unitptr = (caddr_t)up; + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + up->pollcnt = 2; + up->type = t_unknown; + up->state = s_Base; + true_doevent(peer, e_Init); + return (1); +} + +/* + * true_shutdown - shut down the clock + */ +static void +true_shutdown( + int unit, + struct peer *peer + ) +{ + register struct true_unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct true_unit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * true_receive - receive data from the serial interface on a clock + */ +static void +true_receive( + struct recvbuf *rbufp + ) +{ + register struct true_unit *up; + struct refclockproc *pp; + struct peer *peer; + u_short new_station; + char synced; + int i; + int lat, lon, off; /* GOES Satellite position */ + + /* + * Get the clock this applies to and pointers to the data. + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct true_unit *)pp->unitptr; + + /* + * Read clock output. Automatically handles STREAMS, CLKLDISC. + */ + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); + + /* + * There is a case where generates 2 timestamps. + */ + if (pp->lencode == 0) + return; + pp->a_lastcode[pp->lencode] = '\0'; + true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode, pp->lencode); + + up->pollcnt = 2; + record_clock_stats(&peer->srcadr, pp->a_lastcode); + + /* + * We get down to business, check the timecode format and decode + * its contents. This code decodes a multitude of different + * clock messages. Timecodes are processed if needed. All replies + * will be run through the state machine to tweak driver options + * and program the clock. + */ + + /* + * Clock misunderstood our last command? + */ + if (pp->a_lastcode[0] == '?') { + true_doevent(peer, e_Huh); + return; + } + + /* + * Timecode: "nnnnn+nnn-nnn" + * (from GOES clock when asked about satellite position) + */ + if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') && + (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') && + sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3 + ) { + const char *label = "Botch!"; + + /* + * This is less than perfect. Call the (satellite) + * either EAST or WEST and adjust slop accodingly + * Perfectionists would recalculate the exact delay + * and adjust accordingly... + */ + if (lon > 7000 && lon < 14000) { + if (lon < 10000) { + new_station = GOES_EAST; + label = "EAST"; + } else { + new_station = GOES_WEST; + label = "WEST"; + } + + if (new_station != up->station) { + double dtemp; + + dtemp = pp->fudgetime1; + pp->fudgetime1 = pp->fudgetime2; + pp->fudgetime2 = dtemp; + up->station = new_station; + } + } + else { + refclock_report(peer, CEVNT_BADREPLY); + label = "UNKNOWN"; + } + true_debug(peer, "GOES: station %s\n", label); + true_doevent(peer, e_Satellite); + return; + } + + /* + * Timecode: "Fnn" + * (from TM/TMD clock when it wants to tell us what it's up to.) + */ + if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) { + switch (i) { + case 50: + true_doevent(peer, e_F50); + break; + case 51: + true_doevent(peer, e_F51); + break; + default: + true_debug(peer, "got F%02d - ignoring\n", i); + break; + } + return; + } + + /* + * Timecode: " TRUETIME Mk III" + * (from a TM/TMD clock during initialization.) + */ + if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0) { + true_doevent(peer, e_F18); + NLOG(NLOG_CLOCKSTATUS) { + msyslog(LOG_INFO, "TM/TMD: %s", pp->a_lastcode); + } + return; + } + + /* + * Timecode: "N03726428W12209421+000033" + * 1 2 + * 0123456789012345678901234 + * (from a TCU during initialization) + */ + if ((pp->a_lastcode[0] == 'N' || pp->a_lastcode[0] == 'S') && + (pp->a_lastcode[9] == 'W' || pp->a_lastcode[9] == 'E') && + pp->a_lastcode[18] == '+') { + true_doevent(peer, e_Location); + NLOG(NLOG_CLOCKSTATUS) { + msyslog(LOG_INFO, "TCU-800: %s", pp->a_lastcode); + } + return; + } + /* + * Timecode: "ddd:hh:mm:ssQ" + * (from all clocks supported by this driver.) + */ + if (pp->a_lastcode[3] == ':' && + pp->a_lastcode[6] == ':' && + pp->a_lastcode[9] == ':' && + sscanf(pp->a_lastcode, "%3d:%2d:%2d:%2d%c", + &pp->day, &pp->hour, &pp->minute, + &pp->second, &synced) == 5) { + + /* + * Adjust the synchronize indicator according to timecode + */ + if (synced != ' ' && synced != '.' && synced != '*') + pp->leap = LEAP_NOTINSYNC; + + true_doevent(peer, e_TS); + +#ifdef CLOCK_PPS720 + /* If it's taken more than 65ms to get here, we'll lose. */ + if ((pp->sloppyclockflag & CLK_FLAG4) && up->pcl720init) { + l_fp off; + +#ifdef CLOCK_ATOM + /* + * find out what time it really is. Include + * the count from the PCL720 + */ + if (!clocktime(pp->day, pp->hour, pp->minute, + pp->second, GMT, pp->lastrec.l_ui, + &pp->yearstart, &off.l_ui)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } +#endif + + pp->usec = true_sample720(); +#ifdef CLOCK_ATOM + TVUTOTSF(pp->usec, off.l_uf); +#endif + + /* + * Stomp all over the timestamp that was pulled out + * of the input stream. It's irrelevant since we've + * adjusted the input time to reflect now (via pp->usec) + * rather than when the data was collected. + */ + get_systime(&pp->lastrec); +#ifdef CLOCK_ATOM + /* + * Create a true offset for feeding to pps_sample() + */ + L_SUB(&off, &pp->lastrec); + + pps_sample(peer, &off); +#endif + true_debug(peer, "true_sample720: %luus\n", pp->usec); + } +#endif + + /* + * The clock will blurt a timecode every second but we only + * want one when polled. If we havn't been polled, bail out. + */ + if (!up->polled) + return; + + true_doevent(peer, e_Poll); + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); + return; + } + refclock_receive(peer); + + /* + * We have succedded in answering the poll. + * Turn off the flag and return + */ + up->polled = 0; + + return; + } + + /* + * No match to known timecodes, report failure and return + */ + refclock_report(peer, CEVNT_BADREPLY); + return; +} + + +/* + * true_send - time to send the clock a signal to cough up a time sample + */ +static void +true_send( + struct peer *peer, + const char *cmd + ) +{ + struct refclockproc *pp; + + pp = peer->procptr; + if (!(pp->sloppyclockflag & CLK_FLAG1)) { + register int len = strlen(cmd); + + true_debug(peer, "Send '%s'\n", cmd); + if (write(pp->io.fd, cmd, (unsigned)len) != len) + refclock_report(peer, CEVNT_FAULT); + else + pp->polls++; + } +} + + +/* + * state machine for initializing and controlling a clock + */ +static void +true_doevent( + struct peer *peer, + enum true_event event + ) +{ + struct true_unit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct true_unit *)pp->unitptr; + if (event != e_TS) { + NLOG(NLOG_CLOCKSTATUS) { + msyslog(LOG_INFO, "TRUE: clock %s, state %s, event %s", + typeStr(up->type), + stateStr(up->state), + eventStr(event)); + } + } + true_debug(peer, "clock %s, state %s, event %s\n", + typeStr(up->type), stateStr(up->state), eventStr(event)); + switch (up->type) { + case t_goes: + switch (event) { + case e_Init: /* FALLTHROUGH */ + case e_Satellite: + /* + * Switch back to on-second time codes and return. + */ + true_send(peer, "C"); + up->state = s_Start; + break; + case e_Poll: + /* + * After each poll, check the station (satellite). + */ + true_send(peer, "P"); + /* No state change needed. */ + break; + default: + break; + } + /* FALLTHROUGH */ + case t_omega: + switch (event) { + case e_Init: + true_send(peer, "C"); + up->state = s_Start; + break; + case e_TS: + if (up->state != s_Start && up->state != s_Auto) { + true_send(peer, "\03\r"); + break; + } + up->state = s_Auto; + break; + default: + break; + } + break; + case t_tm: + switch (event) { + case e_Init: + true_send(peer, "F18\r"); + up->state = s_Init; + break; + case e_F18: + true_send(peer, "F50\r"); + up->state = s_F18; + break; + case e_F50: + true_send(peer, "F51\r"); + up->state = s_F50; + break; + case e_F51: + true_send(peer, "F08\r"); + up->state = s_Start; + break; + case e_TS: + if (up->state != s_Start && up->state != s_Auto) { + true_send(peer, "\03\r"); + break; + } + up->state = s_Auto; + break; + default: + break; + } + break; + case t_tcu: + switch (event) { + case e_Init: + true_send(peer, "MD3\r"); /* GPS Synch'd Gen. */ + true_send(peer, "TSU\r"); /* UTC, not GPS. */ + true_send(peer, "AU\r"); /* Auto Timestamps. */ + up->state = s_Start; + break; + case e_TS: + if (up->state != s_Start && up->state != s_Auto) { + true_send(peer, "\03\r"); + break; + } + up->state = s_Auto; + break; + default: + break; + } + break; + case t_unknown: + switch (up->state) { + case s_Base: + if (event != e_Init) + abort(); + true_send(peer, "P\r"); + up->state = s_InqGOES; + break; + case s_InqGOES: + switch (event) { + case e_Satellite: + up->type = t_goes; + true_doevent(peer, e_Init); + break; + case e_Init: /*FALLTHROUGH*/ + case e_Huh: /*FALLTHROUGH*/ + case e_TS: + up->state = s_InqOmega; + true_send(peer, "C\r"); + break; + default: + abort(); + } + break; + case s_InqOmega: + switch (event) { + case e_TS: + up->type = t_omega; + up->state = s_Auto; /* Inq side-effect. */ + break; + case e_Init: /*FALLTHROUGH*/ + case e_Huh: + up->state = s_InqTM; + true_send(peer, "F18\r"); + break; + default: + abort(); + } + break; + case s_InqTM: + switch (event) { + case e_F18: + up->type = t_tm; + true_doevent(peer, e_Init); + break; + case e_Init: /*FALLTHROUGH*/ + case e_Huh: + true_send(peer, "PO\r"); + up->state = s_InqTCU; + break; + default: + abort(); + } + break; + case s_InqTCU: + switch (event) { + case e_Location: + up->type = t_tcu; + true_doevent(peer, e_Init); + break; + case e_Init: /*FALLTHROUGH*/ + case e_Huh: + up->state = s_Base; + sleep(1); /* XXX */ + break; + default: + abort(); + } + break; + /* + * An expedient hack to prevent lint complaints, + * these don't actually need to be used here... + */ + case s_Init: + case s_F18: + case s_F50: + case s_Start: + case s_Auto: + case s_Max: + msyslog(LOG_INFO, "TRUE: state %s is unexpected!", stateStr(up->state)); + } + break; + default: + abort(); + /* NOTREACHED */ + } + +#ifdef CLOCK_PPS720 + if ((pp->sloppyclockflag & CLK_FLAG4) && !up->pcl720init) { + /* Make counter trigger on gate0, count down from 65535. */ + pcl720_load(PCL720_IOB, PCL720_CTR, i8253_oneshot, 65535); + /* + * (These constants are OK since + * they represent hardware maximums.) + */ + NLOG(NLOG_CLOCKINFO) { + msyslog(LOG_NOTICE, "PCL-720 initialized"); + } + up->pcl720init++; + } +#endif + + +} + +/* + * true_poll - called by the transmit procedure + */ +static void +true_poll( + int unit, + struct peer *peer + ) +{ + struct true_unit *up; + struct refclockproc *pp; + + /* + * You don't need to poll this clock. It puts out timecodes + * once per second. If asked for a timestamp, take note. + * The next time a timecode comes in, it will be fed back. + */ + pp = peer->procptr; + up = (struct true_unit *)pp->unitptr; + if (up->pollcnt > 0) + up->pollcnt--; + else { + true_doevent(peer, e_Init); + refclock_report(peer, CEVNT_TIMEOUT); + } + + /* + * polled every 64 seconds. Ask true_receive to hand in a + * timestamp. + */ + up->polled = 1; + pp->polls++; +} + +#ifdef CLOCK_PPS720 +/* + * true_sample720 - sample the PCL-720 + */ +static u_long +true_sample720(void) +{ + unsigned long f; + + /* We wire the PCL-720's 8253.OUT0 to bit 0 of connector 3. + * If it is not being held low now, we did not get called + * within 65535us. + */ + if (inb(pcl720_data_16_23(PCL720_IOB)) & 0x01) { + NLOG(NLOG_CLOCKINFO) { + msyslog(LOG_NOTICE, "PCL-720 out of synch"); + } + return (0); + } + f = (65536 - pcl720_read(PCL720_IOB, PCL720_CTR)); +#ifdef PPS720_DEBUG + msyslog(LOG_DEBUG, "PCL-720: %luus", f); +#endif + return (f); +} +#endif + +#else +int refclock_true_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_ulink.c b/contrib/ntp/ntpd/refclock_ulink.c new file mode 100644 index 000000000000..347040dea64e --- /dev/null +++ b/contrib/ntp/ntpd/refclock_ulink.c @@ -0,0 +1,319 @@ +/* + * refclock_ulink - clock driver for Ultralink Model 320 WWVB receivers + * By Dave Strout + * + * Latest version is always on www.linuxfoundary.com + * + * Based on the Spectracom driver + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_ULINK) + +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * This driver supports the Ultralink Model 320 WWVB receiver. The Model 320 is + * an RS-232 powered unit which consists of two parts: a DB-25 shell that contains + * a microprocessor, and an approx 2"x4" plastic box that contains the antenna. + * The two are connected by a 6-wire RJ-25 cable of length up to 1000'. The + * microprocessor steals power from the RS-232 port, which means that the port must + * be kept open all of the time. The unit also has an internal clock for loss of signal + * periods. Claimed accuracy is 0.1 sec. + * + * The timecode format is: + * + * SQRYYYYDDD+HH:MM:SS.mmLT + * + * where: + * + * S = 'S' -- sync'd in last hour, '0'-'9' - hours x 10 since last update, else '?' + * Q = Number of correlating time-frames, from 0 to 5 + * R = 'R' -- reception in progress, 'N' -- Noisy reception, ' ' -- standby mode + * YYYY = year from 1990 to 2089 + * DDD = current day from 1 to 366 + * + = '+' if current year is a leap year, else ' ' + * HH = UTC hour 0 to 23 + * MM = Minutes of current hour from 0 to 59 + * SS = Seconds of current minute from 0 to 59 + * mm = 10's milliseconds of the current second from 00 to 99 + * L = Leap second pending at end of month -- 'I' = inset, 'D'=delete + * T = DST <-> STD transition indicators + * + * Note that this driver does not do anything with the L or T flags. + * + * The M320 also has a 'U' command which returns UT1 correction information. It + * is not used in this driver. + * + */ + +/* + * Interface definitions + */ +#define DEVICE "/dev/ulink%d" /* device name and unit */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ +#define PRECISION (-13) /* precision assumed (about 100 us) */ +#define REFID "M320" /* reference ID */ +#define DESCRIPTION "Ultralink WWVB Receiver" /* WRU */ + +#define LENWWVB0 28 /* format 0 timecode length */ +#define LENWWVB2 24 /* format 2 timecode length */ +#define LENWWVB3 29 /* format 3 timecode length */ + +#define MONLIN 15 /* number of monitoring lines */ + +/* + * ULINK unit control structure + */ +struct ulinkunit { + u_char tcswitch; /* timecode switch */ + l_fp laststamp; /* last receive timestamp */ + u_char lasthour; /* last hour (for monitor) */ + u_char linect; /* count ignored lines (for monitor */ +}; + +/* + * Function prototypes + */ +static int ulink_start P((int, struct peer *)); +static void ulink_shutdown P((int, struct peer *)); +static void ulink_receive P((struct recvbuf *)); +static void ulink_poll P((int, struct peer *)); +static int fd; /* We need to keep the serial port open to power the ULM320 */ + +/* + * Transfer vector + */ +struct refclock refclock_ulink = { + ulink_start, /* start up driver */ + ulink_shutdown, /* shut down driver */ + ulink_poll, /* transmit poll message */ + noentry, /* not used (old wwvb_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old wwvb_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * ulink_start - open the devices and initialize data for processing + */ +static int +ulink_start( + int unit, + struct peer *peer + ) +{ + register struct ulinkunit *up; + struct refclockproc *pp; + char device[20]; + fprintf(stderr, "Starting Ulink driver\n"); + /* + * Open serial port. Use CLK line discipline, if available. + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct ulinkunit *) + emalloc(sizeof(struct ulinkunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct ulinkunit)); + pp = peer->procptr; + pp->unitptr = (caddr_t)up; + pp->io.clock_recv = ulink_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + peer->flags |= FLAG_BURST; + peer->burst = NSTAGE; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + return (1); +} + + +/* + * ulink_shutdown - shut down the clock + */ +static void +ulink_shutdown( + int unit, + struct peer *peer + ) +{ + register struct ulinkunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct ulinkunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); + close(fd); +} + + +/* + * ulink_receive - receive data from the serial interface + */ +static void +ulink_receive( + struct recvbuf *rbufp + ) +{ + struct ulinkunit *up; + struct refclockproc *pp; + struct peer *peer; + + l_fp trtmp; /* arrival timestamp */ + char syncchar; /* synchronization indicator */ + char qualchar; /* quality indicator */ + char modechar; /* Modes: 'R'=rx, 'N'=noise, ' '=standby */ + char leapchar; /* leap indicator */ + int temp; /* int temp */ + + /* + * Initialize pointers and read the timecode and timestamp + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct ulinkunit *)pp->unitptr; + temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); + + /* + * Note we get a buffer and timestamp for both a and , + * but only the timestamp is retained. Note: in format 0 on + * a Netclock/2 or upgraded 8170 the start bit is delayed 100 + * +-50 us relative to the pps; however, on an unmodified 8170 + * the start bit can be delayed up to 10 ms. In format 2 the + * reading precision is only to the millisecond. Thus, unless + * you have a pps gadget and don't have to have the year, format + * 0 provides the lowest jitter. + */ + if (temp == 0) { + if (up->tcswitch == 0) { + up->tcswitch = 1; + up->laststamp = trtmp; + } else + up->tcswitch = 0; + return; + } + pp->lencode = temp; + pp->lastrec = up->laststamp; + up->laststamp = trtmp; + up->tcswitch = 1; +#ifdef DEBUG + if (debug) + printf("ulink: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + + /* + * We get down to business, check the timecode format and decode + * its contents. 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. + */ + syncchar = qualchar = leapchar = ' '; + pp->msec = 0; + + /* + * Timecode format SQRYYYYDDD+HH:MM:SS.mmLT + */ + sscanf(pp->a_lastcode, "%c%c%c%4d%3d%c%2d:%2d:%2d.%2d", + &syncchar, &qualchar, &modechar, &pp->year, &pp->day, + &leapchar,&pp->hour, &pp->minute, &pp->second,&pp->msec); + + pp->msec *= 10; /* M320 returns 10's of msecs */ + qualchar = ' '; + + /* + * Decode synchronization, quality and leap characters. If + * unsynchronized, set the leap bits accordingly and exit. + * Otherwise, set the leap bits according to the leap character. + * Once synchronized, the dispersion depends only on the + * quality character. + */ + pp->disp = .001; + pp->leap = LEAP_NOWARNING; + + /* + * Process the new sample in the median filter and determine the + * timecode timestamp. + */ + if (!refclock_process(pp)) + refclock_report(peer, CEVNT_BADTIME); +} + + +/* + * ulink_poll - called by the transmit procedure + */ +static void +ulink_poll( + int unit, + struct peer *peer + ) +{ + register struct ulinkunit *up; + struct refclockproc *pp; + char pollchar; + + pp = peer->procptr; + up = (struct ulinkunit *)pp->unitptr; + pollchar = 'T'; + if (write(pp->io.fd, &pollchar, 1) != 1) + refclock_report(peer, CEVNT_FAULT); + else + pp->polls++; + if (peer->burst > 0) + return; + if (pp->coderecv == pp->codeproc) { + refclock_report(peer, CEVNT_TIMEOUT); + return; + } + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + peer->burst = NSTAGE; + + /* + * If the monitor flag is set (flag4), we dump the internal + * quality table at the first timecode beginning the day. + */ + if (pp->sloppyclockflag & CLK_FLAG4 && pp->hour < + (int)up->lasthour) + up->linect = MONLIN; + up->lasthour = pp->hour; +} + +#else +int refclock_ulink_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_usno.c b/contrib/ntp/ntpd/refclock_usno.c new file mode 100644 index 000000000000..cf404e74d28d --- /dev/null +++ b/contrib/ntp/ntpd/refclock_usno.c @@ -0,0 +1,674 @@ +/* + * refclock_usno - clock driver for the Naval Observatory dialup + * Michael Shields 1995/02/25 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_USNO) + +#include +#include +#include +#ifdef HAVE_SYS_IOCTL_H +# include +#endif /* HAVE_SYS_IOCTL_H */ + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" +#include "ntp_control.h" + +/* + * This driver supports the Naval Observatory dialup at +1 202 653 0351. + * It is a hacked-up version of the ACTS driver. + * + * This driver does not support the `phone' configuration because that + * is needlessly global; it would clash with the ACTS driver. + * + * The Naval Observatory does not support the echo-delay measurement scheme. + * + * However, this driver *does* support UUCP port locking, allowing the + * line to be shared with other processes when not actually dialing + * for time. + */ + +/* + * Interface definitions + */ + +#define DEVICE "/dev/cua%d" /* device name and unit */ +#define LOCKFILE "/var/lock/LCK..cua%d" +/* #define LOCKFILE "/usr/spool/uucp/LCK..cua%d" */ + +#define PHONE "atdt 202 653 0351" +/* #define PHONE "atdt 1 202 653 0351" */ + +#define SPEED232 B1200 /* uart speed (1200 cowardly baud) */ +#define PRECISION (-10) /* precision assumed (about 1 ms) */ +#define REFID "USNO" /* reference ID */ +#define DESCRIPTION "Naval Observatory dialup" + +#define MODE_AUTO 0 /* automatic mode */ +#define MODE_BACKUP 1 /* backup mode */ +#define MODE_MANUAL 2 /* manual mode */ + +#define MSGCNT 10 /* we need this many time messages */ +#define SMAX 80 /* max token string length */ +#define LENCODE 20 /* length of valid timecode string */ +#define USNO_MINPOLL 10 /* log2 min poll interval (1024 s) */ +#define USNO_MAXPOLL 14 /* log2 max poll interval (16384 s) */ +#define MAXOUTAGE 3600 /* max before USNO kicks in (s) */ + +/* + * Modem control strings. These may have to be changed for some modems. + * + * AT command prefix + * B1 initiate call negotiation using Bell 212A + * &C1 enable carrier detect + * &D2 hang up and return to command mode on DTR transition + * E0 modem command echo disabled + * l1 set modem speaker volume to low level + * M1 speaker enabled untill carrier detect + * Q0 return result codes + * V1 return result codes as English words + */ +#define MODEM_SETUP "ATB1&C1&D2E0L1M1Q0V1" /* modem setup */ +#define MODEM_HANGUP "ATH" /* modem disconnect */ + +/* + * Timeouts + */ +#define IDLE 60 /* idle timeout (s) */ +#define WAIT 2 /* wait timeout (s) */ +#define ANSWER 30 /* answer timeout (s) */ +#define CONNECT 10 /* connect timeout (s) */ +#define TIMECODE (MSGCNT+16) /* timecode timeout (s) */ + +/* + * Unit control structure + */ +struct usnounit { + int pollcnt; /* poll message counter */ + + int state; /* the first one was Delaware */ + int run; /* call program run switch */ + int msgcnt; /* count of time messages received */ + long redial; /* interval to next automatic call */ + int unit; /* unit number (= port) */ +}; + +/* + * Function prototypes + */ +static int usno_start P((int, struct peer *)); +static void usno_shutdown P((int, struct peer *)); +static void usno_poll P((int, struct peer *)); +static void usno_disc P((struct peer *)); +#if 0 +static void usno_timeout P((struct peer *)); +static void usno_receive P((struct recvbuf *)); +static int usno_write P((struct peer *, const char *)); +#endif /* 0 */ + +/* + * Transfer vector + */ +struct refclock refclock_usno = { + usno_start, /* start up driver */ + usno_shutdown, /* shut down driver */ + usno_poll, /* transmit poll message */ + noentry, /* not used (usno_control) */ + noentry, /* not used (usno_init) */ + noentry, /* not used (usno_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * usno_start - open the devices and initialize data for processing + */ +static int +usno_start( + int unit, + struct peer *peer + ) +{ + register struct usnounit *up; + struct refclockproc *pp; + + /* + * Initialize miscellaneous variables + */ + pp = peer->procptr; + peer->precision = PRECISION; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + peer->minpoll = USNO_MINPOLL; + peer->maxpoll = USNO_MAXPOLL; + peer->sstclktype = CTL_SST_TS_TELEPHONE; + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct usnounit *) + emalloc(sizeof(struct usnounit)))) + return (0); + memset((char *)up, 0, sizeof(struct usnounit)); + up->unit = unit; + pp->unitptr = (caddr_t)up; + + /* + * Set up the driver timeout + */ + peer->nextdate = current_time + WAIT; + return (1); +} + + +/* + * usno_shutdown - shut down the clock + */ +static void +usno_shutdown( + int unit, + struct peer *peer + ) +{ + register struct usnounit *up; + struct refclockproc *pp; + +#ifdef DEBUG + if (debug) + printf("usno: clock %s shutting down\n", ntoa(&peer->srcadr)); +#endif + pp = peer->procptr; + up = (struct usnounit *)pp->unitptr; + usno_disc(peer); + free(up); +} + + +#if 0 +/* + * usno_receive - receive data from the serial interface + */ +static void +usno_receive( + struct recvbuf *rbufp + ) +{ + register struct usnounit *up; + struct refclockproc *pp; + struct peer *peer; + char str[SMAX]; + u_long mjd; /* Modified Julian Day */ + static int day, hour, minute, second; + + /* + * Initialize pointers and read the timecode and timestamp. If + * the OK modem status code, leave it where folks can find it. + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct usnounit *)pp->unitptr; + pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, + &pp->lastrec); + if (pp->lencode == 0) { + if (strcmp(pp->a_lastcode, "OK") == 0) + pp->lencode = 2; + return; + } +#ifdef DEBUG + if (debug) + printf("usno: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + + switch (up->state) { + + case 0: + + /* + * State 0. We are not expecting anything. Probably + * modem disconnect noise. Go back to sleep. + */ + return; + + case 1: + + /* + * State 1. We are about to dial. Just drop it. + */ + return; + + case 2: + + /* + * State 2. We are waiting for the call to be answered. + * All we care about here is CONNECT as the first token + * in the string. If the modem signals BUSY, ERROR, NO + * ANSWER, NO CARRIER or NO DIALTONE, we immediately + * hang up the phone. If CONNECT doesn't happen after + * ANSWER seconds, hang up the phone. If everything is + * okay, start the connect timeout and slide into state + * 3. + */ + (void)strncpy(str, strtok(pp->a_lastcode, " "), SMAX); + if (strcmp(str, "BUSY") == 0 || strcmp(str, "ERROR") == + 0 || strcmp(str, "NO") == 0) { + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, + "clock %s USNO modem status %s", + ntoa(&peer->srcadr), pp->a_lastcode); + usno_disc(peer); + } else if (strcmp(str, "CONNECT") == 0) { + peer->nextdate = current_time + CONNECT; + up->msgcnt = 0; + up->state++; + } else { + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_WARNING, + "clock %s USNO unknown modem status %s", + ntoa(&peer->srcadr), pp->a_lastcode); + } + return; + + case 3: + + /* + * State 3. The call has been answered and we are + * waiting for the first message. If this doesn't + * happen within the timecode timeout, hang up the + * phone. We probably got a wrong number or they are + * down. + */ + peer->nextdate = current_time + TIMECODE; + up->state++; + return; + + case 4: + + /* + * State 4. We are reading a timecode. It's an actual + * timecode, or it's the `*' OTM. + * + * jjjjj nnn hhmmss UTC + */ + if (pp->lencode == LENCODE) { + if (sscanf(pp->a_lastcode, "%5ld %3d %2d%2d%2d UTC", + &mjd, &day, &hour, &minute, &second) != 5) { +#ifdef DEBUG + if (debug) + printf("usno: bad timecode format\n"); +#endif + refclock_report(peer, CEVNT_BADREPLY); + } else + up->msgcnt++; + return; + } else if (pp->lencode != 1 || !up->msgcnt) + return; + /* else, OTM; drop out of switch */ + } + + pp->leap = LEAP_NOWARNING; + pp->day = day; + pp->hour = hour; + pp->minute = minute; + pp->second = second; + + /* + * Colossal hack here. We process each sample in a trimmed-mean + * filter and determine the reference clock offset and + * dispersion. The fudge time1 value is added to each sample as + * received. + */ + if (!refclock_process(pp)) { +#ifdef DEBUG + if (debug) + printf("usno: time rejected\n"); +#endif + refclock_report(peer, CEVNT_BADTIME); + return; + } else if (up->msgcnt < MSGCNT) + return; + + /* + * We have a filtered sample offset ready for peer processing. + * We use lastrec as both the reference time and receive time in + * order to avoid being cute, like setting the reference time + * later than the receive time, which may cause a paranoid + * protocol module to chuck out the data. Finaly, we unhook the + * timeout, arm for the next call, fold the tent and go home. + */ + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + pp->sloppyclockflag &= ~CLK_FLAG1; + up->pollcnt = 0; + up->state = 0; + usno_disc(peer); +} +#endif /* 0 */ + + +/* + * usno_poll - called by the transmit routine + */ +static void +usno_poll( + int unit, + struct peer *peer + ) +{ + register struct usnounit *up; + struct refclockproc *pp; + + /* + * If the driver is running, we set the enable flag (fudge + * flag1), which causes the driver timeout routine to initiate a + * call. If not, the enable flag can be set using + * ntpdc. If this is the sustem peer, then follow the system + * poll interval. + */ + pp = peer->procptr; + up = (struct usnounit *)pp->unitptr; + if (up->run) { + pp->sloppyclockflag |= CLK_FLAG1; + if (peer == sys_peer) + peer->hpoll = sys_poll; + else + peer->hpoll = peer->minpoll; + } +} + + +#if 0 +/* + * usno_timeout - called by the timer interrupt + */ +static void +usno_timeout( + struct peer *peer + ) +{ + register struct usnounit *up; + struct refclockproc *pp; + int fd; + char device[20]; + char lockfile[128], pidbuf[8]; + int dtr = TIOCM_DTR; + + /* + * If a timeout occurs in other than state 0, the call has + * failed. If in state 0, we just see if there is other work to + * do. + */ + pp = peer->procptr; + up = (struct usnounit *)pp->unitptr; + if (up->state) { + if (up->state != 1) { + usno_disc(peer); + return; + } + /* + * Call, and start the answer timeout. We think it + * strange if the OK status has not been received from + * the modem, but plow ahead anyway. + * + * This code is *here* because we had to stick in a brief + * delay to let the modem settle down after raising DTR, + * and for the OK to be received. State machines are + * contorted. + */ + if (strcmp(pp->a_lastcode, "OK") != 0) + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, "clock %s USNO no modem status", + ntoa(&peer->srcadr)); + (void)usno_write(peer, PHONE); + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, "clock %s USNO calling %s\n", + ntoa(&peer->srcadr), PHONE); + up->state = 2; + up->pollcnt++; + pp->polls++; + peer->nextdate = current_time + ANSWER; + return; + } + switch (peer->ttl) { + + /* + * In manual mode the calling program is activated + * by the ntpdc program using the enable flag (fudge + * flag1), either manually or by a cron job. + */ + case MODE_MANUAL: + up->run = 0; + break; + + /* + * In automatic mode the calling program runs + * continuously at intervals determined by the sys_poll + * variable. + */ + case MODE_AUTO: + if (!up->run) + pp->sloppyclockflag |= CLK_FLAG1; + up->run = 1; + break; + + /* + * In backup mode the calling program is disabled, + * unless no system peer has been selected for MAXOUTAGE + * (3600 s). Once enabled, it runs until some other NTP + * peer shows up. + */ + case MODE_BACKUP: + if (!up->run && sys_peer == 0) { + if (current_time - last_time > MAXOUTAGE) { + up->run = 1; + peer->hpoll = peer->minpoll; + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, + "clock %s USNO backup started ", + ntoa(&peer->srcadr)); + } + } else if (up->run && sys_peer->sstclktype != CTL_SST_TS_TELEPHONE) { + peer->hpoll = peer->minpoll; + up->run = 0; + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, + "clock %s USNO backup stopped", + ntoa(&peer->srcadr)); + } + break; + + default: + msyslog(LOG_ERR, + "clock %s USNO invalid mode", ntoa(&peer->srcadr)); + + } + + /* + * The fudge flag1 is used as an enable/disable; if set either + * by the code or via ntpdc, the calling program is + * started; if reset, the phones stop ringing. + */ + if (!(pp->sloppyclockflag & CLK_FLAG1)) { + up->pollcnt = 0; + peer->nextdate = current_time + IDLE; + return; + } + + /* + * Lock the port. + */ + (void)sprintf(lockfile, LOCKFILE, up->unit); + fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0644); + if (fd < 0) { + msyslog(LOG_ERR, "clock %s USNO port busy", + ntoa(&peer->srcadr)); + return; + } + sprintf(pidbuf, "%d\n", (int) getpid()); + write(fd, pidbuf, strlen(pidbuf)); + close(fd); + + /* + * Open serial port. Use ACTS line discipline, if available. It + * pumps a timestamp into the data stream at every on-time + * character '*' found. Note: the port must have modem control + * or deep pockets for the phone bill. HP-UX 9.03 users should + * have very deep pockets. + */ + (void)sprintf(device, DEVICE, up->unit); + if (!(fd = refclock_open(device, SPEED232, LDISC_ACTS))) { + unlink(lockfile); + return; + } + if (ioctl(fd, TIOCMBIC, (char *)&dtr) < 0) + msyslog(LOG_WARNING, "usno_timeout: clock %s: couldn't clear DTR: %m", + ntoa(&peer->srcadr)); + + pp->io.clock_recv = usno_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + unlink(lockfile); + free(up); + return; + } + + /* + * Initialize modem and kill DTR. We skedaddle if this comes + * bum. + */ + if (!usno_write(peer, MODEM_SETUP)) { + msyslog(LOG_ERR, "clock %s USNO couldn't write", + ntoa(&peer->srcadr)); + io_closeclock(&pp->io); + unlink(lockfile); + free(up); + return; + } + + /* + * Initiate a call to the Observatory. If we wind up here in + * other than state 0, a successful call could not be completed + * within minpoll seconds. + */ + if (up->pollcnt) { + refclock_report(peer, CEVNT_TIMEOUT); + NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, + "clock %s USNO calling program terminated", + ntoa(&peer->srcadr)); + pp->sloppyclockflag &= ~CLK_FLAG1; + up->pollcnt = 0; +#ifdef DEBUG + if (debug) + printf("usno: calling program terminated\n"); +#endif + usno_disc(peer); + return; + } + + /* + * Raise DTR, and let the modem settle. Then we'll dial. + */ + if (ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr) < -1) + msyslog(LOG_INFO, "usno_timeout: clock %s: couldn't set DTR: %m", + ntoa(&peer->srcadr)); + up->state = 1; + peer->nextdate = current_time + WAIT; +} +#endif /* 0 */ + + +/* + * usno_disc - disconnect the call and wait for the ruckus to cool + */ +static void +usno_disc( + struct peer *peer + ) +{ + register struct usnounit *up; + struct refclockproc *pp; + int dtr = TIOCM_DTR; + char lockfile[128]; + + /* + * We should never get here other than in state 0, unless a call + * has timed out. We drop DTR, which will reliably get the modem + * off the air, even while the modem is hammering away full tilt. + */ + pp = peer->procptr; + up = (struct usnounit *)pp->unitptr; + + if (ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr) < 0) + msyslog(LOG_INFO, "usno_disc: clock %s: couldn't clear DTR: %m", + ntoa(&peer->srcadr)); + + if (up->state > 0) { + up->state = 0; + msyslog(LOG_NOTICE, "clock %s USNO call failed %d", + ntoa(&peer->srcadr), up->state); +#ifdef DEBUG + if (debug) + printf("usno: call failed %d\n", up->state); +#endif + } + + io_closeclock(&pp->io); + sprintf(lockfile, LOCKFILE, up->unit); + unlink(lockfile); + + peer->nextdate = current_time + WAIT; +} + + +#if 0 +/* + * usno_write - write a message to the serial port + */ +static int +usno_write( + struct peer *peer, + const char *str + ) +{ + register struct usnounit *up; + struct refclockproc *pp; + int len; + int code; + char cr = '\r'; + + /* + * Not much to do here, other than send the message, handle + * debug and report faults. + */ + pp = peer->procptr; + up = (struct usnounit *)pp->unitptr; + len = strlen(str); +#ifdef DEBUG + if (debug) + printf("usno: state %d send %d %s\n", up->state, len, + str); +#endif + code = write(pp->io.fd, str, (unsigned)len) == len; + code |= write(pp->io.fd, &cr, 1) == 1; + if (!code) + refclock_report(peer, CEVNT_FAULT); + return (code); +} +#endif /* 0 */ + +#else +int refclock_usno_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpd/refclock_wwvb.c b/contrib/ntp/ntpd/refclock_wwvb.c new file mode 100644 index 000000000000..9d3b3d6b358b --- /dev/null +++ b/contrib/ntp/ntpd/refclock_wwvb.c @@ -0,0 +1,440 @@ +/* + * refclock_wwvb - clock driver for Spectracom WWVB receivers + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(REFCLOCK) && defined(CLOCK_WWVB) + +#include +#include +#include +#include + +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_refclock.h" +#include "ntp_calendar.h" +#include "ntp_stdlib.h" + +/* + * This driver supports the Spectracom Model 8170 and Netclock/2 WWVB + * Synchronized Clocks and the Netclock/GPS Master Clock. Both the WWVB + * and GPS clocks have proven reliable sources of time; however, the + * WWVB clocks have proven vulnerable to high ambient conductive RF + * interference. The claimed accuracy of the WWVB clocks is 100 us + * relative to the broadcast signal, while the claimed accuracy of the + * GPS clock is 50 ns; however, in most cases the actual accuracy is + * limited by the resolution of the timecode and the latencies of the + * serial interface and operating system. + * + * The WWVB and GPS clocks should be configured for 24-hour display, + * AUTO DST off, time zone 0 (UTC), data format 0 or 2 (see below) and + * baud rate 9600. If the clock is to used as the source for the IRIG + * Audio Decoder (refclock_irig.c in this distribution), it should be + * configured for AM IRIG output and IRIG format 1 (IRIG B with + * signature control). The GPS clock can be configured either to respond + * to a 'T' poll character or left running continuously. + * + * There are two timecode formats used by these clocks. Format 0, which + * is available with both the Netclock/2 and 8170, and format 2, which + * is available only with the Netclock/2, specially modified 8170 and + * GPS. + * + * Format 0 (22 ASCII printing characters): + * + * i ddd hh:mm:ss TZ=zz + * + * on-time = first + * hh:mm:ss = hours, minutes, seconds + * i = synchronization flag (' ' = in synch, '?' = out of synch) + * + * The alarm condition is indicated by other than ' ' at a, which occurs + * during initial synchronization and when received signal is lost for + * about ten hours. + * + * Format 2 (24 ASCII printing characters): + * + * iqyy ddd hh:mm:ss.fff ld + * + * on-time = + * i = synchronization flag (' ' = in synch, '?' = out of synch) + * q = quality indicator (' ' = locked, 'A'...'D' = unlocked) + * yy = year (as broadcast) + * ddd = day of year + * hh:mm:ss.fff = hours, minutes, seconds, milliseconds + * + * The alarm condition is indicated by other than ' ' at a, which occurs + * during initial synchronization and when received signal is lost for + * about ten hours. The unlock condition is indicated by other than ' ' + * at q. + * + * The q is normally ' ' when the time error is less than 1 ms and a + * character in the set 'A'...'D' when the time error is less than 10, + * 100, 500 and greater than 500 ms respectively. The l is normally ' ', + * but is set to 'L' early in the month of an upcoming UTC leap second + * and reset to ' ' on the first day of the following month. The d is + * set to 'S' for standard time 'I' on the day preceding a switch to + * daylight time, 'D' for daylight time and 'O' on the day preceding a + * switch to standard time. The start bit of the first is + * synchronized to the indicated time as returned. + * + * This driver does not need to be told which format is in use - it + * figures out which one from the length of the message.The driver makes + * no attempt to correct for the intrinsic jitter of the radio itself, + * which is a known problem with the older radios. + * + * Fudge Factors + * + * This driver can retrieve a table of quality data maintained + * internally by the Netclock/2 clock. If flag4 of the fudge + * configuration command is set to 1, the driver will retrieve this + * table and write it to the clockstats file on when the first timecode + * message of a new day is received. + */ + +/* + * Interface definitions + */ +#define DEVICE "/dev/wwvb%d" /* device name and unit */ +#define SPEED232 B9600 /* uart speed (9600 baud) */ +#define PRECISION (-13) /* precision assumed (about 100 us) */ +#define REFID "WWVB" /* reference ID */ +#define DESCRIPTION "Spectracom WWVB/GPS Receivers" /* WRU */ + +#define LENWWVB0 22 /* format 0 timecode length */ +#define LENWWVB2 24 /* format 2 timecode length */ +#define LENWWVB3 29 /* format 3 timecode length */ +#define MONLIN 15 /* number of monitoring lines */ + +/* + * WWVB unit control structure + */ +struct wwvbunit { + u_char tcswitch; /* timecode switch */ + l_fp laststamp; /* last receive timestamp */ + u_char lasthour; /* last hour (for monitor) */ + u_char linect; /* count ignored lines (for monitor */ +}; + +/* + * Function prototypes + */ +static int wwvb_start P((int, struct peer *)); +static void wwvb_shutdown P((int, struct peer *)); +static void wwvb_receive P((struct recvbuf *)); +static void wwvb_poll P((int, struct peer *)); + +/* + * Transfer vector + */ +struct refclock refclock_wwvb = { + wwvb_start, /* start up driver */ + wwvb_shutdown, /* shut down driver */ + wwvb_poll, /* transmit poll message */ + noentry, /* not used (old wwvb_control) */ + noentry, /* initialize driver (not used) */ + noentry, /* not used (old wwvb_buginfo) */ + NOFLAGS /* not used */ +}; + + +/* + * wwvb_start - open the devices and initialize data for processing + */ +static int +wwvb_start( + int unit, + struct peer *peer + ) +{ + register struct wwvbunit *up; + struct refclockproc *pp; + int fd; + char device[20]; + + /* + * Open serial port. Use CLK line discipline, if available. + */ + (void)sprintf(device, DEVICE, unit); + if (!(fd = refclock_open(device, SPEED232, LDISC_CLK))) + return (0); + + /* + * Allocate and initialize unit structure + */ + if (!(up = (struct wwvbunit *) + emalloc(sizeof(struct wwvbunit)))) { + (void) close(fd); + return (0); + } + memset((char *)up, 0, sizeof(struct wwvbunit)); + pp = peer->procptr; + pp->unitptr = (caddr_t)up; + pp->io.clock_recv = wwvb_receive; + pp->io.srcclock = (caddr_t)peer; + pp->io.datalen = 0; + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + (void) close(fd); + free(up); + return (0); + } + + /* + * Initialize miscellaneous variables + */ + peer->precision = PRECISION; + peer->burst = NSTAGE; + pp->clockdesc = DESCRIPTION; + memcpy((char *)&pp->refid, REFID, 4); + return (1); +} + + +/* + * wwvb_shutdown - shut down the clock + */ +static void +wwvb_shutdown( + int unit, + struct peer *peer + ) +{ + register struct wwvbunit *up; + struct refclockproc *pp; + + pp = peer->procptr; + up = (struct wwvbunit *)pp->unitptr; + io_closeclock(&pp->io); + free(up); +} + + +/* + * wwvb_receive - receive data from the serial interface + */ +static void +wwvb_receive( + struct recvbuf *rbufp + ) +{ + struct wwvbunit *up; + struct refclockproc *pp; + struct peer *peer; + + l_fp trtmp; /* arrival timestamp */ + int tz; /* time zone */ + int day, month; /* ddd conversion */ + int temp; /* int temp */ + char syncchar; /* synchronization indicator */ + char qualchar; /* quality indicator */ + char leapchar; /* leap indicator */ + char dstchar; /* daylight/standard indicator */ + + /* + * Initialize pointers and read the timecode and timestamp + */ + peer = (struct peer *)rbufp->recv_srcclock; + pp = peer->procptr; + up = (struct wwvbunit *)pp->unitptr; + temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); + + /* + * Note we get a buffer and timestamp for both a and , + * but only the timestamp is retained. Note: in format 0 on + * a Netclock/2 or upgraded 8170 the start bit is delayed 100 + * +-50 us relative to the pps; however, on an unmodified 8170 + * the start bit can be delayed up to 10 ms. In format 2 the + * reading precision is only to the millisecond. Thus, unless + * you have a pps gadget and don't have to have the year, format + * 0 provides the lowest jitter. + */ + if (temp == 0) { + if (up->tcswitch == 0) { + up->tcswitch = 1; + up->laststamp = trtmp; + } else + up->tcswitch = 0; + return; + } + pp->lencode = temp; + pp->lastrec = up->laststamp; + up->laststamp = trtmp; + up->tcswitch = 1; +#ifdef DEBUG + if (debug) + printf("wwvb: timecode %d %s\n", pp->lencode, + pp->a_lastcode); +#endif + + /* + * We get down to business, check the timecode format and decode + * its contents. This code uses the timecode length to determine + * format 0, 2 or 3. If the timecode has invalid length or is + * not in proper format, we declare bad format and exit. + */ + syncchar = qualchar = leapchar = dstchar = ' '; + tz = 0; + pp->msec = 0; + switch (pp->lencode) { + + case LENWWVB0: + + /* + * Timecode format 0: "I ddd hh:mm:ss DTZ=nn" + */ + if (sscanf(pp->a_lastcode, + "%c %3d %2d:%2d:%2d %cTZ=%2d", + &syncchar, &pp->day, &pp->hour, &pp->minute, + &pp->second, &dstchar, &tz) == 7) + break; + + case LENWWVB2: + + /* + * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD" + */ + if (sscanf(pp->a_lastcode, + "%c%c %2d %3d %2d:%2d:%2d.%3d %c", + &syncchar, &qualchar, &pp->year, &pp->day, + &pp->hour, &pp->minute, &pp->second, &pp->msec, + &leapchar) == 9) + break; + + case LENWWVB3: + + /* + * Timecode format 3: "0003I yyyymmdd hhmmss+0000SL#" + */ + if (sscanf(pp->a_lastcode, + "0003%c %4d%2d%2d %2d%2d%2d+0000%c%c", + &syncchar, &pp->year, &month, &day, &pp->hour, + &pp->minute, &pp->second, &dstchar, &leapchar) == 8) + { + pp->day = ymd2yd(pp->year, month, day); + break; + } + + default: + + /* + * Unknown format: If dumping internal table, record + * stats; otherwise, declare bad format. + */ + if (up->linect > 0) { + up->linect--; + record_clock_stats(&peer->srcadr, + pp->a_lastcode); + } else { + refclock_report(peer, CEVNT_BADREPLY); + } + return; + } + + /* + * Decode synchronization, quality and leap characters. If + * unsynchronized, set the leap bits accordingly and exit. + * Otherwise, set the leap bits according to the leap character. + * Once synchronized, the dispersion depends only on the + * quality character. + */ + switch (qualchar) { + + case ' ': + pp->disp = .001; + break; + + case 'A': + pp->disp = .01; + break; + + case 'B': + pp->disp = .1; + break; + + case 'C': + pp->disp = .5; + break; + + case 'D': + pp->disp = MAXDISPERSE; + break; + + default: + pp->disp = MAXDISPERSE; + refclock_report(peer, CEVNT_BADREPLY); + break; + } + if (syncchar != ' ') + pp->leap = LEAP_NOTINSYNC; + else if (leapchar == 'L') + pp->leap = LEAP_ADDSECOND; + else + pp->leap = LEAP_NOWARNING; + + /* + * Process the new sample in the median filter and determine the + * timecode timestamp. + */ + if (!refclock_process(pp)) + refclock_report(peer, CEVNT_BADTIME); +} + + +/* + * wwvb_poll - called by the transmit procedure + */ +static void +wwvb_poll( + int unit, + struct peer *peer + ) +{ + register struct wwvbunit *up; + struct refclockproc *pp; + char pollchar; /* character sent to clock */ + + /* + * Time to poll the clock. The Spectracom clock responds to a + * 'T' by returning a timecode in the format(s) specified above. + * Note there is no checking on state, since this may not be the + * only customer reading the clock. Only one customer need poll + * the clock; all others just listen in. If the clock becomes + * unreachable, declare a timeout and keep going. + */ + pp = peer->procptr; + up = (struct wwvbunit *)pp->unitptr; + if (up->linect > 0) + pollchar = 'R'; + else + pollchar = 'T'; + if (write(pp->io.fd, &pollchar, 1) != 1) + refclock_report(peer, CEVNT_FAULT); + else + pp->polls++; + if (peer->burst > 0) + return; + if (pp->coderecv == pp->codeproc) { + refclock_report(peer, CEVNT_TIMEOUT); + return; + } + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + peer->burst = NSTAGE; + + /* + * If the monitor flag is set (flag4), we dump the internal + * quality table at the first timecode beginning the day. + */ + if (pp->sloppyclockflag & CLK_FLAG4 && pp->hour < + (int)up->lasthour) + up->linect = MONLIN; + up->lasthour = pp->hour; +} + +#else +int refclock_wwvb_bs; +#endif /* REFCLOCK */ diff --git a/contrib/ntp/ntpdate/Makefile.am b/contrib/ntp/ntpdate/Makefile.am new file mode 100644 index 000000000000..ba6c21f79463 --- /dev/null +++ b/contrib/ntp/ntpdate/Makefile.am @@ -0,0 +1,20 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +bin_PROGRAMS = ntpdate ntptimeset +ntptimeset_SOURCES = ntptimeset.c ntptime_config.c +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o ../libntp/libntp.a @LIBRSAREF@ +DISTCLEANFILES = .version stamp-v +noinst_HEADERS = ntpdate.h +#EXTRA_DIST = ntpdate.mak +ETAGS_ARGS = Makefile.am + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +version.o: $(ntpdate_OBJECTS) ../libntp/libntp.a @LIBRSAREF@ Makefile + $(top_builddir)/scripts/mkver ntpdate + $(COMPILE) -c version.c diff --git a/contrib/ntp/ntpdate/Makefile.in b/contrib/ntp/ntpdate/Makefile.in new file mode 100644 index 000000000000..80d02326f474 --- /dev/null +++ b/contrib/ntp/ntpdate/Makefile.in @@ -0,0 +1,381 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ../util/ansi2knr +bin_PROGRAMS = ntpdate ntptimeset +ntptimeset_SOURCES = ntptimeset.c ntptime_config.c +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o ../libntp/libntp.a @LIBRSAREF@ +DISTCLEANFILES = .version stamp-v +noinst_HEADERS = ntpdate.h +#EXTRA_DIST = ntpdate.mak +ETAGS_ARGS = Makefile.am +subdir = ntpdate +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +ANSI2KNR = ../util/ansi2knr +ntpdate_SOURCES = ntpdate.c +ntpdate_OBJECTS = ntpdate$U.o +ntpdate_LDADD = $(LDADD) +ntpdate_DEPENDENCIES = version.o ../libntp/libntp.a +ntpdate_LDFLAGS = +am_ntptimeset_OBJECTS = ntptimeset$U.o ntptime_config$U.o +ntptimeset_OBJECTS = $(am_ntptimeset_OBJECTS) +ntptimeset_LDADD = $(LDADD) +ntptimeset_DEPENDENCIES = version.o ../libntp/libntp.a +ntptimeset_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = ntpdate.c $(ntptimeset_SOURCES) +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +SOURCES = ntpdate.c $(ntptimeset_SOURCES) +OBJECTS = ntpdate$U.o $(am_ntptimeset_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ntpdate/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: +../util/ansi2knr: ../util/ansi2knr.o + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr + +../util/ansi2knr.o: + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o + + +mostlyclean-kr: + -rm -f *_.c + +clean-kr: + +distclean-kr: + +maintainer-clean-kr: +ntpdate$U.o: + +ntpdate: $(ntpdate_OBJECTS) $(ntpdate_DEPENDENCIES) + @rm -f ntpdate + $(LINK) $(ntpdate_LDFLAGS) $(ntpdate_OBJECTS) $(ntpdate_LDADD) $(LIBS) +ntptimeset$U.o: +ntptime_config$U.o: + +ntptimeset: $(ntptimeset_OBJECTS) $(ntptimeset_DEPENDENCIES) + @rm -f ntptimeset + $(LINK) $(ntptimeset_LDFLAGS) $(ntptimeset_OBJECTS) $(ntptimeset_LDADD) $(LIBS) +ntpdate_.c: ntpdate.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpdate.c; then echo $(srcdir)/ntpdate.c; else echo ntpdate.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntpdate_.c +ntptime_config_.c: ntptime_config.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntptime_config.c; then echo $(srcdir)/ntptime_config.c; else echo ntptime_config.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntptime_config_.c +ntptimeset_.c: ntptimeset.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntptimeset.c; then echo $(srcdir)/ntptimeset.c; else echo ntptimeset.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntptimeset_.c +ntpdate_.o ntptime_config_.o ntptimeset_.o : $(ANSI2KNR) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +ntpdate.o: ntpdate.c ../config.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ntpdate.h ../include/ntp_malloc.h \ + ../include/ntp_string.h ../include/ntp_syslog.h \ + ../include/ntp_select.h ../include/ntp_stdlib.h \ + ../include/l_stdlib.h ../include/recvbuff.h +ntptime_config.o: ntptime_config.c ../config.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_io.h \ + ../include/ntp_unixtime.h ../include/ntp_filegen.h ntpdate.h \ + ../include/ntp_malloc.h ../include/ntp_syslog.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h \ + ../include/l_stdlib.h +ntptimeset.o: ntptimeset.c ../config.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h ../include/ntp_io.h \ + ../include/iosignal.h ../include/ntp_refclock.h \ + ../include/recvbuff.h ../include/ntp_unixtime.h ntpdate.h \ + ../include/ntp_malloc.h ../include/ntp_string.h \ + ../include/ntp_syslog.h ../include/ntp_select.h \ + ../include/ntp_stdlib.h ../include/l_stdlib.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-kr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-compile clean-kr clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-compile distclean-kr \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-kr \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-kr distclean-kr clean-kr \ +maintainer-clean-kr tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +version.o: $(ntpdate_OBJECTS) ../libntp/libntp.a @LIBRSAREF@ Makefile + $(top_builddir)/scripts/mkver ntpdate + $(COMPILE) -c version.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/ntpdate/README b/contrib/ntp/ntpdate/README new file mode 100644 index 000000000000..27b51ed363ac --- /dev/null +++ b/contrib/ntp/ntpdate/README @@ -0,0 +1,7 @@ +README file for directory ./ntpdate of the NTP Version 4 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/ntp/ntpdate/ntpdate.c b/contrib/ntp/ntpdate/ntpdate.c new file mode 100644 index 000000000000..023b64981761 --- /dev/null +++ b/contrib/ntp/ntpdate/ntpdate.c @@ -0,0 +1,2036 @@ +/* + * ntpdate - set the time of day by polling one or more NTP servers + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#ifdef HAVE_POLL_H +#include +#endif +#ifndef SYS_WINNT +# include +# include +# include +#endif /* SYS_WINNT */ +#include +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif /* HAVE_SYS_RESOURCE_H */ + +#ifdef SYS_VXWORKS +# include "ioLib.h" +# include "sockLib.h" +# include "timers.h" + +/* select wants a zero structure ... */ +struct timeval timeout = {0,0}; +#else +struct timeval timeout = {60,0}; +#endif + + +#if defined(SYS_HPUX) +# include +#endif + +#ifdef HAVE_NETINFO +#include +#endif + +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntpdate.h" +#include "ntp_string.h" +#include "ntp_syslog.h" +#include "ntp_select.h" +#include "ntp_stdlib.h" +#include "recvbuff.h" + +#ifdef SYS_WINNT +# define TARGET_RESOLUTION 1 /* Try for 1-millisecond accuracy + on Windows NT timers. */ +#pragma comment(lib, "winmm") +#endif /* SYS_WINNT */ + +/* + * Scheduling priority we run at + */ +#ifndef SYS_VXWORKS +# define NTPDATE_PRIO (-12) +#else +# define NTPDATE_PRIO (100) +#endif + +#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE) +/* POSIX TIMERS - vxWorks doesn't have itimer - casey */ +static timer_t ntpdate_timerid; +#endif + +/* + * 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 + */ +volatile int debug = 0; + +/* + * File descriptor masks etc. for call to select + */ +int fd; +#ifdef HAVE_POLL_H +struct pollfd fdmask; +#else +fd_set fdmask; +#endif + +/* + * 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 + */ +volatile int alarm_flag = 0; + +/* + * Simple query flag. + */ +int simple_query = 0; + +/* + * Unpriviledged port flag. + */ +int unpriv_port = 0; + +/* + * Time to spend measuring drift rate + */ +int rate = 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_int32 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 +# ifndef SYS_WINNT +#define KEYFILE "/etc/ntp.keys" +# else +#define KEYFILE "%windir%\\ntp.keys" +# endif /* SYS_WINNT */ +#endif /* KEYFILE */ + +#ifndef SYS_WINNT +const char *key_file = KEYFILE; +#else +char key_file_storage[MAX_PATH+1], *key_file ; +#endif /* SYS_WINNT */ + +/* + * Miscellaneous flags + */ +int verbose = 0; +int always_step = 0; +int never_step = 0; + +int ntpdatemain P((int, char **)); +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 *)); + void timer P((void)); +static void init_alarm P((void)); +#ifndef SYS_WINNT +static RETSIGTYPE alarming P((int)); +#endif /* SYS_WINNT */ +static void init_io P((void)); +static void sendpkt P((struct sockaddr_in *, struct pkt *, int)); +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((const char *, u_int32 *)); +static void printserver P((struct server *, FILE *)); + +#ifdef SYS_WINNT +int on = 1; +WORD wVersionRequested; +WSADATA wsaData; +HANDLE TimerThreadHandle = NULL; +#endif /* SYS_WINNT */ + +#ifdef NO_MAIN_ALLOWED +CALL(ntpdate,"ntpdate",ntpdatemain); + +void clear_globals() +{ + /* + * Debugging flag + */ + debug = 0; + + ntp_optind = 0; + /* + * Initializing flag. All async routines watch this and only do their + * thing when it is clear. + */ + initializing = 1; + + /* + * Alarm flag. Set when an alarm occurs + */ + alarm_flag = 0; + + /* + * Simple query flag. + */ + simple_query = 0; + + /* + * Unpriviledged port flag. + */ + unpriv_port = 0; + + /* + * Time to spend measuring drift rate + */ + rate = 0; + /* + * Systemwide parameters and flags + */ + sys_numservers = 0; /* number of servers to poll */ + sys_maxservers = 0; /* max number of servers to deal with */ + sys_authenticate = 0; /* true when authenticating */ + sys_authkey = 0; /* set to authentication key in use */ + sys_authdelay = 0; /* authentication delay */ + sys_version = NTP_VERSION; /* version to poll with */ + + /* + * The current internal time + */ + current_time = 0; + + /* + * Counter for keeping track of completed servers + */ + complete_servers = 0; + verbose = 0; + always_step = 0; + never_step = 0; +} +#endif + +#ifdef HAVE_NETINFO +static ni_namelist *getnetinfoservers P((void)); +#endif + +/* + * Main program. Initialize us and loop waiting for I/O and/or + * timer expiries. + */ +#ifndef NO_MAIN_ALLOWED +int +main( + int argc, + char *argv[] + ) +{ + return ntpdatemain (argc, argv); +} +#endif /* NO_MAIN_ALLOWED */ + +int +ntpdatemain ( + int argc, + char *argv[] + ) +{ + int was_alarmed; + struct recvbuf *rbuflist; + struct recvbuf *rbuf; + l_fp tmp; + int errflg; + int c; +#ifdef HAVE_NETINFO + ni_namelist *netinfoservers; +#endif +#ifdef SYS_WINNT + HANDLE process_handle; + + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) { + msyslog(LOG_ERR, "No useable winsock.dll: %m"); + exit(1); + } + + key_file = key_file_storage; + + if (!ExpandEnvironmentStrings(KEYFILE, key_file, MAX_PATH)) + { + msyslog(LOG_ERR, "ExpandEnvironmentStrings(KEYFILE) failed: %m\n"); + } +#endif /* SYS_WINNT */ + +#ifdef NO_MAIN_ALLOWED + clear_globals(); +#endif + + errflg = 0; + progname = argv[0]; + syslogit = 0; + + /* + * Decode argument list + */ + while ((c = ntp_getopt(argc, argv, "a:bBde:k:o:p:qr:st:uv")) != EOF) + switch (c) + { + case 'a': + c = atoi(ntp_optarg); + sys_authenticate = 1; + sys_authkey = c; + break; + case 'b': + always_step++; + never_step = 0; + break; + case 'B': + never_step++; + always_step = 0; + 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 'r': + c = atoi(ntp_optarg); + if (c <= 0 || c > (60 * 60)) { + (void) fprintf(stderr, + "%s: rate (%d) is invalid: 0 - %d\n", + progname, c, (60 * 60)); + errflg++; + } else { + rate = c; + } + 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 'u': + unpriv_port = 1; + break; + case '?': + ++errflg; + break; + default: + break; + } + + if (errflg) { + (void) fprintf(stderr, + "usage: %s [-bBdqsv] [-a key#] [-e delay] [-k file] [-p samples] [-o version#] [-r rate] [-t timeo] server ...\n", + progname); + exit(2); + } + + if (debug || simple_query) { +#ifdef HAVE_SETVBUF + static char buf[BUFSIZ]; + setvbuf(stdout, buf, _IOLBF, BUFSIZ); +#else + setlinebuf(stdout); +#endif + } + + /* + * Logging. Open the syslog if we have to + */ + if (syslogit) { +#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32 +# 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 */ +#endif /* SYS_WINNT */ + } + + if (debug || verbose) + msyslog(LOG_NOTICE, "%s", Version); + + /* + * Add servers we are going to be polling + */ + sys_maxservers = argc - ntp_optind; +#ifdef HAVE_NETINFO + if ((netinfoservers = getnetinfoservers())) + sys_maxservers += netinfoservers->ni_namelist_len; +#endif + sys_servers = (struct server **) + emalloc(sys_maxservers * sizeof(struct server *)); + + for ( ; ntp_optind < argc; ntp_optind++) + addserver(argv[ntp_optind]); + +#ifdef HAVE_NETINFO + if (netinfoservers) { + if ( netinfoservers->ni_namelist_len && + *netinfoservers->ni_namelist_val ) { + u_int servercount = 0; + while (servercount < netinfoservers->ni_namelist_len) { + if (debug) msyslog(LOG_DEBUG, + "Adding time server %s from NetInfo configuration.", + netinfoservers->ni_namelist_val[servercount]); + addserver(netinfoservers->ni_namelist_val[servercount++]); + } + } + ni_namelist_free(netinfoservers); + free(netinfoservers); + } +#endif + + if (sys_numservers == 0) { + msyslog(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)) { + msyslog(LOG_ERR, "no key file, exitting"); + exit(1); + } + if (!authistrusted(sys_authkey)) { + char buf[10]; + + (void) sprintf(buf, "%lu", (unsigned long)sys_authkey); + msyslog(LOG_ERR, "authentication key %s unknown", buf); + exit(1); + } + } + init_io(); + init_alarm(); + + /* + * Set the priority. + */ +#ifdef SYS_VXWORKS + taskPrioritySet( taskIdSelf(), NTPDATE_PRIO); +#endif +#if defined(HAVE_ATT_NICE) + nice (NTPDATE_PRIO); +#endif +#if defined(HAVE_BSD_NICE) + (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO); +#endif +#ifdef SYS_WINNT + process_handle = GetCurrentProcess(); + if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) { + msyslog(LOG_ERR, "SetPriorityClass failed: %m"); + } +#endif /* SYS_WINNT */ + + initializing = 0; + + was_alarmed = 0; + rbuflist = (struct recvbuf *)0; + while (complete_servers < sys_numservers) { +#ifdef HAVE_POLL_H + struct pollfd rdfdes; +#else + fd_set rdfdes; +#endif + 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; +#ifdef HAVE_POLL_H + nfound = poll(&rdfdes, 1, timeout.tv_sec * 1000); +#else + nfound = select(fd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, &timeout); +#endif + if (nfound > 0) + input_handler(); + else if ( +#ifndef SYS_WINNT + nfound == -1 +#else + nfound == SOCKET_ERROR +#endif /* SYS_WINNT */ + ) { +#ifndef SYS_WINNT + if (errno != EINTR) +#endif + msyslog(LOG_ERR, +#ifdef HAVE_POLL_H + "poll() error: %m" +#else + "select() error: %m" +#endif + ); + } else { +#ifndef SYS_VXWORKS + msyslog(LOG_DEBUG, +#ifdef HAVE_POLL_H + "poll(): nfound = %d, error: %m", +#else + "select(): nfound = %d, error: %m", +#endif + nfound); +#endif + } + 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. + */ +#ifdef SYS_WINNT + WSACleanup(); +#endif +#ifdef SYS_VXWORKS + close (fd); + timer_delete(ntpdate_timerid); +#endif + return 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( + 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. + */ + L_CLR(&ts); + 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); + L_CLR(&xpkt.reftime); + L_CLR(&xpkt.org); + L_CLR(&xpkt.rec); + + /* + * 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.keyid1 = htonl(sys_authkey); + get_systime(&server->xmt); + L_ADDUF(&server->xmt, sys_authdelay); + HTONL_FP(&server->xmt, &xpkt.xmt); + len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC); + sendpkt(&(server->srcadr), &xpkt, (int)(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( + struct recvbuf *rbufp + ) +{ + register struct pkt *rpkt; + register struct server *server; + register s_fp di; + l_fp t10, t23; + l_fp org; + l_fp rec; + l_fp ci; + int has_mac; + int is_authentic; + + if (debug) + printf("receive(%s)\n", ntoa(&rbufp->recv_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->recv_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=%ld sys_authkey=%ld decrypt=%ld\n", + (long int)ntohl(rpkt->keyid1), (long int)sys_authkey, + (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt, + LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC))); + + if (has_mac && ntohl(rpkt->keyid1) == sys_authkey && + authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC, + (int)(rbufp->recv_length - 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 (L_ISZERO(&rec) || !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 = server->org; /* pkt.xmt == t1 */ + L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/ + + t23 = rec; /* pkt.rec == t2 */ + L_SUB(&t23, &org); /* pkt->org == t3 */ + + /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */ + ci = t10; + L_ADD(&ci, &t23); + L_RSHIFT(&ci); + + /* + * Calculate di in t23 in full precision, then truncate + * to an s_fp. + */ + L_SUB(&t23, &t10); + di = LFPTOFP(&t23); + + if (debug > 3) + printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5)); + + di += (FP_SECOND >> (-(int)NTPDATE_PRECISION)) + + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW; + + if (di <= 0) { /* value still too raunchy to use? */ + L_CLR(&ci); + di = 0; + } else { + di = max(di, NTP_MINDIST); + } + + /* + * Shift this data in, then transmit again. + */ + server_data(server, (s_fp) di, &ci, 0); + transmit(server); +} + + +/* + * server_data - add a sample to the server's filter registers + */ +static void +server_data( + 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] = LFPTOFP(c); + server->filter_error[i] = e; + server->filter_nextpt = i + 1; + } +} + + +/* + * clock_filter - determine a server's delay, dispersion and offset + */ +static void +clock_filter( + 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; + L_CLR(&server->offset); + 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(void) +{ + 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 (!L_ISHIS(&server->org, &server->reftime)) { + 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 < (s_fp) 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 ( (s_fp) 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(void) +{ + 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) { + msyslog(LOG_ERR, + "no server suitable for synchronization found"); + return(1); + } + + if (always_step) { + dostep = 1; + } else if (never_step) { + dostep = 0; + } else { + absoffset = server->soffset; + if (absoffset < 0) + absoffset = -absoffset; + dostep = (absoffset >= NTPDATE_THRESHOLD); + } + + if (dostep) { + if (simple_query || l_step_systime(&server->offset)) { + msyslog(LOG_NOTICE, "step time server %s offset %s sec", + ntoa(&server->srcadr), + lfptoa(&server->offset, 6)); + } + } else { +#if !defined SYS_WINNT && !defined SYS_CYGWIN32 + if (simple_query || l_adj_systime(&server->offset)) { + msyslog(LOG_NOTICE, "adjust time server %s offset %s sec", + ntoa(&server->srcadr), + lfptoa(&server->offset, 6)); + } +#else + /* The NT SetSystemTimeAdjustment() call achieves slewing by + * changing the clock frequency. This means that we cannot specify + * it to slew the clock by a definite amount and then stop like + * the Unix adjtime() routine. We can technically adjust the clock + * frequency, have ntpdate sleep for a while, and then wake + * up and reset the clock frequency, but this might cause some + * grief if the user attempts to run ntpd immediately after + * ntpdate and the socket is in use. + */ + printf("\nThe -b option is required by ntpdate on Windows NT platforms\n"); + exit(1); +#endif /* SYS_WINNT */ + } + 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( + char *serv + ) +{ + register struct server *server; + u_int32 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; + msyslog(LOG_ERR, + "too many servers (> %d) specified, remainder not used", + sys_maxservers); + } + return; + } + + if (!getnetnum(serv, &netnum)) { + msyslog(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 = sys_numservers; +} + + +/* + * findserver - find a server in the list given its address + */ +static struct server * +findserver( + struct sockaddr_in *addr + ) +{ + register int i; + register u_int32 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 + */ +void +timer(void) +{ + 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]); + } +} + + +#ifndef SYS_WINNT +/* + * alarming - record the occurance of an alarm interrupt + */ +static RETSIGTYPE +alarming( + int sig + ) +#else +void CALLBACK +alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) +#endif /* SYS_WINNT */ +{ + alarm_flag++; +} + + +/* + * init_alarm - set up the timer interrupt + */ +static void +init_alarm(void) +{ +#ifndef SYS_WINNT +# ifndef HAVE_TIMER_SETTIME + struct itimerval itimer; +# else + struct itimerspec ntpdate_itimer; +# endif +#else + TIMECAPS tc; + UINT wTimerRes, wTimerID; +# endif /* SYS_WINNT */ +#if defined SYS_CYGWIN32 || defined SYS_WINNT + HANDLE hToken; + TOKEN_PRIVILEGES tkp; + DWORD dwUser = 0; +#endif /* SYS_WINNT */ + + alarm_flag = 0; + +#ifndef SYS_WINNT +# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) + alarm_flag = 0; + /* this code was put in as setitimer() is non existant this us the + * POSIX "equivalents" setup - casey + */ + /* ntpdate_timerid is global - so we can kill timer later */ + if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) == +# ifdef SYS_VXWORKS + ERROR +# else + -1 +# endif + ) + { + fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n"); + return; + } + + /* TIMER_HZ = (5) + * 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); + ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0; + ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ; + ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1); + timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL); +# else + /* + * 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); +# endif +#if defined SYS_CYGWIN32 + /* + * Get previleges needed for fiddling with the clock + */ + + /* get the current process token handle */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + msyslog(LOG_ERR, "OpenProcessToken failed: %m"); + exit(1); + } + /* get the LUID for system-time privilege. */ + LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; /* one privilege to set */ + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + /* get set-time privilege for this process. */ + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); + /* cannot test return value of AdjustTokenPrivileges. */ + if (GetLastError() != ERROR_SUCCESS) + msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); +#endif +#else /* SYS_WINNT */ + _tzset(); + + /* + * Get previleges needed for fiddling with the clock + */ + + /* get the current process token handle */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + msyslog(LOG_ERR, "OpenProcessToken failed: %m"); + exit(1); + } + /* get the LUID for system-time privilege. */ + LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; /* one privilege to set */ + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + /* get set-time privilege for this process. */ + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); + /* cannot test return value of AdjustTokenPrivileges. */ + if (GetLastError() != ERROR_SUCCESS) + msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); + + /* + * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds + * Under Win/NT, expiry of timer interval leads to invocation + * of a callback function (on a different thread) rather than + * generating an alarm signal + */ + + /* determine max and min resolution supported */ + if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) { + msyslog(LOG_ERR, "timeGetDevCaps failed: %m"); + exit(1); + } + wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax); + /* establish the minimum timer resolution that we'll use */ + timeBeginPeriod(wTimerRes); + + /* start the timer event */ + wTimerID = timeSetEvent( + (UINT) (1000/TIMER_HZ), /* Delay */ + wTimerRes, /* Resolution */ + (LPTIMECALLBACK) alarming, /* Callback function */ + (DWORD) dwUser, /* User data */ + TIME_PERIODIC); /* Event type (periodic) */ + if (wTimerID == 0) { + msyslog(LOG_ERR, "timeSetEvent failed: %m"); + exit(1); + } +#endif /* SYS_WINNT */ +} + + + + +/* + * 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. + */ + + +/* + * init_io - initialize I/O data and open socket + */ +static void +init_io(void) +{ + /* + * Init buffer free list and stat counters + */ + init_recvbuff(sys_numservers + 2); + /* + * Open the socket + */ + + /* create a datagram (UDP) socket */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + msyslog(LOG_ERR, "socket() failed: %m"); + exit(1); + /*NOTREACHED*/ + } + + /* + * bind the socket to the NTP port + */ + if (!debug && !simple_query && !unpriv_port) { + 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 = htonl(INADDR_ANY); + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { +#ifndef SYS_WINNT + if (errno == EADDRINUSE) +#else + if (WSAGetLastError() == WSAEADDRINUSE) +#endif /* SYS_WINNT */ + msyslog(LOG_ERR, + "the NTP socket is in use, exiting"); + else + msyslog(LOG_ERR, "bind() fails: %m"); + exit(1); + } + } + +#ifdef HAVE_POLL_H + fdmask.fd = fd; + fdmask.events = POLLIN; +#else + FD_ZERO(&fdmask); + FD_SET(fd, &fdmask); +#endif + + /* + * set non-blocking, + */ +#ifndef SYS_WINNT +# ifdef SYS_VXWORKS + { + int on = TRUE; + + if (ioctl(fd,FIONBIO, &on) == ERROR) { + msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m"); + exit(1); + } + } +# else /* not SYS_VXWORKS */ +# if defined(O_NONBLOCK) + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# else /* not O_NONBLOCK */ +# if defined(FNDELAY) + if (fcntl(fd, F_SETFL, FNDELAY) < 0) { + msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# else /* FNDELAY */ +# include "Bletch: Need non blocking I/O" +# endif /* FNDELAY */ +# endif /* not O_NONBLOCK */ +# endif /* SYS_VXWORKS */ +#else /* SYS_WINNT */ + if (ioctlsocket(fd, FIONBIO, (u_long *) &on) == SOCKET_ERROR) { + msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m"); + exit(1); + } +#endif /* SYS_WINNT */ +} + + +/* + * sendpkt - send a packet to the specified destination + */ +static void +sendpkt( + struct sockaddr_in *dest, + struct pkt *pkt, + int len + ) +{ + int cc; + +#ifdef SYS_WINNT + DWORD err; +#endif /* SYS_WINNT */ + + cc = sendto(fd, (char *)pkt, len, 0, (struct sockaddr *)dest, + sizeof(struct sockaddr_in)); +#ifndef SYS_WINNT + if (cc == -1) { + if (errno != EWOULDBLOCK && errno != ENOBUFS) +#else + if (cc == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAENOBUFS) +#endif /* SYS_WINNT */ + msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + } +} + + +/* + * input_handler - receive packets asynchronously + */ +void +input_handler(void) +{ + register int n; + register struct recvbuf *rb; + struct timeval tvzero; + int fromlen; + l_fp ts; +#ifdef HAVE_POLL_H + struct pollfd fds; +#else + fd_set fds; +#endif + + /* + * Do a poll to see if we have data + */ + for (;;) { + fds = fdmask; + tvzero.tv_sec = tvzero.tv_usec = 0; +#ifdef HAVE_POLL_H + n = poll(&fds, 1, tvzero.tv_sec * 1000); +#else + n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero); +#endif + + /* + * 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) { + if (errno != EINTR) + msyslog(LOG_ERR, +#ifdef HAVE_POLL_H + "poll() error: %m" +#else + "select() error: %m" +#endif + ); + 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_recvbuffs() == 0) { + char buf[100]; + +#ifndef SYS_WINNT + (void) read(fd, buf, sizeof buf); +#else + /* NT's _read does not operate on nonblocking sockets + * either recvfrom or ReadFile() has to be used here. + * ReadFile is used in [ntpd]ntp_intres() and ntpdc, + * just to be different use recvfrom() here + */ + recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL); +#endif /* SYS_WINNT */ + continue; + } + + rb = get_free_recv_buffer(); + + fromlen = sizeof(struct sockaddr_in); + rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt, + sizeof(rb->recv_pkt), 0, + (struct sockaddr *)&rb->recv_srcadr, &fromlen); + if (rb->recv_length == -1) { + freerecvbuf(rb); + continue; + } + + /* + * Got one. Mark how and when it got here, + * put it on the full list. + */ + rb->recv_time = ts; + add_full_recv_buffer(rb); + } +} + + +#if !defined SYS_WINNT && !defined SYS_CYGWIN32 +/* + * adj_systime - do a big long slew of the system time + */ +static int +l_adj_systime( + l_fp *ts + ) +{ + struct timeval adjtv, oadjtv; + int isneg = 0; + l_fp offset; +#ifndef STEP_SLEW + l_fp overshoot; +#endif + + /* + * 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) { + msyslog(LOG_ERR, "Can't adjust the time of day: %m"); + return 0; + } + } + return 1; +} +#endif /* SYS_WINNT */ + + +/* + * This fuction is not the same as lib/systime step_systime!!! + */ +static int +l_step_systime( + l_fp *ts + ) +{ + double dtemp; + +#ifdef SLEWALWAYS +#ifdef STEP_SLEW + l_fp ftmp; + int isneg; + int n; + + if (debug) return 1; + /* + * Take the absolute value of the offset + */ + ftmp = *ts; + if (L_ISNEG(&ftmp)) { + L_NEG(&ftmp); + isneg = 1; + } else + isneg = 0; + + if (ftmp.l_ui >= 3) { /* Step it and slew - we might win */ + n = step_systime(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 + LFPTOD(ts, dtemp); + return step_systime(dtemp); +#else + l_adj_systime(ts); + return 1; +#endif +#else /* SLEWALWAYS */ + if (debug) + return 1; + LFPTOD(ts, dtemp); + return step_systime(dtemp); +#endif /* SLEWALWAYS */ +} + +/* + * getnetnum - given a host name, return its net number + */ +static int +getnetnum( + const char *host, + u_int32 *num + ) +{ + struct hostent *hp; + + if (decodenetnum(host, num)) { + return 1; + } else if ((hp = gethostbyname(host)) != 0) { + memmove((char *)num, hp->h_addr, sizeof(u_int32)); + return (1); + } + return (0); +} + +/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */ +/* + * printserver - print detail information for a server + */ +static void +printserver( + 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, 6), fptoa((s_fp)pp->delay, 5)); + 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((s_fp)pp->delay, 5), + ufptoa(pp->dispersion, 5)); + + (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", fptoa(pp->filter_delay[i], 5)); + 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], 6)); + if (i == (PEER_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "delay %s, dispersion %s\n", + fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5)); + + (void) fprintf(fp, "offset %s\n\n", + lfptoa(&pp->offset, 6)); +} + +#if !defined(HAVE_VSPRINTF) +int +vsprintf( + 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 + +#if 0 +/* override function in library since SA_RESTART makes ALL syscalls restart */ +#ifdef SA_RESTART +void +signal_no_reset( + 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); + } +} +#endif +#endif + +#ifdef HAVE_NETINFO +static ni_namelist * +getnetinfoservers(void) +{ + ni_status status; + void *domain; + ni_id confdir; + ni_namelist *namelist = (ni_namelist*)malloc(sizeof(ni_namelist)); + + /* Find a time server in NetInfo */ + if ((status = ni_open(NULL, ".", &domain)) != NI_OK) return NULL; + + while (status = ni_pathsearch(domain, &confdir, NETINFO_CONFIG_DIR) == NI_NODIR) { + void *next_domain; + if (ni_open(domain, "..", &next_domain) != NI_OK) break; + ni_free(domain); + domain = next_domain; + } + if (status != NI_OK) return NULL; + + NI_INIT(namelist); + if (ni_lookupprop(domain, &confdir, "server", namelist) != NI_OK) { + ni_namelist_free(namelist); + free(namelist); + return NULL; + } + + return(namelist); +} +#endif diff --git a/contrib/ntp/ntpdate/ntpdate.h b/contrib/ntp/ntpdate/ntpdate.h new file mode 100644 index 000000000000..85e438e3307c --- /dev/null +++ b/contrib/ntp/ntpdate/ntpdate.h @@ -0,0 +1,95 @@ +/* + * ntpdate.h - declarations for the ntpdate and ntptimeset programs + */ + +#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 server *next_server; /* next server in build list */ + struct sockaddr_in srcadr; /* address of remote host */ + u_char version; /* version to use */ + 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_int32 refid; /* peer reference ID */ + l_fp reftime; /* time of peer's last update */ + u_long event_time; /* time for next timeout */ + u_long last_xmit; /* time of last transmit */ + u_short xmtcnt; /* number of packets transmitted */ + u_short rcvcnt; /* number of packets received */ + u_char reach; /* reachability, NTP_WINDOW bits */ + 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 */ +#define PEER_MAXDISP (64*FP_SECOND) /* maximum dispersion (fp 64) */ + + +/* + * Some defaults + */ +#define DEFTIMEOUT 5 /* 5 timer increments */ +#define DEFSAMPLES 4 /* get 4 samples per server */ +#define DEFPRECISION (-5) /* the precision we claim */ +#define DEFMAXPERIOD 60 /* maximum time to wait */ +#define DEFMINSERVERS 3 /* minimum responding servers */ +#define DEFMINVALID 1 /* mimimum servers with valid time */ diff --git a/contrib/ntp/ntpdate/ntptime_config.c b/contrib/ntp/ntpdate/ntptime_config.c new file mode 100644 index 000000000000..56f653932c2d --- /dev/null +++ b/contrib/ntp/ntpdate/ntptime_config.c @@ -0,0 +1,557 @@ +/* + * ntptime_config.c + * + * What follows is a simplified version of the config parsing code + * in ntpd/ntp_config.c. We only parse a subset of the configuration + * syntax, and don't bother whining about things we don't understand. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#include +#include +#include +#include + +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_filegen.h" +#include "ntpdate.h" +#include "ntp_syslog.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 +# ifndef SYS_WINNT +# define CONFIG_FILE "/etc/ntp.conf" +# else /* SYS_WINNT */ +# define CONFIG_FILE "%windir%\\ntp.conf" +# define ALT_CONFIG_FILE "%windir%\\ntp.ini" +# endif /* SYS_WINNT */ +#endif /* not CONFIG_FILE */ + +/* + * + * We understand the following configuration entries and defaults. + * + * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * server [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * keys file_name + */ + +#define CONFIG_UNKNOWN 0 + +#define CONFIG_PEER 1 +#define CONFIG_SERVER 2 +#define CONFIG_KEYS 8 + +#define CONF_MOD_VERSION 1 +#define CONF_MOD_KEY 2 +#define CONF_MOD_MINPOLL 3 +#define CONF_MOD_MAXPOLL 4 +#define CONF_MOD_PREFER 5 +#define CONF_MOD_BURST 6 +#define CONF_MOD_SKEY 7 +#define CONF_MOD_TTL 8 +#define CONF_MOD_MODE 9 + +/* + * Translation table - keywords to function index + */ +struct keyword { + const char *text; + int keytype; +}; + +/* + * Command keywords + */ +static struct keyword keywords[] = { + { "peer", CONFIG_PEER }, + { "server", CONFIG_SERVER }, + { "keys", CONFIG_KEYS }, + { "", CONFIG_UNKNOWN } +}; + +/* + * "peer", "server", "broadcast" 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 }, + { "burst", CONF_MOD_BURST }, + { "autokey", CONF_MOD_SKEY }, + { "mode", CONF_MOD_MODE }, /* reference clocks */ + { "ttl", CONF_MOD_TTL }, /* NTP peers */ + { "", 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) + +/* + * Systemwide parameters and flags + */ +extern struct server **sys_servers; /* the server list */ +extern int sys_numservers; /* number of servers to poll */ +extern char *key_file; + +/* + * Function prototypes + */ +static int gettokens P((FILE *, char *, char **, int *)); +static int matchkey P((char *, struct keyword *)); +static int getnetnum P((const char *num, struct sockaddr_in *addr, + int complain)); + + +/* + * loadservers - load list of NTP servers from configuration file + */ +void +loadservers( + char *cfgpath + ) +{ + register int i; + int errflg; + int peerversion; + int minpoll; + int maxpoll; + /* int ttl; */ + int srvcnt; + /* u_long peerkey; */ + int peerflags; + struct sockaddr_in peeraddr; + FILE *fp; + char line[MAXLINE]; + char *(tokens[MAXTOKENS]); + int ntokens; + int tok; + const char *config_file; +#ifdef SYS_WINNT + char *alt_config_file; + LPTSTR temp; + char config_file_storage[MAX_PATH]; + char alt_config_file_storage[MAX_PATH]; +#endif /* SYS_WINNT */ + struct server *server, *srvlist; + + /* + * Initialize, initialize + */ + srvcnt = 0; + srvlist = 0; + errflg = 0; +#ifdef DEBUG + debug = 0; +#endif /* DEBUG */ +#ifndef SYS_WINNT + config_file = cfgpath ? cfgpath : CONFIG_FILE; +#else + if (cfgpath) { + config_file = cfgpath; + } else { + temp = CONFIG_FILE; + if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n"); + exit(1); + } + config_file = config_file_storage; + } + + temp = ALT_CONFIG_FILE; + if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n"); + exit(1); + } + alt_config_file = alt_config_file_storage; +M +#endif /* SYS_WINNT */ + + if ((fp = fopen(FindConfig(config_file), "r")) == NULL) + { + fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file)); + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file)); +#ifdef SYS_WINNT + /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */ + + if ((fp = fopen(FindConfig(alt_config_file), "r")) == NULL) { + + /* + * Broadcast clients can sometimes run without + * a configuration file. + */ + + fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file)); + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file)); + return; + } +#else /* not SYS_WINNT */ + return; +#endif /* not SYS_WINNT */ + } + + while ((tok = gettokens(fp, line, tokens, &ntokens)) + != CONFIG_UNKNOWN) { + switch(tok) { + case CONFIG_PEER: + case CONFIG_SERVER: + + if (ntokens < 2) { + msyslog(LOG_ERR, + "No address for %s, line ignored", + tokens[0]); + break; + } + + if (!getnetnum(tokens[1], &peeraddr, 1)) { + /* Resolve now, or lose! */ + break; + } else { + errflg = 0; + + /* Shouldn't be able to specify multicast */ + if (IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr)) + || ISBADADR(&peeraddr)) { + msyslog(LOG_ERR, + "attempt to configure invalid address %s", + ntoa(&peeraddr)); + break; + } + } + + peerversion = NTP_VERSION; + minpoll = NTP_MINDPOLL; + maxpoll = NTP_MAXDPOLL; + /* peerkey = 0; */ + peerflags = 0; + /* ttl = 0; */ + for (i = 2; i < ntokens; i++) + switch (matchkey(tokens[i], mod_keywords)) { + case CONF_MOD_VERSION: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "peer/server version requires an argument"); + errflg = 1; + break; + } + peerversion = atoi(tokens[++i]); + if ((u_char)peerversion > NTP_VERSION + || (u_char)peerversion < NTP_OLDVERSION) { + msyslog(LOG_ERR, + "inappropriate version number %s, line ignored", + tokens[i]); + errflg = 1; + } + break; + + case CONF_MOD_KEY: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "key: argument required"); + errflg = 1; + break; + } + ++i; + /* peerkey = (int)atol(tokens[i]); */ + peerflags |= FLAG_AUTHENABLE; + break; + + case CONF_MOD_MINPOLL: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "minpoll: argument required"); + errflg = 1; + break; + } + minpoll = atoi(tokens[++i]); + if (minpoll < NTP_MINPOLL) + minpoll = NTP_MINPOLL; + break; + + case CONF_MOD_MAXPOLL: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "maxpoll: argument required" + ); + errflg = 1; + break; + } + maxpoll = atoi(tokens[++i]); + if (maxpoll > NTP_MAXPOLL) + maxpoll = NTP_MAXPOLL; + break; + + case CONF_MOD_PREFER: + peerflags |= FLAG_PREFER; + break; + + case CONF_MOD_BURST: + peerflags |= FLAG_BURST; + break; + + case CONF_MOD_SKEY: + peerflags |= FLAG_SKEY | FLAG_AUTHENABLE; + break; + + case CONF_MOD_TTL: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "ttl: argument required"); + errflg = 1; + break; + } + ++i; + /* ttl = atoi(tokens[i]); */ + break; + + case CONF_MOD_MODE: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "mode: argument required"); + errflg = 1; + break; + } + ++i; + /* ttl = atoi(tokens[i]); */ + break; + + case CONFIG_UNKNOWN: + errflg = 1; + break; + } + if (minpoll > maxpoll) { + msyslog(LOG_ERR, "config error: minpoll > maxpoll"); + errflg = 1; + } + if (errflg == 0) { + server = (struct server *)emalloc(sizeof(struct server)); + memset((char *)server, 0, sizeof(struct server)); + server->srcadr = peeraddr; + server->version = peerversion; + server->dispersion = PEER_MAXDISP; + server->next_server = srvlist; + srvlist = server; + srvcnt++; + } + break; + + case CONFIG_KEYS: + if (ntokens >= 2) { + key_file = (char *) emalloc(strlen(tokens[1]) + 1); + strcpy(key_file, tokens[1]); + } + break; + } + } + (void) fclose(fp); + + /* build final list */ + sys_numservers = srvcnt; + sys_servers = (struct server **) + emalloc(sys_numservers * sizeof(struct server *)); + for(i=0;inext_server; + } +} + + + +/* + * gettokens - read a line and return tokens + */ +static int +gettokens( + 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( + register char *word, + register struct keyword *keys + ) +{ + for (;;) { + if (keys->keytype == CONFIG_UNKNOWN) { + return CONFIG_UNKNOWN; + } + if (STRSAME(word, keys->text)) + return keys->keytype; + keys++; + } +} + + +/* + * getnetnum - return a net number (this is crude, but careful) + */ +static int +getnetnum( + const char *num, + struct sockaddr_in *addr, + int complain + ) +{ + register const char *cp; + register char *bp; + register int i; + register int temp; + char buf[80]; /* will core dump on really stupid stuff */ + u_int32 netnum; + + /* XXX ELIMINATE replace with decodenetnum */ + cp = num; + netnum = 0; + for (i = 0; i < 4; i++) { + bp = buf; + while (isdigit((int)*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 %lu\n", + num, i, buf, temp, (u_long)netnum); +#endif + } + + if (i < 4) { + if (complain) + msyslog(LOG_ERR, + "getnetnum: \"%s\" invalid host number, line ignored", + num); +#ifdef DEBUG + if (debug > 3) + printf( + "getnetnum: \"%s\" invalid host number, line ignored\n", + num); +#endif + return 0; + } + + /* + * make up socket address. Clear it out for neatness. + */ + memset((void *)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 (%lx)\n", + num, ntoa(addr), (u_long)netnum); +#endif + return 1; +} diff --git a/contrib/ntp/ntpdate/ntptimeset.c b/contrib/ntp/ntpdate/ntptimeset.c new file mode 100644 index 000000000000..bf618cad9872 --- /dev/null +++ b/contrib/ntp/ntpdate/ntptimeset.c @@ -0,0 +1,2174 @@ +/* + * ntptimeset - get/set the time via ntp + * + * GOAL: + * The goal of ntptime is to set the current time on system startup + * to the best possible time using the network very wisely. It is assumed + * that after a resonable time has been sett then ntp daemon will + * maintain it. + * + * PROBLEM DOMAIN: + * We have three sets of issues related to acheiving the goal. The first + * issue is using the network when normal traffic is happening or when + * the entire network world is recovering from a campus wide power failure + * and is restarting. The second issue is the class of machine whether it + * is a user's office workstation being handled by an uneducated user or + * a server computer being handled by a trained operations staff. The third + * issue is whether the ratio of people to computers and whether the + * environment is stable and viable or not. + * + * NETWORK USAGE: + * The first issue of using the network wisely is a question of whether + * the network load and time server load and state are normal. If things + * are normal ntptime can do what ntpdate does of sending out 4 packets + * quickly to each server (new transmit done with each ack). However + * if network or time load is high then this scheme will simply contribute + * to problems. Given we have minimal state, we simply weight lost packets + * significantly and make sure we throttle output as much as possible + * without performance lost for quick startups. + * + * TRAINING AND KNOWLEDGE: + * The second issue of uneducated user of a office workstation versus a + * trained operation staff of a server machine translates into simply an + * issue of untrained and trained users. + * + * The training issue implies that for the sake of the users involved in the + * handling of their office workstation, problems and options should be + * communicated simply and effectively and not in terse expert related + * descriptions without possible options to be taken. The operator's training + * and education enables them to deal with either type of communication and + * control. + * + * AUTOMATION AND MANUAL CONTROL: + * The last issue boils down to a design problem. If the design tends to go + * into a manual mode when the environment is non-viable then one person + * handling many computers all at the same time will be heavily impacted. On + * the other hand, if the design tends to be automatic and does not indicate + * a way for the user to take over control then the computer will be + * unavailable for the user until the proble is resolved by someone else or + * the user. + * + * NOTE: Please do not have this program print out every minute some line, + * of output. If this happens and the environment is in trouble then + * many pages of paper on many different machines will be filled up. + * Save some tress in your lifetime. + * + * CONCLUSION: + * The behavior of the program derived from these three issues should be + * that during normal situations it quickly sets the time and allow the + * system to startup. + * + * However during abnormal conditions as detected by unresponsive servers, + * out-of-sync or bad responses and other detections, it should print out + * a simple but clear message and continue in a mellow way to get the best + * possible time. It may never get the time and if so should also indicate + * this. + * + * Rudy Nedved + * 18-May-1993 + * + **************************************************************** + * + * Much of the above is confusing or no longer relevant. For example, + * it is rare these days for a machine's console to be a printing terminal, + * so the comment about saving trees doesn't mean much. Nonetheless, + * the basic principles still stand: + * + * - Work automatically, without human control or intervention. To + * this end, we use the same configuration file as ntpd itself, so + * you don't have to specify servers or other information on the + * command line. We also recognize that sometimes we won't be able + * to contact any servers, and give up in that event instead of + * hanging forever. + * + * - Behave in a sane way, both internally and externally, even in the + * face of insane conditions. That means we back off quickly when + * we don't hear a response, to avoid network congestion. Like + * ntpd, we verify responses from several servers before accepting + * the new time data. + * + * However, we don't assume that the local clock is right, or even + * close, because it might not be at boot time, and we want to catch + * and correct that situation. This behaviour has saved us in several + * instances. On HP-UX 9.0x, there used to be a bug in adjtimed which + * would cause the time to be set to some wild value, making the machine + * essentially unusable (we use Kerberos authentication pervasively, + * and it requires workstations and servers to have a time within five + * minutes of the Kerberos server). We also have problems on PC's + * running both Linux and some Microsoft OS -- they tend to disagree + * on what the BIOS clock should say, and who should update it, and + * when. On those systems, we not only run ntptimeset at boot, we + * also reset the BIOS clock based on the result, so the correct + * time will be retained across reboots. + * + * For these reasons, and others, we have continued to use this tool + * rather than ntpdate. It is run automatically at boot time on every + * workstation and server in our facility. + * + * In the past, we called this program 'ntptime'. Unfortunately, the + * ntp v4 distribution also includes a program with that name. In + * order to avoid confusion, we have renamed our program 'ntptimeset', + * which more accurately describes what it does. + * + * Jeffrey T. Hutzelman (N3NHS) + * School of Computer Science - Research Computing Facility + * Carnegie Mellon University - Pittsburgh, PA + * 16-Aug-1999 + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#ifndef SYS_WINNT +# include +# include +# include +#endif /* SYS_WINNT */ +#include +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif /* HAVE_SYS_RESOURCE_H */ + +#ifdef SYS_VXWORKS +# include "ioLib.h" +# include "sockLib.h" +# include "timers.h" +#endif + + +#if defined(SYS_HPUX) +# include +#endif + +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "iosignal.h" +#include "ntp_unixtime.h" +#include "ntpdate.h" +#include "ntp_string.h" +#include "ntp_syslog.h" +#include "ntp_select.h" +#include "ntp_stdlib.h" +#include "recvbuff.h" + +#ifdef SYS_WINNT +# define TARGET_RESOLUTION 1 /* Try for 1-millisecond accuracy + on Windows NT timers. */ +#pragma comment(lib, "winmm") +#endif /* SYS_WINNT */ + +/* + * Scheduling priority we run at + */ +#ifndef SYS_VXWORKS +# define NTPDATE_PRIO (-12) +#else +# define NTPDATE_PRIO (100) +#endif + +#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE) +/* POSIX TIMERS - vxWorks doesn't have itimer - casey */ +static timer_t ntpdate_timerid; +#endif + +/* + * 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 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 + */ +volatile 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 + */ +volatile int alarm_flag = 0; + +/* + * Set the time if valid time determined + */ +int set_time = 0; + +/* + * transmission rate control + */ +#define MINTRANSMITS (3) /* minimum total packets per server */ +#define MAXXMITCOUNT (2) /* maximum packets per time interrupt */ + +/* + * time setting constraints + */ +#define DESIREDDISP (4*FP_SECOND) /* desired dispersion, (fp 4) */ +int max_period = DEFMAXPERIOD; +int min_servers = DEFMINSERVERS; +int min_valid = DEFMINVALID; + +/* + * counters related to time setting constraints + */ +int contacted = 0; /* # of servers we have sent to */ +int responding = 0; /* servers responding */ +int validcount = 0; /* servers with valid time */ +int valid_n_low = 0; /* valid time servers with low dispersion */ + +/* + * Unpriviledged port flag. + */ +int unpriv_port = 0; + +/* + * Program name. + */ +char *progname; + +/* + * Systemwide parameters and flags + */ +struct server **sys_servers; /* the server list */ +int sys_numservers = 0; /* number of servers to poll */ +int sys_authenticate = 0; /* true when authenticating */ +u_int32 sys_authkey = 0; /* set to authentication key in use */ +u_long sys_authdelay = 0; /* authentication delay */ + +/* + * The current internal time + */ +u_long current_time = 0; + +/* + * File of encryption keys + */ + +#ifndef KEYFILE +# ifndef SYS_WINNT +#define KEYFILE "/etc/ntp.keys" +# else +#define KEYFILE "%windir%\\ntp.keys" +# endif /* SYS_WINNT */ +#endif /* KEYFILE */ + +#ifndef SYS_WINNT +const char *key_file = KEYFILE; +#else +char key_file_storage[MAX_PATH+1], *key_file ; +#endif /* SYS_WINNT */ + +/* + * total packet counts + */ +u_long total_xmit = 0; +u_long total_recv = 0; + +/* + * Miscellaneous flags + */ +int verbose = 0; +#define HORRIBLEOK 3 /* how many packets to let out */ +int horrible = 0; /* how many packets we drop for testing */ +int secondhalf = 0; /* second half of timeout period */ +int printmsg = 0; /* print time response analysis */ + +/* + * The half time and finish time in internal time + */ +u_long half_time = 0; +u_long finish_time = 0; + + +int ntptimesetmain P((int argc, char *argv[])); +extern void loadservers P((char *cfgpath)); +static void analysis P((int final)); +static int have_enough P((void)); +static void transmit P((register struct server *server)); +static void receive P((struct recvbuf *rbufp)); +static void clock_filter P((register struct server *server, s_fp d, l_fp *c)); +static void clock_count P((void)); +static struct server *clock_select P((void)); +static void set_local_clock P((void)); +static struct server *findserver P((struct sockaddr_in *addr)); +static void timer P((void)); +#ifndef SYS_WINNT +static RETSIGTYPE alarming P((int sig)); +#endif /* SYS_WINNT */ +static void init_alarm P((void)); +static void init_io P((void)); +static int sendpkt P((struct sockaddr_in *dest, struct pkt *pkt, int len)); + void input_handler P((l_fp *xts)); +static void printserver P((register struct server *pp, FILE *fp)); +#if !defined(HAVE_VSPRINTF) +int vsprintf P((char *str, const char *fmt, va_list ap)); +#endif + +#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 + + +#ifdef NO_MAIN_ALLOWED +CALL(ntptimeset,"ntptimeset",ntptimesetmain); + +void clear_globals() +{ + /* + * Debugging flag + */ + debug = 0; + + ntp_optind = 0; + + /* + * Initializing flag. All async routines watch this and only do their + * thing when it is clear. + */ + initializing = 1; + + /* + * Alarm flag. Set when an alarm occurs + */ + alarm_flag = 0; + + /* + * Unpriviledged port flag. + */ + unpriv_port = 0; + + /* + * Systemwide parameters and flags + */ + sys_numservers = 0; /* number of servers to poll */ + sys_authenticate = 0; /* true when authenticating */ + sys_authkey = 0; /* set to authentication key in use */ + sys_authdelay = 0; /* authentication delay */ + + /* + * The current internal time + */ + current_time = 0; + + verbose = 0; +} +#endif /* NO_MAIN_ALLOWED */ + +/* + * Main program. Initialize us and loop waiting for I/O and/or + * timer expiries. + */ +#ifndef NO_MAIN_ALLOWED +int +main( + int argc, + char *argv[] + ) +{ + return ntptimesetmain(argc, argv); +} +#endif /* NO_MAIN_ALLOWED */ + + +int +ntptimesetmain( + 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; + int ltmp; + char *cfgpath; + +#ifdef SYS_WINNT + HANDLE process_handle; + + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) { + msyslog(LOG_ERR, "No useable winsock.dll: %m"); + exit(1); + } +#endif /* SYS_WINNT */ + +#ifdef NO_MAIN_ALLOWED + clear_globals(); +#endif + + errflg = 0; + cfgpath = 0; + progname = argv[0]; + syslogit = 0; + + /* + * Decode argument list + */ + while ((c = ntp_getopt(argc, argv, "a:c:de:slt:uvHS:V:")) != EOF) + switch (c) + { + case 'a': + c = atoi(ntp_optarg); + sys_authenticate = 1; + sys_authkey = c; + break; + case 'c': + cfgpath = ntp_optarg; + 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 's': + set_time = 1; + break; + case 'l': + syslogit = 1; + break; + case 't': + ltmp = atoi(ntp_optarg); + if (ltmp <= 0) { + (void) fprintf(stderr, + "%s: maximum time period (%d) is invalid\n", + progname, ltmp); + errflg++; + } + else + max_period = ltmp; + break; + case 'u': + unpriv_port = 1; + break; + case 'v': + ++verbose; + break; + case 'H': + horrible++; + break; + case 'S': + ltmp = atoi(ntp_optarg); + if (ltmp <= 0) { + (void) fprintf(stderr, + "%s: minimum responding (%d) is invalid\n", + progname, ltmp); + errflg++; + } + else + min_servers = ltmp; + break; + case 'V': + ltmp = atoi(ntp_optarg); + if (ltmp <= 0) { + (void) fprintf(stderr, + "%s: minimum valid (%d) is invalid\n", + progname, ltmp); + errflg++; + } + else + min_valid = ltmp; + break; + case '?': + ++errflg; + break; + default: + break; + } + + + if (errflg || ntp_optind < argc) { + fprintf(stderr,"usage: %s [switches...]\n",progname); + fprintf(stderr," -v (verbose)\n"); + fprintf(stderr," -c path (set config file path)\n"); + fprintf(stderr," -a key (authenticate using key)\n"); + fprintf(stderr," -e delay (authentication delay)\n"); + fprintf(stderr," -S num (# of servers that must respond)\n"); + fprintf(stderr," -V num (# of servers that must valid)\n"); + fprintf(stderr," -s (set the time based if okay)\n"); + fprintf(stderr," -t secs (time period before ending)\n"); + fprintf(stderr," -l (use syslog facility)\n"); + fprintf(stderr," -u (use unprivileged port)\n"); + fprintf(stderr," -H (drop packets for debugging)\n"); + fprintf(stderr," -d (debug output)\n"); + exit(2); + } + + /* + * Logging. Open the syslog if we have to + */ + if (syslogit) { +#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32 +# ifndef LOG_DAEMON + openlog("ntptimeset", LOG_PID); +# else + +# ifndef LOG_NTP +# define LOG_NTP LOG_DAEMON +# endif + openlog("ntptimeset", LOG_PID | LOG_NDELAY, LOG_NTP); + if (debug) + setlogmask(LOG_UPTO(LOG_DEBUG)); + else + setlogmask(LOG_UPTO(LOG_INFO)); +# endif /* LOG_DAEMON */ +#endif /* SYS_WINNT */ + } + + if (debug || verbose) + msyslog(LOG_INFO, "%s", Version); + + if (horrible) + msyslog(LOG_INFO, "Dropping %d out of %d packets", + horrible,horrible+HORRIBLEOK); + /* + * Add servers we are going to be polling + */ + loadservers(cfgpath); + + if (sys_numservers < min_servers) { + msyslog(LOG_ERR, "Found %d servers, require %d servers", + sys_numservers,min_servers); + exit(2); + } + + /* + * determine when we will end at least + */ + finish_time = max_period * TIMER_HZ; + half_time = finish_time >> 1; + + /* + * Initialize the time of day routines and the I/O subsystem + */ + if (sys_authenticate) { + init_auth(); +#ifdef SYS_WINNT + if (!key_file) key_file = KEYFILE; + if (!ExpandEnvironmentStrings(key_file, key_file_storage, MAX_PATH)) + { + msyslog(LOG_ERR, "ExpandEnvironmentStrings(%s) failed: %m\n", + key_file); + } else { + key_file = key_file_storage; + } +#endif /* SYS_WINNT */ + + if (!authreadkeys(key_file)) { + msyslog(LOG_ERR, "no key file, exiting"); + exit(1); + } + if (!authistrusted(sys_authkey)) { + char buf[10]; + + (void) sprintf(buf, "%lu", (unsigned long)sys_authkey); + msyslog(LOG_ERR, "authentication key %s unknown", buf); + exit(1); + } + } + init_io(); + init_alarm(); + + /* + * Set the priority. + */ +#ifdef SYS_VXWORKS + taskPrioritySet( taskIdSelf(), NTPDATE_PRIO); +#endif +#if defined(HAVE_ATT_NICE) + nice (NTPDATE_PRIO); +#endif +#if defined(HAVE_BSD_NICE) + (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO); +#endif +#ifdef SYS_WINNT + process_handle = GetCurrentProcess(); + if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) { + msyslog(LOG_ERR, "SetPriorityClass failed: %m"); + } +#endif /* SYS_WINNT */ + + initializing = 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. + * Keep going until we have enough information, or time is up. + */ + /* On VMS, I suspect that select() can't be interrupted + * by a "signal" either, so I take the easy way out and + * have select() time out after one second. + * System clock updates really aren't time-critical, + * and - lacking a hardware reference clock - I have + * yet to learn about anything else that is. + */ + was_alarmed = 0; + rbuflist = (struct recvbuf *)0; + while (finish_time > current_time) { +#if !defined(HAVE_SIGNALED_IO) + fd_set rdfdes; + int nfound; +#elif defined(HAVE_SIGNALED_IO) + block_io_and_alarm(); +#endif + + rbuflist = getrecvbufs(); /* get received buffers */ + if (printmsg) { + printmsg = 0; + analysis(0); + } + 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 = fdmask; +# if defined(VMS) || defined(SYS_VXWORKS) + /* make select() wake up after one second */ + { + struct timeval t1; + + t1.tv_sec = 1; t1.tv_usec = 0; + nfound = select(fd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, &t1); + } +# else + nfound = select(fd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, (struct timeval *)0); +# endif /* VMS */ + if (nfound > 0) { + l_fp ts; + get_systime(&ts); + (void)input_handler(&ts); + } + else if (nfound == -1 && errno != EINTR) + msyslog(LOG_ERR, "select() error: %m"); + else if (debug) { +# if !defined SYS_VXWORKS && !defined SYS_CYGWIN32 /* to unclutter log */ + msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound); +# endif + } +#else /* HAVE_SIGNALED_IO */ + + wait_for_signal(); +#endif /* HAVE_SIGNALED_IO */ + if (alarm_flag) /* alarmed? */ + { + was_alarmed = 1; + alarm_flag = 0; + } + rbuflist = getrecvbufs(); /* get received buffers */ + } +#ifdef HAVE_SIGNALED_IO + unblock_io_and_alarm(); +#endif /* HAVE_SIGNALED_IO */ + + /* + * Out here, signals are unblocked. Call timer routine + * to process expiry. + */ + if (was_alarmed) + { + timer(); + was_alarmed = 0; + } + + /* + * Call the data procedure to handle each received + * packet. + */ + while (rbuflist != (struct recvbuf *)0) + { + rbuf = rbuflist; + rbuflist = rbuf->next; + receive(rbuf); + freerecvbuf(rbuf); + } +#if defined DEBUG && defined SYS_WINNT + if (debug > 4) + printf("getrecvbufs: %ld handler interrupts, %ld frames\n", + handler_calls, handler_pkts); +#endif + + /* + * Do we have enough information to stop now? + */ + if (have_enough()) + break; /* time to end */ + + /* + * Go around again + */ + } + + /* + * adjust the clock and exit accordingly + */ + set_local_clock(); + + /* + * if we get here then we are in trouble + */ + return(1); +} + + +/* + * analysis - print a message indicating what is happening with time service + * must mimic have_enough() procedure. + */ +static void +analysis( + int final + ) +{ + if (contacted < sys_numservers) { + printf("%d servers of %d have been probed with %d packets\n", + contacted,sys_numservers,MINTRANSMITS); + return; + } + if (!responding) { + printf("No response from any of %d servers, network problem?\n", + sys_numservers); + return; + } + else if (responding < min_servers) { + printf("%d servers out of %d responding, need at least %d.\n", + responding, sys_numservers, min_servers); + return; + } + if (!validcount) { + printf("%d servers responding but none have valid time\n", + responding); + return; + } + else if (validcount < min_valid) { + printf("%d servers responding, %d are valid, need %d valid\n", + responding,validcount,min_valid); + return; + } + if (!final && valid_n_low != validcount) { + printf("%d valid servers but only %d have low dispersion\n", + validcount,valid_n_low); + return; + } +} + + +/* have_enough - see if we have enough information to terminate probing + */ +static int +have_enough(void) +{ + /* have we contacted all servers yet? */ + if (contacted < sys_numservers) + return 0; /* no...try some more */ + + /* have we got at least minimum servers responding? */ + if (responding < min_servers) + return 0; /* no...try some more */ + + /* count the clocks */ + (void) clock_count(); + + /* have we got at least minimum valid clocks? */ + if (validcount <= 0 || validcount < min_valid) + return 0; /* no...try some more */ + + /* do we have all valid servers with low dispersion */ + if (!secondhalf && valid_n_low != validcount) + return 0; + + /* if we get into the secondhalf then we ignore dispersion */ + + /* all conditions have been met...end */ + return 1; +} + + +/* + * 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( + register struct server *server + ) +{ + struct pkt xpkt; + int timeout; + + if (debug > 2) + printf("transmit(%s)\n", ntoa(&server->srcadr)); + + if ((server->reach & 01) == 0) { + l_fp ts; + /* + * Last message to this server timed out. Shift + * zeros into the filter. + */ + L_CLR(&ts); + clock_filter(server, 0, &ts); + } + + /* + * shift reachable register over + */ + server->reach <<= 1; + + /* + * 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, + server->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); + L_CLR(&xpkt.reftime); + L_CLR(&xpkt.org); + L_CLR(&xpkt.rec); + + /* + * 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.keyid1 = htonl(sys_authkey); + get_systime(&server->xmt); + L_ADDUF(&server->xmt, sys_authdelay); + HTONL_FP(&server->xmt, &xpkt.xmt); + len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC); + if (sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len))) { + if (debug > 1) + printf("failed transmit auth to %s\n", + ntoa(&(server->srcadr))); + return; + } + + if (debug > 1) + printf("transmit auth to %s\n", + ntoa(&(server->srcadr))); + } else { + get_systime(&(server->xmt)); + HTONL_FP(&server->xmt, &xpkt.xmt); + if (sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC)) { + if (debug > 1) + printf("failed transmit to %s\n", + ntoa(&(server->srcadr))); + return; + } + + if (debug > 1) + printf("transmit to %s\n", ntoa(&(server->srcadr))); + } + + /* + * count transmits, record contacted count and set transmit time + */ + if (++server->xmtcnt == MINTRANSMITS) + contacted++; + server->last_xmit = current_time; + + /* + * determine timeout for this packet. The more packets we send + * to the host, the slower we get. If the host indicates that + * it is not "sane" then we expect even less. + */ + if (server->xmtcnt < MINTRANSMITS) { + /* we have not sent enough */ + timeout = TIMER_HZ; /* 1 second probe */ + } + else if (server->rcvcnt <= 0) { + /* we have heard nothing */ + if (secondhalf) + timeout = TIMER_HZ<<4; /* 16 second probe */ + else + timeout = TIMER_HZ<<3; /* 8 second probe */ + } + else { + /* if we have low dispersion then probe infrequently */ + if (server->dispersion <= DESIREDDISP) + timeout = TIMER_HZ<<4; /* 16 second probe */ + /* if the server is not in sync then let it alone */ + else if (server->leap == LEAP_NOTINSYNC) + timeout = TIMER_HZ<<4; /* 16 second probe */ + /* if the server looks broken ignore it */ + else if (server->org.l_ui < server->reftime.l_ui) + timeout = TIMER_HZ<<5; /* 32 second probe */ + else if (secondhalf) + timeout = TIMER_HZ<<2; /* 4 second probe */ + else + timeout = TIMER_HZ<<1; /* 2 second probe */ + } + + /* + * set next transmit time based on timeout + */ + server->event_time = current_time + timeout; +} + + +/* + * receive - receive and process an incoming frame + */ +static void +receive( + struct recvbuf *rbufp + ) +{ + register struct pkt *rpkt; + register struct server *server; + register s_fp di; + l_fp t10, t23; + l_fp org; + l_fp rec; + l_fp ci; + int has_mac; + int is_authentic; + + if (debug > 2) + 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 > 2) + 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) { + if (debug > 1) + printf("receive: bad version %d\n", + PKT_VERSION(rpkt->li_vn_mode)); + return; + } + + if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER + && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) + || rpkt->stratum > NTP_MAXSTRATUM) { + if (debug > 1) + 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 > 1) + 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 > 1) + 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=%ld sys_authkey=%ld decrypt=%ld\n", + (long int)ntohl(rpkt->keyid1), (long int)sys_authkey, + (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt, + LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC))); + + if (has_mac && ntohl(rpkt->keyid1) == sys_authkey && + authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC, + (int)(rbufp->recv_length - 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); + + /* + * count this guy as responding + */ + server->reach |= 1; + if (server->rcvcnt++ == 0) + responding++; + + /* + * Make sure the server is at least somewhat sane. If not, ignore + * it for later. + */ + if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) { + if (debug > 1) + printf("receive: pkt insane\n"); + 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 = server->org; /* pkt.xmt == t1 */ + L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/ + + t23 = rec; /* pkt.rec == t2 */ + L_SUB(&t23, &org); /* pkt->org == t3 */ + + /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */ + ci = t10; + L_ADD(&ci, &t23); + L_RSHIFT(&ci); + + /* + * Calculate di in t23 in full precision, then truncate + * to an s_fp. + */ + L_SUB(&t23, &t10); + di = LFPTOFP(&t23); + + if (debug > 3) + printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5)); + + di += (FP_SECOND >> (-(int)NTPDATE_PRECISION)) + + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW; + + if (di <= 0) { /* value still too raunchy to use? */ + L_CLR(&ci); + di = 0; + } else { + di = max(di, NTP_MINDIST); + } + + + /* + * This one is valid. Give it to clock_filter(), + */ + clock_filter(server, di, &ci); + if (debug > 1) + printf("receive from %s\n", ntoa(&rbufp->srcadr)); + + /* + * See if we should goes the transmission. If not return now + * otherwise have the next event time be shortened + */ + if (server->stratum <= NTP_INFIN) + return; /* server does not have a stratum */ + if (server->leap == LEAP_NOTINSYNC) + return; /* just booted server or out of sync */ + if (!L_ISHIS(&server->org, &server->reftime)) + return; /* broken host */ + if (server->trust != 0) + return; /* can not trust it */ + + if (server->dispersion < DESIREDDISP) + return; /* we have the desired dispersion */ + + server->event_time -= (TIMER_HZ+1); +} + + +/* + * clock_filter - add clock sample, determine a server's delay, dispersion + * and offset + */ +static void +clock_filter( + register struct server *server, + s_fp di, + l_fp *c + ) +{ + register int i, j; + int ord[NTP_SHIFT]; + + /* + * Insert sample and increment nextpt + */ + + i = server->filter_nextpt; + server->filter_delay[i] = di; + server->filter_offset[i] = *c; + server->filter_soffset[i] = LFPTOFP(c); + server->filter_nextpt++; + if (server->filter_nextpt >= NTP_SHIFT) + server->filter_nextpt = 0; + + /* + * Sort indices into increasing delay order + */ + for (i = 0; i < NTP_SHIFT; i++) + ord[i] = i; + + for (i = 0; i < (NTP_SHIFT-1); i++) { + for (j = i+1; j < NTP_SHIFT; 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; + L_CLR(&server->offset); + 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 < NTP_SHIFT; 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_count - count the clock sources we have + */ +static void +clock_count(void) +{ + register struct server *server; + register int n; + + /* reset counts */ + validcount = valid_n_low = 0; + + /* go through the list of servers and count the clocks we believe + * and that have low dispersion + */ + 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 (!L_ISHIS(&server->org, &server->reftime)) { + 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 is a valid time source.. + */ + validcount++; + + /* + * See if this one has a okay low dispersion + */ + if (server->dispersion <= DESIREDDISP) + valid_n_low++; + } + + if (debug > 1) + printf("have %d, valid %d, low %d\n", + responding, validcount, valid_n_low); +} + + +/* + * clock_select - select the pick-of-the-litter clock from the samples + * we've got. + */ +static struct server * +clock_select(void) +{ + 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 (!L_ISHIS(&server->org, &server->reftime)) { + 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 < (s_fp) 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; +} + + +/* + * set_local_clock -- handle setting the local clock or displaying info. + */ +static void +set_local_clock(void) +{ + register int i; + register struct server *server; + time_t tmp; + double dtemp; + + /* + * if setting time then print final analysis + */ + if (set_time) + analysis(1); + + /* + * pick a clock + */ + server = clock_select(); + + /* + * do some display of information + */ + if (debug || verbose) { + for (i = 0; i < sys_numservers; i++) + printserver(sys_servers[i], stdout); + if (debug) + printf("packets sent %ld, received %ld\n", + total_xmit, total_recv); + } + + /* + * see if we have a server to set the time with + */ + if (server == 0) { + if (!set_time || verbose) + fprintf(stdout,"No servers available to sync time with\n"); + exit(1); + } + + /* + * we have a valid and selected time to use!!!!! + */ + + /* + * if we are not setting the time then display offset and exit + */ + if (!set_time) { + fprintf(stdout, + "Your clock is off by %s seconds. (%s) [%ld/%ld]\n", + lfptoa(&server->offset, 7), + ntoa(&server->srcadr), + total_xmit, total_recv); + exit(0); + } + + /* + * set the clock + * XXX: Examine the more flexible approach used by ntpdate. + * Note that a design consideration here is that we sometimes + * _want_ to step the clock by a _huge_ amount in either + * direction, because the local clock is completely bogus. + * This condition must be recognized and dealt with, so + * that we always get a good time when this completes. + * -- jhutz+@cmu.edu, 16-Aug-1999 + */ + LFPTOD(&server->offset, dtemp); + step_systime(dtemp); + time(&tmp); + fprintf(stdout,"Time set to %.20s [%s %s %ld/%ld]\n", + ctime(&tmp)+4, + ntoa(&server->srcadr), + lfptoa(&server->offset, 7), + total_xmit, total_recv); + exit(0); +} + + +/* + * findserver - find a server in the list given its address + */ +static struct server * +findserver( + struct sockaddr_in *addr + ) +{ + register int i; + register u_int32 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(void) +{ + register int k; + + /* + * Bump the current idea of the time + */ + current_time++; + + /* + * see if we have reached half time + */ + if (current_time >= half_time && !secondhalf) { + secondhalf++; + if (debug) + printf("\nSecond Half of Timeout!\n"); + printmsg++; + } + + /* + * We only want to send a few packets per transmit interrupt + * to throttle things + */ + for(k = 0;k < MAXXMITCOUNT;k++) { + register int i, oldi; + register u_long oldxtime; + + /* + * We want to send a packet out for a server that has an + * expired event time. However to be mellow about this, we only + * use one expired event timer and to avoid starvation we use + * the one with the oldest last transmit time. + */ + oldi = -1; + oldxtime = 0; + for (i = 0; i < sys_numservers; i++) { + if (sys_servers[i]->event_time <= current_time) { + if (oldi < 0 || oldxtime > sys_servers[i]->last_xmit) { + oldxtime = sys_servers[i]->last_xmit; + oldi = i; + } + } + } + if (oldi >= 0) + transmit(sys_servers[oldi]); + else + break; /* no expired event */ + } /* end of transmit loop */ +} + + +#ifndef SYS_WINNT +/* + * alarming - record the occurance of an alarm interrupt + */ +static RETSIGTYPE +alarming( + int sig + ) +#else +void CALLBACK +alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) +#endif /* SYS_WINNT */ +{ + alarm_flag++; +} + + +/* + * init_alarm - set up the timer interrupt + */ +static void +init_alarm(void) +{ +#ifndef SYS_WINNT +# ifndef HAVE_TIMER_SETTIME + struct itimerval itimer; +# else + struct itimerspec ntpdate_itimer; +# endif +#else + TIMECAPS tc; + UINT wTimerRes, wTimerID; +# endif /* SYS_WINNT */ +#if defined SYS_CYGWIN32 || defined SYS_WINNT + HANDLE hToken; + TOKEN_PRIVILEGES tkp; + DWORD dwUser = 0; +#endif /* SYS_WINNT */ + + alarm_flag = 0; + +#ifndef SYS_WINNT +# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) + alarm_flag = 0; + /* this code was put in as setitimer() is non existant this us the + * POSIX "equivalents" setup - casey + */ + /* ntpdate_timerid is global - so we can kill timer later */ + if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) == +# ifdef SYS_VXWORKS + ERROR +# else + -1 +# endif + ) + { + fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n"); + return; + } + + /* TIMER_HZ = (5) + * 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); + ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0; + ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ; + ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1); + timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL); +# else + /* + * 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); +# endif +#if defined SYS_CYGWIN32 + /* + * Get previleges needed for fiddling with the clock + */ + + /* get the current process token handle */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + msyslog(LOG_ERR, "OpenProcessToken failed: %m"); + exit(1); + } + /* get the LUID for system-time privilege. */ + LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; /* one privilege to set */ + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + /* get set-time privilege for this process. */ + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); + /* cannot test return value of AdjustTokenPrivileges. */ + if (GetLastError() != ERROR_SUCCESS) + msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); +#endif +#else /* SYS_WINNT */ + _tzset(); + + /* + * Get previleges needed for fiddling with the clock + */ + + /* get the current process token handle */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + msyslog(LOG_ERR, "OpenProcessToken failed: %m"); + exit(1); + } + /* get the LUID for system-time privilege. */ + LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; /* one privilege to set */ + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + /* get set-time privilege for this process. */ + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); + /* cannot test return value of AdjustTokenPrivileges. */ + if (GetLastError() != ERROR_SUCCESS) + msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); + + /* + * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds + * Under Win/NT, expiry of timer interval leads to invocation + * of a callback function (on a different thread) rather than + * generating an alarm signal + */ + + /* determine max and min resolution supported */ + if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) { + msyslog(LOG_ERR, "timeGetDevCaps failed: %m"); + exit(1); + } + wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax); + /* establish the minimum timer resolution that we'll use */ + timeBeginPeriod(wTimerRes); + + /* start the timer event */ + wTimerID = timeSetEvent( + (UINT) (1000/TIMER_HZ), /* Delay */ + wTimerRes, /* Resolution */ + (LPTIMECALLBACK) alarming, /* Callback function */ + (DWORD) dwUser, /* User data */ + TIME_PERIODIC); /* Event type (periodic) */ + if (wTimerID == 0) { + msyslog(LOG_ERR, "timeSetEvent failed: %m"); + exit(1); + } +#endif /* SYS_WINNT */ +} + + +/* + * init_io - initialize I/O data and open socket + */ +static void +init_io(void) +{ +#ifdef SYS_WINNT + WORD wVersionRequested; + WSADATA wsaData; + init_transmitbuff(); +#endif /* SYS_WINNT */ + + /* + * Init buffer free list and stat counters + */ + init_recvbuff(sys_numservers + 2); + +#if defined(HAVE_SIGNALED_IO) + set_signal(); +#endif + +#ifdef SYS_WINNT + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) + { + msyslog(LOG_ERR, "No useable winsock.dll: %m"); + exit(1); + } +#endif /* SYS_WINNT */ + + BLOCKIO(); + + /* create a datagram (UDP) socket */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + msyslog(LOG_ERR, "socket() failed: %m"); + exit(1); + /*NOTREACHED*/ + } + + /* + * bind the socket to the NTP port + */ + if (!debug && set_time && !unpriv_port) { + 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 = htonl(INADDR_ANY); + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { +#ifndef SYS_WINNT + if (errno == EADDRINUSE) +#else + if (WSAGetLastError() == WSAEADDRINUSE) +#endif + msyslog(LOG_ERR, + "the NTP socket is in use, exiting"); + else + msyslog(LOG_ERR, "bind() fails: %m"); + exit(1); + } + } + + FD_ZERO(&fdmask); + FD_SET(fd, &fdmask); + + /* + * set non-blocking, + */ + +#ifdef USE_FIONBIO + /* in vxWorks we use FIONBIO, but the others are defined for old systems, so + * all hell breaks loose if we leave them defined + */ +#undef O_NONBLOCK +#undef FNDELAY +#undef O_NDELAY +#endif + +#if defined(O_NONBLOCK) /* POSIX */ + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + { + msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FNDELAY) + if (fcntl(fd, F_SETFL, FNDELAY) < 0) + { + msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(O_NDELAY) /* generally the same as FNDELAY */ + if (fcntl(fd, F_SETFL, O_NDELAY) < 0) + { + msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FIONBIO) + if ( +# if defined(VMS) + (ioctl(fd,FIONBIO,&1) < 0) +# elif defined(SYS_WINNT) + (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) +# else + (ioctl(fd,FIONBIO,&on) < 0) +# endif + ) + { + msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FIOSNBIO) + if (ioctl(fd,FIOSNBIO,&on) < 0) + { + msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#else +# include "Bletch: Need non-blocking I/O!" +#endif + +#ifdef HAVE_SIGNALED_IO + init_socket_sig(fd); +#endif /* not HAVE_SIGNALED_IO */ + + UNBLOCKIO(); +} + + +/* + * sendpkt - send a packet to the specified destination + */ +static int +sendpkt( + struct sockaddr_in *dest, + struct pkt *pkt, + int len + ) +{ + int cc; + static int horriblecnt = 0; +#ifdef SYS_WINNT + DWORD err; +#endif /* SYS_WINNT */ + + total_xmit++; /* count it */ + + if (horrible) { + if (++horriblecnt > HORRIBLEOK) { + if (debug > 3) + printf("dropping send (%s)\n", ntoa(dest)); + if (horriblecnt >= HORRIBLEOK+horrible) + horriblecnt = 0; + return 0; + } + } + + + cc = sendto(fd, (char *)pkt, len, 0, (struct sockaddr *)dest, + sizeof(struct sockaddr_in)); +#ifndef SYS_WINNT + if (cc == -1) { + if (errno != EWOULDBLOCK && errno != ENOBUFS) +#else + if (cc == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAENOBUFS) +#endif /* SYS_WINNT */ + msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + return -1; + } + return 0; +} + + +/* + * input_handler - receive packets asynchronously + */ +void +input_handler(l_fp *xts) +{ + register int n; + register struct recvbuf *rb; + struct timeval tvzero; + int fromlen; + fd_set fds; + l_fp ts; + ts = *xts; /* we ignore xts, but make the compiler happy */ + + /* + * 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) { + if (errno != EINTR) { + msyslog(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_recvbuffs == 0) { + char buf[100]; + +#ifndef SYS_WINNT + (void) read(fd, buf, sizeof buf); +#else + /* NT's _read does not operate on nonblocking sockets + * either recvfrom or ReadFile() has to be used here. + * ReadFile is used in [ntpd]ntp_intres() and ntpdc, + * just to be different use recvfrom() here + */ + recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL); +#endif /* SYS_WINNT */ + continue; + } + + rb = get_free_recv_buffer(); + + 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) { + freerecvbuf(rb); + continue; + } + + /* + * Got one. Mark how and when it got here, + * put it on the full list. + */ + rb->recv_time = ts; + add_full_recv_buffer(rb); + total_recv++; /* count it */ + } +} + + +/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */ +/* + * printserver - print detail information for a server + */ +static void +printserver( + register struct server *pp, + FILE *fp + ) +{ + register int i; + char junk[5]; + char *str; + + if (!debug) { + (void) fprintf(fp, + "%-15s %d/%d %03o v%d s%d offset %9s delay %s disp %s\n", + ntoa(&pp->srcadr), + pp->xmtcnt,pp->rcvcnt,pp->reach, + pp->version,pp->stratum, + lfptoa(&pp->offset, 6), ufptoa(pp->delay, 5), + ufptoa(pp->dispersion, 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((s_fp)pp->delay, 5), + ufptoa(pp->dispersion, 5)); + + (void) fprintf(fp, "transmitted %d, received %d, reachable %03o\n", + pp->xmtcnt, pp->rcvcnt, pp->reach); + + (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", fptoa(pp->filter_delay[i], 5)); + 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], 6)); + if (i == (PEER_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "delay %s, dispersion %s\n", + fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5)); + + (void) fprintf(fp, "offset %s\n\n", + lfptoa(&pp->offset, 6)); +} + +#if !defined(HAVE_VSPRINTF) +int +vsprintf( + 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/ntp/ntpdc/Makefile.am b/contrib/ntp/ntpdc/Makefile.am new file mode 100644 index 000000000000..19e9cfa79243 --- /dev/null +++ b/contrib/ntp/ntpdc/Makefile.am @@ -0,0 +1,21 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +bin_PROGRAMS = ntpdc +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o ../libntp/libntp.a @LIBRSAREF@ +DISTCLEANFILES = .version version.c +noinst_HEADERS = ntpdc.h +#EXTRA_DIST = ntpdc.mak +ETAGS_ARGS = Makefile.am + +ntpdc_SOURCES = ntpdc.c ntpdc_ops.c + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +version.o: $(ntpdc_OBJECTS) ../libntp/libntp.a @LIBRSAREF@ Makefile + $(top_builddir)/scripts/mkver ntpdc + $(COMPILE) -c version.c diff --git a/contrib/ntp/ntpdc/Makefile.in b/contrib/ntp/ntpdc/Makefile.in new file mode 100644 index 000000000000..6466661fe79e --- /dev/null +++ b/contrib/ntp/ntpdc/Makefile.in @@ -0,0 +1,361 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ../util/ansi2knr +bin_PROGRAMS = ntpdc +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o ../libntp/libntp.a @LIBRSAREF@ +DISTCLEANFILES = .version version.c +noinst_HEADERS = ntpdc.h +#EXTRA_DIST = ntpdc.mak +ETAGS_ARGS = Makefile.am + +ntpdc_SOURCES = ntpdc.c ntpdc_ops.c +subdir = ntpdc +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +ANSI2KNR = ../util/ansi2knr +am_ntpdc_OBJECTS = ntpdc$U.o ntpdc_ops$U.o +ntpdc_OBJECTS = $(am_ntpdc_OBJECTS) +ntpdc_LDADD = $(LDADD) +ntpdc_DEPENDENCIES = version.o ../libntp/libntp.a +ntpdc_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(ntpdc_SOURCES) +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +SOURCES = $(ntpdc_SOURCES) +OBJECTS = $(am_ntpdc_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ntpdc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: +../util/ansi2knr: ../util/ansi2knr.o + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr + +../util/ansi2knr.o: + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o + + +mostlyclean-kr: + -rm -f *_.c + +clean-kr: + +distclean-kr: + +maintainer-clean-kr: +ntpdc$U.o: +ntpdc_ops$U.o: + +ntpdc: $(ntpdc_OBJECTS) $(ntpdc_DEPENDENCIES) + @rm -f ntpdc + $(LINK) $(ntpdc_LDFLAGS) $(ntpdc_OBJECTS) $(ntpdc_LDADD) $(LIBS) +ntpdc_.c: ntpdc.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpdc.c; then echo $(srcdir)/ntpdc.c; else echo ntpdc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntpdc_.c +ntpdc_ops_.c: ntpdc_ops.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpdc_ops.c; then echo $(srcdir)/ntpdc_ops.c; else echo ntpdc_ops.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntpdc_ops_.c +ntpdc_.o ntpdc_ops_.o : $(ANSI2KNR) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +ntpdc.o: ntpdc.c ntpdc.h ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp.h ../include/ntp_request.h \ + ../include/ntp_string.h ../include/ntp_malloc.h \ + ../include/ntp_select.h ../include/ntp_io.h \ + ../include/ntp_stdlib.h ../include/l_stdlib.h +ntpdc_ops.o: ntpdc_ops.c ../config.h ntpdc.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp.h \ + ../include/ntp_request.h ../include/ntp_string.h \ + ../include/ntp_malloc.h ../include/ntp_control.h \ + ../include/ntp_refclock.h ../include/recvbuff.h \ + ../include/ntp_stdlib.h ../include/l_stdlib.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-kr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-compile clean-kr clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-compile distclean-kr \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-kr \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-kr distclean-kr clean-kr \ +maintainer-clean-kr tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +version.o: $(ntpdc_OBJECTS) ../libntp/libntp.a @LIBRSAREF@ Makefile + $(top_builddir)/scripts/mkver ntpdc + $(COMPILE) -c version.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/ntpdc/README b/contrib/ntp/ntpdc/README new file mode 100644 index 000000000000..618e846cd39f --- /dev/null +++ b/contrib/ntp/ntpdc/README @@ -0,0 +1,6 @@ +README file for directory ./xntpdc of the NTP Version 4 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/ntp/ntpdc/ntpdc.c b/contrib/ntp/ntpdc/ntpdc.c new file mode 100644 index 000000000000..a5299548f7ac --- /dev/null +++ b/contrib/ntp/ntpdc/ntpdc.c @@ -0,0 +1,1689 @@ +/* + * ntpdc - control and monitor your ntpd daemon + */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef SYS_WINNT +#include +#else +#define closesocket close +#endif /* SYS_WINNT */ + + +#include "ntpdc.h" +#include "ntp_select.h" +#include "ntp_io.h" +#include "ntp_stdlib.h" + +#ifdef SYS_VXWORKS +/* vxWorks needs mode flag -casey*/ +#define open(name, flags) open(name, flags, 0777) +#define SERVER_PORT_NUM 123 +#endif + +/* + * Because we now potentially understand a lot of commands (and + * it requires a lot of commands to talk to ntpd) we will run + * interactive if connected to a terminal. + */ +static int interactive = 0; /* set to 1 when we should prompt */ +static const char * prompt = "ntpdc> "; /* 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_MD5; /* MD5*/ +u_long current_time; /* needed by authkeys; not used */ + +int ntpdcmain P((int, char **)); +/* + * Built in command handler declarations + */ +static int openhost P((const 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((const char *)); +static void tokenize P((const 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((const char *, u_int32 *, char *)); +static void help P((struct parse *, FILE *)); +#ifdef QSORT_USES_VOID_P +static int helpsort P((const void *, const void *)); +#else +static int helpsort P((char **, char **)); +#endif +static void printusage P((struct xcmd *, FILE *)); +static void timeout P((struct parse *, FILE *)); +static void my_delay P((struct parse *, FILE *)); +static void host 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((const char *, const char *, const char *)); +static void error P((const char *, const char *, const char *)); +static u_long getkeyid P((const char *)); + + + +/* + * Built-in commands we understand + */ +static struct xcmd builtins[] = { + { "?", help, { OPT|NTP_STR, NO, NO, NO }, + { "command", "", "", "" }, + "tell the use and syntax of commands" }, + { "help", help, { OPT|NTP_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", my_delay, { OPT|INT, NO, NO, NO }, + { "msec", "", "", "" }, + "set the delay added to encryption time stamps" }, + { "host", host, { OPT|NTP_STR, NO, NO, NO }, + { "hostname", "", "", "" }, + "specify the host whose NTP server we talk to" }, + { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO }, + { "", "", "", "" }, + "specify a password to use for authenticated requests"}, + { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, + { "yes|no", "", "", "" }, + "specify whether hostnames or net numbers are printed"}, + { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, + { "no|more|less", "", "", "" }, + "set/change debugging level" }, + { "quit", quit, { NO, NO, NO, NO }, + { "", "", "", "" }, + "exit ntpdc" }, + { "exit", quit, { NO, NO, NO, NO }, + { "", "", "", "" }, + "exit ntpdc" }, + { "keyid", keyid, { OPT|UINT, NO, NO, NO }, + { "key#", "", "", "" }, + "set/show keyid to use for authenticated requests" }, + { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, + { "(md5|des)", "", "", "" }, + "set/show key authentication type 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 200 /* 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 */ + +#if defined (SYS_WINNT) || defined (SYS_VXWORKS) +char password[9]; +#endif /* SYS_WINNT || SYS_VXWORKS */ + +#ifdef SYS_WINNT +WORD wVersionRequested; +WSADATA wsaData; +DWORD NumberOfBytesWritten; + +HANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */ +void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */ + +#endif /* SYS_WINNT */ + +/* + * 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 const char *ccmds[MAXCMDS]; +#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) + +/* + * When multiple hosts are specified. + */ +static int numhosts = 0; +static const 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 volatile 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; +volatile int debug; + +#ifdef NO_MAIN_ALLOWED +CALL(ntpdc,"ntpdc",ntpdcmain); +#else +int +main( + int argc, + char *argv[] + ) +{ + return ntpdcmain(argc, argv); +} +#endif + +#ifdef SYS_VXWORKS +void clear_globals(void) +{ + extern int ntp_optind; + extern char *ntp_optarg; + showhostnames = 0; /* show host names by default */ + ntp_optind = 0; + ntp_optarg = 0; + server_entry = NULL; /* server entry for ntp */ + havehost = 0; /* set to 1 when host open */ + numcmds = 0; + numhosts = 0; +} +#endif + +/* + * main - parse arguments and handle options + */ +int +ntpdcmain( + 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; + +#ifdef SYS_VXWORKS + clear_globals(); + taskPrioritySet(taskIdSelf(), 100 ); +#endif + + 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; + } + +#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ + if (interactive) + (void) signal_no_reset(SIGINT, abortcmd); +#endif /* SYS_WINNT */ + + /* + * Initialize the packet data buffer + */ + pktdata = (char *)malloc(INITDATASIZE); + if (pktdata == NULL) { + (void) fprintf(stderr, "%s: malloc() failed!\n", progname); + exit(1); + } + pktdatasize = INITDATASIZE; + +#ifdef SYS_WINNT + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) { + fprintf(stderr, "No useable winsock.dll"); + exit(1); + } +#endif /* SYS_WINNT */ + + 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]); + } + } + } +#ifdef SYS_WINNT + WSACleanup(); +#endif + return(0); +} /* main end */ + + +/* + * openhost - open a socket to a host + */ +static int +openhost( + const char *hname + ) +{ + u_int32 netnum; + char temphost[LENHOSTNAME]; + + if (server_entry == NULL) { + server_entry = getservbyname("ntp", "udp"); + if (server_entry == NULL) { +#ifdef VMS /* UCX getservbyname() doesn't work [yet], but we do know better */ + server_entry = (struct servent *) + malloc(sizeof(struct servent)); + server_entry->s_port = htons(NTP_PORT); +#else + (void) fprintf(stderr, "%s: ntp/udp: unknown service\n", + progname); + exit(1); +#endif /* VMS & UCX */ + } + 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) closesocket(sockfd); + havehost = 0; + } + (void) strcpy(currenthost, temphost); + + hostaddr.sin_family = AF_INET; +#ifndef SYS_VXWORKS + hostaddr.sin_port = server_entry->s_port; +#else + hostaddr.sin_port = htons(SERVER_PORT_NUM); +#endif + hostaddr.sin_addr.s_addr = netnum; + +#ifdef SYS_WINNT + { + int optionValue = SO_SYNCHRONOUS_NONALERT; + int err; + err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)); + if (err != NO_ERROR) { + (void) fprintf(stderr, "cannot open nonoverlapped sockets\n"); + exit(1); + } + } + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == INVALID_SOCKET) { + error("socket", "", ""); + exit(-1); + } +#else + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) + error("socket", "", ""); +#endif /* SYS_WINNT */ + + +#ifdef NEED_RCVBUF_SLOP +# 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( + char *xdata, + int xdatalen + ) +{ + if (send(sockfd, xdata, xdatalen, 0) == -1) { + warning("write to %s failed", currenthost, ""); + return -1; + } + + return 0; +} + + +/* + * growpktdata - grow the packet data area + */ +static void +growpktdata(void) +{ + pktdatasize += INCDATASIZE; + pktdata = (char *)realloc(pktdata, (unsigned)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( + 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 = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); + 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 || + INFO_VERSION(rpkt.rm_vn_mode) < NTP_OLDVERSION) { + 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)) { + int offset = datap - pktdata; + growpktdata(); + *rdata = pktdata; /* might have been realloced ! */ + datap = pktdata + offset; + } + memmove(datap, (char *)rpkt.data, (unsigned)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( + 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, 0); + qpkt.implementation = (u_char)implcode; + qpkt.request = (u_char)reqcode; + + datasize = qitems * qsize; + if (datasize != 0 && qdata != NULL) { + memmove((char *)qpkt.data, qdata, (unsigned)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; + int maclen = 0; + const char *pass = "\0"; + + if (info_auth_keyid == 0) { + maclen = getkeyid("Keyid: "); + if (maclen == 0) { + (void) fprintf(stderr, + "Invalid key identifier\n"); + return 1; + } + info_auth_keyid = maclen; + } + if (!authistrusted(info_auth_keyid)) { + pass = getpass((info_auth_keytype == KEY_TYPE_DES) + ? "DES Password: " : "MD5 Password: "); + if (*pass == '\0') { + (void) fprintf(stderr, + "Invalid password\n"); + return (1); + } + } + authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass); + authtrust(info_auth_keyid, 1); + qpkt.auth_seq = AUTH_SEQ(1, 0); + qpkt.keyid = htonl(info_auth_keyid); + get_systime(&ts); + L_ADD(&ts, &delay_time); + HTONL_FP(&ts, &qpkt.tstamp); + maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt, + REQ_LEN_NOMAC); + if (maclen == 0) { + (void) fprintf(stderr, "Key not found\n"); + return (1); + } + return sendpkt((char *)&qpkt, (int)(REQ_LEN_NOMAC + maclen)); + } + /*NOTREACHED*/ +} + + +/* + * doquery - send a request and process the response + */ +int +doquery( + int implcode, + int reqcode, + int auth, + int qitems, + int qsize, + char *qdata, + int *ritems, + int *rsize, + char **rdata, + int quiet_mask + ) +{ + 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) recv(sockfd, junk, sizeof junk, 0); + } 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); + + /* log error message if not told to be quiet */ + if ((res > 0) && (((1 << res) & quiet_mask) == 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"); + break; + 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(void) +{ + char line[MAXLINE]; + + for (;;) { + if (interactive) { +#ifdef VMS /* work around a problem with mixing stdout & stderr */ + fputs("",stdout); +#endif + (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( + 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( + const 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); + jump = 0; + if (i) (void) fclose(current_output); + } +} + + +/* + * tokenize - turn a command line into tokens + */ +static void +tokenize( + const char *line, + char **tokens, + int *ntok + ) +{ + register const 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( + 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, (unsigned)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( + char *str, + int code, + arg_v *argp + ) +{ + int isneg; + char *cp, *np; + static const char *digits = "0123456789"; + + switch (code & ~OPT) { + case NTP_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( + const char *hname, + u_int32 *num, + char *fullhost + ) +{ + struct hostent *hp; + + if (decodenetnum(hname, num)) { + if (fullhost != 0) { + (void) sprintf(fullhost, + "%u.%u.%u.%u", (u_int)((htonl(*num)>>24)&0xff), + (u_int)((htonl(*num)>>16)&0xff), (u_int)((htonl(*num)>>8)&0xff), + (u_int)(htonl(*num)&0xff)); + } + return 1; + } else if ((hp = gethostbyname(hname)) != 0) { + memmove((char *)num, hp->h_addr, sizeof(u_int32)); + if (fullhost != 0) + (void) strcpy(fullhost, hp->h_name); + return 1; + } else { + (void) fprintf(stderr, "***Can't find host %s\n", hname); + return 0; + } + /*NOTREACHED*/ +} + +/* + * nntohost - convert network number to host name. This routine enforces + * the showhostnames setting. + */ +char * +nntohost( + u_int32 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( + struct parse *pcmd, + FILE *fp + ) +{ + int i; + int n; + struct xcmd *xcp; + char *cmd; + const char *cmdsort[100]; + int length[100]; + int maxlength; + int numperline; + static const 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; + +#ifdef QSORT_USES_VOID_P + qsort(cmdsort, n, sizeof(char *), helpsort); +#else + qsort((char *)cmdsort, n, sizeof(char *), helpsort); +#endif + + 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 + */ +#ifdef QSORT_USES_VOID_P +static int +helpsort( + const void *t1, + const void *t2 + ) +{ + const char **name1 = (const char **)t1; + const char **name2 = (const char **)t2; + + return strcmp(*name1, *name2); +} +#else +static int +helpsort( + char **name1, + char **name2 + ) +{ + return strcmp(*name1, *name2); +} +#endif + + +/* + * printusage - print usage information for a command + */ +static void +printusage( + 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( + 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; + } +} + + +/* + * my_delay - set delay for auth requests + */ +static void +my_delay( + 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 %lu 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( + 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"); + } +} + + +/* + * keyid - get a keyid to use for authenticating requests + */ +static void +keyid( + 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 %lu\n", (u_long)info_auth_keyid); + } else { + info_auth_keyid = pcmd->argval[0].uval; + } +} + + +/* + * keytype - get type of key to use for authenticating requests + */ +static void +keytype( + struct parse *pcmd, + FILE *fp + ) +{ + if (pcmd->nargs == 0) + fprintf(fp, "keytype is %s\n", + (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( + 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; + } + } + if (!interactive) { + authusekey(info_auth_keyid, info_auth_keytype, + (u_char *)pcmd->argval[0].string); + } else { + pass = getpass((info_auth_keytype == KEY_TYPE_DES) + ? "DES Password: " + : "MD5 Password: " + ); + if (*pass == '\0') + (void) fprintf(fp, "Password unchanged\n"); + else + authusekey(info_auth_keyid, info_auth_keytype, + (u_char *)pass); + } +} + + +/* + * hostnames - set the showhostnames flag + */ +static void +hostnames( + 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( + 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( + struct parse *pcmd, + FILE *fp + ) +{ + if (havehost) + closesocket(sockfd); + exit(0); +} + + +/* + * version - print the current version number + */ +/*ARGSUSED*/ +static void +version( + struct parse *pcmd, + FILE *fp + ) +{ + + (void) fprintf(fp, "%s\n", Version); + return; +} + + +/* + * warning - print a warning message + */ +static void +warning( + const char *fmt, + const char *st1, + const 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( + const char *fmt, + const char *st1, + const char *st2 + ) +{ + warning(fmt, st1, st2); + exit(1); +} + +/* + * getkeyid - prompt the user for a keyid to use + */ +static u_long +getkeyid( + const char *keyprompt + ) +{ + register char *p; + register int c; + FILE *fi; + char pbuf[20]; + +#ifndef SYS_WINNT + if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) +#else + if ((fi = _fdopen((int)GetStdHandle(STD_INPUT_HANDLE), "r")) == NULL) +#endif /* SYS_WINNT */ + fi = stdin; + else + setbuf(fi, (char *)NULL); + fprintf(stderr, "%s", keyprompt); 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_int32)atoi(pbuf); +} diff --git a/contrib/ntp/ntpdc/ntpdc.h b/contrib/ntp/ntpdc/ntpdc.h new file mode 100644 index 000000000000..8b35d4fff7e0 --- /dev/null +++ b/contrib/ntp/ntpdc/ntpdc.h @@ -0,0 +1,59 @@ +/* + * ntpdc.h - definitions of interest to ntpdc + */ +#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 NTP_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_int32 netnum; +} arg_v; + +/* + * Structure for passing parsed command line + */ +struct parse { + char *keyword; + arg_v argval[MAXARGS]; + int nargs; +}; + +/* + * ntpdc includes a command parser which could charitably be called + * crude. The following structure is used to define the command + * syntax. + */ +struct xcmd { + const char *keyword; /* command key word */ + void (*handler) P((struct parse *, FILE *)); /* command handler */ + u_char arg[MAXARGS]; /* descriptors for arguments */ + const char *desc[MAXARGS]; /* descriptions for arguments */ + const char *comment; +}; + +extern int doquery P((int, int, int, int, int, char *, int *, int *, char **, int)); +extern char * nntohost P((u_int32)); diff --git a/contrib/ntp/ntpdc/ntpdc_ops.c b/contrib/ntp/ntpdc/ntpdc_ops.c new file mode 100644 index 000000000000..c4b13e6df45b --- /dev/null +++ b/contrib/ntp/ntpdc/ntpdc_ops.c @@ -0,0 +1,2471 @@ +/* + * ntpdc_ops.c - subroutines which are called to perform operations by ntpdc + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#ifdef HAVE_SYS_TIMEX_H +# include +#endif +#include +#if !defined(__bsdi__) && !defined(apollo) +#include +#endif + +#include "ntpdc.h" +#include "ntp_control.h" +#include "ntp_refclock.h" +#include "ntp_stdlib.h" + +#include + +/* + * 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 doconfig P((struct parse *pcmd, FILE *fp, int mode, int refc)); +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 addrefclock P((struct parse *, FILE *)); +static void broadcast P((struct parse *, FILE *)); +static void doconfig P((struct parse *, FILE *, int, 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 new_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 reset P((struct parse *, FILE *)); +static void preset P((struct parse *, FILE *)); +static void readkeys 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 clockstat P((struct parse *, FILE *)); +static void fudge P((struct parse *, FILE *)); +static void clkbug P((struct parse *, FILE *)); +static void kerninfo P((struct parse *, FILE *)); + +/* + * Commands we understand. Ntpdc imports this. + */ +struct xcmd opcmds[] = { + { "listpeers", peerlist, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display list of peers the server knows about" }, + { "peers", peers, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display peer summary information" }, + { "dmpeers", dmpeers, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display 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" }, + "display detailed information for one or more peers" }, + { "pstats", peerstats, { ADD, OPT|ADD, OPT|ADD, OPT|ADD }, + { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" }, + "display statistical information for one or more peers" }, + { "loopinfo", loopinfo, { OPT|NTP_STR, NO, NO, NO }, + { "oneline|multiline", "", "", "" }, + "display loop filter information" }, + { "sysinfo", sysinfo, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display local server information" }, + { "sysstats", sysstats, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display local server statistics" }, + { "memstats", memstats, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display peer memory usage statistics" }, + { "iostats", iostats, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display I/O subsystem statistics" }, + { "timerstats", timerstats, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display event timer subsystem statistics" }, + { "addpeer", addpeer, { ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR }, + { "addr", "keyid", "version", "minpoll|prefer" }, + "configure a new peer association" }, + { "addserver", addserver, { ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR }, + { "addr", "keyid", "version", "minpoll|prefer" }, + "configure a new server" }, + { "addrefclock",addrefclock, { ADD, OPT|UINT, OPT|NTP_STR, OPT|NTP_STR }, + { "addr", "mode", "minpoll|prefer", "minpoll|prefer" }, + "configure a new server" }, + { "broadcast", broadcast, { ADD, OPT|UINT, OPT|UINT, OPT|NTP_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" }, + { "enable", set, { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR }, + { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." }, + "set a system flag (auth, bclient, monitor, pll, kernel, stats)" }, + { "disable", sys_clear, { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR }, + { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." }, + "clear a system flag (auth, bclient, monitor, pll, kernel, stats)" }, + { "reslist", reslist, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display the server's restrict list" }, + { "restrict", new_restrict, { ADD, ADD, NTP_STR, OPT|NTP_STR }, + { "address", "mask", + "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer", + "..." }, + "create restrict entry/add flags to entry" }, + { "unrestrict", unrestrict, { ADD, ADD, NTP_STR, OPT|NTP_STR }, + { "address", "mask", + "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer", + "..." }, + "remove flags from a restrict entry" }, + { "delrestrict", delrestrict, { ADD, ADD, OPT|NTP_STR, NO }, + { "address", "mask", "ntpport", "" }, + "delete a restrict entry" }, + { "monlist", monlist, { OPT|INT, NO, NO, NO }, + { "version", "", "", "" }, + "display data the server's monitor routines have collected" }, + { "reset", reset, { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_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" }, + { "trustedkey", trustkey, { UINT, OPT|UINT, OPT|UINT, OPT|UINT }, + { "keyid", "keyid", "keyid", "keyid" }, + "add one or more key ID's to the trusted list" }, + { "untrustedkey", 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 }, + { "", "", "", "" }, + "display the state of the authentication code" }, + { "traps", traps, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display the traps set in the 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 }, + { "", "", "", "" }, + "display packet count statistics from the control module" }, + { "clockstat", clockstat, { ADD, OPT|ADD, OPT|ADD, OPT|ADD }, + { "address", "address", "address", "address" }, + "display clock status information" }, + { "fudge", fudge, { ADD, NTP_STR, NTP_STR, NO }, + { "address", "time1|time2|val1|val2|flags", "value", "" }, + "set/change one of a clock's fudge factors" }, + { "clkbug", clkbug, { ADD, OPT|ADD, OPT|ADD, OPT|ADD }, + { "address", "address", "address", "address" }, + "display clock debugging information" }, + { "kerninfo", kerninfo, { NO, NO, NO, NO }, + { "", "", "", "" }, + "display the kernel pll/pps variables" }, + + { 0, 0, { NO, NO, NO, NO }, + { "", "", "", "" }, "" } +}; + + +/* + * Imported from ntpdc.c + */ +extern int showhostnames; +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( + 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( + 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( + 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( + 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, 0); + + 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( + struct parse *pcmd, + FILE *fp + ) +{ + dopeers(pcmd, fp, 0); +} + +/* + * dmpeers - show peer summary, Dave Mills style + */ +static void +dmpeers( + struct parse *pcmd, + FILE *fp + ) +{ + dopeers(pcmd, fp, 1); +} + + +/* + * peers - show peer summary + */ +/*ARGSUSED*/ +static void +dopeers( + 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, 0); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_peer_summary))) + return; + + (void) fprintf(fp, + " remote local st poll reach delay offset disp\n"); + (void) fprintf(fp, + "=======================================================================\n"); + while (items > 0) { + if (!dmstyle) { + if (plist->flags & INFO_FLAG_SYSPEER) + c = '*'; + else if (plist->hmode == MODE_ACTIVE) + c = '+'; + else if (plist->hmode == MODE_PASSIVE) + c = '-'; + else if (plist->hmode == MODE_CLIENT) + c = '='; + else if (plist->hmode == MODE_BROADCAST) + c = '^'; + else if (plist->hmode == MODE_BCLIENT) + c = '~'; + else + c = ' '; + } else { + if (plist->flags & INFO_FLAG_SYSPEER) + c = '*'; + else if (plist->flags & INFO_FLAG_SHORTLIST) + c = '+'; + else if (plist->flags & INFO_FLAG_SEL_CANDIDATE) + c = '.'; + else + c = ' '; + } + NTOHL_FP(&(plist->offset), &tempts); + ntp_poll = 1<ppoll, plist->hpoll, NTP_MAXPOLL), + NTP_MINPOLL); + (void) fprintf(fp, + "%c%-15.15s %-15.15s %2d %4d %3o %7.7s %9.9s %7.7s\n", + c, nntohost(plist->srcadr), + numtoa(plist->dstadr), + plist->stratum, ntp_poll, plist->reach, + fptoa(NTOHS_FP(plist->delay), 5), + lfptoa(&tempts, 6), + ufptoa(NTOHS_FP(plist->dispersion), 5)); + + plist++; + items--; + } +} + +/* Convert a refid & stratum (in host order) to a string */ +static char* +refid_string( + u_int32 refid, + int stratum + ) +{ + if (stratum <= 1) { + static char junk[5]; + junk[4] = 0; + memmove(junk, (char *)&refid, 4); + return junk; + } + + return numtoa(refid); +} + +/* + * printpeer - print detail information for a peer + */ +static void +printpeer( + register struct info_peer *pp, + FILE *fp + ) +{ + register int i; + const 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); + + (void) fprintf(fp, + "leap %c%c, refid [%s], rootdistance %s, rootdispersion %s\n", + pp->leap & 0x2 ? '1' : '0', + pp->leap & 0x1 ? '1' : '0', + refid_string(pp->refid, pp->stratum), fptoa(NTOHS_FP(pp->rootdelay), 5), + ufptoa(NTOHS_FP(pp->rootdispersion), 5)); + + (void) fprintf(fp, + "ppoll %d, hpoll %d, keyid %lu, version %d, association %u\n", + pp->ppoll, pp->hpoll, (u_long)pp->keyid, pp->version, ntohs(pp->associd)); + + (void) fprintf(fp, + "valid %d, reach %03o, unreach %d, flash 0x%04x, ", + pp->valid, pp->reach, pp->unreach, pp->flash2); + + (void) fprintf(fp, "boffset %s, ttl/mode %d\n", + fptoa(NTOHS_FP(pp->estbdelay), 5), pp->ttl); + + (void) fprintf(fp, "timer %lds, flags", (long)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 config", str); + str = ","; + } + if (pp->flags & INFO_FLAG_REFCLOCK) { + (void) fprintf(fp, "%s refclock", str); + str = ","; + } + if (pp->flags & INFO_FLAG_AUTHENABLE) { + (void) fprintf(fp, "%s auth", str); + str = ","; + } + if (pp->flags & INFO_FLAG_BCLIENT) { + (void) fprintf(fp, "%s bclient", str); + str = ","; + } + if (pp->flags & INFO_FLAG_PREFER) { + (void) fprintf(fp, "%s prefer", str); + str = ","; + } + if (pp->flags & INFO_FLAG_BURST) { + (void) fprintf(fp, "%s burst", str); + } + (void) fprintf(fp, "\n"); + } + + NTOHL_FP(&pp->reftime, &tempts); + (void) fprintf(fp, "reference time: %s\n", + prettydate(&tempts)); + NTOHL_FP(&pp->org, &tempts); + (void) fprintf(fp, "originate timestamp: %s\n", + prettydate(&tempts)); + NTOHL_FP(&pp->rec, &tempts); + (void) fprintf(fp, "receive timestamp: %s\n", + prettydate(&tempts)); + NTOHL_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(NTOHS_FP(pp->filtdelay[i]), 5)); + 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++) { + NTOHL_FP(&pp->filtoffset[i], &tempts); + (void) fprintf(fp, " %-8.8s", lfptoa(&tempts, 6)); + 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"); + + + NTOHL_FP(&pp->offset, &tempts); + (void) fprintf(fp, + "offset %s, delay %s, error bound %s, filter error %s\n", + lfptoa(&tempts, 6), fptoa(NTOHS_FP(pp->delay), 5), + ufptoa(NTOHS_FP(pp->dispersion), 5), + ufptoa(NTOHS_FP(pp->selectdisp), 5)); +} + + +/* + * showpeer - show detailed information for a peer + */ +static void +showpeer( + 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, 0); + + 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( + 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, 0); + + 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: %lds\n", + (long)ntohl(pp->timereceived)); + (void) fprintf(fp, "time until next send: %lds\n", + (long)ntohl(pp->timetosend)); + (void) fprintf(fp, "reachability change: %lds\n", + (long)ntohl(pp->timereachable)); + (void) fprintf(fp, "packets sent: %ld\n", + (long)ntohl(pp->sent)); + (void) fprintf(fp, "packets received: %ld\n", + (long)ntohl(pp->processed)); + (void) fprintf(fp, "bad authentication: %ld\n", + (long)ntohl(pp->badauth)); + (void) fprintf(fp, "bogus origin: %ld\n", + (long)ntohl(pp->bogusorg)); + (void) fprintf(fp, "duplicate: %ld\n", + (long)ntohl(pp->oldpkt)); + (void) fprintf(fp, "bad dispersion: %ld\n", + (long)ntohl(pp->seldisp)); + (void) fprintf(fp, "bad reference time: %ld\n", + (long)ntohl(pp->selbroken)); + (void) fprintf(fp, "candidate order: %d\n", + (int)pp->candidate); + if (items > 0) + (void) fprintf(fp, "\n"); + pp++; + } +} + + +/* + * loopinfo - show loop filter information + */ +static void +loopinfo( + 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, 0); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (!checkitemsize(itemsize, sizeof(struct info_loop))) + return; + + if (oneline) { + l_fp temp2ts; + + NTOHL_FP(&il->last_offset, &tempts); + NTOHL_FP(&il->drift_comp, &temp2ts); + + (void) fprintf(fp, + "offset %s, frequency %s, time_const %ld, watchdog %ld\n", + lfptoa(&tempts, 6), + lfptoa(&temp2ts, 3), + (u_long)ntohl(il->compliance), + (u_long)ntohl(il->watchdog_timer)); + } else { + NTOHL_FP(&il->last_offset, &tempts); + (void) fprintf(fp, "offset: %s s\n", + lfptoa(&tempts, 6)); + NTOHL_FP(&il->drift_comp, &tempts); + (void) fprintf(fp, "frequency: %s ppm\n", + lfptoa(&tempts, 3)); + (void) fprintf(fp, "poll adjust: %ld\n", + (u_long)ntohl(il->compliance)); + (void) fprintf(fp, "watchdog timer: %ld s\n", + (u_long)ntohl(il->watchdog_timer)); + } +} + + +/* + * sysinfo - show current system state + */ +/*ARGSUSED*/ +static void +sysinfo( + struct parse *pcmd, + FILE *fp + ) +{ + struct info_sys *is; + int items; + int itemsize; + int res; + l_fp tempts; + + res = doquery(IMPL_XNTPD, REQ_SYS_INFO, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&is, 0); + + 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, "root distance: %s s\n", + fptoa(NTOHS_FP(is->rootdelay), 5)); + (void) fprintf(fp, "root dispersion: %s s\n", + ufptoa(NTOHS_FP(is->rootdispersion), 5)); + (void) fprintf(fp, "reference ID: [%s]\n", + refid_string(is->refid, is->stratum)); + NTOHL_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 | + INFO_FLAG_NTP | INFO_FLAG_KERNEL| INFO_FLAG_PLL_SYNC | + INFO_FLAG_PPS_SYNC | INFO_FLAG_MONITOR | INFO_FLAG_FILEGEN)) == 0) { + (void) fprintf(fp, "none\n"); + } else { + if (is->flags & INFO_FLAG_BCLIENT) + (void) fprintf(fp, "bclient "); + if (is->flags & INFO_FLAG_AUTHENTICATE) + (void) fprintf(fp, "auth "); + if (is->flags & INFO_FLAG_MONITOR) + (void) fprintf(fp, "monitor "); + if (is->flags & INFO_FLAG_NTP) + (void) fprintf(fp, "ntp "); + if (is->flags & INFO_FLAG_KERNEL) + (void) fprintf(fp, "kernel "); + if (is->flags & INFO_FLAG_FILEGEN) + (void) fprintf(fp, "stats "); + if (is->flags & INFO_FLAG_PLL_SYNC) + (void) fprintf(fp, "kernel_sync "); + if (is->flags & INFO_FLAG_PPS_SYNC) + (void) fprintf(fp, "pps_sync "); + (void) fprintf(fp, "\n"); + } + (void) fprintf(fp, "jitter: %s s\n", + fptoa(ntohl(is->frequency), 6)); + (void) fprintf(fp, "stability: %s ppm\n", + ufptoa(ntohl(is->stability), 3)); + (void) fprintf(fp, "broadcastdelay: %s s\n", + fptoa(NTOHS_FP(is->bdelay), 6)); + NTOHL_FP(&is->authdelay, &tempts); + (void) fprintf(fp, "authdelay: %s s\n", lfptoa(&tempts, 6)); +} + + +/* + * sysstats - print system statistics + */ +/*ARGSUSED*/ +static void +sysstats( + 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, 0); + + if (res != 0 && items == 0) + return; + + if (!check1item(items, fp)) + return; + + if (itemsize != sizeof(struct info_sys_stats) && + itemsize != sizeof(struct old_info_sys_stats)) { + /* issue warning according to new structure size */ + checkitemsize(itemsize, sizeof(struct info_sys_stats)); + return; + } + + (void) fprintf(fp, "system uptime: %ld\n", + (u_long)ntohl(ss->timeup)); + (void) fprintf(fp, "time since reset: %ld\n", + (u_long)ntohl(ss->timereset)); + (void) fprintf(fp, "bad stratum in packet: %ld\n", + (u_long)ntohl(ss->badstratum)); + (void) fprintf(fp, "old version packets: %ld\n", + (u_long)ntohl(ss->oldversionpkt)); + (void) fprintf(fp, "new version packets: %ld\n", + (u_long)ntohl(ss->newversionpkt)); + (void) fprintf(fp, "unknown version number: %ld\n", + (u_long)ntohl(ss->unknownversion)); + (void) fprintf(fp, "bad packet length: %ld\n", + (u_long)ntohl(ss->badlength)); + (void) fprintf(fp, "packets processed: %ld\n", + (u_long)ntohl(ss->processed)); + (void) fprintf(fp, "bad authentication: %ld\n", + (u_long)ntohl(ss->badauth)); + if (itemsize != sizeof(struct info_sys_stats)) + return; + + (void) fprintf(fp, "limitation rejects: %ld\n", + (u_long)ntohl(ss->limitrejected)); +} + + + +/* + * iostats - print I/O statistics + */ +/*ARGSUSED*/ +static void +iostats( + 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, 0); + + 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: %ld\n", + (u_long)ntohl(io->timereset)); + (void) fprintf(fp, "receive buffers: %d\n", + ntohs(io->totalrecvbufs)); + (void) fprintf(fp, "free receive buffers: %d\n", + ntohs(io->freerecvbufs)); + (void) fprintf(fp, "used receive buffers: %d\n", + ntohs(io->fullrecvbufs)); + (void) fprintf(fp, "low water refills: %d\n", + ntohs(io->lowwater)); + (void) fprintf(fp, "dropped packets: %ld\n", + (u_long)ntohl(io->dropped)); + (void) fprintf(fp, "ignored packets: %ld\n", + (u_long)ntohl(io->ignored)); + (void) fprintf(fp, "received packets: %ld\n", + (u_long)ntohl(io->received)); + (void) fprintf(fp, "packets sent: %ld\n", + (u_long)ntohl(io->sent)); + (void) fprintf(fp, "packets not sent: %ld\n", + (u_long)ntohl(io->notsent)); + (void) fprintf(fp, "interrupts handled: %ld\n", + (u_long)ntohl(io->interrupts)); + (void) fprintf(fp, "received by int: %ld\n", + (u_long)ntohl(io->int_received)); +} + + +/* + * memstats - print peer memory statistics + */ +/*ARGSUSED*/ +static void +memstats( + 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, 0); + + 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: %ld\n", + (u_long)ntohl(mem->timereset)); + (void) fprintf(fp, "total peer memory: %d\n", + ntohs(mem->totalpeermem)); + (void) fprintf(fp, "free peer memory: %d\n", + ntohs(mem->freepeermem)); + (void) fprintf(fp, "calls to findpeer: %ld\n", + (u_long)ntohl(mem->findpeer_calls)); + (void) fprintf(fp, "new peer allocations: %ld\n", + (u_long)ntohl(mem->allocations)); + (void) fprintf(fp, "peer demobilizations: %ld\n", + (u_long)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( + 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, 0); + + 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: %ld\n", + (u_long)ntohl(tim->timereset)); + (void) fprintf(fp, "alarms handled: %ld\n", + (u_long)ntohl(tim->alarms)); + (void) fprintf(fp, "alarm overruns: %ld\n", + (u_long)ntohl(tim->overflows)); + (void) fprintf(fp, "calls to transmit: %ld\n", + (u_long)ntohl(tim->xmtcalls)); +} + + +/* + * addpeer - configure an active mode association + */ +static void +addpeer( + struct parse *pcmd, + FILE *fp + ) +{ + doconfig(pcmd, fp, MODE_ACTIVE, 0); +} + + +/* + * addserver - configure a client mode association + */ +static void +addserver( + struct parse *pcmd, + FILE *fp + ) +{ + doconfig(pcmd, fp, MODE_CLIENT, 0); +} + +/* + * addrefclock - configure a reference clock association + */ +static void +addrefclock( + struct parse *pcmd, + FILE *fp + ) +{ + doconfig(pcmd, fp, MODE_CLIENT, 1); +} + +/* + * broadcast - configure a broadcast mode association + */ +static void +broadcast( + struct parse *pcmd, + FILE *fp + ) +{ + doconfig(pcmd, fp, MODE_BROADCAST, 0); +} + + +/* + * config - configure a new peer association + */ +static void +doconfig( + struct parse *pcmd, + FILE *fp, + int mode, + int refc + ) +{ + struct conf_peer cpeer; + int items; + int itemsize; + char *dummy; + u_long keyid; + u_int version; + u_char minpoll; + u_int flags; + u_char cmode; + int res; + + keyid = 0; + version = NTP_OLDVERSION + 1; + flags = 0; + res = 0; + cmode = 0; + minpoll = NTP_MINDPOLL; + + items = pcmd->nargs; + + if (refc) { + if (pcmd->nargs > 1) { + cmode = (u_char) pcmd->argval[1].uval; + items = 2; + } + } else { + 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, + "invalid version number %u\n", + version); + res++; + } + items = 3; + } + } + } + + while (pcmd->nargs > items) { + if (STREQ(pcmd->argval[items].string, "prefer")) + flags |= CONF_FLAG_PREFER; + else if (STREQ(pcmd->argval[items].string, "burst")) + flags |= CONF_FLAG_BURST; + else { + long val; + if (!atoint(pcmd->argval[items].string, &val)) { + (void) fprintf(fp, + "%s not understood\n", + pcmd->argval[items].string); + res++; + break; + } else { + if (val >= NTP_MINPOLL && val <= NTP_MAXPOLL) { + minpoll = (u_char)val; + } else { + (void) fprintf(fp, + "minpol must be within %d..%d\n", + NTP_MINPOLL, NTP_MAXPOLL); + res++; + break; + } + } + } + items++; + } + + if (res) + return; + + memset((void *)&cpeer, 0, sizeof cpeer); + + cpeer.peeraddr = pcmd->argval[0].netnum; + cpeer.hmode = (u_char) mode; + cpeer.keyid = keyid; + cpeer.version = (u_char) version; + cpeer.minpoll = minpoll; + cpeer.maxpoll = NTP_MAXDPOLL; + cpeer.flags = (u_char)flags; + cpeer.ttl = cmode; + + res = doquery(IMPL_XNTPD, REQ_CONFIG, 1, 1, + sizeof(struct conf_peer), (char *)&cpeer, &items, + &itemsize, &dummy, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + +/* + * unconfig - unconfigure some associations + */ +static void +unconfig( + 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, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); +} + + +/* + * set - set some system flags + */ +static void +set( + struct parse *pcmd, + FILE *fp + ) +{ + doset(pcmd, fp, REQ_SET_SYS_FLAG); +} + + +/* + * clear - clear some system flags + */ +static void +sys_clear( + struct parse *pcmd, + FILE *fp + ) +{ + doset(pcmd, fp, REQ_CLR_SYS_FLAG); +} + + +/* + * doset - set/clear system flags + */ +static void +doset( + 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, "auth")) + sys.flags |= SYS_FLAG_AUTHENTICATE; + else if (STREQ(pcmd->argval[items].string, "bclient")) + sys.flags |= SYS_FLAG_BCLIENT; + else if (STREQ(pcmd->argval[items].string, "monitor")) + sys.flags |= SYS_FLAG_MONITOR; + else if (STREQ(pcmd->argval[items].string, "ntp")) + sys.flags |= SYS_FLAG_NTP; + else if (STREQ(pcmd->argval[items].string, "kernel")) + sys.flags |= SYS_FLAG_KERNEL; + else if (STREQ(pcmd->argval[items].string, "stats")) + sys.flags |= SYS_FLAG_FILEGEN; + 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, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); +} + + +/* + * data for printing/interrpreting the restrict flags + */ +struct resflags { + const 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 }, + { "limited", RES_LIMITED }, + { "", 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( + struct parse *pcmd, + FILE *fp + ) +{ + struct info_restrict *rl; + int items; + int itemsize; + int res; + char *addr; + char *mask; + struct resflags *rf; + u_int32 count; + u_short flags; + u_short mflags; + char flagstr[300]; + static const char *comma = ", "; + + res = doquery(IMPL_XNTPD, REQ_GET_RESTRICT, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&rl, 0); + + 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) { + if ((rl->mask == (u_int32)0xffffffff)) + addr = nntohost(rl->addr); + else + 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 %9ld %s\n", + addr, mask, (u_long)count, flagstr); + rl++; + items--; + } +} + + + +/* + * new_restrict - create/add a set of restrictions + */ +static void +new_restrict( + struct parse *pcmd, + FILE *fp + ) +{ + do_restrict(pcmd, fp, REQ_RESADDFLAGS); +} + + +/* + * unrestrict - remove restriction flags from existing entry + */ +static void +unrestrict( + struct parse *pcmd, + FILE *fp + ) +{ + do_restrict(pcmd, fp, REQ_RESSUBFLAGS); +} + + +/* + * delrestrict - delete an existing restriction + */ +static void +delrestrict( + struct parse *pcmd, + FILE *fp + ) +{ + do_restrict(pcmd, fp, REQ_UNRESTRICT); +} + + +/* + * do_restrict - decode commandline restrictions and make the request + */ +static void +do_restrict( + struct parse *pcmd, + FILE *fp, + int req_code + ) +{ + struct conf_restrict cres; + int items; + int itemsize; + char *dummy; + u_int32 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, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + +/* + * monlist - obtain and print the server's monitor data + */ +/*ARGSUSED*/ +static void +monlist( + struct parse *pcmd, + FILE *fp + ) +{ + char *struct_star; + struct in_addr addr; + int items; + int itemsize; + int res; + int version = -1; + + if (pcmd->nargs > 0) { + version = pcmd->argval[0].ival; + } + + res = doquery(IMPL_XNTPD, + (version == 1 || version == -1) ? REQ_MON_GETLIST_1 : + REQ_MON_GETLIST, 0, 0, 0, (char *)NULL, + &items, &itemsize, &struct_star, + (version < 0) ? (1 << INFO_ERR_REQ) : 0); + + if (res == INFO_ERR_REQ && version < 0) + res = doquery(IMPL_XNTPD, REQ_MON_GETLIST, 0, 0, 0, (char *)NULL, + &items, &itemsize, &struct_star, 0); + + if (res != 0 && items == 0) + return; + + if (!checkitems(items, fp)) + return; + + if (itemsize == sizeof(struct info_monitor_1)) { + struct info_monitor_1 *ml = (struct info_monitor_1 *) struct_star; + + (void) fprintf(fp, + "remote address port local address count m ver drop last first\n"); + (void) fprintf(fp, + "===============================================================================\n"); + while (items > 0) { + addr.s_addr = ml->daddr; + (void) fprintf(fp, + "%-22.22s %5d %-15s %8ld %1d %1d %6lu %6lu %7lu\n", + nntohost(ml->addr), + ntohs(ml->port), + inet_ntoa(addr), + (u_long)ntohl(ml->count), + ml->mode, + ml->version, + (u_long)ntohl(ml->lastdrop), + (u_long)ntohl(ml->lasttime), + (u_long)ntohl(ml->firsttime)); + ml++; + items--; + } + } else if (itemsize == sizeof(struct info_monitor)) { + struct info_monitor *ml = (struct info_monitor *) struct_star; + + (void) fprintf(fp, + " address port count mode ver lastdrop lasttime firsttime\n"); + (void) fprintf(fp, + "===============================================================================\n"); + while (items > 0) { + addr.s_addr = ml->lastdrop; + (void) fprintf(fp, + "%-25.25s %5d %9ld %4d %2d %9lu %9lu %9lu\n", + nntohost(ml->addr), + ntohs(ml->port), + (u_long)ntohl(ml->count), + ml->mode, + ml->version, + (u_long)ntohl(ml->lastdrop), + (u_long)ntohl(ml->lasttime), + (u_long)ntohl(ml->firsttime)); + ml++; + items--; + } + } else if (itemsize == sizeof(struct old_info_monitor)) { + struct old_info_monitor *oml = (struct old_info_monitor *)struct_star; + (void) fprintf(fp, + " address port count mode version lasttime firsttime\n"); + (void) fprintf(fp, + "======================================================================\n"); + while (items > 0) { + (void) fprintf(fp, "%-20.20s %5d %9ld %4d %3d %9lu %9lu\n", + nntohost(oml->addr), + ntohs(oml->port), + (u_long)ntohl(oml->count), + oml->mode, + oml->version, + (u_long)ntohl(oml->lasttime), + (u_long)ntohl(oml->firsttime)); + oml++; + items--; + } + } else { + /* issue warning according to new info_monitor size */ + checkitemsize(itemsize, sizeof(struct info_monitor)); + } +} + + +/* + * Mapping between command line strings and stat reset flags + */ +struct statreset { + const 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( + 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, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * preset - reset stat counters for particular peers + */ +static void +preset( + 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, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); +} + + +/* + * readkeys - request the server to reread the keys file + */ +/*ARGSUSED*/ +static void +readkeys( + 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, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + +/* + * trustkey - add some keys to the trusted key list + */ +static void +trustkey( + struct parse *pcmd, + FILE *fp + ) +{ + do_trustkey(pcmd, fp, REQ_TRUSTKEY); +} + + +/* + * untrustkey - remove some keys from the trusted key list + */ +static void +untrustkey( + struct parse *pcmd, + FILE *fp + ) +{ + do_trustkey(pcmd, fp, REQ_UNTRUSTKEY); +} + + +/* + * do_trustkey - do grunge work of adding/deleting keys + */ +static void +do_trustkey( + 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, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * authinfo - obtain and print info about authentication + */ +/*ARGSUSED*/ +static void +authinfo( + 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, 0); + + 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: %ld\n", + (u_long)ntohl(ia->timereset)); + (void) fprintf(fp, "stored keys: %ld\n", + (u_long)ntohl(ia->numkeys)); + (void) fprintf(fp, "free keys: %ld\n", + (u_long)ntohl(ia->numfreekeys)); + (void) fprintf(fp, "key lookups: %ld\n", + (u_long)ntohl(ia->keylookups)); + (void) fprintf(fp, "keys not found: %ld\n", + (u_long)ntohl(ia->keynotfound)); + (void) fprintf(fp, "uncached keys: %ld\n", + (u_long)ntohl(ia->keyuncached)); + (void) fprintf(fp, "encryptions: %ld\n", + (u_long)ntohl(ia->encryptions)); + (void) fprintf(fp, "decryptions: %ld\n", + (u_long)ntohl(ia->decryptions)); + (void) fprintf(fp, "expired keys: %ld\n", + (u_long)ntohl(ia->expired)); +} + + + +/* + * traps - obtain and print a list of traps + */ +/*ARGSUSED*/ +static void +traps( + 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, 0); + + 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 (ntohl(it->flags) & TRAP_CONFIGURED) + (void) fprintf(fp, "configured\n"); + else if (ntohl(it->flags) & TRAP_NONPRIO) + (void) fprintf(fp, "low priority\n"); + else + (void) fprintf(fp, "normal priority\n"); + + (void) fprintf(fp, "set for %ld secs, last set %ld secs ago\n", + (long)ntohl(it->origtime), + (long)ntohl(it->settime)); + (void) fprintf(fp, "sequence %d, number of resets %ld\n", + ntohs(it->sequence), + (long)ntohl(it->resets)); + } +} + + +/* + * addtrap - configure a trap + */ +static void +addtrap( + struct parse *pcmd, + FILE *fp + ) +{ + do_addclr_trap(pcmd, fp, REQ_ADD_TRAP); +} + + +/* + * clrtrap - clear a trap from the server + */ +static void +clrtrap( + 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( + 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, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * requestkey - change the server's request key (a dangerous request) + */ +static void +requestkey( + struct parse *pcmd, + FILE *fp + ) +{ + do_changekey(pcmd, fp, REQ_REQUEST_KEY); +} + + +/* + * controlkey - change the server's control key + */ +static void +controlkey( + struct parse *pcmd, + FILE *fp + ) +{ + do_changekey(pcmd, fp, REQ_CONTROL_KEY); +} + + + +/* + * do_changekey - do grunge work of changing keys + */ +static void +do_changekey( + struct parse *pcmd, + FILE *fp, + int req + ) +{ + u_long key; + int items; + int itemsize; + char *dummy; + int res; + + + key = htonl((u_int32)pcmd->argval[0].uval); + + res = doquery(IMPL_XNTPD, req, 1, 1, sizeof(u_int32), + (char *)&key, &items, &itemsize, &dummy, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + + + +/* + * ctlstats - obtain and print info about authentication + */ +/*ARGSUSED*/ +static void +ctlstats( + 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, 0); + + 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: %ld\n", + (u_long)ntohl(ic->ctltimereset)); + (void) fprintf(fp, "requests received: %ld\n", + (u_long)ntohl(ic->numctlreq)); + (void) fprintf(fp, "responses sent: %ld\n", + (u_long)ntohl(ic->numctlresponses)); + (void) fprintf(fp, "fragments sent: %ld\n", + (u_long)ntohl(ic->numctlfrags)); + (void) fprintf(fp, "async messages sent: %ld\n", + (u_long)ntohl(ic->numasyncmsgs)); + (void) fprintf(fp, "error msgs sent: %ld\n", + (u_long)ntohl(ic->numctlerrors)); + (void) fprintf(fp, "total bad pkts: %ld\n", + (u_long)ntohl(ic->numctlbadpkts)); + (void) fprintf(fp, "packet too short: %ld\n", + (u_long)ntohl(ic->numctltooshort)); + (void) fprintf(fp, "response on input: %ld\n", + (u_long)ntohl(ic->numctlinputresp)); + (void) fprintf(fp, "fragment on input: %ld\n", + (u_long)ntohl(ic->numctlinputfrag)); + (void) fprintf(fp, "error set on input: %ld\n", + (u_long)ntohl(ic->numctlinputerr)); + (void) fprintf(fp, "bad offset on input: %ld\n", + (u_long)ntohl(ic->numctlbadoffset)); + (void) fprintf(fp, "bad version packets: %ld\n", + (u_long)ntohl(ic->numctlbadversion)); + (void) fprintf(fp, "data in pkt too short: %ld\n", + (u_long)ntohl(ic->numctldatatooshort)); + (void) fprintf(fp, "unknown op codes: %ld\n", + (u_long)ntohl(ic->numctlbadop)); +} + + +/* + * clockstat - get and print clock status information + */ +static void +clockstat( + struct parse *pcmd, + FILE *fp + ) +{ + 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; + u_long ltemp; + + 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_int32), (char *)clist, &items, + &itemsize, (char **)&cl, 0); + + 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: %lu\n", + (u_long)ntohl(cl->polls)); + (void) fprintf(fp, "no response to poll: %lu\n", + (u_long)ntohl(cl->noresponse)); + (void) fprintf(fp, "bad format responses: %lu\n", + (u_long)ntohl(cl->badformat)); + (void) fprintf(fp, "bad data responses: %lu\n", + (u_long)ntohl(cl->baddata)); + (void) fprintf(fp, "running time: %lu\n", + (u_long)ntohl(cl->timestarted)); + NTOHL_FP(&cl->fudgetime1, &ts); + (void) fprintf(fp, "fudge time 1: %s\n", + lfptoa(&ts, 6)); + NTOHL_FP(&cl->fudgetime2, &ts); + (void) fprintf(fp, "fudge time 2: %s\n", + lfptoa(&ts, 6)); + (void) fprintf(fp, "stratum: %ld\n", + (u_long)ntohl(cl->fudgeval1)); + ltemp = ntohl(cl->fudgeval2); + (void) fprintf(fp, "reference ID: %s\n", + (char *)<emp); + (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( + struct parse *pcmd, + FILE *fp + ) +{ + struct conf_fudge fudgedata; + int items; + int itemsize; + char *dummy; + l_fp ts; + int res; + long val; + u_long u_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 + NTOHL_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 + NTOHL_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((u_int32)val); + } else if (STREQ(pcmd->argval[1].string, "flags")) { + fudgedata.which = htonl(FUDGE_FLAGS); + if (!hextoint(pcmd->argval[2].string, &u_val)) + err = 1; + else + fudgedata.fudgeval_flags = htonl((u_int32)(u_val & 0xf)); + } else { + (void) fprintf(stderr, "What fudge is %s?\n", + pcmd->argval[1].string); + return; + } + + if (err) { + (void) fprintf(stderr, "Unknown fudge parameter %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, 0); + + if (res == 0) + (void) fprintf(fp, "done!\n"); + return; +} + +/* + * clkbug - get and print clock debugging information + */ +static void +clkbug( + struct parse *pcmd, + FILE *fp + ) +{ + register int i; + register int n; + register u_int32 s; + struct info_clkbug *cl; + /* 8 is the maximum number of clocks which will fit in a packet */ + u_long clist[min(MAXARGS, 8)]; + u_int32 ltemp; + int qitems; + int items; + int itemsize; + int res; + int needsp; + 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_int32), (char *)clist, &items, + &itemsize, (char **)&cl, 0); + + 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 = ntohs(cl->svalues); + if (n > NUMCBUGVALUES) + n = NUMCBUGVALUES; + for (i = 0; i < n; i++) { + ltemp = ntohl(cl->values[i]); + ltemp &= 0xffffffff; /* HMS: This does nothing now */ + if ((i & 0x3) == 0) + (void) fprintf(fp, "\n"); + if (s & (1 << i)) + (void) fprintf(fp, "%12ld", (u_long)ltemp); + else + (void) fprintf(fp, "%12lu", (u_long)ltemp); + } + (void) fprintf(fp, "\n"); + + n = (int)cl->ntimes; + (void) fprintf(fp, "times: %d", n); + s = ntohl(cl->stimes); + if (n > NUMCBUGTIMES) + n = NUMCBUGTIMES; + needsp = 0; + for (i = 0; i < n; i++) { + if ((i & 0x1) == 0) { + (void) fprintf(fp, "\n"); + } else { + for (;needsp > 0; needsp--) + putc(' ', fp); + } + NTOHL_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"); + } + } +} + + +/* + * kerninfo - display the kernel pll/pps variables + */ +static void +kerninfo( + struct parse *pcmd, + FILE *fp + ) +{ + struct info_kernel *ik; + int items; + int itemsize; + int res; + unsigned status; + double tscale = 1e-6; + + res = doquery(IMPL_XNTPD, REQ_GET_KERNEL, 0, 0, 0, (char *)NULL, + &items, &itemsize, (char **)&ik, 0); + if (res != 0 && items == 0) + return; + if (!check1item(items, fp)) + return; + if (!checkitemsize(itemsize, sizeof(struct info_kernel))) + return; + + status = ntohs(ik->status) & 0xffff; + /* + * pll variables. We know more than we should about the NANO bit. + */ +#ifdef STA_NANO + if (status & STA_NANO) + tscale = 1e-9; +#endif + (void)fprintf(fp, "pll offset: %g s\n", + (long)ntohl(ik->offset) * tscale); + (void)fprintf(fp, "pll frequency: %s ppm\n", + fptoa((s_fp)ntohl(ik->freq), 3)); + (void)fprintf(fp, "maximum error: %g s\n", + (u_long)ntohl(ik->maxerror) * 1e-6); + (void)fprintf(fp, "estimated error: %g s\n", + (u_long)ntohl(ik->esterror) * 1e-6); + (void)fprintf(fp, "status: %04x ", status); +#ifdef STA_PLL + if (status & STA_PLL) (void)fprintf(fp, " pll"); +#endif +#ifdef STA_PPSFREQ + if (status & STA_PPSFREQ) (void)fprintf(fp, " ppsfreq"); +#endif +#ifdef STA_PPSTIME + if (status & STA_PPSTIME) (void)fprintf(fp, " ppstime"); +#endif +#ifdef STA_FLL + if (status & STA_FLL) (void)fprintf(fp, " fll"); +#endif +#ifdef STA_INS + if (status & STA_INS) (void)fprintf(fp, " ins"); +#endif +#ifdef STA_DEL + if (status & STA_DEL) (void)fprintf(fp, " del"); +#endif +#ifdef STA_UNSYNC + if (status & STA_UNSYNC) (void)fprintf(fp, " unsync"); +#endif +#ifdef STA_FREQHOLD + if (status & STA_FREQHOLD) (void)fprintf(fp, " freqhold"); +#endif +#ifdef STA_PPSSIGNAL + if (status & STA_PPSSIGNAL) (void)fprintf(fp, " ppssignal"); +#endif +#ifdef STA_PPSJITTER + if (status & STA_PPSJITTER) (void)fprintf(fp, " ppsjitter"); +#endif +#ifdef STA_PPSWANDER + if (status & STA_PPSWANDER) (void)fprintf(fp, " ppswander"); +#endif +#ifdef STA_PPSERROR + if (status & STA_PPSERROR) (void)fprintf(fp, " ppserror"); +#endif +#ifdef STA_CLOCKERR + if (status & STA_CLOCKERR) (void)fprintf(fp, " clockerr"); +#endif +#ifdef STA_NANO + if (status & STA_NANO) (void)fprintf(fp, " nano"); +#endif +#ifdef STA_MODE + if (status & STA_MODE) (void)fprintf(fp, " mode=fll"); +#endif +#ifdef STA_CLK + if (status & STA_CLK) (void)fprintf(fp, " src=B"); +#endif + (void)fprintf(fp, "\n"); + (void)fprintf(fp, "pll time constant: %ld\n", + (u_long)ntohl(ik->constant)); + (void)fprintf(fp, "precision: %g s\n", + (u_long)ntohl(ik->precision) * tscale); + (void)fprintf(fp, "frequency tolerance: %s ppm\n", + fptoa((s_fp)ntohl(ik->tolerance), 0)); + + /* + * For backwards compatibility (ugh), we find the pps variables + * only if the shift member is nonzero. + */ + if (!ik->shift) + return; + + /* + * pps variables + */ + (void)fprintf(fp, "pps frequency: %s ppm\n", + fptoa((s_fp)ntohl(ik->ppsfreq), 3)); + (void)fprintf(fp, "pps stability: %s ppm\n", + fptoa((s_fp)ntohl(ik->stabil), 3)); + (void)fprintf(fp, "pps jitter: %g s\n", + (u_long)ntohl(ik->jitter) * tscale); + (void)fprintf(fp, "calibration interval: %d s\n", + 1 << ntohs(ik->shift)); + (void)fprintf(fp, "calibration cycles: %ld\n", + (u_long)ntohl(ik->calcnt)); + (void)fprintf(fp, "jitter exceeded: %ld\n", + (u_long)ntohl(ik->jitcnt)); + (void)fprintf(fp, "stability exceeded: %ld\n", + (u_long)ntohl(ik->stbcnt)); + (void)fprintf(fp, "calibration errors: %ld\n", + (u_long)ntohl(ik->errcnt)); +} diff --git a/contrib/ntp/ntpq/Makefile.am b/contrib/ntp/ntpq/Makefile.am new file mode 100644 index 000000000000..aced16938c6a --- /dev/null +++ b/contrib/ntp/ntpq/Makefile.am @@ -0,0 +1,21 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +bin_PROGRAMS = ntpq +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o ../libntp/libntp.a @LIBRSAREF@ +DISTCLEANFILES = .version +noinst_HEADERS = ntpq.h +#EXTRA_DIST = ntpq.mak +ETAGS_ARGS = Makefile.am + +ntpq_SOURCES = ntpq.c ntpq_ops.c + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +version.o: $(ntpq_OBJECTS) ../libntp/libntp.a @LIBRSAREF@ Makefile + $(top_builddir)/scripts/mkver ntpq + $(COMPILE) -c version.c diff --git a/contrib/ntp/ntpq/Makefile.in b/contrib/ntp/ntpq/Makefile.in new file mode 100644 index 000000000000..549840aa47b4 --- /dev/null +++ b/contrib/ntp/ntpq/Makefile.in @@ -0,0 +1,360 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ../util/ansi2knr +bin_PROGRAMS = ntpq +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o ../libntp/libntp.a @LIBRSAREF@ +DISTCLEANFILES = .version +noinst_HEADERS = ntpq.h +#EXTRA_DIST = ntpq.mak +ETAGS_ARGS = Makefile.am + +ntpq_SOURCES = ntpq.c ntpq_ops.c +subdir = ntpq +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +ANSI2KNR = ../util/ansi2knr +am_ntpq_OBJECTS = ntpq$U.o ntpq_ops$U.o +ntpq_OBJECTS = $(am_ntpq_OBJECTS) +ntpq_LDADD = $(LDADD) +ntpq_DEPENDENCIES = version.o ../libntp/libntp.a +ntpq_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(ntpq_SOURCES) +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +SOURCES = $(ntpq_SOURCES) +OBJECTS = $(am_ntpq_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ntpq/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: +../util/ansi2knr: ../util/ansi2knr.o + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr + +../util/ansi2knr.o: + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o + + +mostlyclean-kr: + -rm -f *_.c + +clean-kr: + +distclean-kr: + +maintainer-clean-kr: +ntpq$U.o: +ntpq_ops$U.o: + +ntpq: $(ntpq_OBJECTS) $(ntpq_DEPENDENCIES) + @rm -f ntpq + $(LINK) $(ntpq_LDFLAGS) $(ntpq_OBJECTS) $(ntpq_LDADD) $(LIBS) +ntpq_.c: ntpq.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpq.c; then echo $(srcdir)/ntpq.c; else echo ntpq.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntpq_.c +ntpq_ops_.c: ntpq_ops.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpq_ops.c; then echo $(srcdir)/ntpq_ops.c; else echo ntpq_ops.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntpq_ops_.c +ntpq_.o ntpq_ops_.o : $(ANSI2KNR) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +ntpq.o: ntpq.c ntpq.h ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp.h ../include/ntp_control.h \ + ../include/ntp_string.h ../include/ntp_malloc.h \ + ../include/ntp_unixtime.h ../include/ntp_calendar.h \ + ../include/ntp_io.h ../include/ntp_select.h \ + ../include/ntp_stdlib.h ../include/l_stdlib.h +ntpq_ops.o: ntpq_ops.c ntpq.h ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp.h ../include/ntp_control.h \ + ../include/ntp_string.h ../include/ntp_malloc.h \ + ../include/ntp_stdlib.h ../include/l_stdlib.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-kr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-compile clean-kr clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-compile distclean-kr \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-kr \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-kr distclean-kr clean-kr \ +maintainer-clean-kr tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +version.o: $(ntpq_OBJECTS) ../libntp/libntp.a @LIBRSAREF@ Makefile + $(top_builddir)/scripts/mkver ntpq + $(COMPILE) -c version.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/ntpq/README b/contrib/ntp/ntpq/README new file mode 100644 index 000000000000..d280f7481b3a --- /dev/null +++ b/contrib/ntp/ntpq/README @@ -0,0 +1,6 @@ +README file for directory ./ntpq of the NTP Version 4 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/ntp/ntpq/ntpq.c b/contrib/ntp/ntpq/ntpq.c new file mode 100644 index 000000000000..3361e2bc1fd7 --- /dev/null +++ b/contrib/ntp/ntpq/ntpq.c @@ -0,0 +1,3095 @@ +/* + * ntpq - query an NTP server using mode 6 commands + */ +#include +#include +#include +#include +#include +#include +#include +#ifdef SYS_WINNT +# include +#else +#define closesocket close +#endif /* SYS_WINNT */ + +#include "ntpq.h" +#include "ntp_unixtime.h" +#include "ntp_calendar.h" +#include "ntp_io.h" +#include "ntp_select.h" +#include "ntp_stdlib.h" + +#ifdef SYS_VXWORKS +/* vxWorks needs mode flag -casey*/ +#define open(name, flags) open(name, flags, 0777) +#define SERVER_PORT_NUM 123 +#endif + +/* + * 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 */ +const char *prompt = "ntpq> "; /* prompt to ask him about */ + + +/* + * Keyid used for authenticated requests. Obtained on the fly. + */ +u_long info_auth_keyid = NTP_MAXKEY; + +/* + * Type of key md5 or des + */ +#define KEY_TYPE_DES 3 +#define KEY_TYPE_MD5 4 + +static int info_auth_keytype = KEY_TYPE_MD5; /* MD5 */ +u_long current_time; /* needed by authkeys; not used */ + +/* + * 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_OLDVERSION + 1; + +/* + * Don't jump if no set jmp. + */ +volatile 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 SI 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 FX 15 /* test flags */ +#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, SI, "precision" }, /* 3 */ + { CS_ROOTDELAY, FS, "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_STATE, UI, "state" }, /* 10 */ + { CS_OFFSET, FL, "phase" }, /* 11 */ + { CS_DRIFT, FS, "frequency" }, /* 12 */ + { CS_COMPLIANCE, FU, "jitter" }, /* 13 */ + { CS_CLOCK, TS, "clock" }, /* 14 */ + { CS_PROCESSOR, ST, "processor" }, /* 15 */ + { CS_SYSTEM, ST, "system" }, /* 16 */ + { CS_STABIL, FS, "stability" }, /* 17 */ + { 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, SI, "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, FS, "delay" }, /* 24 */ + { CP_OFFSET, FL, "offset" }, /* 25 */ + { CP_JITTER, FU, "jitter" }, /* 26 */ + { CP_DISPERSION, FU, "dispersion" }, /* 27 */ + { CP_KEYID, UI, "keyid" }, /* 28 */ + { CP_FILTDELAY, AR, "filtdelay" }, /* 29 */ + { CP_FILTOFFSET, AR, "filtoffset" }, /* 30 */ + { CP_PMODE, ST, "pmode" }, /* 31 */ + { CP_RECEIVED, UI, "received" }, /* 32 */ + { CP_SENT, UI, "sent" }, /* 33 */ + { CP_FILTERROR, AR, "filtdisp" }, /* 34 */ + { CP_FLASH, FX, "flash" }, /* 35 */ + { CP_DISP, FU, "disp" }, /* 36 */ + /* + * These are duplicate entries so that we can + * process deviant version of the ntp protocol. + */ + { CP_SRCADR, HA, "peeraddr" }, /* 4 */ + { CP_SRCPORT, UI, "peerport" }, /* 5 */ + { CP_PPOLL, UI, "peerpoll" }, /* 11 */ + { CP_HPOLL, UI, "hostpoll" }, /* 12 */ + { CP_FILTERROR, AR, "filterror" }, /* 34 */ + { 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, UI, "stratum" }, /* 9 */ + { CC_FUDGEVAL2, RF, "refid" }, /* 10 */ + { CC_FLAGS, UI, "flags" }, /* 11 */ + { CC_DEVICE, ST, "device" }, /* 12 */ + { 0, EOV, "" } +}; + + +/* + * flasher bits + */ +static const char *tstflagnames[] = { + "dup_pkt", /* TEST1 */ + "bogus_pkt", /* TEST2 */ + "proto_sync", /* TEST3 */ + "peer_bounds", /* TEST4 */ + "auth", /* TEST5 */ + "peer_sync", /* TEST6 */ + "peer_stratum", /* TEST7 */ + "root_bounds", /* TEST8 */ + "peer_auth", /* TEST9 */ + "access" /* TEST10 */ +}; + + +int ntpqmain P((int, char **)); +/* + * Built in command handler declarations + */ +static int openhost P((const 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 char * tstflags P((u_long)); +static void getcmds P((void)); +static RETSIGTYPE abortcmd P((int)); +static void docmd P((const char *)); +static void tokenize P((const 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 *)); +static int decodearr P((char *, int *, l_fp *)); +static void help P((struct parse *, FILE *)); +#ifdef QSORT_USES_VOID_P +static int helpsort P((const void *, const void *)); +#else +static int helpsort P((char **, char **)); +#endif +static void printusage P((struct xcmd *, FILE *)); +static void timeout P((struct parse *, FILE *)); +static void auth_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((const char *, const char *, const char *)); +static void error P((const char *, const char *, const char *)); +static u_long getkeyid P((const char *)); +static void atoascii P((int, char *, char *)); +static void makeascii P((int, char *, FILE *)); +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 *)); +#ifdef QSORT_USES_VOID_P +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", auth_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" }, + { "exit", 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, { OPT|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 200 /* 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 400 /* 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 opened on */ +int havehost = 0; /* set to 1 when host open */ +struct servent *server_entry = NULL; /* server entry for ntp */ + +#ifdef SYS_WINNT +WORD wVersionRequested; +WSADATA wsaData; +DWORD NumberOfBytesWritten; + +HANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */ +void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */ + +#endif /* SYS_WINNT */ + +/* + * 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; +const char *ccmds[MAXCMDS]; +#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) + +/* + * When multiple hosts are specified. + */ +int numhosts = 0; +const 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; +volatile int debug; + +#ifdef NO_MAIN_ALLOWED +CALL(ntpq,"ntpq",ntpqmain); + +void clear_globals(void) +{ + extern int ntp_optind; + extern char *ntp_optarg; + showhostnames = 0; /* don'tshow host names by default */ + ntp_optind = 0; + ntp_optarg = 0; + server_entry = NULL; /* server entry for ntp */ + havehost = 0; /* set to 1 when host open */ + numassoc = 0; /* number of cached associations */ + numcmds = 0; + numhosts = 0; +} +#endif + +/* + * main - parse arguments and handle options + */ +#ifndef NO_MAIN_ALLOWED +int +main( + int argc, + char *argv[] + ) +{ + return ntpqmain(argc, argv); +} +#endif + +int +ntpqmain( + int argc, + char *argv[] + ) +{ + int c; + int errflg = 0; + extern int ntp_optind; + extern char *ntp_optarg; + +#ifdef NO_MAIN_ALLOWED + clear_globals(); + taskPrioritySet(taskIdSelf(), 100 ); +#endif + 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; + } + +#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ + if (interactive) + (void) signal_no_reset(SIGINT, abortcmd); +#endif /* SYS_WINNT */ + +#ifdef SYS_WINNT + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) { + fprintf(stderr, "No useable winsock.dll"); + exit(1); + } +#endif /* SYS_WINNT */ + + 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]); + } + } +#ifdef SYS_WINNT + WSACleanup(); +#endif /* SYS_WINNT */ + return 0; +} + + +/* + * openhost - open a socket to a host + */ +static int +openhost( + const char *hname + ) +{ + u_int32 netnum; + char temphost[LENHOSTNAME]; + + if (server_entry == NULL) { + server_entry = getservbyname("ntp", "udp"); + if (server_entry == NULL) { +#ifdef VMS /* UCX getservbyname() doesn't work [yet], but we do know better */ + server_entry = (struct servent *) + malloc(sizeof(struct servent)); + server_entry->s_port = htons(NTP_PORT); +#else + (void) fprintf(stderr, "%s: ntp/udp: unknown service\n", + progname); + exit(1); +#endif /* VMS & UCX */ + } + 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) closesocket(sockfd); + havehost = 0; + } + (void) strcpy(currenthost, temphost); + + hostaddr.sin_family = AF_INET; +#ifndef SYS_VXWORKS + hostaddr.sin_port = server_entry->s_port; +#else + hostaddr.sin_port = htons(SERVER_PORT_NUM); +#endif + hostaddr.sin_addr.s_addr = netnum; + +#ifdef SYS_WINNT + { + int optionValue = SO_SYNCHRONOUS_NONALERT; + int err; + err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)); + if (err != NO_ERROR) { + (void) fprintf(stderr, "cannot open nonoverlapped sockets\n"); + exit(1); + } + } + + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == INVALID_SOCKET) { + error("socket", "", ""); + exit(-1); + } +#else + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) + error("socket", "", ""); +#endif /* SYS_WINNT */ + + +#ifdef NEED_RCVBUF_SLOP +# 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( + char *xdata, + int xdatalen + ) +{ + if (debug >= 3) + printf("Sending %d octets\n", xdatalen); + + + if (send(sockfd, xdata, xdatalen, 0) == -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( + 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 0 + if (debug >= 1) + printf("select() returns %d\n", n); +#endif + + 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 = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); + 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", + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 3]), + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 2]), + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 1]), + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long)]), + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 1]), + (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 2])); + key = ntohl(lpkt[(n - maclen) / sizeof(u_long)]); + printf("Authenticated with keyid %lu\n", (u_long)key); + if (key != 0 && key != info_auth_keyid) { + printf("We don't know that key\n"); + } else { + if (authdecrypt(key, (u_int32 *)&rpkt, + n - maclen, 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( + 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, (unsigned)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 { + const char *pass = "\0"; + int maclen = 0; + u_long my_keyid; + + /* + * 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 == 0) { + maclen = getkeyid("Keyid: "); + if (maclen == 0) { + (void) fprintf(stderr, + "Invalid key identifier\n"); + return 1; + } + } + if (!authistrusted(info_auth_keyid)) { + pass = getpass((info_auth_keytype == KEY_TYPE_DES) + ? "DES Password: " : "MD5 Password: "); + if (*pass == '\0') { + (void) fprintf(stderr, + "Invalid password\n"); + return (1); + } + } + info_auth_keyid = maclen; + authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass); + authtrust(info_auth_keyid, 1); + + /* + * Stick the keyid in the packet where + * cp currently points. Cp should be aligned + * properly. Then do the encryptions. + */ + my_keyid = htonl(info_auth_keyid); + memcpy(&qpkt.data[qsize], &my_keyid, sizeof my_keyid); + maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt, + pktsize); + if (maclen == 0) { + (void) fprintf(stderr, "Key not found\n"); + return (1); + } + return sendpkt((char *)&qpkt, pktsize + maclen); + } + /*NOTREACHED*/ +} + + +/* + * doquery - send a request and process the response + */ +int +doquery( + 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 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(void) +{ + char line[MAXLINE]; + + for (;;) { + if (interactive) { +#ifdef VMS /* work around a problem with mixing stdout & stderr */ + fputs("",stdout); +#endif + (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( + 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( + const 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)) { + jump = 0; + return; + } else { + jump++; + (xcmd->handler)(&pcmd, current_output); + jump = 0; /* HMS: 961106: was after fclose() */ + if (i) (void) fclose(current_output); + } +} + + +/* + * tokenize - turn a command line into tokens + */ +static void +tokenize( + const char *line, + char **tokens, + int *ntok + ) +{ + register const 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( + 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, (unsigned)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( + char *str, + int code, + arg_v *argp + ) +{ + int isneg; + char *cp, *np; + static const 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( + const char *hname, + u_int32 *num, + char *fullhost + ) +{ + struct hostent *hp; + + if (decodenetnum(hname, num)) { + if (fullhost != 0) { + (void) sprintf(fullhost, "%lu.%lu.%lu.%lu", + (u_long)((htonl(*num) >> 24) & 0xff), + (u_long)((htonl(*num) >> 16) & 0xff), + (u_long)((htonl(*num) >> 8) & 0xff), + (u_long)(htonl(*num) & 0xff)); + } + return 1; + } else if ((hp = gethostbyname(hname)) != 0) { + memmove((char *)num, hp->h_addr, sizeof(u_int32)); + if (fullhost != 0) + (void) strcpy(fullhost, hp->h_name); + return 1; + } else { + (void) fprintf(stderr, "***Can't find host %s\n", hname); + return 0; + } + /*NOTREACHED*/ +} + +/* + * nntohost - convert network number to host name. This routine enforces + * the showhostnames setting. + */ +char * +nntohost( + u_int32 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( + char *str, + l_fp *lfp + ) +{ + register char *cp; + register int i; + struct calendar cal; + char buf[4]; + static const 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 + * + * (No docs, but assume 4-digit years are also legal...) + * + * d[d]-Mth-y[y[y[y]]] hh:mm:ss + */ + cp = str; + if (!isdigit((int)*cp)) { + if (*cp == '-') { + /* + * Catch special case + */ + L_CLR(lfp); + return 1; + } + return 0; + } + + cal.monthday = *cp++ - '0'; /* ascii dependent */ + if (isdigit((int)*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((int)*cp)) + return 0; + cal.year = *cp++ - '0'; + if (isdigit((int)*cp)) { + cal.year = (cal.year << 3) + (cal.year << 1); + cal.year += *cp++ - '0'; + } + if (isdigit((int)*cp)) { + cal.year = (cal.year << 3) + (cal.year << 1); + cal.year += *cp++ - '0'; + } + if (isdigit((int)*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) { + L_CLR(lfp); + return 1; + } + + if (*cp++ != ' ' || !isdigit((int)*cp)) + return 0; + cal.hour = *cp++ - '0'; + if (isdigit((int)*cp)) { + cal.hour = (cal.hour << 3) + (cal.hour << 1); + cal.hour += *cp++ - '0'; + } + + if (*cp++ != ':' || !isdigit((int)*cp)) + return 0; + cal.minute = *cp++ - '0'; + if (isdigit((int)*cp)) { + cal.minute = (cal.minute << 3) + (cal.minute << 1); + cal.minute += *cp++ - '0'; + } + + if (*cp++ != ':' || !isdigit((int)*cp)) + return 0; + cal.second = *cp++ - '0'; + if (isdigit((int)*cp)) { + cal.second = (cal.second << 3) + (cal.second << 1); + cal.second += *cp++ - '0'; + } + + /* + * For RT-11, 1972 seems to be the pivot year + */ + if (cal.year < 72) + cal.year += 2000; + if (cal.year < 100) + 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( + 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( + char *str, + l_fp *lfp + ) +{ + return mstolfp(str, lfp); +} + + +/* + * decodeint - decode an integer + */ +int +decodeint( + 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( + 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( + 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((int)*cp)) + cp++; + if (*cp == '\0') + break; + + bp = buf; + while (!isspace((int)*cp) && *cp != '\0') + *bp++ = *cp++; + *bp++ = '\0'; + + if (!decodetime(buf, lfp)) + return 0; + (*narr)++; + lfp++; + } + return 1; +} + + +/* + * Finally, the built in command handlers + */ + +/* + * help - tell about commands, or details of a particular command + */ +static void +help( + struct parse *pcmd, + FILE *fp + ) +{ + int i; + int n; + struct xcmd *xcp; + char *cmd; + const char *cmdsort[100]; + int length[100]; + int maxlength; + int numperline; + static const 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; + +#ifdef QSORT_USES_VOID_P + qsort(cmdsort, (unsigned)n, sizeof(char *), helpsort); +#else + qsort((char *)cmdsort, n, sizeof(char *), helpsort); +#endif + + 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 + */ +#ifdef QSORT_USES_VOID_P +static int +helpsort( + const void *t1, + const void *t2 + ) +{ + const char **name1 = (const char **)t1; + const char **name2 = (const char **)t2; + + return strcmp(*name1, *name2); +} + +#else +static int +helpsort( + char **name1, + char **name2 + ) +{ + return strcmp(*name1, *name2); +} +#endif + +/* + * printusage - print usage information for a command + */ +static void +printusage( + 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( + 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; + } +} + + +/* + * auth_delay - set delay for auth requests + */ +static void +auth_delay( + 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 %lu 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( + 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( + 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( + struct parse *pcmd, + FILE *fp + ) +{ + if (pcmd->nargs == 0) { + if (info_auth_keyid > NTP_MAXKEY) + (void) fprintf(fp, "no keyid defined\n"); + else + (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); + } else { + info_auth_keyid = pcmd->argval[0].uval; + } +} + +/* + * keytype - get type of key to use for authenticating requests + */ +static void +keytype( + struct parse *pcmd, + FILE *fp + ) +{ + if (pcmd->nargs == 0) + fprintf(fp, "keytype is %s\n", + (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( + struct parse *pcmd, + FILE *fp + ) +{ + char *pass; + + if (info_auth_keyid > NTP_MAXKEY) { + info_auth_keyid = getkeyid("Keyid: "); + if (info_auth_keyid > NTP_MAXKEY) { + (void)fprintf(fp, "Keyid must be defined\n"); + return; + } + } + pass = getpass((info_auth_keytype == KEY_TYPE_DES) + ? "DES Password: " + : "MD5 Password: " + ); + if (*pass == '\0') + (void) fprintf(fp, "Password unchanged\n"); + else + authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass); +} + + +/* + * hostnames - set the showhostnames flag + */ +static void +hostnames( + 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( + 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( + struct parse *pcmd, + FILE *fp + ) +{ + if (havehost) + closesocket(sockfd); /* cleanliness next to godliness */ + exit(0); +} + + +/* + * version - print the current version number + */ +/*ARGSUSED*/ +static void +version( + struct parse *pcmd, + FILE *fp + ) +{ + + (void) fprintf(fp, "%s\n", Version); + return; +} + + +/* + * raw - set raw mode output + */ +/*ARGSUSED*/ +static void +raw( + struct parse *pcmd, + FILE *fp + ) +{ + rawmode = 1; + (void) fprintf(fp, "Output set to raw\n"); +} + + +/* + * cooked - set cooked mode output + */ +/*ARGSUSED*/ +static void +cooked( + 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( + 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( + 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, NTP_VERSION); + } else { + pktversion = (u_char) pcmd->argval[0].uval; + } + } +} + + +/* + * warning - print a warning message + */ +static void +warning( + const char *fmt, + const char *st1, + const 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( + const char *fmt, + const char *st1, + const char *st2 + ) +{ + warning(fmt, st1, st2); + exit(1); +} + +/* + * getkeyid - prompt the user for a keyid to use + */ +static u_long +getkeyid( + const char *keyprompt + ) +{ + register char *p; + register int c; + FILE *fi; + char pbuf[20]; + +#ifndef SYS_WINNT + if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) +#else + if ((fi = _fdopen((int)GetStdHandle(STD_INPUT_HANDLE), "r")) == NULL) +#endif /* SYS_WINNT */ + fi = stdin; + else + setbuf(fi, (char *)NULL); + fprintf(stderr, "%s", keyprompt); 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( + 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( + 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( + 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; + +/* + * nextvar - find the next variable in the buffer + */ +int +nextvar( + int *datalen, + char **datap, + char **vname, + char **vvalue + ) +{ + register char *cp; + register char *np; + register char *cpend; + register char *npend; /* character after last */ + 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((int)*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; + npend = &name[MAXVARLEN]; + while (cp < cpend && np < npend && *cp != ',' && *cp != '=' + && *cp != '\r' && *cp != '\n') + *np++ = *cp++; + /* + * Check if we ran out of name space, without reaching the end or a + * terminating character + */ + if (np == npend && !(cp == cpend || *cp == ',' || *cp == '=' || + *cp == '\r' || *cp == '\n')) + return 0; + while (isspace((int)(*(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((int)*cp) && *cp != '\r' && *cp != '\n')) + cp++; + np = value; + npend = &value[MAXVALLEN]; + while (cp < cpend && np < npend && ((*cp != ',') || quoted)) + { + quoted ^= ((*np++ = *cp++) == '"'); + } + + /* + * Check if we overran the value buffer while still in a quoted string + * or without finding a comma + */ + if (np == npend && (quoted || *cp != ',')) + return 0; + /* + * Trim off any trailing whitespace + */ + while (np > value && isspace((int)(*(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( + 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( + 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( + 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=0x%04x,\n", 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((int)*cp) || isprint((int)*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(void) +{ + out_chars = 0; + out_linecount = 0; +} + + +/* + * output - output a variable=value combination + */ +static void +output( + 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( + FILE *fp + ) +{ + if (out_chars != 0) + putc('\n', fp); +} + + +/* + * outputarr - output an array of values + */ +static void +outputarr( + 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 + */ + for (i = (int)strlen(name); i < 11; i++) + *bp++ = ' '; + + for (i = narr; i > 0; i--) { + if (i != narr) + *bp++ = ' '; + cp = lfptoms(lfp, 2); + len = strlen(cp); + if (len > 7) { + cp[7] = '\0'; + len = 7; + } + while (len < 7) { + *bp++ = ' '; + len++; + } + while (*cp != '\0') + *bp++ = *cp++; + lfp++; + } + *bp = '\0'; + output(fp, name, buf); +} + +static char * +tstflags( + u_long val + ) +{ + register char *cb, *s; + register int i; + register const char *sep; + + sep = ""; + i = 0; + s = cb = &circ_buf[nextcb][0]; + if (++nextcb >= NUMCB) + nextcb = 0; + + sprintf(cb, "%02lx", val); + cb += strlen(cb); + if (!val) { + strcat(cb, " ok"); + cb += strlen(cb); + } else { + *cb++ = ' '; + for (i = 0; i < 10; i++) { + if (val & 0x1) { + sprintf(cb, "%s%s", sep, tstflagnames[i]); + sep = ", "; + cb += strlen(cb); + } + val >>= 1; + } + } + *cb = '\0'; + return s; +} + +/* + * cookedprint - output variables in cooked mode + */ +static void +cookedprint( + 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_int32 hval; + 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; + } + + (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; + fmt = varlist[varid].fmt; + switch(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, 3)); + break; + case FS: + output(fp, name, + lfptoms(&lfp, 3)); + break; + } + } + break; + + case UI: + if (!decodeuint(value, &uval)) + output_raw = '?'; + else + output(fp, name, uinttoa(uval)); + break; + + case SI: + if (!decodeint(value, &ival)) + output_raw = '?'; + else + output(fp, name, inttoa(ival)); + break; + + case HA: + case NA: + if (!decodenetnum(value, &hval)) + output_raw = '?'; + else if (fmt == HA) + output(fp, name, nntohost(hval)); + else + output(fp, name, numtoa(hval)); + break; + + case ST: + output_raw = '*'; + break; + + case RF: + if (decodenetnum(value, &hval)) + output(fp, name, nntohost(hval)); + 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, "%03lo", 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; + + case FX: + if (!decodeuint(value, &uval)) + output_raw = '?'; + else + output(fp, name, tstflags(uval)); + 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(void) +{ + if (numassoc > 1) + qsort( +#ifdef QSORT_USES_VOID_P + (void *) +#else + (char *) +#endif + assoc_cache, (unsigned)numassoc, + sizeof(struct association), assoccmp); +} + + +/* + * assoccmp - compare two associations + */ +#ifdef QSORT_USES_VOID_P +static int +assoccmp( + const void *t1, + const void *t2 + ) +{ + const struct association *ass1 = (const struct association *)t1; + const struct association *ass2 = (const struct association *)t2; + + if (ass1->assid < ass2->assid) + return -1; + if (ass1->assid > ass2->assid) + return 1; + return 0; +} +#else +static int +assoccmp( + struct association *ass1, + struct association *ass2 + ) +{ + if (ass1->assid < ass2->assid) + return -1; + if (ass1->assid > ass2->assid) + return 1; + return 0; +} +#endif /* not QSORT_USES_VOID_P */ diff --git a/contrib/ntp/ntpq/ntpq.h b/contrib/ntp/ntpq/ntpq.h new file mode 100644 index 000000000000..8739cd4772d8 --- /dev/null +++ b/contrib/ntp/ntpq/ntpq.h @@ -0,0 +1,89 @@ +/* + * 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_int32 netnum; +} arg_v; + +/* + * Structure for passing parsed command line + */ +struct parse { + const char *keyword; + arg_v argval[MAXARGS]; + int nargs; +}; + +/* + * ntpdc includes a command parser which could charitably be called + * crude. The following structure is used to define the command + * syntax. + */ +struct xcmd { + const char *keyword; /* command key word */ + void (*handler) P((struct parse *, FILE *)); /* command handler */ + u_char arg[MAXARGS]; /* descriptors for arguments */ + const char *desc[MAXARGS]; /* descriptions for arguments */ + const char *comment; +}; + +/* + * 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; + const char *text; +}; + +extern void asciize P((int, char *, FILE *)); +extern int getnetnum P((const char *, u_int32 *, char *)); +extern void sortassoc P((void)); +extern int doquery P((int, int, int, int, char *, u_short *, int *, char **)); +extern char * nntohost P((u_int32)); +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/ntp/ntpq/ntpq_ops.c b/contrib/ntp/ntpq/ntpq_ops.c new file mode 100644 index 000000000000..d43d228230f2 --- /dev/null +++ b/contrib/ntp/ntpq/ntpq_ops.c @@ -0,0 +1,1651 @@ +/* + * ntpdc_ops.c - subroutines which are called to perform operations by ntpdc + */ +#include +#include +#include +#include +#include + +#include "ntpq.h" +#include "ntp_stdlib.h" + +extern char * chosts[]; +extern char currenthost[]; +extern int numhosts; +int maxhostlen; + +/* + * Declarations for command handlers in here + */ +static int checkassocid P((u_int32)); +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_int32, u_int32, 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 long when P((l_fp *, l_fp *, l_fp *)); +static char * prettyinterval P((char *, long)); +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 struct servent *server_entry; +extern struct association assoc_cache[]; +extern int numassoc; +extern u_char pktversion; +extern struct ctl_var peer_var[]; + +/* + * 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( + u_int32 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( + 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( + 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( + 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) { + free(vl->value); + vl->value = 0; + } + + if (value != 0) + vl->value = strsave(value); + } +} + + +/* + * dormvlist - remove variable(s) from the variable list + */ +static void +dormvlist( + 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 { + free((void *)vl->name); + if (vl->value != 0) + 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( + struct varlist *vlist + ) +{ + register struct varlist *vl; + + for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) { + free((void *)vl->name); + vl->name = 0; + if (vl->value != 0) { + free(vl->value); + vl->value = 0; + } + } +} + + +/* + * makequerydata - form a data buffer to be included with a query + */ +static void +makequerydata( + 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, (unsigned)namelen); + cp += namelen; + if (valuelen != 0) { + *cp++ = '='; + memmove(cp, vl->value, (unsigned)valuelen); + cp += valuelen; + } + } + *datalen = cp - data; +} + + +/* + * doquerylist - send a message including variables in a list + */ +static int +doquerylist( + 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( + 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( + struct parse *pcmd, + FILE *fp + ) +{ + doaddvlist(varlist, pcmd->argval[0].string); +} + + +/* + * rmvars - remove variables from the variable list + */ +/*ARGSUSED*/ +static void +rmvars( + struct parse *pcmd, + FILE *fp + ) +{ + dormvlist(varlist, pcmd->argval[0].string); +} + + +/* + * clearvars - clear the variable list + */ +/*ARGSUSED*/ +static void +clearvars( + struct parse *pcmd, + FILE *fp + ) +{ + doclearvlist(varlist); +} + + +/* + * showvars - show variables on the variable list + */ +/*ARGSUSED*/ +static void +showvars( + struct parse *pcmd, + FILE *fp + ) +{ + doprintvlist(varlist, fp); +} + + +/* + * dolist - send a request with the given list of variables + */ +static int +dolist( + 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( + struct parse *pcmd, + FILE *fp + ) +{ + int associd; + + if (pcmd->nargs == 0) { + associd = 0; + } else { + /* HMS: I think we want the u_int32 target here, not the u_long */ + 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( + struct parse *pcmd, + FILE *fp + ) +{ + char *datap; + int res; + int associd; + int dsize; + u_short rstatus; + + if (pcmd->nargs == 0) { + associd = 0; + } else { + /* HMS: Do we really want uval here? */ + 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, 1, &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( + struct parse *pcmd, + FILE *fp + ) +{ + int associd; + struct varlist tmplist[MAXLIST]; + + /* HMS: uval? */ + 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( + struct parse *pcmd, + FILE *fp + ) +{ + char *datap; + int res; + int associd; + int dsize; + u_short rstatus; + struct varlist tmplist[MAXLIST]; + + /* HMS: uval? */ + 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, 1, &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( + struct parse *pcmd, + FILE *fp + ) +{ + int associd; + + /* HMS: uval? */ + 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( + struct parse *pcmd, + FILE *fp + ) +{ + int associd; + struct varlist tmplist[MAXLIST]; + + /* HMS: uval? */ + 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( + u_int32 assid1, + u_int32 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", (u_long)assid1); + return 0; + } + + if (assid2 == 0 || assid2 > 65535) { + (void) fprintf(stderr, + "***Invalid association ID %lu specified\n", (u_long)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) ? (u_long)assid1 : (u_long)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( + struct parse *pcmd, + FILE *fp + ) +{ + int i; + int from; + int to; + + /* HMS: uval? */ + 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( + struct parse *pcmd, + FILE *fp + ) +{ + int i; + int from; + int to; + struct varlist tmplist[MAXLIST]; + + /* HMS: uval? */ + 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( + 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( + int showall, + FILE *fp + ) +{ + register char *bp; + int i; + u_char statval; + int event; + u_long event_count; + const char *conf; + const char *reach; + const char *auth; + const char *condition = ""; + const char *last_event; + const 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_OLDVERSION) + switch (statval & 0x7) { + case CTL_PST_SEL_REJECT: + condition = "reject"; + break; + case CTL_PST_SEL_SANE: + condition = "falsetick"; + break; + case CTL_PST_SEL_CORRECT: + condition = "excess"; + break; + case CTL_PST_SEL_SELCAND: + condition = "outlyer"; + break; + case CTL_PST_SEL_SYNCCAND: + condition = "candidat"; + break; + case CTL_PST_SEL_DISTSYSPEER: + condition = "selected"; + 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( + 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( + struct parse *pcmd, + FILE *fp + ) +{ + if (dogetassoc(fp)) + printassoc(1, fp); +} + + +/* + * passociations - print the association list + */ +/*ARGSUSED*/ +static void +passociations( + struct parse *pcmd, + FILE *fp + ) +{ + printassoc(0, fp); +} + + +/* + * lpassociations - print the long association list + */ +/*ARGSUSED*/ +static void +lpassociations( + struct parse *pcmd, + FILE *fp + ) +{ + printassoc(1, fp); +} + + +#ifdef UNUSED +/* + * radiostatus - print the radio status returned by the server + */ +/*ARGSUSED*/ +static void +radiostatus( + 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( + struct parse *pcmd, + FILE *fp + ) +{ + char *datap; + int res; + int associd; + int dsize; + u_short rstatus; + + /* HMS: uval? */ + 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); +} + + +/* + * when - print how long its been since his last packet arrived + */ +static long +when( + l_fp *ts, + l_fp *rec, + l_fp *reftime + ) +{ + l_fp *lasttime; + + if (rec->l_ui != 0) + lasttime = rec; + else if (reftime->l_ui != 0) + lasttime = reftime; + else + return 0; + + return (ts->l_ui - lasttime->l_ui); +} + + +/* + * Pretty-print an interval into the given buffer, in a human-friendly format. + */ +static char * +prettyinterval( + char *buf, + long diff + ) +{ + if (diff <= 0) { + buf[0] = '-'; + buf[1] = 0; + return buf; + } + + if (diff <= 2048) { + (void) sprintf(buf, "%ld", (long int)diff); + return buf; + } + + diff = (diff + 29) / 60; + if (diff <= 300) { + (void) sprintf(buf, "%ldm", (long int)diff); + return buf; + } + + diff = (diff + 29) / 60; + if (diff <= 96) { + (void) sprintf(buf, "%ldh", (long int)diff); + return buf; + } + + diff = (diff + 11) / 24; + (void) sprintf(buf, "%ldd", (long int)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 */ + { "jitter", 0 }, /* 8 */ + { "dispersion", 0 }, /* 9 */ + { "rec", 0 }, /* 10 */ + { "reftime", 0 }, /* 11 */ + { "srcport", 0 }, /* 12 */ + { 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 */ + { "jitter", 0 }, /* 8 */ + { "dispersion", 0 }, /* 9 */ + { "rec", 0 }, /* 10 */ + { "reftime", 0 }, /* 11 */ + { "srcport", 0 }, /* 12 */ + { 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_JITTER 8 +#define HAVE_DISPERSION 9 +#define HAVE_REC 10 +#define HAVE_REFTIME 11 +#define HAVE_SRCPORT 12 +#define MAXHAVE 13 + +/* + * Decode an incoming data buffer and print a line in the peer list + */ +static int +doprintpeers( + struct varlist *pvl, + int associd, + int rstatus, + int datalen, + char *data, + FILE *fp + ) +{ + char *name; + char *value; + int i; + int c; + + u_int32 srcadr; + u_int32 dstadr; + u_long srcport; + const char *dstadr_refid = "0.0.0.0"; + u_long stratum; + long ppoll; + long hpoll; + u_long reach; + l_fp estoffset; + l_fp estdelay; + l_fp estjitter; + l_fp estdisp; + l_fp reftime; + l_fp rec; + l_fp ts; + u_char havevar[MAXHAVE]; + u_long poll; + char type = '?'; + char refid_string[10]; + char whenbuf[8], pollbuf[8]; + + memset((char *)havevar, 0, sizeof(havevar)); + get_systime(&ts); + + while (nextvar(&datalen, &data, &name, &value)) { + u_int32 dummy; + + 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 (decodenetnum(value, &dummy)) { + dummy = ntohl(dummy); + type = ((dummy&0xf0000000)==0xe0000000) ? 'm' : + ((dummy&0x000000ff)==0x000000ff) ? 'b' : + ((dummy&0xffffffff)==0x7f000001) ? 'l' : + ((dummy&0xffffffe0)==0x00000000) ? '-' : + 'u'; + } + 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_JITTER: + if (decodetime(value, &estjitter)) + havevar[HAVE_JITTER] = 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)) + L_CLR(&reftime); + 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); + + /* + * Got everything, format the line + */ + poll = 1< NTP_OLDVERSION) + 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 %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n", + c, nntohost(srcadr), dstadr_refid, stratum, type, + prettyinterval(whenbuf, when(&ts, &rec, &reftime)), + prettyinterval(pollbuf, (int)poll), reach, + lfptoms(&estdelay, 3), lfptoms(&estoffset, 3), + havevar[HAVE_JITTER] ? lfptoms(&estjitter, 3) : + lfptoms(&estdisp, 3)); + 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_JITTER +#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( + 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( + int showall, + FILE *fp + ) +{ + register int i; + char fullname[LENHOSTNAME]; + u_int32 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 t when poll reach delay offset jitter\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( + struct parse *pcmd, + FILE *fp + ) +{ + dopeers(0, fp); +} + + +/* + * lpeers - print a peer spreadsheet including all fuzzball peers + */ +/*ARGSUSED*/ +static void +lpeers( + struct parse *pcmd, + FILE *fp + ) +{ + dopeers(1, fp); +} + + +/* + * opeers - print a peer spreadsheet + */ +static void +doopeers( + int showall, + FILE *fp + ) +{ + register int i; + + if (!dogetassoc(fp)) + return; + + (void) fprintf(fp, + " remote local st t 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( + struct parse *pcmd, + FILE *fp + ) +{ + doopeers(0, fp); +} + + +/* + * lopeers - print a peer spreadsheet including all fuzzball peers + */ +/*ARGSUSED*/ +static void +lopeers( + struct parse *pcmd, + FILE *fp + ) +{ + doopeers(1, fp); +} diff --git a/contrib/ntp/ntptrace/Makefile.am b/contrib/ntp/ntptrace/Makefile.am new file mode 100644 index 000000000000..f7106ec23678 --- /dev/null +++ b/contrib/ntp/ntptrace/Makefile.am @@ -0,0 +1,19 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +bin_PROGRAMS = ntptrace +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o ../libntp/libntp.a +DISTCLEANFILES = .version version.c +noinst_HEADERS = ntptrace.h +#EXTRA_DIST = ntptrace.mak README TAGS save +ETAGS_ARGS = Makefile.am + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +version.o: $(ntptrace_OBJECTS) ../libntp/libntp.a Makefile + $(top_builddir)/scripts/mkver ntptrace + $(COMPILE) -c version.c diff --git a/contrib/ntp/ntptrace/Makefile.in b/contrib/ntp/ntptrace/Makefile.in new file mode 100644 index 000000000000..70d151c7acc7 --- /dev/null +++ b/contrib/ntp/ntptrace/Makefile.in @@ -0,0 +1,349 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ../util/ansi2knr +bin_PROGRAMS = ntptrace +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o ../libntp/libntp.a +DISTCLEANFILES = .version version.c +noinst_HEADERS = ntptrace.h +#EXTRA_DIST = ntptrace.mak README TAGS save +ETAGS_ARGS = Makefile.am +subdir = ntptrace +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +ANSI2KNR = ../util/ansi2knr +ntptrace_SOURCES = ntptrace.c +ntptrace_OBJECTS = ntptrace$U.o +ntptrace_LDADD = $(LDADD) +ntptrace_DEPENDENCIES = version.o ../libntp/libntp.a +ntptrace_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = ntptrace.c +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +SOURCES = ntptrace.c +OBJECTS = ntptrace$U.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps ntptrace/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: +../util/ansi2knr: ../util/ansi2knr.o + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr + +../util/ansi2knr.o: + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o + + +mostlyclean-kr: + -rm -f *_.c + +clean-kr: + +distclean-kr: + +maintainer-clean-kr: +ntptrace$U.o: + +ntptrace: $(ntptrace_OBJECTS) $(ntptrace_DEPENDENCIES) + @rm -f ntptrace + $(LINK) $(ntptrace_LDFLAGS) $(ntptrace_OBJECTS) $(ntptrace_LDADD) $(LIBS) +ntptrace_.c: ntptrace.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntptrace.c; then echo $(srcdir)/ntptrace.c; else echo ntptrace.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntptrace_.c +ntptrace_.o : $(ANSI2KNR) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +ntptrace.o: ntptrace.c ../include/ntp_fp.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../config.h ../include/ntp_proto.h \ + ../include/ntp.h ../include/ntp_io.h ../include/ntp_unixtime.h \ + ntptrace.h ../include/ntp_string.h ../include/ntp_syslog.h \ + ../include/ntp_select.h ../include/ntp_stdlib.h \ + ../include/l_stdlib.h ../include/recvbuff.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-kr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-compile clean-kr clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-compile distclean-kr \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-kr \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-kr distclean-kr clean-kr \ +maintainer-clean-kr tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +version.o: $(ntptrace_OBJECTS) ../libntp/libntp.a Makefile + $(top_builddir)/scripts/mkver ntptrace + $(COMPILE) -c version.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/ntptrace/README b/contrib/ntp/ntptrace/README new file mode 100644 index 000000000000..523f840fe181 --- /dev/null +++ b/contrib/ntp/ntptrace/README @@ -0,0 +1,7 @@ +README file for directory ./ntptrace of the NTP Version 4 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/ntp/ntptrace/ntptrace.c b/contrib/ntp/ntptrace/ntptrace.c new file mode 100644 index 000000000000..d7a4140c05a6 --- /dev/null +++ b/contrib/ntp/ntptrace/ntptrace.c @@ -0,0 +1,784 @@ +/* + * ntptrace - show the chain from an NTP host leading back to + * its source of time + * + * Jeffrey Mogul DECWRL 13 January 1993 + * + * Inspired by a script written by Glenn Trewitt + * + * Large portions stolen from ntpdate.c + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(SYS_HPUX) +#include +#endif + +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntptrace.h" +#include "ntp_string.h" +#include "ntp_syslog.h" +#include "ntp_select.h" +#include "ntp_stdlib.h" +#include "recvbuff.h" +/* + * only 16 stratums, so this is more than enough. + */ +int maxhosts = 20; + +/* + * Debugging flag + */ +volatile int debug = 0; + +#ifndef SYS_VXWORKS +int nonames = 0; /* if set, don't print hostnames */ +#else +int nonames = 1; /* if set, don't print hostnames */ +#endif +/* + * Program name. + */ +char *progname; + +/* + * Systemwide parameters and flags + */ +int sys_retries = 5; /* # of retry attempts per server */ +int 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 */ + + +/* + * File descriptor masks etc. for call to select + */ +int fd; +fd_set fdmask; + +/* + * Miscellaneous flags + */ +int verbose = 0; +int always_step = 0; + +int ntptracemain P((int, char **)); +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((const char *)); +static void setup_io P((void)); +static void sendpkt P((struct sockaddr_in *, struct pkt *, int)); +static int getipaddr P((const char *, u_int32 *)); +static int decodeipaddr P((const char *, u_int32 *)); +static void printserver P((struct server *, FILE *)); +static void printrefid P((FILE *, struct server *)); + +#ifdef SYS_WINNT +int on = 1; +WORD wVersionRequested; +WSADATA wsaData; + +HANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */ +void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */ +#endif /* SYS_WINNT */ + +void +input_handler(l_fp * x) +{ ; +} + +#ifdef NO_MAIN_ALLOWED +CALL(ntptrace,"ntptrace",ntptracemain); +#endif + +/* + * Main program. Initialize us and loop waiting for I/O and/or + * timer expiries. + */ +#ifndef NO_MAIN_ALLOWED +int +main( + int argc, + char *argv[] + ) +{ + return ntptracemain(argc, argv); +} +#endif + +int +ntptracemain( + int argc, + char *argv[] + ) +{ + struct server *firstserver; + int errflg; + int c; + + errflg = 0; + progname = argv[0]; + + /* + * Decode argument list + */ + while ((c = ntp_getopt(argc, argv, "dm:no:r:t:v")) != EOF) + switch (c) { + case 'd': + ++debug; + break; + case 'm': + maxhosts = atoi(ntp_optarg); + 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 [-dnv] [-m maxhosts] [-o version#] [-r retries] [-t timeout] [server]\n", + progname); + exit(2); + } + +#ifdef SYS_WINNT + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) { + msyslog(LOG_ERR, "No useable winsock.dll: %m"); + exit(1); + } +#endif /* SYS_WINNT */ + + sys_servers = (struct server **) + emalloc(sys_maxservers * sizeof(struct server *)); + + if (debug) { +#ifdef HAVE_SETVBUF + static char buf[BUFSIZ]; + setvbuf(stdout, buf, _IOLBF, BUFSIZ); +#else + setlinebuf(stdout); +#endif + } + + if (debug || verbose) + msyslog(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); + +#ifdef SYS_WINNT + WSACleanup(); +#endif + return(0); +} /* main end */ + + +static void +DoTrace( + 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( + 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); + L_CLR(&xpkt.reftime); + L_CLR(&xpkt.org); + L_CLR(&xpkt.rec); + + /* + * 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( + 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) { + msyslog(LOG_ERR, "select() error: %m"); + return(0); + } + get_systime(&ts); + + if (free_recvbuffs() == 0) { + msyslog(LOG_ERR, "no buffers"); + exit(1); + } + + rb = get_free_recv_buffer(); + + fromlen = sizeof(struct sockaddr_in); + rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt, + sizeof(rb->recv_pkt), 0, + (struct sockaddr *)&rb->recv_srcadr, &fromlen); + if (rb->recv_length == -1) { + freerecvbuf(rb); + continue; + } + + /* + * Got one. Mark how and when it got here, + * put it on the full list. + */ + rb->recv_time = ts; + add_full_recv_buffer(rb); + + 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( + struct server *server, + struct recvbuf *rbufp + ) +{ + register struct pkt *rpkt; + register s_fp di; + l_fp t10, t23; + 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->recv_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->recv_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 (L_ISZERO(&rec) || !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 = server->org; /* pkt.xmt == t1 */ + L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/ + + t23 = rec; /* pkt.rec == t2 */ + L_SUB(&t23, &org); /* pkt->org == t3 */ + + /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */ + ci = t10; + L_ADD(&ci, &t23); + L_RSHIFT(&ci); + + /* + * Calculate di in t23 in full precision, then truncate + * to an s_fp. + */ + L_SUB(&t23, &t10); + di = LFPTOFP(&t23); + + server->offset = ci; + server->delay = di; + + printserver(server, stdout); + + /* + * End of recursion if we reach stratum 1 or a local refclock + */ + if ((server->stratum <= 1) || (--maxhosts <= 0) || ((server->refid & 0xff) == 127)) + return(1); + + nextia.s_addr = server->refid; + nextserver = addserver(&nextia); + if (nextserver) + 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( + struct in_addr *iap + ) +{ + register struct server *server; + static int toomany = 0; + + if (sys_numservers >= sys_maxservers) { + if (!toomany) { + toomany = 1; + msyslog(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( + const char *serv + ) +{ + u_int32 ipaddr; + struct in_addr ia; + + if (!getipaddr(serv, &ipaddr)) { + msyslog(LOG_ERR, "can't find host %s\n", serv); + return(NULL); + } + + ia.s_addr = ipaddr; + return(addserver(&ia)); +} + + +static void +setup_io(void) +{ + /* + * Init buffer free list and stat counters + */ + init_recvbuff(sys_maxservers + 2); + + /* create a datagram (UDP) socket */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) +#ifndef SYS_WINNT + < 0 +#else + == INVALID_SOCKET +#endif + ) { + msyslog(LOG_ERR, "socket() failed: %m"); + exit(1); + /*NOTREACHED*/ + } + + FD_ZERO(&fdmask); + FD_SET(fd, &fdmask); +} + + + +/* 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( + 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) { +#ifndef SYS_WINNT + if (errno != EWOULDBLOCK && errno != ENOBUFS) +#else /* SYS_WINNT */ + int iSockErr = WSAGetLastError(); + if (iSockErr != WSAEWOULDBLOCK && iSockErr != WSAENOBUFS) +#endif /* SYS_WINNT */ + msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + } +} + +/* + * getipaddr - given a host name, return its host address + */ +static int +getipaddr( + const char *host, + u_int32 *num + ) +{ + struct hostent *hp; + + if (decodeipaddr(host, num)) { + return 1; + } else if ((hp = gethostbyname(host)) != 0) { + memmove((char *)num, hp->h_addr, sizeof(long)); + return 1; + } + return 0; +} + +/* + * decodeipaddr - return a host address (this is crude, but careful) + */ +static int +decodeipaddr( + const char *num, + u_int32 *ipaddr + ) +{ + register const 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((int)*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( + 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, 6), ufptoa(synchdist, 5)); + 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, 5), + ufptoa(pp->dispersion, 5)); + (void) fprintf(fp, "offset %s\n", lfptoa(&pp->offset, 6)); + (void) fprintf(fp, "rootdelay %s, rootdispersion %s", + ufptoa(pp->rootdelay, 5), ufptoa(pp->rootdispersion, 5)); + (void) fprintf(fp, ", synch dist %s\n", ufptoa(synchdist, 5)); + + (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( + 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(HAVE_VSPRINTF) +int +vsprintf( + 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/ntp/ntptrace/ntptrace.h b/contrib/ntp/ntptrace/ntptrace.h new file mode 100644 index 000000000000..53cbe0107649 --- /dev/null +++ b/contrib/ntp/ntptrace/ntptrace.h @@ -0,0 +1,36 @@ +/* + * 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_int32 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 */ + s_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/ntp/parseutil/Makefile.am b/contrib/ntp/parseutil/Makefile.am new file mode 100644 index 000000000000..902eb5cd4859 --- /dev/null +++ b/contrib/ntp/parseutil/Makefile.am @@ -0,0 +1,10 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +noinst_PROGRAMS = @TESTDCF@ @DCFD@ +EXTRA_PROGRAMS = testdcf dcfd +INCLUDES = -I$(top_srcdir)/include +ETAGS_ARGS = Makefile.am +#EXTRA_DIST= TAGS + +check-local: dcfd + ./dcfd -Y diff --git a/contrib/ntp/parseutil/Makefile.in b/contrib/ntp/parseutil/Makefile.in new file mode 100644 index 000000000000..50cbc7ddbe17 --- /dev/null +++ b/contrib/ntp/parseutil/Makefile.in @@ -0,0 +1,334 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ../util/ansi2knr +noinst_PROGRAMS = @TESTDCF@ @DCFD@ +EXTRA_PROGRAMS = testdcf dcfd +INCLUDES = -I$(top_srcdir)/include +ETAGS_ARGS = Makefile.am +subdir = parseutil +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +ANSI2KNR = ../util/ansi2knr +dcfd_SOURCES = dcfd.c +dcfd_OBJECTS = dcfd$U.o +dcfd_LDADD = $(LDADD) +dcfd_DEPENDENCIES = +dcfd_LDFLAGS = +testdcf_SOURCES = testdcf.c +testdcf_OBJECTS = testdcf$U.o +testdcf_LDADD = $(LDADD) +testdcf_DEPENDENCIES = +testdcf_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = dcfd.c testdcf.c +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +SOURCES = dcfd.c testdcf.c +OBJECTS = dcfd$U.o testdcf$U.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps parseutil/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: +../util/ansi2knr: ../util/ansi2knr.o + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr + +../util/ansi2knr.o: + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr.o + + +mostlyclean-kr: + -rm -f *_.c + +clean-kr: + +distclean-kr: + +maintainer-clean-kr: +dcfd$U.o: + +dcfd: $(dcfd_OBJECTS) $(dcfd_DEPENDENCIES) + @rm -f dcfd + $(LINK) $(dcfd_LDFLAGS) $(dcfd_OBJECTS) $(dcfd_LDADD) $(LIBS) +testdcf$U.o: + +testdcf: $(testdcf_OBJECTS) $(testdcf_DEPENDENCIES) + @rm -f testdcf + $(LINK) $(testdcf_LDFLAGS) $(testdcf_OBJECTS) $(testdcf_LDADD) $(LIBS) +dcfd_.c: dcfd.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/dcfd.c; then echo $(srcdir)/dcfd.c; else echo dcfd.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > dcfd_.c +testdcf_.c: testdcf.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/testdcf.c; then echo $(srcdir)/testdcf.c; else echo testdcf.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > testdcf_.c +dcfd_.o testdcf_.o : $(ANSI2KNR) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +dcfd.o dcfd.lo: dcfd.c ../config.h ../include/ntp_stdlib.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp_string.h \ + ../include/l_stdlib.h ../include/ntpd.h ../include/ntp_syslog.h \ + ../include/ntp_fp.h ../include/ntp.h ../include/ntp_malloc.h \ + ../include/ntp_refclock.h ../include/recvbuff.h +testdcf.o testdcf.lo: testdcf.c ../include/ntp_stdlib.h \ + ../include/ntp_types.h ../include/ntp_machine.h ../config.h \ + ../include/ntp_proto.h ../include/ntp_string.h \ + ../include/l_stdlib.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-kr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstPROGRAMS clean-compile clean-kr clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-kr \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-kr \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-kr distclean-kr clean-kr \ +maintainer-clean-kr tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir info-am info dvi-am dvi check-local check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + +#EXTRA_DIST= TAGS + +check-local: dcfd + ./dcfd -Y + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/parseutil/README b/contrib/ntp/parseutil/README new file mode 100644 index 000000000000..8bc5140e687b --- /dev/null +++ b/contrib/ntp/parseutil/README @@ -0,0 +1,16 @@ +This directory contains some DCF77 related programs. +They have not yet fully been ported to architectures other than 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 + Works only under SunOS with parse Streams Module loaded + and Meinberg-Clocks + +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/ntp/parseutil/dcfd.c b/contrib/ntp/parseutil/dcfd.c new file mode 100644 index 000000000000..7d223de3cbbd --- /dev/null +++ b/contrib/ntp/parseutil/dcfd.c @@ -0,0 +1,1850 @@ +/* + * /src/NTP/ntp-4/parseutil/dcfd.c,v 4.9 1999/02/28 13:06:27 kardel RELEASE_19990228_A + * + * dcfd.c,v 4.9 1999/02/28 13:06:27 kardel RELEASE_19990228_A + * + * DCF77 100/200ms pulse synchronisation daemon program (via 50Baud serial line) + * + * Features: + * DCF77 decoding + * simple NTP loopfilter logic for local clock + * interactive display for debugging + * + * Lacks: + * Leap second handling (at that level you should switch to NTP Version 4 - really!) + * + * Copyright (C) 1995-1999 by Frank Kardel + * Copyright (C) 1993-1994 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * NTP compilation environment + */ +#include "ntp_stdlib.h" +#include "ntpd.h" /* indirectly include ntp.h to get YEAR_PIVOT Y2KFixes */ + +/* + * select which terminal handling to use (currently only SysV variants) + */ +#if defined(HAVE_TERMIOS_H) || defined(STREAM) +#include +#define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) +#define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) +#else /* not HAVE_TERMIOS_H || STREAM */ +# if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS) +# include +# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) +# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) +# endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */ +#endif /* not HAVE_TERMIOS_H || STREAM */ + + +#ifndef TTY_GETATTR +#include "Bletch: MUST DEFINE ONE OF 'HAVE_TERMIOS_H' or 'HAVE_TERMIO_H'" +#endif + +#ifndef days_per_year +#define days_per_year(_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 = 999999 - (-(_a_)->tv_usec - 1); \ + } + +#ifdef timeradd +#undef timeradd +#endif +#define timeradd(_a_, _b_) \ + (_a_)->tv_sec += (_b_)->tv_sec; \ + (_a_)->tv_usec += (_b_)->tv_usec; \ + timernormalize((_a_)) + +#ifdef timersub +#undef timersub +#endif +#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_) LPRINTF _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 accum_drift = 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 l_abs() function + */ +#define l_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 fields 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( + 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( + 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( + unsigned char *buffer, + int size, + clocktime_t *clock_time + ) +{ + 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_time->flags = 0; + clock_time->usecond= 0; + clock_time->second = 0; + clock_time->minute = ext_bf(buffer, DCF_M10); + clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1); + clock_time->hour = ext_bf(buffer, DCF_H10); + clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1); + clock_time->day = ext_bf(buffer, DCF_D10); + clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1); + clock_time->month = ext_bf(buffer, DCF_MO0); + clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO); + clock_time->year = ext_bf(buffer, DCF_Y10); + clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1); + clock_time->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_time->utcoffset = -60; + break; + + case DCF_Z_MED: + clock_time->flags |= DCFB_DST; + clock_time->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_time->flags |= DCFB_ANNOUNCE; + + if (ext_bf(buffer, DCF_A2)) + clock_time->flags |= DCFB_LEAP; + + if (ext_bf(buffer, DCF_R)) + clock_time->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( + unsigned char *buffer, + int size, + clocktime_t *clock_time + ) +{ + 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 = (unsigned char)~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((" ")); + + /* + * 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 + */ + if (rtc != CVT_NONE) + { + PRINTF("%-30s", "*** BAD DATA"); + } + + return (rtc == CVT_NONE) ? convert_rawdcf(buffer, size, clock_time) : rtc; +} + +/*----------------------------------------------------------------------- + * convert a wall clock time description of DCF77 to a Unix time (seconds + * since 1.1. 1970 UTC) + */ +time_t +dcf_to_unixtime( + clocktime_t *clock_time, + unsigned *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_time->year < YEAR_PIVOT ) /* in case of Y2KFixes [ */ + clock_time->year += 100; /* *year%100, make tm_year */ + /* *(do we need this?) */ + if ( clock_time->year < YEAR_BREAK ) /* (failsafe if) */ + clock_time->year += 1900; /* Y2KFixes ] */ + + /* + * must have been a really bad year code - drop it + */ + if (clock_time->year < (YEAR_PIVOT + 1900) ) /* Y2KFixes */ + { + 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 = julian0( clock_time->year ) - julian0( 1970 ); + + /* month */ + if (clock_time->month <= 0 || clock_time->month > 12) + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; /* bad month */ + } + /* adjust current leap year */ +#if 0 + if (clock_time->month < 3 && days_per_year(clock_time->year) == 366) + t--; +#endif + + /* + * collect days from months excluding the current one + */ + for (i = 1; i < clock_time->month; i++) + { + t += days_of_month[i]; + } + /* day */ + if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ? + clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month])) + { + SETRTC(CVT_FAIL|CVT_BADDATE); + return -1; /* bad day */ + } + + /* + * collect days from date excluding the current one + */ + t += clock_time->day - 1; + + /* hour */ + if (clock_time->hour < 0 || clock_time->hour >= 24) + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad hour */ + } + + /* + * calculate hours from 1. 1. 1970 + */ + t = TIMES24(t) + clock_time->hour; + + /* min */ + if (clock_time->minute < 0 || clock_time->minute > 59) + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad min */ + } + + /* + * calculate minutes from 1. 1. 1970 + */ + t = TIMES60(t) + clock_time->minute; + /* sec */ + + /* + * calculate UTC in minutes + */ + t += clock_time->utcoffset; + + if (clock_time->second < 0 || clock_time->second > 60) /* allow for LEAPs */ + { + SETRTC(CVT_FAIL|CVT_BADTIME); + return -1; /* bad sec */ + } + + /* + * calculate UTC in seconds - phew ! + */ + t = TIMES60(t) + clock_time->second; + /* done */ + return t; +} + +/*----------------------------------------------------------------------- + * cheap half baked 1/0 decision - for interactive operation only + */ +static char +type( + unsigned int c + ) +{ + c ^= 0xFF; + return (c > 0xF); +} + +/*----------------------------------------------------------------------- + * week day representation + */ +static const char *wday[8] = +{ + "??", + "Mo", + "Tu", + "We", + "Th", + "Fr", + "Sa", + "Su" +}; + +/*----------------------------------------------------------------------- + * generate a string representation for a timeval + */ +static char * +pr_timeval( + struct timeval *val + ) +{ + static char buf[20]; + + if (val->tv_sec == 0) + sprintf(buf, "%c0.%06ld", (val->tv_usec < 0) ? '-' : '+', (long int)l_abs(val->tv_usec)); + else + sprintf(buf, "%ld.%06ld", (long int)val->tv_sec, (long int)l_abs(val->tv_usec)); + return buf; +} + +/*----------------------------------------------------------------------- + * correct the current time by an offset by setting the time rigorously + */ +static void +set_time( + 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( + 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: %ld us ", (long int)offset); + if (adjtime(&time_offset, 0L) == -1) + perror("adjtime()"); +} + +/*----------------------------------------------------------------------- + * read in a possibly previously written drift value + */ +static void +read_drift( + const char *drift_file + ) +{ + FILE *df; + + df = fopen(drift_file, "r"); + if (df != NULL) + { + int idrift = 0, fdrift = 0; + + fscanf(df, "%4d.%03d", &idrift, &fdrift); + fclose(df); + LPRINTF("read_drift: %d.%03d ppm ", idrift, fdrift); + + accum_drift = idrift << USECSCALE; + fdrift = (fdrift << USECSCALE) / 1000; + accum_drift += fdrift & (1<)) + { + /* + * hopeless - set the clock - and clear the timing + */ + set_time(offset); + clock_adjust = 0; + skip_adjust = 1; + return; + } + + usecoffset = offset->tv_sec * 1000000 + offset->tv_usec; + + clock_adjust = R_SHIFT(usecoffset, TIMECONSTANT); /* adjustment to make for next period */ + + tmp = 0; + while (adjustments > (1 << tmp)) + tmp++; + adjustments = 0; + if (tmp > FREQ_WEIGHT) + tmp = FREQ_WEIGHT; + + accum_drift += R_SHIFT(usecoffset << USECSCALE, TIMECONSTANT+TIMECONSTANT+FREQ_WEIGHT-tmp); + + if (accum_drift > MAX_DRIFT) /* clamp into interval */ + accum_drift = MAX_DRIFT; + else + if (accum_drift < -MAX_DRIFT) + accum_drift = -MAX_DRIFT; + + update_drift(drift_file, usecoffset, reftime); + LPRINTF("clock_adjust: %s, clock_adjust %ld, drift_comp %ld(%ld) ", + pr_timeval(offset),(long int) R_SHIFT(clock_adjust, USECSCALE), + (long int)R_SHIFT(accum_drift, USECSCALE), (long int)accum_drift); +} + +/*----------------------------------------------------------------------- + * adjust the clock by a small mount to simulate frequency correction + */ +static void +periodic_adjust( + void + ) +{ + register long adjustment; + + adjustments++; + + adjustment = R_SHIFT(clock_adjust, PHASE_WEIGHT); + + clock_adjust -= adjustment; + + adjustment += R_SHIFT(accum_drift, USECSCALE+ADJINTERVAL); + + adj_time(adjustment); +} + +/*----------------------------------------------------------------------- + * control synchronisation status (warnings) and do periodic adjusts + * (frequency control simulation) + */ +static void +tick( + void + ) +{ + static unsigned long last_notice = 0; + +#if !defined(HAVE_SIGACTION) && !defined(HAVE_SIGVEC) + (void)signal(SIGALRM, tick); +#endif + + periodic_adjust(); + + ticks += 1< 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< daemon operation) + */ +static void +detach( + void + ) +{ +# ifdef HAVE_DAEMON + daemon(0, 0); +# else /* not HAVE_DAEMON */ + if (fork()) + exit(0); + + { + u_long s; + int max_fd; + +#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) + max_fd = sysconf(_SC_OPEN_MAX); +#else /* HAVE_SYSCONF && _SC_OPEN_MAX */ + max_fd = getdtablesize(); +#endif /* HAVE_SYSCONF && _SC_OPEN_MAX */ + for (s = 0; s < max_fd; s++) + (void) close((int)s); + (void) open("/", 0); + (void) dup2(0, 1); + (void) dup2(0, 2); +#ifdef SYS_DOMAINOS + { + uid_$t puid; + status_$t st; + + proc2_$who_am_i(&puid); + proc2_$make_server(&puid, &st); + } +#endif /* SYS_DOMAINOS */ +#if defined(HAVE_SETPGID) || defined(HAVE_SETSID) +# ifdef HAVE_SETSID + if (setsid() == (pid_t)-1) + syslog(LOG_ERR, "dcfd: setsid(): %m"); +# else + if (setpgid(0, 0) == -1) + syslog(LOG_ERR, "dcfd: setpgid(): %m"); +# endif +#else /* HAVE_SETPGID || HAVE_SETSID */ + { + int fid; + + fid = open("/dev/tty", 2); + if (fid >= 0) + { + (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0); + (void) close(fid); + } +# ifdef HAVE_SETPGRP_0 + (void) setpgrp(); +# else /* HAVE_SETPGRP_0 */ + (void) setpgrp(0, getpid()); +# endif /* HAVE_SETPGRP_0 */ + } +#endif /* HAVE_SETPGID || HAVE_SETSID */ + } +#endif /* not HAVE_DAEMON */ +} + +/*----------------------------------------------------------------------- + * list possible arguments and options + */ +static void +usage( + char *program + ) +{ + fprintf(stderr, "usage: %s [-n] [-f] [-l] [-t] [-i] [-o] [-d ] [-D ] \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-Y make internal Y2K checks then exit\n"); /* Y2KFixes */ + fprintf(stderr, "\t-d specify alternate drift file\n"); + fprintf(stderr, "\t-D specify delay from input edge to processing in micro seconds\n"); +} + +/*----------------------------------------------------------------------- + * check_y2k() - internal check of Y2K logic + * (a lot of this logic lifted from ../ntpd/check_y2k.c) + */ +int +check_y2k( void ) +{ + int year; /* current working year */ + int year0 = 1900; /* sarting year for NTP time */ + int yearend; /* ending year we test for NTP time. + * 32-bit systems: through 2036, the + **year in which NTP time overflows. + * 64-bit systems: a reasonable upper + **limit (well, maybe somewhat beyond + **reasonable, but well before the + **max time, by which time the earth + **will be dead.) */ + time_t Time; + struct tm LocalTime; + + int Fatals, Warnings; +#define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \ + Warnings++; else Fatals++ + + Fatals = Warnings = 0; + + Time = time( (time_t *)NULL ); + LocalTime = *localtime( &Time ); + + year = ( sizeof( u_long ) > 4 ) /* save max span using year as temp */ + ? ( 400 * 3 ) /* three greater gregorian cycles */ + : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/ + /* NOTE: will automacially expand test years on + * 64 bit machines.... this may cause some of the + * existing ntp logic to fail for years beyond + * 2036 (the current 32-bit limit). If all checks + * fail ONLY beyond year 2036 you may ignore such + * errors, at least for a decade or so. */ + yearend = year0 + year; + + year = 1900+YEAR_PIVOT; + printf( " starting year %04d\n", (int) year ); + printf( " ending year %04d\n", (int) yearend ); + + for ( ; year < yearend; year++ ) + { + clocktime_t ct; + time_t Observed; + time_t Expected; + unsigned Flag; + unsigned long t; + + ct.day = 1; + ct.month = 1; + ct.year = year; + ct.hour = ct.minute = ct.second = ct.usecond = 0; + ct.utcoffset = 0; + ct.flags = 0; + + Flag = 0; + Observed = dcf_to_unixtime( &ct, &Flag ); + /* seems to be a clone of parse_to_unixtime() with + * *a minor difference to arg2 type */ + if ( ct.year != year ) + { + fprintf( stdout, + "%04d: dcf_to_unixtime(,%d) CORRUPTED ct.year: was %d\n", + (int)year, (int)Flag, (int)ct.year ); + Error(year); + break; + } + t = julian0(year) - julian0(1970); /* Julian day from 1970 */ + Expected = t * 24 * 60 * 60; + if ( Observed != Expected || Flag ) + { /* time difference */ + fprintf( stdout, + "%04d: dcf_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", + year, (int)Flag, + (unsigned long)Observed, (unsigned long)Expected, + ((long)Observed - (long)Expected) ); + Error(year); + break; + } + + if ( year >= YEAR_PIVOT+1900 ) + { + /* check year % 100 code we put into dcf_to_unixtime() */ + ct.year = year % 100; + Flag = 0; + + Observed = dcf_to_unixtime( &ct, &Flag ); + + if ( Observed != Expected || Flag ) + { /* time difference */ + fprintf( stdout, +"%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", + year, (int)ct.year, (int)Flag, + (unsigned long)Observed, (unsigned long)Expected, + ((long)Observed - (long)Expected) ); + Error(year); + break; + } + + /* check year - 1900 code we put into dcf_to_unixtime() */ + ct.year = year - 1900; + Flag = 0; + + Observed = dcf_to_unixtime( &ct, &Flag ); + + if ( Observed != Expected || Flag ) { /* time difference */ + fprintf( stdout, + "%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", + year, (int)ct.year, (int)Flag, + (unsigned long)Observed, (unsigned long)Expected, + ((long)Observed - (long)Expected) ); + Error(year); + break; + } + + + } + } + + return ( Fatals ); +} + +/*-------------------------------------------------- + * rawdcf_init - set up modem lines for RAWDCF receivers + */ +#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) +static void +rawdcf_init( + int fd + ) +{ + /* + * You can use the RS232 to supply the power for a DCF77 receiver. + * Here a voltage between the DTR and the RTS line is used. Unfortunately + * the name has changed from CIOCM_DTR to TIOCM_DTR recently. + */ + +#ifdef TIOCM_DTR + int sl232 = TIOCM_DTR; /* turn on DTR for power supply */ +#else + int sl232 = CIOCM_DTR; /* turn on DTR for power supply */ +#endif + + if (ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1) + { + syslog(LOG_NOTICE, "rawdcf_init: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m"); + } +} +#else +static void +rawdcf_init( + int fd + ) +{ + syslog(LOG_NOTICE, "rawdcf_init: WARNING: OS interface incapable of setting DTR to power DCF modules"); +} +#endif /* DTR initialisation type */ + +/*----------------------------------------------------------------------- + * main loop - argument interpreter / setup / main loop + */ +int +main( + int argc, + char **argv + ) +{ + unsigned char c; + char **a = argv; + int ac = argc; + char *file = NULL; + const 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; + + case 'Y': + errs=check_y2k(); + exit( errs ? 1 : 0 ); + + 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_time; /* wall clock time */ + time_t utc_time = 0; + time_t last_utc_time = 0; + long usecerror = 0; + long lasterror = 0; +#if defined(HAVE_TERMIOS_H) || defined(STREAM) + struct termios term; +#else /* not HAVE_TERMIOS_H || STREAM */ +# if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS) + struct termio term; +# endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */ +#endif /* not HAVE_TERMIOS_H || STREAM */ + unsigned int rtc = CVT_NONE; + + rawdcf_init(fd); + + 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; +#ifdef NO_PARENB_IGNPAR + term.c_cflag = B50|CS8|CREAD|CLOCAL; +#else + term.c_cflag = B50|CS8|CREAD|CLOCAL|PARENB; +#endif + term.c_iflag = IGNPAR; + 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 HAVE_SIGVEC + { + 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 +#ifdef HAVE_SIGACTION + { + struct sigaction act; + + act.sa_handler = tick; +# ifdef HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION + act.sa_sigaction = (void (*) P((int, siginfo_t *, void *)))0; +# endif /* HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + if (sigaction(SIGALRM, &act, (struct sigaction *)0) == -1) + { + syslog(LOG_ERR, "sigaction(SIGALRM): %m"); + exit(1); + } + } +#else + (void) signal(SIGALRM, tick); +#endif +#endif + +#ifdef ITIMER_REAL + { + struct itimerval it; + + it.it_interval.tv_sec = 1< LINES) + { + PRINTF(" %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]); + PRINTF(" %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]); + errs = 0; + } + + /* + * 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((unsigned char *)buf, i, &clock_time)) != 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++; + } + else + if (trace) + { + PRINTF("\r %.*s ", 59 - offset, &buf[offset]); + } + + + 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_time, &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 (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_time.wday], + clock_time.hour, clock_time.minute, i, clock_time.day, clock_time.month, + clock_time.year, + (clock_time.flags & DCFB_ALTERNATE) ? "R" : "_", + (clock_time.flags & DCFB_ANNOUNCE) ? "A" : "_", + (clock_time.flags & DCFB_DST) ? "D" : "_", + (clock_time.flags & DCFB_LEAP) ? "L" : "_", + (lasterror < 0) ? '-' : '+', l_abs(lasterror) / 1000000, l_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/ntp/parseutil/testdcf.c b/contrib/ntp/parseutil/testdcf.c new file mode 100644 index 000000000000..754ff631fbdf --- /dev/null +++ b/contrib/ntp/parseutil/testdcf.c @@ -0,0 +1,495 @@ +/* + * /src/NTP/REPOSITORY/v4/parseutil/testdcf.c,v 3.18 1996/12/01 16:05:04 kardel Exp + * + * testdcf.c,v 3.18 1996/12/01 16:05:04 kardel Exp + * + * simple DCF77 100/200ms pulse test program (via 50Baud serial line) + * + * Copyright (c) 1993,1994,1995,1996, 1998 by Frank Kardel + * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * This program may not be sold or used for profit without prior + * written consent of the author. + */ + +#include +#include +#include +#include +#include +#include + +#include "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( + 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] != '-'); + } + return sum; +} + +static unsigned +pcheck( + 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] != '-'); + + return psum; +} + +static unsigned long +convert_rawdcf( + register unsigned char *buffer, + register int size, + register clocktime_t *clock_time + ) +{ + 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_time->flags = 0; + clock_time->usecond= 0; + clock_time->second = 0; + clock_time->minute = ext_bf(buffer, DCF_M10); + clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1); + clock_time->hour = ext_bf(buffer, DCF_H10); + clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1); + clock_time->day = ext_bf(buffer, DCF_D10); + clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1); + clock_time->month = ext_bf(buffer, DCF_MO0); + clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO); + clock_time->year = ext_bf(buffer, DCF_Y10); + clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1); + clock_time->wday = ext_bf(buffer, DCF_DW); + + switch (ext_bf(buffer, DCF_Z)) + { + case DCF_Z_MET: + clock_time->utcoffset = -60; + break; + + case DCF_Z_MED: + clock_time->flags |= DCFB_DST; + clock_time->utcoffset = -120; + break; + + default: + printf("%-30s", "*** BAD TIME ZONE"); + return CVT_FAIL|CVT_BADFMT; + } + + if (ext_bf(buffer, DCF_A1)) + clock_time->flags |= DCFB_ANNOUNCE; + + if (ext_bf(buffer, DCF_A2)) + clock_time->flags |= DCFB_LEAP; + + if (ext_bf(buffer, DCF_R)) + clock_time->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( + unsigned int c + ) +{ + c ^= 0xFF; + return (c > 0xF); +} + +static const 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( + int argc, + char *argv[] + ) +{ + if ((argc != 2) && (argc != 3)) + { + fprintf(stderr, "usage: %s [-f|-t|-ft|-tf] \n", argv[0]); + exit(1); + } + else + { + unsigned char c; + char *file; + int fd; + int offset = 15; + int trace = 0; + int errs = LINES+1; + + /* + * SIMPLE(!) argument "parser" + */ + if (argc == 3) + { + if (strcmp(argv[1], "-f") == 0) + offset = 0; + if (strcmp(argv[1], "-t") == 0) + trace = 1; + if ((strcmp(argv[1], "-ft") == 0) || + (strcmp(argv[1], "-tf") == 0)) + { + offset = 0; + trace = 1; + } + file = argv[2]; + } + else + { + file = argv[1]; + } + + fd = open(file, O_RDONLY); + if (fd == -1) + { + perror(file); + exit(1); + } + else + { + int i; +#ifdef TIOCM_RTS + int on = TIOCM_RTS; +#endif + struct timeval t, tt, tlast; + char buf[61]; + clocktime_t clock_time; + 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; +#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined (SYS_IRIX5) */ + /* somehow doesn't grok PARENB & IGNPAR (mj) */ + term.c_cflag = B50|CS8|CREAD|CLOCAL; +#else + term.c_cflag = B50|CS8|CREAD|CLOCAL|PARENB; +#endif + term.c_iflag = IGNPAR; + 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 (C) 1993-1996, Frank Kardel\n\n"); + + clock_time.hour = 0; + clock_time.minute = 0; + clock_time.day = 0; + clock_time.wday = 0; + clock_time.month = 0; + clock_time.year = 0; + clock_time.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((unsigned char *)buf, i, &clock_time)) != CVT_OK) + { + printf("\n"); + clock_time.hour = 0; + clock_time.minute = 0; + clock_time.day = 0; + clock_time.wday = 0; + clock_time.month = 0; + clock_time.year = 0; + clock_time.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_time.wday], + (int)clock_time.hour, (int)clock_time.minute, (int)i, (int)clock_time.day, (int)clock_time.month, + (int)clock_time.year, + (clock_time.flags & DCFB_ALTERNATE) ? "R" : "_", + (clock_time.flags & DCFB_ANNOUNCE) ? "A" : "_", + (clock_time.flags & DCFB_DST) ? "D" : "_", + (clock_time.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/ntp/readme.y2kfixes b/contrib/ntp/readme.y2kfixes new file mode 100755 index 000000000000..e9a63c1e81c9 Binary files /dev/null and b/contrib/ntp/readme.y2kfixes differ diff --git a/contrib/ntp/results.y2kfixes b/contrib/ntp/results.y2kfixes new file mode 100644 index 000000000000..32f42cf6831e --- /dev/null +++ b/contrib/ntp/results.y2kfixes @@ -0,0 +1,76 @@ +Script started on Sat Jan 1 04:14:09 2000 +[root@timetest ntpdate]# date +Sat Jan 1 04:14:11 EST 2000 +[root@timetest ntpdate]# ./ntpdate -b timelord.att.com +14 Jul 13:44:39 ntpdate[11723]: step time server 135.16.xxxx.xxxx offset -14740193.210537 sec +[root@timetest ntpdate]# date +Wed Jul 14 13:44:42 EST 1999 +[root@timetest ntpdate]# cd ../ntptrace +[root@timetest ntptrace]# ./ntptrace timelord.att.com +timelord.att.com: stratum 2, offset -0.000879, synch distance 0.07207 +timemaster.att.com: stratum 1, offset -0.004876, synch distance 0.03485, refid 'GPS' +[root@timetest ntptrace]# cd - +[root@timetest ntpdate]# date +Mon Feb 28 01:00:04 EST 2000 +[root@timetest ntpdate]# ./ntpdate -b timelord.att.com +14 Jul 13:49:01 ntpdate[11760]: step time server 135.16.xxxx.xxxx offset -19739467.533126 sec +[root@timetest ntpdate]# date +Wed Jul 14 13:49:03 EST 1999 +[root@timetest ntpdate]# cd - +[root@timetest ntptrace]# ./ntptrace timelord.att.com +timelord.att.com: stratum 2, offset 0.001383, synch distance 0.05644 +timemaster.att.com: stratum 1, offset -0.006355, synch distance 0.04178, refid 'GPS' +[root@timetest ntptrace]# cd - +[root@timetest ntpdate]# date +Tue Feb 29 01:00:05 EST 2000 +[root@timetest ntpdate]# ./ntpdate -b timelord.att.com +14 Jul 13:57:41 ntpdate[12423]: step time server 135.16.xxxx.xxxx offset -19825349.396585 sec +[root@timetest ntpdate]# date +Wed Jul 14 13:57:43 EST 1999 +[root@timetest ntpdate]# cd - +[root@timetest ntptrace]# ./ntptrace timelord.att.com +timelord.att.com: stratum 2, offset -0.000094, synch distance 0.06522 +timemaster.att.com: stratum 1, offset -0.010803, synch distance 0.03078, refid 'GPS' +[root@timetest ntptrace]# cd - +[root@timetest ntpdate]# date +Wed Mar 1 01:00:03 EST 2000 +[root@timetest ntpdate]# ./ntpdate -b timelord.att.com +14 Jul 13:58:10 ntpdate[12525]: step time server 135.16.xxxx.xxxx offset -19911719.766061 sec +[root@timetest ntpdate]# date +Wed Jul 14 13:58:12 EST 1999 +[root@timetest ntpdate]# cd - +[root@timetest ntptrace]# ./ntptrace timelord.att.com +timelord.att.com: stratum 2, offset -0.000719, synch distance 0.06561 +timemaster.att.com: stratum 1, offset -0.013598, synch distance 0.03116, refid 'GPS' + +Script done on Wed Jul 14 13:58:28 1999 + +RESULTS OK. +--------------------END OF TEST1-------------------- + + +### freeware test configuration +server 127.127.1.0 prefer +fudge 127.127.1.0 stratum 0 +driftfile drift.log + + +ntpdate timelord.att.com +server 135.16.xxxx.xxxx stratum 1, offset 0.000033, delay 0.02975 +31 Dec 23:58:59 ntpdate[83551]: adjust time server 135.16.74.3 offset 0.039057 s +ec + +ntpdate timelord.att.com +server 135.16.xxxx.xxxx stratum 1, offset 0.000019, delay 0.02504 +01 Jan 00:01:05 ntpdate[8352]: adjust time server 135.16.74.3 offset 0.039057 s +ec + +ntpdate timelord.att.com +server 135.25.xxxx.xxxx, stratum 1, offset -0.000023, delay 0.02731 +29 Feb 00:02:15 ntpdate[8353]: adjust time server 135.25.xxxx.xxxx offset -0.000023 sec + + + + + + diff --git a/contrib/ntp/scripts/Makefile.am b/contrib/ntp/scripts/Makefile.am new file mode 100644 index 000000000000..c3bb68415958 --- /dev/null +++ b/contrib/ntp/scripts/Makefile.am @@ -0,0 +1 @@ +noinst_SCRIPTS = mkver ntpver diff --git a/contrib/ntp/scripts/Makefile.in b/contrib/ntp/scripts/Makefile.in new file mode 100644 index 000000000000..008640b5d86e --- /dev/null +++ b/contrib/ntp/scripts/Makefile.in @@ -0,0 +1,210 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + + +noinst_SCRIPTS = mkver ntpver +subdir = scripts +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = mkver ntpver +SCRIPTS = $(noinst_SCRIPTS) + +DIST_SOURCES = +DIST_COMMON = README Makefile.am Makefile.in mkver.in ntpver.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +mkver: $(top_builddir)/config.status mkver.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status +ntpver: $(top_builddir)/config.status ntpver.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu scripts/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(SCRIPTS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/scripts/README b/contrib/ntp/scripts/README new file mode 100644 index 000000000000..37442f152998 --- /dev/null +++ b/contrib/ntp/scripts/README @@ -0,0 +1,30 @@ +README file for directory ./scripts of the NTP Version 4 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. + +calc_tickadj Calculates "optimal" value for tick given ntp.drift file + +mkver.in script to create new version numbers for all sources + +monitoring directory containing perl scripts useful for monitoring + operations + +rc1 start/stop scripts for NTP + +rc2 start/stop script for NTP + +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 + +ntpver What version of the NTP daemon is running? + +stats directory containing awk and 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/ntp/scripts/calc_tickadj b/contrib/ntp/scripts/calc_tickadj new file mode 100644 index 000000000000..f7a9f9f1d799 --- /dev/null +++ b/contrib/ntp/scripts/calc_tickadj @@ -0,0 +1,38 @@ +#! /usr/local/bin/perl +# +# drift of 104.8576 -> +1 tick. Base of 10000 ticks. +# +# 970306 HMS Deal with nanoseconds. Fix sign of adjustments. + +$df="/etc/ntp.drift"; +# Assumes a 100Hz box with "tick" of 10000 +# Someday, we might call "tickadj" for better values... +$base=10000; # tick: 1,000,000 / HZ +$cvt=104.8576; # 2 ** 20 / $base +$v1=0.; +$v2=""; + +if (open(DF, $df)) + { + if ($_=) + { + ($v1, $v2) = split; + } + + while ($v1 < 0) + { + $v1 += $cvt; + $base--; + } + + while ($v1 > $cvt) + { + $v1 -= $cvt; + $base++; + } + } + +printf("%.3f (drift)\n", $v1); + +printf("%d usec; %d nsec\n", $base, ($base + ($v1/$cvt)) * 1000); + diff --git a/contrib/ntp/scripts/checktime b/contrib/ntp/scripts/checktime new file mode 100755 index 000000000000..850e2ecb1848 --- /dev/null +++ b/contrib/ntp/scripts/checktime @@ -0,0 +1,79 @@ +#!/usr/local/bin/perl +#!/usr/local/bin/perl -d +# +# This script compares the time of several machines with the +# time on the local host. +# +# Use or modify it as you wish. +# +# As the original author is only expecting 14 minutes of fame, +# leaving his name attached would be appreciated. +# +# R. Gary Cutbill +# 21 April 1999 +# +$tol=2.0; +$|=1; +print "Time Check"; + +open(HOSTS,"ypcat hosts.byaddr |"); # get a list of hosts from the yp server. + +while ($line=) { # loop for each host getting the offset compared to localhost + ($addr,$host,$aliases)=split(/\s+/,$line,3); + $res=`/usr/local/bin/ntptrace -m 1 -r 1 -t 1 $host`; + print "."; + chop $res; + push (@results,$res); +} +print "\n"; + + +# +# Sort the list of hosts, and print out there offsets +# from the local host. +# +@list=sort appropriately @results; +foreach $i ( @list ) { + + @dargs=split(/\s+/,$i); + if ( $dargs[1] eq "\*Timeout\*" ) { + print "$i\n"; + chop $dargs[0]; + push(@down,$dargs[0]); + } else { + printf "%-25s %7s %3s %6s %10s %5s %8s %8s\n",@dargs; + if ( ( $dargs[4] > $tol ) || ( $dargs[4] < -$tol ) ) { + chop $dargs[0]; + push(@toofarout,$dargs[0]); } + } +} +# +# When the above list finishes, hosts that are different by +/- $tol (two seconds) +# are in @toofarout. Hosts that are down are in @down. They are treated the same +# way here, but you might want to do something different depending on your site. +# +# print a set of suggested rsh commands to run on the hosts that +# don't have "good" time. "restartntp" is left as an excersize to the reader. +# I usually use it to kill a running xntpd, ntpdate some server, and the start xntp +# again. +# +print "\nConsider:\n"; +foreach $i ( (@down,@toofarout) ) { + print " rsh $i sudo restartntp\n"; +} + + +# +# sort the results from the list. First by stratum, then by time deviation +# Put hosts that didn't respond (timed out) on the bottom. +# +sub appropriately { + @af=split(/\s+/,$a); + @bf=split(/\s+/,$b); + $aba= ($af[4]<0)?-$af[4]:$af[4]; + $abb= ($bf[4]<0)?-$bf[4]:$bf[4]; + + ( $af[1] ne $bf[1] ) ? $bf[1] cmp $af[1] : + ( ( $af[2] != $bf[2] ) ? ( $bf[2] <=> $af[2] ) : + ( ( $aba != $abb ) ? ( $abb <=> $aba ) : ($af[0] cmp $bf[0] ) ) ); +} diff --git a/contrib/ntp/scripts/fixautomakedepsmagic b/contrib/ntp/scripts/fixautomakedepsmagic new file mode 100644 index 000000000000..ec82bba548ca --- /dev/null +++ b/contrib/ntp/scripts/fixautomakedepsmagic @@ -0,0 +1,28 @@ +#!/bin/sh + +prog=`basename $0` + + +t=/tmp/$prog.$$ + +trap 'rm -f ${t} ; exit 1' 1 3 15 + +while [ $# -gt 0 ]; do + f=$1 + shift + sed -e '/^DEPS_MAGIC :=/,/^-include \$/s/^/#/' $f > $t + c="diff $f $t" + echo $c + $c + tstatus=$? + if [ $tstatus = 0 ]; then + echo "$prog":" $f not modified" + elif [ ! -w $f ]; then + echo "$prog":" $f not not writable" + else + c="cp $t $f" + echo $c + $c + fi + rm -f $t +done diff --git a/contrib/ntp/scripts/hpadjtime.sh b/contrib/ntp/scripts/hpadjtime.sh new file mode 100755 index 000000000000..3de2a4093046 --- /dev/null +++ b/contrib/ntp/scripts/hpadjtime.sh @@ -0,0 +1,18 @@ +#! /bin/sh +val=1 +if [ -f /bin/uname -o -f /usr/bin/uname ]; then + set `uname -a | tr '[A-Z]' '[a-z]'` + case "$1" in + hp-ux) case "$3" in + *.10.*) val=1 ;; + *.09.03 | *.09.10) case "$5" in + 9000/3*) val=1 ;; + *) val=0 ;; + esac ;; + *) val=0 ;; + esac + ;; + *) + esac +fi +exit $val diff --git a/contrib/ntp/scripts/mkver.in b/contrib/ntp/scripts/mkver.in new file mode 100644 index 000000000000..79d83f83993d --- /dev/null +++ b/contrib/ntp/scripts/mkver.in @@ -0,0 +1,31 @@ +#!@PATH_SH@ +PROG=${1-UNKNOWN} + +ConfStr="$PROG" + +case "@LIBRSAREF@" in + '') ;; + *) ConfStr="$ConfStr RSAREF" ;; +esac + +ConfStr="$ConfStr @VERSION@ `date`" + +if [ ! -f .version ]; then + echo 0 > .version +fi +RUN="`cat .version`" +RUN="`expr $RUN + 1`" +echo $RUN > .version + +ConfStr="$ConfStr (${RUN})" + +echo "Version <${ConfStr}>"; + +rm -f version.c +cat > version.c << -EoF- +/* + * version file for $PROG + */ +#include +const char * Version = "${ConfStr}"; +-EoF- diff --git a/contrib/ntp/scripts/monitoring/README b/contrib/ntp/scripts/monitoring/README new file mode 100644 index 000000000000..fa8ad8bb9585 --- /dev/null +++ b/contrib/ntp/scripts/monitoring/README @@ -0,0 +1,154 @@ +This directory contains support for monitoring the local clock of xntp daemons. + +WARNING: The scripts and routines contained in this directory are bete realease! + Do not depend on their correct operation. They are, however, in regular + use at University of Erlangen-Nuernberg. No severe problems are known + for this code. + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +PLEASE THINK TWICE BEFORE STARTING MONITORING REMOTE XNTP DEAMONS !!!! +MONITORING MAY INCREASE THE LOAD OF THE DEAMON MONITORED AND MAY +INCREASE THE NETWORK LOAD SIGNIFICANTLY +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +Files are: + +README: + This file + +ntptrap: + perl script to log ntp mode 6 trap messages. + + It sends a set_trap request to each server given and dumps the + trap messages received. It handles refresh of set_trap. + Currently it handles only NTP V2, however the NTP V3 servers + also accept v2 requests. It will not interpret v3 system and peer + stati correctly. + + usage: + ntptrap [-n] [-p ] [-l ] servers... + + -n: do not send set_trap requests + + port: port to listen for responses + useful if you have a configured trap + + debug-output: file to write trace output to (for debugging) + + This script convinced me that ntp trap messages are only of + little use. + +ntploopstat: + perl script to gather loop info statistics from xntpd via mode 7 + LOOP_INFO requests. + + This script collects data to allow monitoring of remote xntp servers + where it is not possible to directly access the loopstats file + produced by xntpd itself. Of course, it can be used to sample + a local server if it is not configured to produce a loopstats file. + + Please note, this program poses a high load on the server as + a communication takes place every delay seconds ! USE WITH CARE ! + + usage: + ntploopstat [-d] [-t] [-l ] [-v] [ntpserver] + + delay: number of seconds to wait between samples + default: 60 seconds + timeout: number of seconds to wait for reply + default 12 seconds + logfile: file to log samples to + default: loopstats:: + (note the trailing colon) + This name actually is a prefix. + The file name is dynamically derived by appending + the name of the month the sample belongs to. + Thus all samples of a month end up in the same file. + + the format of the files generated is identical to the format used by + xntpd with the loopstats file: + MJD offset frequency compliance + + if a timeout occurs the next sample is tried after delay/2 seconds + + The script will terminate after MAX_FAIL (currently 60) consecutive errors. + Errors are counted for: + - error on send call + - error on select call + - error on recv call + - short packet received + - bad packet + - error on open for logfile + +ntploopwatch: + perl script to display loop filter statistics collected by ntploopstat + or dumped directly by xntpd. + + Gnuplot is used to produce a graphical representation of the sample + values, that have been preprocessed and analysed by this script. + + It can either be called to produce a printout of specific data set or + used to continously monitor the values. Monitoring is achieved by + periodically reprocessing the logfiles, which are updated regularly + either by a running ntploopstat process or by the running xntpd. + + usage: + to watch statistics permanently: + ntploopwatch [-v[]] [-c ] [-d ] + + to get a single print out specify also + -P [-s] + [-S ] [-E ] + [-O ] [-o ] + + level: level of verbosity for debugging + config-file: file to read configurable settings from + On each iteration it is checked and reread + if it has been changed + default: loopwatch.config + working-dir: specify working directory for process, affects + interpretation of relative file names + + All other flags are only useful with printing plots, as otherwise + command line values would be replaced by settings from the config file. + + printer: specify printer to print plot + BSD print systems semantics apply; if printer is omitted + the name "ps" is used; plots are prepared using + PostScript, thus the printer should best accept + postscript input + + For the following see also the comments in loopwatch.config.SAMPLE + + samples: use last # samples from input data + start-time: ignore input samples before this date + end-time: ignore input samples after this date + if both start-time and end-time are specified + a given samples value is ignored + MaxOffs: + MinOffs: restrict value range + +loopwatch.config.SAMPLE: + sample config file for ntploopwatch + each configurable option is explained there + +lr.pl: + linear regression package used by ntploopwatch to compute + linear approximations for frequency and offset values + within display range + +timelocal.pl: + used during conversion of ISO_DATE_TIME values specified in loopwatch + config files to unix epoch values (seconds since 1970-01-01_00:00_00 UTC) + + A version of this file is distributed with perl-4.x, however, + it has a bug related to dates crossing 1970, causing endless loops.. + The version contained here has been fixed. + +ntp.pl: + perl support for ntp v2 mode 6 message handling + WARNING: This code is beta level - it triggers a memory leak; + as for now it is not quite clear, wether this is caused by a + bug in perl or by bad usage of perl within this script. + diff --git a/contrib/ntp/scripts/monitoring/loopwatch.config.SAMPLE b/contrib/ntp/scripts/monitoring/loopwatch.config.SAMPLE new file mode 100644 index 000000000000..8cefea395db0 --- /dev/null +++ b/contrib/ntp/scripts/monitoring/loopwatch.config.SAMPLE @@ -0,0 +1,89 @@ +# sample configuration and control file for ntploowatch +# +# delay: sampling interval in seconds +delay=60 +# samples: use only last # samples +samples=600 +# DO NOT USE srcprefix in shared config files +# srcprefix: name of file to read samples from +# current time suffix (month name) is appended +# defaults to "./var@$STATHOST/loopstats." +# The string "$STATHOST"is replaced by the name of the host +# being monitored +#srcprefix=./var@$STATHOST/loopstats. +# +# showoffs: yes/no control display of offset values +showoffs=yes +# +# showfreq: yes/no control display of frequency values +showfreq=yes +# +# showcmpl: yes/no control display of compliance values +showcmpl=no +# +# showoreg: yes/no control display of linear regression of offset values +showoreg=no +# +# showfreg: yes/no control display of linear regression of frequency values +showfreg=no +# +# timebase: dynamic/ISO_DATE_TIME point of zero for linear regression +# ISO_DATE_TIME: yyyy-mm-dd_hh:mm:ss.ms +# values are interpreted using local time zone +# parts omitted from front default to current date/time +# parts omitted from end default to lowest permitted values +# to get aa:bb being interpreted as minutes:seconds use aa:bb.0 +# for dynamic '00:00:00.0 of current day' is used +timebase=dynamic +# +# freqbase: dynamic/ +# if a number is given, subtract this from sampling values for display +# if dynamic is selected, freqbase is adjusted to fit into the range of +# offset values +freqbase=dynamic +# +# cmplscale: dynamic/ +# if a number is given, the sampling values are divided by this number +# if dynamic is selected, cmplscale is adjusted to fit into the range of +# offset values +cmplscale=dynamic +# +# DumbScale: 0/1 +# 0 enables dynamic adjust of value ranges for freqbase and cmplscale +# timescale is labeled with human readable times +# 1 only uses explicit scaling for numbers +# timescale is labeled with hours relative to timebase +DumbScale=0 +# +# StartTime: none/ISO_DATE_TIME +# ignore any samples before the specified date +StartTime=none +# +# EndTime: none/ISO_DATE_TIME +# ignore any samples after the specified date +# +# if both StartTime and EndTime are specified +# the value specified for samples is ignored +EndTime=none +# +# MaxOffs: none/ +# limit display (y-axis) to values not larger than +MaxOffset=none +# +# MinOffs: none/ +# limit display (y-axis) to values not smaller than +MinOffset=none + +# +# verbose: +# specify level for debugging +# default is 0 for printing and 1 for monitoring +# level 1 will just print a timestamp for any display update +# (this is every delay seconds) +verbose=1 +# +# deltaT: +# mark `holes' in the sample data grater than +# by a break in the plot +# default: 512 seconds +deltaT=512 diff --git a/contrib/ntp/scripts/monitoring/lr.pl b/contrib/ntp/scripts/monitoring/lr.pl new file mode 100644 index 000000000000..02c7550ec3ad --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/monitoring/ntp.pl b/contrib/ntp/scripts/monitoring/ntp.pl new file mode 100644 index 000000000000..ea9e69c2022a --- /dev/null +++ b/contrib/ntp/scripts/monitoring/ntp.pl @@ -0,0 +1,478 @@ +#!/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]) || + (scalar(@x=sort numerical keys(%FRAGS)) < 2))) + { + @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/ntp/scripts/monitoring/ntploopstat b/contrib/ntp/scripts/monitoring/ntploopstat new file mode 100644 index 000000000000..75cdff227b27 --- /dev/null +++ b/contrib/ntp/scripts/monitoring/ntploopstat @@ -0,0 +1,457 @@ +#!/local/bin/perl -w--*-perl-*- +;# +;# ntploopstat,v 3.1 1993/07/06 01:09:11 jbj Exp +;# +;# Poll NTP server using NTP mode 7 loopinfo request. +;# Log info and timestamp to file for processing by ntploopwatch. +;# +;# +;# Copyright (c) 1992 +;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg +;# +;################################################################# +;# +;# The format written to the logfile is the same as used by xntpd +;# for the loopstats file. +;# This script however allows to gather loop filter statistics from +;# remote servers where you do not have access to the loopstats logfile. +;# +;# Please note: Communication delays affect the accuracy of the +;# timestamps recorded. Effects from these delays will probably +;# not show up, as timestamps are recorded to the second only. +;# (Should have implemented &gettimeofday()..) +;# + +$0 =~ s!^.*/([^/]+)$!\1!; # beautify script name + +$ntpserver = 'localhost'; # default host to poll +$delay = 60; # default sampling rate + ;# keep it shorter than minpoll (=64) + ;# to get all values + +require "ctime.pl"; +;# handle bug in early ctime distributions +$ENV{'TZ'} = 'MET' unless defined($ENV{'TZ'}) || $] > 4.010; + +if (defined(@ctime'MoY)) +{ + *MonthName = *ctime'MoY; +} +else +{ + @MonthName = ('Jan','Feb','Mar','Apr','May','Jun', + 'Jul','Aug','Sep','Oct','Nov','Dec'); +} + +;# this routine can be redefined to point to syslog if necessary +sub msg +{ + return unless $verbose; + + print STDERR "$0: "; + printf STDERR @_; +} + +;############################################################# +;# +;# process command line +$usage = <<"E-O-S"; + +usage: + $0 [-d] [-t] [-l ] [-v] [ntpserver] +E-O-S + +while($_ = shift) +{ + /^-v(\d*)$/ && ($verbose=($1 eq '') ? 1 : $1,1) && next; + /^-d(\d*)$/ && + do { + ($1 ne '') && ($delay = $1,1) && next; + @ARGV || die("$0: delay value missing after -d\n$usage"); + $delay = shift; + ($delay >= 0) || die("$0: bad delay value \"$delay\"\n$usage"); + next; + }; + /^-l$/ && + do { + @ARGV || die("$0: logfile missing after -l\n$usage"); + $logfile = shift; + next; + }; + /^-t(\d*(\.\d*)?)$/ && + do { + ($1 ne '') && ($timeout = $1,1) && next; + @ARGV || die("$0: timeout value missing after -t\n$usage\n"); + $timeout = shift; + ($timeout > 0) || + die("$0: bad timeout value \"$timeout\"\n$usage"); + next; + }; + + /^-/ && die("$0: unknown option \"$_\"\n$usage"); + + ;# any other argument is server to poll + $ntpserver = $_; + last; +} + +if (@ARGV) +{ + warn("unexpected arguments: ".join(" ",@ARGV).".\n"); + die("$0: too many servers specified\n$usage"); +} + +;# logfile defaults to include server name +;# The name of the current month is appended and +;# the file is opened and closed for each sample. +;# +$logfile = "loopstats:$ntpserver." unless defined($logfile); +$timeout = 12.0 unless defined($timeout); # wait $timeout seconds for reply + +$MAX_FAIL = 60; # give up after $MAX_FAIL failed polls + + +$MJD_1970 = 40587; + +if (eval 'require "syscall.ph";') +{ + if (defined(&SYS_gettimeofday)) + { + ;# assume standard + ;# gettimeofday(struct timeval *tp,struct timezone *tzp) + ;# syntax for gettimeofday syscall + ;# tzp = NULL -> undef + ;# tp = (long,long) + eval 'sub time { local($tz) = pack("LL",0,0); + (&msg("gettimeofday failed: $!\n"), + return (time)) + unless syscall(&SYS_gettimeofday,$tz,undef) == 0; + local($s,$us) = unpack("LL",$tz); + return $s + $us/1000000; }'; + local($t1,$t2,$t3); + $t1 = time; + eval '$t2 = &time;'; + $t3 = time; + die("$0: gettimeofday failed: $@.\n") if defined($@) && $@; + die("$0: gettimeofday inconsistency time=$t1,gettimeofday=$t2,time=$t2\n") + if (int($t1) != int($t2) && int($t3) != int($t2)); + &msg("Using gettimeofday for timestamps\n"); + } + else + { + warn("No gettimeofday syscall found - using time builtin for timestamps\n"); + eval 'sub time { return time; }'; + } +} +else +{ + warn("No syscall.ph file found - using time builtin for timestamps\n"); + eval 'sub time { return time; }'; +} + + +;#------------------+ +;# from ntp_request.h +;#------------------+ + +;# NTP mode 7 packet format: +;# Byte 1: ResponseBit MoreBit Version(3bit) Mode(3bit)==7 +;# Byte 2: AuthBit Sequence # - 0 - 127 see MoreBit +;# Byte 3: Implementation # +;# Byte 4: Request Code +;# +;# Short 1: Err(3bit) NumItems(12bit) +;# Short 2: MBZ(3bit)=0 DataItemSize(12bit) +;# 0 - 500 byte Data +;# if AuthBit is set: +;# Long: KeyId +;# 2xLong: AuthCode + +;# +$IMPL_XNTPD = 2; +$REQ_LOOP_INFO = 8; + + +;# request packet for REQ_LOOP_INFO: +;# B1: RB=0 MB=0 V=2 M=7 +;# B2: S# = 0 +;# B3: I# = IMPL_XNTPD +;# B4: RC = REQ_LOOP_INFO +;# S1: E=0 NI=0 +;# S2: MBZ=0 DIS=0 +;# data: 32 byte 0 padding +;# 8byte timestamp if encryption, 0 padding otherwise +$loopinfo_reqpkt = + pack("CCCC nn x32 x8", 0x17, 0, $IMPL_XNTPD, $REQ_LOOP_INFO, 0, 0); + +;# ignore any auth data in packets +$loopinfo_response_size = + 1+1+1+1+2+2 # header size like request pkt + + 8 # l_fp last_offset + + 8 # l_fp drift_comp + + 4 # u_long compliance + + 4 # u_long watchdog_timer + ; +$loopinfo_response_fmt = "C4n2N2N2NN"; +$loopinfo_response_fmt_v2 = "C4n2N2N2N2N"; + +;# +;# prepare connection to server +;# + +;# workaround for broken socket.ph on dynix_ptx +eval 'sub INTEL {1;}' unless defined(&INTEL); +eval 'sub ATT {1;}' unless defined(&ATT); + +require "sys/socket.ph"; + +require 'netinet/in.ph'; + +;# if you do not have netinet/in.ph enable the following lines +;#eval 'sub INADDR_ANY { 0x00000000; }' unless defined(&INADDR_ANY); +;#eval 'sub IPPRORO_UDP { 17; }' unless defined(&IPPROTO_UDP); + +if ($ntpserver =~ /^((0x?)?\w+)\.((0x?)?\w+)\.((0x?)?\w+)\.((0x?)?\w+)$/) +{ + local($a,$b,$c,$d) = ($1,$3,$5,$7); + $a = oct($a) if defined($2); + $b = oct($b) if defined($4); + $c = oct($c) if defined($6); + $d = oct($d) if defined($8); + $server_addr = pack("C4", $a,$b,$c,$d); + + $server_mainname + = (gethostbyaddr($server_addr,&AF_INET))[$[] || $ntpserver; +} +else +{ + ($server_mainname,$server_addr) + = (gethostbyname($ntpserver))[$[,$[+4]; + + die("$0: host \"$ntpserver\" is unknown\n") + unless defined($server_addr); +} +&msg ("Address of server \"$ntpserver\" is \"%d.%d.%d.%d\"\n", + unpack("C4",$server_addr)); + +$proto_udp = (getprotobyname('udp'))[$[+2] || &IPPROTO_UDP; + +$ntp_port = + (getservbyname('ntp','udp'))[$[+2] || + (warn "Could not get port number for service \"ntp/udp\" using 123\n"), + ($ntp_port=123); + +;# +0 && &SOCK_DGRAM; # satisfy perl -w ... +socket(S, &AF_INET, &SOCK_DGRAM, $proto_udp) || + die("Cannot open socket: $!\n"); + +bind(S, pack("S n N x8", &AF_INET, 0, &INADDR_ANY)) || + die("Cannot bind: $!\n"); + +($my_port, $my_addr) = (unpack("S n a4 x8",getsockname(S)))[$[+1,$[+2]; + +&msg("Listening at address %d.%d.%d.%d port %d\n", + unpack("C4",$my_addr), $my_port); + +$server_inaddr = pack("Sna4x8", &AF_INET, $ntp_port, $server_addr); + +;############################################################ +;# +;# the main loop: +;# send request +;# get reply +;# wait til next sample time + +undef($lasttime); +$lostpacket = 0; + +while(1) +{ + $stime = &time; + + &msg("Sending request $stime...\n"); + + $ret = send(S,$loopinfo_reqpkt,0,$server_inaddr); + + if (! defined($ret) || $ret < length($loopinfo_reqpkt)) + { + warn("$0: send failed ret=($ret): $!\n"); + $fail++; + next; + } + + &msg("Waiting for reply...\n"); + + $mask = ""; vec($mask,fileno(S),1) = 1; + $ret = select($mask,undef,undef,$timeout); + + if (! defined($ret)) + { + warn("$0: select failed: $!\n"); + $fail++; + next; + } + elsif ($ret == 0) + { + warn("$0: request to $ntpserver timed out ($timeout seconds)\n"); + ;# do not count this event as failure + ;# it usually this happens due to dropped udp packets on noisy and + ;# havily loaded lines, so just try again; + $lostpacket = 1; + next; + } + + &msg("Receiving reply...\n"); + + $len = 520; # max size of a mode 7 packet + $reply = ""; # just make it defined for -w + $ret = recv(S,$reply,$len,0); + + if (!defined($ret)) + { + warn("$0: recv failed: $!\n"); + $fail++; + next; + } + + $etime = &time; + &msg("Received at\t$etime\n"); + + ;#$time = ($stime + $etime) / 2; # symmetric delay assumed + $time = $etime; # the above assumption breaks for X25 + ;# so taking etime makes timestamps be a + ;# little late, but keeps them increasing + ;# monotonously + + &msg(sprintf("Reply from %d.%d.%d.%d took %f seconds\n", + (unpack("SnC4",$ret))[$[+2 .. $[+5], ($etime - $stime))); + + if ($len < $loopinfo_response_size) + { + warn("$0: short packet ($len bytes) received ($loopinfo_response_size bytes expected\n"); + $fail++; + next; + } + + ($b1,$b2,$b3,$b4,$s1,$s2, + $offset_i,$offset_f,$drift_i,$drift_f,$compl,$watchdog) + = unpack($loopinfo_response_fmt,$reply); + + ;# check reply + if (($s1 >> 12) != 0) # error ! + { + die("$0: got error reply ".($s1>>12)."\n"); + } + if (($b1 != 0x97 && $b1 != 0x9f) || # Reply NotMore V=2 M=7 + ($b2 != 0 && $b2 != 0x80) || # S=0 Auth no/yes + $b3 != $IMPL_XNTPD || # ! IMPL_XNTPD + $b4 != $REQ_LOOP_INFO || # Ehh.. not loopinfo reply ? + $s1 != 1 || # ???? + ($s2 != 24 && $s2 != 28) # + ) + { + warn("$0: Bad/unexpected reply from server:\n"); + warn(" \"".unpack("H*",$reply)."\"\n"); + warn(" ".sprintf("b1=%x b2=%x b3=%x b4=%x s1=%d s2=%d\n", + $b1,$b2,$b3,$b4,$s1,$s2)); + $fail++; + next; + } + elsif ($s2 == 28) + { + ;# seems to be a version 2 xntpd + ($b1,$b2,$b3,$b4,$s1,$s2, + $offset_i,$offset_f,$drift_i,$drift_f,$compl_i,$compl_f,$watchdog) + = unpack($loopinfo_response_fmt_v2,$reply); + $compl = &lfptoa($compl_i, $compl_f); + } + + $time -= $watchdog; + + $offset = &lfptoa($offset_i, $offset_f); + $drift = &lfptoa($drift_i, $drift_f); + + &log($time,$offset,$drift,$compl) && ($fail = 0);; +} +continue +{ + die("$0: Too many failures - terminating\n") if $fail > $MAX_FAIL; + &msg("Sleeping " . ($lostpacket ? ($delay / 2) : $delay) . " seconds...\n"); + + sleep($lostpacket ? ($delay / 2) : $delay); + $lostpacket = 0; +} + +sub log +{ + local($time,$offs,$freq,$cmpl) = @_; + local($y,$m,$d); + local($fname,$suff) = ($logfile); + + + ;# silently drop sample if distance to last sample is too low + if (defined($lasttime) && ($lasttime + 2) >= $time) + { + &msg("Dropped packet - old sample\n"); + return 1; + } + + ;# $suff determines which samples end up in the same file + ;# could have used $year (;-) or WeekOfYear, DayOfYear,.... + ;# Change it to your suit... + + ($d,$m,$y) = (localtime($time))[$[+3 .. $[+5]; + $suff = sprintf("%04d%02d%02d",$y+1900,$m+1,$d); + $fname .= $suff; + if (!open(LOG,">>$fname")) + { + warn("$0: open($fname) failed: $!\n"); + $fail++; + return 0; + } + else + { + ;# file format + ;# MJD seconds offset drift compliance + printf LOG ("%d %.3lf %.8lf %.7lf %d\n", + int($time/86400)+$MJD_1970, + $time - int($time/86400) * 86400, + $offs,$freq,$cmpl); + close(LOG); + $lasttime = $time; + } + return 1; +} + +;# see ntp_fp.h to understand this +sub lfptoa +{ + local($i,$f) = @_; + local($sign) = 1; + + + if ($i & 0x80000000) + { + if ($f == 0) + { + $i = -$i; + } + else + { + $f = -$f; + $i = ~$i; + $i += 1; # 2s complement + } + $sign = -1; + ;#print "NEG: $i $f\n"; + } + else + { + ;#print "POS: $i $f\n"; + } + ;# unlike xntpd I have perl do the dirty work. + ;# Using floats here may affect precision, but + ;# currently these bits aren't significant anyway + return $sign * ($i + $f/2**32); +} diff --git a/contrib/ntp/scripts/monitoring/ntploopwatch b/contrib/ntp/scripts/monitoring/ntploopwatch new file mode 100644 index 000000000000..db661d3b501f --- /dev/null +++ b/contrib/ntp/scripts/monitoring/ntploopwatch @@ -0,0 +1,1667 @@ +#!/usr/bin/perl -w +;# --*-perl-*-- +;# +;# /src/NTP/ntp-4/scripts/monitoring/ntploopwatch,v 4.3 1999/02/21 12:18:38 kardel RELEASE_19990228_A +;# RELEASE_19990228_A +;# +;# process loop filter statistics file and either +;# - show statistics periodically using gnuplot +;# - or print a single plot +;# +;# Copyright (c) 1992-1998 +;# Rainer Pruy, Friedrich-Alexander Universität Erlangen-Nürnberg +;# +;# +;############################################################# +$0 =~ s!^.*/([^/]+)$!$1!; +$F = ' ' x length($0); +$|=1; + +$ENV{'SHELL'} = '/bin/sh'; # use bourne shell + +undef($config); +undef($workdir); +undef($PrintIt); +undef($samples); +undef($StartTime); +undef($EndTime); +($a,$b) if 0; # keep -w happy +$usage = <<"E-O-P"; +usage: + to watch statistics permanently: + $0 [-v[]] [-c ] [-d ] + $F [-h ] + + to get a single print out specify also + $F -P[] [-s] + $F [-S ] [-E ] + $F [-Y ] [-y ] + +If You like long option names, You can use: + -help + -c +config + -d +directory + -h +host + -v +verbose[=] + -P +printer[=] + -s +samples[=] + -S +starttime + -E +endtime + -Y +maxy + -y +miny + +If contains a '/' (slash character) output is directed to +a file of this name instead of delivered to a printer. +E-O-P + +;# add directory to look for lr.pl and timelocal.pl (in front of current list) +unshift(@INC,"/usr/local/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 = 1; # clip Y scales with greater range than this + +;# largest extension of Y scale from mean value, factor for standart deviation +$FuzzLow = 2.2; # for side closer to zero +$FuzzBig = 1.8; # 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; +} # ' re-sync emacs fontification +else +{ + @Month = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); + @Day = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); +} +print @ctime'DoW if 0; # ' re-sync emacs fontification + +;# 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) ? -($_[$[]) : $_[$[]; +} + +sub boolval +{ + local($v) = ($_[$[]); + + return 1 if ($v eq 'yes') || ($v eq 'y'); + return 1 if ($v =~ /^[0-9]*$/) && ($v != 0); + return 0; +} + +;##################### +;# start of real work + +print "starting plot command (" . join(" ",@plotcmd) . ")\n" if $verbose > 1; + +$Plotpid = open(PLOT,"|-"); +select((select(PLOT),$|=1)[$[]); # make PLOT line bufferd + +defined($Plotpid) || + die("$0: failed to start plot command: $!\n"); + +unless ($Plotpid) +{ + ;# child == plot command + close(STDOUT); + open(STDOUT,">&STDERR") || + die("$0: failed to redirect STDOUT of plot command: $!\n"); + + print STDOUT "plot command running as $$\n"; + + exec @plotcmd; + die("$0: failed to exec (@plotcmd): $!\n"); + exit(1); # in case ... +} + +sub read_config +{ + local($at) = (stat($config))[$[+9]; + local($_,$c,$v); + + (undef($laststat),(print("stat $config failed: $!\n")),return) if ! defined($at); + return if (defined($laststat) && ($laststat == $at)); + $laststat = $at; + + print "reading configuration from \"$config\"\n" if $verbose; + + open(CF,"<$config") || + (warn("$0: failed to read \"$config\" - using old settings ($!)\n"), + return); + while() + { + chop; + s/^([^\#]*[^\#\s]?)\s*\#.*$//; + next if /^\s*$/; + + s/^\s*([^=\s]*)\s*=\s*(.*\S)\s*$/$1=$2/; + + ($c,$v) = split(/=/,$_,2); + print "processing \"$c=$v\"\n" if $verbose > 3; + ($c eq "delay") && ($delay = $v,1) && next; + ($c eq 'samples') && (!defined($PrintIt) || !defined($samples)) && + ($samples = $v,1) && next; + ($c eq 'srcprefix') && (($srcprefix=$v)=~s/\$STATHOST/$STATHOST/g,1) + && next; + ($c eq 'showoffs') && + ($showoffs = boolval($v),1) && next; + ($c eq 'showfreq') && + ($showfreq = boolval($v),1) && next; + ($c eq 'showcmpl') && + ($showcmpl = boolval($v),1) && next; + ($c eq 'showoreg') && + ($showoreg = boolval($v),1) && next; + ($c eq 'showfreg') && + ($showfreg = boolval($v),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 = ","); + $LastCmplScale = 1 if ! defined($LastCmplScale); + $showcmpl && + ($doplot .= sprintf($fmt,$c,$tmpfile,4, + "compliance" . + (&abs($LastCmplScale) > 1 + ? " / $LastCmplScale" + : (&abs($LastCmplScale) == 1 ? "" : " * ".(1/$LastCmplScale))), + $mincmpl/$LastCmplScale,$maxcmpl/$LastCmplScale, + ""), + $c = ","); + $LastFreqBase = 0 if ! defined($LastFreqBase); + $LastFreqBaseString = "?" if ! defined($LastFreqBaseString); + $FreqScale = 1 if ! defined($FreqScale); + $FreqScaleInv = 1 if ! defined($FreqScaleInv); + $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; + + $fpos[$[] = '' if !defined($fpos[$[]); + + if (index($in,"/") < $[) + { + $sdir = "."; + $sname = $in; + } + else + { + ($sdir,$sname) = ($in =~ m!^(.*)/([^/]*)!); + $sname = "" unless defined($sname); + } + + $Ltime = -1 if ! defined($Ltime); + if (!defined($Lsdir) || $Lsdir ne $sdir || $Ltime != (stat($sdir))[$[+9] || + grep($F_mtime{$_} != (stat($F_name{$_}))[$[+9], @F_files)) + + { + print "rescanning directory \"$sdir\" for files \"$sname*\"\n" + if $verbose > 1; + + ;# rescan directory on changes + $Lsdir = $sdir; + $Ltime = (stat($sdir))[$[+9]; + if 0; # dummy line - calm down my formatter + local(@newfiles) = < ${in}*[0-9] >; + local($st_dev,$st_ino,$st_mtime,$st_size,$name,$key,$modified); + + foreach $name (@newfiles) + { + ($st_dev,$st_ino,$st_size,$st_mtime) = + (stat($name))[$[,$[+1,$[+7,$[+9]; + $modified = 0; + $key = sprintf("%lx|%lu", $st_dev, $st_ino); + + print "candidate file \"$name\"", + (defined($st_dev) ? "" : " failed: $!"),"\n" + if $verbose > 2; + + if (! defined($F_key{$name}) || $F_key{$name} ne $key) + { + $F_key{$name} = $key; + $modified++; + } + if (!defined($F_name{$key}) || $F_name{$key} ne $name) + { + $F_name{$key} = $name; + $modified++; + } + if (!defined($F_size{$key}) || $F_size{$key} != $st_size) + { + $F_size{$key} = $st_size; + $modified++; + } + if (!defined($F_mtime{$key}) || $F_mtime{$key} != $st_mtime) + { + $F_mtime{$key} = $st_mtime; + $modified++; + } + if ($modified) + { + print "new data \"$name\" key: $key;\n" if $verbose > 1; + print " size: $st_size; mtime: $st_mtime;\n" + if $verbose > 1; + $F_last{$key} = $F_first{$key} = $st_mtime; + $F_first{$key}--; # prevent zero divide later on + ;# now compute derivated attributes + open(IN, "<$name") || + do { + warn "$0: failed to open \"$name\": $!"; + next; + }; + + while() + { + @F = split; + next if @F < 5; + next if $F[$[] eq ""; + $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; + $t += $F[$[+1]; + $F_first{$key} = $t; + print "\tfound first entry: $t ",&ctime($t) + if $verbose > 4; + last; + } + seek(IN, + ($st_size > 4*$RecordSize) ? $st_size - 4*$RecordSize : 0, + 0); + while() + { + @F = split; + next if @F < 5; + next if $F[$[] eq ""; + $t = ($F[$[] - $MJD_1970) * 24 * 60 * 60; + $t += $F[$[+1]; + $F_last{$key} = $t; + $_ = ; + print "\tfound last entry: $t ", &ctime($t) + if $verbose > 4 && ! defined($_); + last unless defined($_); + redo; + ;# Ok, calm down... + ;# using $_ = in conjunction with redo + ;# is semantically equivalent to the while loop, but + ;# I needed a one line look ahead and this solution + ;# was what I thought of first + ;# and.. If you do not like it dont look + } + close(IN); + print(" first: ",$F_first{$key}, + " last: ",$F_last{$key},"\n") if $verbose > 1; + } + } + ;# now reclaim memory used for files no longer referenced ... + local(%Names); + grep($Names{$_} = 1,@newfiles); + foreach (keys %F_key) + { + next if defined($Names{$_}); + delete $F_key{$_}; + $verbose > 2 && print "no longer referenced: \"$_\"\n"; + } + %Names = (); + + grep($Names{$_} = 1,values(%F_key)); + foreach (keys %F_name) + { + next if defined($Names{$_}); + delete $F_name{$_}; + $verbose > 2 && print "unref name($_)= $F_name{$_}\n"; + } + foreach (keys %F_size) + { + next if defined($Names{$_}); + delete $F_size{$_}; + $verbose > 2 && print "unref size($_)\n"; + } + foreach (keys %F_mtime) + { + next if defined($Names{$_}); + delete $F_mtime{$_}; + $verbose > 2 && print "unref mtime($_)\n"; + } + foreach (keys %F_first) + { + next if defined($Names{$_}); + delete $F_first{$_}; + $verbose > 2 && print "unref first($_)\n"; + } + foreach (keys %F_last) + { + next if defined($Names{$_}); + delete $F_last{$_}; + $verbose > 2 && print "unref last($_)\n"; + } + ;# create list sorted by time + @F_files = sort {$F_first{$a} <=> $F_first{$b}; } keys(%F_name); + if ($verbose > 1) + { + print "Resulting file list:\n"; + foreach (@F_files) + { + print "\t$_\t$F_name{$_}\n"; + } + } + } + + printf("processing %s; output \"$out\" (%d input files)\n", + ((defined($StartTime) && defined($EndTime)) + ? "time range" + : (defined($StartTime) ? "$cnt samples from StartTime" : + (defined($EndTime) ? "$cnt samples to EndTime" : + "last $cnt samples"))), + scalar(@F_files)) + if $verbose > 1; + + ;# open output file - will be input for plotcmd + open(OUT,">$out") || + do { + warn("$0: cannot create \"$out\": $!\n"); + }; + + @f = @F_files; + if (defined($StartTime)) + { + while (@f && ($F_last{$f[$[]} < $StartTime)) + { + print("shifting ", $F_name{$f[$[]}, + " last: ", $F_last{$f[$[]}, + " < StartTime: $StartTime\n") + if $verbose > 3; + shift(@f); + } + + + } + if (defined($EndTime)) + { + while (@f && ($F_first{$f[$#f]} > $EndTime)) + { + print("popping ", $F_name{$f[$#f]}, + " first: ", $F_first{$f[$#f]}, + " > EndTime: $EndTime\n") + if $verbose > 3; + pop(@f); + } + } + + if (@f) + { + if (defined($StartTime)) + { + print "guess start according to StartTime ($StartTime)\n" + if $verbose > 3; + + if ($fpos[$[] eq 'start') + { + if (grep($_ eq $fpos[$[+1],@f)) + { + shift(@f) while @f && $f[$[] ne $fpos[$[+1]; + } + else + { + @fpos = ('start', $f[$[], undef); + } + } + else + { + @fpos = ('start' , $f[$[], undef); + } + + if (!defined($fpos[$[+2])) + { + if ($StartTime <= $F_first{$f[$[]}) + { + $fpos[$[+2] = 0; + } + else + { + $fpos[$[+2] = + int($F_size{$f[$[]} * + (($StartTime - $F_first{$f[$[]})/ + ($F_last{$f[$[]} - $F_first{$f[$[]}))); + $fpos[$[+2] = ($fpos[$[+2] <= 2 * $RecordSize) + ? 0 : $fpos[$[+2] - 2 * $RecordSize; + ;# anyway as the data may contain "time holes" + ;# our heuristics may baldly fail + ;# so just start at 0 + $fpos[$[+2] = 0; + } + } + } + elsif (defined($EndTime)) + { + print "guess starting point according to EndTime ($EndTime)\n" + if $verbose > 3; + + if ($fpos[$[] eq 'end') + { + if (grep($_ eq $fpos[$[+1],@f)) + { + shift(@f) while @f && $f[$[] ne $fpos[$[+1]; + } + else + { + @fpos = ('end', $f[$[], undef); + } + } + else + { + @fpos = ('end', $f[$[], undef); + } + + if (!defined($fpos[$[+2])) + { + local(@x) = reverse(@f); + local($s,$c) = (0,$cnt); + if ($EndTime < $F_last{$x[$[]}) + { + ;# last file will only be used partially + $s = int($F_size{$x[$[]} * + (($EndTime - $F_first{$x[$[]}) / + ($F_last{$x[$[]} - $F_first{$x[$[]}))); + $s = int($s/$RecordSize); + $c -= $s - 1; + if ($c <= 0) + { + ;# start is in the same file + $fpos[$[+1] = $x[$[]; + $fpos[$[+2] = ($c >=-2) ? 0 : (-$c - 2) * $RecordSize; + shift(@f) while @f && ($f[$[] ne $x[$[]); + } + else + { + shift(@x); + } + } + + if (!defined($fpos[$[+2])) + { + local($_); + while($_ = shift(@x)) + { + $s = int($F_size{$_}/$RecordSize); + $c -= $s - 1; + if ($c <= 0) + { + $fpos[$[+1] = $_; + $fpos[$[+2] = ($c>-2) ? 0 : (-$c - 2) * $RecordSize; + shift(@f) while @f && ($f[$[] ne $_); + last; + } + } + } + } + } + else + { + print "guessing starting point according to count ($cnt)\n" + if $verbose > 3; + ;# guess offset to get last available $cnt samples + if ($fpos[$[] eq 'cnt') + { + if (grep($_ eq $fpos[$[+1],@f)) + { + print "old positioning applies\n" if $verbose > 3; + shift(@f) while @f && $f[$[] ne $fpos[$[+1]; + } + else + { + @fpos = ('cnt', $f[$[], undef); + } + } + else + { + @fpos = ('cnt', $f[$[], undef); + } + + if (!defined($fpos[$[+2])) + { + local(@x) = reverse(@f); + local($s,$c) = (0,$cnt); + + local($_); + while($_ = shift(@x)) + { + print "examing \"$_\" $c samples still needed\n" + if $verbose > 4; + $s = int($F_size{$_}/$RecordSize); + $c -= $s - 1; + if ($c <= 0) + { + $fpos[$[+1] = $_; + $fpos[$[+2] = ($c>-2) ? 0 : (-$c - 2) * $RecordSize; + shift(@f) while @f && ($f[$[] ne $_); + last; + } + } + if (!defined($fpos[$[+2])) + { + print "no starting point yet - using start of data\n" + if $verbose > 2; + $fpos[$[+2] = 0; + } + } + } + } + print "Ooops, no suitable input file ??\n" + if $verbose > 1 && @f <= 0; + + printf("Starting at (%s) \"%s\" offset %ld using %d files\n", + $fpos[$[+1], + $F_name{$fpos[$[+1]}, + $fpos[$[+2], + scalar(@f)) + if $verbose > 2; + + $lm = 1; + $l = 0; + foreach $key (@f) + { + $file = $F_name{$key}; + print "processing file \"$file\"\n" if $verbose > 2; + + open(IN,"<$file") || + (warn("$0: cannot read \"$file\": $!\n"), next); + + ;# try to seek to a position nearer to the start of the interesting lines + ;# should always affect only first item in @f + ($key eq $fpos[$[+1]) && + (($verbose > 1) && + print("Seeking to offset $fpos[$[+2]\n"), + seek(IN,$fpos[$[+2],0) || + warn("$0: seek(\"$F_name{$key}\" failed: $|\n")); + + while() + { + $l++; + ($verbose > 3) && + (($l % $lm) == 0 && print("\t$l lines read\n") && + (($l == 2) && ($lm = 10) || + ($l == 100) && ($lm = 100) || + ($l == 500) && ($lm = 500) || + ($l == 1000) && ($lm = 1000) || + ($l == 5000) && ($lm = 5000) || + ($l == 10000) && ($lm = 10000))); + + @F = split; + + next if @F < 6; # no valid input line is this short + next if $F[$[] eq ""; + next if ($F[$[] !~ /^\d+$/); + ($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[$[+5]); + + 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; + undef $maxtime; + undef $minoffs; + undef $maxoffs; + undef $minfreq; + undef $maxfreq; + undef $mincmpl; + undef $maxcmpl; + undef $miny; + undef $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.9999); + $FreqScaleInv = + ("$FreqScale" =~ /^10(0*)$/) ? "0.${1}1" : + ($FreqScale == 1 ? "" : (1/$FreqScale)); + + $freqbase = ($maxfreq + $minfreq)/ 2 * $FreqScale; #$m * $FreqScale; + $freqbase -= ($maxy + $miny) / 2; #&lr_mean('offs'); + + ;# round resulting freqbase + ;# to precision of min max difference + $s = -12; + $s = int(log(($maxfreq-$minfreq)*$FreqScale)/log(10))-1 + unless ($maxfreq-$minfreq) < 1e-12; + $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' && scalar(@loffset) >= $cnt) || + ($fpos[$[] eq 'start' && $mintime <= $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 occurred 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; + } +} + +$Ltime = -1 if ! defined($Ltime); +$LastFreqBase = 0; +$LastFreqBaseString = "??"; + +;# 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/ntp/scripts/monitoring/ntptrap b/contrib/ntp/scripts/monitoring/ntptrap new file mode 100644 index 000000000000..5a1bcb1b225e --- /dev/null +++ b/contrib/ntp/scripts/monitoring/ntptrap @@ -0,0 +1,463 @@ +#!/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 +use Socket; + +#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; #'; +$ntp'timeout if 0; + +;###################################### +;# now process options +;# +sub usage +{ + die("usage: $0 [-n] [-p ] [-l ] [host] ...\n"); +} + +$opt_l = "/dev/null"; # where to write debug messages to +$opt_p = 0; # port to use locally - (0 does mean: will be choosen by kernel) + +&usage unless &Getopts('l:p:'); +&Getopts if 0; # make -w happy + +@Hosts = ($#ARGV < $[) ? ("localhost") : @ARGV; + +;# setup for debug output +$DEBUGFILE=$opt_l; +$DEBUGFILE="&STDERR" if $DEBUGFILE eq '-'; + +open(DEBUG,">>$DEBUGFILE") || die("Cannot open \"$DEBUGFILE\": $!\n"); +select((select(DEBUG),$|=1)[$[]); + +;# &log prints a single trap record (adding a (local) time stamp) +sub log +{ + chop($date=&ctime(time)); + print "$date ",@_,"\n"; +} + +sub debug +{ + print DEBUG @_,"\n"; +} +;# +$proto_udp = (getprotobyname('udp'))[$[+2] || + (warn("$0: Could not get protocoll number for 'udp' using 17"), 17); + +$ntp_port = (getservbyname('ntp','udp'))[$[+2] || + (warn("$0: Could not get port number for service ntp/udp using 123"), 123); + +;# +socket(S, &AF_INET, &SOCK_DGRAM, $proto_udp) || die("Cannot open socket: $!\n"); + +;# +bind(S, pack("S n a4 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) + { + if ( ! defined($Host{$_}) ) + { + print "no info for host '$_'\n"; + next; + } + &ntp'send(S,31,0,"",pack("Sna4x8",&AF_INET,$ntp_port,$Host{$_})); #'; + } + 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; + $Host{$_} = $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+)/) + { + local($x) = (gethostbyaddr(pack("C4",$1,$2,$3,$4),&AF_INET)); + $msg .= " " . $x if defined($x) + } + 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/ntp/scripts/monitoring/timelocal.pl b/contrib/ntp/scripts/monitoring/timelocal.pl new file mode 100644 index 000000000000..d0f73a236676 --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/ntp-groper b/contrib/ntp/scripts/ntp-groper new file mode 100755 index 000000000000..1fd0cfe4c2d6 --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/ntp-restart b/contrib/ntp/scripts/ntp-restart new file mode 100755 index 000000000000..d2023f0b67b2 --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/ntpver.in b/contrib/ntp/scripts/ntpver.in new file mode 100644 index 000000000000..be36897c46f7 --- /dev/null +++ b/contrib/ntp/scripts/ntpver.in @@ -0,0 +1,7 @@ +#!@PATH_SH@ +# print version string of NTP daemon +# Copyright (c) 1997 by Ulrich Windl +# Modified 970318: Harlan Stenn: rewritten... +# usage: ntpver hostname + +ntpq -c "rv 0 daemon_version" $* | awk '/daemon_version/ { print $2 }' diff --git a/contrib/ntp/scripts/plot_summary.pl b/contrib/ntp/scripts/plot_summary.pl new file mode 100755 index 000000000000..5be018287911 --- /dev/null +++ b/contrib/ntp/scripts/plot_summary.pl @@ -0,0 +1,333 @@ +#!/usr/bin/perl -w +# $Id: plot_summary.pl,v 1.1.1.1 1999/05/26 00:48:25 stenn Exp $ +# +# Use Gnuplot to display data in summary files produced by summary.pl. +# This script requires GNUPLOT 3.6 (pre 3.6 beta 319)! +# +# Copyright (c) 1997, Ulrich Windl +# +# 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 of the License, 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. + +require 5.003; # "never tested with any other version of Perl" +use strict; + +use Time::Local; +use Getopt::Long; + +# parse command line +my $summary_dir = "/tmp"; +my $identifier = `hostname`; # origin of these data +chomp $identifier; # remove newline +my $offset_limit = 0.128; # limit of absolute offset +my $output_file = ""; # output file defaults to stdout +my $output_file_number = 1; # numbering of output files +my $gnuplot_terminal = $ENV{DISPLAY} ? "x11" : "dumb"; +my $wait_after_plot = 1; +my @peer_list = (); + +my %options = ("directory=s" => \$summary_dir, + "identifier=s" => \$identifier, + "offset-limit=f" => \$offset_limit, + "output-file=s" => \$output_file, + "peer=s@" => \@peer_list, + "plot-term=s" => \$gnuplot_terminal, + "wait-after-plot!" => \$wait_after_plot, + ); +if ( !GetOptions(%options) ) { + print STDERR "usage: $0\n"; + my $opt; + foreach $opt (sort(keys %options)) { + print STDERR "\t--$opt "; + if ( ref($options{$opt}) eq "ARRAY" ) { + print STDERR "(" . join (" ", @{$options{$opt}}) . ")\n"; + } else { + print STDERR "(${$options{$opt}})\n"; + } + } + print STDERR "\n"; + die; +} + +chomp $identifier; +die "illegal offset-limit: $offset_limit" unless $offset_limit > 0.0; +$offset_limit *= 1e6; # scale to microseconds + +# return the smallest value in the given list +sub min +{ + my ($result, @rest) = @_; + map { $result = $_ if ($_ < $result) } @rest; + return($result); +} + +# return the largest value in the given list +sub max +{ + my ($result, @rest) = @_; + map { $result = $_ if ($_ > $result) } @rest; + return($result); +} + +# maybe open alternate output file +sub open_output +{ + my $file; + if ($output_file) { + while ( -r ($file = "$output_file$output_file_number") ) { + ++$output_file_number; + } + open TOUCH, ">$file" and close TOUCH or die "$file: $!"; + print "set output \"$file\"\n"; + } +} + +# make Gnuplot wait +sub maybe_add_pause +{ + print "pause -1 \"Press key to continue...\"\n" if $wait_after_plot; +} + +# plot data from loop summary +sub do_loop +{ + my $fname = shift; + my $line; + my $out_file = "/tmp/tempdata$$"; + my $cmd_file = "/tmp/tempcmd$$"; + my ($first_day, $day_out) = ("", 0); + my ($lower_bound, $upper_bound, $rms); + my ($min_offs, $max_offs) = (1e9, -1e9); + my ($min_rms, $max_rms) = (1e9, -1e9); + open INPUT, "$fname" or die "$fname: $!"; + open OUTPUT, ">$out_file" or die "$out_file: $!"; + my @Fld; + while () { + chop; # strip record separator + @Fld = split; + if ($#Fld == 0) { +# loops.19960405 + $_ = $Fld[0]; s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; + m/(\d{4})(\d{2})(\d{2})/; + $line = timegm (59, 59, 23, $3, $2 - 1, $1 - 1900, 0, 0, 0); + $line = int $line / 86400; # days relative to 1970 + $first_day = "$1-$2-$3 ($line)" unless $day_out; + next; + } + if ($#Fld != 8) { + warn "Illegal number of fields in file $fname, line $."; + next; + } +# loop 216, 856106+/-874041.5, rms 117239.8, freq 67.52+/-10.335, var 4.850 + $_ = $Fld[1]; s/,/ /; $line .= " $_"; + $_ = $Fld[2]; m:(.+?)\+/-(.+),:; + $lower_bound = $1 - $2; + $upper_bound = $1 + $2; + $line .= "$1 $lower_bound $upper_bound"; + $min_offs = min($min_offs, $lower_bound); + $max_offs = max($max_offs, $upper_bound); + $_ = $Fld[4]; s/,/ /; $rms = $_; + $min_rms = min($min_rms, $rms); + $max_rms = max($max_rms, $rms); + $line .= " $rms"; + $_ = $Fld[6]; m:(.+?)\+/-(.+),:; + $line .= " $1 " . ($1-$2) . " " . ($1+$2); + $line .= " $Fld[8]"; + print OUTPUT "$line\n"; + $day_out = 1; +# 9621 216 856106 -17935.5 1730147.5 117239.8 67.52 57.185 77.855 4.850 + } + close INPUT; + close OUTPUT or die "close failed on $out_file: $!"; + my $ylimit = "["; + if ($min_offs < -$offset_limit) { + $ylimit .= "-$offset_limit"; + } + $ylimit .= ":"; + if ($max_offs > $offset_limit) { + $ylimit .= "$offset_limit"; + } + if ( $ylimit eq "[:" ) { + $ylimit = ""; + } else { + $ylimit = "[] $ylimit]"; + } + open OUTPUT, "> $cmd_file" or die "$cmd_file: $!"; + my $oldfh = select OUTPUT; + print "set term $gnuplot_terminal\n"; + open_output; + print "set grid\n"; + print "set title \"Loop Summary for $identifier: " . + "Daily mean values since $first_day\\n" . + "(Offset limit is $offset_limit microseconds)\"\n"; + print "set ylabel \"[us]\"\n"; + print "set data style yerrorbars\n"; + print "set multiplot\n"; + print "set size 1, 0.5\n"; + print "set lmargin 8\n"; + print "set origin 0, 0.5\n"; + print "plot $ylimit \"$out_file\"" . + " using 1:3:4:5 title \"mean offset\", "; + print "\"$out_file\" using 1:(\$3-\$6/2) " . + "title \"(sigma low)\" with lines, "; + print "\"$out_file\" using 1:3 smooth bezier " . + "title \"(Bezier med)\" with lines, "; + print "\"$out_file\" using 1:(\$3+\$6/2) " . + "title \"(sigma high)\" with lines\n"; + print "set ylabel \"[ppm]\"\n"; + print "set origin 0, 0.0\n"; + print "set title\n"; + print "set xlabel \"Days relative to 1970\"\n"; + print "plot \"$out_file\" using 1:7:8:9 title \"mean frequency\", "; + print "\"$out_file\" using 1:(\$7-\$10/2) " . + "title \"(sigma low)\" with lines, "; + print "\"$out_file\" using 1:7 smooth bezier " . + "title \"(Bezier med)\" with lines, "; + print "\"$out_file\" using 1:(\$7+\$10/2) " . + "title \"(sigma high)\" with lines\n"; + print "set nomultiplot\n"; + maybe_add_pause; + + my $ylimit = "["; + if ($min_rms < -$offset_limit) { + $ylimit .= "-$offset_limit"; + } + $ylimit .= ":"; + if ($max_rms > $offset_limit) { + $ylimit .= "$offset_limit"; + } + if ( $ylimit eq "[:" ) { + $ylimit = ""; + } else { + $ylimit = "[] $ylimit]"; + } + + open_output; + print "set title \"Loop Summary for $identifier: " . + "Standard deviation since $first_day\\n" . + "(Offset limit is $offset_limit microseconds)\"\n"; + print "set xlabel\n"; + print "set ylabel \"[us]\"\n"; + print "set origin 0, 0.5\n"; + print "set data style linespoints\n"; + print "set multiplot\n"; + print "plot $ylimit \"$out_file\" using 1:6 title \"Offset\", "; + print "\"$out_file\" using 1:6 smooth bezier " . + "title \"(Bezier)\" with lines\n"; + print "set title\n"; + print "set origin 0, 0.0\n"; + print "set xlabel \"Days relative to 1970\"\n"; + print "set ylabel \"[ppm]\"\n"; + print "plot \"$out_file\" using 1:10 title \"Frequency\", "; + print "\"$out_file\" using 1:10 smooth bezier " . + "title \"(Bezier)\" with lines\n"; + print "set nomultiplot\n"; + maybe_add_pause; + + close OUTPUT or die "close failed on $cmd_file: $!"; + select $oldfh; + print `gnuplot $cmd_file`; + unlink $cmd_file; + unlink $out_file; +} + +# plot data form peer summary +sub do_peer +{ + my $fname = shift; + my $peer = shift; + my $out_file = "/tmp/tempdata$$"; + my $cmd_file = "/tmp/tempcmd$$"; + my $line; + my ($first_day, $day_out) = ("", 0); + open INPUT, "$fname" or die "$fname: $!"; + open OUTPUT, ">$out_file" or die "$out_file: $!"; + my @Fld; + while () { + chop; # strip record separator + @Fld = split; + if ($#Fld == 0) { +# peers.19960405 + $_ = $Fld[0]; s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; + m/(\d{4})(\d{2})(\d{2})/ or next; + $line = timegm (59, 59, 23, $3, $2 - 1, $1 - 1900, 0, 0, 0); + $line = int $line / 86400; # days relative to 1970 + $first_day = "$1-$2-$3 ($line)" unless $day_out; + next; + } + if ($#Fld != 7) { + warn "Illegal number of fields in file $fname, line $."; + next; + } + next if ($Fld[0] ne $peer); +# ident cnt mean rms max delay dist disp +# 127.127.8.1 38 30.972 189.867 1154.607 0.000 879.760 111.037 + $Fld[0] = $line; + print OUTPUT join(' ', @Fld) . "\n"; +# 9969 38 30.972 189.867 1154.607 0.000 879.760 111.037 + $day_out = 1; + } + close INPUT; + close OUTPUT or die "close failed on $out_file: $!"; + die "no data found for peer $peer" if !$day_out; + open OUTPUT, "> $cmd_file" or die "$cmd_file: $!"; + my $oldfh = select OUTPUT; + print "set term $gnuplot_terminal\n"; + open_output; + print "set grid\n"; + print "set multiplot\n"; + print "set lmargin 8\n"; + print "set size 1, 0.34\n"; + print "set origin 0, 0.66\n"; + print "set title " . + "\"Peer Summary for $peer on $identifier since $first_day\"\n"; + print "set data style linespoints\n"; + print "set ylabel \"[us]\"\n"; + print "plot \"$out_file\" using 1:3 title \"mean offset\", "; + print "\"$out_file\" using 1:3 smooth bezier " . + "title \"(Bezier)\" with lines, "; + print "\"$out_file\" using 1:(\$3-\$7/2) " . + "title \"(sigma low)\" with lines, "; + print "\"$out_file\" using 1:(\$3+\$7/2) " . + "title \"(sigma high)\" with lines\n"; + print "set title\n"; + print "set origin 0, 0.34\n"; + print "set size 1, 0.32\n"; + print "set ylabel\n"; + print "plot \"$out_file\" using 1:7 title \"dist\", "; + print "\"$out_file\" using 1:7 smooth bezier " . + "title \"(Bezier)\" with lines\n"; + print "set origin 0, 0.00\n"; + print "set size 1, 0.35\n"; + print "set xlabel \"Days relative to 1970\"\n"; + print "plot \"$out_file\" using 1:8 title \"disp\", "; + print "\"$out_file\" using 1:8 smooth bezier " . + "title \"(Bezier)\" with lines\n"; + print "set nomultiplot\n"; + maybe_add_pause; + + select $oldfh; + close OUTPUT or die "close failed on $cmd_file: $!"; + print `gnuplot $cmd_file`; + unlink $cmd_file; + unlink $out_file; +} + + +my $loop_summary ="$summary_dir/loop_summary"; +my $peer_summary ="$summary_dir/peer_summary"; +my $clock_summary="$summary_dir/clock_summary"; + +do_loop $loop_summary; +map { do_peer $peer_summary, $_ } @peer_list; diff --git a/contrib/ntp/scripts/rc1/postinstall b/contrib/ntp/scripts/rc1/postinstall new file mode 100644 index 000000000000..d84b8c517211 --- /dev/null +++ b/contrib/ntp/scripts/rc1/postinstall @@ -0,0 +1,2 @@ +#!/bin/sh +/etc/init.d/xntp start diff --git a/contrib/ntp/scripts/rc1/preinstall b/contrib/ntp/scripts/rc1/preinstall new file mode 100644 index 000000000000..aa18639c2fe6 --- /dev/null +++ b/contrib/ntp/scripts/rc1/preinstall @@ -0,0 +1,6 @@ +#!/bin/sh +if [ -x /etc/init.d/xntp ] +then + /etc/init.d/xntp stop +fi +exit 0 diff --git a/contrib/ntp/scripts/rc1/preremove b/contrib/ntp/scripts/rc1/preremove new file mode 100644 index 000000000000..b870151a27b4 --- /dev/null +++ b/contrib/ntp/scripts/rc1/preremove @@ -0,0 +1,4 @@ +#!/bin/sh +/etc/init.d/xntp stop + +exit 0 diff --git a/contrib/ntp/scripts/rc1/prototype b/contrib/ntp/scripts/rc1/prototype new file mode 100644 index 000000000000..3de20b076b8c --- /dev/null +++ b/contrib/ntp/scripts/rc1/prototype @@ -0,0 +1,19 @@ +!default 755 root bin +i pkginfo +i preinstall +i postinstall +i preremove +f none /etc/init.d/xntp=xntp 0755 root other +l none /etc/rc2.d/S79xntp=/etc/init.d/xntp +l none /etc/rc1.d/K79xntp=/etc/init.d/xntp +l none /etc/rc0.d/K79xntp=/etc/init.d/xntp +f none /usr/sbin/xntpd=xntpd/xntpd 0555 root other +f none /usr/sbin/xntpdc=xntpdc/xntpdc 0555 root other +f none /usr/sbin/ntpq=ntpq/ntpq 0555 root other +f none /usr/sbin/ntptrace=ntptrace/ntptrace 0555 root other +f none /usr/sbin/ntpdate=ntpdate/ntpdate 0555 root other +f none /usr/share/man/man1m/xntpd.1m=doc/xntpd.8 0444 root other +f none /usr/share/man/man1m/xntpdc.1m=doc/xntpdc.8 0444 root other +f none /usr/share/man/man1m/ntpdate.1m=doc/ntpdate.8 0444 root other +f none /usr/share/man/man1m/ntpq.1m=doc/ntpq.8 0444 root other +f none /usr/share/man/man1m/ntptrace.1m=doc/ntptrace.8 0444 root other diff --git a/contrib/ntp/scripts/rc1/xntp b/contrib/ntp/scripts/rc1/xntp new file mode 100644 index 000000000000..227b943aaa2e --- /dev/null +++ b/contrib/ntp/scripts/rc1/xntp @@ -0,0 +1,29 @@ +#!/bin/sh + +killproc() { # kill named processes + pid=`/usr/bin/ps -e | + /usr/bin/grep $1 | + /usr/bin/sed -e 's/^ *//' -e 's/ .*//'` + [ "$pid" != "" ] && kill $pid +} + +case "$1" in +'start') + ps -e | grep xntpd > /dev/null 2>&1 + if [ $? -eq 0 ] + then + echo "ntp daemon already running. ntp start aborted" + exit 0 + fi + if [ -f /etc/inet/ntp.conf -a -x /usr/sbin/xntpd ] + then + /usr/sbin/xntpd -c /etc/inet/ntp.conf + fi + ;; +'stop') + killproc xntpd + ;; +*) + echo "Usage: /etc/init.d/xntp { start | stop }" + ;; +esac diff --git a/contrib/ntp/scripts/rc2/local.ntpd b/contrib/ntp/scripts/rc2/local.ntpd new file mode 100644 index 000000000000..ba53e05adbbb --- /dev/null +++ b/contrib/ntp/scripts/rc2/local.ntpd @@ -0,0 +1,64 @@ +#! /usr/bin/perl -w +# 980904 Harlan Stenn - created + +# vvv CHANGE THESE vvv + +$ps = "/bin/ps x |"; + +$ntp_conf = "/etc/ntp.conf"; +$ntpd = "/usr/local/bin/xntpd"; +$ntpdate = "/usr/local/bin/ntpdate -b -s 10.0.0.1 10.0.0.2"; + +# ^^^ CHANGE THESE ^^^ + +{ + if (0) + { + } + elsif ($ARGV[0] eq "start") + { + @pidlist = pidlist($ntpd); + if (defined(@pidlist)) + { + warn "NTP is already running\n"; + } + else + { + if ( -f $ntp_conf && -x $ntpd ) + { + system ($ntpdate); + system ($ntpd." -c ".$ntp_conf); + } + } + } + elsif ($ARGV[0] eq "stop") + { + @pidlist = pidlist($ntpd); + kill 'TERM', @pidlist if (scalar(@pidlist) > 0); + } + else + { + die "Usage: $0 {start,stop}\n"; + } +} + +sub pidlist ($) + { + my ($target) = @_; + my ($qt) = quotemeta($target); + my @pids; + + open(PS, $ps) || die "Can't run ps: $!\n"; + while () + { + chomp; + next unless (/$qt/); + print "Got <$_>\n"; + if (/^\s*(\d+)\s+/) + { + push @pids, $1; + } + } + close(PS); + return @pids; + } diff --git a/contrib/ntp/scripts/stats.ulrich.patches b/contrib/ntp/scripts/stats.ulrich.patches new file mode 100644 index 000000000000..fe642f60acd3 --- /dev/null +++ b/contrib/ntp/scripts/stats.ulrich.patches @@ -0,0 +1,1003 @@ + +Received: from huey2.ee.udel.edu by mail.eecis.udel.edu id aa25207; + 10 Dec 1997 10:39 EST +Received: from copland.udel.edu by huey.udel.edu id aa16958; + 10 Dec 1997 10:39 EST +Received: from rrzs2.rz.uni-regensburg.de (rrzs2.rz.uni-regensburg.de [132.199.1.2]) by copland.udel.edu (8.8.5/8.7.3) with ESMTP id KAA21293 for ; Wed, 10 Dec 1997 10:39:12 -0500 (EST) +Received: from ngate.ngate.uni-regensburg.de (ngate.rz.uni-regensburg.de [132.199.3.13]) + by rrzs2.rz.uni-regensburg.de (8.8.5/8.8.5) with SMTP id QAA19974 + for ; Wed, 10 Dec 1997 16:38:42 +0100 (MET) +Received: from rkdvmks1.ngate.uni-regensburg.de by ngate.ngate.uni-regensburg.de; Wed, 10 Dec 97 16:39 MET +Received: from rkdvmks1.ngate.uni-regensburg.de by kgate.ngate.uni-regensburg.de; Wed, 10 Dec 97 15:38 GMT +Received: from RKDVMKS1/SpoolDir by rkdvmks1.ngate.uni-regensburg.de (Mercury 1.32); + 10 Dec 97 16:38:34 +0100 +Received: from SpoolDir by RKDVMKS1 (Mercury 1.32); 10 Dec 97 16:38:06 +0100 +From: Ulrich Windl +Organization: Universitaet Regensburg, Klinikum +To: mills@udel.edu +Date: Wed, 10 Dec 1997 16:38:04 +0100 +MIME-Version: 1.0 +Content-Type: text/plain; charset=US-ASCII +Content-transfer-encoding: 7BIT +Subject: Big patch to scripts/monitoring +Priority: normal +X-mailer: Pegasus Mail for Windows (v2.53/R1) +Message-ID: <103AB9D209F5@rkdvmks1.ngate.uni-regensburg.de> + +Dave, there's another big patch against scripts/monitoring. The Perl +programs in there are rather old. As they are quite nice thogh, I +decided to update them for the latest version of Perl, namely 5.004. + +I'll include the description of changes and the patch. + +Ulrich + +Here is a description of changes made in ntploopwatch: + +Corrected most warnings that PERL 5.004 might emit. Corrected signal +handlers to make them work again. Corrected scaling (at least I +think). Supported case when output is sent to file or printer and +there is no X11 available. Fixed number of month in xlabels of the +plot. + +Added the ability to specify printer for GNUplot other that +PostScript. Use hostname if $STATHOST is not given in configuration +file. Corrected verbosity level for some messages. Added ability to +specify a non-standard print command. + +Perl 5.004_04 does no longer ignore ``-w--*-perl-*-''. Made some +cosmetic changes and added a timescale of 10 minutes. + +(Other programs are functionally unchanged. lr.pl is a PERL module now.) + + +Index: README +=================================================================== +RCS file: /home/windl/NTP/mon-REP/monitoring/README,v +retrieving revision 1.1.1.1 +retrieving revision 1.2 +diff -u -r1.1.1.1 -r1.2 +--- README 1993/08/24 19:29:34 1.1.1.1 ++++ README 1997/10/23 17:51:37 1.2 +@@ -1,14 +1,14 @@ + 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. ++WARNING: The scripts and routines contained in this directory are beta ++ release! 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 ++INCREASE THE NETWORK LOAD SIGNIFICANTLY + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +@@ -23,8 +23,8 @@ + 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. ++ also accept v2 requests. It will not interpret v3 system and ++ peer stati correctly. + + usage: + ntptrap [-n] [-p ] [-l ] servers... +@@ -72,7 +72,9 @@ + + if a timeout occurs the next sample is tried after delay/2 seconds + +- The script will terminate after MAX_FAIL (currently 60) consecutive errors. ++ The script will terminate after MAX_FAIL (currently 60) ++ consecutive errors. ++ + Errors are counted for: + - error on send call + - error on select call +@@ -114,10 +116,10 @@ + 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 ++ 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 + +@@ -139,8 +141,10 @@ + 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) ++ ++ 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.. +Index: lr.pl +=================================================================== +RCS file: /home/windl/NTP/mon-REP/monitoring/lr.pl,v +retrieving revision 1.1.1.1 +retrieving revision 1.4 +diff -u -r1.1.1.1 -r1.4 +--- lr.pl 1993/08/24 19:29:33 1.1.1.1 ++++ lr.pl 1997/10/23 17:51:37 1.4 +@@ -9,9 +9,14 @@ + ;# Frank Kardel, Rainer Pruy + ;# Friedrich-Alexander Universitaet Erlangen-Nuernberg + ;# ++;# Copyright (c) 1997 by ++;# Ulrich Windl ++;# (Converted to a PERL 5.004 package) + ;# + ;############################################################# + ++package lr; ++ + ## + ## y = A + Bx + ## +@@ -23,123 +28,124 @@ + ## + ## 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); ++;# init(tag); initialize data set for tag ++;# sample(x, y, tag); enter sample ++;# Y(x, tag); compute y for given x ++;# X(y, tag); compute x for given y ++;# r(tag); regression coefficient ++;# cov(tag); covariance ++;# A(tag); ++;# B(tag); ++;# sigma(tag); standard deviation ++;# 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 ++sub init + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- $lr_n = 0; +- $lr_sx = 0.0; +- $lr_sx2 = 0.0; +- $lr_sxy = 0.0; +- $lr_sy = 0.0; +- $lr_sy2 = 0.0; ++ $self->{n} = 0; ++ $self->{sx} = 0.0; ++ $self->{sx2} = 0.0; ++ $self->{sxy} = 0.0; ++ $self->{sy} = 0.0; ++ $self->{sy2} = 0.0; + } + +-sub lr_sample ++sub sample($$$) + { +- local($_x, $_y) = @_; +- +- &tagify($_[$[+2]) if defined($_[$[+2]); ++ my $self = shift; ++ my($_x, $_y) = @_; + +- $lr_n++; +- $lr_sx += $_x; +- $lr_sy += $_y; +- $lr_sxy += $_x * $_y; +- $lr_sx2 += $_x**2; +- $lr_sy2 += $_y**2; ++ ++($self->{n}); ++ $self->{sx} += $_x; ++ $self->{sy} += $_y; ++ $self->{sxy} += $_x * $_y; ++ $self->{sx2} += $_x**2; ++ $self->{sy2} += $_y**2; + } + +-sub lr_B ++sub B($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- 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); ++ return 1 unless ($self->{n} * $self->{sx2} - $self->{sx}**2); ++ return ($self->{n} * $self->{sxy} - $self->{sx} * $self->{sy}) ++ / ($self->{n} * $self->{sx2} - $self->{sx}**2); + } + +-sub lr_A ++sub A($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return ($lr_sy - &lr_B * $lr_sx) / $lr_n; ++ return ($self->{sy} - B($self) * $self->{sx}) / $self->{n}; + } + +-sub lr_Y ++sub Y($$) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return &lr_A + &lr_B * $_[$[]; ++ return A($self) + B($self) * $_[$[]; + } + +-sub lr_X ++sub X($$) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return ($_[$[] - &lr_A) / &lr_B; ++ return ($_[$[] - A($self)) / B($self); + } + +-sub lr_r ++sub r($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- local($s) = ($lr_n * $lr_sx2 - $lr_sx**2) * ($lr_n * $lr_sy2 - $lr_sy**2); ++ my $s = ($self->{n} * $self->{sx2} - $self->{sx}**2) ++ * ($self->{n} * $self->{sy2} - $self->{sy}**2); + + return 1 unless $s; + +- return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / sqrt($s); ++ return ($self->{n} * $self->{sxy} - $self->{sx} * $self->{sy}) / sqrt($s); + } + +-sub lr_cov ++sub cov($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return ($lr_sxy - $lr_sx * $lr_sy / $lr_n) / ($lr_n - 1); ++ return ($self->{sxy} - $self->{sx} * $self->{sy} / $self->{n}) ++ / ($self->{n} - 1); + } + +-sub lr_sigma ++sub sigma($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return 0 if $lr_n <= 1; +- return sqrt(($lr_sy2 - ($lr_sy * $lr_sy) / $lr_n) / ($lr_n)); ++ return 0 if $self->{n} <= 1; ++ return sqrt(($self->{sy2} - ($self->{sy} * $self->{sy}) / $self->{n}) ++ / ($self->{n})); + } + +-sub lr_mean ++sub mean($) + { +- &tagify($_[$[]) if defined($_[$[]); ++ my $self = shift; + +- return 0 if $lr_n <= 0; +- return $lr_sy / $lr_n; ++ return 0 if $self->{n} <= 0; ++ return $self->{sy} / $self->{n}; + } + +-&lr_init(); ++sub new ++{ ++ my $class = shift; ++ my $self = { ++ (n => undef, ++ sx => undef, ++ sx2 => undef, ++ sxy => undef, ++ sy => undef, ++ sy2 => undef) ++ }; ++ bless $self, $class; ++ init($self); ++ return $self; ++} + + 1; +Index: ntp.pl +=================================================================== +RCS file: /home/windl/NTP/mon-REP/monitoring/ntp.pl,v +retrieving revision 1.1.1.1 +retrieving revision 1.3 +diff -u -r1.1.1.1 -r1.3 +--- ntp.pl 1993/08/24 19:29:34 1.1.1.1 ++++ ntp.pl 1997/10/23 18:19:41 1.3 +@@ -1,4 +1,4 @@ +-#!/local/bin/perl ++#!/usr/bin/perl -w + ;# + ;# ntp.pl,v 3.1 1993/07/06 01:09:09 jbj Exp + ;# +@@ -43,7 +43,7 @@ + ;# N key + ;# N2 checksum + +-;# first bye of packet ++;# first byte of packet + sub pkt_LI { return ($_[$[] >> 6) & 0x3; } + sub pkt_VN { return ($_[$[] >> 3) & 0x7; } + sub pkt_MODE { return ($_[$[] ) & 0x7; } +@@ -223,6 +223,7 @@ + { + &getval(&psw_PSel($_[$[]),*PeerSelection); + } ++ + sub PeerEvent + { + &getval(&psw_PCode($_[$[]),*PeerEvent); +@@ -394,14 +395,14 @@ + $lastseen = 1 if !&pkt_M($r_e_m_op); + if (!defined(%FRAGS)) + { +- (&pkt_M($r_e_m_op) ? " more" : "")."\n"; ++ print((&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"; ++ print((&pkt_M($r_e_m_op) ? " more" : "")."\n"); + ;# add frag to previous - combine on the fly + if (defined($FRAGS{$offset})) + { +Index: ntploopstat +=================================================================== +RCS file: /home/windl/NTP/mon-REP/monitoring/ntploopstat,v +retrieving revision 1.1.1.1 +retrieving revision 1.3 +diff -u -r1.1.1.1 -r1.3 +--- ntploopstat 1993/08/24 19:29:32 1.1.1.1 ++++ ntploopstat 1997/11/23 19:07:12 1.3 +@@ -1,4 +1,5 @@ +-#!/local/bin/perl -w--*-perl-*- ++#!/usr/bin/perl -w ++# --*-perl-*- + ;# + ;# ntploopstat,v 3.1 1993/07/06 01:09:11 jbj Exp + ;# +@@ -22,7 +23,7 @@ + ;# (Should have implemented &gettimeofday()..) + ;# + +-$0 =~ s!^.*/([^/]+)$!\1!; # beautify script name ++$0 =~ s!^.*/([^/]+)$!$1!; # beautify script name + + $ntpserver = 'localhost'; # default host to poll + $delay = 60; # default sampling rate +Index: ntploopwatch +=================================================================== +RCS file: /home/windl/NTP/mon-REP/monitoring/ntploopwatch,v +retrieving revision 1.1.1.1 +retrieving revision 1.14 +diff -u -r1.1.1.1 -r1.14 +--- ntploopwatch 1993/10/22 14:28:18 1.1.1.1 ++++ ntploopwatch 1997/12/07 17:06:36 1.14 +@@ -1,4 +1,5 @@ +-#!/local/bin/perl -w--*-perl-*- ++#!/usr/bin/perl -w ++#--*-perl-*- + ;# + ;# ntploopwatch,v 3.1 1993/07/06 01:09:13 jbj Exp + ;# +@@ -9,12 +10,17 @@ + ;# Copyright (c) 1992 + ;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg + ;# ++;# Copyright (c) 1997 ++;# Ulrich Windl ++;# (Corrections for Perl5 and other fixes) + ;# + ;############################################################# +-$0 =~ s!^.*/([^/]+)$!\1!; ++$0 =~ s!^.*/([^/]+)$!$1!; + $F = ' ' x length($0); + $|=1; + ++use 5.004; # require 5.004 ++ + $ENV{'SHELL'} = '/bin/sh'; # use bourne shell + + undef($config); +@@ -23,17 +29,17 @@ + undef($samples); + undef($StartTime); + undef($EndTime); +-($a,$b) if 0; # keep -w happy ++ + $usage = <<"E-O-P"; + usage: +- to watch statistics permanently: ++ to watch statistics periodically: + $0 [-v[]] [-c ] [-d ] + $F [-h ] + + to get a single print out specify also +- $F -P[] [-s] +- $F [-S ] [-E ] +- $F [-Y ] [-y ] ++ $F -P[[]] ++ $F [-s] [-S ] [-E ] ++ $F [-Y ] [-y ] + + If You like long option names, You can use: + -help +@@ -41,21 +47,28 @@ + -d +directory + -h +host + -v +verbose[=] +- -P +printer[=] ++ -P +printer[=[:][:]] + -s +samples[=] + -S +starttime + -E +endtime + -Y +maxy + -y +miny + ++If is prefixed with a and a colon, the ++given is used as terminal fpr gnuplot. + If contains a '/' (slash character) output is directed to + a file of this name instead of delivered to a printer. ++If suffix : is given, the suffix is used as the print command, ++and is ignored. If blanks are needed inside or ++, just use underscores instead. + 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 ++my $lr_offs = new lr; ++my $lr_freq = new lr; + + $MJD_1970 = 40587; # from ntp.h (V3) + $RecordSize = 48; # usually a line fits into 42 bytes +@@ -171,16 +184,20 @@ + + ;# configuration file + $config = "loopwatch.config" unless defined($config); +-($STATHOST = $config) =~ s!.*loopwatch\.config.([^/\.]*)$!\1! ++($STATHOST = $config) =~ s!.*loopwatch\.config.([^/\.]+)$!$1! + unless defined($STATHOST); +-($STATTAG = $STATHOST) =~ s/^([^\.\*\s]+)\..*$/\1/; ++if ($STATHOST eq $config) { ++ require "hostname.pl"; ++ $STATHOST = hostname(); ++} ++($STATTAG = $STATHOST) =~ s/^([^\.\*\s]+)\..*$/$1/; + + $srcprefix =~ s/\$STATHOST/$STATHOST/g; + + ;# plot command +-@plotcmd=("gnuplot", +- '-title', "Ntp loop filter statistics $STATHOST", +- '-name', "NtpLoopWatch_$STATTAG"); ++@plotcmd=("gnuplot"); ++push(@plotcmd, '-title', "NTP loop filter statistics for $STATHOST", ++ '-name', "NtpLoopWatch_$STATTAG") unless $PrintIt; + $tmpfile = "/tmp/ntpstat.$$"; + + ;# other variables +@@ -211,9 +228,8 @@ + $?>>8,$? & 0xff)) if $?; + exit(1) if $? && defined($Plotpid) && $pid == $Plotpid; + } +-&sigchld if 0; +-$SIG{'CHLD'} = "sigchld"; +-$SIG{'CLD'} = "sigchld"; ++$SIG{'CHLD'} = \&sigchld; ++$SIG{'CLD'} = \&sigchld; + + sub abort + { +@@ -221,8 +237,7 @@ + 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"; ++$SIG{'INT'} = $SIG{'HUP'} = $SIG{'QUIT'} = $SIG{'TERM'} = $SIG{'PIPE'} = \&abort; + + ;# + sub abs +@@ -248,7 +263,7 @@ + open(STDOUT,">&STDERR") || + die("$0: failed to redirect STDOUT of plot command: $!\n"); + +- print STDOUT "plot command running as $$\n"; ++ print STDOUT "plot command has PID $$\n"; + + exec @plotcmd; + die("$0: failed to exec (@plotcmd): $!\n"); +@@ -275,128 +290,83 @@ + s/^([^\#]*[^\#\s]?)\s*\#.*$//; + next if /^\s*$/; + +- s/^\s*([^=\s]*)\s*=\s*(.*\S)\s*$/\1=\2/; ++ s/^\s*([^=\s]*)\s*=\s*(.*\S)\s*$/$1=$2/; + +- ($c,$v) = split(/=/,$_,2); ++ ($c,$v) = ($1, $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 ++ if ($c eq "delay") { ++ $delay = $v; ++ } elsif ($c eq 'samples') { ++ $samples = $v if (!defined($PrintIt) || !defined($samples)); ++ } elsif ($c eq 'srcprefix') { ++ ($srcprefix = $v) =~ s/\$STATHOST/$STATHOST/g; ++ } elsif ($c eq 'showoffs') { ++ $showoffs = ($v =~ /^yes$|^y$|^1$/); ++ } elsif ($c eq 'showfreq') { ++ $showfreq = ($v =~ /^yes$|^y$|^1$/); ++ } elsif ($c eq 'showcmpl') { ++ $showcmpl = ($v =~ /^yes$|^y$|^1$/); ++ } elsif ($c eq 'showoreg') { ++ $showoreg = ($v =~ /^yes$|^y$|^1$/); ++ } elsif ($c eq 'showfreg') { ++ $showfreg = ($v =~ /^yes$|^y$|^1$/); ++ } elsif ($c eq 'exit') { ++ unlink($tmpfile); die("$0: exit by config request\n"); ++ } elsif ($c eq 'freqbase' || $c eq 'cmplscale') { ++ if (! defined($v) || $v eq "" || $v eq 'dynamic') { ++ eval "undef(\$$c);"; ++ } else { ++ eval "\$$c = \$v;"; ++ } ++ } elsif ($c eq 'timebase') { ++ if (! defined($v) || $v eq "" || $v eq "dynamic") { ++ undef($timebase); ++ } else { ++ $timebase=&date_time_spec2seconds($v); ++ } ++ } elsif ($c eq 'EndTime') { ++ next if defined($EndTime) && defined($PrintIt); ++ if (! defined($v) || $v eq "" || $v eq "none") { ++ undef($EndTime); ++ } else { ++ $EndTime=&date_time_spec2seconds($v); ++ } ++ } elsif ($c eq 'StartTime') { ++ next if defined($StartTime) && defined($PrintIt); ++ if (! defined($v) || $v eq "" || $v eq "none") { ++ undef($StartTime); ++ } else { ++ $StartTime=&date_time_spec2seconds($v); ++ } ++ } elsif ($c eq 'MaxY') { ++ next if defined($MaxY) && defined($PrintIt); ++ if (! defined($v) || $v eq "" || $v eq "none") { ++ undef($MaxY); ++ } else { ++ $MaxY=$v; ++ } ++ } elsif ($c eq 'MinY') { ++ next if defined($MinY) && defined($PrintIt); ++ if (! defined($v) || $v eq "" || $v eq "none") { ++ undef($MinY); ++ } else { ++ $MinY=$v; ++ } ++ } elsif ($c eq 'deltaT') { ++ if (!defined($v) || $v eq "") { ++ undef($deltaT); ++ } else { ++ $deltaT = $v; ++ } ++ } elsif ($c eq 'verbose' && ! defined($PrintIt)) { ++ if (!defined($v) || $v == 0) { ++ $verbose = 0; ++ } else { ++ $verbose = $v; ++ } ++ } else { ++ ;# otherwise: silently ignore unrecognized config line ++ } + } + close(CF); + ;# set show defaults when nothing selected +@@ -413,16 +383,16 @@ + 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"; ++ 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; ++ print "configuration file read\n" if $verbose > 2; + } + + sub make_doplot +@@ -443,10 +413,9 @@ + ;# 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) ++ foreach $i (30, 60, ++ 5*60, 10*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); +@@ -458,31 +427,30 @@ + $i <= $maxtime + $t; + $i += $t, $c=",") + { ++ my ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime($i); ++ + $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))) ++ $hour, $min, $sec, ($i - $LastTimeBase) / 3600))) + || (($t <= 2*60*60) && + ($s .= sprintf("'%d:%02d' %lf", +- (localtime($i))[$[+2,$[+1], +- ($i - $LastTimeBase)/3600))) ++ $hour, $min, ($i - $LastTimeBase) / 3600))) + || (($t <= 12*60*60) && + ($s .= sprintf("'%s %d:00' %lf", +- $Day[(localtime($i))[$[+6]], +- (localtime($i))[$[+2], +- ($i - $LastTimeBase)/3600))) ++ $Day[$wday], $hour, ++ ($i - $LastTimeBase) / 3600))) + || ($s .= sprintf("'%d.%d-%d:00' %lf", +- (localtime($i))[$[+3,$[+4,$[+2], +- ($i - $LastTimeBase)/3600)); ++ $mday, $mon + 1, $hour, ++ ($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 xlabel 'Start: $xts -- Time Scale -- End: $xte'\n"; + $doplot .= "set yrange [" ; + $doplot .= defined($MinY) ? sprintf("%lf", $MinY) : $miny; + $doplot .= ':'; +@@ -518,22 +486,22 @@ + $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'), ++ $lr_offs->B(),$lr_offs->A(), ++ "offset", ++ $lr_offs->B(), ++ (($lr_offs->A()) < 0 ? '-' : '+'), ++ &abs($lr_offs->A()), $lr_offs->r(), + "[ms]"), + $c = ","); + $showfreg && $showfreq && + ($doplot .= sprintf($regfmt, $c, +- &lr_B('freq') * $FreqScale, +- (&lr_A('freq') + $minfreq) * $FreqScale - $LastFreqBase, ++ $lr_freq->B() * $FreqScale, ++ ($lr_freq->A() + $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'), ++ $lr_freq->B() * $FreqScale, ++ (($lr_freq->A() + $minfreq) * $FreqScale - $LastFreqBase) < 0 ? '-' : '+', ++ &abs(($lr_freq->A() + $minfreq) * $FreqScale - $LastFreqBase), ++ $lr_freq->r(), + "[${FreqScaleInv}ppm]"), + $c = ","); + $doplot .= "\n"; +@@ -583,7 +551,7 @@ + $#loffset = $[ - 1; + $#filekey = $[ - 1; + print "memory allocation ready\n" if $verbose > 2; +- sleep(3) if $verbose > 1; ++ sleep(3) if $verbose > 2; + + if (index($in,"/") < $[) + { +@@ -606,7 +574,6 @@ + ;# rescan directory on changes + $Lsdir = $sdir; + $Ltime = (stat($sdir))[$[+9]; +- if 0; # dummy line - calm down my formatter + local(@newfiles) = < ${in}*[0-9] >; + local($st_dev,$st_ino,$st_mtime,$st_size,$name,$key,$modified); + +@@ -626,7 +593,7 @@ + $F_key{$name} = $key; + $modified++; + } +- if (!defined($F_name{$key}) || $F_name{$key} != $name) ++ if (!defined($F_name{$key}) || $F_name{$key} ne $name) + { + $F_name{$key} = $name; + $modified++; +@@ -643,9 +610,9 @@ + } + if ($modified) + { +- print "new data \"$name\" key: $key;\n" if $verbose > 1; ++ print "new data \"$name\" key: $key;\n" if $verbose > 2; + print " size: $st_size; mtime: $st_mtime;\n" +- if $verbose > 1; ++ if $verbose > 2; + $F_last{$key} = $F_first{$key} = $st_mtime; + $F_first{$key}--; # prevent zero divide later on + ;# now compute derivated attributes +@@ -692,7 +659,7 @@ + } + close(IN); + print(" first: ",$F_first{$key}, +- " last: ",$F_last{$key},"\n") if $verbose > 1; ++ " last: ",$F_last{$key},"\n") if $verbose > 2; + } + } + ;# now reclaim memory used for files no longer referenced ... +@@ -739,7 +706,7 @@ + } + ;# create list sorted by time + @F_files = sort {$F_first{$a} <=> $F_first{$b}; } keys(%F_name); +- if ($verbose > 1) ++ if ($verbose > 2) + { + print "Resulting file list:\n"; + foreach (@F_files) +@@ -797,7 +764,7 @@ + print "guess start according to StartTime ($StartTime)\n" + if $verbose > 3; + +- if ($fpos[$[] eq 'start') ++ if (defined $fpos[$[] && $fpos[$[] eq 'start') + { + if (grep($_ eq $fpos[$[+1],@f)) + { +@@ -1001,9 +968,9 @@ + $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/(\d*)\.(\d{3})(\d*)/$1$2.$3/) && + $F[$[+2] =~ s/0+([\d\.])/($1 eq '.') ? '0.' : $1/e) # strip leading zeros +- || $F[$[+2] *= 1000; ++ || ($F[$[+2] *= 1000); + + + ;# skip samples out of specified time range +@@ -1036,8 +1003,8 @@ + print "input scanned ($l lines/",scalar(@time)," samples)\n" + if $verbose > 1; + +- &lr_init('offs'); +- &lr_init('freq'); ++ $lr_offs->init(); ++ $lr_freq->init(); + + if (@time) + { +@@ -1047,17 +1014,17 @@ + local($freqbase) unless defined($freqbase); + local($cmplscale) unless defined($cmplscale); + +- undef($mintime,$maxtime,$minoffs,$maxoffs, +- $minfreq,$maxfreq,$mincmpl,$maxcmpl, +- $miny,$maxy); ++ undef $mintime; undef $maxtime; undef $minoffs; undef $maxoffs; ++ undef $minfreq; undef $maxfreq; undef $mincmpl; undef $maxcmpl; ++ undef $miny; undef $maxy; + + print "computing ranges\n" if $verbose > 2; + + $LastCnt = @time; + + ;# @time is in ascending order (;-) +- $mintime = @time[$[]; +- $maxtime = @time[$#time]; ++ $mintime = $time[$[]; ++ $maxtime = $time[$#time]; + unless (defined($timebase)) + { + local($time,@X) = (time); +@@ -1081,24 +1048,24 @@ + ;# (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[$ + diff --git a/contrib/ntp/scripts/stats/README b/contrib/ntp/scripts/stats/README new file mode 100644 index 000000000000..680896342acb --- /dev/null +++ b/contrib/ntp/scripts/stats/README @@ -0,0 +1,39 @@ +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 processes the +daily loopstats, peerstats and clockstats files produced by the daemon, +updates the loop_summary, peer_summary and clock_summary archive files, +and deletes the daily files. + +In the case of the Austron 2201A GPS receiver, the clockstats file +contains a wealth of additional monitoring data. These data are summarized +and writted to the clock_summary file, then a series of special files are +constructed for later processing by the S utility. + +The summary.sh script invokes a number of 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 summary.sh script can produce input files for the S utility, if it +is found on the search path. This utility makes PostScript graphs of the +loopstats data for each day, as well as various statistics produced by +the Austorn 220aA GPS receiver. The S utility is automatically run +as a background job. Its control files have the .S extension. + +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 +Revised 12 April 1994 diff --git a/contrib/ntp/scripts/stats/README.stats b/contrib/ntp/scripts/stats/README.stats new file mode 100644 index 000000000000..aa8e77fb1bbe --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/stats/README.timecodes b/contrib/ntp/scripts/stats/README.timecodes new file mode 100644 index 000000000000..00b5ba54584f --- /dev/null +++ b/contrib/ntp/scripts/stats/README.timecodes @@ -0,0 +1,149 @@ +Radio Timecode Formats (README.timecodes) + +Following are examples of the serial timecode formats used by various +timecode receivers as given in the instruction manuals. These examples +are intended only for illustration and not as the basis of system +design. The following symbols are used to identify the timecode +character that begins a subfield. The values given after this symbol +represent the character offset from the beginning of the timecode string +as edited to remove control characters. + +C on-time character (start bit) +Y year of century +T time of day +D day of year or month/day +A alarm indicator (format specific) +Q quality indicator (format specific) + ASCII line feed (hex 0a) + ASCII carriage return (hex 0d) + ASCII space (hex 20) + +In order to promote uniform behavior in the various implementations, it +is useful to have a common interpretation of alarm conditions and signal +quality. When the alarm indicator it on, the receiver is not operating +correctly or has never synchronized to the broadcast signal. When the +alarm indicator is off and the quality indicator is on, the receiver has +synchronized to the broadcast signal, then lost the signal and is +coasting on its internal oscillator. + +In the following uppercase letters, punctuation marks and spaces +stand for themselves; lowercase letters stand for fields as described. +Special characters other than , and are preceded by ^. + +Spectracom 8170 and Netclock/2 WWV Synchonized Clock (format 0) + +"i ddd hh:mm:ss TZ=zz" + C A D T + + poll: ?; offsets: Y = none, D = 3, T = 7, A = 0, Q = none + i = synchronization flag ( = in synch, ? = out synch) + ddd = day of year + hh:mm:ss = hours, minutes, seconds + zz = timezone offset (hours from UTC) + + Note: alarm condition is indicated by other than at A, which + occurs during initial synchronization and when received signal has + been lost for about ten hours + + example: " 216 15:36:43 TZ=0" + A D T + +Netclock/2 WWV Synchonized Clock (format 2) + +"iqyy ddd hh:mm:ss.fff ld" + C AQY D T + + poll: ?; offsets: Y = 2, D = 5, T = 9, A = 0, Q = 1 + i = synchronization flag ( = in synch, ? = out synch) + q = quality indicator ( < 1ms, A < 10 ms, B < 100 ms, C < 500 + ms, D > 500 ms) + yy = year (as broadcast) + ddd = day of year + hh:mm:ss.fff = hours, minutes, seconds, milliseconds of day + l = leap-second warning (L indicates leap at end of month) + d = standard/daylight time indicator ( standard, D daylight) + + Note: alarm condition is indicated by other than at A, which + occurs during initial synchronization and when received signal has + been lost for about ten hours; unlock condition is indicated by + other than at Q, with time since last lock indicated by the + letter code A < 13 min, B < 1.5 hr, C < 7 hr, D > 7 hr. + + example: " 92 216 15:36:43.640 D" + AQ D T + +TrueTime 468-DC Satellite Synchronized Clock (and other TrueTime +receivers) + +"<^A>ddd:hh:mm:ssq" + D T QC + + poll: none; offsets: Y = none, D = 0, T = 4, A = 12, Q = 12 + hh:mm:ss = hours, minutes, seconds + q = quality/alarm indicator ( = locked, ? = alarm) + + Note: alarm condition is indicated by ? at A, which occurs during + initial synchronization and when received signal is lost for an + extended period; unlock condition is indicated by other than + at Q + + example: "216:15:36:43 " + D T Q + +Heath GC-1000 Most Accurate Clock (WWV/H) + +"hh:mm:ss.f dd/mm/yy" + C T A D + + poll: none; offsets: Y = none, D = 15, T = 0, A = 9, Q = none + hh:mm:ss = hours, minutes, seconds + f = deciseconds (? when out of spec) + dd/mm = day, month + yy = year of century (from DIPswitches) + + Note: 0?:??:??.? is displayed before synch is first established and + hh:mm:ss.? once synch is established and then lost again for about + a day. + + example: "15:36:43.6 04/08/91" + T A D Y + +PST/Traconex 1020 Time Source (WWV/H) (firmware revision V4.01) + +"frdzycchhSSFTttttuuxx" "ahh:mm:ss.fffs" "yy/dd/mm/ddd" + A Q T Y D + + poll: "QMQDQT"; offsets: Y = 0, D = 3 T = 1,, A = 11, Q = 13 + f = frequency enable (O = all frequencies enabled) + r = baud rate (3 = 1200, 6 = 9600) + d = features indicator (@ = month/day display enabled) + z = time zone (0 = UTC) + y = year (5 = 1991) + cc = WWV propagation delay (52 = 22 ms) + hh = WWVH propagation delay (81 = 33 ms) + SS = status (80 or 82 = operating correctly) + F = current receive frequency (1-5 = 2.5, 5, 10, 15, 20 MHz) + T = transmitter (C = WWV, H = WWVH) + tttt = time since last update (minutes) + uu = flush character (03 = ^C) + xx = 94 (unknown) (firmware revision X4.01.999 only) + + a = AM/PM indicator (A = AM, P = PM, - 24-hour format) + hh:mm:ss.fff = hours, minutes, seconds, milliseconds of day + s = daylight-saving indicator ( standard, D daylight) + + yy = year of century (from DIPswitches) + dd/mm/ddd = day of month, month of year, day of year + + Note: The alarm condition is indicated by other than ? at A, which + occurs during initial synchronization and when received signal is + lost for an extended period. A receiver unlock condition is + indicated by other than "0000" in the tttt subfield at Q. + + example: "O3@055281824C00000394 91/08/04/216 15:36:43.640" + T Y D T + +David L. Mills +University of Delaware +mills@udel.edu +23 October 1993 diff --git a/contrib/ntp/scripts/stats/clock.awk b/contrib/ntp/scripts/stats/clock.awk new file mode 100755 index 000000000000..ef62da9ebdc0 --- /dev/null +++ b/contrib/ntp/scripts/stats/clock.awk @@ -0,0 +1,431 @@ +# awk program to scan clockstat files and report errors/statistics +# +# usage: awk -f check.awk clockstats +# +# This program works for the following radios: +# PST/Traconex 1020 WWV reciever +# Arbiter 1088 GPS receiver +# Spectracom 8170/Netclock-2 WWVB receiver +# IRIG audio decoder +# Austron 2200A/2201A GPS receiver (see README.austron file) +# +BEGIN { + etf_min = osc_vmin = osc_tmin = 1e9 + etf_max = osc_vmax = osc_tmax = -1e9 +} +# +# scan all records in file +# +{ + # + # select PST/Traconex WWV records + # 00:00:37.234 96/07/08/190 O6@0:5281825C07510394 + # + if (NF >= 4 && $3 == "127.127.3.1") { + if (substr($6, 14, 4) > "0010") + wwv_sync++ + if (substr($6, 13, 1) == "C") + wwv_wwv++ + if (substr($6, 13, 1) == "H") + wwv_wwvh++ + x = substr($6, 12, 1) + if (x == "1") + wwv_2.5++ + else if (x == "2") + wwv_5++ + else if (x == "3") + wwv_10++ + else if (x == "4") + wwv_15++ + else if (x == "5") + wwv_20++ + continue + } + # + # select Arbiter GPS records + # 96 190 00:00:37.000 0 V=08 S=44 T=3 P=10.6 E=00 + # N39:42:00.951 W075:46:54.880 210.55 2.50 0.00 + # + if (NF >= 4 && $3 == "127.127.11.1") { + if (NF > 8) { + arb_count++ + if ($7 != 0) + arb_sync++ + x = substr($10, 3, 1) + if (x == "0") + arb_0++ + else if (x == "1") + arb_1++ + else if (x == "2") + arb_2++ + else if (x == "3") + arb_3++ + else if (x == "4") + arb_4++ + else if (x == "5") + arb_5++ + else if (x == "6") + arb_6++ + } else if (NF == 8) { + arbn++ + arb_mean += $7 + arb_rms += $7 * $7 + if (arbn > 0) { + x = $7 - arb_val + arb_var += x * x + } + arb_val = $7 + } + continue + } + # + # select Spectracom WWVB records + # see summary for decode + # 96 189 23:59:32.248 D + # + 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 audio decoder records + # see summary for decode + # + if (NF >= 4 && $3 == "127.127.6.0") { + irig_count++ + if ($5 ~ /\?/) + irig_error++ + continue + } + # + # select Austron GPS 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 Austron 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 Austron 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 Austron 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 Austron 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 Austron 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 Austron 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 Austron 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 Austron 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 { +# +# PST/Traconex WWV summary data +# + if (wwv_wwv + wwv_wwvh > 0) + printf "wwv %d, wwvh %d, err %d, MHz (2.5) %d, (5) %d, (10) %d, (15) %d, (20) %d\n", wwv_wwv, wwv_wwvh, wwv_sync, wwv_2.5, wwv_5, wwv_10, wwv_15, wwv_20 +# +# Arbiter 1088 summary data +# +# gps record count +# err error count +# sats(0-6) satellites tracked +# mean 1 PPS mean (us) +# rms 1 PPS rms error (us) +# var 1 PPS Allan variance +# + if (arb_count > 0) { + printf "gps %d, err %d, sats(0-6) %d %d %d %d %d %d %d", arb_count, arb_sync, arb_0, arb_1, arb_2, arb_3, arb_4, arb_5, arb_6 + if (arbn > 1) { + arb_mean /= arbn + arb_rms = sqrt(arb_rms / arbn - arb_mean * arb_mean) + arb_var = sqrt(arb_var / (2 * (arbn - 1))) + printf ", mean %.2f, rms %.2f, var %.2e\n", arb_mean, arb_rms, arb_var * 1e-6 + } else { + printf "\n" + } + } +# +# 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/ntp/scripts/stats/dupe.awk b/contrib/ntp/scripts/stats/dupe.awk new file mode 100755 index 000000000000..317c2a4faf84 --- /dev/null +++ b/contrib/ntp/scripts/stats/dupe.awk @@ -0,0 +1,8 @@ +# +# delete duplicate lines +# +{ + if (old != $0) + printf "%s\n", $0 + old = $0 +} diff --git a/contrib/ntp/scripts/stats/ensemble.S b/contrib/ntp/scripts/stats/ensemble.S new file mode 100755 index 000000000000..32a4dbabb820 --- /dev/null +++ b/contrib/ntp/scripts/stats/ensemble.S @@ -0,0 +1,5 @@ +ensemble <- scan(file1, list(day=0, sec=0, gps=0, gpsw=0, loran=0, loranw=0, ensemble=0, std=0)) +str <- paste("eps/", file1, ".eps", sep="") +postscript(str, , , , 5, pointsize=18) +par(mgp=c(1, 0, 0), tck = 0.03, mar = c(2, 2, 1, 1)) +plot(ensemble$sec, ensemble$ensemble, type="l", xlab=paste("MJD", ensemble$day, "Time (s)"), ylab="Ensemble Offset (ns)", ylim=c(-400, 400)) diff --git a/contrib/ntp/scripts/stats/ensemble.awk b/contrib/ntp/scripts/stats/ensemble.awk new file mode 100755 index 000000000000..136b33da37cb --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/stats/etf.S b/contrib/ntp/scripts/stats/etf.S new file mode 100755 index 000000000000..9b9c68b937b5 --- /dev/null +++ b/contrib/ntp/scripts/stats/etf.S @@ -0,0 +1,15 @@ +options(digits=4) +file2 <- "etf_summary" +etf <- scan(file1, list(day=0, sec=0, offset=0, stab=0)) +r <- lsfit(etf$sec, etf$offset) +count<-length(etf$sec) +mean<-r$coef[[1]] +std<-sqrt(var(r$residuals)) +slope<-r$coef[[2]] * 1000 +cat("\n", file=file2 , append=TRUE, fill=FALSE, sep="") +cat(file1, "\n", file=file2, append=TRUE, fill=FALSE, sep="") +cat("etf1 ", count, ", T ", mean, " ns, R ", slope, " ps/s, std ", std, " us\n", file=file2, append=TRUE, fill=FALSE, sep="") +str <- paste("eps/", file1, ".eps", sep="") +postscript(str, , , , 5, pointsize=18) +par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1)) +plot(etf$sec, etf$offset, type="l", xlab=paste("MJD", etf$day, "Time (s)"), ylab="External Offset (ns)", ylim=c(-400, 400)) diff --git a/contrib/ntp/scripts/stats/etf.awk b/contrib/ntp/scripts/stats/etf.awk new file mode 100755 index 000000000000..8e6e334c1e01 --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/stats/itf.S b/contrib/ntp/scripts/stats/itf.S new file mode 100755 index 000000000000..56c8c8d0cc7a --- /dev/null +++ b/contrib/ntp/scripts/stats/itf.S @@ -0,0 +1,5 @@ +itf <- scan(file1, list(day=0, sec=0, offset=0, stab=0)) +str <- paste("eps/", file1, ".eps", sep="") +postscript(str, , , , 5, pointsize=18) +par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1)) +plot(itf$sec, itf$offset, type="l", xlab=paste("MJD", itf$day, "Time (s)"), ylab="Internal Offset (ns)", ylim=c(-400, 400)) diff --git a/contrib/ntp/scripts/stats/itf.awk b/contrib/ntp/scripts/stats/itf.awk new file mode 100755 index 000000000000..2b21c5b9b97c --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/stats/loop.S b/contrib/ntp/scripts/stats/loop.S new file mode 100755 index 000000000000..8e564b67eb67 --- /dev/null +++ b/contrib/ntp/scripts/stats/loop.S @@ -0,0 +1,7 @@ +options(digits=4) +loop <- scan(file1, list(day=0, sec=0, offset=0, freq=0, tc=0)) +loop$offset <- loop$offset * 1e6 +str <- paste("eps/", file1, ".eps", sep="") +postscript(str, , , , 5, pointsize=18) +par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1)) +plot(loop$sec, loop$offset, type="l", xlab=paste("MJD", loop$day, "Time (s)"), ylab="PLL Offset (us)", ylim=c(-400, 400)) diff --git a/contrib/ntp/scripts/stats/loop.awk b/contrib/ntp/scripts/stats/loop.awk new file mode 100755 index 000000000000..bac90db8b954 --- /dev/null +++ b/contrib/ntp/scripts/stats/loop.awk @@ -0,0 +1,45 @@ +# 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) poll +# 49235 3.943 0.000016 22.4716 6 +# +# format of output dataset (time values in milliseconds, freq in ppm) +# loopstats.19960706 +# loop 1180, 0+/-11.0, rms 2.3, freq -24.45+/-0.045, var 0.019 +# +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) + printf "loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, var %.3f\n", loop_count, (loop_tmax + loop_tmin) / 2 * 1e6, (loop_tmax - loop_tmin) / 2 * 1e6, loop_time_rms * 1e6, (loop_fmax + loop_fmin) / 2, (loop_fmax - loop_fmin) / 2, loop_freq_rms + } +} + diff --git a/contrib/ntp/scripts/stats/loop_summary b/contrib/ntp/scripts/stats/loop_summary new file mode 100755 index 000000000000..35479ecec0da --- /dev/null +++ b/contrib/ntp/scripts/stats/loop_summary @@ -0,0 +1,2 @@ + +loopstats.[1-9] diff --git a/contrib/ntp/scripts/stats/peer.awk b/contrib/ntp/scripts/stats/peer.awk new file mode 100755 index 000000000000..5fe260e49540 --- /dev/null +++ b/contrib/ntp/scripts/stats/peer.awk @@ -0,0 +1,68 @@ +# 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 +# +# format of output dataset (time values in milliseconds) +# peerstats.19960706 +# ident cnt mean rms max delay dist disp +# ========================================================================== +# 140.173.112.2 85 -0.509 1.345 4.606 80.417 49.260 1.092 +# 128.4.1.20 1364 0.058 0.364 4.465 3.712 10.540 1.101 +# 140.173.16.1 1415 -0.172 0.185 1.736 3.145 5.020 0.312 +#... +# +BEGIN { + n = 0 + MAXDISTANCE = 1.0 +} +# +# scan all records in file +# +# we toss out all distances greater than one second on the assumption the +# peer is in initial acquisition +# +{ + 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/ntp/scripts/stats/psummary.awk b/contrib/ntp/scripts/stats/psummary.awk new file mode 100755 index 000000000000..ec06b0c2cbe3 --- /dev/null +++ b/contrib/ntp/scripts/stats/psummary.awk @@ -0,0 +1,82 @@ +# program to scan peer_summary file and produce summary of daily summaries +# +# usage: awk -f psummary.awk peer_summary +# +# format of input records +# peerstats.19960706 +# ident cnt mean rms max delay dist disp +# ========================================================================== +# 140.173.112.2 85 -0.509 1.345 4.606 80.417 49.260 1.092 +# 128.4.1.20 1364 0.058 0.364 4.465 3.712 10.540 1.101 +# ... +# +# format of output records (actual data from rackety.udel.edu) +# host days mean rms max >1 >5 >10 >50 +# ================================================================== +# 127.127.22.1 1090 0.001 0.401 99.800 19 14 13 10 +# 127.0.0.1 1188 0.060 1.622 105.004 78 65 51 32 +# 127.127.4.1 586 0.000 0.000 0.000 0 0 0 0 +# 140.173.64.1 975 -0.010 2.552 257.595 399 192 114 8 +# 128.175.1.3 1121 0.447 8.637 204.123 479 460 397 147 +# 140.173.16.1 1106 0.027 1.014 267.857 242 38 31 23 +# 128.4.1.4 1119 0.023 1.037 267.748 223 41 34 23 +# 128.4.1.2 850 1.202 1.654 267.704 196 53 45 34 +# 128.4.1.20 1101 0.088 1.139 268.322 430 111 83 16 +# 140.173.32.1 979 -0.949 2.344 257.671 396 217 136 7 +# 140.173.112.2 1066 0.040 2.111 152.969 442 315 152 16 +# 140.173.80.1 1059 0.019 1.858 87.690 438 348 150 9 +# 140.173.96.1 1015 0.110 2.007 266.744 399 314 170 17 +# 140.173.128.1 1103 -0.002 2.600 257.672 465 262 132 13 +# 140.222.135.1 347 -4.626 8.804 196.394 135 135 134 95 +# 140.173.128.2 1081 -0.046 2.967 261.448 463 342 172 17 +# 140.222.141.1 354 0.820 8.809 195.333 142 141 139 100 +# 140.173.144.2 1058 -0.107 2.805 270.498 448 341 163 17 +# 140.222.134.1 354 -0.056 8.479 172.458 142 141 141 100 +# 140.222.144.1 415 -1.456 9.964 191.684 161 161 161 123 +# 140.222.136.1 234 0.902 7.707 182.431 62 62 62 48 +# 128.175.1.1 774 0.890 4.838 266.799 358 291 200 83 +# 127.127.10.1 1086 -0.002 1.462 231.128 240 239 60 57 +# 140.173.48.2 576 0.016 4.092 350.512 213 126 88 16 +# 128.4.1.11 3 0.000 0.000 0.000 0 0 0 0 +# 128.4.1.26 386 -1.363 20.251 341.284 164 164 161 132 +# +# select table beginning with "ident" +{ + 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 days 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/ntp/scripts/stats/summary.sh b/contrib/ntp/scripts/stats/summary.sh new file mode 100755 index 000000000000..655c4be9dcdd --- /dev/null +++ b/contrib/ntp/scripts/stats/summary.sh @@ -0,0 +1,88 @@ +#!/bin/sh +# +# 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. +# +DATE=`date +19%y%m%d` +S=/usr/local/bin/S +SIN=S.in +SOUT=S.out +LOOP=loop_summary +PEER=peer_summary +CLOCK=clock_summary + +rm -f $SIN $SOUT + +# +# Summarize loopstats files +# +for f in loopstats.[12][0-9][0-9][0-9][0-1][0-9][0-3][0-9]; do + d=`echo $f | cut -f2 -d.` + if [ -f $f ] && [ $DATE != $d ]; then + echo " " >>$LOOP + echo $f >>$LOOP + awk -f loop.awk $f >>$LOOP + if [ -f $S ]; then + echo "file1<-"\"${f}\" >>$SIN + echo "source("\""loop.S"\"")" >>$SIN + echo "unix("\""rm ${f}"\"")" >>$SIN + else + rm -f $f + fi + fi +done + +# +# Summarize peerstats files +# +for f in peerstats.199[4-9][0-1][0-9][0-3][0-9]; do + d=`echo $f | cut -f2 -d.` + if [ -f $f ] && [ $DATE != $d ]; then + echo " " >>$PEER + echo $f >>$PEER + awk -f peer.awk $f >>$PEER + rm -f $f + fi +done + +# +# Summarize clockstats files +# +for f in clockstats.199[4-9][0-1][0-9][0-3][0-9]; do + d=`echo $f | cut -f2 -d.` + if [ -f $f ] && [ $DATE != $d ]; then + echo " " >>$CLOCK + echo $f >>$CLOCK + awk -f clock.awk $f >>$CLOCK + if [ -f /dev/gps[0-9] ]; then + awk -f itf.awk $f >itf.$d + awk -f etf.awk $f >etf.$d + awk -f ensemble.awk $f >ensemble.$d + awk -f tdata.awk $f >tdata.$d + fi + rm -f $f + fi +done + +# +# Process clockstat files with S and generate PostScript plots +# +for f in itf etf ensemble tdata; do + for d in ${f}.199[4-9][0-1][0-9][0-3][0-9]; do + if [ -f $d ]; then + if [ -f $S ]; then + echo "file1<-"\"${d}\" >>$SIN + echo "source("\"${f}.S\"")" >>$SIN + echo "unix("\""rm ${d}"\"")" >>$SIN + else + rm -f $d + fi + fi + done +done +if [ -f $SIN ]; then + $S BATCH $SIN $SOUT +fi diff --git a/contrib/ntp/scripts/stats/tdata.S b/contrib/ntp/scripts/stats/tdata.S new file mode 100755 index 000000000000..f360a248c06a --- /dev/null +++ b/contrib/ntp/scripts/stats/tdata.S @@ -0,0 +1,5 @@ +tdata <- scan(file1, list(day=0, sec=0, m=0, w=0, x=0, y=0, z=0)) +str <- paste("eps/", file1, ".eps", sep="") +postscript(str, , , , 5, pointsize=18) +par(mgp=c(1, 0, 0), tck=0.03, mar=c(2, 2, 1, 1)) +plot(tdata$sec, tdata$m, type="l", xlab=paste("MJD", tdata$day, "Time (s)"), ylab="LORAN-M SNR (dB)") diff --git a/contrib/ntp/scripts/stats/tdata.awk b/contrib/ntp/scripts/stats/tdata.awk new file mode 100755 index 000000000000..5be9c0490e3f --- /dev/null +++ b/contrib/ntp/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 (time in nanoseconds, signal values 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/ntp/scripts/summary.pl b/contrib/ntp/scripts/summary.pl new file mode 100644 index 000000000000..c9deda9f1373 --- /dev/null +++ b/contrib/ntp/scripts/summary.pl @@ -0,0 +1,357 @@ +#!/usr/bin/perl -w +# $Id: summary.pl,v 1.1.1.1 1999/05/26 00:48:25 stenn Exp $ +# Perl version of (summary.sh, loop.awk, peer.awk): +# Create summaries from xntpd's loop and peer statistics. +# +# Copyright (c) 1997, Ulrich Windl +# +# 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 of the License, 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. + +require 5.003; # "never tested with any other version of Perl" +use strict; + +use Getopt::Long; + +my $statsdir = "."; +my $skip_time_steps = 3600.0; # ignore time offsets larger that this +my $startdate = "19700101"; # first data file to use +my $enddate=`date -u +%Y%m%d`; chomp $enddate; --$enddate; +my $peer_dist_limit = 400.0; + +my %options = ("directory=s" => \$statsdir, + "skip-time-steps:f" => \$skip_time_steps, + "start-date=s" => \$startdate, + "end-date=s" => \$enddate, + "peer-dist-limit=f" => \$peer_dist_limit); + +if ( !GetOptions(%options) ) +{ + print STDERR "valid options for $0 are:\n"; + my $opt; + foreach $opt (sort(keys %options)) { + print STDERR "\t--$opt "; + if ( ref($options{$opt}) eq "ARRAY" ) { + print STDERR "(" . join (" ", @{$options{$opt}}) . ")\n"; + } else { + print STDERR "(${$options{$opt}})\n"; + } + } + print STDERR "\n"; + die; +} + +die "$statsdir: no such directory" unless (-d $statsdir); +die "$skip_time_steps: skip-time-steps must be positive" + unless ($skip_time_steps >= 0.0); +die "$startdate: invalid start date" + unless ($startdate =~ m/.*([12]\d{3}[01]\d[0-3]\d)$/); +die "$enddate: invalid end date" + unless ($enddate =~ m/.*([12]\d{3}[01]\d[0-3]\d)$/); + +$skip_time_steps = 0.128 if ($skip_time_steps == 0); + +sub min +{ + my ($result, @rest) = @_; + map { $result = $_ if ($_ < $result) } @rest; + return($result); +} + +sub max +{ + my ($result, @rest) = @_; + map { $result = $_ if ($_ > $result) } @rest; + return($result); +} + +# calculate mean, range, and standard deviation for offset and frequency +sub do_loop +{ + my ($directory, $fname, $out_file) = @_; + print "$directory/$fname\n"; + open INPUT, "$directory/$fname"; + open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; + print OUTPUT "$fname\n"; + my ($loop_tmax, $loop_fmax) = (-1e9, -1e9); + my ($loop_tmin, $loop_fmin) = (1e9, 1e9); + my ($loop_time_rms, $loop_freq_rms) = (0, 0); + my $loop_count = 0; + my $loop_time = 0; + my $loop_freq = 0; + my ($freq, $offs); + my @Fld; + while () { + chop; # strip record separator + @Fld = split; + next if ($#Fld < 4); +# 50529 74356.259 -0.000112 16.1230 8 + if ($Fld[2] > $skip_time_steps || $Fld[2] < -$skip_time_steps) { + warn "ignoring loop offset $Fld[2] (file $fname, line $.)\n"; + next + } + $loop_count++; + ($offs, $freq) = ($Fld[2], $Fld[3]); + $loop_tmax = max($loop_tmax, $offs); + $loop_tmin = min($loop_tmin, $offs); + $loop_fmax = max($loop_fmax, $freq); + $loop_fmin = min($loop_fmin, $freq); + $loop_time += $offs; + $loop_time_rms += $offs * $offs; + $loop_freq += $freq; + $loop_freq_rms += $freq * $freq; + } + close INPUT; + if ($loop_count > 1) { + $loop_time /= $loop_count; + $loop_time_rms = $loop_time_rms / $loop_count - $loop_time * $loop_time; + if ($loop_time_rms < 0) { + warn "loop_time_rms: $loop_time_rms < 0"; + $loop_time_rms = 0; + } + $loop_time_rms = sqrt($loop_time_rms); + $loop_freq /= $loop_count; + $loop_freq_rms = $loop_freq_rms / $loop_count - $loop_freq * $loop_freq; + if ($loop_freq_rms < 0) { + warn "loop_freq_rms: $loop_freq_rms < 0"; + $loop_freq_rms = 0; + } + $loop_freq_rms = sqrt($loop_freq_rms); + printf OUTPUT + ("loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, var %.3f\n", + $loop_count, ($loop_tmax + $loop_tmin) / 2 * 1e6, + ($loop_tmax - $loop_tmin) / 2 * 1e6, $loop_time_rms * 1e6, + ($loop_fmax + $loop_fmin) / 2, ($loop_fmax - $loop_fmin) / 2, + $loop_freq_rms); + } + else { + warn "no valid lines in $directory/$fname"; + } + close OUTPUT +} + +# calculate mean, standard deviation, maximum offset, mean dispersion, +# and maximum distance for each peer +sub do_peer +{ + my ($directory, $fname, $out_file) = @_; + print "$directory/$fname\n"; + open INPUT, "$directory/$fname"; + open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; + print OUTPUT "$fname\n"; +# we toss out all distances greater than one second on the assumption the +# peer is in initial acquisition + my ($n, $MAXDISTANCE) = (0, 1.0); + my %peer_time; + my %peer_time_rms; + my %peer_count; + my %peer_delay; + my %peer_disp; + my %peer_dist; + my %peer_ident; + my %peer_tmin; + my %peer_tmax; + my @Fld; + my ($i, $j); + my ($dist, $offs); + while () { + chop; # strip record separator + @Fld = split; + next if ($#Fld < 6); +# 50529 83316.249 127.127.8.1 9674 0.008628 0.00000 0.00700 + $dist = $Fld[6] + $Fld[5] / 2; + next if ($dist > $MAXDISTANCE); + $offs = $Fld[4]; + if ($offs > $skip_time_steps || $offs < -$skip_time_steps) { + warn "ignoring peer offset $offs (file $fname, line $.)\n"; + next + } + $i = $n; + for ($j = 0; $j < $n; $j++) { + if ($Fld[2] eq $peer_ident{$j}) { + $i = $j; # peer found + last; + } + } + if ($i == $n) { # add new peer + $peer_ident{$i} = $Fld[2]; + $peer_tmax{$i} = $peer_dist{$i} = -1e9; + $peer_tmin{$i} = 1e9; + $peer_time{$i} = $peer_time_rms{$i} = 0; + $peer_delay{$i} = $peer_disp{$i} = 0; + $peer_count{$i} = 0; + $n++; + } + $peer_count{$i}++; + $peer_tmax{$i} = max($peer_tmax{$i}, $offs); + $peer_tmin{$i} = min($peer_tmin{$i}, $offs); + $peer_dist{$i} = max($peer_dist{$i}, $dist); + $peer_time{$i} += $offs; + $peer_time_rms{$i} += $offs * $offs; + $peer_delay{$i} += $Fld[5]; + $peer_disp{$i} += $Fld[6]; + } + close INPUT; + print OUTPUT +" ident cnt mean rms max delay dist disp\n"; + print OUTPUT +"==========================================================================\n"; + my @lines = (); + for ($i = 0; $i < $n; $i++) { + next if $peer_count{$i} < 2; + $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}) { # can this happen at all? + $peer_tmax{$i} = $peer_tmin{$i}; + } + push @lines, sprintf + "%-15s %4d %8.3f %8.3f %8.3f %8.3f %8.3f %8.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; + } + print OUTPUT sort @lines; + close OUTPUT; +} + +sub do_clock +{ + my ($directory, $fname, $out_file) = @_; + print "$directory/$fname\n"; + open INPUT, "$directory/$fname"; + open OUTPUT, ">>$out_file" or die "can't open $out_file: $!"; + print OUTPUT "$fname\n"; + close INPUT; + close OUTPUT; +} + +sub peer_summary +{ + my $in_file = shift; + my ($i, $j, $n); + my (%peer_ident, %peer_count, %peer_mean, %peer_var, %peer_max); + my (%peer_1, %peer_2, %peer_3, %peer_4); + my $dist; + my $max; + open INPUT, "<$in_file" or die "can't open $in_file: $!"; + my @Fld; + $n = 0; + while () { + chop; # strip record separator + @Fld = split; + next if ($#Fld < 7 || $Fld[0] eq 'ident'); + $i = $n; + for ($j = 0; $j < $n; $j++) { + if ($Fld[0] eq $peer_ident{$j}) { + $i = $j; + last; # peer found + } + } + if ($i == $n) { # add new peer + $peer_count{$i} = $peer_mean{$i} = $peer_var{$i} = 0; + $peer_max{$i} = 0; + $peer_1{$i} = $peer_2{$i} = $peer_3{$i} = $peer_4{$i} = 0; + $peer_ident{$i} = $Fld[0]; + ++$n; + } + $dist = $Fld[6] - $Fld[5] / 2; + if ($dist < $peer_dist_limit) { + $peer_count{$i}++; + $peer_mean{$i} += $Fld[2]; + $peer_var{$i} += $Fld[3] * $Fld[3]; + $max = $Fld[4]; + $peer_max{$i} = max($peer_max{$i}, $max); + if ($max > 1) { + $peer_1{$i}++; + if ($max > 5) { + $peer_2{$i}++; + if ($max > 10) { + $peer_3{$i}++; + if ($max > 50) { + $peer_4{$i}++; + } + } + } + } + } + else { + warn "dist exceeds limit: $dist (file $in_file, line $.)\n"; + } + } + close INPUT; + my @lines = (); + print + " host days mean rms max >1 >5 >10 >50\n"; + print + "==================================================================\n"; + for ($i = 0; $i < $n; $i++) { + next if ($peer_count{$i} < 2); + $peer_mean{$i} /= $peer_count{$i}; + $peer_var{$i} = sqrt($peer_var{$i} / $peer_count{$i} - + $peer_mean{$i} * $peer_mean{$i}); + push @lines, sprintf + "%-15s %3d %9.3f% 9.3f %9.3f %3d %3d %3d %3d\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}; + } + print sort @lines; +} + +my $loop_summary="/tmp/loop_summary"; +my $peer_summary="/tmp/peer_summary"; +my $clock_summary="/tmp/clock_summary"; +my (@loopfiles, @peerfiles, @clockfiles); + +print STDERR "Creating summaries from $statsdir ($startdate to $enddate)\n"; + +opendir SDIR, $statsdir or die "directory ${statsdir}: $!"; +rewinddir SDIR; +@loopfiles=sort grep /loop.*[12]\d{3}[01]\d[0-3]\d/, readdir SDIR; +rewinddir SDIR; +@peerfiles=sort grep /peer.*[12]\d{3}[01]\d[0-3]\d/, readdir SDIR; +rewinddir SDIR; +@clockfiles=sort grep /clock.*[12]\d{3}[01]\d[0-3]\d/, readdir SDIR; +closedir SDIR; + +map { unlink $_ if -f $_ } ($loop_summary, $peer_summary, $clock_summary); + +my $date; +map { + $date = $_; $date =~ s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; + if ($date ge $startdate && $date le $enddate) { + do_loop $statsdir, $_, $loop_summary; + } +} @loopfiles; + +map { + $date = $_; $date =~ s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; + if ($date ge $startdate && $date le $enddate) { + do_peer $statsdir, $_, $peer_summary; + } +} @peerfiles; + +map { + $date = $_; $date =~ s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/; + if ($date ge $startdate && $date le $enddate) { + do_clock $statsdir, $_, $clock_summary; + } +} @clockfiles; + +print STDERR "Creating peer summary with limit $peer_dist_limit\n"; +peer_summary $peer_summary if (-f $peer_summary); diff --git a/contrib/ntp/scripts/support/README b/contrib/ntp/scripts/support/README new file mode 100644 index 000000000000..812965bd0955 --- /dev/null +++ b/contrib/ntp/scripts/support/README @@ -0,0 +1,73 @@ +The bin and etc directories contain several scripts (sh and perl) that +should ease startup and configuration of NTP sites. + + bin/monl is a monitoring script that prints out new, current and + old customers of an NTP timeserver when monitoring is + in effect. + monl has following options: + -i (regular expression matchin IP addres to be ignored + -d where the current state is kept (default /tmp) + -v debug output + -n do not translate IP addresses into hostnames + host to be analyzed + + monl uses xntpdc for information gathering and is thus + limited to the NTP version xntpdc is compiled for. + + bin/mvstats moves compresses and removes statistics files (useful mainly + for reference servers + + etc/install creates the locally needed directories for NTP (if not residung in /etc) + + etc/rc starts up daemon with configuration file and key file + etc/cron cron called monitor statistic (uses bin/monl) + etc/crontab crontab prototype for reference time servers + etc/setup sh script sourced by the other scripts for variable setup + +YOU MUST EDIT THESE FILES TO REFLECT YOUR LOCAL SETUP ! + +READ THIS BEFORE USING THE STARTUP SCRIPTS + +The startupscript etc/rc has been written for Suns and HPs. They are not +guaranteed to work elsewhere. Following assumptions have been made: + + All NTP related files reside in ONE directory having following structure: + + bin/* - all executables (daemon, control, date, scripts) + etc/* - startup scripts and cron scripts + conf/* - NTP configuration files + +The variable NTPROOT (etc/rc, etc/install) must be edited to reflect +the NTP directory (e.g. /usr/local/NTP) + +NTP config files are located via Suns arch command and have the name +conf/`arch`.`arch -k`. +These are the default configurations (usually clients). If a file with the name +conf/`arch`.`arch -k`.`hostname` is present this file will be preferred (Reference host, +gateway). If the arch command is not available no-arch is used. The arch command +is usually a shell script which echoes a string unique the the current machine +architecture. + +The tickadj command has its own conf/tickconf file which is used to set host +specific tickadj values. The line with DEFAULT specifies the default tickadj +parameters, all other lines consists of +. These lines need only be entered if the specified host +needs parameters different from the default parameters. + +Reference clock support is provided for DCF77. If you need to initialize +certain things for reference clock support (e.g. loading STREAMS modules), +you need to edit etc/rc. + +The current config files of Erlangen are included in the conf directory. +They are just for reference, but might help you a bit in setting up a +synchronisation network. + +The advantage of keeping all config files centralized is the easier +administration. + +We replicate the NTP directory via NFS and rdist. + +When you have set up the local config files (YOUR OWN!) you can call +/etc/rc for daemon startup. + +For more information: time@informatik.uni-erlangen.de diff --git a/contrib/ntp/scripts/support/bin/monl b/contrib/ntp/scripts/support/bin/monl new file mode 100644 index 000000000000..f0c48dbf5f3f --- /dev/null +++ b/contrib/ntp/scripts/support/bin/monl @@ -0,0 +1,213 @@ +#!/local/bin/perl + +%service = ( 0, "unspec", + 1, "Active", + 2, "Passive", + 3, "Client", + 4, "Server", + 5, "Broadcast", + 6, "Control", + 7, "Private" ); +%nc = (); +@ignpat = (); +$noname = 0; +$verbose = 0; +$retries = 5; +$lastkey = 0; + +sub timedelta { + local($tm, $days, $h, $m, $s); + + $tm = @_[$[]; + $days = 0; + $days = sprintf("%dd+", $days) if $days = int($tm / (60*60*24)); + $days = "" unless $days; + $tm = $tm % (60*60*24); + $h = int($tm / (60*60)); + $tm = $tm % (60*60); + $m = int($tm / 60); + $s = $tm % 60; + + return sprintf("%s%02d:%02d:%02d", $days, $h, $m, $s); +} + +sub listentry { + local($host, $mode) = split("$;" , @_[$[]); + local($count, $version, $firsttime) = split("$;" , $_[$[+1]); + local($name); + + if (grep($host =~ m/$_/, @ignpat)) + { + print "ignored $host ...\n" if $verbose; + return; + } + + return if ! $count; + + if (defined($nc{$host})) + { + $name = $nc{$host}; + } + else + { + if ($noname) + { + $nc{$host} = $name = $host; + } + else + { + $name = (gethostbyaddr(pack("C4", split(/\./, $host)), 2))[$[]; + $nc{$host} = $name = $host if ! defined($name); + } + } + + printf ($fmt, ($lastkey eq $host) ? "" : $name, $service{$mode}, $count, $version, &timedelta($firsttime), $firsttime / $count); + + if (@_[$[+2]) + { + $hostcnt++ if $lastkey ne $host; + $packcnt += $count; + $maxtime = $firsttime if $firsttime > $maxtime; + } + + $lastkey = $host; +} + +while ($ARGV[$[] =~ /^-[nvid]$/) + { + if ($ARGV[$[] eq "-i") + { + shift; + push(@ignpat, shift) unless ! defined($ARGV[$[]); + } + elsif ($ARGV[$[] eq "-d") + { + shift; + $dir = shift unless ! defined($ARGV[$[]); + } + elsif ($ARGV[$[] eq "-n") + { + shift; + $noname = 1; + } + elsif ($ARGV[$[] eq "-v") + { + shift; + $verbose = 1; + } + } + +$dir = "/tmp" unless defined($dir); +$gone = 60*60*48; +$fmt = "%48s %10s %7d %7d %13s %14.3f\n"; +$sfmt = "%48s %10s %7s %7s %13s %14s\n"; +@lbl = ("Host", "Mode", "Count", "Version", "Time active", "Packetinterval"); + +if (!defined($ARGV[$[])) + { + $hostname = `hostname`; + chop($hostname); + unshift(@ARGV, $hostname); + } + +foreach $hostname (@ARGV) + { + $dbmfile = $dir . "/monlstats-" . $hostname; + $monl = "xntpdc -c 'hostnames no' -c monl $hostname | tail +3 |"; + $hostcnt = 0; + $packcnt = 0; + $maxtime = 0; + %Seen = (); + %New = (); + %Old = (); + + print "Monitor Status of $hostname\n\n"; + + $cnt = $retries; + do + { + open(MONL, $monl) || die("$monl failed $!"); + @monlout = ; + close(MONL); + } while (! @monlout && $cnt--); + + if (! @monlout) + { + print "not available.\n"; + next; + } + + dbmopen(Clients, $dbmfile, 0644) || die("dbmopen(.., $dbmfile, ...): $!"); + + foreach (@monlout) + { + chop; + split; + ($host, $count, $mode, $version, $lasttime, $firsttime) = + (@_[$[, $[+2 .. $[+4, $#_-1,$#_]); + + $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/ntp/scripts/support/bin/mvstats b/contrib/ntp/scripts/support/bin/mvstats new file mode 100644 index 000000000000..e33dc792e805 --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/support/conf/hp300.hp300 b/contrib/ntp/scripts/support/conf/hp300.hp300 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/hp700.hp700 b/contrib/ntp/scripts/support/conf/hp700.hp700 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/hp700.hp700.faui47 b/contrib/ntp/scripts/support/conf/hp700.hp700.faui47 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/hp800.hp800 b/contrib/ntp/scripts/support/conf/hp800.hp800 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/ntp.conf b/contrib/ntp/scripts/support/conf/ntp.conf new file mode 100644 index 000000000000..2d6bb8549c62 --- /dev/null +++ b/contrib/ntp/scripts/support/conf/ntp.conf @@ -0,0 +1,3 @@ +# +# put your default configuration (e.g. broadcastclient) in here +# diff --git a/contrib/ntp/scripts/support/conf/sun3.sun3 b/contrib/ntp/scripts/support/conf/sun3.sun3 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4.faui01 b/contrib/ntp/scripts/support/conf/sun4.sun4.faui01 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4.faui10 b/contrib/ntp/scripts/support/conf/sun4.sun4.faui10 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4.faui45 b/contrib/ntp/scripts/support/conf/sun4.sun4.faui45 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4c b/contrib/ntp/scripts/support/conf/sun4.sun4c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4c.Lucifer b/contrib/ntp/scripts/support/conf/sun4.sun4c.Lucifer new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4m b/contrib/ntp/scripts/support/conf/sun4.sun4m new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4m.faui42 b/contrib/ntp/scripts/support/conf/sun4.sun4m.faui42 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/sun4.sun4m.faui45m b/contrib/ntp/scripts/support/conf/sun4.sun4m.faui45m new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ntp/scripts/support/conf/tickconf b/contrib/ntp/scripts/support/conf/tickconf new file mode 100644 index 000000000000..b17dbe834743 --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/support/etc/cron b/contrib/ntp/scripts/support/etc/cron new file mode 100644 index 000000000000..07ed18949835 --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/support/etc/crontab b/contrib/ntp/scripts/support/etc/crontab new file mode 100644 index 000000000000..2b2d19ced76c --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/support/etc/install b/contrib/ntp/scripts/support/etc/install new file mode 100644 index 000000000000..169a7e5a06d7 --- /dev/null +++ b/contrib/ntp/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/ntp/scripts/support/etc/rc b/contrib/ntp/scripts/support/etc/rc new file mode 100644 index 000000000000..ef8834a69f7b --- /dev/null +++ b/contrib/ntp/scripts/support/etc/rc @@ -0,0 +1,198 @@ +#!/bin/sh +# NTP time synchronisation +# +# /src/NTP/REPOSITORY/v3/supportscripts/etc/rc,v 1.11 1993/07/09 13:17:00 kardel Exp +# +# rc,v +# Revision 1.11 1993/07/09 13:17:00 kardel +# local NTPROOT +# +# Revision 1.10 1993/07/09 11:37:29 kardel +# Initial restructured version + GPS support +# +# Revision 1.9 1993/06/23 14:10:36 kardel +# June 21st reconcilation +# +# Revision 1.7 1993/06/02 12:04:43 kardel +# May 28th reconcilation & clenaup +# +# +# non reference clock hosts will try to do an ntpdate on NTPSERVERS +# +NTPSERVERS="ntps1-0 ntps1-1 ntps2-0 ntps2-1" +NTPROOT=/local/NTP + +# +# get the initial setup +# +if [ ! -r $NTPROOT/etc/setup ]; then + echo "ERROR: $NTPROOT/etc/setup missing - incorrect installation." + exit 1 +else + . $NTPROOT/etc/setup +fi + +umask 022 # SITE SPECIFIC: local policy - watch out for NFS and "root" rights + +msg="" +# +# default configuration files are named $NTPROOT/conf/. +# +CF=$NTPROOT/conf/$ARCH.$KARCH # default configuration file +# +# Host specific config file (reference clocks) have the hostname tagged on +# +CFH="$CF"."$HOSTNAME" # specific configuration file +# +# where to find the tickadj command +# +KFIX=$NTPROOT/bin/tickadj # kernel variable fix +# +# where to find special tickadj parameters +# +TC=$NTPROOT/conf/tickconf # special tickadj parameters +# +# where to find the keys file (if not found $KEY.dumb will be used) +# +KEY=$NTPROOT/conf/ntp.keys # private key file +# +# the daemon +# +XD=$NTPROOT/bin/xntpd # NTP daemon +# +# HP adjtimed +# +ADJTIMED=$NTPROOT/bin/adjtimed # HP special (adjtime() emulation) +# +# ntpdate command +# +NTPDATE=$NTPROOT/bin/ntpdate + +# +# secondary timed support +# The word "TIMED" must be in the config file for timed to start +# Note that this times is a special version which does not ever set or +# adjust the time. Ask time@informatik.uni-erlangen.de for patches +# +TIMED=$NTPROOT/bin/timed # timed (Berkeley) secondary time service + # here used in a *HARMLESS* version + # to provide time to "inferior" systems +# +# ISREFHOST is a command that returns exit status 0 for a reference host +# Site specific: sample for dcf77 is given +# +ISREFHOST="[ -f $NTPROOT/.karch.$KARCH/sys/OBJ/parsestreams.o -a -f /dev/refclock-0 ]" +# +# SETUP_REFCLOCK +# +# what to do in order to set up a local reference clock +# usually this will load a STREAMS module or initialize other things +# needed +# +SETUP_REFCLOCK() { + if modstat | grep -s 'PARSE'; then + ECHO "loadable PARSER STREAMS module already loaded." + else + ECHO "attempting to load PARSER STREAMS module..." + MDLFILE="/tmp/mdl.$$" + if modload $NTPROOT/.karch.$KARCH/sys/OBJ/parsestreams.o -o $MDLFILE 2>&1; then + modstat + else + echo WARNING: load FAILED + fi | LOG + rm -f $MDLFILE + unset MDLFILE + fi +} + +kargs() { + MATCH=NO + HOSTID="`(hostid) 2>/dev/null || echo 000000`" + if [ -r "$TC" ]; then + exec 0< "$TC" + while [ "$MATCH" != "YES" ] && read HOST ID PARAM; do + if [ "$HOST" = "DEFAULT" ]; then + DEFAULT="$ID $PARAM" + else + if [ "$ID" = "$HOSTID" -o "$HOST" = "$HOSTNAME" ]; then + echo "$PARAM" + MATCH=YES + fi + fi + done + if [ "$MATCH" != "YES" ]; then + if [ -z "$DEFAULT" ]; then + echo "-A -p -s -q"; + else + echo "$DEFAULT"; + fi + fi + else + echo "-A -p -s -q"; + fi +} + +if [ -x $XD ]; then + if [ -x "$ADJTIMED" ]; then + $ADJTIMED && ECHO "adjusttimesupport: adjtimed." + fi + # + # WARNING: check ps command first, or you might kill things you don't want to + # + PID="`(ps -efa 2>/dev/null || ps auxww 2>/dev/null || echo "") | grep xntp | grep -v grep | awk '{ print $2 }'`" + + if [ ! -z "$PID" ]; then + ECHO "killing old NTP daemon (PID=$PID)" + # + # enable this after checking for correctness + # kill $PID + ECHO "should do a kill $PID, if this is the right PID - check rc script" + fi + # + # try an ntpdate when timeservers are configured + # + if [ ! -z "$NTPSERVERS" -a -x $NTPDATE ]; then + ECHO "NTP initial time setting" + $NTPDATE -v $NTPSERVERS | LOG + fi + # + # look for reference clock equipment + # + if $ISREFHOST; then + ECHO "REFERENCE CLOCK SUPPORT (initializing...)" + SETUP_REFCLOCK + fi + + if [ -r "$CFH" ]; then + CF="$CFH" + else + if [ ! -r "$KEY" ]; then + KEY="$KEY.dumb" + fi + fi + + ECHO "NTP configuration file: $CF" + ECHO -n "time daemon startup:" + + if [ -r "$CF" ]; then + if [ -x "$KFIX" ]; then + KARGS="`kargs`" + if [ ! -z "$KARGS" ]; then + $KFIX $KARGS && ECHO -n "tickadj $KARGS" + fi + fi + $XD -c "$CF" -k "$KEY" && ECHO -n ' xntpd' + if [ -x "$TIMED" ] && grep -s TIMED "$CF"; then + $TIMED -M -N && ECHO -n ' timed' + fi + else + msg="configuration file ($CF) not present." + fi +else + msg="daemon binary ($XD) not present." +fi +ECHO "." + +if [ "$msg" ]; then + NLECHO "WARNING: NO NTP time sychronisation: $msg" +fi diff --git a/contrib/ntp/scripts/support/etc/setup b/contrib/ntp/scripts/support/etc/setup new file mode 100644 index 000000000000..d4ea75ecfaa9 --- /dev/null +++ b/contrib/ntp/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/ntp/stamp-h.in b/contrib/ntp/stamp-h.in new file mode 100644 index 000000000000..9788f70238c9 --- /dev/null +++ b/contrib/ntp/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/contrib/ntp/util/Makefile.am b/contrib/ntp/util/Makefile.am new file mode 100644 index 000000000000..4d703182773f --- /dev/null +++ b/contrib/ntp/util/Makefile.am @@ -0,0 +1,18 @@ +#AUTOMAKE_OPTIONS = ../ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ansi2knr +bin_PROGRAMS = @MAKE_TICKADJ@ @MAKE_NTPTIME@ +EXTRA_PROGRAMS = byteorder hist jitter kern longsize ntptime \ +precision tickadj testrs6000 timetrim sht + +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = ../libntp/libntp.a +#EXTRA_DIST = README TAGS +EXTRA_DIST = +ETAGS_ARGS = Makefile.am + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +kern.o: kern.c + $(COMPILE) -DHAVE_TIMEX_H -c kern.c diff --git a/contrib/ntp/util/Makefile.in b/contrib/ntp/util/Makefile.in new file mode 100644 index 000000000000..6de4f225863a --- /dev/null +++ b/contrib/ntp/util/Makefile.in @@ -0,0 +1,492 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +DCFD = @DCFD@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ + +#AUTOMAKE_OPTIONS = ../ansi2knr no-dependencies + + +AUTOMAKE_OPTIONS = ansi2knr +bin_PROGRAMS = @MAKE_TICKADJ@ @MAKE_NTPTIME@ +EXTRA_PROGRAMS = byteorder hist jitter kern longsize ntptime \ +precision tickadj testrs6000 timetrim sht + + +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = ../libntp/libntp.a +#EXTRA_DIST = README TAGS +EXTRA_DIST = +ETAGS_ARGS = Makefile.am +subdir = util +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +ANSI2KNR = @ANSI2KNR@ +byteorder_SOURCES = byteorder.c +byteorder_OBJECTS = byteorder$U.o +byteorder_LDADD = $(LDADD) +byteorder_DEPENDENCIES = ../libntp/libntp.a +byteorder_LDFLAGS = +hist_SOURCES = hist.c +hist_OBJECTS = hist$U.o +hist_LDADD = $(LDADD) +hist_DEPENDENCIES = ../libntp/libntp.a +hist_LDFLAGS = +jitter_SOURCES = jitter.c +jitter_OBJECTS = jitter$U.o +jitter_LDADD = $(LDADD) +jitter_DEPENDENCIES = ../libntp/libntp.a +jitter_LDFLAGS = +kern_SOURCES = kern.c +kern_OBJECTS = kern$U.o +kern_LDADD = $(LDADD) +kern_DEPENDENCIES = ../libntp/libntp.a +kern_LDFLAGS = +longsize_SOURCES = longsize.c +longsize_OBJECTS = longsize$U.o +longsize_LDADD = $(LDADD) +longsize_DEPENDENCIES = ../libntp/libntp.a +longsize_LDFLAGS = +ntptime_SOURCES = ntptime.c +ntptime_OBJECTS = ntptime$U.o +ntptime_LDADD = $(LDADD) +ntptime_DEPENDENCIES = ../libntp/libntp.a +ntptime_LDFLAGS = +precision_SOURCES = precision.c +precision_OBJECTS = precision$U.o +precision_LDADD = $(LDADD) +precision_DEPENDENCIES = ../libntp/libntp.a +precision_LDFLAGS = +sht_SOURCES = sht.c +sht_OBJECTS = sht$U.o +sht_LDADD = $(LDADD) +sht_DEPENDENCIES = ../libntp/libntp.a +sht_LDFLAGS = +testrs6000_SOURCES = testrs6000.c +testrs6000_OBJECTS = testrs6000$U.o +testrs6000_LDADD = $(LDADD) +testrs6000_DEPENDENCIES = ../libntp/libntp.a +testrs6000_LDFLAGS = +tickadj_SOURCES = tickadj.c +tickadj_OBJECTS = tickadj$U.o +tickadj_LDADD = $(LDADD) +tickadj_DEPENDENCIES = ../libntp/libntp.a +tickadj_LDFLAGS = +timetrim_SOURCES = timetrim.c +timetrim_OBJECTS = timetrim$U.o +timetrim_LDADD = $(LDADD) +timetrim_DEPENDENCIES = ../libntp/libntp.a +timetrim_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = byteorder.c hist.c jitter.c kern.c longsize.c ntptime.c \ +precision.c sht.c testrs6000.c tickadj.c timetrim.c +DIST_COMMON = README Makefile.am Makefile.in ansi2knr.1 ansi2knr.c + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +SOURCES = byteorder.c hist.c jitter.c kern.c longsize.c ntptime.c precision.c sht.c testrs6000.c tickadj.c timetrim.c +OBJECTS = byteorder$U.o hist$U.o jitter$U.o kern$U.o longsize$U.o ntptime$U.o precision$U.o sht$U.o testrs6000$U.o tickadj$U.o timetrim$U.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps util/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f="`echo $$p|sed -e 's/$(EXEEXT)$$//' -e '$(transform)' -e 's/$$/$(EXEEXT)/'`"; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mostlyclean-krextra: + +clean-krextra: + -rm -f ansi2knr + +distclean-krextra: + +maintainer-clean-krextra: +ansi2knr: ansi2knr.o + $(LINK) ansi2knr.o $(LIBS) +ansi2knr.o: $(CONFIG_HEADER) + + +mostlyclean-kr: + -rm -f *_.c + +clean-kr: + +distclean-kr: + +maintainer-clean-kr: +byteorder$U.o: + +byteorder: $(byteorder_OBJECTS) $(byteorder_DEPENDENCIES) + @rm -f byteorder + $(LINK) $(byteorder_LDFLAGS) $(byteorder_OBJECTS) $(byteorder_LDADD) $(LIBS) +hist$U.o: + +hist: $(hist_OBJECTS) $(hist_DEPENDENCIES) + @rm -f hist + $(LINK) $(hist_LDFLAGS) $(hist_OBJECTS) $(hist_LDADD) $(LIBS) +jitter$U.o: + +jitter: $(jitter_OBJECTS) $(jitter_DEPENDENCIES) + @rm -f jitter + $(LINK) $(jitter_LDFLAGS) $(jitter_OBJECTS) $(jitter_LDADD) $(LIBS) +kern$U.o: + +kern: $(kern_OBJECTS) $(kern_DEPENDENCIES) + @rm -f kern + $(LINK) $(kern_LDFLAGS) $(kern_OBJECTS) $(kern_LDADD) $(LIBS) +longsize$U.o: + +longsize: $(longsize_OBJECTS) $(longsize_DEPENDENCIES) + @rm -f longsize + $(LINK) $(longsize_LDFLAGS) $(longsize_OBJECTS) $(longsize_LDADD) $(LIBS) +ntptime$U.o: + +ntptime: $(ntptime_OBJECTS) $(ntptime_DEPENDENCIES) + @rm -f ntptime + $(LINK) $(ntptime_LDFLAGS) $(ntptime_OBJECTS) $(ntptime_LDADD) $(LIBS) +precision$U.o: + +precision: $(precision_OBJECTS) $(precision_DEPENDENCIES) + @rm -f precision + $(LINK) $(precision_LDFLAGS) $(precision_OBJECTS) $(precision_LDADD) $(LIBS) +sht$U.o: + +sht: $(sht_OBJECTS) $(sht_DEPENDENCIES) + @rm -f sht + $(LINK) $(sht_LDFLAGS) $(sht_OBJECTS) $(sht_LDADD) $(LIBS) +testrs6000$U.o: + +testrs6000: $(testrs6000_OBJECTS) $(testrs6000_DEPENDENCIES) + @rm -f testrs6000 + $(LINK) $(testrs6000_LDFLAGS) $(testrs6000_OBJECTS) $(testrs6000_LDADD) $(LIBS) +tickadj$U.o: + +tickadj: $(tickadj_OBJECTS) $(tickadj_DEPENDENCIES) + @rm -f tickadj + $(LINK) $(tickadj_LDFLAGS) $(tickadj_OBJECTS) $(tickadj_LDADD) $(LIBS) +timetrim$U.o: + +timetrim: $(timetrim_OBJECTS) $(timetrim_DEPENDENCIES) + @rm -f timetrim + $(LINK) $(timetrim_LDFLAGS) $(timetrim_OBJECTS) $(timetrim_LDADD) $(LIBS) +byteorder_.c: byteorder.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/byteorder.c; then echo $(srcdir)/byteorder.c; else echo byteorder.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > byteorder_.c +hist_.c: hist.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/hist.c; then echo $(srcdir)/hist.c; else echo hist.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > hist_.c +jitter_.c: jitter.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jitter.c; then echo $(srcdir)/jitter.c; else echo jitter.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > jitter_.c +kern_.c: kern.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/kern.c; then echo $(srcdir)/kern.c; else echo kern.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > kern_.c +longsize_.c: longsize.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/longsize.c; then echo $(srcdir)/longsize.c; else echo longsize.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > longsize_.c +ntptime_.c: ntptime.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntptime.c; then echo $(srcdir)/ntptime.c; else echo ntptime.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > ntptime_.c +precision_.c: precision.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/precision.c; then echo $(srcdir)/precision.c; else echo precision.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > precision_.c +sht_.c: sht.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/sht.c; then echo $(srcdir)/sht.c; else echo sht.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > sht_.c +testrs6000_.c: testrs6000.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/testrs6000.c; then echo $(srcdir)/testrs6000.c; else echo testrs6000.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > testrs6000_.c +tickadj_.c: tickadj.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/tickadj.c; then echo $(srcdir)/tickadj.c; else echo tickadj.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > tickadj_.c +timetrim_.c: timetrim.c $(ANSI2KNR) + $(CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/timetrim.c; then echo $(srcdir)/timetrim.c; else echo timetrim.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > timetrim_.c +byteorder_.o hist_.o jitter_.o kern_.o longsize_.o ntptime_.o \ +precision_.o sht_.o testrs6000_.o tickadj_.o timetrim_.o : $(ANSI2KNR) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + ${AWK:-awk} ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +byteorder.o byteorder.lo: byteorder.c +hist.o hist.lo: hist.c ../config.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../include/ntp_proto.h +jitter.o jitter.lo: jitter.c +kern.o kern.lo: kern.c ../config.h +longsize.o longsize.lo: longsize.c +ntptime.o: ntptime.c ../config.h ../include/ntp_fp.h \ + ../include/ntp_types.h ../include/ntp_machine.h \ + ../include/ntp_proto.h ../include/ntp_unixtime.h \ + ../include/ntp_syscall.h ../include/ntp_stdlib.h \ + ../include/ntp_string.h ../include/l_stdlib.h +precision.o precision.lo: precision.c ../include/ntp_unixtime.h \ + ../include/ntp_types.h ../include/ntp_machine.h ../config.h \ + ../include/ntp_proto.h +sht.o sht.lo: sht.c +testrs6000.o testrs6000.lo: testrs6000.c +tickadj.o: tickadj.c ../config.h ../include/ntp_types.h \ + ../include/ntp_machine.h ../include/ntp_proto.h \ + ../include/l_stdlib.h ../include/ntp_io.h \ + ../include/ntp_stdlib.h ../include/ntp_string.h +timetrim.o timetrim.lo: timetrim.c + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(ANSI2KNR) $(PROGRAMS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-krextra mostlyclean-kr mostlyclean-tags \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-compile clean-krextra clean-kr \ + clean-tags clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-compile distclean-krextra \ + distclean-kr distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-krextra \ + maintainer-clean-kr maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-krextra distclean-krextra \ +clean-krextra maintainer-clean-krextra mostlyclean-kr distclean-kr \ +clean-kr maintainer-clean-kr tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all install-strip installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +kern.o: kern.c + $(COMPILE) -DHAVE_TIMEX_H -c kern.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ntp/util/README b/contrib/ntp/util/README new file mode 100644 index 000000000000..b9ed50e19c1e --- /dev/null +++ b/contrib/ntp/util/README @@ -0,0 +1,37 @@ +README file for directory ./util of the NTP Version 4 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. See the kernel page file in the HTML documentation in +distribution for further details. ntptime will be built be if configure +believes your system can use it. + +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 10 us-1 ms. For those systems with +microsecond counters, such as recent Sun and certain HP and DEC 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 configure scripts for further details. + +The testrs6000.c program is used for testing purposes with the IBM +RS/6000 AIX machines. Bill Jones reports: +"I could not get a tickadj of less then 40 us to work on a RS6000. +If you set it less then 40 us do so at your own risk!" + +The tickadj.c program can be used to read and set various kernel +parameters affecting NTP operations. See the tickadj page in the HTML +documentation for further details. tickadj will be built if configure +believes your system can use it. diff --git a/contrib/ntp/util/ansi2knr.1 b/contrib/ntp/util/ansi2knr.1 new file mode 100644 index 000000000000..f9ee5a631c2e --- /dev/null +++ b/contrib/ntp/util/ansi2knr.1 @@ -0,0 +1,36 @@ +.TH ANSI2KNR 1 "19 Jan 1996" +.SH NAME +ansi2knr \- convert ANSI C to Kernighan & Ritchie C +.SH SYNOPSIS +.I ansi2knr +[--varargs] input_file [output_file] +.SH DESCRIPTION +If no output_file is supplied, output goes to stdout. +.br +There are no error messages. +.sp +.I ansi2knr +recognizes function definitions by seeing a non-keyword identifier at the left +margin, followed by a left parenthesis, with a right parenthesis as the last +character on the line, and with a left brace as the first token on the +following line (ignoring possible intervening comments). It will recognize a +multi-line header provided that no intervening line ends with a left or right +brace or a semicolon. These algorithms ignore whitespace and comments, except +that the function name must be the first thing on the line. +.sp +The following constructs will confuse it: +.br + - Any other construct that starts at the left margin and follows the +above syntax (such as a macro or function call). +.br + - Some macros that tinker with the syntax of the function header. +.sp +The --varargs switch is obsolete, and is recognized only for +backwards compatibility. The present version of +.I ansi2knr +will always attempt to convert a ... argument to va_alist and va_dcl. +.SH AUTHOR +L. Peter Deutsch wrote the original ansi2knr and +continues to maintain the current version; most of the code in the current +version is his work. ansi2knr also includes contributions by Francois +Pinard and Jim Avera . diff --git a/contrib/ntp/util/ansi2knr.c b/contrib/ntp/util/ansi2knr.c new file mode 100644 index 000000000000..bc36ce4b51fc --- /dev/null +++ b/contrib/ntp/util/ansi2knr.c @@ -0,0 +1,720 @@ +/* Copyright (C) 1989, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved. */ + +/*$Id: ansi2knr.c,v 1.2 1999/08/18 23:33:56 stenn Exp $*/ +/* Convert ANSI C function definitions to K&R ("traditional C") syntax */ + +/* +ansi2knr is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone for the +consequences of using it or for whether it serves any particular purpose or +works at all, unless he says so in writing. Refer to the GNU General Public +License (the "GPL") for full details. + +Everyone is granted permission to copy, modify and redistribute ansi2knr, +but only under the conditions described in the GPL. A copy of this license +is supposed to have been given to you along with ansi2knr so you can know +your rights and responsibilities. It should be in a file named COPYLEFT, +or, if there is no file named COPYLEFT, a file named COPYING. Among other +things, the copyright notice and this notice must be preserved on all +copies. + +We explicitly state here what we believe is already implied by the GPL: if +the ansi2knr program is distributed as a separate set of sources and a +separate executable file which are aggregated on a storage medium together +with another program, this in itself does not bring the other program under +the GPL, nor does the mere fact that such a program or the procedures for +constructing it invoke the ansi2knr executable bring any other part of the +program under the GPL. +*/ + +/* + * Usage: + ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]] + * --filename provides the file name for the #line directive in the output, + * overriding input_file (if present). + * If no input_file is supplied, input is read from stdin. + * If no output_file is supplied, output goes to stdout. + * There are no error messages. + * + * ansi2knr recognizes function definitions by seeing a non-keyword + * identifier at the left margin, followed by a left parenthesis, with a + * right parenthesis as the last character on the line, and with a left + * brace as the first token on the following line (ignoring possible + * intervening comments and/or preprocessor directives), except that a line + * consisting of only + * identifier1(identifier2) + * will not be considered a function definition unless identifier2 is + * the word "void", and a line consisting of + * identifier1(identifier2, <>) + * will not be considered a function definition. + * ansi2knr will recognize a multi-line header provided that no intervening + * line ends with a left or right brace or a semicolon. These algorithms + * ignore whitespace, comments, and preprocessor directives, except that + * the function name must be the first thing on the line. The following + * constructs will confuse it: + * - Any other construct that starts at the left margin and + * follows the above syntax (such as a macro or function call). + * - Some macros that tinker with the syntax of function headers. + */ + +/* + * The original and principal author of ansi2knr is L. Peter Deutsch + * . Other authors are noted in the change history + * that follows (in reverse chronological order): + lpd 1999-08-17 added code to allow preprocessor directives + wherever comments are allowed + lpd 1999-04-12 added minor fixes from Pavel Roskin + for clean compilation with + gcc -W -Wall + lpd 1999-03-22 added hack to recognize lines consisting of + identifier1(identifier2, xxx) as *not* being procedures + lpd 1999-02-03 made indentation of preprocessor commands consistent + lpd 1999-01-28 fixed two bugs: a '/' in an argument list caused an + endless loop; quoted strings within an argument list + confused the parser + lpd 1999-01-24 added a check for write errors on the output, + suggested by Jim Meyering + lpd 1998-11-09 added further hack to recognize identifier(void) + as being a procedure + lpd 1998-10-23 added hack to recognize lines consisting of + identifier1(identifier2) as *not* being procedures + lpd 1997-12-08 made input_file optional; only closes input and/or + output file if not stdin or stdout respectively; prints + usage message on stderr rather than stdout; adds + --filename switch (changes suggested by + ) + lpd 1996-01-21 added code to cope with not HAVE_CONFIG_H and with + compilers that don't understand void, as suggested by + Tom Lane + lpd 1996-01-15 changed to require that the first non-comment token + on the line following a function header be a left brace, + to reduce sensitivity to macros, as suggested by Tom Lane + + lpd 1995-06-22 removed #ifndefs whose sole purpose was to define + undefined preprocessor symbols as 0; changed all #ifdefs + for configuration symbols to #ifs + lpd 1995-04-05 changed copyright notice to make it clear that + including ansi2knr in a program does not bring the entire + program under the GPL + lpd 1994-12-18 added conditionals for systems where ctype macros + don't handle 8-bit characters properly, suggested by + Francois Pinard ; + removed --varargs switch (this is now the default) + lpd 1994-10-10 removed CONFIG_BROKETS conditional + lpd 1994-07-16 added some conditionals to help GNU `configure', + suggested by Francois Pinard ; + properly erase prototype args in function parameters, + contributed by Jim Avera ; + correct error in writeblanks (it shouldn't erase EOLs) + lpd 1989-xx-xx original version + */ + +/* Most of the conditionals here are to make ansi2knr work with */ +/* or without the GNU configure machinery. */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include + +#if HAVE_CONFIG_H + +/* + For properly autoconfiguring ansi2knr, use AC_CONFIG_HEADER(config.h). + This will define HAVE_CONFIG_H and so, activate the following lines. + */ + +# if STDC_HEADERS || HAVE_STRING_H +# include +# else +# include +# endif + +#else /* not HAVE_CONFIG_H */ + +/* Otherwise do it the hard way */ + +# ifdef BSD +# include +# else +# ifdef VMS + extern int strlen(), strncmp(); +# else +# include +# endif +# endif + +#endif /* not HAVE_CONFIG_H */ + +#if STDC_HEADERS +# include +#else +/* + malloc and free should be declared in stdlib.h, + but if you've got a K&R compiler, they probably aren't. + */ +# ifdef MSDOS +# include +# else +# ifdef VMS + extern char *malloc(); + extern void free(); +# else + extern char *malloc(); + extern int free(); +# endif +# endif + +#endif + +/* Define NULL (for *very* old compilers). */ +#ifndef NULL +# define NULL (0) +#endif + +/* + * The ctype macros don't always handle 8-bit characters correctly. + * Compensate for this here. + */ +#ifdef isascii +# undef HAVE_ISASCII /* just in case */ +# define HAVE_ISASCII 1 +#else +#endif +#if STDC_HEADERS || !HAVE_ISASCII +# define is_ascii(c) 1 +#else +# define is_ascii(c) isascii(c) +#endif + +#define is_space(c) (is_ascii(c) && isspace(c)) +#define is_alpha(c) (is_ascii(c) && isalpha(c)) +#define is_alnum(c) (is_ascii(c) && isalnum(c)) + +/* Scanning macros */ +#define isidchar(ch) (is_alnum(ch) || (ch) == '_') +#define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_') + +/* Forward references */ +char *ppdirforward(); +char *ppdirbackward(); +char *skipspace(); +char *scanstring(); +int writeblanks(); +int test1(); +int convert1(); + +/* The main program */ +int +main(argc, argv) + int argc; + char *argv[]; +{ FILE *in = stdin; + FILE *out = stdout; + char *filename = 0; + char *program_name = argv[0]; + char *output_name = 0; +#define bufsize 5000 /* arbitrary size */ + char *buf; + char *line; + char *more; + char *usage = + "Usage: ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]\n"; + /* + * In previous versions, ansi2knr recognized a --varargs switch. + * If this switch was supplied, ansi2knr would attempt to convert + * a ... argument to va_alist and va_dcl; if this switch was not + * supplied, ansi2knr would simply drop any such arguments. + * Now, ansi2knr always does this conversion, and we only + * check for this switch for backward compatibility. + */ + int convert_varargs = 1; + int output_error; + + while ( argc > 1 && argv[1][0] == '-' ) { + if ( !strcmp(argv[1], "--varargs") ) { + convert_varargs = 1; + argc--; + argv++; + continue; + } + if ( !strcmp(argv[1], "--filename") && argc > 2 ) { + filename = argv[2]; + argc -= 2; + argv += 2; + continue; + } + fprintf(stderr, "%s: Unrecognized switch: %s\n", program_name, + argv[1]); + fprintf(stderr, usage); + exit(1); + } + switch ( argc ) + { + default: + fprintf(stderr, usage); + exit(0); + case 3: + output_name = argv[2]; + out = fopen(output_name, "w"); + if ( out == NULL ) { + fprintf(stderr, "%s: Cannot open output file %s\n", + program_name, output_name); + exit(1); + } + /* falls through */ + case 2: + in = fopen(argv[1], "r"); + if ( in == NULL ) { + fprintf(stderr, "%s: Cannot open input file %s\n", + program_name, argv[1]); + exit(1); + } + if ( filename == 0 ) + filename = argv[1]; + /* falls through */ + case 1: + break; + } + if ( filename ) + fprintf(out, "#line 1 \"%s\"\n", filename); + buf = malloc(bufsize); + if ( buf == NULL ) + { + fprintf(stderr, "Unable to allocate read buffer!\n"); + exit(1); + } + line = buf; + while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL ) + { +test: line += strlen(line); + switch ( test1(buf) ) + { + case 2: /* a function header */ + convert1(buf, out, 1, convert_varargs); + break; + case 1: /* a function */ + /* Check for a { at the start of the next line. */ + more = ++line; +f: if ( line >= buf + (bufsize - 1) ) /* overflow check */ + goto wl; + if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL ) + goto wl; + switch ( *skipspace(ppdirforward(more), 1) ) + { + case '{': + /* Definitely a function header. */ + convert1(buf, out, 0, convert_varargs); + fputs(more, out); + break; + case 0: + /* The next line was blank or a comment: */ + /* keep scanning for a non-comment. */ + line += strlen(line); + goto f; + default: + /* buf isn't a function header, but */ + /* more might be. */ + fputs(buf, out); + strcpy(buf, more); + line = buf; + goto test; + } + break; + case -1: /* maybe the start of a function */ + if ( line != buf + (bufsize - 1) ) /* overflow check */ + continue; + /* falls through */ + default: /* not a function */ +wl: fputs(buf, out); + break; + } + line = buf; + } + if ( line != buf ) + fputs(buf, out); + free(buf); + if ( output_name ) { + output_error = ferror(out); + output_error |= fclose(out); + } else { /* out == stdout */ + fflush(out); + output_error = ferror(out); + } + if ( output_error ) { + fprintf(stderr, "%s: error writing to %s\n", program_name, + (output_name ? output_name : "stdout")); + exit(1); + } + if ( in != stdin ) + fclose(in); + return 0; +} + +/* + * Skip forward or backward over one or more preprocessor directives. + */ +char * +ppdirforward(p) + char *p; +{ + for (; *p == '#'; ++p) { + for (; *p != '\r' && *p != '\n'; ++p) + if (*p == 0) + return p; + if (*p == '\r' && p[1] == '\n') + ++p; + } + return p; +} +char * +ppdirbackward(p, limit) + char *p; + char *limit; +{ + char *np = p; + + for (;; p = --np) { + if (*np == '\n' && np[-1] == '\r') + --np; + for (; np > limit && np[-1] != '\r' && np[-1] != '\n'; --np) + if (np[-1] == 0) + return np; + if (*np != '#') + return p; + } +} + +/* + * Skip over whitespace, comments, and preprocessor directives, + * in either direction. + */ +char * +skipspace(p, dir) + char *p; + int dir; /* 1 for forward, -1 for backward */ +{ + for ( ; ; ) { + while ( is_space(*p) ) + p += dir; + if ( !(*p == '/' && p[dir] == '*') ) + break; + p += dir; p += dir; + while ( !(*p == '*' && p[dir] == '/') ) { + if ( *p == 0 ) + return p; /* multi-line comment?? */ + p += dir; + } + p += dir; p += dir; + } + return p; +} + +/* Scan over a quoted string, in either direction. */ +char * +scanstring(p, dir) + char *p; + int dir; +{ + for (p += dir; ; p += dir) + if (*p == '"' && p[-dir] != '\\') + return p + dir; +} + +/* + * Write blanks over part of a string. + * Don't overwrite end-of-line characters. + */ +int +writeblanks(start, end) + char *start; + char *end; +{ char *p; + for ( p = start; p < end; p++ ) + if ( *p != '\r' && *p != '\n' ) + *p = ' '; + return 0; +} + +/* + * Test whether the string in buf is a function definition. + * The string may contain and/or end with a newline. + * Return as follows: + * 0 - definitely not a function definition; + * 1 - definitely a function definition; + * 2 - definitely a function prototype (NOT USED); + * -1 - may be the beginning of a function definition, + * append another line and look again. + * The reason we don't attempt to convert function prototypes is that + * Ghostscript's declaration-generating macros look too much like + * prototypes, and confuse the algorithms. + */ +int +test1(buf) + char *buf; +{ char *p = buf; + char *bend; + char *endfn; + int contin; + + if ( !isidfirstchar(*p) ) + return 0; /* no name at left margin */ + bend = skipspace(ppdirbackward(buf + strlen(buf) - 1, buf), -1); + switch ( *bend ) + { + case ';': contin = 0 /*2*/; break; + case ')': contin = 1; break; + case '{': return 0; /* not a function */ + case '}': return 0; /* not a function */ + default: contin = -1; + } + while ( isidchar(*p) ) + p++; + endfn = p; + p = skipspace(p, 1); + if ( *p++ != '(' ) + return 0; /* not a function */ + p = skipspace(p, 1); + if ( *p == ')' ) + return 0; /* no parameters */ + /* Check that the apparent function name isn't a keyword. */ + /* We only need to check for keywords that could be followed */ + /* by a left parenthesis (which, unfortunately, is most of them). */ + { static char *words[] = + { "asm", "auto", "case", "char", "const", "double", + "extern", "float", "for", "if", "int", "long", + "register", "return", "short", "signed", "sizeof", + "static", "switch", "typedef", "unsigned", + "void", "volatile", "while", 0 + }; + char **key = words; + char *kp; + unsigned len = endfn - buf; + + while ( (kp = *key) != 0 ) + { if ( strlen(kp) == len && !strncmp(kp, buf, len) ) + return 0; /* name is a keyword */ + key++; + } + } + { + char *id = p; + int len; + /* + * Check for identifier1(identifier2) and not + * identifier1(void), or identifier1(identifier2, xxxx). + */ + + while ( isidchar(*p) ) + p++; + len = p - id; + p = skipspace(p, 1); + if (*p == ',' || + (*p == ')' && (len != 4 || strncmp(id, "void", 4))) + ) + return 0; /* not a function */ + } + /* + * If the last significant character was a ), we need to count + * parentheses, because it might be part of a formal parameter + * that is a procedure. + */ + if (contin > 0) { + int level = 0; + + for (p = skipspace(buf, 1); *p; p = skipspace(p + 1, 1)) + level += (*p == '(' ? 1 : *p == ')' ? -1 : 0); + if (level > 0) + contin = -1; + } + return contin; +} + +/* Convert a recognized function definition or header to K&R syntax. */ +int +convert1(buf, out, header, convert_varargs) + char *buf; + FILE *out; + int header; /* Boolean */ + int convert_varargs; /* Boolean */ +{ char *endfn; + char *p; + /* + * The breaks table contains pointers to the beginning and end + * of each argument. + */ + char **breaks; + unsigned num_breaks = 2; /* for testing */ + char **btop; + char **bp; + char **ap; + char *vararg = 0; + + /* Pre-ANSI implementations don't agree on whether strchr */ + /* is called strchr or index, so we open-code it here. */ + for ( endfn = buf; *(endfn++) != '('; ) + ; +top: p = endfn; + breaks = (char **)malloc(sizeof(char *) * num_breaks * 2); + if ( breaks == NULL ) + { /* Couldn't allocate break table, give up */ + fprintf(stderr, "Unable to allocate break table!\n"); + fputs(buf, out); + return -1; + } + btop = breaks + num_breaks * 2 - 2; + bp = breaks; + /* Parse the argument list */ + do + { int level = 0; + char *lp = NULL; + char *rp = NULL; + char *end = NULL; + + if ( bp >= btop ) + { /* Filled up break table. */ + /* Allocate a bigger one and start over. */ + free((char *)breaks); + num_breaks <<= 1; + goto top; + } + *bp++ = p; + /* Find the end of the argument */ + for ( ; end == NULL; p++ ) + { switch(*p) + { + case ',': + if ( !level ) end = p; + break; + case '(': + if ( !level ) lp = p; + level++; + break; + case ')': + if ( --level < 0 ) end = p; + else rp = p; + break; + case '/': + if (p[1] == '*') + p = skipspace(p, 1) - 1; + break; + case '"': + p = scanstring(p, 1) - 1; + break; + default: + ; + } + } + /* Erase any embedded prototype parameters. */ + if ( lp && rp ) + writeblanks(lp + 1, rp); + p--; /* back up over terminator */ + /* Find the name being declared. */ + /* This is complicated because of procedure and */ + /* array modifiers. */ + for ( ; ; ) + { p = skipspace(p - 1, -1); + switch ( *p ) + { + case ']': /* skip array dimension(s) */ + case ')': /* skip procedure args OR name */ + { int level = 1; + while ( level ) + switch ( *--p ) + { + case ']': case ')': + level++; + break; + case '[': case '(': + level--; + break; + case '/': + if (p > buf && p[-1] == '*') + p = skipspace(p, -1) + 1; + break; + case '"': + p = scanstring(p, -1) + 1; + break; + default: ; + } + } + if ( *p == '(' && *skipspace(p + 1, 1) == '*' ) + { /* We found the name being declared */ + while ( !isidfirstchar(*p) ) + p = skipspace(p, 1) + 1; + goto found; + } + break; + default: + goto found; + } + } +found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' ) + { if ( convert_varargs ) + { *bp++ = "va_alist"; + vararg = p-2; + } + else + { p++; + if ( bp == breaks + 1 ) /* sole argument */ + writeblanks(breaks[0], p); + else + writeblanks(bp[-1] - 1, p); + bp--; + } + } + else + { while ( isidchar(*p) ) p--; + *bp++ = p+1; + } + p = end; + } + while ( *p++ == ',' ); + *bp = p; + /* Make a special check for 'void' arglist */ + if ( bp == breaks+2 ) + { p = skipspace(breaks[0], 1); + if ( !strncmp(p, "void", 4) ) + { p = skipspace(p+4, 1); + if ( p == breaks[2] - 1 ) + { bp = breaks; /* yup, pretend arglist is empty */ + writeblanks(breaks[0], p + 1); + } + } + } + /* Put out the function name and left parenthesis. */ + p = buf; + while ( p != endfn ) putc(*p, out), p++; + /* Put out the declaration. */ + if ( header ) + { fputs(");", out); + for ( p = breaks[0]; *p; p++ ) + if ( *p == '\r' || *p == '\n' ) + putc(*p, out); + } + else + { for ( ap = breaks+1; ap < bp; ap += 2 ) + { p = *ap; + while ( isidchar(*p) ) + putc(*p, out), p++; + if ( ap < bp - 1 ) + fputs(", ", out); + } + fputs(") ", out); + /* Put out the argument declarations */ + for ( ap = breaks+2; ap <= bp; ap += 2 ) + (*ap)[-1] = ';'; + if ( vararg != 0 ) + { *vararg = 0; + fputs(breaks[0], out); /* any prior args */ + fputs("va_dcl", out); /* the final arg */ + fputs(bp[0], out); + } + else + fputs(breaks[0], out); + } + free((char *)breaks); + return 0; +} diff --git a/contrib/ntp/util/byteorder.c b/contrib/ntp/util/byteorder.c new file mode 100644 index 000000000000..188536fa89ab --- /dev/null +++ b/contrib/ntp/util/byteorder.c @@ -0,0 +1,56 @@ +/* + * This works on: + * Crays + * Conven + * sparc's + * Dec mip machines + * Dec alpha machines + * RS6000 + * SGI's + */ + +#include + +int +main( + int argc, + char *argv[] + ) +{ + 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/ntp/util/hist.c b/contrib/ntp/util/hist.c new file mode 100644 index 000000000000..ee4e93ad6a27 --- /dev/null +++ b/contrib/ntp/util/hist.c @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include + +#include "ntp_types.h" + +#define NBUF 100001 /* size of basic histogram */ +#define NSRT 20000 /* size of overflow histogram */ +#define NCNT (600 * 1000000) /* sample interval (us) */ + +int col P((long *, long *)); + +int +main( + int argc, + char *argv[] + ) +{ + struct timeval ts, tr, tp; + struct timezone tzp; + int i, j, n; + long t, u, v, w, gtod[NBUF], ovfl[NSRT]; + + /* + * Force pages into memory + */ + for (i = 0; i < NBUF; i++) + gtod[i] = 0; + for (i = 0; i < NSRT; i++) + ovfl[i] = 0; + + /* + * Construct histogram + */ + n = 0; + gettimeofday(&ts, &tzp); + t = ts.tv_sec * 1000000 + ts.tv_usec; + v = t; + while (1) { + gettimeofday(&tr, &tzp); + u = tr.tv_sec * 1000000 + tr.tv_usec; + if (u - v > NCNT) + break; + w = u - t; + if (w <= 0) { +/* + printf("error <= 0 %ld %d %d, %d %d\n", w, ts.tv_sec, + ts.tv_usec, tr.tv_sec, tr.tv_usec); +*/ + } else if (w > NBUF - 1) { + ovfl[n] = w; + if (n < NSRT - 1) + n++; + } else { + gtod[w]++; + } + ts = tr; + t = u; + } + + /* + * Write out histogram + */ + for (i = 0; i < NBUF - 1; i++) { + if (gtod[i] > 0) + printf("%ld %ld\n", i, gtod[i]); + } + if (n == 0) + return; + qsort((char *)ovfl, (int)n, sizeof(long), col); + w = 0; + j = 0; + for (i = 0; i < n; i++) { + if (ovfl[i] != w) { + if (j > 0) + printf("%ld %ld\n", w, j); + w = ovfl[i]; + j = 1; + } else + j++; + } + if (j > 0) + printf("%ld %ld\n", w, j); + + exit(0); +} + +int +col( + long *x, + long *y + ) +{ + return (*x - *y); +} diff --git a/contrib/ntp/util/jitter.c b/contrib/ntp/util/jitter.c new file mode 100644 index 000000000000..79f47573f584 --- /dev/null +++ b/contrib/ntp/util/jitter.c @@ -0,0 +1,70 @@ +/* + * This program can be used to calibrate the clock reading jitter of a + * particular CPU and operating system. It first tickles every element + * of an array, in order to force pages into memory, then repeatedly calls + * gettimeofday() and, finally, writes out the time values for later + * analysis. From this you can determine the jitter and if the clock ever + * runs backwards. + */ +#include +#include + +#define NBUF 20002 + +int +main( + int argc, + char *argv[] + ) +{ + struct timeval ts, tr; + struct timezone tzp; + long temp, j, i, gtod[NBUF]; + + gettimeofday(&ts, &tzp); + + /* + * Force pages into memory + */ + for (i = 0; i < NBUF; i ++) + gtod[i] = 0; + + /* + * Construct gtod array + */ + for (i = 0; i < NBUF; i ++) { + gettimeofday(&tr, &tzp); + gtod[i] = (tr.tv_sec - ts.tv_sec) * 1000000 + tr.tv_usec; + } + + /* + * Write out gtod array for later processing with S + */ + for (i = 0; i < NBUF - 2; 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 - 2; 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 - 12; i < NBUF - 2; i++) + fprintf(stderr, "%10ld%10ld\n", i, gtod[i]); + exit(0); +} diff --git a/contrib/ntp/util/kern.c b/contrib/ntp/util/kern.c new file mode 100644 index 000000000000..37d925723761 --- /dev/null +++ b/contrib/ntp/util/kern.c @@ -0,0 +1,224 @@ +/* + * 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. + */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_TIMEX_H +# include "timex.h" +#endif + +/* + * 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 + */ +int +main( + int argc, + char *argv[] + ) +{ + 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( + 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(void) +{ + 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(void) +{ + 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/ntp/util/longsize.c b/contrib/ntp/util/longsize.c new file mode 100644 index 000000000000..bba19557ad74 --- /dev/null +++ b/contrib/ntp/util/longsize.c @@ -0,0 +1,11 @@ +#include + +main() +{ + if (sizeof(long) == 8) { + printf("-DLONG8\n"); + } else if (sizeof(long) == 4) { + printf("-DLONG4\n"); + } + exit(0); +} diff --git a/contrib/ntp/util/ntptime.c b/contrib/ntp/util/ntptime.c new file mode 100644 index 000000000000..1a6f2f363723 --- /dev/null +++ b/contrib/ntp/util/ntptime.c @@ -0,0 +1,399 @@ +/* + * 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. + */ +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include "ntp_fp.h" +#include "ntp_unixtime.h" +#include "ntp_syscall.h" +#include "ntp_stdlib.h" + +#ifdef NTP_SYSCALLS_STD +# ifndef SYS_DECOSF1 +# define BADCALL -1 /* this is supposed to be a bad syscall */ +# endif /* SYS_DECOSF1 */ +#endif + +#ifdef HAVE_TV_NSEC_IN_NTPTIMEVAL +#define tv_frac_sec tv_nsec +#else +#define tv_frac_sec tv_usec +#endif + + +#define TIMEX_MOD_BITS \ +"\20\1OFFSET\2FREQUENCY\3MAXERROR\4ESTERROR\5STATUS\6TIMECONST\ +\13PLL\14FLL\15MICRO\16NANO\17CLKB\20CLKA" + +#define TIMEX_STA_BITS \ +"\20\1PLL\2PPSFREQ\3PPSTIME\4FLL\5INS\6DEL\7UNSYNC\10FREQHOLD\ +\11PPSSIGNAL\12PPSJITTER\13PPSWANDER\14PPSERROR\15CLOCKERR\ +\16NANO\17MODE\20CLK" + +#define SCALE_FREQ 65536 /* frequency scale */ + + +/* + * Function prototypes + */ +char *sprintb P((u_int, const char *)); +const char *timex_state P((int)); +volatile int debug = 0; + +#ifdef SIGSYS +void pll_trap P((int)); + +static struct sigaction newsigsys; /* new sigaction status */ +static struct sigaction sigsys; /* current sigaction status */ +static sigjmp_buf env; /* environment var. for pll_trap() */ +#endif + +static volatile int pll_control; /* (0) daemon, (1) kernel loop */ +static volatile int status; /* most recent status bits */ +static volatile int flash; /* most recent ntp_adjtime() bits */ +char* progname; +static char optargs[] = "cde:f:hm:o:rs:t:"; + +int +main( + int argc, + char *argv[] + ) +{ + extern int ntp_optind; + extern char *ntp_optarg; +#ifdef SUBST_ADJTIMEX + struct timex ntv; +#else + struct ntptimeval ntv; +#endif + struct timeval tv; + struct timex ntx, _ntx; + int times[20]; + double ftemp, gtemp, htemp; + long time_frac; /* ntv.time.tv_frac_sec (us/ns) */ + l_fp ts; + unsigned ts_mask = TS_MASK; /* defaults to 20 bits (us) */ + unsigned ts_roundbit = TS_ROUNDBIT; /* defaults to 20 bits (us) */ + int fdigits = 6; /* fractional digits for us */ + int c; + int errflg = 0; + int cost = 0; + int rawtime = 0; + + memset((char *)&ntx, 0, sizeof(ntx)); + progname = argv[0]; + while ((c = ntp_getopt(argc, argv, optargs)) != EOF) switch (c) { + case 'c': + cost++; + break; + case 'd': + debug++; + break; + case 'e': + ntx.modes |= MOD_ESTERROR; + ntx.esterror = atoi(ntp_optarg); + break; + case 'f': + ntx.modes |= MOD_FREQUENCY; + ntx.freq = (long)(atof(ntp_optarg) * SCALE_FREQ); + break; + case 'm': + ntx.modes |= MOD_MAXERROR; + ntx.maxerror = atoi(ntp_optarg); + break; + case 'o': + ntx.modes |= MOD_OFFSET; + ntx.offset = atoi(ntp_optarg); + break; + case 'r': + rawtime++; + break; + case 's': + ntx.modes |= MOD_STATUS; + ntx.status = atoi(ntp_optarg); + if (ntx.status < 0 || ntx.status > 4) errflg++; + break; + case 't': + ntx.modes |= MOD_TIMECONST; + ntx.constant = atoi(ntp_optarg); + 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 (-500 .. 500) (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\ +-l leap Set the leap bits\n\ +-t timeconstant log2 of PLL time constant (0 .. %d)\n", + progname, optargs, MAXTC); + exit(2); + } + +#ifdef SIGSYS + /* + * Test to make sure the sigaction() works in case of invalid + * syscall codes. + */ + newsigsys.sa_handler = pll_trap; + newsigsys.sa_flags = 0; + if (sigaction(SIGSYS, &newsigsys, &sigsys)) { + perror("sigaction() fails to save SIGSYS trap"); + exit(1); + } +#endif /* SIGSYS */ + +#ifdef BADCALL + /* + * Make sure the trapcatcher works. + */ + pll_control = 1; +#ifdef SIGSYS + if (sigsetjmp(env, 1) == 0) + { +#endif + status = syscall(BADCALL, &ntv); /* dummy parameter */ + if ((status < 0) && (errno == ENOSYS)) + --pll_control; +#ifdef SIGSYS + } +#endif + if (pll_control) + printf("sigaction() failed to catch an invalid syscall\n"); +#endif /* BADCALL */ + + if (cost) { +#ifdef SIGSYS + if (sigsetjmp(env, 1) == 0) { +#endif + for (c = 0; c < sizeof times / sizeof times[0]; c++) { + status = ntp_gettime(&ntv); + if ((status < 0) && (errno == ENOSYS)) + --pll_control; + if (pll_control < 0) + break; + times[c] = ntv.time.tv_frac_sec; + } +#ifdef SIGSYS + } +#endif + if (pll_control >= 0) { + printf("[ us %06d:", times[0]); + for (c = 1; c < sizeof times / sizeof times[0]; c++) + printf(" %d", times[c] - times[c - 1]); + printf(" ]\n"); + } + } +#ifdef SIGSYS + if (sigsetjmp(env, 1) == 0) { +#endif + status = ntp_gettime(&ntv); + if ((status < 0) && (errno == ENOSYS)) + --pll_control; +#ifdef SIGSYS + } +#endif + _ntx.modes = 0; /* Ensure nothing is set */ +#ifdef SIGSYS + if (sigsetjmp(env, 1) == 0) { +#endif + status = ntp_adjtime(&_ntx); + if ((status < 0) && (errno == ENOSYS)) + --pll_control; + flash = _ntx.status; +#ifdef SIGSYS + } +#endif + if (pll_control < 0) { + printf("NTP user interface routines are not configured in this kernel.\n"); + goto lexit; + } + + /* + * Fetch timekeeping data and display. + */ + status = ntp_gettime(&ntv); + if (status < 0) + perror("ntp_gettime() call fails"); + else { + printf("ntp_gettime() returns code %d (%s)\n", + status, timex_state(status)); + time_frac = ntv.time.tv_frac_sec; +#ifdef STA_NANO + if (flash & STA_NANO) { + ntv.time.tv_frac_sec /= 1000; + ts_mask = 0xfffffffc; /* 1/2^30 */ + ts_roundbit = 0x00000002; + fdigits = 9; + } +#endif + tv.tv_sec = ntv.time.tv_sec; + tv.tv_usec = ntv.time.tv_frac_sec; + TVTOTS(&tv, &ts); + ts.l_ui += JAN_1970; + ts.l_uf += ts_roundbit; + ts.l_uf &= ts_mask; + printf(" time %s, (.%0*d),\n", + prettydate(&ts), fdigits, (int) time_frac); + printf(" maximum error %lu us, estimated error %lu us.\n", + (u_long)ntv.maxerror, (u_long)ntv.esterror); + if (rawtime) printf(" ntptime=%x.%x unixtime=%x.%0*d %s", + (unsigned int) ts.l_ui, (unsigned int) ts.l_uf, + (int) ntv.time.tv_sec, fdigits, (int) time_frac, + ctime((const time_t *) &ntv.time.tv_sec)); + } + status = ntp_adjtime(&ntx); + if (status < 0) + perror((errno == EPERM) ? + "Must be root to set kernel values\nntp_adjtime() call fails" : + "ntp_adjtime() call fails"); + else { + flash = ntx.status; + printf("ntp_adjtime() returns code %d (%s)\n", + status, timex_state(status)); + printf(" modes %s,\n", sprintb(ntx.modes, TIMEX_MOD_BITS)); + ftemp = (double)ntx.offset; +#ifdef STA_NANO + if (flash & STA_NANO) + ftemp /= 1000.0; +#endif + printf(" offset %.3f", ftemp); + ftemp = (double)ntx.freq / SCALE_FREQ; + printf(" us, frequency %.3f ppm, interval %d s,\n", + ftemp, 1 << ntx.shift); + printf(" maximum error %lu us, estimated error %lu us,\n", + (u_long)ntx.maxerror, (u_long)ntx.esterror); + printf(" status %s,\n", sprintb((u_int)ntx.status, TIMEX_STA_BITS)); + ftemp = (double)ntx.tolerance / SCALE_FREQ; + gtemp = (double)ntx.precision; +#ifdef STA_NANO + if (flash & STA_NANO) + gtemp /= 1000.0; +#endif + printf( + " time constant %lu, precision %.3f us, tolerance %.0f ppm,\n", + (u_long)ntx.constant, gtemp, ftemp); + if (ntx.shift == 0) + exit (0); + ftemp = (double)ntx.ppsfreq / SCALE_FREQ; + gtemp = (double)ntx.stabil / SCALE_FREQ; + htemp = (double)ntx.jitter; +#ifdef STA_NANO + if (flash & STA_NANO) + htemp /= 1000.0; +#endif + printf( + " pps frequency %.3f ppm, stability %.3f ppm, jitter %.3f us,\n", + ftemp, gtemp, htemp); + printf(" intervals %lu, jitter exceeded %lu, stability exceeded %lu, errors %lu.\n", + (u_long)ntx.calcnt, (u_long)ntx.jitcnt, + (u_long)ntx.stbcnt, (u_long)ntx.errcnt); + return (0); + } + + /* + * Put things back together the way we found them. + */ + lexit: +#ifdef SIGSYS + if (sigaction(SIGSYS, &sigsys, (struct sigaction *)NULL)) { + perror("sigaction() fails to restore SIGSYS trap"); + exit(1); + } +#endif + exit(0); +} + +#ifdef SIGSYS +/* + * pll_trap - trap processor for undefined syscalls + */ +void +pll_trap( + int arg + ) +{ + pll_control--; + siglongjmp(env, 1); +} +#endif + +/* + * Print a value a la the %b format of the kernel's printf + */ +char * +sprintb( + register u_int v, + register const char *bits + ) +{ + register char *cp; + register int i, any = 0; + register char c; + static char buf[132]; + + if (bits && *bits == 8) + (void)sprintf(buf, "0%o", v); + else + (void)sprintf(buf, "0x%x", v); + cp = buf + strlen(buf); + bits++; + if (bits) { + *cp++ = ' '; + *cp++ = '('; + while ((i = *bits++) != 0) { + if (v & (1 << (i-1))) { + if (any) + *cp++ = ','; + any = 1; + for (; (c = *bits) > 32; bits++) + *cp++ = c; + } else + for (; *bits > 32; bits++) + continue; + } + *cp++ = ')'; + } + *cp = '\0'; + return (buf); +} + +const char *timex_states[] = { + "OK", "INS", "DEL", "OOP", "WAIT", "ERROR" +}; + +const char * +timex_state( + register int s + ) +{ + static char buf[32]; + + if (s >= 0 && s <= sizeof(timex_states) / sizeof(timex_states[0])) + return (timex_states[s]); + sprintf(buf, "TIME-#%d", s); + return (buf); +} diff --git a/contrib/ntp/util/precision.c b/contrib/ntp/util/precision.c new file mode 100644 index 000000000000..0fd3c3a3a726 --- /dev/null +++ b/contrib/ntp/util/precision.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include "ntp_unixtime.h" + +#define DEFAULT_SYS_PRECISION -99 + +int default_get_resolution(); +int default_get_precision(); + +int +main( + int argc, + char *argv[] + ) +{ + printf("log2(resolution) = %d, log2(precision) = %d\n", + default_get_resolution(), + default_get_precision()); + return 0; +} + +/* Find the resolution 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 resolution (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 resolution < 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 MAXSTEP 20000 /* maximum clock increment (us) */ +#define MINLOOPS 5 /* minimum number of step samples */ +#define MAXLOOPS HUSECS /* Assume precision < .1s ! */ + +int +default_get_resolution(void) +{ + struct timeval tp; + struct timezone tzp; + long last; + int i; + long diff; + long val; + int minsteps = MINLOOPS; /* 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("resolution = %ld usec after %d loop%s\n", + diff, i, (i==1) ? "" : "s"); + + diff = (diff *3)/2; + if (i >= MAXLOOPS) { + printf( + " (Boy this machine is fast ! %d loops without a step)\n", + MAXLOOPS); + diff = 1; /* No STEP, so FAST machine */ + } + if (i == 0) { + printf( + " (The resolution is less than the time to read the clock -- Assume 1us)\n"); + diff = 1; /* time to read clock >= resolution */ + } + for (i=0, val=HUSECS; val>0; i--, val >>= 1) if (diff >= val) return i; + printf(" (Oh dear -- that wasn't expected ! I'll guess !)\n"); + return DEFAULT_SYS_PRECISION /* Something's BUST, so lie ! */; +} + +/* ===== Rest of this code lifted straight from xntpd/ntp_proto.c ! ===== */ + +/* + * This routine calculates the differences between successive calls to + * gettimeofday(). If a difference is less than zero, the us field + * has rolled over to the next second, so we add a second in us. If + * the difference is greater than zero and less than MINSTEP, the + * clock has been advanced by a small amount to avoid standing still. + * If the clock has advanced by a greater amount, then a timer interrupt + * has occurred and this amount represents the precision of the clock. + * In order to guard against spurious values, which could occur if we + * happen to hit a fat interrupt, we do this for MINLOOPS times and + * keep the minimum value obtained. + */ +int +default_get_precision(void) +{ + struct timeval tp; + struct timezone tzp; +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif + long last; + int i; + long diff; + long val; + long usec; + + usec = 0; + val = MAXSTEP; +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tp.tv_sec = ts.tv_sec; + tp.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tp, &tzp); +#endif /* not HAVE_GETCLOCK */ + last = tp.tv_usec; + for (i = 0; i < MINLOOPS && usec < HUSECS;) { +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tp.tv_sec = ts.tv_sec; + tp.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tp, &tzp); +#endif /* not HAVE_GETCLOCK */ + diff = tp.tv_usec - last; + last = tp.tv_usec; + if (diff < 0) + diff += DUSECS; + usec += diff; + if (diff > MINSTEP) { + i++; + if (diff < val) + val = diff; + } + } + printf("precision = %ld usec after %d loop%s\n", + val, i, (i == 1) ? "" : "s"); + if (usec >= HUSECS) { + printf(" (Boy this machine is fast ! usec was %ld)\n", + usec); + val = MINSTEP; /* val <= MINSTEP; fast machine */ + } + diff = HUSECS; + for (i = 0; diff > val; i--) + diff >>= 1; + return (i); +} diff --git a/contrib/ntp/util/sht.c b/contrib/ntp/util/sht.c new file mode 100644 index 000000000000..4abd350505e1 --- /dev/null +++ b/contrib/ntp/util/sht.c @@ -0,0 +1,185 @@ +/* + * sht.c - Testprogram for shared memory refclock + * read/write shared memory segment; see usage + */ +#ifndef SYS_WINNT +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#define sleep(x) Sleep(x*1000) +#endif +#include +struct shmTime { + int mode; /* 0 - if valid set + * use values, + * clear valid + * 1 - if valid set + * if count before and after read of values is equal, + * use values + * clear valid + */ + int count; + time_t clockTimeStampSec; + int clockTimeStampUSec; + time_t receiveTimeStampSec; + int receiveTimeStampUSec; + int leap; + int precision; + int nsamples; + int valid; +}; + +struct shmTime * +getShmTime ( + int unit + ) +{ +#ifndef SYS_WINNT + int shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|0777); + if (shmid==-1) { + perror ("shmget"); + exit (1); + } + else { + struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0); + if ((int)(long)p==-1) { + perror ("shmat"); + p=0; + } + assert (p!=0); + return p; + } +#else + char buf[10]; + LPSECURITY_ATTRIBUTES psec=0; + sprintf (buf,"NTP%d",unit); + SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sa; + HANDLE shmid; + + assert (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)); + assert (SetSecurityDescriptorDacl(&sd,1,0,0)); + sa.nLength=sizeof (SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor=&sd; + sa.bInheritHandle=0; + shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE, + psec, sizeof (struct shmTime),buf); + if (!shmid) { + shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE, + 0, sizeof (struct shmTime),buf); + cout <<"CreateFileMapping with psec!=0 failed"<nsamples=atoi(&argv[1][1]); + } + break; + case 'l': { + p->leap=atoi(&argv[1][1]); + } + break; + case 'p': { + p->precision=-atoi(&argv[1][1]); + } + break; + case 'r': { + char *ap=&argv[1][1]; + int clear=0; + int loop=0; + printf ("reader\n"); + while (*ap) { + switch (*ap) { + case 'l' : loop=1; break; + case 'c' : clear=1; break; + } + ap++; + } + do { + printf ("mode=%d, count=%d, clock=%d.%d, rec=%d.%d,\n", + p->mode,p->count,p->clockTimeStampSec,p->clockTimeStampUSec, + p->receiveTimeStampSec,p->receiveTimeStampUSec); + printf (" leap=%d, precision=%d, nsamples=%d, valid=%d\n", + p->leap, p->precision, p->nsamples, p->valid); + if (!p->valid) + printf ("***\n"); + if (clear) { + p->valid=0; + printf ("cleared\n"); + } + if (loop) + sleep (1); + } while (loop); + } + break; + case 'w': { + printf ("writer\n"); + p->mode=0; + if (!p->valid) { + p->clockTimeStampSec=time(0)-20; + p->clockTimeStampUSec=0; + p->receiveTimeStampSec=time(0)-1; + p->receiveTimeStampUSec=0; + printf ("%d %d\n",p->clockTimeStampSec, p->receiveTimeStampSec); + p->valid=1; + } + else { + printf ("p->valid still set\n"); // not an error! + } + } + break; + } +} diff --git a/contrib/ntp/util/testrs6000.c b/contrib/ntp/util/testrs6000.c new file mode 100644 index 000000000000..e4d939ae4f0a --- /dev/null +++ b/contrib/ntp/util/testrs6000.c @@ -0,0 +1,55 @@ +/* Checks for the RS/6000 AIX adjtime() bug, in which if a negative + * offset is given, the system gets messed up and never completes the + * adjustment. If the problem is fixed, this program will print the + * time, sit there for 10 seconds, and exit. If the problem isn't fixed, + * the program will print an occasional "result=nnnnnn" (the residual + * slew from adjtime()). + * + * Compile this with bsdcc and run it as root! + */ +#include +#include +#include +#include + +int timeout(); +struct timeval adjustment, result; + +int +main ( + int argc, + char *argv[] + ) +{ + 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( + int sig, + int 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/ntp/util/tickadj.c b/contrib/ntp/util/tickadj.c new file mode 100644 index 000000000000..5ac812142dbc --- /dev/null +++ b/contrib/ntp/util/tickadj.c @@ -0,0 +1,904 @@ +/* + * 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. + * + * HMS: The #includes here are different from those in xntpd/ntp_unixclock.c + * These seem "worse". + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ + +#include "ntp_types.h" +#include "l_stdlib.h" + +#ifdef HAVE___ADJTIMEX /* Linux */ + +#include +struct timex txc; + +#if 0 +int +main( + int argc, + char *argv[] + ) +{ + int c, i; + int quiet = 0; + int errflg = 0; + char *progname; + extern int ntp_optind; + extern char *ntp_optarg; + + progname = argv[0]; + if (argc==2 && argv[1][0] != '-') { /* old Linux format, for compatability */ + if ((i = atoi(argv[1])) > 0) { + txc.time_tick = i; + txc.modes = ADJ_TIMETICK; + } else { + fprintf(stderr, "Silly value for tick: %s\n", argv[1]); + errflg++; + } + } else { + while ((c = ntp_getopt(argc, argv, "a:qt:")) != EOF) { + switch (c) { + case 'a': + if ((i=atoi(ntp_optarg)) > 0) { + txc.tickadj = i; + txc.modes |= ADJ_TICKADJ; + } else { + (void) fprintf(stderr, + "%s: unlikely value for tickadj: %s\n", + progname, ntp_optarg); + errflg++; + } + break; + + case 'q': + quiet = 1; + break; + + case 't': + if ((i=atoi(ntp_optarg)) > 0) { + txc.time_tick = i; + txc.modes |= ADJ_TIMETICK; + } else { + (void) fprintf(stderr, + "%s: unlikely value for tick: %s\n", + progname, ntp_optarg); + errflg++; + } + break; + + default: + fprintf(stderr, + "Usage: %s [tick_value]\n-or- %s [ -q ] [ -t tick ] [ -a tickadj ]\n", + progname, progname); + errflg++; + break; + } + } + } + + if (!errflg) { + if (__adjtimex(&txc) < 0) + perror("adjtimex"); + else if (!quiet) + printf("tick = %ld\ntick_adj = %d\n", + txc.time_tick, txc.tickadj); + } + + exit(errflg ? 1 : 0); +} +#else +int +main( + int argc, + char *argv[] + ) +{ + if (argc > 2) + { + fprintf(stderr, "Usage: %s [tick_value]\n", argv[0]); + exit(-1); + } + else if (argc == 2) + { +#ifdef ADJ_TIMETICK + if ( (txc.time_tick = atoi(argv[1])) < 1 ) +#else + if ( (txc.tick = atoi(argv[1])) < 1 ) +#endif + { + fprintf(stderr, "Silly value for tick: %s\n", argv[1]); + exit(-1); + } +#ifdef ADJ_TIMETICK + txc.modes = ADJ_TIMETICK; +#else +#ifdef MOD_OFFSET + txc.modes = ADJ_TICK; +#else + txc.mode = ADJ_TICK; +#endif +#endif + } + else + { +#ifdef ADJ_TIMETICK + txc.modes = 0; +#else +#ifdef MOD_OFFSET + txc.modes = 0; +#else + txc.mode = 0; +#endif +#endif + } + + if (__adjtimex(&txc) < 0) + { + perror("adjtimex"); + } + else + { +#ifdef ADJ_TIMETICK + printf("tick = %ld\ntick_adj = %ld\n", txc.time_tick, txc.tickadj); +#else + printf("tick = %ld\n", txc.tick); +#endif + } + + exit(0); +} +#endif + +#else /* not Linux... kmem tweaking: */ + +#ifdef HAVE_SYS_FILE_H +# include +#endif +#include + +#ifdef HAVE_SYS_PARAM_H +# include +#endif + +#ifdef NLIST_STRUCT +# include +#else /* not NLIST_STRUCT */ /* was defined(SYS_AUX3) || defined(SYS_AUX2) */ +# include +# include +# include +# include +# include +#endif + +#include "ntp_io.h" +#include "ntp_stdlib.h" + +#ifdef hz /* Was: RS6000 */ +# undef hz +#endif /* hz */ + +#ifdef HAVE_KVM_OPEN +# include +#endif + +#ifdef SYS_VXWORKS +/* vxWorks needs mode flag -casey*/ +#define open(name, flags) open(name, flags, 0777) +#endif + +#ifndef L_SET /* Was: defined(SYS_PTX) || defined(SYS_IX86OSF1) */ +# define L_SET SEEK_SET +#endif + +#ifndef HZ +# define HZ DEFAULT_HZ +#endif + +#define KMEM "/dev/kmem" +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +char *progname; +volatile int debug; + +int dokmem = 1; +int writetickadj = 0; +int writeopttickadj = 0; +int unsetdosync = 0; +int writetick = 0; +int quiet = 0; +int setnoprintf = 0; + +const char *kmem = KMEM; +const char *file = NULL; +int fd = -1; + +static void getoffsets P((off_t *, off_t *, off_t *, off_t *)); +static int openfile P((const char *, int)); +static void writevar P((int, off_t, int)); +static void readvar P((int, off_t, int *)); + +/* + * main - parse arguments and handle options + */ +int +main( + int argc, + char *argv[] + ) +{ + int c; + int errflg = 0; + off_t tickadj_offset; + off_t tick_offset; + off_t dosync_offset; + off_t noprintf_offset; + int tickadj, ktickadj; /* HMS: Why isn't this u_long? */ + int tick, ktick; /* HMS: Why isn't this u_long? */ + int dosynctodr; + int noprintf; + int hz; + int hz_int, hz_hundredths; + int recommend_tickadj; + long tmp; + + progname = argv[0]; + while ((c = ntp_getopt(argc, argv, "a:Adkpqst:")) != EOF) + { + switch (c) + { + case 'a': + writetickadj = atoi(ntp_optarg); + if (writetickadj <= 0) + { + (void) fprintf(stderr, + "%s: unlikely value for tickadj: %s\n", + progname, ntp_optarg); + errflg++; + } + +#if defined SCO5_CLOCK + if (writetickadj % HZ) + { + writetickadj = (writetickadj / HZ) * HZ; + (void) fprintf(stderr, + "tickadj truncated to: %d\n", writetickadj); + } +#endif /* SCO5_CLOCK */ + + break; + case 'A': + writeopttickadj = 1; + break; + case 'd': + ++debug; + break; + case 'k': + dokmem = 1; + break; + case 'p': + setnoprintf = 1; + break; + case 'q': + quiet = 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 [-Adkpqs] [-a newadj] [-t newtick]\n", progname); + exit(2); + } + + getoffsets(&tick_offset, &tickadj_offset, &dosync_offset, &noprintf_offset); + + if (debug) + { + (void) printf("tick offset = %lu\n", (unsigned long)tick_offset); + (void) printf("tickadj offset = %lu\n", (unsigned long)tickadj_offset); + (void) printf("dosynctodr offset = %lu\n", (unsigned long)dosync_offset); + (void) printf("noprintf offset = %lu\n", (unsigned long)noprintf_offset); + } + + if (writetick && (tick_offset == 0)) + { + (void) fprintf(stderr, + "No tick kernel variable\n"); + errflg++; + } + + if (writeopttickadj && (tickadj_offset == 0)) + { + (void) fprintf(stderr, + "No tickadj kernel variable\n"); + errflg++; + } + + if (unsetdosync && (dosync_offset == 0)) + { + (void) fprintf(stderr, + "No dosynctodr kernel variable\n"); + errflg++; + } + + if (setnoprintf && (noprintf_offset == 0)) + { + (void) fprintf(stderr, + "No noprintf kernel variable\n"); + errflg++; + } + + if (tick_offset != 0) + { + readvar(fd, tick_offset, &tick); +#if defined(TICK_NANO) && defined(K_TICK_NAME) + if (!quiet) + (void) printf("KERNEL %s = %d nsec\n", K_TICK_NAME, tick); +#endif /* TICK_NANO && K_TICK_NAME */ + +#ifdef TICK_NANO + tick /= 1000; +#endif + } + else + { + tick = 0; + } + + if (tickadj_offset != 0) + { + readvar(fd, tickadj_offset, &tickadj); + +#ifdef SCO5_CLOCK + /* scale from nsec/sec to usec/tick */ + tickadj /= (1000L * HZ); +#endif /*SCO5_CLOCK */ + +#if defined(TICKADJ_NANO) && defined(K_TICKADJ_NAME) + if (!quiet) + (void) printf("KERNEL %s = %d nsec\n", K_TICKADJ_NAME, tickadj); +#endif /* TICKADJ_NANO && K_TICKADJ_NAME */ + +#ifdef TICKADJ_NANO + tickadj += 999; + tickadj /= 1000; +#endif + } + else + { + tickadj = 0; + } + + 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 %s in namelist\n", + progname, +#ifdef K_DOSYNCTODR_NAME + K_DOSYNCTODR_NAME +#else /* not K_DOSYNCTODR_NAME */ + "dosynctodr" +#endif /* not K_DOSYNCTODR_NAME */ + ); + exit(1); + } + + hz = HZ; +#if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) + hz = (int) sysconf (_SC_CLK_TCK); +#endif /* not HAVE_SYSCONF && _SC_CLK_TCK */ +#ifdef OVERRIDE_HZ + hz = DEFAULT_HZ; +#endif + ktick = tick; +#ifdef PRESET_TICK + tick = PRESET_TICK; +#endif /* PRESET_TICK */ +#ifdef TICKADJ_NANO + tickadj /= 1000; + if (tickadj == 0) + tickadj = 1; +#endif + ktickadj = tickadj; +#ifdef PRESET_TICKADJ + tickadj = (PRESET_TICKADJ) ? PRESET_TICKADJ : 1; +#endif /* PRESET_TICKADJ */ + + if (!quiet) + { + if (tick_offset != 0) + { + (void) printf("KERNEL tick = %d usec (from %s kernel variable)\n", + ktick, +#ifdef K_TICK_NAME + K_TICK_NAME +#else + "" +#endif + ); + } +#ifdef PRESET_TICK + (void) printf("PRESET tick = %d usec\n", tick); +#endif /* PRESET_TICK */ + if (tickadj_offset != 0) + { + (void) printf("KERNEL tickadj = %d usec (from %s kernel variable)\n", + ktickadj, +#ifdef K_TICKADJ_NAME + K_TICKADJ_NAME +#else + "" +#endif + ); + } +#ifdef PRESET_TICKADJ + (void) printf("PRESET tickadj = %d usec\n", tickadj); +#endif /* PRESET_TICKADJ */ + if (dosync_offset != 0) + { + (void) printf("dosynctodr is %s\n", dosynctodr ? "on" : "off"); + } + 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 = (int)(1000000L / (long)tick); + hz_hundredths = (int)((100000000L / (long)tick) - ((long)hz_int * 100L)); + if (!quiet) + { + (void) printf("KERNEL hz = %d\n", hz); + (void) printf("calculated hz = %d.%02d Hz\n", hz_int, + hz_hundredths); + } + +#if defined SCO5_CLOCK + recommend_tickadj = 100; +#else /* SCO5_CLOCK */ + tmp = (long) tick * 500L; + recommend_tickadj = (int)(tmp / 1000000L); + if (tmp % 1000000L > 0) + { + recommend_tickadj++; + } + +#ifdef MIN_REC_TICKADJ + if (recommend_tickadj < MIN_REC_TICKADJ) + { + recommend_tickadj = MIN_REC_TICKADJ; + } +#endif /* MIN_REC_TICKADJ */ +#endif /* SCO5_CLOCK */ + + + 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 && (noprintf_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); + } + +#ifdef SCO5_CLOCK + /* scale from usec/tick to nsec/sec */ + writetickadj *= (1000L * HZ); +#endif /* SCO5_CLOCK */ + + 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); + return(errflg ? 1 : 0); +} + +/* + * getoffsets - read the magic offsets from the specified file + */ +static void +getoffsets( + off_t *tick_off, + off_t *tickadj_off, + off_t *dosync_off, + off_t *noprintf_off + ) +{ + +#ifndef NOKMEM +# ifndef HAVE_KVM_OPEN + const char **kname; +# endif +#endif + +#ifndef NOKMEM +# ifdef NLIST_NAME_UNION +# define NL_B {{ +# define NL_E }} +# else +# define NL_B { +# define NL_E } +# endif +#endif + +#define K_FILLER_NAME "DavidLetterman" + +#ifdef NLIST_EXTRA_INDIRECTION + int i; +#endif + +#ifndef NOKMEM + static struct nlist nl[] = + { + NL_B +#ifdef K_TICKADJ_NAME +#define N_TICKADJ 0 + K_TICKADJ_NAME +#else + K_FILLER_NAME +#endif + NL_E, + NL_B +#ifdef K_TICK_NAME +#define N_TICK 1 + K_TICK_NAME +#else + K_FILLER_NAME +#endif + NL_E, + NL_B +#ifdef K_DOSYNCTODR_NAME +#define N_DOSYNC 2 + K_DOSYNCTODR_NAME +#else + K_FILLER_NAME +#endif + NL_E, + NL_B +#ifdef K_NOPRINTF_NAME +#define N_NOPRINTF 3 + K_NOPRINTF_NAME +#else + K_FILLER_NAME +#endif + NL_E, + NL_B "" NL_E, + }; + +#ifndef HAVE_KVM_OPEN + static const char *kernels[] = + { +#ifdef HAVE_GETBOOTFILE + NULL, /* *** SEE BELOW! *** */ +#endif + "/kernel/unix", + "/kernel", + "/vmunix", + "/unix", + "/mach", + "/hp-ux", + "/386bsd", + "/netbsd", + "/stand/vmunix", + "/bsd", + NULL + }; +#endif /* not HAVE_KVM_OPEN */ + +#ifdef HAVE_KVM_OPEN + /* + * Solaris > 2.5 doesn't have a kernel file. Use the kvm_* interface + * to read the kernel name list. -- stolcke 3/4/96 + */ + kvm_t *kvm_handle = kvm_open(NULL, NULL, NULL, O_RDONLY, progname); + + if (kvm_handle == NULL) + { + (void) fprintf(stderr, + "%s: kvm_open failed\n", + progname); + exit(1); + } + if (kvm_nlist(kvm_handle, nl) == -1) + { + (void) fprintf(stderr, + "%s: kvm_nlist failed\n", + progname); + exit(1); + } + kvm_close(kvm_handle); +#else /* not HAVE_KVM_OPEN */ +#ifdef HAVE_GETBOOTFILE /* *** SEE HERE! *** */ + if (kernels[0] == NULL) + { + char * cp = (char *)getbootfile(); + + if (cp) + { + kernels[0] = cp; + } + else + { + kernels[0] = "/Placeholder"; + } + } +#endif /* HAVE_GETBOOTFILE */ + for (kname = kernels; *kname != NULL; kname++) + { + struct stat stbuf; + + if (stat(*kname, &stbuf) == -1) + { + continue; + } + if (nlist(*kname, nl) >= 0) + { + break; + } + else + { + (void) fprintf(stderr, + "%s: nlist didn't find needed symbols from <%s>: %m\n", + progname, *kname); + } + } + if (*kname == NULL) + { + (void) fprintf(stderr, + "%s: Couldn't find the kernel\n", + progname); + exit(1); + } +#endif /* HAVE_KVM_OPEN */ + + if (dokmem) + { + file = kmem; + + fd = openfile(file, O_RDONLY); +#ifdef NLIST_EXTRA_INDIRECTION + /* + * Go one more round of indirection. + */ + for (i = 0; i < (sizeof(nl) / sizeof(struct nlist)); i++) + { + if ((nl[i].n_value) && (nl[i].n_sclass == 0x6b)) + { + readvar(fd, nl[i].n_value, &nl[i].n_value); + } + } +#endif /* NLIST_EXTRA_INDIRECTION */ + } +#endif /* not NOKMEM */ + + *tickadj_off = 0; + *tick_off = 0; + *dosync_off = 0; + *noprintf_off = 0; + +#if defined(N_TICKADJ) + *tickadj_off = nl[N_TICKADJ].n_value; +#endif + +#if defined(N_TICK) + *tick_off = nl[N_TICK].n_value; +#endif + +#if defined(N_DOSYNC) + *dosync_off = nl[N_DOSYNC].n_value; +#endif + +#if defined(N_NOPRINTF) + *noprintf_off = nl[N_NOPRINTF].n_value; +#endif + return; +} + +#undef N_TICKADJ +#undef N_TICK +#undef N_DOSYNC +#undef N_NOPRINTF + + +/* + * openfile - open the file, check for errors + */ +static int +openfile( + const char *name, + int mode + ) +{ + int ifd; + + ifd = open(name, mode); + if (ifd < 0) + { + (void) fprintf(stderr, "%s: open %s: ", progname, name); + perror(""); + exit(1); + } + return ifd; +} + + +/* + * writevar - write a variable into the file + */ +static void +writevar( + int ofd, + off_t off, + int var + ) +{ + + if (lseek(ofd, off, L_SET) == -1) + { + (void) fprintf(stderr, "%s: lseek fails: ", progname); + perror(""); + exit(1); + } + if (write(ofd, (char *)&var, sizeof(int)) != sizeof(int)) + { + (void) fprintf(stderr, "%s: write fails: ", progname); + perror(""); + exit(1); + } + return; +} + + +/* + * readvar - read a variable from the file + */ +static void +readvar( + int ifd, + off_t off, + int *var + ) +{ + int i; + + if (lseek(ifd, off, L_SET) == -1) + { + (void) fprintf(stderr, "%s: lseek fails: ", progname); + perror(""); + exit(1); + } + i = read(ifd, (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, (int)sizeof(int), i); + exit(1); + } + return; +} +#endif /* not Linux */ diff --git a/contrib/ntp/util/timetrim.c b/contrib/ntp/util/timetrim.c new file mode 100644 index 000000000000..4397b569aff6 --- /dev/null +++ b/contrib/ntp/util/timetrim.c @@ -0,0 +1,95 @@ +#ifdef sgi +/* + * timetrim.c + * + * "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. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#ifdef HAVE_SYS_SYSSGI_H +# include +#endif + +#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)) + +int +main( + 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); + } + } +} +#endif -- cgit v1.2.3