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