PageRenderTime 69ms CodeModel.GetById 19ms app.highlight 41ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/ntp/ntpd/ntp_refclock.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1229 lines | 762 code | 134 blank | 333 comment | 155 complexity | a8a7d33697cd7f64653a63518f78c652 MD5 | raw file
   1/*
   2 * ntp_refclock - processing support for reference clocks
   3 */
   4#ifdef HAVE_CONFIG_H
   5# include <config.h>
   6#endif
   7
   8#include "ntpd.h"
   9#include "ntp_io.h"
  10#include "ntp_unixtime.h"
  11#include "ntp_tty.h"
  12#include "ntp_refclock.h"
  13#include "ntp_stdlib.h"
  14
  15#include <stdio.h>
  16
  17#ifdef HAVE_SYS_IOCTL_H
  18# include <sys/ioctl.h>
  19#endif /* HAVE_SYS_IOCTL_H */
  20
  21#ifdef REFCLOCK
  22
  23#ifdef TTYCLK
  24# ifdef HAVE_SYS_CLKDEFS_H
  25#  include <sys/clkdefs.h>
  26#  include <stropts.h>
  27# endif
  28# ifdef HAVE_SYS_SIO_H
  29#  include <sys/sio.h>
  30# endif
  31#endif /* TTYCLK */
  32
  33#ifdef KERNEL_PLL
  34#include "ntp_syscall.h"
  35#endif /* KERNEL_PLL */
  36
  37/*
  38 * Reference clock support is provided here by maintaining the fiction
  39 * that the clock is actually a peer. As no packets are exchanged with a
  40 * reference clock, however, we replace the transmit, receive and packet
  41 * procedures with separate code to simulate them. Routines
  42 * refclock_transmit() and refclock_receive() maintain the peer
  43 * variables in a state analogous to an actual peer and pass reference
  44 * clock data on through the filters. Routines refclock_peer() and
  45 * refclock_unpeer() are called to initialize and terminate reference
  46 * clock associations. A set of utility routines is included to open
  47 * serial devices, process sample data, edit input lines to extract
  48 * embedded timestamps and to peform various debugging functions.
  49 *
  50 * The main interface used by these routines is the refclockproc
  51 * structure, which contains for most drivers the decimal equivalants of
  52 * the year, day, month, hour, second and millisecond/microsecond
  53 * decoded from the ASCII timecode. Additional information includes the
  54 * receive timestamp, exception report, statistics tallies, etc. In
  55 * addition, there may be a driver-specific unit structure used for
  56 * local control of the device.
  57 *
  58 * The support routines are passed a pointer to the peer structure,
  59 * which is used for all peer-specific processing and contains a pointer
  60 * to the refclockproc structure, which in turn containes a pointer to
  61 * the unit structure, if used. The peer structure is identified by an
  62 * interface address in the dotted quad form 127.127.t.u (for now only
  63 * IPv4 addresses are used, so we need to be sure the address is it),
  64 * where t is the clock type and u the unit. Some legacy drivers derive
  65 * the refclockproc structure pointer from the table
  66 * typeunit[type][unit]. This interface is strongly discouraged and may
  67 * be abandoned in future.
  68 */
  69#define MAXUNIT 	4	/* max units */
  70#define FUDGEFAC	.1	/* fudge correction factor */
  71#define LF		0x0a	/* ASCII LF */
  72
  73#ifdef PPS
  74int	fdpps;			/* ppsclock legacy */
  75#endif /* PPS */
  76int	cal_enable;		/* enable refclock calibrate */
  77
  78/*
  79 * Type/unit peer index. Used to find the peer structure for control and
  80 * debugging. When all clock drivers have been converted to new style,
  81 * this dissapears.
  82 */
  83static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT];
  84
  85/*
  86 * Forward declarations
  87 */
  88#ifdef QSORT_USES_VOID_P
  89static int refclock_cmpl_fp P((const void *, const void *));
  90#else
  91static int refclock_cmpl_fp P((const double *, const double *));
  92#endif /* QSORT_USES_VOID_P */
  93static int refclock_sample P((struct refclockproc *));
  94
  95
  96/*
  97 * refclock_report - note the occurance of an event
  98 *
  99 * This routine presently just remembers the report and logs it, but
 100 * does nothing heroic for the trap handler. It tries to be a good
 101 * citizen and bothers the system log only if things change.
 102 */
 103void
 104refclock_report(
 105	struct peer *peer,
 106	int code
 107	)
 108{
 109	struct refclockproc *pp;
 110
 111	pp = peer->procptr;
 112	if (pp == NULL)
 113		return;
 114
 115	switch (code) {
 116		case CEVNT_NOMINAL:
 117			break;
 118
 119		case CEVNT_TIMEOUT:
 120			pp->noreply++;
 121			break;
 122
 123		case CEVNT_BADREPLY:
 124			pp->badformat++;
 125			break;
 126
 127		case CEVNT_FAULT:
 128			break;
 129
 130		case CEVNT_PROP:
 131			break;
 132
 133		case CEVNT_BADDATE:
 134		case CEVNT_BADTIME:
 135			pp->baddata++;
 136			break;
 137
 138		default:
 139			/* shouldn't happen */
 140			break;
 141	}
 142
 143	if (pp->currentstatus != code) {
 144		pp->currentstatus = (u_char)code;
 145
 146		/* RFC1305: copy only iff not CEVNT_NOMINAL */
 147		if (code != CEVNT_NOMINAL)
 148			pp->lastevent = (u_char)code;
 149
 150		if (code == CEVNT_FAULT)
 151			msyslog(LOG_ERR,
 152			    "clock %s event '%s' (0x%02x)",
 153			    refnumtoa(&peer->srcadr),
 154			    ceventstr(code), code);
 155		else {
 156			NLOG(NLOG_CLOCKEVENT)
 157			  msyslog(LOG_INFO,
 158			    "clock %s event '%s' (0x%02x)",
 159			    refnumtoa(&peer->srcadr),
 160			    ceventstr(code), code);
 161		}
 162
 163		/* RFC1305: post peer clock event */
 164		report_event(EVNT_PEERCLOCK, peer);
 165	}
 166}
 167
 168/*
 169 * init_refclock - initialize the reference clock drivers
 170 *
 171 * This routine calls each of the drivers in turn to initialize internal
 172 * variables, if necessary. Most drivers have nothing to say at this
 173 * point.
 174 */
 175void
 176init_refclock(void)
 177{
 178	int i, j;
 179
 180	for (i = 0; i < (int)num_refclock_conf; i++) {
 181		if (refclock_conf[i]->clock_init != noentry)
 182			(refclock_conf[i]->clock_init)();
 183		for (j = 0; j < MAXUNIT; j++)
 184			typeunit[i][j] = 0;
 185	}
 186}
 187
 188
 189/*
 190 * refclock_newpeer - initialize and start a reference clock
 191 *
 192 * This routine allocates and initializes the interface structure which
 193 * supports a reference clock in the form of an ordinary NTP peer. A
 194 * driver-specific support routine completes the initialization, if
 195 * used. Default peer variables which identify the clock and establish
 196 * its reference ID and stratum are set here. It returns one if success
 197 * and zero if the clock address is invalid or already running,
 198 * insufficient resources are available or the driver declares a bum
 199 * rap.
 200 */
 201int
 202refclock_newpeer(
 203	struct peer *peer	/* peer structure pointer */
 204	)
 205{
 206	struct refclockproc *pp;
 207	u_char clktype;
 208	int unit;
 209
 210	/*
 211	 * Check for valid clock address. If already running, shut it
 212	 * down first.
 213	 */
 214	if (peer->srcadr.ss_family != AF_INET) {
 215		msyslog(LOG_ERR,
 216		       "refclock_newpeer: clock address %s invalid, address family not implemented for refclock",
 217                        stoa(&peer->srcadr));
 218                return (0);
 219        }
 220	if (!ISREFCLOCKADR(&peer->srcadr)) {
 221		msyslog(LOG_ERR,
 222			"refclock_newpeer: clock address %s invalid",
 223			stoa(&peer->srcadr));
 224		return (0);
 225	}
 226	clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);
 227	unit = REFCLOCKUNIT(&peer->srcadr);
 228	if (clktype >= num_refclock_conf || unit >= MAXUNIT ||
 229		refclock_conf[clktype]->clock_start == noentry) {
 230		msyslog(LOG_ERR,
 231			"refclock_newpeer: clock type %d invalid\n",
 232			clktype);
 233		return (0);
 234	}
 235
 236	/*
 237	 * Allocate and initialize interface structure
 238	 */
 239	pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc));
 240	if (pp == NULL)
 241		return (0);
 242
 243	memset((char *)pp, 0, sizeof(struct refclockproc));
 244	typeunit[clktype][unit] = peer;
 245	peer->procptr = pp;
 246
 247	/*
 248	 * Initialize structures
 249	 */
 250	peer->refclktype = clktype;
 251	peer->refclkunit = (u_char)unit;
 252	peer->flags |= FLAG_REFCLOCK | FLAG_FIXPOLL;
 253	peer->leap = LEAP_NOTINSYNC;
 254	peer->stratum = STRATUM_REFCLOCK;
 255	peer->ppoll = peer->maxpoll;
 256	pp->type = clktype;
 257	pp->timestarted = current_time;
 258
 259	/*
 260	 * Set peer.pmode based on the hmode. For appearances only.
 261	 */
 262	switch (peer->hmode) {
 263	case MODE_ACTIVE:
 264		peer->pmode = MODE_PASSIVE;
 265		break;
 266
 267	default:
 268		peer->pmode = MODE_SERVER;
 269		break;
 270	}
 271
 272	/*
 273	 * Do driver dependent initialization. The above defaults
 274	 * can be wiggled, then finish up for consistency.
 275	 */
 276	if (!((refclock_conf[clktype]->clock_start)(unit, peer))) {
 277		refclock_unpeer(peer);
 278		return (0);
 279	}
 280	peer->refid = pp->refid;
 281	return (1);
 282}
 283
 284
 285/*
 286 * refclock_unpeer - shut down a clock
 287 */
 288void
 289refclock_unpeer(
 290	struct peer *peer	/* peer structure pointer */
 291	)
 292{
 293	u_char clktype;
 294	int unit;
 295
 296	/*
 297	 * Wiggle the driver to release its resources, then give back
 298	 * the interface structure.
 299	 */
 300	if (!peer->procptr)
 301		return;
 302
 303	clktype = peer->refclktype;
 304	unit = peer->refclkunit;
 305	if (refclock_conf[clktype]->clock_shutdown != noentry)
 306		(refclock_conf[clktype]->clock_shutdown)(unit, peer);
 307	free(peer->procptr);
 308	peer->procptr = 0;
 309}
 310
 311
 312/*
 313 * refclock_timer - called once per second for housekeeping.
 314 */
 315void
 316refclock_timer(
 317	struct peer *peer	/* peer structure pointer */
 318	)
 319{
 320	u_char clktype;
 321	int unit;
 322
 323	clktype = peer->refclktype;
 324	unit = peer->refclkunit;
 325	if (refclock_conf[clktype]->clock_timer != noentry)
 326		(refclock_conf[clktype]->clock_timer)(unit, peer);
 327}
 328	
 329
 330/*
 331 * refclock_transmit - simulate the transmit procedure
 332 *
 333 * This routine implements the NTP transmit procedure for a reference
 334 * clock. This provides a mechanism to call the driver at the NTP poll
 335 * interval, as well as provides a reachability mechanism to detect a
 336 * broken radio or other madness.
 337 */
 338void
 339refclock_transmit(
 340	struct peer *peer	/* peer structure pointer */
 341	)
 342{
 343	u_char clktype;
 344	int unit;
 345
 346	clktype = peer->refclktype;
 347	unit = peer->refclkunit;
 348	peer->sent++;
 349	get_systime(&peer->xmt);
 350
 351	/*
 352	 * This is a ripoff of the peer transmit routine, but
 353	 * specialized for reference clocks. We do a little less
 354	 * protocol here and call the driver-specific transmit routine.
 355	 */
 356	if (peer->burst == 0) {
 357		u_char oreach;
 358#ifdef DEBUG
 359		if (debug)
 360			printf("refclock_transmit: at %ld %s\n",
 361			    current_time, stoa(&(peer->srcadr)));
 362#endif
 363
 364		/*
 365		 * Update reachability and poll variables like the
 366		 * network code.
 367		 */
 368		oreach = peer->reach;
 369		peer->reach <<= 1;
 370		peer->outdate = current_time;
 371		if (!peer->reach) {
 372			if (oreach) {
 373				report_event(EVNT_UNREACH, peer);
 374				peer->timereachable = current_time;
 375			}
 376		} else {
 377			if (!(oreach & 0x07)) {
 378				clock_filter(peer, 0., 0., MAXDISPERSE);
 379				clock_select();
 380			}
 381			if (peer->flags & FLAG_BURST)
 382				peer->burst = NSTAGE;
 383		}
 384	} else {
 385		peer->burst--;
 386	}
 387	if (refclock_conf[clktype]->clock_poll != noentry)
 388		(refclock_conf[clktype]->clock_poll)(unit, peer);
 389	poll_update(peer, peer->hpoll);
 390}
 391
 392
 393/*
 394 * Compare two doubles - used with qsort()
 395 */
 396#ifdef QSORT_USES_VOID_P
 397static int
 398refclock_cmpl_fp(
 399	const void *p1,
 400	const void *p2
 401	)
 402{
 403	const double *dp1 = (const double *)p1;
 404	const double *dp2 = (const double *)p2;
 405
 406	if (*dp1 < *dp2)
 407		return (-1);
 408
 409	if (*dp1 > *dp2)
 410		return (1);
 411
 412	return (0);
 413}
 414
 415#else
 416static int
 417refclock_cmpl_fp(
 418	const double *dp1,
 419	const double *dp2
 420	)
 421{
 422	if (*dp1 < *dp2)
 423		return (-1);
 424
 425	if (*dp1 > *dp2)
 426		return (1);
 427
 428	return (0);
 429}
 430#endif /* QSORT_USES_VOID_P */
 431
 432
 433/*
 434 * refclock_process_offset - update median filter
 435 *
 436 * This routine uses the given offset and timestamps to construct a new
 437 * entry in the median filter circular buffer. Samples that overflow the
 438 * filter are quietly discarded.
 439 */
 440void
 441refclock_process_offset(
 442	struct refclockproc *pp,	/* refclock structure pointer */
 443	l_fp lasttim,			/* last timecode timestamp */
 444	l_fp lastrec,			/* last receive timestamp */
 445	double fudge
 446	)
 447{
 448	l_fp lftemp;
 449	double doffset;
 450
 451	pp->lastrec = lastrec;
 452	lftemp = lasttim;
 453	L_SUB(&lftemp, &lastrec);
 454	LFPTOD(&lftemp, doffset);
 455	SAMPLE(doffset + fudge);
 456}
 457
 458
 459/*
 460 * refclock_process - process a sample from the clock
 461 *
 462 * This routine converts the timecode in the form days, hours, minutes,
 463 * seconds and milliseconds/microseconds to internal timestamp format,
 464 * then constructs a new entry in the median filter circular buffer.
 465 * Return success (1) if the data are correct and consistent with the
 466 * converntional calendar.
 467 *
 468 * Important for PPS users: Normally, the pp->lastrec is set to the
 469 * system time when the on-time character is received and the pp->year,
 470 * ..., pp->second decoded and the seconds fraction pp->nsec in
 471 * nanoseconds). When a PPS offset is available, pp->nsec is forced to
 472 * zero and the fraction for pp->lastrec is set to the PPS offset.
 473 */
 474int
 475refclock_process(
 476	struct refclockproc *pp		/* refclock structure pointer */
 477	)
 478{
 479	l_fp offset, ltemp;
 480
 481	/*
 482	 * Compute the timecode timestamp from the days, hours, minutes,
 483	 * seconds and milliseconds/microseconds of the timecode. Use
 484	 * clocktime() for the aggregate seconds and the msec/usec for
 485	 * the fraction, when present. Note that this code relies on the
 486	 * filesystem time for the years and does not use the years of
 487	 * the timecode.
 488	 */
 489	if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
 490		pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui))
 491		return (0);
 492
 493	offset.l_uf = 0;
 494	DTOLFP(pp->nsec / 1e9, &ltemp);
 495	L_ADD(&offset, &ltemp);
 496	refclock_process_offset(pp, offset, pp->lastrec,
 497	    pp->fudgetime1);
 498	return (1);
 499}
 500
 501
 502/*
 503 * refclock_sample - process a pile of samples from the clock
 504 *
 505 * This routine implements a recursive median filter to suppress spikes
 506 * in the data, as well as determine a performance statistic. It
 507 * calculates the mean offset and RMS jitter. A time adjustment
 508 * fudgetime1 can be added to the final offset to compensate for various
 509 * systematic errors. The routine returns the number of samples
 510 * processed, which could be zero.
 511 */
 512static int
 513refclock_sample(
 514	struct refclockproc *pp		/* refclock structure pointer */
 515	)
 516{
 517	int	i, j, k, m, n;
 518	double	off[MAXSTAGE];
 519	double	offset;
 520
 521	/*
 522	 * Copy the raw offsets and sort into ascending order. Don't do
 523	 * anything if the buffer is empty.
 524	 */
 525	n = 0;
 526	while (pp->codeproc != pp->coderecv) {
 527		pp->codeproc = (pp->codeproc + 1) % MAXSTAGE;
 528		off[n] = pp->filter[pp->codeproc];
 529		n++;
 530	}
 531	if (n == 0)
 532		return (0);
 533
 534	if (n > 1)
 535		qsort(
 536#ifdef QSORT_USES_VOID_P
 537		    (void *)
 538#else
 539		    (char *)
 540#endif
 541		    off, (size_t)n, sizeof(double), refclock_cmpl_fp);
 542
 543	/*
 544	 * Reject the furthest from the median of the samples until
 545	 * approximately 60 percent of the samples remain.
 546	 */
 547	i = 0; j = n;
 548	m = n - (n * 4) / 10;
 549	while ((j - i) > m) {
 550		offset = off[(j + i) / 2];
 551		if (off[j - 1] - offset < offset - off[i])
 552			i++;	/* reject low end */
 553		else
 554			j--;	/* reject high end */
 555	}
 556
 557	/*
 558	 * Determine the offset and jitter.
 559	 */
 560	pp->offset = 0;
 561	pp->jitter = 0;
 562	for (k = i; k < j; k++) {
 563		pp->offset += off[k];
 564		if (k > i)
 565			pp->jitter += SQUARE(off[k] - off[k - 1]);
 566	}
 567	pp->offset /= m;
 568	pp->jitter = max(SQRT(pp->jitter / m), LOGTOD(sys_precision));
 569#ifdef DEBUG
 570	if (debug)
 571		printf(
 572		    "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n",
 573		    n, pp->offset, pp->disp, pp->jitter);
 574#endif
 575	return (n);
 576}
 577
 578
 579/*
 580 * refclock_receive - simulate the receive and packet procedures
 581 *
 582 * This routine simulates the NTP receive and packet procedures for a
 583 * reference clock. This provides a mechanism in which the ordinary NTP
 584 * filter, selection and combining algorithms can be used to suppress
 585 * misbehaving radios and to mitigate between them when more than one is
 586 * available for backup.
 587 */
 588void
 589refclock_receive(
 590	struct peer *peer	/* peer structure pointer */
 591	)
 592{
 593	struct refclockproc *pp;
 594
 595#ifdef DEBUG
 596	if (debug)
 597		printf("refclock_receive: at %lu %s\n",
 598		    current_time, stoa(&peer->srcadr));
 599#endif
 600
 601	/*
 602	 * Do a little sanity dance and update the peer structure. Groom
 603	 * the median filter samples and give the data to the clock
 604	 * filter.
 605	 */
 606	pp = peer->procptr;
 607	peer->leap = pp->leap;
 608	if (peer->leap == LEAP_NOTINSYNC)
 609		return;
 610
 611	peer->received++;
 612	peer->timereceived = current_time;
 613	if (!peer->reach) {
 614		report_event(EVNT_REACH, peer);
 615		peer->timereachable = current_time;
 616	}
 617	peer->reach |= 1;
 618	peer->reftime = pp->lastref;
 619	peer->org = pp->lastrec;
 620	peer->rootdispersion = pp->disp;
 621	get_systime(&peer->rec);
 622	if (!refclock_sample(pp))
 623		return;
 624
 625	clock_filter(peer, pp->offset, 0., pp->jitter);
 626	record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
 627	    peer->offset, peer->delay, clock_phi * (current_time -
 628	    peer->epoch), peer->jitter);
 629	if (cal_enable && last_offset < MINDISPERSE) {
 630#ifdef KERNEL_PLL
 631		if (peer != sys_peer || pll_status & STA_PPSTIME)
 632#else
 633		if (peer != sys_peer)
 634#endif /* KERNEL_PLL */
 635			pp->fudgetime1 -= pp->offset * FUDGEFAC;
 636		else
 637			pp->fudgetime1 -= pp->fudgetime1 * FUDGEFAC;
 638	}
 639}
 640
 641
 642/*
 643 * refclock_gtlin - groom next input line and extract timestamp
 644 *
 645 * This routine processes the timecode received from the clock and
 646 * strips the parity bit and control characters. It returns the number
 647 * of characters in the line followed by a NULL character ('\0'), which
 648 * is not included in the count. In case of an empty line, the previous
 649 * line is preserved.
 650 */
 651int
 652refclock_gtlin(
 653	struct recvbuf *rbufp,	/* receive buffer pointer */
 654	char	*lineptr,	/* current line pointer */
 655	int	bmax,		/* remaining characters in line */
 656	l_fp	*tsptr		/* pointer to timestamp returned */
 657	)
 658{
 659	char	s[BMAX];
 660	char	*dpt, *dpend, *dp;
 661
 662	dpt = s;
 663	dpend = s + refclock_gtraw(rbufp, s, BMAX - 1, tsptr);
 664	if (dpend - dpt > bmax - 1)
 665		dpend = dpt + bmax - 1;
 666	for (dp = lineptr; dpt < dpend; dpt++) {
 667		char	c;
 668
 669		c = *dpt & 0x7f;
 670		if (c >= 0x20 && c < 0x7f)
 671			*dp++ = c;
 672	}
 673	if (dp == lineptr)
 674		return (0);
 675
 676	*dp = '\0';
 677	return (dp - lineptr);
 678}
 679
 680
 681/*
 682 * refclock_gtraw - get next line/chunk of data
 683 *
 684 * This routine returns the raw data received from the clock in both
 685 * canonical or raw modes. The terminal interface routines map CR to LF.
 686 * In canonical mode this results in two lines, one containing data
 687 * followed by LF and another containing only LF. In raw mode the
 688 * interface routines can deliver arbitraty chunks of data from one
 689 * character to a maximum specified by the calling routine. In either
 690 * mode the routine returns the number of characters in the line
 691 * followed by a NULL character ('\0'), which is not included in the
 692 * count.
 693 *
 694 * If a timestamp is present in the timecode, as produced by the tty_clk
 695 * STREAMS module, it returns that as the timestamp; otherwise, it
 696 * returns the buffer timestamp.
 697 */
 698int
 699refclock_gtraw(
 700	struct recvbuf *rbufp,	/* receive buffer pointer */
 701	char	*lineptr,	/* current line pointer */
 702	int	bmax,		/* remaining characters in line */
 703	l_fp	*tsptr		/* pointer to timestamp returned */
 704	)
 705{
 706	char	*dpt, *dpend, *dp;
 707	l_fp	trtmp, tstmp;
 708	int	i;
 709
 710	/*
 711	 * Check for the presence of a timestamp left by the tty_clock
 712	 * module and, if present, use that instead of the buffer
 713	 * timestamp captured by the I/O routines. We recognize a
 714	 * timestamp by noting its value is earlier than the buffer
 715	 * timestamp, but not more than one second earlier.
 716	 */
 717	dpt = (char *)rbufp->recv_buffer;
 718	dpend = dpt + rbufp->recv_length;
 719	trtmp = rbufp->recv_time;
 720	if (dpend >= dpt + 8) {
 721		if (buftvtots(dpend - 8, &tstmp)) {
 722			L_SUB(&trtmp, &tstmp);
 723			if (trtmp.l_ui == 0) {
 724#ifdef DEBUG
 725				if (debug > 1) {
 726					printf(
 727					    "refclock_gtlin: fd %d ldisc %s",
 728					    rbufp->fd, lfptoa(&trtmp,
 729					    6));
 730					get_systime(&trtmp);
 731					L_SUB(&trtmp, &tstmp);
 732					printf(" sigio %s\n",
 733					    lfptoa(&trtmp, 6));
 734				}
 735#endif
 736				dpend -= 8;
 737				trtmp = tstmp;
 738			} else
 739				trtmp = rbufp->recv_time;
 740		}
 741	}
 742
 743	/*
 744	 * Copy the raw buffer to the user string. The string is padded
 745	 * with a NULL, which is not included in the character count.
 746	 */
 747	if (dpend - dpt > bmax - 1)
 748		dpend = dpt + bmax - 1;
 749	for (dp = lineptr; dpt < dpend; dpt++)
 750		*dp++ = *dpt;
 751	*dp = '\0';
 752	i = dp - lineptr;
 753#ifdef DEBUG
 754	if (debug > 1)
 755		printf("refclock_gtraw: fd %d time %s timecode %d %s\n",
 756		    rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr);
 757#endif
 758	*tsptr = trtmp;
 759	return (i);
 760}
 761
 762
 763/*
 764 * The following code does not apply to WINNT & VMS ...
 765 */
 766#if !defined SYS_VXWORKS && !defined SYS_WINNT
 767#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
 768
 769/*
 770 * refclock_open - open serial port for reference clock
 771 *
 772 * This routine opens a serial port for I/O and sets default options. It
 773 * returns the file descriptor if success and zero if failure.
 774 */
 775int
 776refclock_open(
 777	char	*dev,		/* device name pointer */
 778	u_int	speed,		/* serial port speed (code) */
 779	u_int	lflags		/* line discipline flags */
 780	)
 781{
 782	int	fd;
 783	int	omode;
 784
 785	/*
 786	 * Open serial port and set default options
 787	 */
 788	omode = O_RDWR;
 789#ifdef O_NONBLOCK
 790	omode |= O_NONBLOCK;
 791#endif
 792#ifdef O_NOCTTY
 793	omode |= O_NOCTTY;
 794#endif
 795
 796	fd = open(dev, omode, 0777);
 797	if (fd < 0) {
 798		msyslog(LOG_ERR, "refclock_open %s: %m", dev);
 799		return (0);
 800	}
 801	if (!refclock_setup(fd, speed, lflags)) {
 802		close(fd);
 803		return (0);
 804	}
 805	if (!refclock_ioctl(fd, lflags)) {
 806		close(fd);
 807		return (0);
 808	}
 809	return (fd);
 810}
 811
 812/*
 813 * refclock_setup - initialize terminal interface structure
 814 */
 815int
 816refclock_setup(
 817	int	fd,		/* file descriptor */
 818	u_int	speed,		/* serial port speed (code) */
 819	u_int	lflags		/* line discipline flags */
 820	)
 821{
 822	int	i;
 823	TTY	ttyb, *ttyp;
 824#ifdef PPS
 825	fdpps = fd;		/* ppsclock legacy */
 826#endif /* PPS */
 827
 828	/*
 829	 * By default, the serial line port is initialized in canonical
 830	 * (line-oriented) mode at specified line speed, 8 bits and no
 831	 * parity. LF ends the line and CR is mapped to LF. The break,
 832	 * erase and kill functions are disabled. There is a different
 833	 * section for each terminal interface, as selected at compile
 834	 * time. The flag bits can be used to set raw mode and echo.
 835	 */
 836	ttyp = &ttyb;
 837#ifdef HAVE_TERMIOS
 838
 839	/*
 840	 * POSIX serial line parameters (termios interface)
 841	 */
 842	if (tcgetattr(fd, ttyp) < 0) {
 843		msyslog(LOG_ERR,
 844			"refclock_setup fd %d tcgetattr: %m", fd);
 845		return (0);
 846	}
 847
 848	/*
 849	 * Set canonical mode and local connection; set specified speed,
 850	 * 8 bits and no parity; map CR to NL; ignore break.
 851	 */
 852	if (speed) {
 853		u_int	ltemp = 0;
 854
 855		ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
 856		ttyp->c_oflag = 0;
 857		ttyp->c_cflag = CS8 | CLOCAL | CREAD;
 858		if (lflags & LDISC_7O1) {
 859			/* HP Z3801A needs 7-bit, odd parity */
 860  			ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD;
 861		}
 862		cfsetispeed(&ttyb, speed);
 863		cfsetospeed(&ttyb, speed);
 864		for (i = 0; i < NCCS; ++i)
 865			ttyp->c_cc[i] = '\0';
 866
 867#if defined(TIOCMGET) && !defined(SCO5_CLOCK)
 868
 869		/*
 870		 * If we have modem control, check to see if modem leads
 871		 * are active; if so, set remote connection. This is
 872		 * necessary for the kernel pps mods to work.
 873		 */
 874		if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
 875			msyslog(LOG_ERR,
 876			    "refclock_setup fd %d TIOCMGET: %m", fd);
 877#ifdef DEBUG
 878		if (debug)
 879			printf("refclock_setup fd %d modem status: 0x%x\n",
 880			    fd, ltemp);
 881#endif
 882		if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE)
 883			ttyp->c_cflag &= ~CLOCAL;
 884#endif /* TIOCMGET */
 885	}
 886
 887	/*
 888	 * Set raw and echo modes. These can be changed on-fly.
 889	 */
 890	ttyp->c_lflag = ICANON;
 891	if (lflags & LDISC_RAW) {
 892		ttyp->c_lflag = 0;
 893		ttyp->c_iflag = 0;
 894		ttyp->c_cc[VMIN] = 1;
 895	}
 896	if (lflags & LDISC_ECHO)
 897		ttyp->c_lflag |= ECHO;
 898	if (tcsetattr(fd, TCSANOW, ttyp) < 0) {
 899		msyslog(LOG_ERR,
 900		    "refclock_setup fd %d TCSANOW: %m", fd);
 901		return (0);
 902	}
 903#endif /* HAVE_TERMIOS */
 904
 905#ifdef HAVE_SYSV_TTYS
 906
 907	/*
 908	 * System V serial line parameters (termio interface)
 909	 *
 910	 */
 911	if (ioctl(fd, TCGETA, ttyp) < 0) {
 912		msyslog(LOG_ERR,
 913		    "refclock_setup fd %d TCGETA: %m", fd);
 914		return (0);
 915	}
 916
 917	/*
 918	 * Set canonical mode and local connection; set specified speed,
 919	 * 8 bits and no parity; map CR to NL; ignore break.
 920	 */
 921	if (speed) {
 922		u_int	ltemp = 0;
 923
 924		ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
 925		ttyp->c_oflag = 0;
 926		ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD;
 927		for (i = 0; i < NCCS; ++i)
 928			ttyp->c_cc[i] = '\0';
 929
 930#if defined(TIOCMGET) && !defined(SCO5_CLOCK)
 931
 932		/*
 933		 * If we have modem control, check to see if modem leads
 934		 * are active; if so, set remote connection. This is
 935		 * necessary for the kernel pps mods to work.
 936		 */
 937		if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
 938			msyslog(LOG_ERR,
 939			    "refclock_setup fd %d TIOCMGET: %m", fd);
 940#ifdef DEBUG
 941		if (debug)
 942			printf("refclock_setup fd %d modem status: %x\n",
 943			    fd, ltemp);
 944#endif
 945		if (ltemp & TIOCM_DSR)
 946			ttyp->c_cflag &= ~CLOCAL;
 947#endif /* TIOCMGET */
 948	}
 949
 950	/*
 951	 * Set raw and echo modes. These can be changed on-fly.
 952	 */
 953	ttyp->c_lflag = ICANON;
 954	if (lflags & LDISC_RAW) {
 955		ttyp->c_lflag = 0;
 956		ttyp->c_iflag = 0;
 957		ttyp->c_cc[VMIN] = 1;
 958	}
 959	if (ioctl(fd, TCSETA, ttyp) < 0) {
 960		msyslog(LOG_ERR,
 961		    "refclock_setup fd %d TCSETA: %m", fd);
 962		return (0);
 963	}
 964#endif /* HAVE_SYSV_TTYS */
 965
 966#ifdef HAVE_BSD_TTYS
 967
 968	/*
 969	 * 4.3bsd serial line parameters (sgttyb interface)
 970	 */
 971	if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) {
 972		msyslog(LOG_ERR,
 973		    "refclock_setup fd %d TIOCGETP: %m", fd);
 974		return (0);
 975	}
 976	if (speed)
 977		ttyp->sg_ispeed = ttyp->sg_ospeed = speed;
 978	ttyp->sg_flags = EVENP | ODDP | CRMOD;
 979	if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {
 980		msyslog(LOG_ERR,
 981		    "refclock_setup TIOCSETP: %m");
 982		return (0);
 983	}
 984#endif /* HAVE_BSD_TTYS */
 985	return(1);
 986}
 987#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
 988#endif /* SYS_VXWORKS SYS_WINNT */
 989
 990
 991/*
 992 * refclock_ioctl - set serial port control functions
 993 *
 994 * This routine attempts to hide the internal, system-specific details
 995 * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
 996 * (sgtty) interfaces with varying degrees of success. The routine sets
 997 * up optional features such as tty_clk. The routine returns 1 if
 998 * success and 0 if failure.
 999 */
