xref: /freebsd/contrib/ntp/ntpd/ntp_request.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * ntp_request.c - respond to information requests
3c0b746e5SOllivier Robert  */
49c2daa00SOllivier Robert 
5c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
6c0b746e5SOllivier Robert # include <config.h>
7c0b746e5SOllivier Robert #endif
8c0b746e5SOllivier Robert 
9c0b746e5SOllivier Robert #include "ntpd.h"
10c0b746e5SOllivier Robert #include "ntp_io.h"
11c0b746e5SOllivier Robert #include "ntp_request.h"
12c0b746e5SOllivier Robert #include "ntp_control.h"
13c0b746e5SOllivier Robert #include "ntp_refclock.h"
14c0b746e5SOllivier Robert #include "ntp_if.h"
15c0b746e5SOllivier Robert #include "ntp_stdlib.h"
162b15cb3dSCy Schubert #include "ntp_assert.h"
17224ba2bdSOllivier Robert 
18224ba2bdSOllivier Robert #include <stdio.h>
199c2daa00SOllivier Robert #include <stddef.h>
20224ba2bdSOllivier Robert #include <signal.h>
212b15cb3dSCy Schubert #ifdef HAVE_NETINET_IN_H
22224ba2bdSOllivier Robert #include <netinet/in.h>
232b15cb3dSCy Schubert #endif
24224ba2bdSOllivier Robert #include <arpa/inet.h>
25224ba2bdSOllivier Robert 
26c0b746e5SOllivier Robert #include "recvbuff.h"
27c0b746e5SOllivier Robert 
28c0b746e5SOllivier Robert #ifdef KERNEL_PLL
29c0b746e5SOllivier Robert #include "ntp_syscall.h"
30c0b746e5SOllivier Robert #endif /* KERNEL_PLL */
31c0b746e5SOllivier Robert 
32c0b746e5SOllivier Robert /*
33c0b746e5SOllivier Robert  * Structure to hold request procedure information
34c0b746e5SOllivier Robert  */
35c0b746e5SOllivier Robert #define	NOAUTH	0
36c0b746e5SOllivier Robert #define	AUTH	1
37c0b746e5SOllivier Robert 
38c0b746e5SOllivier Robert #define	NO_REQUEST	(-1)
399c2daa00SOllivier Robert /*
409c2daa00SOllivier Robert  * Because we now have v6 addresses in the messages, we need to compensate
419c2daa00SOllivier Robert  * for the larger size.  Therefore, we introduce the alternate size to
429c2daa00SOllivier Robert  * keep us friendly with older implementations.  A little ugly.
439c2daa00SOllivier Robert  */
449c2daa00SOllivier Robert static int client_v6_capable = 0;   /* the client can handle longer messages */
459c2daa00SOllivier Robert 
469c2daa00SOllivier Robert #define v6sizeof(type)	(client_v6_capable ? sizeof(type) : v4sizeof(type))
47c0b746e5SOllivier Robert 
48c0b746e5SOllivier Robert struct req_proc {
49c0b746e5SOllivier Robert 	short request_code;	/* defined request code */
50c0b746e5SOllivier Robert 	short needs_auth;	/* true when authentication needed */
519c2daa00SOllivier Robert 	short sizeofitem;	/* size of request data item (older size)*/
529c2daa00SOllivier Robert 	short v6_sizeofitem;	/* size of request data item (new size)*/
532b15cb3dSCy Schubert 	void (*handler) (sockaddr_u *, endpt *,
542b15cb3dSCy Schubert 			   struct req_pkt *);	/* routine to handle request */
55c0b746e5SOllivier Robert };
56c0b746e5SOllivier Robert 
57c0b746e5SOllivier Robert /*
58c0b746e5SOllivier Robert  * Universal request codes
59c0b746e5SOllivier Robert  */
602b15cb3dSCy Schubert static const struct req_proc univ_codes[] = {
612b15cb3dSCy Schubert 	{ NO_REQUEST,		NOAUTH,	 0,	0, NULL }
62c0b746e5SOllivier Robert };
63c0b746e5SOllivier Robert 
642b15cb3dSCy Schubert static	void	req_ack	(sockaddr_u *, endpt *, struct req_pkt *, int);
652b15cb3dSCy Schubert static	void *	prepare_pkt	(sockaddr_u *, endpt *,
662b15cb3dSCy Schubert 				 struct req_pkt *, size_t);
672b15cb3dSCy Schubert static	void *	more_pkt	(void);
682b15cb3dSCy Schubert static	void	flush_pkt	(void);
692b15cb3dSCy Schubert static	void	list_peers	(sockaddr_u *, endpt *, struct req_pkt *);
702b15cb3dSCy Schubert static	void	list_peers_sum	(sockaddr_u *, endpt *, struct req_pkt *);
712b15cb3dSCy Schubert static	void	peer_info	(sockaddr_u *, endpt *, struct req_pkt *);
722b15cb3dSCy Schubert static	void	peer_stats	(sockaddr_u *, endpt *, struct req_pkt *);
732b15cb3dSCy Schubert static	void	sys_info	(sockaddr_u *, endpt *, struct req_pkt *);
742b15cb3dSCy Schubert static	void	sys_stats	(sockaddr_u *, endpt *, struct req_pkt *);
752b15cb3dSCy Schubert static	void	mem_stats	(sockaddr_u *, endpt *, struct req_pkt *);
762b15cb3dSCy Schubert static	void	io_stats	(sockaddr_u *, endpt *, struct req_pkt *);
772b15cb3dSCy Schubert static	void	timer_stats	(sockaddr_u *, endpt *, struct req_pkt *);
782b15cb3dSCy Schubert static	void	loop_info	(sockaddr_u *, endpt *, struct req_pkt *);
792b15cb3dSCy Schubert static	void	do_conf		(sockaddr_u *, endpt *, struct req_pkt *);
802b15cb3dSCy Schubert static	void	do_unconf	(sockaddr_u *, endpt *, struct req_pkt *);
812b15cb3dSCy Schubert static	void	set_sys_flag	(sockaddr_u *, endpt *, struct req_pkt *);
822b15cb3dSCy Schubert static	void	clr_sys_flag	(sockaddr_u *, endpt *, struct req_pkt *);
832b15cb3dSCy Schubert static	void	setclr_flags	(sockaddr_u *, endpt *, struct req_pkt *, u_long);
8468ba7e87SXin LI static	void	list_restrict4	(const restrict_u *, struct info_restrict **);
8568ba7e87SXin LI static	void	list_restrict6	(const restrict_u *, struct info_restrict **);
862b15cb3dSCy Schubert static	void	list_restrict	(sockaddr_u *, endpt *, struct req_pkt *);
872b15cb3dSCy Schubert static	void	do_resaddflags	(sockaddr_u *, endpt *, struct req_pkt *);
882b15cb3dSCy Schubert static	void	do_ressubflags	(sockaddr_u *, endpt *, struct req_pkt *);
892b15cb3dSCy Schubert static	void	do_unrestrict	(sockaddr_u *, endpt *, struct req_pkt *);
9009100258SXin LI static	void	do_restrict	(sockaddr_u *, endpt *, struct req_pkt *, restrict_op);
912b15cb3dSCy Schubert static	void	mon_getlist	(sockaddr_u *, endpt *, struct req_pkt *);
922b15cb3dSCy Schubert static	void	reset_stats	(sockaddr_u *, endpt *, struct req_pkt *);
932b15cb3dSCy Schubert static	void	reset_peer	(sockaddr_u *, endpt *, struct req_pkt *);
942b15cb3dSCy Schubert static	void	do_key_reread	(sockaddr_u *, endpt *, struct req_pkt *);
952b15cb3dSCy Schubert static	void	trust_key	(sockaddr_u *, endpt *, struct req_pkt *);
962b15cb3dSCy Schubert static	void	untrust_key	(sockaddr_u *, endpt *, struct req_pkt *);
972b15cb3dSCy Schubert static	void	do_trustkey	(sockaddr_u *, endpt *, struct req_pkt *, u_long);
982b15cb3dSCy Schubert static	void	get_auth_info	(sockaddr_u *, endpt *, struct req_pkt *);
992b15cb3dSCy Schubert static	void	req_get_traps	(sockaddr_u *, endpt *, struct req_pkt *);
1002b15cb3dSCy Schubert static	void	req_set_trap	(sockaddr_u *, endpt *, struct req_pkt *);
1012b15cb3dSCy Schubert static	void	req_clr_trap	(sockaddr_u *, endpt *, struct req_pkt *);
1022b15cb3dSCy Schubert static	void	do_setclr_trap	(sockaddr_u *, endpt *, struct req_pkt *, int);
1032b15cb3dSCy Schubert static	void	set_request_keyid (sockaddr_u *, endpt *, struct req_pkt *);
1042b15cb3dSCy Schubert static	void	set_control_keyid (sockaddr_u *, endpt *, struct req_pkt *);
1052b15cb3dSCy Schubert static	void	get_ctl_stats   (sockaddr_u *, endpt *, struct req_pkt *);
1062b15cb3dSCy Schubert static	void	get_if_stats    (sockaddr_u *, endpt *, struct req_pkt *);
1072b15cb3dSCy Schubert static	void	do_if_reload    (sockaddr_u *, endpt *, struct req_pkt *);
108c0b746e5SOllivier Robert #ifdef KERNEL_PLL
1092b15cb3dSCy Schubert static	void	get_kernel_info (sockaddr_u *, endpt *, struct req_pkt *);
110c0b746e5SOllivier Robert #endif /* KERNEL_PLL */
111c0b746e5SOllivier Robert #ifdef REFCLOCK
1122b15cb3dSCy Schubert static	void	get_clock_info (sockaddr_u *, endpt *, struct req_pkt *);
1132b15cb3dSCy Schubert static	void	set_clock_fudge (sockaddr_u *, endpt *, struct req_pkt *);
114c0b746e5SOllivier Robert #endif	/* REFCLOCK */
115c0b746e5SOllivier Robert #ifdef REFCLOCK
1162b15cb3dSCy Schubert static	void	get_clkbug_info (sockaddr_u *, endpt *, struct req_pkt *);
117c0b746e5SOllivier Robert #endif	/* REFCLOCK */
118c0b746e5SOllivier Robert 
119c0b746e5SOllivier Robert /*
120c0b746e5SOllivier Robert  * ntpd request codes
121c0b746e5SOllivier Robert  */
1222b15cb3dSCy Schubert static const struct req_proc ntp_codes[] = {
1232b15cb3dSCy Schubert 	{ REQ_PEER_LIST,	NOAUTH,	0, 0,	list_peers },
1242b15cb3dSCy Schubert 	{ REQ_PEER_LIST_SUM,	NOAUTH,	0, 0,	list_peers_sum },
1259c2daa00SOllivier Robert 	{ REQ_PEER_INFO,    NOAUTH, v4sizeof(struct info_peer_list),
1269c2daa00SOllivier Robert 				sizeof(struct info_peer_list), peer_info},
1279c2daa00SOllivier Robert 	{ REQ_PEER_STATS,   NOAUTH, v4sizeof(struct info_peer_list),
1289c2daa00SOllivier Robert 				sizeof(struct info_peer_list), peer_stats},
1299c2daa00SOllivier Robert 	{ REQ_SYS_INFO,		NOAUTH,	0, 0,	sys_info },
1309c2daa00SOllivier Robert 	{ REQ_SYS_STATS,	NOAUTH,	0, 0,	sys_stats },
1319c2daa00SOllivier Robert 	{ REQ_IO_STATS,		NOAUTH,	0, 0,	io_stats },
1329c2daa00SOllivier Robert 	{ REQ_MEM_STATS,	NOAUTH,	0, 0,	mem_stats },
1339c2daa00SOllivier Robert 	{ REQ_LOOP_INFO,	NOAUTH,	0, 0,	loop_info },
1349c2daa00SOllivier Robert 	{ REQ_TIMER_STATS,	NOAUTH,	0, 0,	timer_stats },
1359c2daa00SOllivier Robert 	{ REQ_CONFIG,	    AUTH, v4sizeof(struct conf_peer),
1369c2daa00SOllivier Robert 				sizeof(struct conf_peer), do_conf },
1379c2daa00SOllivier Robert 	{ REQ_UNCONFIG,	    AUTH, v4sizeof(struct conf_unpeer),
1389c2daa00SOllivier Robert 				sizeof(struct conf_unpeer), do_unconf },
1399c2daa00SOllivier Robert 	{ REQ_SET_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags),
1409c2daa00SOllivier Robert 				sizeof(struct conf_sys_flags), set_sys_flag },
1419c2daa00SOllivier Robert 	{ REQ_CLR_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags),
1429c2daa00SOllivier Robert 				sizeof(struct conf_sys_flags),  clr_sys_flag },
1439c2daa00SOllivier Robert 	{ REQ_GET_RESTRICT,	NOAUTH,	0, 0,	list_restrict },
1449c2daa00SOllivier Robert 	{ REQ_RESADDFLAGS, AUTH, v4sizeof(struct conf_restrict),
1459c2daa00SOllivier Robert 				sizeof(struct conf_restrict), do_resaddflags },
1469c2daa00SOllivier Robert 	{ REQ_RESSUBFLAGS, AUTH, v4sizeof(struct conf_restrict),
1479c2daa00SOllivier Robert 				sizeof(struct conf_restrict), do_ressubflags },
1489c2daa00SOllivier Robert 	{ REQ_UNRESTRICT, AUTH, v4sizeof(struct conf_restrict),
1499c2daa00SOllivier Robert 				sizeof(struct conf_restrict), do_unrestrict },
1502b15cb3dSCy Schubert 	{ REQ_MON_GETLIST,	NOAUTH,	0, 0,	mon_getlist },
1512b15cb3dSCy Schubert 	{ REQ_MON_GETLIST_1,	NOAUTH,	0, 0,	mon_getlist },
1529c2daa00SOllivier Robert 	{ REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), 0, reset_stats },
1539c2daa00SOllivier Robert 	{ REQ_RESET_PEER,  AUTH, v4sizeof(struct conf_unpeer),
1549c2daa00SOllivier Robert 				sizeof(struct conf_unpeer), reset_peer },
1559c2daa00SOllivier Robert 	{ REQ_REREAD_KEYS,	AUTH,	0, 0,	do_key_reread },
1569c2daa00SOllivier Robert 	{ REQ_TRUSTKEY,   AUTH, sizeof(u_long), sizeof(u_long), trust_key },
1579c2daa00SOllivier Robert 	{ REQ_UNTRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), untrust_key },
1589c2daa00SOllivier Robert 	{ REQ_AUTHINFO,		NOAUTH,	0, 0,	get_auth_info },
1599c2daa00SOllivier Robert 	{ REQ_TRAPS,		NOAUTH, 0, 0,	req_get_traps },
1609c2daa00SOllivier Robert 	{ REQ_ADD_TRAP,	AUTH, v4sizeof(struct conf_trap),
1619c2daa00SOllivier Robert 				sizeof(struct conf_trap), req_set_trap },
1629c2daa00SOllivier Robert 	{ REQ_CLR_TRAP,	AUTH, v4sizeof(struct conf_trap),
1639c2daa00SOllivier Robert 				sizeof(struct conf_trap), req_clr_trap },
1649c2daa00SOllivier Robert 	{ REQ_REQUEST_KEY, AUTH, sizeof(u_long), sizeof(u_long),
1659c2daa00SOllivier Robert 				set_request_keyid },
1669c2daa00SOllivier Robert 	{ REQ_CONTROL_KEY, AUTH, sizeof(u_long), sizeof(u_long),
1679c2daa00SOllivier Robert 				set_control_keyid },
1689c2daa00SOllivier Robert 	{ REQ_GET_CTLSTATS,	NOAUTH,	0, 0,	get_ctl_stats },
169c0b746e5SOllivier Robert #ifdef KERNEL_PLL
1709c2daa00SOllivier Robert 	{ REQ_GET_KERNEL,	NOAUTH,	0, 0,	get_kernel_info },
171c0b746e5SOllivier Robert #endif
172c0b746e5SOllivier Robert #ifdef REFCLOCK
1739c2daa00SOllivier Robert 	{ REQ_GET_CLOCKINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32),
1749c2daa00SOllivier Robert 				get_clock_info },
1759c2daa00SOllivier Robert 	{ REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge),
1769c2daa00SOllivier Robert 				sizeof(struct conf_fudge), set_clock_fudge },
1779c2daa00SOllivier Robert 	{ REQ_GET_CLKBUGINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32),
1789c2daa00SOllivier Robert 				get_clkbug_info },
179c0b746e5SOllivier Robert #endif
180ea906c41SOllivier Robert 	{ REQ_IF_STATS,		AUTH, 0, 0,	get_if_stats },
181ea906c41SOllivier Robert 	{ REQ_IF_RELOAD,	AUTH, 0, 0,	do_if_reload },
182ea906c41SOllivier Robert 
1839c2daa00SOllivier Robert 	{ NO_REQUEST,		NOAUTH,	0, 0,	0 }
184c0b746e5SOllivier Robert };
185c0b746e5SOllivier Robert 
186c0b746e5SOllivier Robert 
187c0b746e5SOllivier Robert /*
188c0b746e5SOllivier Robert  * Authentication keyid used to authenticate requests.  Zero means we
189c0b746e5SOllivier Robert  * don't allow writing anything.
190c0b746e5SOllivier Robert  */
191224ba2bdSOllivier Robert keyid_t info_auth_keyid;
192c0b746e5SOllivier Robert 
193c0b746e5SOllivier Robert /*
194c0b746e5SOllivier Robert  * Statistic counters to keep track of requests and responses.
195c0b746e5SOllivier Robert  */
196c0b746e5SOllivier Robert u_long numrequests;		/* number of requests we've received */
197c0b746e5SOllivier Robert u_long numresppkts;		/* number of resp packets sent with data */
198c0b746e5SOllivier Robert 
1992b15cb3dSCy Schubert /*
2002b15cb3dSCy Schubert  * lazy way to count errors, indexed by the error code
2012b15cb3dSCy Schubert  */
2022b15cb3dSCy Schubert u_long errorcounter[MAX_INFO_ERR + 1];
203c0b746e5SOllivier Robert 
204c0b746e5SOllivier Robert /*
205c0b746e5SOllivier Robert  * A hack.  To keep the authentication module clear of ntp-ism's, we
206c0b746e5SOllivier Robert  * include a time reset variable for its stats here.
207c0b746e5SOllivier Robert  */
2082b15cb3dSCy Schubert u_long auth_timereset;
209c0b746e5SOllivier Robert 
210c0b746e5SOllivier Robert /*
211c0b746e5SOllivier Robert  * Response packet used by these routines.  Also some state information
212c0b746e5SOllivier Robert  * so that we can handle packet formatting within a common set of
213c0b746e5SOllivier Robert  * subroutines.  Note we try to enter data in place whenever possible,
214c0b746e5SOllivier Robert  * but the need to set the more bit correctly means we occasionally
215c0b746e5SOllivier Robert  * use the extra buffer and copy.
216c0b746e5SOllivier Robert  */
217c0b746e5SOllivier Robert static struct resp_pkt rpkt;
218c0b746e5SOllivier Robert static int reqver;
219c0b746e5SOllivier Robert static int seqno;
220c0b746e5SOllivier Robert static int nitems;
221c0b746e5SOllivier Robert static int itemsize;
222c0b746e5SOllivier Robert static int databytes;
223c0b746e5SOllivier Robert static char exbuf[RESP_DATA_SIZE];
224c0b746e5SOllivier Robert static int usingexbuf;
2252b15cb3dSCy Schubert static sockaddr_u *toaddr;
2262b15cb3dSCy Schubert static endpt *frominter;
227c0b746e5SOllivier Robert 
228c0b746e5SOllivier Robert /*
229c0b746e5SOllivier Robert  * init_request - initialize request data
230c0b746e5SOllivier Robert  */
231c0b746e5SOllivier Robert void
232c0b746e5SOllivier Robert init_request (void)
233c0b746e5SOllivier Robert {
2342b15cb3dSCy Schubert 	size_t i;
235c0b746e5SOllivier Robert 
236c0b746e5SOllivier Robert 	numrequests = 0;
237c0b746e5SOllivier Robert 	numresppkts = 0;
238c0b746e5SOllivier Robert 	auth_timereset = 0;
239c0b746e5SOllivier Robert 	info_auth_keyid = 0;	/* by default, can't do this */
240c0b746e5SOllivier Robert 
241c0b746e5SOllivier Robert 	for (i = 0; i < sizeof(errorcounter)/sizeof(errorcounter[0]); i++)
242c0b746e5SOllivier Robert 	    errorcounter[i] = 0;
243c0b746e5SOllivier Robert }
244c0b746e5SOllivier Robert 
245c0b746e5SOllivier Robert 
246c0b746e5SOllivier Robert /*
247c0b746e5SOllivier Robert  * req_ack - acknowledge request with no data
248c0b746e5SOllivier Robert  */
249c0b746e5SOllivier Robert static void
250c0b746e5SOllivier Robert req_ack(
2512b15cb3dSCy Schubert 	sockaddr_u *srcadr,
2522b15cb3dSCy Schubert 	endpt *inter,
253c0b746e5SOllivier Robert 	struct req_pkt *inpkt,
254c0b746e5SOllivier Robert 	int errcode
255c0b746e5SOllivier Robert 	)
256c0b746e5SOllivier Robert {
257c0b746e5SOllivier Robert 	/*
258c0b746e5SOllivier Robert 	 * fill in the fields
259c0b746e5SOllivier Robert 	 */
260c0b746e5SOllivier Robert 	rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
261c0b746e5SOllivier Robert 	rpkt.auth_seq = AUTH_SEQ(0, 0);
262c0b746e5SOllivier Robert 	rpkt.implementation = inpkt->implementation;
263c0b746e5SOllivier Robert 	rpkt.request = inpkt->request;
264c0b746e5SOllivier Robert 	rpkt.err_nitems = ERR_NITEMS(errcode, 0);
265c0b746e5SOllivier Robert 	rpkt.mbz_itemsize = MBZ_ITEMSIZE(0);
266c0b746e5SOllivier Robert 
267c0b746e5SOllivier Robert 	/*
268c0b746e5SOllivier Robert 	 * send packet and bump counters
269c0b746e5SOllivier Robert 	 */
270c0b746e5SOllivier Robert 	sendpkt(srcadr, inter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE);
271c0b746e5SOllivier Robert 	errorcounter[errcode]++;
272c0b746e5SOllivier Robert }
273c0b746e5SOllivier Robert 
274c0b746e5SOllivier Robert 
275c0b746e5SOllivier Robert /*
276c0b746e5SOllivier Robert  * prepare_pkt - prepare response packet for transmission, return pointer
277c0b746e5SOllivier Robert  *		 to storage for data item.
278c0b746e5SOllivier Robert  */
2792b15cb3dSCy Schubert static void *
280c0b746e5SOllivier Robert prepare_pkt(
2812b15cb3dSCy Schubert 	sockaddr_u *srcadr,
2822b15cb3dSCy Schubert 	endpt *inter,
283c0b746e5SOllivier Robert 	struct req_pkt *pkt,
2842b15cb3dSCy Schubert 	size_t structsize
285c0b746e5SOllivier Robert 	)
286c0b746e5SOllivier Robert {
2872b15cb3dSCy Schubert 	DPRINTF(4, ("request: preparing pkt\n"));
288c0b746e5SOllivier Robert 
289c0b746e5SOllivier Robert 	/*
2909c2daa00SOllivier Robert 	 * Fill in the implementation, request and itemsize fields
291c0b746e5SOllivier Robert 	 * since these won't change.
292c0b746e5SOllivier Robert 	 */
293c0b746e5SOllivier Robert 	rpkt.implementation = pkt->implementation;
294c0b746e5SOllivier Robert 	rpkt.request = pkt->request;
295c0b746e5SOllivier Robert 	rpkt.mbz_itemsize = MBZ_ITEMSIZE(structsize);
296c0b746e5SOllivier Robert 
297c0b746e5SOllivier Robert 	/*
298c0b746e5SOllivier Robert 	 * Compute the static data needed to carry on.
299c0b746e5SOllivier Robert 	 */
300c0b746e5SOllivier Robert 	toaddr = srcadr;
301c0b746e5SOllivier Robert 	frominter = inter;
302c0b746e5SOllivier Robert 	seqno = 0;
303c0b746e5SOllivier Robert 	nitems = 0;
304c0b746e5SOllivier Robert 	itemsize = structsize;
305c0b746e5SOllivier Robert 	databytes = 0;
306c0b746e5SOllivier Robert 	usingexbuf = 0;
307c0b746e5SOllivier Robert 
308c0b746e5SOllivier Robert 	/*
309c0b746e5SOllivier Robert 	 * return the beginning of the packet buffer.
310c0b746e5SOllivier Robert 	 */
3112b15cb3dSCy Schubert 	return &rpkt.u;
312c0b746e5SOllivier Robert }
313c0b746e5SOllivier Robert 
314c0b746e5SOllivier Robert 
315c0b746e5SOllivier Robert /*
316c0b746e5SOllivier Robert  * more_pkt - return a data pointer for a new item.
317c0b746e5SOllivier Robert  */
3182b15cb3dSCy Schubert static void *
319c0b746e5SOllivier Robert more_pkt(void)
320c0b746e5SOllivier Robert {
321c0b746e5SOllivier Robert 	/*
322c0b746e5SOllivier Robert 	 * If we were using the extra buffer, send the packet.
323c0b746e5SOllivier Robert 	 */
324c0b746e5SOllivier Robert 	if (usingexbuf) {
3252b15cb3dSCy Schubert 		DPRINTF(3, ("request: sending pkt\n"));
326c0b746e5SOllivier Robert 		rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT, reqver);
327c0b746e5SOllivier Robert 		rpkt.auth_seq = AUTH_SEQ(0, seqno);
328c0b746e5SOllivier Robert 		rpkt.err_nitems = htons((u_short)nitems);
329c0b746e5SOllivier Robert 		sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
330c0b746e5SOllivier Robert 			RESP_HEADER_SIZE + databytes);
331c0b746e5SOllivier Robert 		numresppkts++;
332c0b746e5SOllivier Robert 
333c0b746e5SOllivier Robert 		/*
334c0b746e5SOllivier Robert 		 * Copy data out of exbuf into the packet.
335c0b746e5SOllivier Robert 		 */
3362b15cb3dSCy Schubert 		memcpy(&rpkt.u.data[0], exbuf, (unsigned)itemsize);
337c0b746e5SOllivier Robert 		seqno++;
338c0b746e5SOllivier Robert 		databytes = 0;
339c0b746e5SOllivier Robert 		nitems = 0;
340c0b746e5SOllivier Robert 		usingexbuf = 0;
341c0b746e5SOllivier Robert 	}
342c0b746e5SOllivier Robert 
343c0b746e5SOllivier Robert 	databytes += itemsize;
344c0b746e5SOllivier Robert 	nitems++;
345c0b746e5SOllivier Robert 	if (databytes + itemsize <= RESP_DATA_SIZE) {
3462b15cb3dSCy Schubert 		DPRINTF(4, ("request: giving him more data\n"));
347c0b746e5SOllivier Robert 		/*
348c0b746e5SOllivier Robert 		 * More room in packet.  Give him the
349c0b746e5SOllivier Robert 		 * next address.
350c0b746e5SOllivier Robert 		 */
3512b15cb3dSCy Schubert 		return &rpkt.u.data[databytes];
352c0b746e5SOllivier Robert 	} else {
353c0b746e5SOllivier Robert 		/*
354c0b746e5SOllivier Robert 		 * No room in packet.  Give him the extra
355c0b746e5SOllivier Robert 		 * buffer unless this was the last in the sequence.
356c0b746e5SOllivier Robert 		 */
3572b15cb3dSCy Schubert 		DPRINTF(4, ("request: into extra buffer\n"));
358c0b746e5SOllivier Robert 		if (seqno == MAXSEQ)
3592b15cb3dSCy Schubert 			return NULL;
360c0b746e5SOllivier Robert 		else {
361c0b746e5SOllivier Robert 			usingexbuf = 1;
362c0b746e5SOllivier Robert 			return exbuf;
363c0b746e5SOllivier Robert 		}
364c0b746e5SOllivier Robert 	}
365c0b746e5SOllivier Robert }
366c0b746e5SOllivier Robert 
367c0b746e5SOllivier Robert 
368c0b746e5SOllivier Robert /*
369c0b746e5SOllivier Robert  * flush_pkt - we're done, return remaining information.
370c0b746e5SOllivier Robert  */
371c0b746e5SOllivier Robert static void
372c0b746e5SOllivier Robert flush_pkt(void)
373c0b746e5SOllivier Robert {
3742b15cb3dSCy Schubert 	DPRINTF(3, ("request: flushing packet, %d items\n", nitems));
375c0b746e5SOllivier Robert 	/*
376c0b746e5SOllivier Robert 	 * Must send the last packet.  If nothing in here and nothing
377c0b746e5SOllivier Robert 	 * has been sent, send an error saying no data to be found.
378c0b746e5SOllivier Robert 	 */
379c0b746e5SOllivier Robert 	if (seqno == 0 && nitems == 0)
380c0b746e5SOllivier Robert 		req_ack(toaddr, frominter, (struct req_pkt *)&rpkt,
381c0b746e5SOllivier Robert 			INFO_ERR_NODATA);
382c0b746e5SOllivier Robert 	else {
383c0b746e5SOllivier Robert 		rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
384c0b746e5SOllivier Robert 		rpkt.auth_seq = AUTH_SEQ(0, seqno);
385c0b746e5SOllivier Robert 		rpkt.err_nitems = htons((u_short)nitems);
386c0b746e5SOllivier Robert 		sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
387c0b746e5SOllivier Robert 			RESP_HEADER_SIZE+databytes);
388c0b746e5SOllivier Robert 		numresppkts++;
389c0b746e5SOllivier Robert 	}
390c0b746e5SOllivier Robert }
391c0b746e5SOllivier Robert 
392c0b746e5SOllivier Robert 
393c0b746e5SOllivier Robert 
394c0b746e5SOllivier Robert /*
3952b15cb3dSCy Schubert  * Given a buffer, return the packet mode
3962b15cb3dSCy Schubert  */
3972b15cb3dSCy Schubert int
3982b15cb3dSCy Schubert get_packet_mode(struct recvbuf *rbufp)
3992b15cb3dSCy Schubert {
4002b15cb3dSCy Schubert 	struct req_pkt *inpkt = (struct req_pkt *)&rbufp->recv_pkt;
4012b15cb3dSCy Schubert 	return (INFO_MODE(inpkt->rm_vn_mode));
4022b15cb3dSCy Schubert }
4032b15cb3dSCy Schubert 
4042b15cb3dSCy Schubert 
4052b15cb3dSCy Schubert /*
406c0b746e5SOllivier Robert  * process_private - process private mode (7) packets
407c0b746e5SOllivier Robert  */
408c0b746e5SOllivier Robert void
409c0b746e5SOllivier Robert process_private(
410c0b746e5SOllivier Robert 	struct recvbuf *rbufp,
411c0b746e5SOllivier Robert 	int mod_okay
412c0b746e5SOllivier Robert 	)
413c0b746e5SOllivier Robert {
414eb6d21b4SOllivier Robert 	static u_long quiet_until;
415c0b746e5SOllivier Robert 	struct req_pkt *inpkt;
416ce265a54SOllivier Robert 	struct req_pkt_tail *tailinpkt;
4172b15cb3dSCy Schubert 	sockaddr_u *srcadr;
4182b15cb3dSCy Schubert 	endpt *inter;
4192b15cb3dSCy Schubert 	const struct req_proc *proc;
420224ba2bdSOllivier Robert 	int ec;
4219c2daa00SOllivier Robert 	short temp_size;
4222b15cb3dSCy Schubert 	l_fp ftmp;
4232b15cb3dSCy Schubert 	double dtemp;
4242b15cb3dSCy Schubert 	size_t recv_len;
4252b15cb3dSCy Schubert 	size_t noslop_len;
4262b15cb3dSCy Schubert 	size_t mac_len;
427c0b746e5SOllivier Robert 
428c0b746e5SOllivier Robert 	/*
429c0b746e5SOllivier Robert 	 * Initialize pointers, for convenience
430c0b746e5SOllivier Robert 	 */
4312b15cb3dSCy Schubert 	recv_len = rbufp->recv_length;
432c0b746e5SOllivier Robert 	inpkt = (struct req_pkt *)&rbufp->recv_pkt;
433c0b746e5SOllivier Robert 	srcadr = &rbufp->recv_srcadr;
434c0b746e5SOllivier Robert 	inter = rbufp->dstadr;
435c0b746e5SOllivier Robert 
4362b15cb3dSCy Schubert 	DPRINTF(3, ("process_private: impl %d req %d\n",
4372b15cb3dSCy Schubert 		    inpkt->implementation, inpkt->request));
438c0b746e5SOllivier Robert 
439c0b746e5SOllivier Robert 	/*
440c0b746e5SOllivier Robert 	 * Do some sanity checks on the packet.  Return a format
441c0b746e5SOllivier Robert 	 * error if it fails.
442c0b746e5SOllivier Robert 	 */
443224ba2bdSOllivier Robert 	ec = 0;
444224ba2bdSOllivier Robert 	if (   (++ec, ISRESPONSE(inpkt->rm_vn_mode))
445224ba2bdSOllivier Robert 	    || (++ec, ISMORE(inpkt->rm_vn_mode))
446224ba2bdSOllivier Robert 	    || (++ec, INFO_VERSION(inpkt->rm_vn_mode) > NTP_VERSION)
447224ba2bdSOllivier Robert 	    || (++ec, INFO_VERSION(inpkt->rm_vn_mode) < NTP_OLDVERSION)
448224ba2bdSOllivier Robert 	    || (++ec, INFO_SEQ(inpkt->auth_seq) != 0)
449224ba2bdSOllivier Robert 	    || (++ec, INFO_ERR(inpkt->err_nitems) != 0)
450224ba2bdSOllivier Robert 	    || (++ec, INFO_MBZ(inpkt->mbz_itemsize) != 0)
4512b15cb3dSCy Schubert 	    || (++ec, rbufp->recv_length < (int)REQ_LEN_HDR)
452224ba2bdSOllivier Robert 		) {
453eb6d21b4SOllivier Robert 		NLOG(NLOG_SYSEVENT)
454eb6d21b4SOllivier Robert 			if (current_time >= quiet_until) {
455eb6d21b4SOllivier Robert 				msyslog(LOG_ERR,
456eb6d21b4SOllivier Robert 					"process_private: drop test %d"
457eb6d21b4SOllivier Robert 					" failed, pkt from %s",
458eb6d21b4SOllivier Robert 					ec, stoa(srcadr));
459eb6d21b4SOllivier Robert 				quiet_until = current_time + 60;
460eb6d21b4SOllivier Robert 			}
461c0b746e5SOllivier Robert 		return;
462c0b746e5SOllivier Robert 	}
463c0b746e5SOllivier Robert 
464c0b746e5SOllivier Robert 	reqver = INFO_VERSION(inpkt->rm_vn_mode);
465c0b746e5SOllivier Robert 
466c0b746e5SOllivier Robert 	/*
467c0b746e5SOllivier Robert 	 * Get the appropriate procedure list to search.
468c0b746e5SOllivier Robert 	 */
469c0b746e5SOllivier Robert 	if (inpkt->implementation == IMPL_UNIV)
470c0b746e5SOllivier Robert 		proc = univ_codes;
4719c2daa00SOllivier Robert 	else if ((inpkt->implementation == IMPL_XNTPD) ||
4729c2daa00SOllivier Robert 		 (inpkt->implementation == IMPL_XNTPD_OLD))
473c0b746e5SOllivier Robert 		proc = ntp_codes;
474c0b746e5SOllivier Robert 	else {
475c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL);
476c0b746e5SOllivier Robert 		return;
477c0b746e5SOllivier Robert 	}
478c0b746e5SOllivier Robert 
479c0b746e5SOllivier Robert 	/*
480c0b746e5SOllivier Robert 	 * Search the list for the request codes.  If it isn't one
481c0b746e5SOllivier Robert 	 * we know, return an error.
482c0b746e5SOllivier Robert 	 */
483c0b746e5SOllivier Robert 	while (proc->request_code != NO_REQUEST) {
484c0b746e5SOllivier Robert 		if (proc->request_code == (short) inpkt->request)
485c0b746e5SOllivier Robert 			break;
486c0b746e5SOllivier Robert 		proc++;
487c0b746e5SOllivier Robert 	}
488c0b746e5SOllivier Robert 	if (proc->request_code == NO_REQUEST) {
489c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_REQ);
490c0b746e5SOllivier Robert 		return;
491c0b746e5SOllivier Robert 	}
492c0b746e5SOllivier Robert 
4932b15cb3dSCy Schubert 	DPRINTF(4, ("found request in tables\n"));
494c0b746e5SOllivier Robert 
495c0b746e5SOllivier Robert 	/*
4969c2daa00SOllivier Robert 	 * If we need data, check to see if we have some.  If we
4979c2daa00SOllivier Robert 	 * don't, check to see that there is none (picky, picky).
4989c2daa00SOllivier Robert 	 */
4999c2daa00SOllivier Robert 
5009c2daa00SOllivier Robert 	/* This part is a bit tricky, we want to be sure that the size
5019c2daa00SOllivier Robert 	 * returned is either the old or the new size.  We also can find
5029c2daa00SOllivier Robert 	 * out if the client can accept both types of messages this way.
5039c2daa00SOllivier Robert 	 *
5049c2daa00SOllivier Robert 	 * Handle the exception of REQ_CONFIG. It can have two data sizes.
5059c2daa00SOllivier Robert 	 */
5069c2daa00SOllivier Robert 	temp_size = INFO_ITEMSIZE(inpkt->mbz_itemsize);
5079c2daa00SOllivier Robert 	if ((temp_size != proc->sizeofitem &&
5089c2daa00SOllivier Robert 	     temp_size != proc->v6_sizeofitem) &&
5099c2daa00SOllivier Robert 	    !(inpkt->implementation == IMPL_XNTPD &&
5109c2daa00SOllivier Robert 	      inpkt->request == REQ_CONFIG &&
5119c2daa00SOllivier Robert 	      temp_size == sizeof(struct old_conf_peer))) {
5122b15cb3dSCy Schubert 		DPRINTF(3, ("process_private: wrong item size, received %d, should be %d or %d\n",
5132b15cb3dSCy Schubert 			    temp_size, proc->sizeofitem, proc->v6_sizeofitem));
5149c2daa00SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
5159c2daa00SOllivier Robert 		return;
5169c2daa00SOllivier Robert 	}
5179c2daa00SOllivier Robert 	if ((proc->sizeofitem != 0) &&
5182b15cb3dSCy Schubert 	    ((size_t)(temp_size * INFO_NITEMS(inpkt->err_nitems)) >
5192b15cb3dSCy Schubert 	     (recv_len - REQ_LEN_HDR))) {
5202b15cb3dSCy Schubert 		DPRINTF(3, ("process_private: not enough data\n"));
5219c2daa00SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
5229c2daa00SOllivier Robert 		return;
5239c2daa00SOllivier Robert 	}
5249c2daa00SOllivier Robert 
5259c2daa00SOllivier Robert 	switch (inpkt->implementation) {
5269c2daa00SOllivier Robert 	case IMPL_XNTPD:
5279c2daa00SOllivier Robert 		client_v6_capable = 1;
5289c2daa00SOllivier Robert 		break;
5299c2daa00SOllivier Robert 	case IMPL_XNTPD_OLD:
5309c2daa00SOllivier Robert 		client_v6_capable = 0;
5319c2daa00SOllivier Robert 		break;
5329c2daa00SOllivier Robert 	default:
5339c2daa00SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
5349c2daa00SOllivier Robert 		return;
5359c2daa00SOllivier Robert 	}
5369c2daa00SOllivier Robert 
5379c2daa00SOllivier Robert 	/*
538c0b746e5SOllivier Robert 	 * If we need to authenticate, do so.  Note that an
539c0b746e5SOllivier Robert 	 * authenticatable packet must include a mac field, must
540c0b746e5SOllivier Robert 	 * have used key info_auth_keyid and must have included
541c0b746e5SOllivier Robert 	 * a time stamp in the appropriate field.  The time stamp
542c0b746e5SOllivier Robert 	 * must be within INFO_TS_MAXSKEW of the receive
543c0b746e5SOllivier Robert 	 * time stamp.
544c0b746e5SOllivier Robert 	 */
545c0b746e5SOllivier Robert 	if (proc->needs_auth && sys_authenticate) {
546c0b746e5SOllivier Robert 
5472b15cb3dSCy Schubert 		if (recv_len < (REQ_LEN_HDR +
548ce265a54SOllivier Robert 		    (INFO_ITEMSIZE(inpkt->mbz_itemsize) *
5492b15cb3dSCy Schubert 		    INFO_NITEMS(inpkt->err_nitems)) +
5502b15cb3dSCy Schubert 		    REQ_TAIL_MIN)) {
551ce265a54SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
5522b15cb3dSCy Schubert 			return;
553ce265a54SOllivier Robert 		}
554ce265a54SOllivier Robert 
555c0b746e5SOllivier Robert 		/*
5562b15cb3dSCy Schubert 		 * For 16-octet digests, regardless of itemsize and
5572b15cb3dSCy Schubert 		 * nitems, authenticated requests are a fixed size
5582b15cb3dSCy Schubert 		 * with the timestamp, key ID, and digest located
5592b15cb3dSCy Schubert 		 * at the end of the packet.  Because the key ID
5602b15cb3dSCy Schubert 		 * determining the digest size precedes the digest,
5612b15cb3dSCy Schubert 		 * for larger digests the fixed size request scheme
5622b15cb3dSCy Schubert 		 * is abandoned and the timestamp, key ID, and digest
5632b15cb3dSCy Schubert 		 * are located relative to the start of the packet,
5642b15cb3dSCy Schubert 		 * with the digest size determined by the packet size.
565c0b746e5SOllivier Robert 		 */
5662b15cb3dSCy Schubert 		noslop_len = REQ_LEN_HDR
5672b15cb3dSCy Schubert 			     + INFO_ITEMSIZE(inpkt->mbz_itemsize) *
5682b15cb3dSCy Schubert 			       INFO_NITEMS(inpkt->err_nitems)
5692b15cb3dSCy Schubert 			     + sizeof(inpkt->tstamp);
5702b15cb3dSCy Schubert 		/* 32-bit alignment */
5712b15cb3dSCy Schubert 		noslop_len = (noslop_len + 3) & ~3;
5722b15cb3dSCy Schubert 		if (recv_len > (noslop_len + MAX_MAC_LEN))
5732b15cb3dSCy Schubert 			mac_len = 20;
5742b15cb3dSCy Schubert 		else
5752b15cb3dSCy Schubert 			mac_len = recv_len - noslop_len;
5762b15cb3dSCy Schubert 
5772b15cb3dSCy Schubert 		tailinpkt = (void *)((char *)inpkt + recv_len -
5782b15cb3dSCy Schubert 			    (mac_len + sizeof(inpkt->tstamp)));
5792b15cb3dSCy Schubert 
5802b15cb3dSCy Schubert 		/*
5812b15cb3dSCy Schubert 		 * If this guy is restricted from doing this, don't let
5822b15cb3dSCy Schubert 		 * him.  If the wrong key was used, or packet doesn't
5832b15cb3dSCy Schubert 		 * have mac, return.
5842b15cb3dSCy Schubert 		 */
58509100258SXin LI 		/* XXX: Use authistrustedip(), or equivalent. */
5862b15cb3dSCy Schubert 		if (!INFO_IS_AUTH(inpkt->auth_seq) || !info_auth_keyid
587ce265a54SOllivier Robert 		    || ntohl(tailinpkt->keyid) != info_auth_keyid) {
5882b15cb3dSCy Schubert 			DPRINTF(5, ("failed auth %d info_auth_keyid %u pkt keyid %u maclen %lu\n",
5892b15cb3dSCy Schubert 				    INFO_IS_AUTH(inpkt->auth_seq),
5902b15cb3dSCy Schubert 				    info_auth_keyid,
5912b15cb3dSCy Schubert 				    ntohl(tailinpkt->keyid), (u_long)mac_len));
592c0b746e5SOllivier Robert #ifdef DEBUG
5939c2daa00SOllivier Robert 			msyslog(LOG_DEBUG,
5942b15cb3dSCy Schubert 				"process_private: failed auth %d info_auth_keyid %u pkt keyid %u maclen %lu\n",
5959c2daa00SOllivier Robert 				INFO_IS_AUTH(inpkt->auth_seq),
5962b15cb3dSCy Schubert 				info_auth_keyid,
5972b15cb3dSCy Schubert 				ntohl(tailinpkt->keyid), (u_long)mac_len);
598c0b746e5SOllivier Robert #endif
599c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
600c0b746e5SOllivier Robert 			return;
601c0b746e5SOllivier Robert 		}
6022b15cb3dSCy Schubert 		if (recv_len > REQ_LEN_NOMAC + MAX_MAC_LEN) {
6032b15cb3dSCy Schubert 			DPRINTF(5, ("bad pkt length %zu\n", recv_len));
6042b15cb3dSCy Schubert 			msyslog(LOG_ERR,
6052b15cb3dSCy Schubert 				"process_private: bad pkt length %zu",
6062b15cb3dSCy Schubert 				recv_len);
607c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
608c0b746e5SOllivier Robert 			return;
609c0b746e5SOllivier Robert 		}
610c0b746e5SOllivier Robert 		if (!mod_okay || !authhavekey(info_auth_keyid)) {
6112b15cb3dSCy Schubert 			DPRINTF(5, ("failed auth mod_okay %d\n",
6122b15cb3dSCy Schubert 				    mod_okay));
613c0b746e5SOllivier Robert #ifdef DEBUG
6149c2daa00SOllivier Robert 			msyslog(LOG_DEBUG,
6159c2daa00SOllivier Robert 				"process_private: failed auth mod_okay %d\n",
6169c2daa00SOllivier Robert 				mod_okay);
617c0b746e5SOllivier Robert #endif
6182b15cb3dSCy Schubert 			if (!mod_okay) {
6192b15cb3dSCy Schubert 				sys_restricted++;
6202b15cb3dSCy Schubert 			}
621c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
622c0b746e5SOllivier Robert 			return;
623c0b746e5SOllivier Robert 		}
624c0b746e5SOllivier Robert 
625c0b746e5SOllivier Robert 		/*
626c0b746e5SOllivier Robert 		 * calculate absolute time difference between xmit time stamp
627c0b746e5SOllivier Robert 		 * and receive time stamp.  If too large, too bad.
628c0b746e5SOllivier Robert 		 */
629ce265a54SOllivier Robert 		NTOHL_FP(&tailinpkt->tstamp, &ftmp);
630c0b746e5SOllivier Robert 		L_SUB(&ftmp, &rbufp->recv_time);
631c0b746e5SOllivier Robert 		LFPTOD(&ftmp, dtemp);
6322b15cb3dSCy Schubert 		if (fabs(dtemp) > INFO_TS_MAXSKEW) {
633c0b746e5SOllivier Robert 			/*
634c0b746e5SOllivier Robert 			 * He's a loser.  Tell him.
635c0b746e5SOllivier Robert 			 */
6362b15cb3dSCy Schubert 			DPRINTF(5, ("xmit/rcv timestamp delta %g > INFO_TS_MAXSKEW %g\n",
6372b15cb3dSCy Schubert 				    dtemp, INFO_TS_MAXSKEW));
638c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
639c0b746e5SOllivier Robert 			return;
640c0b746e5SOllivier Robert 		}
641c0b746e5SOllivier Robert 
642c0b746e5SOllivier Robert 		/*
643c0b746e5SOllivier Robert 		 * So far so good.  See if decryption works out okay.
644c0b746e5SOllivier Robert 		 */
645c0b746e5SOllivier Robert 		if (!authdecrypt(info_auth_keyid, (u_int32 *)inpkt,
6462b15cb3dSCy Schubert 				 recv_len - mac_len, mac_len)) {
6472b15cb3dSCy Schubert 			DPRINTF(5, ("authdecrypt failed\n"));
648c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
649c0b746e5SOllivier Robert 			return;
650c0b746e5SOllivier Robert 		}
651c0b746e5SOllivier Robert 	}
652c0b746e5SOllivier Robert 
6532b15cb3dSCy Schubert 	DPRINTF(3, ("process_private: all okay, into handler\n"));
654c0b746e5SOllivier Robert 	/*
655c0b746e5SOllivier Robert 	 * Packet is okay.  Call the handler to send him data.
656c0b746e5SOllivier Robert 	 */
657c0b746e5SOllivier Robert 	(proc->handler)(srcadr, inter, inpkt);
658c0b746e5SOllivier Robert }
659c0b746e5SOllivier Robert 
660c0b746e5SOllivier Robert 
661c0b746e5SOllivier Robert /*
6622b15cb3dSCy Schubert  * list_peers - send a list of the peers
663c0b746e5SOllivier Robert  */
664c0b746e5SOllivier Robert static void
6652b15cb3dSCy Schubert list_peers(
6662b15cb3dSCy Schubert 	sockaddr_u *srcadr,
6672b15cb3dSCy Schubert 	endpt *inter,
668c0b746e5SOllivier Robert 	struct req_pkt *inpkt
669c0b746e5SOllivier Robert 	)
670c0b746e5SOllivier Robert {
6712b15cb3dSCy Schubert 	struct info_peer_list *	ip;
67268ba7e87SXin LI 	const struct peer *	pp;
673c0b746e5SOllivier Robert 
674c0b746e5SOllivier Robert 	ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt,
6759c2daa00SOllivier Robert 	    v6sizeof(struct info_peer_list));
6762b15cb3dSCy Schubert 	for (pp = peer_list; pp != NULL && ip != NULL; pp = pp->p_link) {
6772b15cb3dSCy Schubert 		if (IS_IPV6(&pp->srcadr)) {
67868ba7e87SXin LI 			if (!client_v6_capable)
67968ba7e87SXin LI 				continue;
6802b15cb3dSCy Schubert 			ip->addr6 = SOCK_ADDR6(&pp->srcadr);
6819c2daa00SOllivier Robert 			ip->v6_flag = 1;
6829c2daa00SOllivier Robert 		} else {
6832b15cb3dSCy Schubert 			ip->addr = NSRCADR(&pp->srcadr);
6849c2daa00SOllivier Robert 			if (client_v6_capable)
6859c2daa00SOllivier Robert 				ip->v6_flag = 0;
6869c2daa00SOllivier Robert 		}
6879c2daa00SOllivier Robert 
6889c2daa00SOllivier Robert 		ip->port = NSRCPORT(&pp->srcadr);
689c0b746e5SOllivier Robert 		ip->hmode = pp->hmode;
690c0b746e5SOllivier Robert 		ip->flags = 0;
691c0b746e5SOllivier Robert 		if (pp->flags & FLAG_CONFIG)
692c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_CONFIG;
693c0b746e5SOllivier Robert 		if (pp == sys_peer)
694c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_SYSPEER;
695c0b746e5SOllivier Robert 		if (pp->status == CTL_PST_SEL_SYNCCAND)
696c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_SEL_CANDIDATE;
697c0b746e5SOllivier Robert 		if (pp->status >= CTL_PST_SEL_SYSPEER)
698c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_SHORTLIST;
699c0b746e5SOllivier Robert 		ip = (struct info_peer_list *)more_pkt();
7002b15cb3dSCy Schubert 	}	/* for pp */
7012b15cb3dSCy Schubert 
702c0b746e5SOllivier Robert 	flush_pkt();
703c0b746e5SOllivier Robert }
704c0b746e5SOllivier Robert 
705c0b746e5SOllivier Robert 
706c0b746e5SOllivier Robert /*
7072b15cb3dSCy Schubert  * list_peers_sum - return extended peer list
708c0b746e5SOllivier Robert  */
709c0b746e5SOllivier Robert static void
7102b15cb3dSCy Schubert list_peers_sum(
7112b15cb3dSCy Schubert 	sockaddr_u *srcadr,
7122b15cb3dSCy Schubert 	endpt *inter,
713c0b746e5SOllivier Robert 	struct req_pkt *inpkt
714c0b746e5SOllivier Robert 	)
715c0b746e5SOllivier Robert {
71668ba7e87SXin LI 	struct info_peer_summary *	ips;
71768ba7e87SXin LI 	const struct peer *		pp;
718c0b746e5SOllivier Robert 	l_fp 				ltmp;
719c0b746e5SOllivier Robert 
7202b15cb3dSCy Schubert 	DPRINTF(3, ("wants peer list summary\n"));
7212b15cb3dSCy Schubert 
722c0b746e5SOllivier Robert 	ips = (struct info_peer_summary *)prepare_pkt(srcadr, inter, inpkt,
7239c2daa00SOllivier Robert 	    v6sizeof(struct info_peer_summary));
7242b15cb3dSCy Schubert 	for (pp = peer_list; pp != NULL && ips != NULL; pp = pp->p_link) {
7252b15cb3dSCy Schubert 		DPRINTF(4, ("sum: got one\n"));
7269c2daa00SOllivier Robert 		/*
7279c2daa00SOllivier Robert 		 * Be careful here not to return v6 peers when we
7289c2daa00SOllivier Robert 		 * want only v4.
7299c2daa00SOllivier Robert 		 */
7302b15cb3dSCy Schubert 		if (IS_IPV6(&pp->srcadr)) {
73168ba7e87SXin LI 			if (!client_v6_capable)
73268ba7e87SXin LI 				continue;
7332b15cb3dSCy Schubert 			ips->srcadr6 = SOCK_ADDR6(&pp->srcadr);
7349c2daa00SOllivier Robert 			ips->v6_flag = 1;
735ea906c41SOllivier Robert 			if (pp->dstadr)
7362b15cb3dSCy Schubert 				ips->dstadr6 = SOCK_ADDR6(&pp->dstadr->sin);
737ea906c41SOllivier Robert 			else
7382b15cb3dSCy Schubert 				ZERO(ips->dstadr6);
7399c2daa00SOllivier Robert 		} else {
7402b15cb3dSCy Schubert 			ips->srcadr = NSRCADR(&pp->srcadr);
7419c2daa00SOllivier Robert 			if (client_v6_capable)
7429c2daa00SOllivier Robert 				ips->v6_flag = 0;
743ea906c41SOllivier Robert 
7442b15cb3dSCy Schubert 			if (pp->dstadr) {
7452b15cb3dSCy Schubert 				if (!pp->processed)
7462b15cb3dSCy Schubert 					ips->dstadr = NSRCADR(&pp->dstadr->sin);
7472b15cb3dSCy Schubert 				else {
7482b15cb3dSCy Schubert 					if (MDF_BCAST == pp->cast_flags)
7492b15cb3dSCy Schubert 						ips->dstadr = NSRCADR(&pp->dstadr->bcast);
7502b15cb3dSCy Schubert 					else if (pp->cast_flags) {
7512b15cb3dSCy Schubert 						ips->dstadr = NSRCADR(&pp->dstadr->sin);
7522b15cb3dSCy Schubert 						if (!ips->dstadr)
7532b15cb3dSCy Schubert 							ips->dstadr = NSRCADR(&pp->dstadr->bcast);
7542b15cb3dSCy Schubert 					}
7552b15cb3dSCy Schubert 				}
75668ba7e87SXin LI 			} else {
7572b15cb3dSCy Schubert 				ips->dstadr = 0;
75868ba7e87SXin LI 			}
7599c2daa00SOllivier Robert 		}
760ea906c41SOllivier Robert 
7619c2daa00SOllivier Robert 		ips->srcport = NSRCPORT(&pp->srcadr);
762c0b746e5SOllivier Robert 		ips->stratum = pp->stratum;
763c0b746e5SOllivier Robert 		ips->hpoll = pp->hpoll;
764c0b746e5SOllivier Robert 		ips->ppoll = pp->ppoll;
765c0b746e5SOllivier Robert 		ips->reach = pp->reach;
766c0b746e5SOllivier Robert 		ips->flags = 0;
767c0b746e5SOllivier Robert 		if (pp == sys_peer)
768c0b746e5SOllivier Robert 			ips->flags |= INFO_FLAG_SYSPEER;
769c0b746e5SOllivier Robert 		if (pp->flags & FLAG_CONFIG)
770c0b746e5SOllivier Robert 			ips->flags |= INFO_FLAG_CONFIG;
771c0b746e5SOllivier Robert 		if (pp->flags & FLAG_REFCLOCK)
772c0b746e5SOllivier Robert 			ips->flags |= INFO_FLAG_REFCLOCK;
773c0b746e5SOllivier Robert 		if (pp->flags & FLAG_PREFER)
774c0b746e5SOllivier Robert 			ips->flags |= INFO_FLAG_PREFER;
775c0b746e5SOllivier Robert 		if (pp->flags & FLAG_BURST)
776c0b746e5SOllivier Robert 			ips->flags |= INFO_FLAG_BURST;
777c0b746e5SOllivier Robert 		if (pp->status == CTL_PST_SEL_SYNCCAND)
778c0b746e5SOllivier Robert 			ips->flags |= INFO_FLAG_SEL_CANDIDATE;
779c0b746e5SOllivier Robert 		if (pp->status >= CTL_PST_SEL_SYSPEER)
780c0b746e5SOllivier Robert 			ips->flags |= INFO_FLAG_SHORTLIST;
781c0b746e5SOllivier Robert 		ips->hmode = pp->hmode;
782c0b746e5SOllivier Robert 		ips->delay = HTONS_FP(DTOFP(pp->delay));
783c0b746e5SOllivier Robert 		DTOLFP(pp->offset, &ltmp);
784c0b746e5SOllivier Robert 		HTONL_FP(&ltmp, &ips->offset);
785ea906c41SOllivier Robert 		ips->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
78668ba7e87SXin LI 
787c0b746e5SOllivier Robert 		ips = (struct info_peer_summary *)more_pkt();
7882b15cb3dSCy Schubert 	}	/* for pp */
7892b15cb3dSCy Schubert 
790c0b746e5SOllivier Robert 	flush_pkt();
791c0b746e5SOllivier Robert }
792c0b746e5SOllivier Robert 
793c0b746e5SOllivier Robert 
794c0b746e5SOllivier Robert /*
795c0b746e5SOllivier Robert  * peer_info - send information for one or more peers
796c0b746e5SOllivier Robert  */
797c0b746e5SOllivier Robert static void
798c0b746e5SOllivier Robert peer_info (
7992b15cb3dSCy Schubert 	sockaddr_u *srcadr,
8002b15cb3dSCy Schubert 	endpt *inter,
801c0b746e5SOllivier Robert 	struct req_pkt *inpkt
802c0b746e5SOllivier Robert 	)
803c0b746e5SOllivier Robert {
8042b15cb3dSCy Schubert 	u_short			items;
8052b15cb3dSCy Schubert 	size_t			item_sz;
8062b15cb3dSCy Schubert 	char *			datap;
8072b15cb3dSCy Schubert 	struct info_peer_list	ipl;
8082b15cb3dSCy Schubert 	struct peer *		pp;
8092b15cb3dSCy Schubert 	struct info_peer *	ip;
8102b15cb3dSCy Schubert 	int			i;
8112b15cb3dSCy Schubert 	int			j;
8122b15cb3dSCy Schubert 	sockaddr_u		addr;
813c0b746e5SOllivier Robert 	l_fp			ltmp;
814c0b746e5SOllivier Robert 
815c0b746e5SOllivier Robert 	items = INFO_NITEMS(inpkt->err_nitems);
8162b15cb3dSCy Schubert 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
8172b15cb3dSCy Schubert 	datap = inpkt->u.data;
8182b15cb3dSCy Schubert 	if (item_sz != sizeof(ipl)) {
8192b15cb3dSCy Schubert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
8202b15cb3dSCy Schubert 		return;
8219c2daa00SOllivier Robert 	}
8222b15cb3dSCy Schubert 	ip = prepare_pkt(srcadr, inter, inpkt,
8232b15cb3dSCy Schubert 			 v6sizeof(struct info_peer));
8242b15cb3dSCy Schubert 	while (items-- > 0 && ip != NULL) {
8252b15cb3dSCy Schubert 		ZERO(ipl);
8262b15cb3dSCy Schubert 		memcpy(&ipl, datap, item_sz);
8272b15cb3dSCy Schubert 		ZERO_SOCK(&addr);
8282b15cb3dSCy Schubert 		NSRCPORT(&addr) = ipl.port;
8292b15cb3dSCy Schubert 		if (client_v6_capable && ipl.v6_flag) {
8302b15cb3dSCy Schubert 			AF(&addr) = AF_INET6;
8312b15cb3dSCy Schubert 			SOCK_ADDR6(&addr) = ipl.addr6;
8322b15cb3dSCy Schubert 		} else {
8332b15cb3dSCy Schubert 			AF(&addr) = AF_INET;
8342b15cb3dSCy Schubert 			NSRCADR(&addr) = ipl.addr;
8352b15cb3dSCy Schubert 		}
8362b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
8372b15cb3dSCy Schubert 		addr.sa.sa_len = SOCKLEN(&addr);
8389c2daa00SOllivier Robert #endif
8392b15cb3dSCy Schubert 		datap += item_sz;
840ea906c41SOllivier Robert 
84109100258SXin LI 		pp = findexistingpeer(&addr, NULL, NULL, -1, 0, NULL);
8422b15cb3dSCy Schubert 		if (NULL == pp)
8432b15cb3dSCy Schubert 			continue;
8442d4e511cSCy Schubert 		if (IS_IPV6(&pp->srcadr)) {
8452b15cb3dSCy Schubert 			if (pp->dstadr)
8462b15cb3dSCy Schubert 				ip->dstadr6 =
8472b15cb3dSCy Schubert 				    (MDF_BCAST == pp->cast_flags)
8482b15cb3dSCy Schubert 					? SOCK_ADDR6(&pp->dstadr->bcast)
8492b15cb3dSCy Schubert 					: SOCK_ADDR6(&pp->dstadr->sin);
8502b15cb3dSCy Schubert 			else
8512b15cb3dSCy Schubert 				ZERO(ip->dstadr6);
8522b15cb3dSCy Schubert 
8532b15cb3dSCy Schubert 			ip->srcadr6 = SOCK_ADDR6(&pp->srcadr);
8549c2daa00SOllivier Robert 			ip->v6_flag = 1;
8559c2daa00SOllivier Robert 		} else {
8562b15cb3dSCy Schubert 			if (pp->dstadr) {
8572b15cb3dSCy Schubert 				if (!pp->processed)
8582b15cb3dSCy Schubert 					ip->dstadr = NSRCADR(&pp->dstadr->sin);
8592b15cb3dSCy Schubert 				else {
8602b15cb3dSCy Schubert 					if (MDF_BCAST == pp->cast_flags)
8612b15cb3dSCy Schubert 						ip->dstadr = NSRCADR(&pp->dstadr->bcast);
8622b15cb3dSCy Schubert 					else if (pp->cast_flags) {
8632b15cb3dSCy Schubert 						ip->dstadr = NSRCADR(&pp->dstadr->sin);
8642b15cb3dSCy Schubert 						if (!ip->dstadr)
8652b15cb3dSCy Schubert 							ip->dstadr = NSRCADR(&pp->dstadr->bcast);
8662b15cb3dSCy Schubert 					}
8672b15cb3dSCy Schubert 				}
8682b15cb3dSCy Schubert 			} else
8692b15cb3dSCy Schubert 				ip->dstadr = 0;
8709c2daa00SOllivier Robert 
8712b15cb3dSCy Schubert 			ip->srcadr = NSRCADR(&pp->srcadr);
8729c2daa00SOllivier Robert 			if (client_v6_capable)
8739c2daa00SOllivier Robert 				ip->v6_flag = 0;
8749c2daa00SOllivier Robert 		}
875c0b746e5SOllivier Robert 		ip->srcport = NSRCPORT(&pp->srcadr);
876c0b746e5SOllivier Robert 		ip->flags = 0;
877c0b746e5SOllivier Robert 		if (pp == sys_peer)
878c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_SYSPEER;
879c0b746e5SOllivier Robert 		if (pp->flags & FLAG_CONFIG)
880c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_CONFIG;
881c0b746e5SOllivier Robert 		if (pp->flags & FLAG_REFCLOCK)
882c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_REFCLOCK;
883c0b746e5SOllivier Robert 		if (pp->flags & FLAG_PREFER)
884c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_PREFER;
885c0b746e5SOllivier Robert 		if (pp->flags & FLAG_BURST)
886c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_BURST;
887c0b746e5SOllivier Robert 		if (pp->status == CTL_PST_SEL_SYNCCAND)
888c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_SEL_CANDIDATE;
889c0b746e5SOllivier Robert 		if (pp->status >= CTL_PST_SEL_SYSPEER)
890c0b746e5SOllivier Robert 			ip->flags |= INFO_FLAG_SHORTLIST;
891c0b746e5SOllivier Robert 		ip->leap = pp->leap;
892c0b746e5SOllivier Robert 		ip->hmode = pp->hmode;
8934e1ef62aSXin LI 		ip->pmode = pp->pmode;
894c0b746e5SOllivier Robert 		ip->keyid = pp->keyid;
895c0b746e5SOllivier Robert 		ip->stratum = pp->stratum;
896c0b746e5SOllivier Robert 		ip->ppoll = pp->ppoll;
897c0b746e5SOllivier Robert 		ip->hpoll = pp->hpoll;
898c0b746e5SOllivier Robert 		ip->precision = pp->precision;
899c0b746e5SOllivier Robert 		ip->version = pp->version;
900c0b746e5SOllivier Robert 		ip->reach = pp->reach;
9019c2daa00SOllivier Robert 		ip->unreach = (u_char)pp->unreach;
902c0b746e5SOllivier Robert 		ip->flash = (u_char)pp->flash;
9039c2daa00SOllivier Robert 		ip->flash2 = (u_short)pp->flash;
9042b15cb3dSCy Schubert 		ip->estbdelay = HTONS_FP(DTOFP(pp->delay));
9052b15cb3dSCy Schubert 		ip->ttl = (u_char)pp->ttl;
906c0b746e5SOllivier Robert 		ip->associd = htons(pp->associd);
907c0b746e5SOllivier Robert 		ip->rootdelay = HTONS_FP(DTOUFP(pp->rootdelay));
9082b15cb3dSCy Schubert 		ip->rootdispersion = HTONS_FP(DTOUFP(pp->rootdisp));
909c0b746e5SOllivier Robert 		ip->refid = pp->refid;
910c0b746e5SOllivier Robert 		HTONL_FP(&pp->reftime, &ip->reftime);
9112b15cb3dSCy Schubert 		HTONL_FP(&pp->aorg, &ip->org);
912c0b746e5SOllivier Robert 		HTONL_FP(&pp->rec, &ip->rec);
913c0b746e5SOllivier Robert 		HTONL_FP(&pp->xmt, &ip->xmt);
914c0b746e5SOllivier Robert 		j = pp->filter_nextpt - 1;
915c0b746e5SOllivier Robert 		for (i = 0; i < NTP_SHIFT; i++, j--) {
916c0b746e5SOllivier Robert 			if (j < 0)
917c0b746e5SOllivier Robert 				j = NTP_SHIFT-1;
918c0b746e5SOllivier Robert 			ip->filtdelay[i] = HTONS_FP(DTOFP(pp->filter_delay[j]));
919c0b746e5SOllivier Robert 			DTOLFP(pp->filter_offset[j], &ltmp);
920c0b746e5SOllivier Robert 			HTONL_FP(&ltmp, &ip->filtoffset[i]);
9212b15cb3dSCy Schubert 			ip->order[i] = (u_char)((pp->filter_nextpt +
9222b15cb3dSCy Schubert 						 NTP_SHIFT - 1) -
9232b15cb3dSCy Schubert 						pp->filter_order[i]);
924c0b746e5SOllivier Robert 			if (ip->order[i] >= NTP_SHIFT)
925c0b746e5SOllivier Robert 				ip->order[i] -= NTP_SHIFT;
926c0b746e5SOllivier Robert 		}
927c0b746e5SOllivier Robert 		DTOLFP(pp->offset, &ltmp);
928c0b746e5SOllivier Robert 		HTONL_FP(&ltmp, &ip->offset);
929c0b746e5SOllivier Robert 		ip->delay = HTONS_FP(DTOFP(pp->delay));
930c0b746e5SOllivier Robert 		ip->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
931224ba2bdSOllivier Robert 		ip->selectdisp = HTONS_FP(DTOUFP(SQRT(pp->jitter)));
9322b15cb3dSCy Schubert 		ip = more_pkt();
933c0b746e5SOllivier Robert 	}
934c0b746e5SOllivier Robert 	flush_pkt();
935c0b746e5SOllivier Robert }
936c0b746e5SOllivier Robert 
937c0b746e5SOllivier Robert 
938c0b746e5SOllivier Robert /*
939c0b746e5SOllivier Robert  * peer_stats - send statistics for one or more peers
940c0b746e5SOllivier Robert  */
941c0b746e5SOllivier Robert static void
942c0b746e5SOllivier Robert peer_stats (
9432b15cb3dSCy Schubert 	sockaddr_u *srcadr,
9442b15cb3dSCy Schubert 	endpt *inter,
945c0b746e5SOllivier Robert 	struct req_pkt *inpkt
946c0b746e5SOllivier Robert 	)
947c0b746e5SOllivier Robert {
9482b15cb3dSCy Schubert 	u_short			items;
9492b15cb3dSCy Schubert 	size_t			item_sz;
9502b15cb3dSCy Schubert 	char *			datap;
9512b15cb3dSCy Schubert 	struct info_peer_list	ipl;
9522b15cb3dSCy Schubert 	struct peer *		pp;
9532b15cb3dSCy Schubert 	struct info_peer_stats *ip;
9542b15cb3dSCy Schubert 	sockaddr_u addr;
955c0b746e5SOllivier Robert 
9562b15cb3dSCy Schubert 	DPRINTF(1, ("peer_stats: called\n"));
957c0b746e5SOllivier Robert 	items = INFO_NITEMS(inpkt->err_nitems);
9582b15cb3dSCy Schubert 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
9592b15cb3dSCy Schubert 	datap = inpkt->u.data;
9602b15cb3dSCy Schubert 	if (item_sz > sizeof(ipl)) {
9612b15cb3dSCy Schubert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
9622b15cb3dSCy Schubert 		return;
9639c2daa00SOllivier Robert 	}
9642b15cb3dSCy Schubert 	ip = prepare_pkt(srcadr, inter, inpkt,
9652b15cb3dSCy Schubert 			 v6sizeof(struct info_peer_stats));
9662b15cb3dSCy Schubert 	while (items-- > 0 && ip != NULL) {
9672b15cb3dSCy Schubert 		ZERO(ipl);
9682b15cb3dSCy Schubert 		memcpy(&ipl, datap, item_sz);
9692b15cb3dSCy Schubert 		ZERO(addr);
9702b15cb3dSCy Schubert 		NSRCPORT(&addr) = ipl.port;
9712b15cb3dSCy Schubert 		if (client_v6_capable && ipl.v6_flag) {
9722b15cb3dSCy Schubert 			AF(&addr) = AF_INET6;
9732b15cb3dSCy Schubert 			SOCK_ADDR6(&addr) = ipl.addr6;
9742b15cb3dSCy Schubert 		} else {
9752b15cb3dSCy Schubert 			AF(&addr) = AF_INET;
9762b15cb3dSCy Schubert 			NSRCADR(&addr) = ipl.addr;
9772b15cb3dSCy Schubert 		}
9782b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
9792b15cb3dSCy Schubert 		addr.sa.sa_len = SOCKLEN(&addr);
9809c2daa00SOllivier Robert #endif
9812b15cb3dSCy Schubert 		DPRINTF(1, ("peer_stats: looking for %s, %d, %d\n",
9822b15cb3dSCy Schubert 			    stoa(&addr), ipl.port, NSRCPORT(&addr)));
9839c2daa00SOllivier Robert 
9842b15cb3dSCy Schubert 		datap += item_sz;
9852b15cb3dSCy Schubert 
98609100258SXin LI 		pp = findexistingpeer(&addr, NULL, NULL, -1, 0, NULL);
9872b15cb3dSCy Schubert 		if (NULL == pp)
988c0b746e5SOllivier Robert 			continue;
989ea906c41SOllivier Robert 
9902b15cb3dSCy Schubert 		DPRINTF(1, ("peer_stats: found %s\n", stoa(&addr)));
9912b15cb3dSCy Schubert 
9922b15cb3dSCy Schubert 		if (IS_IPV4(&pp->srcadr)) {
9932b15cb3dSCy Schubert 			if (pp->dstadr) {
9942b15cb3dSCy Schubert 				if (!pp->processed)
9952b15cb3dSCy Schubert 					ip->dstadr = NSRCADR(&pp->dstadr->sin);
9962b15cb3dSCy Schubert 				else {
9972b15cb3dSCy Schubert 					if (MDF_BCAST == pp->cast_flags)
9982b15cb3dSCy Schubert 						ip->dstadr = NSRCADR(&pp->dstadr->bcast);
9992b15cb3dSCy Schubert 					else if (pp->cast_flags) {
10002b15cb3dSCy Schubert 						ip->dstadr = NSRCADR(&pp->dstadr->sin);
10012b15cb3dSCy Schubert 						if (!ip->dstadr)
10022b15cb3dSCy Schubert 							ip->dstadr = NSRCADR(&pp->dstadr->bcast);
10032b15cb3dSCy Schubert 					}
10042b15cb3dSCy Schubert 				}
10052b15cb3dSCy Schubert 			} else
10062b15cb3dSCy Schubert 				ip->dstadr = 0;
10072b15cb3dSCy Schubert 
10082b15cb3dSCy Schubert 			ip->srcadr = NSRCADR(&pp->srcadr);
10099c2daa00SOllivier Robert 			if (client_v6_capable)
10109c2daa00SOllivier Robert 				ip->v6_flag = 0;
10119c2daa00SOllivier Robert 		} else {
1012ea906c41SOllivier Robert 			if (pp->dstadr)
10132b15cb3dSCy Schubert 				ip->dstadr6 =
10142b15cb3dSCy Schubert 				    (MDF_BCAST == pp->cast_flags)
10152b15cb3dSCy Schubert 					? SOCK_ADDR6(&pp->dstadr->bcast)
10162b15cb3dSCy Schubert 					: SOCK_ADDR6(&pp->dstadr->sin);
1017ea906c41SOllivier Robert 			else
10182b15cb3dSCy Schubert 				ZERO(ip->dstadr6);
1019ea906c41SOllivier Robert 
10202b15cb3dSCy Schubert 			ip->srcadr6 = SOCK_ADDR6(&pp->srcadr);
10219c2daa00SOllivier Robert 			ip->v6_flag = 1;
10229c2daa00SOllivier Robert 		}
1023c0b746e5SOllivier Robert 		ip->srcport = NSRCPORT(&pp->srcadr);
1024c0b746e5SOllivier Robert 		ip->flags = 0;
1025c0b746e5SOllivier Robert 		if (pp == sys_peer)
1026c0b746e5SOllivier Robert 		    ip->flags |= INFO_FLAG_SYSPEER;
1027c0b746e5SOllivier Robert 		if (pp->flags & FLAG_CONFIG)
1028c0b746e5SOllivier Robert 		    ip->flags |= INFO_FLAG_CONFIG;
1029c0b746e5SOllivier Robert 		if (pp->flags & FLAG_REFCLOCK)
1030c0b746e5SOllivier Robert 		    ip->flags |= INFO_FLAG_REFCLOCK;
1031c0b746e5SOllivier Robert 		if (pp->flags & FLAG_PREFER)
1032c0b746e5SOllivier Robert 		    ip->flags |= INFO_FLAG_PREFER;
1033c0b746e5SOllivier Robert 		if (pp->flags & FLAG_BURST)
1034c0b746e5SOllivier Robert 		    ip->flags |= INFO_FLAG_BURST;
1035ea906c41SOllivier Robert 		if (pp->flags & FLAG_IBURST)
1036ea906c41SOllivier Robert 		    ip->flags |= INFO_FLAG_IBURST;
1037c0b746e5SOllivier Robert 		if (pp->status == CTL_PST_SEL_SYNCCAND)
1038c0b746e5SOllivier Robert 		    ip->flags |= INFO_FLAG_SEL_CANDIDATE;
1039c0b746e5SOllivier Robert 		if (pp->status >= CTL_PST_SEL_SYSPEER)
1040c0b746e5SOllivier Robert 		    ip->flags |= INFO_FLAG_SHORTLIST;
1041ea906c41SOllivier Robert 		ip->flags = htons(ip->flags);
1042c0b746e5SOllivier Robert 		ip->timereceived = htonl((u_int32)(current_time - pp->timereceived));
1043c0b746e5SOllivier Robert 		ip->timetosend = htonl(pp->nextdate - current_time);
1044c0b746e5SOllivier Robert 		ip->timereachable = htonl((u_int32)(current_time - pp->timereachable));
1045c0b746e5SOllivier Robert 		ip->sent = htonl((u_int32)(pp->sent));
1046c0b746e5SOllivier Robert 		ip->processed = htonl((u_int32)(pp->processed));
1047c0b746e5SOllivier Robert 		ip->badauth = htonl((u_int32)(pp->badauth));
1048c0b746e5SOllivier Robert 		ip->bogusorg = htonl((u_int32)(pp->bogusorg));
1049c0b746e5SOllivier Robert 		ip->oldpkt = htonl((u_int32)(pp->oldpkt));
1050c0b746e5SOllivier Robert 		ip->seldisp = htonl((u_int32)(pp->seldisptoolarge));
1051c0b746e5SOllivier Robert 		ip->selbroken = htonl((u_int32)(pp->selbroken));
1052c0b746e5SOllivier Robert 		ip->candidate = pp->status;
1053c0b746e5SOllivier Robert 		ip = (struct info_peer_stats *)more_pkt();
1054c0b746e5SOllivier Robert 	}
1055c0b746e5SOllivier Robert 	flush_pkt();
1056c0b746e5SOllivier Robert }
1057c0b746e5SOllivier Robert 
1058c0b746e5SOllivier Robert 
1059c0b746e5SOllivier Robert /*
1060c0b746e5SOllivier Robert  * sys_info - return system info
1061c0b746e5SOllivier Robert  */
1062c0b746e5SOllivier Robert static void
1063c0b746e5SOllivier Robert sys_info(
10642b15cb3dSCy Schubert 	sockaddr_u *srcadr,
10652b15cb3dSCy Schubert 	endpt *inter,
1066c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1067c0b746e5SOllivier Robert 	)
1068c0b746e5SOllivier Robert {
1069c0b746e5SOllivier Robert 	register struct info_sys *is;
1070c0b746e5SOllivier Robert 
1071c0b746e5SOllivier Robert 	is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt,
10729c2daa00SOllivier Robert 	    v6sizeof(struct info_sys));
1073c0b746e5SOllivier Robert 
10742b15cb3dSCy Schubert 	if (sys_peer) {
10752b15cb3dSCy Schubert 		if (IS_IPV4(&sys_peer->srcadr)) {
10762b15cb3dSCy Schubert 			is->peer = NSRCADR(&sys_peer->srcadr);
10779c2daa00SOllivier Robert 			if (client_v6_capable)
10789c2daa00SOllivier Robert 				is->v6_flag = 0;
10799c2daa00SOllivier Robert 		} else if (client_v6_capable) {
10802b15cb3dSCy Schubert 			is->peer6 = SOCK_ADDR6(&sys_peer->srcadr);
10819c2daa00SOllivier Robert 			is->v6_flag = 1;
10829c2daa00SOllivier Robert 		}
1083c0b746e5SOllivier Robert 		is->peer_mode = sys_peer->hmode;
1084c0b746e5SOllivier Robert 	} else {
1085c0b746e5SOllivier Robert 		is->peer = 0;
10869c2daa00SOllivier Robert 		if (client_v6_capable) {
10879c2daa00SOllivier Robert 			is->v6_flag = 0;
10889c2daa00SOllivier Robert 		}
1089c0b746e5SOllivier Robert 		is->peer_mode = 0;
1090c0b746e5SOllivier Robert 	}
10919c2daa00SOllivier Robert 
1092c0b746e5SOllivier Robert 	is->leap = sys_leap;
1093c0b746e5SOllivier Robert 	is->stratum = sys_stratum;
1094c0b746e5SOllivier Robert 	is->precision = sys_precision;
1095c0b746e5SOllivier Robert 	is->rootdelay = htonl(DTOFP(sys_rootdelay));
10962b15cb3dSCy Schubert 	is->rootdispersion = htonl(DTOUFP(sys_rootdisp));
1097224ba2bdSOllivier Robert 	is->frequency = htonl(DTOFP(sys_jitter));
10982b15cb3dSCy Schubert 	is->stability = htonl(DTOUFP(clock_stability * 1e6));
1099c0b746e5SOllivier Robert 	is->refid = sys_refid;
1100c0b746e5SOllivier Robert 	HTONL_FP(&sys_reftime, &is->reftime);
1101c0b746e5SOllivier Robert 
1102c0b746e5SOllivier Robert 	is->poll = sys_poll;
1103c0b746e5SOllivier Robert 
1104c0b746e5SOllivier Robert 	is->flags = 0;
1105c0b746e5SOllivier Robert 	if (sys_authenticate)
1106c0b746e5SOllivier Robert 		is->flags |= INFO_FLAG_AUTHENTICATE;
1107a466cc55SCy Schubert 	if (sys_bclient || sys_mclient)
1108ce265a54SOllivier Robert 		is->flags |= INFO_FLAG_BCLIENT;
1109ce265a54SOllivier Robert #ifdef REFCLOCK
1110ce265a54SOllivier Robert 	if (cal_enable)
1111ce265a54SOllivier Robert 		is->flags |= INFO_FLAG_CAL;
1112ce265a54SOllivier Robert #endif /* REFCLOCK */
1113c0b746e5SOllivier Robert 	if (kern_enable)
1114c0b746e5SOllivier Robert 		is->flags |= INFO_FLAG_KERNEL;
1115c0b746e5SOllivier Robert 	if (mon_enabled != MON_OFF)
1116c0b746e5SOllivier Robert 		is->flags |= INFO_FLAG_MONITOR;
1117ce265a54SOllivier Robert 	if (ntp_enable)
1118ce265a54SOllivier Robert 		is->flags |= INFO_FLAG_NTP;
11192b15cb3dSCy Schubert 	if (hardpps_enable)
1120ce265a54SOllivier Robert 		is->flags |= INFO_FLAG_PPS_SYNC;
1121c0b746e5SOllivier Robert 	if (stats_control)
1122c0b746e5SOllivier Robert 		is->flags |= INFO_FLAG_FILEGEN;
1123c0b746e5SOllivier Robert 	is->bdelay = HTONS_FP(DTOFP(sys_bdelay));
11242b15cb3dSCy Schubert 	HTONL_UF(sys_authdelay.l_uf, &is->authdelay);
1125c0b746e5SOllivier Robert 	(void) more_pkt();
1126c0b746e5SOllivier Robert 	flush_pkt();
1127c0b746e5SOllivier Robert }
1128c0b746e5SOllivier Robert 
1129c0b746e5SOllivier Robert 
1130c0b746e5SOllivier Robert /*
1131c0b746e5SOllivier Robert  * sys_stats - return system statistics
1132c0b746e5SOllivier Robert  */
1133c0b746e5SOllivier Robert static void
1134c0b746e5SOllivier Robert sys_stats(
11352b15cb3dSCy Schubert 	sockaddr_u *srcadr,
11362b15cb3dSCy Schubert 	endpt *inter,
1137c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1138c0b746e5SOllivier Robert 	)
1139c0b746e5SOllivier Robert {
1140c0b746e5SOllivier Robert 	register struct info_sys_stats *ss;
1141c0b746e5SOllivier Robert 
1142c0b746e5SOllivier Robert 	ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt,
1143c0b746e5SOllivier Robert 		sizeof(struct info_sys_stats));
1144c0b746e5SOllivier Robert 	ss->timeup = htonl((u_int32)current_time);
1145c0b746e5SOllivier Robert 	ss->timereset = htonl((u_int32)(current_time - sys_stattime));
11469c2daa00SOllivier Robert 	ss->denied = htonl((u_int32)sys_restricted);
11472b15cb3dSCy Schubert 	ss->oldversionpkt = htonl((u_int32)sys_oldversion);
11482b15cb3dSCy Schubert 	ss->newversionpkt = htonl((u_int32)sys_newversion);
11492b15cb3dSCy Schubert 	ss->unknownversion = htonl((u_int32)sys_declined);
1150c0b746e5SOllivier Robert 	ss->badlength = htonl((u_int32)sys_badlength);
1151c0b746e5SOllivier Robert 	ss->processed = htonl((u_int32)sys_processed);
1152c0b746e5SOllivier Robert 	ss->badauth = htonl((u_int32)sys_badauth);
1153c0b746e5SOllivier Robert 	ss->limitrejected = htonl((u_int32)sys_limitrejected);
11549c2daa00SOllivier Robert 	ss->received = htonl((u_int32)sys_received);
115509100258SXin LI 	ss->lamport = htonl((u_int32)sys_lamport);
115609100258SXin LI 	ss->tsrounding = htonl((u_int32)sys_tsrounding);
1157c0b746e5SOllivier Robert 	(void) more_pkt();
1158c0b746e5SOllivier Robert 	flush_pkt();
1159c0b746e5SOllivier Robert }
1160c0b746e5SOllivier Robert 
1161c0b746e5SOllivier Robert 
1162c0b746e5SOllivier Robert /*
1163c0b746e5SOllivier Robert  * mem_stats - return memory statistics
1164c0b746e5SOllivier Robert  */
1165c0b746e5SOllivier Robert static void
1166c0b746e5SOllivier Robert mem_stats(
11672b15cb3dSCy Schubert 	sockaddr_u *srcadr,
11682b15cb3dSCy Schubert 	endpt *inter,
1169c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1170c0b746e5SOllivier Robert 	)
1171c0b746e5SOllivier Robert {
1172c0b746e5SOllivier Robert 	register struct info_mem_stats *ms;
1173c0b746e5SOllivier Robert 	register int i;
1174c0b746e5SOllivier Robert 
1175c0b746e5SOllivier Robert 	ms = (struct info_mem_stats *)prepare_pkt(srcadr, inter, inpkt,
1176c0b746e5SOllivier Robert 						  sizeof(struct info_mem_stats));
1177c0b746e5SOllivier Robert 
1178c0b746e5SOllivier Robert 	ms->timereset = htonl((u_int32)(current_time - peer_timereset));
1179c0b746e5SOllivier Robert 	ms->totalpeermem = htons((u_short)total_peer_structs);
1180c0b746e5SOllivier Robert 	ms->freepeermem = htons((u_short)peer_free_count);
1181c0b746e5SOllivier Robert 	ms->findpeer_calls = htonl((u_int32)findpeer_calls);
1182c0b746e5SOllivier Robert 	ms->allocations = htonl((u_int32)peer_allocations);
1183c0b746e5SOllivier Robert 	ms->demobilizations = htonl((u_int32)peer_demobilizations);
1184c0b746e5SOllivier Robert 
11852b15cb3dSCy Schubert 	for (i = 0; i < NTP_HASH_SIZE; i++)
11862b15cb3dSCy Schubert 		ms->hashcount[i] = (u_char)
1187767173ceSCy Schubert 		    min((u_int)peer_hash_count[i], UCHAR_MAX);
1188c0b746e5SOllivier Robert 
118968ba7e87SXin LI 	(void) more_pkt();
1190c0b746e5SOllivier Robert 	flush_pkt();
1191c0b746e5SOllivier Robert }
1192c0b746e5SOllivier Robert 
1193c0b746e5SOllivier Robert 
1194c0b746e5SOllivier Robert /*
1195c0b746e5SOllivier Robert  * io_stats - return io statistics
1196c0b746e5SOllivier Robert  */
1197c0b746e5SOllivier Robert static void
1198c0b746e5SOllivier Robert io_stats(
11992b15cb3dSCy Schubert 	sockaddr_u *srcadr,
12002b15cb3dSCy Schubert 	endpt *inter,
1201c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1202c0b746e5SOllivier Robert 	)
1203c0b746e5SOllivier Robert {
12042b15cb3dSCy Schubert 	struct info_io_stats *io;
1205c0b746e5SOllivier Robert 
1206c0b746e5SOllivier Robert 	io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt,
1207c0b746e5SOllivier Robert 						 sizeof(struct info_io_stats));
1208c0b746e5SOllivier Robert 
1209c0b746e5SOllivier Robert 	io->timereset = htonl((u_int32)(current_time - io_timereset));
1210c0b746e5SOllivier Robert 	io->totalrecvbufs = htons((u_short) total_recvbuffs());
1211c0b746e5SOllivier Robert 	io->freerecvbufs = htons((u_short) free_recvbuffs());
1212c0b746e5SOllivier Robert 	io->fullrecvbufs = htons((u_short) full_recvbuffs());
1213c0b746e5SOllivier Robert 	io->lowwater = htons((u_short) lowater_additions());
1214c0b746e5SOllivier Robert 	io->dropped = htonl((u_int32)packets_dropped);
1215c0b746e5SOllivier Robert 	io->ignored = htonl((u_int32)packets_ignored);
1216c0b746e5SOllivier Robert 	io->received = htonl((u_int32)packets_received);
1217c0b746e5SOllivier Robert 	io->sent = htonl((u_int32)packets_sent);
1218c0b746e5SOllivier Robert 	io->notsent = htonl((u_int32)packets_notsent);
1219c0b746e5SOllivier Robert 	io->interrupts = htonl((u_int32)handler_calls);
1220c0b746e5SOllivier Robert 	io->int_received = htonl((u_int32)handler_pkts);
1221c0b746e5SOllivier Robert 
1222c0b746e5SOllivier Robert 	(void) more_pkt();
1223c0b746e5SOllivier Robert 	flush_pkt();
1224c0b746e5SOllivier Robert }
1225c0b746e5SOllivier Robert 
1226c0b746e5SOllivier Robert 
1227c0b746e5SOllivier Robert /*
1228c0b746e5SOllivier Robert  * timer_stats - return timer statistics
1229c0b746e5SOllivier Robert  */
1230c0b746e5SOllivier Robert static void
1231c0b746e5SOllivier Robert timer_stats(
12322b15cb3dSCy Schubert 	sockaddr_u *		srcadr,
12332b15cb3dSCy Schubert 	endpt *			inter,
1234c0b746e5SOllivier Robert 	struct req_pkt *	inpkt
1235c0b746e5SOllivier Robert 	)
1236c0b746e5SOllivier Robert {
12372b15cb3dSCy Schubert 	struct info_timer_stats *	ts;
12382b15cb3dSCy Schubert 	u_long				sincereset;
1239c0b746e5SOllivier Robert 
12402b15cb3dSCy Schubert 	ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter,
12412b15cb3dSCy Schubert 						    inpkt, sizeof(*ts));
1242c0b746e5SOllivier Robert 
12432b15cb3dSCy Schubert 	sincereset = current_time - timer_timereset;
12442b15cb3dSCy Schubert 	ts->timereset = htonl((u_int32)sincereset);
12452b15cb3dSCy Schubert 	ts->alarms = ts->timereset;
12462b15cb3dSCy Schubert 	ts->overflows = htonl((u_int32)alarm_overflow);
1247c0b746e5SOllivier Robert 	ts->xmtcalls = htonl((u_int32)timer_xmtcalls);
1248c0b746e5SOllivier Robert 
1249c0b746e5SOllivier Robert 	(void) more_pkt();
1250c0b746e5SOllivier Robert 	flush_pkt();
1251c0b746e5SOllivier Robert }
1252c0b746e5SOllivier Robert 
1253c0b746e5SOllivier Robert 
1254c0b746e5SOllivier Robert /*
1255c0b746e5SOllivier Robert  * loop_info - return the current state of the loop filter
1256c0b746e5SOllivier Robert  */
1257c0b746e5SOllivier Robert static void
1258c0b746e5SOllivier Robert loop_info(
12592b15cb3dSCy Schubert 	sockaddr_u *srcadr,
12602b15cb3dSCy Schubert 	endpt *inter,
1261c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1262c0b746e5SOllivier Robert 	)
1263c0b746e5SOllivier Robert {
12642b15cb3dSCy Schubert 	struct info_loop *li;
1265c0b746e5SOllivier Robert 	l_fp ltmp;
1266c0b746e5SOllivier Robert 
1267c0b746e5SOllivier Robert 	li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt,
1268c0b746e5SOllivier Robert 	    sizeof(struct info_loop));
1269c0b746e5SOllivier Robert 
1270c0b746e5SOllivier Robert 	DTOLFP(last_offset, &ltmp);
1271c0b746e5SOllivier Robert 	HTONL_FP(&ltmp, &li->last_offset);
1272c0b746e5SOllivier Robert 	DTOLFP(drift_comp * 1e6, &ltmp);
1273c0b746e5SOllivier Robert 	HTONL_FP(&ltmp, &li->drift_comp);
1274c0b746e5SOllivier Robert 	li->compliance = htonl((u_int32)(tc_counter));
12752b15cb3dSCy Schubert 	li->watchdog_timer = htonl((u_int32)(current_time - sys_epoch));
1276c0b746e5SOllivier Robert 
127768ba7e87SXin LI 	(void) more_pkt();
1278c0b746e5SOllivier Robert 	flush_pkt();
1279c0b746e5SOllivier Robert }
1280c0b746e5SOllivier Robert 
1281c0b746e5SOllivier Robert 
1282c0b746e5SOllivier Robert /*
1283c0b746e5SOllivier Robert  * do_conf - add a peer to the configuration list
1284c0b746e5SOllivier Robert  */
1285c0b746e5SOllivier Robert static void
1286c0b746e5SOllivier Robert do_conf(
12872b15cb3dSCy Schubert 	sockaddr_u *srcadr,
12882b15cb3dSCy Schubert 	endpt *inter,
1289c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1290c0b746e5SOllivier Robert 	)
1291c0b746e5SOllivier Robert {
12922b15cb3dSCy Schubert 	u_short			items;
12932b15cb3dSCy Schubert 	size_t			item_sz;
1294224ba2bdSOllivier Robert 	u_int			fl;
12952b15cb3dSCy Schubert 	char *			datap;
12969c2daa00SOllivier Robert 	struct conf_peer	temp_cp;
12972b15cb3dSCy Schubert 	sockaddr_u		peeraddr;
1298c0b746e5SOllivier Robert 
1299c0b746e5SOllivier Robert 	/*
1300c0b746e5SOllivier Robert 	 * Do a check of everything to see that it looks
1301c0b746e5SOllivier Robert 	 * okay.  If not, complain about it.  Note we are
1302c0b746e5SOllivier Robert 	 * very picky here.
1303c0b746e5SOllivier Robert 	 */
1304c0b746e5SOllivier Robert 	items = INFO_NITEMS(inpkt->err_nitems);
13052b15cb3dSCy Schubert 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
13062b15cb3dSCy Schubert 	datap = inpkt->u.data;
13072b15cb3dSCy Schubert 	if (item_sz > sizeof(temp_cp)) {
1308c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1309c0b746e5SOllivier Robert 		return;
1310c0b746e5SOllivier Robert 	}
1311c0b746e5SOllivier Robert 
13129c2daa00SOllivier Robert 	while (items-- > 0) {
13132b15cb3dSCy Schubert 		ZERO(temp_cp);
13142b15cb3dSCy Schubert 		memcpy(&temp_cp, datap, item_sz);
13152b15cb3dSCy Schubert 		ZERO_SOCK(&peeraddr);
13169c2daa00SOllivier Robert 
13179c2daa00SOllivier Robert 		fl = 0;
13189c2daa00SOllivier Robert 		if (temp_cp.flags & CONF_FLAG_PREFER)
13199c2daa00SOllivier Robert 			fl |= FLAG_PREFER;
13209c2daa00SOllivier Robert 		if (temp_cp.flags & CONF_FLAG_BURST)
13219c2daa00SOllivier Robert 			fl |= FLAG_BURST;
1322ea906c41SOllivier Robert 		if (temp_cp.flags & CONF_FLAG_IBURST)
1323ea906c41SOllivier Robert 			fl |= FLAG_IBURST;
13242b15cb3dSCy Schubert #ifdef AUTOKEY
13259c2daa00SOllivier Robert 		if (temp_cp.flags & CONF_FLAG_SKEY)
13269c2daa00SOllivier Robert 			fl |= FLAG_SKEY;
13272b15cb3dSCy Schubert #endif	/* AUTOKEY */
13282b15cb3dSCy Schubert 		if (client_v6_capable && temp_cp.v6_flag) {
13292b15cb3dSCy Schubert 			AF(&peeraddr) = AF_INET6;
13302b15cb3dSCy Schubert 			SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6;
13319c2daa00SOllivier Robert 		} else {
13322b15cb3dSCy Schubert 			AF(&peeraddr) = AF_INET;
13332b15cb3dSCy Schubert 			NSRCADR(&peeraddr) = temp_cp.peeraddr;
1334c0b746e5SOllivier Robert 			/*
1335c0b746e5SOllivier Robert 			 * Make sure the address is valid
1336c0b746e5SOllivier Robert 			 */
13372b15cb3dSCy Schubert 			if (!ISREFCLOCKADR(&peeraddr) &&
13382b15cb3dSCy Schubert 			    ISBADADR(&peeraddr)) {
1339c0b746e5SOllivier Robert 				req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1340c0b746e5SOllivier Robert 				return;
1341c0b746e5SOllivier Robert 			}
1342c0b746e5SOllivier Robert 
13439c2daa00SOllivier Robert 		}
13449c2daa00SOllivier Robert 		NSRCPORT(&peeraddr) = htons(NTP_PORT);
13452b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
13462b15cb3dSCy Schubert 		peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
13479c2daa00SOllivier Robert #endif
13489c2daa00SOllivier Robert 
13494990d495SXin LI 		/* check mode value: 0 <= hmode <= 6
13504990d495SXin LI 		 *
13514990d495SXin LI 		 * There's no good global define for that limit, and
13524990d495SXin LI 		 * using a magic define is as good (or bad, actually) as
13534990d495SXin LI 		 * a magic number. So we use the highest possible peer
13544990d495SXin LI 		 * mode, and that is MODE_BCLIENT.
13554990d495SXin LI 		 *
13564990d495SXin LI 		 * [Bug 3009] claims that a problem occurs for hmode > 7,
13574990d495SXin LI 		 * but the code in ntp_peer.c indicates trouble for any
13584990d495SXin LI 		 * hmode > 6 ( --> MODE_BCLIENT).
13594990d495SXin LI 		 */
13604990d495SXin LI 		if (temp_cp.hmode > MODE_BCLIENT) {
13614990d495SXin LI 			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
13624990d495SXin LI 			return;
13634990d495SXin LI 		}
13644990d495SXin LI 
13654990d495SXin LI 		/* Any more checks on the values? Unchecked at this
13664990d495SXin LI 		 * point:
13674990d495SXin LI 		 *   - version
13684990d495SXin LI 		 *   - ttl
13694990d495SXin LI 		 *   - keyid
13704990d495SXin LI 		 *
13714990d495SXin LI 		 *   - minpoll/maxpoll, but they are treated properly
13724990d495SXin LI 		 *     for all cases internally. Checking not necessary.
137309100258SXin LI 		 *
137409100258SXin LI 		 * Note that we ignore any previously-specified ippeerlimit.
137509100258SXin LI 		 * If we're told to create the peer, we create the peer.
13764990d495SXin LI 		 */
13774990d495SXin LI 
13784990d495SXin LI 		/* finally create the peer */
137909100258SXin LI 		if (peer_config(&peeraddr, NULL, NULL, -1,
13809c2daa00SOllivier Robert 		    temp_cp.hmode, temp_cp.version, temp_cp.minpoll,
13819c2daa00SOllivier Robert 		    temp_cp.maxpoll, fl, temp_cp.ttl, temp_cp.keyid,
13824990d495SXin LI 		    NULL) == 0)
13834990d495SXin LI 		{
1384c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
1385c0b746e5SOllivier Robert 			return;
1386c0b746e5SOllivier Robert 		}
1387eb6d21b4SOllivier Robert 
13882b15cb3dSCy Schubert 		datap += item_sz;
1389eb6d21b4SOllivier Robert 	}
1390c0b746e5SOllivier Robert 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
1391c0b746e5SOllivier Robert }
1392c0b746e5SOllivier Robert 
1393224ba2bdSOllivier Robert 
1394224ba2bdSOllivier Robert /*
1395c0b746e5SOllivier Robert  * do_unconf - remove a peer from the configuration list
1396c0b746e5SOllivier Robert  */
1397c0b746e5SOllivier Robert static void
1398c0b746e5SOllivier Robert do_unconf(
13992b15cb3dSCy Schubert 	sockaddr_u *	srcadr,
14002b15cb3dSCy Schubert 	endpt *		inter,
1401c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1402c0b746e5SOllivier Robert 	)
1403c0b746e5SOllivier Robert {
14042b15cb3dSCy Schubert 	u_short			items;
14052b15cb3dSCy Schubert 	size_t			item_sz;
14062b15cb3dSCy Schubert 	char *			datap;
14079c2daa00SOllivier Robert 	struct conf_unpeer	temp_cp;
14082b15cb3dSCy Schubert 	struct peer *		p;
14092b15cb3dSCy Schubert 	sockaddr_u		peeraddr;
14104990d495SXin LI 	int			loops;
1411c0b746e5SOllivier Robert 
1412c0b746e5SOllivier Robert 	/*
1413c0b746e5SOllivier Robert 	 * This is a bit unstructured, but I like to be careful.
1414c0b746e5SOllivier Robert 	 * We check to see that every peer exists and is actually
1415c0b746e5SOllivier Robert 	 * configured.  If so, we remove them.  If not, we return
1416c0b746e5SOllivier Robert 	 * an error.
14174990d495SXin LI 	 *
14184990d495SXin LI 	 * [Bug 3011] Even if we checked all peers given in the request
14194990d495SXin LI 	 * in a dry run, there's still a chance that the caller played
14204990d495SXin LI 	 * unfair and gave the same peer multiple times. So we still
14214990d495SXin LI 	 * have to be prepared for nasty surprises in the second run ;)
1422c0b746e5SOllivier Robert 	 */
14234990d495SXin LI 
14244990d495SXin LI 	/* basic consistency checks */
14252b15cb3dSCy Schubert 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
14262b15cb3dSCy Schubert 	if (item_sz > sizeof(temp_cp)) {
14272b15cb3dSCy Schubert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
14282b15cb3dSCy Schubert 		return;
14299c2daa00SOllivier Robert 	}
14302b15cb3dSCy Schubert 
14314990d495SXin LI 	/* now do two runs: first a dry run, then a busy one */
14324990d495SXin LI 	for (loops = 0; loops != 2; ++loops) {
14334990d495SXin LI 		items = INFO_NITEMS(inpkt->err_nitems);
14344990d495SXin LI 		datap = inpkt->u.data;
14354990d495SXin LI 		while (items-- > 0) {
14364990d495SXin LI 			/* copy from request to local */
14372b15cb3dSCy Schubert 			ZERO(temp_cp);
14382b15cb3dSCy Schubert 			memcpy(&temp_cp, datap, item_sz);
14394990d495SXin LI 			/* get address structure */
14402b15cb3dSCy Schubert 			ZERO_SOCK(&peeraddr);
14412b15cb3dSCy Schubert 			if (client_v6_capable && temp_cp.v6_flag) {
14422b15cb3dSCy Schubert 				AF(&peeraddr) = AF_INET6;
14432b15cb3dSCy Schubert 				SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6;
14442b15cb3dSCy Schubert 			} else {
14452b15cb3dSCy Schubert 				AF(&peeraddr) = AF_INET;
14462b15cb3dSCy Schubert 				NSRCADR(&peeraddr) = temp_cp.peeraddr;
14472b15cb3dSCy Schubert 			}
14482b15cb3dSCy Schubert 			SET_PORT(&peeraddr, NTP_PORT);
14492b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
14502b15cb3dSCy Schubert 			peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
14519c2daa00SOllivier Robert #endif
14524990d495SXin LI 			DPRINTF(1, ("searching for %s\n",
14534990d495SXin LI 				    stoa(&peeraddr)));
14544990d495SXin LI 
14554990d495SXin LI 			/* search for matching configred(!) peer */
14562b15cb3dSCy Schubert 			p = NULL;
14574990d495SXin LI 			do {
14584990d495SXin LI 				p = findexistingpeer(
145909100258SXin LI 					&peeraddr, NULL, p, -1, 0, NULL);
14604990d495SXin LI 			} while (p && !(FLAG_CONFIG & p->flags));
14612b15cb3dSCy Schubert 
14624990d495SXin LI 			if (!loops && !p) {
14634990d495SXin LI 				/* Item not found in dry run -- bail! */
14644990d495SXin LI 				req_ack(srcadr, inter, inpkt,
14654990d495SXin LI 					INFO_ERR_NODATA);
1466c0b746e5SOllivier Robert 				return;
14674990d495SXin LI 			} else if (loops && p) {
14684990d495SXin LI 				/* Item found in busy run -- remove! */
14692b15cb3dSCy Schubert 				peer_clear(p, "GONE");
14702b15cb3dSCy Schubert 				unpeer(p);
14714990d495SXin LI 			}
14722b15cb3dSCy Schubert 			datap += item_sz;
1473c0b746e5SOllivier Robert 		}
14744990d495SXin LI 	}
1475c0b746e5SOllivier Robert 
14764990d495SXin LI 	/* report success */
1477c0b746e5SOllivier Robert 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
1478c0b746e5SOllivier Robert }
1479c0b746e5SOllivier Robert 
1480c0b746e5SOllivier Robert 
1481c0b746e5SOllivier Robert /*
1482c0b746e5SOllivier Robert  * set_sys_flag - set system flags
1483c0b746e5SOllivier Robert  */
1484c0b746e5SOllivier Robert static void
1485c0b746e5SOllivier Robert set_sys_flag(
14862b15cb3dSCy Schubert 	sockaddr_u *srcadr,
14872b15cb3dSCy Schubert 	endpt *inter,
1488c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1489c0b746e5SOllivier Robert 	)
1490c0b746e5SOllivier Robert {
1491c0b746e5SOllivier Robert 	setclr_flags(srcadr, inter, inpkt, 1);
1492c0b746e5SOllivier Robert }
1493c0b746e5SOllivier Robert 
1494c0b746e5SOllivier Robert 
1495c0b746e5SOllivier Robert /*
1496c0b746e5SOllivier Robert  * clr_sys_flag - clear system flags
1497c0b746e5SOllivier Robert  */
1498c0b746e5SOllivier Robert static void
1499c0b746e5SOllivier Robert clr_sys_flag(
15002b15cb3dSCy Schubert 	sockaddr_u *srcadr,
15012b15cb3dSCy Schubert 	endpt *inter,
1502c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1503c0b746e5SOllivier Robert 	)
1504c0b746e5SOllivier Robert {
1505c0b746e5SOllivier Robert 	setclr_flags(srcadr, inter, inpkt, 0);
1506c0b746e5SOllivier Robert }
1507c0b746e5SOllivier Robert 
1508c0b746e5SOllivier Robert 
1509c0b746e5SOllivier Robert /*
1510c0b746e5SOllivier Robert  * setclr_flags - do the grunge work of flag setting/clearing
1511c0b746e5SOllivier Robert  */
1512c0b746e5SOllivier Robert static void
1513c0b746e5SOllivier Robert setclr_flags(
15142b15cb3dSCy Schubert 	sockaddr_u *srcadr,
15152b15cb3dSCy Schubert 	endpt *inter,
1516c0b746e5SOllivier Robert 	struct req_pkt *inpkt,
1517c0b746e5SOllivier Robert 	u_long set
1518c0b746e5SOllivier Robert 	)
1519c0b746e5SOllivier Robert {
15202b15cb3dSCy Schubert 	struct conf_sys_flags *sf;
15212b15cb3dSCy Schubert 	u_int32 flags;
1522c0b746e5SOllivier Robert 
1523c0b746e5SOllivier Robert 	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
1524224ba2bdSOllivier Robert 		msyslog(LOG_ERR, "setclr_flags: err_nitems > 1");
1525c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1526c0b746e5SOllivier Robert 		return;
1527c0b746e5SOllivier Robert 	}
1528c0b746e5SOllivier Robert 
15292b15cb3dSCy Schubert 	sf = (struct conf_sys_flags *)&inpkt->u;
15302b15cb3dSCy Schubert 	flags = ntohl(sf->flags);
1531c0b746e5SOllivier Robert 
1532224ba2bdSOllivier Robert 	if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS |
1533c0b746e5SOllivier Robert 		      SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR |
1534ce265a54SOllivier Robert 		      SYS_FLAG_FILEGEN | SYS_FLAG_AUTH | SYS_FLAG_CAL)) {
1535224ba2bdSOllivier Robert 		msyslog(LOG_ERR, "setclr_flags: extra flags: %#x",
1536224ba2bdSOllivier Robert 			flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS |
1537224ba2bdSOllivier Robert 				  SYS_FLAG_NTP | SYS_FLAG_KERNEL |
1538ce265a54SOllivier Robert 				  SYS_FLAG_MONITOR | SYS_FLAG_FILEGEN |
1539ce265a54SOllivier Robert 				  SYS_FLAG_AUTH | SYS_FLAG_CAL));
1540c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1541c0b746e5SOllivier Robert 		return;
1542c0b746e5SOllivier Robert 	}
1543c0b746e5SOllivier Robert 
1544c0b746e5SOllivier Robert 	if (flags & SYS_FLAG_BCLIENT)
15459c2daa00SOllivier Robert 		proto_config(PROTO_BROADCLIENT, set, 0., NULL);
1546224ba2bdSOllivier Robert 	if (flags & SYS_FLAG_PPS)
15479c2daa00SOllivier Robert 		proto_config(PROTO_PPS, set, 0., NULL);
1548c0b746e5SOllivier Robert 	if (flags & SYS_FLAG_NTP)
15499c2daa00SOllivier Robert 		proto_config(PROTO_NTP, set, 0., NULL);
1550c0b746e5SOllivier Robert 	if (flags & SYS_FLAG_KERNEL)
15519c2daa00SOllivier Robert 		proto_config(PROTO_KERNEL, set, 0., NULL);
1552c0b746e5SOllivier Robert 	if (flags & SYS_FLAG_MONITOR)
15539c2daa00SOllivier Robert 		proto_config(PROTO_MONITOR, set, 0., NULL);
1554c0b746e5SOllivier Robert 	if (flags & SYS_FLAG_FILEGEN)
15559c2daa00SOllivier Robert 		proto_config(PROTO_FILEGEN, set, 0., NULL);
1556ce265a54SOllivier Robert 	if (flags & SYS_FLAG_AUTH)
15579c2daa00SOllivier Robert 		proto_config(PROTO_AUTHENTICATE, set, 0., NULL);
1558ce265a54SOllivier Robert 	if (flags & SYS_FLAG_CAL)
15599c2daa00SOllivier Robert 		proto_config(PROTO_CAL, set, 0., NULL);
1560c0b746e5SOllivier Robert 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
15612b15cb3dSCy Schubert }
1562ea906c41SOllivier Robert 
156368ba7e87SXin LI /* There have been some issues with the restrict list processing,
156468ba7e87SXin LI  * ranging from problems with deep recursion (resulting in stack
156568ba7e87SXin LI  * overflows) and overfull reply buffers.
156668ba7e87SXin LI  *
156768ba7e87SXin LI  * To avoid this trouble the list reversal is done iteratively using a
156868ba7e87SXin LI  * scratch pad.
156968ba7e87SXin LI  */
157068ba7e87SXin LI typedef struct RestrictStack RestrictStackT;
157168ba7e87SXin LI struct RestrictStack {
157268ba7e87SXin LI 	RestrictStackT   *link;
157368ba7e87SXin LI 	size_t            fcnt;
157468ba7e87SXin LI 	const restrict_u *pres[63];
157568ba7e87SXin LI };
157668ba7e87SXin LI 
157768ba7e87SXin LI static size_t
157868ba7e87SXin LI getStackSheetSize(
157968ba7e87SXin LI 	RestrictStackT *sp
158068ba7e87SXin LI 	)
158168ba7e87SXin LI {
158268ba7e87SXin LI 	if (sp)
158368ba7e87SXin LI 		return sizeof(sp->pres)/sizeof(sp->pres[0]);
158468ba7e87SXin LI 	return 0u;
158568ba7e87SXin LI }
158668ba7e87SXin LI 
158768ba7e87SXin LI static int/*BOOL*/
158868ba7e87SXin LI pushRestriction(
158968ba7e87SXin LI 	RestrictStackT  **spp,
159068ba7e87SXin LI 	const restrict_u *ptr
159168ba7e87SXin LI 	)
159268ba7e87SXin LI {
159368ba7e87SXin LI 	RestrictStackT *sp;
159468ba7e87SXin LI 
159568ba7e87SXin LI 	if (NULL == (sp = *spp) || 0 == sp->fcnt) {
159668ba7e87SXin LI 		/* need another sheet in the scratch pad */
159768ba7e87SXin LI 		sp = emalloc(sizeof(*sp));
159868ba7e87SXin LI 		sp->link = *spp;
159968ba7e87SXin LI 		sp->fcnt = getStackSheetSize(sp);
160068ba7e87SXin LI 		*spp = sp;
160168ba7e87SXin LI 	}
160268ba7e87SXin LI 	sp->pres[--sp->fcnt] = ptr;
160368ba7e87SXin LI 	return TRUE;
160468ba7e87SXin LI }
160568ba7e87SXin LI 
160668ba7e87SXin LI static int/*BOOL*/
160768ba7e87SXin LI popRestriction(
160868ba7e87SXin LI 	RestrictStackT   **spp,
160968ba7e87SXin LI 	const restrict_u **opp
161068ba7e87SXin LI 	)
161168ba7e87SXin LI {
161268ba7e87SXin LI 	RestrictStackT *sp;
161368ba7e87SXin LI 
161468ba7e87SXin LI 	if (NULL == (sp = *spp) || sp->fcnt >= getStackSheetSize(sp))
161568ba7e87SXin LI 		return FALSE;
161668ba7e87SXin LI 
161768ba7e87SXin LI 	*opp = sp->pres[sp->fcnt++];
161868ba7e87SXin LI 	if (sp->fcnt >= getStackSheetSize(sp)) {
161968ba7e87SXin LI 		/* discard sheet from scratch pad */
162068ba7e87SXin LI 		*spp = sp->link;
162168ba7e87SXin LI 		free(sp);
162268ba7e87SXin LI 	}
162368ba7e87SXin LI 	return TRUE;
162468ba7e87SXin LI }
162568ba7e87SXin LI 
162668ba7e87SXin LI static void
162768ba7e87SXin LI flushRestrictionStack(
162868ba7e87SXin LI 	RestrictStackT **spp
162968ba7e87SXin LI 	)
163068ba7e87SXin LI {
163168ba7e87SXin LI 	RestrictStackT *sp;
163268ba7e87SXin LI 
163368ba7e87SXin LI 	while (NULL != (sp = *spp)) {
163468ba7e87SXin LI 		*spp = sp->link;
163568ba7e87SXin LI 		free(sp);
163668ba7e87SXin LI 	}
163768ba7e87SXin LI }
163868ba7e87SXin LI 
16392b15cb3dSCy Schubert /*
164068ba7e87SXin LI  * list_restrict4 - iterative helper for list_restrict dumps IPv4
16412b15cb3dSCy Schubert  *		    restriction list in reverse order.
16422b15cb3dSCy Schubert  */
16432b15cb3dSCy Schubert static void
16442b15cb3dSCy Schubert list_restrict4(
164568ba7e87SXin LI 	const restrict_u *	res,
16462b15cb3dSCy Schubert 	struct info_restrict **	ppir
16472b15cb3dSCy Schubert 	)
16482b15cb3dSCy Schubert {
164968ba7e87SXin LI 	RestrictStackT *	rpad;
16502b15cb3dSCy Schubert 	struct info_restrict *	pir;
16512b15cb3dSCy Schubert 
16522b15cb3dSCy Schubert 	pir = *ppir;
165368ba7e87SXin LI 	for (rpad = NULL; res; res = res->link)
165468ba7e87SXin LI 		if (!pushRestriction(&rpad, res))
165568ba7e87SXin LI 			break;
165668ba7e87SXin LI 
165768ba7e87SXin LI 	while (pir && popRestriction(&rpad, &res)) {
16582b15cb3dSCy Schubert 		pir->addr = htonl(res->u.v4.addr);
16592b15cb3dSCy Schubert 		if (client_v6_capable)
16602b15cb3dSCy Schubert 			pir->v6_flag = 0;
16612b15cb3dSCy Schubert 		pir->mask = htonl(res->u.v4.mask);
16622b15cb3dSCy Schubert 		pir->count = htonl(res->count);
166309100258SXin LI 		pir->rflags = htons(res->rflags);
16642b15cb3dSCy Schubert 		pir->mflags = htons(res->mflags);
166568ba7e87SXin LI 		pir = (struct info_restrict *)more_pkt();
166668ba7e87SXin LI 	}
166768ba7e87SXin LI 	flushRestrictionStack(&rpad);
166868ba7e87SXin LI 	*ppir = pir;
16692b15cb3dSCy Schubert }
16702b15cb3dSCy Schubert 
16712b15cb3dSCy Schubert /*
167268ba7e87SXin LI  * list_restrict6 - iterative helper for list_restrict dumps IPv6
16732b15cb3dSCy Schubert  *		    restriction list in reverse order.
16742b15cb3dSCy Schubert  */
16752b15cb3dSCy Schubert static void
16762b15cb3dSCy Schubert list_restrict6(
167768ba7e87SXin LI 	const restrict_u *	res,
16782b15cb3dSCy Schubert 	struct info_restrict **	ppir
16792b15cb3dSCy Schubert 	)
16802b15cb3dSCy Schubert {
168168ba7e87SXin LI 	RestrictStackT *	rpad;
16822b15cb3dSCy Schubert 	struct info_restrict *	pir;
16832b15cb3dSCy Schubert 
16842b15cb3dSCy Schubert 	pir = *ppir;
168568ba7e87SXin LI 	for (rpad = NULL; res; res = res->link)
168668ba7e87SXin LI 		if (!pushRestriction(&rpad, res))
168768ba7e87SXin LI 			break;
168868ba7e87SXin LI 
168968ba7e87SXin LI 	while (pir && popRestriction(&rpad, &res)) {
16902b15cb3dSCy Schubert 		pir->addr6 = res->u.v6.addr;
16912b15cb3dSCy Schubert 		pir->mask6 = res->u.v6.mask;
16922b15cb3dSCy Schubert 		pir->v6_flag = 1;
16932b15cb3dSCy Schubert 		pir->count = htonl(res->count);
169409100258SXin LI 		pir->rflags = htons(res->rflags);
16952b15cb3dSCy Schubert 		pir->mflags = htons(res->mflags);
169668ba7e87SXin LI 		pir = (struct info_restrict *)more_pkt();
169768ba7e87SXin LI 	}
169868ba7e87SXin LI 	flushRestrictionStack(&rpad);
169968ba7e87SXin LI 	*ppir = pir;
1700c0b746e5SOllivier Robert }
1701c0b746e5SOllivier Robert 
1702c0b746e5SOllivier Robert 
1703c0b746e5SOllivier Robert /*
1704c0b746e5SOllivier Robert  * list_restrict - return the restrict list
1705c0b746e5SOllivier Robert  */
1706c0b746e5SOllivier Robert static void
1707c0b746e5SOllivier Robert list_restrict(
17082b15cb3dSCy Schubert 	sockaddr_u *srcadr,
17092b15cb3dSCy Schubert 	endpt *inter,
1710c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1711c0b746e5SOllivier Robert 	)
1712c0b746e5SOllivier Robert {
17132b15cb3dSCy Schubert 	struct info_restrict *ir;
1714c0b746e5SOllivier Robert 
17152b15cb3dSCy Schubert 	DPRINTF(3, ("wants restrict list summary\n"));
1716c0b746e5SOllivier Robert 
1717c0b746e5SOllivier Robert 	ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt,
17189c2daa00SOllivier Robert 	    v6sizeof(struct info_restrict));
17199c2daa00SOllivier Robert 
17202b15cb3dSCy Schubert 	/*
17212b15cb3dSCy Schubert 	 * The restriction lists are kept sorted in the reverse order
17222b15cb3dSCy Schubert 	 * than they were originally.  To preserve the output semantics,
172368ba7e87SXin LI 	 * dump each list in reverse order. The workers take care of that.
17242b15cb3dSCy Schubert 	 */
17252b15cb3dSCy Schubert 	list_restrict4(restrictlist4, &ir);
17269c2daa00SOllivier Robert 	if (client_v6_capable)
17272b15cb3dSCy Schubert 		list_restrict6(restrictlist6, &ir);
1728c0b746e5SOllivier Robert 	flush_pkt();
1729c0b746e5SOllivier Robert }
1730c0b746e5SOllivier Robert 
1731c0b746e5SOllivier Robert 
1732c0b746e5SOllivier Robert /*
1733c0b746e5SOllivier Robert  * do_resaddflags - add flags to a restrict entry (or create one)
1734c0b746e5SOllivier Robert  */
1735c0b746e5SOllivier Robert static void
1736c0b746e5SOllivier Robert do_resaddflags(
17372b15cb3dSCy Schubert 	sockaddr_u *srcadr,
17382b15cb3dSCy Schubert 	endpt *inter,
1739c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1740c0b746e5SOllivier Robert 	)
1741c0b746e5SOllivier Robert {
1742c0b746e5SOllivier Robert 	do_restrict(srcadr, inter, inpkt, RESTRICT_FLAGS);
1743c0b746e5SOllivier Robert }
1744c0b746e5SOllivier Robert 
1745c0b746e5SOllivier Robert 
1746c0b746e5SOllivier Robert 
1747c0b746e5SOllivier Robert /*
1748c0b746e5SOllivier Robert  * do_ressubflags - remove flags from a restrict entry
1749c0b746e5SOllivier Robert  */
1750c0b746e5SOllivier Robert static void
1751c0b746e5SOllivier Robert do_ressubflags(
17522b15cb3dSCy Schubert 	sockaddr_u *srcadr,
17532b15cb3dSCy Schubert 	endpt *inter,
1754c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1755c0b746e5SOllivier Robert 	)
1756c0b746e5SOllivier Robert {
1757c0b746e5SOllivier Robert 	do_restrict(srcadr, inter, inpkt, RESTRICT_UNFLAG);
1758c0b746e5SOllivier Robert }
1759c0b746e5SOllivier Robert 
1760c0b746e5SOllivier Robert 
1761c0b746e5SOllivier Robert /*
1762c0b746e5SOllivier Robert  * do_unrestrict - remove a restrict entry from the list
1763c0b746e5SOllivier Robert  */
1764c0b746e5SOllivier Robert static void
1765c0b746e5SOllivier Robert do_unrestrict(
17662b15cb3dSCy Schubert 	sockaddr_u *srcadr,
17672b15cb3dSCy Schubert 	endpt *inter,
1768c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1769c0b746e5SOllivier Robert 	)
1770c0b746e5SOllivier Robert {
1771c0b746e5SOllivier Robert 	do_restrict(srcadr, inter, inpkt, RESTRICT_REMOVE);
1772c0b746e5SOllivier Robert }
1773c0b746e5SOllivier Robert 
1774c0b746e5SOllivier Robert 
1775c0b746e5SOllivier Robert /*
1776c0b746e5SOllivier Robert  * do_restrict - do the dirty stuff of dealing with restrictions
1777c0b746e5SOllivier Robert  */
1778c0b746e5SOllivier Robert static void
1779c0b746e5SOllivier Robert do_restrict(
17802b15cb3dSCy Schubert 	sockaddr_u *srcadr,
17812b15cb3dSCy Schubert 	endpt *inter,
1782c0b746e5SOllivier Robert 	struct req_pkt *inpkt,
178309100258SXin LI 	restrict_op op
1784c0b746e5SOllivier Robert 	)
1785c0b746e5SOllivier Robert {
17862b15cb3dSCy Schubert 	char *			datap;
17872b15cb3dSCy Schubert 	struct conf_restrict	cr;
17882b15cb3dSCy Schubert 	u_short			items;
17892b15cb3dSCy Schubert 	size_t			item_sz;
17902b15cb3dSCy Schubert 	sockaddr_u		matchaddr;
17912b15cb3dSCy Schubert 	sockaddr_u		matchmask;
1792c0b746e5SOllivier Robert 	int			bad;
1793*f5f40dd6SCy Schubert 	int/*BOOL*/		success;
1794c0b746e5SOllivier Robert 
179509100258SXin LI 	switch(op) {
179609100258SXin LI 	    case RESTRICT_FLAGS:
179709100258SXin LI 	    case RESTRICT_UNFLAG:
179809100258SXin LI 	    case RESTRICT_REMOVE:
179909100258SXin LI 	    case RESTRICT_REMOVEIF:
180009100258SXin LI 	    	break;
180109100258SXin LI 
180209100258SXin LI 	    default:
180309100258SXin LI 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
180409100258SXin LI 		return;
180509100258SXin LI 	}
180609100258SXin LI 
1807c0b746e5SOllivier Robert 	/*
1808c0b746e5SOllivier Robert 	 * Do a check of the flags to make sure that only
1809c0b746e5SOllivier Robert 	 * the NTPPORT flag is set, if any.  If not, complain
1810c0b746e5SOllivier Robert 	 * about it.  Note we are very picky here.
1811c0b746e5SOllivier Robert 	 */
1812c0b746e5SOllivier Robert 	items = INFO_NITEMS(inpkt->err_nitems);
18132b15cb3dSCy Schubert 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
18142b15cb3dSCy Schubert 	datap = inpkt->u.data;
18152b15cb3dSCy Schubert 	if (item_sz > sizeof(cr)) {
18162b15cb3dSCy Schubert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
18172b15cb3dSCy Schubert 		return;
18182b15cb3dSCy Schubert 	}
1819c0b746e5SOllivier Robert 
182009100258SXin LI 	bad = 0;
1821c0b746e5SOllivier Robert 	while (items-- > 0 && !bad) {
18222b15cb3dSCy Schubert 		memcpy(&cr, datap, item_sz);
18232d4e511cSCy Schubert 		cr.flags = ntohs(cr.flags);	/* XXX */
18242b15cb3dSCy Schubert 		cr.mflags = ntohs(cr.mflags);
18252b15cb3dSCy Schubert 		if (~RESM_NTPONLY & cr.mflags)
1826224ba2bdSOllivier Robert 			bad |= 1;
18272b15cb3dSCy Schubert 		if (~RES_ALLFLAGS & cr.flags)
1828224ba2bdSOllivier Robert 			bad |= 2;
18292b15cb3dSCy Schubert 		if (INADDR_ANY != cr.mask) {
18302b15cb3dSCy Schubert 			if (client_v6_capable && cr.v6_flag) {
18312b15cb3dSCy Schubert 				if (IN6_IS_ADDR_UNSPECIFIED(&cr.addr6))
1832224ba2bdSOllivier Robert 					bad |= 4;
18332b15cb3dSCy Schubert 			} else {
18342b15cb3dSCy Schubert 				if (INADDR_ANY == cr.addr)
18359c2daa00SOllivier Robert 					bad |= 8;
18369c2daa00SOllivier Robert 			}
18372b15cb3dSCy Schubert 		}
18382b15cb3dSCy Schubert 		datap += item_sz;
1839c0b746e5SOllivier Robert 	}
1840c0b746e5SOllivier Robert 
1841c0b746e5SOllivier Robert 	if (bad) {
1842*f5f40dd6SCy Schubert 		msyslog(LOG_ERR, "%s: bad = 0x%x", __func__, bad);
1843c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1844c0b746e5SOllivier Robert 		return;
1845c0b746e5SOllivier Robert 	}
1846c0b746e5SOllivier Robert 
1847c0b746e5SOllivier Robert 	/*
18489034852cSGleb Smirnoff 	 * Looks okay, try it out.  Needs to reload data pointer and
18499034852cSGleb Smirnoff 	 * item counter. (Talos-CAN-0052)
1850c0b746e5SOllivier Robert 	 */
18512b15cb3dSCy Schubert 	ZERO_SOCK(&matchaddr);
18522b15cb3dSCy Schubert 	ZERO_SOCK(&matchmask);
18539034852cSGleb Smirnoff 	items = INFO_NITEMS(inpkt->err_nitems);
18542b15cb3dSCy Schubert 	datap = inpkt->u.data;
1855c0b746e5SOllivier Robert 
1856c0b746e5SOllivier Robert 	while (items-- > 0) {
18572b15cb3dSCy Schubert 		memcpy(&cr, datap, item_sz);
18582d4e511cSCy Schubert 		cr.flags = ntohs(cr.flags);	/* XXX: size */
18592b15cb3dSCy Schubert 		cr.mflags = ntohs(cr.mflags);
186009100258SXin LI 		cr.ippeerlimit = ntohs(cr.ippeerlimit);
18612b15cb3dSCy Schubert 		if (client_v6_capable && cr.v6_flag) {
18622b15cb3dSCy Schubert 			AF(&matchaddr) = AF_INET6;
18632b15cb3dSCy Schubert 			AF(&matchmask) = AF_INET6;
18642b15cb3dSCy Schubert 			SOCK_ADDR6(&matchaddr) = cr.addr6;
18652b15cb3dSCy Schubert 			SOCK_ADDR6(&matchmask) = cr.mask6;
18669c2daa00SOllivier Robert 		} else {
18672b15cb3dSCy Schubert 			AF(&matchaddr) = AF_INET;
18682b15cb3dSCy Schubert 			AF(&matchmask) = AF_INET;
18692b15cb3dSCy Schubert 			NSRCADR(&matchaddr) = cr.addr;
18702b15cb3dSCy Schubert 			NSRCADR(&matchmask) = cr.mask;
18719c2daa00SOllivier Robert 		}
1872*f5f40dd6SCy Schubert 		success =  hack_restrict(op, &matchaddr, &matchmask,
1873*f5f40dd6SCy Schubert 					 cr.ippeerlimit, cr.mflags,
1874*f5f40dd6SCy Schubert 					 cr.flags, 0);
1875*f5f40dd6SCy Schubert 		if (!success) {
1876*f5f40dd6SCy Schubert 			DPRINTF(1, ("%s: %s %s mask %s ippeerlimit %hd %s %s failed",
1877*f5f40dd6SCy Schubert 				    __func__, resop_str(op),
1878*f5f40dd6SCy Schubert 				    stoa(&matchaddr), stoa(&matchmask),
1879*f5f40dd6SCy Schubert 				    cr.ippeerlimit, mflags_str(cr.mflags),
1880*f5f40dd6SCy Schubert 				    rflags_str(cr.flags)));
1881*f5f40dd6SCy Schubert 		}
18822b15cb3dSCy Schubert 		datap += item_sz;
1883c0b746e5SOllivier Robert 	}
1884c0b746e5SOllivier Robert 
1885c0b746e5SOllivier Robert 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
1886c0b746e5SOllivier Robert }
1887c0b746e5SOllivier Robert 
1888c0b746e5SOllivier Robert 
1889c0b746e5SOllivier Robert /*
1890c0b746e5SOllivier Robert  * mon_getlist - return monitor data
1891c0b746e5SOllivier Robert  */
1892c0b746e5SOllivier Robert static void
18932b15cb3dSCy Schubert mon_getlist(
18942b15cb3dSCy Schubert 	sockaddr_u *srcadr,
18952b15cb3dSCy Schubert 	endpt *inter,
1896c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1897c0b746e5SOllivier Robert 	)
1898c0b746e5SOllivier Robert {
18992b15cb3dSCy Schubert 	req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
1900c0b746e5SOllivier Robert }
1901c0b746e5SOllivier Robert 
1902c0b746e5SOllivier Robert 
1903c0b746e5SOllivier Robert /*
1904c0b746e5SOllivier Robert  * Module entry points and the flags they correspond with
1905c0b746e5SOllivier Robert  */
1906c0b746e5SOllivier Robert struct reset_entry {
1907c0b746e5SOllivier Robert 	int flag;		/* flag this corresponds to */
19082b15cb3dSCy Schubert 	void (*handler)(void);	/* routine to handle request */
1909c0b746e5SOllivier Robert };
1910c0b746e5SOllivier Robert 
1911c0b746e5SOllivier Robert struct reset_entry reset_entries[] = {
1912c0b746e5SOllivier Robert 	{ RESET_FLAG_ALLPEERS,	peer_all_reset },
1913c0b746e5SOllivier Robert 	{ RESET_FLAG_IO,	io_clr_stats },
1914c0b746e5SOllivier Robert 	{ RESET_FLAG_SYS,	proto_clr_stats },
1915c0b746e5SOllivier Robert 	{ RESET_FLAG_MEM,	peer_clr_stats },
1916c0b746e5SOllivier Robert 	{ RESET_FLAG_TIMER,	timer_clr_stats },
1917c0b746e5SOllivier Robert 	{ RESET_FLAG_AUTH,	reset_auth_stats },
1918c0b746e5SOllivier Robert 	{ RESET_FLAG_CTL,	ctl_clr_stats },
1919c0b746e5SOllivier Robert 	{ 0,			0 }
1920c0b746e5SOllivier Robert };
1921c0b746e5SOllivier Robert 
1922c0b746e5SOllivier Robert /*
1923c0b746e5SOllivier Robert  * reset_stats - reset statistic counters here and there
1924c0b746e5SOllivier Robert  */
1925c0b746e5SOllivier Robert static void
1926c0b746e5SOllivier Robert reset_stats(
19272b15cb3dSCy Schubert 	sockaddr_u *srcadr,
19282b15cb3dSCy Schubert 	endpt *inter,
1929c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1930c0b746e5SOllivier Robert 	)
1931c0b746e5SOllivier Robert {
19322b15cb3dSCy Schubert 	struct reset_flags *rflags;
1933c0b746e5SOllivier Robert 	u_long flags;
1934c0b746e5SOllivier Robert 	struct reset_entry *rent;
1935c0b746e5SOllivier Robert 
1936c0b746e5SOllivier Robert 	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
1937224ba2bdSOllivier Robert 		msyslog(LOG_ERR, "reset_stats: err_nitems > 1");
1938c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1939c0b746e5SOllivier Robert 		return;
1940c0b746e5SOllivier Robert 	}
1941c0b746e5SOllivier Robert 
19422b15cb3dSCy Schubert 	rflags = (struct reset_flags *)&inpkt->u;
19432b15cb3dSCy Schubert 	flags = ntohl(rflags->flags);
1944c0b746e5SOllivier Robert 
1945c0b746e5SOllivier Robert 	if (flags & ~RESET_ALLFLAGS) {
1946224ba2bdSOllivier Robert 		msyslog(LOG_ERR, "reset_stats: reset leaves %#lx",
1947224ba2bdSOllivier Robert 			flags & ~RESET_ALLFLAGS);
1948c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1949c0b746e5SOllivier Robert 		return;
1950c0b746e5SOllivier Robert 	}
1951c0b746e5SOllivier Robert 
1952c0b746e5SOllivier Robert 	for (rent = reset_entries; rent->flag != 0; rent++) {
1953c0b746e5SOllivier Robert 		if (flags & rent->flag)
19542b15cb3dSCy Schubert 			(*rent->handler)();
1955c0b746e5SOllivier Robert 	}
1956c0b746e5SOllivier Robert 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
1957c0b746e5SOllivier Robert }
1958c0b746e5SOllivier Robert 
1959c0b746e5SOllivier Robert 
1960c0b746e5SOllivier Robert /*
1961c0b746e5SOllivier Robert  * reset_peer - clear a peer's statistics
1962c0b746e5SOllivier Robert  */
1963c0b746e5SOllivier Robert static void
1964c0b746e5SOllivier Robert reset_peer(
19652b15cb3dSCy Schubert 	sockaddr_u *srcadr,
19662b15cb3dSCy Schubert 	endpt *inter,
1967c0b746e5SOllivier Robert 	struct req_pkt *inpkt
1968c0b746e5SOllivier Robert 	)
1969c0b746e5SOllivier Robert {
19702b15cb3dSCy Schubert 	u_short			items;
19712b15cb3dSCy Schubert 	size_t			item_sz;
19722b15cb3dSCy Schubert 	char *			datap;
19732b15cb3dSCy Schubert 	struct conf_unpeer	cp;
19742b15cb3dSCy Schubert 	struct peer *		p;
19752b15cb3dSCy Schubert 	sockaddr_u		peeraddr;
1976c0b746e5SOllivier Robert 	int			bad;
1977c0b746e5SOllivier Robert 
1978c0b746e5SOllivier Robert 	/*
1979c0b746e5SOllivier Robert 	 * We check first to see that every peer exists.  If not,
1980c0b746e5SOllivier Robert 	 * we return an error.
1981c0b746e5SOllivier Robert 	 */
1982c0b746e5SOllivier Robert 
1983c0b746e5SOllivier Robert 	items = INFO_NITEMS(inpkt->err_nitems);
19842b15cb3dSCy Schubert 	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
19852b15cb3dSCy Schubert 	datap = inpkt->u.data;
19862b15cb3dSCy Schubert 	if (item_sz > sizeof(cp)) {
19872b15cb3dSCy Schubert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
19882b15cb3dSCy Schubert 		return;
19899c2daa00SOllivier Robert 	}
19902b15cb3dSCy Schubert 
19912b15cb3dSCy Schubert 	bad = FALSE;
19922b15cb3dSCy Schubert 	while (items-- > 0 && !bad) {
19932b15cb3dSCy Schubert 		ZERO(cp);
19942b15cb3dSCy Schubert 		memcpy(&cp, datap, item_sz);
19952b15cb3dSCy Schubert 		ZERO_SOCK(&peeraddr);
19962b15cb3dSCy Schubert 		if (client_v6_capable && cp.v6_flag) {
19972b15cb3dSCy Schubert 			AF(&peeraddr) = AF_INET6;
19982b15cb3dSCy Schubert 			SOCK_ADDR6(&peeraddr) = cp.peeraddr6;
19992b15cb3dSCy Schubert 		} else {
20002b15cb3dSCy Schubert 			AF(&peeraddr) = AF_INET;
20012b15cb3dSCy Schubert 			NSRCADR(&peeraddr) = cp.peeraddr;
20022b15cb3dSCy Schubert 		}
20032b15cb3dSCy Schubert 
20042b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
20052b15cb3dSCy Schubert 		peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
20069c2daa00SOllivier Robert #endif
200709100258SXin LI 		p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
20082b15cb3dSCy Schubert 		if (NULL == p)
2009c0b746e5SOllivier Robert 			bad++;
20102b15cb3dSCy Schubert 		datap += item_sz;
2011c0b746e5SOllivier Robert 	}
2012c0b746e5SOllivier Robert 
2013c0b746e5SOllivier Robert 	if (bad) {
2014c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2015c0b746e5SOllivier Robert 		return;
2016c0b746e5SOllivier Robert 	}
2017c0b746e5SOllivier Robert 
2018c0b746e5SOllivier Robert 	/*
20199034852cSGleb Smirnoff 	 * Now do it in earnest. Needs to reload data pointer and item
20209034852cSGleb Smirnoff 	 * counter. (Talos-CAN-0052)
2021c0b746e5SOllivier Robert 	 */
2022c0b746e5SOllivier Robert 
20239034852cSGleb Smirnoff 	items = INFO_NITEMS(inpkt->err_nitems);
20242b15cb3dSCy Schubert 	datap = inpkt->u.data;
2025c0b746e5SOllivier Robert 	while (items-- > 0) {
20262b15cb3dSCy Schubert 		ZERO(cp);
20272b15cb3dSCy Schubert 		memcpy(&cp, datap, item_sz);
20282b15cb3dSCy Schubert 		ZERO_SOCK(&peeraddr);
20292b15cb3dSCy Schubert 		if (client_v6_capable && cp.v6_flag) {
20302b15cb3dSCy Schubert 			AF(&peeraddr) = AF_INET6;
20312b15cb3dSCy Schubert 			SOCK_ADDR6(&peeraddr) = cp.peeraddr6;
20329c2daa00SOllivier Robert 		} else {
20332b15cb3dSCy Schubert 			AF(&peeraddr) = AF_INET;
20342b15cb3dSCy Schubert 			NSRCADR(&peeraddr) = cp.peeraddr;
20359c2daa00SOllivier Robert 		}
20362b15cb3dSCy Schubert 		SET_PORT(&peeraddr, 123);
20372b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
20382b15cb3dSCy Schubert 		peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
20399c2daa00SOllivier Robert #endif
204009100258SXin LI 		p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
20412b15cb3dSCy Schubert 		while (p != NULL) {
20422b15cb3dSCy Schubert 			peer_reset(p);
204309100258SXin LI 			p = findexistingpeer(&peeraddr, NULL, p, -1, 0, NULL);
2044c0b746e5SOllivier Robert 		}
20452b15cb3dSCy Schubert 		datap += item_sz;
2046c0b746e5SOllivier Robert 	}
2047c0b746e5SOllivier Robert 
2048c0b746e5SOllivier Robert 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
2049c0b746e5SOllivier Robert }
2050c0b746e5SOllivier Robert 
2051c0b746e5SOllivier Robert 
2052c0b746e5SOllivier Robert /*
2053c0b746e5SOllivier Robert  * do_key_reread - reread the encryption key file
2054c0b746e5SOllivier Robert  */
2055c0b746e5SOllivier Robert static void
2056c0b746e5SOllivier Robert do_key_reread(
20572b15cb3dSCy Schubert 	sockaddr_u *srcadr,
20582b15cb3dSCy Schubert 	endpt *inter,
2059c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2060c0b746e5SOllivier Robert 	)
2061c0b746e5SOllivier Robert {
2062c0b746e5SOllivier Robert 	rereadkeys();
2063c0b746e5SOllivier Robert 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
2064c0b746e5SOllivier Robert }
2065c0b746e5SOllivier Robert 
2066c0b746e5SOllivier Robert 
2067c0b746e5SOllivier Robert /*
2068c0b746e5SOllivier Robert  * trust_key - make one or more keys trusted
2069c0b746e5SOllivier Robert  */
2070c0b746e5SOllivier Robert static void
2071c0b746e5SOllivier Robert trust_key(
20722b15cb3dSCy Schubert 	sockaddr_u *srcadr,
20732b15cb3dSCy Schubert 	endpt *inter,
2074c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2075c0b746e5SOllivier Robert 	)
2076c0b746e5SOllivier Robert {
2077c0b746e5SOllivier Robert 	do_trustkey(srcadr, inter, inpkt, 1);
2078c0b746e5SOllivier Robert }
2079c0b746e5SOllivier Robert 
2080c0b746e5SOllivier Robert 
2081c0b746e5SOllivier Robert /*
2082c0b746e5SOllivier Robert  * untrust_key - make one or more keys untrusted
2083c0b746e5SOllivier Robert  */
2084c0b746e5SOllivier Robert static void
2085c0b746e5SOllivier Robert untrust_key(
20862b15cb3dSCy Schubert 	sockaddr_u *srcadr,
20872b15cb3dSCy Schubert 	endpt *inter,
2088c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2089c0b746e5SOllivier Robert 	)
2090c0b746e5SOllivier Robert {
2091c0b746e5SOllivier Robert 	do_trustkey(srcadr, inter, inpkt, 0);
2092c0b746e5SOllivier Robert }
2093c0b746e5SOllivier Robert 
2094c0b746e5SOllivier Robert 
2095c0b746e5SOllivier Robert /*
2096c0b746e5SOllivier Robert  * do_trustkey - make keys either trustable or untrustable
2097c0b746e5SOllivier Robert  */
2098c0b746e5SOllivier Robert static void
2099c0b746e5SOllivier Robert do_trustkey(
21002b15cb3dSCy Schubert 	sockaddr_u *srcadr,
21012b15cb3dSCy Schubert 	endpt *inter,
2102c0b746e5SOllivier Robert 	struct req_pkt *inpkt,
2103224ba2bdSOllivier Robert 	u_long trust
2104c0b746e5SOllivier Robert 	)
2105c0b746e5SOllivier Robert {
21063311ff84SXin LI 	register uint32_t *kp;
2107c0b746e5SOllivier Robert 	register int items;
2108c0b746e5SOllivier Robert 
2109c0b746e5SOllivier Robert 	items = INFO_NITEMS(inpkt->err_nitems);
21103311ff84SXin LI 	kp = (uint32_t *)&inpkt->u;
2111c0b746e5SOllivier Robert 	while (items-- > 0) {
2112c0b746e5SOllivier Robert 		authtrust(*kp, trust);
2113c0b746e5SOllivier Robert 		kp++;
2114c0b746e5SOllivier Robert 	}
2115c0b746e5SOllivier Robert 
2116c0b746e5SOllivier Robert 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
2117c0b746e5SOllivier Robert }
2118c0b746e5SOllivier Robert 
2119c0b746e5SOllivier Robert 
2120c0b746e5SOllivier Robert /*
2121c0b746e5SOllivier Robert  * get_auth_info - return some stats concerning the authentication module
2122c0b746e5SOllivier Robert  */
2123c0b746e5SOllivier Robert static void
2124c0b746e5SOllivier Robert get_auth_info(
21252b15cb3dSCy Schubert 	sockaddr_u *srcadr,
21262b15cb3dSCy Schubert 	endpt *inter,
2127c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2128c0b746e5SOllivier Robert 	)
2129c0b746e5SOllivier Robert {
2130c0b746e5SOllivier Robert 	register struct info_auth *ia;
2131c0b746e5SOllivier Robert 
2132c0b746e5SOllivier Robert 	ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt,
2133c0b746e5SOllivier Robert 					     sizeof(struct info_auth));
2134c0b746e5SOllivier Robert 
2135c0b746e5SOllivier Robert 	ia->numkeys = htonl((u_int32)authnumkeys);
2136c0b746e5SOllivier Robert 	ia->numfreekeys = htonl((u_int32)authnumfreekeys);
2137c0b746e5SOllivier Robert 	ia->keylookups = htonl((u_int32)authkeylookups);
2138c0b746e5SOllivier Robert 	ia->keynotfound = htonl((u_int32)authkeynotfound);
2139c0b746e5SOllivier Robert 	ia->encryptions = htonl((u_int32)authencryptions);
2140c0b746e5SOllivier Robert 	ia->decryptions = htonl((u_int32)authdecryptions);
2141c0b746e5SOllivier Robert 	ia->keyuncached = htonl((u_int32)authkeyuncached);
2142c0b746e5SOllivier Robert 	ia->expired = htonl((u_int32)authkeyexpired);
2143c0b746e5SOllivier Robert 	ia->timereset = htonl((u_int32)(current_time - auth_timereset));
2144c0b746e5SOllivier Robert 
2145c0b746e5SOllivier Robert 	(void) more_pkt();
2146c0b746e5SOllivier Robert 	flush_pkt();
2147c0b746e5SOllivier Robert }
2148c0b746e5SOllivier Robert 
2149c0b746e5SOllivier Robert 
2150c0b746e5SOllivier Robert 
2151c0b746e5SOllivier Robert /*
2152c0b746e5SOllivier Robert  * reset_auth_stats - reset the authentication stat counters.  Done here
2153c0b746e5SOllivier Robert  *		      to keep ntp-isms out of the authentication module
2154c0b746e5SOllivier Robert  */
21552b15cb3dSCy Schubert void
2156c0b746e5SOllivier Robert reset_auth_stats(void)
2157c0b746e5SOllivier Robert {
2158c0b746e5SOllivier Robert 	authkeylookups = 0;
2159c0b746e5SOllivier Robert 	authkeynotfound = 0;
2160c0b746e5SOllivier Robert 	authencryptions = 0;
2161c0b746e5SOllivier Robert 	authdecryptions = 0;
2162c0b746e5SOllivier Robert 	authkeyuncached = 0;
2163c0b746e5SOllivier Robert 	auth_timereset = current_time;
2164c0b746e5SOllivier Robert }
2165c0b746e5SOllivier Robert 
2166c0b746e5SOllivier Robert 
2167c0b746e5SOllivier Robert /*
2168c0b746e5SOllivier Robert  * req_get_traps - return information about current trap holders
2169c0b746e5SOllivier Robert  */
2170c0b746e5SOllivier Robert static void
2171c0b746e5SOllivier Robert req_get_traps(
21722b15cb3dSCy Schubert 	sockaddr_u *srcadr,
21732b15cb3dSCy Schubert 	endpt *inter,
2174c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2175c0b746e5SOllivier Robert 	)
2176c0b746e5SOllivier Robert {
21772b15cb3dSCy Schubert 	struct info_trap *it;
21782b15cb3dSCy Schubert 	struct ctl_trap *tr;
21792b15cb3dSCy Schubert 	size_t i;
2180c0b746e5SOllivier Robert 
2181c0b746e5SOllivier Robert 	if (num_ctl_traps == 0) {
2182c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2183c0b746e5SOllivier Robert 		return;
2184c0b746e5SOllivier Robert 	}
2185c0b746e5SOllivier Robert 
2186c0b746e5SOllivier Robert 	it = (struct info_trap *)prepare_pkt(srcadr, inter, inpkt,
21879c2daa00SOllivier Robert 	    v6sizeof(struct info_trap));
2188c0b746e5SOllivier Robert 
218968ba7e87SXin LI 	for (i = 0, tr = ctl_traps; it && i < COUNTOF(ctl_traps); i++, tr++) {
2190c0b746e5SOllivier Robert 		if (tr->tr_flags & TRAP_INUSE) {
21912b15cb3dSCy Schubert 			if (IS_IPV4(&tr->tr_addr)) {
2192c0b746e5SOllivier Robert 				if (tr->tr_localaddr == any_interface)
2193c0b746e5SOllivier Robert 					it->local_address = 0;
2194c0b746e5SOllivier Robert 				else
2195c0b746e5SOllivier Robert 					it->local_address
21962b15cb3dSCy Schubert 					    = NSRCADR(&tr->tr_localaddr->sin);
21972b15cb3dSCy Schubert 				it->trap_address = NSRCADR(&tr->tr_addr);
21989c2daa00SOllivier Robert 				if (client_v6_capable)
21999c2daa00SOllivier Robert 					it->v6_flag = 0;
22009c2daa00SOllivier Robert 			} else {
22019c2daa00SOllivier Robert 				if (!client_v6_capable)
22029c2daa00SOllivier Robert 					continue;
22039c2daa00SOllivier Robert 				it->local_address6
22042b15cb3dSCy Schubert 				    = SOCK_ADDR6(&tr->tr_localaddr->sin);
22052b15cb3dSCy Schubert 				it->trap_address6 = SOCK_ADDR6(&tr->tr_addr);
22069c2daa00SOllivier Robert 				it->v6_flag = 1;
22079c2daa00SOllivier Robert 			}
2208c0b746e5SOllivier Robert 			it->trap_port = NSRCPORT(&tr->tr_addr);
2209c0b746e5SOllivier Robert 			it->sequence = htons(tr->tr_sequence);
2210c0b746e5SOllivier Robert 			it->settime = htonl((u_int32)(current_time - tr->tr_settime));
2211c0b746e5SOllivier Robert 			it->origtime = htonl((u_int32)(current_time - tr->tr_origtime));
2212c0b746e5SOllivier Robert 			it->resets = htonl((u_int32)tr->tr_resets);
2213c0b746e5SOllivier Robert 			it->flags = htonl((u_int32)tr->tr_flags);
2214c0b746e5SOllivier Robert 			it = (struct info_trap *)more_pkt();
2215c0b746e5SOllivier Robert 		}
2216c0b746e5SOllivier Robert 	}
2217c0b746e5SOllivier Robert 	flush_pkt();
2218c0b746e5SOllivier Robert }
2219c0b746e5SOllivier Robert 
2220c0b746e5SOllivier Robert 
2221c0b746e5SOllivier Robert /*
2222c0b746e5SOllivier Robert  * req_set_trap - configure a trap
2223c0b746e5SOllivier Robert  */
2224c0b746e5SOllivier Robert static void
2225c0b746e5SOllivier Robert req_set_trap(
22262b15cb3dSCy Schubert 	sockaddr_u *srcadr,
22272b15cb3dSCy Schubert 	endpt *inter,
2228c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2229c0b746e5SOllivier Robert 	)
2230c0b746e5SOllivier Robert {
2231c0b746e5SOllivier Robert 	do_setclr_trap(srcadr, inter, inpkt, 1);
2232c0b746e5SOllivier Robert }
2233c0b746e5SOllivier Robert 
2234c0b746e5SOllivier Robert 
2235c0b746e5SOllivier Robert 
2236c0b746e5SOllivier Robert /*
2237c0b746e5SOllivier Robert  * req_clr_trap - unconfigure a trap
2238c0b746e5SOllivier Robert  */
2239c0b746e5SOllivier Robert static void
2240c0b746e5SOllivier Robert req_clr_trap(
22412b15cb3dSCy Schubert 	sockaddr_u *srcadr,
22422b15cb3dSCy Schubert 	endpt *inter,
2243c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2244c0b746e5SOllivier Robert 	)
2245c0b746e5SOllivier Robert {
2246c0b746e5SOllivier Robert 	do_setclr_trap(srcadr, inter, inpkt, 0);
2247c0b746e5SOllivier Robert }
2248c0b746e5SOllivier Robert 
2249c0b746e5SOllivier Robert 
2250c0b746e5SOllivier Robert 
2251c0b746e5SOllivier Robert /*
2252c0b746e5SOllivier Robert  * do_setclr_trap - do the grunge work of (un)configuring a trap
2253c0b746e5SOllivier Robert  */
2254c0b746e5SOllivier Robert static void
2255c0b746e5SOllivier Robert do_setclr_trap(
22562b15cb3dSCy Schubert 	sockaddr_u *srcadr,
22572b15cb3dSCy Schubert 	endpt *inter,
2258c0b746e5SOllivier Robert 	struct req_pkt *inpkt,
2259c0b746e5SOllivier Robert 	int set
2260c0b746e5SOllivier Robert 	)
2261c0b746e5SOllivier Robert {
2262c0b746e5SOllivier Robert 	register struct conf_trap *ct;
22632b15cb3dSCy Schubert 	register endpt *linter;
2264c0b746e5SOllivier Robert 	int res;
22652b15cb3dSCy Schubert 	sockaddr_u laddr;
2266c0b746e5SOllivier Robert 
2267c0b746e5SOllivier Robert 	/*
22682b15cb3dSCy Schubert 	 * Prepare sockaddr
2269c0b746e5SOllivier Robert 	 */
22702b15cb3dSCy Schubert 	ZERO_SOCK(&laddr);
22712b15cb3dSCy Schubert 	AF(&laddr) = AF(srcadr);
22722b15cb3dSCy Schubert 	SET_PORT(&laddr, NTP_PORT);
2273c0b746e5SOllivier Robert 
2274c0b746e5SOllivier Robert 	/*
2275c0b746e5SOllivier Robert 	 * Restrict ourselves to one item only.  This eliminates
2276c0b746e5SOllivier Robert 	 * the error reporting problem.
2277c0b746e5SOllivier Robert 	 */
2278c0b746e5SOllivier Robert 	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
2279224ba2bdSOllivier Robert 		msyslog(LOG_ERR, "do_setclr_trap: err_nitems > 1");
2280c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
2281c0b746e5SOllivier Robert 		return;
2282c0b746e5SOllivier Robert 	}
22832b15cb3dSCy Schubert 	ct = (struct conf_trap *)&inpkt->u;
2284c0b746e5SOllivier Robert 
2285c0b746e5SOllivier Robert 	/*
2286c0b746e5SOllivier Robert 	 * Look for the local interface.  If none, use the default.
2287c0b746e5SOllivier Robert 	 */
2288c0b746e5SOllivier Robert 	if (ct->local_address == 0) {
2289c0b746e5SOllivier Robert 		linter = any_interface;
2290c0b746e5SOllivier Robert 	} else {
22912b15cb3dSCy Schubert 		if (IS_IPV4(&laddr))
22922b15cb3dSCy Schubert 			NSRCADR(&laddr) = ct->local_address;
22939c2daa00SOllivier Robert 		else
22942b15cb3dSCy Schubert 			SOCK_ADDR6(&laddr) = ct->local_address6;
2295c0b746e5SOllivier Robert 		linter = findinterface(&laddr);
22962b15cb3dSCy Schubert 		if (NULL == linter) {
2297c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2298c0b746e5SOllivier Robert 			return;
2299c0b746e5SOllivier Robert 		}
2300c0b746e5SOllivier Robert 	}
2301c0b746e5SOllivier Robert 
23022b15cb3dSCy Schubert 	if (IS_IPV4(&laddr))
23032b15cb3dSCy Schubert 		NSRCADR(&laddr) = ct->trap_address;
2304c0b746e5SOllivier Robert 	else
23052b15cb3dSCy Schubert 		SOCK_ADDR6(&laddr) = ct->trap_address6;
23062b15cb3dSCy Schubert 	if (ct->trap_port)
23079c2daa00SOllivier Robert 		NSRCPORT(&laddr) = ct->trap_port;
23089c2daa00SOllivier Robert 	else
23092b15cb3dSCy Schubert 		SET_PORT(&laddr, TRAPPORT);
2310c0b746e5SOllivier Robert 
2311c0b746e5SOllivier Robert 	if (set) {
2312c0b746e5SOllivier Robert 		res = ctlsettrap(&laddr, linter, 0,
2313c0b746e5SOllivier Robert 				 INFO_VERSION(inpkt->rm_vn_mode));
2314c0b746e5SOllivier Robert 	} else {
2315c0b746e5SOllivier Robert 		res = ctlclrtrap(&laddr, linter, 0);
2316c0b746e5SOllivier Robert 	}
2317c0b746e5SOllivier Robert 
2318c0b746e5SOllivier Robert 	if (!res) {
2319c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2320c0b746e5SOllivier Robert 	} else {
2321c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_OKAY);
2322c0b746e5SOllivier Robert 	}
2323c0b746e5SOllivier Robert 	return;
2324c0b746e5SOllivier Robert }
2325c0b746e5SOllivier Robert 
23264990d495SXin LI /*
23274990d495SXin LI  * Validate a request packet for a new request or control key:
23284990d495SXin LI  *  - only one item allowed
23294990d495SXin LI  *  - key must be valid (that is, known, and not in the autokey range)
23304990d495SXin LI  */
23314990d495SXin LI static void
23324990d495SXin LI set_keyid_checked(
23334990d495SXin LI 	keyid_t        *into,
23344990d495SXin LI 	const char     *what,
23354990d495SXin LI 	sockaddr_u     *srcadr,
23364990d495SXin LI 	endpt          *inter,
23374990d495SXin LI 	struct req_pkt *inpkt
23384990d495SXin LI 	)
23394990d495SXin LI {
23404990d495SXin LI 	keyid_t *pkeyid;
23414990d495SXin LI 	keyid_t  tmpkey;
2342c0b746e5SOllivier Robert 
23434990d495SXin LI 	/* restrict ourselves to one item only */
23444990d495SXin LI 	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
23454990d495SXin LI 		msyslog(LOG_ERR, "set_keyid_checked[%s]: err_nitems > 1",
23464990d495SXin LI 			what);
23474990d495SXin LI 		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
23484990d495SXin LI 		return;
23494990d495SXin LI 	}
23504990d495SXin LI 
23514990d495SXin LI 	/* plug the new key from the packet */
23524990d495SXin LI 	pkeyid = (keyid_t *)&inpkt->u;
23534990d495SXin LI 	tmpkey = ntohl(*pkeyid);
23544990d495SXin LI 
23554990d495SXin LI 	/* validate the new key id, claim data error on failure */
23564990d495SXin LI 	if (tmpkey < 1 || tmpkey > NTP_MAXKEY || !auth_havekey(tmpkey)) {
23574990d495SXin LI 		msyslog(LOG_ERR, "set_keyid_checked[%s]: invalid key id: %ld",
23584990d495SXin LI 			what, (long)tmpkey);
23594990d495SXin LI 		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
23604990d495SXin LI 		return;
23614990d495SXin LI 	}
23624990d495SXin LI 
23634990d495SXin LI 	/* if we arrive here, the key is good -- use it */
23644990d495SXin LI 	*into = tmpkey;
23654990d495SXin LI 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
23664990d495SXin LI }
2367c0b746e5SOllivier Robert 
2368c0b746e5SOllivier Robert /*
2369c0b746e5SOllivier Robert  * set_request_keyid - set the keyid used to authenticate requests
2370c0b746e5SOllivier Robert  */
2371c0b746e5SOllivier Robert static void
2372c0b746e5SOllivier Robert set_request_keyid(
23732b15cb3dSCy Schubert 	sockaddr_u *srcadr,
23742b15cb3dSCy Schubert 	endpt *inter,
2375c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2376c0b746e5SOllivier Robert 	)
2377c0b746e5SOllivier Robert {
23784990d495SXin LI 	set_keyid_checked(&info_auth_keyid, "request",
23794990d495SXin LI 			  srcadr, inter, inpkt);
2380c0b746e5SOllivier Robert }
2381c0b746e5SOllivier Robert 
2382c0b746e5SOllivier Robert 
2383c0b746e5SOllivier Robert 
2384c0b746e5SOllivier Robert /*
2385c0b746e5SOllivier Robert  * set_control_keyid - set the keyid used to authenticate requests
2386c0b746e5SOllivier Robert  */
2387c0b746e5SOllivier Robert static void
2388c0b746e5SOllivier Robert set_control_keyid(
23892b15cb3dSCy Schubert 	sockaddr_u *srcadr,
23902b15cb3dSCy Schubert 	endpt *inter,
2391c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2392c0b746e5SOllivier Robert 	)
2393c0b746e5SOllivier Robert {
23944990d495SXin LI 	set_keyid_checked(&ctl_auth_keyid, "control",
23954990d495SXin LI 			  srcadr, inter, inpkt);
2396c0b746e5SOllivier Robert }
2397c0b746e5SOllivier Robert 
2398c0b746e5SOllivier Robert 
2399c0b746e5SOllivier Robert 
2400c0b746e5SOllivier Robert /*
2401c0b746e5SOllivier Robert  * get_ctl_stats - return some stats concerning the control message module
2402c0b746e5SOllivier Robert  */
2403c0b746e5SOllivier Robert static void
2404c0b746e5SOllivier Robert get_ctl_stats(
24052b15cb3dSCy Schubert 	sockaddr_u *srcadr,
24062b15cb3dSCy Schubert 	endpt *inter,
2407c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2408c0b746e5SOllivier Robert 	)
2409c0b746e5SOllivier Robert {
2410c0b746e5SOllivier Robert 	register struct info_control *ic;
2411c0b746e5SOllivier Robert 
2412c0b746e5SOllivier Robert 	ic = (struct info_control *)prepare_pkt(srcadr, inter, inpkt,
2413c0b746e5SOllivier Robert 						sizeof(struct info_control));
2414c0b746e5SOllivier Robert 
2415c0b746e5SOllivier Robert 	ic->ctltimereset = htonl((u_int32)(current_time - ctltimereset));
2416c0b746e5SOllivier Robert 	ic->numctlreq = htonl((u_int32)numctlreq);
2417c0b746e5SOllivier Robert 	ic->numctlbadpkts = htonl((u_int32)numctlbadpkts);
2418c0b746e5SOllivier Robert 	ic->numctlresponses = htonl((u_int32)numctlresponses);
2419c0b746e5SOllivier Robert 	ic->numctlfrags = htonl((u_int32)numctlfrags);
2420c0b746e5SOllivier Robert 	ic->numctlerrors = htonl((u_int32)numctlerrors);
2421c0b746e5SOllivier Robert 	ic->numctltooshort = htonl((u_int32)numctltooshort);
2422c0b746e5SOllivier Robert 	ic->numctlinputresp = htonl((u_int32)numctlinputresp);
2423c0b746e5SOllivier Robert 	ic->numctlinputfrag = htonl((u_int32)numctlinputfrag);
2424c0b746e5SOllivier Robert 	ic->numctlinputerr = htonl((u_int32)numctlinputerr);
2425c0b746e5SOllivier Robert 	ic->numctlbadoffset = htonl((u_int32)numctlbadoffset);
2426c0b746e5SOllivier Robert 	ic->numctlbadversion = htonl((u_int32)numctlbadversion);
2427c0b746e5SOllivier Robert 	ic->numctldatatooshort = htonl((u_int32)numctldatatooshort);
2428c0b746e5SOllivier Robert 	ic->numctlbadop = htonl((u_int32)numctlbadop);
2429c0b746e5SOllivier Robert 	ic->numasyncmsgs = htonl((u_int32)numasyncmsgs);
2430c0b746e5SOllivier Robert 
2431c0b746e5SOllivier Robert 	(void) more_pkt();
2432c0b746e5SOllivier Robert 	flush_pkt();
2433c0b746e5SOllivier Robert }
2434c0b746e5SOllivier Robert 
2435c0b746e5SOllivier Robert 
2436c0b746e5SOllivier Robert #ifdef KERNEL_PLL
2437c0b746e5SOllivier Robert /*
2438c0b746e5SOllivier Robert  * get_kernel_info - get kernel pll/pps information
2439c0b746e5SOllivier Robert  */
2440c0b746e5SOllivier Robert static void
2441c0b746e5SOllivier Robert get_kernel_info(
24422b15cb3dSCy Schubert 	sockaddr_u *srcadr,
24432b15cb3dSCy Schubert 	endpt *inter,
2444c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2445c0b746e5SOllivier Robert 	)
2446c0b746e5SOllivier Robert {
2447c0b746e5SOllivier Robert 	register struct info_kernel *ik;
2448c0b746e5SOllivier Robert 	struct timex ntx;
2449c0b746e5SOllivier Robert 
2450c0b746e5SOllivier Robert 	if (!pll_control) {
2451c0b746e5SOllivier Robert 		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2452c0b746e5SOllivier Robert 		return;
2453c0b746e5SOllivier Robert 	}
2454c0b746e5SOllivier Robert 
24552b15cb3dSCy Schubert 	ZERO(ntx);
2456c0b746e5SOllivier Robert 	if (ntp_adjtime(&ntx) < 0)
2457c0b746e5SOllivier Robert 		msyslog(LOG_ERR, "get_kernel_info: ntp_adjtime() failed: %m");
2458c0b746e5SOllivier Robert 	ik = (struct info_kernel *)prepare_pkt(srcadr, inter, inpkt,
2459c0b746e5SOllivier Robert 	    sizeof(struct info_kernel));
2460c0b746e5SOllivier Robert 
2461c0b746e5SOllivier Robert 	/*
2462c0b746e5SOllivier Robert 	 * pll variables
2463c0b746e5SOllivier Robert 	 */
2464c0b746e5SOllivier Robert 	ik->offset = htonl((u_int32)ntx.offset);
2465c0b746e5SOllivier Robert 	ik->freq = htonl((u_int32)ntx.freq);
2466c0b746e5SOllivier Robert 	ik->maxerror = htonl((u_int32)ntx.maxerror);
2467c0b746e5SOllivier Robert 	ik->esterror = htonl((u_int32)ntx.esterror);
2468c0b746e5SOllivier Robert 	ik->status = htons(ntx.status);
2469c0b746e5SOllivier Robert 	ik->constant = htonl((u_int32)ntx.constant);
2470c0b746e5SOllivier Robert 	ik->precision = htonl((u_int32)ntx.precision);
2471c0b746e5SOllivier Robert 	ik->tolerance = htonl((u_int32)ntx.tolerance);
2472c0b746e5SOllivier Robert 
2473c0b746e5SOllivier Robert 	/*
2474c0b746e5SOllivier Robert 	 * pps variables
2475c0b746e5SOllivier Robert 	 */
2476c0b746e5SOllivier Robert 	ik->ppsfreq = htonl((u_int32)ntx.ppsfreq);
2477c0b746e5SOllivier Robert 	ik->jitter = htonl((u_int32)ntx.jitter);
2478c0b746e5SOllivier Robert 	ik->shift = htons(ntx.shift);
2479c0b746e5SOllivier Robert 	ik->stabil = htonl((u_int32)ntx.stabil);
2480c0b746e5SOllivier Robert 	ik->jitcnt = htonl((u_int32)ntx.jitcnt);
2481c0b746e5SOllivier Robert 	ik->calcnt = htonl((u_int32)ntx.calcnt);
2482c0b746e5SOllivier Robert 	ik->errcnt = htonl((u_int32)ntx.errcnt);
2483c0b746e5SOllivier Robert 	ik->stbcnt = htonl((u_int32)ntx.stbcnt);
2484c0b746e5SOllivier Robert 
2485c0b746e5SOllivier Robert 	(void) more_pkt();
2486c0b746e5SOllivier Robert 	flush_pkt();
2487c0b746e5SOllivier Robert }
2488c0b746e5SOllivier Robert #endif /* KERNEL_PLL */
2489c0b746e5SOllivier Robert 
2490c0b746e5SOllivier Robert 
2491c0b746e5SOllivier Robert #ifdef REFCLOCK
2492c0b746e5SOllivier Robert /*
2493c0b746e5SOllivier Robert  * get_clock_info - get info about a clock
2494c0b746e5SOllivier Robert  */
2495c0b746e5SOllivier Robert static void
2496c0b746e5SOllivier Robert get_clock_info(
24972b15cb3dSCy Schubert 	sockaddr_u *srcadr,
24982b15cb3dSCy Schubert 	endpt *inter,
2499c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2500c0b746e5SOllivier Robert 	)
2501c0b746e5SOllivier Robert {
2502c0b746e5SOllivier Robert 	register struct info_clock *ic;
2503c0b746e5SOllivier Robert 	register u_int32 *clkaddr;
2504c0b746e5SOllivier Robert 	register int items;
2505c0b746e5SOllivier Robert 	struct refclockstat clock_stat;
25062b15cb3dSCy Schubert 	sockaddr_u addr;
2507c0b746e5SOllivier Robert 	l_fp ltmp;
2508c0b746e5SOllivier Robert 
25092b15cb3dSCy Schubert 	ZERO_SOCK(&addr);
25102b15cb3dSCy Schubert 	AF(&addr) = AF_INET;
25112b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
25122b15cb3dSCy Schubert 	addr.sa.sa_len = SOCKLEN(&addr);
25139c2daa00SOllivier Robert #endif
25142b15cb3dSCy Schubert 	SET_PORT(&addr, NTP_PORT);
2515c0b746e5SOllivier Robert 	items = INFO_NITEMS(inpkt->err_nitems);
25162b15cb3dSCy Schubert 	clkaddr = &inpkt->u.u32[0];
2517c0b746e5SOllivier Robert 
2518c0b746e5SOllivier Robert 	ic = (struct info_clock *)prepare_pkt(srcadr, inter, inpkt,
2519c0b746e5SOllivier Robert 					      sizeof(struct info_clock));
2520c0b746e5SOllivier Robert 
252168ba7e87SXin LI 	while (items-- > 0 && ic) {
25222b15cb3dSCy Schubert 		NSRCADR(&addr) = *clkaddr++;
25232b15cb3dSCy Schubert 		if (!ISREFCLOCKADR(&addr) || NULL ==
252409100258SXin LI 		    findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) {
2525c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2526c0b746e5SOllivier Robert 			return;
2527c0b746e5SOllivier Robert 		}
2528c0b746e5SOllivier Robert 
2529c0b746e5SOllivier Robert 		clock_stat.kv_list = (struct ctl_var *)0;
2530c0b746e5SOllivier Robert 
25312b15cb3dSCy Schubert 		refclock_control(&addr, NULL, &clock_stat);
2532c0b746e5SOllivier Robert 
25332b15cb3dSCy Schubert 		ic->clockadr = NSRCADR(&addr);
2534c0b746e5SOllivier Robert 		ic->type = clock_stat.type;
2535c0b746e5SOllivier Robert 		ic->flags = clock_stat.flags;
2536c0b746e5SOllivier Robert 		ic->lastevent = clock_stat.lastevent;
2537c0b746e5SOllivier Robert 		ic->currentstatus = clock_stat.currentstatus;
2538c0b746e5SOllivier Robert 		ic->polls = htonl((u_int32)clock_stat.polls);
2539c0b746e5SOllivier Robert 		ic->noresponse = htonl((u_int32)clock_stat.noresponse);
2540c0b746e5SOllivier Robert 		ic->badformat = htonl((u_int32)clock_stat.badformat);
2541c0b746e5SOllivier Robert 		ic->baddata = htonl((u_int32)clock_stat.baddata);
2542c0b746e5SOllivier Robert 		ic->timestarted = htonl((u_int32)clock_stat.timereset);
2543c0b746e5SOllivier Robert 		DTOLFP(clock_stat.fudgetime1, &ltmp);
2544c0b746e5SOllivier Robert 		HTONL_FP(&ltmp, &ic->fudgetime1);
25459c2daa00SOllivier Robert 		DTOLFP(clock_stat.fudgetime2, &ltmp);
2546c0b746e5SOllivier Robert 		HTONL_FP(&ltmp, &ic->fudgetime2);
2547c0b746e5SOllivier Robert 		ic->fudgeval1 = htonl((u_int32)clock_stat.fudgeval1);
2548052d159aSCy Schubert 		/* [Bug3527] Backward Incompatible: ic->fudgeval2 is
2549052d159aSCy Schubert 		 * a string, instantiated via memcpy() so there is no
2550052d159aSCy Schubert 		 * endian issue to correct.
2551052d159aSCy Schubert 		 */
2552052d159aSCy Schubert #ifdef DISABLE_BUG3527_FIX
25532b15cb3dSCy Schubert 		ic->fudgeval2 = htonl(clock_stat.fudgeval2);
2554052d159aSCy Schubert #else
2555052d159aSCy Schubert 		ic->fudgeval2 = clock_stat.fudgeval2;
2556052d159aSCy Schubert #endif
2557c0b746e5SOllivier Robert 
2558c0b746e5SOllivier Robert 		free_varlist(clock_stat.kv_list);
2559c0b746e5SOllivier Robert 
2560c0b746e5SOllivier Robert 		ic = (struct info_clock *)more_pkt();
2561c0b746e5SOllivier Robert 	}
2562c0b746e5SOllivier Robert 	flush_pkt();
2563c0b746e5SOllivier Robert }
2564c0b746e5SOllivier Robert 
2565c0b746e5SOllivier Robert 
2566c0b746e5SOllivier Robert 
2567c0b746e5SOllivier Robert /*
2568c0b746e5SOllivier Robert  * set_clock_fudge - get a clock's fudge factors
2569c0b746e5SOllivier Robert  */
2570c0b746e5SOllivier Robert static void
2571c0b746e5SOllivier Robert set_clock_fudge(
25722b15cb3dSCy Schubert 	sockaddr_u *srcadr,
25732b15cb3dSCy Schubert 	endpt *inter,
2574c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2575c0b746e5SOllivier Robert 	)
2576c0b746e5SOllivier Robert {
2577c0b746e5SOllivier Robert 	register struct conf_fudge *cf;
2578c0b746e5SOllivier Robert 	register int items;
2579c0b746e5SOllivier Robert 	struct refclockstat clock_stat;
25802b15cb3dSCy Schubert 	sockaddr_u addr;
2581c0b746e5SOllivier Robert 	l_fp ltmp;
2582c0b746e5SOllivier Robert 
25832b15cb3dSCy Schubert 	ZERO(addr);
25842b15cb3dSCy Schubert 	ZERO(clock_stat);
2585c0b746e5SOllivier Robert 	items = INFO_NITEMS(inpkt->err_nitems);
25862b15cb3dSCy Schubert 	cf = (struct conf_fudge *)&inpkt->u;
2587c0b746e5SOllivier Robert 
2588c0b746e5SOllivier Robert 	while (items-- > 0) {
25892b15cb3dSCy Schubert 		AF(&addr) = AF_INET;
25902b15cb3dSCy Schubert 		NSRCADR(&addr) = cf->clockadr;
25912b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
25922b15cb3dSCy Schubert 		addr.sa.sa_len = SOCKLEN(&addr);
25939c2daa00SOllivier Robert #endif
25942b15cb3dSCy Schubert 		SET_PORT(&addr, NTP_PORT);
25952b15cb3dSCy Schubert 		if (!ISREFCLOCKADR(&addr) || NULL ==
259609100258SXin LI 		    findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) {
2597c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2598c0b746e5SOllivier Robert 			return;
2599c0b746e5SOllivier Robert 		}
2600c0b746e5SOllivier Robert 
2601c0b746e5SOllivier Robert 		switch(ntohl(cf->which)) {
2602c0b746e5SOllivier Robert 		    case FUDGE_TIME1:
2603c0b746e5SOllivier Robert 			NTOHL_FP(&cf->fudgetime, &ltmp);
2604c0b746e5SOllivier Robert 			LFPTOD(&ltmp, clock_stat.fudgetime1);
2605c0b746e5SOllivier Robert 			clock_stat.haveflags = CLK_HAVETIME1;
2606c0b746e5SOllivier Robert 			break;
2607c0b746e5SOllivier Robert 		    case FUDGE_TIME2:
2608c0b746e5SOllivier Robert 			NTOHL_FP(&cf->fudgetime, &ltmp);
2609c0b746e5SOllivier Robert 			LFPTOD(&ltmp, clock_stat.fudgetime2);
2610c0b746e5SOllivier Robert 			clock_stat.haveflags = CLK_HAVETIME2;
2611c0b746e5SOllivier Robert 			break;
2612c0b746e5SOllivier Robert 		    case FUDGE_VAL1:
2613c0b746e5SOllivier Robert 			clock_stat.fudgeval1 = ntohl(cf->fudgeval_flags);
2614c0b746e5SOllivier Robert 			clock_stat.haveflags = CLK_HAVEVAL1;
2615c0b746e5SOllivier Robert 			break;
2616c0b746e5SOllivier Robert 		    case FUDGE_VAL2:
2617c0b746e5SOllivier Robert 			clock_stat.fudgeval2 = ntohl(cf->fudgeval_flags);
2618c0b746e5SOllivier Robert 			clock_stat.haveflags = CLK_HAVEVAL2;
2619c0b746e5SOllivier Robert 			break;
2620c0b746e5SOllivier Robert 		    case FUDGE_FLAGS:
26219c2daa00SOllivier Robert 			clock_stat.flags = (u_char) (ntohl(cf->fudgeval_flags) & 0xf);
2622c0b746e5SOllivier Robert 			clock_stat.haveflags =
2623c0b746e5SOllivier Robert 				(CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4);
2624c0b746e5SOllivier Robert 			break;
2625c0b746e5SOllivier Robert 		    default:
2626224ba2bdSOllivier Robert 			msyslog(LOG_ERR, "set_clock_fudge: default!");
2627c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
2628c0b746e5SOllivier Robert 			return;
2629c0b746e5SOllivier Robert 		}
2630c0b746e5SOllivier Robert 
2631c0b746e5SOllivier Robert 		refclock_control(&addr, &clock_stat, (struct refclockstat *)0);
2632c0b746e5SOllivier Robert 	}
2633c0b746e5SOllivier Robert 
2634c0b746e5SOllivier Robert 	req_ack(srcadr, inter, inpkt, INFO_OKAY);
2635c0b746e5SOllivier Robert }
2636c0b746e5SOllivier Robert #endif
2637c0b746e5SOllivier Robert 
2638c0b746e5SOllivier Robert #ifdef REFCLOCK
2639c0b746e5SOllivier Robert /*
2640c0b746e5SOllivier Robert  * get_clkbug_info - get debugging info about a clock
2641c0b746e5SOllivier Robert  */
2642c0b746e5SOllivier Robert static void
2643c0b746e5SOllivier Robert get_clkbug_info(
26442b15cb3dSCy Schubert 	sockaddr_u *srcadr,
26452b15cb3dSCy Schubert 	endpt *inter,
2646c0b746e5SOllivier Robert 	struct req_pkt *inpkt
2647c0b746e5SOllivier Robert 	)
2648c0b746e5SOllivier Robert {
2649c0b746e5SOllivier Robert 	register int i;
2650c0b746e5SOllivier Robert 	register struct info_clkbug *ic;
2651c0b746e5SOllivier Robert 	register u_int32 *clkaddr;
2652c0b746e5SOllivier Robert 	register int items;
2653c0b746e5SOllivier Robert 	struct refclockbug bug;
26542b15cb3dSCy Schubert 	sockaddr_u addr;
2655c0b746e5SOllivier Robert 
26562b15cb3dSCy Schubert 	ZERO_SOCK(&addr);
26572b15cb3dSCy Schubert 	AF(&addr) = AF_INET;
26582b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
26592b15cb3dSCy Schubert 	addr.sa.sa_len = SOCKLEN(&addr);
26609c2daa00SOllivier Robert #endif
26612b15cb3dSCy Schubert 	SET_PORT(&addr, NTP_PORT);
2662c0b746e5SOllivier Robert 	items = INFO_NITEMS(inpkt->err_nitems);
26632b15cb3dSCy Schubert 	clkaddr = (u_int32 *)&inpkt->u;
2664c0b746e5SOllivier Robert 
2665c0b746e5SOllivier Robert 	ic = (struct info_clkbug *)prepare_pkt(srcadr, inter, inpkt,
2666c0b746e5SOllivier Robert 					       sizeof(struct info_clkbug));
2667c0b746e5SOllivier Robert 
266868ba7e87SXin LI 	while (items-- > 0 && ic) {
26692b15cb3dSCy Schubert 		NSRCADR(&addr) = *clkaddr++;
26702b15cb3dSCy Schubert 		if (!ISREFCLOCKADR(&addr) || NULL ==
267109100258SXin LI 		    findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) {
2672c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2673c0b746e5SOllivier Robert 			return;
2674c0b746e5SOllivier Robert 		}
2675c0b746e5SOllivier Robert 
26762b15cb3dSCy Schubert 		ZERO(bug);
2677c0b746e5SOllivier Robert 		refclock_buginfo(&addr, &bug);
2678c0b746e5SOllivier Robert 		if (bug.nvalues == 0 && bug.ntimes == 0) {
2679c0b746e5SOllivier Robert 			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2680c0b746e5SOllivier Robert 			return;
2681c0b746e5SOllivier Robert 		}
2682c0b746e5SOllivier Robert 
26832b15cb3dSCy Schubert 		ic->clockadr = NSRCADR(&addr);
2684c0b746e5SOllivier Robert 		i = bug.nvalues;
2685c0b746e5SOllivier Robert 		if (i > NUMCBUGVALUES)
2686c0b746e5SOllivier Robert 		    i = NUMCBUGVALUES;
2687c0b746e5SOllivier Robert 		ic->nvalues = (u_char)i;
2688c0b746e5SOllivier Robert 		ic->svalues = htons((u_short) (bug.svalues & ((1<<i)-1)));
2689c0b746e5SOllivier Robert 		while (--i >= 0)
2690c0b746e5SOllivier Robert 		    ic->values[i] = htonl(bug.values[i]);
2691c0b746e5SOllivier Robert 
2692c0b746e5SOllivier Robert 		i = bug.ntimes;
2693c0b746e5SOllivier Robert 		if (i > NUMCBUGTIMES)
2694c0b746e5SOllivier Robert 		    i = NUMCBUGTIMES;
2695c0b746e5SOllivier Robert 		ic->ntimes = (u_char)i;
2696c0b746e5SOllivier Robert 		ic->stimes = htonl(bug.stimes);
2697c0b746e5SOllivier Robert 		while (--i >= 0) {
2698c0b746e5SOllivier Robert 			HTONL_FP(&bug.times[i], &ic->times[i]);
2699c0b746e5SOllivier Robert 		}
2700c0b746e5SOllivier Robert 
2701c0b746e5SOllivier Robert 		ic = (struct info_clkbug *)more_pkt();
2702c0b746e5SOllivier Robert 	}
2703c0b746e5SOllivier Robert 	flush_pkt();
2704c0b746e5SOllivier Robert }
2705c0b746e5SOllivier Robert #endif
2706ea906c41SOllivier Robert 
2707ea906c41SOllivier Robert /*
2708ea906c41SOllivier Robert  * receiver of interface structures
2709ea906c41SOllivier Robert  */
2710ea906c41SOllivier Robert static void
2711ea906c41SOllivier Robert fill_info_if_stats(void *data, interface_info_t *interface_info)
2712ea906c41SOllivier Robert {
2713ea906c41SOllivier Robert 	struct info_if_stats **ifsp = (struct info_if_stats **)data;
2714ea906c41SOllivier Robert 	struct info_if_stats *ifs = *ifsp;
27152b15cb3dSCy Schubert 	endpt *ep = interface_info->ep;
2716ea906c41SOllivier Robert 
271768ba7e87SXin LI 	if (NULL == ifs)
271868ba7e87SXin LI 		return;
271968ba7e87SXin LI 
27202b15cb3dSCy Schubert 	ZERO(*ifs);
2721ea906c41SOllivier Robert 
27222b15cb3dSCy Schubert 	if (IS_IPV6(&ep->sin)) {
272368ba7e87SXin LI 		if (!client_v6_capable)
2724ea906c41SOllivier Robert 			return;
2725ea906c41SOllivier Robert 		ifs->v6_flag = 1;
27262b15cb3dSCy Schubert 		ifs->unaddr.addr6 = SOCK_ADDR6(&ep->sin);
27272b15cb3dSCy Schubert 		ifs->unbcast.addr6 = SOCK_ADDR6(&ep->bcast);
27282b15cb3dSCy Schubert 		ifs->unmask.addr6 = SOCK_ADDR6(&ep->mask);
2729ea906c41SOllivier Robert 	} else {
2730ea906c41SOllivier Robert 		ifs->v6_flag = 0;
27312b15cb3dSCy Schubert 		ifs->unaddr.addr = SOCK_ADDR4(&ep->sin);
27322b15cb3dSCy Schubert 		ifs->unbcast.addr = SOCK_ADDR4(&ep->bcast);
27332b15cb3dSCy Schubert 		ifs->unmask.addr = SOCK_ADDR4(&ep->mask);
2734ea906c41SOllivier Robert 	}
2735ea906c41SOllivier Robert 	ifs->v6_flag = htonl(ifs->v6_flag);
27362b15cb3dSCy Schubert 	strlcpy(ifs->name, ep->name, sizeof(ifs->name));
27372b15cb3dSCy Schubert 	ifs->family = htons(ep->family);
27382b15cb3dSCy Schubert 	ifs->flags = htonl(ep->flags);
27392b15cb3dSCy Schubert 	ifs->last_ttl = htonl(ep->last_ttl);
27402b15cb3dSCy Schubert 	ifs->num_mcast = htonl(ep->num_mcast);
27412b15cb3dSCy Schubert 	ifs->received = htonl(ep->received);
27422b15cb3dSCy Schubert 	ifs->sent = htonl(ep->sent);
27432b15cb3dSCy Schubert 	ifs->notsent = htonl(ep->notsent);
27442b15cb3dSCy Schubert 	ifs->ifindex = htonl(ep->ifindex);
27452b15cb3dSCy Schubert 	/* scope no longer in endpt, in in6_addr typically */
27462b15cb3dSCy Schubert 	ifs->scopeid = ifs->ifindex;
27472b15cb3dSCy Schubert 	ifs->ifnum = htonl(ep->ifnum);
27482b15cb3dSCy Schubert 	ifs->uptime = htonl(current_time - ep->starttime);
27492b15cb3dSCy Schubert 	ifs->ignore_packets = ep->ignore_packets;
27502b15cb3dSCy Schubert 	ifs->peercnt = htonl(ep->peercnt);
2751ea906c41SOllivier Robert 	ifs->action = interface_info->action;
2752ea906c41SOllivier Robert 
2753ea906c41SOllivier Robert 	*ifsp = (struct info_if_stats *)more_pkt();
2754ea906c41SOllivier Robert }
2755ea906c41SOllivier Robert 
2756ea906c41SOllivier Robert /*
2757ea906c41SOllivier Robert  * get_if_stats - get interface statistics
2758ea906c41SOllivier Robert  */
2759ea906c41SOllivier Robert static void
2760ea906c41SOllivier Robert get_if_stats(
27612b15cb3dSCy Schubert 	sockaddr_u *srcadr,
27622b15cb3dSCy Schubert 	endpt *inter,
2763ea906c41SOllivier Robert 	struct req_pkt *inpkt
2764ea906c41SOllivier Robert 	)
2765ea906c41SOllivier Robert {
2766ea906c41SOllivier Robert 	struct info_if_stats *ifs;
2767ea906c41SOllivier Robert 
2768ea906c41SOllivier Robert 	DPRINTF(3, ("wants interface statistics\n"));
2769ea906c41SOllivier Robert 
2770ea906c41SOllivier Robert 	ifs = (struct info_if_stats *)prepare_pkt(srcadr, inter, inpkt,
2771ea906c41SOllivier Robert 	    v6sizeof(struct info_if_stats));
2772ea906c41SOllivier Robert 
2773ea906c41SOllivier Robert 	interface_enumerate(fill_info_if_stats, &ifs);
2774ea906c41SOllivier Robert 
2775ea906c41SOllivier Robert 	flush_pkt();
2776ea906c41SOllivier Robert }
2777ea906c41SOllivier Robert 
2778ea906c41SOllivier Robert static void
2779ea906c41SOllivier Robert do_if_reload(
27802b15cb3dSCy Schubert 	sockaddr_u *srcadr,
27812b15cb3dSCy Schubert 	endpt *inter,
2782ea906c41SOllivier Robert 	struct req_pkt *inpkt
2783ea906c41SOllivier Robert 	)
2784ea906c41SOllivier Robert {
2785ea906c41SOllivier Robert 	struct info_if_stats *ifs;
2786ea906c41SOllivier Robert 
2787ea906c41SOllivier Robert 	DPRINTF(3, ("wants interface reload\n"));
2788ea906c41SOllivier Robert 
2789ea906c41SOllivier Robert 	ifs = (struct info_if_stats *)prepare_pkt(srcadr, inter, inpkt,
2790ea906c41SOllivier Robert 	    v6sizeof(struct info_if_stats));
2791ea906c41SOllivier Robert 
2792ea906c41SOllivier Robert 	interface_update(fill_info_if_stats, &ifs);
2793ea906c41SOllivier Robert 
2794ea906c41SOllivier Robert 	flush_pkt();
2795ea906c41SOllivier Robert }
2796ea906c41SOllivier Robert 
2797