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