Home | History | Annotate | Line # | Download | only in ntpd
      1  1.12  christos /*	$NetBSD: refclock_acts.c,v 1.13 2024/08/18 20:47:18 christos Exp $	*/
      2   1.1    kardel 
      3   1.1    kardel /*
      4   1.1    kardel  * refclock_acts - clock driver for the NIST/USNO/PTB/NPL Computer Time
      5   1.1    kardel  *	Services
      6   1.1    kardel  */
      7   1.1    kardel #ifdef HAVE_CONFIG_H
      8   1.1    kardel #include <config.h>
      9   1.1    kardel #endif
     10   1.1    kardel 
     11   1.6  christos #if defined(REFCLOCK) && defined(CLOCK_ACTS)
     12   1.1    kardel 
     13   1.1    kardel #include "ntpd.h"
     14   1.1    kardel #include "ntp_io.h"
     15   1.1    kardel #include "ntp_unixtime.h"
     16   1.1    kardel #include "ntp_refclock.h"
     17   1.1    kardel #include "ntp_stdlib.h"
     18   1.1    kardel #include "ntp_control.h"
     19   1.1    kardel 
     20   1.1    kardel #include <stdio.h>
     21   1.1    kardel #include <ctype.h>
     22   1.1    kardel #ifdef HAVE_SYS_IOCTL_H
     23   1.1    kardel # include <sys/ioctl.h>
     24   1.1    kardel #endif /* HAVE_SYS_IOCTL_H */
     25   1.1    kardel 
     26   1.1    kardel /*
     27   1.1    kardel  * This driver supports the US (NIST, USNO) and European (PTB, NPL,
     28   1.1    kardel  * etc.) modem time services, as well as Spectracom GPS and WWVB
     29   1.1    kardel  * receivers connected via a modem. The driver periodically dials a
     30   1.1    kardel  * number from a telephone list, receives the timecode data and
     31   1.1    kardel  * calculates the local clock correction. It is designed primarily for
     32   1.1    kardel  * use as backup when neither a radio clock nor connectivity to Internet
     33   1.1    kardel  * time servers is available.
     34   1.1    kardel  *
     35   1.1    kardel  * This driver requires a modem with a Hayes-compatible command set and
     36   1.1    kardel  * control over the modem data terminal ready (DTR) control line. The
     37   1.1    kardel  * modem setup string is hard-coded in the driver and may require
     38   1.6  christos  * changes for nonstandard modems or special circumstances.
     39   1.6  christos  *
     40   1.6  christos  * When enabled, the calling program dials the first number in the
     41   1.6  christos  * phones file. If that call fails, it dials the second number and
     42   1.6  christos  * so on. The phone number is specified by the Hayes ATDT prefix
     43   1.6  christos  * followed by the number itself, including the long-distance prefix
     44   1.6  christos  * and delay code, if necessary. The calling program is enabled
     45   1.6  christos  * when (a) fudge flag1 is set by ntpdc, (b) at each poll interval
     46   1.6  christos  * when no other synchronization sources are present, and (c) at each
     47   1.6  christos  * poll interval whether or not other synchronization sources are
     48   1.6  christos  * present. The calling program disconnects if (a) the called party
     49   1.6  christos  * is busy or does not answer, (b) the called party disconnects
     50   1.6  christos  * before a sufficient nuimber of timecodes have been received.
     51   1.1    kardel  *
     52   1.1    kardel  * The driver is transparent to each of the modem time services and
     53   1.1    kardel  * Spectracom radios. It selects the parsing algorithm depending on the
     54   1.1    kardel  * message length. There is some hazard should the message be corrupted.
     55   1.1    kardel  * However, the data format is checked carefully and only if all checks
     56   1.1    kardel  * succeed is the message accepted. Corrupted lines are discarded
     57   1.1    kardel  * without complaint.
     58   1.1    kardel  *
     59   1.1    kardel  * Fudge controls
     60   1.1    kardel  *
     61   1.1    kardel  * flag1	force a call in manual mode
     62   1.1    kardel  * flag2	enable port locking (not verified)
     63   1.6  christos  * flag3	not used
     64   1.1    kardel  * flag4	not used
     65   1.1    kardel  *
     66   1.1    kardel  * time1	offset adjustment (s)
     67   1.1    kardel  *
     68   1.6  christos  * Ordinarily, the serial port is connected to a modem and the phones
     69   1.6  christos  * list is defined. If no phones list is defined, the port can be
     70   1.6  christos  * connected directly to a device or another computer. In this case the
     71   1.6  christos  * driver will send a single character 'T' at each poll event. If
     72   1.6  christos  * fudge flag2 is enabled, port locking allows the modem to be shared
     73   1.6  christos  * when not in use by this driver.
     74   1.1    kardel  */
     75   1.1    kardel /*
     76   1.1    kardel  * National Institute of Science and Technology (NIST)
     77   1.1    kardel  *
     78   1.1    kardel  * Phone: (303) 494-4774 (Boulder, CO); (808) 335-4721 (Hawaii)
     79   1.1    kardel  *
     80   1.1    kardel  * Data Format
     81   1.1    kardel  *
     82   1.1    kardel  * National Institute of Standards and Technology
     83   1.1    kardel  * Telephone Time Service, Generator 3B
     84   1.1    kardel  * Enter question mark "?" for HELP
     85   1.1    kardel  *                         D  L D
     86   1.1    kardel  *  MJD  YR MO DA H  M  S  ST S UT1 msADV        <OTM>
     87   1.1    kardel  * 47999 90-04-18 21:39:15 50 0 +.1 045.0 UTC(NIST) *<CR><LF>
     88   1.1    kardel  * ...
     89   1.1    kardel  *
     90   1.1    kardel  * MJD, DST, DUT1 and UTC are not used by this driver. The "*" or "#" is
     91   1.1    kardel  * the on-time markers echoed by the driver and used by NIST to measure
     92   1.6  christos  * and correct for the propagation delay. Note: the ACTS timecode has
     93   1.6  christos  * recently been changed to eliminate the * on-time indicator. The
     94   1.6  christos  * reason for this and the long term implications are not clear.
     95   1.1    kardel  *
     96   1.1    kardel  * US Naval Observatory (USNO)
     97   1.1    kardel  *
     98   1.1    kardel  * Phone: (202) 762-1594 (Washington, DC); (719) 567-6742 (Boulder, CO)
     99   1.1    kardel  *
    100   1.1    kardel  * Data Format (two lines, repeating at one-second intervals)
    101   1.1    kardel  *
    102   1.1    kardel  * jjjjj nnn hhmmss UTC<CR><LF>
    103   1.1    kardel  * *<CR><LF>
    104   1.1    kardel  *
    105   1.1    kardel  * jjjjj	modified Julian day number (not used)
    106   1.1    kardel  * nnn		day of year
    107   1.1    kardel  * hhmmss	second of day
    108   1.1    kardel  * *		on-time marker for previous timecode
    109   1.1    kardel  * ...
    110   1.1    kardel  *
    111   1.1    kardel  * USNO does not correct for the propagation delay. A fudge time1 of
    112   1.1    kardel  * about .06 s is advisable.
    113   1.1    kardel  *
    114   1.1    kardel  * European Services (PTB, NPL, etc.)
    115   1.1    kardel  *
    116   1.1    kardel  * PTB: +49 531 512038 (Germany)
    117   1.1    kardel  * NPL: 0906 851 6333 (UK only)
    118   1.1    kardel  *
    119   1.1    kardel  * Data format (see the documentation for phone numbers and formats.)
    120   1.1    kardel  *
    121   1.1    kardel  * 1995-01-23 20:58:51 MEZ  10402303260219950123195849740+40000500<CR><LF>
    122   1.1    kardel  *
    123   1.1    kardel  * Spectracom GPS and WWVB Receivers
    124   1.1    kardel  *
    125   1.1    kardel  * If a modem is connected to a Spectracom receiver, this driver will
    126   1.1    kardel  * call it up and retrieve the time in one of two formats. As this
    127   1.1    kardel  * driver does not send anything, the radio will have to either be
    128   1.1    kardel  * configured in continuous mode or be polled by another local driver.
    129   1.1    kardel  */
    130   1.1    kardel /*
    131   1.1    kardel  * Interface definitions
    132   1.1    kardel  */
    133   1.1    kardel #define	DEVICE		"/dev/acts%d" /* device name and unit */
    134   1.6  christos #define	SPEED232	B19200	/* uart speed (19200 bps) */
    135   1.1    kardel #define	PRECISION	(-10)	/* precision assumed (about 1 ms) */
    136   1.6  christos #define LOCKFILE	"/var/spool/lock/LCK..cua%d"
    137   1.1    kardel #define DESCRIPTION	"Automated Computer Time Service" /* WRU */
    138   1.1    kardel #define REFID		"NONE"	/* default reference ID */
    139   1.1    kardel #define MSGCNT		20	/* max message count */
    140   1.1    kardel #define	MAXPHONE	10	/* max number of phone numbers */
    141   1.1    kardel 
    142   1.1    kardel /*
    143   1.6  christos  * Calling program modes (mode)
    144   1.1    kardel  */
    145   1.6  christos #define MODE_BACKUP	0	/* backup mode */
    146   1.6  christos #define MODE_AUTO	1	/* automatic mode */
    147   1.1    kardel #define MODE_MANUAL	2	/* manual mode */
    148   1.1    kardel 
    149   1.1    kardel /*
    150   1.6  christos  * Service identifiers (message length)
    151   1.1    kardel  */
    152   1.1    kardel #define REFACTS		"NIST"	/* NIST reference ID */
    153   1.6  christos #define LENACTS		50	/* NIST format A */
    154   1.1    kardel #define REFUSNO		"USNO"	/* USNO reference ID */
    155   1.1    kardel #define LENUSNO		20	/* USNO */
    156   1.1    kardel #define REFPTB		"PTB\0"	/* PTB/NPL reference ID */
    157   1.1    kardel #define LENPTB		78	/* PTB/NPL format */
    158   1.1    kardel #define REFWWVB		"WWVB"	/* WWVB reference ID */
    159   1.1    kardel #define	LENWWVB0	22	/* WWVB format 0 */
    160   1.1    kardel #define	LENWWVB2	24	/* WWVB format 2 */
    161   1.1    kardel #define LF		0x0a	/* ASCII LF */
    162   1.1    kardel 
    163   1.1    kardel /*
    164   1.6  christos  * Modem setup strings. These may have to be changed for
    165   1.6  christos  * some modems.
    166   1.1    kardel  *
    167   1.1    kardel  * AT	command prefix
    168   1.1    kardel  * B1	US answer tone
    169   1.1    kardel  * &C0	disable carrier detect
    170   1.1    kardel  * &D2	hang up and return to command mode on DTR transition
    171   1.1    kardel  * E0	modem command echo disabled
    172   1.6  christos  * L1	set modem speaker volume to low level
    173   1.1    kardel  * M1	speaker enabled until carrier detect
    174   1.1    kardel  * Q0	return result codes
    175   1.1    kardel  * V1	return result codes as English words
    176   1.6  christos  * Y1	enable long-space disconnect
    177   1.1    kardel  */
    178   1.6  christos const char def_modem_setup[] = "ATB1&C0&D2E0L1M1Q0V1Y1";
    179   1.6  christos const char *modem_setup = def_modem_setup;
    180   1.1    kardel 
    181   1.1    kardel /*
    182   1.1    kardel  * Timeouts (all in seconds)
    183   1.1    kardel  */
    184   1.1    kardel #define SETUP		3	/* setup timeout */
    185   1.6  christos #define	REDIAL		30	/* redial timeout */
    186   1.1    kardel #define ANSWER		60	/* answer timeout */
    187   1.6  christos #define TIMECODE	60	/* message timeout */
    188   1.6  christos #define	MAXCODE		20	/* max timecodes */
    189   1.1    kardel 
    190   1.1    kardel /*
    191   1.1    kardel  * State machine codes
    192   1.1    kardel  */
    193   1.6  christos typedef enum {
    194   1.6  christos 	S_IDLE,			/* wait for poll */
    195   1.6  christos 	S_SETUP,		/* send modem setup */
    196   1.6  christos 	S_CONNECT,		/* wait for answer */
    197   1.6  christos 	S_MSG			/* wait for timecode */
    198   1.6  christos } teModemState;
    199   1.1    kardel 
    200   1.1    kardel /*
    201   1.1    kardel  * Unit control structure
    202   1.1    kardel  */
    203   1.1    kardel struct actsunit {
    204   1.1    kardel 	int	unit;		/* unit number */
    205   1.1    kardel 	int	state;		/* the first one was Delaware */
    206   1.1    kardel 	int	timer;		/* timeout counter */
    207   1.1    kardel 	int	retry;		/* retry index */
    208   1.1    kardel 	int	msgcnt;		/* count of messages received */
    209   1.1    kardel 	l_fp	tstamp;		/* on-time timestamp */
    210   1.6  christos 	char	*bufptr;	/* next incoming char stored here */
    211   1.6  christos 	char	buf[BMAX];	/* bufptr roams within buf[] */
    212   1.1    kardel };
    213   1.1    kardel 
    214   1.1    kardel /*
    215   1.1    kardel  * Function prototypes
    216   1.1    kardel  */
    217   1.1    kardel static	int	acts_start	(int, struct peer *);
    218   1.1    kardel static	void	acts_shutdown	(int, struct peer *);
    219   1.1    kardel static	void	acts_receive	(struct recvbuf *);
    220   1.6  christos static	void	acts_message	(struct peer *, const char *);
    221   1.6  christos static	void	acts_timecode	(struct peer *, const char *);
    222   1.1    kardel static	void	acts_poll	(int, struct peer *);
    223   1.6  christos static	void	acts_timeout	(struct peer *, teModemState);
    224   1.1    kardel static	void	acts_timer	(int, struct peer *);
    225   1.6  christos static	void	acts_close	(struct peer *);
    226   1.1    kardel 
    227   1.1    kardel /*
    228   1.1    kardel  * Transfer vector (conditional structure name)
    229   1.1    kardel  */
    230   1.6  christos struct refclock refclock_acts = {
    231   1.1    kardel 	acts_start,		/* start up driver */
    232   1.1    kardel 	acts_shutdown,		/* shut down driver */
    233   1.1    kardel 	acts_poll,		/* transmit poll message */
    234   1.1    kardel 	noentry,		/* not used */
    235   1.1    kardel 	noentry,		/* not used */
    236   1.1    kardel 	noentry,		/* not used */
    237   1.1    kardel 	acts_timer		/* housekeeping timer */
    238   1.1    kardel };
    239   1.1    kardel 
    240   1.1    kardel /*
    241   1.1    kardel  * Initialize data for processing
    242   1.1    kardel  */
    243   1.1    kardel static int
    244   1.6  christos acts_start(
    245   1.1    kardel 	int	unit,
    246   1.1    kardel 	struct peer *peer
    247   1.1    kardel 	)
    248   1.1    kardel {
    249   1.1    kardel 	struct actsunit *up;
    250   1.1    kardel 	struct refclockproc *pp;
    251   1.6  christos 	const char *setup;
    252   1.1    kardel 
    253   1.1    kardel 	/*
    254   1.1    kardel 	 * Allocate and initialize unit structure
    255   1.1    kardel 	 */
    256   1.6  christos 	up = emalloc_zero(sizeof(struct actsunit));
    257   1.1    kardel 	up->unit = unit;
    258   1.1    kardel 	pp = peer->procptr;
    259   1.6  christos 	pp->unitptr = up;
    260   1.1    kardel 	pp->io.clock_recv = acts_receive;
    261   1.6  christos 	pp->io.srcclock = peer;
    262   1.1    kardel 	pp->io.datalen = 0;
    263   1.6  christos 	pp->io.fd = -1;
    264   1.1    kardel 
    265   1.1    kardel 	/*
    266   1.1    kardel 	 * Initialize miscellaneous variables
    267   1.1    kardel 	 */
    268   1.1    kardel 	peer->precision = PRECISION;
    269   1.1    kardel 	pp->clockdesc = DESCRIPTION;
    270   1.6  christos 	memcpy(&pp->refid, REFID, 4);
    271   1.1    kardel 	peer->sstclktype = CTL_SST_TS_TELEPHONE;
    272   1.6  christos 	up->bufptr = up->buf;
    273   1.6  christos 	if (def_modem_setup == modem_setup) {
    274   1.6  christos 		setup = get_ext_sys_var("modemsetup");
    275   1.6  christos 		if (setup != NULL)
    276   1.6  christos 			modem_setup = estrdup(setup);
    277   1.6  christos 	}
    278   1.6  christos 
    279   1.1    kardel 	return (1);
    280   1.1    kardel }
    281   1.1    kardel 
    282   1.1    kardel 
    283   1.1    kardel /*
    284   1.1    kardel  * acts_shutdown - shut down the clock
    285   1.1    kardel  */
    286   1.1    kardel static void
    287   1.6  christos acts_shutdown(
    288   1.1    kardel 	int	unit,
    289   1.1    kardel 	struct peer *peer
    290   1.1    kardel 	)
    291   1.1    kardel {
    292   1.1    kardel 	struct actsunit *up;
    293   1.1    kardel 	struct refclockproc *pp;
    294   1.1    kardel 
    295   1.1    kardel 	/*
    296   1.1    kardel 	 * Warning: do this only when a call is not in progress.
    297   1.1    kardel 	 */
    298   1.1    kardel 	pp = peer->procptr;
    299   1.6  christos 	up = pp->unitptr;
    300   1.6  christos 	acts_close(peer);
    301   1.1    kardel 	free(up);
    302   1.1    kardel }
    303   1.1    kardel 
    304   1.1    kardel 
    305   1.1    kardel /*
    306   1.1    kardel  * acts_receive - receive data from the serial interface
    307   1.1    kardel  */
    308   1.1    kardel static void
    309   1.6  christos acts_receive(
    310   1.1    kardel 	struct recvbuf *rbufp
    311   1.1    kardel 	)
    312   1.1    kardel {
    313   1.1    kardel 	struct actsunit *up;
    314   1.1    kardel 	struct refclockproc *pp;
    315   1.1    kardel 	struct peer *peer;
    316   1.6  christos 	char	tbuf[sizeof(up->buf)];
    317   1.6  christos 	char *	tptr;
    318   1.6  christos 	int	octets;
    319   1.1    kardel 
    320   1.1    kardel 	/*
    321   1.1    kardel 	 * Initialize pointers and read the timecode and timestamp. Note
    322   1.1    kardel 	 * we are in raw mode and victim of whatever the terminal
    323   1.1    kardel 	 * interface kicks up; so, we have to reassemble messages from
    324   1.1    kardel 	 * arbitrary fragments. Capture the timecode at the beginning of
    325   1.1    kardel 	 * the message and at the '*' and '#' on-time characters.
    326   1.1    kardel 	 */
    327   1.6  christos 	peer = rbufp->recv_peer;
    328   1.1    kardel 	pp = peer->procptr;
    329   1.6  christos 	up = pp->unitptr;
    330   1.6  christos 	octets = sizeof(up->buf) - (up->bufptr - up->buf);
    331   1.6  christos 	refclock_gtraw(rbufp, tbuf, octets, &pp->lastrec);
    332   1.1    kardel 	for (tptr = tbuf; *tptr != '\0'; tptr++) {
    333   1.1    kardel 		if (*tptr == LF) {
    334   1.6  christos 			if (up->bufptr == up->buf) {
    335   1.1    kardel 				up->tstamp = pp->lastrec;
    336   1.1    kardel 				continue;
    337   1.1    kardel 			} else {
    338   1.1    kardel 				*up->bufptr = '\0';
    339   1.6  christos 				up->bufptr = up->buf;
    340   1.6  christos 				acts_message(peer, up->buf);
    341   1.1    kardel 			}
    342   1.2  christos 		} else if (!iscntrl((unsigned char)*tptr)) {
    343   1.1    kardel 			*up->bufptr++ = *tptr;
    344   1.1    kardel 			if (*tptr == '*' || *tptr == '#') {
    345   1.1    kardel 				up->tstamp = pp->lastrec;
    346  1.13  christos 				refclock_write(peer, tptr, 1, "data");
    347   1.1    kardel 			}
    348   1.1    kardel 		}
    349   1.1    kardel 	}
    350   1.1    kardel }
    351   1.1    kardel 
    352   1.1    kardel 
    353   1.1    kardel /*
    354   1.1    kardel  * acts_message - process message
    355   1.1    kardel  */
    356   1.1    kardel void
    357   1.1    kardel acts_message(
    358   1.6  christos 	struct peer *peer,
    359   1.6  christos 	const char *msg
    360   1.1    kardel 	)
    361   1.1    kardel {
    362   1.1    kardel 	struct actsunit *up;
    363   1.1    kardel 	struct refclockproc *pp;
    364   1.6  christos 	char	tbuf[BMAX];
    365   1.6  christos 	int		dtr = TIOCM_DTR;
    366   1.6  christos 
    367   1.6  christos 	DPRINTF(1, ("acts: %d %s\n", (int)strlen(msg), msg));
    368   1.1    kardel 
    369   1.1    kardel 	/*
    370   1.1    kardel 	 * What to do depends on the state and the first token in the
    371   1.6  christos 	 * message.
    372   1.6  christos 	 */
    373   1.1    kardel 	pp = peer->procptr;
    374   1.6  christos 	up = pp->unitptr;
    375   1.1    kardel 
    376   1.1    kardel 	/*
    377   1.6  christos 	 * Extract the first token in the line.
    378   1.1    kardel 	 */
    379   1.6  christos 	strlcpy(tbuf, msg, sizeof(tbuf));
    380   1.1    kardel 	strtok(tbuf, " ");
    381   1.6  christos 	switch (up->state) {
    382   1.6  christos 
    383   1.6  christos 	/*
    384   1.6  christos 	 * We are waiting for the OK response to the modem setup
    385   1.6  christos 	 * command. When this happens, dial the number followed.
    386   1.6  christos 	 * If anything other than OK is received, just ignore it
    387   1.6  christos 	 * and wait for timeoue.
    388   1.6  christos 	 */
    389   1.6  christos 	case S_SETUP:
    390   1.6  christos 		if (strcmp(tbuf, "OK") != 0) {
    391   1.6  christos 			/*
    392   1.6  christos 			 * We disable echo with MODEM_SETUP's E0 but
    393   1.6  christos 			 * if the modem was previously E1, we will
    394   1.6  christos 			 * see MODEM_SETUP echoed before the OK/ERROR.
    395   1.6  christos 			 * Ignore it.
    396   1.6  christos 			 */
    397   1.6  christos 			if (!strcmp(tbuf, modem_setup))
    398   1.6  christos 				return;
    399   1.6  christos 			break;
    400   1.6  christos 		}
    401   1.6  christos 
    402   1.6  christos 		mprintf_event(PEVNT_CLOCK, peer, "DIAL #%d %s",
    403   1.6  christos 			      up->retry, sys_phone[up->retry]);
    404   1.6  christos 		if (ioctl(pp->io.fd, TIOCMBIS, &dtr) < 0)
    405   1.6  christos 			msyslog(LOG_ERR, "acts: ioctl(TIOCMBIS) failed: %m");
    406  1.13  christos 		refclock_write(peer, sys_phone[up->retry],
    407  1.13  christos 			       strlen(sys_phone[up->retry]),
    408  1.13  christos 			       "DIAL");
    409  1.13  christos 		refclock_write(peer, "\r", 1, "CR");
    410   1.6  christos 		up->retry++;
    411   1.6  christos 		up->state = S_CONNECT;
    412   1.6  christos 		up->timer = ANSWER;
    413   1.6  christos 		return;
    414   1.6  christos 
    415   1.6  christos 	/*
    416   1.6  christos 	 * We are waiting for the CONNECT response to the dial
    417   1.6  christos 	 * command. When this happens, listen for timecodes. If
    418   1.6  christos 	 * somthing other than CONNECT is received, like BUSY
    419   1.6  christos 	 * or NO CARRIER, abort the call.
    420   1.6  christos 	 */
    421   1.6  christos 	case S_CONNECT:
    422   1.6  christos 		if (strcmp(tbuf, "CONNECT") != 0)
    423   1.6  christos 			break;
    424   1.6  christos 
    425   1.6  christos 		report_event(PEVNT_CLOCK, peer, msg);
    426   1.6  christos 		up->state = S_MSG;
    427   1.6  christos 		up->timer = TIMECODE;
    428   1.6  christos 		return;
    429   1.6  christos 
    430   1.6  christos 	/*
    431   1.6  christos 	 * We are waiting for a timecode response. Pass it to
    432   1.6  christos 	 * the parser. If NO CARRIER is received, save the
    433   1.6  christos 	 * messages and abort the call.
    434   1.6  christos 	 */
    435   1.6  christos 	case S_MSG:
    436   1.6  christos 		if (strcmp(tbuf, "NO") == 0)
    437   1.6  christos 			report_event(PEVNT_CLOCK, peer, msg);
    438   1.6  christos 		if (up->msgcnt < MAXCODE)
    439   1.6  christos 			acts_timecode(peer, msg);
    440   1.6  christos 		else
    441   1.6  christos 			acts_timeout(peer, S_MSG);
    442   1.1    kardel 		return;
    443   1.1    kardel 	}
    444   1.1    kardel 
    445   1.1    kardel 	/*
    446   1.6  christos 	 * Other response. Tell us about it.
    447   1.6  christos 	 */
    448   1.6  christos 	report_event(PEVNT_CLOCK, peer, msg);
    449   1.6  christos 	acts_close(peer);
    450   1.6  christos }
    451   1.6  christos 
    452   1.6  christos 
    453   1.6  christos /*
    454   1.6  christos  * acts_timeout - called on timeout
    455   1.6  christos  */
    456   1.6  christos static void
    457   1.6  christos acts_timeout(
    458   1.6  christos 	struct peer *peer,
    459   1.6  christos 	teModemState	dstate
    460   1.6  christos 	)
    461   1.6  christos {
    462   1.6  christos 	struct actsunit *up;
    463   1.6  christos 	struct refclockproc *pp;
    464   1.6  christos 	int	fd;
    465   1.6  christos 	char	device[20];
    466   1.6  christos 	char	lockfile[128], pidbuf[8];
    467   1.6  christos 
    468   1.6  christos 	/*
    469   1.6  christos 	 * The state machine is driven by messages from the modem,
    470   1.6  christos 	 * when first started and at timeout.
    471   1.6  christos 	 */
    472   1.6  christos 	pp = peer->procptr;
    473   1.6  christos 	up = pp->unitptr;
    474   1.6  christos 	switch (dstate) {
    475   1.6  christos 
    476   1.6  christos 	/*
    477   1.6  christos 	 * System poll event. Lock the modem port, open the device
    478   1.6  christos 	 * and send the setup command.
    479   1.1    kardel 	 */
    480   1.6  christos 	case S_IDLE:
    481   1.6  christos 		if (-1 != pp->io.fd)
    482   1.6  christos 			return;		/* port is already open */
    483   1.6  christos 
    484   1.6  christos 		/*
    485   1.6  christos 		 * Lock the modem port. If busy, retry later. Note: if
    486   1.6  christos 		 * something fails between here and the close, the lock
    487   1.6  christos 		 * file may not be removed.
    488   1.6  christos 		 */
    489   1.6  christos 		if (pp->sloppyclockflag & CLK_FLAG2) {
    490   1.6  christos 			snprintf(lockfile, sizeof(lockfile), LOCKFILE,
    491   1.6  christos 			    up->unit);
    492   1.6  christos 			fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL,
    493   1.6  christos 			    0644);
    494   1.6  christos 			if (fd < 0) {
    495   1.6  christos 				report_event(PEVNT_CLOCK, peer, "acts: port busy");
    496   1.6  christos 				return;
    497   1.6  christos 			}
    498   1.6  christos 			snprintf(pidbuf, sizeof(pidbuf), "%d\n",
    499   1.6  christos 			    (u_int)getpid());
    500   1.6  christos 			if (write(fd, pidbuf, strlen(pidbuf)) < 0)
    501   1.6  christos 				msyslog(LOG_ERR, "acts: write lock fails %m");
    502   1.6  christos 			close(fd);
    503   1.6  christos 		}
    504   1.6  christos 
    505   1.6  christos 		/*
    506   1.6  christos 		 * Open the device in raw mode and link the I/O.
    507   1.6  christos 		 */
    508   1.6  christos 		snprintf(device, sizeof(device), DEVICE,
    509   1.6  christos 		    up->unit);
    510  1.13  christos 		fd = refclock_open(&peer->srcadr, device, SPEED232, LDISC_ACTS |
    511   1.6  christos 		    LDISC_RAW | LDISC_REMOTE);
    512   1.7  christos 		if (fd < 0) {
    513   1.6  christos 			msyslog(LOG_ERR, "acts: open fails %m");
    514   1.6  christos 			return;
    515   1.6  christos 		}
    516   1.6  christos 		pp->io.fd = fd;
    517   1.6  christos 		if (!io_addclock(&pp->io)) {
    518   1.6  christos 			msyslog(LOG_ERR, "acts: addclock fails");
    519   1.6  christos 			close(fd);
    520   1.6  christos 			pp->io.fd = -1;
    521   1.6  christos 			return;
    522   1.6  christos 		}
    523   1.6  christos 		up->msgcnt = 0;
    524   1.6  christos 		up->bufptr = up->buf;
    525   1.6  christos 
    526   1.6  christos 		/*
    527   1.6  christos 		 * If the port is directly connected to the device, skip
    528   1.6  christos 		 * the modem business and send 'T' for Spectrabum.
    529   1.6  christos 		 */
    530   1.6  christos 		if (sys_phone[up->retry] == NULL) {
    531  1.13  christos 			refclock_write(peer, "T", 1, "T");
    532   1.6  christos 			up->state = S_MSG;
    533   1.6  christos 			up->timer = TIMECODE;
    534   1.1    kardel 			return;
    535   1.1    kardel 		}
    536   1.6  christos 
    537   1.6  christos 		/*
    538   1.6  christos 		 * Initialize the modem. This works with Hayes-
    539   1.6  christos 		 * compatible modems.
    540   1.6  christos 		 */
    541   1.6  christos 		mprintf_event(PEVNT_CLOCK, peer, "SETUP %s",
    542   1.6  christos 			      modem_setup);
    543  1.13  christos 		refclock_write(peer, modem_setup, strlen(modem_setup),
    544  1.13  christos 			       "SETUP");
    545  1.13  christos 		refclock_write(peer, "\r", 1, "CR");
    546   1.6  christos 		up->state = S_SETUP;
    547   1.6  christos 		up->timer = SETUP;
    548   1.1    kardel 		return;
    549   1.1    kardel 
    550   1.1    kardel 	/*
    551   1.6  christos 	 * In SETUP state the modem did not respond OK to setup string.
    552   1.6  christos 	 */
    553   1.6  christos 	case S_SETUP:
    554   1.6  christos 		report_event(PEVNT_CLOCK, peer, "no modem");
    555   1.6  christos 		break;
    556   1.6  christos 
    557   1.6  christos 	/*
    558   1.6  christos 	 * In CONNECT state the call did not complete. Abort the call.
    559   1.1    kardel 	 */
    560   1.1    kardel 	case S_CONNECT:
    561   1.6  christos 		report_event(PEVNT_CLOCK, peer, "no answer");
    562   1.6  christos 		break;
    563   1.6  christos 
    564   1.6  christos 	/*
    565   1.6  christos 	 * In MSG states no further timecodes are expected. If any
    566   1.6  christos 	 * timecodes have arrived, update the clock. In any case,
    567   1.6  christos 	 * terminate the call.
    568   1.6  christos 	 */
    569   1.6  christos 	case S_MSG:
    570   1.6  christos 		if (up->msgcnt == 0) {
    571   1.6  christos 			report_event(PEVNT_CLOCK, peer, "no timecodes");
    572   1.6  christos 		} else {
    573   1.6  christos 			pp->lastref = pp->lastrec;
    574   1.6  christos 			record_clock_stats(&peer->srcadr, pp->a_lastcode);
    575   1.6  christos 			refclock_receive(peer);
    576   1.6  christos 		}
    577   1.6  christos 		break;
    578   1.6  christos 	}
    579   1.6  christos 	acts_close(peer);
    580   1.6  christos }
    581   1.6  christos 
    582   1.6  christos 
    583   1.6  christos /*
    584   1.6  christos  * acts_close - close and prepare for next call.
    585   1.6  christos  *
    586   1.6  christos  * In ClOSE state no further protocol actions are required
    587   1.6  christos  * other than to close and release the device and prepare to
    588   1.6  christos  * dial the next number if necessary.
    589   1.6  christos  */
    590   1.6  christos void
    591   1.6  christos acts_close(
    592   1.6  christos 	struct peer *peer
    593   1.6  christos 	)
    594   1.6  christos {
    595   1.6  christos 	struct actsunit *up;
    596   1.6  christos 	struct refclockproc *pp;
    597   1.6  christos 	char	lockfile[128];
    598   1.6  christos 	int	dtr;
    599   1.6  christos 
    600   1.6  christos 	pp = peer->procptr;
    601   1.6  christos 	up = pp->unitptr;
    602   1.6  christos 	if (pp->io.fd != -1) {
    603   1.6  christos 		report_event(PEVNT_CLOCK, peer, "close");
    604   1.6  christos 		dtr = TIOCM_DTR;
    605   1.6  christos 		if (ioctl(pp->io.fd, TIOCMBIC, &dtr) < 0)
    606   1.6  christos 			msyslog(LOG_ERR, "acts: ioctl(TIOCMBIC) failed: %m");
    607   1.6  christos 		io_closeclock(&pp->io);
    608   1.6  christos 		pp->io.fd = -1;
    609   1.6  christos 	}
    610   1.6  christos 	if (pp->sloppyclockflag & CLK_FLAG2) {
    611   1.6  christos 		snprintf(lockfile, sizeof(lockfile),
    612   1.6  christos 		    LOCKFILE, up->unit);
    613   1.6  christos 		unlink(lockfile);
    614   1.6  christos 	}
    615   1.6  christos 	if (up->msgcnt == 0 && up->retry > 0) {
    616   1.6  christos 		if (sys_phone[up->retry] != NULL) {
    617   1.6  christos 			up->state = S_IDLE;
    618   1.6  christos 			up->timer = REDIAL;
    619   1.1    kardel 			return;
    620   1.1    kardel 		}
    621   1.6  christos 	}
    622   1.6  christos 	up->state = S_IDLE;
    623   1.6  christos 	up->timer = 0;
    624   1.6  christos }
    625   1.6  christos 
    626   1.6  christos 
    627   1.6  christos /*
    628   1.6  christos  * acts_poll - called by the transmit routine
    629   1.6  christos  */
    630   1.6  christos static void
    631   1.6  christos acts_poll(
    632   1.6  christos 	int	unit,
    633   1.6  christos 	struct peer *peer
    634   1.6  christos 	)
    635   1.6  christos {
    636   1.6  christos 	struct actsunit *up;
    637   1.6  christos 	struct refclockproc *pp;
    638   1.6  christos 
    639   1.6  christos 	/*
    640   1.6  christos 	 * This routine is called at every system poll. All it does is
    641   1.6  christos 	 * set flag1 under certain conditions. The real work is done by
    642   1.6  christos 	 * the timeout routine and state machine.
    643   1.6  christos 	 */
    644   1.6  christos 	pp = peer->procptr;
    645   1.6  christos 	up = pp->unitptr;
    646   1.6  christos 	switch (peer->ttl) {
    647   1.6  christos 
    648   1.6  christos 	/*
    649   1.6  christos 	 * In manual mode the calling program is activated by the ntpdc
    650   1.6  christos 	 * program using the enable flag (fudge flag1), either manually
    651   1.6  christos 	 * or by a cron job.
    652   1.6  christos 	 */
    653   1.6  christos 	case MODE_MANUAL:
    654   1.1    kardel 		return;
    655   1.1    kardel 
    656   1.1    kardel 	/*
    657   1.6  christos 	 * In automatic mode the calling program runs continuously at
    658   1.6  christos 	 * intervals determined by the poll event or specified timeout.
    659   1.1    kardel 	 */
    660   1.6  christos 	case MODE_AUTO:
    661   1.6  christos 		break;
    662   1.6  christos 
    663   1.6  christos 	/*
    664   1.6  christos 	 * In backup mode the calling program runs continuously as long
    665   1.6  christos 	 * as either no peers are available or this peer is selected.
    666   1.6  christos 	 */
    667   1.6  christos 	case MODE_BACKUP:
    668   1.6  christos 		if (!(sys_peer == NULL || sys_peer == peer))
    669   1.6  christos 			return;
    670   1.6  christos 
    671   1.1    kardel 		break;
    672   1.1    kardel 	}
    673   1.6  christos 	pp->polls++;
    674   1.6  christos 	if (S_IDLE == up->state) {
    675   1.6  christos 		up->retry = 0;
    676   1.6  christos 		acts_timeout(peer, S_IDLE);
    677   1.6  christos 	}
    678   1.6  christos }
    679   1.6  christos 
    680   1.6  christos 
    681   1.6  christos /*
    682   1.6  christos  * acts_timer - called at one-second intervals
    683   1.6  christos  */
    684   1.6  christos static void
    685   1.6  christos acts_timer(
    686   1.6  christos 	int	unit,
    687   1.6  christos 	struct peer *peer
    688   1.6  christos 	)
    689   1.6  christos {
    690   1.6  christos 	struct actsunit *up;
    691   1.6  christos 	struct refclockproc *pp;
    692   1.6  christos 
    693   1.6  christos 	/*
    694   1.6  christos 	 * This routine implments a timeout which runs for a programmed
    695   1.6  christos 	 * interval. The counter is initialized by the state machine and
    696   1.6  christos 	 * counts down to zero. Upon reaching zero, the state machine is
    697   1.6  christos 	 * called. If flag1 is set while timer is zero, force a call.
    698   1.6  christos 	 */
    699   1.6  christos 	pp = peer->procptr;
    700   1.6  christos 	up = pp->unitptr;
    701   1.6  christos 	if (up->timer == 0) {
    702   1.6  christos 		if (pp->sloppyclockflag & CLK_FLAG1) {
    703   1.6  christos 			pp->sloppyclockflag &= ~CLK_FLAG1;
    704   1.6  christos 			acts_timeout(peer, S_IDLE);
    705   1.6  christos 		}
    706   1.6  christos 	} else {
    707   1.6  christos 		up->timer--;
    708   1.6  christos 		if (up->timer == 0)
    709   1.6  christos 			acts_timeout(peer, up->state);
    710   1.6  christos 	}
    711   1.1    kardel }
    712   1.1    kardel 
    713   1.1    kardel /*
    714   1.1    kardel  * acts_timecode - identify the service and parse the timecode message
    715   1.1    kardel  */
    716   1.1    kardel void
    717   1.1    kardel acts_timecode(
    718   1.6  christos 	struct peer *	peer,	/* peer structure pointer */
    719   1.6  christos 	const char *	str	/* timecode string */
    720   1.1    kardel 	)
    721   1.1    kardel {
    722   1.1    kardel 	struct actsunit *up;
    723   1.1    kardel 	struct refclockproc *pp;
    724   1.1    kardel 	int	day;		/* day of the month */
    725   1.1    kardel 	int	month;		/* month of the year */
    726   1.1    kardel 	u_long	mjd;		/* Modified Julian Day */
    727   1.1    kardel 	double	dut1;		/* DUT adjustment */
    728   1.1    kardel 
    729   1.1    kardel 	u_int	dst;		/* ACTS daylight/standard time */
    730   1.1    kardel 	u_int	leap;		/* ACTS leap indicator */
    731   1.1    kardel 	double	msADV;		/* ACTS transmit advance (ms) */
    732   1.1    kardel 	char	utc[10];	/* ACTS timescale */
    733   1.1    kardel 	char	flag;		/* ACTS on-time character (* or #) */
    734   1.1    kardel 
    735   1.1    kardel 	char	synchar;	/* WWVB synchronized indicator */
    736   1.1    kardel 	char	qualchar;	/* WWVB quality indicator */
    737   1.1    kardel 	char	leapchar;	/* WWVB leap indicator */
    738   1.1    kardel 	char	dstchar;	/* WWVB daylight/savings indicator */
    739   1.1    kardel 	int	tz;		/* WWVB timezone */
    740   1.1    kardel 
    741   1.3  christos 	int	leapmonth;	/* PTB/NPL month of leap */
    742   1.1    kardel 	char	leapdir;	/* PTB/NPL leap direction */
    743   1.1    kardel 
    744   1.1    kardel 	/*
    745   1.1    kardel 	 * The parser selects the modem format based on the message
    746   1.1    kardel 	 * length. Since the data are checked carefully, occasional
    747   1.1    kardel 	 * errors due noise are forgivable.
    748   1.1    kardel 	 */
    749   1.1    kardel 	pp = peer->procptr;
    750   1.6  christos 	up = pp->unitptr;
    751   1.1    kardel 	pp->nsec = 0;
    752   1.6  christos 	switch (strlen(str)) {
    753   1.1    kardel 
    754   1.1    kardel 	/*
    755   1.1    kardel 	 * For USNO format on-time character '*', which is on a line by
    756   1.1    kardel 	 * itself. Be sure a timecode has been received.
    757   1.1    kardel 	 */
    758   1.1    kardel 	case 1:
    759   1.1    kardel 		if (*str == '*' && up->msgcnt > 0)
    760   1.1    kardel 			break;
    761   1.1    kardel 
    762   1.1    kardel 		return;
    763   1.1    kardel 
    764   1.1    kardel 	/*
    765   1.6  christos 	 * ACTS format A: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa
    766   1.6  christos 	 * UTC(NIST) *".
    767   1.1    kardel 	 */
    768   1.1    kardel 	case LENACTS:
    769   1.1    kardel 		if (sscanf(str,
    770   1.1    kardel 		    "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %9s %c",
    771   1.1    kardel 		    &mjd, &pp->year, &month, &day, &pp->hour,
    772   1.1    kardel 		    &pp->minute, &pp->second, &dst, &leap, &dut1,
    773   1.1    kardel 		    &msADV, utc, &flag) != 13) {
    774   1.1    kardel 			refclock_report(peer, CEVNT_BADREPLY);
    775   1.1    kardel 			return;
    776   1.1    kardel 		}
    777   1.1    kardel 		pp->day = ymd2yd(pp->year, month, day);
    778   1.1    kardel 		pp->leap = LEAP_NOWARNING;
    779   1.1    kardel 		if (leap == 1)
    780   1.6  christos 			pp->leap = LEAP_ADDSECOND;
    781   1.6  christos 		else if (leap == 2)
    782   1.6  christos 			pp->leap = LEAP_DELSECOND;
    783   1.1    kardel 		memcpy(&pp->refid, REFACTS, 4);
    784   1.1    kardel 		up->msgcnt++;
    785   1.6  christos 		if (flag != '#' && up->msgcnt < 10)
    786   1.6  christos 			return;
    787   1.6  christos 
    788   1.1    kardel 		break;
    789   1.1    kardel 
    790   1.1    kardel 	/*
    791   1.1    kardel 	 * USNO format: "jjjjj nnn hhmmss UTC"
    792   1.1    kardel 	 */
    793   1.1    kardel 	case LENUSNO:
    794   1.1    kardel 		if (sscanf(str, "%5ld %3d %2d%2d%2d %3s",
    795   1.1    kardel 		    &mjd, &pp->day, &pp->hour, &pp->minute,
    796   1.1    kardel 		    &pp->second, utc) != 6) {
    797   1.1    kardel 			refclock_report(peer, CEVNT_BADREPLY);
    798   1.1    kardel 			return;
    799   1.1    kardel 		}
    800   1.1    kardel 
    801   1.1    kardel 		/*
    802   1.1    kardel 		 * Wait for the on-time character, which follows in a
    803   1.1    kardel 		 * separate message. There is no provision for leap
    804   1.1    kardel 		 * warning.
    805   1.1    kardel 		 */
    806   1.1    kardel 		pp->leap = LEAP_NOWARNING;
    807   1.1    kardel 		memcpy(&pp->refid, REFUSNO, 4);
    808   1.1    kardel 		up->msgcnt++;
    809   1.6  christos 		break;
    810   1.1    kardel 
    811   1.1    kardel 	/*
    812   1.1    kardel 	 * PTB/NPL format: "yyyy-mm-dd hh:mm:ss MEZ"
    813   1.1    kardel 	 */
    814   1.1    kardel 	case LENPTB:
    815   1.1    kardel 		if (sscanf(str,
    816   1.1    kardel 		    "%*4d-%*2d-%*2d %*2d:%*2d:%2d %*5c%*12c%4d%2d%2d%2d%2d%5ld%2lf%c%2d%3lf%*15c%c",
    817   1.1    kardel 		    &pp->second, &pp->year, &month, &day, &pp->hour,
    818   1.1    kardel 		    &pp->minute, &mjd, &dut1, &leapdir, &leapmonth,
    819   1.1    kardel 		    &msADV, &flag) != 12) {
    820   1.1    kardel 			refclock_report(peer, CEVNT_BADREPLY);
    821   1.1    kardel 			return;
    822   1.1    kardel 		}
    823   1.1    kardel 		pp->leap = LEAP_NOWARNING;
    824   1.1    kardel 		if (leapmonth == month) {
    825   1.1    kardel 			if (leapdir == '+')
    826   1.6  christos 				pp->leap = LEAP_ADDSECOND;
    827   1.1    kardel 			else if (leapdir == '-')
    828   1.6  christos 				pp->leap = LEAP_DELSECOND;
    829   1.1    kardel 		}
    830   1.1    kardel 		pp->day = ymd2yd(pp->year, month, day);
    831   1.1    kardel 		memcpy(&pp->refid, REFPTB, 4);
    832   1.1    kardel 		up->msgcnt++;
    833   1.1    kardel 		break;
    834   1.1    kardel 
    835   1.1    kardel 
    836   1.1    kardel 	/*
    837   1.1    kardel 	 * WWVB format 0: "I  ddd hh:mm:ss DTZ=nn"
    838   1.1    kardel 	 */
    839   1.1    kardel 	case LENWWVB0:
    840   1.1    kardel 		if (sscanf(str, "%c %3d %2d:%2d:%2d %cTZ=%2d",
    841   1.1    kardel 		    &synchar, &pp->day, &pp->hour, &pp->minute,
    842   1.1    kardel 		    &pp->second, &dstchar, &tz) != 7) {
    843   1.1    kardel 			refclock_report(peer, CEVNT_BADREPLY);
    844   1.1    kardel 			return;
    845   1.1    kardel 		}
    846   1.1    kardel 		pp->leap = LEAP_NOWARNING;
    847   1.1    kardel 		if (synchar != ' ')
    848   1.1    kardel 			pp->leap = LEAP_NOTINSYNC;
    849   1.1    kardel 		memcpy(&pp->refid, REFWWVB, 4);
    850   1.1    kardel 		up->msgcnt++;
    851   1.1    kardel 		break;
    852   1.1    kardel 
    853   1.1    kardel 	/*
    854   1.1    kardel 	 * WWVB format 2: "IQyy ddd hh:mm:ss.mmm LD"
    855   1.1    kardel 	 */
    856   1.1    kardel 	case LENWWVB2:
    857   1.1    kardel 		if (sscanf(str, "%c%c%2d %3d %2d:%2d:%2d.%3ld%c%c%c",
    858   1.1    kardel 		    &synchar, &qualchar, &pp->year, &pp->day,
    859   1.1    kardel 		    &pp->hour, &pp->minute, &pp->second, &pp->nsec,
    860   1.1    kardel 		    &dstchar, &leapchar, &dstchar) != 11) {
    861   1.1    kardel 			refclock_report(peer, CEVNT_BADREPLY);
    862   1.1    kardel 			return;
    863   1.1    kardel 		}
    864   1.1    kardel 		pp->nsec *= 1000000;
    865   1.1    kardel 		pp->leap = LEAP_NOWARNING;
    866   1.1    kardel 		if (synchar != ' ')
    867   1.1    kardel 			pp->leap = LEAP_NOTINSYNC;
    868   1.1    kardel 		else if (leapchar == 'L')
    869   1.1    kardel 			pp->leap = LEAP_ADDSECOND;
    870   1.1    kardel 		memcpy(&pp->refid, REFWWVB, 4);
    871   1.1    kardel 		up->msgcnt++;
    872   1.1    kardel 		break;
    873   1.1    kardel 
    874   1.1    kardel 	/*
    875   1.1    kardel 	 * None of the above. Just forget about it and wait for the next
    876   1.1    kardel 	 * message or timeout.
    877   1.1    kardel 	 */
    878   1.1    kardel 	default:
    879   1.1    kardel 		return;
    880   1.1    kardel 	}
    881   1.1    kardel 
    882   1.1    kardel 	/*
    883   1.1    kardel 	 * We have a valid timecode. The fudge time1 value is added to
    884   1.1    kardel 	 * each sample by the main line routines. Note that in current
    885   1.1    kardel 	 * telephone networks the propatation time can be different for
    886   1.1    kardel 	 * each call and can reach 200 ms for some calls.
    887   1.1    kardel 	 */
    888   1.1    kardel 	peer->refid = pp->refid;
    889   1.1    kardel 	pp->lastrec = up->tstamp;
    890   1.6  christos 	if (up->msgcnt == 0)
    891   1.6  christos 		return;
    892   1.6  christos 
    893   1.6  christos 	strlcpy(pp->a_lastcode, str, sizeof(pp->a_lastcode));
    894   1.6  christos 	pp->lencode = strlen(pp->a_lastcode);
    895   1.1    kardel 	if (!refclock_process(pp)) {
    896   1.1    kardel 		refclock_report(peer, CEVNT_BADTIME);
    897   1.1    kardel 		return;
    898   1.1    kardel 	}
    899   1.1    kardel 	pp->lastref = pp->lastrec;
    900   1.1    kardel }
    901   1.1    kardel #else
    902  1.13  christos NONEMPTY_TRANSLATION_UNIT
    903   1.1    kardel #endif /* REFCLOCK */
    904