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_control.c < prev    next >
C/C++ Source or Header  |  1992-08-04  |  49KB  |  2,300 lines

  1. /*
  2.  * ntp_control.c - respond to control messages and send async traps
  3.  */
  4. #include <stdio.h>
  5. #include <strings.h>
  6. #include <signal.h>
  7. #include <errno.h>
  8. #include <ctype.h>
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <sys/ioctl.h>
  12. #include <sys/file.h>
  13. #include <sys/time.h>
  14. #ifdef convex
  15. #include "/sys/sync/queue.h"
  16. #include "/sys/sync/sema.h"
  17. #endif
  18. #include <net/if.h>
  19. #include <netinet/in.h>
  20.  
  21. #include "ntp_syslog.h"
  22. #include "ntp_fp.h"
  23. #include "ntp.h"
  24. #include "ntp_refclock.h"
  25. #include "ntp_control.h"
  26.  
  27. /*
  28.  * Structure to hold request procedure information
  29.  */
  30. #define    NOAUTH    0
  31. #define    AUTH    1
  32.  
  33. #define    NO_REQUEST    (-1)
  34.  
  35. struct ctl_proc {
  36.     short control_code;    /* defined request code */
  37.     u_short flags;        /* flags word */
  38.     void (*handler)();    /* routine to handle request */
  39. };
  40.  
  41. /*
  42.  * Only one flag.  Authentication required or not.
  43.  */
  44. #define    NOAUTH    0
  45. #define    AUTH    1
  46.  
  47. /*
  48.  * Request processing routines
  49.  */
  50. void control_unspec(), read_status(), read_variables();
  51. void write_variables(), read_clock_status(), write_clock_status();
  52. void set_trap(), unset_trap();
  53.  
  54. struct ctl_proc control_codes[] = {
  55.     { CTL_OP_UNSPEC,    NOAUTH,    control_unspec },
  56.     { CTL_OP_READSTAT,    NOAUTH,    read_status },
  57.     { CTL_OP_READVAR,    NOAUTH,    read_variables },
  58.     { CTL_OP_WRITEVAR,    AUTH,    write_variables },
  59.     { CTL_OP_READCLOCK,    NOAUTH,    read_clock_status },
  60.     { CTL_OP_WRITECLOCK,    NOAUTH,    write_clock_status },
  61.     { CTL_OP_SETTRAP,    NOAUTH,    set_trap },
  62.     { CTL_OP_UNSETTRAP,    NOAUTH,    unset_trap },
  63.     { NO_REQUEST,        0 }
  64. };
  65.  
  66.  
  67. /*
  68.  * Structure for translation tables between internal system
  69.  * variable indices and text format.
  70.  */
  71. struct ctl_var {
  72.     u_short code;
  73.     u_short flags;
  74.     char *text;
  75. };
  76.  
  77. /*
  78.  * Flag values
  79.  */
  80. #define    CAN_READ    0x1
  81. #define    CAN_WRITE    0x2
  82. #define    PADDING        0x80
  83. #define    EOV        0x40
  84.  
  85. #define    RO    (CAN_READ)
  86. #define    WO    (CAN_WRITE)
  87. #define    RW    (CAN_READ|CAN_WRITE)
  88.  
  89.  
  90. /*
  91.  * System variable values.  The array can be indexed by
  92.  * the variable index to find the textual name.
  93.  */
  94. struct ctl_var sys_var[] = {
  95.     { 0,        PADDING, "" },        /* 0 */
  96.     { CS_LEAP,    RW,    "leap" },    /* 1 */
  97.     { CS_STRATUM,    RO,    "stratum" },    /* 2 */
  98.     { CS_PRECISION,    RO,    "precision" },    /* 3 */
  99.     { CS_ROOTDELAY,    RO,    "rootdelay" },    /* 4 */
  100.     { CS_ROOTDISPERSION, RO, "rootdispersion" }, /* 5 */
  101.     { CS_REFID,    RO,    "refid" },    /* 6 */
  102.     { CS_REFTIME,    RO,    "reftime" },    /* 7 */
  103.     { CS_POLL,    RO,    "poll" },    /* 8 */
  104.     { CS_PEERID,    RO,    "peer" },    /* 9 */
  105.     { CS_OFFSET,    RO,    "phase" },    /* 10 */
  106.     { CS_DRIFT,    RO,    "freq" },    /* 11 */
  107.     { CS_COMPLIANCE, RO,    "compliance" },    /* 12 */
  108.     { CS_CLOCK,    RO,    "clock" },    /* 13 */
  109.     { CS_LEAPIND,    RW,    "leapindicator" }, /* 14 */
  110.     { CS_LEAPWARNING, RW,    "leapwarning" }, /* 15 */
  111.     { CS_PROCESSOR,    RO,    "processor" },    /* 16 */
  112.     { CS_SYSTEM,    RO,    "system" },    /* 17 */
  113.     { CS_KEYID,    RO,    "keyid" },    /* 18 */
  114.     { CS_REFSKEW,    RO,    "refskew" },    /* 19 */
  115.     { 0,        EOV,    ""    }
  116. };
  117.  
  118. /*
  119.  * System variables we print by default (in fuzzball order, more-or-less)
  120.  */
  121. u_char def_sys_var[] = {
  122.     CS_SYSTEM,
  123.     CS_LEAP,
  124.     CS_STRATUM,
  125.     CS_ROOTDELAY,
  126.     CS_ROOTDISPERSION,
  127.     CS_PEERID,
  128.     CS_REFID,
  129.     CS_REFTIME,
  130.     CS_POLL,
  131.     CS_CLOCK,
  132.     CS_OFFSET,
  133.     CS_DRIFT,
  134.     CS_COMPLIANCE,
  135.     0
  136. };
  137.  
  138.  
  139. /*
  140.  * Peer variable list
  141.  */
  142. struct ctl_var peer_var[] = {
  143.     { 0,        PADDING, "" },        /* 0 */
  144.     { CP_CONFIG,    RO,    "config" },    /* 1 */
  145.     { CP_AUTHENABLE, RO,    "authenable" },    /* 2 */
  146.     { CP_AUTHENTIC,    RO,    "authentic" },    /* 3 */
  147.     { CP_SRCADR,    RO,    "srcadr" },    /* 4 */
  148.     { CP_SRCPORT,    RO,    "srcport" },    /* 5 */
  149.     { CP_DSTADR,    RO,    "dstadr" },    /* 6 */
  150.     { CP_DSTPORT,    RO,    "dstport" },    /* 7 */
  151.     { CP_LEAP,    RO,    "leap" },    /* 8 */
  152.     { CP_HMODE,    RO,    "hmode" },    /* 9 */
  153.     { CP_STRATUM,    RO,    "stratum" },    /* 10 */
  154.     { CP_PPOLL,    RO,    "ppoll" },    /* 11 */
  155.     { CP_HPOLL,    RO,    "hpoll" },    /* 12 */
  156.     { CP_PRECISION,    RO,    "precision" },    /* 13 */
  157.     { CP_ROOTDELAY,    RO,    "rootdelay" },    /* 14 */
  158.     { CP_ROOTDISPERSION, RO, "rootdispersion" }, /* 15 */
  159.     { CP_REFID,    RO,    "refid" },    /* 16 */
  160.     { CP_REFTIME,    RO,    "reftime" },    /* 17 */
  161.     { CP_ORG,    RO,    "org" },    /* 18 */
  162.     { CP_REC,    RO,    "rec" },    /* 19 */
  163.     { CP_XMT,    RO,    "xmt" },    /* 20 */
  164.     { CP_REACH,    RO,    "reach" },    /* 21 */
  165.     { CP_VALID,    RO,    "valid" },    /* 22 */
  166.     { CP_TIMER,    RO,    "timer" },    /* 23 */
  167.     { CP_DELAY,    RO,    "delay" },    /* 24 */
  168.     { CP_OFFSET,    RO,    "offset" },    /* 25 */
  169.     { CP_DISPERSION,RO,    "dispersion" },    /* 26 */
  170.     { CP_KEYID,    RO,    "keyid" },    /* 27 */
  171.     { CP_FILTDELAY,    RO,    "filtdelay" },    /* 28 */
  172.     { CP_FILTOFFSET, RO,    "filtoffset" },    /* 29 */
  173.     { CP_PMODE,    RO,    "pmode" },    /* 30 */
  174.     { CP_RECEIVED,    RO,    "received" },    /* 31 */
  175.     { CP_SENT,    RO,    "sent" },    /* 32 */
  176.     { CP_FILTERROR,    RO,    "filterror" },    /* 33 */
  177.     { CP_FLASH,    RO,    "flash" },    /* 34 */
  178.     { 0,        EOV,    ""    }
  179. };
  180.  
  181.  
  182. /*
  183.  * Peer variables we print by default
  184.  */
  185. u_char def_peer_var[] = {
  186.     CP_SRCADR,
  187.     CP_SRCPORT,
  188.     CP_DSTADR,
  189.     CP_DSTPORT,
  190.     CP_KEYID,
  191.     CP_STRATUM,
  192.     CP_PRECISION,
  193.     CP_ROOTDELAY,
  194.     CP_ROOTDISPERSION,
  195.     CP_REFID,
  196.     CP_REFTIME,
  197.     CP_DELAY,
  198.     CP_OFFSET,
  199.     CP_DISPERSION,
  200.     CP_REACH,
  201.     CP_VALID,
  202.     CP_HMODE,
  203.     CP_PMODE,
  204.     CP_HPOLL,
  205.     CP_PPOLL,
  206.     CP_LEAP,
  207.     CP_FLASH,
  208.     CP_ORG,
  209.     CP_REC,
  210.     CP_XMT,
  211.     CP_FILTDELAY,
  212.     CP_FILTOFFSET,
  213.     CP_FILTERROR,
  214.     0
  215. };
  216.  
  217.  
  218. #ifdef REFCLOCK
  219. /*
  220.  * Clock variable list
  221.  */
  222. struct ctl_var clock_var[] = {
  223.     { 0,        PADDING, "" },        /* 0 */
  224.     { CC_TYPE,    RO,    "type" },    /* 1 */
  225.     { CC_TIMECODE,    RO,    "timecode" },    /* 2 */
  226.     { CC_POLL,    RO,    "poll" },    /* 3 */
  227.     { CC_NOREPLY,    RO,    "noreply" },    /* 4 */
  228.     { CC_BADFORMAT,    RO,    "badformat" },    /* 5 */
  229.     { CC_BADDATA,    RO,    "baddata" },    /* 6 */
  230.     { CC_FUDGETIME1, RO,    "fudgetime1" },    /* 7 */
  231.     { CC_FUDGETIME2, RO,    "fudgetime2" },    /* 8 */
  232.     { CC_FUDGEVAL1,    RO,    "fudgeval1" },    /* 9 */
  233.     { CC_FUDGEVAL2,    RO,    "fudgeval2" },    /* 10 */
  234.     { CC_FLAGS,    RO,    "flags" },    /* 11 */
  235.     { CC_DEVICE,    RO,    "device" },    /* 12 */
  236.     { 0,        EOV,    ""    }
  237. };
  238.  
  239.  
  240. /*
  241.  * Clock variables printed by default
  242.  */
  243. u_char def_clock_var[] = {
  244.     CC_DEVICE,
  245.     CC_TYPE,    /* won't be output if device= known */
  246.     CC_TIMECODE,
  247.     CC_POLL,
  248.     CC_NOREPLY,
  249.     CC_BADFORMAT,
  250.     CC_BADDATA,
  251.     CC_FUDGETIME1,
  252.     CC_FUDGETIME2,
  253.     CC_FUDGEVAL1,
  254.     CC_FUDGEVAL2,
  255.     CC_FLAGS,
  256.     0
  257. };
  258. #endif
  259.  
  260.  
  261. /*
  262.  * System and processor definitions.  These will change for the gizmo board.
  263.  */
  264. #define    STR_SYSTEM    "UNIX"
  265. #define    STR_PROCESSOR    "unknown"
  266.  
  267.  
  268. /*
  269.  * Trap structures.  We only allow a few of these, and send
  270.  * a copy of each async message to each live one.  Traps time
  271.  * out after an hour, it is up to the trap receipient to
  272.  * keep resetting it to avoid being timed out.
  273.  */
  274. struct ctl_trap ctl_trap[CTL_MAXTRAPS];
  275. int num_ctl_traps;
  276.  
  277. /*
  278.  * Type bits, for ctlsettrap() call.
  279.  */
  280. #define    TRAP_TYPE_CONFIG    0    /* used by configuration code */
  281. #define    TRAP_TYPE_PRIO        1    /* priority trap */
  282. #define    TRAP_TYPE_NONPRIO    2    /* nonpriority trap */
  283.  
  284.  
  285. /*
  286.  * List relating reference clock types to control message time sources.
  287.  * Index by the reference clock type.
  288.  */
  289. static u_char clocktypes[] = {
  290.     CTL_SST_TS_NTP,        /* REFCLK_NONE */
  291.     CTL_SST_TS_UNSPEC,    /* REFCLK_LOCALCLOCK */
  292.     CTL_SST_TS_HF,        /* REFCLK_WWV_HEATH */
  293.     CTL_SST_TS_HF,        /* REFCLK_WWV_PST */
  294.     CTL_SST_TS_LF,        /* REFCLK_WWVB_SPECTRACOM */
  295.     CTL_SST_TS_UHF,        /* REFCLK_GOES_TRUETIME */
  296.     CTL_SST_TS_UHF,        /* REFCLK_GOES_TRAK */
  297.     CTL_SST_TS_HF,        /* REFCLK_CHU */
  298.     CTL_SST_TS_LF,        /* REFCLOCK_DCF77 */
  299.     CTL_SST_TS_LF,        /* REFCLK_WWVB_SPECTRACOM_HP */
  300.     CTL_SST_TS_UNSPEC,    /* Future expansion */
  301.     CTL_SST_TS_UNSPEC,    /* Future expansion */
  302.     CTL_SST_TS_UNSPEC,    /* Future expansion */
  303.     CTL_SST_TS_UNSPEC,    /* Future expansion */
  304.     CTL_SST_TS_UNSPEC,    /* Future expansion */
  305.     CTL_SST_TS_UNSPEC    /* Future expansion */
  306. };
  307.  
  308.  
  309.  
  310. /*
  311.  * Keyid used for authenticating write requests.
  312.  */
  313. u_long ctl_auth_keyid;
  314.  
  315. /*
  316.  * We keep track of the last error reported by the system internally
  317.  */
  318. u_char ctl_sys_last_event;
  319. u_char ctl_sys_num_events;
  320.  
  321.  
  322. /*
  323.  * Statistic counters to keep track of requests and responses.
  324.  */
  325. u_long ctltimereset;        /* time stats reset */
  326. u_long numctlreq;        /* number of requests we've received */
  327. u_long numctlbadpkts;        /* number of bad control packets */
  328. u_long numctlresponses;        /* number of resp packets sent with data */
  329. u_long numctlfrags;        /* number of fragments sent */
  330. u_long numctlerrors;        /* number of error responses sent */
  331. u_long numctltooshort;        /* number of too short input packets */
  332. u_long numctlinputresp;        /* number of responses on input */
  333. u_long numctlinputfrag;        /* number of fragments on input */
  334. u_long numctlinputerr;        /* number of input pkts with err bit set */
  335. u_long numctlbadoffset;        /* number of input pkts with nonzero offset */
  336. u_long numctlbadversion;    /* number of input pkts with unknown version */
  337. u_long numctldatatooshort;    /* data too short for count */
  338. u_long numctlbadop;        /* bad op code found in packet */
  339. u_long numasyncmsgs;        /* number of async messages we've sent */
  340.  
  341.  
  342. /*
  343.  * Imported from the I/O module
  344.  */
  345. extern struct interface *any_interface;
  346.  
  347. /*
  348.  * Imported from the main routines
  349.  */
  350. extern int debug;
  351.  
  352. /*
  353.  * Imported from the timer module
  354.  */
  355. extern u_long current_time;
  356.  
  357.  
  358. /*
  359.  * Response packet used by these routines.  Also some state information
  360.  * so that we can handle packet formatting within a common set of
  361.  * subroutines.  Note we try to enter data in place whenever possible,
  362.  * but the need to set the more bit correctly means we occasionally
  363.  * use the extra buffer and copy.
  364.  */
  365. static struct ntp_control rpkt;
  366. static u_char res_version;
  367. static u_char res_opcode;
  368. static u_short res_associd;
  369. static int res_offset;
  370. static u_char *datapt;
  371. static u_char *dataend;
  372. static int datalinelen;
  373. static int datanotbinflag;
  374. static struct sockaddr_in *rmt_addr;
  375. static struct interface *lcl_inter;
  376.  
  377. static u_char res_authenticate;
  378. static u_char res_authokay;
  379. static u_long res_keyid;
  380.  
  381. #define    MAXDATALINELEN    (72)
  382.  
  383. static u_char res_async;    /* set to 1 if this is async trap response */
  384.  
  385. /*
  386.  * Pointers for saving state when decoding request packets
  387.  */
  388. char *reqpt;
  389. char *reqend;
  390.  
  391. /*
  392.  * init_control - initialize request data
  393.  */
  394. void
  395. init_control()
  396. {
  397.     int i;
  398.     void ctl_clr_stats();
  399.  
  400.     ctl_clr_stats();
  401.  
  402.     ctl_auth_keyid = 0;
  403.     ctl_sys_last_event = EVNT_UNSPEC;
  404.     ctl_sys_num_events = 0;
  405.  
  406.     num_ctl_traps = 0;
  407.     for (i = 0; i < CTL_MAXTRAPS; i++)
  408.         ctl_trap[i].tr_flags = 0;
  409. }
  410.  
  411.  
  412. /*
  413.  * ctl_error - send an error response for the current request
  414.  */
  415. void
  416. ctl_error(errcode)
  417.     int errcode;
  418. {
  419. #ifdef DEBUG
  420.     if (debug >= 4)
  421.         printf("sending control error %d\n", errcode);
  422. #endif
  423.     /*
  424.      * fill in the fields.  We assume rpkt.sequence and rpkt.associd
  425.      * have already been filled in.
  426.      */
  427.     rpkt.r_m_e_op = CTL_RESPONSE|CTL_ERROR|(res_opcode & CTL_OP_MASK);
  428.     rpkt.status = htons((errcode<<8) & 0xff00);
  429.     rpkt.count = 0;
  430.  
  431.     /*
  432.      * send packet and bump counters
  433.      */
  434.     if (res_authenticate) {
  435.         int maclen;
  436.  
  437.         *(u_long *)((u_char *)&rpkt + CTL_HEADER_LEN)
  438.             = htonl(res_keyid);
  439.         maclen = 
  440.             authencrypt(res_keyid, (u_long *)&rpkt, CTL_HEADER_LEN);
  441.         sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
  442.             CTL_HEADER_LEN + maclen);
  443.     } else {
  444.         sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
  445.             CTL_HEADER_LEN);
  446.     }
  447.     numctlerrors++;
  448. }
  449.  
  450.  
  451. /*
  452.  * process_control - process an incoming control message
  453.  */
  454. void
  455. process_control(rbufp, restrict)
  456.     struct recvbuf *rbufp;
  457.     int restrict;
  458. {
  459.     register struct ntp_control *pkt;
  460.     register int req_count;
  461.     register int req_data;
  462.     register struct ctl_proc *cc;
  463.     int properlen;
  464.     int maclen;
  465.     extern u_char sys_leap;
  466.  
  467. #ifdef DEBUG
  468.     if (debug)
  469.         printf("in process_control()\n");
  470. #endif
  471.  
  472.     /*
  473.      * Save the addresses for error responses
  474.      */
  475.     numctlreq++;
  476.     rmt_addr = &rbufp->recv_srcadr;
  477.     lcl_inter = rbufp->dstadr;
  478.     pkt = (struct ntp_control *)&rbufp->recv_pkt;
  479.  
  480.     /*
  481.      * If the length is less than required for the header, or
  482.      * it is a response or a fragment, ignore this.
  483.      */
  484.     if (rbufp->recv_length < CTL_HEADER_LEN
  485.         || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR)
  486.         || pkt->offset != 0) {
  487. #ifdef DEBUG
  488.         if (debug)
  489.             printf("invalid format in control packet\n");
  490. #endif
  491.         if (rbufp->recv_length < CTL_HEADER_LEN)
  492.             numctltooshort++;
  493.         if (pkt->r_m_e_op & CTL_RESPONSE)
  494.             numctlinputresp++;
  495.         if (pkt->r_m_e_op & CTL_MORE)
  496.             numctlinputfrag++;
  497.         if (pkt->r_m_e_op & CTL_ERROR)
  498.             numctlinputerr++;
  499.         if (pkt->offset != 0)
  500.             numctlbadoffset++;
  501.         return;
  502.     }
  503.     res_version = PKT_VERSION(pkt->li_vn_mode);
  504.     if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) {
  505. #ifdef DEBUG
  506.         if (debug)
  507.             printf("unknown version %d in control packet\n",
  508.                 res_version);
  509. #endif
  510.         numctlbadversion++;
  511.         return;
  512.     }
  513.  
  514.     /*
  515.      * Pull enough data from the packet to make intelligent responses
  516.      */
  517.     rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version, MODE_CONTROL);
  518.     res_opcode = pkt->r_m_e_op;
  519.     rpkt.sequence = pkt->sequence;
  520.     rpkt.associd = pkt->associd;
  521.     rpkt.status = 0;
  522.     res_offset = 0;
  523.     res_associd = htons(pkt->associd);
  524.     res_async = 0;
  525.     res_authenticate = 0;
  526.     res_keyid = 0;
  527.     res_authokay = 0;
  528.     req_count = (int)htons(pkt->count);
  529.     datanotbinflag = 0;
  530.     datalinelen = 0;
  531.     datapt = rpkt.data;
  532.     dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
  533.  
  534.     /*
  535.      * We're set up now.  Make sure we've got at least
  536.      * enough incoming data space to match the count.
  537.      */
  538.     req_data = rbufp->recv_length - CTL_HEADER_LEN;
  539.     if (req_data < req_count || rbufp->recv_length & 0x3) {
  540.         ctl_error(CERR_BADFMT);
  541.         numctldatatooshort++;
  542.         return;
  543.     }
  544.  
  545.     properlen = req_count + CTL_HEADER_LEN;
  546. #ifdef DEBUG
  547.     if (debug >= 2 && (rbufp->recv_length & 0x3) != 0)
  548.         printf("Packet length %d unrounded\n", rbufp->recv_length);
  549. #endif
  550.     /* round up proper len to a 8 octet boundary */
  551.  
  552.     properlen = (properlen + 7) & ~7;
  553.  
  554.     if ((rbufp->recv_length & (sizeof(u_long)-1)) == 0
  555.         && (maclen = (rbufp->recv_length - properlen)) >= MIN_MAC_LEN
  556.         && maclen <= MAX_MAC_LEN) {
  557.  
  558.         res_authenticate = 1;
  559.         res_keyid = ntohl(*(u_long *)((u_char *)pkt + properlen));
  560.  
  561. #ifdef DEBUG
  562.         if (debug >= 3)
  563.             printf(
  564.       "recv_len %d, properlen %d, wants auth with keyid %d, MAC length=%d\n",
  565.                 rbufp->recv_length, properlen, res_keyid, maclen);
  566. #endif
  567.         if (!authhavekey(res_keyid)) {
  568. #ifdef DEBUG
  569.             if (debug >= 2)
  570.                 printf("keyid %lu unknown\n", res_keyid);
  571. #endif
  572.         } else if (authdecrypt(res_keyid, (u_long *)pkt,
  573.                        rbufp->recv_length - maclen, maclen)) {
  574. #ifdef DEBUG
  575.             if (debug >= 3)
  576.                 printf("authenticated okay\n");
  577. #endif
  578.             res_authokay = 1;
  579.         } else {
  580. #ifdef DEBUG
  581.             if (debug >= 3)
  582.                 printf("authentication failed\n");
  583. #endif
  584.             res_keyid = 0;
  585.         }
  586.     }
  587.  
  588.     /*
  589.      * Set up translate pointers
  590.      */
  591.     reqpt = (char *)pkt->data;
  592.     reqend = reqpt + req_count;
  593.  
  594.     /*
  595.      * Look for the opcode processor
  596.      */
  597.     for (cc = control_codes; cc->control_code != NO_REQUEST; cc++) {
  598.         if (cc->control_code == res_opcode) {
  599. #ifdef DEBUG    
  600.             if (debug >= 2)
  601.                 printf("opcode %d, found command handler\n",
  602.                     res_opcode);
  603. #endif
  604.             if (cc->flags == AUTH && (!res_authokay
  605.                 || res_keyid != ctl_auth_keyid)) {
  606.                 ctl_error(CERR_PERMISSION);
  607.                 return;
  608.             }
  609.             (cc->handler)(rbufp, restrict);
  610.             return;
  611.         }
  612.     }
  613.  
  614.     /*
  615.      * Can't find this one, return an error.
  616.      */
  617.     numctlbadop++;
  618.     ctl_error(CERR_BADOP);
  619.     return;
  620. }
  621.  
  622.  
  623. /*
  624.  * ctlpeerstatus - return a status word for this peer
  625.  */
  626. u_short
  627. ctlpeerstatus(peer)
  628.     register struct peer *peer;
  629. {
  630.     register u_short status;
  631.     extern struct peer *sys_peer;
  632.     extern int pps_control;    /* flag for 1-pps signal present */
  633.  
  634.     status = CTL_PST_SEL_REJECT;
  635.     if (peer->was_sane != 0)
  636.         status = CTL_PST_SEL_SANE;
  637.     if (peer->correct != 0)
  638.         status = CTL_PST_SEL_CORRECT;
  639.     if (peer->candidate != 0)
  640.         status = CTL_PST_SEL_SELCAND;
  641.     if (peer->select != 0)
  642.         status = CTL_PST_SEL_SYNCCAND;
  643.     if (peer == sys_peer) {
  644.         status = CTL_PST_SEL_DISTSYSPEER;
  645.         if (peer->synch < NTP_MAXDISTANCE) {
  646.             status = CTL_PST_SEL_SYSPEER;
  647.             if (pps_control)
  648.                 status = CTL_PST_SEL_PPS;
  649.         }
  650.     }
  651.     if (peer->flags & FLAG_CONFIG)
  652.         status |= CTL_PST_CONFIG;
  653.     if (peer->flags & FLAG_AUTHENABLE) {
  654.         status |= CTL_PST_AUTHENABLE;
  655.         if (peer->flags & FLAG_AUTHENTIC)
  656.             status |= CTL_PST_AUTHENTIC;
  657.     }
  658.     if (peer->reach != 0)
  659.         status |= CTL_PST_REACH;
  660.  
  661.     return (u_short)CTL_PEER_STATUS(status, peer->num_events,
  662.         peer->last_event);
  663. }
  664.  
  665.  
  666. /*
  667.  * ctlclkstatus - return a status word for this clock
  668.  */
  669. u_short
  670. ctlclkstatus(clock)
  671.     struct refclockstat *clock;
  672. {
  673.     return ((u_short)(clock->currentstatus) << 8)
  674.         | (u_short)(clock->lastevent);
  675. }
  676.  
  677.  
  678.  
  679. /*
  680.  * ctlsysstatus - return the system status word
  681.  */
  682. u_short
  683. ctlsysstatus()
  684. {
  685.     register u_char clock;
  686.     extern struct peer *sys_peer;
  687.     extern u_char sys_leap;
  688.  
  689.     if (sys_peer == 0 || sys_peer->refclktype >= sizeof(clocktypes))
  690.         clock = CTL_SST_TS_UNSPEC;
  691.     else
  692.         clock = clocktypes[sys_peer->refclktype];
  693.  
  694.     return (u_short)CTL_SYS_STATUS(sys_leap, clock, 
  695.         ctl_sys_num_events, ctl_sys_last_event);
  696. }
  697.  
  698.  
  699.  
  700. /*
  701.  * ctl_flushpkt - write out the current packet and prepare
  702.  *          another if necessary.
  703.  */
  704. void
  705. ctl_flushpkt(more)
  706.     int more;
  707. {
  708.     int dlen;
  709.     int sendlen;
  710.  
  711.     if (!more && datanotbinflag) {
  712.         /*
  713.          * Big hack, output a trailing \r\n
  714.          */
  715.         *datapt++ = '\r';
  716.         *datapt++ = '\n';
  717.     }
  718.     dlen = datapt - (u_char *)rpkt.data;
  719.     sendlen = dlen + CTL_HEADER_LEN;
  720.  
  721.     /*
  722.      * Pad to a multiple of 32 bits
  723.      */
  724.     while (sendlen & 0x3) {
  725.         *datapt++ = '\0';
  726.         sendlen++;
  727.     }
  728.  
  729.     /*
  730.      * Fill in the packet with the current info
  731.      */
  732.     rpkt.r_m_e_op = CTL_RESPONSE|more|(res_opcode & CTL_OP_MASK);
  733.     rpkt.count = htons((u_short)dlen);
  734.     rpkt.offset = htons(res_offset);
  735.     if (res_async) {
  736.         register int i;
  737.         extern u_char sys_leap;
  738.  
  739.         for (i = 0; i < CTL_MAXTRAPS; i++) {
  740.             if (ctl_trap[i].tr_flags & TRAP_INUSE) {
  741.                 rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap,
  742.                     ctl_trap[i].tr_version, MODE_CONTROL);
  743.                 rpkt.sequence = htons(ctl_trap[i].tr_sequence);
  744.                 sendpkt(&ctl_trap[i].tr_addr,
  745.                     ctl_trap[i].tr_localaddr,
  746.                     (struct pkt *)&rpkt, sendlen);
  747.                 if (!more)
  748.                     ctl_trap[i].tr_sequence++;
  749.                 numasyncmsgs++;
  750.             }
  751.         }
  752.     } else {
  753.         if (res_authenticate) {
  754.             int maclen;
  755.             int totlen = sendlen;
  756.  
  757.             /*
  758.              *  If we are going to authenticate, then there is
  759.              *  an additional requirement that the MAC begin on
  760.              *  a 64 bit boundary.
  761.              */
  762.             while (totlen & 7) {
  763.                 *datapt++ = '\0';
  764.                 totlen++;
  765.             }
  766.             *(u_long *)datapt = htonl(res_keyid);
  767.             maclen = 
  768.                 authencrypt(res_keyid, (u_long *)&rpkt, totlen);
  769.  
  770.              sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
  771.                 sendlen + maclen);
  772.         } else {
  773.              sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
  774.                 sendlen);
  775.         }
  776.         if (more)
  777.             numctlfrags++;
  778.         else
  779.             numctlresponses++;
  780.     }
  781.  
  782.     /*
  783.      * Set us up for another go around.
  784.      */
  785.     res_offset += dlen;
  786.     datapt = (u_char *)rpkt.data;
  787. }
  788.  
  789.  
  790. /*
  791.  * ctl_putdata - write data into the packet, fragmenting and
  792.  *         starting another if this one is full.
  793.  */
  794. void
  795. ctl_putdata(dp, dlen, bin)
  796.     char *dp;
  797.     int dlen;
  798.     int bin;    /* set to 1 when data is binary */
  799. {
  800.     int overhead;
  801.  
  802.     overhead = 0;
  803.     if (!bin) {
  804.         datanotbinflag = 1;
  805.         overhead = 3;
  806.         if (datapt != rpkt.data) {
  807.             *datapt++ = ',';
  808.             datalinelen++;
  809.             if ((dlen + datalinelen + 1) >= MAXDATALINELEN) {
  810.                 *datapt++ = '\r';
  811.                 *datapt++ = '\n';
  812.                 datalinelen = 0;
  813.             } else {
  814.                 *datapt++ = ' ';
  815.                 datalinelen++;
  816.             }
  817.         }
  818.     }
  819.  
  820.     /*
  821.      * Save room for trailing junk
  822.      */
  823.     if (dlen + overhead + datapt > dataend) {
  824.         /*
  825.          * Not enough room in this one, flush it out.
  826.          */
  827.         ctl_flushpkt(CTL_MORE);
  828.     }
  829.  
  830.     bcopy(dp, (char *)datapt, dlen);
  831.     datapt += dlen;
  832.     datalinelen += dlen;
  833. }
  834.  
  835.  
  836. /*
  837.  * ctl_putstr - write a tagged string into the response packet
  838.  */
  839. void
  840. ctl_putstr(tag, data, len)
  841.     char *tag;
  842.     char *data;
  843.     int len;
  844. {
  845.     register char *cp, *cq;
  846.     char buffer[200];
  847.  
  848.     cp = buffer;
  849.     cq = tag;
  850.     while (*cq != '\0')
  851.         *cp++ = *cq++;
  852.     
  853.     if (len > 0) {
  854.         *cp++ = '=';
  855.         *cp++ = '"';
  856.         if (len > (sizeof(buffer) - (cp - buffer) - 1))
  857.             len = sizeof(buffer) - (cp - buffer) - 1;
  858.         bcopy(data, cp, len);
  859.         cp += len;
  860.         *cp++ = '"';
  861.     }
  862.  
  863.     ctl_putdata(buffer, cp - buffer, 0);
  864. }
  865.  
  866.  
  867.  
  868. /*
  869.  * ctl_putlfp - write a tagged, signed l_fp into the response packet
  870.  */
  871. void
  872. ctl_putlfp(tag, ts)
  873.     char *tag;
  874.     l_fp *ts;
  875. {
  876.     register char *cp, *cq;
  877.     char buffer[200];
  878.     extern char *lfptoms();
  879.  
  880.     cp = buffer;
  881.     cq = tag;
  882.     while (*cq != '\0')
  883.         *cp++ = *cq++;
  884.  
  885.     *cp++ = '=';
  886.     cq = lfptoms(ts, 3);
  887.     while (*cq != '\0')
  888.         *cp++ = *cq++;
  889.     
  890.     ctl_putdata(buffer, cp - buffer, 0);
  891. }
  892.  
  893.  
  894. /*
  895.  * ctl_putlfp - write a tagged, unsigned l_fp into the response
  896.  */
  897. void
  898. ctl_putulfp(tag, ts)
  899.     char *tag;
  900.     l_fp *ts;
  901. {
  902.     register char *cp, *cq;
  903.     char buffer[200];
  904.     extern char *ulfptoms();
  905.  
  906.     cp = buffer;
  907.     cq = tag;
  908.     while (*cq != '\0')
  909.         *cp++ = *cq++;
  910.  
  911.     *cp++ = '=';
  912.     cq = ulfptoms(ts, 3);
  913.     while (*cq != '\0')
  914.         *cp++ = *cq++;
  915.     
  916.     ctl_putdata(buffer, cp - buffer, 0);
  917. }
  918.  
  919.  
  920. /*
  921.  * ctl_putfp - write a tagged s_fp number into the response
  922.  */
  923. void
  924. ctl_putfp(tag, fp)
  925.     char *tag;
  926.     s_fp fp;
  927. {
  928.     register char *cp, *cq;
  929.     char buffer[200];
  930.     extern char *fptoms();
  931.  
  932.     cp = buffer;
  933.     cq = tag;
  934.     while (*cq != '\0')
  935.         *cp++ = *cq++;
  936.  
  937.     *cp++ = '=';
  938.     cq = fptoms(fp, 2);
  939.     while (*cq != '\0')
  940.         *cp++ = *cq++;
  941.     
  942.     ctl_putdata(buffer, cp - buffer, 0);
  943. }
  944.  
  945.  
  946. /*
  947.  * ctl_putufp - write a tagged u_fp number into the response
  948.  */
  949. void
  950. ctl_putufp(tag, ufp)
  951.     char *tag;
  952.     u_fp ufp;
  953. {
  954.     register char *cp, *cq;
  955.     char buffer[200];
  956.     extern char *ufptoms();
  957.  
  958.     cp = buffer;
  959.     cq = tag;
  960.     while (*cq != '\0')
  961.         *cp++ = *cq++;
  962.  
  963.     *cp++ = '=';
  964.     cq = ufptoms(ufp, 2);
  965.     while (*cq != '\0')
  966.         *cp++ = *cq++;
  967.     
  968.     ctl_putdata(buffer, cp - buffer, 0);
  969. }
  970.  
  971.  
  972. /*
  973.  * ctl_putuint - write a tagged unsigned integer into the response
  974.  */
  975. void
  976. ctl_putuint(tag, uval)
  977.     char *tag;
  978.     u_long uval;
  979. {
  980.     register char *cp, *cq;
  981.     char buffer[200];
  982.  
  983.     cp = buffer;
  984.     cq = tag;
  985.     while (*cq != '\0')
  986.         *cp++ = *cq++;
  987.  
  988.     *cp++ = '=';
  989.     (void) sprintf(cp, "%u", uval);
  990.     while (*cp != '\0')
  991.         *cp++;
  992.     
  993.     ctl_putdata(buffer, cp - buffer, 0);
  994. }
  995.  
  996.  
  997. /*
  998.  * ctl_puthex - write a tagged unsigned integer, in hex, into the response
  999.  */
  1000. void
  1001. ctl_puthex(tag, uval)
  1002.     char *tag;
  1003.     u_long uval;
  1004. {
  1005.     register char *cp, *cq;
  1006.     char buffer[200];
  1007.  
  1008.     cp = buffer;
  1009.     cq = tag;
  1010.     while (*cq != '\0')
  1011.         *cp++ = *cq++;
  1012.  
  1013.     *cp++ = '=';
  1014.     (void) sprintf(cp, "0x%lx", uval);
  1015.     while (*cp != '\0')
  1016.         *cp++;
  1017.  
  1018.     ctl_putdata(buffer, cp - buffer, 0);
  1019. }
  1020.  
  1021.  
  1022. /*
  1023.  * ctl_putint - write a tagged signed integer into the response
  1024.  */
  1025. void
  1026. ctl_putint(tag, ival)
  1027.     char *tag;
  1028.     long ival;
  1029. {
  1030.     register char *cp, *cq;
  1031.     char buffer[200];
  1032.  
  1033.     cp = buffer;
  1034.     cq = tag;
  1035.     while (*cq != '\0')
  1036.         *cp++ = *cq++;
  1037.  
  1038.     *cp++ = '=';
  1039.     (void) sprintf(cp, "%d", ival);
  1040.     while (*cp != '\0')
  1041.         *cp++;
  1042.     
  1043.     ctl_putdata(buffer, cp - buffer, 0);
  1044. }
  1045.  
  1046.  
  1047. /*
  1048.  * ctl_putts - write a tagged timestamp, in hex, into the response
  1049.  */
  1050. void
  1051. ctl_putts(tag, ts)
  1052.     char *tag;
  1053.     l_fp *ts;
  1054. {
  1055.     register char *cp, *cq;
  1056.     char buffer[200];
  1057.  
  1058.     cp = buffer;
  1059.     cq = tag;
  1060.     while (*cq != '\0')
  1061.         *cp++ = *cq++;
  1062.  
  1063.     *cp++ = '=';
  1064.     (void) sprintf(cp, "0x%08lx.%08lx", ts->l_ui, ts->l_uf);
  1065.     while (*cp != '\0')
  1066.         *cp++;
  1067.     
  1068.     ctl_putdata(buffer, cp - buffer, 0);
  1069. }
  1070.  
  1071.  
  1072. /*
  1073.  * ctl_putadr - write a dotted quad IP address into the response
  1074.  */
  1075. void
  1076. ctl_putadr(tag, addr)
  1077.     char *tag;
  1078.     u_long addr;
  1079. {
  1080.     register char *cp, *cq;
  1081.     char buffer[200];
  1082.     extern char *numtoa();
  1083.  
  1084.     cp = buffer;
  1085.     cq = tag;
  1086.     while (*cq != '\0')
  1087.         *cp++ = *cq++;
  1088.  
  1089.     *cp++ = '=';
  1090.     cq = numtoa(addr);
  1091.     while (*cq != '\0')
  1092.         *cp++ = *cq++;
  1093.     
  1094.     ctl_putdata(buffer, cp - buffer, 0);
  1095. }
  1096.  
  1097.  
  1098. /*
  1099.  * ctl_putid - write a tagged clock ID into the response
  1100.  */
  1101. void
  1102. ctl_putid(tag, id)
  1103.     char *tag;
  1104.     char *id;
  1105. {
  1106.     register char *cp, *cq;
  1107.     char buffer[200];
  1108.  
  1109.     cp = buffer;
  1110.     cq = tag;
  1111.     while (*cq != '\0')
  1112.         *cp++ = *cq++;
  1113.  
  1114.     *cp++ = '=';
  1115.     cq = id;
  1116.     while (*cq != '\0' && (cq - id) < 4)
  1117.         *cp++ = *cq++;
  1118.     
  1119.     ctl_putdata(buffer, cp - buffer, 0);
  1120. }
  1121.  
  1122.  
  1123. /*
  1124.  * ctl_putarray - write a tagged eight element s_fp array into the response
  1125.  */
  1126. void
  1127. ctl_putarray(tag, arr, start)
  1128.     char *tag;
  1129.     s_fp *arr;
  1130.     int start;
  1131. {
  1132.     register char *cp, *cq;
  1133.     char buffer[200];
  1134.     int i, ind;
  1135.     int len;
  1136.     extern char *fptoms();
  1137.  
  1138.     cp = buffer;
  1139.     cq = tag;
  1140.     while (*cq != '\0')
  1141.         *cp++ = *cq++;
  1142.     *cp++ = '=';
  1143.     /*
  1144.      * Hack.  We know the tag is either filtdelay, filtoffset,
  1145.      * or filterror.  Space over the shorter words one space.
  1146.      */
  1147.     if ((cp - buffer) < 11)
  1148.         *cp++ = ' ';
  1149.  
  1150.     i = start;
  1151.     ind = 0;
  1152.     do {
  1153.         if (i == 0)
  1154.             i = NTP_SHIFT;
  1155.         i--;
  1156.         if (ind) {
  1157.             *cp++ = ' ';
  1158.         } else {
  1159.             ind = 1;
  1160.         }
  1161.         cq = fptoms(arr[i], 2);
  1162.         len = strlen(cq);
  1163.         while (len < 7) {
  1164.             *cp++ = ' ';
  1165.             len++;
  1166.         }
  1167.         while (*cq != '\0')
  1168.             *cp++ = *cq++;
  1169.     } while(i != start);
  1170.  
  1171.     ctl_putdata(buffer, cp - buffer, 0);
  1172. }
  1173.  
  1174.  
  1175. /*
  1176.  * ctl_putsys - output a system variable
  1177.  */
  1178. void
  1179. ctl_putsys(varid)
  1180.     int varid;
  1181. {
  1182.     l_fp tmp;
  1183.     /*
  1184.      * Importations from the protocol module
  1185.      */
  1186.     extern u_char sys_leap;
  1187.     extern u_char sys_stratum;
  1188.     extern s_char sys_precision;
  1189.     extern s_fp sys_rootdelay;
  1190.     extern u_fp sys_rootdispersion;
  1191.     extern u_long sys_refid;
  1192.     extern l_fp sys_reftime;
  1193.     extern l_fp sys_refskew;
  1194.     extern int sys_poll;
  1195.     extern struct peer *sys_peer;
  1196.     /*
  1197.      * Imported from the loop filter module
  1198.      */
  1199.     extern l_fp last_offset;
  1200.     extern s_fp drift_comp;
  1201.     extern int time_constant;
  1202.     /*
  1203.      * Imported from the leap module
  1204.      */
  1205.     extern u_char leap_indicator;
  1206.     extern u_char leap_warning;
  1207.  
  1208.     extern void get_systime();
  1209.  
  1210.     switch (varid) {
  1211.     case CS_LEAP:
  1212.         ctl_putuint(sys_var[CS_LEAP].text, (u_long)sys_leap);
  1213.         break;
  1214.     case CS_STRATUM:
  1215.         ctl_putuint(sys_var[CS_STRATUM].text, (u_long)sys_stratum);
  1216.         break;
  1217.     case CS_PRECISION:
  1218.         ctl_putint(sys_var[CS_PRECISION].text, (long)sys_precision);
  1219.         break;
  1220.     case CS_ROOTDELAY:
  1221.         ctl_putfp(sys_var[CS_ROOTDELAY].text, sys_rootdelay);
  1222.         break;
  1223.     case CS_ROOTDISPERSION:
  1224.         ctl_putufp(sys_var[CS_ROOTDISPERSION].text,
  1225.                sys_rootdispersion);
  1226.         break;
  1227.     case CS_REFID:
  1228.         if (sys_stratum <= 1)
  1229.             ctl_putid(sys_var[CS_REFID].text, (char *)&sys_refid);
  1230.         else
  1231.             ctl_putadr(sys_var[CS_REFID].text, sys_refid);
  1232.         break;
  1233.     case CS_REFTIME:
  1234.         ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime);
  1235.         break;
  1236.     case CS_POLL:
  1237.         ctl_putuint(sys_var[CS_POLL].text, (u_long)sys_poll);
  1238.         break;
  1239.     case CS_PEERID:
  1240.         if (sys_peer == NULL)
  1241.             ctl_putuint(sys_var[CS_PEERID].text, (u_long)0);
  1242.         else
  1243.             ctl_putuint(sys_var[CS_PEERID].text,
  1244.                 (u_long)sys_peer->associd);
  1245.         break;
  1246.     case CS_OFFSET:
  1247.         ctl_putlfp(sys_var[CS_OFFSET].text, &last_offset);
  1248.         break;
  1249.     case CS_DRIFT:
  1250.         ctl_putfp(sys_var[CS_DRIFT].text, drift_comp);
  1251.         break;
  1252.     case CS_COMPLIANCE:
  1253.         ctl_putuint(sys_var[CS_COMPLIANCE].text, time_constant);
  1254.         break;
  1255.     case CS_CLOCK:
  1256.         get_systime(&tmp);
  1257.         ctl_putts(sys_var[CS_CLOCK].text, &tmp);
  1258.         break;
  1259.     case CS_LEAPIND:
  1260.         ctl_putuint(sys_var[CS_LEAPIND].text, (u_long)leap_indicator);
  1261.         break;
  1262.     case CS_LEAPWARNING:
  1263.         ctl_putuint(sys_var[CS_LEAPWARNING].text, (u_long)leap_warning);
  1264.         break;
  1265.     case CS_PROCESSOR:
  1266.         ctl_putstr(sys_var[CS_PROCESSOR].text, STR_PROCESSOR,
  1267.             sizeof(STR_PROCESSOR) - 1);
  1268.         break;
  1269.     case CS_SYSTEM:
  1270.         ctl_putstr(sys_var[CS_SYSTEM].text, STR_SYSTEM,
  1271.             sizeof(STR_SYSTEM) - 1);
  1272.         break;
  1273.     case CS_KEYID:
  1274.         ctl_putuint(sys_var[CS_KEYID].text, (u_long)0);
  1275.         break;
  1276.     case CS_REFSKEW:
  1277.         ctl_putlfp(sys_var[CS_REFSKEW].text, &sys_refskew);
  1278.         break;
  1279.     }
  1280. }
  1281.  
  1282.  
  1283. /*
  1284.  * ctl_putpeer - output a peer variable
  1285.  */
  1286. void
  1287. ctl_putpeer(varid, peer)
  1288.     int varid;
  1289.     struct peer *peer;
  1290. {
  1291.     switch (varid) {
  1292.     case CP_CONFIG:
  1293.         ctl_putuint(peer_var[CP_CONFIG].text,
  1294.             (u_long)((peer->flags & FLAG_CONFIG) != 0));
  1295.         break;
  1296.     case CP_AUTHENABLE:
  1297.         ctl_putuint(peer_var[CP_AUTHENABLE].text,
  1298.             (u_long)((peer->flags & FLAG_AUTHENABLE) != 0));
  1299.         break;
  1300.     case CP_AUTHENTIC:
  1301.         ctl_putuint(peer_var[CP_AUTHENTIC].text,
  1302.             (u_long)((peer->flags & FLAG_AUTHENTIC) != 0));
  1303.         break;
  1304.     case CP_SRCADR:
  1305.         ctl_putadr(peer_var[CP_SRCADR].text,
  1306.             peer->srcadr.sin_addr.s_addr);
  1307.         break;
  1308.     case CP_SRCPORT:
  1309.         ctl_putuint(peer_var[CP_SRCPORT].text,
  1310.             (u_long)ntohs(peer->srcadr.sin_port));
  1311.         break;
  1312.     case CP_DSTADR:
  1313.         ctl_putadr(peer_var[CP_DSTADR].text,
  1314.             peer->dstadr->sin.sin_addr.s_addr);
  1315.         break;
  1316.     case CP_DSTPORT:
  1317.         ctl_putuint(peer_var[CP_DSTPORT].text,
  1318.             (u_long)ntohs(peer->dstadr->sin.sin_port));
  1319.         break;
  1320.     case CP_LEAP:
  1321.         ctl_putuint(peer_var[CP_LEAP].text, (u_long)peer->leap);
  1322.         break;
  1323.     case CP_HMODE:
  1324.         ctl_putuint(peer_var[CP_HMODE].text, (u_long)peer->hmode);
  1325.         break;
  1326.     case CP_STRATUM:
  1327.         ctl_putuint(peer_var[CP_STRATUM].text, (u_long)peer->stratum);
  1328.         break;
  1329.     case CP_PPOLL:
  1330.         ctl_putuint(peer_var[CP_PPOLL].text, (u_long)peer->ppoll);
  1331.         break;
  1332.     case CP_HPOLL:
  1333.         ctl_putuint(peer_var[CP_HPOLL].text, (u_long)peer->hpoll);
  1334.         break;
  1335.     case CP_PRECISION:
  1336.         ctl_putint(peer_var[CP_PRECISION].text, (long)peer->precision);
  1337.         break;
  1338.     case CP_ROOTDELAY:
  1339.         ctl_putfp(peer_var[CP_ROOTDELAY].text, peer->rootdelay);
  1340.         break;
  1341.     case CP_ROOTDISPERSION:
  1342.         ctl_putufp(peer_var[CP_ROOTDISPERSION].text,
  1343.                peer->rootdispersion);
  1344.         break;
  1345.     case CP_REFID:
  1346.         if (peer->stratum > 1)
  1347.             ctl_putadr(peer_var[CP_REFID].text, peer->refid);
  1348.         else
  1349.             ctl_putid(peer_var[CP_REFID].text,
  1350.                 (char *)&peer->refid);
  1351.         break;
  1352.     case CP_REFTIME:
  1353.         ctl_putts(peer_var[CP_REFTIME].text, &peer->reftime);
  1354.         break;
  1355.     case CP_ORG:
  1356.         ctl_putts(peer_var[CP_ORG].text, &peer->org);
  1357.         break;
  1358.     case CP_REC:
  1359.         ctl_putts(peer_var[CP_REC].text, &peer->rec);
  1360.         break;
  1361.     case CP_XMT:
  1362.         ctl_putts(peer_var[CP_XMT].text, &peer->xmt);
  1363.         break;
  1364.     case CP_REACH:
  1365.         ctl_puthex(peer_var[CP_REACH].text, (u_long)peer->reach);
  1366.         break;
  1367.     case CP_FLASH:
  1368.         ctl_puthex(peer_var[CP_FLASH].text, (u_long)peer->flash);
  1369.         break;
  1370.     case CP_VALID:
  1371.         ctl_putuint(peer_var[CP_VALID].text, (u_long)peer->valid);
  1372.         break;
  1373.     case CP_TIMER:
  1374.         ctl_putuint(peer_var[CP_TIMER].text,
  1375.             peer->event_timer.event_time - current_time);
  1376.         break;
  1377.     case CP_DELAY:
  1378.         ctl_putfp(peer_var[CP_DELAY].text, peer->delay);
  1379.         break;
  1380.     case CP_OFFSET:
  1381.         ctl_putlfp(peer_var[CP_OFFSET].text, &peer->offset);
  1382.         break;
  1383.     case CP_DISPERSION:
  1384.         ctl_putufp(peer_var[CP_DISPERSION].text, peer->dispersion);
  1385.         break;
  1386.     case CP_KEYID:
  1387.         ctl_putuint(peer_var[CP_KEYID].text, peer->keyid);
  1388.         break;
  1389.     case CP_FILTDELAY:
  1390.         ctl_putarray(peer_var[CP_FILTDELAY].text,
  1391.              peer->filter_delay, peer->filter_nextpt);
  1392.         break;
  1393.     case CP_FILTOFFSET:
  1394.         ctl_putarray(peer_var[CP_FILTOFFSET].text,
  1395.              peer->filter_soffset, peer->filter_nextpt);
  1396.         break;
  1397.     case CP_FILTERROR:
  1398.         ctl_putarray(peer_var[CP_FILTERROR].text,
  1399.              (s_fp *)peer->filter_error, peer->filter_nextpt);
  1400.         break;
  1401.     case CP_PMODE:
  1402.         ctl_putuint(peer_var[CP_PMODE].text, (u_long)peer->pmode);
  1403.         break;
  1404.     case CP_RECEIVED:
  1405.         ctl_putuint(peer_var[CP_RECEIVED].text, peer->received);
  1406.         break;
  1407.     case CP_SENT:
  1408.         ctl_putuint(peer_var[CP_SENT].text, peer->sent);
  1409.         break;
  1410.     }
  1411. }
  1412.  
  1413.  
  1414. #ifdef REFCLOCK
  1415. /*
  1416.  * ctl_putclock - output clock variables
  1417.  */
  1418. void
  1419. ctl_putclock(varid, clock, mustput)
  1420.     int varid;
  1421.     struct refclockstat *clock;
  1422.     int mustput;
  1423. {
  1424.     switch(varid) {
  1425.     case CC_TYPE:
  1426.         if (mustput || clock->clockdesc == NULL
  1427.             || *(clock->clockdesc) == '\0') {
  1428.             ctl_putuint(clock_var[CC_TYPE].text,
  1429.                 (u_long)clock->type);
  1430.         }
  1431.         break;
  1432.     case CC_TIMECODE:
  1433.         ctl_putstr(clock_var[CC_TIMECODE].text, clock->lastcode,
  1434.             (int)clock->lencode);
  1435.         break;
  1436.     case CC_POLL:
  1437.         ctl_putuint(clock_var[CC_POLL].text, (u_long)clock->polls);
  1438.         break;
  1439.     case CC_NOREPLY:
  1440.         ctl_putuint(clock_var[CC_NOREPLY].text, clock->noresponse);
  1441.         break;
  1442.     case CC_BADFORMAT:
  1443.         ctl_putuint(clock_var[CC_BADFORMAT].text, clock->badformat);
  1444.         break;
  1445.     case CC_BADDATA:
  1446.         ctl_putuint(clock_var[CC_BADDATA].text, clock->baddata);
  1447.         break;
  1448.     case CC_FUDGETIME1:
  1449.         if (mustput || (clock->haveflags & CLK_HAVETIME1))
  1450.             ctl_putlfp(clock_var[CC_FUDGETIME1].text,
  1451.                 &clock->fudgetime1);
  1452.         break;
  1453.     case CC_FUDGETIME2:
  1454.         if (mustput || (clock->haveflags & CLK_HAVETIME2))
  1455.             ctl_putlfp(clock_var[CC_FUDGETIME2].text,
  1456.                 &clock->fudgetime2);
  1457.         break;
  1458.     case CC_FUDGEVAL1:
  1459.         if (mustput || (clock->haveflags & CLK_HAVEVAL1))
  1460.             ctl_putint(clock_var[CC_FUDGEVAL1].text,
  1461.                 clock->fudgeval1);
  1462.         break;
  1463.     case CC_FUDGEVAL2:
  1464.         if (mustput || (clock->haveflags & CLK_HAVEVAL2))
  1465.             ctl_putint(clock_var[CC_FUDGEVAL2].text,
  1466.                 clock->fudgeval2);
  1467.         break;
  1468.     case CC_FLAGS:
  1469.         if (mustput || (clock->haveflags &
  1470.             (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)))
  1471.             ctl_putuint(clock_var[CC_FLAGS].text,
  1472.                 (u_long)clock->flags);
  1473.         break;
  1474.     case CC_DEVICE:
  1475.         if (clock->clockdesc == NULL || *(clock->clockdesc) == '\0') {
  1476.             if (mustput)
  1477.                 ctl_putstr(clock_var[CC_DEVICE].text, "", 0);
  1478.         } else {
  1479.             ctl_putstr(clock_var[CC_DEVICE].text, clock->clockdesc,
  1480.                 strlen(clock->clockdesc));
  1481.         }
  1482.         break;
  1483.     }
  1484. }
  1485. #endif
  1486.  
  1487.  
  1488.  
  1489. /*
  1490.  * ctl_getitem - get the next data item from the incoming packet
  1491.  */
  1492. struct ctl_var *
  1493. ctl_getitem(var_list, data)
  1494.     struct ctl_var *var_list;
  1495.     char **data;
  1496. {
  1497.     register struct ctl_var *v;
  1498.     register char *cp, *tp;
  1499.     static char buf[128];
  1500.  
  1501.     /*
  1502.      * Delete leading commas and white space
  1503.      */
  1504.     while (reqpt < reqend && (*reqpt == ',' || isspace(*reqpt))) {
  1505.         reqpt++;
  1506.     }
  1507.  
  1508.     if (reqpt >= reqend)
  1509.         return 0;
  1510.     
  1511.     /*
  1512.      * Look for a first character match on the tag.  If we find
  1513.      * one, see if it is a full match.
  1514.      */
  1515.     v = var_list;
  1516.     cp = reqpt;
  1517.     while (!(v->flags & EOV)) {
  1518.         if (!(v->flags & PADDING) && *cp == *(v->text)) {
  1519.             tp = v->text;
  1520.             while (*tp != '\0' && cp < reqend && *cp == *tp) {
  1521.                 cp++;
  1522.                 tp++;
  1523.             }
  1524.             if (*tp == '\0') {
  1525.                 while (cp < reqend && isspace(*cp))
  1526.                     cp++;
  1527.                 if (cp == reqend || *cp == ',') {
  1528.                     buf[0] = '\0';
  1529.                     *data = buf;
  1530.                     if (cp < reqend)
  1531.                         cp++;
  1532.                     reqpt = cp;
  1533.                     return v;
  1534.                 }
  1535.                 if (*cp == '=') {
  1536.                     cp++;
  1537.                     tp = buf;
  1538.                     while (cp < reqend && isspace(*cp))
  1539.                         cp++;
  1540.                     while (cp < reqend && *cp != ',')
  1541.                         *tp++ = *cp++;
  1542.                     if (cp < reqend)
  1543.                         cp++;
  1544.                     *tp = '\0';
  1545.                     while (isspace(*(tp-1)))
  1546.                         *(--tp) = '\0';
  1547.                     reqpt = cp;
  1548.                     *data = buf;
  1549.                     return v;
  1550.                 }
  1551.             }
  1552.             cp = reqpt;
  1553.         }
  1554.         v++;
  1555.     }
  1556.     return v;
  1557. }
  1558.  
  1559.  
  1560. /*
  1561.  * control_unspec - response to an unspecified op-code
  1562.  */
  1563. /*ARGSUSED*/
  1564. void
  1565. control_unspec(rbufp, restrict)
  1566.     struct recvbuf *rbufp;
  1567.     int restrict;
  1568. {
  1569.     extern struct peer *findpeerbyassoc();
  1570.     struct peer *peer;
  1571.  
  1572.     /*
  1573.      * What is an appropriate response to an unspecified op-code?
  1574.      * I return no errors and no data, unless a specified assocation
  1575.      * doesn't exist.
  1576.      */
  1577.     if (res_associd != 0) {
  1578.         if ((peer = findpeerbyassoc((int)res_associd)) == 0) {
  1579.             ctl_error(CERR_BADASSOC);
  1580.             return;
  1581.         }
  1582.         rpkt.status = htons(ctlpeerstatus(peer));
  1583.     } else {
  1584.         rpkt.status = htons(ctlsysstatus());
  1585.     }
  1586.     ctl_flushpkt(0);
  1587. }
  1588.  
  1589.  
  1590. /*
  1591.  * read_status - return either a list of associd's, or a particular
  1592.  *         peer's status.
  1593.  */
  1594. /*ARGSUSED*/
  1595. void
  1596. read_status(rbufp, restrict)
  1597.     struct recvbuf *rbufp;
  1598.     int restrict;
  1599. {
  1600.     register int i;
  1601.     register struct peer *peer;
  1602.     u_short ass_stat[CTL_MAX_DATA_LEN/sizeof(u_short)];
  1603.     extern struct peer *assoc_hash[];
  1604.     extern struct peer *findpeerbyassoc();
  1605.  
  1606. #ifdef DEBUG
  1607.     if (debug >= 2)
  1608.         printf("read_status: ID %d\n", res_associd);
  1609. #endif
  1610.     /*
  1611.      * Two choices here.  If the specified association ID is
  1612.      * zero we return all known assocation ID's.  Otherwise
  1613.      * we return a bunch of stuff about the particular peer.
  1614.      */
  1615.     if (res_associd == 0) {
  1616.         register int n;
  1617.  
  1618.         n = 0;
  1619.         rpkt.status = htons(ctlsysstatus());
  1620.         for (i = 0; i < HASH_SIZE; i++) {
  1621.             for (peer = assoc_hash[i]; peer != 0;
  1622.                 peer = peer->ass_next) {
  1623.                 ass_stat[n++] = htons(peer->associd);
  1624.                 ass_stat[n++] = htons(ctlpeerstatus(peer));
  1625.                 if (n == CTL_MAX_DATA_LEN/sizeof(u_short)) {
  1626.                     ctl_putdata((char *)ass_stat,
  1627.                         n * sizeof(u_short), 1);
  1628.                     n = 0;
  1629.                 }
  1630.             }
  1631.         }
  1632.  
  1633.         if (n != 0)
  1634.             ctl_putdata((char *)ass_stat, n * sizeof(u_short), 1);
  1635.         ctl_flushpkt(0);
  1636.     } else {
  1637.         peer = findpeerbyassoc((int)res_associd);
  1638.         if (peer == 0) {
  1639.             ctl_error(CERR_BADASSOC);
  1640.         } else {
  1641.             register u_char *cp;
  1642.  
  1643.             rpkt.status = htons(ctlpeerstatus(peer));
  1644.             if (res_authokay)
  1645.                 peer->num_events = 0;
  1646.             /*
  1647.              * For now, output everything we know about the peer.
  1648.              * May be more selective later.
  1649.              */
  1650.             for (cp = def_peer_var; *cp != 0; cp++)
  1651.                 ctl_putpeer((int)*cp, peer);
  1652.             ctl_flushpkt(0);
  1653.         }
  1654.     }
  1655. }
  1656.  
  1657.  
  1658. /*
  1659.  * read_variables - return the variables the caller asks for
  1660.  */
  1661. /*ARGSUSED*/
  1662. void
  1663. read_variables(rbufp, restrict)
  1664.     struct recvbuf *rbufp;
  1665.     int restrict;
  1666. {
  1667.     register struct ctl_var *v;
  1668.     register int i;
  1669.     char *valuep;
  1670.     u_char wants[(CS_MAXCODE>CP_MAXCODE) ? (CS_MAXCODE+1) : (CP_MAXCODE+1)];
  1671.     int gotvar;
  1672.     extern struct peer *findpeerbyassoc();
  1673.  
  1674.     if (res_associd == 0) {
  1675.         /*
  1676.          * Wants system variables.  Figure out which he wants
  1677.          * and give them to him.
  1678.          */
  1679.         rpkt.status = htons(ctlsysstatus());
  1680.         if (res_authokay)
  1681.             ctl_sys_num_events = 0;
  1682.         bzero(wants, CS_MAXCODE+1);
  1683.         gotvar = 0;
  1684.         while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
  1685.             if (v->flags & EOV) {
  1686.                 ctl_error(CERR_UNKNOWNVAR);
  1687.                 return;
  1688.             }
  1689.             wants[v->code] = 1;
  1690.             gotvar = 1;
  1691.         }
  1692.         if (gotvar) {
  1693.             for (i = 1; i <= CS_MAXCODE; i++)
  1694.                 if (wants[i])
  1695.                     ctl_putsys(i);
  1696.         } else {
  1697.             register u_char *cs;
  1698.  
  1699.             for (cs = def_sys_var; *cs != 0; cs++)
  1700.                 ctl_putsys((int)*cs);
  1701.         }
  1702.     } else {
  1703.         register struct peer *peer;
  1704.  
  1705.         /*
  1706.          * Wants info for a particular peer.  See if we know
  1707.          * the guy.
  1708.          */
  1709.         peer = findpeerbyassoc((int)res_associd);
  1710.         if (peer == 0) {
  1711.             ctl_error(CERR_BADASSOC);
  1712.             return;
  1713.         }
  1714.  
  1715.         rpkt.status = htons(ctlpeerstatus(peer));
  1716.         if (res_authokay)
  1717.             peer->num_events = 0;
  1718.         bzero(wants, CP_MAXCODE+1);
  1719.         gotvar = 0;
  1720.         while ((v = ctl_getitem(peer_var, &valuep)) != 0) {
  1721.             if (v->flags & EOV) {
  1722.                 ctl_error(CERR_UNKNOWNVAR);
  1723.                 return;
  1724.             }
  1725.             wants[v->code] = 1;
  1726.             gotvar = 1;
  1727.         }
  1728.         if (gotvar) {
  1729.             for (i = 1; i <= CP_MAXCODE; i++)
  1730.                 if (wants[i])
  1731.                     ctl_putpeer(i, peer);
  1732.         } else {
  1733.             register u_char *cp;
  1734.  
  1735.             for (cp = def_peer_var; *cp != 0; cp++)
  1736.                 ctl_putpeer((int)*cp, peer);
  1737.         }
  1738.     }
  1739.     ctl_flushpkt(0);
  1740. }
  1741.  
  1742.  
  1743. /*
  1744.  * write_variables - write into variables.  We only allow leap bit writing
  1745.  *             this way.
  1746.  */
  1747. /*ARGSUSED*/
  1748. void
  1749. write_variables(rbufp, restrict)
  1750.     struct recvbuf *rbufp;
  1751.     int restrict;
  1752. {
  1753.     register struct ctl_var *v;
  1754.     char *valuep;
  1755.     long val;
  1756.     u_char leapind, leapwarn;
  1757.     extern int atoint();
  1758.     extern int leap_setleap();
  1759.  
  1760.     /*
  1761.      * If he's trying to write into a peer tell him no way
  1762.      */
  1763.     if (res_associd != 0) {
  1764.         ctl_error(CERR_PERMISSION);
  1765.         return;
  1766.     }
  1767.  
  1768.     /*
  1769.      * Set status
  1770.      */
  1771.     rpkt.status = htons(ctlsysstatus());
  1772.  
  1773.     /*
  1774.      * Set flags to not-in-sync so we can tell when we get something.
  1775.      */
  1776.     leapind = LEAP_NOTINSYNC;
  1777.     leapwarn = LEAP_NOTINSYNC;
  1778.  
  1779.     /*
  1780.      * Look through the variables.  Dump out at the first sign of trouble.
  1781.      */
  1782.     while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
  1783.         if (v->flags & EOV) {
  1784.             ctl_error(CERR_UNKNOWNVAR);
  1785.             return;
  1786.         }
  1787.         if (!(v->flags & CAN_WRITE)) {
  1788.             ctl_error(CERR_PERMISSION);
  1789.             return;
  1790.         }
  1791.         if (*valuep == '\0' || !atoint(valuep, &val)) {
  1792.             ctl_error(CERR_BADFMT);
  1793.             return;
  1794.         }
  1795.         if ((val & ~LEAP_NOTINSYNC) != 0 || val == LEAP_NOTINSYNC) {
  1796.             ctl_error(CERR_BADVALUE);
  1797.             return;
  1798.         }
  1799.  
  1800.         /*
  1801.          * This one seems sane.  Save it.
  1802.          */
  1803.         switch(v->code) {
  1804.         case CS_LEAP:
  1805.         case CS_LEAPIND:
  1806.             leapind = (u_char)val;
  1807.             break;
  1808.         case CS_LEAPWARNING:
  1809.             leapwarn = (u_char)val;
  1810.             break;
  1811.         default:
  1812.             ctl_error(CERR_UNSPEC);        /* our fault, really */
  1813.             return;
  1814.         }
  1815.     }
  1816.  
  1817.     /*
  1818.      * If we got anything, do it.
  1819.      */
  1820.     if (leapind != LEAP_NOTINSYNC || leapwarn != LEAP_NOTINSYNC) {
  1821.         if (!leap_setleap((int)leapind, (int)leapwarn)) {
  1822.             ctl_error(CERR_PERMISSION);
  1823.             return;
  1824.         }
  1825.     }
  1826.     ctl_flushpkt(0);
  1827. }
  1828.  
  1829.  
  1830. /*
  1831.  * read_clock_status - return clock radio status
  1832.  */
  1833. /*ARGSUSED*/
  1834. void
  1835. read_clock_status(rbufp, restrict)
  1836.     struct recvbuf *rbufp;
  1837.     int restrict;
  1838. {
  1839. #ifndef REFCLOCK
  1840.     /*
  1841.      * If no refclock support, no data to return
  1842.      */
  1843.     ctl_error(CERR_BADASSOC);
  1844. #else
  1845.     register struct ctl_var *v;
  1846.     register int i;
  1847.     register struct peer *peer;
  1848.     char *valuep;
  1849.     u_char wants[CC_MAXCODE+1];
  1850.     int gotvar;
  1851.     struct refclockstat clock;
  1852.     extern struct peer *assoc_hash[];
  1853.     extern struct peer *sys_peer;
  1854.     extern struct peer *findpeerbyassoc();
  1855.     extern void refclock_control();
  1856.  
  1857.     if (res_associd == 0) {
  1858.         /*
  1859.          * Find a clock for this jerk.  If the system peer
  1860.          * is a clock use it, else search the hash tables
  1861.          * for one.
  1862.          */
  1863.         if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK)) {
  1864.             peer = sys_peer;
  1865.         } else {
  1866.             peer = 0;
  1867.             for (i = 0; peer == 0 && i < HASH_SIZE; i++) {
  1868.                 for (peer = assoc_hash[i]; peer != 0;
  1869.                     peer = peer->ass_next) {
  1870.                     if (peer->flags & FLAG_REFCLOCK)
  1871.                         break;
  1872.                 }
  1873.             }
  1874.             if (peer == 0) {
  1875.                 ctl_error(CERR_BADASSOC);
  1876.                 return;
  1877.             }
  1878.         }
  1879.     } else {
  1880.         peer = findpeerbyassoc((int)res_associd);
  1881.         if (peer == 0 || !(peer->flags & FLAG_REFCLOCK)) {
  1882.             ctl_error(CERR_BADASSOC);
  1883.             return;
  1884.         }
  1885.     }
  1886.  
  1887.     /*
  1888.      * If we got here we have a peer which is a clock.  Get his status.
  1889.      */
  1890.     refclock_control(&peer->srcadr, (struct refclockstat *)0, &clock);
  1891.  
  1892.     /*
  1893.      * Look for variables in the packet.
  1894.      */
  1895.     rpkt.status = htons(ctlclkstatus(&clock));
  1896.     gotvar = 0;
  1897.     bzero(wants, CC_MAXCODE+1);
  1898.     while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
  1899.         if (v->flags & EOV) {
  1900.             ctl_error(CERR_UNKNOWNVAR);
  1901.             return;
  1902.         }
  1903.         wants[v->code] = 1;
  1904.         gotvar = 1;
  1905.     }
  1906.  
  1907.     if (gotvar) {
  1908.         for (i = 1; i <= CC_MAXCODE; i++)
  1909.             if (wants[i])
  1910.                 ctl_putclock(i, &clock, 1);
  1911.     } else {
  1912.         register u_char *cc;
  1913.  
  1914.         for (cc = def_clock_var; *cc != 0; cc++)
  1915.             ctl_putclock((int)*cc, &clock, 0);
  1916.     }
  1917.     ctl_flushpkt(0);
  1918. #endif
  1919. }
  1920.  
  1921.  
  1922. /*
  1923.  * write_clock_status - we don't do this
  1924.  */
  1925. /*ARGSUSED*/
  1926. void
  1927. write_clock_status(rbufp, restrict)
  1928.     struct recvbuf *rbufp;
  1929.     int restrict;
  1930. {
  1931.     ctl_error(CERR_PERMISSION);
  1932. }
  1933.  
  1934. /*
  1935.  * Trap support from here on down.  We send async trap messages when the
  1936.  * upper levels report trouble.  Traps can by set either by control
  1937.  * messages or by configuration.
  1938.  */
  1939.  
  1940. /*
  1941.  * set_trap - set a trap in response to a control message
  1942.  */
  1943. void
  1944. set_trap(rbufp, restrict)
  1945.     struct recvbuf *rbufp;
  1946.     int restrict;
  1947. {
  1948.     int traptype;
  1949.     int ctlsettrap();
  1950.  
  1951.     /*
  1952.      * See if this guy is allowed
  1953.      */
  1954.     if (restrict & RES_NOTRAP) {
  1955.         ctl_error(CERR_PERMISSION);
  1956.         return;
  1957.     }
  1958.  
  1959.     /*
  1960.      * Determine his allowed trap type.
  1961.      */
  1962.     traptype = TRAP_TYPE_PRIO;
  1963.     if (restrict & RES_LPTRAP)
  1964.         traptype = TRAP_TYPE_NONPRIO;
  1965.  
  1966.     /*
  1967.      * Call ctlsettrap() to do the work.  Return
  1968.      * an error if it can't assign the trap.
  1969.      */
  1970.     if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype,
  1971.         res_version))
  1972.         ctl_error(CERR_NORESOURCE);
  1973.     ctl_flushpkt(0);
  1974. }
  1975.  
  1976.  
  1977. /*
  1978.  * unset_trap - unset a trap in response to a control message
  1979.  */
  1980. void
  1981. unset_trap(rbufp, restrict)
  1982.     struct recvbuf *rbufp;
  1983.     int restrict;
  1984. {
  1985.     int traptype;
  1986.     int ctlclrtrap();
  1987.  
  1988.     /*
  1989.      * We don't prevent anyone from removing his own
  1990.      * trap unless the trap is configured.  Note we also
  1991.      * must be aware of the possibility that restriction
  1992.      * flags were changed since this guy last set his trap.
  1993.      * Set the trap type based on this.
  1994.      */
  1995.     traptype = TRAP_TYPE_PRIO;
  1996.     if (restrict & RES_LPTRAP)
  1997.         traptype = TRAP_TYPE_NONPRIO;
  1998.  
  1999.     /*
  2000.      * Call ctlclrtrap() to clear this out.
  2001.      */
  2002.     if (!ctlclrtrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype))
  2003.         ctl_error(CERR_BADASSOC);
  2004.     ctl_flushpkt(0);
  2005. }
  2006.  
  2007.  
  2008. /*
  2009.  * ctlsettrap - called to set a trap
  2010.  */
  2011. int
  2012. ctlsettrap(raddr, linter, traptype, version)
  2013.     struct sockaddr_in *raddr;
  2014.     struct interface *linter;
  2015.     int traptype;
  2016.     int version;
  2017. {
  2018.     register struct ctl_trap *tp;
  2019.     register struct ctl_trap *tptouse;
  2020.     struct ctl_trap *ctlfindtrap();
  2021.  
  2022.     /*
  2023.      * See if we can find this trap.  If so, we only need update
  2024.      * the flags and the time.
  2025.      */
  2026.     if ((tp = ctlfindtrap(raddr, linter)) != NULL) {
  2027.         switch (traptype) {
  2028.         case TRAP_TYPE_CONFIG:
  2029.             tp->tr_flags = TRAP_INUSE|TRAP_CONFIGURED;
  2030.             break;
  2031.         case TRAP_TYPE_PRIO:
  2032.             if (tp->tr_flags & TRAP_CONFIGURED)
  2033.                 return 1;    /* don't change anything */
  2034.             tp->tr_flags = TRAP_INUSE;
  2035.             break;
  2036.         case TRAP_TYPE_NONPRIO:
  2037.             if (tp->tr_flags & TRAP_CONFIGURED)
  2038.                 return 1;    /* don't change anything */
  2039.             tp->tr_flags = TRAP_INUSE|TRAP_NONPRIO;
  2040.             break;
  2041.         }
  2042.         tp->tr_settime = current_time;
  2043.         tp->tr_resets++;
  2044.         return 1;
  2045.     }
  2046.  
  2047.     /*
  2048.      * First we heard of this guy.  Try to find a trap structure
  2049.      * for him to use, clearing out lesser priority guys if we
  2050.      * have to.  Clear out anyone who's expired while we're at it.
  2051.      */
  2052.     tptouse = NULL;
  2053.     for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
  2054.         if ((tp->tr_flags & TRAP_INUSE) &&
  2055.             !(tp->tr_flags & TRAP_CONFIGURED) &&
  2056.             ((tp->tr_settime + CTL_TRAPTIME) > current_time)) {
  2057.             tp->tr_flags = 0;
  2058.             num_ctl_traps--;
  2059.         }
  2060.  
  2061.         if (!(tp->tr_flags & TRAP_INUSE)) {
  2062.             tptouse = tp;
  2063.         } else if (!(tp->tr_flags & TRAP_CONFIGURED)) {
  2064.             switch (traptype) {
  2065.             case TRAP_TYPE_CONFIG:
  2066.                 if (tptouse == NULL) {
  2067.                     tptouse = tp;
  2068.                     break;
  2069.                 }
  2070.                 if (tptouse->tr_flags & TRAP_NONPRIO
  2071.                     && !(tp->tr_flags & TRAP_NONPRIO))
  2072.                     break;
  2073.                 if (!(tptouse->tr_flags & TRAP_NONPRIO)
  2074.                     && tp->tr_flags & TRAP_NONPRIO) {
  2075.                     tptouse = tp;
  2076.                     break;
  2077.                 }
  2078.                 if (tptouse->tr_origtime < tp->tr_origtime)
  2079.                     tptouse = tp;
  2080.                 break;
  2081.             case TRAP_TYPE_PRIO:
  2082.                 if (tp->tr_flags & TRAP_NONPRIO) {
  2083.                     if (tptouse == NULL ||
  2084.                         (tptouse->tr_flags & TRAP_INUSE
  2085.                         && tptouse->tr_origtime
  2086.                         < tp->tr_origtime))
  2087.                         tptouse = tp;
  2088.                 }
  2089.                 break;
  2090.             case TRAP_TYPE_NONPRIO:
  2091.                 break;
  2092.             }
  2093.         }
  2094.     }
  2095.  
  2096.     /*
  2097.      * If we don't have room for him return an error.
  2098.      */
  2099.     if (tptouse == NULL)
  2100.         return 0;
  2101.     
  2102.     /*
  2103.      * Set up this structure for him.
  2104.      */
  2105.     tptouse->tr_settime = tptouse->tr_origtime = current_time;
  2106.     tptouse->tr_count = tptouse->tr_resets = 0;
  2107.     tptouse->tr_sequence = 1;
  2108.     tptouse->tr_addr = *raddr;
  2109.     tptouse->tr_localaddr = linter;
  2110.     tptouse->tr_version = version;
  2111.  
  2112.     tptouse->tr_flags = TRAP_INUSE;
  2113.     if (traptype == TRAP_TYPE_CONFIG)
  2114.         tptouse->tr_flags |= TRAP_CONFIGURED;
  2115.     else if (traptype == TRAP_TYPE_NONPRIO)
  2116.         tptouse->tr_flags |= TRAP_NONPRIO;
  2117.     num_ctl_traps++;
  2118.     return 1;
  2119. }
  2120.  
  2121.  
  2122. /*
  2123.  * ctlclrtrap - called to clr a trap
  2124.  */
  2125. int
  2126. ctlclrtrap(raddr, linter, traptype)
  2127.     struct sockaddr_in *raddr;
  2128.     struct interface *linter;
  2129.     int traptype;
  2130. {
  2131.     register struct ctl_trap *tp;
  2132.     struct ctl_trap *ctlfindtrap();
  2133.  
  2134.     if ((tp = ctlfindtrap(raddr, linter)) == NULL)
  2135.         return 0;
  2136.     
  2137.     if (tp->tr_flags & TRAP_CONFIGURED
  2138.         && traptype != TRAP_TYPE_CONFIG)
  2139.         return 0;
  2140.     
  2141.     tp->tr_flags = 0;
  2142.     num_ctl_traps--;
  2143.     return 1;
  2144. }
  2145.  
  2146.  
  2147. /*
  2148.  * ctlfindtrap - find a trap given the remote and local addresses
  2149.  */
  2150. struct ctl_trap *
  2151. ctlfindtrap(raddr, linter)
  2152.     struct sockaddr_in *raddr;
  2153.     struct interface *linter;
  2154. {
  2155.     register struct ctl_trap *tp;
  2156.  
  2157.     for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
  2158.         if (tp->tr_flags & TRAP_INUSE
  2159.             && NSRCADR(raddr) == NSRCADR(&tp->tr_addr)
  2160.             && NSRCPORT(raddr) == NSRCPORT(&tp->tr_addr)
  2161.             && linter == tp->tr_localaddr)
  2162.             return tp;
  2163.     }
  2164.     return (struct ctl_trap *)NULL;
  2165. }
  2166.  
  2167.  
  2168. /*
  2169.  * report_event - report an event to the trappers
  2170.  */
  2171. void
  2172. report_event(err, peer)
  2173.     int err;
  2174.     struct peer *peer;
  2175. {
  2176.     register int i;
  2177.     extern char *ntoa();
  2178.  
  2179.     /*
  2180.      * Record error code in proper spots, but have mercy on the
  2181.      * log file.
  2182.      */
  2183.     if (!(err & PEER_EVENT)) {
  2184.         if (ctl_sys_num_events < CTL_SYS_MAXEVENTS)
  2185.             ctl_sys_num_events++;
  2186.         if (ctl_sys_last_event != (u_char)err)
  2187.             syslog(LOG_INFO, "system event %x status %x",
  2188.             err, ctlsysstatus());
  2189.         ctl_sys_last_event = (u_char)err;
  2190.     } else if (peer != 0) {
  2191.         peer->last_event = (u_char)(err & ~PEER_EVENT);
  2192.         if (peer->num_events < CTL_PEER_MAXEVENTS)
  2193.             peer->num_events++;
  2194.         syslog(LOG_INFO, "peer %s event %x status %x",
  2195.             ntoa(&peer->srcadr), err, ctlpeerstatus(peer));
  2196.     } else {
  2197.         syslog(LOG_ERR, "report_event: err %x, no peer", err);
  2198.         return;
  2199.     }
  2200.  
  2201.     /*
  2202.      * If no trappers, return.
  2203.      */
  2204.     if (num_ctl_traps <= 0)
  2205.         return;
  2206.  
  2207.     /*
  2208.      * Set up the outgoing packet variables
  2209.      */
  2210.     res_opcode = CTL_OP_ASYNCMSG;
  2211.     res_offset = 0;
  2212.     res_async = 1;
  2213.     res_authenticate = 0;
  2214.     datapt = rpkt.data;
  2215.     dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
  2216.  
  2217.     if (!(err & PEER_EVENT)) {
  2218.         rpkt.associd = 0;
  2219.         rpkt.status = htons(ctlsysstatus());
  2220.  
  2221.         /*
  2222.          * For now, put everything we know about system
  2223.          * variables.  Maybe more selective later
  2224.          */
  2225.         for (i = 1; i <= CS_MAXCODE; i++)
  2226.             ctl_putsys(i);
  2227. #ifdef REFCLOCK
  2228.         /*
  2229.          * for clock exception events:
  2230.          *    add clock variables to reflect info on exception
  2231.          */
  2232.         if (err == EVNT_CLOCKEXCPT) {
  2233.                 struct refclockstat clock;
  2234.                 refclock_control(&peer->srcadr,
  2235.                      (struct refclockstat *)0,
  2236.                      &clock);
  2237.             ctl_puthex("refclockstatus",
  2238.                    ctlclkstatus(&clock));
  2239.             for (i = 1; i <= CC_MAXCODE; i++)
  2240.                         ctl_putclock(i, &clock, 0);
  2241.         }
  2242. #endif /*REFCLOCK*/
  2243.     } else {
  2244.         rpkt.associd = htons(peer->associd);
  2245.         rpkt.status = htons(ctlpeerstatus(peer));
  2246.  
  2247.         /*
  2248.          * Dump it all.  Later, maybe less.
  2249.          */
  2250.         for (i = 1; i <= CP_MAXCODE; i++)
  2251.             ctl_putpeer(i, peer);
  2252. #ifdef REFCLOCK
  2253.             /*
  2254.              * for clock exception events:
  2255.              *    add clock variables to reflect info on exception
  2256.              */
  2257.             if (err == EVNT_PEERCLOCK) {
  2258.                     struct refclockstat clock;
  2259.                  refclock_control(&peer->srcadr,
  2260.                          (struct refclockstat *)0,
  2261.                          &clock);
  2262.                 ctl_puthex("refclockstatus",
  2263.                        ctlclkstatus(&clock));
  2264.                 for (i = 1; i <= CC_MAXCODE; i++)
  2265.                          ctl_putclock(i, &clock, 0);
  2266.             }
  2267. #endif /*REFCLOCK*/
  2268.     }
  2269.  
  2270.     /*
  2271.      * We're done, return.
  2272.      */
  2273.     ctl_flushpkt(0);
  2274. }
  2275.  
  2276.  
  2277. /*
  2278.  * ctl_clr_stats - clear stat counters
  2279.  */
  2280. void
  2281. ctl_clr_stats()
  2282. {
  2283.     ctltimereset = current_time;
  2284.     numctlreq = 0;
  2285.     numctlbadpkts = 0;
  2286.     numctlresponses = 0;
  2287.     numctlfrags = 0;
  2288.     numctlerrors = 0;
  2289.     numctlfrags = 0;
  2290.     numctltooshort = 0;
  2291.     numctlinputresp = 0;
  2292.     numctlinputfrag = 0;
  2293.     numctlinputerr = 0;
  2294.     numctlbadoffset = 0;
  2295.     numctlbadversion = 0;
  2296.     numctldatatooshort = 0;
  2297.     numctlbadop = 0;
  2298.     numasyncmsgs = 0;
  2299. }
  2300.