1000int
1001refclock_ioctl(
1002	int	fd, 		/* file descriptor */
1003	u_int	lflags		/* line discipline flags */
1004	)
1005{
1006	/*
1007	 * simply return 1 if no UNIX line discipline is supported
1008	 */
1009#if !defined SYS_VXWORKS && !defined SYS_WINNT
1010#if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
1011
1012#ifdef DEBUG
1013	if (debug)
1014		printf("refclock_ioctl: fd %d flags 0x%x\n", fd,
1015		    lflags);
1016#endif
1017#ifdef TTYCLK
1018
1019	/*
1020	 * The TTYCLK option provides timestamping at the driver level.
1021	 * It requires the tty_clk streams module and System V STREAMS
1022	 * support. If not available, don't complain.
1023	 */
1024	if (lflags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) {
1025		int rval = 0;
1026
1027		if (ioctl(fd, I_PUSH, "clk") < 0) {
1028			msyslog(LOG_NOTICE,
1029			    "refclock_ioctl fd %d I_PUSH: %m", fd);
1030			return (0);
1031#ifdef CLK_SETSTR
1032		} else {
1033			char *str;
1034
1035			if (lflags & LDISC_CLKPPS)
1036				str = "\377";
1037			else if (lflags & LDISC_ACTS)
1038				str = "*";
1039			else
1040				str = "\n";
1041			if (ioctl(fd, CLK_SETSTR, str) < 0) {
1042				msyslog(LOG_ERR,
1043				    "refclock_ioctl fd %d CLK_SETSTR: %m", fd);
1044				return (0);
1045			}
1046#endif /*CLK_SETSTR */
1047		}
1048	}
1049#endif /* TTYCLK */
1050#endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
1051#endif /* SYS_VXWORKS SYS_WINNT */
1052	return (1);
1053}
1054
1055
1056/*
1057 * refclock_control - set and/or return clock values
1058 *
1059 * This routine is used mainly for debugging. It returns designated
1060 * values from the interface structure that can be displayed using
1061 * ntpdc and the clockstat command. It can also be used to initialize
1062 * configuration variables, such as fudgetimes, fudgevalues, reference
1063 * ID and stratum.
1064 */
1065void
1066refclock_control(
1067	struct sockaddr_storage *srcadr,
1068	struct refclockstat *in,
1069	struct refclockstat *out
1070	)
1071{
1072	struct peer *peer;
1073	struct refclockproc *pp;
1074	u_char clktype;
1075	int unit;
1076
1077	/*
1078	 * Check for valid address and running peer
1079	 */
1080	if (srcadr->ss_family != AF_INET)
1081		return;
1082
1083	if (!ISREFCLOCKADR(srcadr))
1084		return;
1085
1086	clktype = (u_char)REFCLOCKTYPE(srcadr);
1087	unit = REFCLOCKUNIT(srcadr);
1088	if (clktype >= num_refclock_conf || unit >= MAXUNIT)
1089		return;
1090
1091	peer = typeunit[clktype][unit];
1092	if (peer == NULL)
1093		return;
1094
1095	if (peer->procptr == NULL)
1096		return;
1097
1098	pp = peer->procptr;
1099
1100	/*
1101	 * Initialize requested data
1102	 */
1103	if (in != 0) {
1104		if (in->haveflags & CLK_HAVETIME1)
1105			pp->fudgetime1 = in->fudgetime1;
1106		if (in->haveflags & CLK_HAVETIME2)
1107			pp->fudgetime2 = in->fudgetime2;
1108		if (in->haveflags & CLK_HAVEVAL1)
1109			peer->stratum = pp->stratum = (u_char)in->fudgeval1;
1110		if (in->haveflags & CLK_HAVEVAL2)
1111			peer->refid = pp->refid = in->fudgeval2;
1112		if (in->haveflags & CLK_HAVEFLAG1) {
1113			pp->sloppyclockflag &= ~CLK_FLAG1;
1114			pp->sloppyclockflag |= in->flags & CLK_FLAG1;
1115		}
1116		if (in->haveflags & CLK_HAVEFLAG2) {
1117			pp->sloppyclockflag &= ~CLK_FLAG2;
1118			pp->sloppyclockflag |= in->flags & CLK_FLAG2;
1119		}
1120		if (in->haveflags & CLK_HAVEFLAG3) {
1121			pp->sloppyclockflag &= ~CLK_FLAG3;
1122			pp->sloppyclockflag |= in->flags & CLK_FLAG3;
1123		}
1124		if (in->haveflags & CLK_HAVEFLAG4) {
1125			pp->sloppyclockflag &= ~CLK_FLAG4;
1126			pp->sloppyclockflag |= in->flags & CLK_FLAG4;
1127		}
1128	}
1129
1130	/*
1131	 * Readback requested data
1132	 */
1133	if (out != 0) {
1134		out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 |
1135			CLK_HAVEVAL2 | CLK_HAVEFLAG4;
1136		out->fudgetime1 = pp->fudgetime1;
1137		out->fudgetime2 = pp->fudgetime2;
1138		out->fudgeval1 = pp->stratum;
1139		out->fudgeval2 = pp->refid;
1140		out->flags = (u_char) pp->sloppyclockflag;
1141
1142		out->timereset = current_time - pp->timestarted;
1143		out->polls = pp->polls;
1144		out->noresponse = pp->noreply;
1145		out->badformat = pp->badformat;
1146		out->baddata = pp->baddata;
1147
1148		out->lastevent = pp->lastevent;
1149		out->currentstatus = pp->currentstatus;
1150		out->type = pp->type;
1151		out->clockdesc = pp->clockdesc;
1152		out->lencode = pp->lencode;
1153		out->p_lastcode = pp->a_lastcode;
1154	}
1155
1156	/*
1157	 * Give the stuff to the clock
1158	 */
1159	if (refclock_conf[clktype]->clock_control != noentry)
1160		(refclock_conf[clktype]->clock_control)(unit, in, out, peer);
1161}
1162
1163
1164/*
1165 * refclock_buginfo - return debugging info
1166 *
1167 * This routine is used mainly for debugging. It returns designated
1168 * values from the interface structure that can be displayed using
1169 * ntpdc and the clkbug command.
1170 */
1171void
1172refclock_buginfo(
1173	struct sockaddr_storage *srcadr, /* clock address */
1174	struct refclockbug *bug /* output structure */
1175	)
1176{
1177	struct peer *peer;
1178	struct refclockproc *pp;
1179	u_char clktype;
1180	int unit;
1181	int i;
1182
1183	/*
1184	 * Check for valid address and peer structure
1185	 */
1186	if (srcadr->ss_family != AF_INET)
1187		return;
1188
1189	if (!ISREFCLOCKADR(srcadr))
1190		return;
1191
1192	clktype = (u_char) REFCLOCKTYPE(srcadr);
1193	unit = REFCLOCKUNIT(srcadr);
1194	if (clktype >= num_refclock_conf || unit >= MAXUNIT)
1195		return;
1196
1197	peer = typeunit[clktype][unit];
1198	if (peer == NULL)
1199		return;
1200
1201	pp = peer->procptr;
1202
1203	/*
1204	 * Copy structure values
1205	 */
1206	bug->nvalues = 8;
1207	bug->svalues = 0x0000003f;
1208	bug->values[0] = pp->year;
1209	bug->values[1] = pp->day;
1210	bug->values[2] = pp->hour;
1211	bug->values[3] = pp->minute;
1212	bug->values[4] = pp->second;
1213	bug->values[5] = pp->nsec;
1214	bug->values[6] = pp->yearstart;
1215	bug->values[7] = pp->coderecv;
1216	bug->stimes = 0xfffffffc;
1217	bug->times[0] = pp->lastref;
1218	bug->times[1] = pp->lastrec;
1219	for (i = 2; i < (int)bug->ntimes; i++)
1220		DTOLFP(pp->filter[i - 2], &bug->times[i]);
1221
1222	/*
1223	 * Give the stuff to the clock
1224	 */
1225	if (refclock_conf[clktype]->clock_buginfo != noentry)
1226		(refclock_conf[clktype]->clock_buginfo)(unit, bug, peer);
1227}
1228
1229#endif /* REFCLOCK */