home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xntp3.zip / xntpd / ntp_refclock.c < prev    next >
C/C++ Source or Header  |  1992-07-14  |  10KB  |  479 lines

  1. /*
  2.  * ntp_refclock - processing support for reference clocks
  3.  */
  4. #include <stdio.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8.  
  9. #include "ntp_syslog.h"
  10. #include "ntp_fp.h"
  11. #include "ntp.h"
  12. #include "ntp_refclock.h"
  13.  
  14. #ifdef REFCLOCK
  15. /*
  16.  * Reference clock support is provided here by maintaining the
  17.  * fiction that the clock is actually a peer.  As no packets are
  18.  * exchanged with a reference clock, however, we replace the
  19.  * transmit, receive and packet procedures with separate code
  20.  * to simulate them.  Refclock_transmit and refclock_receive
  21.  * maintain the peer variables in a state analogous to an
  22.  * actual peer and pass reference clock data on through the
  23.  * filters.  Refclock_peer and refclock_unpeer are called to
  24.  * initialize and terminate reference clock associations.
  25.  */
  26.  
  27. /*
  28.  * The refclock configuration table.  Imported from refclock_conf.c
  29.  */
  30. extern struct refclock refclock_conf[];
  31. extern int num_refclock_conf;
  32.  
  33. /*
  34.  * Imported from the I/O module
  35.  */
  36. extern struct interface *any_interface;
  37. extern struct interface *loopback_interface;
  38.  
  39. /*
  40.  * Imported from the timer module
  41.  */
  42. extern u_long current_time;
  43. extern struct event timerqueue[];
  44.  
  45. /*
  46.  * Imported from the main and peer modules.  We use the same
  47.  * algorithm for spacing out timers at configuration time that
  48.  * the peer module does.
  49.  */
  50. extern u_long init_peer_starttime;
  51. extern int initializing;
  52. extern int debug;
  53.  
  54. /*
  55.  * refclock_newpeer - initialize and start a reference clock
  56.  */
  57. int
  58. refclock_newpeer(peer)
  59.     struct peer *peer;
  60. {
  61.     int clktype;
  62.     int unit;
  63.     extern char *ntoa();
  64.     void refclock_transmit();
  65.  
  66.     /*
  67.      * Sanity...
  68.      */
  69.     if (!ISREFCLOCKADR(&peer->srcadr)) {
  70.         syslog(LOG_ERR,
  71.     "Internal error: attempting to initialize %s as reference clock",
  72.             ntoa(&peer->srcadr));
  73.         return 0;
  74.     }
  75.  
  76.     clktype = REFCLOCKTYPE(&peer->srcadr);
  77.     unit = REFCLOCKUNIT(&peer->srcadr);
  78.  
  79.     /*
  80.      * If clktype is invalid, return
  81.      */
  82.     if (clktype >= num_refclock_conf
  83.         || refclock_conf[clktype].clock_start == noentry) {
  84.         syslog(LOG_ERR,
  85.             "Can't initialize %s, no support for clock type %d\n",
  86.             ntoa(&peer->srcadr), clktype);
  87.         return 0;
  88.     }
  89.  
  90.     /*
  91.      * Complete initialization of peer structure.
  92.      */
  93.     peer->refclktype = clktype;
  94.     peer->refclkunit = unit;
  95.     peer->flags |= FLAG_REFCLOCK;
  96.     peer->stratum = STRATUM_REFCLOCK;
  97.     peer->ppoll = NTP_MINPOLL;
  98.     
  99.     /*
  100.      * Check the flags.  If the peer is configured in client mode
  101.      * but prefers the broadcast client filter algorithm, change
  102.      * him over.
  103.      */
  104.     if (peer->hmode == MODE_CLIENT
  105.         && refclock_conf[clktype].clock_flags & REF_FLAG_BCLIENT)
  106.         peer->hmode = MODE_BCLIENT;
  107.  
  108.     peer->event_timer.peer = peer;
  109.     peer->event_timer.event_handler = refclock_transmit;
  110.  
  111.     /*
  112.      * Do driver dependent initialization
  113.      */
  114.     if (!((refclock_conf[clktype].clock_start)(unit, peer))) {
  115.         syslog(LOG_ERR, "Clock dependent initialization of %s failed",
  116.             ntoa(&peer->srcadr));
  117.         return 0;
  118.     }
  119.  
  120.     /*
  121.      * If the driver wants the transmit routine to do unreachability
  122.      * determination, set up the time out.
  123.      */
  124.     if (refclock_conf[clktype].clock_xmitinterval != NOPOLL) {
  125.         if (initializing) {
  126.             init_peer_starttime += (1<<EVENT_TIMEOUT);
  127.             if (init_peer_starttime >= (1<<NTP_MINPOLL))
  128.                 init_peer_starttime = (1<<EVENT_TIMEOUT);
  129.             peer->event_timer.event_time = init_peer_starttime;
  130.         } else {
  131.             peer->event_timer.event_time = current_time
  132.                 + refclock_conf[clktype].clock_xmitinterval;
  133.         }
  134.         TIMER_ENQUEUE(timerqueue, &peer->event_timer);
  135.     }
  136.     return 1;
  137. }
  138.  
  139.  
  140. /*
  141.  * refclock_unpeer - shut down a clock
  142.  */
  143. void
  144. refclock_unpeer(peer)
  145.     struct peer *peer;
  146. {
  147.     extern char *ntoa();
  148.  
  149.     /*
  150.      * Do sanity checks.  I know who programmed the calling routine!
  151.      */
  152.     if (peer->refclktype >= num_refclock_conf
  153.         || refclock_conf[peer->refclktype].clock_shutdown == noentry) {
  154.         syslog(LOG_ERR, "Attempting to shutdown %s: no such clock!",
  155.             ntoa(&peer->srcadr));
  156.         return;
  157.     }
  158.  
  159.     /*
  160.      * Tell the driver we're finished.
  161.      */
  162.     (refclock_conf[peer->refclktype].clock_shutdown)(peer->refclkunit);
  163. }
  164.  
  165.  
  166. /*
  167.  * refclock_transmit - replacement transmit procedure for reference clocks
  168.  */
  169. void
  170. refclock_transmit(peer)
  171.     struct peer *peer;
  172. {
  173.     u_char opeer_reach;
  174.     int clktype;
  175.     int unit;
  176.     extern struct peer *sys_peer;
  177.     extern void get_systime();
  178.     extern void clock_filter();
  179.     extern void clock_select();
  180.     extern void report_event();
  181.  
  182.     clktype = peer->refclktype;
  183.     unit = peer->refclkunit;
  184.     peer->sent++;
  185.  
  186.     /*
  187.      * The transmit procedure is supposed to freeze a time stamp.
  188.      * Get one just for fun, and to tell when we last were here.
  189.      */
  190.     get_systime(&peer->xmt);
  191.  
  192.     /*
  193.      * Fiddle reachability.
  194.      */
  195.     opeer_reach = peer->reach;
  196.     peer->reach <<= 1;
  197.     if (peer->reach == 0) {
  198.         /*
  199.          * Clear this one out.  No need to redo
  200.          * selection since this fellow will definitely
  201.          * be suffering from dispersion madness.
  202.          */
  203.         if (opeer_reach != 0) {
  204.             clear(peer);
  205.             peer->timereachable = current_time;
  206.             report_event(EVNT_UNREACH, peer);
  207.         }
  208.  
  209.     /*
  210.      * Update reachability and poll variables
  211.      */
  212.     } else if ((opeer_reach & 3) == 0) {
  213.  
  214.         l_fp off;
  215.  
  216.         if (peer->valid > 0) peer->valid--;
  217.         if (peer->hpoll > NTP_MINPOLL) peer->hpoll--;
  218.         off.l_ui = off.l_uf = 0;
  219.         clock_filter(peer, &off, 0, NTP_MAXDISPERSE);
  220.         if (peer->flags & FLAG_SYSPEER)
  221.             clock_select(peer);
  222.     } else {
  223.         if (peer->valid < NTP_SHIFT) {
  224.             peer->valid++;
  225.         } else {
  226.             if (peer->hpoll < NTP_MAXPOLL)
  227.                 peer->hpoll++;
  228.         }
  229.     }
  230.  
  231.     /*
  232.      * If he wants to be polled, do it.
  233.      */
  234.     if (refclock_conf[clktype].clock_poll != noentry)
  235.         (refclock_conf[clktype].clock_poll)(unit, peer);
  236.     
  237.     /*
  238.      * Finally, reset the timer
  239.      */
  240.     peer->event_timer.event_time
  241.         += refclock_conf[clktype].clock_xmitinterval;
  242.     TIMER_ENQUEUE(timerqueue, &peer->event_timer);
  243. }
  244.  
  245.  
  246. /*
  247.  * refclock_receive - simulate the receive and packet procedures for clocks
  248.  */
  249. void
  250. refclock_receive(peer, offset, delay, dispersion, reftime, rectime, leap)
  251.     struct peer *peer;
  252.     l_fp *offset;
  253.     s_fp delay;
  254.     u_fp dispersion;
  255.     l_fp *reftime;
  256.     l_fp *rectime;
  257.     char leap;
  258. {
  259.     int restrict;
  260.     int trustable;
  261.     extern void clock_filter();
  262.     extern void clock_update();
  263.     extern void report_event();
  264.     extern int restrictions();
  265.     extern char *ntoa();
  266.     extern u_char leap_indicator;
  267.     extern s_char sys_precision;
  268.  
  269. #ifdef DEBUG
  270.     if (debug)
  271.         printf("refclock_receive: %s %s %s %s)\n",
  272.             ntoa(&peer->srcadr), lfptoa(offset, 6),
  273.             fptoa(delay, 5), ufptoa(dispersion, 5));
  274. #endif
  275.  
  276.     /*
  277.      * The name of this routine is actually a misnomer since
  278.      * we mostly simulate the variable setting of the packet
  279.      * procedure.  We do check the flag values, though, and
  280.      * set the trust bits based on this.
  281.      */
  282.     restrict = restrictions(&peer->srcadr);
  283.     if (restrict & (RES_IGNORE|RES_DONTSERVE)) {
  284.         /*
  285.          * Ours is not to reason why...
  286.          */
  287.         return;
  288.     }
  289.  
  290.     peer->received++;
  291.     peer->processed++;
  292.     peer->timereceived = current_time;
  293.     if (restrict & RES_DONTTRUST)
  294.         trustable = 0;
  295.     else
  296.         trustable = 1;
  297.  
  298.     if (peer->flags & FLAG_AUTHENABLE) {
  299.         if (trustable)
  300.             peer->flags |= FLAG_AUTHENTIC;
  301.         else
  302.             peer->flags &= ~FLAG_AUTHENTIC;
  303.     }
  304.     if (leap == 0)
  305.         peer->leap = leap_indicator;
  306.     else
  307.         peer->leap = leap;
  308.  
  309.     /*
  310.      * Set the timestamps. rec and org are in local time,
  311.      * while ref is in timecode time.
  312.      */
  313.     peer->rec = peer->org = *rectime;
  314.     peer->reftime = *reftime;
  315.  
  316.     /*
  317.      * If the interface has been set to any_interface, set it
  318.      * to the loop back address if we have one.  This is so
  319.      * that peers which are unreachable are easy to see in
  320.      * peer display.
  321.      */
  322.     if (peer->dstadr == any_interface && loopback_interface != 0)
  323.         peer->dstadr = loopback_interface;
  324.  
  325.     /*
  326.      * Set peer.pmode based on the hmode.  For appearances only.
  327.      */
  328.     switch (peer->hmode) {
  329.     case MODE_ACTIVE:
  330.         peer->pmode = MODE_PASSIVE;
  331.         break;
  332.     case MODE_CLIENT:
  333.         peer->pmode = MODE_SERVER;
  334.         break;
  335.     case MODE_BCLIENT:
  336.         peer->pmode = MODE_BROADCAST;
  337.         break;
  338.     default:
  339.         syslog(LOG_ERR, "refclock_receive: internal error, mode = %d",
  340.             peer->hmode);
  341.     }
  342.  
  343.     /*
  344.      * Abandon ship if the radio came bum. We only got this far
  345.      * in order to make pretty billboards, even if bum.
  346.      */
  347.     if (leap == LEAP_NOTINSYNC) return;
  348.     /*
  349.      * If this guy was previously unreachable, report him
  350.      * reachable.
  351.      */
  352.     if (peer->reach == 0) report_event(EVNT_REACH, peer);
  353.     peer->reach |= 1;
  354.  
  355.     /*
  356.      * Give the data to the clock filter and update the clock.
  357.      */
  358.     clock_filter(peer, offset, delay, dispersion);
  359.     clock_update(peer);
  360. }
  361.  
  362.  
  363. /*
  364.  * refclock_control - set and/or return clock values
  365.  */
  366. void
  367. refclock_control(srcadr, in, out)
  368.     struct sockaddr_in *srcadr;
  369.     struct refclockstat *in;
  370.     struct refclockstat *out;
  371. {
  372.     int clktype;
  373.     int unit;
  374.     extern char *ntoa();
  375.  
  376.     /*
  377.      * Sanity...
  378.      */
  379.     if (!ISREFCLOCKADR(srcadr)) {
  380.         syslog(LOG_ERR,
  381.     "Internal error: refclock_control received %s as reference clock",
  382.             ntoa(srcadr));
  383.         return;
  384.     }
  385.  
  386.     clktype = REFCLOCKTYPE(srcadr);
  387.     unit = REFCLOCKUNIT(srcadr);
  388.  
  389.     /*
  390.      * If clktype is invalid, return
  391.      */
  392.     if (clktype >= num_refclock_conf
  393.         || refclock_conf[clktype].clock_control == noentry) {
  394.         syslog(LOG_ERR,
  395.            "Internal error: refclock_control finds %s as not supported",
  396.             ntoa(srcadr));
  397.         return;
  398.     }
  399.  
  400.     /*
  401.      * Give the stuff to the clock.
  402.      */
  403.     (refclock_conf[clktype].clock_control)(unit, in, out);
  404. }
  405.  
  406.  
  407.  
  408. /*
  409.  * refclock_buginfo - return debugging info
  410.  */
  411. void
  412. refclock_buginfo(srcadr, bug)
  413.     struct sockaddr_in *srcadr;
  414.     struct refclockbug *bug;
  415. {
  416.     int clktype;
  417.     int unit;
  418.     extern char *ntoa();
  419.  
  420.     /*
  421.      * Sanity...
  422.      */
  423.     if (!ISREFCLOCKADR(srcadr)) {
  424.         syslog(LOG_ERR,
  425.     "Internal error: refclock_buginfo received %s as reference clock",
  426.             ntoa(srcadr));
  427.         return;
  428.     }
  429.  
  430.     clktype = REFCLOCKTYPE(srcadr);
  431.     unit = REFCLOCKUNIT(srcadr);
  432.  
  433.     /*
  434.      * If clktype is invalid or call is unsupported, return
  435.      */
  436.     if (clktype >= num_refclock_conf ||
  437.         refclock_conf[clktype].clock_buginfo == noentry) {
  438.         return;
  439.     }
  440.  
  441.     /*
  442.      * Give the stuff to the clock.
  443.      */
  444.     (refclock_conf[clktype].clock_buginfo)(unit, bug);
  445. }
  446.  
  447.  
  448.  
  449. /*
  450.  * refclock_leap - inform the reference clocks that need it that
  451.  *           we've had a leap second
  452.  */
  453. void
  454. refclock_leap()
  455. {
  456.     register int i;
  457.  
  458.     for (i = 0; i < num_refclock_conf; i++) {
  459.         if (refclock_conf[i].clock_leap != noentry)
  460.             (refclock_conf[i].clock_leap)();
  461.     }
  462. }
  463.  
  464.  
  465. /*
  466.  * init_refclock - initialize the reference clock drivers
  467.  */
  468. void
  469. init_refclock()
  470. {
  471.     register int i;
  472.  
  473.     for (i = 0; i < num_refclock_conf; i++) {
  474.         if (refclock_conf[i].clock_init != noentry)
  475.             (refclock_conf[i].clock_init)();
  476.     }
  477. }
  478. #endif
  479.