]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/ntpd/ntp_refclock.c
This commit was generated by cvs2svn to compensate for changes in r169691,
[FreeBSD/FreeBSD.git] / contrib / ntp / ntpd / ntp_refclock.c
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, &ltemp);
444         L_ADD(&offset, &ltemp);
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 *)&ltemp) < 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 *)&ltemp) < 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 */