1 /* $NetBSD: refclock_acts.c,v 1.5 2013/10/20 02:47:38 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 refclockproc *pp; 642 643 /* 644 * This routine is called at every system poll. All it does is 645 * set flag1 under certain conditions. The real work is done by 646 * the timeout routine and state machine. 647 */ 648 pp = peer->procptr; 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 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 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[SMAX]; 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 snprintf(lockfile, sizeof(lockfile), LOCKFILE, 755 up->unit); 756 fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 757 0644); 758 if (fd < 0) { 759 msyslog(LOG_ERR, "acts: port busy"); 760 return; 761 } 762 snprintf(pidbuf, sizeof(pidbuf), "%d\n", 763 (u_int)getpid()); 764 write(fd, pidbuf, strlen(pidbuf)); 765 close(fd); 766 } 767 768 /* 769 * Open the device in raw mode and link the I/O. 770 */ 771 if (!pp->io.fd) { 772 snprintf(device, sizeof(device), DEVICE, 773 up->unit); 774 fd = refclock_open(device, SPEED232, 775 LDISC_ACTS | LDISC_RAW | LDISC_REMOTE); 776 if (fd == 0) { 777 msyslog(LOG_ERR, 778 "acts: open fails"); 779 return; 780 } 781 pp->io.fd = fd; 782 if (!io_addclock(&pp->io)) { 783 msyslog(LOG_ERR, 784 "acts: addclock fails"); 785 close(fd); 786 pp->io.fd = 0; 787 return; 788 } 789 } 790 791 /* 792 * If the port is directly connected to the device, skip 793 * the modem business and send 'T' for Spectrabum. 794 */ 795 if (pp->sloppyclockflag & CLK_FLAG3) { 796 if (write(pp->io.fd, "T", 1) < 0) { 797 msyslog(LOG_ERR, "acts: write %m"); 798 return; 799 } 800 up->state = S_FIRST; 801 up->timer = CONNECT; 802 return; 803 } 804 805 /* 806 * Initialize the modem. This works with Hayes commands. 807 */ 808 #ifdef DEBUG 809 if (debug) 810 printf("acts: setup %s\n", MODEM_SETUP); 811 #endif 812 if (write(pp->io.fd, MODEM_SETUP, strlen(MODEM_SETUP)) < 813 0) { 814 msyslog(LOG_ERR, "acts: write %m"); 815 return; 816 } 817 up->state = S_OK; 818 up->timer = SETUP; 819 return; 820 821 /* 822 * In OK state the modem did not respond to setup. 823 */ 824 case S_OK: 825 msyslog(LOG_ERR, "acts: no modem"); 826 break; 827 828 /* 829 * In DTR state we are waiting for the modem to settle down 830 * before hammering it with a dial command. 831 */ 832 case S_DTR: 833 snprintf(tbuf, sizeof(tbuf), "DIAL #%d %s", up->retry, 834 sys_phone[up->retry]); 835 report_event(PEVNT_CLOCK, peer, tbuf); 836 #ifdef DEBUG 837 if (debug) 838 printf("%s\n", tbuf); 839 #endif 840 write(pp->io.fd, sys_phone[up->retry], 841 strlen(sys_phone[up->retry])); 842 write(pp->io.fd, "\r", 1); 843 up->state = S_CONNECT; 844 up->timer = ANSWER; 845 return; 846 847 /* 848 * In CONNECT state the call did not complete. 849 */ 850 case S_CONNECT: 851 msyslog(LOG_ERR, "acts: no answer"); 852 break; 853 854 /* 855 * In FIRST state no messages were received. 856 */ 857 case S_FIRST: 858 msyslog(LOG_ERR, "acts: no messages"); 859 break; 860 861 /* 862 * In CLOSE state hangup is complete. Close the doors and 863 * windows and get some air. 864 */ 865 case S_CLOSE: 866 867 /* 868 * Close the device and unlock a shared modem. 869 */ 870 if (pp->io.fd) { 871 io_closeclock(&pp->io); 872 close(pp->io.fd); 873 if (pp->sloppyclockflag & CLK_FLAG2) { 874 snprintf(lockfile, sizeof(lockfile), 875 LOCKFILE, up->unit); 876 unlink(lockfile); 877 } 878 pp->io.fd = 0; 879 } 880 881 /* 882 * If messages were received, fold the tent and wait for 883 * the next poll. If no messages and there are more 884 * numbers to dial, retry after a short wait. 885 */ 886 up->bufptr = pp->a_lastcode; 887 up->timer = 0; 888 up->state = S_IDLE; 889 if ( up->msgcnt == 0) { 890 up->retry++; 891 if (sys_phone[up->retry] == NULL) 892 up->retry = 0; 893 else 894 up->timer = SETUP; 895 } else { 896 up->retry = 0; 897 } 898 up->msgcnt = 0; 899 return; 900 } 901 acts_disc(peer); 902 } 903 904 905 /* 906 * acts_disc - disconnect the call and clean the place up. 907 */ 908 static void 909 acts_disc ( 910 struct peer *peer 911 ) 912 { 913 struct actsunit *up; 914 struct refclockproc *pp; 915 int dtr = TIOCM_DTR; 916 917 /* 918 * We get here if the call terminated successfully or if an 919 * error occured. If the median filter has something in it, 920 * feed the data to the clock filter. If a modem port, drop DTR 921 * to force command mode and send modem hangup. 922 */ 923 pp = peer->procptr; 924 up = (struct actsunit *)pp->unitptr; 925 if (up->msgcnt > 0) 926 refclock_receive(peer); 927 if (!(pp->sloppyclockflag & CLK_FLAG3)) { 928 ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr); 929 write(pp->io.fd, MODEM_HANGUP, strlen(MODEM_HANGUP)); 930 } 931 up->timer = SETUP; 932 up->state = S_CLOSE; 933 } 934 #else 935 int refclock_acts_bs; 936 #endif /* REFCLOCK */ 937