4 * ntp_control.c - respond to control messages and send async traps
13 #include "ntp_refclock.h"
14 #include "ntp_control.h"
15 #include "ntp_unixtime.h"
16 #include "ntp_stdlib.h"
17 #include "ntp_config.h"
18 #include "ntp_assert.h"
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h>
28 #include <arpa/inet.h>
31 * Structure to hold request procedure information
35 short control_code
; /* defined request code */
36 #define NO_REQUEST (-1)
37 u_short flags
; /* flags word */
38 /* Only one flag. Authentication required or not. */
41 void (*handler
) (struct recvbuf
*, int); /* handle request */
46 * Request processing routines
48 static void ctl_error (int);
50 static u_short
ctlclkstatus (struct refclockstat
*);
52 static void ctl_flushpkt (int);
53 static void ctl_putdata (const char *, unsigned int, int);
54 static void ctl_putstr (const char *, const char *,
56 static void ctl_putdbl (const char *, double);
57 static void ctl_putuint (const char *, u_long
);
58 static void ctl_puthex (const char *, u_long
);
59 static void ctl_putint (const char *, long);
60 static void ctl_putts (const char *, l_fp
*);
61 static void ctl_putadr (const char *, u_int32
,
63 static void ctl_putid (const char *, char *);
64 static void ctl_putarray (const char *, double *, int);
65 static void ctl_putsys (int);
66 static void ctl_putpeer (int, struct peer
*);
67 static void ctl_putfs (const char *, tstamp_t
);
69 static void ctl_putclock (int, struct refclockstat
*, int);
71 static struct ctl_var
*ctl_getitem (struct ctl_var
*, char **);
72 static u_long
count_var (struct ctl_var
*);
73 static void control_unspec (struct recvbuf
*, int);
74 static void read_status (struct recvbuf
*, int);
75 static void read_variables (struct recvbuf
*, int);
76 static void write_variables (struct recvbuf
*, int);
77 static void read_clock_status (struct recvbuf
*, int);
78 static void write_clock_status (struct recvbuf
*, int);
79 static void set_trap (struct recvbuf
*, int);
80 static void unset_trap (struct recvbuf
*, int);
81 static void configure (struct recvbuf
*, int);
82 static void save_config (struct recvbuf
*, int);
83 static struct ctl_trap
*ctlfindtrap (sockaddr_u
*,
86 static struct ctl_proc control_codes
[] = {
87 { CTL_OP_UNSPEC
, NOAUTH
, control_unspec
},
88 { CTL_OP_READSTAT
, NOAUTH
, read_status
},
89 { CTL_OP_READVAR
, NOAUTH
, read_variables
},
90 { CTL_OP_WRITEVAR
, AUTH
, write_variables
},
91 { CTL_OP_READCLOCK
, NOAUTH
, read_clock_status
},
92 { CTL_OP_WRITECLOCK
, NOAUTH
, write_clock_status
},
93 { CTL_OP_SETTRAP
, NOAUTH
, set_trap
},
94 { CTL_OP_UNSETTRAP
, NOAUTH
, unset_trap
},
95 { CTL_OP_SAVECONFIG
, AUTH
, save_config
},
96 { CTL_OP_CONFIGURE
, AUTH
, configure
},
101 * System variable values. The array can be indexed by the variable
102 * index to find the textual name.
104 static struct ctl_var sys_var
[] = {
105 { 0, PADDING
, "" }, /* 0 */
106 { CS_LEAP
, RW
, "leap" }, /* 1 */
107 { CS_STRATUM
, RO
, "stratum" }, /* 2 */
108 { CS_PRECISION
, RO
, "precision" }, /* 3 */
109 { CS_ROOTDELAY
, RO
, "rootdelay" }, /* 4 */
110 { CS_ROOTDISPERSION
, RO
, "rootdisp" }, /* 5 */
111 { CS_REFID
, RO
, "refid" }, /* 6 */
112 { CS_REFTIME
, RO
, "reftime" }, /* 7 */
113 { CS_POLL
, RO
, "tc" }, /* 8 */
114 { CS_PEERID
, RO
, "peer" }, /* 9 */
115 { CS_OFFSET
, RO
, "offset" }, /* 10 */
116 { CS_DRIFT
, RO
, "frequency" }, /* 11 */
117 { CS_JITTER
, RO
, "sys_jitter" }, /* 12 */
118 { CS_ERROR
, RO
, "clk_jitter" }, /* 13 */
119 { CS_CLOCK
, RO
, "clock" }, /* 14 */
120 { CS_PROCESSOR
, RO
, "processor" }, /* 15 */
121 { CS_SYSTEM
, RO
, "system" }, /* 16 */
122 { CS_VERSION
, RO
, "version" }, /* 17 */
123 { CS_STABIL
, RO
, "clk_wander" }, /* 18 */
124 { CS_VARLIST
, RO
, "sys_var_list" }, /* 19 */
125 { CS_TAI
, RO
, "tai" }, /* 20 */
126 { CS_LEAPTAB
, RO
, "leapsec" }, /* 21 */
127 { CS_LEAPEND
, RO
, "expire" }, /* 22 */
128 { CS_RATE
, RO
, "mintc" }, /* 23 */
130 { CS_FLAGS
, RO
, "flags" }, /* 24 */
131 { CS_HOST
, RO
, "host" }, /* 25 */
132 { CS_PUBLIC
, RO
, "update" }, /* 26 */
133 { CS_CERTIF
, RO
, "cert" }, /* 27 */
134 { CS_SIGNATURE
, RO
, "signature" }, /* 28 */
135 { CS_REVTIME
, RO
, "until" }, /* 29 */
136 { CS_GROUP
, RO
, "group" }, /* 30 */
137 { CS_DIGEST
, RO
, "digest" }, /* 31 */
139 { 0, EOV
, "" } /* 24/3 2*/
142 static struct ctl_var
*ext_sys_var
= (struct ctl_var
*)0;
145 * System variables we print by default (in fuzzball order,
148 static u_char def_sys_var
[] = {
187 static struct ctl_var peer_var
[] = {
188 { 0, PADDING
, "" }, /* 0 */
189 { CP_CONFIG
, RO
, "config" }, /* 1 */
190 { CP_AUTHENABLE
, RO
, "authenable" }, /* 2 */
191 { CP_AUTHENTIC
, RO
, "authentic" }, /* 3 */
192 { CP_SRCADR
, RO
, "srcadr" }, /* 4 */
193 { CP_SRCPORT
, RO
, "srcport" }, /* 5 */
194 { CP_DSTADR
, RO
, "dstadr" }, /* 6 */
195 { CP_DSTPORT
, RO
, "dstport" }, /* 7 */
196 { CP_LEAP
, RO
, "leap" }, /* 8 */
197 { CP_HMODE
, RO
, "hmode" }, /* 9 */
198 { CP_STRATUM
, RO
, "stratum" }, /* 10 */
199 { CP_PPOLL
, RO
, "ppoll" }, /* 11 */
200 { CP_HPOLL
, RO
, "hpoll" }, /* 12 */
201 { CP_PRECISION
, RO
, "precision" }, /* 13 */
202 { CP_ROOTDELAY
, RO
, "rootdelay" }, /* 14 */
203 { CP_ROOTDISPERSION
, RO
, "rootdisp" }, /* 15 */
204 { CP_REFID
, RO
, "refid" }, /* 16 */
205 { CP_REFTIME
, RO
, "reftime" }, /* 17 */
206 { CP_ORG
, RO
, "org" }, /* 18 */
207 { CP_REC
, RO
, "rec" }, /* 19 */
208 { CP_XMT
, RO
, "xleave" }, /* 20 */
209 { CP_REACH
, RO
, "reach" }, /* 21 */
210 { CP_UNREACH
, RO
, "unreach" }, /* 22 */
211 { CP_TIMER
, RO
, "timer" }, /* 23 */
212 { CP_DELAY
, RO
, "delay" }, /* 24 */
213 { CP_OFFSET
, RO
, "offset" }, /* 25 */
214 { CP_JITTER
, RO
, "jitter" }, /* 26 */
215 { CP_DISPERSION
, RO
, "dispersion" }, /* 27 */
216 { CP_KEYID
, RO
, "keyid" }, /* 28 */
217 { CP_FILTDELAY
, RO
, "filtdelay=" }, /* 29 */
218 { CP_FILTOFFSET
, RO
, "filtoffset=" }, /* 30 */
219 { CP_PMODE
, RO
, "pmode" }, /* 31 */
220 { CP_RECEIVED
, RO
, "received"}, /* 32 */
221 { CP_SENT
, RO
, "sent" }, /* 33 */
222 { CP_FILTERROR
, RO
, "filtdisp=" }, /* 34 */
223 { CP_FLASH
, RO
, "flash" }, /* 35 */
224 { CP_TTL
, RO
, "ttl" }, /* 36 */
225 { CP_VARLIST
, RO
, "peer_var_list" }, /* 37 */
226 { CP_IN
, RO
, "in" }, /* 38 */
227 { CP_OUT
, RO
, "out" }, /* 39 */
228 { CP_RATE
, RO
, "headway" }, /* 40 */
229 { CP_BIAS
, RO
, "bias" }, /* 41 */
231 { CP_FLAGS
, RO
, "flags" }, /* 42 */
232 { CP_HOST
, RO
, "host" }, /* 43 */
233 { CP_VALID
, RO
, "valid" }, /* 44 */
234 { CP_INITSEQ
, RO
, "initsequence" }, /* 45 */
235 { CP_INITKEY
, RO
, "initkey" }, /* 46 */
236 { CP_INITTSP
, RO
, "timestamp" }, /* 47 */
237 { CP_SIGNATURE
, RO
, "signature" }, /* 48 */
239 { 0, EOV
, "" } /* 42/49 */
244 * Peer variables we print by default
246 static u_char def_peer_var
[] = {
293 * Clock variable list
295 static struct ctl_var clock_var
[] = {
296 { 0, PADDING
, "" }, /* 0 */
297 { CC_TYPE
, RO
, "type" }, /* 1 */
298 { CC_TIMECODE
, RO
, "timecode" }, /* 2 */
299 { CC_POLL
, RO
, "poll" }, /* 3 */
300 { CC_NOREPLY
, RO
, "noreply" }, /* 4 */
301 { CC_BADFORMAT
, RO
, "badformat" }, /* 5 */
302 { CC_BADDATA
, RO
, "baddata" }, /* 6 */
303 { CC_FUDGETIME1
, RO
, "fudgetime1" }, /* 7 */
304 { CC_FUDGETIME2
, RO
, "fudgetime2" }, /* 8 */
305 { CC_FUDGEVAL1
, RO
, "stratum" }, /* 9 */
306 { CC_FUDGEVAL2
, RO
, "refid" }, /* 10 */
307 { CC_FLAGS
, RO
, "flags" }, /* 11 */
308 { CC_DEVICE
, RO
, "device" }, /* 12 */
309 { CC_VARLIST
, RO
, "clock_var_list" }, /* 13 */
310 { 0, EOV
, "" } /* 14 */
315 * Clock variables printed by default
317 static u_char def_clock_var
[] = {
319 CC_TYPE
, /* won't be output if device = known */
336 * System and processor definitions.
340 # define STR_SYSTEM "UNIX"
342 # ifndef STR_PROCESSOR
343 # define STR_PROCESSOR "unknown"
346 static char str_system
[] = STR_SYSTEM
;
347 static char str_processor
[] = STR_PROCESSOR
;
349 # include <sys/utsname.h>
350 static struct utsname utsnamebuf
;
351 #endif /* HAVE_UNAME */
354 * Trap structures. We only allow a few of these, and send a copy of
355 * each async message to each live one. Traps time out after an hour, it
356 * is up to the trap receipient to keep resetting it to avoid being
360 struct ctl_trap ctl_trap
[CTL_MAXTRAPS
];
364 * Type bits, for ctlsettrap() call.
366 #define TRAP_TYPE_CONFIG 0 /* used by configuration code */
367 #define TRAP_TYPE_PRIO 1 /* priority trap */
368 #define TRAP_TYPE_NONPRIO 2 /* nonpriority trap */
372 * List relating reference clock types to control message time sources.
373 * Index by the reference clock type. This list will only be used iff
374 * the reference clock driver doesn't set peer->sstclktype to something
375 * different than CTL_SST_TS_UNSPEC.
377 static u_char clocktypes
[] = {
378 CTL_SST_TS_NTP
, /* REFCLK_NONE (0) */
379 CTL_SST_TS_LOCAL
, /* REFCLK_LOCALCLOCK (1) */
380 CTL_SST_TS_UHF
, /* deprecated REFCLK_GPS_TRAK (2) */
381 CTL_SST_TS_HF
, /* REFCLK_WWV_PST (3) */
382 CTL_SST_TS_LF
, /* REFCLK_WWVB_SPECTRACOM (4) */
383 CTL_SST_TS_UHF
, /* REFCLK_TRUETIME (5) */
384 CTL_SST_TS_UHF
, /* REFCLK_GOES_TRAK (6) IRIG_AUDIO? */
385 CTL_SST_TS_HF
, /* REFCLK_CHU (7) */
386 CTL_SST_TS_LF
, /* REFCLOCK_PARSE (default) (8) */
387 CTL_SST_TS_LF
, /* REFCLK_GPS_MX4200 (9) */
388 CTL_SST_TS_UHF
, /* REFCLK_GPS_AS2201 (10) */
389 CTL_SST_TS_UHF
, /* REFCLK_GPS_ARBITER (11) */
390 CTL_SST_TS_UHF
, /* REFCLK_IRIG_TPRO (12) */
391 CTL_SST_TS_ATOM
, /* REFCLK_ATOM_LEITCH (13) */
392 CTL_SST_TS_LF
, /* deprecated REFCLK_MSF_EES (14) */
393 CTL_SST_TS_NTP
, /* not used (15) */
394 CTL_SST_TS_UHF
, /* REFCLK_IRIG_BANCOMM (16) */
395 CTL_SST_TS_UHF
, /* REFCLK_GPS_DATU (17) */
396 CTL_SST_TS_TELEPHONE
, /* REFCLK_NIST_ACTS (18) */
397 CTL_SST_TS_HF
, /* REFCLK_WWV_HEATH (19) */
398 CTL_SST_TS_UHF
, /* REFCLK_GPS_NMEA (20) */
399 CTL_SST_TS_UHF
, /* REFCLK_GPS_VME (21) */
400 CTL_SST_TS_ATOM
, /* REFCLK_ATOM_PPS (22) */
401 CTL_SST_TS_NTP
, /* not used (23) */
402 CTL_SST_TS_NTP
, /* not used (24) */
403 CTL_SST_TS_NTP
, /* not used (25) */
404 CTL_SST_TS_UHF
, /* REFCLK_GPS_HP (26) */
405 CTL_SST_TS_TELEPHONE
, /* REFCLK_ARCRON_MSF (27) */
406 CTL_SST_TS_TELEPHONE
, /* REFCLK_SHM (28) */
407 CTL_SST_TS_UHF
, /* REFCLK_PALISADE (29) */
408 CTL_SST_TS_UHF
, /* REFCLK_ONCORE (30) */
409 CTL_SST_TS_UHF
, /* REFCLK_JUPITER (31) */
410 CTL_SST_TS_LF
, /* REFCLK_CHRONOLOG (32) */
411 CTL_SST_TS_LF
, /* REFCLK_DUMBCLOCK (33) */
412 CTL_SST_TS_LF
, /* REFCLK_ULINK (34) */
413 CTL_SST_TS_LF
, /* REFCLK_PCF (35) */
414 CTL_SST_TS_HF
, /* REFCLK_WWV (36) */
415 CTL_SST_TS_LF
, /* REFCLK_FG (37) */
416 CTL_SST_TS_UHF
, /* REFCLK_HOPF_SERIAL (38) */
417 CTL_SST_TS_UHF
, /* REFCLK_HOPF_PCI (39) */
418 CTL_SST_TS_LF
, /* REFCLK_JJY (40) */
419 CTL_SST_TS_UHF
, /* REFCLK_TT560 (41) */
420 CTL_SST_TS_UHF
, /* REFCLK_ZYFER (42) */
421 CTL_SST_TS_UHF
, /* REFCLK_RIPENCC (43) */
422 CTL_SST_TS_UHF
, /* REFCLK_NEOCLOCK4X (44) */
427 * Keyid used for authenticating write requests.
429 keyid_t ctl_auth_keyid
;
432 * We keep track of the last error reported by the system internally
434 static u_char ctl_sys_last_event
;
435 static u_char ctl_sys_num_events
;
439 * Statistic counters to keep track of requests and responses.
441 u_long ctltimereset
; /* time stats reset */
442 u_long numctlreq
; /* number of requests we've received */
443 u_long numctlbadpkts
; /* number of bad control packets */
444 u_long numctlresponses
; /* number of resp packets sent with data */
445 u_long numctlfrags
; /* number of fragments sent */
446 u_long numctlerrors
; /* number of error responses sent */
447 u_long numctltooshort
; /* number of too short input packets */
448 u_long numctlinputresp
; /* number of responses on input */
449 u_long numctlinputfrag
; /* number of fragments on input */
450 u_long numctlinputerr
; /* number of input pkts with err bit set */
451 u_long numctlbadoffset
; /* number of input pkts with nonzero offset */
452 u_long numctlbadversion
; /* number of input pkts with unknown version */
453 u_long numctldatatooshort
; /* data too short for count */
454 u_long numctlbadop
; /* bad op code found in packet */
455 u_long numasyncmsgs
; /* number of async messages we've sent */
458 * Response packet used by these routines. Also some state information
459 * so that we can handle packet formatting within a common set of
460 * subroutines. Note we try to enter data in place whenever possible,
461 * but the need to set the more bit correctly means we occasionally
462 * use the extra buffer and copy.
464 static struct ntp_control rpkt
;
465 static u_char res_version
;
466 static u_char res_opcode
;
467 static associd_t res_associd
;
468 static int res_offset
;
469 static u_char
* datapt
;
470 static u_char
* dataend
;
471 static int datalinelen
;
472 static int datanotbinflag
;
473 static sockaddr_u
*rmt_addr
;
474 static struct interface
*lcl_inter
;
476 static u_char res_authenticate
;
477 static u_char res_authokay
;
478 static keyid_t res_keyid
;
480 #define MAXDATALINELEN (72)
482 static u_char res_async
; /* set to 1 if this is async trap response */
485 * Pointers for saving state when decoding request packets
491 * init_control - initialize request data
500 #endif /* HAVE_UNAME */
505 ctl_sys_last_event
= EVNT_UNSPEC
;
506 ctl_sys_num_events
= 0;
509 for (i
= 0; i
< CTL_MAXTRAPS
; i
++)
510 ctl_trap
[i
].tr_flags
= 0;
515 * ctl_error - send an error response for the current request
522 DPRINTF(3, ("sending control error %d\n", errcode
));
525 * Fill in the fields. We assume rpkt.sequence and rpkt.associd
526 * have already been filled in.
528 rpkt
.r_m_e_op
= (u_char
) (CTL_RESPONSE
|CTL_ERROR
|(res_opcode
&
530 rpkt
.status
= htons((u_short
) ((errcode
<<8) & 0xff00));
534 * send packet and bump counters
536 if (res_authenticate
&& sys_authenticate
) {
539 *(u_int32
*)((u_char
*)&rpkt
+ CTL_HEADER_LEN
) =
541 maclen
= authencrypt(res_keyid
, (u_int32
*)&rpkt
,
543 sendpkt(rmt_addr
, lcl_inter
, -2, (struct pkt
*)&rpkt
,
544 CTL_HEADER_LEN
+ maclen
);
546 sendpkt(rmt_addr
, lcl_inter
, -3, (struct pkt
*)&rpkt
,
553 * save_config - Implements ntpq -c "saveconfig <filename>"
554 * Writes current configuration including any runtime
555 * changes by ntpq's :config or config-from-file
559 struct recvbuf
*rbufp
,
568 const char savedconfig_eq
[] = "savedconfig=";
569 char savedconfig
[sizeof(savedconfig_eq
) + sizeof(filename
)];
575 if (restrict_mask
& RES_NOMODIFY
) {
576 snprintf(reply
, sizeof(reply
),
577 "saveconfig prohibited by restrict ... nomodify");
578 ctl_putdata(reply
, strlen(reply
), 0);
581 "saveconfig from %s rejected due to nomodify restriction",
582 stoa(&rbufp
->recv_srcadr
));
587 if (NULL
== saveconfigdir
) {
588 snprintf(reply
, sizeof(reply
),
589 "saveconfig prohibited, no saveconfigdir configured");
590 ctl_putdata(reply
, strlen(reply
), 0);
593 "saveconfig from %s rejected, no saveconfigdir",
594 stoa(&rbufp
->recv_srcadr
));
598 if (0 == reqend
- reqpt
)
601 strncpy(filespec
, reqpt
, sizeof(filespec
));
602 filespec
[sizeof(filespec
) - 1] = '\0';
607 * allow timestamping of the saved config filename with
608 * strftime() format such as:
609 * ntpq -c "saveconfig ntp-%Y%m%d-%H%M%S.conf"
611 if (0 == strftime(filename
, sizeof(filename
), filespec
,
613 strncpy(filename
, filespec
, sizeof(filename
));
615 filename
[sizeof(filename
) - 1] = '\0';
617 if (strchr(filename
, '\\') || strchr(filename
, '/')) {
618 snprintf(reply
, sizeof(reply
),
619 "saveconfig does not allow directory in filename");
620 ctl_putdata(reply
, strlen(reply
), 0);
623 "saveconfig with path from %s rejected",
624 stoa(&rbufp
->recv_srcadr
));
628 snprintf(fullpath
, sizeof(fullpath
), "%s%s",
629 saveconfigdir
, filename
);
631 fd
= open(fullpath
, O_CREAT
| O_TRUNC
| O_WRONLY
,
636 fptr
= fdopen(fd
, "w");
638 if (NULL
== fptr
|| -1 == dump_all_config_trees(fptr
, 1)) {
639 snprintf(reply
, sizeof(reply
),
640 "Unable to save configuration to file %s",
643 "saveconfig %s from %s failed", filename
,
644 stoa(&rbufp
->recv_srcadr
));
646 snprintf(reply
, sizeof(reply
),
647 "Configuration saved to %s", filename
);
649 "Configuration saved to %s (requested by %s)",
650 fullpath
, stoa(&rbufp
->recv_srcadr
));
652 * save the output filename in system variable
653 * savedconfig, retrieved with:
654 * ntpq -c "rv 0 savedconfig"
656 snprintf(savedconfig
, sizeof(savedconfig
), "%s%s",
657 savedconfig_eq
, filename
);
658 set_sys_var(savedconfig
, strlen(savedconfig
) + 1, RO
);
663 #else /* !SAVECONFIG follows */
664 snprintf(reply
, sizeof(reply
),
665 "saveconfig unavailable, configured with --disable-saveconfig");
668 ctl_putdata(reply
, strlen(reply
), 0);
674 * process_control - process an incoming control message
678 struct recvbuf
*rbufp
,
682 register struct ntp_control
*pkt
;
683 register int req_count
;
684 register int req_data
;
685 register struct ctl_proc
*cc
;
689 DPRINTF(3, ("in process_control()\n"));
692 * Save the addresses for error responses
695 rmt_addr
= &rbufp
->recv_srcadr
;
696 lcl_inter
= rbufp
->dstadr
;
697 pkt
= (struct ntp_control
*)&rbufp
->recv_pkt
;
700 * If the length is less than required for the header, or
701 * it is a response or a fragment, ignore this.
703 if (rbufp
->recv_length
< CTL_HEADER_LEN
704 || pkt
->r_m_e_op
& (CTL_RESPONSE
|CTL_MORE
|CTL_ERROR
)
705 || pkt
->offset
!= 0) {
706 DPRINTF(1, ("invalid format in control packet\n"));
707 if (rbufp
->recv_length
< CTL_HEADER_LEN
)
709 if (pkt
->r_m_e_op
& CTL_RESPONSE
)
711 if (pkt
->r_m_e_op
& CTL_MORE
)
713 if (pkt
->r_m_e_op
& CTL_ERROR
)
715 if (pkt
->offset
!= 0)
719 res_version
= PKT_VERSION(pkt
->li_vn_mode
);
720 if (res_version
> NTP_VERSION
|| res_version
< NTP_OLDVERSION
) {
721 DPRINTF(1, ("unknown version %d in control packet\n",
728 * Pull enough data from the packet to make intelligent
731 rpkt
.li_vn_mode
= PKT_LI_VN_MODE(sys_leap
, res_version
,
733 res_opcode
= pkt
->r_m_e_op
;
734 rpkt
.sequence
= pkt
->sequence
;
735 rpkt
.associd
= pkt
->associd
;
738 res_associd
= htons(pkt
->associd
);
740 res_authenticate
= 0;
743 req_count
= (int)ntohs(pkt
->count
);
747 dataend
= &(rpkt
.data
[CTL_MAX_DATA_LEN
]);
749 if ((rbufp
->recv_length
& 0x3) != 0)
750 DPRINTF(3, ("Control packet length %d unrounded\n",
751 rbufp
->recv_length
));
754 * We're set up now. Make sure we've got at least enough
755 * incoming data space to match the count.
757 req_data
= rbufp
->recv_length
- CTL_HEADER_LEN
;
758 if (req_data
< req_count
|| rbufp
->recv_length
& 0x3) {
759 ctl_error(CERR_BADFMT
);
760 numctldatatooshort
++;
764 properlen
= req_count
+ CTL_HEADER_LEN
;
765 /* round up proper len to a 8 octet boundary */
767 properlen
= (properlen
+ 7) & ~7;
768 maclen
= rbufp
->recv_length
- properlen
;
769 if ((rbufp
->recv_length
& 3) == 0 &&
770 maclen
>= MIN_MAC_LEN
&& maclen
<= MAX_MAC_LEN
&&
772 res_authenticate
= 1;
773 res_keyid
= ntohl(*(u_int32
*)((u_char
*)pkt
+
776 DPRINTF(3, ("recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n",
777 rbufp
->recv_length
, properlen
, res_keyid
,
780 if (!authistrusted(res_keyid
))
781 DPRINTF(3, ("invalid keyid %08x\n", res_keyid
));
782 else if (authdecrypt(res_keyid
, (u_int32
*)pkt
,
783 rbufp
->recv_length
- maclen
,
785 DPRINTF(3, ("authenticated okay\n"));
788 DPRINTF(3, ("authentication failed\n"));
794 * Set up translate pointers
796 reqpt
= (char *)pkt
->data
;
797 reqend
= reqpt
+ req_count
;
800 * Look for the opcode processor
802 for (cc
= control_codes
; cc
->control_code
!= NO_REQUEST
; cc
++) {
803 if (cc
->control_code
== res_opcode
) {
804 DPRINTF(3, ("opcode %d, found command handler\n",
806 if (cc
->flags
== AUTH
808 || res_keyid
!= ctl_auth_keyid
)) {
809 ctl_error(CERR_PERMISSION
);
812 (cc
->handler
)(rbufp
, restrict_mask
);
818 * Can't find this one, return an error.
821 ctl_error(CERR_BADOP
);
827 * ctlpeerstatus - return a status word for this peer
831 register struct peer
*peer
836 status
= peer
->status
;
837 if (!(peer
->flags
& FLAG_PREEMPT
))
838 status
|= CTL_PST_CONFIG
;
839 if (peer
->keyid
!= 0)
840 status
|= CTL_PST_AUTHENABLE
;
841 if (peer
->flags
& FLAG_AUTHENTIC
)
842 status
|= CTL_PST_AUTHENTIC
;
843 if (peer
->reach
!= 0)
844 status
|= CTL_PST_REACH
;
845 if (peer
->cast_flags
& (MDF_BCAST
| MDF_MCAST
| MDF_ACAST
))
846 status
|= CTL_PST_BCAST
;
847 return (u_short
)CTL_PEER_STATUS(status
, peer
->num_events
,
853 * ctlclkstatus - return a status word for this clock
858 struct refclockstat
*this_clock
861 return (u_short
)CTL_PEER_STATUS(0, this_clock
->lastevent
,
862 this_clock
->currentstatus
);
868 * ctlsysstatus - return the system status word
873 register u_char this_clock
;
875 this_clock
= CTL_SST_TS_UNSPEC
;
878 if (sys_peer
->sstclktype
!= CTL_SST_TS_UNSPEC
) {
879 this_clock
= sys_peer
->sstclktype
;
881 if (sys_peer
->refclktype
< sizeof(clocktypes
))
883 clocktypes
[sys_peer
->refclktype
];
888 this_clock
= CTL_SST_TS_NTP
;
889 #endif /* REFCLOCK */
890 return (u_short
)CTL_SYS_STATUS(sys_leap
, this_clock
,
891 ctl_sys_num_events
, ctl_sys_last_event
);
896 * ctl_flushpkt - write out the current packet and prepare
897 * another if necessary.
907 if (!more
&& datanotbinflag
) {
909 * Big hack, output a trailing \r\n
914 dlen
= datapt
- (u_char
*)rpkt
.data
;
915 sendlen
= dlen
+ CTL_HEADER_LEN
;
918 * Pad to a multiple of 32 bits
920 while (sendlen
& 0x3) {
926 * Fill in the packet with the current info
928 rpkt
.r_m_e_op
= (u_char
)(CTL_RESPONSE
|more
|(res_opcode
&
930 rpkt
.count
= htons((u_short
) dlen
);
931 rpkt
.offset
= htons( (u_short
) res_offset
);
935 for (i
= 0; i
< CTL_MAXTRAPS
; i
++) {
936 if (ctl_trap
[i
].tr_flags
& TRAP_INUSE
) {
938 PKT_LI_VN_MODE(sys_leap
,
939 ctl_trap
[i
].tr_version
,
942 htons(ctl_trap
[i
].tr_sequence
);
943 sendpkt(&ctl_trap
[i
].tr_addr
,
944 ctl_trap
[i
].tr_localaddr
, -4,
945 (struct pkt
*)&rpkt
, sendlen
);
947 ctl_trap
[i
].tr_sequence
++;
952 if (res_authenticate
&& sys_authenticate
) {
954 int totlen
= sendlen
;
955 keyid_t keyid
= htonl(res_keyid
);
958 * If we are going to authenticate, then there
959 * is an additional requirement that the MAC
960 * begin on a 64 bit boundary.
966 memcpy(datapt
, &keyid
, sizeof keyid
);
967 maclen
= authencrypt(res_keyid
,
968 (u_int32
*)&rpkt
, totlen
);
969 sendpkt(rmt_addr
, lcl_inter
, -5,
970 (struct pkt
*)&rpkt
, totlen
+ maclen
);
972 sendpkt(rmt_addr
, lcl_inter
, -6,
973 (struct pkt
*)&rpkt
, sendlen
);
982 * Set us up for another go around.
985 datapt
= (u_char
*)rpkt
.data
;
990 * ctl_putdata - write data into the packet, fragmenting and starting
991 * another if this one is full.
997 int bin
/* set to 1 when data is binary */
1006 if (datapt
!= rpkt
.data
) {
1009 if ((dlen
+ datalinelen
+ 1) >= MAXDATALINELEN
)
1022 * Save room for trailing junk
1024 if (dlen
+ overhead
+ datapt
> dataend
) {
1026 * Not enough room in this one, flush it out.
1028 ctl_flushpkt(CTL_MORE
);
1030 memmove((char *)datapt
, dp
, (unsigned)dlen
);
1032 datalinelen
+= dlen
;
1037 * ctl_putstr - write a tagged string into the response packet
1047 register const char *cq
;
1057 if (len
> (int) (sizeof(buffer
) - (cp
- buffer
) - 1))
1058 len
= sizeof(buffer
) - (cp
- buffer
) - 1;
1059 memmove(cp
, data
, (unsigned)len
);
1063 ctl_putdata(buffer
, (unsigned)( cp
- buffer
), 0);
1068 * ctl_putdbl - write a tagged, signed double into the response packet
1077 register const char *cq
;
1085 (void)sprintf(cp
, "%.3f", ts
);
1088 ctl_putdata(buffer
, (unsigned)(cp
- buffer
), 0);
1092 * ctl_putuint - write a tagged unsigned integer into the response
1101 register const char *cq
;
1110 (void) sprintf(cp
, "%lu", uval
);
1113 ctl_putdata(buffer
, (unsigned)( cp
- buffer
), 0);
1117 * ctl_putfs - write a decoded filestamp into the response
1126 register const char *cq
;
1128 struct tm
*tm
= NULL
;
1137 fstamp
= uval
- JAN_1970
;
1138 tm
= gmtime(&fstamp
);
1142 sprintf(cp
, "%04d%02d%02d%02d%02d", tm
->tm_year
+ 1900,
1143 tm
->tm_mon
+ 1, tm
->tm_mday
, tm
->tm_hour
, tm
->tm_min
);
1146 ctl_putdata(buffer
, (unsigned)( cp
- buffer
), 0);
1151 * ctl_puthex - write a tagged unsigned integer, in hex, into the
1161 register const char *cq
;
1170 (void) sprintf(cp
, "0x%lx", uval
);
1173 ctl_putdata(buffer
,(unsigned)( cp
- buffer
), 0);
1178 * ctl_putint - write a tagged signed integer into the response
1187 register const char *cq
;
1196 (void) sprintf(cp
, "%ld", ival
);
1199 ctl_putdata(buffer
, (unsigned)( cp
- buffer
), 0);
1204 * ctl_putts - write a tagged timestamp, in hex, into the response
1213 register const char *cq
;
1222 (void) sprintf(cp
, "0x%08lx.%08lx", ts
->l_ui
& 0xffffffffUL
,
1223 ts
->l_uf
& 0xffffffffUL
);
1226 ctl_putdata(buffer
, (unsigned)( cp
- buffer
), 0);
1231 * ctl_putadr - write an IP address into the response
1241 register const char *cq
;
1251 cq
= numtoa(addr32
);
1256 ctl_putdata(buffer
, (unsigned)(cp
- buffer
), 0);
1260 * ctl_putid - write a tagged clock ID into the response
1269 register const char *cq
;
1279 while (*cq
!= '\0' && (cq
- id
) < 4)
1281 ctl_putdata(buffer
, (unsigned)( cp
- buffer
), 0);
1286 * ctl_putarray - write a tagged eight element double array into the response
1296 register const char *cq
;
1308 (void)sprintf(cp
, " %.2f", arr
[i
] * 1e3
);
1311 } while(i
!= start
);
1312 ctl_putdata(buffer
, (unsigned)(cp
- buffer
), 0);
1317 * ctl_putsys - output a system variable
1327 struct cert_info
*cp
;
1329 #endif /* OPENSSL */
1334 ctl_putuint(sys_var
[CS_LEAP
].text
, sys_leap
);
1338 ctl_putuint(sys_var
[CS_STRATUM
].text
, sys_stratum
);
1342 ctl_putint(sys_var
[CS_PRECISION
].text
, sys_precision
);
1346 ctl_putdbl(sys_var
[CS_ROOTDELAY
].text
, sys_rootdelay
*
1350 case CS_ROOTDISPERSION
:
1351 ctl_putdbl(sys_var
[CS_ROOTDISPERSION
].text
,
1352 sys_rootdisp
* 1e3
);
1356 if (sys_stratum
> 1 && sys_stratum
< STRATUM_UNSPEC
)
1357 ctl_putadr(sys_var
[CS_REFID
].text
, sys_refid
, NULL
);
1359 ctl_putid(sys_var
[CS_REFID
].text
,
1360 (char *)&sys_refid
);
1364 ctl_putts(sys_var
[CS_REFTIME
].text
, &sys_reftime
);
1368 ctl_putuint(sys_var
[CS_POLL
].text
, sys_poll
);
1372 if (sys_peer
== NULL
)
1373 ctl_putuint(sys_var
[CS_PEERID
].text
, 0);
1375 ctl_putuint(sys_var
[CS_PEERID
].text
,
1380 ctl_putdbl(sys_var
[CS_OFFSET
].text
, last_offset
* 1e3
);
1384 ctl_putdbl(sys_var
[CS_DRIFT
].text
, drift_comp
* 1e6
);
1388 ctl_putdbl(sys_var
[CS_JITTER
].text
, sys_jitter
* 1e3
);
1392 ctl_putdbl(sys_var
[CS_ERROR
].text
, clock_jitter
* 1e3
);
1397 ctl_putts(sys_var
[CS_CLOCK
].text
, &tmp
);
1402 ctl_putstr(sys_var
[CS_PROCESSOR
].text
, str_processor
,
1403 sizeof(str_processor
) - 1);
1405 ctl_putstr(sys_var
[CS_PROCESSOR
].text
,
1406 utsnamebuf
.machine
, strlen(utsnamebuf
.machine
));
1407 #endif /* HAVE_UNAME */
1412 ctl_putstr(sys_var
[CS_SYSTEM
].text
, str_system
,
1413 sizeof(str_system
) - 1);
1415 sprintf(str
, "%s/%s", utsnamebuf
.sysname
, utsnamebuf
.release
);
1416 ctl_putstr(sys_var
[CS_SYSTEM
].text
, str
, strlen(str
));
1417 #endif /* HAVE_UNAME */
1421 ctl_putstr(sys_var
[CS_VERSION
].text
, Version
,
1426 ctl_putdbl(sys_var
[CS_STABIL
].text
, clock_stability
*
1432 char buf
[CTL_MAX_DATA_LEN
];
1433 register char *s
, *t
, *be
;
1434 register const char *ss
;
1436 register struct ctl_var
*k
;
1439 be
= buf
+ sizeof(buf
);
1440 if (s
+ strlen(sys_var
[CS_VARLIST
].text
) + 4 > be
)
1441 break; /* really long var name */
1443 snprintf(s
, sizeof(buf
), "%s=\"",
1444 sys_var
[CS_VARLIST
].text
);
1447 for (k
= sys_var
; !(k
->flags
& EOV
); k
++) {
1448 if (k
->flags
& PADDING
)
1450 i
= strlen(k
->text
);
1456 memcpy(s
, k
->text
, i
);
1460 for (k
= ext_sys_var
; k
&& !(k
->flags
& EOV
);
1462 if (k
->flags
& PADDING
)
1469 while (*ss
&& *ss
!= '=')
1472 if (s
+ i
+ 1 >= be
)
1487 ctl_putdata(buf
, (unsigned)( s
- buf
),
1494 ctl_putuint(sys_var
[CS_TAI
].text
, sys_tai
);
1499 ctl_putfs(sys_var
[CS_LEAPTAB
].text
,
1504 if (leap_expire
> 0)
1505 ctl_putfs(sys_var
[CS_LEAPEND
].text
,
1510 ctl_putuint(sys_var
[CS_RATE
].text
, ntp_minpoll
);
1516 ctl_puthex(sys_var
[CS_FLAGS
].text
,
1522 strcpy(str
, OBJ_nid2ln(crypto_nid
));
1523 ctl_putstr(sys_var
[CS_DIGEST
].text
, str
,
1532 dp
= EVP_get_digestbynid(crypto_flags
>> 16);
1533 strcpy(str
, OBJ_nid2ln(EVP_MD_pkey_type(dp
)));
1534 ctl_putstr(sys_var
[CS_SIGNATURE
].text
, str
,
1540 if (sys_hostname
!= NULL
)
1541 ctl_putstr(sys_var
[CS_HOST
].text
, sys_hostname
,
1542 strlen(sys_hostname
));
1546 if (sys_groupname
!= NULL
)
1547 ctl_putstr(sys_var
[CS_GROUP
].text
, sys_groupname
,
1548 strlen(sys_groupname
));
1552 for (cp
= cinfo
; cp
!= NULL
; cp
= cp
->link
) {
1553 snprintf(cbuf
, sizeof(cbuf
), "%s %s 0x%x",
1554 cp
->subject
, cp
->issuer
, cp
->flags
);
1555 ctl_putstr(sys_var
[CS_CERTIF
].text
, cbuf
,
1557 ctl_putfs(sys_var
[CS_REVTIME
].text
, cp
->last
);
1562 if (hostval
.tstamp
!= 0)
1563 ctl_putfs(sys_var
[CS_PUBLIC
].text
,
1564 ntohl(hostval
.tstamp
));
1566 #endif /* OPENSSL */
1572 * ctl_putpeer - output a peer variable
1584 #endif /* OPENSSL */
1589 ctl_putuint(peer_var
[CP_CONFIG
].text
,
1590 (unsigned)((peer
->flags
& FLAG_PREEMPT
) == 0));
1594 ctl_putuint(peer_var
[CP_AUTHENABLE
].text
,
1595 (unsigned)(peer
->keyid
!= 0));
1599 ctl_putuint(peer_var
[CP_AUTHENTIC
].text
,
1600 (unsigned)((peer
->flags
& FLAG_AUTHENTIC
) != 0));
1604 ctl_putadr(peer_var
[CP_SRCADR
].text
, 0,
1609 ctl_putuint(peer_var
[CP_SRCPORT
].text
,
1610 ntohs(((struct sockaddr_in
*)&peer
->srcadr
)->sin_port
));
1615 ctl_putadr(peer_var
[CP_DSTADR
].text
, 0,
1616 &(peer
->dstadr
->sin
));
1618 ctl_putadr(peer_var
[CP_DSTADR
].text
, 0,
1624 ctl_putuint(peer_var
[CP_DSTPORT
].text
,
1625 (u_long
)(peer
->dstadr
?
1626 ntohs(((struct sockaddr_in
*)&peer
->dstadr
->sin
)->sin_port
) : 0));
1631 ctl_putdbl(peer_var
[CP_IN
].text
,
1637 ctl_putdbl(peer_var
[CP_OUT
].text
,
1642 ctl_putuint(peer_var
[CP_RATE
].text
, peer
->throttle
);
1646 ctl_putuint(peer_var
[CP_LEAP
].text
, peer
->leap
);
1650 ctl_putuint(peer_var
[CP_HMODE
].text
, peer
->hmode
);
1654 ctl_putuint(peer_var
[CP_STRATUM
].text
, peer
->stratum
);
1658 ctl_putuint(peer_var
[CP_PPOLL
].text
, peer
->ppoll
);
1662 ctl_putuint(peer_var
[CP_HPOLL
].text
, peer
->hpoll
);
1666 ctl_putint(peer_var
[CP_PRECISION
].text
,
1671 ctl_putdbl(peer_var
[CP_ROOTDELAY
].text
,
1672 peer
->rootdelay
* 1e3
);
1675 case CP_ROOTDISPERSION
:
1676 ctl_putdbl(peer_var
[CP_ROOTDISPERSION
].text
,
1677 peer
->rootdisp
* 1e3
);
1681 if (peer
->flags
& FLAG_REFCLOCK
) {
1682 ctl_putid(peer_var
[CP_REFID
].text
,
1683 (char *)&peer
->refid
);
1685 if (peer
->stratum
> 1 && peer
->stratum
<
1687 ctl_putadr(peer_var
[CP_REFID
].text
,
1690 ctl_putid(peer_var
[CP_REFID
].text
,
1691 (char *)&peer
->refid
);
1696 ctl_putts(peer_var
[CP_REFTIME
].text
, &peer
->reftime
);
1700 ctl_putts(peer_var
[CP_ORG
].text
, &peer
->aorg
);
1704 ctl_putts(peer_var
[CP_REC
].text
, &peer
->dst
);
1708 if (peer
->xleave
!= 0)
1709 ctl_putdbl(peer_var
[CP_XMT
].text
, peer
->xleave
*
1714 if (peer
->bias
!= 0)
1715 ctl_putdbl(peer_var
[CP_BIAS
].text
, peer
->bias
*
1720 ctl_puthex(peer_var
[CP_REACH
].text
, peer
->reach
);
1725 ctl_puthex(peer_var
[CP_FLASH
].text
, temp
);
1730 ctl_putint(peer_var
[CP_TTL
].text
,
1731 sys_ttl
[peer
->ttl
]);
1735 ctl_putuint(peer_var
[CP_UNREACH
].text
, peer
->unreach
);
1739 ctl_putuint(peer_var
[CP_TIMER
].text
,
1740 peer
->nextdate
- current_time
);
1744 ctl_putdbl(peer_var
[CP_DELAY
].text
, peer
->delay
* 1e3
);
1748 ctl_putdbl(peer_var
[CP_OFFSET
].text
, peer
->offset
*
1753 ctl_putdbl(peer_var
[CP_JITTER
].text
, peer
->jitter
*
1758 ctl_putdbl(peer_var
[CP_DISPERSION
].text
, peer
->disp
*
1763 if (peer
->keyid
> NTP_MAXKEY
)
1764 ctl_puthex(peer_var
[CP_KEYID
].text
,
1767 ctl_putuint(peer_var
[CP_KEYID
].text
,
1772 ctl_putarray(peer_var
[CP_FILTDELAY
].text
,
1773 peer
->filter_delay
, (int)peer
->filter_nextpt
);
1777 ctl_putarray(peer_var
[CP_FILTOFFSET
].text
,
1778 peer
->filter_offset
, (int)peer
->filter_nextpt
);
1782 ctl_putarray(peer_var
[CP_FILTERROR
].text
,
1783 peer
->filter_disp
, (int)peer
->filter_nextpt
);
1787 ctl_putuint(peer_var
[CP_PMODE
].text
, peer
->pmode
);
1791 ctl_putuint(peer_var
[CP_RECEIVED
].text
, peer
->received
);
1795 ctl_putuint(peer_var
[CP_SENT
].text
, peer
->sent
);
1800 char buf
[CTL_MAX_DATA_LEN
];
1801 register char *s
, *t
, *be
;
1803 register struct ctl_var
*k
;
1806 be
= buf
+ sizeof(buf
);
1807 if (s
+ strlen(peer_var
[CP_VARLIST
].text
) + 4 > be
)
1808 break; /* really long var name */
1810 snprintf(s
, sizeof(buf
), "%s=\"",
1811 peer_var
[CP_VARLIST
].text
);
1814 for (k
= peer_var
; !(k
->flags
& EOV
); k
++) {
1815 if (k
->flags
& PADDING
)
1818 i
= strlen(k
->text
);
1819 if (s
+ i
+ 1 >= be
)
1824 memcpy(s
, k
->text
, i
);
1832 ctl_putdata(buf
, (unsigned)(s
- buf
), 0);
1838 ctl_puthex(peer_var
[CP_FLAGS
].text
, peer
->crypto
);
1845 dp
= EVP_get_digestbynid(peer
->crypto
>> 16);
1846 strcpy(str
, OBJ_nid2ln(EVP_MD_pkey_type(dp
)));
1847 ctl_putstr(peer_var
[CP_SIGNATURE
].text
, str
,
1853 if (peer
->subject
!= NULL
)
1854 ctl_putstr(peer_var
[CP_HOST
].text
,
1855 peer
->subject
, strlen(peer
->subject
));
1858 case CP_VALID
: /* not used */
1862 if ((ap
= (struct autokey
*)peer
->recval
.ptr
) == NULL
)
1865 ctl_putint(peer_var
[CP_INITSEQ
].text
, ap
->seq
);
1866 ctl_puthex(peer_var
[CP_INITKEY
].text
, ap
->key
);
1867 ctl_putfs(peer_var
[CP_INITTSP
].text
,
1868 ntohl(peer
->recval
.tstamp
));
1870 #endif /* OPENSSL */
1877 * ctl_putclock - output clock variables
1882 struct refclockstat
*clock_stat
,
1889 if (mustput
|| clock_stat
->clockdesc
== NULL
1890 || *(clock_stat
->clockdesc
) == '\0') {
1891 ctl_putuint(clock_var
[CC_TYPE
].text
, clock_stat
->type
);
1895 ctl_putstr(clock_var
[CC_TIMECODE
].text
,
1896 clock_stat
->p_lastcode
,
1897 (unsigned)clock_stat
->lencode
);
1901 ctl_putuint(clock_var
[CC_POLL
].text
, clock_stat
->polls
);
1905 ctl_putuint(clock_var
[CC_NOREPLY
].text
,
1906 clock_stat
->noresponse
);
1910 ctl_putuint(clock_var
[CC_BADFORMAT
].text
,
1911 clock_stat
->badformat
);
1915 ctl_putuint(clock_var
[CC_BADDATA
].text
,
1916 clock_stat
->baddata
);
1920 if (mustput
|| (clock_stat
->haveflags
& CLK_HAVETIME1
))
1921 ctl_putdbl(clock_var
[CC_FUDGETIME1
].text
,
1922 clock_stat
->fudgetime1
* 1e3
);
1926 if (mustput
|| (clock_stat
->haveflags
& CLK_HAVETIME2
)) ctl_putdbl(clock_var
[CC_FUDGETIME2
].text
,
1927 clock_stat
->fudgetime2
* 1e3
);
1931 if (mustput
|| (clock_stat
->haveflags
& CLK_HAVEVAL1
))
1932 ctl_putint(clock_var
[CC_FUDGEVAL1
].text
,
1933 clock_stat
->fudgeval1
);
1937 if (mustput
|| (clock_stat
->haveflags
& CLK_HAVEVAL2
)) {
1938 if (clock_stat
->fudgeval1
> 1)
1939 ctl_putadr(clock_var
[CC_FUDGEVAL2
].text
,
1940 (u_int32
)clock_stat
->fudgeval2
, NULL
);
1942 ctl_putid(clock_var
[CC_FUDGEVAL2
].text
,
1943 (char *)&clock_stat
->fudgeval2
);
1948 if (mustput
|| (clock_stat
->haveflags
& (CLK_HAVEFLAG1
|
1949 CLK_HAVEFLAG2
| CLK_HAVEFLAG3
| CLK_HAVEFLAG4
)))
1950 ctl_putuint(clock_var
[CC_FLAGS
].text
,
1955 if (clock_stat
->clockdesc
== NULL
||
1956 *(clock_stat
->clockdesc
) == '\0') {
1958 ctl_putstr(clock_var
[CC_DEVICE
].text
,
1961 ctl_putstr(clock_var
[CC_DEVICE
].text
,
1962 clock_stat
->clockdesc
,
1963 strlen(clock_stat
->clockdesc
));
1969 char buf
[CTL_MAX_DATA_LEN
];
1970 register char *s
, *t
, *be
;
1971 register const char *ss
;
1973 register struct ctl_var
*k
;
1976 be
= buf
+ sizeof(buf
);
1977 if (s
+ strlen(clock_var
[CC_VARLIST
].text
) + 4 >
1979 break; /* really long var name */
1981 snprintf(s
, sizeof(buf
), "%s=\"",
1982 clock_var
[CC_VARLIST
].text
);
1986 for (k
= clock_var
; !(k
->flags
& EOV
); k
++) {
1987 if (k
->flags
& PADDING
)
1990 i
= strlen(k
->text
);
1991 if (s
+ i
+ 1 >= be
)
1996 memcpy(s
, k
->text
, i
);
2000 for (k
= clock_stat
->kv_list
; k
&& !(k
->flags
&
2002 if (k
->flags
& PADDING
)
2009 while (*ss
&& *ss
!= '=')
2017 memcpy(s
, k
->text
, (unsigned)i
);
2026 ctl_putdata(buf
, (unsigned)( s
- buf
), 0);
2036 * ctl_getitem - get the next data item from the incoming packet
2038 static struct ctl_var
*
2040 struct ctl_var
*var_list
,
2044 register struct ctl_var
*v
;
2047 static struct ctl_var eol
= { 0, EOV
, };
2048 static char buf
[128];
2051 * Delete leading commas and white space
2053 while (reqpt
< reqend
&& (*reqpt
== ',' ||
2054 isspace((unsigned char)*reqpt
)))
2056 if (reqpt
>= reqend
)
2059 if (var_list
== (struct ctl_var
*)0)
2063 * Look for a first character match on the tag. If we find
2064 * one, see if it is a full match.
2068 while (!(v
->flags
& EOV
)) {
2069 if (!(v
->flags
& PADDING
) && *cp
== *(v
->text
)) {
2071 while (*tp
!= '\0' && *tp
!= '=' && cp
<
2072 reqend
&& *cp
== *tp
) {
2076 if ((*tp
== '\0') || (*tp
== '=')) {
2077 while (cp
< reqend
&& isspace((unsigned char)*cp
))
2079 if (cp
== reqend
|| *cp
== ',') {
2090 while (cp
< reqend
&& isspace((unsigned char)*cp
))
2092 while (cp
< reqend
&& *cp
!= ',') {
2094 if (tp
>= buf
+ sizeof(buf
)) {
2095 ctl_error(CERR_BADFMT
);
2097 #if 0 /* Avoid possible DOS attack */
2098 /* If we get a smarter msyslog we can re-enable this */
2099 msyslog(LOG_WARNING
,
2100 "Possible 'ntpdx' exploit from %s:%d (possibly spoofed)\n",
2101 stoa(rmt_addr
), SRCPORT(rmt_addr
)
2111 if (!isspace((unsigned int)(*tp
)))
2129 * control_unspec - response to an unspecified op-code
2134 struct recvbuf
*rbufp
,
2141 * What is an appropriate response to an unspecified op-code?
2142 * I return no errors and no data, unless a specified assocation
2145 if (res_associd
!= 0) {
2146 if ((peer
= findpeerbyassoc(res_associd
)) == 0) {
2147 ctl_error(CERR_BADASSOC
);
2150 rpkt
.status
= htons(ctlpeerstatus(peer
));
2152 rpkt
.status
= htons(ctlsysstatus());
2159 * read_status - return either a list of associd's, or a particular
2165 struct recvbuf
*rbufp
,
2170 register struct peer
*peer
;
2171 u_short ass_stat
[CTL_MAX_DATA_LEN
/ sizeof(u_short
)];
2175 printf("read_status: ID %d\n", res_associd
);
2178 * Two choices here. If the specified association ID is
2179 * zero we return all known assocation ID's. Otherwise
2180 * we return a bunch of stuff about the particular peer.
2182 if (res_associd
== 0) {
2186 rpkt
.status
= htons(ctlsysstatus());
2187 for (i
= 0; i
< NTP_HASH_SIZE
; i
++) {
2188 for (peer
= assoc_hash
[i
]; peer
!= 0;
2189 peer
= peer
->ass_next
) {
2190 ass_stat
[n
++] = htons(peer
->associd
);
2192 htons(ctlpeerstatus(peer
));
2194 CTL_MAX_DATA_LEN
/sizeof(u_short
)) {
2195 ctl_putdata((char *)ass_stat
,
2196 n
* sizeof(u_short
), 1);
2203 ctl_putdata((char *)ass_stat
, n
*
2204 sizeof(u_short
), 1);
2207 peer
= findpeerbyassoc(res_associd
);
2209 ctl_error(CERR_BADASSOC
);
2211 register u_char
*cp
;
2213 rpkt
.status
= htons(ctlpeerstatus(peer
));
2215 peer
->num_events
= 0;
2217 * For now, output everything we know about the
2218 * peer. May be more selective later.
2220 for (cp
= def_peer_var
; *cp
!= 0; cp
++)
2221 ctl_putpeer((int)*cp
, peer
);
2229 * read_variables - return the variables the caller asks for
2234 struct recvbuf
*rbufp
,
2238 register struct ctl_var
*v
;
2242 unsigned int gotvar
= (CS_MAXCODE
> CP_MAXCODE
) ? (CS_MAXCODE
+
2243 1) : (CP_MAXCODE
+ 1);
2244 if (res_associd
== 0) {
2246 * Wants system variables. Figure out which he wants
2247 * and give them to him.
2249 rpkt
.status
= htons(ctlsysstatus());
2251 ctl_sys_num_events
= 0;
2252 gotvar
+= count_var(ext_sys_var
);
2253 wants
= (u_char
*)emalloc(gotvar
);
2254 memset((char *)wants
, 0, gotvar
);
2256 while ((v
= ctl_getitem(sys_var
, &valuep
)) != 0) {
2257 if (v
->flags
& EOV
) {
2258 if ((v
= ctl_getitem(ext_sys_var
,
2260 if (v
->flags
& EOV
) {
2261 ctl_error(CERR_UNKNOWNVAR
);
2262 free((char *)wants
);
2265 wants
[CS_MAXCODE
+ 1 +
2270 break; /* shouldn't happen ! */
2277 for (i
= 1; i
<= CS_MAXCODE
; i
++)
2280 for (i
= 0; ext_sys_var
&&
2281 !(ext_sys_var
[i
].flags
& EOV
); i
++)
2282 if (wants
[i
+ CS_MAXCODE
+ 1])
2283 ctl_putdata(ext_sys_var
[i
].text
,
2284 strlen(ext_sys_var
[i
].text
),
2287 register u_char
*cs
;
2288 register struct ctl_var
*kv
;
2290 for (cs
= def_sys_var
; *cs
!= 0; cs
++)
2291 ctl_putsys((int)*cs
);
2292 for (kv
= ext_sys_var
; kv
&& !(kv
->flags
& EOV
);
2294 if (kv
->flags
& DEF
)
2295 ctl_putdata(kv
->text
,
2296 strlen(kv
->text
), 0);
2298 free((char *)wants
);
2300 register struct peer
*peer
;
2303 * Wants info for a particular peer. See if we know
2306 peer
= findpeerbyassoc(res_associd
);
2308 ctl_error(CERR_BADASSOC
);
2311 rpkt
.status
= htons(ctlpeerstatus(peer
));
2313 peer
->num_events
= 0;
2314 wants
= (u_char
*)emalloc(gotvar
);
2315 memset((char*)wants
, 0, gotvar
);
2317 while ((v
= ctl_getitem(peer_var
, &valuep
)) != 0) {
2318 if (v
->flags
& EOV
) {
2319 ctl_error(CERR_UNKNOWNVAR
);
2320 free((char *)wants
);
2327 for (i
= 1; i
<= CP_MAXCODE
; i
++)
2329 ctl_putpeer(i
, peer
);
2331 register u_char
*cp
;
2333 for (cp
= def_peer_var
; *cp
!= 0; cp
++)
2334 ctl_putpeer((int)*cp
, peer
);
2336 free((char *)wants
);
2343 * write_variables - write into variables. We only allow leap bit
2349 struct recvbuf
*rbufp
,
2353 register struct ctl_var
*v
;
2354 register int ext_var
;
2359 * If he's trying to write into a peer tell him no way
2361 if (res_associd
!= 0) {
2362 ctl_error(CERR_PERMISSION
);
2369 rpkt
.status
= htons(ctlsysstatus());
2372 * Look through the variables. Dump out at the first sign of
2375 while ((v
= ctl_getitem(sys_var
, &valuep
)) != 0) {
2377 if (v
->flags
& EOV
) {
2378 if ((v
= ctl_getitem(ext_sys_var
, &valuep
)) !=
2380 if (v
->flags
& EOV
) {
2381 ctl_error(CERR_UNKNOWNVAR
);
2389 if (!(v
->flags
& CAN_WRITE
)) {
2390 ctl_error(CERR_PERMISSION
);
2393 if (!ext_var
&& (*valuep
== '\0' || !atoint(valuep
,
2395 ctl_error(CERR_BADFMT
);
2398 if (!ext_var
&& (val
& ~LEAP_NOTINSYNC
) != 0) {
2399 ctl_error(CERR_BADVALUE
);
2404 char *s
= (char *)emalloc(strlen(v
->text
) +
2405 strlen(valuep
) + 2);
2410 while (*t
&& *t
!= '=')
2415 set_sys_var(s
, strlen(s
)+1, v
->flags
);
2419 * This one seems sane. Save it.
2425 ctl_error(CERR_UNSPEC
); /* really */
2432 * If we got anything, do it. xxx nothing to do ***
2435 if (leapind != ~0 || leapwarn != ~0) {
2436 if (!leap_setleap((int)leapind, (int)leapwarn)) {
2437 ctl_error(CERR_PERMISSION);
2446 * configure() processes ntpq :config/config-from-file, allowing
2447 * generic runtime reconfiguration.
2449 static void configure(
2450 struct recvbuf
*rbufp
,
2454 int data_count
, retval
, replace_nl
;
2456 /* I haven't yet implemented changes to an existing association.
2457 * Hence check if the association id is 0
2459 if (res_associd
!= 0) {
2460 ctl_error(CERR_BADVALUE
);
2464 if (restrict_mask
& RES_NOMODIFY
) {
2465 snprintf(remote_config
.err_msg
,
2466 sizeof(remote_config
.err_msg
),
2467 "runtime configuration prohibited by restrict ... nomodify");
2468 ctl_putdata(remote_config
.err_msg
,
2469 strlen(remote_config
.err_msg
), 0);
2472 "runtime config from %s rejected due to nomodify restriction",
2473 stoa(&rbufp
->recv_srcadr
));
2477 /* Initialize the remote config buffer */
2478 data_count
= reqend
- reqpt
;
2479 memcpy(remote_config
.buffer
, reqpt
, data_count
);
2481 && '\n' != remote_config
.buffer
[data_count
- 1])
2482 remote_config
.buffer
[data_count
++] = '\n';
2483 remote_config
.buffer
[data_count
] = '\0';
2484 remote_config
.pos
= 0;
2485 remote_config
.err_pos
= 0;
2486 remote_config
.no_errors
= 0;
2488 /* do not include terminating newline in log */
2490 && '\n' == remote_config
.buffer
[data_count
- 1]) {
2491 remote_config
.buffer
[data_count
- 1] = '\0';
2496 DPRINTF(1, ("Got Remote Configuration Command: %s\n",
2497 remote_config
.buffer
));
2498 msyslog(LOG_NOTICE
, "%s config: %s",
2499 stoa(&rbufp
->recv_srcadr
),
2500 remote_config
.buffer
);
2503 remote_config
.buffer
[data_count
- 1] = '\n';
2505 config_remotely(&rbufp
->recv_srcadr
);
2508 * Check if errors were reported. If not, output 'Config
2509 * Succeeded'. Else output the error count. It would be nice
2510 * to output any parser error messages.
2512 if (0 == remote_config
.no_errors
) {
2513 retval
= snprintf(remote_config
.err_msg
,
2514 sizeof(remote_config
.err_msg
),
2515 "Config Succeeded");
2517 remote_config
.err_pos
+= retval
;
2520 ctl_putdata(remote_config
.err_msg
, remote_config
.err_pos
, 0);
2523 DPRINTF(1, ("Reply: %s\n", remote_config
.err_msg
));
2525 if (remote_config
.no_errors
> 0)
2526 msyslog(LOG_NOTICE
, "%d error in %s config",
2527 remote_config
.no_errors
,
2528 stoa(&rbufp
->recv_srcadr
));
2533 * read_clock_status - return clock radio status
2538 struct recvbuf
*rbufp
,
2544 * If no refclock support, no data to return
2546 ctl_error(CERR_BADASSOC
);
2548 register struct ctl_var
*v
;
2550 register struct peer
*peer
;
2553 unsigned int gotvar
;
2554 struct refclockstat clock_stat
;
2556 if (res_associd
== 0) {
2559 * Find a clock for this jerk. If the system peer
2560 * is a clock use it, else search the hash tables
2563 if (sys_peer
!= 0 && (sys_peer
->flags
& FLAG_REFCLOCK
))
2568 for (i
= 0; peer
== 0 && i
< NTP_HASH_SIZE
; i
++) {
2569 for (peer
= assoc_hash
[i
]; peer
!= 0;
2570 peer
= peer
->ass_next
) {
2571 if (peer
->flags
& FLAG_REFCLOCK
)
2576 ctl_error(CERR_BADASSOC
);
2581 peer
= findpeerbyassoc(res_associd
);
2582 if (peer
== 0 || !(peer
->flags
& FLAG_REFCLOCK
)) {
2583 ctl_error(CERR_BADASSOC
);
2589 * If we got here we have a peer which is a clock. Get his
2592 clock_stat
.kv_list
= (struct ctl_var
*)0;
2593 refclock_control(&peer
->srcadr
, (struct refclockstat
*)0,
2597 * Look for variables in the packet.
2599 rpkt
.status
= htons(ctlclkstatus(&clock_stat
));
2600 gotvar
= CC_MAXCODE
+ 1 + count_var(clock_stat
.kv_list
);
2601 wants
= (u_char
*)emalloc(gotvar
);
2602 memset((char*)wants
, 0, gotvar
);
2604 while ((v
= ctl_getitem(clock_var
, &valuep
)) != 0) {
2605 if (v
->flags
& EOV
) {
2606 if ((v
= ctl_getitem(clock_stat
.kv_list
,
2608 if (v
->flags
& EOV
) {
2609 ctl_error(CERR_UNKNOWNVAR
);
2611 free_varlist(clock_stat
.kv_list
);
2614 wants
[CC_MAXCODE
+ 1 + v
->code
] = 1;
2618 break; /* shouldn't happen ! */
2626 for (i
= 1; i
<= CC_MAXCODE
; i
++)
2628 ctl_putclock(i
, &clock_stat
, 1);
2629 for (i
= 0; clock_stat
.kv_list
&&
2630 !(clock_stat
.kv_list
[i
].flags
& EOV
); i
++)
2631 if (wants
[i
+ CC_MAXCODE
+ 1])
2632 ctl_putdata(clock_stat
.kv_list
[i
].text
,
2633 strlen(clock_stat
.kv_list
[i
].text
),
2636 register u_char
*cc
;
2637 register struct ctl_var
*kv
;
2639 for (cc
= def_clock_var
; *cc
!= 0; cc
++)
2640 ctl_putclock((int)*cc
, &clock_stat
, 0);
2641 for (kv
= clock_stat
.kv_list
; kv
&& !(kv
->flags
& EOV
);
2643 if (kv
->flags
& DEF
)
2644 ctl_putdata(kv
->text
, strlen(kv
->text
),
2649 free_varlist(clock_stat
.kv_list
);
2657 * write_clock_status - we don't do this
2662 struct recvbuf
*rbufp
,
2666 ctl_error(CERR_PERMISSION
);
2670 * Trap support from here on down. We send async trap messages when the
2671 * upper levels report trouble. Traps can by set either by control
2672 * messages or by configuration.
2675 * set_trap - set a trap in response to a control message
2679 struct recvbuf
*rbufp
,
2686 * See if this guy is allowed
2688 if (restrict_mask
& RES_NOTRAP
) {
2689 ctl_error(CERR_PERMISSION
);
2694 * Determine his allowed trap type.
2696 traptype
= TRAP_TYPE_PRIO
;
2697 if (restrict_mask
& RES_LPTRAP
)
2698 traptype
= TRAP_TYPE_NONPRIO
;
2701 * Call ctlsettrap() to do the work. Return
2702 * an error if it can't assign the trap.
2704 if (!ctlsettrap(&rbufp
->recv_srcadr
, rbufp
->dstadr
, traptype
,
2706 ctl_error(CERR_NORESOURCE
);
2712 * unset_trap - unset a trap in response to a control message
2716 struct recvbuf
*rbufp
,
2723 * We don't prevent anyone from removing his own trap unless the
2724 * trap is configured. Note we also must be aware of the
2725 * possibility that restriction flags were changed since this
2726 * guy last set his trap. Set the trap type based on this.
2728 traptype
= TRAP_TYPE_PRIO
;
2729 if (restrict_mask
& RES_LPTRAP
)
2730 traptype
= TRAP_TYPE_NONPRIO
;
2733 * Call ctlclrtrap() to clear this out.
2735 if (!ctlclrtrap(&rbufp
->recv_srcadr
, rbufp
->dstadr
, traptype
))
2736 ctl_error(CERR_BADASSOC
);
2742 * ctlsettrap - called to set a trap
2747 struct interface
*linter
,
2752 register struct ctl_trap
*tp
;
2753 register struct ctl_trap
*tptouse
;
2756 * See if we can find this trap. If so, we only need update
2757 * the flags and the time.
2759 if ((tp
= ctlfindtrap(raddr
, linter
)) != NULL
) {
2762 case TRAP_TYPE_CONFIG
:
2763 tp
->tr_flags
= TRAP_INUSE
|TRAP_CONFIGURED
;
2766 case TRAP_TYPE_PRIO
:
2767 if (tp
->tr_flags
& TRAP_CONFIGURED
)
2768 return (1); /* don't change anything */
2769 tp
->tr_flags
= TRAP_INUSE
;
2772 case TRAP_TYPE_NONPRIO
:
2773 if (tp
->tr_flags
& TRAP_CONFIGURED
)
2774 return (1); /* don't change anything */
2775 tp
->tr_flags
= TRAP_INUSE
|TRAP_NONPRIO
;
2778 tp
->tr_settime
= current_time
;
2784 * First we heard of this guy. Try to find a trap structure
2785 * for him to use, clearing out lesser priority guys if we
2786 * have to. Clear out anyone who's expired while we're at it.
2789 for (tp
= ctl_trap
; tp
< &ctl_trap
[CTL_MAXTRAPS
]; tp
++) {
2790 if ((tp
->tr_flags
& TRAP_INUSE
) &&
2791 !(tp
->tr_flags
& TRAP_CONFIGURED
) &&
2792 ((tp
->tr_settime
+ CTL_TRAPTIME
) > current_time
)) {
2796 if (!(tp
->tr_flags
& TRAP_INUSE
)) {
2798 } else if (!(tp
->tr_flags
& TRAP_CONFIGURED
)) {
2801 case TRAP_TYPE_CONFIG
:
2802 if (tptouse
== NULL
) {
2806 if (tptouse
->tr_flags
& TRAP_NONPRIO
&&
2807 !(tp
->tr_flags
& TRAP_NONPRIO
))
2810 if (!(tptouse
->tr_flags
& TRAP_NONPRIO
)
2811 && tp
->tr_flags
& TRAP_NONPRIO
) {
2815 if (tptouse
->tr_origtime
<
2820 case TRAP_TYPE_PRIO
:
2821 if (tp
->tr_flags
& TRAP_NONPRIO
) {
2822 if (tptouse
== NULL
||
2823 (tptouse
->tr_flags
&
2825 tptouse
->tr_origtime
<
2831 case TRAP_TYPE_NONPRIO
:
2838 * If we don't have room for him return an error.
2840 if (tptouse
== NULL
)
2844 * Set up this structure for him.
2846 tptouse
->tr_settime
= tptouse
->tr_origtime
= current_time
;
2847 tptouse
->tr_count
= tptouse
->tr_resets
= 0;
2848 tptouse
->tr_sequence
= 1;
2849 tptouse
->tr_addr
= *raddr
;
2850 tptouse
->tr_localaddr
= linter
;
2851 tptouse
->tr_version
= (u_char
) version
;
2852 tptouse
->tr_flags
= TRAP_INUSE
;
2853 if (traptype
== TRAP_TYPE_CONFIG
)
2854 tptouse
->tr_flags
|= TRAP_CONFIGURED
;
2855 else if (traptype
== TRAP_TYPE_NONPRIO
)
2856 tptouse
->tr_flags
|= TRAP_NONPRIO
;
2863 * ctlclrtrap - called to clear a trap
2868 struct interface
*linter
,
2872 register struct ctl_trap
*tp
;
2874 if ((tp
= ctlfindtrap(raddr
, linter
)) == NULL
)
2877 if (tp
->tr_flags
& TRAP_CONFIGURED
2878 && traptype
!= TRAP_TYPE_CONFIG
)
2888 * ctlfindtrap - find a trap given the remote and local addresses
2890 static struct ctl_trap
*
2893 struct interface
*linter
2896 register struct ctl_trap
*tp
;
2898 for (tp
= ctl_trap
; tp
< &ctl_trap
[CTL_MAXTRAPS
]; tp
++) {
2899 if ((tp
->tr_flags
& TRAP_INUSE
)
2900 && (NSRCPORT(raddr
) == NSRCPORT(&tp
->tr_addr
))
2901 && SOCK_EQ(raddr
, &tp
->tr_addr
)
2902 && (linter
== tp
->tr_localaddr
) )
2905 return (struct ctl_trap
*)NULL
;
2910 * report_event - report an event to the trappers
2914 int err
, /* error code */
2915 struct peer
*peer
, /* peer structure pointer */
2916 const char *str
/* protostats string */
2919 char statstr
[NTP_MAXSTRLEN
];
2924 * Report the error to the protostats file, system log and
2930 * Discard a system report if the number of reports of
2931 * the same type exceeds the maximum.
2933 if (ctl_sys_last_event
!= (u_char
)err
)
2934 ctl_sys_num_events
= 0;
2935 if (ctl_sys_num_events
>= CTL_SYS_MAXEVENTS
)
2938 ctl_sys_last_event
= (u_char
)err
;
2939 ctl_sys_num_events
++;
2940 snprintf(statstr
, NTP_MAXSTRLEN
,
2941 "0.0.0.0 %04x %02x %s",
2942 ctlsysstatus(), err
, eventstr(err
));
2944 len
= strlen(statstr
);
2945 snprintf(statstr
+ len
, sizeof(statstr
) - len
,
2949 msyslog(LOG_INFO
, statstr
);
2953 * Discard a peer report if the number of reports of
2954 * the same type exceeds the maximum for that peer.
2959 errlast
= (u_char
)err
& ~PEER_EVENT
;
2960 if (peer
->last_event
== errlast
)
2961 peer
->num_events
= 0;
2962 if (peer
->num_events
>= CTL_PEER_MAXEVENTS
)
2965 peer
->last_event
= errlast
;
2967 if (ISREFCLOCKADR(&peer
->srcadr
))
2968 src
= refnumtoa(&peer
->srcadr
);
2970 src
= stoa(&peer
->srcadr
);
2972 snprintf(statstr
, NTP_MAXSTRLEN
,
2973 "%s %04x %02x %s", src
,
2974 ctlpeerstatus(peer
), err
, eventstr(err
));
2976 len
= strlen(statstr
);
2977 snprintf(statstr
+ len
, sizeof(statstr
) - len
,
2980 NLOG(NLOG_PEEREVENT
)
2981 msyslog(LOG_INFO
, statstr
);
2983 record_proto_stats(statstr
);
2986 printf("event at %lu %s\n", current_time
, statstr
);
2990 * If no trappers, return.
2992 if (num_ctl_traps
<= 0)
2996 * Set up the outgoing packet variables
2998 res_opcode
= CTL_OP_ASYNCMSG
;
3001 res_authenticate
= 0;
3003 dataend
= &(rpkt
.data
[CTL_MAX_DATA_LEN
]);
3004 if (!(err
& PEER_EVENT
)) {
3006 rpkt
.status
= htons(ctlsysstatus());
3009 * For now, put everything we know about system
3010 * variables. Don't send crypto strings.
3012 for (i
= 1; i
<= CS_MAXCODE
; i
++) {
3016 #endif /* OPENSSL */
3020 NTP_INSIST(peer
!= NULL
);
3021 rpkt
.associd
= htons(peer
->associd
);
3022 rpkt
.status
= htons(ctlpeerstatus(peer
));
3025 * Dump it all. Later, maybe less.
3027 for (i
= 1; i
<= CP_MAXCODE
; i
++) {
3031 #endif /* OPENSSL */
3032 ctl_putpeer(i
, peer
);
3036 * for clock exception events: add clock variables to
3037 * reflect info on exception
3039 if (err
== PEVNT_CLOCK
) {
3040 struct refclockstat clock_stat
;
3043 clock_stat
.kv_list
= (struct ctl_var
*)0;
3044 refclock_control(&peer
->srcadr
,
3045 (struct refclockstat
*)0, &clock_stat
);
3047 ctl_puthex("refclockstatus",
3048 ctlclkstatus(&clock_stat
));
3050 for (i
= 1; i
<= CC_MAXCODE
; i
++)
3051 ctl_putclock(i
, &clock_stat
, 0);
3052 for (kv
= clock_stat
.kv_list
; kv
&&
3053 !(kv
->flags
& EOV
); kv
++)
3054 if (kv
->flags
& DEF
)
3055 ctl_putdata(kv
->text
,
3056 strlen(kv
->text
), 0);
3057 free_varlist(clock_stat
.kv_list
);
3059 #endif /* REFCLOCK */
3063 * We're done, return.
3070 * ctl_clr_stats - clear stat counters
3075 ctltimereset
= current_time
;
3078 numctlresponses
= 0;
3083 numctlinputresp
= 0;
3084 numctlinputfrag
= 0;
3086 numctlbadoffset
= 0;
3087 numctlbadversion
= 0;
3088 numctldatatooshort
= 0;
3104 while (!(k
++->flags
& EOV
))
3111 struct ctl_var
**kv
,
3117 register struct ctl_var
*k
;
3122 *kv
= (struct ctl_var
*)emalloc((c
+2)*sizeof(struct ctl_var
));
3124 memmove((char *)*kv
, (char *)k
,
3125 sizeof(struct ctl_var
)*c
);
3128 (*kv
)[c
].code
= (u_short
) c
;
3129 (*kv
)[c
].text
= (char *)emalloc(size
);
3130 (*kv
)[c
].flags
= def
;
3131 (*kv
)[c
+1].code
= 0;
3132 (*kv
)[c
+1].text
= (char *)0;
3133 (*kv
)[c
+1].flags
= EOV
;
3134 return (char *)(*kv
)[c
].text
;
3139 struct ctl_var
**kv
,
3145 register struct ctl_var
*k
;
3146 register const char *s
;
3147 register const char *t
;
3155 while (!(k
->flags
& EOV
)) {
3159 while (*t
!= '=' && *s
- *t
== 0) {
3163 if (*s
== *t
&& ((*t
== '=') || !*t
)) {
3164 free((void *)k
->text
);
3165 td
= (char *)emalloc(size
);
3166 memmove(td
, data
, size
);
3172 td
= (char *)emalloc(size
);
3173 memmove(td
, data
, size
);
3181 td
= add_var(kv
, size
, def
);
3182 memmove(td
, data
, size
);
3192 set_var(&ext_sys_var
, data
, size
, def
);
3202 for (k
= kv
; !(k
->flags
& EOV
); k
++)
3203 free((void *)k
->text
);