Change the default for ntpd back to -s, the bug which triggered this
[dragonfly.git] / contrib / ntp / ntpd / refclock_usno.c
1 /*
2  * refclock_usno - clock driver for the Naval Observatory dialup
3  * Michael Shields <shields@tembel.org> 1995/02/25
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9
10 #if defined(REFCLOCK) && defined(CLOCK_USNO)
11
12 #include "ntpd.h"
13 #include "ntp_io.h"
14 #include "ntp_unixtime.h"
15 #include "ntp_refclock.h"
16 #include "ntp_stdlib.h"
17 #include "ntp_control.h"
18
19 #include <stdio.h>
20 #include <ctype.h>
21 #ifdef HAVE_SYS_IOCTL_H
22 # include <sys/ioctl.h>
23 #endif /* HAVE_SYS_IOCTL_H */
24
25 /*
26  * This driver supports the Naval Observatory dialup at +1 202 653 0351.
27  * It is a hacked-up version of the ACTS driver.
28  *
29  * This driver does not support the `phone' configuration because that
30  * is needlessly global; it would clash with the ACTS driver.
31  *
32  * The Naval Observatory does not support the echo-delay measurement scheme.
33  *
34  * However, this driver *does* support UUCP port locking, allowing the
35  * line to be shared with other processes when not actually dialing
36  * for time.
37  */
38
39 /*
40  * Interface definitions
41  */
42
43 #define DEVICE          "/dev/cua%d" /* device name and unit */
44 #define LOCKFILE        "/var/lock/LCK..cua%d"
45 /* #define LOCKFILE     "/usr/spool/uucp/LCK..cua%d" */
46
47 #define PHONE           "atdt 202 653 0351"
48 /* #define PHONE        "atdt 1 202 653 0351" */
49
50 #define SPEED232        B1200   /* uart speed (1200 cowardly baud) */
51 #define PRECISION       (-10)   /* precision assumed (about 1 ms) */
52 #define REFID           "USNO"  /* reference ID */
53 #define DESCRIPTION     "Naval Observatory dialup"
54
55 #define MODE_AUTO       0       /* automatic mode */
56 #define MODE_BACKUP     1       /* backup mode */
57 #define MODE_MANUAL     2       /* manual mode */
58
59 #define MSGCNT          10      /* we need this many time messages */
60 #define SMAX            80      /* max token string length */
61 #define LENCODE         20      /* length of valid timecode string */
62 #define USNO_MINPOLL    10      /* log2 min poll interval (1024 s) */
63 #define USNO_MAXPOLL    14      /* log2 max poll interval (16384 s) */
64 #define MAXOUTAGE       3600    /* max before USNO kicks in (s) */
65
66 /*
67  * Modem control strings. These may have to be changed for some modems.
68  *
69  * AT   command prefix
70  * B1   initiate call negotiation using Bell 212A
71  * &C1  enable carrier detect
72  * &D2  hang up and return to command mode on DTR transition
73  * E0   modem command echo disabled
74  * l1   set modem speaker volume to low level
75  * M1   speaker enabled untill carrier detect
76  * Q0   return result codes
77  * V1   return result codes as English words
78  */
79 #define MODEM_SETUP     "ATB1&C1&D2E0L1M1Q0V1" /* modem setup */
80 #define MODEM_HANGUP    "ATH"   /* modem disconnect */
81
82 /*
83  * Timeouts
84  */
85 #define IDLE            60      /* idle timeout (s) */
86 #define WAIT            2       /* wait timeout (s) */
87 #define ANSWER          30      /* answer timeout (s) */
88 #define CONNECT         10      /* connect timeout (s) */
89 #define TIMECODE        (MSGCNT+16)     /* timecode timeout (s) */
90
91 /*
92  * Unit control structure
93  */
94 struct usnounit {
95         int     pollcnt;        /* poll message counter */
96
97         int     state;          /* the first one was Delaware */
98         int     run;            /* call program run switch */
99         int     msgcnt;         /* count of time messages received */
100         long    redial;         /* interval to next automatic call */
101         int     unit;           /* unit number (= port) */
102 };
103
104 /*
105  * Function prototypes
106  */
107 static  int     usno_start      P((int, struct peer *));
108 static  void    usno_shutdown   P((int, struct peer *));
109 static  void    usno_poll       P((int, struct peer *));
110 static  void    usno_disc       P((struct peer *));
111 #if 0
112 static  void    usno_timeout    P((struct peer *));
113 static  void    usno_receive    P((struct recvbuf *));
114 static  int     usno_write      P((struct peer *, const char *));
115 #endif /* 0 */
116
117 /*
118  * Transfer vector
119  */
120 struct  refclock refclock_usno = {
121         usno_start,             /* start up driver */
122         usno_shutdown,          /* shut down driver */
123         usno_poll,              /* transmit poll message */
124         noentry,                /* not used (usno_control) */
125         noentry,                /* not used (usno_init) */
126         noentry,                /* not used (usno_buginfo) */
127         NOFLAGS                 /* not used */
128 };
129
130
131 /*
132  * usno_start - open the devices and initialize data for processing
133  */
134 static int
135 usno_start(
136         int unit,
137         struct peer *peer
138         )
139 {
140         register struct usnounit *up;
141         struct refclockproc *pp;
142
143         /*
144          * Initialize miscellaneous variables
145          */
146         pp = peer->procptr;
147         peer->precision = PRECISION;
148         pp->clockdesc = DESCRIPTION;
149         memcpy((char *)&pp->refid, REFID, 4);
150         peer->minpoll = USNO_MINPOLL;
151         peer->maxpoll = USNO_MAXPOLL;
152         peer->sstclktype = CTL_SST_TS_TELEPHONE;
153
154         /*
155          * Allocate and initialize unit structure
156          */
157         if (!(up = (struct usnounit *)
158               emalloc(sizeof(struct usnounit))))
159             return (0);
160         memset((char *)up, 0, sizeof(struct usnounit));
161         up->unit = unit;
162         pp->unitptr = (caddr_t)up;
163
164         /*
165          * Set up the driver timeout
166          */
167         peer->nextdate = current_time + WAIT;
168         return (1);
169 }
170
171
172 /*
173  * usno_shutdown - shut down the clock
174  */
175 static void
176 usno_shutdown(
177         int unit,
178         struct peer *peer
179         )
180 {
181         register struct usnounit *up;
182         struct refclockproc *pp;
183
184 #ifdef DEBUG
185         if (debug)
186             printf("usno: clock %s shutting down\n", ntoa(&peer->srcadr));
187 #endif
188         pp = peer->procptr;
189         up = (struct usnounit *)pp->unitptr;
190         usno_disc(peer);
191         free(up);
192 }
193
194
195 #if 0
196 /*
197  * usno_receive - receive data from the serial interface
198  */
199 static void
200 usno_receive(
201         struct recvbuf *rbufp
202         )
203 {
204         register struct usnounit *up;
205         struct refclockproc *pp;
206         struct peer *peer;
207         char str[SMAX];
208         u_long mjd;             /* Modified Julian Day */
209         static int day, hour, minute, second;
210
211         /*
212          * Initialize pointers and read the timecode and timestamp. If
213          * the OK modem status code, leave it where folks can find it.
214          */
215         peer = (struct peer *)rbufp->recv_srcclock;
216         pp = peer->procptr;
217         up = (struct usnounit *)pp->unitptr;
218         pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX,
219                                      &pp->lastrec);
220         if (pp->lencode == 0) {
221                 if (strcmp(pp->a_lastcode, "OK") == 0)
222                     pp->lencode = 2;
223                 return;
224         }
225 #ifdef DEBUG
226         if (debug)
227             printf("usno: timecode %d %s\n", pp->lencode,
228                    pp->a_lastcode);
229 #endif
230
231         switch (up->state) {
232
233             case 0:
234
235                 /*
236                  * State 0. We are not expecting anything. Probably
237                  * modem disconnect noise. Go back to sleep.
238                  */
239                 return;
240
241             case 1:
242
243                 /*
244                  * State 1. We are about to dial. Just drop it.
245                  */
246                 return;
247
248             case 2:
249
250                 /*
251                  * State 2. We are waiting for the call to be answered.
252                  * All we care about here is CONNECT as the first token
253                  * in the string. If the modem signals BUSY, ERROR, NO
254                  * ANSWER, NO CARRIER or NO DIALTONE, we immediately
255                  * hang up the phone. If CONNECT doesn't happen after
256                  * ANSWER seconds, hang up the phone. If everything is
257                  * okay, start the connect timeout and slide into state
258                  * 3.
259                  */
260                 (void)strncpy(str, strtok(pp->a_lastcode, " "), SMAX);
261                 if (strcmp(str, "BUSY") == 0 || strcmp(str, "ERROR") ==
262                     0 || strcmp(str, "NO") == 0) {
263                         NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
264                                 msyslog(LOG_NOTICE,
265                                         "clock %s USNO modem status %s",
266                                         ntoa(&peer->srcadr), pp->a_lastcode);
267                         usno_disc(peer);
268                 } else if (strcmp(str, "CONNECT") == 0) {
269                         peer->nextdate = current_time + CONNECT;
270                         up->msgcnt = 0;
271                         up->state++;
272                 } else {
273                         NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
274                                 msyslog(LOG_WARNING,
275                                         "clock %s USNO unknown modem status %s",
276                                         ntoa(&peer->srcadr), pp->a_lastcode);
277                 }
278                 return;
279
280             case 3:
281
282                 /*
283                  * State 3. The call has been answered and we are
284                  * waiting for the first message. If this doesn't
285                  * happen within the timecode timeout, hang up the
286                  * phone. We probably got a wrong number or they are
287                  * down.
288                  */
289                 peer->nextdate = current_time + TIMECODE;
290                 up->state++;
291                 return;
292
293             case 4:
294
295                 /*
296                  * State 4. We are reading a timecode.  It's an actual
297                  * timecode, or it's the `*' OTM.
298                  *
299                  * jjjjj nnn hhmmss UTC
300                  */
301                 if (pp->lencode == LENCODE) {
302                         if (sscanf(pp->a_lastcode, "%5ld %3d %2d%2d%2d UTC",
303                                    &mjd, &day, &hour, &minute, &second) != 5) {
304 #ifdef DEBUG
305                                 if (debug)
306                                     printf("usno: bad timecode format\n");
307 #endif
308                                 refclock_report(peer, CEVNT_BADREPLY);
309                         } else
310                             up->msgcnt++;
311                         return;
312                 } else if (pp->lencode != 1 || !up->msgcnt)
313                     return;
314                 /* else, OTM; drop out of switch */
315         }
316
317         pp->leap = LEAP_NOWARNING;
318         pp->day = day;
319         pp->hour = hour;
320         pp->minute = minute;
321         pp->second = second;
322
323         /*
324          * Colossal hack here. We process each sample in a trimmed-mean
325          * filter and determine the reference clock offset and
326          * dispersion. The fudge time1 value is added to each sample as
327          * received.
328          */
329         if (!refclock_process(pp)) {
330 #ifdef DEBUG
331                 if (debug)
332                     printf("usno: time rejected\n");
333 #endif
334                 refclock_report(peer, CEVNT_BADTIME);
335                 return;
336         } else if (up->msgcnt < MSGCNT)
337             return;
338
339         /*
340          * We have a filtered sample offset ready for peer processing.
341          * We use lastrec as both the reference time and receive time in
342          * order to avoid being cute, like setting the reference time
343          * later than the receive time, which may cause a paranoid
344          * protocol module to chuck out the data. Finaly, we unhook the
345          * timeout, arm for the next call, fold the tent and go home.
346          */
347         record_clock_stats(&peer->srcadr, pp->a_lastcode);
348         refclock_receive(peer);
349         pp->sloppyclockflag &= ~CLK_FLAG1;
350         up->pollcnt = 0;
351         up->state = 0;
352         usno_disc(peer);
353 }
354 #endif /* 0 */
355
356
357 /*
358  * usno_poll - called by the transmit routine
359  */
360 static void
361 usno_poll(
362         int unit,
363         struct peer *peer
364         )
365 {
366         register struct usnounit *up;
367         struct refclockproc *pp;
368
369         /*
370          * If the driver is running, we set the enable flag (fudge
371          * flag1), which causes the driver timeout routine to initiate a
372          * call. If not, the enable flag can be set using
373          * ntpdc. If this is the sustem peer, then follow the system
374          * poll interval.
375          */
376         pp = peer->procptr;
377         up = (struct usnounit *)pp->unitptr;
378         if (up->run) {
379                 pp->sloppyclockflag |= CLK_FLAG1;
380                 if (peer == sys_peer)
381                     peer->hpoll = sys_poll;
382                 else
383                     peer->hpoll = peer->minpoll;
384         }
385 }
386
387
388 #if 0
389 /*
390  * usno_timeout - called by the timer interrupt
391  */
392 static void
393 usno_timeout(
394         struct peer *peer
395         )
396 {
397         register struct usnounit *up;
398         struct refclockproc *pp;
399         int fd;
400         char device[20];
401         char lockfile[128], pidbuf[8];
402         int dtr = TIOCM_DTR;
403
404         /*
405          * If a timeout occurs in other than state 0, the call has
406          * failed. If in state 0, we just see if there is other work to
407          * do.
408          */
409         pp = peer->procptr;
410         up = (struct usnounit *)pp->unitptr;
411         if (up->state) {
412                 if (up->state != 1) {
413                         usno_disc(peer);
414                         return;
415                 }
416                 /*
417                  * Call, and start the answer timeout. We think it
418                  * strange if the OK status has not been received from
419                  * the modem, but plow ahead anyway.
420                  *
421                  * This code is *here* because we had to stick in a brief
422                  * delay to let the modem settle down after raising DTR,
423                  * and for the OK to be received.  State machines are
424                  * contorted.
425                  */
426                 if (strcmp(pp->a_lastcode, "OK") != 0)
427                     NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
428                             msyslog(LOG_NOTICE, "clock %s USNO no modem status",
429                                     ntoa(&peer->srcadr));
430                 (void)usno_write(peer, PHONE);
431                 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
432                         msyslog(LOG_NOTICE, "clock %s USNO calling %s\n",
433                                 ntoa(&peer->srcadr), PHONE);
434                 up->state = 2;
435                 up->pollcnt++;
436                 pp->polls++;
437                 peer->nextdate = current_time + ANSWER;
438                 return;
439         }
440         switch (peer->ttlmax) {
441
442                 /*
443                  * In manual mode the calling program is activated
444                  * by the ntpdc program using the enable flag (fudge
445                  * flag1), either manually or by a cron job.
446                  */
447             case MODE_MANUAL:
448                 up->run = 0;
449                 break;
450
451                 /*
452                  * In automatic mode the calling program runs
453                  * continuously at intervals determined by the sys_poll
454                  * variable.
455                  */
456             case MODE_AUTO:
457                 if (!up->run)
458                     pp->sloppyclockflag |= CLK_FLAG1;
459                 up->run = 1;
460                 break;
461
462                 /*
463                  * In backup mode the calling program is disabled,
464                  * unless no system peer has been selected for MAXOUTAGE
465                  * (3600 s). Once enabled, it runs until some other NTP
466                  * peer shows up.
467                  */
468             case MODE_BACKUP:
469                 if (!up->run && sys_peer == 0) {
470                         if (current_time - last_time > MAXOUTAGE) {
471                                 up->run = 1;
472                                 peer->hpoll = peer->minpoll;
473                                 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
474                                         msyslog(LOG_NOTICE,
475                                                 "clock %s USNO backup started ",
476                                                 ntoa(&peer->srcadr));
477                         }
478                 } else if (up->run && sys_peer->sstclktype != CTL_SST_TS_TELEPHONE) {
479                         peer->hpoll = peer->minpoll;
480                         up->run = 0;
481                         NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
482                                 msyslog(LOG_NOTICE,
483                                         "clock %s USNO backup stopped",
484                                         ntoa(&peer->srcadr));
485                 }
486                 break;
487
488             default:
489                 msyslog(LOG_ERR,
490                         "clock %s USNO invalid mode", ntoa(&peer->srcadr));
491                 
492         }
493
494         /*
495          * The fudge flag1 is used as an enable/disable; if set either
496          * by the code or via ntpdc, the calling program is
497          * started; if reset, the phones stop ringing.
498          */
499         if (!(pp->sloppyclockflag & CLK_FLAG1)) {
500                 up->pollcnt = 0;
501                 peer->nextdate = current_time + IDLE;
502                 return;
503         }
504
505         /*
506          * Lock the port.
507          */
508         (void)sprintf(lockfile, LOCKFILE, up->unit);
509         fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0644);
510         if (fd < 0) {
511                 msyslog(LOG_ERR, "clock %s USNO port busy",
512                         ntoa(&peer->srcadr));
513                 return;
514         }
515         sprintf(pidbuf, "%d\n", (int) getpid());
516         write(fd, pidbuf, strlen(pidbuf));
517         close(fd);
518
519         /*
520          * Open serial port. Use ACTS line discipline, if available. It
521          * pumps a timestamp into the data stream at every on-time
522          * character '*' found. Note: the port must have modem control
523          * or deep pockets for the phone bill. HP-UX 9.03 users should
524          * have very deep pockets.
525          */
526         (void)sprintf(device, DEVICE, up->unit);
527         if (!(fd = refclock_open(device, SPEED232, LDISC_ACTS))) {
528                 unlink(lockfile);
529                 return;
530         }
531         if (ioctl(fd, TIOCMBIC, (char *)&dtr) < 0)
532             msyslog(LOG_WARNING, "usno_timeout: clock %s: couldn't clear DTR: %m",
533                     ntoa(&peer->srcadr));
534
535         pp->io.clock_recv = usno_receive;
536         pp->io.srcclock = (caddr_t)peer;
537         pp->io.datalen = 0;
538         pp->io.fd = fd;
539         if (!io_addclock(&pp->io)) {
540                 (void) close(fd);
541                 unlink(lockfile);
542                 free(up);
543                 return;
544         }
545
546         /*
547          * Initialize modem and kill DTR. We skedaddle if this comes
548          * bum.
549          */
550         if (!usno_write(peer, MODEM_SETUP)) {
551                 msyslog(LOG_ERR, "clock %s USNO couldn't write",
552                         ntoa(&peer->srcadr));
553                 io_closeclock(&pp->io);
554                 unlink(lockfile);
555                 free(up);
556                 return;
557         }
558
559         /*
560          * Initiate a call to the Observatory. If we wind up here in
561          * other than state 0, a successful call could not be completed
562          * within minpoll seconds.
563          */
564         if (up->pollcnt) {
565                 refclock_report(peer, CEVNT_TIMEOUT);
566                 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
567                         msyslog(LOG_NOTICE,
568                                 "clock %s USNO calling program terminated",
569                                 ntoa(&peer->srcadr));
570                 pp->sloppyclockflag &= ~CLK_FLAG1;
571                 up->pollcnt = 0;
572 #ifdef DEBUG
573                 if (debug)
574                     printf("usno: calling program terminated\n");
575 #endif
576                 usno_disc(peer);
577                 return;
578         }
579
580         /*
581          * Raise DTR, and let the modem settle.  Then we'll dial.
582          */
583         if (ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr) < -1)
584             msyslog(LOG_INFO, "usno_timeout: clock %s: couldn't set DTR: %m",
585                     ntoa(&peer->srcadr));
586         up->state = 1;
587         peer->nextdate = current_time + WAIT;
588 }
589 #endif /* 0 */
590
591
592 /*
593  * usno_disc - disconnect the call and wait for the ruckus to cool
594  */
595 static void
596 usno_disc(
597         struct peer *peer
598         )
599 {
600         register struct usnounit *up;
601         struct refclockproc *pp;
602         int dtr = TIOCM_DTR;
603         char lockfile[128];
604
605         /*
606          * We should never get here other than in state 0, unless a call
607          * has timed out. We drop DTR, which will reliably get the modem
608          * off the air, even while the modem is hammering away full tilt.
609          */
610         pp = peer->procptr;
611         up = (struct usnounit *)pp->unitptr;
612
613         if (ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr) < 0)
614             msyslog(LOG_INFO, "usno_disc: clock %s: couldn't clear DTR: %m",
615                     ntoa(&peer->srcadr));
616
617         if (up->state > 0) {
618                 up->state = 0;
619                 msyslog(LOG_NOTICE, "clock %s USNO call failed %d",
620                         ntoa(&peer->srcadr), up->state);
621 #ifdef DEBUG
622                 if (debug)
623                     printf("usno: call failed %d\n", up->state);
624 #endif
625         }
626
627         io_closeclock(&pp->io);
628         sprintf(lockfile, LOCKFILE, up->unit);
629         unlink(lockfile);
630
631         peer->nextdate = current_time + WAIT;
632 }
633
634
635 #if 0
636 /*
637  * usno_write - write a message to the serial port
638  */
639 static int
640 usno_write(
641         struct peer *peer,
642         const char *str
643         )
644 {
645         register struct usnounit *up;
646         struct refclockproc *pp;
647         int len;
648         int code;
649         char cr = '\r';
650
651         /*
652          * Not much to do here, other than send the message, handle
653          * debug and report faults.
654          */
655         pp = peer->procptr;
656         up = (struct usnounit *)pp->unitptr;
657         len = strlen(str);
658 #ifdef DEBUG
659         if (debug)
660             printf("usno: state %d send %d %s\n", up->state, len,
661                    str);
662 #endif
663         code = write(pp->io.fd, str, (unsigned)len) == len;
664         code |= write(pp->io.fd, &cr, 1) == 1;
665         if (!code)
666             refclock_report(peer, CEVNT_FAULT);
667         return (code);
668 }
669 #endif /* 0 */
670
671 #else
672 int refclock_usno_bs;
673 #endif /* REFCLOCK */