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