ntp_request.c revision 200576
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"
1682498Sroberto
1782498Sroberto#include <stdio.h>
18132451Sroberto#include <stddef.h>
1982498Sroberto#include <signal.h>
2082498Sroberto#include <netinet/in.h>
2182498Sroberto#include <arpa/inet.h>
2282498Sroberto
2354359Sroberto#include "recvbuff.h"
2454359Sroberto
2554359Sroberto#ifdef KERNEL_PLL
2654359Sroberto#include "ntp_syscall.h"
2754359Sroberto#endif /* KERNEL_PLL */
2854359Sroberto
2954359Sroberto/*
3054359Sroberto * Structure to hold request procedure information
3154359Sroberto */
3254359Sroberto#define	NOAUTH	0
3354359Sroberto#define	AUTH	1
3454359Sroberto
3554359Sroberto#define	NO_REQUEST	(-1)
36132451Sroberto/*
37132451Sroberto * Because we now have v6 addresses in the messages, we need to compensate
38132451Sroberto * for the larger size.  Therefore, we introduce the alternate size to
39132451Sroberto * keep us friendly with older implementations.  A little ugly.
40132451Sroberto */
41132451Srobertostatic int client_v6_capable = 0;   /* the client can handle longer messages */
4254359Sroberto
43132451Sroberto#define v6sizeof(type)	(client_v6_capable ? sizeof(type) : v4sizeof(type))
44132451Sroberto
4554359Srobertostruct req_proc {
4654359Sroberto	short request_code;	/* defined request code */
4754359Sroberto	short needs_auth;	/* true when authentication needed */
48132451Sroberto	short sizeofitem;	/* size of request data item (older size)*/
49132451Sroberto	short v6_sizeofitem;	/* size of request data item (new size)*/
50132451Sroberto	void (*handler) P((struct sockaddr_storage *, struct interface *,
5154359Sroberto			   struct req_pkt *));	/* routine to handle request */
5254359Sroberto};
5354359Sroberto
5454359Sroberto/*
5554359Sroberto * Universal request codes
5654359Sroberto */
5754359Srobertostatic	struct req_proc univ_codes[] = {
5854359Sroberto	{ NO_REQUEST,		NOAUTH,	 0,	0 }
5954359Sroberto};
6054359Sroberto
61132451Srobertostatic	void	req_ack	P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int));
62132451Srobertostatic	char *	prepare_pkt	P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_int));
6354359Srobertostatic	char *	more_pkt	P((void));
6454359Srobertostatic	void	flush_pkt	P((void));
65132451Srobertostatic	void	peer_list	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
66132451Srobertostatic	void	peer_list_sum	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
67132451Srobertostatic	void	peer_info	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
68132451Srobertostatic	void	peer_stats	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
69132451Srobertostatic	void	sys_info	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
70132451Srobertostatic	void	sys_stats	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
71132451Srobertostatic	void	mem_stats	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
72132451Srobertostatic	void	io_stats	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
73132451Srobertostatic	void	timer_stats	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
74132451Srobertostatic	void	loop_info	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
75132451Srobertostatic	void	do_conf		P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
76132451Srobertostatic	void	do_unconf	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
77132451Srobertostatic	void	set_sys_flag	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
78132451Srobertostatic	void	clr_sys_flag	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
79132451Srobertostatic	void	setclr_flags	P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_long));
80132451Srobertostatic	void	list_restrict	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
81132451Srobertostatic	void	do_resaddflags	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
82132451Srobertostatic	void	do_ressubflags	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
83132451Srobertostatic	void	do_unrestrict	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
84132451Srobertostatic	void	do_restrict	P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int));
85132451Srobertostatic	void	mon_getlist_0	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
86132451Srobertostatic	void	mon_getlist_1	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
87132451Srobertostatic	void	reset_stats	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
88132451Srobertostatic	void	reset_peer	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
89132451Srobertostatic	void	do_key_reread	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
90132451Srobertostatic	void	trust_key	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
91132451Srobertostatic	void	untrust_key	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
92132451Srobertostatic	void	do_trustkey	P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_long));
93132451Srobertostatic	void	get_auth_info	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
9454359Srobertostatic	void	reset_auth_stats P((void));
95132451Srobertostatic	void	req_get_traps	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
96132451Srobertostatic	void	req_set_trap	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
97132451Srobertostatic	void	req_clr_trap	P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
98132451Srobertostatic	void	do_setclr_trap	P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int));
99132451Srobertostatic	void	set_request_keyid P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
100132451Srobertostatic	void	set_control_keyid P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
101182007Srobertostatic	void	get_ctl_stats   P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
102182007Srobertostatic	void	get_if_stats    P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
103182007Srobertostatic	void	do_if_reload    P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
10454359Sroberto#ifdef KERNEL_PLL
105132451Srobertostatic	void	get_kernel_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
10654359Sroberto#endif /* KERNEL_PLL */
10754359Sroberto#ifdef REFCLOCK
108132451Srobertostatic	void	get_clock_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
109132451Srobertostatic	void	set_clock_fudge P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
11054359Sroberto#endif	/* REFCLOCK */
11154359Sroberto#ifdef REFCLOCK
112132451Srobertostatic	void	get_clkbug_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));
11354359Sroberto#endif	/* REFCLOCK */
11454359Sroberto
11554359Sroberto/*
11654359Sroberto * ntpd request codes
11754359Sroberto */
11854359Srobertostatic	struct req_proc ntp_codes[] = {
119132451Sroberto	{ REQ_PEER_LIST,	NOAUTH,	0, 0,	peer_list },
120132451Sroberto	{ REQ_PEER_LIST_SUM,	NOAUTH,	0, 0,	peer_list_sum },
121132451Sroberto	{ REQ_PEER_INFO,    NOAUTH, v4sizeof(struct info_peer_list),
122132451Sroberto				sizeof(struct info_peer_list), peer_info},
123132451Sroberto	{ REQ_PEER_STATS,   NOAUTH, v4sizeof(struct info_peer_list),
124132451Sroberto				sizeof(struct info_peer_list), peer_stats},
125132451Sroberto	{ REQ_SYS_INFO,		NOAUTH,	0, 0,	sys_info },
126132451Sroberto	{ REQ_SYS_STATS,	NOAUTH,	0, 0,	sys_stats },
127132451Sroberto	{ REQ_IO_STATS,		NOAUTH,	0, 0,	io_stats },
128132451Sroberto	{ REQ_MEM_STATS,	NOAUTH,	0, 0,	mem_stats },
129132451Sroberto	{ REQ_LOOP_INFO,	NOAUTH,	0, 0,	loop_info },
130132451Sroberto	{ REQ_TIMER_STATS,	NOAUTH,	0, 0,	timer_stats },
131132451Sroberto	{ REQ_CONFIG,	    AUTH, v4sizeof(struct conf_peer),
132132451Sroberto				sizeof(struct conf_peer), do_conf },
133132451Sroberto	{ REQ_UNCONFIG,	    AUTH, v4sizeof(struct conf_unpeer),
134132451Sroberto				sizeof(struct conf_unpeer), do_unconf },
135132451Sroberto	{ REQ_SET_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags),
136132451Sroberto				sizeof(struct conf_sys_flags), set_sys_flag },
137132451Sroberto	{ REQ_CLR_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags),
138132451Sroberto				sizeof(struct conf_sys_flags),  clr_sys_flag },
139132451Sroberto	{ REQ_GET_RESTRICT,	NOAUTH,	0, 0,	list_restrict },
140132451Sroberto	{ REQ_RESADDFLAGS, AUTH, v4sizeof(struct conf_restrict),
141132451Sroberto				sizeof(struct conf_restrict), do_resaddflags },
142132451Sroberto	{ REQ_RESSUBFLAGS, AUTH, v4sizeof(struct conf_restrict),
143132451Sroberto				sizeof(struct conf_restrict), do_ressubflags },
144132451Sroberto	{ REQ_UNRESTRICT, AUTH, v4sizeof(struct conf_restrict),
145132451Sroberto				sizeof(struct conf_restrict), do_unrestrict },
146132451Sroberto	{ REQ_MON_GETLIST,	NOAUTH,	0, 0,	mon_getlist_0 },
147132451Sroberto	{ REQ_MON_GETLIST_1,	NOAUTH,	0, 0,	mon_getlist_1 },
148132451Sroberto	{ REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), 0, reset_stats },
149132451Sroberto	{ REQ_RESET_PEER,  AUTH, v4sizeof(struct conf_unpeer),
150132451Sroberto				sizeof(struct conf_unpeer), reset_peer },
151132451Sroberto	{ REQ_REREAD_KEYS,	AUTH,	0, 0,	do_key_reread },
152132451Sroberto	{ REQ_TRUSTKEY,   AUTH, sizeof(u_long), sizeof(u_long), trust_key },
153132451Sroberto	{ REQ_UNTRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), untrust_key },
154132451Sroberto	{ REQ_AUTHINFO,		NOAUTH,	0, 0,	get_auth_info },
155132451Sroberto	{ REQ_TRAPS,		NOAUTH, 0, 0,	req_get_traps },
156132451Sroberto	{ REQ_ADD_TRAP,	AUTH, v4sizeof(struct conf_trap),
157132451Sroberto				sizeof(struct conf_trap), req_set_trap },
158132451Sroberto	{ REQ_CLR_TRAP,	AUTH, v4sizeof(struct conf_trap),
159132451Sroberto				sizeof(struct conf_trap), req_clr_trap },
160132451Sroberto	{ REQ_REQUEST_KEY, AUTH, sizeof(u_long), sizeof(u_long),
161132451Sroberto				set_request_keyid },
162132451Sroberto	{ REQ_CONTROL_KEY, AUTH, sizeof(u_long), sizeof(u_long),
163132451Sroberto				set_control_keyid },
164132451Sroberto	{ REQ_GET_CTLSTATS,	NOAUTH,	0, 0,	get_ctl_stats },
16554359Sroberto#ifdef KERNEL_PLL
166132451Sroberto	{ REQ_GET_KERNEL,	NOAUTH,	0, 0,	get_kernel_info },
16754359Sroberto#endif
16854359Sroberto#ifdef REFCLOCK
169132451Sroberto	{ REQ_GET_CLOCKINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32),
170132451Sroberto				get_clock_info },
171132451Sroberto	{ REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge),
172132451Sroberto				sizeof(struct conf_fudge), set_clock_fudge },
173132451Sroberto	{ REQ_GET_CLKBUGINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32),
174132451Sroberto				get_clkbug_info },
17554359Sroberto#endif
176182007Sroberto	{ REQ_IF_STATS,		AUTH, 0, 0,	get_if_stats },
177182007Sroberto	{ REQ_IF_RELOAD,        AUTH, 0, 0,	do_if_reload },
178182007Sroberto
179132451Sroberto	{ NO_REQUEST,		NOAUTH,	0, 0,	0 }
18054359Sroberto};
18154359Sroberto
18254359Sroberto
18354359Sroberto/*
18454359Sroberto * Authentication keyid used to authenticate requests.  Zero means we
18554359Sroberto * don't allow writing anything.
18654359Sroberto */
18782498Srobertokeyid_t info_auth_keyid;
18854359Sroberto
18954359Sroberto/*
19054359Sroberto * Statistic counters to keep track of requests and responses.
19154359Sroberto */
19254359Srobertou_long numrequests;		/* number of requests we've received */
19354359Srobertou_long numresppkts;		/* number of resp packets sent with data */
19454359Sroberto
19554359Srobertou_long errorcounter[INFO_ERR_AUTH+1];	/* lazy way to count errors, indexed */
19654359Sroberto/* by the error code */
19754359Sroberto
19854359Sroberto/*
19954359Sroberto * A hack.  To keep the authentication module clear of ntp-ism's, we
20054359Sroberto * include a time reset variable for its stats here.
20154359Sroberto */
20254359Srobertostatic u_long auth_timereset;
20354359Sroberto
20454359Sroberto/*
20554359Sroberto * Response packet used by these routines.  Also some state information
20654359Sroberto * so that we can handle packet formatting within a common set of
20754359Sroberto * subroutines.  Note we try to enter data in place whenever possible,
20854359Sroberto * but the need to set the more bit correctly means we occasionally
20954359Sroberto * use the extra buffer and copy.
21054359Sroberto */
21154359Srobertostatic struct resp_pkt rpkt;
21254359Srobertostatic int reqver;
21354359Srobertostatic int seqno;
21454359Srobertostatic int nitems;
21554359Srobertostatic int itemsize;
21654359Srobertostatic int databytes;
21754359Srobertostatic char exbuf[RESP_DATA_SIZE];
21854359Srobertostatic int usingexbuf;
219132451Srobertostatic struct sockaddr_storage *toaddr;
22054359Srobertostatic struct interface *frominter;
22154359Sroberto
22254359Sroberto/*
22354359Sroberto * init_request - initialize request data
22454359Sroberto */
22554359Srobertovoid
22654359Srobertoinit_request (void)
22754359Sroberto{
22854359Sroberto	int i;
22954359Sroberto
23054359Sroberto	numrequests = 0;
23154359Sroberto	numresppkts = 0;
23254359Sroberto	auth_timereset = 0;
23354359Sroberto	info_auth_keyid = 0;	/* by default, can't do this */
23454359Sroberto
23554359Sroberto	for (i = 0; i < sizeof(errorcounter)/sizeof(errorcounter[0]); i++)
23654359Sroberto	    errorcounter[i] = 0;
23754359Sroberto}
23854359Sroberto
23954359Sroberto
24054359Sroberto/*
24154359Sroberto * req_ack - acknowledge request with no data
24254359Sroberto */
24354359Srobertostatic void
24454359Srobertoreq_ack(
245132451Sroberto	struct sockaddr_storage *srcadr,
24654359Sroberto	struct interface *inter,
24754359Sroberto	struct req_pkt *inpkt,
24854359Sroberto	int errcode
24954359Sroberto	)
25054359Sroberto{
25154359Sroberto	/*
25254359Sroberto	 * fill in the fields
25354359Sroberto	 */
25454359Sroberto	rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
25554359Sroberto	rpkt.auth_seq = AUTH_SEQ(0, 0);
25654359Sroberto	rpkt.implementation = inpkt->implementation;
25754359Sroberto	rpkt.request = inpkt->request;
25854359Sroberto	rpkt.err_nitems = ERR_NITEMS(errcode, 0);
25954359Sroberto	rpkt.mbz_itemsize = MBZ_ITEMSIZE(0);
26054359Sroberto
26154359Sroberto	/*
26254359Sroberto	 * send packet and bump counters
26354359Sroberto	 */
26454359Sroberto	sendpkt(srcadr, inter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE);
26554359Sroberto	errorcounter[errcode]++;
26654359Sroberto}
26754359Sroberto
26854359Sroberto
26954359Sroberto/*
27054359Sroberto * prepare_pkt - prepare response packet for transmission, return pointer
27154359Sroberto *		 to storage for data item.
27254359Sroberto */
27354359Srobertostatic char *
27454359Srobertoprepare_pkt(
275132451Sroberto	struct sockaddr_storage *srcadr,
27654359Sroberto	struct interface *inter,
27754359Sroberto	struct req_pkt *pkt,
27854359Sroberto	u_int structsize
27954359Sroberto	)
28054359Sroberto{
28154359Sroberto#ifdef DEBUG
28254359Sroberto	if (debug > 3)
28354359Sroberto	    printf("request: preparing pkt\n");
28454359Sroberto#endif
28554359Sroberto
28654359Sroberto	/*
287132451Sroberto	 * Fill in the implementation, request and itemsize fields
28854359Sroberto	 * since these won't change.
28954359Sroberto	 */
29054359Sroberto	rpkt.implementation = pkt->implementation;
29154359Sroberto	rpkt.request = pkt->request;
29254359Sroberto	rpkt.mbz_itemsize = MBZ_ITEMSIZE(structsize);
29354359Sroberto
29454359Sroberto	/*
29554359Sroberto	 * Compute the static data needed to carry on.
29654359Sroberto	 */
29754359Sroberto	toaddr = srcadr;
29854359Sroberto	frominter = inter;
29954359Sroberto	seqno = 0;
30054359Sroberto	nitems = 0;
30154359Sroberto	itemsize = structsize;
30254359Sroberto	databytes = 0;
30354359Sroberto	usingexbuf = 0;
30454359Sroberto
30554359Sroberto	/*
30654359Sroberto	 * return the beginning of the packet buffer.
30754359Sroberto	 */
30854359Sroberto	return &rpkt.data[0];
30954359Sroberto}
31054359Sroberto
31154359Sroberto
31254359Sroberto/*
31354359Sroberto * more_pkt - return a data pointer for a new item.
31454359Sroberto */
31554359Srobertostatic char *
31654359Srobertomore_pkt(void)
31754359Sroberto{
31854359Sroberto	/*
31954359Sroberto	 * If we were using the extra buffer, send the packet.
32054359Sroberto	 */
32154359Sroberto	if (usingexbuf) {
32254359Sroberto#ifdef DEBUG
32354359Sroberto		if (debug > 2)
32454359Sroberto		    printf("request: sending pkt\n");
32554359Sroberto#endif
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,
33054359Sroberto			RESP_HEADER_SIZE+databytes);
33154359Sroberto		numresppkts++;
33254359Sroberto
33354359Sroberto		/*
33454359Sroberto		 * Copy data out of exbuf into the packet.
33554359Sroberto		 */
33654359Sroberto		memmove(&rpkt.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) {
34654359Sroberto#ifdef DEBUG
34754359Sroberto		if (debug > 3)
34854359Sroberto		    printf("request: giving him more data\n");
34954359Sroberto#endif
35054359Sroberto		/*
35154359Sroberto		 * More room in packet.  Give him the
35254359Sroberto		 * next address.
35354359Sroberto		 */
35454359Sroberto		return &rpkt.data[databytes];
35554359Sroberto	} else {
35654359Sroberto		/*
35754359Sroberto		 * No room in packet.  Give him the extra
35854359Sroberto		 * buffer unless this was the last in the sequence.
35954359Sroberto		 */
36054359Sroberto#ifdef DEBUG
36154359Sroberto		if (debug > 3)
36254359Sroberto		    printf("request: into extra buffer\n");
36354359Sroberto#endif
36454359Sroberto		if (seqno == MAXSEQ)
36554359Sroberto		    return (char *)0;
36654359Sroberto		else {
36754359Sroberto			usingexbuf = 1;
36854359Sroberto			return exbuf;
36954359Sroberto		}
37054359Sroberto	}
37154359Sroberto}
37254359Sroberto
37354359Sroberto
37454359Sroberto/*
37554359Sroberto * flush_pkt - we're done, return remaining information.
37654359Sroberto */
37754359Srobertostatic void
37854359Srobertoflush_pkt(void)
37954359Sroberto{
38054359Sroberto#ifdef DEBUG
38154359Sroberto	if (debug > 2)
38254359Sroberto	    printf("request: flushing packet, %d items\n", nitems);
38354359Sroberto#endif
38454359Sroberto	/*
38554359Sroberto	 * Must send the last packet.  If nothing in here and nothing
38654359Sroberto	 * has been sent, send an error saying no data to be found.
38754359Sroberto	 */
38854359Sroberto	if (seqno == 0 && nitems == 0)
38954359Sroberto	    req_ack(toaddr, frominter, (struct req_pkt *)&rpkt,
39054359Sroberto		    INFO_ERR_NODATA);
39154359Sroberto	else {
39254359Sroberto		rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
39354359Sroberto		rpkt.auth_seq = AUTH_SEQ(0, seqno);
39454359Sroberto		rpkt.err_nitems = htons((u_short)nitems);
39554359Sroberto		sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
39654359Sroberto			RESP_HEADER_SIZE+databytes);
39754359Sroberto		numresppkts++;
39854359Sroberto	}
39954359Sroberto}
40054359Sroberto
40154359Sroberto
40254359Sroberto
40354359Sroberto/*
40454359Sroberto * process_private - process private mode (7) packets
40554359Sroberto */
40654359Srobertovoid
40754359Srobertoprocess_private(
40854359Sroberto	struct recvbuf *rbufp,
40954359Sroberto	int mod_okay
41054359Sroberto	)
41154359Sroberto{
412200576Sroberto	static u_long quiet_until;
41354359Sroberto	struct req_pkt *inpkt;
414106163Sroberto	struct req_pkt_tail *tailinpkt;
415132451Sroberto	struct sockaddr_storage *srcadr;
41654359Sroberto	struct interface *inter;
41754359Sroberto	struct req_proc *proc;
41882498Sroberto	int ec;
419132451Sroberto	short temp_size;
42054359Sroberto
42154359Sroberto	/*
42254359Sroberto	 * Initialize pointers, for convenience
42354359Sroberto	 */
42454359Sroberto	inpkt = (struct req_pkt *)&rbufp->recv_pkt;
42554359Sroberto	srcadr = &rbufp->recv_srcadr;
42654359Sroberto	inter = rbufp->dstadr;
42754359Sroberto
42854359Sroberto#ifdef DEBUG
42954359Sroberto	if (debug > 2)
43082498Sroberto	    printf("process_private: impl %d req %d\n",
43154359Sroberto		   inpkt->implementation, inpkt->request);
43254359Sroberto#endif
43354359Sroberto
43454359Sroberto	/*
43554359Sroberto	 * Do some sanity checks on the packet.  Return a format
43654359Sroberto	 * error if it fails.
43754359Sroberto	 */
43882498Sroberto	ec = 0;
43982498Sroberto	if (   (++ec, ISRESPONSE(inpkt->rm_vn_mode))
44082498Sroberto	    || (++ec, ISMORE(inpkt->rm_vn_mode))
44182498Sroberto	    || (++ec, INFO_VERSION(inpkt->rm_vn_mode) > NTP_VERSION)
44282498Sroberto	    || (++ec, INFO_VERSION(inpkt->rm_vn_mode) < NTP_OLDVERSION)
44382498Sroberto	    || (++ec, INFO_SEQ(inpkt->auth_seq) != 0)
44482498Sroberto	    || (++ec, INFO_ERR(inpkt->err_nitems) != 0)
44582498Sroberto	    || (++ec, INFO_MBZ(inpkt->mbz_itemsize) != 0)
446106163Sroberto	    || (++ec, rbufp->recv_length < REQ_LEN_HDR)
44782498Sroberto		) {
448200576Sroberto		NLOG(NLOG_SYSEVENT)
449200576Sroberto			if (current_time >= quiet_until) {
450200576Sroberto				msyslog(LOG_ERR,
451200576Sroberto					"process_private: drop test %d"
452200576Sroberto					" failed, pkt from %s",
453200576Sroberto					ec, stoa(srcadr));
454200576Sroberto				quiet_until = current_time + 60;
455200576Sroberto			}
45654359Sroberto		return;
45754359Sroberto	}
45854359Sroberto
45954359Sroberto	reqver = INFO_VERSION(inpkt->rm_vn_mode);
46054359Sroberto
46154359Sroberto	/*
46254359Sroberto	 * Get the appropriate procedure list to search.
46354359Sroberto	 */
46454359Sroberto	if (inpkt->implementation == IMPL_UNIV)
46554359Sroberto	    proc = univ_codes;
466132451Sroberto	else if ((inpkt->implementation == IMPL_XNTPD) ||
467132451Sroberto		 (inpkt->implementation == IMPL_XNTPD_OLD))
46854359Sroberto	    proc = ntp_codes;
46954359Sroberto	else {
47054359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL);
47154359Sroberto		return;
47254359Sroberto	}
47354359Sroberto
47454359Sroberto	/*
47554359Sroberto	 * Search the list for the request codes.  If it isn't one
47654359Sroberto	 * we know, return an error.
47754359Sroberto	 */
47854359Sroberto	while (proc->request_code != NO_REQUEST) {
47954359Sroberto		if (proc->request_code == (short) inpkt->request)
48054359Sroberto		    break;
48154359Sroberto		proc++;
48254359Sroberto	}
48354359Sroberto	if (proc->request_code == NO_REQUEST) {
48454359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_REQ);
48554359Sroberto		return;
48654359Sroberto	}
48754359Sroberto
48854359Sroberto#ifdef DEBUG
48954359Sroberto	if (debug > 3)
49054359Sroberto	    printf("found request in tables\n");
49154359Sroberto#endif
49254359Sroberto
49354359Sroberto	/*
494132451Sroberto	 * If we need data, check to see if we have some.  If we
495132451Sroberto	 * don't, check to see that there is none (picky, picky).
496132451Sroberto	 */
497132451Sroberto
498132451Sroberto	/* This part is a bit tricky, we want to be sure that the size
499132451Sroberto	 * returned is either the old or the new size.  We also can find
500132451Sroberto	 * out if the client can accept both types of messages this way.
501132451Sroberto	 *
502132451Sroberto	 * Handle the exception of REQ_CONFIG. It can have two data sizes.
503132451Sroberto	 */
504132451Sroberto	temp_size = INFO_ITEMSIZE(inpkt->mbz_itemsize);
505132451Sroberto	if ((temp_size != proc->sizeofitem &&
506200576Sroberto	     temp_size != proc->v6_sizeofitem) &&
507132451Sroberto	    !(inpkt->implementation == IMPL_XNTPD &&
508200576Sroberto	      inpkt->request == REQ_CONFIG &&
509200576Sroberto	      temp_size == sizeof(struct old_conf_peer))) {
510182007Sroberto#ifdef DEBUG
511132451Sroberto		if (debug > 2)
512132451Sroberto			printf("process_private: wrong item size, received %d, should be %d or %d\n",
513132451Sroberto			    temp_size, proc->sizeofitem, proc->v6_sizeofitem);
514182007Sroberto#endif
515132451Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
516132451Sroberto		return;
517132451Sroberto	}
518132451Sroberto	if ((proc->sizeofitem != 0) &&
519132451Sroberto	    ((temp_size * INFO_NITEMS(inpkt->err_nitems)) >
520132451Sroberto	    (rbufp->recv_length - REQ_LEN_HDR))) {
521182007Sroberto#ifdef DEBUG
522132451Sroberto		if (debug > 2)
523132451Sroberto			printf("process_private: not enough data\n");
524182007Sroberto#endif
525132451Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
526132451Sroberto		return;
527132451Sroberto	}
528132451Sroberto
529132451Sroberto	switch (inpkt->implementation) {
530132451Sroberto	case IMPL_XNTPD:
531132451Sroberto		client_v6_capable = 1;
532132451Sroberto		break;
533132451Sroberto	case IMPL_XNTPD_OLD:
534132451Sroberto		client_v6_capable = 0;
535132451Sroberto		break;
536132451Sroberto	default:
537132451Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
538132451Sroberto		return;
539132451Sroberto	}
540132451Sroberto
541132451Sroberto	/*
54254359Sroberto	 * If we need to authenticate, do so.  Note that an
54354359Sroberto	 * authenticatable packet must include a mac field, must
54454359Sroberto	 * have used key info_auth_keyid and must have included
54554359Sroberto	 * a time stamp in the appropriate field.  The time stamp
54654359Sroberto	 * must be within INFO_TS_MAXSKEW of the receive
54754359Sroberto	 * time stamp.
54854359Sroberto	 */
54954359Sroberto	if (proc->needs_auth && sys_authenticate) {
55054359Sroberto		l_fp ftmp;
55154359Sroberto		double dtemp;
55254359Sroberto
553132451Sroberto		if (rbufp->recv_length < (int)((REQ_LEN_HDR +
554106163Sroberto		    (INFO_ITEMSIZE(inpkt->mbz_itemsize) *
555106163Sroberto		    INFO_NITEMS(inpkt->err_nitems))
556132451Sroberto		    + sizeof(struct req_pkt_tail)))) {
557106163Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
558106163Sroberto		}
559106163Sroberto		tailinpkt = (struct req_pkt_tail *)((char *)&rbufp->recv_pkt +
560106163Sroberto		    rbufp->recv_length - sizeof(struct req_pkt_tail));
561106163Sroberto
56254359Sroberto		/*
56354359Sroberto		 * If this guy is restricted from doing this, don't let him
56454359Sroberto		 * If wrong key was used, or packet doesn't have mac, return.
56554359Sroberto		 */
56654359Sroberto		if (!INFO_IS_AUTH(inpkt->auth_seq) || info_auth_keyid == 0
567106163Sroberto		    || ntohl(tailinpkt->keyid) != info_auth_keyid) {
56854359Sroberto#ifdef DEBUG
56954359Sroberto			if (debug > 4)
57054359Sroberto			    printf("failed auth %d info_auth_keyid %lu pkt keyid %lu\n",
571132451Sroberto				   INFO_IS_AUTH(inpkt->auth_seq),
572132451Sroberto				   (u_long)info_auth_keyid,
573132451Sroberto				   (u_long)ntohl(tailinpkt->keyid));
574132451Sroberto			msyslog(LOG_DEBUG,
575132451Sroberto				"process_private: failed auth %d info_auth_keyid %lu pkt keyid %lu\n",
576132451Sroberto				INFO_IS_AUTH(inpkt->auth_seq),
577132451Sroberto				(u_long)info_auth_keyid,
578132451Sroberto				(u_long)ntohl(tailinpkt->keyid));
57954359Sroberto#endif
58054359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
58154359Sroberto			return;
58254359Sroberto		}
58354359Sroberto		if (rbufp->recv_length > REQ_LEN_MAC) {
58454359Sroberto#ifdef DEBUG
58554359Sroberto			if (debug > 4)
58654359Sroberto			    printf("bad pkt length %d\n",
58754359Sroberto				   rbufp->recv_length);
58854359Sroberto#endif
589132451Sroberto			msyslog(LOG_ERR, "process_private: bad pkt length %d",
590132451Sroberto				rbufp->recv_length);
59154359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
59254359Sroberto			return;
59354359Sroberto		}
59454359Sroberto		if (!mod_okay || !authhavekey(info_auth_keyid)) {
59554359Sroberto#ifdef DEBUG
59654359Sroberto			if (debug > 4)
59754359Sroberto			    printf("failed auth mod_okay %d\n", mod_okay);
598132451Sroberto			msyslog(LOG_DEBUG,
599132451Sroberto				"process_private: failed auth mod_okay %d\n",
600132451Sroberto				mod_okay);
60154359Sroberto#endif
60254359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
60354359Sroberto			return;
60454359Sroberto		}
60554359Sroberto
60654359Sroberto		/*
60754359Sroberto		 * calculate absolute time difference between xmit time stamp
60854359Sroberto		 * and receive time stamp.  If too large, too bad.
60954359Sroberto		 */
610106163Sroberto		NTOHL_FP(&tailinpkt->tstamp, &ftmp);
61154359Sroberto		L_SUB(&ftmp, &rbufp->recv_time);
61254359Sroberto		LFPTOD(&ftmp, dtemp);
61354359Sroberto		if (fabs(dtemp) >= INFO_TS_MAXSKEW) {
61454359Sroberto			/*
61554359Sroberto			 * He's a loser.  Tell him.
61654359Sroberto			 */
617132451Sroberto#ifdef DEBUG
618132451Sroberto			if (debug > 4)
619132451Sroberto			    printf("xmit/rcv timestamp delta > INFO_TS_MAXSKEW\n");
620132451Sroberto#endif
62154359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
62254359Sroberto			return;
62354359Sroberto		}
62454359Sroberto
62554359Sroberto		/*
62654359Sroberto		 * So far so good.  See if decryption works out okay.
62754359Sroberto		 */
62854359Sroberto		if (!authdecrypt(info_auth_keyid, (u_int32 *)inpkt,
629106163Sroberto		    rbufp->recv_length - sizeof(struct req_pkt_tail) +
630106163Sroberto		    REQ_LEN_HDR, sizeof(struct req_pkt_tail) - REQ_LEN_HDR)) {
631132451Sroberto#ifdef DEBUG
632132451Sroberto			if (debug > 4)
633132451Sroberto			    printf("authdecrypt failed\n");
634132451Sroberto#endif
63554359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
63654359Sroberto			return;
63754359Sroberto		}
63854359Sroberto	}
63954359Sroberto
64054359Sroberto#ifdef DEBUG
64154359Sroberto	if (debug > 3)
64254359Sroberto	    printf("process_private: all okay, into handler\n");
64354359Sroberto#endif
64454359Sroberto
64554359Sroberto	/*
64654359Sroberto	 * Packet is okay.  Call the handler to send him data.
64754359Sroberto	 */
64854359Sroberto	(proc->handler)(srcadr, inter, inpkt);
64954359Sroberto}
65054359Sroberto
65154359Sroberto
65254359Sroberto/*
65354359Sroberto * peer_list - send a list of the peers
65454359Sroberto */
65554359Srobertostatic void
65654359Srobertopeer_list(
657132451Sroberto	struct sockaddr_storage *srcadr,
65854359Sroberto	struct interface *inter,
65954359Sroberto	struct req_pkt *inpkt
66054359Sroberto	)
66154359Sroberto{
66254359Sroberto	register struct info_peer_list *ip;
66354359Sroberto	register struct peer *pp;
66454359Sroberto	register int i;
665132451Sroberto	register int skip = 0;
66654359Sroberto
66754359Sroberto	ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt,
668132451Sroberto	    v6sizeof(struct info_peer_list));
669182007Sroberto	for (i = 0; i < NTP_HASH_SIZE && ip != 0; i++) {
67054359Sroberto		pp = peer_hash[i];
67154359Sroberto		while (pp != 0 && ip != 0) {
672132451Sroberto			if (pp->srcadr.ss_family == AF_INET6) {
673132451Sroberto				if (client_v6_capable) {
674132451Sroberto					ip->addr6 = GET_INADDR6(pp->srcadr);
675132451Sroberto					ip->v6_flag = 1;
676132451Sroberto					skip = 0;
677132451Sroberto				} else {
678132451Sroberto					skip = 1;
679132451Sroberto					break;
680132451Sroberto				}
681132451Sroberto			} else {
682132451Sroberto				ip->addr = GET_INADDR(pp->srcadr);
683132451Sroberto				if (client_v6_capable)
684132451Sroberto					ip->v6_flag = 0;
685132451Sroberto				skip = 0;
686132451Sroberto			}
687132451Sroberto
688132451Sroberto			if(!skip) {
689132451Sroberto				ip->port = NSRCPORT(&pp->srcadr);
690132451Sroberto				ip->hmode = pp->hmode;
691132451Sroberto				ip->flags = 0;
692132451Sroberto				if (pp->flags & FLAG_CONFIG)
693132451Sroberto				    ip->flags |= INFO_FLAG_CONFIG;
694132451Sroberto				if (pp == sys_peer)
695132451Sroberto				    ip->flags |= INFO_FLAG_SYSPEER;
696132451Sroberto				if (pp->status == CTL_PST_SEL_SYNCCAND)
697132451Sroberto				    ip->flags |= INFO_FLAG_SEL_CANDIDATE;
698132451Sroberto				if (pp->status >= CTL_PST_SEL_SYSPEER)
699132451Sroberto				    ip->flags |= INFO_FLAG_SHORTLIST;
700132451Sroberto				ip = (struct info_peer_list *)more_pkt();
701132451Sroberto			}
702132451Sroberto			pp = pp->next;
70354359Sroberto		}
70454359Sroberto	}
70554359Sroberto	flush_pkt();
70654359Sroberto}
70754359Sroberto
70854359Sroberto
70954359Sroberto/*
71054359Sroberto * peer_list_sum - return extended peer list
71154359Sroberto */
71254359Srobertostatic void
71354359Srobertopeer_list_sum(
714132451Sroberto	struct sockaddr_storage *srcadr,
71554359Sroberto	struct interface *inter,
71654359Sroberto	struct req_pkt *inpkt
71754359Sroberto	)
71854359Sroberto{
71954359Sroberto	register struct info_peer_summary *ips;
72054359Sroberto	register struct peer *pp;
72154359Sroberto	register int i;
72254359Sroberto	l_fp ltmp;
723132451Sroberto	register int skip;
72454359Sroberto
72554359Sroberto#ifdef DEBUG
72654359Sroberto	if (debug > 2)
72754359Sroberto	    printf("wants peer list summary\n");
72854359Sroberto#endif
72954359Sroberto	ips = (struct info_peer_summary *)prepare_pkt(srcadr, inter, inpkt,
730132451Sroberto	    v6sizeof(struct info_peer_summary));
731182007Sroberto	for (i = 0; i < NTP_HASH_SIZE && ips != 0; i++) {
73254359Sroberto		pp = peer_hash[i];
73354359Sroberto		while (pp != 0 && ips != 0) {
73454359Sroberto#ifdef DEBUG
73554359Sroberto			if (debug > 3)
73654359Sroberto			    printf("sum: got one\n");
73754359Sroberto#endif
738132451Sroberto			/*
739132451Sroberto			 * Be careful here not to return v6 peers when we
740132451Sroberto			 * want only v4.
741132451Sroberto			 */
742132451Sroberto			if (pp->srcadr.ss_family == AF_INET6) {
743132451Sroberto				if (client_v6_capable) {
744132451Sroberto					ips->srcadr6 = GET_INADDR6(pp->srcadr);
745132451Sroberto					ips->v6_flag = 1;
746182007Sroberto					if (pp->dstadr)
747182007Sroberto						ips->dstadr6 = GET_INADDR6(pp->dstadr->sin);
748182007Sroberto					else
749182007Sroberto						memset(&ips->dstadr6, 0, sizeof(ips->dstadr6));
750132451Sroberto					skip = 0;
751132451Sroberto				} else {
752132451Sroberto					skip = 1;
753132451Sroberto					break;
754132451Sroberto				}
755132451Sroberto			} else {
756132451Sroberto				ips->srcadr = GET_INADDR(pp->srcadr);
757132451Sroberto				if (client_v6_capable)
758132451Sroberto					ips->v6_flag = 0;
759132451Sroberto/* XXX PDM This code is buggy. Need to replace with a straightforward assignment */
760182007Sroberto
761182007Sroberto				if (pp->dstadr)
762182007Sroberto					ips->dstadr = (pp->processed) ?
763182007Sroberto						pp->cast_flags == MDF_BCAST ?
764182007Sroberto						GET_INADDR(pp->dstadr->bcast):
765182007Sroberto						pp->cast_flags ?
766182007Sroberto						GET_INADDR(pp->dstadr->sin) ?
767182007Sroberto						GET_INADDR(pp->dstadr->sin):
768182007Sroberto						GET_INADDR(pp->dstadr->bcast):
769182007Sroberto						1 : GET_INADDR(pp->dstadr->sin);
770182007Sroberto				else
771182007Sroberto						memset(&ips->dstadr, 0, sizeof(ips->dstadr));
77254359Sroberto
773132451Sroberto				skip = 0;
774132451Sroberto			}
775182007Sroberto
776132451Sroberto			if (!skip){
777132451Sroberto				ips->srcport = NSRCPORT(&pp->srcadr);
778132451Sroberto				ips->stratum = pp->stratum;
779132451Sroberto				ips->hpoll = pp->hpoll;
780132451Sroberto				ips->ppoll = pp->ppoll;
781132451Sroberto				ips->reach = pp->reach;
782132451Sroberto				ips->flags = 0;
783132451Sroberto				if (pp == sys_peer)
784132451Sroberto				    ips->flags |= INFO_FLAG_SYSPEER;
785132451Sroberto				if (pp->flags & FLAG_CONFIG)
786132451Sroberto				    ips->flags |= INFO_FLAG_CONFIG;
787132451Sroberto				if (pp->flags & FLAG_REFCLOCK)
788132451Sroberto				    ips->flags |= INFO_FLAG_REFCLOCK;
789132451Sroberto				if (pp->flags & FLAG_AUTHENABLE)
790132451Sroberto				    ips->flags |= INFO_FLAG_AUTHENABLE;
791132451Sroberto				if (pp->flags & FLAG_PREFER)
792132451Sroberto				    ips->flags |= INFO_FLAG_PREFER;
793132451Sroberto				if (pp->flags & FLAG_BURST)
794132451Sroberto				    ips->flags |= INFO_FLAG_BURST;
795132451Sroberto				if (pp->status == CTL_PST_SEL_SYNCCAND)
796132451Sroberto				    ips->flags |= INFO_FLAG_SEL_CANDIDATE;
797132451Sroberto				if (pp->status >= CTL_PST_SEL_SYSPEER)
798132451Sroberto				    ips->flags |= INFO_FLAG_SHORTLIST;
799132451Sroberto				ips->hmode = pp->hmode;
800132451Sroberto				ips->delay = HTONS_FP(DTOFP(pp->delay));
801132451Sroberto				DTOLFP(pp->offset, &ltmp);
802132451Sroberto				HTONL_FP(&ltmp, &ips->offset);
803182007Sroberto				ips->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
804132451Sroberto			}
805132451Sroberto			pp = pp->next;
80654359Sroberto			ips = (struct info_peer_summary *)more_pkt();
80754359Sroberto		}
80854359Sroberto	}
80954359Sroberto	flush_pkt();
81054359Sroberto}
81154359Sroberto
81254359Sroberto
81354359Sroberto/*
81454359Sroberto * peer_info - send information for one or more peers
81554359Sroberto */
81654359Srobertostatic void
81754359Srobertopeer_info (
818132451Sroberto	struct sockaddr_storage *srcadr,
81954359Sroberto	struct interface *inter,
82054359Sroberto	struct req_pkt *inpkt
82154359Sroberto	)
82254359Sroberto{
82354359Sroberto	register struct info_peer_list *ipl;
82454359Sroberto	register struct peer *pp;
82554359Sroberto	register struct info_peer *ip;
82654359Sroberto	register int items;
82754359Sroberto	register int i, j;
828132451Sroberto	struct sockaddr_storage addr;
82954359Sroberto	extern struct peer *sys_peer;
83054359Sroberto	l_fp ltmp;
83154359Sroberto
83254359Sroberto	memset((char *)&addr, 0, sizeof addr);
83354359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
83454359Sroberto	ipl = (struct info_peer_list *) inpkt->data;
835132451Sroberto
83654359Sroberto	ip = (struct info_peer *)prepare_pkt(srcadr, inter, inpkt,
837132451Sroberto	    v6sizeof(struct info_peer));
83854359Sroberto	while (items-- > 0 && ip != 0) {
839132451Sroberto		memset((char *)&addr, 0, sizeof(addr));
840132451Sroberto		NSRCPORT(&addr) = ipl->port;
841132451Sroberto		if (client_v6_capable && ipl->v6_flag != 0) {
842132451Sroberto			addr.ss_family = AF_INET6;
843132451Sroberto			GET_INADDR6(addr) = ipl->addr6;
844132451Sroberto		} else {
845132451Sroberto			addr.ss_family = AF_INET;
846132451Sroberto			GET_INADDR(addr) = ipl->addr;
847132451Sroberto		}
848132451Sroberto#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
849132451Sroberto		addr.ss_len = SOCKLEN(&addr);
850132451Sroberto#endif
85154359Sroberto		ipl++;
85254359Sroberto		if ((pp = findexistingpeer(&addr, (struct peer *)0, -1)) == 0)
85354359Sroberto		    continue;
854132451Sroberto		if (pp->srcadr.ss_family == AF_INET6) {
855182007Sroberto			if (pp->dstadr)
856182007Sroberto				ip->dstadr6 = pp->cast_flags == MDF_BCAST ?
857182007Sroberto					GET_INADDR6(pp->dstadr->bcast) :
858182007Sroberto					GET_INADDR6(pp->dstadr->sin);
859182007Sroberto			else
860182007Sroberto				memset(&ip->dstadr6, 0, sizeof(ip->dstadr6));
861182007Sroberto
862132451Sroberto			ip->srcadr6 = GET_INADDR6(pp->srcadr);
863132451Sroberto			ip->v6_flag = 1;
864132451Sroberto		} else {
865132451Sroberto/* XXX PDM This code is buggy. Need to replace with a straightforward assignment */
866182007Sroberto			if (pp->dstadr)
867182007Sroberto				ip->dstadr = (pp->processed) ?
868182007Sroberto					pp->cast_flags == MDF_BCAST ?
869182007Sroberto					GET_INADDR(pp->dstadr->bcast):
870182007Sroberto					pp->cast_flags ?
871182007Sroberto					GET_INADDR(pp->dstadr->sin) ?
872182007Sroberto					GET_INADDR(pp->dstadr->sin):
873182007Sroberto					GET_INADDR(pp->dstadr->bcast):
874182007Sroberto					2 : GET_INADDR(pp->dstadr->sin);
875182007Sroberto			else
876182007Sroberto				memset(&ip->dstadr, 0, sizeof(ip->dstadr));
877132451Sroberto
878132451Sroberto			ip->srcadr = GET_INADDR(pp->srcadr);
879132451Sroberto			if (client_v6_capable)
880132451Sroberto				ip->v6_flag = 0;
881132451Sroberto		}
88254359Sroberto		ip->srcport = NSRCPORT(&pp->srcadr);
88354359Sroberto		ip->flags = 0;
88454359Sroberto		if (pp == sys_peer)
88554359Sroberto		    ip->flags |= INFO_FLAG_SYSPEER;
88654359Sroberto		if (pp->flags & FLAG_CONFIG)
88754359Sroberto		    ip->flags |= INFO_FLAG_CONFIG;
88854359Sroberto		if (pp->flags & FLAG_REFCLOCK)
88954359Sroberto		    ip->flags |= INFO_FLAG_REFCLOCK;
89054359Sroberto		if (pp->flags & FLAG_AUTHENABLE)
89154359Sroberto		    ip->flags |= INFO_FLAG_AUTHENABLE;
89254359Sroberto		if (pp->flags & FLAG_PREFER)
89354359Sroberto		    ip->flags |= INFO_FLAG_PREFER;
89454359Sroberto		if (pp->flags & FLAG_BURST)
89554359Sroberto		    ip->flags |= INFO_FLAG_BURST;
89654359Sroberto		if (pp->status == CTL_PST_SEL_SYNCCAND)
89754359Sroberto		    ip->flags |= INFO_FLAG_SEL_CANDIDATE;
89854359Sroberto		if (pp->status >= CTL_PST_SEL_SYSPEER)
89954359Sroberto		    ip->flags |= INFO_FLAG_SHORTLIST;
90054359Sroberto		ip->leap = pp->leap;
90154359Sroberto		ip->hmode = pp->hmode;
90254359Sroberto		ip->keyid = pp->keyid;
90354359Sroberto		ip->stratum = pp->stratum;
90454359Sroberto		ip->ppoll = pp->ppoll;
90554359Sroberto		ip->hpoll = pp->hpoll;
90654359Sroberto		ip->precision = pp->precision;
90754359Sroberto		ip->version = pp->version;
90854359Sroberto		ip->reach = pp->reach;
909132451Sroberto		ip->unreach = (u_char) pp->unreach;
91054359Sroberto		ip->flash = (u_char)pp->flash;
911132451Sroberto		ip->flash2 = (u_short) pp->flash;
91254359Sroberto		ip->estbdelay = HTONS_FP(DTOFP(pp->estbdelay));
91354359Sroberto		ip->ttl = pp->ttl;
91454359Sroberto		ip->associd = htons(pp->associd);
91554359Sroberto		ip->rootdelay = HTONS_FP(DTOUFP(pp->rootdelay));
91654359Sroberto		ip->rootdispersion = HTONS_FP(DTOUFP(pp->rootdispersion));
91754359Sroberto		ip->refid = pp->refid;
91854359Sroberto		HTONL_FP(&pp->reftime, &ip->reftime);
91954359Sroberto		HTONL_FP(&pp->org, &ip->org);
92054359Sroberto		HTONL_FP(&pp->rec, &ip->rec);
92154359Sroberto		HTONL_FP(&pp->xmt, &ip->xmt);
92254359Sroberto		j = pp->filter_nextpt - 1;
92354359Sroberto		for (i = 0; i < NTP_SHIFT; i++, j--) {
92454359Sroberto			if (j < 0)
92554359Sroberto			    j = NTP_SHIFT-1;
92654359Sroberto			ip->filtdelay[i] = HTONS_FP(DTOFP(pp->filter_delay[j]));
92754359Sroberto			DTOLFP(pp->filter_offset[j], &ltmp);
92854359Sroberto			HTONL_FP(&ltmp, &ip->filtoffset[i]);
929132451Sroberto			ip->order[i] = (u_char)((pp->filter_nextpt+NTP_SHIFT-1)
930132451Sroberto				- pp->filter_order[i]);
93154359Sroberto			if (ip->order[i] >= NTP_SHIFT)
93254359Sroberto			    ip->order[i] -= NTP_SHIFT;
93354359Sroberto		}
93454359Sroberto		DTOLFP(pp->offset, &ltmp);
93554359Sroberto		HTONL_FP(&ltmp, &ip->offset);
93654359Sroberto		ip->delay = HTONS_FP(DTOFP(pp->delay));
93754359Sroberto		ip->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp)));
93882498Sroberto		ip->selectdisp = HTONS_FP(DTOUFP(SQRT(pp->jitter)));
93954359Sroberto		ip = (struct info_peer *)more_pkt();
94054359Sroberto	}
94154359Sroberto	flush_pkt();
94254359Sroberto}
94354359Sroberto
94454359Sroberto
94554359Sroberto/*
94654359Sroberto * peer_stats - send statistics for one or more peers
94754359Sroberto */
94854359Srobertostatic void
94954359Srobertopeer_stats (
950132451Sroberto	struct sockaddr_storage *srcadr,
95154359Sroberto	struct interface *inter,
95254359Sroberto	struct req_pkt *inpkt
95354359Sroberto	)
95454359Sroberto{
95554359Sroberto	register struct info_peer_list *ipl;
95654359Sroberto	register struct peer *pp;
95754359Sroberto	register struct info_peer_stats *ip;
95854359Sroberto	register int items;
959132451Sroberto	struct sockaddr_storage addr;
96054359Sroberto	extern struct peer *sys_peer;
96154359Sroberto
962182007Sroberto#ifdef DEBUG
963182007Sroberto	if (debug)
964182007Sroberto	     printf("peer_stats: called\n");
965182007Sroberto#endif
96654359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
96754359Sroberto	ipl = (struct info_peer_list *) inpkt->data;
96854359Sroberto	ip = (struct info_peer_stats *)prepare_pkt(srcadr, inter, inpkt,
969132451Sroberto	    v6sizeof(struct info_peer_stats));
97054359Sroberto	while (items-- > 0 && ip != 0) {
971132451Sroberto		memset((char *)&addr, 0, sizeof(addr));
972132451Sroberto		NSRCPORT(&addr) = ipl->port;
973132451Sroberto		if (client_v6_capable && ipl->v6_flag) {
974132451Sroberto			addr.ss_family = AF_INET6;
975132451Sroberto			GET_INADDR6(addr) = ipl->addr6;
976132451Sroberto		} else {
977132451Sroberto			addr.ss_family = AF_INET;
978132451Sroberto			GET_INADDR(addr) = ipl->addr;
979132451Sroberto		}
980132451Sroberto#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
981132451Sroberto		addr.ss_len = SOCKLEN(&addr);
982132451Sroberto#endif
983182007Sroberto#ifdef DEBUG
984182007Sroberto		if (debug)
985182007Sroberto		    printf("peer_stats: looking for %s, %d, %d\n", stoa(&addr),
986132451Sroberto		    ipl->port, ((struct sockaddr_in6 *)&addr)->sin6_port);
987182007Sroberto#endif
988132451Sroberto		ipl = (struct info_peer_list *)((char *)ipl +
989132451Sroberto		    INFO_ITEMSIZE(inpkt->mbz_itemsize));
990132451Sroberto
99154359Sroberto		if ((pp = findexistingpeer(&addr, (struct peer *)0, -1)) == 0)
99254359Sroberto		    continue;
993182007Sroberto#ifdef DEBUG
994182007Sroberto		if (debug)
995182007Sroberto		     printf("peer_stats: found %s\n", stoa(&addr));
996182007Sroberto#endif
997132451Sroberto		if (pp->srcadr.ss_family == AF_INET) {
998182007Sroberto			if (pp->dstadr)
999182007Sroberto				ip->dstadr = (pp->processed) ?
1000182007Sroberto					pp->cast_flags == MDF_BCAST ?
1001182007Sroberto					GET_INADDR(pp->dstadr->bcast):
1002182007Sroberto					pp->cast_flags ?
1003182007Sroberto					GET_INADDR(pp->dstadr->sin) ?
1004182007Sroberto					GET_INADDR(pp->dstadr->sin):
1005182007Sroberto					GET_INADDR(pp->dstadr->bcast):
1006182007Sroberto					3 : 7;
1007182007Sroberto			else
1008182007Sroberto				memset(&ip->dstadr, 0, sizeof(ip->dstadr));
1009182007Sroberto
1010132451Sroberto			ip->srcadr = GET_INADDR(pp->srcadr);
1011132451Sroberto			if (client_v6_capable)
1012132451Sroberto				ip->v6_flag = 0;
1013132451Sroberto		} else {
1014182007Sroberto			if (pp->dstadr)
1015182007Sroberto				ip->dstadr6 = pp->cast_flags == MDF_BCAST ?
1016182007Sroberto					GET_INADDR6(pp->dstadr->bcast):
1017182007Sroberto					GET_INADDR6(pp->dstadr->sin);
1018182007Sroberto			else
1019182007Sroberto				memset(&ip->dstadr6, 0, sizeof(ip->dstadr6));
1020182007Sroberto
1021132451Sroberto			ip->srcadr6 = GET_INADDR6(pp->srcadr);
1022132451Sroberto			ip->v6_flag = 1;
1023132451Sroberto		}
102454359Sroberto		ip->srcport = NSRCPORT(&pp->srcadr);
102554359Sroberto		ip->flags = 0;
102654359Sroberto		if (pp == sys_peer)
102754359Sroberto		    ip->flags |= INFO_FLAG_SYSPEER;
102854359Sroberto		if (pp->flags & FLAG_CONFIG)
102954359Sroberto		    ip->flags |= INFO_FLAG_CONFIG;
103054359Sroberto		if (pp->flags & FLAG_REFCLOCK)
103154359Sroberto		    ip->flags |= INFO_FLAG_REFCLOCK;
103254359Sroberto		if (pp->flags & FLAG_AUTHENABLE)
103354359Sroberto		    ip->flags |= INFO_FLAG_AUTHENABLE;
103454359Sroberto		if (pp->flags & FLAG_PREFER)
103554359Sroberto		    ip->flags |= INFO_FLAG_PREFER;
103654359Sroberto		if (pp->flags & FLAG_BURST)
103754359Sroberto		    ip->flags |= INFO_FLAG_BURST;
1038182007Sroberto		if (pp->flags & FLAG_IBURST)
1039182007Sroberto		    ip->flags |= INFO_FLAG_IBURST;
104054359Sroberto		if (pp->status == CTL_PST_SEL_SYNCCAND)
104154359Sroberto		    ip->flags |= INFO_FLAG_SEL_CANDIDATE;
104254359Sroberto		if (pp->status >= CTL_PST_SEL_SYSPEER)
104354359Sroberto		    ip->flags |= INFO_FLAG_SHORTLIST;
1044182007Sroberto		ip->flags = htons(ip->flags);
104554359Sroberto		ip->timereceived = htonl((u_int32)(current_time - pp->timereceived));
104654359Sroberto		ip->timetosend = htonl(pp->nextdate - current_time);
104754359Sroberto		ip->timereachable = htonl((u_int32)(current_time - pp->timereachable));
104854359Sroberto		ip->sent = htonl((u_int32)(pp->sent));
104954359Sroberto		ip->processed = htonl((u_int32)(pp->processed));
105054359Sroberto		ip->badauth = htonl((u_int32)(pp->badauth));
105154359Sroberto		ip->bogusorg = htonl((u_int32)(pp->bogusorg));
105254359Sroberto		ip->oldpkt = htonl((u_int32)(pp->oldpkt));
105354359Sroberto		ip->seldisp = htonl((u_int32)(pp->seldisptoolarge));
105454359Sroberto		ip->selbroken = htonl((u_int32)(pp->selbroken));
105554359Sroberto		ip->candidate = pp->status;
105654359Sroberto		ip = (struct info_peer_stats *)more_pkt();
105754359Sroberto	}
105854359Sroberto	flush_pkt();
105954359Sroberto}
106054359Sroberto
106154359Sroberto
106254359Sroberto/*
106354359Sroberto * sys_info - return system info
106454359Sroberto */
106554359Srobertostatic void
106654359Srobertosys_info(
1067132451Sroberto	struct sockaddr_storage *srcadr,
106854359Sroberto	struct interface *inter,
106954359Sroberto	struct req_pkt *inpkt
107054359Sroberto	)
107154359Sroberto{
107254359Sroberto	register struct info_sys *is;
107354359Sroberto
107454359Sroberto	is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt,
1075132451Sroberto	    v6sizeof(struct info_sys));
107654359Sroberto
107754359Sroberto	if (sys_peer != 0) {
1078132451Sroberto		if (sys_peer->srcadr.ss_family == AF_INET) {
1079132451Sroberto			is->peer = GET_INADDR(sys_peer->srcadr);
1080132451Sroberto			if (client_v6_capable)
1081132451Sroberto				is->v6_flag = 0;
1082132451Sroberto		} else if (client_v6_capable) {
1083132451Sroberto			is->peer6 = GET_INADDR6(sys_peer->srcadr);
1084132451Sroberto			is->v6_flag = 1;
1085132451Sroberto		}
108654359Sroberto		is->peer_mode = sys_peer->hmode;
108754359Sroberto	} else {
108854359Sroberto		is->peer = 0;
1089132451Sroberto		if (client_v6_capable) {
1090132451Sroberto			is->v6_flag = 0;
1091132451Sroberto		}
109254359Sroberto		is->peer_mode = 0;
109354359Sroberto	}
1094132451Sroberto
109554359Sroberto	is->leap = sys_leap;
109654359Sroberto	is->stratum = sys_stratum;
109754359Sroberto	is->precision = sys_precision;
109854359Sroberto	is->rootdelay = htonl(DTOFP(sys_rootdelay));
109954359Sroberto	is->rootdispersion = htonl(DTOUFP(sys_rootdispersion));
110082498Sroberto	is->frequency = htonl(DTOFP(sys_jitter));
1101182007Sroberto	is->stability = htonl(DTOUFP(clock_stability));
110254359Sroberto	is->refid = sys_refid;
110354359Sroberto	HTONL_FP(&sys_reftime, &is->reftime);
110454359Sroberto
110554359Sroberto	is->poll = sys_poll;
110654359Sroberto
110754359Sroberto	is->flags = 0;
1108106163Sroberto	if (sys_authenticate)
1109106163Sroberto		is->flags |= INFO_FLAG_AUTHENTICATE;
111054359Sroberto	if (sys_bclient)
1111106163Sroberto		is->flags |= INFO_FLAG_BCLIENT;
1112106163Sroberto#ifdef REFCLOCK
1113106163Sroberto	if (cal_enable)
1114106163Sroberto		is->flags |= INFO_FLAG_CAL;
1115106163Sroberto#endif /* REFCLOCK */
111654359Sroberto	if (kern_enable)
1117106163Sroberto		is->flags |= INFO_FLAG_KERNEL;
1118106163Sroberto	if (mon_enabled != MON_OFF)
1119106163Sroberto		is->flags |= INFO_FLAG_MONITOR;
112054359Sroberto	if (ntp_enable)
1121106163Sroberto		is->flags |= INFO_FLAG_NTP;
1122106163Sroberto	if (pps_enable)
1123106163Sroberto		is->flags |= INFO_FLAG_PPS_SYNC;
112454359Sroberto	if (stats_control)
1125106163Sroberto		is->flags |= INFO_FLAG_FILEGEN;
112654359Sroberto	is->bdelay = HTONS_FP(DTOFP(sys_bdelay));
112754359Sroberto	HTONL_UF(sys_authdelay.l_f, &is->authdelay);
112854359Sroberto
112954359Sroberto	(void) more_pkt();
113054359Sroberto	flush_pkt();
113154359Sroberto}
113254359Sroberto
113354359Sroberto
113454359Sroberto/*
113554359Sroberto * sys_stats - return system statistics
113654359Sroberto */
113754359Srobertostatic void
113854359Srobertosys_stats(
1139132451Sroberto	struct sockaddr_storage *srcadr,
114054359Sroberto	struct interface *inter,
114154359Sroberto	struct req_pkt *inpkt
114254359Sroberto	)
114354359Sroberto{
114454359Sroberto	register struct info_sys_stats *ss;
114554359Sroberto
114654359Sroberto	/*
114754359Sroberto	 * Importations from the protocol module
114854359Sroberto	 */
114954359Sroberto	ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt,
1150132451Sroberto		sizeof(struct info_sys_stats));
115154359Sroberto	ss->timeup = htonl((u_int32)current_time);
115254359Sroberto	ss->timereset = htonl((u_int32)(current_time - sys_stattime));
1153132451Sroberto	ss->denied = htonl((u_int32)sys_restricted);
115454359Sroberto	ss->oldversionpkt = htonl((u_int32)sys_oldversionpkt);
115554359Sroberto	ss->newversionpkt = htonl((u_int32)sys_newversionpkt);
115654359Sroberto	ss->unknownversion = htonl((u_int32)sys_unknownversion);
115754359Sroberto	ss->badlength = htonl((u_int32)sys_badlength);
115854359Sroberto	ss->processed = htonl((u_int32)sys_processed);
115954359Sroberto	ss->badauth = htonl((u_int32)sys_badauth);
116054359Sroberto	ss->limitrejected = htonl((u_int32)sys_limitrejected);
1161132451Sroberto	ss->received = htonl((u_int32)sys_received);
116254359Sroberto	(void) more_pkt();
116354359Sroberto	flush_pkt();
116454359Sroberto}
116554359Sroberto
116654359Sroberto
116754359Sroberto/*
116854359Sroberto * mem_stats - return memory statistics
116954359Sroberto */
117054359Srobertostatic void
117154359Srobertomem_stats(
1172132451Sroberto	struct sockaddr_storage *srcadr,
117354359Sroberto	struct interface *inter,
117454359Sroberto	struct req_pkt *inpkt
117554359Sroberto	)
117654359Sroberto{
117754359Sroberto	register struct info_mem_stats *ms;
117854359Sroberto	register int i;
117954359Sroberto
118054359Sroberto	/*
118154359Sroberto	 * Importations from the peer module
118254359Sroberto	 */
1183182007Sroberto	extern int peer_hash_count[NTP_HASH_SIZE];
118454359Sroberto	extern int peer_free_count;
118554359Sroberto	extern u_long peer_timereset;
118654359Sroberto	extern u_long findpeer_calls;
118754359Sroberto	extern u_long peer_allocations;
118854359Sroberto	extern u_long peer_demobilizations;
118954359Sroberto	extern int total_peer_structs;
119054359Sroberto
119154359Sroberto	ms = (struct info_mem_stats *)prepare_pkt(srcadr, inter, inpkt,
119254359Sroberto						  sizeof(struct info_mem_stats));
119354359Sroberto
119454359Sroberto	ms->timereset = htonl((u_int32)(current_time - peer_timereset));
119554359Sroberto	ms->totalpeermem = htons((u_short)total_peer_structs);
119654359Sroberto	ms->freepeermem = htons((u_short)peer_free_count);
119754359Sroberto	ms->findpeer_calls = htonl((u_int32)findpeer_calls);
119854359Sroberto	ms->allocations = htonl((u_int32)peer_allocations);
119954359Sroberto	ms->demobilizations = htonl((u_int32)peer_demobilizations);
120054359Sroberto
1201182007Sroberto	for (i = 0; i < NTP_HASH_SIZE; i++) {
120254359Sroberto		if (peer_hash_count[i] > 255)
120354359Sroberto		    ms->hashcount[i] = 255;
120454359Sroberto		else
120554359Sroberto		    ms->hashcount[i] = (u_char)peer_hash_count[i];
120654359Sroberto	}
120754359Sroberto
120854359Sroberto	(void) more_pkt();
120954359Sroberto	flush_pkt();
121054359Sroberto}
121154359Sroberto
121254359Sroberto
121354359Sroberto/*
121454359Sroberto * io_stats - return io statistics
121554359Sroberto */
121654359Srobertostatic void
121754359Srobertoio_stats(
1218132451Sroberto	struct sockaddr_storage *srcadr,
121954359Sroberto	struct interface *inter,
122054359Sroberto	struct req_pkt *inpkt
122154359Sroberto	)
122254359Sroberto{
122354359Sroberto	register struct info_io_stats *io;
122454359Sroberto
122554359Sroberto	/*
122654359Sroberto	 * Importations from the io module
122754359Sroberto	 */
122854359Sroberto	extern u_long io_timereset;
122954359Sroberto
123054359Sroberto	io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt,
123154359Sroberto						 sizeof(struct info_io_stats));
123254359Sroberto
123354359Sroberto	io->timereset = htonl((u_int32)(current_time - io_timereset));
123454359Sroberto	io->totalrecvbufs = htons((u_short) total_recvbuffs());
123554359Sroberto	io->freerecvbufs = htons((u_short) free_recvbuffs());
123654359Sroberto	io->fullrecvbufs = htons((u_short) full_recvbuffs());
123754359Sroberto	io->lowwater = htons((u_short) lowater_additions());
123854359Sroberto	io->dropped = htonl((u_int32)packets_dropped);
123954359Sroberto	io->ignored = htonl((u_int32)packets_ignored);
124054359Sroberto	io->received = htonl((u_int32)packets_received);
124154359Sroberto	io->sent = htonl((u_int32)packets_sent);
124254359Sroberto	io->notsent = htonl((u_int32)packets_notsent);
124354359Sroberto	io->interrupts = htonl((u_int32)handler_calls);
124454359Sroberto	io->int_received = htonl((u_int32)handler_pkts);
124554359Sroberto
124654359Sroberto	(void) more_pkt();
124754359Sroberto	flush_pkt();
124854359Sroberto}
124954359Sroberto
125054359Sroberto
125154359Sroberto/*
125254359Sroberto * timer_stats - return timer statistics
125354359Sroberto */
125454359Srobertostatic void
125554359Srobertotimer_stats(
1256132451Sroberto	struct sockaddr_storage *srcadr,
125754359Sroberto	struct interface *inter,
125854359Sroberto	struct req_pkt *inpkt
125954359Sroberto	)
126054359Sroberto{
126154359Sroberto	register struct info_timer_stats *ts;
126254359Sroberto
126354359Sroberto	/*
126454359Sroberto	 * Importations from the timer module
126554359Sroberto	 */
126654359Sroberto	extern u_long timer_timereset;
126754359Sroberto	extern u_long timer_overflows;
126854359Sroberto	extern u_long timer_xmtcalls;
126954359Sroberto
127054359Sroberto	ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter, inpkt,
127154359Sroberto						    sizeof(struct info_timer_stats));
127254359Sroberto
127354359Sroberto	ts->timereset = htonl((u_int32)(current_time - timer_timereset));
127454359Sroberto	ts->alarms = htonl((u_int32)alarm_overflow);
127554359Sroberto	ts->overflows = htonl((u_int32)timer_overflows);
127654359Sroberto	ts->xmtcalls = htonl((u_int32)timer_xmtcalls);
127754359Sroberto
127854359Sroberto	(void) more_pkt();
127954359Sroberto	flush_pkt();
128054359Sroberto}
128154359Sroberto
128254359Sroberto
128354359Sroberto/*
128454359Sroberto * loop_info - return the current state of the loop filter
128554359Sroberto */
128654359Srobertostatic void
128754359Srobertoloop_info(
1288132451Sroberto	struct sockaddr_storage *srcadr,
128954359Sroberto	struct interface *inter,
129054359Sroberto	struct req_pkt *inpkt
129154359Sroberto	)
129254359Sroberto{
129354359Sroberto	register struct info_loop *li;
129454359Sroberto	l_fp ltmp;
129554359Sroberto
129654359Sroberto	/*
129754359Sroberto	 * Importations from the loop filter module
129854359Sroberto	 */
129954359Sroberto	extern double last_offset;
130054359Sroberto	extern double drift_comp;
130154359Sroberto	extern int tc_counter;
1302182007Sroberto	extern u_long sys_clocktime;
130354359Sroberto
130454359Sroberto	li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt,
130554359Sroberto	    sizeof(struct info_loop));
130654359Sroberto
130754359Sroberto	DTOLFP(last_offset, &ltmp);
130854359Sroberto	HTONL_FP(&ltmp, &li->last_offset);
130954359Sroberto	DTOLFP(drift_comp * 1e6, &ltmp);
131054359Sroberto	HTONL_FP(&ltmp, &li->drift_comp);
131154359Sroberto	li->compliance = htonl((u_int32)(tc_counter));
1312182007Sroberto	li->watchdog_timer = htonl((u_int32)(current_time - sys_clocktime));
131354359Sroberto
131454359Sroberto	(void) more_pkt();
131554359Sroberto	flush_pkt();
131654359Sroberto}
131754359Sroberto
131854359Sroberto
131954359Sroberto/*
132054359Sroberto * do_conf - add a peer to the configuration list
132154359Sroberto */
132254359Srobertostatic void
132354359Srobertodo_conf(
1324132451Sroberto	struct sockaddr_storage *srcadr,
132554359Sroberto	struct interface *inter,
132654359Sroberto	struct req_pkt *inpkt
132754359Sroberto	)
132854359Sroberto{
1329200576Sroberto	static u_long soonest_ifrescan_time = 0;
1330132451Sroberto	int items;
133182498Sroberto	u_int fl;
1332132451Sroberto	struct conf_peer *cp;
1333132451Sroberto	struct conf_peer temp_cp;
1334132451Sroberto	struct sockaddr_storage peeraddr;
1335132451Sroberto	struct sockaddr_in tmp_clock;
133654359Sroberto
133754359Sroberto	/*
133854359Sroberto	 * Do a check of everything to see that it looks
133954359Sroberto	 * okay.  If not, complain about it.  Note we are
134054359Sroberto	 * very picky here.
134154359Sroberto	 */
134254359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
134354359Sroberto	cp = (struct conf_peer *)inpkt->data;
1344132451Sroberto	memset(&temp_cp, 0, sizeof(struct conf_peer));
1345132451Sroberto	memcpy(&temp_cp, (char *)cp, INFO_ITEMSIZE(inpkt->mbz_itemsize));
134654359Sroberto	fl = 0;
134754359Sroberto	while (items-- > 0 && !fl) {
1348132451Sroberto		if (((temp_cp.version) > NTP_VERSION)
1349132451Sroberto		    || ((temp_cp.version) < NTP_OLDVERSION))
135054359Sroberto		    fl = 1;
1351132451Sroberto		if (temp_cp.hmode != MODE_ACTIVE
1352132451Sroberto		    && temp_cp.hmode != MODE_CLIENT
1353132451Sroberto		    && temp_cp.hmode != MODE_BROADCAST)
135454359Sroberto		    fl = 1;
1355132451Sroberto		if (temp_cp.flags & ~(CONF_FLAG_AUTHENABLE | CONF_FLAG_PREFER
1356182007Sroberto				  | CONF_FLAG_BURST | CONF_FLAG_IBURST | CONF_FLAG_SKEY))
135754359Sroberto		    fl = 1;
1358132451Sroberto		cp = (struct conf_peer *)
1359132451Sroberto		    ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize));
136054359Sroberto	}
136154359Sroberto
136254359Sroberto	if (fl) {
136354359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
136454359Sroberto		return;
136554359Sroberto	}
136654359Sroberto
136754359Sroberto	/*
136854359Sroberto	 * Looks okay, try it out
136954359Sroberto	 */
137054359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
1371132451Sroberto	cp = (struct conf_peer *)inpkt->data;
137254359Sroberto
1373132451Sroberto	while (items-- > 0) {
1374132451Sroberto		memset(&temp_cp, 0, sizeof(struct conf_peer));
1375132451Sroberto		memcpy(&temp_cp, (char *)cp, INFO_ITEMSIZE(inpkt->mbz_itemsize));
1376132451Sroberto		memset((char *)&peeraddr, 0, sizeof(struct sockaddr_storage));
1377132451Sroberto
1378132451Sroberto		fl = 0;
1379132451Sroberto		if (temp_cp.flags & CONF_FLAG_AUTHENABLE)
1380182007Sroberto			fl |= FLAG_AUTHENABLE;
1381132451Sroberto		if (temp_cp.flags & CONF_FLAG_PREFER)
1382182007Sroberto			fl |= FLAG_PREFER;
1383132451Sroberto		if (temp_cp.flags & CONF_FLAG_BURST)
1384132451Sroberto		    fl |= FLAG_BURST;
1385182007Sroberto		if (temp_cp.flags & CONF_FLAG_IBURST)
1386182007Sroberto		    fl |= FLAG_IBURST;
1387132451Sroberto		if (temp_cp.flags & CONF_FLAG_SKEY)
1388132451Sroberto			fl |= FLAG_SKEY;
1389182007Sroberto
1390132451Sroberto		if (client_v6_capable && temp_cp.v6_flag != 0) {
1391132451Sroberto			peeraddr.ss_family = AF_INET6;
1392132451Sroberto			GET_INADDR6(peeraddr) = temp_cp.peeraddr6;
1393132451Sroberto		} else {
1394132451Sroberto			peeraddr.ss_family = AF_INET;
1395132451Sroberto			GET_INADDR(peeraddr) = temp_cp.peeraddr;
1396132451Sroberto			/*
1397132451Sroberto			 * Make sure the address is valid
1398132451Sroberto			 */
1399132451Sroberto			tmp_clock = *CAST_V4(peeraddr);
1400132451Sroberto			if (
140154359Sroberto#ifdef REFCLOCK
1402132451Sroberto				!ISREFCLOCKADR(&tmp_clock) &&
140354359Sroberto#endif
1404132451Sroberto				ISBADADR(&tmp_clock)) {
1405132451Sroberto				req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
1406132451Sroberto				return;
1407132451Sroberto			}
1408132451Sroberto
1409132451Sroberto		}
1410132451Sroberto		NSRCPORT(&peeraddr) = htons(NTP_PORT);
1411132451Sroberto#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1412132451Sroberto		peeraddr.ss_len = SOCKLEN(&peeraddr);
141382498Sroberto#endif
141454359Sroberto
141554359Sroberto		/* XXX W2DO? minpoll/maxpoll arguments ??? */
1416132451Sroberto		if (peer_config(&peeraddr, (struct interface *)0,
1417132451Sroberto		    temp_cp.hmode, temp_cp.version, temp_cp.minpoll,
1418132451Sroberto		    temp_cp.maxpoll, fl, temp_cp.ttl, temp_cp.keyid,
1419132451Sroberto		    NULL) == 0) {
142054359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
142154359Sroberto			return;
142254359Sroberto		}
1423200576Sroberto
1424200576Sroberto		/*
1425200576Sroberto		 * ntp_intres.c uses REQ_CONFIG/doconf() to add each
1426200576Sroberto		 * server after its name is resolved.  If we have been
1427200576Sroberto		 * disconnected from the network, it may notice the
1428200576Sroberto		 * network has returned and add the first server while
1429200576Sroberto		 * the relevant interface is still disabled, awaiting
1430200576Sroberto		 * the next interface rescan.  To get things moving
1431200576Sroberto		 * more quickly, trigger an interface scan now, except
1432200576Sroberto		 * if we have done so in the last half minute.
1433200576Sroberto		 */
1434200576Sroberto		if (soonest_ifrescan_time < current_time) {
1435200576Sroberto			soonest_ifrescan_time = current_time + 30;
1436200576Sroberto			timer_interfacetimeout(current_time);
1437200576Sroberto			DPRINTF(1, ("do_conf triggering interface rescan\n"));
1438200576Sroberto		}
1439200576Sroberto
1440132451Sroberto		cp = (struct conf_peer *)
1441132451Sroberto		    ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize));
144254359Sroberto	}
144354359Sroberto
144454359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
144554359Sroberto}
144654359Sroberto
1447132451Sroberto#if 0
1448132451Sroberto/* XXX */
144954359Sroberto/*
145082498Sroberto * dns_a - Snarf DNS info for an association ID
145182498Sroberto */
145282498Srobertostatic void
145382498Srobertodns_a(
1454132451Sroberto	struct sockaddr_storage *srcadr,
145582498Sroberto	struct interface *inter,
145682498Sroberto	struct req_pkt *inpkt
145782498Sroberto	)
145882498Sroberto{
145982498Sroberto	register struct info_dns_assoc *dp;
146082498Sroberto	register int items;
146182498Sroberto	struct sockaddr_in peeraddr;
146282498Sroberto
146382498Sroberto	/*
146482498Sroberto	 * Do a check of everything to see that it looks
146582498Sroberto	 * okay.  If not, complain about it.  Note we are
146682498Sroberto	 * very picky here.
146782498Sroberto	 */
146882498Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
146982498Sroberto	dp = (struct info_dns_assoc *)inpkt->data;
147082498Sroberto
147182498Sroberto	/*
147282498Sroberto	 * Looks okay, try it out
147382498Sroberto	 */
147482498Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
147582498Sroberto	dp = (struct info_dns_assoc *)inpkt->data;
147682498Sroberto	memset((char *)&peeraddr, 0, sizeof(struct sockaddr_in));
147782498Sroberto	peeraddr.sin_family = AF_INET;
147882498Sroberto	peeraddr.sin_port = htons(NTP_PORT);
147982498Sroberto
148082498Sroberto	/*
148182498Sroberto	 * Make sure the address is valid
148282498Sroberto	 */
148382498Sroberto	if (
148482498Sroberto#ifdef REFCLOCK
148582498Sroberto		!ISREFCLOCKADR(&peeraddr) &&
148682498Sroberto#endif
148782498Sroberto		ISBADADR(&peeraddr)) {
148882498Sroberto#ifdef REFCLOCK
148982498Sroberto		msyslog(LOG_ERR, "dns_a: !ISREFCLOCK && ISBADADR");
149082498Sroberto#else
149182498Sroberto		msyslog(LOG_ERR, "dns_a: ISBADADR");
149282498Sroberto#endif
149382498Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
149482498Sroberto		return;
149582498Sroberto	}
149682498Sroberto
149782498Sroberto	while (items-- > 0) {
149882498Sroberto		associd_t associd;
149982498Sroberto		size_t hnl;
150082498Sroberto		struct peer *peer;
150182498Sroberto		int bogon = 0;
150282498Sroberto
150382498Sroberto		associd = dp->associd;
150482498Sroberto		peer = findpeerbyassoc(associd);
150582498Sroberto		if (peer == 0 || peer->flags & FLAG_REFCLOCK) {
150682498Sroberto			msyslog(LOG_ERR, "dns_a: %s",
150782498Sroberto				(peer == 0)
150882498Sroberto				? "peer == 0"
150982498Sroberto				: "peer->flags & FLAG_REFCLOCK");
151082498Sroberto			++bogon;
151182498Sroberto		}
151282498Sroberto		peeraddr.sin_addr.s_addr = dp->peeraddr;
151382498Sroberto		for (hnl = 0; dp->hostname[hnl] && hnl < sizeof dp->hostname; ++hnl) ;
151482498Sroberto		if (hnl >= sizeof dp->hostname) {
151582498Sroberto			msyslog(LOG_ERR, "dns_a: hnl (%ld) >= %ld",
151682498Sroberto				(long)hnl, (long)sizeof dp->hostname);
151782498Sroberto			++bogon;
151882498Sroberto		}
151982498Sroberto
152082498Sroberto		msyslog(LOG_INFO, "dns_a: <%s> for %s, AssocID %d, bogon %d",
1521132451Sroberto			dp->hostname,
1522132451Sroberto			stoa((struct sockaddr_storage *)&peeraddr), associd,
152382498Sroberto			bogon);
1524132451Sroberto
152582498Sroberto		if (bogon) {
152682498Sroberto			/* If it didn't work */
152782498Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
152882498Sroberto			return;
152982498Sroberto		} else {
153082498Sroberto#if 0
153182498Sroberto#ifdef PUBKEY
153282498Sroberto			crypto_public(peer, dp->hostname);
153382498Sroberto#endif /* PUBKEY */
153482498Sroberto#endif
153582498Sroberto		}
1536132451Sroberto
153782498Sroberto		dp++;
153882498Sroberto	}
153982498Sroberto
154082498Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
154182498Sroberto}
1542132451Sroberto#endif /* 0 */
154382498Sroberto
154482498Sroberto/*
154554359Sroberto * do_unconf - remove a peer from the configuration list
154654359Sroberto */
154754359Srobertostatic void
154854359Srobertodo_unconf(
1549132451Sroberto	struct sockaddr_storage *srcadr,
155054359Sroberto	struct interface *inter,
155154359Sroberto	struct req_pkt *inpkt
155254359Sroberto	)
155354359Sroberto{
155454359Sroberto	register struct conf_unpeer *cp;
1555132451Sroberto	struct conf_unpeer temp_cp;
155654359Sroberto	register int items;
155754359Sroberto	register struct peer *peer;
1558132451Sroberto	struct sockaddr_storage peeraddr;
155954359Sroberto	int bad, found;
156054359Sroberto
156154359Sroberto	/*
156254359Sroberto	 * This is a bit unstructured, but I like to be careful.
156354359Sroberto	 * We check to see that every peer exists and is actually
156454359Sroberto	 * configured.  If so, we remove them.  If not, we return
156554359Sroberto	 * an error.
156654359Sroberto	 */
156754359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
156854359Sroberto	cp = (struct conf_unpeer *)inpkt->data;
156954359Sroberto
157054359Sroberto	bad = 0;
157154359Sroberto	while (items-- > 0 && !bad) {
1572132451Sroberto		memset(&temp_cp, 0, sizeof(temp_cp));
1573132451Sroberto		memset(&peeraddr, 0, sizeof(peeraddr));
1574132451Sroberto		memcpy(&temp_cp, cp, INFO_ITEMSIZE(inpkt->mbz_itemsize));
1575132451Sroberto		if (client_v6_capable && temp_cp.v6_flag != 0) {
1576132451Sroberto			peeraddr.ss_family = AF_INET6;
1577132451Sroberto			GET_INADDR6(peeraddr) = temp_cp.peeraddr6;
1578132451Sroberto		} else {
1579132451Sroberto			peeraddr.ss_family = AF_INET;
1580132451Sroberto			GET_INADDR(peeraddr) = temp_cp.peeraddr;
1581132451Sroberto		}
1582132451Sroberto		NSRCPORT(&peeraddr) = htons(NTP_PORT);
1583132451Sroberto#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1584132451Sroberto		peeraddr.ss_len = SOCKLEN(&peeraddr);
1585132451Sroberto#endif
158654359Sroberto		found = 0;
158754359Sroberto		peer = (struct peer *)0;
1588182007Sroberto#ifdef DEBUG
1589182007Sroberto		if (debug)
1590182007Sroberto		     printf("searching for %s\n", stoa(&peeraddr));
1591182007Sroberto#endif
159254359Sroberto		while (!found) {
159354359Sroberto			peer = findexistingpeer(&peeraddr, peer, -1);
159454359Sroberto			if (peer == (struct peer *)0)
159554359Sroberto			    break;
159654359Sroberto			if (peer->flags & FLAG_CONFIG)
159754359Sroberto			    found = 1;
159854359Sroberto		}
159954359Sroberto		if (!found)
160054359Sroberto		    bad = 1;
1601132451Sroberto		cp = (struct conf_unpeer *)
1602132451Sroberto		    ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize));
160354359Sroberto	}
160454359Sroberto
160554359Sroberto	if (bad) {
160654359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
160754359Sroberto		return;
160854359Sroberto	}
160954359Sroberto
161054359Sroberto	/*
161154359Sroberto	 * Now do it in earnest.
161254359Sroberto	 */
161354359Sroberto
161454359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
161554359Sroberto	cp = (struct conf_unpeer *)inpkt->data;
161654359Sroberto	while (items-- > 0) {
1617132451Sroberto		memset(&temp_cp, 0, sizeof(temp_cp));
1618132451Sroberto		memset(&peeraddr, 0, sizeof(peeraddr));
1619132451Sroberto		memcpy(&temp_cp, cp, INFO_ITEMSIZE(inpkt->mbz_itemsize));
1620132451Sroberto		if (client_v6_capable && temp_cp.v6_flag != 0) {
1621132451Sroberto			peeraddr.ss_family = AF_INET6;
1622132451Sroberto			GET_INADDR6(peeraddr) = temp_cp.peeraddr6;
1623132451Sroberto		} else {
1624132451Sroberto			peeraddr.ss_family = AF_INET;
1625132451Sroberto			GET_INADDR(peeraddr) = temp_cp.peeraddr;
1626132451Sroberto		}
1627132451Sroberto		NSRCPORT(&peeraddr) = htons(NTP_PORT);
1628132451Sroberto#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1629132451Sroberto		peeraddr.ss_len = SOCKLEN(&peeraddr);
1630132451Sroberto#endif
163154359Sroberto		peer_unconfig(&peeraddr, (struct interface *)0, -1);
1632132451Sroberto		cp = (struct conf_unpeer *)
1633132451Sroberto		    ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize));
163454359Sroberto	}
163554359Sroberto
163654359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
163754359Sroberto}
163854359Sroberto
163954359Sroberto
164054359Sroberto/*
164154359Sroberto * set_sys_flag - set system flags
164254359Sroberto */
164354359Srobertostatic void
164454359Srobertoset_sys_flag(
1645132451Sroberto	struct sockaddr_storage *srcadr,
164654359Sroberto	struct interface *inter,
164754359Sroberto	struct req_pkt *inpkt
164854359Sroberto	)
164954359Sroberto{
165054359Sroberto	setclr_flags(srcadr, inter, inpkt, 1);
165154359Sroberto}
165254359Sroberto
165354359Sroberto
165454359Sroberto/*
165554359Sroberto * clr_sys_flag - clear system flags
165654359Sroberto */
165754359Srobertostatic void
165854359Srobertoclr_sys_flag(
1659132451Sroberto	struct sockaddr_storage *srcadr,
166054359Sroberto	struct interface *inter,
166154359Sroberto	struct req_pkt *inpkt
166254359Sroberto	)
166354359Sroberto{
166454359Sroberto	setclr_flags(srcadr, inter, inpkt, 0);
166554359Sroberto}
166654359Sroberto
166754359Sroberto
166854359Sroberto/*
166954359Sroberto * setclr_flags - do the grunge work of flag setting/clearing
167054359Sroberto */
167154359Srobertostatic void
167254359Srobertosetclr_flags(
1673132451Sroberto	struct sockaddr_storage *srcadr,
167454359Sroberto	struct interface *inter,
167554359Sroberto	struct req_pkt *inpkt,
167654359Sroberto	u_long set
167754359Sroberto	)
167854359Sroberto{
167982498Sroberto	register u_int flags;
1680182007Sroberto	int prev_kern_enable;
168154359Sroberto
1682182007Sroberto	prev_kern_enable = kern_enable;
168354359Sroberto	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
168482498Sroberto		msyslog(LOG_ERR, "setclr_flags: err_nitems > 1");
168554359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
168654359Sroberto		return;
168754359Sroberto	}
168854359Sroberto
168954359Sroberto	flags = ((struct conf_sys_flags *)inpkt->data)->flags;
1690182007Sroberto	flags = ntohl(flags);
1691182007Sroberto
169282498Sroberto	if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS |
169354359Sroberto		      SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR |
1694106163Sroberto		      SYS_FLAG_FILEGEN | SYS_FLAG_AUTH | SYS_FLAG_CAL)) {
169582498Sroberto		msyslog(LOG_ERR, "setclr_flags: extra flags: %#x",
1696132451Sroberto			flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS |
169782498Sroberto				  SYS_FLAG_NTP | SYS_FLAG_KERNEL |
1698106163Sroberto				  SYS_FLAG_MONITOR | SYS_FLAG_FILEGEN |
1699106163Sroberto				  SYS_FLAG_AUTH | SYS_FLAG_CAL));
170054359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
170154359Sroberto		return;
170254359Sroberto	}
170354359Sroberto
170454359Sroberto	if (flags & SYS_FLAG_BCLIENT)
1705132451Sroberto		proto_config(PROTO_BROADCLIENT, set, 0., NULL);
170682498Sroberto	if (flags & SYS_FLAG_PPS)
1707132451Sroberto		proto_config(PROTO_PPS, set, 0., NULL);
170854359Sroberto	if (flags & SYS_FLAG_NTP)
1709132451Sroberto		proto_config(PROTO_NTP, set, 0., NULL);
171054359Sroberto	if (flags & SYS_FLAG_KERNEL)
1711132451Sroberto		proto_config(PROTO_KERNEL, set, 0., NULL);
171254359Sroberto	if (flags & SYS_FLAG_MONITOR)
1713132451Sroberto		proto_config(PROTO_MONITOR, set, 0., NULL);
171454359Sroberto	if (flags & SYS_FLAG_FILEGEN)
1715132451Sroberto		proto_config(PROTO_FILEGEN, set, 0., NULL);
1716106163Sroberto	if (flags & SYS_FLAG_AUTH)
1717132451Sroberto		proto_config(PROTO_AUTHENTICATE, set, 0., NULL);
1718106163Sroberto	if (flags & SYS_FLAG_CAL)
1719132451Sroberto		proto_config(PROTO_CAL, set, 0., NULL);
172054359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
1721182007Sroberto
1722182007Sroberto	/* Reset the kernel ntp parameters if the kernel flag changed. */
1723182007Sroberto	if (prev_kern_enable && !kern_enable)
1724182007Sroberto	     	loop_config(LOOP_KERN_CLEAR, 0.0);
1725182007Sroberto	if (!prev_kern_enable && kern_enable)
1726182007Sroberto	     	loop_config(LOOP_DRIFTCOMP, drift_comp);
172754359Sroberto}
172854359Sroberto
172954359Sroberto
173054359Sroberto/*
173154359Sroberto * list_restrict - return the restrict list
173254359Sroberto */
173354359Srobertostatic void
173454359Srobertolist_restrict(
1735132451Sroberto	struct sockaddr_storage *srcadr,
173654359Sroberto	struct interface *inter,
173754359Sroberto	struct req_pkt *inpkt
173854359Sroberto	)
173954359Sroberto{
174054359Sroberto	register struct info_restrict *ir;
174154359Sroberto	register struct restrictlist *rl;
1742132451Sroberto	register struct restrictlist6 *rl6;
174354359Sroberto
174454359Sroberto#ifdef DEBUG
174554359Sroberto	if (debug > 2)
1746132451Sroberto	    printf("wants restrict list summary\n");
174754359Sroberto#endif
174854359Sroberto
174954359Sroberto	ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt,
1750132451Sroberto	    v6sizeof(struct info_restrict));
1751132451Sroberto
175254359Sroberto	for (rl = restrictlist; rl != 0 && ir != 0; rl = rl->next) {
175354359Sroberto		ir->addr = htonl(rl->addr);
1754132451Sroberto		if (client_v6_capable)
1755132451Sroberto			ir->v6_flag = 0;
175654359Sroberto		ir->mask = htonl(rl->mask);
175754359Sroberto		ir->count = htonl((u_int32)rl->count);
175854359Sroberto		ir->flags = htons(rl->flags);
175954359Sroberto		ir->mflags = htons(rl->mflags);
176054359Sroberto		ir = (struct info_restrict *)more_pkt();
176154359Sroberto	}
1762132451Sroberto	if (client_v6_capable)
1763132451Sroberto		for (rl6 = restrictlist6; rl6 != 0 && ir != 0; rl6 = rl6->next) {
1764132451Sroberto			ir->addr6 = rl6->addr6;
1765132451Sroberto			ir->mask6 = rl6->mask6;
1766132451Sroberto			ir->v6_flag = 1;
1767132451Sroberto			ir->count = htonl((u_int32)rl6->count);
1768132451Sroberto			ir->flags = htons(rl6->flags);
1769132451Sroberto			ir->mflags = htons(rl6->mflags);
1770132451Sroberto			ir = (struct info_restrict *)more_pkt();
1771132451Sroberto		}
177254359Sroberto	flush_pkt();
177354359Sroberto}
177454359Sroberto
177554359Sroberto
177654359Sroberto
177754359Sroberto/*
177854359Sroberto * do_resaddflags - add flags to a restrict entry (or create one)
177954359Sroberto */
178054359Srobertostatic void
178154359Srobertodo_resaddflags(
1782132451Sroberto	struct sockaddr_storage *srcadr,
178354359Sroberto	struct interface *inter,
178454359Sroberto	struct req_pkt *inpkt
178554359Sroberto	)
178654359Sroberto{
178754359Sroberto	do_restrict(srcadr, inter, inpkt, RESTRICT_FLAGS);
178854359Sroberto}
178954359Sroberto
179054359Sroberto
179154359Sroberto
179254359Sroberto/*
179354359Sroberto * do_ressubflags - remove flags from a restrict entry
179454359Sroberto */
179554359Srobertostatic void
179654359Srobertodo_ressubflags(
1797132451Sroberto	struct sockaddr_storage *srcadr,
179854359Sroberto	struct interface *inter,
179954359Sroberto	struct req_pkt *inpkt
180054359Sroberto	)
180154359Sroberto{
180254359Sroberto	do_restrict(srcadr, inter, inpkt, RESTRICT_UNFLAG);
180354359Sroberto}
180454359Sroberto
180554359Sroberto
180654359Sroberto/*
180754359Sroberto * do_unrestrict - remove a restrict entry from the list
180854359Sroberto */
180954359Srobertostatic void
181054359Srobertodo_unrestrict(
1811132451Sroberto	struct sockaddr_storage *srcadr,
181254359Sroberto	struct interface *inter,
181354359Sroberto	struct req_pkt *inpkt
181454359Sroberto	)
181554359Sroberto{
181654359Sroberto	do_restrict(srcadr, inter, inpkt, RESTRICT_REMOVE);
181754359Sroberto}
181854359Sroberto
181954359Sroberto
182054359Sroberto
182154359Sroberto
182254359Sroberto
182354359Sroberto/*
182454359Sroberto * do_restrict - do the dirty stuff of dealing with restrictions
182554359Sroberto */
182654359Srobertostatic void
182754359Srobertodo_restrict(
1828132451Sroberto	struct sockaddr_storage *srcadr,
182954359Sroberto	struct interface *inter,
183054359Sroberto	struct req_pkt *inpkt,
183154359Sroberto	int op
183254359Sroberto	)
183354359Sroberto{
183454359Sroberto	register struct conf_restrict *cr;
183554359Sroberto	register int items;
1836132451Sroberto	struct sockaddr_storage matchaddr;
1837132451Sroberto	struct sockaddr_storage matchmask;
183854359Sroberto	int bad;
183954359Sroberto
184054359Sroberto	/*
184154359Sroberto	 * Do a check of the flags to make sure that only
184254359Sroberto	 * the NTPPORT flag is set, if any.  If not, complain
184354359Sroberto	 * about it.  Note we are very picky here.
184454359Sroberto	 */
184554359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
184654359Sroberto	cr = (struct conf_restrict *)inpkt->data;
184754359Sroberto
184854359Sroberto	bad = 0;
1849182007Sroberto	cr->flags = ntohs(cr->flags);
1850182007Sroberto	cr->mflags = ntohs(cr->mflags);
185154359Sroberto	while (items-- > 0 && !bad) {
185254359Sroberto		if (cr->mflags & ~(RESM_NTPONLY))
185382498Sroberto		    bad |= 1;
185454359Sroberto		if (cr->flags & ~(RES_ALLFLAGS))
185582498Sroberto		    bad |= 2;
1856132451Sroberto		if (cr->mask != htonl(INADDR_ANY)) {
1857132451Sroberto			if (client_v6_capable && cr->v6_flag != 0) {
1858132451Sroberto				if (IN6_IS_ADDR_UNSPECIFIED(&cr->addr6))
1859132451Sroberto					bad |= 4;
1860132451Sroberto			} else
1861132451Sroberto				if (cr->addr == htonl(INADDR_ANY))
1862132451Sroberto					bad |= 8;
1863132451Sroberto		}
1864132451Sroberto		cr = (struct conf_restrict *)((char *)cr +
1865132451Sroberto		    INFO_ITEMSIZE(inpkt->mbz_itemsize));
186654359Sroberto	}
186754359Sroberto
186854359Sroberto	if (bad) {
186982498Sroberto		msyslog(LOG_ERR, "do_restrict: bad = %#x", bad);
187054359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
187154359Sroberto		return;
187254359Sroberto	}
187354359Sroberto
187454359Sroberto	/*
187554359Sroberto	 * Looks okay, try it out
187654359Sroberto	 */
187754359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
187854359Sroberto	cr = (struct conf_restrict *)inpkt->data;
1879132451Sroberto	memset((char *)&matchaddr, 0, sizeof(struct sockaddr_storage));
1880132451Sroberto	memset((char *)&matchmask, 0, sizeof(struct sockaddr_storage));
188154359Sroberto
188254359Sroberto	while (items-- > 0) {
1883132451Sroberto		if (client_v6_capable && cr->v6_flag != 0) {
1884132451Sroberto			GET_INADDR6(matchaddr) = cr->addr6;
1885132451Sroberto			GET_INADDR6(matchmask) = cr->mask6;
1886132451Sroberto			matchaddr.ss_family = AF_INET6;
1887132451Sroberto			matchmask.ss_family = AF_INET6;
1888132451Sroberto		} else {
1889132451Sroberto			GET_INADDR(matchaddr) = cr->addr;
1890132451Sroberto			GET_INADDR(matchmask) = cr->mask;
1891132451Sroberto			matchaddr.ss_family = AF_INET;
1892132451Sroberto			matchmask.ss_family = AF_INET;
1893132451Sroberto		}
189454359Sroberto		hack_restrict(op, &matchaddr, &matchmask, cr->mflags,
189554359Sroberto			 cr->flags);
189654359Sroberto		cr++;
189754359Sroberto	}
189854359Sroberto
189954359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
190054359Sroberto}
190154359Sroberto
190254359Sroberto
190354359Sroberto/*
190454359Sroberto * mon_getlist - return monitor data
190554359Sroberto */
190654359Srobertostatic void
190754359Srobertomon_getlist_0(
1908132451Sroberto	struct sockaddr_storage *srcadr,
190954359Sroberto	struct interface *inter,
191054359Sroberto	struct req_pkt *inpkt
191154359Sroberto	)
191254359Sroberto{
191354359Sroberto	register struct info_monitor *im;
191454359Sroberto	register struct mon_data *md;
191554359Sroberto	extern struct mon_data mon_mru_list;
191654359Sroberto	extern int mon_enabled;
191754359Sroberto
191854359Sroberto#ifdef DEBUG
191954359Sroberto	if (debug > 2)
192054359Sroberto	    printf("wants monitor 0 list\n");
192154359Sroberto#endif
192254359Sroberto	if (!mon_enabled) {
192354359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
192454359Sroberto		return;
192554359Sroberto	}
192654359Sroberto	im = (struct info_monitor *)prepare_pkt(srcadr, inter, inpkt,
1927132451Sroberto	    v6sizeof(struct info_monitor));
192854359Sroberto	for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0;
192954359Sroberto	     md = md->mru_next) {
1930132451Sroberto		im->lasttime = htonl((u_int32)md->avg_interval);
1931132451Sroberto		im->firsttime = htonl((u_int32)(current_time - md->lasttime));
1932132451Sroberto		im->lastdrop = htonl((u_int32)md->drop_count);
193354359Sroberto		im->count = htonl((u_int32)(md->count));
1934132451Sroberto		if (md->rmtadr.ss_family == AF_INET6) {
1935132451Sroberto			if (!client_v6_capable)
1936132451Sroberto				continue;
1937132451Sroberto			im->addr6 = GET_INADDR6(md->rmtadr);
1938132451Sroberto			im->v6_flag = 1;
1939132451Sroberto		} else {
1940132451Sroberto			im->addr = GET_INADDR(md->rmtadr);
1941132451Sroberto			if (client_v6_capable)
1942132451Sroberto				im->v6_flag = 0;
1943132451Sroberto		}
194454359Sroberto		im->port = md->rmtport;
194554359Sroberto		im->mode = md->mode;
194654359Sroberto		im->version = md->version;
194754359Sroberto		im = (struct info_monitor *)more_pkt();
194854359Sroberto	}
194954359Sroberto	flush_pkt();
195054359Sroberto}
195154359Sroberto
195254359Sroberto/*
195354359Sroberto * mon_getlist - return monitor data
195454359Sroberto */
195554359Srobertostatic void
195654359Srobertomon_getlist_1(
1957132451Sroberto	struct sockaddr_storage *srcadr,
195854359Sroberto	struct interface *inter,
195954359Sroberto	struct req_pkt *inpkt
196054359Sroberto	)
196154359Sroberto{
196254359Sroberto	register struct info_monitor_1 *im;
196354359Sroberto	register struct mon_data *md;
196454359Sroberto	extern struct mon_data mon_mru_list;
196554359Sroberto	extern int mon_enabled;
196654359Sroberto
196754359Sroberto	if (!mon_enabled) {
196854359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
196954359Sroberto		return;
197054359Sroberto	}
197154359Sroberto	im = (struct info_monitor_1 *)prepare_pkt(srcadr, inter, inpkt,
1972132451Sroberto	    v6sizeof(struct info_monitor_1));
197354359Sroberto	for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0;
197454359Sroberto	     md = md->mru_next) {
1975132451Sroberto		im->lasttime = htonl((u_int32)md->avg_interval);
1976132451Sroberto		im->firsttime = htonl((u_int32)(current_time - md->lasttime));
1977132451Sroberto		im->lastdrop = htonl((u_int32)md->drop_count);
197854359Sroberto		im->count = htonl((u_int32)md->count);
1979132451Sroberto		if (md->rmtadr.ss_family == AF_INET6) {
1980132451Sroberto			if (!client_v6_capable)
1981132451Sroberto				continue;
1982132451Sroberto			im->addr6 = GET_INADDR6(md->rmtadr);
1983132451Sroberto			im->v6_flag = 1;
1984132451Sroberto			im->daddr6 = GET_INADDR6(md->interface->sin);
1985132451Sroberto		} else {
1986132451Sroberto			im->addr = GET_INADDR(md->rmtadr);
1987132451Sroberto			if (client_v6_capable)
1988132451Sroberto				im->v6_flag = 0;
1989132451Sroberto			im->daddr = (md->cast_flags == MDF_BCAST)
1990132451Sroberto				? GET_INADDR(md->interface->bcast)
1991132451Sroberto				: (md->cast_flags
1992132451Sroberto				? (GET_INADDR(md->interface->sin)
1993132451Sroberto				? GET_INADDR(md->interface->sin)
1994132451Sroberto				: GET_INADDR(md->interface->bcast))
1995132451Sroberto				: 4);
1996132451Sroberto		}
1997182007Sroberto		im->flags = htonl(md->cast_flags);
199854359Sroberto		im->port = md->rmtport;
199954359Sroberto		im->mode = md->mode;
200054359Sroberto		im->version = md->version;
200154359Sroberto		im = (struct info_monitor_1 *)more_pkt();
200254359Sroberto	}
200354359Sroberto	flush_pkt();
200454359Sroberto}
200554359Sroberto
200654359Sroberto/*
200754359Sroberto * Module entry points and the flags they correspond with
200854359Sroberto */
200954359Srobertostruct reset_entry {
201054359Sroberto	int flag;		/* flag this corresponds to */
201154359Sroberto	void (*handler) P((void)); /* routine to handle request */
201254359Sroberto};
201354359Sroberto
201454359Srobertostruct reset_entry reset_entries[] = {
201554359Sroberto	{ RESET_FLAG_ALLPEERS,	peer_all_reset },
201654359Sroberto	{ RESET_FLAG_IO,	io_clr_stats },
201754359Sroberto	{ RESET_FLAG_SYS,	proto_clr_stats },
201854359Sroberto	{ RESET_FLAG_MEM,	peer_clr_stats },
201954359Sroberto	{ RESET_FLAG_TIMER,	timer_clr_stats },
202054359Sroberto	{ RESET_FLAG_AUTH,	reset_auth_stats },
202154359Sroberto	{ RESET_FLAG_CTL,	ctl_clr_stats },
202254359Sroberto	{ 0,			0 }
202354359Sroberto};
202454359Sroberto
202554359Sroberto/*
202654359Sroberto * reset_stats - reset statistic counters here and there
202754359Sroberto */
202854359Srobertostatic void
202954359Srobertoreset_stats(
2030132451Sroberto	struct sockaddr_storage *srcadr,
203154359Sroberto	struct interface *inter,
203254359Sroberto	struct req_pkt *inpkt
203354359Sroberto	)
203454359Sroberto{
203554359Sroberto	u_long flags;
203654359Sroberto	struct reset_entry *rent;
203754359Sroberto
203854359Sroberto	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
203982498Sroberto		msyslog(LOG_ERR, "reset_stats: err_nitems > 1");
204054359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
204154359Sroberto		return;
204254359Sroberto	}
204354359Sroberto
204454359Sroberto	flags = ((struct reset_flags *)inpkt->data)->flags;
2045182007Sroberto	flags = ntohl(flags);
2046182007Sroberto
204754359Sroberto	if (flags & ~RESET_ALLFLAGS) {
204882498Sroberto		msyslog(LOG_ERR, "reset_stats: reset leaves %#lx",
204982498Sroberto			flags & ~RESET_ALLFLAGS);
205054359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
205154359Sroberto		return;
205254359Sroberto	}
205354359Sroberto
205454359Sroberto	for (rent = reset_entries; rent->flag != 0; rent++) {
205554359Sroberto		if (flags & rent->flag)
205654359Sroberto		    (rent->handler)();
205754359Sroberto	}
205854359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
205954359Sroberto}
206054359Sroberto
206154359Sroberto
206254359Sroberto/*
206354359Sroberto * reset_peer - clear a peer's statistics
206454359Sroberto */
206554359Srobertostatic void
206654359Srobertoreset_peer(
2067132451Sroberto	struct sockaddr_storage *srcadr,
206854359Sroberto	struct interface *inter,
206954359Sroberto	struct req_pkt *inpkt
207054359Sroberto	)
207154359Sroberto{
207254359Sroberto	register struct conf_unpeer *cp;
207354359Sroberto	register int items;
207454359Sroberto	register struct peer *peer;
2075132451Sroberto	struct sockaddr_storage peeraddr;
207654359Sroberto	int bad;
207754359Sroberto
207854359Sroberto	/*
207954359Sroberto	 * We check first to see that every peer exists.  If not,
208054359Sroberto	 * we return an error.
208154359Sroberto	 */
208254359Sroberto
208354359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
208454359Sroberto	cp = (struct conf_unpeer *)inpkt->data;
208554359Sroberto
208654359Sroberto	bad = 0;
208754359Sroberto	while (items-- > 0 && !bad) {
2088132451Sroberto		memset((char *)&peeraddr, 0, sizeof(peeraddr));
2089132451Sroberto		if (client_v6_capable && cp->v6_flag != 0) {
2090132451Sroberto			GET_INADDR6(peeraddr) = cp->peeraddr6;
2091132451Sroberto			peeraddr.ss_family = AF_INET6;
2092132451Sroberto		} else {
2093132451Sroberto			GET_INADDR(peeraddr) = cp->peeraddr;
2094132451Sroberto			peeraddr.ss_family = AF_INET;
2095132451Sroberto		}
2096132451Sroberto		NSRCPORT(&peeraddr) = htons(NTP_PORT);
2097132451Sroberto#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
2098132451Sroberto		peeraddr.ss_len = SOCKLEN(&peeraddr);
2099132451Sroberto#endif
210054359Sroberto		peer = findexistingpeer(&peeraddr, (struct peer *)0, -1);
210154359Sroberto		if (peer == (struct peer *)0)
210254359Sroberto		    bad++;
2103132451Sroberto		cp = (struct conf_unpeer *)((char *)cp +
2104132451Sroberto		    INFO_ITEMSIZE(inpkt->mbz_itemsize));
210554359Sroberto	}
210654359Sroberto
210754359Sroberto	if (bad) {
210854359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
210954359Sroberto		return;
211054359Sroberto	}
211154359Sroberto
211254359Sroberto	/*
211354359Sroberto	 * Now do it in earnest.
211454359Sroberto	 */
211554359Sroberto
211654359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
211754359Sroberto	cp = (struct conf_unpeer *)inpkt->data;
211854359Sroberto	while (items-- > 0) {
2119132451Sroberto		memset((char *)&peeraddr, 0, sizeof(peeraddr));
2120132451Sroberto		if (client_v6_capable && cp->v6_flag != 0) {
2121132451Sroberto			GET_INADDR6(peeraddr) = cp->peeraddr6;
2122132451Sroberto			peeraddr.ss_family = AF_INET6;
2123132451Sroberto		} else {
2124132451Sroberto			GET_INADDR(peeraddr) = cp->peeraddr;
2125132451Sroberto			peeraddr.ss_family = AF_INET;
2126132451Sroberto		}
2127132451Sroberto#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
2128132451Sroberto		peeraddr.ss_len = SOCKLEN(&peeraddr);
2129132451Sroberto#endif
213054359Sroberto		peer = findexistingpeer(&peeraddr, (struct peer *)0, -1);
213154359Sroberto		while (peer != 0) {
213254359Sroberto			peer_reset(peer);
213354359Sroberto			peer = findexistingpeer(&peeraddr, (struct peer *)peer, -1);
213454359Sroberto		}
2135132451Sroberto		cp = (struct conf_unpeer *)((char *)cp +
2136132451Sroberto		    INFO_ITEMSIZE(inpkt->mbz_itemsize));
213754359Sroberto	}
213854359Sroberto
213954359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
214054359Sroberto}
214154359Sroberto
214254359Sroberto
214354359Sroberto/*
214454359Sroberto * do_key_reread - reread the encryption key file
214554359Sroberto */
214654359Srobertostatic void
214754359Srobertodo_key_reread(
2148132451Sroberto	struct sockaddr_storage *srcadr,
214954359Sroberto	struct interface *inter,
215054359Sroberto	struct req_pkt *inpkt
215154359Sroberto	)
215254359Sroberto{
215354359Sroberto	rereadkeys();
215454359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
215554359Sroberto}
215654359Sroberto
215754359Sroberto
215854359Sroberto/*
215954359Sroberto * trust_key - make one or more keys trusted
216054359Sroberto */
216154359Srobertostatic void
216254359Srobertotrust_key(
2163132451Sroberto	struct sockaddr_storage *srcadr,
216454359Sroberto	struct interface *inter,
216554359Sroberto	struct req_pkt *inpkt
216654359Sroberto	)
216754359Sroberto{
216854359Sroberto	do_trustkey(srcadr, inter, inpkt, 1);
216954359Sroberto}
217054359Sroberto
217154359Sroberto
217254359Sroberto/*
217354359Sroberto * untrust_key - make one or more keys untrusted
217454359Sroberto */
217554359Srobertostatic void
217654359Srobertountrust_key(
2177132451Sroberto	struct sockaddr_storage *srcadr,
217854359Sroberto	struct interface *inter,
217954359Sroberto	struct req_pkt *inpkt
218054359Sroberto	)
218154359Sroberto{
218254359Sroberto	do_trustkey(srcadr, inter, inpkt, 0);
218354359Sroberto}
218454359Sroberto
218554359Sroberto
218654359Sroberto/*
218754359Sroberto * do_trustkey - make keys either trustable or untrustable
218854359Sroberto */
218954359Srobertostatic void
219054359Srobertodo_trustkey(
2191132451Sroberto	struct sockaddr_storage *srcadr,
219254359Sroberto	struct interface *inter,
219354359Sroberto	struct req_pkt *inpkt,
219482498Sroberto	u_long trust
219554359Sroberto	)
219654359Sroberto{
219754359Sroberto	register u_long *kp;
219854359Sroberto	register int items;
219954359Sroberto
220054359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
220154359Sroberto	kp = (u_long *)inpkt->data;
220254359Sroberto	while (items-- > 0) {
220354359Sroberto		authtrust(*kp, trust);
220454359Sroberto		kp++;
220554359Sroberto	}
220654359Sroberto
220754359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
220854359Sroberto}
220954359Sroberto
221054359Sroberto
221154359Sroberto/*
221254359Sroberto * get_auth_info - return some stats concerning the authentication module
221354359Sroberto */
221454359Srobertostatic void
221554359Srobertoget_auth_info(
2216132451Sroberto	struct sockaddr_storage *srcadr,
221754359Sroberto	struct interface *inter,
221854359Sroberto	struct req_pkt *inpkt
221954359Sroberto	)
222054359Sroberto{
222154359Sroberto	register struct info_auth *ia;
222254359Sroberto
222354359Sroberto	/*
222454359Sroberto	 * Importations from the authentication module
222554359Sroberto	 */
222654359Sroberto	extern u_long authnumkeys;
222754359Sroberto	extern int authnumfreekeys;
222854359Sroberto	extern u_long authkeylookups;
222954359Sroberto	extern u_long authkeynotfound;
223054359Sroberto	extern u_long authencryptions;
223154359Sroberto	extern u_long authdecryptions;
223254359Sroberto	extern u_long authkeyuncached;
223354359Sroberto	extern u_long authkeyexpired;
223454359Sroberto
223554359Sroberto	ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt,
223654359Sroberto					     sizeof(struct info_auth));
223754359Sroberto
223854359Sroberto	ia->numkeys = htonl((u_int32)authnumkeys);
223954359Sroberto	ia->numfreekeys = htonl((u_int32)authnumfreekeys);
224054359Sroberto	ia->keylookups = htonl((u_int32)authkeylookups);
224154359Sroberto	ia->keynotfound = htonl((u_int32)authkeynotfound);
224254359Sroberto	ia->encryptions = htonl((u_int32)authencryptions);
224354359Sroberto	ia->decryptions = htonl((u_int32)authdecryptions);
224454359Sroberto	ia->keyuncached = htonl((u_int32)authkeyuncached);
224554359Sroberto	ia->expired = htonl((u_int32)authkeyexpired);
224654359Sroberto	ia->timereset = htonl((u_int32)(current_time - auth_timereset));
224754359Sroberto
224854359Sroberto	(void) more_pkt();
224954359Sroberto	flush_pkt();
225054359Sroberto}
225154359Sroberto
225254359Sroberto
225354359Sroberto
225454359Sroberto/*
225554359Sroberto * reset_auth_stats - reset the authentication stat counters.  Done here
225654359Sroberto *		      to keep ntp-isms out of the authentication module
225754359Sroberto */
225854359Srobertostatic void
225954359Srobertoreset_auth_stats(void)
226054359Sroberto{
226154359Sroberto	/*
226254359Sroberto	 * Importations from the authentication module
226354359Sroberto	 */
226454359Sroberto	extern u_long authkeylookups;
226554359Sroberto	extern u_long authkeynotfound;
226654359Sroberto	extern u_long authencryptions;
226754359Sroberto	extern u_long authdecryptions;
226854359Sroberto	extern u_long authkeyuncached;
226954359Sroberto
227054359Sroberto	authkeylookups = 0;
227154359Sroberto	authkeynotfound = 0;
227254359Sroberto	authencryptions = 0;
227354359Sroberto	authdecryptions = 0;
227454359Sroberto	authkeyuncached = 0;
227554359Sroberto	auth_timereset = current_time;
227654359Sroberto}
227754359Sroberto
227854359Sroberto
227954359Sroberto/*
228054359Sroberto * req_get_traps - return information about current trap holders
228154359Sroberto */
228254359Srobertostatic void
228354359Srobertoreq_get_traps(
2284132451Sroberto	struct sockaddr_storage *srcadr,
228554359Sroberto	struct interface *inter,
228654359Sroberto	struct req_pkt *inpkt
228754359Sroberto	)
228854359Sroberto{
228954359Sroberto	register struct info_trap *it;
229054359Sroberto	register struct ctl_trap *tr;
229154359Sroberto	register int i;
229254359Sroberto
229354359Sroberto	/*
229454359Sroberto	 * Imported from the control module
229554359Sroberto	 */
229654359Sroberto	extern struct ctl_trap ctl_trap[];
229754359Sroberto	extern int num_ctl_traps;
229854359Sroberto
229954359Sroberto	if (num_ctl_traps == 0) {
230054359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
230154359Sroberto		return;
230254359Sroberto	}
230354359Sroberto
230454359Sroberto	it = (struct info_trap *)prepare_pkt(srcadr, inter, inpkt,
2305132451Sroberto	    v6sizeof(struct info_trap));
230654359Sroberto
230754359Sroberto	for (i = 0, tr = ctl_trap; i < CTL_MAXTRAPS; i++, tr++) {
230854359Sroberto		if (tr->tr_flags & TRAP_INUSE) {
2309132451Sroberto			if (tr->tr_addr.ss_family == AF_INET) {
2310132451Sroberto				if (tr->tr_localaddr == any_interface)
2311132451Sroberto					it->local_address = 0;
2312132451Sroberto				else
2313132451Sroberto					it->local_address
2314132451Sroberto					    = GET_INADDR(tr->tr_localaddr->sin);
2315132451Sroberto				it->trap_address = GET_INADDR(tr->tr_addr);
2316132451Sroberto				if (client_v6_capable)
2317132451Sroberto					it->v6_flag = 0;
2318132451Sroberto			} else {
2319132451Sroberto				if (!client_v6_capable)
2320132451Sroberto					continue;
2321132451Sroberto				it->local_address6
2322132451Sroberto				    = GET_INADDR6(tr->tr_localaddr->sin);
2323132451Sroberto				it->trap_address6 = GET_INADDR6(tr->tr_addr);
2324132451Sroberto				it->v6_flag = 1;
2325132451Sroberto			}
232654359Sroberto			it->trap_port = NSRCPORT(&tr->tr_addr);
232754359Sroberto			it->sequence = htons(tr->tr_sequence);
232854359Sroberto			it->settime = htonl((u_int32)(current_time - tr->tr_settime));
232954359Sroberto			it->origtime = htonl((u_int32)(current_time - tr->tr_origtime));
233054359Sroberto			it->resets = htonl((u_int32)tr->tr_resets);
233154359Sroberto			it->flags = htonl((u_int32)tr->tr_flags);
233254359Sroberto			it = (struct info_trap *)more_pkt();
233354359Sroberto		}
233454359Sroberto	}
233554359Sroberto	flush_pkt();
233654359Sroberto}
233754359Sroberto
233854359Sroberto
233954359Sroberto/*
234054359Sroberto * req_set_trap - configure a trap
234154359Sroberto */
234254359Srobertostatic void
234354359Srobertoreq_set_trap(
2344132451Sroberto	struct sockaddr_storage *srcadr,
234554359Sroberto	struct interface *inter,
234654359Sroberto	struct req_pkt *inpkt
234754359Sroberto	)
234854359Sroberto{
234954359Sroberto	do_setclr_trap(srcadr, inter, inpkt, 1);
235054359Sroberto}
235154359Sroberto
235254359Sroberto
235354359Sroberto
235454359Sroberto/*
235554359Sroberto * req_clr_trap - unconfigure a trap
235654359Sroberto */
235754359Srobertostatic void
235854359Srobertoreq_clr_trap(
2359132451Sroberto	struct sockaddr_storage *srcadr,
236054359Sroberto	struct interface *inter,
236154359Sroberto	struct req_pkt *inpkt
236254359Sroberto	)
236354359Sroberto{
236454359Sroberto	do_setclr_trap(srcadr, inter, inpkt, 0);
236554359Sroberto}
236654359Sroberto
236754359Sroberto
236854359Sroberto
236954359Sroberto/*
237054359Sroberto * do_setclr_trap - do the grunge work of (un)configuring a trap
237154359Sroberto */
237254359Srobertostatic void
237354359Srobertodo_setclr_trap(
2374132451Sroberto	struct sockaddr_storage *srcadr,
237554359Sroberto	struct interface *inter,
237654359Sroberto	struct req_pkt *inpkt,
237754359Sroberto	int set
237854359Sroberto	)
237954359Sroberto{
238054359Sroberto	register struct conf_trap *ct;
238154359Sroberto	register struct interface *linter;
238254359Sroberto	int res;
2383132451Sroberto	struct sockaddr_storage laddr;
238454359Sroberto
238554359Sroberto	/*
2386132451Sroberto	 * Prepare sockaddr_storage structure
238754359Sroberto	 */
238854359Sroberto	memset((char *)&laddr, 0, sizeof laddr);
2389132451Sroberto	laddr.ss_family = srcadr->ss_family;
2390132451Sroberto	NSRCPORT(&laddr) = ntohs(NTP_PORT);
239154359Sroberto
239254359Sroberto	/*
239354359Sroberto	 * Restrict ourselves to one item only.  This eliminates
239454359Sroberto	 * the error reporting problem.
239554359Sroberto	 */
239654359Sroberto	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
239782498Sroberto		msyslog(LOG_ERR, "do_setclr_trap: err_nitems > 1");
239854359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
239954359Sroberto		return;
240054359Sroberto	}
240154359Sroberto	ct = (struct conf_trap *)inpkt->data;
240254359Sroberto
240354359Sroberto	/*
240454359Sroberto	 * Look for the local interface.  If none, use the default.
240554359Sroberto	 */
240654359Sroberto	if (ct->local_address == 0) {
240754359Sroberto		linter = any_interface;
240854359Sroberto	} else {
2409132451Sroberto		if (laddr.ss_family == AF_INET)
2410132451Sroberto			GET_INADDR(laddr) = ct->local_address;
2411132451Sroberto		else
2412132451Sroberto			GET_INADDR6(laddr) = ct->local_address6;
241354359Sroberto		linter = findinterface(&laddr);
241454359Sroberto		if (linter == NULL) {
241554359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
241654359Sroberto			return;
241754359Sroberto		}
241854359Sroberto	}
241954359Sroberto
2420132451Sroberto	if (laddr.ss_family == AF_INET)
2421132451Sroberto		GET_INADDR(laddr) = ct->trap_address;
2422132451Sroberto	else
2423132451Sroberto		GET_INADDR6(laddr) = ct->trap_address6;
242454359Sroberto	if (ct->trap_port != 0)
2425132451Sroberto	    NSRCPORT(&laddr) = ct->trap_port;
242654359Sroberto	else
2427132451Sroberto	    NSRCPORT(&laddr) = htons(TRAPPORT);
242854359Sroberto
242954359Sroberto	if (set) {
243054359Sroberto		res = ctlsettrap(&laddr, linter, 0,
243154359Sroberto				 INFO_VERSION(inpkt->rm_vn_mode));
243254359Sroberto	} else {
243354359Sroberto		res = ctlclrtrap(&laddr, linter, 0);
243454359Sroberto	}
243554359Sroberto
243654359Sroberto	if (!res) {
243754359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
243854359Sroberto	} else {
243954359Sroberto		req_ack(srcadr, inter, inpkt, INFO_OKAY);
244054359Sroberto	}
244154359Sroberto	return;
244254359Sroberto}
244354359Sroberto
244454359Sroberto
244554359Sroberto
244654359Sroberto/*
244754359Sroberto * set_request_keyid - set the keyid used to authenticate requests
244854359Sroberto */
244954359Srobertostatic void
245054359Srobertoset_request_keyid(
2451132451Sroberto	struct sockaddr_storage *srcadr,
245254359Sroberto	struct interface *inter,
245354359Sroberto	struct req_pkt *inpkt
245454359Sroberto	)
245554359Sroberto{
245682498Sroberto	keyid_t keyid;
245754359Sroberto
245854359Sroberto	/*
245954359Sroberto	 * Restrict ourselves to one item only.
246054359Sroberto	 */
246154359Sroberto	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
246282498Sroberto		msyslog(LOG_ERR, "set_request_keyid: err_nitems > 1");
246354359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
246454359Sroberto		return;
246554359Sroberto	}
246654359Sroberto
246754359Sroberto	keyid = ntohl(*((u_int32 *)(inpkt->data)));
246854359Sroberto	info_auth_keyid = keyid;
246954359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
247054359Sroberto}
247154359Sroberto
247254359Sroberto
247354359Sroberto
247454359Sroberto/*
247554359Sroberto * set_control_keyid - set the keyid used to authenticate requests
247654359Sroberto */
247754359Srobertostatic void
247854359Srobertoset_control_keyid(
2479132451Sroberto	struct sockaddr_storage *srcadr,
248054359Sroberto	struct interface *inter,
248154359Sroberto	struct req_pkt *inpkt
248254359Sroberto	)
248354359Sroberto{
248482498Sroberto	keyid_t keyid;
248582498Sroberto	extern keyid_t ctl_auth_keyid;
248654359Sroberto
248754359Sroberto	/*
248854359Sroberto	 * Restrict ourselves to one item only.
248954359Sroberto	 */
249054359Sroberto	if (INFO_NITEMS(inpkt->err_nitems) > 1) {
249182498Sroberto		msyslog(LOG_ERR, "set_control_keyid: err_nitems > 1");
249254359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
249354359Sroberto		return;
249454359Sroberto	}
249554359Sroberto
249654359Sroberto	keyid = ntohl(*((u_int32 *)(inpkt->data)));
249754359Sroberto	ctl_auth_keyid = keyid;
249854359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
249954359Sroberto}
250054359Sroberto
250154359Sroberto
250254359Sroberto
250354359Sroberto/*
250454359Sroberto * get_ctl_stats - return some stats concerning the control message module
250554359Sroberto */
250654359Srobertostatic void
250754359Srobertoget_ctl_stats(
2508132451Sroberto	struct sockaddr_storage *srcadr,
250954359Sroberto	struct interface *inter,
251054359Sroberto	struct req_pkt *inpkt
251154359Sroberto	)
251254359Sroberto{
251354359Sroberto	register struct info_control *ic;
251454359Sroberto
251554359Sroberto	/*
251654359Sroberto	 * Importations from the control module
251754359Sroberto	 */
251854359Sroberto	extern u_long ctltimereset;
251954359Sroberto	extern u_long numctlreq;
252054359Sroberto	extern u_long numctlbadpkts;
252154359Sroberto	extern u_long numctlresponses;
252254359Sroberto	extern u_long numctlfrags;
252354359Sroberto	extern u_long numctlerrors;
252454359Sroberto	extern u_long numctltooshort;
252554359Sroberto	extern u_long numctlinputresp;
252654359Sroberto	extern u_long numctlinputfrag;
252754359Sroberto	extern u_long numctlinputerr;
252854359Sroberto	extern u_long numctlbadoffset;
252954359Sroberto	extern u_long numctlbadversion;
253054359Sroberto	extern u_long numctldatatooshort;
253154359Sroberto	extern u_long numctlbadop;
253254359Sroberto	extern u_long numasyncmsgs;
253354359Sroberto
253454359Sroberto	ic = (struct info_control *)prepare_pkt(srcadr, inter, inpkt,
253554359Sroberto						sizeof(struct info_control));
253654359Sroberto
253754359Sroberto	ic->ctltimereset = htonl((u_int32)(current_time - ctltimereset));
253854359Sroberto	ic->numctlreq = htonl((u_int32)numctlreq);
253954359Sroberto	ic->numctlbadpkts = htonl((u_int32)numctlbadpkts);
254054359Sroberto	ic->numctlresponses = htonl((u_int32)numctlresponses);
254154359Sroberto	ic->numctlfrags = htonl((u_int32)numctlfrags);
254254359Sroberto	ic->numctlerrors = htonl((u_int32)numctlerrors);
254354359Sroberto	ic->numctltooshort = htonl((u_int32)numctltooshort);
254454359Sroberto	ic->numctlinputresp = htonl((u_int32)numctlinputresp);
254554359Sroberto	ic->numctlinputfrag = htonl((u_int32)numctlinputfrag);
254654359Sroberto	ic->numctlinputerr = htonl((u_int32)numctlinputerr);
254754359Sroberto	ic->numctlbadoffset = htonl((u_int32)numctlbadoffset);
254854359Sroberto	ic->numctlbadversion = htonl((u_int32)numctlbadversion);
254954359Sroberto	ic->numctldatatooshort = htonl((u_int32)numctldatatooshort);
255054359Sroberto	ic->numctlbadop = htonl((u_int32)numctlbadop);
255154359Sroberto	ic->numasyncmsgs = htonl((u_int32)numasyncmsgs);
255254359Sroberto
255354359Sroberto	(void) more_pkt();
255454359Sroberto	flush_pkt();
255554359Sroberto}
255654359Sroberto
255754359Sroberto
255854359Sroberto#ifdef KERNEL_PLL
255954359Sroberto/*
256054359Sroberto * get_kernel_info - get kernel pll/pps information
256154359Sroberto */
256254359Srobertostatic void
256354359Srobertoget_kernel_info(
2564132451Sroberto	struct sockaddr_storage *srcadr,
256554359Sroberto	struct interface *inter,
256654359Sroberto	struct req_pkt *inpkt
256754359Sroberto	)
256854359Sroberto{
256954359Sroberto	register struct info_kernel *ik;
257054359Sroberto	struct timex ntx;
257154359Sroberto
257254359Sroberto	if (!pll_control) {
257354359Sroberto		req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
257454359Sroberto		return;
257554359Sroberto	}
257654359Sroberto
257754359Sroberto	memset((char *)&ntx, 0, sizeof(ntx));
257854359Sroberto	if (ntp_adjtime(&ntx) < 0)
257954359Sroberto		msyslog(LOG_ERR, "get_kernel_info: ntp_adjtime() failed: %m");
258054359Sroberto	ik = (struct info_kernel *)prepare_pkt(srcadr, inter, inpkt,
258154359Sroberto	    sizeof(struct info_kernel));
258254359Sroberto
258354359Sroberto	/*
258454359Sroberto	 * pll variables
258554359Sroberto	 */
258654359Sroberto	ik->offset = htonl((u_int32)ntx.offset);
258754359Sroberto	ik->freq = htonl((u_int32)ntx.freq);
258854359Sroberto	ik->maxerror = htonl((u_int32)ntx.maxerror);
258954359Sroberto	ik->esterror = htonl((u_int32)ntx.esterror);
259054359Sroberto	ik->status = htons(ntx.status);
259154359Sroberto	ik->constant = htonl((u_int32)ntx.constant);
259254359Sroberto	ik->precision = htonl((u_int32)ntx.precision);
259354359Sroberto	ik->tolerance = htonl((u_int32)ntx.tolerance);
259454359Sroberto
259554359Sroberto	/*
259654359Sroberto	 * pps variables
259754359Sroberto	 */
259854359Sroberto	ik->ppsfreq = htonl((u_int32)ntx.ppsfreq);
259954359Sroberto	ik->jitter = htonl((u_int32)ntx.jitter);
260054359Sroberto	ik->shift = htons(ntx.shift);
260154359Sroberto	ik->stabil = htonl((u_int32)ntx.stabil);
260254359Sroberto	ik->jitcnt = htonl((u_int32)ntx.jitcnt);
260354359Sroberto	ik->calcnt = htonl((u_int32)ntx.calcnt);
260454359Sroberto	ik->errcnt = htonl((u_int32)ntx.errcnt);
260554359Sroberto	ik->stbcnt = htonl((u_int32)ntx.stbcnt);
260654359Sroberto
260754359Sroberto	(void) more_pkt();
260854359Sroberto	flush_pkt();
260954359Sroberto}
261054359Sroberto#endif /* KERNEL_PLL */
261154359Sroberto
261254359Sroberto
261354359Sroberto#ifdef REFCLOCK
261454359Sroberto/*
261554359Sroberto * get_clock_info - get info about a clock
261654359Sroberto */
261754359Srobertostatic void
261854359Srobertoget_clock_info(
2619132451Sroberto	struct sockaddr_storage *srcadr,
262054359Sroberto	struct interface *inter,
262154359Sroberto	struct req_pkt *inpkt
262254359Sroberto	)
262354359Sroberto{
262454359Sroberto	register struct info_clock *ic;
262554359Sroberto	register u_int32 *clkaddr;
262654359Sroberto	register int items;
262754359Sroberto	struct refclockstat clock_stat;
2628132451Sroberto	struct sockaddr_storage addr;
2629132451Sroberto	struct sockaddr_in tmp_clock;
263054359Sroberto	l_fp ltmp;
263154359Sroberto
263254359Sroberto	memset((char *)&addr, 0, sizeof addr);
2633132451Sroberto	addr.ss_family = AF_INET;
2634132451Sroberto#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
2635132451Sroberto	addr.ss_len = SOCKLEN(&addr);
2636132451Sroberto#endif
2637132451Sroberto	NSRCPORT(&addr) = htons(NTP_PORT);
263854359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
263954359Sroberto	clkaddr = (u_int32 *) inpkt->data;
264054359Sroberto
264154359Sroberto	ic = (struct info_clock *)prepare_pkt(srcadr, inter, inpkt,
264254359Sroberto					      sizeof(struct info_clock));
264354359Sroberto
264454359Sroberto	while (items-- > 0) {
2645132451Sroberto		tmp_clock.sin_addr.s_addr = *clkaddr++;
2646132451Sroberto		CAST_V4(addr)->sin_addr = tmp_clock.sin_addr;
2647132451Sroberto		if (!ISREFCLOCKADR(&tmp_clock) ||
264854359Sroberto		    findexistingpeer(&addr, (struct peer *)0, -1) == 0) {
264954359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
265054359Sroberto			return;
265154359Sroberto		}
265254359Sroberto
265354359Sroberto		clock_stat.kv_list = (struct ctl_var *)0;
265454359Sroberto
265554359Sroberto		refclock_control(&addr, (struct refclockstat *)0, &clock_stat);
265654359Sroberto
2657132451Sroberto		ic->clockadr = tmp_clock.sin_addr.s_addr;
265854359Sroberto		ic->type = clock_stat.type;
265954359Sroberto		ic->flags = clock_stat.flags;
266054359Sroberto		ic->lastevent = clock_stat.lastevent;
266154359Sroberto		ic->currentstatus = clock_stat.currentstatus;
266254359Sroberto		ic->polls = htonl((u_int32)clock_stat.polls);
266354359Sroberto		ic->noresponse = htonl((u_int32)clock_stat.noresponse);
266454359Sroberto		ic->badformat = htonl((u_int32)clock_stat.badformat);
266554359Sroberto		ic->baddata = htonl((u_int32)clock_stat.baddata);
266654359Sroberto		ic->timestarted = htonl((u_int32)clock_stat.timereset);
266754359Sroberto		DTOLFP(clock_stat.fudgetime1, &ltmp);
266854359Sroberto		HTONL_FP(&ltmp, &ic->fudgetime1);
2669132451Sroberto		DTOLFP(clock_stat.fudgetime2, &ltmp);
267054359Sroberto		HTONL_FP(&ltmp, &ic->fudgetime2);
267154359Sroberto		ic->fudgeval1 = htonl((u_int32)clock_stat.fudgeval1);
267254359Sroberto		ic->fudgeval2 = htonl((u_int32)clock_stat.fudgeval2);
267354359Sroberto
267454359Sroberto		free_varlist(clock_stat.kv_list);
267554359Sroberto
267654359Sroberto		ic = (struct info_clock *)more_pkt();
267754359Sroberto	}
267854359Sroberto	flush_pkt();
267954359Sroberto}
268054359Sroberto
268154359Sroberto
268254359Sroberto
268354359Sroberto/*
268454359Sroberto * set_clock_fudge - get a clock's fudge factors
268554359Sroberto */
268654359Srobertostatic void
268754359Srobertoset_clock_fudge(
2688132451Sroberto	struct sockaddr_storage *srcadr,
268954359Sroberto	struct interface *inter,
269054359Sroberto	struct req_pkt *inpkt
269154359Sroberto	)
269254359Sroberto{
269354359Sroberto	register struct conf_fudge *cf;
269454359Sroberto	register int items;
269554359Sroberto	struct refclockstat clock_stat;
2696132451Sroberto	struct sockaddr_storage addr;
2697132451Sroberto	struct sockaddr_in tmp_clock;
269854359Sroberto	l_fp ltmp;
269954359Sroberto
270054359Sroberto	memset((char *)&addr, 0, sizeof addr);
270154359Sroberto	memset((char *)&clock_stat, 0, sizeof clock_stat);
270254359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
270354359Sroberto	cf = (struct conf_fudge *) inpkt->data;
270454359Sroberto
270554359Sroberto	while (items-- > 0) {
2706132451Sroberto		tmp_clock.sin_addr.s_addr = cf->clockadr;
2707132451Sroberto		*CAST_V4(addr) = tmp_clock;
2708132451Sroberto		addr.ss_family = AF_INET;
2709132451Sroberto#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
2710132451Sroberto		addr.ss_len = SOCKLEN(&addr);
2711132451Sroberto#endif
2712132451Sroberto		NSRCPORT(&addr) = htons(NTP_PORT);
2713132451Sroberto		if (!ISREFCLOCKADR(&tmp_clock) ||
271454359Sroberto		    findexistingpeer(&addr, (struct peer *)0, -1) == 0) {
271554359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
271654359Sroberto			return;
271754359Sroberto		}
271854359Sroberto
271954359Sroberto		switch(ntohl(cf->which)) {
272054359Sroberto		    case FUDGE_TIME1:
272154359Sroberto			NTOHL_FP(&cf->fudgetime, &ltmp);
272254359Sroberto			LFPTOD(&ltmp, clock_stat.fudgetime1);
272354359Sroberto			clock_stat.haveflags = CLK_HAVETIME1;
272454359Sroberto			break;
272554359Sroberto		    case FUDGE_TIME2:
272654359Sroberto			NTOHL_FP(&cf->fudgetime, &ltmp);
272754359Sroberto			LFPTOD(&ltmp, clock_stat.fudgetime2);
272854359Sroberto			clock_stat.haveflags = CLK_HAVETIME2;
272954359Sroberto			break;
273054359Sroberto		    case FUDGE_VAL1:
273154359Sroberto			clock_stat.fudgeval1 = ntohl(cf->fudgeval_flags);
273254359Sroberto			clock_stat.haveflags = CLK_HAVEVAL1;
273354359Sroberto			break;
273454359Sroberto		    case FUDGE_VAL2:
273554359Sroberto			clock_stat.fudgeval2 = ntohl(cf->fudgeval_flags);
273654359Sroberto			clock_stat.haveflags = CLK_HAVEVAL2;
273754359Sroberto			break;
273854359Sroberto		    case FUDGE_FLAGS:
2739132451Sroberto			clock_stat.flags = (u_char) (ntohl(cf->fudgeval_flags) & 0xf);
274054359Sroberto			clock_stat.haveflags =
274154359Sroberto				(CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4);
274254359Sroberto			break;
274354359Sroberto		    default:
274482498Sroberto			msyslog(LOG_ERR, "set_clock_fudge: default!");
274554359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
274654359Sroberto			return;
274754359Sroberto		}
274854359Sroberto
274954359Sroberto		refclock_control(&addr, &clock_stat, (struct refclockstat *)0);
275054359Sroberto	}
275154359Sroberto
275254359Sroberto	req_ack(srcadr, inter, inpkt, INFO_OKAY);
275354359Sroberto}
275454359Sroberto#endif
275554359Sroberto
275654359Sroberto#ifdef REFCLOCK
275754359Sroberto/*
275854359Sroberto * get_clkbug_info - get debugging info about a clock
275954359Sroberto */
276054359Srobertostatic void
276154359Srobertoget_clkbug_info(
2762132451Sroberto	struct sockaddr_storage *srcadr,
276354359Sroberto	struct interface *inter,
276454359Sroberto	struct req_pkt *inpkt
276554359Sroberto	)
276654359Sroberto{
276754359Sroberto	register int i;
276854359Sroberto	register struct info_clkbug *ic;
276954359Sroberto	register u_int32 *clkaddr;
277054359Sroberto	register int items;
277154359Sroberto	struct refclockbug bug;
2772132451Sroberto	struct sockaddr_storage addr;
2773132451Sroberto	struct sockaddr_in tmp_clock;
277454359Sroberto
277554359Sroberto	memset((char *)&addr, 0, sizeof addr);
2776132451Sroberto	addr.ss_family = AF_INET;
2777132451Sroberto#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
2778132451Sroberto	addr.ss_len = SOCKLEN(&addr);
2779132451Sroberto#endif
2780132451Sroberto	NSRCPORT(&addr) = htons(NTP_PORT);
278154359Sroberto	items = INFO_NITEMS(inpkt->err_nitems);
278254359Sroberto	clkaddr = (u_int32 *) inpkt->data;
278354359Sroberto
278454359Sroberto	ic = (struct info_clkbug *)prepare_pkt(srcadr, inter, inpkt,
278554359Sroberto					       sizeof(struct info_clkbug));
278654359Sroberto
278754359Sroberto	while (items-- > 0) {
2788132451Sroberto		tmp_clock.sin_addr.s_addr = *clkaddr++;
2789132451Sroberto		GET_INADDR(addr) = tmp_clock.sin_addr.s_addr;
2790132451Sroberto		if (!ISREFCLOCKADR(&tmp_clock) ||
279154359Sroberto		    findexistingpeer(&addr, (struct peer *)0, -1) == 0) {
279254359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
279354359Sroberto			return;
279454359Sroberto		}
279554359Sroberto
279654359Sroberto		memset((char *)&bug, 0, sizeof bug);
279754359Sroberto		refclock_buginfo(&addr, &bug);
279854359Sroberto		if (bug.nvalues == 0 && bug.ntimes == 0) {
279954359Sroberto			req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
280054359Sroberto			return;
280154359Sroberto		}
280254359Sroberto
2803132451Sroberto		ic->clockadr = tmp_clock.sin_addr.s_addr;
280454359Sroberto		i = bug.nvalues;
280554359Sroberto		if (i > NUMCBUGVALUES)
280654359Sroberto		    i = NUMCBUGVALUES;
280754359Sroberto		ic->nvalues = (u_char)i;
280854359Sroberto		ic->svalues = htons((u_short) (bug.svalues & ((1<<i)-1)));
280954359Sroberto		while (--i >= 0)
281054359Sroberto		    ic->values[i] = htonl(bug.values[i]);
281154359Sroberto
281254359Sroberto		i = bug.ntimes;
281354359Sroberto		if (i > NUMCBUGTIMES)
281454359Sroberto		    i = NUMCBUGTIMES;
281554359Sroberto		ic->ntimes = (u_char)i;
281654359Sroberto		ic->stimes = htonl(bug.stimes);
281754359Sroberto		while (--i >= 0) {
281854359Sroberto			HTONL_FP(&bug.times[i], &ic->times[i]);
281954359Sroberto		}
282054359Sroberto
282154359Sroberto		ic = (struct info_clkbug *)more_pkt();
282254359Sroberto	}
282354359Sroberto	flush_pkt();
282454359Sroberto}
282554359Sroberto#endif
2826182007Sroberto
2827182007Sroberto/*
2828182007Sroberto * receiver of interface structures
2829182007Sroberto */
2830182007Srobertostatic void
2831182007Srobertofill_info_if_stats(void *data, interface_info_t *interface_info)
2832182007Sroberto{
2833182007Sroberto	struct info_if_stats **ifsp = (struct info_if_stats **)data;
2834182007Sroberto	struct info_if_stats *ifs = *ifsp;
2835182007Sroberto	struct interface *interface = interface_info->interface;
2836182007Sroberto
2837182007Sroberto	memset((char*)ifs, 0, sizeof(*ifs));
2838182007Sroberto
2839182007Sroberto	if (interface->sin.ss_family == AF_INET6) {
2840182007Sroberto		if (!client_v6_capable) {
2841182007Sroberto			return;
2842182007Sroberto		}
2843182007Sroberto		ifs->v6_flag = 1;
2844182007Sroberto		memcpy((char *)&ifs->unaddr.addr6, (char *)&CAST_V6(interface->sin)->sin6_addr, sizeof(struct in6_addr));
2845182007Sroberto		memcpy((char *)&ifs->unbcast.addr6, (char *)&CAST_V6(interface->bcast)->sin6_addr, sizeof(struct in6_addr));
2846182007Sroberto		memcpy((char *)&ifs->unmask.addr6, (char *)&CAST_V6(interface->mask)->sin6_addr, sizeof(struct in6_addr));
2847182007Sroberto	} else {
2848182007Sroberto		ifs->v6_flag = 0;
2849182007Sroberto		memcpy((char *)&ifs->unaddr.addr, (char *)&CAST_V4(interface->sin)->sin_addr, sizeof(struct in_addr));
2850182007Sroberto		memcpy((char *)&ifs->unbcast.addr, (char *)&CAST_V4(interface->bcast)->sin_addr, sizeof(struct in_addr));
2851182007Sroberto		memcpy((char *)&ifs->unmask.addr, (char *)&CAST_V4(interface->mask)->sin_addr, sizeof(struct in_addr));
2852182007Sroberto	}
2853182007Sroberto	ifs->v6_flag = htonl(ifs->v6_flag);
2854182007Sroberto	strcpy(ifs->name, interface->name);
2855182007Sroberto	ifs->family = htons(interface->family);
2856182007Sroberto	ifs->flags = htonl(interface->flags);
2857182007Sroberto	ifs->last_ttl = htonl(interface->last_ttl);
2858182007Sroberto	ifs->num_mcast = htonl(interface->num_mcast);
2859182007Sroberto	ifs->received = htonl(interface->received);
2860182007Sroberto	ifs->sent = htonl(interface->sent);
2861182007Sroberto	ifs->notsent = htonl(interface->notsent);
2862182007Sroberto	ifs->scopeid = htonl(interface->scopeid);
2863182007Sroberto	ifs->ifindex = htonl(interface->ifindex);
2864182007Sroberto	ifs->ifnum = htonl(interface->ifnum);
2865182007Sroberto	ifs->uptime = htonl(current_time - interface->starttime);
2866182007Sroberto	ifs->ignore_packets = interface->ignore_packets;
2867182007Sroberto	ifs->peercnt = htonl(interface->peercnt);
2868182007Sroberto	ifs->action = interface_info->action;
2869182007Sroberto
2870182007Sroberto	*ifsp = (struct info_if_stats *)more_pkt();
2871182007Sroberto}
2872182007Sroberto
2873182007Sroberto/*
2874182007Sroberto * get_if_stats - get interface statistics
2875182007Sroberto */
2876182007Srobertostatic void
2877182007Srobertoget_if_stats(
2878182007Sroberto	struct sockaddr_storage *srcadr,
2879182007Sroberto	struct interface *inter,
2880182007Sroberto	struct req_pkt *inpkt
2881182007Sroberto	)
2882182007Sroberto{
2883182007Sroberto	struct info_if_stats *ifs;
2884182007Sroberto
2885182007Sroberto	DPRINTF(3, ("wants interface statistics\n"));
2886182007Sroberto
2887182007Sroberto	ifs = (struct info_if_stats *)prepare_pkt(srcadr, inter, inpkt,
2888182007Sroberto	    v6sizeof(struct info_if_stats));
2889182007Sroberto
2890182007Sroberto	interface_enumerate(fill_info_if_stats, &ifs);
2891182007Sroberto
2892182007Sroberto	flush_pkt();
2893182007Sroberto}
2894182007Sroberto
2895182007Srobertostatic void
2896182007Srobertodo_if_reload(
2897182007Sroberto	struct sockaddr_storage *srcadr,
2898182007Sroberto	struct interface *inter,
2899182007Sroberto	struct req_pkt *inpkt
2900182007Sroberto	)
2901182007Sroberto{
2902182007Sroberto	struct info_if_stats *ifs;
2903182007Sroberto
2904182007Sroberto	DPRINTF(3, ("wants interface reload\n"));
2905182007Sroberto
2906182007Sroberto	ifs = (struct info_if_stats *)prepare_pkt(srcadr, inter, inpkt,
2907182007Sroberto	    v6sizeof(struct info_if_stats));
2908182007Sroberto
2909182007Sroberto	interface_update(fill_info_if_stats, &ifs);
2910182007Sroberto
2911182007Sroberto	flush_pkt();
2912182007Sroberto}
2913182007Sroberto
2914