1 /* 2 * ntp_refclock - processing support for reference clocks 3 */ 4 #ifdef HAVE_CONFIG_H 5 # include <config.h> 6 #endif 7 8 #include "ntpd.h" 9 #include "ntp_io.h" 10 #include "ntp_unixtime.h" 11 #include "ntp_tty.h" 12 #include "ntp_refclock.h" 13 #include "ntp_stdlib.h" 14 15 #include <stdio.h> 16 17 #ifdef HAVE_SYS_IOCTL_H 18 # include <sys/ioctl.h> 19 #endif /* HAVE_SYS_IOCTL_H */ 20 21 #ifdef REFCLOCK 22 23 #ifdef TTYCLK 24 # ifdef HAVE_SYS_CLKDEFS_H 25 # include <sys/clkdefs.h> 26 # include <stropts.h> 27 # endif 28 # ifdef HAVE_SYS_SIO_H 29 # include <sys/sio.h> 30 # endif 31 #endif /* TTYCLK */ 32 33 #ifdef HAVE_PPSCLOCK_H 34 #include <sys/ppsclock.h> 35 #endif /* HAVE_PPSCLOCK_H */ 36 37 #ifdef KERNEL_PLL 38 #include "ntp_syscall.h" 39 #endif /* KERNEL_PLL */ 40 41 /* 42 * Reference clock support is provided here by maintaining the fiction 43 * that the clock is actually a peer. As no packets are exchanged with a 44 * reference clock, however, we replace the transmit, receive and packet 45 * procedures with separate code to simulate them. Routines 46 * refclock_transmit() and refclock_receive() maintain the peer 47 * variables in a state analogous to an actual peer and pass reference 48 * clock data on through the filters. Routines refclock_peer() and 49 * refclock_unpeer() are called to initialize and terminate reference 50 * clock associations. A set of utility routines is included to open 51 * serial devices, process sample data, edit input lines to extract 52 * embedded timestamps and to peform various debugging functions. 53 * 54 * The main interface used by these routines is the refclockproc 55 * structure, which contains for most drivers the decimal equivalants of 56 * the year, day, month, hour, second and millisecond/microsecond 57 * decoded from the ASCII timecode. Additional information includes the 58 * receive timestamp, exception report, statistics tallies, etc. In 59 * addition, there may be a driver-specific unit structure used for 60 * local control of the device. 61 * 62 * The support routines are passed a pointer to the peer structure, 63 * which is used for all peer-specific processing and contains a pointer 64 * to the refclockproc structure, which in turn containes a pointer to 65 * the unit structure, if used. The peer structure is identified by an 66 * interface address in the dotted quad form 127.127.t.u (for now only IPv4 67 * addresses are used, so we need to be sure the address is it), where t is 68 * the clock type and u the unit. Some legacy drivers derive the 69 * refclockproc structure pointer from the table typeunit[type][unit]. 70 * This interface is strongly discouraged and may be abandoned in 71 * future. 72 */ 73 #define MAXUNIT 4 /* max units */ 74 #define FUDGEFAC .1 /* fudge correction factor */ 75 76 int fdpps; /* pps file descriptor */ 77 int cal_enable; /* enable refclock calibrate */ 78 79 /* 80 * Type/unit peer index. Used to find the peer structure for control and 81 * debugging. When all clock drivers have been converted to new style, 82 * this dissapears. 83 */ 84 static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT]; 85 86 /* 87 * Forward declarations 88 */ 89 #ifdef QSORT_USES_VOID_P 90 static int refclock_cmpl_fp P((const void *, const void *)); 91 #else 92 static int refclock_cmpl_fp P((const double *, const double *)); 93 #endif /* QSORT_USES_VOID_P */ 94 static int refclock_sample P((struct refclockproc *)); 95 96 /* 97 * refclock_report - note the occurance of an event 98 * 99 * This routine presently just remembers the report and logs it, but 100 * does nothing heroic for the trap handler. It tries to be a good 101 * citizen and bothers the system log only if things change. 102 */ 103 void 104 refclock_report( 105 struct peer *peer, 106 int code 107 ) 108 { 109 struct refclockproc *pp; 110 111 pp = peer->procptr; 112 if (pp == NULL) 113 return; 114 if (code == CEVNT_BADREPLY) 115 pp->badformat++; 116 if (code == CEVNT_BADTIME) 117 pp->baddata++; 118 if (code == CEVNT_TIMEOUT) 119 pp->noreply++; 120 if (pp->currentstatus != code) { 121 pp->currentstatus = (u_char)code; 122 pp->lastevent = (u_char)code; 123 if (code == CEVNT_FAULT) 124 msyslog(LOG_ERR, 125 "clock %s event '%s' (0x%02x)", 126 refnumtoa(&peer->srcadr), 127 ceventstr(code), code); 128 else { 129 NLOG(NLOG_CLOCKEVENT) 130 msyslog(LOG_INFO, 131 "clock %s event '%s' (0x%02x)", 132 refnumtoa(&peer->srcadr), 133 ceventstr(code), code); 134 } 135 } 136 #ifdef DEBUG 137 if (debug) 138 printf("clock %s event '%s' (0x%02x)\n", 139 refnumtoa(&peer->srcadr), 140 ceventstr(code), code); 141 #endif 142 } 143 144 145 /* 146 * init_refclock - initialize the reference clock drivers 147 * 148 * This routine calls each of the drivers in turn to initialize internal 149 * variables, if necessary. Most drivers have nothing to say at this 150 * point. 151 */ 152 void 153 init_refclock(void) 154 { 155 int i, j; 156 157 for (i = 0; i < (int)num_refclock_conf; i++) { 158 if (refclock_conf[i]->clock_init != noentry) 159 (refclock_conf[i]->clock_init)(); 160 for (j = 0; j < MAXUNIT; j++) 161 typeunit[i][j] = 0; 162 } 163 } 164 165 166 /* 167 * refclock_newpeer - initialize and start a reference clock 168 * 169 * This routine allocates and initializes the interface structure which 170 * supports a reference clock in the form of an ordinary NTP peer. A 171 * driver-specific support routine completes the initialization, if 172 * used. Default peer variables which identify the clock and establish 173 * its reference ID and stratum are set here. It returns one if success 174 * and zero if the clock address is invalid or already running, 175 * insufficient resources are available or the driver declares a bum 176 * rap. 177 */ 178 int 179 refclock_newpeer( 180 struct peer *peer /* peer structure pointer */ 181 ) 182 { 183 struct refclockproc *pp; 184 u_char clktype; 185 int unit; 186 187 /* 188 * Check for valid clock address. If already running, shut it 189 * down first. 190 */ 191 if (peer->srcadr.ss_family != AF_INET) { 192 msyslog(LOG_ERR, 193 "refclock_newpeer: clock address %s invalid, address family not implemented for refclock", 194 stoa(&peer->srcadr)); 195 return (0); 196 } 197 if (!ISREFCLOCKADR(&peer->srcadr)) { 198 msyslog(LOG_ERR, 199 "refclock_newpeer: clock address %s invalid", 200 stoa(&peer->srcadr)); 201 return (0); 202 } 203 clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); 204 unit = REFCLOCKUNIT(&peer->srcadr); 205 if (clktype >= num_refclock_conf || unit >= MAXUNIT || 206 refclock_conf[clktype]->clock_start == noentry) { 207 msyslog(LOG_ERR, 208 "refclock_newpeer: clock type %d invalid\n", 209 clktype); 210 return (0); 211 } 212 213 /* 214 * Allocate and initialize interface structure 215 */ 216 pp = (struct refclockproc *)emalloc(sizeof(struct refclockproc)); 217 if (pp == NULL) 218 return (0); 219 memset((char *)pp, 0, sizeof(struct refclockproc)); 220 typeunit[clktype][unit] = peer; 221 peer->procptr = pp; 222 223 /* 224 * Initialize structures 225 */ 226 peer->refclktype = clktype; 227 peer->refclkunit = (u_char)unit; 228 peer->flags |= FLAG_REFCLOCK; 229 peer->maxpoll = peer->minpoll; 230 peer->stratum = STRATUM_REFCLOCK; 231 pp->type = clktype; 232 pp->timestarted = current_time; 233 234 /* 235 * Set peer.pmode based on the hmode. For appearances only. 236 */ 237 switch (peer->hmode) { 238 case MODE_ACTIVE: 239 peer->pmode = MODE_PASSIVE; 240 break; 241 242 default: 243 peer->pmode = MODE_SERVER; 244 break; 245 } 246 247 /* 248 * Do driver dependent initialization. The above defaults 249 * can be wiggled, then finish up for consistency. 250 */ 251 if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { 252 refclock_unpeer(peer); 253 return (0); 254 } 255 peer->hpoll = peer->minpoll; 256 peer->ppoll = peer->maxpoll; 257 peer->refid = pp->refid; 258 return (1); 259 } 260 261 262 /* 263 * refclock_unpeer - shut down a clock 264 */ 265 void 266 refclock_unpeer( 267 struct peer *peer /* peer structure pointer */ 268 ) 269 { 270 u_char clktype; 271 int unit; 272 273 /* 274 * Wiggle the driver to release its resources, then give back 275 * the interface structure. 276 */ 277 if (!peer->procptr) 278 return; 279 clktype = peer->refclktype; 280 unit = peer->refclkunit; 281 if (refclock_conf[clktype]->clock_shutdown != noentry) 282 (refclock_conf[clktype]->clock_shutdown)(unit, peer); 283 free(peer->procptr); 284 peer->procptr = 0; 285 } 286 287 288 /* 289 * refclock_transmit - simulate the transmit procedure 290 * 291 * This routine implements the NTP transmit procedure for a reference 292 * clock. This provides a mechanism to call the driver at the NTP poll 293 * interval, as well as provides a reachability mechanism to detect a 294 * broken radio or other madness. 295 */ 296 void 297 refclock_transmit( 298 struct peer *peer /* peer structure pointer */ 299 ) 300 { 301 u_char clktype; 302 int unit; 303 u_long next; 304 305 clktype = peer->refclktype; 306 unit = peer->refclkunit; 307 peer->sent++; 308 309 /* 310 * This is a ripoff of the peer transmit routine, but 311 * specialized for reference clocks. We do a little less 312 * protocol here and call the driver-specific transmit routine. 313 */ 314 next = peer->outdate; 315 if (peer->burst == 0) { 316 u_char oreach; 317 #ifdef DEBUG 318 if (debug) 319 printf("refclock_transmit: at %ld %s\n", 320 current_time, stoa(&(peer->srcadr))); 321 #endif 322 323 /* 324 * Update reachability and poll variables like the 325 * network code. 326 */ 327 oreach = peer->reach; 328 peer->reach <<= 1; 329 if (!peer->reach) { 330 if (oreach) { 331 report_event(EVNT_UNREACH, peer); 332 peer->timereachable = current_time; 333 peer_clear(peer, "NONE"); 334 } 335 } else { 336 if (!(oreach & 0x03)) { 337 clock_filter(peer, 0., 0., MAXDISPERSE); 338 clock_select(); 339 } 340 if (peer->flags & FLAG_BURST) 341 peer->burst = NSTAGE; 342 } 343 next = current_time; 344 } 345 get_systime(&peer->xmt); 346 if (refclock_conf[clktype]->clock_poll != noentry) 347 (refclock_conf[clktype]->clock_poll)(unit, peer); 348 peer->outdate = next; 349 if (peer->burst > 0) 350 peer->burst--; 351 poll_update(peer, 0); 352 } 353 354 355 /* 356 * Compare two doubles - used with qsort() 357 */ 358 #ifdef QSORT_USES_VOID_P 359 static int 360 refclock_cmpl_fp( 361 const void *p1, 362 const void *p2 363 ) 364 { 365 const double *dp1 = (const double *)p1; 366 const double *dp2 = (const double *)p2; 367 368 if (*dp1 < *dp2) 369 return (-1); 370 if (*dp1 > *dp2) 371 return (1); 372 return (0); 373 } 374 #else 375 static int 376 refclock_cmpl_fp( 377 const double *dp1, 378 const double *dp2 379 ) 380 { 381 if (*dp1 < *dp2) 382 return (-1); 383 if (*dp1 > *dp2) 384 return (1); 385 return (0); 386 } 387 #endif /* QSORT_USES_VOID_P */ 388 389 390 /* 391 * refclock_process_offset - update median filter 392 * 393 * This routine uses the given offset and timestamps to construct a new 394 * entry in the median filter circular buffer. Samples that overflow the 395 * filter are quietly discarded. 396 */ 397 void 398 refclock_process_offset( 399 struct refclockproc *pp, /* refclock structure pointer */ 400 l_fp lasttim, /* last timecode timestamp */ 401 l_fp lastrec, /* last receive timestamp */ 402 double fudge 403 ) 404 { 405 l_fp lftemp; 406 double doffset; 407 408 pp->lastrec = lastrec; 409 lftemp = lasttim; 410 L_SUB(&lftemp, &lastrec); 411 LFPTOD(&lftemp, doffset); 412 SAMPLE(doffset + fudge); 413 } 414 415 /* 416 * refclock_process - process a sample from the clock 417 * 418 * This routine converts the timecode in the form days, hours, minutes, 419 * seconds and milliseconds/microseconds to internal timestamp format, 420 * then constructs a new entry in the median filter circular buffer. 421 * Return success (1) if the data are correct and consistent with the 422 * converntional calendar. 423 */ 424 int 425 refclock_process( 426 struct refclockproc *pp /* refclock structure pointer */ 427 ) 428 { 429 l_fp offset, ltemp; 430 431 /* 432 * Compute the timecode timestamp from the days, hours, minutes, 433 * seconds and milliseconds/microseconds of the timecode. Use 434 * clocktime() for the aggregate seconds and the msec/usec for 435 * the fraction, when present. Note that this code relies on the 436 * filesystem time for the years and does not use the years of 437 * the timecode. 438 */ 439 if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT, 440 pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui)) 441 return (0); 442 offset.l_uf = 0; 443 DTOLFP(pp->nsec / 1e9, <emp); 444 L_ADD(&offset, <emp); 445 refclock_process_offset(pp, offset, pp->lastrec, 446 pp->fudgetime1); 447 return (1); 448 } 449 450 /* 451 * refclock_sample - process a pile of samples from the clock 452 * 453 * This routine implements a recursive median filter to suppress spikes 454 * in the data, as well as determine a performance statistic. It 455 * calculates the mean offset and jitter (squares). A time adjustment 456 * fudgetime1 can be added to the final offset to compensate for various 457 * systematic errors. The routine returns the number of samples 458 * processed, which could be zero. 459 */ 460 static int 461 refclock_sample( 462 struct refclockproc *pp /* refclock structure pointer */ 463 ) 464 { 465 int i, j, k, m, n; 466 double offset; 467 double off[MAXSTAGE]; 468 469 /* 470 * Copy the raw offsets and sort into ascending order. Don't do 471 * anything if the buffer is empty. 472 */ 473 n = 0; 474 while (pp->codeproc != pp->coderecv) { 475 pp->codeproc = (pp->codeproc + 1) % MAXSTAGE; 476 off[n] = pp->filter[pp->codeproc]; 477 n++; 478 } 479 if (n == 0) 480 return (0); 481 if (n > 1) 482 qsort((char *)off, (size_t)n, sizeof(double), refclock_cmpl_fp); 483 484 /* 485 * Reject the furthest from the median of the samples until 486 * approximately 60 percent of the samples remain. 487 */ 488 i = 0; j = n; 489 m = n - (n * 2) / NSTAGE; 490 while ((j - i) > m) { 491 offset = off[(j + i) / 2]; 492 if (off[j - 1] - offset < offset - off[i]) 493 i++; /* reject low end */ 494 else 495 j--; /* reject high end */ 496 } 497 498 /* 499 * Determine the offset and jitter. 500 */ 501 offset = 0; 502 for (k = i; k < j; k++) 503 offset += off[k]; 504 pp->offset = offset / m; 505 if (m > 1) 506 pp->jitter = SQUARE(off[i] - off[j - 1]); 507 else 508 pp->jitter = 0; 509 #ifdef DEBUG 510 if (debug) 511 printf( 512 "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n", 513 n, pp->offset, pp->disp, SQRT(pp->jitter)); 514 #endif 515 return (n); 516 } 517 518 519 /* 520 * refclock_receive - simulate the receive and packet procedures 521 * 522 * This routine simulates the NTP receive and packet procedures for a 523 * reference clock. This provides a mechanism in which the ordinary NTP 524 * filter, selection and combining algorithms can be used to suppress 525 * misbehaving radios and to mitigate between them when more than one is 526 * available for backup. 527 */ 528 void 529 refclock_receive( 530 struct peer *peer /* peer structure pointer */ 531 ) 532 { 533 struct refclockproc *pp; 534 535 #ifdef DEBUG 536 if (debug) 537 printf("refclock_receive: at %lu %s\n", 538 current_time, stoa(&peer->srcadr)); 539 #endif 540 541 /* 542 * Do a little sanity dance and update the peer structure. Groom 543 * the median filter samples and give the data to the clock 544 * filter. 545 */ 546 peer->received++; 547 pp = peer->procptr; 548 peer->processed++; 549 peer->timereceived = current_time; 550 peer->leap = pp->leap; 551 if (peer->leap == LEAP_NOTINSYNC) { 552 refclock_report(peer, CEVNT_FAULT); 553 return; 554 } 555 if (!peer->reach) 556 report_event(EVNT_REACH, peer); 557 peer->reach |= 1; 558 peer->reftime = pp->lastref; 559 peer->org = pp->lastrec; 560 peer->rootdispersion = pp->disp; 561 get_systime(&peer->rec); 562 if (!refclock_sample(pp)) 563 return; 564 clock_filter(peer, pp->offset, 0., pp->jitter); 565 clock_select(); 566 record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), 567 peer->offset, peer->delay, clock_phi * (current_time - 568 peer->epoch), SQRT(peer->jitter)); 569 if (cal_enable && last_offset < MINDISPERSE) { 570 #ifdef KERNEL_PLL 571 if (peer != sys_peer || pll_status & STA_PPSTIME) 572 #else 573 if (peer != sys_peer) 574 #endif /* KERNEL_PLL */ 575 pp->fudgetime1 -= pp->offset * FUDGEFAC; 576 else 577 pp->fudgetime1 -= pp->fudgetime1 * FUDGEFAC; 578 } 579 } 580 581 /* 582 * refclock_gtlin - groom next input line and extract timestamp 583 * 584 * This routine processes the timecode received from the clock and 585 * removes the parity bit and control characters. If a timestamp is 586 * present in the timecode, as produced by the tty_clk STREAMS module, 587 * it returns that as the timestamp; otherwise, it returns the buffer 588 * timestamp. The routine return code is the number of characters in 589 * the line. 590 */ 591 int 592 refclock_gtlin( 593 struct recvbuf *rbufp, /* receive buffer pointer */ 594 char *lineptr, /* current line pointer */ 595 int bmax, /* remaining characters in line */ 596 l_fp *tsptr /* pointer to timestamp returned */ 597 ) 598 { 599 char *dpt, *dpend, *dp; 600 int i; 601 l_fp trtmp, tstmp; 602 char c; 603 604 /* 605 * Check for the presence of a timestamp left by the tty_clock 606 * module and, if present, use that instead of the buffer 607 * timestamp captured by the I/O routines. We recognize a 608 * timestamp by noting its value is earlier than the buffer 609 * timestamp, but not more than one second earlier. 610 */ 611 dpt = (char *)rbufp->recv_buffer; 612 dpend = dpt + rbufp->recv_length; 613 trtmp = rbufp->recv_time; 614 615 if (dpend >= dpt + 8) { 616 if (buftvtots(dpend - 8, &tstmp)) { 617 L_SUB(&trtmp, &tstmp); 618 if (trtmp.l_ui == 0) { 619 #ifdef DEBUG 620 if (debug > 1) { 621 printf( 622 "refclock_gtlin: fd %d ldisc %s", 623 rbufp->fd, lfptoa(&trtmp, 6)); 624 get_systime(&trtmp); 625 L_SUB(&trtmp, &tstmp); 626 printf(" sigio %s\n", lfptoa(&trtmp, 6)); 627 } 628 #endif 629 dpend -= 8; 630 trtmp = tstmp; 631 } else 632 trtmp = rbufp->recv_time; 633 } 634 } 635 636 /* 637 * Edit timecode to remove control chars. Don't monkey with the 638 * line buffer if the input buffer contains no ASCII printing 639 * characters. 640 */ 641 if (dpend - dpt > bmax - 1) 642 dpend = dpt + bmax - 1; 643 for (dp = lineptr; dpt < dpend; dpt++) { 644 c = (char) (*dpt & 0x7f); 645 if (c >= ' ') 646 *dp++ = c; 647 } 648 i = dp - lineptr; 649 if (i > 0) 650 *dp = '\0'; 651 #ifdef DEBUG 652 if (debug > 1) { 653 if (i > 0) 654 printf("refclock_gtlin: fd %d time %s timecode %d %s\n", 655 rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr); 656 else 657 printf("refclock_gtlin: fd %d time %s\n", 658 rbufp->fd, ulfptoa(&trtmp, 6)); 659 } 660 #endif 661 *tsptr = trtmp; 662 return (i); 663 } 664 665 /* 666 * The following code does not apply to WINNT & VMS ... 667 */ 668 #if !defined SYS_VXWORKS && !defined SYS_WINNT 669 #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) 670 671 /* 672 * refclock_open - open serial port for reference clock 673 * 674 * This routine opens a serial port for I/O and sets default options. It 675 * returns the file descriptor if success and zero if failure. 676 */ 677 int 678 refclock_open( 679 char *dev, /* device name pointer */ 680 int speed, /* serial port speed (code) */ 681 int lflags /* line discipline flags */ 682 ) 683 { 684 int fd, i; 685 int flags; 686 TTY ttyb, *ttyp; 687 #ifdef TIOCMGET 688 u_long ltemp; 689 #endif /* TIOCMGET */ 690 int omode; 691 692 /* 693 * Open serial port and set default options 694 */ 695 flags = lflags; 696 697 omode = O_RDWR; 698 #ifdef O_NONBLOCK 699 omode |= O_NONBLOCK; 700 #endif 701 #ifdef O_NOCTTY 702 omode |= O_NOCTTY; 703 #endif 704 705 fd = open(dev, omode, 0777); 706 707 if (fd < 0) { 708 msyslog(LOG_ERR, "refclock_open: %s: %m", dev); 709 return (0); 710 } 711 712 /* 713 * This little jewel lights up the PPS file descriptor if the 714 * device name matches the name in the pps line in the 715 * configuration file. This is so the atom driver can glom onto 716 * the right device. Very silly. 717 */ 718 if (strcmp(dev, pps_device) == 0) 719 fdpps = fd; 720 721 /* 722 * The following sections initialize the serial line port in 723 * canonical (line-oriented) mode and set the specified line 724 * speed, 8 bits and no parity. The modem control, break, erase 725 * and kill functions are normally disabled. There is a 726 * different section for each terminal interface, as selected at 727 * compile time. 728 */ 729 ttyp = &ttyb; 730 731 #ifdef HAVE_TERMIOS 732 /* 733 * POSIX serial line parameters (termios interface) 734 */ 735 if (tcgetattr(fd, ttyp) < 0) { 736 msyslog(LOG_ERR, 737 "refclock_open: fd %d tcgetattr: %m", fd); 738 return (0); 739 } 740 741 /* 742 * Set canonical mode and local connection; set specified speed, 743 * 8 bits and no parity; map CR to NL; ignore break. 744 */ 745 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 746 ttyp->c_oflag = 0; 747 ttyp->c_cflag = CS8 | CLOCAL | CREAD; 748 (void)cfsetispeed(&ttyb, (u_int)speed); 749 (void)cfsetospeed(&ttyb, (u_int)speed); 750 ttyp->c_lflag = ICANON; 751 for (i = 0; i < NCCS; ++i) 752 { 753 ttyp->c_cc[i] = '\0'; 754 } 755 756 /* 757 * Some special cases 758 */ 759 if (flags & LDISC_RAW) { 760 ttyp->c_iflag = 0; 761 ttyp->c_lflag = 0; 762 ttyp->c_cc[VMIN] = 1; 763 } 764 #if defined(TIOCMGET) && !defined(SCO5_CLOCK) 765 /* 766 * If we have modem control, check to see if modem leads are 767 * active; if so, set remote connection. This is necessary for 768 * the kernel pps mods to work. 769 */ 770 ltemp = 0; 771 if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 772 msyslog(LOG_ERR, 773 "refclock_open: fd %d TIOCMGET failed: %m", fd); 774 #ifdef DEBUG 775 if (debug) 776 printf("refclock_open: fd %d modem status 0x%lx\n", 777 fd, ltemp); 778 #endif 779 if (ltemp & TIOCM_DSR) 780 ttyp->c_cflag &= ~CLOCAL; 781 #endif /* TIOCMGET */ 782 if (tcsetattr(fd, TCSANOW, ttyp) < 0) { 783 msyslog(LOG_ERR, 784 "refclock_open: fd %d TCSANOW failed: %m", fd); 785 return (0); 786 } 787 if (tcflush(fd, TCIOFLUSH) < 0) { 788 msyslog(LOG_ERR, 789 "refclock_open: fd %d TCIOFLUSH failed: %m", fd); 790 return (0); 791 } 792 #endif /* HAVE_TERMIOS */ 793 794 #ifdef HAVE_SYSV_TTYS 795 796 /* 797 * System V serial line parameters (termio interface) 798 * 799 */ 800 if (ioctl(fd, TCGETA, ttyp) < 0) { 801 msyslog(LOG_ERR, 802 "refclock_open: fd %d TCGETA failed: %m", fd); 803 return (0); 804 } 805 806 /* 807 * Set canonical mode and local connection; set specified speed, 808 * 8 bits and no parity; map CR to NL; ignore break. 809 */ 810 ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL; 811 ttyp->c_oflag = 0; 812 ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD; 813 ttyp->c_lflag = ICANON; 814 ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; 815 816 /* 817 * Some special cases 818 */ 819 if (flags & LDISC_RAW) { 820 ttyp->c_iflag = 0; 821 ttyp->c_lflag = 0; 822 } 823 #ifdef TIOCMGET 824 /* 825 * If we have modem control, check to see if modem leads are 826 * active; if so, set remote connection. This is necessary for 827 * the kernel pps mods to work. 828 */ 829 ltemp = 0; 830 if (ioctl(fd, TIOCMGET, (char *)<emp) < 0) 831 msyslog(LOG_ERR, 832 "refclock_open: fd %d TIOCMGET failed: %m", fd); 833 #ifdef DEBUG 834 if (debug) 835 printf("refclock_open: fd %d modem status %lx\n", 836 fd, ltemp); 837 #endif 838 if (ltemp & TIOCM_DSR) 839 ttyp->c_cflag &= ~CLOCAL; 840 #endif /* TIOCMGET */ 841 if (ioctl(fd, TCSETA, ttyp) < 0) { 842 msyslog(LOG_ERR, 843 "refclock_open: fd %d TCSETA failed: %m", fd); 844 return (0); 845 } 846 #endif /* HAVE_SYSV_TTYS */ 847 848 #ifdef HAVE_BSD_TTYS 849 850 /* 851 * 4.3bsd serial line parameters (sgttyb interface) 852 */ 853 if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) { 854 msyslog(LOG_ERR, 855 "refclock_open: fd %d TIOCGETP %m", fd); 856 return (0); 857 } 858 ttyp->sg_ispeed = ttyp->sg_ospeed = speed; 859 ttyp->sg_flags = EVENP | ODDP | CRMOD; 860 if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) { 861 msyslog(LOG_ERR, 862 "refclock_open: TIOCSETP failed: %m"); 863 return (0); 864 } 865 #endif /* HAVE_BSD_TTYS */ 866 if (!refclock_ioctl(fd, flags)) { 867 (void)close(fd); 868 msyslog(LOG_ERR, 869 "refclock_open: fd %d ioctl failed: %m", fd); 870 return (0); 871 } 872 return (fd); 873 } 874 #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ 875 #endif /* SYS_VXWORKS SYS_WINNT */ 876 877 /* 878 * refclock_ioctl - set serial port control functions 879 * 880 * This routine attempts to hide the internal, system-specific details 881 * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD 882 * (sgtty) interfaces with varying degrees of success. The routine sets 883 * up optional features such as tty_clk. The routine returns 1 if 884 * success and 0 if failure. 885 */ 886 int 887 refclock_ioctl( 888 int fd, /* file descriptor */ 889 int flags /* line discipline flags */ 890 ) 891 { 892 /* simply return 1 if no UNIX line discipline is supported */ 893 #if !defined SYS_VXWORKS && !defined SYS_WINNT 894 #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS) 895 896 #ifdef TTYCLK 897 TTY ttyb, *ttyp; 898 #endif /* TTYCLK */ 899 900 #ifdef DEBUG 901 if (debug) 902 printf("refclock_ioctl: fd %d flags 0x%x\n", fd, flags); 903 #endif 904 if (flags == 0) 905 return (1); 906 #if !(defined(HAVE_TERMIOS) || defined(HAVE_BSD_TTYS)) 907 if (flags & (LDISC_CLK | LDISC_PPS | LDISC_ACTS)) { 908 msyslog(LOG_ERR, 909 "refclock_ioctl: unsupported terminal interface"); 910 return (0); 911 } 912 #endif /* HAVE_TERMIOS HAVE_BSD_TTYS */ 913 #ifdef TTYCLK 914 ttyp = &ttyb; 915 #endif /* TTYCLK */ 916 917 /* 918 * The following features may or may not require System V 919 * STREAMS support, depending on the particular implementation. 920 */ 921 #if defined(TTYCLK) 922 /* 923 * The TTYCLK option provides timestamping at the driver level. 924 * It requires the tty_clk streams module and System V STREAMS 925 * support. If not available, don't complain. 926 */ 927 if (flags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) { 928 int rval = 0; 929 930 if (ioctl(fd, I_PUSH, "clk") < 0) { 931 msyslog(LOG_NOTICE, 932 "refclock_ioctl: I_PUSH clk failed: %m"); 933 } else { 934 char *str; 935 936 if (flags & LDISC_CLKPPS) 937 str = "\377"; 938 else if (flags & LDISC_ACTS) 939 str = "*"; 940 else 941 str = "\n"; 942 #ifdef CLK_SETSTR 943 if ((rval = ioctl(fd, CLK_SETSTR, str)) < 0) 944 msyslog(LOG_ERR, 945 "refclock_ioctl: CLK_SETSTR failed: %m"); 946 if (debug) 947 printf("refclock_ioctl: fd %d CLK_SETSTR %d str %s\n", 948 fd, rval, str); 949 #endif 950 } 951 } 952 #endif /* TTYCLK */ 953 #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */ 954 #endif /* SYS_VXWORKS SYS_WINNT */ 955 return (1); 956 } 957 958 /* 959 * refclock_control - set and/or return clock values 960 * 961 * This routine is used mainly for debugging. It returns designated 962 * values from the interface structure that can be displayed using 963 * ntpdc and the clockstat command. It can also be used to initialize 964 * configuration variables, such as fudgetimes, fudgevalues, reference 965 * ID and stratum. 966 */ 967 void 968 refclock_control( 969 struct sockaddr_storage *srcadr, 970 struct refclockstat *in, 971 struct refclockstat *out 972 ) 973 { 974 struct peer *peer; 975 struct refclockproc *pp; 976 u_char clktype; 977 int unit; 978 979 /* 980 * Check for valid address and running peer 981 */ 982 if (srcadr->ss_family != AF_INET) 983 return; 984 if (!ISREFCLOCKADR(srcadr)) 985 return; 986 clktype = (u_char)REFCLOCKTYPE(srcadr); 987 unit = REFCLOCKUNIT(srcadr); 988 if (clktype >= num_refclock_conf || unit >= MAXUNIT) 989 return; 990 peer = typeunit[clktype][unit]; 991 if (peer == NULL) 992 return; 993 if (peer->procptr == NULL) 994 return; 995 pp = peer->procptr; 996 997 /* 998 * Initialize requested data 999 */ 1000 if (in != 0) { 1001 if (in->haveflags & CLK_HAVETIME1) 1002 pp->fudgetime1 = in->fudgetime1; 1003 if (in->haveflags & CLK_HAVETIME2) 1004 pp->fudgetime2 = in->fudgetime2; 1005 if (in->haveflags & CLK_HAVEVAL1) 1006 pp->stratum = (u_char) in->fudgeval1; 1007 if (in->haveflags & CLK_HAVEVAL2) 1008 pp->refid = in->fudgeval2; 1009 peer->stratum = pp->stratum; 1010 if (peer->stratum == STRATUM_REFCLOCK || peer->stratum == 1011 STRATUM_UNSPEC) 1012 peer->refid = pp->refid; 1013 else 1014 peer->refid = ((struct 1015 sockaddr_in*)&peer->srcadr)->sin_addr.s_addr; 1016 if (in->haveflags & CLK_HAVEFLAG1) { 1017 pp->sloppyclockflag &= ~CLK_FLAG1; 1018 pp->sloppyclockflag |= in->flags & CLK_FLAG1; 1019 } 1020 if (in->haveflags & CLK_HAVEFLAG2) { 1021 pp->sloppyclockflag &= ~CLK_FLAG2; 1022 pp->sloppyclockflag |= in->flags & CLK_FLAG2; 1023 } 1024 if (in->haveflags & CLK_HAVEFLAG3) { 1025 pp->sloppyclockflag &= ~CLK_FLAG3; 1026 pp->sloppyclockflag |= in->flags & CLK_FLAG3; 1027 } 1028 if (in->haveflags & CLK_HAVEFLAG4) { 1029 pp->sloppyclockflag &= ~CLK_FLAG4; 1030 pp->sloppyclockflag |= in->flags & CLK_FLAG4; 1031 } 1032 } 1033 1034 /* 1035 * Readback requested data 1036 */ 1037 if (out != 0) { 1038 out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 | 1039 CLK_HAVEVAL2 | CLK_HAVEFLAG4; 1040 out->fudgetime1 = pp->fudgetime1; 1041 out->fudgetime2 = pp->fudgetime2; 1042 out->fudgeval1 = pp->stratum; 1043 out->fudgeval2 = pp->refid; 1044 out->flags = (u_char) pp->sloppyclockflag; 1045 1046 out->timereset = current_time - pp->timestarted; 1047 out->polls = pp->polls; 1048 out->noresponse = pp->noreply; 1049 out->badformat = pp->badformat; 1050 out->baddata = pp->baddata; 1051 1052 out->lastevent = pp->lastevent; 1053 out->currentstatus = pp->currentstatus; 1054 out->type = pp->type; 1055 out->clockdesc = pp->clockdesc; 1056 out->lencode = pp->lencode; 1057 out->p_lastcode = pp->a_lastcode; 1058 } 1059 1060 /* 1061 * Give the stuff to the clock 1062 */ 1063 if (refclock_conf[clktype]->clock_control != noentry) 1064 (refclock_conf[clktype]->clock_control)(unit, in, out, peer); 1065 } 1066 1067 1068 /* 1069 * refclock_buginfo - return debugging info 1070 * 1071 * This routine is used mainly for debugging. It returns designated 1072 * values from the interface structure that can be displayed using 1073 * ntpdc and the clkbug command. 1074 */ 1075 void 1076 refclock_buginfo( 1077 struct sockaddr_storage *srcadr, /* clock address */ 1078 struct refclockbug *bug /* output structure */ 1079 ) 1080 { 1081 struct peer *peer; 1082 struct refclockproc *pp; 1083 u_char clktype; 1084 int unit; 1085 int i; 1086 1087 /* 1088 * Check for valid address and peer structure 1089 */ 1090 if (srcadr->ss_family != AF_INET) 1091 return; 1092 if (!ISREFCLOCKADR(srcadr)) 1093 return; 1094 clktype = (u_char) REFCLOCKTYPE(srcadr); 1095 unit = REFCLOCKUNIT(srcadr); 1096 if (clktype >= num_refclock_conf || unit >= MAXUNIT) 1097 return; 1098 peer = typeunit[clktype][unit]; 1099 if (peer == NULL) 1100 return; 1101 pp = peer->procptr; 1102 1103 /* 1104 * Copy structure values 1105 */ 1106 bug->nvalues = 8; 1107 bug->svalues = 0x0000003f; 1108 bug->values[0] = pp->year; 1109 bug->values[1] = pp->day; 1110 bug->values[2] = pp->hour; 1111 bug->values[3] = pp->minute; 1112 bug->values[4] = pp->second; 1113 bug->values[5] = pp->nsec; 1114 bug->values[6] = pp->yearstart; 1115 bug->values[7] = pp->coderecv; 1116 bug->stimes = 0xfffffffc; 1117 bug->times[0] = pp->lastref; 1118 bug->times[1] = pp->lastrec; 1119 for (i = 2; i < (int)bug->ntimes; i++) 1120 DTOLFP(pp->filter[i - 2], &bug->times[i]); 1121 1122 /* 1123 * Give the stuff to the clock 1124 */ 1125 if (refclock_conf[clktype]->clock_buginfo != noentry) 1126 (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer); 1127 } 1128 1129 #endif /* REFCLOCK */ 1130