154359Sroberto/*
254359Sroberto * ntp_request.c - respond to information requests
354359Sroberto */
4132451Sroberto
554359Sroberto#ifdef HAVE_CONFIG_H
682498Sroberto# include <config.h>
754359Sroberto#endif
854359Sroberto
954359Sroberto#include "ntpd.h"
1054359Sroberto#include "ntp_io.h"
1154359Sroberto#include "ntp_request.h"
1254359Sroberto#include "ntp_control.h"
1354359Sroberto#include "ntp_refclock.h"
1454359Sroberto#include "ntp_if.h"
1554359Sroberto#include "ntp_stdlib.h"
16285612Sdelphij#include "ntp_assert.h"
1782498Sroberto
1882498Sroberto#include <stdio.h>
19132451Sroberto#include <stddef.h>
2082498Sroberto#include <signal.h>
21285612Sdelphij#ifdef HAVE_NETINET_IN_H
2282498Sroberto#include <netinet/in.h>
23285612Sdelphij#endif
2482498Sroberto#include <arpa/inet.h>
2582498Sroberto
2654359Sroberto#include "recvbuff.h"
2754359Sroberto
2854359Sroberto#ifdef KERNEL_PLL
2954359Sroberto#include "ntp_syscall.h"
3054359Sroberto#endif /* KERNEL_PLL */
3154359Sroberto
3254359Sroberto/*
3354359Sroberto * Structure to hold request procedure information
3454359Sroberto */
3554359Sroberto#define	NOAUTH	0
3654359Sroberto#define	AUTH	1
3754359Sroberto
3854359Sroberto#define	NO_REQUEST	(-1)
39132451Sroberto/*
40132451Sroberto * Because we now have v6 addresses in the messages, we need to compensate
41132451Sroberto * for the larger size.  Therefore, we introduce the alternate size to
42132451Sroberto * keep us friendly with older implementations.  A little ugly.
43132451Sroberto */
44132451Srobertostatic int client_v6_capable = 0;   /* the client can handle longer messages */
4554359Sroberto
46132451Sroberto#define v6sizeof(type)	(client_v6_capable ? sizeof(type) : v4sizeof(type))
47132451Sroberto
4854359Srobertostruct req_proc {
4954359Sroberto	short request_code;	/* defined request code */
5054359Sroberto	short needs_auth;	/* true when authentication needed */
51132451Sroberto	short sizeofitem;	/* size of request data item (older size)*/
52132451Sroberto	short v6_sizeofitem;	/* size of request data item (new size)*/
53285612Sdelphij	void (*handler) (sockaddr_u *, endpt *,
54285612Sdelphij			   struct req_pkt *);	/* routine to handle request */
5554359Sroberto};
5654359Sroberto
5754359Sroberto/*
5854359Sroberto * Universal request codes
5954359Sroberto */
60285612Sdelphijstatic const struct req_proc univ_codes[] = {
61285612Sdelphij	{ NO_REQUEST,		NOAUTH,	 0,	0, NULL }
6254359Sroberto};
6354359Sroberto
64285612Sdelphijstatic	void	req_ack	(sockaddr_u *, endpt *, struct req_pkt *, int);
65285612Sdelphijstatic	void *	prepare_pkt	(sockaddr_u *, endpt *,
66285612Sdelphij				 struct req_pkt *, size_t);
67285612Sdelphijstatic	void *	more_pkt	(void);
68285612Sdelphijstatic	void	flush_pkt	(void);
69285612Sdelphijstatic	void	list_peers	(sockaddr_u *, endpt *, struct req_pkt *);
70285612Sdelphijstatic	void	list_peers_sum	(sockaddr_u *, endpt *, struct req_pkt *);
71285612Sdelphijstatic	void	peer_info	(sockaddr_u *, endpt *, struct req_pkt *);
72285612Sdelphijstatic	void	peer_stats	(sockaddr_u *, endpt *, struct req_pkt *);
73285612Sdelphijstatic	void	sys_info	(sockaddr_u *, endpt *, struct req_pkt *);
74285612Sdelphijstatic	void	sys_stats	(sockaddr_u *, endpt *, struct req_pkt *);
75285612Sdelphijstatic	void	mem_stats	(sockaddr_u *, endpt *, struct req_pkt *);
76285612Sdelphijstatic	void	io_stats	(sockaddr_u *, endpt *, struct req_pkt *);
77285612Sdelphijstatic	void	timer_stats	(sockaddr_u *, endpt *, struct req_pkt *);
78285612Sdelphijstatic	void	loop_info	(sockaddr_u *, endpt *, struct req_pkt *);
79285612Sdelphijstatic	void	do_conf		(sockaddr_u *, endpt *, struct req_pkt *);
80285612Sdelphijstatic	void	do_unconf	(sockaddr_u *, endpt *, struct req_pkt *);
81285612Sdelphijstatic	void	set_sys_flag	(sockaddr_u *, endpt *, struct req_pkt *);
82285612Sdelphijstatic	void	clr_sys_flag	(sockaddr_u *, endpt *, struct req_pkt *);
83285612Sdelphijstatic	void	setclr_flags	(sockaddr_u *, endpt *, struct req_pkt *, u_long);
84294569Sdelphijstatic	void	list_restrict4	(const restrict_u *, struct info_restrict **);
85294569Sdelphijstatic	void	list_restrict6	(const restrict_u *, struct info_restrict **);
86285612Sdelphijstatic	void	list_restrict	(sockaddr_u *, endpt *, struct req_pkt *);
87285612Sdelphijstatic	void	do_resaddflags	(sockaddr_u *, endpt *, struct req_pkt *);
88285612Sdelphijstatic	void	do_ressubflags	(sockaddr_u *, endpt *, struct req_pkt *);
89285612Sdelphijstatic	void	do_unrestrict	(sockaddr_u *, endpt *, struct req_pkt *);
90330141Sdelphijstatic	void	do_restrict	(sockaddr_u *, endpt *, struct req_pkt *, restrict_op);
91285612Sdelphijstatic	void	mon_getlist	(sockaddr_u *, endpt *, struct req_pkt *);
92285612Sdelphijstatic	void	reset_stats	(sockaddr_u *, endpt *, struct req_pkt *);
93285612Sdelphijstatic	void	reset_peer	(sockaddr_u *, endpt *, struct req_pkt *);
94285612Sdelphijstatic	void	do_key_reread	(sockaddr_u *, endpt *, struct req_pkt *);
95285612Sdelphijstatic	void	trust_key	(sockaddr_u *, endpt *, struct req_pkt *);
96285612Sdelphijstatic	void	untrust_key	(sockaddr_u *, endpt *, struct req_pkt *);
97285612Sdelphijstatic	void	do_trustkey	(sockaddr_u *, endpt *, struct req_pkt *, u_long);
98285612Sdelphijstatic	void	get_auth_info	(sockaddr_u *, endpt *, struct req_pkt *);
99285612Sdelphijstatic	void	req_get_traps	(sockaddr_u *, endpt *, struct req_pkt *);
100285612Sdelphijstatic	void	req_set_trap	(sockaddr_u *, endpt *, struct req_pkt *);
101285612Sdelphijstatic	void	req_clr_trap	(sockaddr_u *, endpt *, struct req_pkt *);
102285612Sdelphijstatic	void	do_setclr_trap	(sockaddr_u *, endpt *, struct req_pkt *, int);
103285612Sdelphijstatic	void	set_request_keyid (sockaddr_u *, endpt *, struct req_pkt *);
104285612Sdelphijstatic	void	set_control_keyid (sockaddr_u *, endpt *, struct req_pkt *);
105285612Sdelphijstatic	void	get_ctl_stats   (sockaddr_u *, endpt *, struct req_pkt *);
106285612Sdelphijstatic	void	get_if_stats    (sockaddr_u *, endpt *, struct req_pkt *);
107285612Sdelphijstatic	void	do_if_reload    (sockaddr_u *, endpt *, struct req_pkt *);
10854359Sroberto#ifdef KERNEL_PLL
109285612Sdelphijstatic	void	get_kernel_info (sockaddr_u *, endpt *, struct req_pkt *);
11054359Sroberto#endif /* KERNEL_PLL */
11154359Sroberto#ifdef REFCLOCK
112285612Sdelphijstatic	void	get_clock_info (sockaddr_u *, endpt *, struct req_pkt *);
113285612Sdelphijstatic	void	set_clock_fudge (sockaddr_u *, endpt *, struct req_pkt *);
11454359Sroberto#endif	/* REFCLOCK */
11554359Sroberto#ifdef REFCLOCK
116285612Sdelphijstatic	void	get_clkbug_info (sockaddr_u *, endpt *, struct req_pkt *);
11754359Sroberto#endif	/* REFCLOCK */
11854359Sroberto
11954359Sroberto/*
12054359Sroberto * ntpd request codes
12154359Sroberto */
122285612Sdelphijstatic const struct req_proc ntp_codes[] = {
123285612Sdelphij	{ REQ_PEER_LIST,	NOAUTH,	0, 0,	list_peers },
124285612Sdelphij	{ REQ_PEER_LIST_SUM,	NOAUTH,	0, 0,	list_peers_sum },
125132451Sroberto	{ REQ_PEER_INFO,    NOAUTH, v4sizeof(struct info_peer_list),
126132451Sroberto				sizeof(struct info_peer_list), peer_info},
127132451Sroberto	{ REQ_PEER_STATS,   NOAUTH, v4sizeof(struct info_peer_list),
128132451Sroberto				sizeof(struct info_peer_list), peer_stats},
129132451Sroberto	{ REQ_SYS_INFO,		NOAUTH,	0, 0,	sys_info },
130132451Sroberto	{ REQ_SYS_STATS,	NOAUTH,	0, 0,	sys_stats },
131132451Sroberto	{ REQ_IO_STATS,		NOAUTH,	0, 0,	io_stats },
132132451Sroberto	{ REQ_MEM_STATS,	NOAUTH,	0, 0,	mem_stats },
133132451Sroberto	{ REQ_LOOP_INFO,	NOAUTH,	0, 0,	loop_info },
134132451Sroberto	{ REQ_TIMER_STATS,	NOAUTH,	0, 0,	timer_stats },
135132451Sroberto	{ REQ_CONFIG,	    AUTH, v4sizeof(struct conf_peer),
136132451Sroberto				sizeof(struct conf_peer), do_conf },
137132451Sroberto	{ REQ_UNCONFIG,	    AUTH, v4sizeof(struct conf_unpeer),
138132451Sroberto				sizeof(struct conf_unpeer), do_unconf },
139132451Sroberto	{ REQ_SET_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags),
140132451Sroberto				sizeof(struct conf_sys_flags), set_sys_flag },
141132451Sroberto	{ REQ_CLR_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags),
142132451Sroberto				sizeof(struct conf_sys_flags),  clr_sys_flag },
143132451Sroberto	{ REQ_GET_RESTRICT,	NOAUTH,	0, 0,	list_restrict },
144132451Sroberto	{ REQ_RESADDFLAGS, AUTH, v4sizeof(struct conf_restrict),
145132451Sroberto				sizeof(struct conf_restrict), do_resaddflags },
146132451Sroberto	{ REQ_RESSUBFLAGS, AUTH, v4sizeof(struct conf_restrict),
147132451Sroberto				sizeof(struct conf_restrict), do_ressubflags },
148132451Sroberto	{ REQ_UNRESTRICT, AUTH, v4sizeof(struct conf_restrict),
149132451Sroberto				sizeof(struct conf_restrict), do_unrestrict },
150285612Sdelphij	{ REQ_MON_GETLIST,	NOAUTH,	0, 0,	mon_getlist },
151285612Sdelphij	{ REQ_MON_GETLIST_1,	NOAUTH,	0, 0,	mon_getlist },
152132451Sroberto	{ REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), 0, reset_stats },
153132451Sroberto	{ REQ_RESET_PEER,  AUTH, v4sizeof(struct conf_unpeer),
154132451Sroberto				sizeof(struct conf_unpeer), reset_peer },
155132451Sroberto	{ REQ_REREAD_KEYS,	AUTH,	0, 0,	do_key_reread },
156132451Sroberto	{ REQ_TRUSTKEY,   AUTH, sizeof(u_long), sizeof(u_long), trust_key },
157132451Sroberto	{ REQ_UNTRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), untrust_key },
158132451Sroberto	{ REQ_AUTHINFO,		NOAUTH,	0, 0,	get_auth_info },
159132451Sroberto	{ REQ_TRAPS,		NOAUTH, 0, 0,	req_get_traps },
160132451Sroberto	{ REQ_ADD_TRAP,	AUTH, v4sizeof(struct conf_trap),
161132451Sroberto				sizeof(struct conf_trap), req_set_trap },
162132451Sroberto	{ REQ_CLR_TRAP,	AUTH, v4sizeof(struct conf_trap),
163132451Sroberto				sizeof(struct conf_trap), req_clr_trap },
164132451Sroberto	{ REQ_REQUEST_KEY, AUTH, sizeof(u_long), sizeof(u_long),
165132451Sroberto				set_request_keyid },
166132451Sroberto	{ REQ_CONTROL_KEY, AUTH, sizeof(u_long), sizeof(u_long),
167132451Sroberto				set_control_keyid },
168132451Sroberto	{ REQ_GET_CTLSTATS,	NOAUTH,	0, 0,	get_ctl_stats },
16954359Sroberto#ifdef KERNEL_PLL
170132451Sroberto	{ REQ_GET_KERNEL,	NOAUTH,	0, 0,	get_kernel_info },
17154359Sroberto#endif
17254359Sroberto#ifdef REFCLOCK
173132451Sroberto	{ REQ_GET_CLOCKINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32),
174132451Sroberto				get_clock_info },
175132451Sroberto	{ REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge),
176132451Sroberto				sizeof(struct conf_fudge), set_clock_fudge },
177132451Sroberto	{ REQ_GET_CLKBUGINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32),
178132451Sroberto				get_clkbug_info },
17954359Sroberto#endif
180182007Sroberto	{ REQ_IF_STATS,		AUTH, 0, 0,	get_if_stats },
181285612Sdelphij	{ REQ_IF_RELOAD,	AUTH, 0, 0,	do_if_reload },
182182007Sroberto
183132451Sroberto	{ NO_REQUEST,		NOAUTH,	0, 0,	0 }
18454359Sroberto};
18554359Sroberto
18654359Sroberto
18754359Sroberto/*
18854359Sroberto * Authentication keyid used to authenticate requests.  Zero means we
18954359Sroberto * don't allow writing anything.
19054359Sroberto */
19182498Srobertokeyid_t info_auth_keyid;
19254359Sroberto
19354359Sroberto/*
19454359Sroberto * Statistic counters to keep track of requests and responses.
19554359Sroberto */
19654359Srobertou_long numrequests;		/* number of requests we've received */
19754359Srobertou_long numresppkts;		/* number of resp packets sent with data */
19854359Sroberto
199285612Sdelphij/*
200285612Sdelphij * lazy way to count errors, indexed by the error code
201285612Sdelphij */
202285612Sdelphiju_long errorcounter[MAX_INFO_ERR + 1];
20354359Sroberto
20454359Sroberto/*
20554359Sroberto * A hack.  To keep the authentication module clear of ntp-ism's, we
20654359Sroberto * include a time reset variable for its stats here.
20754359Sroberto */
208285612Sdelphiju_long auth_timereset;
20954359Sroberto
21054359Sroberto/*
21154359Sroberto * Response packet used by these routines.  Also some state information
21254359Sroberto * so that we can handle packet formatting within a common set of
21354359Sroberto * subroutines.  Note we try to enter data in place whenever possible,
21454359Sroberto * but the need to set the more bit correctly means we occasionally
21554359Sroberto * use the extra buffer and copy.
21654359Sroberto */
21754359Srobertostatic struct resp_pkt rpkt;
21854359Srobertostatic int reqver;
21954359Srobertostatic int seqno;
22054359Srobertostatic int nitems;
22154359Srobertostatic int itemsize;
22254359Srobertostatic int databytes;
22354359Srobertostatic char exbuf[RESP_DATA_SIZE];
22454359Srobertostatic int usingexbuf;
225285612Sdelphijstatic sockaddr_u *toaddr;
226285612Sdelphijstatic endpt *frominter;
22754359Sroberto
22854359Sroberto/*
22954359Sroberto * init_request - initialize request data
23054359Sroberto */
23154359Srobertovoid
23254359Srobertoinit_request (void)
23354359Sroberto{
234285612Sdelphij	size_t i;
23554359Sroberto
23654359Sroberto	numrequests = 0;
23754359Sroberto	numresppkts = 0;
23854359Sroberto	auth_timereset = 0;
23954359Sroberto	info_auth_keyid = 0;	/* by default, can't do this */
24054359Sroberto
24154359Sroberto	for (i = 0; i < sizeof(errorcounter)/sizeof(errorcounter[0]); i++)
24254359Sroberto	    errorcounter[i] = 0;
24354359Sroberto}
24454359Sroberto
24554359Sroberto
24654359Sroberto/*
24754359Sroberto * req_ack - acknowledge request with no data
24854359Sroberto */
24954359Srobertostatic void
25054359Srobertoreq_ack(
251285612Sdelphij	sockaddr_u *srcadr,
252285612Sdelphij	endpt *inter,
25354359Sroberto	struct req_pkt *inpkt,
25454359Sroberto	int errcode
25554359Sroberto	)
25654359Sroberto{
25754359Sroberto	/*
25854359Sroberto	 * fill in the fields
25954359Sroberto	 */
26054359Sroberto	rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
26154359Sroberto	rpkt.auth_seq = AUTH_SEQ(0, 0);
26254359Sroberto	rpkt.implementation = inpkt->implementation;
26354359Sroberto	rpkt.request = inpkt->request;
264285612Sdelphij	rpkt.err_nitems = ERR_NITEMS(errcode, 0);
26554359Sroberto	rpkt.mbz_itemsize = MBZ_ITEMSIZE(0);
26654359Sroberto
26754359Sroberto	/*
26854359Sroberto	 * send packet and bump counters
26954359Sroberto	 */
27054359Sroberto	sendpkt(srcadr, inter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE);
27154359Sroberto	errorcounter[errcode]++;
27254359Sroberto}
27354359Sroberto
27454359Sroberto
27554359Sroberto/*
27654359Sroberto * prepare_pkt - prepare response packet for transmission, return pointer
27754359Sroberto *		 to storage for data item.
27854359Sroberto */
279285612Sdelphijstatic void *
28054359Srobertoprepare_pkt(
281285612Sdelphij	sockaddr_u *srcadr,
282285612Sdelphij	endpt *inter,
28354359Sroberto	struct req_pkt *pkt,
284285612Sdelphij	size_t structsize
28554359Sroberto	)
28654359Sroberto{
287285612Sdelphij	DPRINTF(4, ("request: preparing pkt\n"));
28854359Sroberto
28954359Sroberto	/*
290132451Sroberto	 * Fill in the implementation, request and itemsize fields
29154359Sroberto	 * since these won't change.
29254359Sroberto	 */
29354359Sroberto	rpkt.implementation = pkt->implementation;
29454359Sroberto	rpkt.request = pkt->request;
29554359Sroberto	rpkt.mbz_itemsize = MBZ_ITEMSIZE(structsize);
29654359Sroberto
29754359Sroberto	/*
29854359Sroberto	 * Compute the static data needed to carry on.
29954359Sroberto	 */
30054359Sroberto	toaddr = srcadr;
30154359Sroberto	frominter = inter;
30254359Sroberto	seqno = 0;
30354359Sroberto	nitems = 0;
30454359Sroberto	itemsize = structsize;
30554359Sroberto	databytes = 0;
30654359Sroberto	usingexbuf = 0;
30754359Sroberto
30854359Sroberto	/*
30954359Sroberto	 * return the beginning of the packet buffer.
31054359Sroberto	 */
311285612Sdelphij	return &rpkt.u;
31254359Sroberto}
31354359Sroberto
31454359Sroberto
31554359Sroberto/*
31654359Sroberto * more_pkt - return a data pointer for a new item.
31754359Sroberto */
318285612Sdelphijstatic void *
31954359Srobertomore_pkt(void)
32054359Sroberto{
32154359Sroberto	/*
32254359Sroberto	 * If we were using the extra buffer, send the packet.
32354359Sroberto	 */
32454359Sroberto	if (usingexbuf) {
325285612Sdelphij		DPRINTF(3, ("request: sending pkt\n"));
32654359Sroberto		rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT, reqver);
32754359Sroberto		rpkt.auth_seq = AUTH_SEQ(0, seqno);
32854359Sroberto		rpkt.err_nitems = htons((u_short)nitems);
32954359Sroberto		sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
330285612Sdelphij			RESP_HEADER_SIZE + databytes);
33154359Sroberto		numresppkts++;
33254359Sroberto
33354359Sroberto		/*
33454359Sroberto		 * Copy data out of exbuf into the packet.
33554359Sroberto		 */
336285612Sdelphij		memcpy(&rpkt.u.data[0], exbuf, (unsigned)itemsize);
33754359Sroberto		seqno++;
33854359Sroberto		databytes = 0;
33954359Sroberto		nitems = 0;
34054359Sroberto		usingexbuf = 0;
34154359Sroberto	}
34254359Sroberto
34354359Sroberto	databytes += itemsize;
34454359Sroberto	nitems++;
34554359Sroberto	if (databytes + itemsize <= RESP_DATA_SIZE) {
346285612Sdelphij		DPRINTF(4, ("request: giving him more data\n"));
34754359Sroberto		/*
34854359Sroberto		 * More room in packet.  Give him the
34954359Sroberto		 * next address.
35054359Sroberto		 */
351285612Sdelphij		return &rpkt.u.data[databytes];
35254359Sroberto	} else {
35354359Sroberto		/*
35454359Sroberto		 * No room in packet.  Give him the extra
35554359Sroberto		 * buffer unless this was the last in the sequence.
35654359Sroberto		 */
357285612Sdelphij		DPRINTF(4, ("request: into extra buffer\n"));
35854359Sroberto		if (seqno == MAXSEQ)
359285612Sdelphij			return NULL;
36054359Sroberto		else {
36154359Sroberto			usingexbuf = 1;
36254359Sroberto			return exbuf;
36354359Sroberto		}
36454359Sroberto	}
36554359Sroberto}
36654359Sroberto
36754359Sroberto
36854359Sroberto/*
36954359Sroberto * flush_pkt - we're done, return remaining information.
37054359Sroberto */
37154359Srobertostatic void
37254359Srobertoflush_pkt(void)
37354359Sroberto{
374285612Sdelphij	DPRINTF(3, ("request: flushing packet, %d items\n", nitems));
37554359Sroberto	/*
37654359Sroberto	 * Must send the last packet.  If nothing in here and nothing
37754359Sroberto	 * has been sent, send an error saying no data to be found.
37854359Sroberto	 */
37954359Sroberto	if (seqno == 0 && nitems == 0)
380285612Sdelphij		req_ack(toaddr, frominter, (struct req_pkt *)&rpkt,
381285612Sdelphij			INFO_ERR_NODATA);
38254359Sroberto	else {
38354359Sroberto		rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
38454359Sroberto		rpkt.auth_seq = AUTH_SEQ(0, seqno);
38554359Sroberto		rpkt.err_nitems = htons((u_short)nitems);
38654359Sroberto		sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
38754359Sroberto			RESP_HEADER_SIZE+databytes);
38854359Sroberto		numresppkts++;
38954359Sroberto	}
39054359Sroberto}
39154359Sroberto
39254359Sroberto
39354359Sroberto
39454359Sroberto/*
395285612Sdelphij * Given a buffer, return the packet mode
396285612Sdelphij */
397285612Sdelphijint
398285612Sdelphijget_packet_mode(struct recvbuf *rbufp)
399285612Sdelphij{
400285612Sdelphij	struct req_pkt *inpkt = (struct req_pkt *)&rbufp->recv_pkt;
401285612Sdelphij	return (INFO_MODE(inpkt->rm_vn_mode));
402285612Sdelphij}
403285612Sdelphij
404285612Sdelphij
405285612Sdelphij/*
40654359Sroberto * process_private - process private mode (7) packets
40754359Sroberto */
40854359Srobertovoid
40954359Srobertoprocess_private(
41054359Sroberto	struct recvbuf *rbufp,
41154359Sroberto	int mod_okay
41254359Sroberto	)
41354359Sroberto{
414200576Sroberto	static u_long quiet_until;
41554359Sroberto	struct req_pkt *inpkt;
416106163Sroberto	struct req_pkt_tail *tailinpkt;
417285612Sdelphij	sockaddr_u *srcadr;
418285612Sdelphij	endpt *inter;
419285612Sdelphij	const struct req_proc *proc;
42082498Sroberto	int ec;
421132451Sroberto	short temp_size;
422285612Sdelphij	l_fp ftmp;
423285612Sdelphij	double dtemp;
424285612Sdelphij	size_t recv_len;
425285612Sdelphij	size_t noslop_len;
426285612Sdelphij	size_t mac_len;
42754359Sroberto
42854359Sroberto	/*
42954359Sroberto	 * Initialize pointers, for convenience
43054359Sroberto	 */
431285612Sdelphij	recv_len = rbufp->recv_length;
43254359Sroberto	inpkt = (struct req_pkt *)&rbufp->recv_pkt;
43354359Sroberto	srcadr = &rbufp->recv_srcadr;
43454359Sroberto	inter = rbufp->dstadr;
43554359Sroberto
436285612Sdelphij	DPRINTF(3, ("process_private: impl %d req %d\n",
437285612Sdelphij		    inpkt->implementation, inpkt->request));
43854359Sroberto
43954359Sroberto	/*
44054359Sroberto	 * Do some sanity checks on the packet.  Return a format
44154359Sroberto	 * error if it fails.
44254359Sroberto	 */
44382498Sroberto	ec = 0;
44482498Sroberto	if (   (++ec, ISRESPONSE(inpkt->rm_vn_mode))
44582498Sroberto	    || (++ec, ISMORE(inpkt->rm_vn_mode))
44682498Sroberto	    || (++ec, INFO_VERSION(inpkt->rm_vn_mode) > NTP_VERSION)
44782498Sroberto	    || (++ec, INFO_VERSION(inpkt->rm_vn_mode) < NTP_OLDVERSION)
44882498Sroberto	    || (++ec, INFO_SEQ(inpkt->auth_seq) != 0)
44982498Sroberto	    || (++ec, INFO_ERR(inpkt->err_nitems) != 0)
45082498Sroberto	    || (++ec, INFO_MBZ(inpkt->mbz_itemsize) != 0)
451285612Sdelphij	    || (++ec, rbufp->recv_length < (int)REQ_LEN_HDR)
45282498Sroberto		) {
453200576Sroberto		NLOG(NLOG_SYSEVENT)
454200576Sroberto			if (current_time >= quiet_until) {
455200576Sroberto				msyslog(LOG_ERR,
456200576Sroberto					"process_private: drop test %d"
457200576Sroberto					" failed, pkt from %s",
458200576Sroberto					ec, stoa(srcadr));
459200576Sroberto				quiet_until = current_time + 60;
460200576Sroberto			}
46154359Sroberto		return;
46254359Sroberto	}
46354359Sroberto
46454359Sroberto	reqver = INFO_VERSION(inpkt->rm_vn_mode);
46554359Sroberto
46654359Sroberto	/*
46754359Sroberto	 * Get the appropriate procedure list to search.
46854359Sroberto	 */
46954359Sroberto	if (inpkt->implementation == IMPL_UNIV)
470285612Sdelphij		proc = univ_codes;
471132451Sroberto	else if ((inpkt->implementation == IMPL_XNTPD) ||
472132451Sroberto		 (inpkt->implementation == IMPL_XNTPD_OLD))
473285612Sdelphij		proc = ntp_codes;
47454359Sroberto	else {
47554359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL);
47654359Sroberto		return;
47754359Sroberto	}
47854359Sroberto
47954359Sroberto	/*
48054359Sroberto	 * Search the list for the request codes.  If it isn't one
48154359Sroberto	 * we know, return an error.
48254359Sroberto	 */
48354359Sroberto	while (proc->request_code != NO_REQUEST) {
48454359Sroberto		if (proc->request_code == (short) inpkt->request)
485285612Sdelphij			break;
48654359Sroberto		proc++;
48754359Sroberto	}
48854359Sroberto	if (proc->request_code == NO_REQUEST) {
48954359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_REQ);
49054359Sroberto		return;
49154359Sroberto	}
49254359Sroberto
493285612Sdelphij	DPRINTF(4, ("found request in tables\n"));
49454359Sroberto
49554359Sroberto	/*
496132451Sroberto	 * If we need data, check to see if we have some.  If we
497132451Sroberto	 * don't, check to see that there is none (picky, picky).
498132451Sroberto	 */
499132451Sroberto
500132451Sroberto	/* This part is a bit tricky, we want to be sure that the size
501132451Sroberto	 * returned is either the old or the new size.  We also can find
502132451Sroberto	 * out if the client can accept both types of messages this way.
503132451Sroberto	 *
504132451Sroberto	 * Handle the exception of REQ_CONFIG. It can have two data sizes.
505132451Sroberto	 */
506132451Sroberto	temp_size = INFO_ITEMSIZE(inpkt->mbz_itemsize);
507132451Sroberto	if ((temp_size != proc->sizeofitem &&
508200576Sroberto	     temp_size != proc->v6_sizeofitem) &&
509132451Sroberto	    !(inpkt->implementation == IMPL_XNTPD &&
510200576Sroberto	      inpkt->request == REQ_CONFIG &&
511200576Sroberto	      temp_size == sizeof(struct old_conf_peer))) {
512285612Sdelphij		DPRINTF(3, ("process_private: wrong item size, received %d, should be %d or %d\n",
513285612Sdelphij			    temp_size, proc->sizeofitem, proc->v6_sizeofitem));
514132451Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
515132451Sroberto		return;
516132451Sroberto	}
517132451Sroberto	if ((proc->sizeofitem != 0) &&
518285612Sdelphij	    ((size_t)(temp_size * INFO_NITEMS(inpkt->err_nitems)) >
519285612Sdelphij	     (recv_len - REQ_LEN_HDR))) {
520285612Sdelphij		DPRINTF(3, ("process_private: not enough data\n"));
521132451Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
522132451Sroberto		return;
523132451Sroberto	}
524132451Sroberto
525132451Sroberto	switch (inpkt->implementation) {
526132451Sroberto	case IMPL_XNTPD:
527132451Sroberto		client_v6_capable = 1;
528132451Sroberto		break;
529132451Sroberto	case IMPL_XNTPD_OLD:
530132451Sroberto		client_v6_capable = 0;
531132451Sroberto		break;
532132451Sroberto	default:
533132451Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
534132451Sroberto		return;
535132451Sroberto	}
536132451Sroberto
537132451Sroberto	/*
53854359Sroberto	 * If we need to authenticate, do so.  Note that an
53954359Sroberto	 * authenticatable packet must include a mac field, must
54054359Sroberto	 * have used key info_auth_keyid and must have included
54154359Sroberto	 * a time stamp in the appropriate field.  The time stamp
54254359Sroberto	 * must be within INFO_TS_MAXSKEW of the receive
54354359Sroberto	 * time stamp.
54454359Sroberto	 */
54554359Sroberto	if (proc->needs_auth && sys_authenticate) {
546285612Sdelphij
547285612Sdelphij		if (recv_len < (REQ_LEN_HDR +
548106163Sroberto		    (INFO_ITEMSIZE(inpkt->mbz_itemsize) *
549285612Sdelphij		    INFO_NITEMS(inpkt->err_nitems)) +
550285612Sdelphij		    REQ_TAIL_MIN)) {
551106163Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
552285612Sdelphij			return;
553106163Sroberto		}
554106163Sroberto
55554359Sroberto		/*
556285612Sdelphij		 * For 16-octet digests, regardless of itemsize and
557285612Sdelphij		 * nitems, authenticated requests are a fixed size
558285612Sdelphij		 * with the timestamp, key ID, and digest located
559285612Sdelphij		 * at the end of the packet.  Because the key ID
560285612Sdelphij		 * determining the digest size precedes the digest,
561285612Sdelphij		 * for larger digests the fixed size request scheme
562285612Sdelphij		 * is abandoned and the timestamp, key ID, and digest
563285612Sdelphij		 * are located relative to the start of the packet,
564285612Sdelphij		 * with the digest size determined by the packet size.
56554359Sroberto		 */
566285612Sdelphij		noslop_len = REQ_LEN_HDR
567285612Sdelphij			     + INFO_ITEMSIZE(inpkt->mbz_itemsize) *
568285612Sdelphij			       INFO_NITEMS(inpkt->err_nitems)
569285612Sdelphij			     + sizeof(inpkt->tstamp);
570285612Sdelphij		/* 32-bit alignment */
571285612Sdelphij		noslop_len = (noslop_len + 3) & ~3;
572285612Sdelphij		if (recv_len > (noslop_len + MAX_MAC_LEN))
573285612Sdelphij			mac_len = 20;
574285612Sdelphij		else
575285612Sdelphij			mac_len = recv_len - noslop_len;
576285612Sdelphij
577285612Sdelphij		tailinpkt = (void *)((char *)inpkt + recv_len -
578285612Sdelphij			    (mac_len + sizeof(inpkt->tstamp)));
579285612Sdelphij
580285612Sdelphij		/*
581285612Sdelphij		 * If this guy is restricted from doing this, don't let
582285612Sdelphij		 * him.  If the wrong key was used, or packet doesn't
583285612Sdelphij		 * have mac, return.
584285612Sdelphij		 */
585330141Sdelphij		/* XXX: Use authistrustedip(), or equivalent. */
586285612Sdelphij		if (!INFO_IS_AUTH(inpkt->auth_seq) || !info_auth_keyid
587106163Sroberto		    || ntohl(tailinpkt->keyid) != info_auth_keyid) {
588285612Sdelphij			DPRINTF(5, ("failed auth %d info_auth_keyid %u pkt keyid %u maclen %lu\n",
589285612Sdelphij				    INFO_IS_AUTH(inpkt->auth_seq),
590285612Sdelphij				    info_auth_keyid,
591285612Sdelphij				    ntohl(tailinpkt->keyid), (u_long)mac_len));
59254359Sroberto#ifdef DEBUG
593132451Sroberto			msyslog(LOG_DEBUG,
594285612Sdelphij				"process_private: failed auth %d info_auth_keyid %u pkt keyid %u maclen %lu\n",
595132451Sroberto				INFO_IS_AUTH(inpkt->auth_seq),
596285612Sdelphij				info_auth_keyid,
597285612Sdelphij				ntohl(tailinpkt->keyid), (u_long)mac_len);
59854359Sroberto#endif
59954359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
60054359Sroberto			return;
60154359Sroberto		}
602285612Sdelphij		if (recv_len > REQ_LEN_NOMAC + MAX_MAC_LEN) {
603285612Sdelphij			DPRINTF(5, ("bad pkt length %zu\n", recv_len));
604285612Sdelphij			msyslog(LOG_ERR,
605285612Sdelphij				"process_private: bad pkt length %zu",
606285612Sdelphij				recv_len);
60754359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
60854359Sroberto			return;
60954359Sroberto		}
61054359Sroberto		if (!mod_okay || !authhavekey(info_auth_keyid)) {
611285612Sdelphij			DPRINTF(5, ("failed auth mod_okay %d\n",
612285612Sdelphij				    mod_okay));
61354359Sroberto#ifdef DEBUG
614132451Sroberto			msyslog(LOG_DEBUG,
615132451Sroberto				"process_private: failed auth mod_okay %d\n",
616132451Sroberto				mod_okay);
61754359Sroberto#endif
618285612Sdelphij			if (!mod_okay) {
619285612Sdelphij				sys_restricted++;
620285612Sdelphij			}
62154359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
62254359Sroberto			return;
62354359Sroberto		}
62454359Sroberto
62554359Sroberto		/*
62654359Sroberto		 * calculate absolute time difference between xmit time stamp
62754359Sroberto		 * and receive time stamp.  If too large, too bad.
62854359Sroberto		 */
629106163Sroberto		NTOHL_FP(&tailinpkt->tstamp, &ftmp);
63054359Sroberto		L_SUB(&ftmp, &rbufp->recv_time);
63154359Sroberto		LFPTOD(&ftmp, dtemp);
632285612Sdelphij		if (fabs(dtemp) > INFO_TS_MAXSKEW) {
63354359Sroberto			/*
63454359Sroberto			 * He's a loser.  Tell him.
63554359Sroberto			 */
636285612Sdelphij			DPRINTF(5, ("xmit/rcv timestamp delta %g > INFO_TS_MAXSKEW %g\n",
637285612Sdelphij				    dtemp, INFO_TS_MAXSKEW));
63854359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
63954359Sroberto			return;
64054359Sroberto		}
64154359Sroberto
64254359Sroberto		/*
64354359Sroberto		 * So far so good.  See if decryption works out okay.
64454359Sroberto		 */
64554359Sroberto		if (!authdecrypt(info_auth_keyid, (u_int32 *)inpkt,
646285612Sdelphij				 recv_len - mac_len, mac_len)) {
647285612Sdelphij			DPRINTF(5, ("authdecrypt failed\n"));
64854359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
64954359Sroberto			return;
65054359Sroberto		}
65154359Sroberto	}
65254359Sroberto
653285612Sdelphij	DPRINTF(3, ("process_private: all okay, into handler\n"));
65454359Sroberto	/*
65554359Sroberto	 * Packet is okay.  Call the handler to send him data.
65654359Sroberto	 */
65754359Sroberto	(proc->handler)(srcadr, inter, inpkt);
65854359Sroberto}
65954359Sroberto
66054359Sroberto
66154359Sroberto/*
662285612Sdelphij * list_peers - send a list of the peers
66354359Sroberto */
66454359Srobertostatic void
665285612Sdelphijlist_peers(
666285612Sdelphij	sockaddr_u *srcadr,
667285612Sdelphij	endpt *inter,
66854359Sroberto	struct req_pkt *inpkt
66954359Sroberto	)
67054359Sroberto{
671294569Sdelphij	struct info_peer_list *	ip;
672294569Sdelphij	const struct peer *	pp;
67354359Sroberto
67454359Sroberto	ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt,
675132451Sroberto	    v6sizeof(struct info_peer_list));
676285612Sdelphij	for (pp = peer_list; pp != NULL && ip != NULL; pp = pp->p_link) {
677285612Sdelphij		if (IS_IPV6(&pp->srcadr)) {
678294569Sdelphij			if (!client_v6_capable)
679294569Sdelphij				continue;
680294569Sdelphij			ip->addr6 = SOCK_ADDR6(&pp->srcadr);
681294569Sdelphij			ip->v6_flag = 1;
682285612Sdelphij		} else {
683285612Sdelphij			ip->addr = NSRCADR(&pp->srcadr);
684285612Sdelphij			if (client_v6_capable)
685285612Sdelphij				ip->v6_flag = 0;
686285612Sdelphij		}
687132451Sroberto
688294569Sdelphij		ip->port = NSRCPORT(&pp->srcadr);
689294569Sdelphij		ip->hmode = pp->hmode;
690294569Sdelphij		ip->flags = 0;
691294569Sdelphij		if (pp->flags & FLAG_CONFIG)
692294569Sdelphij			ip->flags |= INFO_FLAG_CONFIG;
693294569Sdelphij		if (pp == sys_peer)
694294569Sdelphij			ip->flags |= INFO_FLAG_SYSPEER;
695294569Sdelphij		if (pp->status == CTL_PST_SEL_SYNCCAND)
696294569Sdelphij			ip->flags |= INFO_FLAG_SEL_CANDIDATE;
697294569Sdelphij		if (pp->status >= CTL_PST_SEL_SYSPEER)
698294569Sdelphij			ip->flags |= INFO_FLAG_SHORTLIST;
699294569Sdelphij		ip = (struct info_peer_list *)more_pkt();
700285612Sdelphij	}	/* for pp */
701285612Sdelphij
70254359Sroberto	flush_pkt();
70354359Sroberto}
70454359Sroberto
70554359Sroberto
70654359Sroberto/*
707285612Sdelphij * list_peers_sum - return extended peer list
70854359Sroberto */
70954359Srobertostatic void
710285612Sdelphijlist_peers_sum(
711285612Sdelphij	sockaddr_u *srcadr,
712285612Sdelphij	endpt *inter,
71354359Sroberto	struct req_pkt *inpkt
71454359Sroberto	)
71554359Sroberto{
716294569Sdelphij	struct info_peer_summary *	ips;
717294569Sdelphij	const struct peer *		pp;
718294569Sdelphij	l_fp 				ltmp;
71954359Sroberto
720285612Sdelphij	DPRINTF(3, ("wants peer list summary\n"));
721285612Sdelphij
72254359Sroberto	ips = (struct info_peer_summary *)prepare_pkt(srcadr, inter, inpkt,
723132451Sroberto	    v6sizeof(struct info_peer_summary));
724285612Sdelphij	for (pp = peer_list; pp != NULL && ips != NULL; pp = pp->p_link) {
725285612Sdelphij		DPRINTF(4, ("sum: got one\n"));
726285612Sdelphij		/*
727285612Sdelphij		 * Be careful here not to return v6 peers when we
728285612Sdelphij		 * want only v4.
729285612Sdelphij		 */
730285612Sdelphij		if (IS_IPV6(&pp->srcadr)) {
731294569Sdelphij			if (!client_v6_capable)
732294569Sdelphij				continue;
733294569Sdelphij			ips->srcadr6 = SOCK_ADDR6(&pp->srcadr);
734294569Sdelphij			ips->v6_flag = 1;
735294569Sdelphij			if (pp->dstadr)
736294569Sdelphij				ips->dstadr6 = SOCK_ADDR6(&pp->dstadr->sin);
737294569Sdelphij			else
738294569Sdelphij				ZERO(ips->dstadr6);
739285612Sdelphij		} else {
740285612Sdelphij			ips->srcadr = NSRCADR(&pp->srcadr);
741285612Sdelphij			if (client_v6_capable)
742285612Sdelphij				ips->v6_flag = 0;
743182007Sroberto
744285612Sdelphij			if (pp->dstadr) {
745285612Sdelphij				if (!pp->processed)
746285612Sdelphij					ips->dstadr = NSRCADR(&pp->dstadr->sin);
747285612Sdelphij				else {
748285612Sdelphij					if (MDF_BCAST == pp->cast_flags)
749285612Sdelphij						ips->dstadr = NSRCADR(&pp->dstadr->bcast);
750285612Sdelphij					else if (pp->cast_flags) {
751285612Sdelphij						ips->dstadr = NSRCADR(&pp->dstadr->sin);
752285612Sdelphij						if (!ips->dstadr)
753285612Sdelphij							ips->dstadr = NSRCADR(&pp->dstadr->bcast);
754285612Sdelphij					}
755285612Sdelphij				}
756294569Sdelphij			} else {
757285612Sdelphij				ips->dstadr = 0;
758294569Sdelphij			}
75954359Sroberto		}
760285612Sdelphij
761294569Sdelphij		ips->srcport = NSRCPORT(&pp->srcadr);
762294569Sdelphij		ips->stratum = pp->stratum;
763294569Sdelphij		ips->hpoll = pp->hpoll;
764294569Sdelphij		ips->ppoll = pp->ppoll;
765294569Sdelphij		ips->reach = pp->reach;
766294569Sdelphij		ips->flags = 0;
767294569Sdelphij		if (pp == sys_peer)
768294569Sdelphij			ips->flags |= INFO_FLAG_SYSPEER;
769294569Sdelphij		if (pp->flags & FLAG_CONFIG)
770294569Sdelphij			ips->flags |= INFO_FLAG_CONFIG;
771294569Sdelphij		if (pp->flags & FLAG_REFCLOCK)
772294569Sdelphij			ips->flags |= INFO_FLAG_REFCLOCK;
773294569Sdelphij		if (pp->flags & FLAG_PREFER)
774294569Sdelphij			ips->flags |= INFO_FLAG_PREFER;
775294569Sdelphij		if (pp->flags & FLAG_BURST)
776294569Sdelphij			ips->flags |= INFO_FLAG_BURST;
777294569Sdelphij		if (pp->status == CTL_PST_SEL_SYNCCAND)
778294569Sdelphij			ips->flags |= INFO_FLAG_SEL_CANDIDATE;
779294569Sdelphij		if (pp->status >= CTL_PST_SEL_SYSPEER)
780294569Sdelphij			ips->flags |= INFO_FLAG_SHORTLIST;
781294569Sdelphij		ips->hmode = pp->hmode;
782294569Sdelphij		ips->delay = HTONS_FP(DTOFP(pp->delay));
783294569Sdelphij		DTOLFP(pp->offset, &ltmp);
784294569Sdelphij		HTONL_FP(&ltmp, &ips->offset);
785294569Sdelphij		ips->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
786294569Sdelphij
787285612Sdelphij		ips = (struct info_peer_summary *)more_pkt();
788285612Sdelphij	}	/* for pp */
789285612Sdelphij
79054359Sroberto	flush_pkt();
79154359Sroberto}
79254359Sroberto
79354359Sroberto
79454359Sroberto/*
79554359Sroberto * peer_info - send information for one or more peers
79654359Sroberto */
79754359Srobertostatic void
79854359Srobertopeer_info (
799285612Sdelphij	sockaddr_u *srcadr,
800285612Sdelphij	endpt *inter,
80154359Sroberto	struct req_pkt *inpkt
80254359Sroberto	)
80354359Sroberto{
804285612Sdelphij	u_short			items;
805285612Sdelphij	size_t			item_sz;
806285612Sdelphij	char *			datap;
807285612Sdelphij	struct info_peer_list	ipl;
808285612Sdelphij	struct peer *		pp;
809285612Sdelphij	struct info_peer *	ip;
810285612Sdelphij	int			i;
811285612Sdelphij	int			j;
812285612Sdelphij	sockaddr_u		addr;
813285612Sdelphij	l_fp			ltmp;
81454359Sroberto
81554359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
816285612Sdelphij	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
817285612Sdelphij	datap = inpkt->u.data;
818285612Sdelphij	if (item_sz != sizeof(ipl)) {
819285612Sdelphij		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
820285612Sdelphij		return;
821285612Sdelphij	}
822285612Sdelphij	ip = prepare_pkt(srcadr, inter, inpkt,
823285612Sdelphij			 v6sizeof(struct info_peer));
824285612Sdelphij	while (items-- > 0 && ip != NULL) {
825285612Sdelphij		ZERO(ipl);
826285612Sdelphij		memcpy(&ipl, datap, item_sz);
827285612Sdelphij		ZERO_SOCK(&addr);
828285612Sdelphij		NSRCPORT(&addr) = ipl.port;
829285612Sdelphij		if (client_v6_capable && ipl.v6_flag) {
830285612Sdelphij			AF(&addr) = AF_INET6;
831285612Sdelphij			SOCK_ADDR6(&addr) = ipl.addr6;
832132451Sroberto		} else {
833285612Sdelphij			AF(&addr) = AF_INET;
834285612Sdelphij			NSRCADR(&addr) = ipl.addr;
835132451Sroberto		}
836285612Sdelphij#ifdef ISC_PLATFORM_HAVESALEN
837285612Sdelphij		addr.sa.sa_len = SOCKLEN(&addr);
838132451Sroberto#endif
839285612Sdelphij		datap += item_sz;
840285612Sdelphij
841330141Sdelphij		pp = findexistingpeer(&addr, NULL, NULL, -1, 0, NULL);
842285612Sdelphij		if (NULL == pp)
843285612Sdelphij			continue;
844285612Sdelphij		if (IS_IPV6(srcadr)) {
845182007Sroberto			if (pp->dstadr)
846285612Sdelphij				ip->dstadr6 =
847285612Sdelphij				    (MDF_BCAST == pp->cast_flags)
848285612Sdelphij					? SOCK_ADDR6(&pp->dstadr->bcast)
849285612Sdelphij					: SOCK_ADDR6(&pp->dstadr->sin);
850182007Sroberto			else
851285612Sdelphij				ZERO(ip->dstadr6);
852182007Sroberto
853285612Sdelphij			ip->srcadr6 = SOCK_ADDR6(&pp->srcadr);
854132451Sroberto			ip->v6_flag = 1;
855132451Sroberto		} else {
856285612Sdelphij			if (pp->dstadr) {
857285612Sdelphij				if (!pp->processed)
858285612Sdelphij					ip->dstadr = NSRCADR(&pp->dstadr->sin);
859285612Sdelphij				else {
860285612Sdelphij					if (MDF_BCAST == pp->cast_flags)
861285612Sdelphij						ip->dstadr = NSRCADR(&pp->dstadr->bcast);
862285612Sdelphij					else if (pp->cast_flags) {
863285612Sdelphij						ip->dstadr = NSRCADR(&pp->dstadr->sin);
864285612Sdelphij						if (!ip->dstadr)
865285612Sdelphij							ip->dstadr = NSRCADR(&pp->dstadr->bcast);
866285612Sdelphij					}
867285612Sdelphij				}
868285612Sdelphij			} else
869285612Sdelphij				ip->dstadr = 0;
870132451Sroberto
871285612Sdelphij			ip->srcadr = NSRCADR(&pp->srcadr);
872132451Sroberto			if (client_v6_capable)
873132451Sroberto				ip->v6_flag = 0;
874132451Sroberto		}
87554359Sroberto		ip->srcport = NSRCPORT(&pp->srcadr);
87654359Sroberto		ip->flags = 0;
87754359Sroberto		if (pp == sys_peer)
878285612Sdelphij			ip->flags |= INFO_FLAG_SYSPEER;
87954359Sroberto		if (pp->flags & FLAG_CONFIG)
880285612Sdelphij			ip->flags |= INFO_FLAG_CONFIG;
88154359Sroberto		if (pp->flags & FLAG_REFCLOCK)
882285612Sdelphij			ip->flags |= INFO_FLAG_REFCLOCK;
88354359Sroberto		if (pp->flags & FLAG_PREFER)
884285612Sdelphij			ip->flags |= INFO_FLAG_PREFER;
88554359Sroberto		if (pp->flags & FLAG_BURST)
886285612Sdelphij			ip->flags |= INFO_FLAG_BURST;
88754359Sroberto		if (pp->status == CTL_PST_SEL_SYNCCAND)
888285612Sdelphij			ip->flags |= INFO_FLAG_SEL_CANDIDATE;
88954359Sroberto		if (pp->status >= CTL_PST_SEL_SYSPEER)
890285612Sdelphij			ip->flags |= INFO_FLAG_SHORTLIST;
89154359Sroberto		ip->leap = pp->leap;
89254359Sroberto		ip->hmode = pp->hmode;
893338531Sdelphij		ip->pmode = pp->pmode;
89454359Sroberto		ip->keyid = pp->keyid;
89554359Sroberto		ip->stratum = pp->stratum;
89654359Sroberto		ip->ppoll = pp->ppoll;
89754359Sroberto		ip->hpoll = pp->hpoll;
89854359Sroberto		ip->precision = pp->precision;
89954359Sroberto		ip->version = pp->version;
90054359Sroberto		ip->reach = pp->reach;
901285612Sdelphij		ip->unreach = (u_char)pp->unreach;
90254359Sroberto		ip->flash = (u_char)pp->flash;
903285612Sdelphij		ip->flash2 = (u_short)pp->flash;
904285612Sdelphij		ip->estbdelay = HTONS_FP(DTOFP(pp->delay));
905285612Sdelphij		ip->ttl = (u_char)pp->ttl;
90654359Sroberto		ip->associd = htons(pp->associd);
90754359Sroberto		ip->rootdelay = HTONS_FP(DTOUFP(pp->rootdelay));
908285612Sdelphij		ip->rootdispersion = HTONS_FP(DTOUFP(pp->rootdisp));
90954359Sroberto		ip->refid = pp->refid;
91054359Sroberto		HTONL_FP(&pp->reftime, &ip->reftime);
911285612Sdelphij		HTONL_FP(&pp->aorg, &ip->org);
91254359Sroberto		HTONL_FP(&pp->rec, &ip->rec);
91354359Sroberto		HTONL_FP(&pp->xmt, &ip->xmt);
91454359Sroberto		j = pp->filter_nextpt - 1;
91554359Sroberto		for (i = 0; i < NTP_SHIFT; i++, j--) {
91654359Sroberto			if (j < 0)
917285612Sdelphij				j = NTP_SHIFT-1;
91854359Sroberto			ip->filtdelay[i] = HTONS_FP(DTOFP(pp->filter_delay[j]));
91954359Sroberto			DTOLFP(pp->filter_offset[j], &ltmp);
92054359Sroberto			HTONL_FP(&ltmp, &ip->filtoffset[i]);
921285612Sdelphij			ip->order[i] = (u_char)((pp->filter_nextpt +
922285612Sdelphij						 NTP_SHIFT - 1) -
923285612Sdelphij						pp->filter_order[i]);
92454359Sroberto			if (ip->order[i] >= NTP_SHIFT)
925285612Sdelphij				ip->order[i] -= NTP_SHIFT;
92654359Sroberto		}
92754359Sroberto		DTOLFP(pp->offset, &ltmp);
92854359Sroberto		HTONL_FP(&ltmp, &ip->offset);
92954359Sroberto		ip->delay = HTONS_FP(DTOFP(pp->delay));
93054359Sroberto		ip->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
93182498Sroberto		ip->selectdisp = HTONS_FP(DTOUFP(SQRT(pp->jitter)));
932285612Sdelphij		ip = more_pkt();
93354359Sroberto	}
93454359Sroberto	flush_pkt();
93554359Sroberto}
93654359Sroberto
93754359Sroberto
93854359Sroberto/*
93954359Sroberto * peer_stats - send statistics for one or more peers
94054359Sroberto */
94154359Srobertostatic void
94254359Srobertopeer_stats (
943285612Sdelphij	sockaddr_u *srcadr,
944285612Sdelphij	endpt *inter,
94554359Sroberto	struct req_pkt *inpkt
94654359Sroberto	)
94754359Sroberto{
948285612Sdelphij	u_short			items;
949285612Sdelphij	size_t			item_sz;
950285612Sdelphij	char *			datap;
951285612Sdelphij	struct info_peer_list	ipl;
952285612Sdelphij	struct peer *		pp;
953285612Sdelphij	struct info_peer_stats *ip;
954285612Sdelphij	sockaddr_u addr;
95554359Sroberto
956285612Sdelphij	DPRINTF(1, ("peer_stats: called\n"));
95754359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
958285612Sdelphij	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
959285612Sdelphij	datap = inpkt->u.data;
960285612Sdelphij	if (item_sz > sizeof(ipl)) {
961285612Sdelphij		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
962285612Sdelphij		return;
963285612Sdelphij	}
964285612Sdelphij	ip = prepare_pkt(srcadr, inter, inpkt,
965285612Sdelphij			 v6sizeof(struct info_peer_stats));
966285612Sdelphij	while (items-- > 0 && ip != NULL) {
967285612Sdelphij		ZERO(ipl);
968285612Sdelphij		memcpy(&ipl, datap, item_sz);
969285612Sdelphij		ZERO(addr);
970285612Sdelphij		NSRCPORT(&addr) = ipl.port;
971285612Sdelphij		if (client_v6_capable && ipl.v6_flag) {
972285612Sdelphij			AF(&addr) = AF_INET6;
973285612Sdelphij			SOCK_ADDR6(&addr) = ipl.addr6;
974132451Sroberto		} else {
975285612Sdelphij			AF(&addr) = AF_INET;
976285612Sdelphij			NSRCADR(&addr) = ipl.addr;
977132451Sroberto		}
978285612Sdelphij#ifdef ISC_PLATFORM_HAVESALEN
979285612Sdelphij		addr.sa.sa_len = SOCKLEN(&addr);
980132451Sroberto#endif
981285612Sdelphij		DPRINTF(1, ("peer_stats: looking for %s, %d, %d\n",
982285612Sdelphij			    stoa(&addr), ipl.port, NSRCPORT(&addr)));
983132451Sroberto
984285612Sdelphij		datap += item_sz;
985285612Sdelphij
986330141Sdelphij		pp = findexistingpeer(&addr, NULL, NULL, -1, 0, NULL);
987285612Sdelphij		if (NULL == pp)
988285612Sdelphij			continue;
989285612Sdelphij
990285612Sdelphij		DPRINTF(1, ("peer_stats: found %s\n", stoa(&addr)));
991285612Sdelphij
992285612Sdelphij		if (IS_IPV4(&pp->srcadr)) {
993285612Sdelphij			if (pp->dstadr) {
994285612Sdelphij				if (!pp->processed)
995285612Sdelphij					ip->dstadr = NSRCADR(&pp->dstadr->sin);
996285612Sdelphij				else {
997285612Sdelphij					if (MDF_BCAST == pp->cast_flags)
998285612Sdelphij						ip->dstadr = NSRCADR(&pp->dstadr->bcast);
999285612Sdelphij					else if (pp->cast_flags) {
1000285612Sdelphij						ip->dstadr = NSRCADR(&pp->dstadr->sin);
1001285612Sdelphij						if (!ip->dstadr)
1002285612Sdelphij							ip->dstadr = NSRCADR(&pp->dstadr->bcast);
1003285612Sdelphij					}
1004285612Sdelphij				}
1005285612Sdelphij			} else
1006285612Sdelphij				ip->dstadr = 0;
1007182007Sroberto
1008285612Sdelphij			ip->srcadr = NSRCADR(&pp->srcadr);
1009132451Sroberto			if (client_v6_capable)
1010132451Sroberto				ip->v6_flag = 0;
1011132451Sroberto		} else {
1012182007Sroberto			if (pp->dstadr)
1013285612Sdelphij				ip->dstadr6 =
1014285612Sdelphij				    (MDF_BCAST == pp->cast_flags)
1015285612Sdelphij					? SOCK_ADDR6(&pp->dstadr->bcast)
1016285612Sdelphij					: SOCK_ADDR6(&pp->dstadr->sin);
1017182007Sroberto			else
1018285612Sdelphij				ZERO(ip->dstadr6);
1019285612Sdelphij
1020285612Sdelphij			ip->srcadr6 = SOCK_ADDR6(&pp->srcadr);
1021132451Sroberto			ip->v6_flag = 1;
1022132451Sroberto		}
102354359Sroberto		ip->srcport = NSRCPORT(&pp->srcadr);
102454359Sroberto		ip->flags = 0;
102554359Sroberto		if (pp == sys_peer)
102654359Sroberto		    ip->flags |= INFO_FLAG_SYSPEER;
102754359Sroberto		if (pp->flags & FLAG_CONFIG)
102854359Sroberto		    ip->flags |= INFO_FLAG_CONFIG;
102954359Sroberto		if (pp->flags & FLAG_REFCLOCK)
103054359Sroberto		    ip->flags |= INFO_FLAG_REFCLOCK;
103154359Sroberto		if (pp->flags & FLAG_PREFER)
103254359Sroberto		    ip->flags |= INFO_FLAG_PREFER;
103354359Sroberto		if (pp->flags & FLAG_BURST)
103454359Sroberto		    ip->flags |= INFO_FLAG_BURST;
1035182007Sroberto		if (pp->flags & FLAG_IBURST)
1036182007Sroberto		    ip->flags |= INFO_FLAG_IBURST;
103754359Sroberto		if (pp->status == CTL_PST_SEL_SYNCCAND)
103854359Sroberto		    ip->flags |= INFO_FLAG_SEL_CANDIDATE;
103954359Sroberto		if (pp->status >= CTL_PST_SEL_SYSPEER)
104054359Sroberto		    ip->flags |= INFO_FLAG_SHORTLIST;
1041182007Sroberto		ip->flags = htons(ip->flags);
104254359Sroberto		ip->timereceived = htonl((u_int32)(current_time - pp->timereceived));
104354359Sroberto		ip->timetosend = htonl(pp->nextdate - current_time);
104454359Sroberto		ip->timereachable = htonl((u_int32)(current_time - pp->timereachable));
104554359Sroberto		ip->sent = htonl((u_int32)(pp->sent));
104654359Sroberto		ip->processed = htonl((u_int32)(pp->processed));
104754359Sroberto		ip->badauth = htonl((u_int32)(pp->badauth));
104854359Sroberto		ip->bogusorg = htonl((u_int32)(pp->bogusorg));
104954359Sroberto		ip->oldpkt = htonl((u_int32)(pp->oldpkt));
105054359Sroberto		ip->seldisp = htonl((u_int32)(pp->seldisptoolarge));
105154359Sroberto		ip->selbroken = htonl((u_int32)(pp->selbroken));
105254359Sroberto		ip->candidate = pp->status;
105354359Sroberto		ip = (struct info_peer_stats *)more_pkt();
105454359Sroberto	}
105554359Sroberto	flush_pkt();
105654359Sroberto}
105754359Sroberto
105854359Sroberto
105954359Sroberto/*
106054359Sroberto * sys_info - return system info
106154359Sroberto */
106254359Srobertostatic void
106354359Srobertosys_info(
1064285612Sdelphij	sockaddr_u *srcadr,
1065285612Sdelphij	endpt *inter,
106654359Sroberto	struct req_pkt *inpkt
106754359Sroberto	)
106854359Sroberto{
106954359Sroberto	register struct info_sys *is;
107054359Sroberto
107154359Sroberto	is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt,
1072132451Sroberto	    v6sizeof(struct info_sys));
107354359Sroberto
1074285612Sdelphij	if (sys_peer) {
1075285612Sdelphij		if (IS_IPV4(&sys_peer->srcadr)) {
1076285612Sdelphij			is->peer = NSRCADR(&sys_peer->srcadr);
1077132451Sroberto			if (client_v6_capable)
1078132451Sroberto				is->v6_flag = 0;
1079132451Sroberto		} else if (client_v6_capable) {
1080285612Sdelphij			is->peer6 = SOCK_ADDR6(&sys_peer->srcadr);
1081132451Sroberto			is->v6_flag = 1;
1082132451Sroberto		}
108354359Sroberto		is->peer_mode = sys_peer->hmode;
108454359Sroberto	} else {
108554359Sroberto		is->peer = 0;
1086132451Sroberto		if (client_v6_capable) {
1087132451Sroberto			is->v6_flag = 0;
1088132451Sroberto		}
108954359Sroberto		is->peer_mode = 0;
109054359Sroberto	}
1091132451Sroberto
109254359Sroberto	is->leap = sys_leap;
109354359Sroberto	is->stratum = sys_stratum;
109454359Sroberto	is->precision = sys_precision;
109554359Sroberto	is->rootdelay = htonl(DTOFP(sys_rootdelay));
1096285612Sdelphij	is->rootdispersion = htonl(DTOUFP(sys_rootdisp));
109782498Sroberto	is->frequency = htonl(DTOFP(sys_jitter));
1098285612Sdelphij	is->stability = htonl(DTOUFP(clock_stability * 1e6));
109954359Sroberto	is->refid = sys_refid;
110054359Sroberto	HTONL_FP(&sys_reftime, &is->reftime);
110154359Sroberto
110254359Sroberto	is->poll = sys_poll;
110354359Sroberto
110454359Sroberto	is->flags = 0;
1105106163Sroberto	if (sys_authenticate)
1106106163Sroberto		is->flags |= INFO_FLAG_AUTHENTICATE;
110754359Sroberto	if (sys_bclient)
1108106163Sroberto		is->flags |= INFO_FLAG_BCLIENT;
1109106163Sroberto#ifdef REFCLOCK
1110106163Sroberto	if (cal_enable)
1111106163Sroberto		is->flags |= INFO_FLAG_CAL;
1112106163Sroberto#endif /* REFCLOCK */
111354359Sroberto	if (kern_enable)
1114106163Sroberto		is->flags |= INFO_FLAG_KERNEL;
1115106163Sroberto	if (mon_enabled != MON_OFF)
1116106163Sroberto		is->flags |= INFO_FLAG_MONITOR;
111754359Sroberto	if (ntp_enable)
1118106163Sroberto		is->flags |= INFO_FLAG_NTP;
1119285612Sdelphij	if (hardpps_enable)
1120106163Sroberto		is->flags |= INFO_FLAG_PPS_SYNC;
112154359Sroberto	if (stats_control)
1122106163Sroberto		is->flags |= INFO_FLAG_FILEGEN;
112354359Sroberto	is->bdelay = HTONS_FP(DTOFP(sys_bdelay));
1124285612Sdelphij	HTONL_UF(sys_authdelay.l_uf, &is->authdelay);
112554359Sroberto	(void) more_pkt();
112654359Sroberto	flush_pkt();
112754359Sroberto}
112854359Sroberto
112954359Sroberto
113054359Sroberto/*
113154359Sroberto * sys_stats - return system statistics
113254359Sroberto */
113354359Srobertostatic void
113454359Srobertosys_stats(
1135285612Sdelphij	sockaddr_u *srcadr,
1136285612Sdelphij	endpt *inter,
113754359Sroberto	struct req_pkt *inpkt
113854359Sroberto	)
113954359Sroberto{
114054359Sroberto	register struct info_sys_stats *ss;
114154359Sroberto
114254359Sroberto	ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt,
1143132451Sroberto		sizeof(struct info_sys_stats));
114454359Sroberto	ss->timeup = htonl((u_int32)current_time);
114554359Sroberto	ss->timereset = htonl((u_int32)(current_time - sys_stattime));
1146132451Sroberto	ss->denied = htonl((u_int32)sys_restricted);
1147285612Sdelphij	ss->oldversionpkt = htonl((u_int32)sys_oldversion);
1148285612Sdelphij	ss->newversionpkt = htonl((u_int32)sys_newversion);
1149285612Sdelphij	ss->unknownversion = htonl((u_int32)sys_declined);
115054359Sroberto	ss->badlength = htonl((u_int32)sys_badlength);
115154359Sroberto	ss->processed = htonl((u_int32)sys_processed);
115254359Sroberto	ss->badauth = htonl((u_int32)sys_badauth);
115354359Sroberto	ss->limitrejected = htonl((u_int32)sys_limitrejected);
1154132451Sroberto	ss->received = htonl((u_int32)sys_received);
1155330141Sdelphij	ss->lamport = htonl((u_int32)sys_lamport);
1156330141Sdelphij	ss->tsrounding = htonl((u_int32)sys_tsrounding);
115754359Sroberto	(void) more_pkt();
115854359Sroberto	flush_pkt();
115954359Sroberto}
116054359Sroberto
116154359Sroberto
116254359Sroberto/*
116354359Sroberto * mem_stats - return memory statistics
116454359Sroberto */
116554359Srobertostatic void
116654359Srobertomem_stats(
1167285612Sdelphij	sockaddr_u *srcadr,
1168285612Sdelphij	endpt *inter,
116954359Sroberto	struct req_pkt *inpkt
117054359Sroberto	)
117154359Sroberto{
117254359Sroberto	register struct info_mem_stats *ms;
117354359Sroberto	register int i;
117454359Sroberto
117554359Sroberto	ms = (struct info_mem_stats *)prepare_pkt(srcadr, inter, inpkt,
117654359Sroberto						  sizeof(struct info_mem_stats));
117754359Sroberto
117854359Sroberto	ms->timereset = htonl((u_int32)(current_time - peer_timereset));
117954359Sroberto	ms->totalpeermem = htons((u_short)total_peer_structs);
118054359Sroberto	ms->freepeermem = htons((u_short)peer_free_count);
118154359Sroberto	ms->findpeer_calls = htonl((u_int32)findpeer_calls);
118254359Sroberto	ms->allocations = htonl((u_int32)peer_allocations);
118354359Sroberto	ms->demobilizations = htonl((u_int32)peer_demobilizations);
118454359Sroberto
1185285612Sdelphij	for (i = 0; i < NTP_HASH_SIZE; i++)
1186285612Sdelphij		ms->hashcount[i] = (u_char)
1187285612Sdelphij		    max((u_int)peer_hash_count[i], UCHAR_MAX);
118854359Sroberto
1189294569Sdelphij	(void) more_pkt();
119054359Sroberto	flush_pkt();
119154359Sroberto}
119254359Sroberto
119354359Sroberto
119454359Sroberto/*
119554359Sroberto * io_stats - return io statistics
119654359Sroberto */
119754359Srobertostatic void
119854359Srobertoio_stats(
1199285612Sdelphij	sockaddr_u *srcadr,
1200285612Sdelphij	endpt *inter,
120154359Sroberto	struct req_pkt *inpkt
120254359Sroberto	)
120354359Sroberto{
1204285612Sdelphij	struct info_io_stats *io;
120554359Sroberto
120654359Sroberto	io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt,
120754359Sroberto						 sizeof(struct info_io_stats));
120854359Sroberto
120954359Sroberto	io->timereset = htonl((u_int32)(current_time - io_timereset));
121054359Sroberto	io->totalrecvbufs = htons((u_short) total_recvbuffs());
121154359Sroberto	io->freerecvbufs = htons((u_short) free_recvbuffs());
121254359Sroberto	io->fullrecvbufs = htons((u_short) full_recvbuffs());
121354359Sroberto	io->lowwater = htons((u_short) lowater_additions());
121454359Sroberto	io->dropped = htonl((u_int32)packets_dropped);
121554359Sroberto	io->ignored = htonl((u_int32)packets_ignored);
121654359Sroberto	io->received = htonl((u_int32)packets_received);
121754359Sroberto	io->sent = htonl((u_int32)packets_sent);
121854359Sroberto	io->notsent = htonl((u_int32)packets_notsent);
121954359Sroberto	io->interrupts = htonl((u_int32)handler_calls);
122054359Sroberto	io->int_received = htonl((u_int32)handler_pkts);
122154359Sroberto
122254359Sroberto	(void) more_pkt();
122354359Sroberto	flush_pkt();
122454359Sroberto}
122554359Sroberto
122654359Sroberto
122754359Sroberto/*
122854359Sroberto * timer_stats - return timer statistics
122954359Sroberto */
123054359Srobertostatic void
123154359Srobertotimer_stats(
1232285612Sdelphij	sockaddr_u *		srcadr,
1233285612Sdelphij	endpt *			inter,
1234285612Sdelphij	struct req_pkt *	inpkt
123554359Sroberto	)
123654359Sroberto{
1237285612Sdelphij	struct info_timer_stats *	ts;
1238285612Sdelphij	u_long				sincereset;
123954359Sroberto
1240285612Sdelphij	ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter,
1241285612Sdelphij						    inpkt, sizeof(*ts));
124254359Sroberto
1243285612Sdelphij	sincereset = current_time - timer_timereset;
1244285612Sdelphij	ts->timereset = htonl((u_int32)sincereset);
1245285612Sdelphij	ts->alarms = ts->timereset;
1246285612Sdelphij	ts->overflows = htonl((u_int32)alarm_overflow);
124754359Sroberto	ts->xmtcalls = htonl((u_int32)timer_xmtcalls);
124854359Sroberto
124954359Sroberto	(void) more_pkt();
125054359Sroberto	flush_pkt();
125154359Sroberto}
125254359Sroberto
125354359Sroberto
125454359Sroberto/*
125554359Sroberto * loop_info - return the current state of the loop filter
125654359Sroberto */
125754359Srobertostatic void
125854359Srobertoloop_info(
1259285612Sdelphij	sockaddr_u *srcadr,
1260285612Sdelphij	endpt *inter,
126154359Sroberto	struct req_pkt *inpkt
126254359Sroberto	)
126354359Sroberto{
1264285612Sdelphij	struct info_loop *li;
126554359Sroberto	l_fp ltmp;
126654359Sroberto
126754359Sroberto	li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt,
126854359Sroberto	    sizeof(struct info_loop));
126954359Sroberto
127054359Sroberto	DTOLFP(last_offset, &ltmp);
127154359Sroberto	HTONL_FP(&ltmp, &li->last_offset);
127254359Sroberto	DTOLFP(drift_comp * 1e6, &ltmp);
127354359Sroberto	HTONL_FP(&ltmp, &li->drift_comp);
127454359Sroberto	li->compliance = htonl((u_int32)(tc_counter));
1275285612Sdelphij	li->watchdog_timer = htonl((u_int32)(current_time - sys_epoch));
127654359Sroberto
1277294569Sdelphij	(void) more_pkt();
127854359Sroberto	flush_pkt();
127954359Sroberto}
128054359Sroberto
128154359Sroberto
128254359Sroberto/*
128354359Sroberto * do_conf - add a peer to the configuration list
128454359Sroberto */
128554359Srobertostatic void
128654359Srobertodo_conf(
1287285612Sdelphij	sockaddr_u *srcadr,
1288285612Sdelphij	endpt *inter,
128954359Sroberto	struct req_pkt *inpkt
129054359Sroberto	)
129154359Sroberto{
1292285612Sdelphij	u_short			items;
1293285612Sdelphij	size_t			item_sz;
1294285612Sdelphij	u_int			fl;
1295285612Sdelphij	char *			datap;
1296285612Sdelphij	struct conf_peer	temp_cp;
1297285612Sdelphij	sockaddr_u		peeraddr;
129854359Sroberto
129954359Sroberto	/*
130054359Sroberto	 * Do a check of everything to see that it looks
130154359Sroberto	 * okay.  If not, complain about it.  Note we are
130254359Sroberto	 * very picky here.
130354359Sroberto	 */
130454359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
1305285612Sdelphij	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
1306285612Sdelphij	datap = inpkt->u.data;
1307285612Sdelphij	if (item_sz > sizeof(temp_cp)) {
130854359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
130954359Sroberto		return;
131054359Sroberto	}
131154359Sroberto
1312132451Sroberto	while (items-- > 0) {
1313285612Sdelphij		ZERO(temp_cp);
1314285612Sdelphij		memcpy(&temp_cp, datap, item_sz);
1315285612Sdelphij		ZERO_SOCK(&peeraddr);
1316132451Sroberto
1317132451Sroberto		fl = 0;
1318132451Sroberto		if (temp_cp.flags & CONF_FLAG_PREFER)
1319182007Sroberto			fl |= FLAG_PREFER;
1320132451Sroberto		if (temp_cp.flags & CONF_FLAG_BURST)
1321285612Sdelphij			fl |= FLAG_BURST;
1322182007Sroberto		if (temp_cp.flags & CONF_FLAG_IBURST)
1323285612Sdelphij			fl |= FLAG_IBURST;
1324285612Sdelphij#ifdef AUTOKEY
1325132451Sroberto		if (temp_cp.flags & CONF_FLAG_SKEY)
1326132451Sroberto			fl |= FLAG_SKEY;
1327285612Sdelphij#endif	/* AUTOKEY */
1328285612Sdelphij		if (client_v6_capable && temp_cp.v6_flag) {
1329285612Sdelphij			AF(&peeraddr) = AF_INET6;
1330285612Sdelphij			SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6;
1331132451Sroberto		} else {
1332285612Sdelphij			AF(&peeraddr) = AF_INET;
1333285612Sdelphij			NSRCADR(&peeraddr) = temp_cp.peeraddr;
1334132451Sroberto			/*
1335132451Sroberto			 * Make sure the address is valid
1336132451Sroberto			 */
1337285612Sdelphij			if (!ISREFCLOCKADR(&peeraddr) &&
1338285612Sdelphij			    ISBADADR(&peeraddr)) {
1339132451Sroberto				req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1340132451Sroberto				return;
1341132451Sroberto			}
1342132451Sroberto
1343132451Sroberto		}
1344132451Sroberto		NSRCPORT(&peeraddr) = htons(NTP_PORT);
1345285612Sdelphij#ifdef ISC_PLATFORM_HAVESALEN
1346285612Sdelphij		peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
134782498Sroberto#endif
134854359Sroberto
1349298699Sdelphij		/* check mode value: 0 <= hmode <= 6
1350298699Sdelphij		 *
1351298699Sdelphij		 * There's no good global define for that limit, and
1352298699Sdelphij		 * using a magic define is as good (or bad, actually) as
1353298699Sdelphij		 * a magic number. So we use the highest possible peer
1354298699Sdelphij		 * mode, and that is MODE_BCLIENT.
1355298699Sdelphij		 *
1356298699Sdelphij		 * [Bug 3009] claims that a problem occurs for hmode > 7,
1357298699Sdelphij		 * but the code in ntp_peer.c indicates trouble for any
1358298699Sdelphij		 * hmode > 6 ( --> MODE_BCLIENT).
1359298699Sdelphij		 */
1360298699Sdelphij		if (temp_cp.hmode > MODE_BCLIENT) {
1361298699Sdelphij			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1362298699Sdelphij			return;
1363298699Sdelphij		}
1364298699Sdelphij
1365298699Sdelphij		/* Any more checks on the values? Unchecked at this
1366298699Sdelphij		 * point:
1367298699Sdelphij		 *   - version
1368298699Sdelphij		 *   - ttl
1369298699Sdelphij		 *   - keyid
1370298699Sdelphij		 *
1371298699Sdelphij		 *   - minpoll/maxpoll, but they are treated properly
1372298699Sdelphij		 *     for all cases internally. Checking not necessary.
1373330141Sdelphij		 *
1374330141Sdelphij		 * Note that we ignore any previously-specified ippeerlimit.
1375330141Sdelphij		 * If we're told to create the peer, we create the peer.
1376298699Sdelphij		 */
1377298699Sdelphij
1378298699Sdelphij		/* finally create the peer */
1379330141Sdelphij		if (peer_config(&peeraddr, NULL, NULL, -1,
1380132451Sroberto		    temp_cp.hmode, temp_cp.version, temp_cp.minpoll,
1381132451Sroberto		    temp_cp.maxpoll, fl, temp_cp.ttl, temp_cp.keyid,
1382298699Sdelphij		    NULL) == 0)
1383298699Sdelphij		{
138454359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
138554359Sroberto			return;
138654359Sroberto		}
1387200576Sroberto
1388285612Sdelphij		datap += item_sz;
138954359Sroberto	}
139054359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
139154359Sroberto}
139254359Sroberto
139382498Sroberto
139482498Sroberto/*
139554359Sroberto * do_unconf - remove a peer from the configuration list
139654359Sroberto */
139754359Srobertostatic void
139854359Srobertodo_unconf(
1399285612Sdelphij	sockaddr_u *	srcadr,
1400285612Sdelphij	endpt *		inter,
140154359Sroberto	struct req_pkt *inpkt
140254359Sroberto	)
140354359Sroberto{
1404285612Sdelphij	u_short			items;
1405285612Sdelphij	size_t			item_sz;
1406285612Sdelphij	char *			datap;
1407285612Sdelphij	struct conf_unpeer	temp_cp;
1408285612Sdelphij	struct peer *		p;
1409285612Sdelphij	sockaddr_u		peeraddr;
1410298699Sdelphij	int			loops;
141154359Sroberto
141254359Sroberto	/*
141354359Sroberto	 * This is a bit unstructured, but I like to be careful.
141454359Sroberto	 * We check to see that every peer exists and is actually
141554359Sroberto	 * configured.  If so, we remove them.  If not, we return
141654359Sroberto	 * an error.
1417298699Sdelphij	 *
1418298699Sdelphij	 * [Bug 3011] Even if we checked all peers given in the request
1419298699Sdelphij	 * in a dry run, there's still a chance that the caller played
1420298699Sdelphij	 * unfair and gave the same peer multiple times. So we still
1421298699Sdelphij	 * have to be prepared for nasty surprises in the second run ;)
142254359Sroberto	 */
1423298699Sdelphij
1424298699Sdelphij	/* basic consistency checks */
1425285612Sdelphij	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
1426285612Sdelphij	if (item_sz > sizeof(temp_cp)) {
1427285612Sdelphij		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1428285612Sdelphij		return;
1429285612Sdelphij	}
143054359Sroberto
1431298699Sdelphij	/* now do two runs: first a dry run, then a busy one */
1432298699Sdelphij	for (loops = 0; loops != 2; ++loops) {
1433298699Sdelphij		items = INFO_NITEMS(inpkt->err_nitems);
1434298699Sdelphij		datap = inpkt->u.data;
1435298699Sdelphij		while (items-- > 0) {
1436298699Sdelphij			/* copy from request to local */
1437298699Sdelphij			ZERO(temp_cp);
1438298699Sdelphij			memcpy(&temp_cp, datap, item_sz);
1439298699Sdelphij			/* get address structure */
1440298699Sdelphij			ZERO_SOCK(&peeraddr);
1441298699Sdelphij			if (client_v6_capable && temp_cp.v6_flag) {
1442298699Sdelphij				AF(&peeraddr) = AF_INET6;
1443298699Sdelphij				SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6;
1444298699Sdelphij			} else {
1445298699Sdelphij				AF(&peeraddr) = AF_INET;
1446298699Sdelphij				NSRCADR(&peeraddr) = temp_cp.peeraddr;
1447298699Sdelphij			}
1448298699Sdelphij			SET_PORT(&peeraddr, NTP_PORT);
1449285612Sdelphij#ifdef ISC_PLATFORM_HAVESALEN
1450298699Sdelphij			peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
1451132451Sroberto#endif
1452298699Sdelphij			DPRINTF(1, ("searching for %s\n",
1453298699Sdelphij				    stoa(&peeraddr)));
1454285612Sdelphij
1455298699Sdelphij			/* search for matching configred(!) peer */
1456298699Sdelphij			p = NULL;
1457298699Sdelphij			do {
1458298699Sdelphij				p = findexistingpeer(
1459330141Sdelphij					&peeraddr, NULL, p, -1, 0, NULL);
1460298699Sdelphij			} while (p && !(FLAG_CONFIG & p->flags));
1461298699Sdelphij
1462298699Sdelphij			if (!loops && !p) {
1463298699Sdelphij				/* Item not found in dry run -- bail! */
1464298699Sdelphij				req_ack(srcadr, inter, inpkt,
1465298699Sdelphij					INFO_ERR_NODATA);
1466298699Sdelphij				return;
1467298699Sdelphij			} else if (loops && p) {
1468298699Sdelphij				/* Item found in busy run -- remove! */
1469298699Sdelphij				peer_clear(p, "GONE");
1470298699Sdelphij				unpeer(p);
1471298699Sdelphij			}
1472298699Sdelphij			datap += item_sz;
147354359Sroberto		}
147454359Sroberto	}
147554359Sroberto
1476298699Sdelphij	/* report success */
147754359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
147854359Sroberto}
147954359Sroberto
148054359Sroberto
148154359Sroberto/*
148254359Sroberto * set_sys_flag - set system flags
148354359Sroberto */
148454359Srobertostatic void
148554359Srobertoset_sys_flag(
1486285612Sdelphij	sockaddr_u *srcadr,
1487285612Sdelphij	endpt *inter,
148854359Sroberto	struct req_pkt *inpkt
148954359Sroberto	)
149054359Sroberto{
149154359Sroberto	setclr_flags(srcadr, inter, inpkt, 1);
149254359Sroberto}
149354359Sroberto
149454359Sroberto
149554359Sroberto/*
149654359Sroberto * clr_sys_flag - clear system flags
149754359Sroberto */
149854359Srobertostatic void
149954359Srobertoclr_sys_flag(
1500285612Sdelphij	sockaddr_u *srcadr,
1501285612Sdelphij	endpt *inter,
150254359Sroberto	struct req_pkt *inpkt
150354359Sroberto	)
150454359Sroberto{
150554359Sroberto	setclr_flags(srcadr, inter, inpkt, 0);
150654359Sroberto}
150754359Sroberto
150854359Sroberto
150954359Sroberto/*
151054359Sroberto * setclr_flags - do the grunge work of flag setting/clearing
151154359Sroberto */
151254359Srobertostatic void
151354359Srobertosetclr_flags(
1514285612Sdelphij	sockaddr_u *srcadr,
1515285612Sdelphij	endpt *inter,
151654359Sroberto	struct req_pkt *inpkt,
151754359Sroberto	u_long set
151854359Sroberto	)
151954359Sroberto{
1520285612Sdelphij	struct conf_sys_flags *sf;
1521285612Sdelphij	u_int32 flags;
152254359Sroberto
152354359Sroberto	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
152482498Sroberto		msyslog(LOG_ERR, "setclr_flags: err_nitems > 1");
152554359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
152654359Sroberto		return;
152754359Sroberto	}
152854359Sroberto
1529285612Sdelphij	sf = (struct conf_sys_flags *)&inpkt->u;
1530285612Sdelphij	flags = ntohl(sf->flags);
1531182007Sroberto
153282498Sroberto	if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS |
153354359Sroberto		      SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR |
1534106163Sroberto		      SYS_FLAG_FILEGEN | SYS_FLAG_AUTH | SYS_FLAG_CAL)) {
153582498Sroberto		msyslog(LOG_ERR, "setclr_flags: extra flags: %#x",
1536132451Sroberto			flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS |
153782498Sroberto				  SYS_FLAG_NTP | SYS_FLAG_KERNEL |
1538106163Sroberto				  SYS_FLAG_MONITOR | SYS_FLAG_FILEGEN |
1539106163Sroberto				  SYS_FLAG_AUTH | SYS_FLAG_CAL));
154054359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
154154359Sroberto		return;
154254359Sroberto	}
154354359Sroberto
154454359Sroberto	if (flags & SYS_FLAG_BCLIENT)
1545132451Sroberto		proto_config(PROTO_BROADCLIENT, set, 0., NULL);
154682498Sroberto	if (flags & SYS_FLAG_PPS)
1547132451Sroberto		proto_config(PROTO_PPS, set, 0., NULL);
154854359Sroberto	if (flags & SYS_FLAG_NTP)
1549132451Sroberto		proto_config(PROTO_NTP, set, 0., NULL);
155054359Sroberto	if (flags & SYS_FLAG_KERNEL)
1551132451Sroberto		proto_config(PROTO_KERNEL, set, 0., NULL);
155254359Sroberto	if (flags & SYS_FLAG_MONITOR)
1553132451Sroberto		proto_config(PROTO_MONITOR, set, 0., NULL);
155454359Sroberto	if (flags & SYS_FLAG_FILEGEN)
1555132451Sroberto		proto_config(PROTO_FILEGEN, set, 0., NULL);
1556106163Sroberto	if (flags & SYS_FLAG_AUTH)
1557132451Sroberto		proto_config(PROTO_AUTHENTICATE, set, 0., NULL);
1558106163Sroberto	if (flags & SYS_FLAG_CAL)
1559132451Sroberto		proto_config(PROTO_CAL, set, 0., NULL);
156054359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
1561285612Sdelphij}
1562182007Sroberto
1563294569Sdelphij/* There have been some issues with the restrict list processing,
1564294569Sdelphij * ranging from problems with deep recursion (resulting in stack
1565294569Sdelphij * overflows) and overfull reply buffers.
1566294569Sdelphij *
1567294569Sdelphij * To avoid this trouble the list reversal is done iteratively using a
1568294569Sdelphij * scratch pad.
1569294569Sdelphij */
1570294569Sdelphijtypedef struct RestrictStack RestrictStackT;
1571294569Sdelphijstruct RestrictStack {
1572294569Sdelphij	RestrictStackT   *link;
1573294569Sdelphij	size_t            fcnt;
1574294569Sdelphij	const restrict_u *pres[63];
1575294569Sdelphij};
1576294569Sdelphij
1577294569Sdelphijstatic size_t
1578294569SdelphijgetStackSheetSize(
1579294569Sdelphij	RestrictStackT *sp
1580294569Sdelphij	)
1581294569Sdelphij{
1582294569Sdelphij	if (sp)
1583294569Sdelphij		return sizeof(sp->pres)/sizeof(sp->pres[0]);
1584294569Sdelphij	return 0u;
1585294569Sdelphij}
1586294569Sdelphij
1587294569Sdelphijstatic int/*BOOL*/
1588294569SdelphijpushRestriction(
1589294569Sdelphij	RestrictStackT  **spp,
1590294569Sdelphij	const restrict_u *ptr
1591294569Sdelphij	)
1592294569Sdelphij{
1593294569Sdelphij	RestrictStackT *sp;
1594294569Sdelphij
1595294569Sdelphij	if (NULL == (sp = *spp) || 0 == sp->fcnt) {
1596294569Sdelphij		/* need another sheet in the scratch pad */
1597294569Sdelphij		sp = emalloc(sizeof(*sp));
1598294569Sdelphij		sp->link = *spp;
1599294569Sdelphij		sp->fcnt = getStackSheetSize(sp);
1600294569Sdelphij		*spp = sp;
1601294569Sdelphij	}
1602294569Sdelphij	sp->pres[--sp->fcnt] = ptr;
1603294569Sdelphij	return TRUE;
1604294569Sdelphij}
1605294569Sdelphij
1606294569Sdelphijstatic int/*BOOL*/
1607294569SdelphijpopRestriction(
1608294569Sdelphij	RestrictStackT   **spp,
1609294569Sdelphij	const restrict_u **opp
1610294569Sdelphij	)
1611294569Sdelphij{
1612294569Sdelphij	RestrictStackT *sp;
1613294569Sdelphij
1614294569Sdelphij	if (NULL == (sp = *spp) || sp->fcnt >= getStackSheetSize(sp))
1615294569Sdelphij		return FALSE;
1616294569Sdelphij
1617294569Sdelphij	*opp = sp->pres[sp->fcnt++];
1618294569Sdelphij	if (sp->fcnt >= getStackSheetSize(sp)) {
1619294569Sdelphij		/* discard sheet from scratch pad */
1620294569Sdelphij		*spp = sp->link;
1621294569Sdelphij		free(sp);
1622294569Sdelphij	}
1623294569Sdelphij	return TRUE;
1624294569Sdelphij}
1625294569Sdelphij
1626294569Sdelphijstatic void
1627294569SdelphijflushRestrictionStack(
1628294569Sdelphij	RestrictStackT **spp
1629294569Sdelphij	)
1630294569Sdelphij{
1631294569Sdelphij	RestrictStackT *sp;
1632294569Sdelphij
1633294569Sdelphij	while (NULL != (sp = *spp)) {
1634294569Sdelphij		*spp = sp->link;
1635294569Sdelphij		free(sp);
1636294569Sdelphij	}
1637294569Sdelphij}
1638294569Sdelphij
1639285612Sdelphij/*
1640294569Sdelphij * list_restrict4 - iterative helper for list_restrict dumps IPv4
1641285612Sdelphij *		    restriction list in reverse order.
1642285612Sdelphij */
1643285612Sdelphijstatic void
1644285612Sdelphijlist_restrict4(
1645294569Sdelphij	const restrict_u *	res,
1646285612Sdelphij	struct info_restrict **	ppir
1647285612Sdelphij	)
1648285612Sdelphij{
1649294569Sdelphij	RestrictStackT *	rpad;
1650285612Sdelphij	struct info_restrict *	pir;
1651285612Sdelphij
1652285612Sdelphij	pir = *ppir;
1653294569Sdelphij	for (rpad = NULL; res; res = res->link)
1654294569Sdelphij		if (!pushRestriction(&rpad, res))
1655294569Sdelphij			break;
1656294569Sdelphij
1657294569Sdelphij	while (pir && popRestriction(&rpad, &res)) {
1658294569Sdelphij		pir->addr = htonl(res->u.v4.addr);
1659294569Sdelphij		if (client_v6_capable)
1660294569Sdelphij			pir->v6_flag = 0;
1661294569Sdelphij		pir->mask = htonl(res->u.v4.mask);
1662294569Sdelphij		pir->count = htonl(res->count);
1663330141Sdelphij		pir->rflags = htons(res->rflags);
1664294569Sdelphij		pir->mflags = htons(res->mflags);
1665294569Sdelphij		pir = (struct info_restrict *)more_pkt();
1666294569Sdelphij	}
1667294569Sdelphij	flushRestrictionStack(&rpad);
1668294569Sdelphij	*ppir = pir;
166954359Sroberto}
167054359Sroberto
167154359Sroberto/*
1672294569Sdelphij * list_restrict6 - iterative helper for list_restrict dumps IPv6
1673285612Sdelphij *		    restriction list in reverse order.
1674285612Sdelphij */
1675285612Sdelphijstatic void
1676285612Sdelphijlist_restrict6(
1677294569Sdelphij	const restrict_u *	res,
1678285612Sdelphij	struct info_restrict **	ppir
1679285612Sdelphij	)
1680285612Sdelphij{
1681294569Sdelphij	RestrictStackT *	rpad;
1682285612Sdelphij	struct info_restrict *	pir;
1683285612Sdelphij
1684294569Sdelphij	pir = *ppir;
1685294569Sdelphij	for (rpad = NULL; res; res = res->link)
1686294569Sdelphij		if (!pushRestriction(&rpad, res))
1687294569Sdelphij			break;
1688285612Sdelphij
1689294569Sdelphij	while (pir && popRestriction(&rpad, &res)) {
1690294569Sdelphij		pir->addr6 = res->u.v6.addr;
1691294569Sdelphij		pir->mask6 = res->u.v6.mask;
1692294569Sdelphij		pir->v6_flag = 1;
1693294569Sdelphij		pir->count = htonl(res->count);
1694330141Sdelphij		pir->rflags = htons(res->rflags);
1695294569Sdelphij		pir->mflags = htons(res->mflags);
1696294569Sdelphij		pir = (struct info_restrict *)more_pkt();
1697294569Sdelphij	}
1698294569Sdelphij	flushRestrictionStack(&rpad);
1699294569Sdelphij	*ppir = pir;
1700285612Sdelphij}
1701285612Sdelphij
1702285612Sdelphij
1703285612Sdelphij/*
170454359Sroberto * list_restrict - return the restrict list
170554359Sroberto */
170654359Srobertostatic void
170754359Srobertolist_restrict(
1708285612Sdelphij	sockaddr_u *srcadr,
1709285612Sdelphij	endpt *inter,
171054359Sroberto	struct req_pkt *inpkt
171154359Sroberto	)
171254359Sroberto{
1713285612Sdelphij	struct info_restrict *ir;
171454359Sroberto
1715285612Sdelphij	DPRINTF(3, ("wants restrict list summary\n"));
171654359Sroberto
171754359Sroberto	ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt,
1718132451Sroberto	    v6sizeof(struct info_restrict));
1719132451Sroberto
1720285612Sdelphij	/*
1721285612Sdelphij	 * The restriction lists are kept sorted in the reverse order
1722285612Sdelphij	 * than they were originally.  To preserve the output semantics,
1723294569Sdelphij	 * dump each list in reverse order. The workers take care of that.
1724285612Sdelphij	 */
1725285612Sdelphij	list_restrict4(restrictlist4, &ir);
1726132451Sroberto	if (client_v6_capable)
1727285612Sdelphij		list_restrict6(restrictlist6, &ir);
172854359Sroberto	flush_pkt();
172954359Sroberto}
173054359Sroberto
173154359Sroberto
173254359Sroberto/*
173354359Sroberto * do_resaddflags - add flags to a restrict entry (or create one)
173454359Sroberto */
173554359Srobertostatic void
173654359Srobertodo_resaddflags(
1737285612Sdelphij	sockaddr_u *srcadr,
1738285612Sdelphij	endpt *inter,
173954359Sroberto	struct req_pkt *inpkt
174054359Sroberto	)
174154359Sroberto{
174254359Sroberto	do_restrict(srcadr, inter, inpkt, RESTRICT_FLAGS);
174354359Sroberto}
174454359Sroberto
174554359Sroberto
174654359Sroberto
174754359Sroberto/*
174854359Sroberto * do_ressubflags - remove flags from a restrict entry
174954359Sroberto */
175054359Srobertostatic void
175154359Srobertodo_ressubflags(
1752285612Sdelphij	sockaddr_u *srcadr,
1753285612Sdelphij	endpt *inter,
175454359Sroberto	struct req_pkt *inpkt
175554359Sroberto	)
175654359Sroberto{
175754359Sroberto	do_restrict(srcadr, inter, inpkt, RESTRICT_UNFLAG);
175854359Sroberto}
175954359Sroberto
176054359Sroberto
176154359Sroberto/*
176254359Sroberto * do_unrestrict - remove a restrict entry from the list
176354359Sroberto */
176454359Srobertostatic void
176554359Srobertodo_unrestrict(
1766285612Sdelphij	sockaddr_u *srcadr,
1767285612Sdelphij	endpt *inter,
176854359Sroberto	struct req_pkt *inpkt
176954359Sroberto	)
177054359Sroberto{
177154359Sroberto	do_restrict(srcadr, inter, inpkt, RESTRICT_REMOVE);
177254359Sroberto}
177354359Sroberto
177454359Sroberto
177554359Sroberto/*
177654359Sroberto * do_restrict - do the dirty stuff of dealing with restrictions
177754359Sroberto */
177854359Srobertostatic void
177954359Srobertodo_restrict(
1780285612Sdelphij	sockaddr_u *srcadr,
1781285612Sdelphij	endpt *inter,
178254359Sroberto	struct req_pkt *inpkt,
1783330141Sdelphij	restrict_op op
178454359Sroberto	)
178554359Sroberto{
1786285612Sdelphij	char *			datap;
1787285612Sdelphij	struct conf_restrict	cr;
1788285612Sdelphij	u_short			items;
1789285612Sdelphij	size_t			item_sz;
1790285612Sdelphij	sockaddr_u		matchaddr;
1791285612Sdelphij	sockaddr_u		matchmask;
1792285612Sdelphij	int			bad;
179354359Sroberto
1794330141Sdelphij	switch(op) {
1795330141Sdelphij	    case RESTRICT_FLAGS:
1796330141Sdelphij	    case RESTRICT_UNFLAG:
1797330141Sdelphij	    case RESTRICT_REMOVE:
1798330141Sdelphij	    case RESTRICT_REMOVEIF:
1799330141Sdelphij	    	break;
1800330141Sdelphij
1801330141Sdelphij	    default:
1802330141Sdelphij		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1803330141Sdelphij		return;
1804330141Sdelphij	}
1805330141Sdelphij
180654359Sroberto	/*
180754359Sroberto	 * Do a check of the flags to make sure that only
180854359Sroberto	 * the NTPPORT flag is set, if any.  If not, complain
180954359Sroberto	 * about it.  Note we are very picky here.
181054359Sroberto	 */
181154359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
1812285612Sdelphij	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
1813285612Sdelphij	datap = inpkt->u.data;
1814285612Sdelphij	if (item_sz > sizeof(cr)) {
1815285612Sdelphij		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1816285612Sdelphij		return;
1817285612Sdelphij	}
181854359Sroberto
1819330141Sdelphij	bad = 0;
182054359Sroberto	while (items-- > 0 && !bad) {
1821285612Sdelphij		memcpy(&cr, datap, item_sz);
1822285612Sdelphij		cr.flags = ntohs(cr.flags);
1823285612Sdelphij		cr.mflags = ntohs(cr.mflags);
1824285612Sdelphij		if (~RESM_NTPONLY & cr.mflags)
1825285612Sdelphij			bad |= 1;
1826285612Sdelphij		if (~RES_ALLFLAGS & cr.flags)
1827285612Sdelphij			bad |= 2;
1828285612Sdelphij		if (INADDR_ANY != cr.mask) {
1829285612Sdelphij			if (client_v6_capable && cr.v6_flag) {
1830285612Sdelphij				if (IN6_IS_ADDR_UNSPECIFIED(&cr.addr6))
1831132451Sroberto					bad |= 4;
1832285612Sdelphij			} else {
1833285612Sdelphij				if (INADDR_ANY == cr.addr)
1834132451Sroberto					bad |= 8;
1835285612Sdelphij			}
1836132451Sroberto		}
1837285612Sdelphij		datap += item_sz;
183854359Sroberto	}
183954359Sroberto
184054359Sroberto	if (bad) {
184182498Sroberto		msyslog(LOG_ERR, "do_restrict: bad = %#x", bad);
184254359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
184354359Sroberto		return;
184454359Sroberto	}
184554359Sroberto
184654359Sroberto	/*
1847289997Sglebius	 * Looks okay, try it out.  Needs to reload data pointer and
1848289997Sglebius	 * item counter. (Talos-CAN-0052)
184954359Sroberto	 */
1850285612Sdelphij	ZERO_SOCK(&matchaddr);
1851285612Sdelphij	ZERO_SOCK(&matchmask);
1852289997Sglebius	items = INFO_NITEMS(inpkt->err_nitems);
1853285612Sdelphij	datap = inpkt->u.data;
185454359Sroberto
185554359Sroberto	while (items-- > 0) {
1856285612Sdelphij		memcpy(&cr, datap, item_sz);
1857285612Sdelphij		cr.flags = ntohs(cr.flags);
1858285612Sdelphij		cr.mflags = ntohs(cr.mflags);
1859330141Sdelphij		cr.ippeerlimit = ntohs(cr.ippeerlimit);
1860285612Sdelphij		if (client_v6_capable && cr.v6_flag) {
1861285612Sdelphij			AF(&matchaddr) = AF_INET6;
1862285612Sdelphij			AF(&matchmask) = AF_INET6;
1863285612Sdelphij			SOCK_ADDR6(&matchaddr) = cr.addr6;
1864285612Sdelphij			SOCK_ADDR6(&matchmask) = cr.mask6;
1865132451Sroberto		} else {
1866285612Sdelphij			AF(&matchaddr) = AF_INET;
1867285612Sdelphij			AF(&matchmask) = AF_INET;
1868285612Sdelphij			NSRCADR(&matchaddr) = cr.addr;
1869285612Sdelphij			NSRCADR(&matchmask) = cr.mask;
1870132451Sroberto		}
1871285612Sdelphij		hack_restrict(op, &matchaddr, &matchmask, cr.mflags,
1872330141Sdelphij			      cr.ippeerlimit, cr.flags, 0);
1873285612Sdelphij		datap += item_sz;
187454359Sroberto	}
187554359Sroberto
187654359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
187754359Sroberto}
187854359Sroberto
187954359Sroberto
188054359Sroberto/*
188154359Sroberto * mon_getlist - return monitor data
188254359Sroberto */
188354359Srobertostatic void
1884285612Sdelphijmon_getlist(
1885285612Sdelphij	sockaddr_u *srcadr,
1886285612Sdelphij	endpt *inter,
188754359Sroberto	struct req_pkt *inpkt
188854359Sroberto	)
188954359Sroberto{
1890285612Sdelphij	req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
189154359Sroberto}
189254359Sroberto
189354359Sroberto
189454359Sroberto/*
189554359Sroberto * Module entry points and the flags they correspond with
189654359Sroberto */
189754359Srobertostruct reset_entry {
189854359Sroberto	int flag;		/* flag this corresponds to */
1899285612Sdelphij	void (*handler)(void);	/* routine to handle request */
190054359Sroberto};
190154359Sroberto
190254359Srobertostruct reset_entry reset_entries[] = {
190354359Sroberto	{ RESET_FLAG_ALLPEERS,	peer_all_reset },
190454359Sroberto	{ RESET_FLAG_IO,	io_clr_stats },
190554359Sroberto	{ RESET_FLAG_SYS,	proto_clr_stats },
190654359Sroberto	{ RESET_FLAG_MEM,	peer_clr_stats },
190754359Sroberto	{ RESET_FLAG_TIMER,	timer_clr_stats },
190854359Sroberto	{ RESET_FLAG_AUTH,	reset_auth_stats },
190954359Sroberto	{ RESET_FLAG_CTL,	ctl_clr_stats },
191054359Sroberto	{ 0,			0 }
191154359Sroberto};
191254359Sroberto
191354359Sroberto/*
191454359Sroberto * reset_stats - reset statistic counters here and there
191554359Sroberto */
191654359Srobertostatic void
191754359Srobertoreset_stats(
1918285612Sdelphij	sockaddr_u *srcadr,
1919285612Sdelphij	endpt *inter,
192054359Sroberto	struct req_pkt *inpkt
192154359Sroberto	)
192254359Sroberto{
1923285612Sdelphij	struct reset_flags *rflags;
192454359Sroberto	u_long flags;
192554359Sroberto	struct reset_entry *rent;
192654359Sroberto
192754359Sroberto	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
192882498Sroberto		msyslog(LOG_ERR, "reset_stats: err_nitems > 1");
192954359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
193054359Sroberto		return;
193154359Sroberto	}
193254359Sroberto
1933285612Sdelphij	rflags = (struct reset_flags *)&inpkt->u;
1934285612Sdelphij	flags = ntohl(rflags->flags);
1935285612Sdelphij
193654359Sroberto	if (flags & ~RESET_ALLFLAGS) {
193782498Sroberto		msyslog(LOG_ERR, "reset_stats: reset leaves %#lx",
193882498Sroberto			flags & ~RESET_ALLFLAGS);
193954359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
194054359Sroberto		return;
194154359Sroberto	}
194254359Sroberto
194354359Sroberto	for (rent = reset_entries; rent->flag != 0; rent++) {
194454359Sroberto		if (flags & rent->flag)
1945285612Sdelphij			(*rent->handler)();
194654359Sroberto	}
194754359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
194854359Sroberto}
194954359Sroberto
195054359Sroberto
195154359Sroberto/*
195254359Sroberto * reset_peer - clear a peer's statistics
195354359Sroberto */
195454359Srobertostatic void
195554359Srobertoreset_peer(
1956285612Sdelphij	sockaddr_u *srcadr,
1957285612Sdelphij	endpt *inter,
195854359Sroberto	struct req_pkt *inpkt
195954359Sroberto	)
196054359Sroberto{
1961285612Sdelphij	u_short			items;
1962285612Sdelphij	size_t			item_sz;
1963285612Sdelphij	char *			datap;
1964285612Sdelphij	struct conf_unpeer	cp;
1965285612Sdelphij	struct peer *		p;
1966285612Sdelphij	sockaddr_u		peeraddr;
1967285612Sdelphij	int			bad;
196854359Sroberto
196954359Sroberto	/*
197054359Sroberto	 * We check first to see that every peer exists.  If not,
197154359Sroberto	 * we return an error.
197254359Sroberto	 */
197354359Sroberto
197454359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
1975285612Sdelphij	item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize);
1976285612Sdelphij	datap = inpkt->u.data;
1977285612Sdelphij	if (item_sz > sizeof(cp)) {
1978285612Sdelphij		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1979285612Sdelphij		return;
1980285612Sdelphij	}
198154359Sroberto
1982285612Sdelphij	bad = FALSE;
198354359Sroberto	while (items-- > 0 && !bad) {
1984285612Sdelphij		ZERO(cp);
1985285612Sdelphij		memcpy(&cp, datap, item_sz);
1986285612Sdelphij		ZERO_SOCK(&peeraddr);
1987285612Sdelphij		if (client_v6_capable && cp.v6_flag) {
1988285612Sdelphij			AF(&peeraddr) = AF_INET6;
1989285612Sdelphij			SOCK_ADDR6(&peeraddr) = cp.peeraddr6;
1990132451Sroberto		} else {
1991285612Sdelphij			AF(&peeraddr) = AF_INET;
1992285612Sdelphij			NSRCADR(&peeraddr) = cp.peeraddr;
1993132451Sroberto		}
1994285612Sdelphij
1995285612Sdelphij#ifdef ISC_PLATFORM_HAVESALEN
1996285612Sdelphij		peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
1997132451Sroberto#endif
1998330141Sdelphij		p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
1999285612Sdelphij		if (NULL == p)
2000285612Sdelphij			bad++;
2001285612Sdelphij		datap += item_sz;
200254359Sroberto	}
200354359Sroberto
200454359Sroberto	if (bad) {
200554359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
200654359Sroberto		return;
200754359Sroberto	}
200854359Sroberto
200954359Sroberto	/*
2010289997Sglebius	 * Now do it in earnest. Needs to reload data pointer and item
2011289997Sglebius	 * counter. (Talos-CAN-0052)
201254359Sroberto	 */
2013289997Sglebius
2014289997Sglebius	items = INFO_NITEMS(inpkt->err_nitems);
2015285612Sdelphij	datap = inpkt->u.data;
201654359Sroberto	while (items-- > 0) {
2017285612Sdelphij		ZERO(cp);
2018285612Sdelphij		memcpy(&cp, datap, item_sz);
2019285612Sdelphij		ZERO_SOCK(&peeraddr);
2020285612Sdelphij		if (client_v6_capable && cp.v6_flag) {
2021285612Sdelphij			AF(&peeraddr) = AF_INET6;
2022285612Sdelphij			SOCK_ADDR6(&peeraddr) = cp.peeraddr6;
2023132451Sroberto		} else {
2024285612Sdelphij			AF(&peeraddr) = AF_INET;
2025285612Sdelphij			NSRCADR(&peeraddr) = cp.peeraddr;
2026132451Sroberto		}
2027285612Sdelphij		SET_PORT(&peeraddr, 123);
2028285612Sdelphij#ifdef ISC_PLATFORM_HAVESALEN
2029285612Sdelphij		peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
2030132451Sroberto#endif
2031330141Sdelphij		p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL);
2032285612Sdelphij		while (p != NULL) {
2033285612Sdelphij			peer_reset(p);
2034330141Sdelphij			p = findexistingpeer(&peeraddr, NULL, p, -1, 0, NULL);
203554359Sroberto		}
2036285612Sdelphij		datap += item_sz;
203754359Sroberto	}
203854359Sroberto
203954359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
204054359Sroberto}
204154359Sroberto
204254359Sroberto
204354359Sroberto/*
204454359Sroberto * do_key_reread - reread the encryption key file
204554359Sroberto */
204654359Srobertostatic void
204754359Srobertodo_key_reread(
2048285612Sdelphij	sockaddr_u *srcadr,
2049285612Sdelphij	endpt *inter,
205054359Sroberto	struct req_pkt *inpkt
205154359Sroberto	)
205254359Sroberto{
205354359Sroberto	rereadkeys();
205454359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
205554359Sroberto}
205654359Sroberto
205754359Sroberto
205854359Sroberto/*
205954359Sroberto * trust_key - make one or more keys trusted
206054359Sroberto */
206154359Srobertostatic void
206254359Srobertotrust_key(
2063285612Sdelphij	sockaddr_u *srcadr,
2064285612Sdelphij	endpt *inter,
206554359Sroberto	struct req_pkt *inpkt
206654359Sroberto	)
206754359Sroberto{
206854359Sroberto	do_trustkey(srcadr, inter, inpkt, 1);
206954359Sroberto}
207054359Sroberto
207154359Sroberto
207254359Sroberto/*
207354359Sroberto * untrust_key - make one or more keys untrusted
207454359Sroberto */
207554359Srobertostatic void
207654359Srobertountrust_key(
2077285612Sdelphij	sockaddr_u *srcadr,
2078285612Sdelphij	endpt *inter,
207954359Sroberto	struct req_pkt *inpkt
208054359Sroberto	)
208154359Sroberto{
208254359Sroberto	do_trustkey(srcadr, inter, inpkt, 0);
208354359Sroberto}
208454359Sroberto
208554359Sroberto
208654359Sroberto/*
208754359Sroberto * do_trustkey - make keys either trustable or untrustable
208854359Sroberto */
208954359Srobertostatic void
209054359Srobertodo_trustkey(
2091285612Sdelphij	sockaddr_u *srcadr,
2092285612Sdelphij	endpt *inter,
209354359Sroberto	struct req_pkt *inpkt,
209482498Sroberto	u_long trust
209554359Sroberto	)
209654359Sroberto{
2097293650Sglebius	register uint32_t *kp;
209854359Sroberto	register int items;
209954359Sroberto
210054359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
2101294569Sdelphij	kp = (uint32_t *)&inpkt->u;
210254359Sroberto	while (items-- > 0) {
210354359Sroberto		authtrust(*kp, trust);
210454359Sroberto		kp++;
210554359Sroberto	}
210654359Sroberto
210754359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
210854359Sroberto}
210954359Sroberto
211054359Sroberto
211154359Sroberto/*
211254359Sroberto * get_auth_info - return some stats concerning the authentication module
211354359Sroberto */
211454359Srobertostatic void
211554359Srobertoget_auth_info(
2116285612Sdelphij	sockaddr_u *srcadr,
2117285612Sdelphij	endpt *inter,
211854359Sroberto	struct req_pkt *inpkt
211954359Sroberto	)
212054359Sroberto{
212154359Sroberto	register struct info_auth *ia;
212254359Sroberto
212354359Sroberto	ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt,
212454359Sroberto					     sizeof(struct info_auth));
212554359Sroberto
212654359Sroberto	ia->numkeys = htonl((u_int32)authnumkeys);
212754359Sroberto	ia->numfreekeys = htonl((u_int32)authnumfreekeys);
212854359Sroberto	ia->keylookups = htonl((u_int32)authkeylookups);
212954359Sroberto	ia->keynotfound = htonl((u_int32)authkeynotfound);
213054359Sroberto	ia->encryptions = htonl((u_int32)authencryptions);
213154359Sroberto	ia->decryptions = htonl((u_int32)authdecryptions);
213254359Sroberto	ia->keyuncached = htonl((u_int32)authkeyuncached);
213354359Sroberto	ia->expired = htonl((u_int32)authkeyexpired);
213454359Sroberto	ia->timereset = htonl((u_int32)(current_time - auth_timereset));
213554359Sroberto
213654359Sroberto	(void) more_pkt();
213754359Sroberto	flush_pkt();
213854359Sroberto}
213954359Sroberto
214054359Sroberto
214154359Sroberto
214254359Sroberto/*
214354359Sroberto * reset_auth_stats - reset the authentication stat counters.  Done here
214454359Sroberto *		      to keep ntp-isms out of the authentication module
214554359Sroberto */
2146285612Sdelphijvoid
214754359Srobertoreset_auth_stats(void)
214854359Sroberto{
214954359Sroberto	authkeylookups = 0;
215054359Sroberto	authkeynotfound = 0;
215154359Sroberto	authencryptions = 0;
215254359Sroberto	authdecryptions = 0;
215354359Sroberto	authkeyuncached = 0;
215454359Sroberto	auth_timereset = current_time;
215554359Sroberto}
215654359Sroberto
215754359Sroberto
215854359Sroberto/*
215954359Sroberto * req_get_traps - return information about current trap holders
216054359Sroberto */
216154359Srobertostatic void
216254359Srobertoreq_get_traps(
2163285612Sdelphij	sockaddr_u *srcadr,
2164285612Sdelphij	endpt *inter,
216554359Sroberto	struct req_pkt *inpkt
216654359Sroberto	)
216754359Sroberto{
2168285612Sdelphij	struct info_trap *it;
2169285612Sdelphij	struct ctl_trap *tr;
2170285612Sdelphij	size_t i;
217154359Sroberto
217254359Sroberto	if (num_ctl_traps == 0) {
217354359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
217454359Sroberto		return;
217554359Sroberto	}
217654359Sroberto
217754359Sroberto	it = (struct info_trap *)prepare_pkt(srcadr, inter, inpkt,
2178132451Sroberto	    v6sizeof(struct info_trap));
217954359Sroberto
2180294569Sdelphij	for (i = 0, tr = ctl_traps; it && i < COUNTOF(ctl_traps); i++, tr++) {
218154359Sroberto		if (tr->tr_flags & TRAP_INUSE) {
2182285612Sdelphij			if (IS_IPV4(&tr->tr_addr)) {
2183132451Sroberto				if (tr->tr_localaddr == any_interface)
2184132451Sroberto					it->local_address = 0;
2185132451Sroberto				else
2186132451Sroberto					it->local_address
2187285612Sdelphij					    = NSRCADR(&tr->tr_localaddr->sin);
2188285612Sdelphij				it->trap_address = NSRCADR(&tr->tr_addr);
2189132451Sroberto				if (client_v6_capable)
2190132451Sroberto					it->v6_flag = 0;
2191132451Sroberto			} else {
2192132451Sroberto				if (!client_v6_capable)
2193132451Sroberto					continue;
2194132451Sroberto				it->local_address6
2195285612Sdelphij				    = SOCK_ADDR6(&tr->tr_localaddr->sin);
2196285612Sdelphij				it->trap_address6 = SOCK_ADDR6(&tr->tr_addr);
2197132451Sroberto				it->v6_flag = 1;
2198132451Sroberto			}
219954359Sroberto			it->trap_port = NSRCPORT(&tr->tr_addr);
220054359Sroberto			it->sequence = htons(tr->tr_sequence);
220154359Sroberto			it->settime = htonl((u_int32)(current_time - tr->tr_settime));
220254359Sroberto			it->origtime = htonl((u_int32)(current_time - tr->tr_origtime));
220354359Sroberto			it->resets = htonl((u_int32)tr->tr_resets);
220454359Sroberto			it->flags = htonl((u_int32)tr->tr_flags);
220554359Sroberto			it = (struct info_trap *)more_pkt();
220654359Sroberto		}
220754359Sroberto	}
220854359Sroberto	flush_pkt();
220954359Sroberto}
221054359Sroberto
221154359Sroberto
221254359Sroberto/*
221354359Sroberto * req_set_trap - configure a trap
221454359Sroberto */
221554359Srobertostatic void
221654359Srobertoreq_set_trap(
2217285612Sdelphij	sockaddr_u *srcadr,
2218285612Sdelphij	endpt *inter,
221954359Sroberto	struct req_pkt *inpkt
222054359Sroberto	)
222154359Sroberto{
222254359Sroberto	do_setclr_trap(srcadr, inter, inpkt, 1);
222354359Sroberto}
222454359Sroberto
222554359Sroberto
222654359Sroberto
222754359Sroberto/*
222854359Sroberto * req_clr_trap - unconfigure a trap
222954359Sroberto */
223054359Srobertostatic void
223154359Srobertoreq_clr_trap(
2232285612Sdelphij	sockaddr_u *srcadr,
2233285612Sdelphij	endpt *inter,
223454359Sroberto	struct req_pkt *inpkt
223554359Sroberto	)
223654359Sroberto{
223754359Sroberto	do_setclr_trap(srcadr, inter, inpkt, 0);
223854359Sroberto}
223954359Sroberto
224054359Sroberto
224154359Sroberto
224254359Sroberto/*
224354359Sroberto * do_setclr_trap - do the grunge work of (un)configuring a trap
224454359Sroberto */
224554359Srobertostatic void
224654359Srobertodo_setclr_trap(
2247285612Sdelphij	sockaddr_u *srcadr,
2248285612Sdelphij	endpt *inter,
224954359Sroberto	struct req_pkt *inpkt,
225054359Sroberto	int set
225154359Sroberto	)
225254359Sroberto{
225354359Sroberto	register struct conf_trap *ct;
2254285612Sdelphij	register endpt *linter;
225554359Sroberto	int res;
2256285612Sdelphij	sockaddr_u laddr;
225754359Sroberto
225854359Sroberto	/*
2259285612Sdelphij	 * Prepare sockaddr
226054359Sroberto	 */
2261285612Sdelphij	ZERO_SOCK(&laddr);
2262285612Sdelphij	AF(&laddr) = AF(srcadr);
2263285612Sdelphij	SET_PORT(&laddr, NTP_PORT);
226454359Sroberto
226554359Sroberto	/*
226654359Sroberto	 * Restrict ourselves to one item only.  This eliminates
226754359Sroberto	 * the error reporting problem.
226854359Sroberto	 */
226954359Sroberto	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
227082498Sroberto		msyslog(LOG_ERR, "do_setclr_trap: err_nitems > 1");
227154359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
227254359Sroberto		return;
227354359Sroberto	}
2274285612Sdelphij	ct = (struct conf_trap *)&inpkt->u;
227554359Sroberto
227654359Sroberto	/*
227754359Sroberto	 * Look for the local interface.  If none, use the default.
227854359Sroberto	 */
227954359Sroberto	if (ct->local_address == 0) {
228054359Sroberto		linter = any_interface;
228154359Sroberto	} else {
2282285612Sdelphij		if (IS_IPV4(&laddr))
2283285612Sdelphij			NSRCADR(&laddr) = ct->local_address;
2284132451Sroberto		else
2285285612Sdelphij			SOCK_ADDR6(&laddr) = ct->local_address6;
228654359Sroberto		linter = findinterface(&laddr);
2287285612Sdelphij		if (NULL == linter) {
228854359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
228954359Sroberto			return;
229054359Sroberto		}
229154359Sroberto	}
229254359Sroberto
2293285612Sdelphij	if (IS_IPV4(&laddr))
2294285612Sdelphij		NSRCADR(&laddr) = ct->trap_address;
2295132451Sroberto	else
2296285612Sdelphij		SOCK_ADDR6(&laddr) = ct->trap_address6;
2297285612Sdelphij	if (ct->trap_port)
2298285612Sdelphij		NSRCPORT(&laddr) = ct->trap_port;
229954359Sroberto	else
2300285612Sdelphij		SET_PORT(&laddr, TRAPPORT);
230154359Sroberto
230254359Sroberto	if (set) {
230354359Sroberto		res = ctlsettrap(&laddr, linter, 0,
230454359Sroberto				 INFO_VERSION(inpkt->rm_vn_mode));
230554359Sroberto	} else {
230654359Sroberto		res = ctlclrtrap(&laddr, linter, 0);
230754359Sroberto	}
230854359Sroberto
230954359Sroberto	if (!res) {
231054359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
231154359Sroberto	} else {
231254359Sroberto		req_ack(srcadr, inter, inpkt, INFO_OKAY);
231354359Sroberto	}
231454359Sroberto	return;
231554359Sroberto}
231654359Sroberto
231754359Sroberto/*
2318298699Sdelphij * Validate a request packet for a new request or control key:
2319298699Sdelphij *  - only one item allowed
2320298699Sdelphij *  - key must be valid (that is, known, and not in the autokey range)
232154359Sroberto */
232254359Srobertostatic void
2323298699Sdelphijset_keyid_checked(
2324298699Sdelphij	keyid_t        *into,
2325298699Sdelphij	const char     *what,
2326298699Sdelphij	sockaddr_u     *srcadr,
2327298699Sdelphij	endpt          *inter,
232854359Sroberto	struct req_pkt *inpkt
232954359Sroberto	)
233054359Sroberto{
2331285612Sdelphij	keyid_t *pkeyid;
2332298699Sdelphij	keyid_t  tmpkey;
233354359Sroberto
2334298699Sdelphij	/* restrict ourselves to one item only */
233554359Sroberto	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
2336298699Sdelphij		msyslog(LOG_ERR, "set_keyid_checked[%s]: err_nitems > 1",
2337298699Sdelphij			what);
233854359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
233954359Sroberto		return;
234054359Sroberto	}
234154359Sroberto
2342298699Sdelphij	/* plug the new key from the packet */
2343285612Sdelphij	pkeyid = (keyid_t *)&inpkt->u;
2344298699Sdelphij	tmpkey = ntohl(*pkeyid);
2345298699Sdelphij
2346298699Sdelphij	/* validate the new key id, claim data error on failure */
2347298699Sdelphij	if (tmpkey < 1 || tmpkey > NTP_MAXKEY || !auth_havekey(tmpkey)) {
2348298699Sdelphij		msyslog(LOG_ERR, "set_keyid_checked[%s]: invalid key id: %ld",
2349298699Sdelphij			what, (long)tmpkey);
2350298699Sdelphij		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
2351298699Sdelphij		return;
2352298699Sdelphij	}
2353298699Sdelphij
2354298699Sdelphij	/* if we arrive here, the key is good -- use it */
2355298699Sdelphij	*into = tmpkey;
235654359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
235754359Sroberto}
235854359Sroberto
2359298699Sdelphij/*
2360298699Sdelphij * set_request_keyid - set the keyid used to authenticate requests
2361298699Sdelphij */
2362298699Sdelphijstatic void
2363298699Sdelphijset_request_keyid(
2364298699Sdelphij	sockaddr_u *srcadr,
2365298699Sdelphij	endpt *inter,
2366298699Sdelphij	struct req_pkt *inpkt
2367298699Sdelphij	)
2368298699Sdelphij{
2369298699Sdelphij	set_keyid_checked(&info_auth_keyid, "request",
2370298699Sdelphij			  srcadr, inter, inpkt);
2371298699Sdelphij}
237254359Sroberto
237354359Sroberto
2374298699Sdelphij
237554359Sroberto/*
237654359Sroberto * set_control_keyid - set the keyid used to authenticate requests
237754359Sroberto */
237854359Srobertostatic void
237954359Srobertoset_control_keyid(
2380285612Sdelphij	sockaddr_u *srcadr,
2381285612Sdelphij	endpt *inter,
238254359Sroberto	struct req_pkt *inpkt
238354359Sroberto	)
238454359Sroberto{
2385298699Sdelphij	set_keyid_checked(&ctl_auth_keyid, "control",
2386298699Sdelphij			  srcadr, inter, inpkt);
238754359Sroberto}
238854359Sroberto
238954359Sroberto
239054359Sroberto
239154359Sroberto/*
239254359Sroberto * get_ctl_stats - return some stats concerning the control message module
239354359Sroberto */
239454359Srobertostatic void
239554359Srobertoget_ctl_stats(
2396285612Sdelphij	sockaddr_u *srcadr,
2397285612Sdelphij	endpt *inter,
239854359Sroberto	struct req_pkt *inpkt
239954359Sroberto	)
240054359Sroberto{
240154359Sroberto	register struct info_control *ic;
240254359Sroberto
240354359Sroberto	ic = (struct info_control *)prepare_pkt(srcadr, inter, inpkt,
240454359Sroberto						sizeof(struct info_control));
240554359Sroberto
240654359Sroberto	ic->ctltimereset = htonl((u_int32)(current_time - ctltimereset));
240754359Sroberto	ic->numctlreq = htonl((u_int32)numctlreq);
240854359Sroberto	ic->numctlbadpkts = htonl((u_int32)numctlbadpkts);
240954359Sroberto	ic->numctlresponses = htonl((u_int32)numctlresponses);
241054359Sroberto	ic->numctlfrags = htonl((u_int32)numctlfrags);
241154359Sroberto	ic->numctlerrors = htonl((u_int32)numctlerrors);
241254359Sroberto	ic->numctltooshort = htonl((u_int32)numctltooshort);
241354359Sroberto	ic->numctlinputresp = htonl((u_int32)numctlinputresp);
241454359Sroberto	ic->numctlinputfrag = htonl((u_int32)numctlinputfrag);
241554359Sroberto	ic->numctlinputerr = htonl((u_int32)numctlinputerr);
241654359Sroberto	ic->numctlbadoffset = htonl((u_int32)numctlbadoffset);
241754359Sroberto	ic->numctlbadversion = htonl((u_int32)numctlbadversion);
241854359Sroberto	ic->numctldatatooshort = htonl((u_int32)numctldatatooshort);
241954359Sroberto	ic->numctlbadop = htonl((u_int32)numctlbadop);
242054359Sroberto	ic->numasyncmsgs = htonl((u_int32)numasyncmsgs);
242154359Sroberto
242254359Sroberto	(void) more_pkt();
242354359Sroberto	flush_pkt();
242454359Sroberto}
242554359Sroberto
242654359Sroberto
242754359Sroberto#ifdef KERNEL_PLL
242854359Sroberto/*
242954359Sroberto * get_kernel_info - get kernel pll/pps information
243054359Sroberto */
243154359Srobertostatic void
243254359Srobertoget_kernel_info(
2433285612Sdelphij	sockaddr_u *srcadr,
2434285612Sdelphij	endpt *inter,
243554359Sroberto	struct req_pkt *inpkt
243654359Sroberto	)
243754359Sroberto{
243854359Sroberto	register struct info_kernel *ik;
243954359Sroberto	struct timex ntx;
244054359Sroberto
244154359Sroberto	if (!pll_control) {
244254359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
244354359Sroberto		return;
244454359Sroberto	}
244554359Sroberto
2446285612Sdelphij	ZERO(ntx);
244754359Sroberto	if (ntp_adjtime(&ntx) < 0)
244854359Sroberto		msyslog(LOG_ERR, "get_kernel_info: ntp_adjtime() failed: %m");
244954359Sroberto	ik = (struct info_kernel *)prepare_pkt(srcadr, inter, inpkt,
245054359Sroberto	    sizeof(struct info_kernel));
245154359Sroberto
245254359Sroberto	/*
245354359Sroberto	 * pll variables
245454359Sroberto	 */
245554359Sroberto	ik->offset = htonl((u_int32)ntx.offset);
245654359Sroberto	ik->freq = htonl((u_int32)ntx.freq);
245754359Sroberto	ik->maxerror = htonl((u_int32)ntx.maxerror);
245854359Sroberto	ik->esterror = htonl((u_int32)ntx.esterror);
245954359Sroberto	ik->status = htons(ntx.status);
246054359Sroberto	ik->constant = htonl((u_int32)ntx.constant);
246154359Sroberto	ik->precision = htonl((u_int32)ntx.precision);
246254359Sroberto	ik->tolerance = htonl((u_int32)ntx.tolerance);
246354359Sroberto
246454359Sroberto	/*
246554359Sroberto	 * pps variables
246654359Sroberto	 */
246754359Sroberto	ik->ppsfreq = htonl((u_int32)ntx.ppsfreq);
246854359Sroberto	ik->jitter = htonl((u_int32)ntx.jitter);
246954359Sroberto	ik->shift = htons(ntx.shift);
247054359Sroberto	ik->stabil = htonl((u_int32)ntx.stabil);
247154359Sroberto	ik->jitcnt = htonl((u_int32)ntx.jitcnt);
247254359Sroberto	ik->calcnt = htonl((u_int32)ntx.calcnt);
247354359Sroberto	ik->errcnt = htonl((u_int32)ntx.errcnt);
247454359Sroberto	ik->stbcnt = htonl((u_int32)ntx.stbcnt);
247554359Sroberto
247654359Sroberto	(void) more_pkt();
247754359Sroberto	flush_pkt();
247854359Sroberto}
247954359Sroberto#endif /* KERNEL_PLL */
248054359Sroberto
248154359Sroberto
248254359Sroberto#ifdef REFCLOCK
248354359Sroberto/*
248454359Sroberto * get_clock_info - get info about a clock
248554359Sroberto */
248654359Srobertostatic void
248754359Srobertoget_clock_info(
2488285612Sdelphij	sockaddr_u *srcadr,
2489285612Sdelphij	endpt *inter,
249054359Sroberto	struct req_pkt *inpkt
249154359Sroberto	)
249254359Sroberto{
249354359Sroberto	register struct info_clock *ic;
249454359Sroberto	register u_int32 *clkaddr;
249554359Sroberto	register int items;
249654359Sroberto	struct refclockstat clock_stat;
2497285612Sdelphij	sockaddr_u addr;
249854359Sroberto	l_fp ltmp;
249954359Sroberto
2500285612Sdelphij	ZERO_SOCK(&addr);
2501285612Sdelphij	AF(&addr) = AF_INET;
2502285612Sdelphij#ifdef ISC_PLATFORM_HAVESALEN
2503285612Sdelphij	addr.sa.sa_len = SOCKLEN(&addr);
2504132451Sroberto#endif
2505285612Sdelphij	SET_PORT(&addr, NTP_PORT);
250654359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
2507285612Sdelphij	clkaddr = &inpkt->u.u32[0];
250854359Sroberto
250954359Sroberto	ic = (struct info_clock *)prepare_pkt(srcadr, inter, inpkt,
251054359Sroberto					      sizeof(struct info_clock));
251154359Sroberto
2512294569Sdelphij	while (items-- > 0 && ic) {
2513285612Sdelphij		NSRCADR(&addr) = *clkaddr++;
2514285612Sdelphij		if (!ISREFCLOCKADR(&addr) || NULL ==
2515330141Sdelphij		    findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) {
251654359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
251754359Sroberto			return;
251854359Sroberto		}
251954359Sroberto
252054359Sroberto		clock_stat.kv_list = (struct ctl_var *)0;
252154359Sroberto
2522285612Sdelphij		refclock_control(&addr, NULL, &clock_stat);
252354359Sroberto
2524285612Sdelphij		ic->clockadr = NSRCADR(&addr);
252554359Sroberto		ic->type = clock_stat.type;
252654359Sroberto		ic->flags = clock_stat.flags;
252754359Sroberto		ic->lastevent = clock_stat.lastevent;
252854359Sroberto		ic->currentstatus = clock_stat.currentstatus;
252954359Sroberto		ic->polls = htonl((u_int32)clock_stat.polls);
253054359Sroberto		ic->noresponse = htonl((u_int32)clock_stat.noresponse);
253154359Sroberto		ic->badformat = htonl((u_int32)clock_stat.badformat);
253254359Sroberto		ic->baddata = htonl((u_int32)clock_stat.baddata);
253354359Sroberto		ic->timestarted = htonl((u_int32)clock_stat.timereset);
253454359Sroberto		DTOLFP(clock_stat.fudgetime1, &ltmp);
253554359Sroberto		HTONL_FP(&ltmp, &ic->fudgetime1);
2536132451Sroberto		DTOLFP(clock_stat.fudgetime2, &ltmp);
253754359Sroberto		HTONL_FP(&ltmp, &ic->fudgetime2);
253854359Sroberto		ic->fudgeval1 = htonl((u_int32)clock_stat.fudgeval1);
2539285612Sdelphij		ic->fudgeval2 = htonl(clock_stat.fudgeval2);
254054359Sroberto
254154359Sroberto		free_varlist(clock_stat.kv_list);
254254359Sroberto
254354359Sroberto		ic = (struct info_clock *)more_pkt();
254454359Sroberto	}
254554359Sroberto	flush_pkt();
254654359Sroberto}
254754359Sroberto
254854359Sroberto
254954359Sroberto
255054359Sroberto/*
255154359Sroberto * set_clock_fudge - get a clock's fudge factors
255254359Sroberto */
255354359Srobertostatic void
255454359Srobertoset_clock_fudge(
2555285612Sdelphij	sockaddr_u *srcadr,
2556285612Sdelphij	endpt *inter,
255754359Sroberto	struct req_pkt *inpkt
255854359Sroberto	)
255954359Sroberto{
256054359Sroberto	register struct conf_fudge *cf;
256154359Sroberto	register int items;
256254359Sroberto	struct refclockstat clock_stat;
2563285612Sdelphij	sockaddr_u addr;
256454359Sroberto	l_fp ltmp;
256554359Sroberto
2566285612Sdelphij	ZERO(addr);
2567285612Sdelphij	ZERO(clock_stat);
256854359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
2569285612Sdelphij	cf = (struct conf_fudge *)&inpkt->u;
257054359Sroberto
257154359Sroberto	while (items-- > 0) {
2572285612Sdelphij		AF(&addr) = AF_INET;
2573285612Sdelphij		NSRCADR(&addr) = cf->clockadr;
2574285612Sdelphij#ifdef ISC_PLATFORM_HAVESALEN
2575285612Sdelphij		addr.sa.sa_len = SOCKLEN(&addr);
2576132451Sroberto#endif
2577285612Sdelphij		SET_PORT(&addr, NTP_PORT);
2578285612Sdelphij		if (!ISREFCLOCKADR(&addr) || NULL ==
2579330141Sdelphij		    findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) {
258054359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
258154359Sroberto			return;
258254359Sroberto		}
258354359Sroberto
258454359Sroberto		switch(ntohl(cf->which)) {
258554359Sroberto		    case FUDGE_TIME1:
258654359Sroberto			NTOHL_FP(&cf->fudgetime, &ltmp);
258754359Sroberto			LFPTOD(&ltmp, clock_stat.fudgetime1);
258854359Sroberto			clock_stat.haveflags = CLK_HAVETIME1;
258954359Sroberto			break;
259054359Sroberto		    case FUDGE_TIME2:
259154359Sroberto			NTOHL_FP(&cf->fudgetime, &ltmp);
259254359Sroberto			LFPTOD(&ltmp, clock_stat.fudgetime2);
259354359Sroberto			clock_stat.haveflags = CLK_HAVETIME2;
259454359Sroberto			break;
259554359Sroberto		    case FUDGE_VAL1:
259654359Sroberto			clock_stat.fudgeval1 = ntohl(cf->fudgeval_flags);
259754359Sroberto			clock_stat.haveflags = CLK_HAVEVAL1;
259854359Sroberto			break;
259954359Sroberto		    case FUDGE_VAL2:
260054359Sroberto			clock_stat.fudgeval2 = ntohl(cf->fudgeval_flags);
260154359Sroberto			clock_stat.haveflags = CLK_HAVEVAL2;
260254359Sroberto			break;
260354359Sroberto		    case FUDGE_FLAGS:
2604132451Sroberto			clock_stat.flags = (u_char) (ntohl(cf->fudgeval_flags) & 0xf);
260554359Sroberto			clock_stat.haveflags =
260654359Sroberto				(CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4);
260754359Sroberto			break;
260854359Sroberto		    default:
260982498Sroberto			msyslog(LOG_ERR, "set_clock_fudge: default!");
261054359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
261154359Sroberto			return;
261254359Sroberto		}
261354359Sroberto
261454359Sroberto		refclock_control(&addr, &clock_stat, (struct refclockstat *)0);
261554359Sroberto	}
261654359Sroberto
261754359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
261854359Sroberto}
261954359Sroberto#endif
262054359Sroberto
262154359Sroberto#ifdef REFCLOCK
262254359Sroberto/*
262354359Sroberto * get_clkbug_info - get debugging info about a clock
262454359Sroberto */
262554359Srobertostatic void
262654359Srobertoget_clkbug_info(
2627285612Sdelphij	sockaddr_u *srcadr,
2628285612Sdelphij	endpt *inter,
262954359Sroberto	struct req_pkt *inpkt
263054359Sroberto	)
263154359Sroberto{
263254359Sroberto	register int i;
263354359Sroberto	register struct info_clkbug *ic;
263454359Sroberto	register u_int32 *clkaddr;
263554359Sroberto	register int items;
263654359Sroberto	struct refclockbug bug;
2637285612Sdelphij	sockaddr_u addr;
263854359Sroberto
2639285612Sdelphij	ZERO_SOCK(&addr);
2640285612Sdelphij	AF(&addr) = AF_INET;
2641285612Sdelphij#ifdef ISC_PLATFORM_HAVESALEN
2642285612Sdelphij	addr.sa.sa_len = SOCKLEN(&addr);
2643132451Sroberto#endif
2644285612Sdelphij	SET_PORT(&addr, NTP_PORT);
264554359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
2646285612Sdelphij	clkaddr = (u_int32 *)&inpkt->u;
264754359Sroberto
264854359Sroberto	ic = (struct info_clkbug *)prepare_pkt(srcadr, inter, inpkt,
264954359Sroberto					       sizeof(struct info_clkbug));
265054359Sroberto
2651294569Sdelphij	while (items-- > 0 && ic) {
2652285612Sdelphij		NSRCADR(&addr) = *clkaddr++;
2653285612Sdelphij		if (!ISREFCLOCKADR(&addr) || NULL ==
2654330141Sdelphij		    findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) {
265554359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
265654359Sroberto			return;
265754359Sroberto		}
265854359Sroberto
2659285612Sdelphij		ZERO(bug);
266054359Sroberto		refclock_buginfo(&addr, &bug);
266154359Sroberto		if (bug.nvalues == 0 && bug.ntimes == 0) {
266254359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
266354359Sroberto			return;
266454359Sroberto		}
266554359Sroberto
2666285612Sdelphij		ic->clockadr = NSRCADR(&addr);
266754359Sroberto		i = bug.nvalues;
266854359Sroberto		if (i > NUMCBUGVALUES)
266954359Sroberto		    i = NUMCBUGVALUES;
267054359Sroberto		ic->nvalues = (u_char)i;
267154359Sroberto		ic->svalues = htons((u_short) (bug.svalues & ((1<<i)-1)));
267254359Sroberto		while (--i >= 0)
267354359Sroberto		    ic->values[i] = htonl(bug.values[i]);
267454359Sroberto
267554359Sroberto		i = bug.ntimes;
267654359Sroberto		if (i > NUMCBUGTIMES)
267754359Sroberto		    i = NUMCBUGTIMES;
267854359Sroberto		ic->ntimes = (u_char)i;
267954359Sroberto		ic->stimes = htonl(bug.stimes);
268054359Sroberto		while (--i >= 0) {
268154359Sroberto			HTONL_FP(&bug.times[i], &ic->times[i]);
268254359Sroberto		}
268354359Sroberto
268454359Sroberto		ic = (struct info_clkbug *)more_pkt();
268554359Sroberto	}
268654359Sroberto	flush_pkt();
268754359Sroberto}
268854359Sroberto#endif
2689182007Sroberto
2690182007Sroberto/*
2691182007Sroberto * receiver of interface structures
2692182007Sroberto */
2693182007Srobertostatic void
2694182007Srobertofill_info_if_stats(void *data, interface_info_t *interface_info)
2695182007Sroberto{
2696182007Sroberto	struct info_if_stats **ifsp = (struct info_if_stats **)data;
2697182007Sroberto	struct info_if_stats *ifs = *ifsp;
2698285612Sdelphij	endpt *ep = interface_info->ep;
2699294569Sdelphij
2700294569Sdelphij	if (NULL == ifs)
2701294569Sdelphij		return;
2702182007Sroberto
2703285612Sdelphij	ZERO(*ifs);
2704182007Sroberto
2705285612Sdelphij	if (IS_IPV6(&ep->sin)) {
2706294569Sdelphij		if (!client_v6_capable)
2707182007Sroberto			return;
2708182007Sroberto		ifs->v6_flag = 1;
2709285612Sdelphij		ifs->unaddr.addr6 = SOCK_ADDR6(&ep->sin);
2710285612Sdelphij		ifs->unbcast.addr6 = SOCK_ADDR6(&ep->bcast);
2711285612Sdelphij		ifs->unmask.addr6 = SOCK_ADDR6(&ep->mask);
2712182007Sroberto	} else {
2713182007Sroberto		ifs->v6_flag = 0;
2714285612Sdelphij		ifs->unaddr.addr = SOCK_ADDR4(&ep->sin);
2715285612Sdelphij		ifs->unbcast.addr = SOCK_ADDR4(&ep->bcast);
2716285612Sdelphij		ifs->unmask.addr = SOCK_ADDR4(&ep->mask);
2717182007Sroberto	}
2718182007Sroberto	ifs->v6_flag = htonl(ifs->v6_flag);
2719285612Sdelphij	strlcpy(ifs->name, ep->name, sizeof(ifs->name));
2720285612Sdelphij	ifs->family = htons(ep->family);
2721285612Sdelphij	ifs->flags = htonl(ep->flags);
2722285612Sdelphij	ifs->last_ttl = htonl(ep->last_ttl);
2723285612Sdelphij	ifs->num_mcast = htonl(ep->num_mcast);
2724285612Sdelphij	ifs->received = htonl(ep->received);
2725285612Sdelphij	ifs->sent = htonl(ep->sent);
2726285612Sdelphij	ifs->notsent = htonl(ep->notsent);
2727285612Sdelphij	ifs->ifindex = htonl(ep->ifindex);
2728285612Sdelphij	/* scope no longer in endpt, in in6_addr typically */
2729285612Sdelphij	ifs->scopeid = ifs->ifindex;
2730285612Sdelphij	ifs->ifnum = htonl(ep->ifnum);
2731285612Sdelphij	ifs->uptime = htonl(current_time - ep->starttime);
2732285612Sdelphij	ifs->ignore_packets = ep->ignore_packets;
2733285612Sdelphij	ifs->peercnt = htonl(ep->peercnt);
2734182007Sroberto	ifs->action = interface_info->action;
2735182007Sroberto
2736182007Sroberto	*ifsp = (struct info_if_stats *)more_pkt();
2737182007Sroberto}
2738182007Sroberto
2739182007Sroberto/*
2740182007Sroberto * get_if_stats - get interface statistics
2741182007Sroberto */
2742182007Srobertostatic void
2743182007Srobertoget_if_stats(
2744285612Sdelphij	sockaddr_u *srcadr,
2745285612Sdelphij	endpt *inter,
2746182007Sroberto	struct req_pkt *inpkt
2747182007Sroberto	)
2748182007Sroberto{
2749182007Sroberto	struct info_if_stats *ifs;
2750182007Sroberto
2751182007Sroberto	DPRINTF(3, ("wants interface statistics\n"));
2752182007Sroberto
2753182007Sroberto	ifs = (struct info_if_stats *)prepare_pkt(srcadr, inter, inpkt,
2754182007Sroberto	    v6sizeof(struct info_if_stats));
2755182007Sroberto
2756182007Sroberto	interface_enumerate(fill_info_if_stats, &ifs);
2757182007Sroberto
2758182007Sroberto	flush_pkt();
2759182007Sroberto}
2760182007Sroberto
2761182007Srobertostatic void
2762182007Srobertodo_if_reload(
2763285612Sdelphij	sockaddr_u *srcadr,
2764285612Sdelphij	endpt *inter,
2765182007Sroberto	struct req_pkt *inpkt
2766182007Sroberto	)
2767182007Sroberto{
2768182007Sroberto	struct info_if_stats *ifs;
2769182007Sroberto
2770182007Sroberto	DPRINTF(3, ("wants interface reload\n"));
2771182007Sroberto
2772182007Sroberto	ifs = (struct info_if_stats *)prepare_pkt(srcadr, inter, inpkt,
2773182007Sroberto	    v6sizeof(struct info_if_stats));
2774182007Sroberto
2775182007Sroberto	interface_update(fill_info_if_stats, &ifs);
2776182007Sroberto
2777182007Sroberto	flush_pkt();
2778182007Sroberto}
2779182007Sroberto
2780