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