xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntp_request.c (revision 9e9fa66ad400fe02341b89216c5270e23a212d33)
1*9e9fa66aSchristos /*	$NetBSD: ntp_request.c,v 1.20 2024/10/01 20:59:51 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * ntp_request.c - respond to information requests
5abb0f93cSkardel  */
6abb0f93cSkardel 
7abb0f93cSkardel #ifdef HAVE_CONFIG_H
8abb0f93cSkardel # include <config.h>
9abb0f93cSkardel #endif
10abb0f93cSkardel 
11abb0f93cSkardel #include "ntpd.h"
12abb0f93cSkardel #include "ntp_io.h"
13abb0f93cSkardel #include "ntp_request.h"
14abb0f93cSkardel #include "ntp_control.h"
15abb0f93cSkardel #include "ntp_refclock.h"
16abb0f93cSkardel #include "ntp_if.h"
17abb0f93cSkardel #include "ntp_stdlib.h"
18abb0f93cSkardel #include "ntp_assert.h"
19abb0f93cSkardel 
20abb0f93cSkardel #include <stdio.h>
21abb0f93cSkardel #include <stddef.h>
22abb0f93cSkardel #include <signal.h>
23abb0f93cSkardel #ifdef HAVE_NETINET_IN_H
24abb0f93cSkardel #include <netinet/in.h>
25abb0f93cSkardel #endif
26abb0f93cSkardel #include <arpa/inet.h>
27abb0f93cSkardel 
28abb0f93cSkardel #include "recvbuff.h"
29abb0f93cSkardel 
30abb0f93cSkardel #ifdef KERNEL_PLL
31abb0f93cSkardel #include "ntp_syscall.h"
32abb0f93cSkardel #endif /* KERNEL_PLL */
33abb0f93cSkardel 
34abb0f93cSkardel /*
35abb0f93cSkardel  * Structure to hold request procedure information
36abb0f93cSkardel  */
37abb0f93cSkardel #define	NOAUTH	0
38abb0f93cSkardel #define	AUTH	1
39abb0f93cSkardel 
40abb0f93cSkardel #define	NO_REQUEST	(-1)
41abb0f93cSkardel /*
42abb0f93cSkardel  * Because we now have v6 addresses in the messages, we need to compensate
43abb0f93cSkardel  * for the larger size.  Therefore, we introduce the alternate size to
44abb0f93cSkardel  * keep us friendly with older implementations.  A little ugly.
45abb0f93cSkardel  */
46abb0f93cSkardel static int client_v6_capable = 0;   /* the client can handle longer messages */
47abb0f93cSkardel 
48abb0f93cSkardel #define v6sizeof(type)	(client_v6_capable ? sizeof(type) : v4sizeof(type))
49abb0f93cSkardel 
50abb0f93cSkardel struct req_proc {
51abb0f93cSkardel 	short request_code;	/* defined request code */
52abb0f93cSkardel 	short needs_auth;	/* true when authentication needed */
53abb0f93cSkardel 	short sizeofitem;	/* size of request data item (older size)*/
54abb0f93cSkardel 	short v6_sizeofitem;	/* size of request data item (new size)*/
552950cc38Schristos 	void (*handler) (sockaddr_u *, endpt *,
56abb0f93cSkardel 			   struct req_pkt *);	/* routine to handle request */
57abb0f93cSkardel };
58abb0f93cSkardel 
59abb0f93cSkardel /*
60abb0f93cSkardel  * Universal request codes
61abb0f93cSkardel  */
622950cc38Schristos static const struct req_proc univ_codes[] = {
63e19314b7Schristos 	{ NO_REQUEST,		NOAUTH,	 0,	0, NULL }
64abb0f93cSkardel };
65abb0f93cSkardel 
662950cc38Schristos static	void	req_ack	(sockaddr_u *, endpt *, struct req_pkt *, int);
672950cc38Schristos static	void *	prepare_pkt	(sockaddr_u *, endpt *,
68abb0f93cSkardel 				 struct req_pkt *, size_t);
692950cc38Schristos static	void *	more_pkt	(void);
70abb0f93cSkardel static	void	flush_pkt	(void);
712950cc38Schristos static	void	list_peers	(sockaddr_u *, endpt *, struct req_pkt *);
722950cc38Schristos static	void	list_peers_sum	(sockaddr_u *, endpt *, struct req_pkt *);
732950cc38Schristos static	void	peer_info	(sockaddr_u *, endpt *, struct req_pkt *);
742950cc38Schristos static	void	peer_stats	(sockaddr_u *, endpt *, struct req_pkt *);
752950cc38Schristos static	void	sys_info	(sockaddr_u *, endpt *, struct req_pkt *);
762950cc38Schristos static	void	sys_stats	(sockaddr_u *, endpt *, struct req_pkt *);
772950cc38Schristos static	void	mem_stats	(sockaddr_u *, endpt *, struct req_pkt *);
782950cc38Schristos static	void	io_stats	(sockaddr_u *, endpt *, struct req_pkt *);
792950cc38Schristos static	void	timer_stats	(sockaddr_u *, endpt *, struct req_pkt *);
802950cc38Schristos static	void	loop_info	(sockaddr_u *, endpt *, struct req_pkt *);
812950cc38Schristos static	void	do_conf		(sockaddr_u *, endpt *, struct req_pkt *);
822950cc38Schristos static	void	do_unconf	(sockaddr_u *, endpt *, struct req_pkt *);
832950cc38Schristos static	void	set_sys_flag	(sockaddr_u *, endpt *, struct req_pkt *);
842950cc38Schristos static	void	clr_sys_flag	(sockaddr_u *, endpt *, struct req_pkt *);
852950cc38Schristos static	void	setclr_flags	(sockaddr_u *, endpt *, struct req_pkt *, u_long);
86*9e9fa66aSchristos static	void	list_restrict4	(const struct restrict_4 *, struct info_restrict **);
87*9e9fa66aSchristos static	void	list_restrict6	(const struct restrict_6 *, struct info_restrict **);
882950cc38Schristos static	void	list_restrict	(sockaddr_u *, endpt *, struct req_pkt *);
892950cc38Schristos static	void	do_resaddflags	(sockaddr_u *, endpt *, struct req_pkt *);
902950cc38Schristos static	void	do_ressubflags	(sockaddr_u *, endpt *, struct req_pkt *);
912950cc38Schristos static	void	do_unrestrict	(sockaddr_u *, endpt *, struct req_pkt *);
924eea345dSchristos static	void	do_restrict	(sockaddr_u *, endpt *, struct req_pkt *, restrict_op);
932950cc38Schristos static	void	mon_getlist	(sockaddr_u *, endpt *, struct req_pkt *);
942950cc38Schristos static	void	reset_stats	(sockaddr_u *, endpt *, struct req_pkt *);
952950cc38Schristos static	void	reset_peer	(sockaddr_u *, endpt *, struct req_pkt *);
962950cc38Schristos static	void	do_key_reread	(sockaddr_u *, endpt *, struct req_pkt *);
972950cc38Schristos static	void	trust_key	(sockaddr_u *, endpt *, struct req_pkt *);
982950cc38Schristos static	void	untrust_key	(sockaddr_u *, endpt *, struct req_pkt *);
992950cc38Schristos static	void	do_trustkey	(sockaddr_u *, endpt *, struct req_pkt *, u_long);
1002950cc38Schristos static	void	get_auth_info	(sockaddr_u *, endpt *, struct req_pkt *);
1012950cc38Schristos static	void	req_get_traps	(sockaddr_u *, endpt *, struct req_pkt *);
1022950cc38Schristos static	void	req_set_trap	(sockaddr_u *, endpt *, struct req_pkt *);
1032950cc38Schristos static	void	req_clr_trap	(sockaddr_u *, endpt *, struct req_pkt *);
1042950cc38Schristos static	void	do_setclr_trap	(sockaddr_u *, endpt *, struct req_pkt *, int);
1052950cc38Schristos static	void	set_request_keyid (sockaddr_u *, endpt *, struct req_pkt *);
1062950cc38Schristos static	void	set_control_keyid (sockaddr_u *, endpt *, struct req_pkt *);
1072950cc38Schristos static	void	get_ctl_stats   (sockaddr_u *, endpt *, struct req_pkt *);
1082950cc38Schristos static	void	get_if_stats    (sockaddr_u *, endpt *, struct req_pkt *);
1092950cc38Schristos static	void	do_if_reload    (sockaddr_u *, endpt *, struct req_pkt *);
110abb0f93cSkardel #ifdef KERNEL_PLL
1112950cc38Schristos static	void	get_kernel_info (sockaddr_u *, endpt *, struct req_pkt *);
112abb0f93cSkardel #endif /* KERNEL_PLL */
113abb0f93cSkardel #ifdef REFCLOCK
1142950cc38Schristos static	void	get_clock_info (sockaddr_u *, endpt *, struct req_pkt *);
1152950cc38Schristos static	void	set_clock_fudge (sockaddr_u *, endpt *, struct req_pkt *);
116abb0f93cSkardel #endif	/* REFCLOCK */
117abb0f93cSkardel #ifdef REFCLOCK
1182950cc38Schristos static	void	get_clkbug_info (sockaddr_u *, endpt *, struct req_pkt *);
119abb0f93cSkardel #endif	/* REFCLOCK */
120abb0f93cSkardel 
121abb0f93cSkardel /*
122abb0f93cSkardel  * ntpd request codes
123abb0f93cSkardel  */
1242950cc38Schristos static const struct req_proc ntp_codes[] = {
1252950cc38Schristos 	{ REQ_PEER_LIST,	NOAUTH,	0, 0,	list_peers },
1262950cc38Schristos 	{ REQ_PEER_LIST_SUM,	NOAUTH,	0, 0,	list_peers_sum },
127abb0f93cSkardel 	{ REQ_PEER_INFO,    NOAUTH, v4sizeof(struct info_peer_list),
128abb0f93cSkardel 				sizeof(struct info_peer_list), peer_info},
129abb0f93cSkardel 	{ REQ_PEER_STATS,   NOAUTH, v4sizeof(struct info_peer_list),
130abb0f93cSkardel 				sizeof(struct info_peer_list), peer_stats},
131abb0f93cSkardel 	{ REQ_SYS_INFO,		NOAUTH,	0, 0,	sys_info },
132abb0f93cSkardel 	{ REQ_SYS_STATS,	NOAUTH,	0, 0,	sys_stats },
133abb0f93cSkardel 	{ REQ_IO_STATS,		NOAUTH,	0, 0,	io_stats },
134abb0f93cSkardel 	{ REQ_MEM_STATS,	NOAUTH,	0, 0,	mem_stats },
135abb0f93cSkardel 	{ REQ_LOOP_INFO,	NOAUTH,	0, 0,	loop_info },
136abb0f93cSkardel 	{ REQ_TIMER_STATS,	NOAUTH,	0, 0,	timer_stats },
137abb0f93cSkardel 	{ REQ_CONFIG,	    AUTH, v4sizeof(struct conf_peer),
138abb0f93cSkardel 				sizeof(struct conf_peer), do_conf },
139abb0f93cSkardel 	{ REQ_UNCONFIG,	    AUTH, v4sizeof(struct conf_unpeer),
140abb0f93cSkardel 				sizeof(struct conf_unpeer), do_unconf },
141abb0f93cSkardel 	{ REQ_SET_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags),
142abb0f93cSkardel 				sizeof(struct conf_sys_flags), set_sys_flag },
143abb0f93cSkardel 	{ REQ_CLR_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags),
144abb0f93cSkardel 				sizeof(struct conf_sys_flags),  clr_sys_flag },
145abb0f93cSkardel 	{ REQ_GET_RESTRICT,	NOAUTH,	0, 0,	list_restrict },
146abb0f93cSkardel 	{ REQ_RESADDFLAGS, AUTH, v4sizeof(struct conf_restrict),
147abb0f93cSkardel 				sizeof(struct conf_restrict), do_resaddflags },
148abb0f93cSkardel 	{ REQ_RESSUBFLAGS, AUTH, v4sizeof(struct conf_restrict),
149abb0f93cSkardel 				sizeof(struct conf_restrict), do_ressubflags },
150abb0f93cSkardel 	{ REQ_UNRESTRICT, AUTH, v4sizeof(struct conf_restrict),
151abb0f93cSkardel 				sizeof(struct conf_restrict), do_unrestrict },
1522950cc38Schristos 	{ REQ_MON_GETLIST,	NOAUTH,	0, 0,	mon_getlist },
1532950cc38Schristos 	{ REQ_MON_GETLIST_1,	NOAUTH,	0, 0,	mon_getlist },
154abb0f93cSkardel 	{ REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), 0, reset_stats },
155abb0f93cSkardel 	{ REQ_RESET_PEER,  AUTH, v4sizeof(struct conf_unpeer),
156abb0f93cSkardel 				sizeof(struct conf_unpeer), reset_peer },
157abb0f93cSkardel 	{ REQ_REREAD_KEYS,	AUTH,	0, 0,	do_key_reread },
158abb0f93cSkardel 	{ REQ_TRUSTKEY,   AUTH, sizeof(u_long), sizeof(u_long), trust_key },
159abb0f93cSkardel 	{ REQ_UNTRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), untrust_key },
160abb0f93cSkardel 	{ REQ_AUTHINFO,		NOAUTH,	0, 0,	get_auth_info },
161abb0f93cSkardel 	{ REQ_TRAPS,		NOAUTH, 0, 0,	req_get_traps },
162abb0f93cSkardel 	{ REQ_ADD_TRAP,	AUTH, v4sizeof(struct conf_trap),
163abb0f93cSkardel 				sizeof(struct conf_trap), req_set_trap },
164abb0f93cSkardel 	{ REQ_CLR_TRAP,	AUTH, v4sizeof(struct conf_trap),
165abb0f93cSkardel 				sizeof(struct conf_trap), req_clr_trap },
166abb0f93cSkardel 	{ REQ_REQUEST_KEY, AUTH, sizeof(u_long), sizeof(u_long),
167abb0f93cSkardel 				set_request_keyid },
168abb0f93cSkardel 	{ REQ_CONTROL_KEY, AUTH, sizeof(u_long), sizeof(u_long),
169abb0f93cSkardel 				set_control_keyid },
170abb0f93cSkardel 	{ REQ_GET_CTLSTATS,	NOAUTH,	0, 0,	get_ctl_stats },
171abb0f93cSkardel #ifdef KERNEL_PLL
172abb0f93cSkardel 	{ REQ_GET_KERNEL,	NOAUTH,	0, 0,	get_kernel_info },
173abb0f93cSkardel #endif
174abb0f93cSkardel #ifdef REFCLOCK
175abb0f93cSkardel 	{ REQ_GET_CLOCKINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32),
176abb0f93cSkardel 				get_clock_info },
177abb0f93cSkardel 	{ REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge),
178abb0f93cSkardel 				sizeof(struct conf_fudge), set_clock_fudge },
179abb0f93cSkardel 	{ REQ_GET_CLKBUGINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32),
180abb0f93cSkardel 				get_clkbug_info },
181abb0f93cSkardel #endif
182abb0f93cSkardel 	{ REQ_IF_STATS,		AUTH, 0, 0,	get_if_stats },
183abb0f93cSkardel 	{ REQ_IF_RELOAD,	AUTH, 0, 0,	do_if_reload },
184abb0f93cSkardel 
185abb0f93cSkardel 	{ NO_REQUEST,		NOAUTH,	0, 0,	0 }
186abb0f93cSkardel };
187abb0f93cSkardel 
188abb0f93cSkardel 
189abb0f93cSkardel /*
190abb0f93cSkardel  * Authentication keyid used to authenticate requests.  Zero means we
191abb0f93cSkardel  * don't allow writing anything.
192abb0f93cSkardel  */
193abb0f93cSkardel keyid_t info_auth_keyid;
194abb0f93cSkardel 
195abb0f93cSkardel /*
196abb0f93cSkardel  * Statistic counters to keep track of requests and responses.
197abb0f93cSkardel  */
198abb0f93cSkardel u_long numrequests;		/* number of requests we've received */
199abb0f93cSkardel u_long numresppkts;		/* number of resp packets sent with data */
200abb0f93cSkardel 
2012950cc38Schristos /*
2022950cc38Schristos  * lazy way to count errors, indexed by the error code
2032950cc38Schristos  */
2042950cc38Schristos u_long errorcounter[MAX_INFO_ERR + 1];
205abb0f93cSkardel 
206abb0f93cSkardel /*
207abb0f93cSkardel  * A hack.  To keep the authentication module clear of ntp-ism's, we
208abb0f93cSkardel  * include a time reset variable for its stats here.
209abb0f93cSkardel  */
2102950cc38Schristos u_long auth_timereset;
211abb0f93cSkardel 
212abb0f93cSkardel /*
213abb0f93cSkardel  * Response packet used by these routines.  Also some state information
214abb0f93cSkardel  * so that we can handle packet formatting within a common set of
215abb0f93cSkardel  * subroutines.  Note we try to enter data in place whenever possible,
216abb0f93cSkardel  * but the need to set the more bit correctly means we occasionally
217abb0f93cSkardel  * use the extra buffer and copy.
218abb0f93cSkardel  */
219abb0f93cSkardel static struct resp_pkt rpkt;
220abb0f93cSkardel static int reqver;
221abb0f93cSkardel static int seqno;
222abb0f93cSkardel static int nitems;
223abb0f93cSkardel static int itemsize;
224abb0f93cSkardel static int databytes;
225abb0f93cSkardel static char exbuf[RESP_DATA_SIZE];
226abb0f93cSkardel static int usingexbuf;
227abb0f93cSkardel static sockaddr_u *toaddr;
2282950cc38Schristos static endpt *frominter;
229abb0f93cSkardel 
230abb0f93cSkardel /*
231abb0f93cSkardel  * init_request - initialize request data
232abb0f93cSkardel  */
233abb0f93cSkardel void
234abb0f93cSkardel init_request (void)
235abb0f93cSkardel {
236e19314b7Schristos 	size_t i;
237abb0f93cSkardel 
238abb0f93cSkardel 	numrequests = 0;
239abb0f93cSkardel 	numresppkts = 0;
240abb0f93cSkardel 	auth_timereset = 0;
241abb0f93cSkardel 	info_auth_keyid = 0;	/* by default, can't do this */
242abb0f93cSkardel 
243abb0f93cSkardel 	for (i = 0; i < sizeof(errorcounter)/sizeof(errorcounter[0]); i++)
244abb0f93cSkardel 	    errorcounter[i] = 0;
245abb0f93cSkardel }
246abb0f93cSkardel 
247abb0f93cSkardel 
248abb0f93cSkardel /*
249abb0f93cSkardel  * req_ack - acknowledge request with no data
250abb0f93cSkardel  */
251abb0f93cSkardel static void
252abb0f93cSkardel req_ack(
253abb0f93cSkardel 	sockaddr_u *srcadr,
2542950cc38Schristos 	endpt *inter,
255abb0f93cSkardel 	struct req_pkt *inpkt,
256abb0f93cSkardel 	int errcode
257abb0f93cSkardel 	)
258abb0f93cSkardel {
259abb0f93cSkardel 	/*
260abb0f93cSkardel 	 * fill in the fields
261abb0f93cSkardel 	 */
262abb0f93cSkardel 	rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
263abb0f93cSkardel 	rpkt.auth_seq = AUTH_SEQ(0, 0);
264abb0f93cSkardel 	rpkt.implementation = inpkt->implementation;
265abb0f93cSkardel 	rpkt.request = inpkt->request;
266abb0f93cSkardel 	rpkt.err_nitems = ERR_NITEMS(errcode, 0);
267abb0f93cSkardel 	rpkt.mbz_itemsize = MBZ_ITEMSIZE(0);
268abb0f93cSkardel 
269abb0f93cSkardel 	/*
270abb0f93cSkardel 	 * send packet and bump counters
271abb0f93cSkardel 	 */
272abb0f93cSkardel 	sendpkt(srcadr, inter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE);
273abb0f93cSkardel 	errorcounter[errcode]++;
274abb0f93cSkardel }
275abb0f93cSkardel 
276abb0f93cSkardel 
277abb0f93cSkardel /*
278abb0f93cSkardel  * prepare_pkt - prepare response packet for transmission, return pointer
279abb0f93cSkardel  *		 to storage for data item.
280abb0f93cSkardel  */
2812950cc38Schristos static void *
282abb0f93cSkardel prepare_pkt(
283abb0f93cSkardel 	sockaddr_u *srcadr,
2842950cc38Schristos 	endpt *inter,
285abb0f93cSkardel 	struct req_pkt *pkt,
286abb0f93cSkardel 	size_t structsize
287abb0f93cSkardel 	)
288abb0f93cSkardel {
289abb0f93cSkardel 	DPRINTF(4, ("request: preparing pkt\n"));
290abb0f93cSkardel 
291abb0f93cSkardel 	/*
292abb0f93cSkardel 	 * Fill in the implementation, request and itemsize fields
293abb0f93cSkardel 	 * since these won't change.
294abb0f93cSkardel 	 */
295abb0f93cSkardel 	rpkt.implementation = pkt->implementation;
296abb0f93cSkardel 	rpkt.request = pkt->request;
297abb0f93cSkardel 	rpkt.mbz_itemsize = MBZ_ITEMSIZE(structsize);
298abb0f93cSkardel 
299abb0f93cSkardel 	/*
300abb0f93cSkardel 	 * Compute the static data needed to carry on.
301abb0f93cSkardel 	 */
302abb0f93cSkardel 	toaddr = srcadr;
303abb0f93cSkardel 	frominter = inter;
304abb0f93cSkardel 	seqno = 0;
305abb0f93cSkardel 	nitems = 0;
306abb0f93cSkardel 	itemsize = structsize;
307abb0f93cSkardel 	databytes = 0;
308abb0f93cSkardel 	usingexbuf = 0;
309abb0f93cSkardel 
310abb0f93cSkardel 	/*
311abb0f93cSkardel 	 * return the beginning of the packet buffer.
312abb0f93cSkardel 	 */
3132950cc38Schristos 	return &rpkt.u;
314abb0f93cSkardel }
315abb0f93cSkardel 
316abb0f93cSkardel 
317abb0f93cSkardel /*
318abb0f93cSkardel  * more_pkt - return a data pointer for a new item.
319abb0f93cSkardel  */
3202950cc38Schristos static void *
321abb0f93cSkardel more_pkt(void)
322abb0f93cSkardel {
323abb0f93cSkardel 	/*
324abb0f93cSkardel 	 * If we were using the extra buffer, send the packet.
325abb0f93cSkardel 	 */
326abb0f93cSkardel 	if (usingexbuf) {
327abb0f93cSkardel 		DPRINTF(3, ("request: sending pkt\n"));
328abb0f93cSkardel 		rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT, reqver);
329abb0f93cSkardel 		rpkt.auth_seq = AUTH_SEQ(0, seqno);
330abb0f93cSkardel 		rpkt.err_nitems = htons((u_short)nitems);
331abb0f93cSkardel 		sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
332abb0f93cSkardel 			RESP_HEADER_SIZE + databytes);
333abb0f93cSkardel 		numresppkts++;
334abb0f93cSkardel 
335abb0f93cSkardel 		/*
336abb0f93cSkardel 		 * Copy data out of exbuf into the packet.
337abb0f93cSkardel 		 */
3382950cc38Schristos 		memcpy(&rpkt.u.data[0], exbuf, (unsigned)itemsize);
339abb0f93cSkardel 		seqno++;
340abb0f93cSkardel 		databytes = 0;
341abb0f93cSkardel 		nitems = 0;
342abb0f93cSkardel 		usingexbuf = 0;
343abb0f93cSkardel 	}
344abb0f93cSkardel 
345abb0f93cSkardel 	databytes += itemsize;
346abb0f93cSkardel 	nitems++;
347abb0f93cSkardel 	if (databytes + itemsize <= RESP_DATA_SIZE) {
348abb0f93cSkardel 		DPRINTF(4, ("request: giving him more data\n"));
349abb0f93cSkardel 		/*
350abb0f93cSkardel 		 * More room in packet.  Give him the
351abb0f93cSkardel 		 * next address.
352abb0f93cSkardel 		 */
3532950cc38Schristos 		return &rpkt.u.data[databytes];
354abb0f93cSkardel 	} else {
355abb0f93cSkardel 		/*
356abb0f93cSkardel 		 * No room in packet.  Give him the extra
357abb0f93cSkardel 		 * buffer unless this was the last in the sequence.
358abb0f93cSkardel 		 */
359abb0f93cSkardel 		DPRINTF(4, ("request: into extra buffer\n"));
360abb0f93cSkardel 		if (seqno == MAXSEQ)
361abb0f93cSkardel 			return NULL;
362abb0f93cSkardel 		else {
363abb0f93cSkardel 			usingexbuf = 1;
364abb0f93cSkardel 			return exbuf;
365abb0f93cSkardel 		}
366abb0f93cSkardel 	}
367abb0f93cSkardel }
368abb0f93cSkardel 
369abb0f93cSkardel 
370abb0f93cSkardel /*
371abb0f93cSkardel  * flush_pkt - we're done, return remaining information.
372abb0f93cSkardel  */
373abb0f93cSkardel static void
374abb0f93cSkardel flush_pkt(void)
375abb0f93cSkardel {
376abb0f93cSkardel 	DPRINTF(3, ("request: flushing packet, %d items\n", nitems));
377abb0f93cSkardel 	/*
378abb0f93cSkardel 	 * Must send the last packet.  If nothing in here and nothing
379abb0f93cSkardel 	 * has been sent, send an error saying no data to be found.
380abb0f93cSkardel 	 */
381abb0f93cSkardel 	if (seqno == 0 && nitems == 0)
382abb0f93cSkardel 		req_ack(toaddr, frominter, (struct req_pkt *)&rpkt,
383abb0f93cSkardel 			INFO_ERR_NODATA);
384abb0f93cSkardel 	else {
385abb0f93cSkardel 		rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
386abb0f93cSkardel 		rpkt.auth_seq = AUTH_SEQ(0, seqno);
387abb0f93cSkardel 		rpkt.err_nitems = htons((u_short)nitems);
388abb0f93cSkardel 		sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
389abb0f93cSkardel 			RESP_HEADER_SIZE+databytes);
390abb0f93cSkardel 		numresppkts++;
391abb0f93cSkardel 	}
392abb0f93cSkardel }
393abb0f93cSkardel 
394abb0f93cSkardel 
395abb0f93cSkardel 
396abb0f93cSkardel /*
397abb0f93cSkardel  * Given a buffer, return the packet mode
398abb0f93cSkardel  */
399abb0f93cSkardel int
400abb0f93cSkardel get_packet_mode(struct recvbuf *rbufp)
401abb0f93cSkardel {
402abb0f93cSkardel 	struct req_pkt *inpkt = (struct req_pkt *)&rbufp->recv_pkt;
403abb0f93cSkardel 	return (INFO_MODE(inpkt->rm_vn_mode));
404abb0f93cSkardel }
405abb0f93cSkardel 
406abb0f93cSkardel 
407abb0f93cSkardel /*
408abb0f93cSkardel  * process_private - process private mode (7) packets
409abb0f93cSkardel  */
410abb0f93cSkardel void
411abb0f93cSkardel process_private(
412abb0f93cSkardel 	struct recvbuf *rbufp,
413abb0f93cSkardel 	int mod_okay
414abb0f93cSkardel 	)
415abb0f93cSkardel {
41689ba794eStonnerre 	static u_long quiet_until;
417abb0f93cSkardel 	struct req_pkt *inpkt;
418abb0f93cSkardel 	struct req_pkt_tail *tailinpkt;
419abb0f93cSkardel 	sockaddr_u *srcadr;
4202950cc38Schristos 	endpt *inter;
4212950cc38Schristos 	const struct req_proc *proc;
422abb0f93cSkardel 	int ec;
423abb0f93cSkardel 	short temp_size;
424abb0f93cSkardel 	l_fp ftmp;
425abb0f93cSkardel 	double dtemp;
426abb0f93cSkardel 	size_t recv_len;
427abb0f93cSkardel 	size_t noslop_len;
428abb0f93cSkardel 	size_t mac_len;
429abb0f93cSkardel 
430abb0f93cSkardel 	/*
431abb0f93cSkardel 	 * Initialize pointers, for convenience
432abb0f93cSkardel 	 */
433abb0f93cSkardel 	recv_len = rbufp->recv_length;
434abb0f93cSkardel 	inpkt = (struct req_pkt *)&rbufp->recv_pkt;
435abb0f93cSkardel 	srcadr = &rbufp->recv_srcadr;
436abb0f93cSkardel 	inter = rbufp->dstadr;
437abb0f93cSkardel 
438abb0f93cSkardel 	DPRINTF(3, ("process_private: impl %d req %d\n",
439abb0f93cSkardel 		    inpkt->implementation, inpkt->request));
440abb0f93cSkardel 
441abb0f93cSkardel 	/*
442abb0f93cSkardel 	 * Do some sanity checks on the packet.  Return a format
443abb0f93cSkardel 	 * error if it fails.
444abb0f93cSkardel 	 */
445abb0f93cSkardel 	ec = 0;
446abb0f93cSkardel 	if (   (++ec, ISRESPONSE(inpkt->rm_vn_mode))
447abb0f93cSkardel 	    || (++ec, ISMORE(inpkt->rm_vn_mode))
448abb0f93cSkardel 	    || (++ec, INFO_VERSION(inpkt->rm_vn_mode) > NTP_VERSION)
449abb0f93cSkardel 	    || (++ec, INFO_VERSION(inpkt->rm_vn_mode) < NTP_OLDVERSION)
450abb0f93cSkardel 	    || (++ec, INFO_SEQ(inpkt->auth_seq) != 0)
451abb0f93cSkardel 	    || (++ec, INFO_ERR(inpkt->err_nitems) != 0)
452abb0f93cSkardel 	    || (++ec, INFO_MBZ(inpkt->mbz_itemsize) != 0)
453e19314b7Schristos 	    || (++ec, rbufp->recv_length < (int)REQ_LEN_HDR)
454abb0f93cSkardel 		) {
45589ba794eStonnerre 		NLOG(NLOG_SYSEVENT)
45689ba794eStonnerre 			if (current_time >= quiet_until) {
45789ba794eStonnerre 				msyslog(LOG_ERR,
45889ba794eStonnerre 					"process_private: drop test %d"
45989ba794eStonnerre 					" failed, pkt from %s",
46089ba794eStonnerre 					ec, stoa(srcadr));
46189ba794eStonnerre 				quiet_until = current_time + 60;
46289ba794eStonnerre 			}
463abb0f93cSkardel 		return;
464abb0f93cSkardel 	}
465abb0f93cSkardel 
466abb0f93cSkardel 	reqver = INFO_VERSION(inpkt->rm_vn_mode);
467abb0f93cSkardel 
468abb0f93cSkardel 	/*
469abb0f93cSkardel 	 * Get the appropriate procedure list to search.
470abb0f93cSkardel 	 */
471abb0f93cSkardel 	if (inpkt->implementation == IMPL_UNIV)
472abb0f93cSkardel 		proc = univ_codes;
473abb0f93cSkardel 	else if ((inpkt->implementation == IMPL_XNTPD) ||
474abb0f93cSkardel 		 (inpkt->implementation == IMPL_XNTPD_OLD))
475abb0f93cSkardel 		proc = ntp_codes;
476abb0f93cSkardel 	else {
477abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL);
478abb0f93cSkardel 		return;
479abb0f93cSkardel 	}
480abb0f93cSkardel 
481abb0f93cSkardel 	/*
482abb0f93cSkardel 	 * Search the list for the request codes.  If it isn't one
483abb0f93cSkardel 	 * we know, return an error.
484abb0f93cSkardel 	 */
485abb0f93cSkardel 	while (proc->request_code != NO_REQUEST) {
486abb0f93cSkardel 		if (proc->request_code == (short) inpkt->request)
487abb0f93cSkardel 			break;
488abb0f93cSkardel 		proc++;
489abb0f93cSkardel 	}
490abb0f93cSkardel 	if (proc->request_code == NO_REQUEST) {
491abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_REQ);
492abb0f93cSkardel 		return;
493abb0f93cSkardel 	}
494abb0f93cSkardel 
495abb0f93cSkardel 	DPRINTF(4, ("found request in tables\n"));
496abb0f93cSkardel 
497abb0f93cSkardel 	/*
498abb0f93cSkardel 	 * If we need data, check to see if we have some.  If we
499abb0f93cSkardel 	 * don't, check to see that there is none (picky, picky).
500abb0f93cSkardel 	 */
501abb0f93cSkardel 
502abb0f93cSkardel 	/* This part is a bit tricky, we want to be sure that the size
503abb0f93cSkardel 	 * returned is either the old or the new size.  We also can find
504abb0f93cSkardel 	 * out if the client can accept both types of messages this way.
505abb0f93cSkardel 	 *
506abb0f93cSkardel 	 * Handle the exception of REQ_CONFIG. It can have two data sizes.
507abb0f93cSkardel 	 */
508abb0f93cSkardel 	temp_size = INFO_ITEMSIZE(inpkt->mbz_itemsize);
509abb0f93cSkardel 	if ((temp_size != proc->sizeofitem &&
510abb0f93cSkardel 	     temp_size != proc->v6_sizeofitem) &&
511abb0f93cSkardel 	    !(inpkt->implementation == IMPL_XNTPD &&
512abb0f93cSkardel 	      inpkt->request == REQ_CONFIG &&
513abb0f93cSkardel 	      temp_size == sizeof(struct old_conf_peer))) {
514abb0f93cSkardel 		DPRINTF(3, ("process_private: wrong item size, received %d, should be %d or %d\n",
515abb0f93cSkardel 			    temp_size, proc->sizeofitem, proc->v6_sizeofitem));
516abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
517abb0f93cSkardel 		return;
518abb0f93cSkardel 	}
519abb0f93cSkardel 	if ((proc->sizeofitem != 0) &&
520abb0f93cSkardel 	    ((size_t)(temp_size * INFO_NITEMS(inpkt->err_nitems)) >
521abb0f93cSkardel 	     (recv_len - REQ_LEN_HDR))) {
522abb0f93cSkardel 		DPRINTF(3, ("process_private: not enough data\n"));
523abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
524abb0f93cSkardel 		return;
525abb0f93cSkardel 	}
526abb0f93cSkardel 
527abb0f93cSkardel 	switch (inpkt->implementation) {
528abb0f93cSkardel 	case IMPL_XNTPD:
529abb0f93cSkardel 		client_v6_capable = 1;
530abb0f93cSkardel 		break;
531abb0f93cSkardel 	case IMPL_XNTPD_OLD:
532abb0f93cSkardel 		client_v6_capable = 0;
533abb0f93cSkardel 		break;
534abb0f93cSkardel 	default:
535abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
536abb0f93cSkardel 		return;
537abb0f93cSkardel 	}
538abb0f93cSkardel 
539abb0f93cSkardel 	/*
540abb0f93cSkardel 	 * If we need to authenticate, do so.  Note that an
541abb0f93cSkardel 	 * authenticatable packet must include a mac field, must
542abb0f93cSkardel 	 * have used key info_auth_keyid and must have included
543abb0f93cSkardel 	 * a time stamp in the appropriate field.  The time stamp
544abb0f93cSkardel 	 * must be within INFO_TS_MAXSKEW of the receive
545abb0f93cSkardel 	 * time stamp.
546abb0f93cSkardel 	 */
547abb0f93cSkardel 	if (proc->needs_auth && sys_authenticate) {
548abb0f93cSkardel 
549abb0f93cSkardel 		if (recv_len < (REQ_LEN_HDR +
550abb0f93cSkardel 		    (INFO_ITEMSIZE(inpkt->mbz_itemsize) *
551abb0f93cSkardel 		    INFO_NITEMS(inpkt->err_nitems)) +
552abb0f93cSkardel 		    REQ_TAIL_MIN)) {
553abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
554abb0f93cSkardel 			return;
555abb0f93cSkardel 		}
556abb0f93cSkardel 
557abb0f93cSkardel 		/*
558abb0f93cSkardel 		 * For 16-octet digests, regardless of itemsize and
559abb0f93cSkardel 		 * nitems, authenticated requests are a fixed size
560abb0f93cSkardel 		 * with the timestamp, key ID, and digest located
561abb0f93cSkardel 		 * at the end of the packet.  Because the key ID
562abb0f93cSkardel 		 * determining the digest size precedes the digest,
563abb0f93cSkardel 		 * for larger digests the fixed size request scheme
564abb0f93cSkardel 		 * is abandoned and the timestamp, key ID, and digest
565abb0f93cSkardel 		 * are located relative to the start of the packet,
566abb0f93cSkardel 		 * with the digest size determined by the packet size.
567abb0f93cSkardel 		 */
568abb0f93cSkardel 		noslop_len = REQ_LEN_HDR
569abb0f93cSkardel 			     + INFO_ITEMSIZE(inpkt->mbz_itemsize) *
570abb0f93cSkardel 			       INFO_NITEMS(inpkt->err_nitems)
571abb0f93cSkardel 			     + sizeof(inpkt->tstamp);
572abb0f93cSkardel 		/* 32-bit alignment */
573abb0f93cSkardel 		noslop_len = (noslop_len + 3) & ~3;
574abb0f93cSkardel 		if (recv_len > (noslop_len + MAX_MAC_LEN))
575abb0f93cSkardel 			mac_len = 20;
576abb0f93cSkardel 		else
577abb0f93cSkardel 			mac_len = recv_len - noslop_len;
578abb0f93cSkardel 
579abb0f93cSkardel 		tailinpkt = (void *)((char *)inpkt + recv_len -
580abb0f93cSkardel 			    (mac_len + sizeof(inpkt->tstamp)));
581abb0f93cSkardel 
582abb0f93cSkardel 		/*
583abb0f93cSkardel 		 * If this guy is restricted from doing this, don't let
584abb0f93cSkardel 		 * him.  If the wrong key was used, or packet doesn't
585abb0f93cSkardel 		 * have mac, return.
586abb0f93cSkardel 		 */
5874eea345dSchristos 		/* XXX: Use authistrustedip(), or equivalent. */
588abb0f93cSkardel 		if (!INFO_IS_AUTH(inpkt->auth_seq) || !info_auth_keyid
589abb0f93cSkardel 		    || ntohl(tailinpkt->keyid) != info_auth_keyid) {
5902f3ccb49Skardel 			DPRINTF(5, ("failed auth %d info_auth_keyid %u pkt keyid %u maclen %lu\n",
591abb0f93cSkardel 				    INFO_IS_AUTH(inpkt->auth_seq),
592abb0f93cSkardel 				    info_auth_keyid,
5933123f114Skardel 				    ntohl(tailinpkt->keyid), (u_long)mac_len));
594abb0f93cSkardel #ifdef DEBUG
595abb0f93cSkardel 			msyslog(LOG_DEBUG,
5962f3ccb49Skardel 				"process_private: failed auth %d info_auth_keyid %u pkt keyid %u maclen %lu\n",
597abb0f93cSkardel 				INFO_IS_AUTH(inpkt->auth_seq),
598abb0f93cSkardel 				info_auth_keyid,
5993123f114Skardel 				ntohl(tailinpkt->keyid), (u_long)mac_len);
600abb0f93cSkardel #endif
601abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
602abb0f93cSkardel 			return;
603abb0f93cSkardel 		}
604abb0f93cSkardel 		if (recv_len > REQ_LEN_NOMAC + MAX_MAC_LEN) {
605e19314b7Schristos 			DPRINTF(5, ("bad pkt length %zu\n", recv_len));
606abb0f93cSkardel 			msyslog(LOG_ERR,
607e19314b7Schristos 				"process_private: bad pkt length %zu",
608abb0f93cSkardel 				recv_len);
609abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
610abb0f93cSkardel 			return;
611abb0f93cSkardel 		}
612abb0f93cSkardel 		if (!mod_okay || !authhavekey(info_auth_keyid)) {
613abb0f93cSkardel 			DPRINTF(5, ("failed auth mod_okay %d\n",
614abb0f93cSkardel 				    mod_okay));
615abb0f93cSkardel #ifdef DEBUG
616abb0f93cSkardel 			msyslog(LOG_DEBUG,
617abb0f93cSkardel 				"process_private: failed auth mod_okay %d\n",
618abb0f93cSkardel 				mod_okay);
619abb0f93cSkardel #endif
6202950cc38Schristos 			if (!mod_okay) {
6212950cc38Schristos 				sys_restricted++;
6222950cc38Schristos 			}
623abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
624abb0f93cSkardel 			return;
625abb0f93cSkardel 		}
626abb0f93cSkardel 
627abb0f93cSkardel 		/*
628abb0f93cSkardel 		 * calculate absolute time difference between xmit time stamp
629abb0f93cSkardel 		 * and receive time stamp.  If too large, too bad.
630abb0f93cSkardel 		 */
631abb0f93cSkardel 		NTOHL_FP(&tailinpkt->tstamp, &ftmp);
632abb0f93cSkardel 		L_SUB(&ftmp, &rbufp->recv_time);
633abb0f93cSkardel 		LFPTOD(&ftmp, dtemp);
634abb0f93cSkardel 		if (fabs(dtemp) > INFO_TS_MAXSKEW) {
635abb0f93cSkardel 			/*
636abb0f93cSkardel 			 * He's a loser.  Tell him.
637abb0f93cSkardel 			 */
638abb0f93cSkardel 			DPRINTF(5, ("xmit/rcv timestamp delta %g > INFO_TS_MAXSKEW %g\n",
639abb0f93cSkardel 				    dtemp, INFO_TS_MAXSKEW));
640abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
641abb0f93cSkardel 			return;
642abb0f93cSkardel 		}
643abb0f93cSkardel 
644abb0f93cSkardel 		/*
645abb0f93cSkardel 		 * So far so good.  See if decryption works out okay.
646abb0f93cSkardel 		 */
647abb0f93cSkardel 		if (!authdecrypt(info_auth_keyid, (u_int32 *)inpkt,
648abb0f93cSkardel 				 recv_len - mac_len, mac_len)) {
649abb0f93cSkardel 			DPRINTF(5, ("authdecrypt failed\n"));
650abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
651abb0f93cSkardel 			return;
652abb0f93cSkardel 		}
653abb0f93cSkardel 	}
654abb0f93cSkardel 
655abb0f93cSkardel 	DPRINTF(3, ("process_private: all okay, into handler\n"));
656abb0f93cSkardel 	/*
657abb0f93cSkardel 	 * Packet is okay.  Call the handler to send him data.
658abb0f93cSkardel 	 */
659abb0f93cSkardel 	(proc->handler)(srcadr, inter, inpkt);
660abb0f93cSkardel }
661abb0f93cSkardel 
662abb0f93cSkardel 
663abb0f93cSkardel /*
6642950cc38Schristos  * list_peers - send a list of the peers
665abb0f93cSkardel  */
666abb0f93cSkardel static void
6672950cc38Schristos list_peers(
668abb0f93cSkardel 	sockaddr_u *srcadr,
6692950cc38Schristos 	endpt *inter,
670abb0f93cSkardel 	struct req_pkt *inpkt
671abb0f93cSkardel 	)
672abb0f93cSkardel {
6732950cc38Schristos 	struct info_peer_list *	ip;
67468dbbb44Schristos 	const struct peer *	pp;
675abb0f93cSkardel 
676abb0f93cSkardel 	ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt,
677abb0f93cSkardel 	    v6sizeof(struct info_peer_list));
6782950cc38Schristos 	for (pp = peer_list; pp != NULL && ip != NULL; pp = pp->p_link) {
679abb0f93cSkardel 		if (IS_IPV6(&pp->srcadr)) {
68068dbbb44Schristos 			if (!client_v6_capable)
68168dbbb44Schristos 				continue;
682abb0f93cSkardel 			ip->addr6 = SOCK_ADDR6(&pp->srcadr);
683abb0f93cSkardel 			ip->v6_flag = 1;
684abb0f93cSkardel 		} else {
685abb0f93cSkardel 			ip->addr = NSRCADR(&pp->srcadr);
686abb0f93cSkardel 			if (client_v6_capable)
687abb0f93cSkardel 				ip->v6_flag = 0;
688abb0f93cSkardel 		}
689abb0f93cSkardel 
690abb0f93cSkardel 		ip->port = NSRCPORT(&pp->srcadr);
691abb0f93cSkardel 		ip->hmode = pp->hmode;
692abb0f93cSkardel 		ip->flags = 0;
693abb0f93cSkardel 		if (pp->flags & FLAG_CONFIG)
694abb0f93cSkardel 			ip->flags |= INFO_FLAG_CONFIG;
695abb0f93cSkardel 		if (pp == sys_peer)
696abb0f93cSkardel 			ip->flags |= INFO_FLAG_SYSPEER;
697abb0f93cSkardel 		if (pp->status == CTL_PST_SEL_SYNCCAND)
698abb0f93cSkardel 			ip->flags |= INFO_FLAG_SEL_CANDIDATE;
699abb0f93cSkardel 		if (pp->status >= CTL_PST_SEL_SYSPEER)
700abb0f93cSkardel 			ip->flags |= INFO_FLAG_SHORTLIST;
701abb0f93cSkardel 		ip = (struct info_peer_list *)more_pkt();
7022950cc38Schristos 	}	/* for pp */
7032950cc38Schristos 
704abb0f93cSkardel 	flush_pkt();
705abb0f93cSkardel }
706abb0f93cSkardel 
707abb0f93cSkardel 
708abb0f93cSkardel /*
7092950cc38Schristos  * list_peers_sum - return extended peer list
710abb0f93cSkardel  */
711abb0f93cSkardel static void
7122950cc38Schristos list_peers_sum(
713abb0f93cSkardel 	sockaddr_u *srcadr,
7142950cc38Schristos 	endpt *inter,
715abb0f93cSkardel 	struct req_pkt *inpkt
716abb0f93cSkardel 	)
717abb0f93cSkardel {
71868dbbb44Schristos 	struct info_peer_summary *	ips;
71968dbbb44Schristos 	const struct peer *		pp;
720abb0f93cSkardel 	l_fp 				ltmp;
721abb0f93cSkardel 
7222950cc38Schristos 	DPRINTF(3, ("wants peer list summary\n"));
7232950cc38Schristos 
724abb0f93cSkardel 	ips = (struct info_peer_summary *)prepare_pkt(srcadr, inter, inpkt,
725abb0f93cSkardel 	    v6sizeof(struct info_peer_summary));
7262950cc38Schristos 	for (pp = peer_list; pp != NULL && ips != NULL; pp = pp->p_link) {
7272950cc38Schristos 		DPRINTF(4, ("sum: got one\n"));
728abb0f93cSkardel 		/*
729abb0f93cSkardel 		 * Be careful here not to return v6 peers when we
730abb0f93cSkardel 		 * want only v4.
731abb0f93cSkardel 		 */
732abb0f93cSkardel 		if (IS_IPV6(&pp->srcadr)) {
73368dbbb44Schristos 			if (!client_v6_capable)
73468dbbb44Schristos 				continue;
735abb0f93cSkardel 			ips->srcadr6 = SOCK_ADDR6(&pp->srcadr);
736abb0f93cSkardel 			ips->v6_flag = 1;
737abb0f93cSkardel 			if (pp->dstadr)
738abb0f93cSkardel 				ips->dstadr6 = SOCK_ADDR6(&pp->dstadr->sin);
739abb0f93cSkardel 			else
7402950cc38Schristos 				ZERO(ips->dstadr6);
741abb0f93cSkardel 		} else {
742abb0f93cSkardel 			ips->srcadr = NSRCADR(&pp->srcadr);
743abb0f93cSkardel 			if (client_v6_capable)
744abb0f93cSkardel 				ips->v6_flag = 0;
745abb0f93cSkardel 
746abb0f93cSkardel 			if (pp->dstadr) {
747abb0f93cSkardel 				if (!pp->processed)
748abb0f93cSkardel 					ips->dstadr = NSRCADR(&pp->dstadr->sin);
749abb0f93cSkardel 				else {
750abb0f93cSkardel 					if (MDF_BCAST == pp->cast_flags)
751abb0f93cSkardel 						ips->dstadr = NSRCADR(&pp->dstadr->bcast);
752abb0f93cSkardel 					else if (pp->cast_flags) {
753abb0f93cSkardel 						ips->dstadr = NSRCADR(&pp->dstadr->sin);
754abb0f93cSkardel 						if (!ips->dstadr)
755abb0f93cSkardel 							ips->dstadr = NSRCADR(&pp->dstadr->bcast);
756abb0f93cSkardel 					}
757abb0f93cSkardel 				}
75868dbbb44Schristos 			} else {
759abb0f93cSkardel 				ips->dstadr = 0;
76068dbbb44Schristos 			}
761abb0f93cSkardel 		}
762abb0f93cSkardel 
763abb0f93cSkardel 		ips->srcport = NSRCPORT(&pp->srcadr);
764abb0f93cSkardel 		ips->stratum = pp->stratum;
765abb0f93cSkardel 		ips->hpoll = pp->hpoll;
766abb0f93cSkardel 		ips->ppoll = pp->ppoll;
767abb0f93cSkardel 		ips->reach = pp->reach;
768abb0f93cSkardel 		ips->flags = 0;
769abb0f93cSkardel 		if (pp == sys_peer)
770abb0f93cSkardel 			ips->flags |= INFO_FLAG_SYSPEER;
771abb0f93cSkardel 		if (pp->flags & FLAG_CONFIG)
772abb0f93cSkardel 			ips->flags |= INFO_FLAG_CONFIG;
773abb0f93cSkardel 		if (pp->flags & FLAG_REFCLOCK)
774abb0f93cSkardel 			ips->flags |= INFO_FLAG_REFCLOCK;
775abb0f93cSkardel 		if (pp->flags & FLAG_PREFER)
776abb0f93cSkardel 			ips->flags |= INFO_FLAG_PREFER;
777abb0f93cSkardel 		if (pp->flags & FLAG_BURST)
778abb0f93cSkardel 			ips->flags |= INFO_FLAG_BURST;
779abb0f93cSkardel 		if (pp->status == CTL_PST_SEL_SYNCCAND)
780abb0f93cSkardel 			ips->flags |= INFO_FLAG_SEL_CANDIDATE;
781abb0f93cSkardel 		if (pp->status >= CTL_PST_SEL_SYSPEER)
782abb0f93cSkardel 			ips->flags |= INFO_FLAG_SHORTLIST;
783abb0f93cSkardel 		ips->hmode = pp->hmode;
784abb0f93cSkardel 		ips->delay = HTONS_FP(DTOFP(pp->delay));
785abb0f93cSkardel 		DTOLFP(pp->offset, &ltmp);
786abb0f93cSkardel 		HTONL_FP(&ltmp, &ips->offset);
787abb0f93cSkardel 		ips->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
78868dbbb44Schristos 
789abb0f93cSkardel 		ips = (struct info_peer_summary *)more_pkt();
7902950cc38Schristos 	}	/* for pp */
7912950cc38Schristos 
792abb0f93cSkardel 	flush_pkt();
793abb0f93cSkardel }
794abb0f93cSkardel 
795abb0f93cSkardel 
796abb0f93cSkardel /*
797abb0f93cSkardel  * peer_info - send information for one or more peers
798abb0f93cSkardel  */
799abb0f93cSkardel static void
800abb0f93cSkardel peer_info (
801abb0f93cSkardel 	sockaddr_u *srcadr,
8022950cc38Schristos 	endpt *inter,
803abb0f93cSkardel 	struct req_pkt *inpkt
804abb0f93cSkardel 	)
805abb0f93cSkardel {
8062950cc38Schristos 	u_short			items;
8072950cc38Schristos 	size_t			item_sz;
8082950cc38Schristos 	char *			datap;
8092950cc38Schristos 	struct info_peer_list	ipl;
8102950cc38Schristos 	struct peer *		pp;
8112950cc38Schristos 	struct info_peer *	ip;
8122950cc38Schristos 	int			i;
8132950cc38Schristos 	int			j;
814abb0f93cSkardel 	sockaddr_u		addr;
815abb0f93cSkardel 	l_fp			ltmp;
816abb0f93cSkardel 
817abb0f93cSkardel 	items = INFO_NITEMS(inpkt->err_nitems);
8182950cc38Schristos 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
8192950cc38Schristos 	datap = inpkt->u.data;
8202950cc38Schristos 	if (item_sz != sizeof(ipl)) {
8212950cc38Schristos 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
8222950cc38Schristos 		return;
8232950cc38Schristos 	}
8242950cc38Schristos 	ip = prepare_pkt(srcadr, inter, inpkt,
825abb0f93cSkardel 			 v6sizeof(struct info_peer));
8262950cc38Schristos 	while (items-- > 0 && ip != NULL) {
8272950cc38Schristos 		ZERO(ipl);
8282950cc38Schristos 		memcpy(&ipl, datap, item_sz);
829abb0f93cSkardel 		ZERO_SOCK(&addr);
8302950cc38Schristos 		NSRCPORT(&addr) = ipl.port;
8312950cc38Schristos 		if (client_v6_capable && ipl.v6_flag) {
832abb0f93cSkardel 			AF(&addr) = AF_INET6;
8332950cc38Schristos 			SOCK_ADDR6(&addr) = ipl.addr6;
834abb0f93cSkardel 		} else {
835abb0f93cSkardel 			AF(&addr) = AF_INET;
8362950cc38Schristos 			NSRCADR(&addr) = ipl.addr;
837abb0f93cSkardel 		}
838abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN
8393123f114Skardel 		addr.sa.sa_len = SOCKLEN(&addr);
840abb0f93cSkardel #endif
8412950cc38Schristos 		datap += item_sz;
8422950cc38Schristos 
8434eea345dSchristos 		pp = findexistingpeer(&addr, NULL, NULL, -1, 0, NULL);
8443123f114Skardel 		if (NULL == pp)
845abb0f93cSkardel 			continue;
846cdfa2a7eSchristos 		if (IS_IPV6(&pp->srcadr)) {
847abb0f93cSkardel 			if (pp->dstadr)
848abb0f93cSkardel 				ip->dstadr6 =
849abb0f93cSkardel 				    (MDF_BCAST == pp->cast_flags)
850abb0f93cSkardel 					? SOCK_ADDR6(&pp->dstadr->bcast)
851abb0f93cSkardel 					: SOCK_ADDR6(&pp->dstadr->sin);
852abb0f93cSkardel 			else
8532950cc38Schristos 				ZERO(ip->dstadr6);
854abb0f93cSkardel 
855abb0f93cSkardel 			ip->srcadr6 = SOCK_ADDR6(&pp->srcadr);
856abb0f93cSkardel 			ip->v6_flag = 1;
857abb0f93cSkardel 		} else {
858abb0f93cSkardel 			if (pp->dstadr) {
859abb0f93cSkardel 				if (!pp->processed)
860abb0f93cSkardel 					ip->dstadr = NSRCADR(&pp->dstadr->sin);
861abb0f93cSkardel 				else {
862abb0f93cSkardel 					if (MDF_BCAST == pp->cast_flags)
863abb0f93cSkardel 						ip->dstadr = NSRCADR(&pp->dstadr->bcast);
864abb0f93cSkardel 					else if (pp->cast_flags) {
865abb0f93cSkardel 						ip->dstadr = NSRCADR(&pp->dstadr->sin);
866abb0f93cSkardel 						if (!ip->dstadr)
867abb0f93cSkardel 							ip->dstadr = NSRCADR(&pp->dstadr->bcast);
868abb0f93cSkardel 					}
869abb0f93cSkardel 				}
870abb0f93cSkardel 			} else
871abb0f93cSkardel 				ip->dstadr = 0;
872abb0f93cSkardel 
873abb0f93cSkardel 			ip->srcadr = NSRCADR(&pp->srcadr);
874abb0f93cSkardel 			if (client_v6_capable)
875abb0f93cSkardel 				ip->v6_flag = 0;
876abb0f93cSkardel 		}
877abb0f93cSkardel 		ip->srcport = NSRCPORT(&pp->srcadr);
878abb0f93cSkardel 		ip->flags = 0;
879abb0f93cSkardel 		if (pp == sys_peer)
880abb0f93cSkardel 			ip->flags |= INFO_FLAG_SYSPEER;
881abb0f93cSkardel 		if (pp->flags & FLAG_CONFIG)
882abb0f93cSkardel 			ip->flags |= INFO_FLAG_CONFIG;
883abb0f93cSkardel 		if (pp->flags & FLAG_REFCLOCK)
884abb0f93cSkardel 			ip->flags |= INFO_FLAG_REFCLOCK;
885abb0f93cSkardel 		if (pp->flags & FLAG_PREFER)
886abb0f93cSkardel 			ip->flags |= INFO_FLAG_PREFER;
887abb0f93cSkardel 		if (pp->flags & FLAG_BURST)
888abb0f93cSkardel 			ip->flags |= INFO_FLAG_BURST;
889abb0f93cSkardel 		if (pp->status == CTL_PST_SEL_SYNCCAND)
890abb0f93cSkardel 			ip->flags |= INFO_FLAG_SEL_CANDIDATE;
891abb0f93cSkardel 		if (pp->status >= CTL_PST_SEL_SYSPEER)
892abb0f93cSkardel 			ip->flags |= INFO_FLAG_SHORTLIST;
893abb0f93cSkardel 		ip->leap = pp->leap;
894abb0f93cSkardel 		ip->hmode = pp->hmode;
89579045f13Schristos 		ip->pmode = pp->pmode;
896abb0f93cSkardel 		ip->keyid = pp->keyid;
897abb0f93cSkardel 		ip->stratum = pp->stratum;
898abb0f93cSkardel 		ip->ppoll = pp->ppoll;
899abb0f93cSkardel 		ip->hpoll = pp->hpoll;
900abb0f93cSkardel 		ip->precision = pp->precision;
901abb0f93cSkardel 		ip->version = pp->version;
902abb0f93cSkardel 		ip->reach = pp->reach;
903abb0f93cSkardel 		ip->unreach = (u_char)pp->unreach;
904abb0f93cSkardel 		ip->flash = (u_char)pp->flash;
905abb0f93cSkardel 		ip->flash2 = (u_short)pp->flash;
906abb0f93cSkardel 		ip->estbdelay = HTONS_FP(DTOFP(pp->delay));
9072950cc38Schristos 		ip->ttl = (u_char)pp->ttl;
908abb0f93cSkardel 		ip->associd = htons(pp->associd);
909abb0f93cSkardel 		ip->rootdelay = HTONS_FP(DTOUFP(pp->rootdelay));
910abb0f93cSkardel 		ip->rootdispersion = HTONS_FP(DTOUFP(pp->rootdisp));
911abb0f93cSkardel 		ip->refid = pp->refid;
912abb0f93cSkardel 		HTONL_FP(&pp->reftime, &ip->reftime);
913abb0f93cSkardel 		HTONL_FP(&pp->aorg, &ip->org);
914abb0f93cSkardel 		HTONL_FP(&pp->rec, &ip->rec);
915abb0f93cSkardel 		HTONL_FP(&pp->xmt, &ip->xmt);
916abb0f93cSkardel 		j = pp->filter_nextpt - 1;
917abb0f93cSkardel 		for (i = 0; i < NTP_SHIFT; i++, j--) {
918abb0f93cSkardel 			if (j < 0)
919abb0f93cSkardel 				j = NTP_SHIFT-1;
920abb0f93cSkardel 			ip->filtdelay[i] = HTONS_FP(DTOFP(pp->filter_delay[j]));
921abb0f93cSkardel 			DTOLFP(pp->filter_offset[j], &ltmp);
922abb0f93cSkardel 			HTONL_FP(&ltmp, &ip->filtoffset[i]);
9232950cc38Schristos 			ip->order[i] = (u_char)((pp->filter_nextpt +
9242950cc38Schristos 						 NTP_SHIFT - 1) -
9252950cc38Schristos 						pp->filter_order[i]);
926abb0f93cSkardel 			if (ip->order[i] >= NTP_SHIFT)
927abb0f93cSkardel 				ip->order[i] -= NTP_SHIFT;
928abb0f93cSkardel 		}
929abb0f93cSkardel 		DTOLFP(pp->offset, &ltmp);
930abb0f93cSkardel 		HTONL_FP(&ltmp, &ip->offset);
931abb0f93cSkardel 		ip->delay = HTONS_FP(DTOFP(pp->delay));
932abb0f93cSkardel 		ip->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
933abb0f93cSkardel 		ip->selectdisp = HTONS_FP(DTOUFP(SQRT(pp->jitter)));
9342950cc38Schristos 		ip = more_pkt();
935abb0f93cSkardel 	}
936abb0f93cSkardel 	flush_pkt();
937abb0f93cSkardel }
938abb0f93cSkardel 
939abb0f93cSkardel 
940abb0f93cSkardel /*
941abb0f93cSkardel  * peer_stats - send statistics for one or more peers
942abb0f93cSkardel  */
943abb0f93cSkardel static void
944abb0f93cSkardel peer_stats (
945abb0f93cSkardel 	sockaddr_u *srcadr,
9462950cc38Schristos 	endpt *inter,
947abb0f93cSkardel 	struct req_pkt *inpkt
948abb0f93cSkardel 	)
949abb0f93cSkardel {
9502950cc38Schristos 	u_short			items;
9512950cc38Schristos 	size_t			item_sz;
9522950cc38Schristos 	char *			datap;
9532950cc38Schristos 	struct info_peer_list	ipl;
9542950cc38Schristos 	struct peer *		pp;
9552950cc38Schristos 	struct info_peer_stats *ip;
956abb0f93cSkardel 	sockaddr_u addr;
957abb0f93cSkardel 
9582950cc38Schristos 	DPRINTF(1, ("peer_stats: called\n"));
959abb0f93cSkardel 	items = INFO_NITEMS(inpkt->err_nitems);
9602950cc38Schristos 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
9612950cc38Schristos 	datap = inpkt->u.data;
9622950cc38Schristos 	if (item_sz > sizeof(ipl)) {
9632950cc38Schristos 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
9642950cc38Schristos 		return;
9652950cc38Schristos 	}
9662950cc38Schristos 	ip = prepare_pkt(srcadr, inter, inpkt,
967abb0f93cSkardel 			 v6sizeof(struct info_peer_stats));
9682950cc38Schristos 	while (items-- > 0 && ip != NULL) {
9692950cc38Schristos 		ZERO(ipl);
9702950cc38Schristos 		memcpy(&ipl, datap, item_sz);
9712950cc38Schristos 		ZERO(addr);
9722950cc38Schristos 		NSRCPORT(&addr) = ipl.port;
9732950cc38Schristos 		if (client_v6_capable && ipl.v6_flag) {
974abb0f93cSkardel 			AF(&addr) = AF_INET6;
9752950cc38Schristos 			SOCK_ADDR6(&addr) = ipl.addr6;
976abb0f93cSkardel 		} else {
977abb0f93cSkardel 			AF(&addr) = AF_INET;
9782950cc38Schristos 			NSRCADR(&addr) = ipl.addr;
979abb0f93cSkardel 		}
980abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN
9813123f114Skardel 		addr.sa.sa_len = SOCKLEN(&addr);
982abb0f93cSkardel #endif
983abb0f93cSkardel 		DPRINTF(1, ("peer_stats: looking for %s, %d, %d\n",
9842950cc38Schristos 			    stoa(&addr), ipl.port, NSRCPORT(&addr)));
985abb0f93cSkardel 
9862950cc38Schristos 		datap += item_sz;
987abb0f93cSkardel 
9884eea345dSchristos 		pp = findexistingpeer(&addr, NULL, NULL, -1, 0, NULL);
9893123f114Skardel 		if (NULL == pp)
990abb0f93cSkardel 			continue;
991abb0f93cSkardel 
992abb0f93cSkardel 		DPRINTF(1, ("peer_stats: found %s\n", stoa(&addr)));
993abb0f93cSkardel 
994abb0f93cSkardel 		if (IS_IPV4(&pp->srcadr)) {
995abb0f93cSkardel 			if (pp->dstadr) {
996abb0f93cSkardel 				if (!pp->processed)
997abb0f93cSkardel 					ip->dstadr = NSRCADR(&pp->dstadr->sin);
998abb0f93cSkardel 				else {
999abb0f93cSkardel 					if (MDF_BCAST == pp->cast_flags)
1000abb0f93cSkardel 						ip->dstadr = NSRCADR(&pp->dstadr->bcast);
1001abb0f93cSkardel 					else if (pp->cast_flags) {
1002abb0f93cSkardel 						ip->dstadr = NSRCADR(&pp->dstadr->sin);
1003abb0f93cSkardel 						if (!ip->dstadr)
1004abb0f93cSkardel 							ip->dstadr = NSRCADR(&pp->dstadr->bcast);
1005abb0f93cSkardel 					}
1006abb0f93cSkardel 				}
1007abb0f93cSkardel 			} else
1008abb0f93cSkardel 				ip->dstadr = 0;
1009abb0f93cSkardel 
1010abb0f93cSkardel 			ip->srcadr = NSRCADR(&pp->srcadr);
1011abb0f93cSkardel 			if (client_v6_capable)
1012abb0f93cSkardel 				ip->v6_flag = 0;
1013abb0f93cSkardel 		} else {
1014abb0f93cSkardel 			if (pp->dstadr)
1015abb0f93cSkardel 				ip->dstadr6 =
1016abb0f93cSkardel 				    (MDF_BCAST == pp->cast_flags)
1017abb0f93cSkardel 					? SOCK_ADDR6(&pp->dstadr->bcast)
1018abb0f93cSkardel 					: SOCK_ADDR6(&pp->dstadr->sin);
1019abb0f93cSkardel 			else
10202950cc38Schristos 				ZERO(ip->dstadr6);
1021abb0f93cSkardel 
1022abb0f93cSkardel 			ip->srcadr6 = SOCK_ADDR6(&pp->srcadr);
1023abb0f93cSkardel 			ip->v6_flag = 1;
1024abb0f93cSkardel 		}
1025abb0f93cSkardel 		ip->srcport = NSRCPORT(&pp->srcadr);
1026abb0f93cSkardel 		ip->flags = 0;
1027abb0f93cSkardel 		if (pp == sys_peer)
1028abb0f93cSkardel 		    ip->flags |= INFO_FLAG_SYSPEER;
1029abb0f93cSkardel 		if (pp->flags & FLAG_CONFIG)
1030abb0f93cSkardel 		    ip->flags |= INFO_FLAG_CONFIG;
1031abb0f93cSkardel 		if (pp->flags & FLAG_REFCLOCK)
1032abb0f93cSkardel 		    ip->flags |= INFO_FLAG_REFCLOCK;
1033abb0f93cSkardel 		if (pp->flags & FLAG_PREFER)
1034abb0f93cSkardel 		    ip->flags |= INFO_FLAG_PREFER;
1035abb0f93cSkardel 		if (pp->flags & FLAG_BURST)
1036abb0f93cSkardel 		    ip->flags |= INFO_FLAG_BURST;
1037abb0f93cSkardel 		if (pp->flags & FLAG_IBURST)
1038abb0f93cSkardel 		    ip->flags |= INFO_FLAG_IBURST;
1039abb0f93cSkardel 		if (pp->status == CTL_PST_SEL_SYNCCAND)
1040abb0f93cSkardel 		    ip->flags |= INFO_FLAG_SEL_CANDIDATE;
1041abb0f93cSkardel 		if (pp->status >= CTL_PST_SEL_SYSPEER)
1042abb0f93cSkardel 		    ip->flags |= INFO_FLAG_SHORTLIST;
1043abb0f93cSkardel 		ip->flags = htons(ip->flags);
1044abb0f93cSkardel 		ip->timereceived = htonl((u_int32)(current_time - pp->timereceived));
1045abb0f93cSkardel 		ip->timetosend = htonl(pp->nextdate - current_time);
1046abb0f93cSkardel 		ip->timereachable = htonl((u_int32)(current_time - pp->timereachable));
1047abb0f93cSkardel 		ip->sent = htonl((u_int32)(pp->sent));
1048abb0f93cSkardel 		ip->processed = htonl((u_int32)(pp->processed));
1049abb0f93cSkardel 		ip->badauth = htonl((u_int32)(pp->badauth));
1050abb0f93cSkardel 		ip->bogusorg = htonl((u_int32)(pp->bogusorg));
1051abb0f93cSkardel 		ip->oldpkt = htonl((u_int32)(pp->oldpkt));
1052abb0f93cSkardel 		ip->seldisp = htonl((u_int32)(pp->seldisptoolarge));
1053abb0f93cSkardel 		ip->selbroken = htonl((u_int32)(pp->selbroken));
1054abb0f93cSkardel 		ip->candidate = pp->status;
1055abb0f93cSkardel 		ip = (struct info_peer_stats *)more_pkt();
1056abb0f93cSkardel 	}
1057abb0f93cSkardel 	flush_pkt();
1058abb0f93cSkardel }
1059abb0f93cSkardel 
1060abb0f93cSkardel 
1061abb0f93cSkardel /*
1062abb0f93cSkardel  * sys_info - return system info
1063abb0f93cSkardel  */
1064abb0f93cSkardel static void
1065abb0f93cSkardel sys_info(
1066abb0f93cSkardel 	sockaddr_u *srcadr,
10672950cc38Schristos 	endpt *inter,
1068abb0f93cSkardel 	struct req_pkt *inpkt
1069abb0f93cSkardel 	)
1070abb0f93cSkardel {
1071abb0f93cSkardel 	register struct info_sys *is;
1072abb0f93cSkardel 
1073abb0f93cSkardel 	is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt,
1074abb0f93cSkardel 	    v6sizeof(struct info_sys));
1075abb0f93cSkardel 
1076abb0f93cSkardel 	if (sys_peer) {
1077abb0f93cSkardel 		if (IS_IPV4(&sys_peer->srcadr)) {
1078abb0f93cSkardel 			is->peer = NSRCADR(&sys_peer->srcadr);
1079abb0f93cSkardel 			if (client_v6_capable)
1080abb0f93cSkardel 				is->v6_flag = 0;
1081abb0f93cSkardel 		} else if (client_v6_capable) {
1082abb0f93cSkardel 			is->peer6 = SOCK_ADDR6(&sys_peer->srcadr);
1083abb0f93cSkardel 			is->v6_flag = 1;
1084abb0f93cSkardel 		}
1085abb0f93cSkardel 		is->peer_mode = sys_peer->hmode;
1086abb0f93cSkardel 	} else {
1087abb0f93cSkardel 		is->peer = 0;
1088abb0f93cSkardel 		if (client_v6_capable) {
1089abb0f93cSkardel 			is->v6_flag = 0;
1090abb0f93cSkardel 		}
1091abb0f93cSkardel 		is->peer_mode = 0;
1092abb0f93cSkardel 	}
1093abb0f93cSkardel 
1094abb0f93cSkardel 	is->leap = sys_leap;
1095abb0f93cSkardel 	is->stratum = sys_stratum;
1096abb0f93cSkardel 	is->precision = sys_precision;
1097abb0f93cSkardel 	is->rootdelay = htonl(DTOFP(sys_rootdelay));
1098abb0f93cSkardel 	is->rootdispersion = htonl(DTOUFP(sys_rootdisp));
1099abb0f93cSkardel 	is->frequency = htonl(DTOFP(sys_jitter));
11002950cc38Schristos 	is->stability = htonl(DTOUFP(clock_stability * 1e6));
1101abb0f93cSkardel 	is->refid = sys_refid;
1102abb0f93cSkardel 	HTONL_FP(&sys_reftime, &is->reftime);
1103abb0f93cSkardel 
1104abb0f93cSkardel 	is->poll = sys_poll;
1105abb0f93cSkardel 
1106abb0f93cSkardel 	is->flags = 0;
1107abb0f93cSkardel 	if (sys_authenticate)
1108abb0f93cSkardel 		is->flags |= INFO_FLAG_AUTHENTICATE;
1109eabc0478Schristos 	if (sys_bclient || sys_mclient)
1110abb0f93cSkardel 		is->flags |= INFO_FLAG_BCLIENT;
1111abb0f93cSkardel #ifdef REFCLOCK
1112abb0f93cSkardel 	if (cal_enable)
1113abb0f93cSkardel 		is->flags |= INFO_FLAG_CAL;
1114abb0f93cSkardel #endif /* REFCLOCK */
1115abb0f93cSkardel 	if (kern_enable)
1116abb0f93cSkardel 		is->flags |= INFO_FLAG_KERNEL;
1117abb0f93cSkardel 	if (mon_enabled != MON_OFF)
1118abb0f93cSkardel 		is->flags |= INFO_FLAG_MONITOR;
1119abb0f93cSkardel 	if (ntp_enable)
1120abb0f93cSkardel 		is->flags |= INFO_FLAG_NTP;
1121ea66d795Schristos 	if (hardpps_enable)
1122abb0f93cSkardel 		is->flags |= INFO_FLAG_PPS_SYNC;
1123abb0f93cSkardel 	if (stats_control)
1124abb0f93cSkardel 		is->flags |= INFO_FLAG_FILEGEN;
1125abb0f93cSkardel 	is->bdelay = HTONS_FP(DTOFP(sys_bdelay));
11262950cc38Schristos 	HTONL_UF(sys_authdelay.l_uf, &is->authdelay);
1127abb0f93cSkardel 	(void) more_pkt();
1128abb0f93cSkardel 	flush_pkt();
1129abb0f93cSkardel }
1130abb0f93cSkardel 
1131abb0f93cSkardel 
1132abb0f93cSkardel /*
1133abb0f93cSkardel  * sys_stats - return system statistics
1134abb0f93cSkardel  */
1135abb0f93cSkardel static void
1136abb0f93cSkardel sys_stats(
1137abb0f93cSkardel 	sockaddr_u *srcadr,
11382950cc38Schristos 	endpt *inter,
1139abb0f93cSkardel 	struct req_pkt *inpkt
1140abb0f93cSkardel 	)
1141abb0f93cSkardel {
1142abb0f93cSkardel 	register struct info_sys_stats *ss;
1143abb0f93cSkardel 
1144abb0f93cSkardel 	ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt,
1145abb0f93cSkardel 		sizeof(struct info_sys_stats));
1146abb0f93cSkardel 	ss->timeup = htonl((u_int32)current_time);
1147abb0f93cSkardel 	ss->timereset = htonl((u_int32)(current_time - sys_stattime));
1148abb0f93cSkardel 	ss->denied = htonl((u_int32)sys_restricted);
1149abb0f93cSkardel 	ss->oldversionpkt = htonl((u_int32)sys_oldversion);
1150abb0f93cSkardel 	ss->newversionpkt = htonl((u_int32)sys_newversion);
1151abb0f93cSkardel 	ss->unknownversion = htonl((u_int32)sys_declined);
1152abb0f93cSkardel 	ss->badlength = htonl((u_int32)sys_badlength);
1153abb0f93cSkardel 	ss->processed = htonl((u_int32)sys_processed);
1154abb0f93cSkardel 	ss->badauth = htonl((u_int32)sys_badauth);
1155abb0f93cSkardel 	ss->limitrejected = htonl((u_int32)sys_limitrejected);
1156abb0f93cSkardel 	ss->received = htonl((u_int32)sys_received);
11574eea345dSchristos 	ss->lamport = htonl((u_int32)sys_lamport);
11584eea345dSchristos 	ss->tsrounding = htonl((u_int32)sys_tsrounding);
1159abb0f93cSkardel 	(void) more_pkt();
1160abb0f93cSkardel 	flush_pkt();
1161abb0f93cSkardel }
1162abb0f93cSkardel 
1163abb0f93cSkardel 
1164abb0f93cSkardel /*
1165abb0f93cSkardel  * mem_stats - return memory statistics
1166abb0f93cSkardel  */
1167abb0f93cSkardel static void
1168abb0f93cSkardel mem_stats(
1169abb0f93cSkardel 	sockaddr_u *srcadr,
11702950cc38Schristos 	endpt *inter,
1171abb0f93cSkardel 	struct req_pkt *inpkt
1172abb0f93cSkardel 	)
1173abb0f93cSkardel {
1174abb0f93cSkardel 	register struct info_mem_stats *ms;
1175abb0f93cSkardel 	register int i;
1176abb0f93cSkardel 
1177abb0f93cSkardel 	ms = (struct info_mem_stats *)prepare_pkt(srcadr, inter, inpkt,
1178abb0f93cSkardel 						  sizeof(struct info_mem_stats));
1179abb0f93cSkardel 
1180abb0f93cSkardel 	ms->timereset = htonl((u_int32)(current_time - peer_timereset));
1181abb0f93cSkardel 	ms->totalpeermem = htons((u_short)total_peer_structs);
1182abb0f93cSkardel 	ms->freepeermem = htons((u_short)peer_free_count);
1183abb0f93cSkardel 	ms->findpeer_calls = htonl((u_int32)findpeer_calls);
1184abb0f93cSkardel 	ms->allocations = htonl((u_int32)peer_allocations);
1185abb0f93cSkardel 	ms->demobilizations = htonl((u_int32)peer_demobilizations);
1186abb0f93cSkardel 
11872950cc38Schristos 	for (i = 0; i < NTP_HASH_SIZE; i++)
11882950cc38Schristos 		ms->hashcount[i] = (u_char)
118950c1baceSchristos 		    min((u_int)peer_hash_count[i], UCHAR_MAX);
1190abb0f93cSkardel 
119168dbbb44Schristos 	(void) more_pkt();
1192abb0f93cSkardel 	flush_pkt();
1193abb0f93cSkardel }
1194abb0f93cSkardel 
1195abb0f93cSkardel 
1196abb0f93cSkardel /*
1197abb0f93cSkardel  * io_stats - return io statistics
1198abb0f93cSkardel  */
1199abb0f93cSkardel static void
1200abb0f93cSkardel io_stats(
1201abb0f93cSkardel 	sockaddr_u *srcadr,
12022950cc38Schristos 	endpt *inter,
1203abb0f93cSkardel 	struct req_pkt *inpkt
1204abb0f93cSkardel 	)
1205abb0f93cSkardel {
12062950cc38Schristos 	struct info_io_stats *io;
1207abb0f93cSkardel 
1208abb0f93cSkardel 	io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt,
1209abb0f93cSkardel 						 sizeof(struct info_io_stats));
1210abb0f93cSkardel 
1211abb0f93cSkardel 	io->timereset = htonl((u_int32)(current_time - io_timereset));
1212abb0f93cSkardel 	io->totalrecvbufs = htons((u_short) total_recvbuffs());
1213abb0f93cSkardel 	io->freerecvbufs = htons((u_short) free_recvbuffs());
1214abb0f93cSkardel 	io->fullrecvbufs = htons((u_short) full_recvbuffs());
1215abb0f93cSkardel 	io->lowwater = htons((u_short) lowater_additions());
1216abb0f93cSkardel 	io->dropped = htonl((u_int32)packets_dropped);
1217abb0f93cSkardel 	io->ignored = htonl((u_int32)packets_ignored);
1218abb0f93cSkardel 	io->received = htonl((u_int32)packets_received);
1219abb0f93cSkardel 	io->sent = htonl((u_int32)packets_sent);
1220abb0f93cSkardel 	io->notsent = htonl((u_int32)packets_notsent);
1221abb0f93cSkardel 	io->interrupts = htonl((u_int32)handler_calls);
1222abb0f93cSkardel 	io->int_received = htonl((u_int32)handler_pkts);
1223abb0f93cSkardel 
1224abb0f93cSkardel 	(void) more_pkt();
1225abb0f93cSkardel 	flush_pkt();
1226abb0f93cSkardel }
1227abb0f93cSkardel 
1228abb0f93cSkardel 
1229abb0f93cSkardel /*
1230abb0f93cSkardel  * timer_stats - return timer statistics
1231abb0f93cSkardel  */
1232abb0f93cSkardel static void
1233abb0f93cSkardel timer_stats(
1234abb0f93cSkardel 	sockaddr_u *		srcadr,
12352950cc38Schristos 	endpt *			inter,
1236abb0f93cSkardel 	struct req_pkt *	inpkt
1237abb0f93cSkardel 	)
1238abb0f93cSkardel {
12393123f114Skardel 	struct info_timer_stats *	ts;
12403123f114Skardel 	u_long				sincereset;
1241abb0f93cSkardel 
12423123f114Skardel 	ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter,
12433123f114Skardel 						    inpkt, sizeof(*ts));
1244abb0f93cSkardel 
12453123f114Skardel 	sincereset = current_time - timer_timereset;
12463123f114Skardel 	ts->timereset = htonl((u_int32)sincereset);
12473123f114Skardel 	ts->alarms = ts->timereset;
12483123f114Skardel 	ts->overflows = htonl((u_int32)alarm_overflow);
1249abb0f93cSkardel 	ts->xmtcalls = htonl((u_int32)timer_xmtcalls);
1250abb0f93cSkardel 
1251abb0f93cSkardel 	(void) more_pkt();
1252abb0f93cSkardel 	flush_pkt();
1253abb0f93cSkardel }
1254abb0f93cSkardel 
1255abb0f93cSkardel 
1256abb0f93cSkardel /*
1257abb0f93cSkardel  * loop_info - return the current state of the loop filter
1258abb0f93cSkardel  */
1259abb0f93cSkardel static void
1260abb0f93cSkardel loop_info(
1261abb0f93cSkardel 	sockaddr_u *srcadr,
12622950cc38Schristos 	endpt *inter,
1263abb0f93cSkardel 	struct req_pkt *inpkt
1264abb0f93cSkardel 	)
1265abb0f93cSkardel {
12662950cc38Schristos 	struct info_loop *li;
1267abb0f93cSkardel 	l_fp ltmp;
1268abb0f93cSkardel 
1269abb0f93cSkardel 	li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt,
1270abb0f93cSkardel 	    sizeof(struct info_loop));
1271abb0f93cSkardel 
1272abb0f93cSkardel 	DTOLFP(last_offset, &ltmp);
1273abb0f93cSkardel 	HTONL_FP(&ltmp, &li->last_offset);
1274abb0f93cSkardel 	DTOLFP(drift_comp * 1e6, &ltmp);
1275abb0f93cSkardel 	HTONL_FP(&ltmp, &li->drift_comp);
1276abb0f93cSkardel 	li->compliance = htonl((u_int32)(tc_counter));
1277abb0f93cSkardel 	li->watchdog_timer = htonl((u_int32)(current_time - sys_epoch));
1278abb0f93cSkardel 
127968dbbb44Schristos 	(void) more_pkt();
1280abb0f93cSkardel 	flush_pkt();
1281abb0f93cSkardel }
1282abb0f93cSkardel 
1283abb0f93cSkardel 
1284abb0f93cSkardel /*
1285abb0f93cSkardel  * do_conf - add a peer to the configuration list
1286abb0f93cSkardel  */
1287abb0f93cSkardel static void
1288abb0f93cSkardel do_conf(
1289abb0f93cSkardel 	sockaddr_u *srcadr,
12902950cc38Schristos 	endpt *inter,
1291abb0f93cSkardel 	struct req_pkt *inpkt
1292abb0f93cSkardel 	)
1293abb0f93cSkardel {
12942950cc38Schristos 	u_short			items;
12952950cc38Schristos 	size_t			item_sz;
1296abb0f93cSkardel 	u_int			fl;
12972950cc38Schristos 	char *			datap;
1298abb0f93cSkardel 	struct conf_peer	temp_cp;
1299abb0f93cSkardel 	sockaddr_u		peeraddr;
1300abb0f93cSkardel 
1301abb0f93cSkardel 	/*
1302abb0f93cSkardel 	 * Do a check of everything to see that it looks
1303abb0f93cSkardel 	 * okay.  If not, complain about it.  Note we are
1304abb0f93cSkardel 	 * very picky here.
1305abb0f93cSkardel 	 */
1306abb0f93cSkardel 	items = INFO_NITEMS(inpkt->err_nitems);
13072950cc38Schristos 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
13082950cc38Schristos 	datap = inpkt->u.data;
13092950cc38Schristos 	if (item_sz > sizeof(temp_cp)) {
1310abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1311abb0f93cSkardel 		return;
1312abb0f93cSkardel 	}
1313abb0f93cSkardel 
1314abb0f93cSkardel 	while (items-- > 0) {
13152950cc38Schristos 		ZERO(temp_cp);
13162950cc38Schristos 		memcpy(&temp_cp, datap, item_sz);
1317abb0f93cSkardel 		ZERO_SOCK(&peeraddr);
1318abb0f93cSkardel 
1319abb0f93cSkardel 		fl = 0;
1320abb0f93cSkardel 		if (temp_cp.flags & CONF_FLAG_PREFER)
1321abb0f93cSkardel 			fl |= FLAG_PREFER;
1322abb0f93cSkardel 		if (temp_cp.flags & CONF_FLAG_BURST)
1323abb0f93cSkardel 			fl |= FLAG_BURST;
1324abb0f93cSkardel 		if (temp_cp.flags & CONF_FLAG_IBURST)
1325abb0f93cSkardel 			fl |= FLAG_IBURST;
13262950cc38Schristos #ifdef AUTOKEY
1327abb0f93cSkardel 		if (temp_cp.flags & CONF_FLAG_SKEY)
1328abb0f93cSkardel 			fl |= FLAG_SKEY;
13292950cc38Schristos #endif	/* AUTOKEY */
13302950cc38Schristos 		if (client_v6_capable && temp_cp.v6_flag) {
1331abb0f93cSkardel 			AF(&peeraddr) = AF_INET6;
1332abb0f93cSkardel 			SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6;
1333abb0f93cSkardel 		} else {
1334abb0f93cSkardel 			AF(&peeraddr) = AF_INET;
1335abb0f93cSkardel 			NSRCADR(&peeraddr) = temp_cp.peeraddr;
1336abb0f93cSkardel 			/*
1337abb0f93cSkardel 			 * Make sure the address is valid
1338abb0f93cSkardel 			 */
1339abb0f93cSkardel 			if (!ISREFCLOCKADR(&peeraddr) &&
1340abb0f93cSkardel 			    ISBADADR(&peeraddr)) {
1341abb0f93cSkardel 				req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1342abb0f93cSkardel 				return;
1343abb0f93cSkardel 			}
1344abb0f93cSkardel 
1345abb0f93cSkardel 		}
1346abb0f93cSkardel 		NSRCPORT(&peeraddr) = htons(NTP_PORT);
1347abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN
13483123f114Skardel 		peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
1349abb0f93cSkardel #endif
1350abb0f93cSkardel 
135168dbbb44Schristos 		/* check mode value: 0 <= hmode <= 6
135268dbbb44Schristos 		 *
135368dbbb44Schristos 		 * There's no good global define for that limit, and
135468dbbb44Schristos 		 * using a magic define is as good (or bad, actually) as
135568dbbb44Schristos 		 * a magic number. So we use the highest possible peer
135668dbbb44Schristos 		 * mode, and that is MODE_BCLIENT.
135768dbbb44Schristos 		 *
135868dbbb44Schristos 		 * [Bug 3009] claims that a problem occurs for hmode > 7,
135968dbbb44Schristos 		 * but the code in ntp_peer.c indicates trouble for any
136068dbbb44Schristos 		 * hmode > 6 ( --> MODE_BCLIENT).
136168dbbb44Schristos 		 */
136268dbbb44Schristos 		if (temp_cp.hmode > MODE_BCLIENT) {
136368dbbb44Schristos 			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
136468dbbb44Schristos 			return;
136568dbbb44Schristos 		}
136668dbbb44Schristos 
136768dbbb44Schristos 		/* Any more checks on the values? Unchecked at this
136868dbbb44Schristos 		 * point:
136968dbbb44Schristos 		 *   - version
137068dbbb44Schristos 		 *   - ttl
137168dbbb44Schristos 		 *   - keyid
137268dbbb44Schristos 		 *
137368dbbb44Schristos 		 *   - minpoll/maxpoll, but they are treated properly
137468dbbb44Schristos 		 *     for all cases internally. Checking not necessary.
13754eea345dSchristos 		 *
13764eea345dSchristos 		 * Note that we ignore any previously-specified ippeerlimit.
13774eea345dSchristos 		 * If we're told to create the peer, we create the peer.
137868dbbb44Schristos 		 */
137968dbbb44Schristos 
138068dbbb44Schristos 		/* finally create the peer */
13814eea345dSchristos 		if (peer_config(&peeraddr, NULL, NULL, -1,
1382abb0f93cSkardel 		    temp_cp.hmode, temp_cp.version, temp_cp.minpoll,
1383abb0f93cSkardel 		    temp_cp.maxpoll, fl, temp_cp.ttl, temp_cp.keyid,
138468dbbb44Schristos 		    NULL) == 0)
138568dbbb44Schristos 		{
1386abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
1387abb0f93cSkardel 			return;
1388abb0f93cSkardel 		}
1389abb0f93cSkardel 
13902950cc38Schristos 		datap += item_sz;
1391abb0f93cSkardel 	}
1392abb0f93cSkardel 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
1393abb0f93cSkardel }
1394abb0f93cSkardel 
1395abb0f93cSkardel 
1396abb0f93cSkardel /*
1397abb0f93cSkardel  * do_unconf - remove a peer from the configuration list
1398abb0f93cSkardel  */
1399abb0f93cSkardel static void
1400abb0f93cSkardel do_unconf(
1401abb0f93cSkardel 	sockaddr_u *	srcadr,
14022950cc38Schristos 	endpt *		inter,
1403abb0f93cSkardel 	struct req_pkt *inpkt
1404abb0f93cSkardel 	)
1405abb0f93cSkardel {
14062950cc38Schristos 	u_short			items;
14072950cc38Schristos 	size_t			item_sz;
14082950cc38Schristos 	char *			datap;
1409abb0f93cSkardel 	struct conf_unpeer	temp_cp;
14102950cc38Schristos 	struct peer *		p;
1411abb0f93cSkardel 	sockaddr_u		peeraddr;
141268dbbb44Schristos 	int			loops;
1413abb0f93cSkardel 
1414abb0f93cSkardel 	/*
1415abb0f93cSkardel 	 * This is a bit unstructured, but I like to be careful.
1416abb0f93cSkardel 	 * We check to see that every peer exists and is actually
1417abb0f93cSkardel 	 * configured.  If so, we remove them.  If not, we return
1418abb0f93cSkardel 	 * an error.
141968dbbb44Schristos 	 *
142068dbbb44Schristos 	 * [Bug 3011] Even if we checked all peers given in the request
142168dbbb44Schristos 	 * in a dry run, there's still a chance that the caller played
142268dbbb44Schristos 	 * unfair and gave the same peer multiple times. So we still
142368dbbb44Schristos 	 * have to be prepared for nasty surprises in the second run ;)
1424abb0f93cSkardel 	 */
142568dbbb44Schristos 
142668dbbb44Schristos 	/* basic consistency checks */
14272950cc38Schristos 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
14282950cc38Schristos 	if (item_sz > sizeof(temp_cp)) {
14292950cc38Schristos 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
14302950cc38Schristos 		return;
14312950cc38Schristos 	}
1432abb0f93cSkardel 
143368dbbb44Schristos 	/* now do two runs: first a dry run, then a busy one */
143468dbbb44Schristos 	for (loops = 0; loops != 2; ++loops) {
143568dbbb44Schristos 		items = INFO_NITEMS(inpkt->err_nitems);
143668dbbb44Schristos 		datap = inpkt->u.data;
143768dbbb44Schristos 		while (items-- > 0) {
143868dbbb44Schristos 			/* copy from request to local */
14392950cc38Schristos 			ZERO(temp_cp);
14402950cc38Schristos 			memcpy(&temp_cp, datap, item_sz);
144168dbbb44Schristos 			/* get address structure */
1442abb0f93cSkardel 			ZERO_SOCK(&peeraddr);
1443abb0f93cSkardel 			if (client_v6_capable && temp_cp.v6_flag) {
1444abb0f93cSkardel 				AF(&peeraddr) = AF_INET6;
1445abb0f93cSkardel 				SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6;
1446abb0f93cSkardel 			} else {
1447abb0f93cSkardel 				AF(&peeraddr) = AF_INET;
1448abb0f93cSkardel 				NSRCADR(&peeraddr) = temp_cp.peeraddr;
1449abb0f93cSkardel 			}
1450abb0f93cSkardel 			SET_PORT(&peeraddr, NTP_PORT);
1451abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN
14523123f114Skardel 			peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
1453abb0f93cSkardel #endif
145468dbbb44Schristos 			DPRINTF(1, ("searching for %s\n",
145568dbbb44Schristos 				    stoa(&peeraddr)));
145668dbbb44Schristos 
145768dbbb44Schristos 			/* search for matching configred(!) peer */
14582950cc38Schristos 			p = NULL;
145968dbbb44Schristos 			do {
146068dbbb44Schristos 				p = findexistingpeer(
14614eea345dSchristos 					&peeraddr, NULL, p, -1, 0, NULL);
146268dbbb44Schristos 			} while (p && !(FLAG_CONFIG & p->flags));
1463abb0f93cSkardel 
146468dbbb44Schristos 			if (!loops && !p) {
146568dbbb44Schristos 				/* Item not found in dry run -- bail! */
146668dbbb44Schristos 				req_ack(srcadr, inter, inpkt,
146768dbbb44Schristos 					INFO_ERR_NODATA);
1468abb0f93cSkardel 				return;
146968dbbb44Schristos 			} else if (loops && p) {
147068dbbb44Schristos 				/* Item found in busy run -- remove! */
14712950cc38Schristos 				peer_clear(p, "GONE");
14722950cc38Schristos 				unpeer(p);
147368dbbb44Schristos 			}
14742950cc38Schristos 			datap += item_sz;
1475abb0f93cSkardel 		}
147668dbbb44Schristos 	}
1477abb0f93cSkardel 
147868dbbb44Schristos 	/* report success */
1479abb0f93cSkardel 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
1480abb0f93cSkardel }
1481abb0f93cSkardel 
1482abb0f93cSkardel 
1483abb0f93cSkardel /*
1484abb0f93cSkardel  * set_sys_flag - set system flags
1485abb0f93cSkardel  */
1486abb0f93cSkardel static void
1487abb0f93cSkardel set_sys_flag(
1488abb0f93cSkardel 	sockaddr_u *srcadr,
14892950cc38Schristos 	endpt *inter,
1490abb0f93cSkardel 	struct req_pkt *inpkt
1491abb0f93cSkardel 	)
1492abb0f93cSkardel {
1493abb0f93cSkardel 	setclr_flags(srcadr, inter, inpkt, 1);
1494abb0f93cSkardel }
1495abb0f93cSkardel 
1496abb0f93cSkardel 
1497abb0f93cSkardel /*
1498abb0f93cSkardel  * clr_sys_flag - clear system flags
1499abb0f93cSkardel  */
1500abb0f93cSkardel static void
1501abb0f93cSkardel clr_sys_flag(
1502abb0f93cSkardel 	sockaddr_u *srcadr,
15032950cc38Schristos 	endpt *inter,
1504abb0f93cSkardel 	struct req_pkt *inpkt
1505abb0f93cSkardel 	)
1506abb0f93cSkardel {
1507abb0f93cSkardel 	setclr_flags(srcadr, inter, inpkt, 0);
1508abb0f93cSkardel }
1509abb0f93cSkardel 
1510abb0f93cSkardel 
1511abb0f93cSkardel /*
1512abb0f93cSkardel  * setclr_flags - do the grunge work of flag setting/clearing
1513abb0f93cSkardel  */
1514abb0f93cSkardel static void
1515abb0f93cSkardel setclr_flags(
1516abb0f93cSkardel 	sockaddr_u *srcadr,
15172950cc38Schristos 	endpt *inter,
1518abb0f93cSkardel 	struct req_pkt *inpkt,
1519abb0f93cSkardel 	u_long set
1520abb0f93cSkardel 	)
1521abb0f93cSkardel {
15223123f114Skardel 	struct conf_sys_flags *sf;
15233123f114Skardel 	u_int32 flags;
1524abb0f93cSkardel 
1525abb0f93cSkardel 	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
1526abb0f93cSkardel 		msyslog(LOG_ERR, "setclr_flags: err_nitems > 1");
1527abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1528abb0f93cSkardel 		return;
1529abb0f93cSkardel 	}
1530abb0f93cSkardel 
15312950cc38Schristos 	sf = (struct conf_sys_flags *)&inpkt->u;
15323123f114Skardel 	flags = ntohl(sf->flags);
1533abb0f93cSkardel 
1534abb0f93cSkardel 	if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS |
1535abb0f93cSkardel 		      SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR |
1536abb0f93cSkardel 		      SYS_FLAG_FILEGEN | SYS_FLAG_AUTH | SYS_FLAG_CAL)) {
1537abb0f93cSkardel 		msyslog(LOG_ERR, "setclr_flags: extra flags: %#x",
1538abb0f93cSkardel 			flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS |
1539abb0f93cSkardel 				  SYS_FLAG_NTP | SYS_FLAG_KERNEL |
1540abb0f93cSkardel 				  SYS_FLAG_MONITOR | SYS_FLAG_FILEGEN |
1541abb0f93cSkardel 				  SYS_FLAG_AUTH | SYS_FLAG_CAL));
1542abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1543abb0f93cSkardel 		return;
1544abb0f93cSkardel 	}
1545abb0f93cSkardel 
1546abb0f93cSkardel 	if (flags & SYS_FLAG_BCLIENT)
1547abb0f93cSkardel 		proto_config(PROTO_BROADCLIENT, set, 0., NULL);
1548abb0f93cSkardel 	if (flags & SYS_FLAG_PPS)
1549abb0f93cSkardel 		proto_config(PROTO_PPS, set, 0., NULL);
1550abb0f93cSkardel 	if (flags & SYS_FLAG_NTP)
1551abb0f93cSkardel 		proto_config(PROTO_NTP, set, 0., NULL);
1552abb0f93cSkardel 	if (flags & SYS_FLAG_KERNEL)
1553abb0f93cSkardel 		proto_config(PROTO_KERNEL, set, 0., NULL);
1554abb0f93cSkardel 	if (flags & SYS_FLAG_MONITOR)
1555abb0f93cSkardel 		proto_config(PROTO_MONITOR, set, 0., NULL);
1556abb0f93cSkardel 	if (flags & SYS_FLAG_FILEGEN)
1557abb0f93cSkardel 		proto_config(PROTO_FILEGEN, set, 0., NULL);
1558abb0f93cSkardel 	if (flags & SYS_FLAG_AUTH)
1559abb0f93cSkardel 		proto_config(PROTO_AUTHENTICATE, set, 0., NULL);
1560abb0f93cSkardel 	if (flags & SYS_FLAG_CAL)
1561abb0f93cSkardel 		proto_config(PROTO_CAL, set, 0., NULL);
1562abb0f93cSkardel 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
1563abb0f93cSkardel }
1564abb0f93cSkardel 
156568dbbb44Schristos /* There have been some issues with the restrict list processing,
156668dbbb44Schristos  * ranging from problems with deep recursion (resulting in stack
156768dbbb44Schristos  * overflows) and overfull reply buffers.
156868dbbb44Schristos  *
156968dbbb44Schristos  * To avoid this trouble the list reversal is done iteratively using a
157068dbbb44Schristos  * scratch pad.
157168dbbb44Schristos  */
1572*9e9fa66aSchristos typedef struct RestrictStack4 RestrictStack4T;
1573*9e9fa66aSchristos struct RestrictStack4 {
1574*9e9fa66aSchristos 	RestrictStack4T   *link;
157568dbbb44Schristos 	size_t            fcnt;
1576*9e9fa66aSchristos 	const struct restrict_4 *pres[63];
157768dbbb44Schristos };
157868dbbb44Schristos 
157968dbbb44Schristos static size_t
1580*9e9fa66aSchristos getStackSheetSize4(
1581*9e9fa66aSchristos 	RestrictStack4T *sp
158268dbbb44Schristos 	)
158368dbbb44Schristos {
158468dbbb44Schristos 	if (sp)
158568dbbb44Schristos 		return sizeof(sp->pres)/sizeof(sp->pres[0]);
158668dbbb44Schristos 	return 0u;
158768dbbb44Schristos }
158868dbbb44Schristos 
158968dbbb44Schristos static int/*BOOL*/
1590*9e9fa66aSchristos pushRestriction4(
1591*9e9fa66aSchristos 	RestrictStack4T  **spp,
1592*9e9fa66aSchristos 	const struct restrict_4 *ptr
159368dbbb44Schristos 	)
159468dbbb44Schristos {
1595*9e9fa66aSchristos 	RestrictStack4T *sp;
159668dbbb44Schristos 
159768dbbb44Schristos 	if (NULL == (sp = *spp) || 0 == sp->fcnt) {
159868dbbb44Schristos 		/* need another sheet in the scratch pad */
159968dbbb44Schristos 		sp = emalloc(sizeof(*sp));
160068dbbb44Schristos 		sp->link = *spp;
1601*9e9fa66aSchristos 		sp->fcnt = getStackSheetSize4(sp);
160268dbbb44Schristos 		*spp = sp;
160368dbbb44Schristos 	}
160468dbbb44Schristos 	sp->pres[--sp->fcnt] = ptr;
160568dbbb44Schristos 	return TRUE;
160668dbbb44Schristos }
160768dbbb44Schristos 
160868dbbb44Schristos static int/*BOOL*/
1609*9e9fa66aSchristos popRestriction4(
1610*9e9fa66aSchristos 	RestrictStack4T   **spp,
1611*9e9fa66aSchristos 	const struct restrict_4 **opp
161268dbbb44Schristos 	)
161368dbbb44Schristos {
1614*9e9fa66aSchristos 	RestrictStack4T *sp;
161568dbbb44Schristos 
1616*9e9fa66aSchristos 	if (NULL == (sp = *spp) || sp->fcnt >= getStackSheetSize4(sp))
161768dbbb44Schristos 		return FALSE;
161868dbbb44Schristos 
161968dbbb44Schristos 	*opp = sp->pres[sp->fcnt++];
1620*9e9fa66aSchristos 	if (sp->fcnt >= getStackSheetSize4(sp)) {
162168dbbb44Schristos 		/* discard sheet from scratch pad */
162268dbbb44Schristos 		*spp = sp->link;
162368dbbb44Schristos 		free(sp);
162468dbbb44Schristos 	}
162568dbbb44Schristos 	return TRUE;
162668dbbb44Schristos }
162768dbbb44Schristos 
162868dbbb44Schristos static void
1629*9e9fa66aSchristos flushRestrictionStack4(
1630*9e9fa66aSchristos 	RestrictStack4T **spp
163168dbbb44Schristos 	)
163268dbbb44Schristos {
1633*9e9fa66aSchristos 	RestrictStack4T *sp;
163468dbbb44Schristos 
163568dbbb44Schristos 	while (NULL != (sp = *spp)) {
163668dbbb44Schristos 		*spp = sp->link;
163768dbbb44Schristos 		free(sp);
163868dbbb44Schristos 	}
163968dbbb44Schristos }
164068dbbb44Schristos 
16413123f114Skardel /*
164268dbbb44Schristos  * list_restrict4 - iterative helper for list_restrict dumps IPv4
16433123f114Skardel  *		    restriction list in reverse order.
16443123f114Skardel  */
16453123f114Skardel static void
16463123f114Skardel list_restrict4(
1647*9e9fa66aSchristos 	const struct restrict_4 *	res,
16483123f114Skardel 	struct info_restrict **	ppir
16493123f114Skardel 	)
16503123f114Skardel {
1651*9e9fa66aSchristos 	RestrictStack4T *	rpad;
16523123f114Skardel 	struct info_restrict *	pir;
16533123f114Skardel 
16543123f114Skardel 	pir = *ppir;
165568dbbb44Schristos 	for (rpad = NULL; res; res = res->link)
1656*9e9fa66aSchristos 		if (!pushRestriction4(&rpad, res))
165768dbbb44Schristos 			break;
165868dbbb44Schristos 
1659*9e9fa66aSchristos 	while (pir && popRestriction4(&rpad, &res)) {
1660*9e9fa66aSchristos 		pir->addr = htonl(res->v4.addr);
16613123f114Skardel 		if (client_v6_capable)
16623123f114Skardel 			pir->v6_flag = 0;
1663*9e9fa66aSchristos 		pir->mask = htonl(res->v4.mask);
1664*9e9fa66aSchristos 		pir->count = htonl(res->ri.count);
1665*9e9fa66aSchristos 		pir->rflags = htons(res->ri.rflags);
1666*9e9fa66aSchristos 		pir->mflags = htons(res->ri.mflags);
166768dbbb44Schristos 		pir = (struct info_restrict *)more_pkt();
166868dbbb44Schristos 	}
1669*9e9fa66aSchristos 	flushRestrictionStack4(&rpad);
167068dbbb44Schristos 	*ppir = pir;
16713123f114Skardel }
16723123f114Skardel 
1673*9e9fa66aSchristos typedef struct RestrictStack6 RestrictStack6T;
1674*9e9fa66aSchristos struct RestrictStack6 {
1675*9e9fa66aSchristos 	RestrictStack6T   *link;
1676*9e9fa66aSchristos 	size_t            fcnt;
1677*9e9fa66aSchristos 	const struct restrict_6 *pres[63];
1678*9e9fa66aSchristos };
1679*9e9fa66aSchristos 
1680*9e9fa66aSchristos static size_t
1681*9e9fa66aSchristos getStackSheetSize6(
1682*9e9fa66aSchristos 	RestrictStack6T *sp
1683*9e9fa66aSchristos 	)
1684*9e9fa66aSchristos {
1685*9e9fa66aSchristos 	if (sp)
1686*9e9fa66aSchristos 		return sizeof(sp->pres)/sizeof(sp->pres[0]);
1687*9e9fa66aSchristos 	return 0u;
1688*9e9fa66aSchristos }
1689*9e9fa66aSchristos 
1690*9e9fa66aSchristos static int/*BOOL*/
1691*9e9fa66aSchristos pushRestriction6(
1692*9e9fa66aSchristos 	RestrictStack6T  **spp,
1693*9e9fa66aSchristos 	const struct restrict_6 *ptr
1694*9e9fa66aSchristos 	)
1695*9e9fa66aSchristos {
1696*9e9fa66aSchristos 	RestrictStack6T *sp;
1697*9e9fa66aSchristos 
1698*9e9fa66aSchristos 	if (NULL == (sp = *spp) || 0 == sp->fcnt) {
1699*9e9fa66aSchristos 		/* need another sheet in the scratch pad */
1700*9e9fa66aSchristos 		sp = emalloc(sizeof(*sp));
1701*9e9fa66aSchristos 		sp->link = *spp;
1702*9e9fa66aSchristos 		sp->fcnt = getStackSheetSize6(sp);
1703*9e9fa66aSchristos 		*spp = sp;
1704*9e9fa66aSchristos 	}
1705*9e9fa66aSchristos 	sp->pres[--sp->fcnt] = ptr;
1706*9e9fa66aSchristos 	return TRUE;
1707*9e9fa66aSchristos }
1708*9e9fa66aSchristos 
1709*9e9fa66aSchristos static int/*BOOL*/
1710*9e9fa66aSchristos popRestriction6(
1711*9e9fa66aSchristos 	RestrictStack6T   **spp,
1712*9e9fa66aSchristos 	const struct restrict_6 **opp
1713*9e9fa66aSchristos 	)
1714*9e9fa66aSchristos {
1715*9e9fa66aSchristos 	RestrictStack6T *sp;
1716*9e9fa66aSchristos 
1717*9e9fa66aSchristos 	if (NULL == (sp = *spp) || sp->fcnt >= getStackSheetSize6(sp))
1718*9e9fa66aSchristos 		return FALSE;
1719*9e9fa66aSchristos 
1720*9e9fa66aSchristos 	*opp = sp->pres[sp->fcnt++];
1721*9e9fa66aSchristos 	if (sp->fcnt >= getStackSheetSize6(sp)) {
1722*9e9fa66aSchristos 		/* discard sheet from scratch pad */
1723*9e9fa66aSchristos 		*spp = sp->link;
1724*9e9fa66aSchristos 		free(sp);
1725*9e9fa66aSchristos 	}
1726*9e9fa66aSchristos 	return TRUE;
1727*9e9fa66aSchristos }
1728*9e9fa66aSchristos 
1729*9e9fa66aSchristos static void
1730*9e9fa66aSchristos flushRestrictionStack6(
1731*9e9fa66aSchristos 	RestrictStack6T **spp
1732*9e9fa66aSchristos 	)
1733*9e9fa66aSchristos {
1734*9e9fa66aSchristos 	RestrictStack6T *sp;
1735*9e9fa66aSchristos 
1736*9e9fa66aSchristos 	while (NULL != (sp = *spp)) {
1737*9e9fa66aSchristos 		*spp = sp->link;
1738*9e9fa66aSchristos 		free(sp);
1739*9e9fa66aSchristos 	}
1740*9e9fa66aSchristos }
1741*9e9fa66aSchristos 
17423123f114Skardel /*
174368dbbb44Schristos  * list_restrict6 - iterative helper for list_restrict dumps IPv6
17443123f114Skardel  *		    restriction list in reverse order.
17453123f114Skardel  */
17463123f114Skardel static void
17473123f114Skardel list_restrict6(
1748*9e9fa66aSchristos 	const struct restrict_6 *	res,
17493123f114Skardel 	struct info_restrict **	ppir
17503123f114Skardel 	)
17513123f114Skardel {
1752*9e9fa66aSchristos 	RestrictStack6T *	rpad;
17533123f114Skardel 	struct info_restrict *	pir;
17543123f114Skardel 
17553123f114Skardel 	pir = *ppir;
175668dbbb44Schristos 	for (rpad = NULL; res; res = res->link)
1757*9e9fa66aSchristos 		if (!pushRestriction6(&rpad, res))
175868dbbb44Schristos 			break;
175968dbbb44Schristos 
1760*9e9fa66aSchristos 	while (pir && popRestriction6(&rpad, &res)) {
1761*9e9fa66aSchristos 		pir->addr6 = res->v6.addr;
1762*9e9fa66aSchristos 		pir->mask6 = res->v6.mask;
17633123f114Skardel 		pir->v6_flag = 1;
1764*9e9fa66aSchristos 		pir->count = htonl(res->ri.count);
1765*9e9fa66aSchristos 		pir->rflags = htons(res->ri.rflags);
1766*9e9fa66aSchristos 		pir->mflags = htons(res->ri.mflags);
176768dbbb44Schristos 		pir = (struct info_restrict *)more_pkt();
176868dbbb44Schristos 	}
1769*9e9fa66aSchristos 	flushRestrictionStack6(&rpad);
177068dbbb44Schristos 	*ppir = pir;
17713123f114Skardel }
17723123f114Skardel 
1773abb0f93cSkardel 
1774abb0f93cSkardel /*
1775abb0f93cSkardel  * list_restrict - return the restrict list
1776abb0f93cSkardel  */
1777abb0f93cSkardel static void
1778abb0f93cSkardel list_restrict(
1779abb0f93cSkardel 	sockaddr_u *srcadr,
17802950cc38Schristos 	endpt *inter,
1781abb0f93cSkardel 	struct req_pkt *inpkt
1782abb0f93cSkardel 	)
1783abb0f93cSkardel {
17843123f114Skardel 	struct info_restrict *ir;
1785abb0f93cSkardel 
17863123f114Skardel 	DPRINTF(3, ("wants restrict list summary\n"));
1787abb0f93cSkardel 
1788abb0f93cSkardel 	ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt,
1789abb0f93cSkardel 	    v6sizeof(struct info_restrict));
1790abb0f93cSkardel 
17913123f114Skardel 	/*
17923123f114Skardel 	 * The restriction lists are kept sorted in the reverse order
17933123f114Skardel 	 * than they were originally.  To preserve the output semantics,
179468dbbb44Schristos 	 * dump each list in reverse order. The workers take care of that.
17953123f114Skardel 	 */
17963123f114Skardel 	list_restrict4(restrictlist4, &ir);
1797abb0f93cSkardel 	if (client_v6_capable)
17983123f114Skardel 		list_restrict6(restrictlist6, &ir);
1799abb0f93cSkardel 	flush_pkt();
1800abb0f93cSkardel }
1801abb0f93cSkardel 
1802abb0f93cSkardel 
1803abb0f93cSkardel /*
1804abb0f93cSkardel  * do_resaddflags - add flags to a restrict entry (or create one)
1805abb0f93cSkardel  */
1806abb0f93cSkardel static void
1807abb0f93cSkardel do_resaddflags(
1808abb0f93cSkardel 	sockaddr_u *srcadr,
18092950cc38Schristos 	endpt *inter,
1810abb0f93cSkardel 	struct req_pkt *inpkt
1811abb0f93cSkardel 	)
1812abb0f93cSkardel {
1813abb0f93cSkardel 	do_restrict(srcadr, inter, inpkt, RESTRICT_FLAGS);
1814abb0f93cSkardel }
1815abb0f93cSkardel 
1816abb0f93cSkardel 
1817abb0f93cSkardel 
1818abb0f93cSkardel /*
1819abb0f93cSkardel  * do_ressubflags - remove flags from a restrict entry
1820abb0f93cSkardel  */
1821abb0f93cSkardel static void
1822abb0f93cSkardel do_ressubflags(
1823abb0f93cSkardel 	sockaddr_u *srcadr,
18242950cc38Schristos 	endpt *inter,
1825abb0f93cSkardel 	struct req_pkt *inpkt
1826abb0f93cSkardel 	)
1827abb0f93cSkardel {
1828abb0f93cSkardel 	do_restrict(srcadr, inter, inpkt, RESTRICT_UNFLAG);
1829abb0f93cSkardel }
1830abb0f93cSkardel 
1831abb0f93cSkardel 
1832abb0f93cSkardel /*
1833abb0f93cSkardel  * do_unrestrict - remove a restrict entry from the list
1834abb0f93cSkardel  */
1835abb0f93cSkardel static void
1836abb0f93cSkardel do_unrestrict(
1837abb0f93cSkardel 	sockaddr_u *srcadr,
18382950cc38Schristos 	endpt *inter,
1839abb0f93cSkardel 	struct req_pkt *inpkt
1840abb0f93cSkardel 	)
1841abb0f93cSkardel {
1842abb0f93cSkardel 	do_restrict(srcadr, inter, inpkt, RESTRICT_REMOVE);
1843abb0f93cSkardel }
1844abb0f93cSkardel 
1845abb0f93cSkardel 
1846abb0f93cSkardel /*
1847abb0f93cSkardel  * do_restrict - do the dirty stuff of dealing with restrictions
1848abb0f93cSkardel  */
1849abb0f93cSkardel static void
1850abb0f93cSkardel do_restrict(
1851abb0f93cSkardel 	sockaddr_u *srcadr,
18522950cc38Schristos 	endpt *inter,
1853abb0f93cSkardel 	struct req_pkt *inpkt,
18544eea345dSchristos 	restrict_op op
1855abb0f93cSkardel 	)
1856abb0f93cSkardel {
18572950cc38Schristos 	char *			datap;
18582950cc38Schristos 	struct conf_restrict	cr;
18592950cc38Schristos 	u_short			items;
18602950cc38Schristos 	size_t			item_sz;
1861abb0f93cSkardel 	sockaddr_u		matchaddr;
1862abb0f93cSkardel 	sockaddr_u		matchmask;
1863abb0f93cSkardel 	int			bad;
1864eabc0478Schristos 	int/*BOOL*/		success;
1865abb0f93cSkardel 
18664eea345dSchristos 	switch(op) {
18674eea345dSchristos 	    case RESTRICT_FLAGS:
18684eea345dSchristos 	    case RESTRICT_UNFLAG:
18694eea345dSchristos 	    case RESTRICT_REMOVE:
18704eea345dSchristos 	    case RESTRICT_REMOVEIF:
18714eea345dSchristos 	    	break;
18724eea345dSchristos 
18734eea345dSchristos 	    default:
18744eea345dSchristos 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
18754eea345dSchristos 		return;
18764eea345dSchristos 	}
18774eea345dSchristos 
1878abb0f93cSkardel 	/*
1879abb0f93cSkardel 	 * Do a check of the flags to make sure that only
1880abb0f93cSkardel 	 * the NTPPORT flag is set, if any.  If not, complain
1881abb0f93cSkardel 	 * about it.  Note we are very picky here.
1882abb0f93cSkardel 	 */
1883abb0f93cSkardel 	items = INFO_NITEMS(inpkt->err_nitems);
18842950cc38Schristos 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
18852950cc38Schristos 	datap = inpkt->u.data;
18862950cc38Schristos 	if (item_sz > sizeof(cr)) {
18872950cc38Schristos 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
18882950cc38Schristos 		return;
18892950cc38Schristos 	}
1890abb0f93cSkardel 
18914eea345dSchristos 	bad = 0;
1892abb0f93cSkardel 	while (items-- > 0 && !bad) {
18932950cc38Schristos 		memcpy(&cr, datap, item_sz);
1894cdfa2a7eSchristos 		cr.flags = ntohs(cr.flags);	/* XXX */
18952950cc38Schristos 		cr.mflags = ntohs(cr.mflags);
18962950cc38Schristos 		if (~RESM_NTPONLY & cr.mflags)
1897abb0f93cSkardel 			bad |= 1;
18982950cc38Schristos 		if (~RES_ALLFLAGS & cr.flags)
1899abb0f93cSkardel 			bad |= 2;
19002950cc38Schristos 		if (INADDR_ANY != cr.mask) {
19012950cc38Schristos 			if (client_v6_capable && cr.v6_flag) {
19022950cc38Schristos 				if (IN6_IS_ADDR_UNSPECIFIED(&cr.addr6))
1903abb0f93cSkardel 					bad |= 4;
19042950cc38Schristos 			} else {
19052950cc38Schristos 				if (INADDR_ANY == cr.addr)
1906abb0f93cSkardel 					bad |= 8;
1907abb0f93cSkardel 			}
19082950cc38Schristos 		}
19092950cc38Schristos 		datap += item_sz;
1910abb0f93cSkardel 	}
1911abb0f93cSkardel 
1912abb0f93cSkardel 	if (bad) {
1913eabc0478Schristos 		msyslog(LOG_ERR, "%s: bad = 0x%x", __func__, bad);
1914abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1915abb0f93cSkardel 		return;
1916abb0f93cSkardel 	}
1917abb0f93cSkardel 
1918abb0f93cSkardel 	/*
1919af12ab5eSchristos 	 * Looks okay, try it out.  Needs to reload data pointer and
1920af12ab5eSchristos 	 * item counter. (Talos-CAN-0052)
1921abb0f93cSkardel 	 */
1922abb0f93cSkardel 	ZERO_SOCK(&matchaddr);
1923abb0f93cSkardel 	ZERO_SOCK(&matchmask);
1924af12ab5eSchristos 	items = INFO_NITEMS(inpkt->err_nitems);
19252950cc38Schristos 	datap = inpkt->u.data;
1926abb0f93cSkardel 
1927abb0f93cSkardel 	while (items-- > 0) {
19282950cc38Schristos 		memcpy(&cr, datap, item_sz);
1929cdfa2a7eSchristos 		cr.flags = ntohs(cr.flags);	/* XXX: size */
19302950cc38Schristos 		cr.mflags = ntohs(cr.mflags);
19314eea345dSchristos 		cr.ippeerlimit = ntohs(cr.ippeerlimit);
19322950cc38Schristos 		if (client_v6_capable && cr.v6_flag) {
1933abb0f93cSkardel 			AF(&matchaddr) = AF_INET6;
1934abb0f93cSkardel 			AF(&matchmask) = AF_INET6;
19352950cc38Schristos 			SOCK_ADDR6(&matchaddr) = cr.addr6;
19362950cc38Schristos 			SOCK_ADDR6(&matchmask) = cr.mask6;
1937abb0f93cSkardel 		} else {
1938abb0f93cSkardel 			AF(&matchaddr) = AF_INET;
1939abb0f93cSkardel 			AF(&matchmask) = AF_INET;
19402950cc38Schristos 			NSRCADR(&matchaddr) = cr.addr;
19412950cc38Schristos 			NSRCADR(&matchmask) = cr.mask;
1942abb0f93cSkardel 		}
1943eabc0478Schristos 		success =  hack_restrict(op, &matchaddr, &matchmask,
1944eabc0478Schristos 					 cr.ippeerlimit, cr.mflags,
1945eabc0478Schristos 					 cr.flags, 0);
1946eabc0478Schristos 		if (!success) {
1947eabc0478Schristos 			DPRINTF(1, ("%s: %s %s mask %s ippeerlimit %hd %s %s failed",
1948eabc0478Schristos 				    __func__, resop_str(op),
1949eabc0478Schristos 				    stoa(&matchaddr), stoa(&matchmask),
1950eabc0478Schristos 				    cr.ippeerlimit, mflags_str(cr.mflags),
1951eabc0478Schristos 				    rflags_str(cr.flags)));
1952eabc0478Schristos 		}
19532950cc38Schristos 		datap += item_sz;
1954abb0f93cSkardel 	}
1955abb0f93cSkardel 
1956abb0f93cSkardel 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
1957abb0f93cSkardel }
1958abb0f93cSkardel 
1959abb0f93cSkardel 
1960abb0f93cSkardel /*
1961abb0f93cSkardel  * mon_getlist - return monitor data
1962abb0f93cSkardel  */
1963abb0f93cSkardel static void
19642950cc38Schristos mon_getlist(
1965abb0f93cSkardel 	sockaddr_u *srcadr,
19662950cc38Schristos 	endpt *inter,
1967abb0f93cSkardel 	struct req_pkt *inpkt
1968abb0f93cSkardel 	)
1969abb0f93cSkardel {
1970abb0f93cSkardel 	req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
1971abb0f93cSkardel }
1972abb0f93cSkardel 
1973abb0f93cSkardel 
1974abb0f93cSkardel /*
1975abb0f93cSkardel  * Module entry points and the flags they correspond with
1976abb0f93cSkardel  */
1977abb0f93cSkardel struct reset_entry {
1978abb0f93cSkardel 	int flag;		/* flag this corresponds to */
1979abb0f93cSkardel 	void (*handler)(void);	/* routine to handle request */
1980abb0f93cSkardel };
1981abb0f93cSkardel 
1982abb0f93cSkardel struct reset_entry reset_entries[] = {
1983abb0f93cSkardel 	{ RESET_FLAG_ALLPEERS,	peer_all_reset },
1984abb0f93cSkardel 	{ RESET_FLAG_IO,	io_clr_stats },
1985abb0f93cSkardel 	{ RESET_FLAG_SYS,	proto_clr_stats },
1986abb0f93cSkardel 	{ RESET_FLAG_MEM,	peer_clr_stats },
1987abb0f93cSkardel 	{ RESET_FLAG_TIMER,	timer_clr_stats },
1988abb0f93cSkardel 	{ RESET_FLAG_AUTH,	reset_auth_stats },
1989abb0f93cSkardel 	{ RESET_FLAG_CTL,	ctl_clr_stats },
1990abb0f93cSkardel 	{ 0,			0 }
1991abb0f93cSkardel };
1992abb0f93cSkardel 
1993abb0f93cSkardel /*
1994abb0f93cSkardel  * reset_stats - reset statistic counters here and there
1995abb0f93cSkardel  */
1996abb0f93cSkardel static void
1997abb0f93cSkardel reset_stats(
1998abb0f93cSkardel 	sockaddr_u *srcadr,
19992950cc38Schristos 	endpt *inter,
2000abb0f93cSkardel 	struct req_pkt *inpkt
2001abb0f93cSkardel 	)
2002abb0f93cSkardel {
20033123f114Skardel 	struct reset_flags *rflags;
2004abb0f93cSkardel 	u_long flags;
2005abb0f93cSkardel 	struct reset_entry *rent;
2006abb0f93cSkardel 
2007abb0f93cSkardel 	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
2008abb0f93cSkardel 		msyslog(LOG_ERR, "reset_stats: err_nitems > 1");
2009abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
2010abb0f93cSkardel 		return;
2011abb0f93cSkardel 	}
2012abb0f93cSkardel 
20132950cc38Schristos 	rflags = (struct reset_flags *)&inpkt->u;
20143123f114Skardel 	flags = ntohl(rflags->flags);
2015abb0f93cSkardel 
2016abb0f93cSkardel 	if (flags & ~RESET_ALLFLAGS) {
2017abb0f93cSkardel 		msyslog(LOG_ERR, "reset_stats: reset leaves %#lx",
2018abb0f93cSkardel 			flags & ~RESET_ALLFLAGS);
2019abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
2020abb0f93cSkardel 		return;
2021abb0f93cSkardel 	}
2022abb0f93cSkardel 
2023abb0f93cSkardel 	for (rent = reset_entries; rent->flag != 0; rent++) {
2024abb0f93cSkardel 		if (flags & rent->flag)
20253123f114Skardel 			(*rent->handler)();
2026abb0f93cSkardel 	}
2027abb0f93cSkardel 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
2028abb0f93cSkardel }
2029abb0f93cSkardel 
2030abb0f93cSkardel 
2031abb0f93cSkardel /*
2032abb0f93cSkardel  * reset_peer - clear a peer's statistics
2033abb0f93cSkardel  */
2034abb0f93cSkardel static void
2035abb0f93cSkardel reset_peer(
2036abb0f93cSkardel 	sockaddr_u *srcadr,
20372950cc38Schristos 	endpt *inter,
2038abb0f93cSkardel 	struct req_pkt *inpkt
2039abb0f93cSkardel 	)
2040abb0f93cSkardel {
20412950cc38Schristos 	u_short			items;
20422950cc38Schristos 	size_t			item_sz;
20432950cc38Schristos 	char *			datap;
20442950cc38Schristos 	struct conf_unpeer	cp;
20452950cc38Schristos 	struct peer *		p;
2046abb0f93cSkardel 	sockaddr_u		peeraddr;
2047abb0f93cSkardel 	int			bad;
2048abb0f93cSkardel 
2049abb0f93cSkardel 	/*
2050abb0f93cSkardel 	 * We check first to see that every peer exists.  If not,
2051abb0f93cSkardel 	 * we return an error.
2052abb0f93cSkardel 	 */
2053abb0f93cSkardel 
2054abb0f93cSkardel 	items = INFO_NITEMS(inpkt->err_nitems);
20552950cc38Schristos 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
20562950cc38Schristos 	datap = inpkt->u.data;
20572950cc38Schristos 	if (item_sz > sizeof(cp)) {
20582950cc38Schristos 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
20592950cc38Schristos 		return;
20602950cc38Schristos 	}
2061abb0f93cSkardel 
20622950cc38Schristos 	bad = FALSE;
2063abb0f93cSkardel 	while (items-- > 0 && !bad) {
20642950cc38Schristos 		ZERO(cp);
20652950cc38Schristos 		memcpy(&cp, datap, item_sz);
2066abb0f93cSkardel 		ZERO_SOCK(&peeraddr);
20672950cc38Schristos 		if (client_v6_capable && cp.v6_flag) {
2068abb0f93cSkardel 			AF(&peeraddr) = AF_INET6;
20692950cc38Schristos 			SOCK_ADDR6(&peeraddr) = cp.peeraddr6;
2070abb0f93cSkardel 		} else {
2071abb0f93cSkardel 			AF(&peeraddr) = AF_INET;
20722950cc38Schristos 			NSRCADR(&peeraddr) = cp.peeraddr;
2073abb0f93cSkardel 		}
2074abb0f93cSkardel 
2075abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN
20763123f114Skardel 		peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
2077abb0f93cSkardel #endif
20784eea345dSchristos 		p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
20792950cc38Schristos 		if (NULL == p)
2080abb0f93cSkardel 			bad++;
20812950cc38Schristos 		datap += item_sz;
2082abb0f93cSkardel 	}
2083abb0f93cSkardel 
2084abb0f93cSkardel 	if (bad) {
2085abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2086abb0f93cSkardel 		return;
2087abb0f93cSkardel 	}
2088abb0f93cSkardel 
2089abb0f93cSkardel 	/*
2090af12ab5eSchristos 	 * Now do it in earnest. Needs to reload data pointer and item
2091af12ab5eSchristos 	 * counter. (Talos-CAN-0052)
2092abb0f93cSkardel 	 */
2093abb0f93cSkardel 
2094af12ab5eSchristos 	items = INFO_NITEMS(inpkt->err_nitems);
20952950cc38Schristos 	datap = inpkt->u.data;
2096abb0f93cSkardel 	while (items-- > 0) {
20972950cc38Schristos 		ZERO(cp);
20982950cc38Schristos 		memcpy(&cp, datap, item_sz);
2099abb0f93cSkardel 		ZERO_SOCK(&peeraddr);
21002950cc38Schristos 		if (client_v6_capable && cp.v6_flag) {
2101abb0f93cSkardel 			AF(&peeraddr) = AF_INET6;
21022950cc38Schristos 			SOCK_ADDR6(&peeraddr) = cp.peeraddr6;
2103abb0f93cSkardel 		} else {
2104abb0f93cSkardel 			AF(&peeraddr) = AF_INET;
21052950cc38Schristos 			NSRCADR(&peeraddr) = cp.peeraddr;
2106abb0f93cSkardel 		}
2107abb0f93cSkardel 		SET_PORT(&peeraddr, 123);
2108abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN
21093123f114Skardel 		peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
2110abb0f93cSkardel #endif
21114eea345dSchristos 		p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
21122950cc38Schristos 		while (p != NULL) {
21132950cc38Schristos 			peer_reset(p);
21144eea345dSchristos 			p = findexistingpeer(&peeraddr, NULL, p, -1, 0, NULL);
2115abb0f93cSkardel 		}
21162950cc38Schristos 		datap += item_sz;
2117abb0f93cSkardel 	}
2118abb0f93cSkardel 
2119abb0f93cSkardel 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
2120abb0f93cSkardel }
2121abb0f93cSkardel 
2122abb0f93cSkardel 
2123abb0f93cSkardel /*
2124abb0f93cSkardel  * do_key_reread - reread the encryption key file
2125abb0f93cSkardel  */
2126abb0f93cSkardel static void
2127abb0f93cSkardel do_key_reread(
2128abb0f93cSkardel 	sockaddr_u *srcadr,
21292950cc38Schristos 	endpt *inter,
2130abb0f93cSkardel 	struct req_pkt *inpkt
2131abb0f93cSkardel 	)
2132abb0f93cSkardel {
2133abb0f93cSkardel 	rereadkeys();
2134abb0f93cSkardel 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
2135abb0f93cSkardel }
2136abb0f93cSkardel 
2137abb0f93cSkardel 
2138abb0f93cSkardel /*
2139abb0f93cSkardel  * trust_key - make one or more keys trusted
2140abb0f93cSkardel  */
2141abb0f93cSkardel static void
2142abb0f93cSkardel trust_key(
2143abb0f93cSkardel 	sockaddr_u *srcadr,
21442950cc38Schristos 	endpt *inter,
2145abb0f93cSkardel 	struct req_pkt *inpkt
2146abb0f93cSkardel 	)
2147abb0f93cSkardel {
2148abb0f93cSkardel 	do_trustkey(srcadr, inter, inpkt, 1);
2149abb0f93cSkardel }
2150abb0f93cSkardel 
2151abb0f93cSkardel 
2152abb0f93cSkardel /*
2153abb0f93cSkardel  * untrust_key - make one or more keys untrusted
2154abb0f93cSkardel  */
2155abb0f93cSkardel static void
2156abb0f93cSkardel untrust_key(
2157abb0f93cSkardel 	sockaddr_u *srcadr,
21582950cc38Schristos 	endpt *inter,
2159abb0f93cSkardel 	struct req_pkt *inpkt
2160abb0f93cSkardel 	)
2161abb0f93cSkardel {
2162abb0f93cSkardel 	do_trustkey(srcadr, inter, inpkt, 0);
2163abb0f93cSkardel }
2164abb0f93cSkardel 
2165abb0f93cSkardel 
2166abb0f93cSkardel /*
2167abb0f93cSkardel  * do_trustkey - make keys either trustable or untrustable
2168abb0f93cSkardel  */
2169abb0f93cSkardel static void
2170abb0f93cSkardel do_trustkey(
2171abb0f93cSkardel 	sockaddr_u *srcadr,
21722950cc38Schristos 	endpt *inter,
2173abb0f93cSkardel 	struct req_pkt *inpkt,
2174abb0f93cSkardel 	u_long trust
2175abb0f93cSkardel 	)
2176abb0f93cSkardel {
21778b8da087Schristos 	register uint32_t *kp;
2178abb0f93cSkardel 	register int items;
2179abb0f93cSkardel 
2180abb0f93cSkardel 	items = INFO_NITEMS(inpkt->err_nitems);
21818b8da087Schristos 	kp = (uint32_t *)&inpkt->u;
2182abb0f93cSkardel 	while (items-- > 0) {
2183abb0f93cSkardel 		authtrust(*kp, trust);
2184abb0f93cSkardel 		kp++;
2185abb0f93cSkardel 	}
2186abb0f93cSkardel 
2187abb0f93cSkardel 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
2188abb0f93cSkardel }
2189abb0f93cSkardel 
2190abb0f93cSkardel 
2191abb0f93cSkardel /*
2192abb0f93cSkardel  * get_auth_info - return some stats concerning the authentication module
2193abb0f93cSkardel  */
2194abb0f93cSkardel static void
2195abb0f93cSkardel get_auth_info(
2196abb0f93cSkardel 	sockaddr_u *srcadr,
21972950cc38Schristos 	endpt *inter,
2198abb0f93cSkardel 	struct req_pkt *inpkt
2199abb0f93cSkardel 	)
2200abb0f93cSkardel {
2201abb0f93cSkardel 	register struct info_auth *ia;
2202abb0f93cSkardel 
2203abb0f93cSkardel 	ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt,
2204abb0f93cSkardel 					     sizeof(struct info_auth));
2205abb0f93cSkardel 
2206abb0f93cSkardel 	ia->numkeys = htonl((u_int32)authnumkeys);
2207abb0f93cSkardel 	ia->numfreekeys = htonl((u_int32)authnumfreekeys);
2208abb0f93cSkardel 	ia->keylookups = htonl((u_int32)authkeylookups);
2209abb0f93cSkardel 	ia->keynotfound = htonl((u_int32)authkeynotfound);
2210abb0f93cSkardel 	ia->encryptions = htonl((u_int32)authencryptions);
2211abb0f93cSkardel 	ia->decryptions = htonl((u_int32)authdecryptions);
2212abb0f93cSkardel 	ia->keyuncached = htonl((u_int32)authkeyuncached);
2213abb0f93cSkardel 	ia->expired = htonl((u_int32)authkeyexpired);
2214abb0f93cSkardel 	ia->timereset = htonl((u_int32)(current_time - auth_timereset));
2215abb0f93cSkardel 
2216abb0f93cSkardel 	(void) more_pkt();
2217abb0f93cSkardel 	flush_pkt();
2218abb0f93cSkardel }
2219abb0f93cSkardel 
2220abb0f93cSkardel 
2221abb0f93cSkardel 
2222abb0f93cSkardel /*
2223abb0f93cSkardel  * reset_auth_stats - reset the authentication stat counters.  Done here
2224abb0f93cSkardel  *		      to keep ntp-isms out of the authentication module
2225abb0f93cSkardel  */
22262950cc38Schristos void
2227abb0f93cSkardel reset_auth_stats(void)
2228abb0f93cSkardel {
2229abb0f93cSkardel 	authkeylookups = 0;
2230abb0f93cSkardel 	authkeynotfound = 0;
2231abb0f93cSkardel 	authencryptions = 0;
2232abb0f93cSkardel 	authdecryptions = 0;
2233abb0f93cSkardel 	authkeyuncached = 0;
2234abb0f93cSkardel 	auth_timereset = current_time;
2235abb0f93cSkardel }
2236abb0f93cSkardel 
2237abb0f93cSkardel 
2238abb0f93cSkardel /*
2239abb0f93cSkardel  * req_get_traps - return information about current trap holders
2240abb0f93cSkardel  */
2241abb0f93cSkardel static void
2242abb0f93cSkardel req_get_traps(
2243abb0f93cSkardel 	sockaddr_u *srcadr,
22442950cc38Schristos 	endpt *inter,
2245abb0f93cSkardel 	struct req_pkt *inpkt
2246abb0f93cSkardel 	)
2247abb0f93cSkardel {
22482950cc38Schristos 	struct info_trap *it;
22492950cc38Schristos 	struct ctl_trap *tr;
22502950cc38Schristos 	size_t i;
2251abb0f93cSkardel 
2252abb0f93cSkardel 	if (num_ctl_traps == 0) {
2253abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2254abb0f93cSkardel 		return;
2255abb0f93cSkardel 	}
2256abb0f93cSkardel 
2257abb0f93cSkardel 	it = (struct info_trap *)prepare_pkt(srcadr, inter, inpkt,
2258abb0f93cSkardel 	    v6sizeof(struct info_trap));
2259abb0f93cSkardel 
226068dbbb44Schristos 	for (i = 0, tr = ctl_traps; it && i < COUNTOF(ctl_traps); i++, tr++) {
2261abb0f93cSkardel 		if (tr->tr_flags & TRAP_INUSE) {
2262abb0f93cSkardel 			if (IS_IPV4(&tr->tr_addr)) {
2263abb0f93cSkardel 				if (tr->tr_localaddr == any_interface)
2264abb0f93cSkardel 					it->local_address = 0;
2265abb0f93cSkardel 				else
2266abb0f93cSkardel 					it->local_address
2267abb0f93cSkardel 					    = NSRCADR(&tr->tr_localaddr->sin);
2268abb0f93cSkardel 				it->trap_address = NSRCADR(&tr->tr_addr);
2269abb0f93cSkardel 				if (client_v6_capable)
2270abb0f93cSkardel 					it->v6_flag = 0;
2271abb0f93cSkardel 			} else {
2272abb0f93cSkardel 				if (!client_v6_capable)
2273abb0f93cSkardel 					continue;
2274abb0f93cSkardel 				it->local_address6
2275abb0f93cSkardel 				    = SOCK_ADDR6(&tr->tr_localaddr->sin);
2276abb0f93cSkardel 				it->trap_address6 = SOCK_ADDR6(&tr->tr_addr);
2277abb0f93cSkardel 				it->v6_flag = 1;
2278abb0f93cSkardel 			}
2279abb0f93cSkardel 			it->trap_port = NSRCPORT(&tr->tr_addr);
2280abb0f93cSkardel 			it->sequence = htons(tr->tr_sequence);
2281abb0f93cSkardel 			it->settime = htonl((u_int32)(current_time - tr->tr_settime));
2282abb0f93cSkardel 			it->origtime = htonl((u_int32)(current_time - tr->tr_origtime));
2283abb0f93cSkardel 			it->resets = htonl((u_int32)tr->tr_resets);
2284abb0f93cSkardel 			it->flags = htonl((u_int32)tr->tr_flags);
2285abb0f93cSkardel 			it = (struct info_trap *)more_pkt();
2286abb0f93cSkardel 		}
2287abb0f93cSkardel 	}
2288abb0f93cSkardel 	flush_pkt();
2289abb0f93cSkardel }
2290abb0f93cSkardel 
2291abb0f93cSkardel 
2292abb0f93cSkardel /*
2293abb0f93cSkardel  * req_set_trap - configure a trap
2294abb0f93cSkardel  */
2295abb0f93cSkardel static void
2296abb0f93cSkardel req_set_trap(
2297abb0f93cSkardel 	sockaddr_u *srcadr,
22982950cc38Schristos 	endpt *inter,
2299abb0f93cSkardel 	struct req_pkt *inpkt
2300abb0f93cSkardel 	)
2301abb0f93cSkardel {
2302abb0f93cSkardel 	do_setclr_trap(srcadr, inter, inpkt, 1);
2303abb0f93cSkardel }
2304abb0f93cSkardel 
2305abb0f93cSkardel 
2306abb0f93cSkardel 
2307abb0f93cSkardel /*
2308abb0f93cSkardel  * req_clr_trap - unconfigure a trap
2309abb0f93cSkardel  */
2310abb0f93cSkardel static void
2311abb0f93cSkardel req_clr_trap(
2312abb0f93cSkardel 	sockaddr_u *srcadr,
23132950cc38Schristos 	endpt *inter,
2314abb0f93cSkardel 	struct req_pkt *inpkt
2315abb0f93cSkardel 	)
2316abb0f93cSkardel {
2317abb0f93cSkardel 	do_setclr_trap(srcadr, inter, inpkt, 0);
2318abb0f93cSkardel }
2319abb0f93cSkardel 
2320abb0f93cSkardel 
2321abb0f93cSkardel 
2322abb0f93cSkardel /*
2323abb0f93cSkardel  * do_setclr_trap - do the grunge work of (un)configuring a trap
2324abb0f93cSkardel  */
2325abb0f93cSkardel static void
2326abb0f93cSkardel do_setclr_trap(
2327abb0f93cSkardel 	sockaddr_u *srcadr,
23282950cc38Schristos 	endpt *inter,
2329abb0f93cSkardel 	struct req_pkt *inpkt,
2330abb0f93cSkardel 	int set
2331abb0f93cSkardel 	)
2332abb0f93cSkardel {
2333abb0f93cSkardel 	register struct conf_trap *ct;
23342950cc38Schristos 	register endpt *linter;
2335abb0f93cSkardel 	int res;
2336abb0f93cSkardel 	sockaddr_u laddr;
2337abb0f93cSkardel 
2338abb0f93cSkardel 	/*
2339abb0f93cSkardel 	 * Prepare sockaddr
2340abb0f93cSkardel 	 */
2341abb0f93cSkardel 	ZERO_SOCK(&laddr);
2342abb0f93cSkardel 	AF(&laddr) = AF(srcadr);
2343abb0f93cSkardel 	SET_PORT(&laddr, NTP_PORT);
2344abb0f93cSkardel 
2345abb0f93cSkardel 	/*
2346abb0f93cSkardel 	 * Restrict ourselves to one item only.  This eliminates
2347abb0f93cSkardel 	 * the error reporting problem.
2348abb0f93cSkardel 	 */
2349abb0f93cSkardel 	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
2350abb0f93cSkardel 		msyslog(LOG_ERR, "do_setclr_trap: err_nitems > 1");
2351abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
2352abb0f93cSkardel 		return;
2353abb0f93cSkardel 	}
23542950cc38Schristos 	ct = (struct conf_trap *)&inpkt->u;
2355abb0f93cSkardel 
2356abb0f93cSkardel 	/*
2357abb0f93cSkardel 	 * Look for the local interface.  If none, use the default.
2358abb0f93cSkardel 	 */
2359abb0f93cSkardel 	if (ct->local_address == 0) {
2360abb0f93cSkardel 		linter = any_interface;
2361abb0f93cSkardel 	} else {
2362abb0f93cSkardel 		if (IS_IPV4(&laddr))
2363abb0f93cSkardel 			NSRCADR(&laddr) = ct->local_address;
2364abb0f93cSkardel 		else
2365abb0f93cSkardel 			SOCK_ADDR6(&laddr) = ct->local_address6;
2366abb0f93cSkardel 		linter = findinterface(&laddr);
2367abb0f93cSkardel 		if (NULL == linter) {
2368abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2369abb0f93cSkardel 			return;
2370abb0f93cSkardel 		}
2371abb0f93cSkardel 	}
2372abb0f93cSkardel 
2373abb0f93cSkardel 	if (IS_IPV4(&laddr))
2374abb0f93cSkardel 		NSRCADR(&laddr) = ct->trap_address;
2375abb0f93cSkardel 	else
2376abb0f93cSkardel 		SOCK_ADDR6(&laddr) = ct->trap_address6;
2377abb0f93cSkardel 	if (ct->trap_port)
2378abb0f93cSkardel 		NSRCPORT(&laddr) = ct->trap_port;
2379abb0f93cSkardel 	else
2380abb0f93cSkardel 		SET_PORT(&laddr, TRAPPORT);
2381abb0f93cSkardel 
2382abb0f93cSkardel 	if (set) {
2383abb0f93cSkardel 		res = ctlsettrap(&laddr, linter, 0,
2384abb0f93cSkardel 				 INFO_VERSION(inpkt->rm_vn_mode));
2385abb0f93cSkardel 	} else {
2386abb0f93cSkardel 		res = ctlclrtrap(&laddr, linter, 0);
2387abb0f93cSkardel 	}
2388abb0f93cSkardel 
2389abb0f93cSkardel 	if (!res) {
2390abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2391abb0f93cSkardel 	} else {
2392abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_OKAY);
2393abb0f93cSkardel 	}
2394abb0f93cSkardel 	return;
2395abb0f93cSkardel }
2396abb0f93cSkardel 
239768dbbb44Schristos /*
239868dbbb44Schristos  * Validate a request packet for a new request or control key:
239968dbbb44Schristos  *  - only one item allowed
240068dbbb44Schristos  *  - key must be valid (that is, known, and not in the autokey range)
240168dbbb44Schristos  */
240268dbbb44Schristos static void
240368dbbb44Schristos set_keyid_checked(
240468dbbb44Schristos 	keyid_t        *into,
240568dbbb44Schristos 	const char     *what,
240668dbbb44Schristos 	sockaddr_u     *srcadr,
240768dbbb44Schristos 	endpt          *inter,
240868dbbb44Schristos 	struct req_pkt *inpkt
240968dbbb44Schristos 	)
241068dbbb44Schristos {
241168dbbb44Schristos 	keyid_t *pkeyid;
241268dbbb44Schristos 	keyid_t  tmpkey;
2413abb0f93cSkardel 
241468dbbb44Schristos 	/* restrict ourselves to one item only */
241568dbbb44Schristos 	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
241668dbbb44Schristos 		msyslog(LOG_ERR, "set_keyid_checked[%s]: err_nitems > 1",
241768dbbb44Schristos 			what);
241868dbbb44Schristos 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
241968dbbb44Schristos 		return;
242068dbbb44Schristos 	}
242168dbbb44Schristos 
242268dbbb44Schristos 	/* plug the new key from the packet */
242368dbbb44Schristos 	pkeyid = (keyid_t *)&inpkt->u;
242468dbbb44Schristos 	tmpkey = ntohl(*pkeyid);
242568dbbb44Schristos 
242668dbbb44Schristos 	/* validate the new key id, claim data error on failure */
242768dbbb44Schristos 	if (tmpkey < 1 || tmpkey > NTP_MAXKEY || !auth_havekey(tmpkey)) {
242868dbbb44Schristos 		msyslog(LOG_ERR, "set_keyid_checked[%s]: invalid key id: %ld",
242968dbbb44Schristos 			what, (long)tmpkey);
243068dbbb44Schristos 		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
243168dbbb44Schristos 		return;
243268dbbb44Schristos 	}
243368dbbb44Schristos 
243468dbbb44Schristos 	/* if we arrive here, the key is good -- use it */
243568dbbb44Schristos 	*into = tmpkey;
243668dbbb44Schristos 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
243768dbbb44Schristos }
2438abb0f93cSkardel 
2439abb0f93cSkardel /*
2440abb0f93cSkardel  * set_request_keyid - set the keyid used to authenticate requests
2441abb0f93cSkardel  */
2442abb0f93cSkardel static void
2443abb0f93cSkardel set_request_keyid(
2444abb0f93cSkardel 	sockaddr_u *srcadr,
24452950cc38Schristos 	endpt *inter,
2446abb0f93cSkardel 	struct req_pkt *inpkt
2447abb0f93cSkardel 	)
2448abb0f93cSkardel {
244968dbbb44Schristos 	set_keyid_checked(&info_auth_keyid, "request",
245068dbbb44Schristos 			  srcadr, inter, inpkt);
2451abb0f93cSkardel }
2452abb0f93cSkardel 
2453abb0f93cSkardel 
2454abb0f93cSkardel 
2455abb0f93cSkardel /*
2456abb0f93cSkardel  * set_control_keyid - set the keyid used to authenticate requests
2457abb0f93cSkardel  */
2458abb0f93cSkardel static void
2459abb0f93cSkardel set_control_keyid(
2460abb0f93cSkardel 	sockaddr_u *srcadr,
24612950cc38Schristos 	endpt *inter,
2462abb0f93cSkardel 	struct req_pkt *inpkt
2463abb0f93cSkardel 	)
2464abb0f93cSkardel {
246568dbbb44Schristos 	set_keyid_checked(&ctl_auth_keyid, "control",
246668dbbb44Schristos 			  srcadr, inter, inpkt);
2467abb0f93cSkardel }
2468abb0f93cSkardel 
2469abb0f93cSkardel 
2470abb0f93cSkardel 
2471abb0f93cSkardel /*
2472abb0f93cSkardel  * get_ctl_stats - return some stats concerning the control message module
2473abb0f93cSkardel  */
2474abb0f93cSkardel static void
2475abb0f93cSkardel get_ctl_stats(
2476abb0f93cSkardel 	sockaddr_u *srcadr,
24772950cc38Schristos 	endpt *inter,
2478abb0f93cSkardel 	struct req_pkt *inpkt
2479abb0f93cSkardel 	)
2480abb0f93cSkardel {
2481abb0f93cSkardel 	register struct info_control *ic;
2482abb0f93cSkardel 
2483abb0f93cSkardel 	ic = (struct info_control *)prepare_pkt(srcadr, inter, inpkt,
2484abb0f93cSkardel 						sizeof(struct info_control));
2485abb0f93cSkardel 
2486abb0f93cSkardel 	ic->ctltimereset = htonl((u_int32)(current_time - ctltimereset));
2487abb0f93cSkardel 	ic->numctlreq = htonl((u_int32)numctlreq);
2488abb0f93cSkardel 	ic->numctlbadpkts = htonl((u_int32)numctlbadpkts);
2489abb0f93cSkardel 	ic->numctlresponses = htonl((u_int32)numctlresponses);
2490abb0f93cSkardel 	ic->numctlfrags = htonl((u_int32)numctlfrags);
2491abb0f93cSkardel 	ic->numctlerrors = htonl((u_int32)numctlerrors);
2492abb0f93cSkardel 	ic->numctltooshort = htonl((u_int32)numctltooshort);
2493abb0f93cSkardel 	ic->numctlinputresp = htonl((u_int32)numctlinputresp);
2494abb0f93cSkardel 	ic->numctlinputfrag = htonl((u_int32)numctlinputfrag);
2495abb0f93cSkardel 	ic->numctlinputerr = htonl((u_int32)numctlinputerr);
2496abb0f93cSkardel 	ic->numctlbadoffset = htonl((u_int32)numctlbadoffset);
2497abb0f93cSkardel 	ic->numctlbadversion = htonl((u_int32)numctlbadversion);
2498abb0f93cSkardel 	ic->numctldatatooshort = htonl((u_int32)numctldatatooshort);
2499abb0f93cSkardel 	ic->numctlbadop = htonl((u_int32)numctlbadop);
2500abb0f93cSkardel 	ic->numasyncmsgs = htonl((u_int32)numasyncmsgs);
2501abb0f93cSkardel 
2502abb0f93cSkardel 	(void) more_pkt();
2503abb0f93cSkardel 	flush_pkt();
2504abb0f93cSkardel }
2505abb0f93cSkardel 
2506abb0f93cSkardel 
2507abb0f93cSkardel #ifdef KERNEL_PLL
2508abb0f93cSkardel /*
2509abb0f93cSkardel  * get_kernel_info - get kernel pll/pps information
2510abb0f93cSkardel  */
2511abb0f93cSkardel static void
2512abb0f93cSkardel get_kernel_info(
2513abb0f93cSkardel 	sockaddr_u *srcadr,
25142950cc38Schristos 	endpt *inter,
2515abb0f93cSkardel 	struct req_pkt *inpkt
2516abb0f93cSkardel 	)
2517abb0f93cSkardel {
2518abb0f93cSkardel 	register struct info_kernel *ik;
2519abb0f93cSkardel 	struct timex ntx;
2520abb0f93cSkardel 
2521abb0f93cSkardel 	if (!pll_control) {
2522abb0f93cSkardel 		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2523abb0f93cSkardel 		return;
2524abb0f93cSkardel 	}
2525abb0f93cSkardel 
25262950cc38Schristos 	ZERO(ntx);
2527abb0f93cSkardel 	if (ntp_adjtime(&ntx) < 0)
2528abb0f93cSkardel 		msyslog(LOG_ERR, "get_kernel_info: ntp_adjtime() failed: %m");
2529abb0f93cSkardel 	ik = (struct info_kernel *)prepare_pkt(srcadr, inter, inpkt,
2530abb0f93cSkardel 	    sizeof(struct info_kernel));
2531abb0f93cSkardel 
2532abb0f93cSkardel 	/*
2533abb0f93cSkardel 	 * pll variables
2534abb0f93cSkardel 	 */
2535abb0f93cSkardel 	ik->offset = htonl((u_int32)ntx.offset);
2536abb0f93cSkardel 	ik->freq = htonl((u_int32)ntx.freq);
2537abb0f93cSkardel 	ik->maxerror = htonl((u_int32)ntx.maxerror);
2538abb0f93cSkardel 	ik->esterror = htonl((u_int32)ntx.esterror);
2539abb0f93cSkardel 	ik->status = htons(ntx.status);
2540abb0f93cSkardel 	ik->constant = htonl((u_int32)ntx.constant);
2541abb0f93cSkardel 	ik->precision = htonl((u_int32)ntx.precision);
2542abb0f93cSkardel 	ik->tolerance = htonl((u_int32)ntx.tolerance);
2543abb0f93cSkardel 
2544abb0f93cSkardel 	/*
2545abb0f93cSkardel 	 * pps variables
2546abb0f93cSkardel 	 */
2547abb0f93cSkardel 	ik->ppsfreq = htonl((u_int32)ntx.ppsfreq);
2548abb0f93cSkardel 	ik->jitter = htonl((u_int32)ntx.jitter);
2549abb0f93cSkardel 	ik->shift = htons(ntx.shift);
2550abb0f93cSkardel 	ik->stabil = htonl((u_int32)ntx.stabil);
2551abb0f93cSkardel 	ik->jitcnt = htonl((u_int32)ntx.jitcnt);
2552abb0f93cSkardel 	ik->calcnt = htonl((u_int32)ntx.calcnt);
2553abb0f93cSkardel 	ik->errcnt = htonl((u_int32)ntx.errcnt);
2554abb0f93cSkardel 	ik->stbcnt = htonl((u_int32)ntx.stbcnt);
2555abb0f93cSkardel 
2556abb0f93cSkardel 	(void) more_pkt();
2557abb0f93cSkardel 	flush_pkt();
2558abb0f93cSkardel }
2559abb0f93cSkardel #endif /* KERNEL_PLL */
2560abb0f93cSkardel 
2561abb0f93cSkardel 
2562abb0f93cSkardel #ifdef REFCLOCK
2563abb0f93cSkardel /*
2564abb0f93cSkardel  * get_clock_info - get info about a clock
2565abb0f93cSkardel  */
2566abb0f93cSkardel static void
2567abb0f93cSkardel get_clock_info(
2568abb0f93cSkardel 	sockaddr_u *srcadr,
25692950cc38Schristos 	endpt *inter,
2570abb0f93cSkardel 	struct req_pkt *inpkt
2571abb0f93cSkardel 	)
2572abb0f93cSkardel {
2573abb0f93cSkardel 	register struct info_clock *ic;
2574abb0f93cSkardel 	register u_int32 *clkaddr;
2575abb0f93cSkardel 	register int items;
2576abb0f93cSkardel 	struct refclockstat clock_stat;
2577abb0f93cSkardel 	sockaddr_u addr;
2578abb0f93cSkardel 	l_fp ltmp;
2579abb0f93cSkardel 
2580abb0f93cSkardel 	ZERO_SOCK(&addr);
2581abb0f93cSkardel 	AF(&addr) = AF_INET;
2582abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN
25833123f114Skardel 	addr.sa.sa_len = SOCKLEN(&addr);
2584abb0f93cSkardel #endif
2585abb0f93cSkardel 	SET_PORT(&addr, NTP_PORT);
2586abb0f93cSkardel 	items = INFO_NITEMS(inpkt->err_nitems);
25872950cc38Schristos 	clkaddr = &inpkt->u.u32[0];
2588abb0f93cSkardel 
2589abb0f93cSkardel 	ic = (struct info_clock *)prepare_pkt(srcadr, inter, inpkt,
2590abb0f93cSkardel 					      sizeof(struct info_clock));
2591abb0f93cSkardel 
259268dbbb44Schristos 	while (items-- > 0 && ic) {
2593abb0f93cSkardel 		NSRCADR(&addr) = *clkaddr++;
25942950cc38Schristos 		if (!ISREFCLOCKADR(&addr) || NULL ==
25954eea345dSchristos 		    findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) {
2596abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2597abb0f93cSkardel 			return;
2598abb0f93cSkardel 		}
2599abb0f93cSkardel 
2600abb0f93cSkardel 		clock_stat.kv_list = (struct ctl_var *)0;
2601abb0f93cSkardel 
2602abb0f93cSkardel 		refclock_control(&addr, NULL, &clock_stat);
2603abb0f93cSkardel 
2604abb0f93cSkardel 		ic->clockadr = NSRCADR(&addr);
2605abb0f93cSkardel 		ic->type = clock_stat.type;
2606abb0f93cSkardel 		ic->flags = clock_stat.flags;
2607abb0f93cSkardel 		ic->lastevent = clock_stat.lastevent;
2608abb0f93cSkardel 		ic->currentstatus = clock_stat.currentstatus;
2609abb0f93cSkardel 		ic->polls = htonl((u_int32)clock_stat.polls);
2610abb0f93cSkardel 		ic->noresponse = htonl((u_int32)clock_stat.noresponse);
2611abb0f93cSkardel 		ic->badformat = htonl((u_int32)clock_stat.badformat);
2612abb0f93cSkardel 		ic->baddata = htonl((u_int32)clock_stat.baddata);
2613abb0f93cSkardel 		ic->timestarted = htonl((u_int32)clock_stat.timereset);
2614abb0f93cSkardel 		DTOLFP(clock_stat.fudgetime1, &ltmp);
2615abb0f93cSkardel 		HTONL_FP(&ltmp, &ic->fudgetime1);
2616abb0f93cSkardel 		DTOLFP(clock_stat.fudgetime2, &ltmp);
2617abb0f93cSkardel 		HTONL_FP(&ltmp, &ic->fudgetime2);
2618abb0f93cSkardel 		ic->fudgeval1 = htonl((u_int32)clock_stat.fudgeval1);
2619cdfa2a7eSchristos 		/* [Bug3527] Backward Incompatible: ic->fudgeval2 is
2620cdfa2a7eSchristos 		 * a string, instantiated via memcpy() so there is no
2621cdfa2a7eSchristos 		 * endian issue to correct.
2622cdfa2a7eSchristos 		 */
2623cdfa2a7eSchristos #ifdef DISABLE_BUG3527_FIX
26243123f114Skardel 		ic->fudgeval2 = htonl(clock_stat.fudgeval2);
2625cdfa2a7eSchristos #else
2626cdfa2a7eSchristos 		ic->fudgeval2 = clock_stat.fudgeval2;
2627cdfa2a7eSchristos #endif
2628abb0f93cSkardel 
2629abb0f93cSkardel 		free_varlist(clock_stat.kv_list);
2630abb0f93cSkardel 
2631abb0f93cSkardel 		ic = (struct info_clock *)more_pkt();
2632abb0f93cSkardel 	}
2633abb0f93cSkardel 	flush_pkt();
2634abb0f93cSkardel }
2635abb0f93cSkardel 
2636abb0f93cSkardel 
2637abb0f93cSkardel 
2638abb0f93cSkardel /*
2639abb0f93cSkardel  * set_clock_fudge - get a clock's fudge factors
2640abb0f93cSkardel  */
2641abb0f93cSkardel static void
2642abb0f93cSkardel set_clock_fudge(
2643abb0f93cSkardel 	sockaddr_u *srcadr,
26442950cc38Schristos 	endpt *inter,
2645abb0f93cSkardel 	struct req_pkt *inpkt
2646abb0f93cSkardel 	)
2647abb0f93cSkardel {
2648abb0f93cSkardel 	register struct conf_fudge *cf;
2649abb0f93cSkardel 	register int items;
2650abb0f93cSkardel 	struct refclockstat clock_stat;
2651abb0f93cSkardel 	sockaddr_u addr;
2652abb0f93cSkardel 	l_fp ltmp;
2653abb0f93cSkardel 
26542950cc38Schristos 	ZERO(addr);
26552950cc38Schristos 	ZERO(clock_stat);
2656abb0f93cSkardel 	items = INFO_NITEMS(inpkt->err_nitems);
26572950cc38Schristos 	cf = (struct conf_fudge *)&inpkt->u;
2658abb0f93cSkardel 
2659abb0f93cSkardel 	while (items-- > 0) {
2660abb0f93cSkardel 		AF(&addr) = AF_INET;
2661abb0f93cSkardel 		NSRCADR(&addr) = cf->clockadr;
2662abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN
26633123f114Skardel 		addr.sa.sa_len = SOCKLEN(&addr);
2664abb0f93cSkardel #endif
2665abb0f93cSkardel 		SET_PORT(&addr, NTP_PORT);
26662950cc38Schristos 		if (!ISREFCLOCKADR(&addr) || NULL ==
26674eea345dSchristos 		    findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) {
2668abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2669abb0f93cSkardel 			return;
2670abb0f93cSkardel 		}
2671abb0f93cSkardel 
2672abb0f93cSkardel 		switch(ntohl(cf->which)) {
2673abb0f93cSkardel 		    case FUDGE_TIME1:
2674abb0f93cSkardel 			NTOHL_FP(&cf->fudgetime, &ltmp);
2675abb0f93cSkardel 			LFPTOD(&ltmp, clock_stat.fudgetime1);
2676abb0f93cSkardel 			clock_stat.haveflags = CLK_HAVETIME1;
2677abb0f93cSkardel 			break;
2678abb0f93cSkardel 		    case FUDGE_TIME2:
2679abb0f93cSkardel 			NTOHL_FP(&cf->fudgetime, &ltmp);
2680abb0f93cSkardel 			LFPTOD(&ltmp, clock_stat.fudgetime2);
2681abb0f93cSkardel 			clock_stat.haveflags = CLK_HAVETIME2;
2682abb0f93cSkardel 			break;
2683abb0f93cSkardel 		    case FUDGE_VAL1:
2684abb0f93cSkardel 			clock_stat.fudgeval1 = ntohl(cf->fudgeval_flags);
2685abb0f93cSkardel 			clock_stat.haveflags = CLK_HAVEVAL1;
2686abb0f93cSkardel 			break;
2687abb0f93cSkardel 		    case FUDGE_VAL2:
2688abb0f93cSkardel 			clock_stat.fudgeval2 = ntohl(cf->fudgeval_flags);
2689abb0f93cSkardel 			clock_stat.haveflags = CLK_HAVEVAL2;
2690abb0f93cSkardel 			break;
2691abb0f93cSkardel 		    case FUDGE_FLAGS:
2692abb0f93cSkardel 			clock_stat.flags = (u_char) (ntohl(cf->fudgeval_flags) & 0xf);
2693abb0f93cSkardel 			clock_stat.haveflags =
2694abb0f93cSkardel 				(CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4);
2695abb0f93cSkardel 			break;
2696abb0f93cSkardel 		    default:
2697abb0f93cSkardel 			msyslog(LOG_ERR, "set_clock_fudge: default!");
2698abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
2699abb0f93cSkardel 			return;
2700abb0f93cSkardel 		}
2701abb0f93cSkardel 
2702abb0f93cSkardel 		refclock_control(&addr, &clock_stat, (struct refclockstat *)0);
2703abb0f93cSkardel 	}
2704abb0f93cSkardel 
2705abb0f93cSkardel 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
2706abb0f93cSkardel }
2707abb0f93cSkardel #endif
2708abb0f93cSkardel 
2709abb0f93cSkardel #ifdef REFCLOCK
2710abb0f93cSkardel /*
2711abb0f93cSkardel  * get_clkbug_info - get debugging info about a clock
2712abb0f93cSkardel  */
2713abb0f93cSkardel static void
2714abb0f93cSkardel get_clkbug_info(
2715abb0f93cSkardel 	sockaddr_u *srcadr,
27162950cc38Schristos 	endpt *inter,
2717abb0f93cSkardel 	struct req_pkt *inpkt
2718abb0f93cSkardel 	)
2719abb0f93cSkardel {
2720abb0f93cSkardel 	register int i;
2721abb0f93cSkardel 	register struct info_clkbug *ic;
2722abb0f93cSkardel 	register u_int32 *clkaddr;
2723abb0f93cSkardel 	register int items;
2724abb0f93cSkardel 	struct refclockbug bug;
2725abb0f93cSkardel 	sockaddr_u addr;
2726abb0f93cSkardel 
2727abb0f93cSkardel 	ZERO_SOCK(&addr);
2728abb0f93cSkardel 	AF(&addr) = AF_INET;
2729abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN
27303123f114Skardel 	addr.sa.sa_len = SOCKLEN(&addr);
2731abb0f93cSkardel #endif
2732abb0f93cSkardel 	SET_PORT(&addr, NTP_PORT);
2733abb0f93cSkardel 	items = INFO_NITEMS(inpkt->err_nitems);
27342950cc38Schristos 	clkaddr = (u_int32 *)&inpkt->u;
2735abb0f93cSkardel 
2736abb0f93cSkardel 	ic = (struct info_clkbug *)prepare_pkt(srcadr, inter, inpkt,
2737abb0f93cSkardel 					       sizeof(struct info_clkbug));
2738abb0f93cSkardel 
273968dbbb44Schristos 	while (items-- > 0 && ic) {
2740abb0f93cSkardel 		NSRCADR(&addr) = *clkaddr++;
27412950cc38Schristos 		if (!ISREFCLOCKADR(&addr) || NULL ==
27424eea345dSchristos 		    findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) {
2743abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2744abb0f93cSkardel 			return;
2745abb0f93cSkardel 		}
2746abb0f93cSkardel 
27472950cc38Schristos 		ZERO(bug);
2748abb0f93cSkardel 		refclock_buginfo(&addr, &bug);
2749abb0f93cSkardel 		if (bug.nvalues == 0 && bug.ntimes == 0) {
2750abb0f93cSkardel 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2751abb0f93cSkardel 			return;
2752abb0f93cSkardel 		}
2753abb0f93cSkardel 
2754abb0f93cSkardel 		ic->clockadr = NSRCADR(&addr);
2755abb0f93cSkardel 		i = bug.nvalues;
2756abb0f93cSkardel 		if (i > NUMCBUGVALUES)
2757abb0f93cSkardel 		    i = NUMCBUGVALUES;
2758abb0f93cSkardel 		ic->nvalues = (u_char)i;
2759abb0f93cSkardel 		ic->svalues = htons((u_short) (bug.svalues & ((1<<i)-1)));
2760abb0f93cSkardel 		while (--i >= 0)
2761abb0f93cSkardel 		    ic->values[i] = htonl(bug.values[i]);
2762abb0f93cSkardel 
2763abb0f93cSkardel 		i = bug.ntimes;
2764abb0f93cSkardel 		if (i > NUMCBUGTIMES)
2765abb0f93cSkardel 		    i = NUMCBUGTIMES;
2766abb0f93cSkardel 		ic->ntimes = (u_char)i;
2767abb0f93cSkardel 		ic->stimes = htonl(bug.stimes);
2768abb0f93cSkardel 		while (--i >= 0) {
2769abb0f93cSkardel 			HTONL_FP(&bug.times[i], &ic->times[i]);
2770abb0f93cSkardel 		}
2771abb0f93cSkardel 
2772abb0f93cSkardel 		ic = (struct info_clkbug *)more_pkt();
2773abb0f93cSkardel 	}
2774abb0f93cSkardel 	flush_pkt();
2775abb0f93cSkardel }
2776abb0f93cSkardel #endif
2777abb0f93cSkardel 
2778abb0f93cSkardel /*
2779abb0f93cSkardel  * receiver of interface structures
2780abb0f93cSkardel  */
2781abb0f93cSkardel static void
2782abb0f93cSkardel fill_info_if_stats(void *data, interface_info_t *interface_info)
2783abb0f93cSkardel {
2784abb0f93cSkardel 	struct info_if_stats **ifsp = (struct info_if_stats **)data;
2785abb0f93cSkardel 	struct info_if_stats *ifs = *ifsp;
27863123f114Skardel 	endpt *ep = interface_info->ep;
2787abb0f93cSkardel 
278868dbbb44Schristos 	if (NULL == ifs)
278968dbbb44Schristos 		return;
279068dbbb44Schristos 
27912950cc38Schristos 	ZERO(*ifs);
2792abb0f93cSkardel 
27933123f114Skardel 	if (IS_IPV6(&ep->sin)) {
279468dbbb44Schristos 		if (!client_v6_capable)
2795abb0f93cSkardel 			return;
2796abb0f93cSkardel 		ifs->v6_flag = 1;
27973123f114Skardel 		ifs->unaddr.addr6 = SOCK_ADDR6(&ep->sin);
27983123f114Skardel 		ifs->unbcast.addr6 = SOCK_ADDR6(&ep->bcast);
27993123f114Skardel 		ifs->unmask.addr6 = SOCK_ADDR6(&ep->mask);
2800abb0f93cSkardel 	} else {
2801abb0f93cSkardel 		ifs->v6_flag = 0;
28023123f114Skardel 		ifs->unaddr.addr = SOCK_ADDR4(&ep->sin);
28033123f114Skardel 		ifs->unbcast.addr = SOCK_ADDR4(&ep->bcast);
28043123f114Skardel 		ifs->unmask.addr = SOCK_ADDR4(&ep->mask);
2805abb0f93cSkardel 	}
2806abb0f93cSkardel 	ifs->v6_flag = htonl(ifs->v6_flag);
28072950cc38Schristos 	strlcpy(ifs->name, ep->name, sizeof(ifs->name));
28083123f114Skardel 	ifs->family = htons(ep->family);
28093123f114Skardel 	ifs->flags = htonl(ep->flags);
28103123f114Skardel 	ifs->last_ttl = htonl(ep->last_ttl);
28113123f114Skardel 	ifs->num_mcast = htonl(ep->num_mcast);
28123123f114Skardel 	ifs->received = htonl(ep->received);
28133123f114Skardel 	ifs->sent = htonl(ep->sent);
28143123f114Skardel 	ifs->notsent = htonl(ep->notsent);
28153123f114Skardel 	ifs->ifindex = htonl(ep->ifindex);
28162950cc38Schristos 	/* scope no longer in endpt, in in6_addr typically */
28173123f114Skardel 	ifs->scopeid = ifs->ifindex;
28183123f114Skardel 	ifs->ifnum = htonl(ep->ifnum);
28193123f114Skardel 	ifs->uptime = htonl(current_time - ep->starttime);
28203123f114Skardel 	ifs->ignore_packets = ep->ignore_packets;
28213123f114Skardel 	ifs->peercnt = htonl(ep->peercnt);
2822abb0f93cSkardel 	ifs->action = interface_info->action;
2823abb0f93cSkardel 
2824abb0f93cSkardel 	*ifsp = (struct info_if_stats *)more_pkt();
2825abb0f93cSkardel }
2826abb0f93cSkardel 
2827abb0f93cSkardel /*
2828abb0f93cSkardel  * get_if_stats - get interface statistics
2829abb0f93cSkardel  */
2830abb0f93cSkardel static void
2831abb0f93cSkardel get_if_stats(
2832abb0f93cSkardel 	sockaddr_u *srcadr,
28332950cc38Schristos 	endpt *inter,
2834abb0f93cSkardel 	struct req_pkt *inpkt
2835abb0f93cSkardel 	)
2836abb0f93cSkardel {
2837abb0f93cSkardel 	struct info_if_stats *ifs;
2838abb0f93cSkardel 
2839abb0f93cSkardel 	DPRINTF(3, ("wants interface statistics\n"));
2840abb0f93cSkardel 
2841abb0f93cSkardel 	ifs = (struct info_if_stats *)prepare_pkt(srcadr, inter, inpkt,
2842abb0f93cSkardel 	    v6sizeof(struct info_if_stats));
2843abb0f93cSkardel 
2844abb0f93cSkardel 	interface_enumerate(fill_info_if_stats, &ifs);
2845abb0f93cSkardel 
2846abb0f93cSkardel 	flush_pkt();
2847abb0f93cSkardel }
2848abb0f93cSkardel 
2849abb0f93cSkardel static void
2850abb0f93cSkardel do_if_reload(
2851abb0f93cSkardel 	sockaddr_u *srcadr,
28522950cc38Schristos 	endpt *inter,
2853abb0f93cSkardel 	struct req_pkt *inpkt
2854abb0f93cSkardel 	)
2855abb0f93cSkardel {
2856abb0f93cSkardel 	struct info_if_stats *ifs;
2857abb0f93cSkardel 
2858abb0f93cSkardel 	DPRINTF(3, ("wants interface reload\n"));
2859abb0f93cSkardel 
2860abb0f93cSkardel 	ifs = (struct info_if_stats *)prepare_pkt(srcadr, inter, inpkt,
2861abb0f93cSkardel 	    v6sizeof(struct info_if_stats));
2862abb0f93cSkardel 
2863abb0f93cSkardel 	interface_update(fill_info_if_stats, &ifs);
2864abb0f93cSkardel 
2865abb0f93cSkardel 	flush_pkt();
2866abb0f93cSkardel }
2867abb0f93cSkardel 
2868