154359Sroberto/*
2290000Sglebius * ntpdc_ops.c - subroutines which are called to perform operations by
3290000Sglebius *		 ntpdc
454359Sroberto */
554359Sroberto
654359Sroberto#ifdef HAVE_CONFIG_H
754359Sroberto# include <config.h>
854359Sroberto#endif
954359Sroberto
1054359Sroberto#include <stdio.h>
11132451Sroberto#include <stddef.h>
1282498Sroberto
1382498Sroberto#include "ntpdc.h"
14290000Sglebius#include "ntp_net.h"
1582498Sroberto#include "ntp_control.h"
1682498Sroberto#include "ntp_refclock.h"
1782498Sroberto#include "ntp_stdlib.h"
1882498Sroberto
1954359Sroberto#include <ctype.h>
2054359Sroberto#ifdef HAVE_SYS_TIMEX_H
2154359Sroberto# include <sys/timex.h>
2254359Sroberto#endif
2354359Sroberto#if !defined(__bsdi__) && !defined(apollo)
24290000Sglebius#ifdef HAVE_NETINET_IN_H
2554359Sroberto#include <netinet/in.h>
2654359Sroberto#endif
27290000Sglebius#endif
2854359Sroberto
2954359Sroberto#include <arpa/inet.h>
3054359Sroberto
3154359Sroberto/*
32290000Sglebius * utility functions
33290000Sglebius */
34293894Sglebiusstatic	int	checkitems	(size_t, FILE *);
35293894Sglebiusstatic	int	checkitemsize	(size_t, size_t);
36293894Sglebiusstatic	int	check1item	(size_t, FILE *);
37290000Sglebius
38290000Sglebius/*
3954359Sroberto * Declarations for command handlers in here
4054359Sroberto */
41290000Sglebiusstatic	void	peerlist	(struct parse *, FILE *);
42290000Sglebiusstatic	void	peers		(struct parse *, FILE *);
43290000Sglebiusstatic void	doconfig	(struct parse *pcmd, FILE *fp, int mode, int refc);
44290000Sglebiusstatic	void	dmpeers		(struct parse *, FILE *);
45290000Sglebiusstatic	void	dopeers		(struct parse *, FILE *, int);
46290000Sglebiusstatic	void	printpeer	(struct info_peer *, FILE *);
47290000Sglebiusstatic	void	showpeer	(struct parse *, FILE *);
48290000Sglebiusstatic	void	peerstats	(struct parse *, FILE *);
49290000Sglebiusstatic	void	loopinfo	(struct parse *, FILE *);
50290000Sglebiusstatic	void	sysinfo		(struct parse *, FILE *);
51290000Sglebiusstatic	void	sysstats	(struct parse *, FILE *);
52290000Sglebiusstatic	void	iostats		(struct parse *, FILE *);
53290000Sglebiusstatic	void	memstats	(struct parse *, FILE *);
54290000Sglebiusstatic	void	timerstats	(struct parse *, FILE *);
55290000Sglebiusstatic	void	addpeer		(struct parse *, FILE *);
56290000Sglebiusstatic	void	addserver	(struct parse *, FILE *);
57290000Sglebiusstatic	void	addrefclock	(struct parse *, FILE *);
58290000Sglebiusstatic	void	broadcast	(struct parse *, FILE *);
59290000Sglebiusstatic	void	doconfig	(struct parse *, FILE *, int, int);
60290000Sglebiusstatic	void	unconfig	(struct parse *, FILE *);
61290000Sglebiusstatic	void	set		(struct parse *, FILE *);
62290000Sglebiusstatic	void	sys_clear	(struct parse *, FILE *);
63290000Sglebiusstatic	void	doset		(struct parse *, FILE *, int);
64290000Sglebiusstatic	void	reslist		(struct parse *, FILE *);
65290000Sglebiusstatic	void	new_restrict	(struct parse *, FILE *);
66290000Sglebiusstatic	void	unrestrict	(struct parse *, FILE *);
67290000Sglebiusstatic	void	delrestrict	(struct parse *, FILE *);
68290000Sglebiusstatic	void	do_restrict	(struct parse *, FILE *, int);
69290000Sglebiusstatic	void	monlist		(struct parse *, FILE *);
70290000Sglebiusstatic	void	reset		(struct parse *, FILE *);
71290000Sglebiusstatic	void	preset		(struct parse *, FILE *);
72290000Sglebiusstatic	void	readkeys	(struct parse *, FILE *);
73290000Sglebiusstatic	void	trustkey	(struct parse *, FILE *);
74290000Sglebiusstatic	void	untrustkey	(struct parse *, FILE *);
75290000Sglebiusstatic	void	do_trustkey	(struct parse *, FILE *, int);
76290000Sglebiusstatic	void	authinfo	(struct parse *, FILE *);
77290000Sglebiusstatic	void	traps		(struct parse *, FILE *);
78290000Sglebiusstatic	void	addtrap		(struct parse *, FILE *);
79290000Sglebiusstatic	void	clrtrap		(struct parse *, FILE *);
80290000Sglebiusstatic	void	do_addclr_trap	(struct parse *, FILE *, int);
81290000Sglebiusstatic	void	requestkey	(struct parse *, FILE *);
82290000Sglebiusstatic	void	controlkey	(struct parse *, FILE *);
83290000Sglebiusstatic	void	do_changekey	(struct parse *, FILE *, int);
84290000Sglebiusstatic	void	ctlstats	(struct parse *, FILE *);
85290000Sglebiusstatic	void	clockstat	(struct parse *, FILE *);
86290000Sglebiusstatic	void	fudge		(struct parse *, FILE *);
87290000Sglebiusstatic	void	clkbug		(struct parse *, FILE *);
88290000Sglebiusstatic	void	kerninfo	(struct parse *, FILE *);
89290000Sglebiusstatic	void	get_if_stats	(struct parse *, FILE *);
90290000Sglebiusstatic	void	do_if_reload	(struct parse *, FILE *);
9154359Sroberto
9254359Sroberto/*
9354359Sroberto * Commands we understand.  Ntpdc imports this.
9454359Sroberto */
9554359Srobertostruct xcmd opcmds[] = {
96132451Sroberto	{ "listpeers",	peerlist,	{ OPT|IP_VERSION, NO, NO, NO },
97132451Sroberto	  { "-4|-6", "", "", "" },
98132451Sroberto	  "display list of peers the server knows about [IP Version]" },
99132451Sroberto	{ "peers",	peers,	{ OPT|IP_VERSION, NO, NO, NO },
100132451Sroberto	  { "-4|-6", "", "", "" },
101132451Sroberto	  "display peer summary information [IP Version]" },
102132451Sroberto	{ "dmpeers",	dmpeers,	{ OPT|IP_VERSION, NO, NO, NO },
103132451Sroberto	  { "-4|-6", "", "", "" },
104132451Sroberto	  "display peer summary info the way Dave Mills likes it (IP Version)" },
105182007Sroberto	{ "showpeer",	showpeer, 	{ NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD},
10654359Sroberto	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
10754359Sroberto	  "display detailed information for one or more peers" },
108182007Sroberto	{ "pstats",	peerstats,	{ NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD },
10954359Sroberto	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
11054359Sroberto	  "display statistical information for one or more peers" },
11154359Sroberto	{ "loopinfo",	loopinfo,	{ OPT|NTP_STR, NO, NO, NO },
11254359Sroberto	  { "oneline|multiline", "", "", "" },
11354359Sroberto	  "display loop filter information" },
11454359Sroberto	{ "sysinfo",	sysinfo,	{ NO, NO, NO, NO },
11554359Sroberto	  { "", "", "", "" },
11654359Sroberto	  "display local server information" },
11754359Sroberto	{ "sysstats",	sysstats,	{ NO, NO, NO, NO },
11854359Sroberto	  { "", "", "", "" },
11954359Sroberto	  "display local server statistics" },
12054359Sroberto	{ "memstats",	memstats,	{ NO, NO, NO, NO },
12154359Sroberto	  { "", "", "", "" },
12254359Sroberto	  "display peer memory usage statistics" },
12354359Sroberto	{ "iostats",	iostats,	{ NO, NO, NO, NO },
12454359Sroberto	  { "", "", "", "" },
12554359Sroberto	  "display I/O subsystem statistics" },
12654359Sroberto	{ "timerstats",	timerstats,	{ NO, NO, NO, NO },
12754359Sroberto	  { "", "", "", "" },
12854359Sroberto	  "display event timer subsystem statistics" },
129182007Sroberto	{ "addpeer",	addpeer,	{ NTP_ADD, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
130182007Sroberto	  { "addr", "keyid", "version", "minpoll#|prefer|burst|iburst|'minpoll N'|'maxpoll N'|'keyid N'|'version N' ..." },
13154359Sroberto	  "configure a new peer association" },
132182007Sroberto	{ "addserver",	addserver,	{ NTP_ADD, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
133182007Sroberto	  { "addr", "keyid", "version", "minpoll#|prefer|burst|iburst|'minpoll N'|'maxpoll N'|'keyid N'|'version N' ..." },
13454359Sroberto	  "configure a new server" },
135182007Sroberto	{ "addrefclock",addrefclock,	{ NTP_ADD, OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR },
13654359Sroberto	  { "addr", "mode", "minpoll|prefer", "minpoll|prefer" },
13754359Sroberto	  "configure a new server" },
138182007Sroberto	{ "broadcast",	broadcast,	{ NTP_ADD, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
13954359Sroberto	  { "addr", "keyid", "version", "minpoll" },
14054359Sroberto	  "configure broadcasting time service" },
141182007Sroberto	{ "unconfig",	unconfig,	{ NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD },
14254359Sroberto	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
14354359Sroberto	  "unconfigure existing peer assocations" },
14454359Sroberto	{ "enable",	set,		{ NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
14554359Sroberto	  { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." },
14654359Sroberto	  "set a system flag (auth, bclient, monitor, pll, kernel, stats)" },
147290000Sglebius	{ "disable",	sys_clear,	{ NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
14854359Sroberto	  { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." },
14954359Sroberto	  "clear a system flag (auth, bclient, monitor, pll, kernel, stats)" },
150132451Sroberto	{ "reslist",	reslist,	{OPT|IP_VERSION, NO, NO, NO },
151132451Sroberto	  { "-4|-6", "", "", "" },
15254359Sroberto	  "display the server's restrict list" },
153182007Sroberto	{ "restrict",	new_restrict,	{ NTP_ADD, NTP_ADD, NTP_STR, OPT|NTP_STR },
15454359Sroberto	  { "address", "mask",
15582498Sroberto	    "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer|version|kod",
15654359Sroberto	    "..." },
15754359Sroberto	  "create restrict entry/add flags to entry" },
158182007Sroberto	{ "unrestrict", unrestrict,	{ NTP_ADD, NTP_ADD, NTP_STR, OPT|NTP_STR },
15954359Sroberto	  { "address", "mask",
16082498Sroberto	    "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer|version|kod",
16154359Sroberto	    "..." },
16254359Sroberto	  "remove flags from a restrict entry" },
163182007Sroberto	{ "delrestrict", delrestrict,	{ NTP_ADD, NTP_ADD, OPT|NTP_STR, NO },
16454359Sroberto	  { "address", "mask", "ntpport", "" },
16554359Sroberto	  "delete a restrict entry" },
166182007Sroberto	{ "monlist",	monlist,	{ OPT|NTP_INT, NO, NO, NO },
16754359Sroberto	  { "version", "", "", "" },
16854359Sroberto	  "display data the server's monitor routines have collected" },
16954359Sroberto	{ "reset",	reset,		{ NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
170290000Sglebius	  { "io|sys|mem|timer|auth|ctl|allpeers", "...", "...", "..." },
17154359Sroberto	  "reset various subsystem statistics counters" },
172182007Sroberto	{ "preset",	preset,		{ NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD },
17354359Sroberto	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
17454359Sroberto	  "reset stat counters associated with particular peer(s)" },
17554359Sroberto	{ "readkeys",	readkeys,	{ NO, NO, NO, NO },
17654359Sroberto	  { "", "", "", "" },
17754359Sroberto	  "request a reread of the keys file and re-init of system keys" },
178182007Sroberto	{ "trustedkey",	trustkey,	{ NTP_UINT, OPT|NTP_UINT, OPT|NTP_UINT, OPT|NTP_UINT },
17954359Sroberto	  { "keyid", "keyid", "keyid", "keyid" },
18054359Sroberto	  "add one or more key ID's to the trusted list" },
181182007Sroberto	{ "untrustedkey", untrustkey,	{ NTP_UINT, OPT|NTP_UINT, OPT|NTP_UINT, OPT|NTP_UINT },
18254359Sroberto	  { "keyid", "keyid", "keyid", "keyid" },
18354359Sroberto	  "remove one or more key ID's from the trusted list" },
18454359Sroberto	{ "authinfo",	authinfo,	{ NO, NO, NO, NO },
18554359Sroberto	  { "", "", "", "" },
18654359Sroberto	  "display the state of the authentication code" },
18754359Sroberto	{ "traps",	traps,		{ NO, NO, NO, NO },
18854359Sroberto	  { "", "", "", "" },
18954359Sroberto	  "display the traps set in the server" },
190182007Sroberto	{ "addtrap",	addtrap,	{ NTP_ADD, OPT|NTP_UINT, OPT|NTP_ADD, NO },
19154359Sroberto	  { "address", "port", "interface", "" },
19254359Sroberto	  "configure a trap in the server" },
193182007Sroberto	{ "clrtrap",	clrtrap,	{ NTP_ADD, OPT|NTP_UINT, OPT|NTP_ADD, NO },
19454359Sroberto	  { "address", "port", "interface", "" },
19554359Sroberto	  "remove a trap (configured or otherwise) from the server" },
196182007Sroberto	{ "requestkey",	requestkey,	{ NTP_UINT, NO, NO, NO },
19754359Sroberto	  { "keyid", "", "", "" },
19854359Sroberto	  "change the keyid the server uses to authenticate requests" },
199182007Sroberto	{ "controlkey",	controlkey,	{ NTP_UINT, NO, NO, NO },
20054359Sroberto	  { "keyid", "", "", "" },
20154359Sroberto	  "change the keyid the server uses to authenticate control messages" },
20254359Sroberto	{ "ctlstats",	ctlstats,	{ NO, NO, NO, NO },
20354359Sroberto	  { "", "", "", "" },
20454359Sroberto	  "display packet count statistics from the control module" },
205182007Sroberto	{ "clockstat",	clockstat,	{ NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD },
20654359Sroberto	  { "address", "address", "address", "address" },
20754359Sroberto	  "display clock status information" },
208182007Sroberto	{ "fudge",	fudge,		{ NTP_ADD, NTP_STR, NTP_STR, NO },
20954359Sroberto	  { "address", "time1|time2|val1|val2|flags", "value", "" },
21054359Sroberto	  "set/change one of a clock's fudge factors" },
211182007Sroberto	{ "clkbug",	clkbug,		{ NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD },
21254359Sroberto	  { "address", "address", "address", "address" },
21354359Sroberto	  "display clock debugging information" },
21454359Sroberto	{ "kerninfo",	kerninfo,	{ NO, NO, NO, NO },
21554359Sroberto	  { "", "", "", "" },
21654359Sroberto	  "display the kernel pll/pps variables" },
217182007Sroberto	{ "ifstats",	get_if_stats,	{ NO, NO, NO, NO },
218182007Sroberto	  { "", "", "", "" },
219182007Sroberto	  "list interface statistics" },
220182007Sroberto	{ "ifreload",	do_if_reload,	{ NO, NO, NO, NO },
221182007Sroberto	  { "", "", "", "" },
222182007Sroberto	  "reload interface configuration" },
22354359Sroberto	{ 0,		0,		{ NO, NO, NO, NO },
22454359Sroberto	  { "", "", "", "" }, "" }
22554359Sroberto};
22654359Sroberto
22754359Sroberto/*
22854359Sroberto * For quick string comparisons
22954359Sroberto */
23054359Sroberto#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
23154359Sroberto
232290000Sglebius/*
233290000Sglebius * SET_SS_LEN_IF_PRESENT - used by SET_ADDR, SET_ADDRS macros
234290000Sglebius */
23554359Sroberto
236290000Sglebius#ifdef ISC_PLATFORM_HAVESALEN
237290000Sglebius#define SET_SS_LEN_IF_PRESENT(psau)				\
238290000Sglebius	do {							\
239290000Sglebius		(psau)->sa.sa_len = SOCKLEN(psau);		\
240290000Sglebius	} while (0)
241290000Sglebius#else
242290000Sglebius#define SET_SS_LEN_IF_PRESENT(psau)	do { } while (0)
243290000Sglebius#endif
244290000Sglebius
24554359Sroberto/*
246290000Sglebius * SET_ADDR - setup address for v4/v6 as needed
247290000Sglebius */
248290000Sglebius#define SET_ADDR(address, v6flag, v4addr, v6addr)		\
249290000Sglebiusdo {								\
250290000Sglebius	ZERO(address);						\
251290000Sglebius	if (v6flag) {						\
252290000Sglebius		AF(&(address)) = AF_INET6;			\
253290000Sglebius		SOCK_ADDR6(&(address)) = (v6addr);		\
254290000Sglebius	} else {						\
255290000Sglebius		AF(&(address)) = AF_INET;			\
256290000Sglebius		NSRCADR(&(address)) = (v4addr);			\
257290000Sglebius	}							\
258290000Sglebius	SET_SS_LEN_IF_PRESENT(&(address));			\
259290000Sglebius} while (0)
260290000Sglebius
261290000Sglebius
262290000Sglebius/*
263290000Sglebius * SET_ADDRS - setup source and destination addresses for
264290000Sglebius * v4/v6 as needed
265290000Sglebius */
266290000Sglebius#define SET_ADDRS(a1, a2, info, a1prefix, a2prefix)		\
267290000Sglebiusdo {								\
268290000Sglebius	ZERO(a1);						\
269290000Sglebius	ZERO(a2);						\
270290000Sglebius	if ((info)->v6_flag) {					\
271290000Sglebius		AF(&(a1)) = AF_INET6;				\
272290000Sglebius		AF(&(a2)) = AF_INET6;				\
273290000Sglebius		SOCK_ADDR6(&(a1)) = (info)->a1prefix##6;	\
274290000Sglebius		SOCK_ADDR6(&(a2)) = (info)->a2prefix##6;	\
275290000Sglebius	} else {						\
276290000Sglebius		AF(&(a1)) = AF_INET;				\
277290000Sglebius		AF(&(a2)) = AF_INET;				\
278290000Sglebius		NSRCADR(&(a1)) = (info)->a1prefix;		\
279290000Sglebius		NSRCADR(&(a2)) = (info)->a2prefix;		\
280290000Sglebius	}							\
281290000Sglebius	SET_SS_LEN_IF_PRESENT(&(a1));				\
282290000Sglebius	SET_SS_LEN_IF_PRESENT(&(a2));				\
283290000Sglebius} while (0)
284290000Sglebius
285290000Sglebius
286290000Sglebius/*
28754359Sroberto * checkitems - utility to print a message if no items were returned
28854359Sroberto */
28954359Srobertostatic int
29054359Srobertocheckitems(
291293894Sglebius	size_t items,
29254359Sroberto	FILE *fp
29354359Sroberto	)
29454359Sroberto{
29554359Sroberto	if (items == 0) {
29654359Sroberto		(void) fprintf(fp, "No data returned in response to query\n");
29754359Sroberto		return 0;
29854359Sroberto	}
29954359Sroberto	return 1;
30054359Sroberto}
30154359Sroberto
30254359Sroberto
30354359Sroberto/*
30454359Sroberto * checkitemsize - utility to print a message if the item size is wrong
30554359Sroberto */
30654359Srobertostatic int
30754359Srobertocheckitemsize(
308293894Sglebius	size_t itemsize,
309293894Sglebius	size_t expected
31054359Sroberto	)
31154359Sroberto{
31254359Sroberto	if (itemsize != expected) {
31354359Sroberto		(void) fprintf(stderr,
314293894Sglebius			       "***Incorrect item size returned by remote host (%lu should be %lu)\n",
315293894Sglebius			       (u_long)itemsize, (u_long)expected);
31654359Sroberto		return 0;
31754359Sroberto	}
31854359Sroberto	return 1;
31954359Sroberto}
32054359Sroberto
32154359Sroberto
32254359Sroberto/*
32354359Sroberto * check1item - check to make sure we have exactly one item
32454359Sroberto */
32554359Srobertostatic int
32654359Srobertocheck1item(
327293894Sglebius	size_t items,
32854359Sroberto	FILE *fp
32954359Sroberto	)
33054359Sroberto{
33154359Sroberto	if (items == 0) {
33254359Sroberto		(void) fprintf(fp, "No data returned in response to query\n");
33354359Sroberto		return 0;
33454359Sroberto	}
33554359Sroberto	if (items > 1) {
336293894Sglebius		(void) fprintf(fp, "Expected one item in response, got %lu\n",
337293894Sglebius			       (u_long)items);
33854359Sroberto		return 0;
33954359Sroberto	}
34054359Sroberto	return 1;
34154359Sroberto}
34254359Sroberto
34354359Sroberto
34454359Sroberto/*
34554359Sroberto * peerlist - get a short list of peers
34654359Sroberto */
34754359Sroberto/*ARGSUSED*/
34854359Srobertostatic void
34954359Srobertopeerlist(
35054359Sroberto	struct parse *pcmd,
35154359Sroberto	FILE *fp
35254359Sroberto	)
35354359Sroberto{
35454359Sroberto	struct info_peer_list *plist;
355290000Sglebius	sockaddr_u paddr;
356293894Sglebius	size_t items;
357293894Sglebius	size_t itemsize;
35854359Sroberto	int res;
35954359Sroberto
360132451Srobertoagain:
361132451Sroberto	res = doquery(impl_ver, REQ_PEER_LIST, 0, 0, 0, (char *)NULL, &items,
362132451Sroberto		      &itemsize, (void *)&plist, 0,
363132451Sroberto		      sizeof(struct info_peer_list));
36454359Sroberto
365132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
366132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
367132451Sroberto		goto again;
368132451Sroberto	}
369132451Sroberto
370182007Sroberto	if (res != 0)
37154359Sroberto	    return;
37254359Sroberto
37354359Sroberto	if (!checkitems(items, fp))
37454359Sroberto	    return;
37554359Sroberto
376132451Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_peer_list)) &&
377132451Sroberto	    !checkitemsize(itemsize, v4sizeof(struct info_peer_list)))
37854359Sroberto	    return;
37954359Sroberto
38054359Sroberto	while (items > 0) {
381290000Sglebius		SET_ADDR(paddr, plist->v6_flag, plist->addr, plist->addr6);
382132451Sroberto		if ((pcmd->nargs == 0) ||
383132451Sroberto		    ((pcmd->argval->ival == 6) && (plist->v6_flag != 0)) ||
384132451Sroberto		    ((pcmd->argval->ival == 4) && (plist->v6_flag == 0)))
385132451Sroberto			(void) fprintf(fp, "%-9s %s\n",
386132451Sroberto				modetoa(plist->hmode),
387132451Sroberto				nntohost(&paddr));
38854359Sroberto		plist++;
38954359Sroberto		items--;
39054359Sroberto	}
39154359Sroberto}
39254359Sroberto
39354359Sroberto
39454359Sroberto/*
39554359Sroberto * peers - show peer summary
39654359Sroberto */
39754359Srobertostatic void
39854359Srobertopeers(
39954359Sroberto	struct parse *pcmd,
40054359Sroberto	FILE *fp
40154359Sroberto	)
40254359Sroberto{
40354359Sroberto	dopeers(pcmd, fp, 0);
40454359Sroberto}
40554359Sroberto
40654359Sroberto/*
40754359Sroberto * dmpeers - show peer summary, Dave Mills style
40854359Sroberto */
40954359Srobertostatic void
41054359Srobertodmpeers(
41154359Sroberto	struct parse *pcmd,
41254359Sroberto	FILE *fp
41354359Sroberto	)
41454359Sroberto{
41554359Sroberto	dopeers(pcmd, fp, 1);
41654359Sroberto}
41754359Sroberto
41854359Sroberto
41954359Sroberto/*
42054359Sroberto * peers - show peer summary
42154359Sroberto */
42254359Sroberto/*ARGSUSED*/
42354359Srobertostatic void
42454359Srobertodopeers(
42554359Sroberto	struct parse *pcmd,
42654359Sroberto	FILE *fp,
42754359Sroberto	int dmstyle
42854359Sroberto	)
42954359Sroberto{
43054359Sroberto	struct info_peer_summary *plist;
431290000Sglebius	sockaddr_u dstadr;
432290000Sglebius	sockaddr_u srcadr;
433293894Sglebius	size_t items;
434293894Sglebius	size_t itemsize;
43554359Sroberto	int ntp_poll;
43654359Sroberto	int res;
43754359Sroberto	int c;
43854359Sroberto	l_fp tempts;
43954359Sroberto
440132451Srobertoagain:
441132451Sroberto	res = doquery(impl_ver, REQ_PEER_LIST_SUM, 0, 0, 0, (char *)NULL,
442132451Sroberto		      &items, &itemsize, (void *)&plist, 0,
443132451Sroberto		      sizeof(struct info_peer_summary));
44454359Sroberto
445132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
446132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
447132451Sroberto		goto again;
448132451Sroberto	}
449132451Sroberto
450182007Sroberto	if (res != 0)
45154359Sroberto	    return;
45254359Sroberto
45354359Sroberto	if (!checkitems(items, fp))
45454359Sroberto	    return;
45554359Sroberto
456132451Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_peer_summary)) &&
457132451Sroberto	    !checkitemsize(itemsize, v4sizeof(struct info_peer_summary)))
458132451Sroberto		return;
45954359Sroberto
46054359Sroberto	(void) fprintf(fp,
46154359Sroberto		       "     remote           local      st poll reach  delay   offset    disp\n");
46254359Sroberto	(void) fprintf(fp,
46354359Sroberto		       "=======================================================================\n");
46454359Sroberto	while (items > 0) {
46554359Sroberto		if (!dmstyle) {
46654359Sroberto			if (plist->flags & INFO_FLAG_SYSPEER)
46754359Sroberto			    c = '*';
46854359Sroberto			else if (plist->hmode == MODE_ACTIVE)
46954359Sroberto			    c = '+';
47054359Sroberto			else if (plist->hmode == MODE_PASSIVE)
47154359Sroberto			    c = '-';
47254359Sroberto			else if (plist->hmode == MODE_CLIENT)
47354359Sroberto			    c = '=';
47454359Sroberto			else if (plist->hmode == MODE_BROADCAST)
47554359Sroberto			    c = '^';
47654359Sroberto			else if (plist->hmode == MODE_BCLIENT)
47754359Sroberto			    c = '~';
47854359Sroberto			else
47954359Sroberto			    c = ' ';
48054359Sroberto		} else {
48154359Sroberto			if (plist->flags & INFO_FLAG_SYSPEER)
48254359Sroberto			    c = '*';
48354359Sroberto			else if (plist->flags & INFO_FLAG_SHORTLIST)
48454359Sroberto			    c = '+';
48554359Sroberto			else if (plist->flags & INFO_FLAG_SEL_CANDIDATE)
48654359Sroberto			    c = '.';
48754359Sroberto			else
48854359Sroberto			    c = ' ';
48954359Sroberto		}
49054359Sroberto		NTOHL_FP(&(plist->offset), &tempts);
49154359Sroberto		ntp_poll = 1<<max(min3(plist->ppoll, plist->hpoll, NTP_MAXPOLL),
49254359Sroberto				  NTP_MINPOLL);
493290000Sglebius		SET_ADDRS(dstadr, srcadr, plist, dstadr, srcadr);
494132451Sroberto		if ((pcmd->nargs == 0) ||
495132451Sroberto		    ((pcmd->argval->ival == 6) && (plist->v6_flag != 0)) ||
496132451Sroberto		    ((pcmd->argval->ival == 4) && (plist->v6_flag == 0)))
497132451Sroberto			(void) fprintf(fp,
498290000Sglebius			    "%c%-15.15s %-15.15s %2u %4d  %3o %7.7s %9.9s %7.7s\n",
499132451Sroberto			    c, nntohost(&srcadr), stoa(&dstadr),
500132451Sroberto			    plist->stratum, ntp_poll, plist->reach,
501132451Sroberto			    fptoa(NTOHS_FP(plist->delay), 5),
502132451Sroberto			    lfptoa(&tempts, 6),
503132451Sroberto			    ufptoa(NTOHS_FP(plist->dispersion), 5));
50454359Sroberto		plist++;
50554359Sroberto		items--;
50654359Sroberto	}
50754359Sroberto}
50854359Sroberto
50954359Sroberto/* Convert a refid & stratum (in host order) to a string */
510290000Sglebiusstatic char *
51154359Srobertorefid_string(
51254359Sroberto	u_int32 refid,
51354359Sroberto	int stratum
51454359Sroberto	)
51554359Sroberto{
51654359Sroberto	if (stratum <= 1) {
51754359Sroberto		static char junk[5];
51854359Sroberto		junk[4] = 0;
519290000Sglebius		memcpy(junk, &refid, 4);
52054359Sroberto		return junk;
52154359Sroberto	}
52254359Sroberto
52354359Sroberto	return numtoa(refid);
52454359Sroberto}
52554359Sroberto
526182007Srobertostatic void
527182007Srobertoprint_pflag(
528290000Sglebius	FILE *	fp,
529290000Sglebius	u_int32	flags
530290000Sglebius	)
531182007Sroberto{
532290000Sglebius	static const char none[] = "";
533290000Sglebius	static const char comma[] = ",";
534290000Sglebius	const char *dlim;
535182007Sroberto
536290000Sglebius	if (0 == flags) {
537290000Sglebius		fprintf(fp, " none\n");
538290000Sglebius		return;
539182007Sroberto	}
540290000Sglebius	dlim = none;
541290000Sglebius	if (flags & INFO_FLAG_SYSPEER) {
542290000Sglebius		fprintf(fp, " system_peer");
543290000Sglebius		dlim = comma;
544290000Sglebius	}
545290000Sglebius	if (flags & INFO_FLAG_CONFIG) {
546290000Sglebius		fprintf(fp, "%s config", dlim);
547290000Sglebius		dlim = comma;
548290000Sglebius	}
549290000Sglebius	if (flags & INFO_FLAG_REFCLOCK) {
550290000Sglebius		fprintf(fp, "%s refclock", dlim);
551290000Sglebius		dlim = comma;
552290000Sglebius	}
553290000Sglebius	if (flags & INFO_FLAG_AUTHENABLE) {
554290000Sglebius		fprintf(fp, "%s auth", dlim);
555290000Sglebius		dlim = comma;
556290000Sglebius	}
557290000Sglebius	if (flags & INFO_FLAG_PREFER) {
558290000Sglebius		fprintf(fp, "%s prefer", dlim);
559290000Sglebius		dlim = comma;
560290000Sglebius	}
561290000Sglebius	if (flags & INFO_FLAG_IBURST) {
562290000Sglebius		fprintf(fp, "%s iburst", dlim);
563290000Sglebius		dlim = comma;
564290000Sglebius	}
565290000Sglebius	if (flags & INFO_FLAG_BURST) {
566290000Sglebius		fprintf(fp, "%s burst", dlim);
567290000Sglebius		dlim = comma;
568290000Sglebius	}
569290000Sglebius	if (flags & INFO_FLAG_SEL_CANDIDATE) {
570290000Sglebius		fprintf(fp, "%s candidate", dlim);
571290000Sglebius		dlim = comma;
572290000Sglebius	}
573290000Sglebius	if (flags & INFO_FLAG_SHORTLIST) {
574290000Sglebius		fprintf(fp, "%s shortlist", dlim);
575290000Sglebius		dlim = comma;
576290000Sglebius	}
577290000Sglebius	fprintf(fp, "\n");
578182007Sroberto}
57954359Sroberto/*
58054359Sroberto * printpeer - print detail information for a peer
58154359Sroberto */
58254359Srobertostatic void
58354359Srobertoprintpeer(
58454359Sroberto	register struct info_peer *pp,
58554359Sroberto	FILE *fp
58654359Sroberto	)
58754359Sroberto{
58854359Sroberto	register int i;
58954359Sroberto	l_fp tempts;
590290000Sglebius	sockaddr_u srcadr, dstadr;
591132451Sroberto
592290000Sglebius	SET_ADDRS(dstadr, srcadr, pp, dstadr, srcadr);
593290000Sglebius
59454359Sroberto	(void) fprintf(fp, "remote %s, local %s\n",
595132451Sroberto		       stoa(&srcadr), stoa(&dstadr));
59654359Sroberto	(void) fprintf(fp, "hmode %s, pmode %s, stratum %d, precision %d\n",
59754359Sroberto		       modetoa(pp->hmode), modetoa(pp->pmode),
59854359Sroberto		       pp->stratum, pp->precision);
59954359Sroberto
60054359Sroberto	(void) fprintf(fp,
60154359Sroberto		       "leap %c%c, refid [%s], rootdistance %s, rootdispersion %s\n",
60254359Sroberto		       pp->leap & 0x2 ? '1' : '0',
60354359Sroberto		       pp->leap & 0x1 ? '1' : '0',
60454359Sroberto		       refid_string(pp->refid, pp->stratum), fptoa(NTOHS_FP(pp->rootdelay), 5),
60554359Sroberto		       ufptoa(NTOHS_FP(pp->rootdispersion), 5));
60654359Sroberto
60754359Sroberto	(void) fprintf(fp,
60854359Sroberto		       "ppoll %d, hpoll %d, keyid %lu, version %d, association %u\n",
60954359Sroberto		       pp->ppoll, pp->hpoll, (u_long)pp->keyid, pp->version, ntohs(pp->associd));
61054359Sroberto
61154359Sroberto	(void) fprintf(fp,
61282498Sroberto		       "reach %03o, unreach %d, flash 0x%04x, ",
61382498Sroberto		       pp->reach, pp->unreach, pp->flash2);
61454359Sroberto
61554359Sroberto	(void) fprintf(fp, "boffset %s, ttl/mode %d\n",
61654359Sroberto		       fptoa(NTOHS_FP(pp->estbdelay), 5), pp->ttl);
61754359Sroberto
61854359Sroberto	(void) fprintf(fp, "timer %lds, flags", (long)ntohl(pp->timer));
619182007Sroberto	print_pflag(fp, pp->flags);
62054359Sroberto
62154359Sroberto	NTOHL_FP(&pp->reftime, &tempts);
62254359Sroberto	(void) fprintf(fp, "reference time:      %s\n",
62354359Sroberto		       prettydate(&tempts));
62454359Sroberto	NTOHL_FP(&pp->org, &tempts);
62554359Sroberto	(void) fprintf(fp, "originate timestamp: %s\n",
62654359Sroberto		       prettydate(&tempts));
62754359Sroberto	NTOHL_FP(&pp->rec, &tempts);
62854359Sroberto	(void) fprintf(fp, "receive timestamp:   %s\n",
62954359Sroberto		       prettydate(&tempts));
63054359Sroberto	NTOHL_FP(&pp->xmt, &tempts);
63154359Sroberto	(void) fprintf(fp, "transmit timestamp:  %s\n",
63254359Sroberto		       prettydate(&tempts));
63354359Sroberto
63454359Sroberto	(void) fprintf(fp, "filter delay: ");
63554359Sroberto	for (i = 0; i < NTP_SHIFT; i++) {
63654359Sroberto		(void) fprintf(fp, " %-8.8s",
63754359Sroberto			       fptoa(NTOHS_FP(pp->filtdelay[i]), 5));
63854359Sroberto		if (i == (NTP_SHIFT>>1)-1)
63954359Sroberto		    (void) fprintf(fp, "\n              ");
64054359Sroberto	}
64154359Sroberto	(void) fprintf(fp, "\n");
64254359Sroberto
64354359Sroberto	(void) fprintf(fp, "filter offset:");
64454359Sroberto	for (i = 0; i < NTP_SHIFT; i++) {
64554359Sroberto		NTOHL_FP(&pp->filtoffset[i], &tempts);
64654359Sroberto		(void) fprintf(fp, " %-8.8s", lfptoa(&tempts, 6));
64754359Sroberto		if (i == (NTP_SHIFT>>1)-1)
64854359Sroberto		    (void) fprintf(fp, "\n              ");
64954359Sroberto	}
65054359Sroberto	(void) fprintf(fp, "\n");
65154359Sroberto
65254359Sroberto	(void) fprintf(fp, "filter order: ");
65354359Sroberto	for (i = 0; i < NTP_SHIFT; i++) {
65454359Sroberto		(void) fprintf(fp, " %-8d", pp->order[i]);
65554359Sroberto		if (i == (NTP_SHIFT>>1)-1)
65654359Sroberto		    (void) fprintf(fp, "\n              ");
65754359Sroberto	}
65854359Sroberto	(void) fprintf(fp, "\n");
65954359Sroberto
66054359Sroberto
66154359Sroberto	NTOHL_FP(&pp->offset, &tempts);
66254359Sroberto	(void) fprintf(fp,
66354359Sroberto		       "offset %s, delay %s, error bound %s, filter error %s\n",
66454359Sroberto		       lfptoa(&tempts, 6), fptoa(NTOHS_FP(pp->delay), 5),
66554359Sroberto		       ufptoa(NTOHS_FP(pp->dispersion), 5),
66654359Sroberto		       ufptoa(NTOHS_FP(pp->selectdisp), 5));
66754359Sroberto}
66854359Sroberto
66954359Sroberto
67054359Sroberto/*
67154359Sroberto * showpeer - show detailed information for a peer
67254359Sroberto */
67354359Srobertostatic void
67454359Srobertoshowpeer(
67554359Sroberto	struct parse *pcmd,
67654359Sroberto	FILE *fp
67754359Sroberto	)
67854359Sroberto{
67954359Sroberto	struct info_peer *pp;
68054359Sroberto	/* 4 is the maximum number of peers which will fit in a packet */
681132451Sroberto	struct info_peer_list *pl, plist[min(MAXARGS, 4)];
682293894Sglebius	size_t qitemlim;
683293894Sglebius	size_t qitems;
684293894Sglebius	size_t items;
685293894Sglebius	size_t itemsize;
68654359Sroberto	int res;
687132451Sroberto	int sendsize;
68854359Sroberto
689132451Srobertoagain:
690132451Sroberto	if (impl_ver == IMPL_XNTPD)
691132451Sroberto		sendsize = sizeof(struct info_peer_list);
692132451Sroberto	else
693132451Sroberto		sendsize = v4sizeof(struct info_peer_list);
694132451Sroberto
695290000Sglebius	qitemlim = min(pcmd->nargs, COUNTOF(plist));
696290000Sglebius	for (qitems = 0, pl = plist; qitems < qitemlim; qitems++) {
697290000Sglebius		if (IS_IPV4(&pcmd->argval[qitems].netnum)) {
698290000Sglebius			pl->addr = NSRCADR(&pcmd->argval[qitems].netnum);
699132451Sroberto			if (impl_ver == IMPL_XNTPD)
700132451Sroberto				pl->v6_flag = 0;
701132451Sroberto		} else {
702132451Sroberto			if (impl_ver == IMPL_XNTPD_OLD) {
703132451Sroberto				fprintf(stderr,
704132451Sroberto				    "***Server doesn't understand IPv6 addresses\n");
705132451Sroberto				return;
706132451Sroberto			}
707290000Sglebius			pl->addr6 = SOCK_ADDR6(&pcmd->argval[qitems].netnum);
708132451Sroberto			pl->v6_flag = 1;
709132451Sroberto		}
710132451Sroberto		pl->port = (u_short)s_port;
711132451Sroberto		pl->hmode = pl->flags = 0;
712290000Sglebius		pl = (void *)((char *)pl + sendsize);
71354359Sroberto	}
71454359Sroberto
715132451Sroberto	res = doquery(impl_ver, REQ_PEER_INFO, 0, qitems,
716132451Sroberto		      sendsize, (char *)plist, &items,
717132451Sroberto		      &itemsize, (void *)&pp, 0, sizeof(struct info_peer));
71854359Sroberto
719132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
720132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
721132451Sroberto		goto again;
722132451Sroberto	}
723132451Sroberto
724182007Sroberto	if (res != 0)
725290000Sglebius		return;
72654359Sroberto
72754359Sroberto	if (!checkitems(items, fp))
728290000Sglebius		return;
72954359Sroberto
730132451Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_peer)) &&
731132451Sroberto	    !checkitemsize(itemsize, v4sizeof(struct info_peer)))
732290000Sglebius		return;
73354359Sroberto
73454359Sroberto	while (items-- > 0) {
73554359Sroberto		printpeer(pp, fp);
73654359Sroberto		if (items > 0)
737290000Sglebius			fprintf(fp, "\n");
73854359Sroberto		pp++;
73954359Sroberto	}
74054359Sroberto}
74154359Sroberto
74254359Sroberto
74354359Sroberto/*
74454359Sroberto * peerstats - return statistics for a peer
74554359Sroberto */
74654359Srobertostatic void
74754359Srobertopeerstats(
74854359Sroberto	struct parse *pcmd,
74954359Sroberto	FILE *fp
75054359Sroberto	)
75154359Sroberto{
75254359Sroberto	struct info_peer_stats *pp;
75354359Sroberto	/* 4 is the maximum number of peers which will fit in a packet */
754132451Sroberto	struct info_peer_list *pl, plist[min(MAXARGS, 4)];
755290000Sglebius	sockaddr_u src, dst;
756293894Sglebius	size_t qitemlim;
757293894Sglebius	size_t qitems;
758293894Sglebius	size_t items;
759293894Sglebius	size_t itemsize;
76054359Sroberto	int res;
761293894Sglebius	size_t sendsize;
76254359Sroberto
763132451Srobertoagain:
764132451Sroberto	if (impl_ver == IMPL_XNTPD)
765132451Sroberto		sendsize = sizeof(struct info_peer_list);
766132451Sroberto	else
767132451Sroberto		sendsize = v4sizeof(struct info_peer_list);
768132451Sroberto
769290000Sglebius	ZERO(plist);
770290000Sglebius
771290000Sglebius	qitemlim = min(pcmd->nargs, COUNTOF(plist));
772290000Sglebius	for (qitems = 0, pl = plist; qitems < qitemlim; qitems++) {
773290000Sglebius		if (IS_IPV4(&pcmd->argval[qitems].netnum)) {
774290000Sglebius			pl->addr = NSRCADR(&pcmd->argval[qitems].netnum);
775132451Sroberto			if (impl_ver == IMPL_XNTPD)
776132451Sroberto				pl->v6_flag = 0;
777132451Sroberto		} else {
778132451Sroberto			if (impl_ver == IMPL_XNTPD_OLD) {
779132451Sroberto				fprintf(stderr,
780132451Sroberto				    "***Server doesn't understand IPv6 addresses\n");
781132451Sroberto				return;
782132451Sroberto			}
783290000Sglebius			pl->addr6 = SOCK_ADDR6(&pcmd->argval[qitems].netnum);
784132451Sroberto			pl->v6_flag = 1;
785132451Sroberto		}
786132451Sroberto		pl->port = (u_short)s_port;
787132451Sroberto		pl->hmode = plist[qitems].flags = 0;
788290000Sglebius		pl = (void *)((char *)pl + sendsize);
78954359Sroberto	}
79054359Sroberto
791132451Sroberto	res = doquery(impl_ver, REQ_PEER_STATS, 0, qitems,
792132451Sroberto		      sendsize, (char *)plist, &items,
793132451Sroberto		      &itemsize, (void *)&pp, 0,
794132451Sroberto		      sizeof(struct info_peer_stats));
79554359Sroberto
796132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
797132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
798132451Sroberto		goto again;
799132451Sroberto	}
800132451Sroberto
801182007Sroberto	if (res != 0)
802290000Sglebius		return;
80354359Sroberto
80454359Sroberto	if (!checkitems(items, fp))
80554359Sroberto	    return;
80654359Sroberto
807132451Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_peer_stats)) &&
808132451Sroberto	    !checkitemsize(itemsize, v4sizeof(struct info_peer_stats)))
80954359Sroberto	    return;
81054359Sroberto
81154359Sroberto	while (items-- > 0) {
812290000Sglebius		ZERO_SOCK(&dst);
813290000Sglebius		ZERO_SOCK(&src);
814132451Sroberto		if (pp->v6_flag != 0) {
815290000Sglebius			AF(&dst) = AF_INET6;
816290000Sglebius			AF(&src) = AF_INET6;
817290000Sglebius			SOCK_ADDR6(&dst) = pp->dstadr6;
818290000Sglebius			SOCK_ADDR6(&src) = pp->srcadr6;
819132451Sroberto		} else {
820290000Sglebius			AF(&dst) = AF_INET;
821290000Sglebius			AF(&src) = AF_INET;
822290000Sglebius			NSRCADR(&dst) = pp->dstadr;
823290000Sglebius			NSRCADR(&src) = pp->srcadr;
824132451Sroberto		}
825290000Sglebius#ifdef ISC_PLATFORM_HAVESALEN
826290000Sglebius		src.sa.sa_len = SOCKLEN(&src);
827290000Sglebius		dst.sa.sa_len = SOCKLEN(&dst);
828132451Sroberto#endif
829290000Sglebius		fprintf(fp, "remote host:          %s\n",
830290000Sglebius			nntohost(&src));
831290000Sglebius		fprintf(fp, "local interface:      %s\n",
832290000Sglebius			stoa(&dst));
833290000Sglebius		fprintf(fp, "time last received:   %lus\n",
834290000Sglebius			(u_long)ntohl(pp->timereceived));
835290000Sglebius		fprintf(fp, "time until next send: %lus\n",
836290000Sglebius			(u_long)ntohl(pp->timetosend));
837290000Sglebius		fprintf(fp, "reachability change:  %lus\n",
838290000Sglebius			(u_long)ntohl(pp->timereachable));
839290000Sglebius		fprintf(fp, "packets sent:         %lu\n",
840290000Sglebius			(u_long)ntohl(pp->sent));
841290000Sglebius		fprintf(fp, "packets received:     %lu\n",
842290000Sglebius			(u_long)ntohl(pp->processed));
843290000Sglebius		fprintf(fp, "bad authentication:   %lu\n",
844290000Sglebius			(u_long)ntohl(pp->badauth));
845290000Sglebius		fprintf(fp, "bogus origin:         %lu\n",
846290000Sglebius			(u_long)ntohl(pp->bogusorg));
847290000Sglebius		fprintf(fp, "duplicate:            %lu\n",
848290000Sglebius			(u_long)ntohl(pp->oldpkt));
849290000Sglebius		fprintf(fp, "bad dispersion:       %lu\n",
850290000Sglebius			(u_long)ntohl(pp->seldisp));
851290000Sglebius		fprintf(fp, "bad reference time:   %lu\n",
852290000Sglebius			(u_long)ntohl(pp->selbroken));
853290000Sglebius		fprintf(fp, "candidate order:      %u\n",
854290000Sglebius			pp->candidate);
85554359Sroberto		if (items > 0)
856290000Sglebius			fprintf(fp, "\n");
857290000Sglebius		fprintf(fp, "flags:	");
858182007Sroberto		print_pflag(fp, ntohs(pp->flags));
859290000Sglebius		pp++;
86054359Sroberto	}
86154359Sroberto}
86254359Sroberto
86354359Sroberto
86454359Sroberto/*
86554359Sroberto * loopinfo - show loop filter information
86654359Sroberto */
86754359Srobertostatic void
86854359Srobertoloopinfo(
86954359Sroberto	struct parse *pcmd,
87054359Sroberto	FILE *fp
87154359Sroberto	)
87254359Sroberto{
87354359Sroberto	struct info_loop *il;
874293894Sglebius	size_t items;
875293894Sglebius	size_t itemsize;
87654359Sroberto	int oneline = 0;
87754359Sroberto	int res;
87854359Sroberto	l_fp tempts;
87954359Sroberto
88054359Sroberto	if (pcmd->nargs > 0) {
88154359Sroberto		if (STREQ(pcmd->argval[0].string, "oneline"))
88254359Sroberto		    oneline = 1;
88354359Sroberto		else if (STREQ(pcmd->argval[0].string, "multiline"))
88454359Sroberto		    oneline = 0;
88554359Sroberto		else {
88654359Sroberto			(void) fprintf(stderr, "How many lines?\n");
88754359Sroberto			return;
88854359Sroberto		}
88954359Sroberto	}
89054359Sroberto
891132451Srobertoagain:
892132451Sroberto	res = doquery(impl_ver, REQ_LOOP_INFO, 0, 0, 0, (char *)NULL,
893132451Sroberto		      &items, &itemsize, (void *)&il, 0,
894132451Sroberto		      sizeof(struct info_loop));
89554359Sroberto
896132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
897132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
898132451Sroberto		goto again;
899132451Sroberto	}
900132451Sroberto
901182007Sroberto	if (res != 0)
90254359Sroberto	    return;
90354359Sroberto
90454359Sroberto	if (!check1item(items, fp))
90554359Sroberto	    return;
90654359Sroberto
90754359Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_loop)))
90854359Sroberto	    return;
90954359Sroberto
91054359Sroberto	if (oneline) {
91154359Sroberto		l_fp temp2ts;
91254359Sroberto
91354359Sroberto		NTOHL_FP(&il->last_offset, &tempts);
91454359Sroberto		NTOHL_FP(&il->drift_comp, &temp2ts);
91554359Sroberto
91654359Sroberto		(void) fprintf(fp,
91754359Sroberto			       "offset %s, frequency %s, time_const %ld, watchdog %ld\n",
91854359Sroberto			       lfptoa(&tempts, 6),
91954359Sroberto			       lfptoa(&temp2ts, 3),
920290000Sglebius			       (long)(int32)ntohl((u_long)il->compliance),
921182007Sroberto			       (u_long)ntohl((u_long)il->watchdog_timer));
92254359Sroberto	} else {
92354359Sroberto		NTOHL_FP(&il->last_offset, &tempts);
92454359Sroberto		(void) fprintf(fp, "offset:               %s s\n",
92554359Sroberto			       lfptoa(&tempts, 6));
92654359Sroberto		NTOHL_FP(&il->drift_comp, &tempts);
92754359Sroberto		(void) fprintf(fp, "frequency:            %s ppm\n",
92854359Sroberto			       lfptoa(&tempts, 3));
92954359Sroberto		(void) fprintf(fp, "poll adjust:          %ld\n",
930290000Sglebius			       (long)(int32)ntohl(il->compliance));
93154359Sroberto		(void) fprintf(fp, "watchdog timer:       %ld s\n",
93254359Sroberto			       (u_long)ntohl(il->watchdog_timer));
93354359Sroberto	}
93454359Sroberto}
93554359Sroberto
93654359Sroberto
93754359Sroberto/*
93854359Sroberto * sysinfo - show current system state
93954359Sroberto */
94054359Sroberto/*ARGSUSED*/
94154359Srobertostatic void
94254359Srobertosysinfo(
94354359Sroberto	struct parse *pcmd,
94454359Sroberto	FILE *fp
94554359Sroberto	)
94654359Sroberto{
94754359Sroberto	struct info_sys *is;
948290000Sglebius	sockaddr_u peeraddr;
949293894Sglebius	size_t items;
950293894Sglebius	size_t itemsize;
95154359Sroberto	int res;
95254359Sroberto	l_fp tempts;
95354359Sroberto
954132451Srobertoagain:
955132451Sroberto	res = doquery(impl_ver, REQ_SYS_INFO, 0, 0, 0, (char *)NULL,
956132451Sroberto		      &items, &itemsize, (void *)&is, 0,
957132451Sroberto		      sizeof(struct info_sys));
95854359Sroberto
959132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
960132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
961132451Sroberto		goto again;
962132451Sroberto	}
963132451Sroberto
964182007Sroberto	if (res != 0)
96554359Sroberto	    return;
96654359Sroberto
96754359Sroberto	if (!check1item(items, fp))
96854359Sroberto	    return;
96954359Sroberto
970132451Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_sys)) &&
971132451Sroberto	    !checkitemsize(itemsize, v4sizeof(struct info_sys)))
97254359Sroberto	    return;
97354359Sroberto
974290000Sglebius	SET_ADDR(peeraddr, is->v6_flag, is->peer, is->peer6);
975290000Sglebius
976132451Sroberto	(void) fprintf(fp, "system peer:          %s\n", nntohost(&peeraddr));
97754359Sroberto	(void) fprintf(fp, "system peer mode:     %s\n", modetoa(is->peer_mode));
97854359Sroberto	(void) fprintf(fp, "leap indicator:       %c%c\n",
97954359Sroberto		       is->leap & 0x2 ? '1' : '0',
98054359Sroberto		       is->leap & 0x1 ? '1' : '0');
98154359Sroberto	(void) fprintf(fp, "stratum:              %d\n", (int)is->stratum);
98254359Sroberto	(void) fprintf(fp, "precision:            %d\n", (int)is->precision);
98354359Sroberto	(void) fprintf(fp, "root distance:        %s s\n",
98454359Sroberto		       fptoa(NTOHS_FP(is->rootdelay), 5));
98554359Sroberto	(void) fprintf(fp, "root dispersion:      %s s\n",
98654359Sroberto		       ufptoa(NTOHS_FP(is->rootdispersion), 5));
98754359Sroberto	(void) fprintf(fp, "reference ID:         [%s]\n",
98854359Sroberto		       refid_string(is->refid, is->stratum));
98954359Sroberto	NTOHL_FP(&is->reftime, &tempts);
99054359Sroberto	(void) fprintf(fp, "reference time:       %s\n", prettydate(&tempts));
99154359Sroberto
99254359Sroberto	(void) fprintf(fp, "system flags:         ");
99354359Sroberto	if ((is->flags & (INFO_FLAG_BCLIENT | INFO_FLAG_AUTHENABLE |
994106163Sroberto	    INFO_FLAG_NTP | INFO_FLAG_KERNEL| INFO_FLAG_CAL |
99554359Sroberto	    INFO_FLAG_PPS_SYNC | INFO_FLAG_MONITOR | INFO_FLAG_FILEGEN)) == 0) {
99654359Sroberto		(void) fprintf(fp, "none\n");
99754359Sroberto	} else {
99854359Sroberto		if (is->flags & INFO_FLAG_BCLIENT)
99954359Sroberto		    (void) fprintf(fp, "bclient ");
100054359Sroberto		if (is->flags & INFO_FLAG_AUTHENTICATE)
100154359Sroberto		    (void) fprintf(fp, "auth ");
100254359Sroberto		if (is->flags & INFO_FLAG_MONITOR)
100354359Sroberto		    (void) fprintf(fp, "monitor ");
100454359Sroberto		if (is->flags & INFO_FLAG_NTP)
100554359Sroberto		    (void) fprintf(fp, "ntp ");
100654359Sroberto		if (is->flags & INFO_FLAG_KERNEL)
100754359Sroberto		    (void) fprintf(fp, "kernel ");
100854359Sroberto		if (is->flags & INFO_FLAG_FILEGEN)
100954359Sroberto		    (void) fprintf(fp, "stats ");
1010106163Sroberto		if (is->flags & INFO_FLAG_CAL)
1011106163Sroberto		    (void) fprintf(fp, "calibrate ");
101254359Sroberto		if (is->flags & INFO_FLAG_PPS_SYNC)
1013106163Sroberto		    (void) fprintf(fp, "pps ");
101454359Sroberto		(void) fprintf(fp, "\n");
101554359Sroberto	}
101654359Sroberto	(void) fprintf(fp, "jitter:               %s s\n",
101754359Sroberto		       fptoa(ntohl(is->frequency), 6));
101854359Sroberto	(void) fprintf(fp, "stability:            %s ppm\n",
101954359Sroberto		       ufptoa(ntohl(is->stability), 3));
102054359Sroberto	(void) fprintf(fp, "broadcastdelay:       %s s\n",
102154359Sroberto		       fptoa(NTOHS_FP(is->bdelay), 6));
102254359Sroberto	NTOHL_FP(&is->authdelay, &tempts);
102354359Sroberto	(void) fprintf(fp, "authdelay:            %s s\n", lfptoa(&tempts, 6));
102454359Sroberto}
102554359Sroberto
102654359Sroberto
102754359Sroberto/*
102854359Sroberto * sysstats - print system statistics
102954359Sroberto */
103054359Sroberto/*ARGSUSED*/
103154359Srobertostatic void
103254359Srobertosysstats(
103354359Sroberto	struct parse *pcmd,
103454359Sroberto	FILE *fp
103554359Sroberto	)
103654359Sroberto{
103754359Sroberto	struct info_sys_stats *ss;
1038293894Sglebius	size_t items;
1039293894Sglebius	size_t itemsize;
104054359Sroberto	int res;
104154359Sroberto
1042132451Srobertoagain:
1043132451Sroberto	res = doquery(impl_ver, REQ_SYS_STATS, 0, 0, 0, (char *)NULL,
1044132451Sroberto		      &items, &itemsize, (void *)&ss, 0,
1045132451Sroberto		      sizeof(struct info_sys_stats));
104654359Sroberto
1047132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1048132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
1049132451Sroberto		goto again;
1050132451Sroberto	}
1051132451Sroberto
1052182007Sroberto	if (res != 0)
105354359Sroberto	    return;
105454359Sroberto
105554359Sroberto	if (!check1item(items, fp))
105654359Sroberto	    return;
105754359Sroberto
105854359Sroberto	if (itemsize != sizeof(struct info_sys_stats) &&
105954359Sroberto	    itemsize != sizeof(struct old_info_sys_stats)) {
106054359Sroberto		/* issue warning according to new structure size */
106154359Sroberto		checkitemsize(itemsize, sizeof(struct info_sys_stats));
106254359Sroberto		return;
106354359Sroberto	}
1064290000Sglebius	fprintf(fp, "time since restart:     %lu\n",
1065290000Sglebius		(u_long)ntohl(ss->timeup));
1066290000Sglebius	fprintf(fp, "time since reset:       %lu\n",
1067132451Sroberto		(u_long)ntohl(ss->timereset));
1068290000Sglebius	fprintf(fp, "packets received:       %lu\n",
1069132451Sroberto		(u_long)ntohl(ss->received));
1070290000Sglebius	fprintf(fp, "packets processed:      %lu\n",
1071132451Sroberto		(u_long)ntohl(ss->processed));
1072290000Sglebius	fprintf(fp, "current version:        %lu\n",
1073290000Sglebius		(u_long)ntohl(ss->newversionpkt));
1074290000Sglebius	fprintf(fp, "previous version:       %lu\n",
1075290000Sglebius		(u_long)ntohl(ss->oldversionpkt));
1076290000Sglebius	fprintf(fp, "declined:               %lu\n",
1077290000Sglebius		(u_long)ntohl(ss->unknownversion));
1078290000Sglebius	fprintf(fp, "access denied:          %lu\n",
1079132451Sroberto		(u_long)ntohl(ss->denied));
1080290000Sglebius	fprintf(fp, "bad length or format:   %lu\n",
1081290000Sglebius		(u_long)ntohl(ss->badlength));
1082290000Sglebius	fprintf(fp, "bad authentication:     %lu\n",
1083290000Sglebius		(u_long)ntohl(ss->badauth));
108454359Sroberto	if (itemsize != sizeof(struct info_sys_stats))
108554359Sroberto	    return;
108654359Sroberto
1087290000Sglebius	fprintf(fp, "rate exceeded:          %lu\n",
1088132451Sroberto	       (u_long)ntohl(ss->limitrejected));
108954359Sroberto}
109054359Sroberto
109154359Sroberto
109254359Sroberto
109354359Sroberto/*
109454359Sroberto * iostats - print I/O statistics
109554359Sroberto */
109654359Sroberto/*ARGSUSED*/
109754359Srobertostatic void
109854359Srobertoiostats(
109954359Sroberto	struct parse *pcmd,
110054359Sroberto	FILE *fp
110154359Sroberto	)
110254359Sroberto{
110354359Sroberto	struct info_io_stats *io;
1104293894Sglebius	size_t items;
1105293894Sglebius	size_t itemsize;
110654359Sroberto	int res;
110754359Sroberto
1108132451Srobertoagain:
1109290000Sglebius	res = doquery(impl_ver, REQ_IO_STATS, 0, 0, 0, NULL, &items,
1110290000Sglebius		      &itemsize, (void *)&io, 0, sizeof(*io));
111154359Sroberto
1112132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1113132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
1114132451Sroberto		goto again;
1115132451Sroberto	}
1116132451Sroberto
1117182007Sroberto	if (res != 0)
1118290000Sglebius		return;
111954359Sroberto
112054359Sroberto	if (!check1item(items, fp))
1121290000Sglebius		return;
112254359Sroberto
1123290000Sglebius	if (!checkitemsize(itemsize, sizeof(*io)))
1124290000Sglebius		return;
112554359Sroberto
1126290000Sglebius	fprintf(fp, "time since reset:     %lu\n",
1127290000Sglebius		(u_long)ntohl(io->timereset));
1128290000Sglebius	fprintf(fp, "receive buffers:      %u\n",
1129290000Sglebius		(u_int)ntohs(io->totalrecvbufs));
1130290000Sglebius	fprintf(fp, "free receive buffers: %u\n",
1131290000Sglebius		(u_int)ntohs(io->freerecvbufs));
1132290000Sglebius	fprintf(fp, "used receive buffers: %u\n",
1133290000Sglebius		(u_int)ntohs(io->fullrecvbufs));
1134290000Sglebius	fprintf(fp, "low water refills:    %u\n",
1135290000Sglebius		(u_int)ntohs(io->lowwater));
1136290000Sglebius	fprintf(fp, "dropped packets:      %lu\n",
1137290000Sglebius		(u_long)ntohl(io->dropped));
1138290000Sglebius	fprintf(fp, "ignored packets:      %lu\n",
1139290000Sglebius		(u_long)ntohl(io->ignored));
1140290000Sglebius	fprintf(fp, "received packets:     %lu\n",
1141290000Sglebius		(u_long)ntohl(io->received));
1142290000Sglebius	fprintf(fp, "packets sent:         %lu\n",
1143290000Sglebius		(u_long)ntohl(io->sent));
1144290000Sglebius	fprintf(fp, "packets not sent:     %lu\n",
1145290000Sglebius		(u_long)ntohl(io->notsent));
1146290000Sglebius	fprintf(fp, "interrupts handled:   %lu\n",
1147290000Sglebius		(u_long)ntohl(io->interrupts));
1148290000Sglebius	fprintf(fp, "received by int:      %lu\n",
1149290000Sglebius		(u_long)ntohl(io->int_received));
115054359Sroberto}
115154359Sroberto
115254359Sroberto
115354359Sroberto/*
115454359Sroberto * memstats - print peer memory statistics
115554359Sroberto */
115654359Sroberto/*ARGSUSED*/
115754359Srobertostatic void
115854359Srobertomemstats(
115954359Sroberto	struct parse *pcmd,
116054359Sroberto	FILE *fp
116154359Sroberto	)
116254359Sroberto{
116354359Sroberto	struct info_mem_stats *mem;
116454359Sroberto	int i;
1165293894Sglebius	size_t items;
1166293894Sglebius	size_t itemsize;
116754359Sroberto	int res;
116854359Sroberto
1169132451Srobertoagain:
1170290000Sglebius	res = doquery(impl_ver, REQ_MEM_STATS, 0, 0, 0, NULL, &items,
1171290000Sglebius		      &itemsize, (void *)&mem, 0, sizeof(*mem));
117254359Sroberto
1173132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1174132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
1175132451Sroberto		goto again;
1176132451Sroberto	}
1177132451Sroberto
1178182007Sroberto	if (res != 0)
1179290000Sglebius		return;
118054359Sroberto
118154359Sroberto	if (!check1item(items, fp))
1182290000Sglebius		return;
118354359Sroberto
1184290000Sglebius	if (!checkitemsize(itemsize, sizeof(*mem)))
1185290000Sglebius		return;
118654359Sroberto
1187290000Sglebius	fprintf(fp, "time since reset:     %lu\n",
1188290000Sglebius		(u_long)ntohl(mem->timereset));
1189290000Sglebius	fprintf(fp, "total peer memory:    %u\n",
1190290000Sglebius		(u_int)ntohs(mem->totalpeermem));
1191290000Sglebius	fprintf(fp, "free peer memory:     %u\n",
1192290000Sglebius		(u_int)ntohs(mem->freepeermem));
1193290000Sglebius	fprintf(fp, "calls to findpeer:    %lu\n",
1194290000Sglebius		(u_long)ntohl(mem->findpeer_calls));
1195290000Sglebius	fprintf(fp, "new peer allocations: %lu\n",
1196290000Sglebius		(u_long)ntohl(mem->allocations));
1197290000Sglebius	fprintf(fp, "peer demobilizations: %lu\n",
1198290000Sglebius		(u_long)ntohl(mem->demobilizations));
119954359Sroberto
1200290000Sglebius	fprintf(fp, "hash table counts:   ");
1201182007Sroberto	for (i = 0; i < NTP_HASH_SIZE; i++) {
1202290000Sglebius		fprintf(fp, "%4d", (int)mem->hashcount[i]);
1203290000Sglebius		if ((i % 8) == 7 && i != (NTP_HASH_SIZE-1))
1204290000Sglebius			fprintf(fp, "\n                     ");
120554359Sroberto	}
1206290000Sglebius	fprintf(fp, "\n");
120754359Sroberto}
120854359Sroberto
120954359Sroberto
121054359Sroberto
121154359Sroberto/*
121254359Sroberto * timerstats - print timer statistics
121354359Sroberto */
121454359Sroberto/*ARGSUSED*/
121554359Srobertostatic void
121654359Srobertotimerstats(
121754359Sroberto	struct parse *pcmd,
121854359Sroberto	FILE *fp
121954359Sroberto	)
122054359Sroberto{
122154359Sroberto	struct info_timer_stats *tim;
1222293894Sglebius	size_t items;
1223293894Sglebius	size_t itemsize;
122454359Sroberto	int res;
122554359Sroberto
1226132451Srobertoagain:
1227290000Sglebius	res = doquery(impl_ver, REQ_TIMER_STATS, 0, 0, 0, NULL, &items,
1228290000Sglebius		      &itemsize, (void *)&tim, 0, sizeof(*tim));
122954359Sroberto
1230132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1231132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
1232132451Sroberto		goto again;
1233132451Sroberto	}
1234132451Sroberto
1235182007Sroberto	if (res != 0)
1236290000Sglebius		return;
123754359Sroberto
123854359Sroberto	if (!check1item(items, fp))
1239290000Sglebius		return;
124054359Sroberto
1241290000Sglebius	if (!checkitemsize(itemsize, sizeof(*tim)))
1242290000Sglebius		return;
124354359Sroberto
1244290000Sglebius	fprintf(fp, "time since reset:  %lu\n",
1245290000Sglebius		(u_long)ntohl(tim->timereset));
1246290000Sglebius	fprintf(fp, "alarms handled:    %lu\n",
1247290000Sglebius		(u_long)ntohl(tim->alarms));
1248290000Sglebius	fprintf(fp, "alarm overruns:    %lu\n",
1249290000Sglebius		(u_long)ntohl(tim->overflows));
1250290000Sglebius	fprintf(fp, "calls to transmit: %lu\n",
1251290000Sglebius		(u_long)ntohl(tim->xmtcalls));
125254359Sroberto}
125354359Sroberto
125454359Sroberto
125554359Sroberto/*
125654359Sroberto * addpeer - configure an active mode association
125754359Sroberto */
125854359Srobertostatic void
125954359Srobertoaddpeer(
126054359Sroberto	struct parse *pcmd,
126154359Sroberto	FILE *fp
126254359Sroberto	)
126354359Sroberto{
126454359Sroberto	doconfig(pcmd, fp, MODE_ACTIVE, 0);
126554359Sroberto}
126654359Sroberto
126754359Sroberto
126854359Sroberto/*
126954359Sroberto * addserver - configure a client mode association
127054359Sroberto */
127154359Srobertostatic void
127254359Srobertoaddserver(
127354359Sroberto	struct parse *pcmd,
127454359Sroberto	FILE *fp
127554359Sroberto	)
127654359Sroberto{
127754359Sroberto	doconfig(pcmd, fp, MODE_CLIENT, 0);
127854359Sroberto}
127954359Sroberto
128054359Sroberto/*
128154359Sroberto * addrefclock - configure a reference clock association
128254359Sroberto */
128354359Srobertostatic void
128454359Srobertoaddrefclock(
128554359Sroberto	struct parse *pcmd,
128654359Sroberto	FILE *fp
128754359Sroberto	)
128854359Sroberto{
128954359Sroberto	doconfig(pcmd, fp, MODE_CLIENT, 1);
129054359Sroberto}
129154359Sroberto
129254359Sroberto/*
129354359Sroberto * broadcast - configure a broadcast mode association
129454359Sroberto */
129554359Srobertostatic void
129654359Srobertobroadcast(
129754359Sroberto	struct parse *pcmd,
129854359Sroberto	FILE *fp
129954359Sroberto	)
130054359Sroberto{
130154359Sroberto	doconfig(pcmd, fp, MODE_BROADCAST, 0);
130254359Sroberto}
130354359Sroberto
130454359Sroberto
130554359Sroberto/*
130654359Sroberto * config - configure a new peer association
130754359Sroberto */
130854359Srobertostatic void
130954359Srobertodoconfig(
131054359Sroberto	struct parse *pcmd,
131154359Sroberto	FILE *fp,
131254359Sroberto	int mode,
1313290000Sglebius	int refc
131454359Sroberto	)
131554359Sroberto{
131654359Sroberto	struct conf_peer cpeer;
1317293894Sglebius	size_t items;
1318293894Sglebius	size_t itemsize;
1319293894Sglebius	const char *dummy;
132054359Sroberto	u_long keyid;
132154359Sroberto	u_int version;
132254359Sroberto	u_char minpoll;
1323182007Sroberto	u_char maxpoll;
132454359Sroberto	u_int flags;
132554359Sroberto	u_char cmode;
132654359Sroberto	int res;
1327132451Sroberto	int sendsize;
1328182007Sroberto	int numtyp;
1329290000Sglebius	long val;
133054359Sroberto
1331132451Srobertoagain:
133254359Sroberto	keyid = 0;
1333182007Sroberto	version = 3;
133454359Sroberto	flags = 0;
1335290000Sglebius	res = FALSE;
133654359Sroberto	cmode = 0;
133754359Sroberto	minpoll = NTP_MINDPOLL;
1338182007Sroberto	maxpoll = NTP_MAXDPOLL;
1339182007Sroberto	numtyp = 1;
1340182007Sroberto	if (refc)
1341290000Sglebius		numtyp = 5;
134254359Sroberto
1343132451Sroberto	if (impl_ver == IMPL_XNTPD)
1344132451Sroberto		sendsize = sizeof(struct conf_peer);
1345132451Sroberto	else
1346132451Sroberto		sendsize = v4sizeof(struct conf_peer);
1347132451Sroberto
1348182007Sroberto	items = 1;
1349290000Sglebius	while (pcmd->nargs > (size_t)items) {
135054359Sroberto		if (STREQ(pcmd->argval[items].string, "prefer"))
1351290000Sglebius			flags |= CONF_FLAG_PREFER;
135254359Sroberto		else if (STREQ(pcmd->argval[items].string, "burst"))
1353290000Sglebius			flags |= CONF_FLAG_BURST;
1354182007Sroberto		else if (STREQ(pcmd->argval[items].string, "iburst"))
1355290000Sglebius			flags |= CONF_FLAG_IBURST;
1356182007Sroberto		else if (!refc && STREQ(pcmd->argval[items].string, "keyid"))
1357290000Sglebius			numtyp = 1;
1358182007Sroberto		else if (!refc && STREQ(pcmd->argval[items].string, "version"))
1359290000Sglebius			numtyp = 2;
1360182007Sroberto		else if (STREQ(pcmd->argval[items].string, "minpoll"))
1361290000Sglebius			numtyp = 3;
1362182007Sroberto		else if (STREQ(pcmd->argval[items].string, "maxpoll"))
1363290000Sglebius			numtyp = 4;
136454359Sroberto		else {
1365182007Sroberto			if (!atoint(pcmd->argval[items].string, &val))
1366290000Sglebius				numtyp = 0;
1367182007Sroberto			switch (numtyp) {
1368182007Sroberto			case 1:
1369290000Sglebius				keyid = val;
1370290000Sglebius				numtyp = 2;
1371290000Sglebius				break;
1372290000Sglebius
1373182007Sroberto			case 2:
1374290000Sglebius				version = (u_int)val;
1375290000Sglebius				numtyp = 0;
1376290000Sglebius				break;
1377182007Sroberto
1378182007Sroberto			case 3:
1379290000Sglebius				minpoll = (u_char)val;
1380290000Sglebius				numtyp = 0;
1381290000Sglebius				break;
1382182007Sroberto
1383182007Sroberto			case 4:
1384290000Sglebius				maxpoll = (u_char)val;
1385290000Sglebius				numtyp = 0;
1386290000Sglebius				break;
1387182007Sroberto
1388182007Sroberto			case 5:
1389290000Sglebius				cmode = (u_char)val;
1390290000Sglebius				numtyp = 0;
1391290000Sglebius				break;
1392182007Sroberto
1393182007Sroberto			default:
1394290000Sglebius				fprintf(fp, "*** '%s' not understood\n",
1395290000Sglebius					pcmd->argval[items].string);
1396290000Sglebius				res = TRUE;
1397290000Sglebius				numtyp = 0;
139854359Sroberto			}
1399182007Sroberto			if (val < 0) {
1400290000Sglebius				fprintf(stderr,
1401290000Sglebius					"*** Value '%s' should be unsigned\n",
1402290000Sglebius					pcmd->argval[items].string);
1403290000Sglebius				res = TRUE;
1404182007Sroberto			}
1405290000Sglebius		}
1406290000Sglebius		items++;
140754359Sroberto	}
1408182007Sroberto	if (keyid > 0)
1409290000Sglebius		flags |= CONF_FLAG_AUTHENABLE;
1410290000Sglebius	if (version > NTP_VERSION || version < NTP_OLDVERSION) {
1411290000Sglebius		fprintf(fp, "***invalid version number: %u\n",
1412290000Sglebius			version);
1413290000Sglebius		res = TRUE;
1414182007Sroberto	}
1415182007Sroberto	if (minpoll < NTP_MINPOLL || minpoll > NTP_MAXPOLL ||
1416182007Sroberto	    maxpoll < NTP_MINPOLL || maxpoll > NTP_MAXPOLL ||
1417182007Sroberto	    minpoll > maxpoll) {
1418290000Sglebius		fprintf(fp, "***min/max-poll must be within %d..%d\n",
1419290000Sglebius			NTP_MINPOLL, NTP_MAXPOLL);
1420290000Sglebius		res = TRUE;
1421182007Sroberto	}
142254359Sroberto
142354359Sroberto	if (res)
1424290000Sglebius		return;
142554359Sroberto
1426290000Sglebius	ZERO(cpeer);
142754359Sroberto
1428290000Sglebius	if (IS_IPV4(&pcmd->argval[0].netnum)) {
1429290000Sglebius		cpeer.peeraddr = NSRCADR(&pcmd->argval[0].netnum);
1430132451Sroberto		if (impl_ver == IMPL_XNTPD)
1431132451Sroberto			cpeer.v6_flag = 0;
1432132451Sroberto	} else {
1433132451Sroberto		if (impl_ver == IMPL_XNTPD_OLD) {
1434132451Sroberto			fprintf(stderr,
1435132451Sroberto			    "***Server doesn't understand IPv6 addresses\n");
1436132451Sroberto			return;
1437132451Sroberto		}
1438290000Sglebius		cpeer.peeraddr6 = SOCK_ADDR6(&pcmd->argval[0].netnum);
1439132451Sroberto		cpeer.v6_flag = 1;
1440132451Sroberto	}
144154359Sroberto	cpeer.hmode = (u_char) mode;
144254359Sroberto	cpeer.keyid = keyid;
144354359Sroberto	cpeer.version = (u_char) version;
144454359Sroberto	cpeer.minpoll = minpoll;
1445182007Sroberto	cpeer.maxpoll = maxpoll;
144654359Sroberto	cpeer.flags = (u_char)flags;
144754359Sroberto	cpeer.ttl = cmode;
144854359Sroberto
1449132451Sroberto	res = doquery(impl_ver, REQ_CONFIG, 1, 1,
1450132451Sroberto		      sendsize, (char *)&cpeer, &items,
1451132451Sroberto		      &itemsize, &dummy, 0, sizeof(struct conf_peer));
145254359Sroberto
1453132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1454132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
1455132451Sroberto		goto again;
1456132451Sroberto	}
1457132451Sroberto
1458106163Sroberto	if (res == INFO_ERR_FMT) {
1459106163Sroberto		(void) fprintf(fp,
1460106163Sroberto		    "***Retrying command with old conf_peer size\n");
1461132451Sroberto		res = doquery(impl_ver, REQ_CONFIG, 1, 1,
1462106163Sroberto			      sizeof(struct old_conf_peer), (char *)&cpeer,
1463132451Sroberto			      &items, &itemsize, &dummy, 0,
1464132451Sroberto			      sizeof(struct conf_peer));
1465106163Sroberto	}
146654359Sroberto	if (res == 0)
146754359Sroberto	    (void) fprintf(fp, "done!\n");
146854359Sroberto	return;
146954359Sroberto}
147054359Sroberto
147154359Sroberto
147254359Sroberto/*
147354359Sroberto * unconfig - unconfigure some associations
147454359Sroberto */
147554359Srobertostatic void
147654359Srobertounconfig(
147754359Sroberto	struct parse *pcmd,
147854359Sroberto	FILE *fp
147954359Sroberto	)
148054359Sroberto{
148154359Sroberto	/* 8 is the maximum number of peers which will fit in a packet */
1482132451Sroberto	struct conf_unpeer *pl, plist[min(MAXARGS, 8)];
1483293894Sglebius	size_t qitemlim;
1484293894Sglebius	size_t qitems;
1485293894Sglebius	size_t items;
1486293894Sglebius	size_t itemsize;
1487293894Sglebius	const char *dummy;
148854359Sroberto	int res;
1489293894Sglebius	size_t sendsize;
149054359Sroberto
1491132451Srobertoagain:
1492132451Sroberto	if (impl_ver == IMPL_XNTPD)
1493132451Sroberto		sendsize = sizeof(struct conf_unpeer);
1494132451Sroberto	else
1495132451Sroberto		sendsize = v4sizeof(struct conf_unpeer);
1496132451Sroberto
1497290000Sglebius	qitemlim = min(pcmd->nargs, COUNTOF(plist));
1498290000Sglebius	for (qitems = 0, pl = plist; qitems < qitemlim; qitems++) {
1499290000Sglebius		if (IS_IPV4(&pcmd->argval[0].netnum)) {
1500290000Sglebius			pl->peeraddr = NSRCADR(&pcmd->argval[qitems].netnum);
1501132451Sroberto			if (impl_ver == IMPL_XNTPD)
1502132451Sroberto				pl->v6_flag = 0;
1503132451Sroberto		} else {
1504132451Sroberto			if (impl_ver == IMPL_XNTPD_OLD) {
1505132451Sroberto				fprintf(stderr,
1506132451Sroberto				    "***Server doesn't understand IPv6 addresses\n");
1507132451Sroberto				return;
1508132451Sroberto			}
1509132451Sroberto			pl->peeraddr6 =
1510290000Sglebius			    SOCK_ADDR6(&pcmd->argval[qitems].netnum);
1511132451Sroberto			pl->v6_flag = 1;
1512132451Sroberto		}
1513290000Sglebius		pl = (void *)((char *)pl + sendsize);
151454359Sroberto	}
151554359Sroberto
1516132451Sroberto	res = doquery(impl_ver, REQ_UNCONFIG, 1, qitems,
1517132451Sroberto		      sendsize, (char *)plist, &items,
1518132451Sroberto		      &itemsize, &dummy, 0, sizeof(struct conf_unpeer));
151954359Sroberto
1520132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1521132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
1522132451Sroberto		goto again;
1523132451Sroberto	}
1524132451Sroberto
152554359Sroberto	if (res == 0)
152654359Sroberto	    (void) fprintf(fp, "done!\n");
152754359Sroberto}
152854359Sroberto
152954359Sroberto
153054359Sroberto/*
153154359Sroberto * set - set some system flags
153254359Sroberto */
153354359Srobertostatic void
153454359Srobertoset(
153554359Sroberto	struct parse *pcmd,
153654359Sroberto	FILE *fp
153754359Sroberto	)
153854359Sroberto{
153954359Sroberto	doset(pcmd, fp, REQ_SET_SYS_FLAG);
154054359Sroberto}
154154359Sroberto
154254359Sroberto
154354359Sroberto/*
154454359Sroberto * clear - clear some system flags
154554359Sroberto */
154654359Srobertostatic void
154754359Srobertosys_clear(
154854359Sroberto	struct parse *pcmd,
154954359Sroberto	FILE *fp
155054359Sroberto	)
155154359Sroberto{
155254359Sroberto	doset(pcmd, fp, REQ_CLR_SYS_FLAG);
155354359Sroberto}
155454359Sroberto
155554359Sroberto
155654359Sroberto/*
155754359Sroberto * doset - set/clear system flags
155854359Sroberto */
155954359Srobertostatic void
156054359Srobertodoset(
156154359Sroberto	struct parse *pcmd,
156254359Sroberto	FILE *fp,
156354359Sroberto	int req
156454359Sroberto	)
156554359Sroberto{
156654359Sroberto	struct conf_sys_flags sys;
1567293894Sglebius	size_t items;
1568293894Sglebius	size_t itemsize;
1569293894Sglebius	const char *dummy;
157054359Sroberto	int res;
157154359Sroberto
157254359Sroberto	sys.flags = 0;
157354359Sroberto	res = 0;
1574290000Sglebius	for (items = 0; (size_t)items < pcmd->nargs; items++) {
1575106163Sroberto		if (STREQ(pcmd->argval[items].string, "auth"))
1576106163Sroberto			sys.flags |= SYS_FLAG_AUTH;
157754359Sroberto		else if (STREQ(pcmd->argval[items].string, "bclient"))
1578106163Sroberto			sys.flags |= SYS_FLAG_BCLIENT;
1579106163Sroberto		else if (STREQ(pcmd->argval[items].string, "calibrate"))
1580106163Sroberto			sys.flags |= SYS_FLAG_CAL;
1581106163Sroberto		else if (STREQ(pcmd->argval[items].string, "kernel"))
1582106163Sroberto			sys.flags |= SYS_FLAG_KERNEL;
158354359Sroberto		else if (STREQ(pcmd->argval[items].string, "monitor"))
1584106163Sroberto			sys.flags |= SYS_FLAG_MONITOR;
158554359Sroberto		else if (STREQ(pcmd->argval[items].string, "ntp"))
1586106163Sroberto			sys.flags |= SYS_FLAG_NTP;
1587106163Sroberto		else if (STREQ(pcmd->argval[items].string, "pps"))
1588106163Sroberto			sys.flags |= SYS_FLAG_PPS;
158954359Sroberto		else if (STREQ(pcmd->argval[items].string, "stats"))
1590106163Sroberto			sys.flags |= SYS_FLAG_FILEGEN;
159154359Sroberto		else {
159254359Sroberto			(void) fprintf(fp, "Unknown flag %s\n",
1593106163Sroberto			    pcmd->argval[items].string);
159454359Sroberto			res = 1;
159554359Sroberto		}
159654359Sroberto	}
159754359Sroberto
1598182007Sroberto	sys.flags = htonl(sys.flags);
159954359Sroberto	if (res || sys.flags == 0)
160054359Sroberto	    return;
160154359Sroberto
1602132451Srobertoagain:
1603132451Sroberto	res = doquery(impl_ver, req, 1, 1,
160454359Sroberto		      sizeof(struct conf_sys_flags), (char *)&sys, &items,
1605132451Sroberto		      &itemsize, &dummy, 0, sizeof(struct conf_sys_flags));
160654359Sroberto
1607132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1608132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
1609132451Sroberto		goto again;
1610132451Sroberto	}
1611132451Sroberto
161254359Sroberto	if (res == 0)
161354359Sroberto	    (void) fprintf(fp, "done!\n");
161454359Sroberto}
161554359Sroberto
161654359Sroberto
161754359Sroberto/*
161854359Sroberto * data for printing/interrpreting the restrict flags
161954359Sroberto */
162054359Srobertostruct resflags {
162154359Sroberto  const char *str;
162254359Sroberto	int bit;
162354359Sroberto};
162454359Sroberto
1625182007Sroberto/* XXX: HMS: we apparently don't report set bits we do not recognize. */
1626182007Sroberto
1627182007Srobertostatic struct resflags resflagsV2[] = {
1628182007Sroberto	{ "ignore",	0x001 },
1629182007Sroberto	{ "noserve",	0x002 },
1630182007Sroberto	{ "notrust",	0x004 },
1631182007Sroberto	{ "noquery",	0x008 },
1632182007Sroberto	{ "nomodify",	0x010 },
1633182007Sroberto	{ "nopeer",	0x020 },
1634182007Sroberto	{ "notrap",	0x040 },
1635182007Sroberto	{ "lptrap",	0x080 },
1636182007Sroberto	{ "limited",	0x100 },
1637182007Sroberto	{ "",		0 }
1638182007Sroberto};
1639182007Sroberto
1640182007Srobertostatic struct resflags resflagsV3[] = {
164154359Sroberto	{ "ignore",	RES_IGNORE },
164254359Sroberto	{ "noserve",	RES_DONTSERVE },
164354359Sroberto	{ "notrust",	RES_DONTTRUST },
164454359Sroberto	{ "noquery",	RES_NOQUERY },
164554359Sroberto	{ "nomodify",	RES_NOMODIFY },
164654359Sroberto	{ "nopeer",	RES_NOPEER },
164754359Sroberto	{ "notrap",	RES_NOTRAP },
164854359Sroberto	{ "lptrap",	RES_LPTRAP },
164954359Sroberto	{ "limited",	RES_LIMITED },
165082498Sroberto	{ "version",	RES_VERSION },
1651290000Sglebius	{ "kod",	RES_KOD },
1652290000Sglebius	{ "flake",	RES_FLAKE },
165382498Sroberto
165454359Sroberto	{ "",		0 }
165554359Sroberto};
165654359Sroberto
165754359Srobertostatic struct resflags resmflags[] = {
165854359Sroberto	{ "ntpport",	RESM_NTPONLY },
165954359Sroberto	{ "interface",	RESM_INTERFACE },
1660290000Sglebius	{ "source",	RESM_SOURCE },
166154359Sroberto	{ "",		0 }
166254359Sroberto};
166354359Sroberto
166454359Sroberto
166554359Sroberto/*
166654359Sroberto * reslist - obtain and print the server's restrict list
166754359Sroberto */
166854359Sroberto/*ARGSUSED*/
166954359Srobertostatic void
167054359Srobertoreslist(
167154359Sroberto	struct parse *pcmd,
167254359Sroberto	FILE *fp
167354359Sroberto	)
167454359Sroberto{
167554359Sroberto	struct info_restrict *rl;
1676290000Sglebius	sockaddr_u resaddr;
1677290000Sglebius	sockaddr_u maskaddr;
1678293894Sglebius	size_t items;
1679293894Sglebius	size_t itemsize;
168054359Sroberto	int res;
1681132451Sroberto	int skip;
1682290000Sglebius	const char *addr;
1683290000Sglebius	const char *mask;
168454359Sroberto	struct resflags *rf;
168554359Sroberto	u_int32 count;
168654359Sroberto	u_short flags;
168754359Sroberto	u_short mflags;
168854359Sroberto	char flagstr[300];
168954359Sroberto	static const char *comma = ", ";
169054359Sroberto
1691132451Srobertoagain:
1692132451Sroberto	res = doquery(impl_ver, REQ_GET_RESTRICT, 0, 0, 0, (char *)NULL,
1693132451Sroberto		      &items, &itemsize, (void *)&rl, 0,
1694132451Sroberto		      sizeof(struct info_restrict));
169554359Sroberto
1696132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1697132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
1698132451Sroberto		goto again;
1699132451Sroberto	}
1700132451Sroberto
1701182007Sroberto	if (res != 0)
1702290000Sglebius		return;
170354359Sroberto
170454359Sroberto	if (!checkitems(items, fp))
1705290000Sglebius		return;
170654359Sroberto
1707132451Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_restrict)) &&
1708132451Sroberto	    !checkitemsize(itemsize, v4sizeof(struct info_restrict)))
1709290000Sglebius		return;
171054359Sroberto
1711290000Sglebius	fprintf(fp,
1712290000Sglebius		"   address          mask            count        flags\n");
1713290000Sglebius	fprintf(fp,
1714290000Sglebius		"=====================================================================\n");
1715132451Sroberto
171654359Sroberto	while (items > 0) {
1717290000Sglebius		SET_ADDRS(resaddr, maskaddr, rl, addr, mask);
1718132451Sroberto		if (rl->v6_flag != 0) {
1719132451Sroberto			addr = nntohost(&resaddr);
1720132451Sroberto		} else {
1721290000Sglebius			if (rl->mask == (u_int32)0xffffffff)
1722290000Sglebius				addr = nntohost(&resaddr);
1723132451Sroberto			else
1724132451Sroberto				addr = stoa(&resaddr);
1725132451Sroberto		}
1726132451Sroberto		mask = stoa(&maskaddr);
1727132451Sroberto		skip = 1;
1728132451Sroberto		if ((pcmd->nargs == 0) ||
1729132451Sroberto		    ((pcmd->argval->ival == 6) && (rl->v6_flag != 0)) ||
1730132451Sroberto		    ((pcmd->argval->ival == 4) && (rl->v6_flag == 0)))
1731132451Sroberto			skip = 0;
173254359Sroberto		count = ntohl(rl->count);
173354359Sroberto		flags = ntohs(rl->flags);
173454359Sroberto		mflags = ntohs(rl->mflags);
173554359Sroberto		flagstr[0] = '\0';
173654359Sroberto
173754359Sroberto		res = 1;
173854359Sroberto		rf = &resmflags[0];
173954359Sroberto		while (rf->bit != 0) {
174054359Sroberto			if (mflags & rf->bit) {
174154359Sroberto				if (!res)
1742290000Sglebius					strlcat(flagstr, comma,
1743290000Sglebius						sizeof(flagstr));
174454359Sroberto				res = 0;
1745290000Sglebius				strlcat(flagstr, rf->str,
1746290000Sglebius					sizeof(flagstr));
174754359Sroberto			}
174854359Sroberto			rf++;
174954359Sroberto		}
175054359Sroberto
1751182007Sroberto		rf = (impl_ver == IMPL_XNTPD_OLD)
1752290000Sglebius			 ? &resflagsV2[0]
1753290000Sglebius			 : &resflagsV3[0];
1754290000Sglebius
175554359Sroberto		while (rf->bit != 0) {
175654359Sroberto			if (flags & rf->bit) {
175754359Sroberto				if (!res)
1758290000Sglebius					strlcat(flagstr, comma,
1759290000Sglebius						sizeof(flagstr));
176054359Sroberto				res = 0;
1761290000Sglebius				strlcat(flagstr, rf->str,
1762290000Sglebius					sizeof(flagstr));
176354359Sroberto			}
176454359Sroberto			rf++;
176554359Sroberto		}
176654359Sroberto
176754359Sroberto		if (flagstr[0] == '\0')
1768290000Sglebius			strlcpy(flagstr, "none", sizeof(flagstr));
176954359Sroberto
1770132451Sroberto		if (!skip)
1771290000Sglebius			fprintf(fp, "%-15.15s %-15.15s %9lu  %s\n",
1772290000Sglebius				addr, mask, (u_long)count, flagstr);
177354359Sroberto		rl++;
177454359Sroberto		items--;
177554359Sroberto	}
177654359Sroberto}
177754359Sroberto
177854359Sroberto
177954359Sroberto
178054359Sroberto/*
178154359Sroberto * new_restrict - create/add a set of restrictions
178254359Sroberto */
178354359Srobertostatic void
178454359Srobertonew_restrict(
178554359Sroberto	struct parse *pcmd,
178654359Sroberto	FILE *fp
178754359Sroberto	)
178854359Sroberto{
178954359Sroberto	do_restrict(pcmd, fp, REQ_RESADDFLAGS);
179054359Sroberto}
179154359Sroberto
179254359Sroberto
179354359Sroberto/*
179454359Sroberto * unrestrict - remove restriction flags from existing entry
179554359Sroberto */
179654359Srobertostatic void
179754359Srobertounrestrict(
179854359Sroberto	struct parse *pcmd,
179954359Sroberto	FILE *fp
180054359Sroberto	)
180154359Sroberto{
180254359Sroberto	do_restrict(pcmd, fp, REQ_RESSUBFLAGS);
180354359Sroberto}
180454359Sroberto
180554359Sroberto
180654359Sroberto/*
180754359Sroberto * delrestrict - delete an existing restriction
180854359Sroberto */
180954359Srobertostatic void
181054359Srobertodelrestrict(
181154359Sroberto	struct parse *pcmd,
181254359Sroberto	FILE *fp
181354359Sroberto	)
181454359Sroberto{
181554359Sroberto	do_restrict(pcmd, fp, REQ_UNRESTRICT);
181654359Sroberto}
181754359Sroberto
181854359Sroberto
181954359Sroberto/*
182054359Sroberto * do_restrict - decode commandline restrictions and make the request
182154359Sroberto */
182254359Srobertostatic void
182354359Srobertodo_restrict(
182454359Sroberto	struct parse *pcmd,
182554359Sroberto	FILE *fp,
182654359Sroberto	int req_code
182754359Sroberto	)
182854359Sroberto{
182954359Sroberto	struct conf_restrict cres;
1830293894Sglebius	size_t items;
1831293894Sglebius	size_t itemsize;
1832293894Sglebius	const char *dummy;
183354359Sroberto	u_int32 num;
183454359Sroberto	u_long bit;
183554359Sroberto	int i;
1836290000Sglebius	size_t res;
183754359Sroberto	int err;
1838132451Sroberto	int sendsize;
183954359Sroberto
1840132451Sroberto	/* Initialize cres */
1841132451Sroberto	cres.addr = 0;
1842132451Sroberto	cres.mask = 0;
184354359Sroberto	cres.flags = 0;
184454359Sroberto	cres.mflags = 0;
1845132451Sroberto	cres.v6_flag = 0;
1846132451Sroberto
1847132451Srobertoagain:
1848132451Sroberto	if (impl_ver == IMPL_XNTPD)
1849132451Sroberto		sendsize = sizeof(struct conf_restrict);
1850132451Sroberto	else
1851132451Sroberto		sendsize = v4sizeof(struct conf_restrict);
1852132451Sroberto
1853290000Sglebius	if (IS_IPV4(&pcmd->argval[0].netnum)) {
1854290000Sglebius		cres.addr = NSRCADR(&pcmd->argval[0].netnum);
1855290000Sglebius		cres.mask = NSRCADR(&pcmd->argval[1].netnum);
1856132451Sroberto		if (impl_ver == IMPL_XNTPD)
1857132451Sroberto			cres.v6_flag = 0;
1858132451Sroberto	} else {
1859132451Sroberto		if (impl_ver == IMPL_XNTPD_OLD) {
1860132451Sroberto			fprintf(stderr,
1861290000Sglebius				"***Server doesn't understand IPv6 addresses\n");
1862132451Sroberto			return;
1863132451Sroberto		}
1864290000Sglebius		cres.addr6 = SOCK_ADDR6(&pcmd->argval[0].netnum);
1865132451Sroberto		cres.v6_flag = 1;
1866132451Sroberto	}
1867132451Sroberto	cres.flags = 0;
1868132451Sroberto	cres.mflags = 0;
1869290000Sglebius	err = FALSE;
187054359Sroberto	for (res = 2; res < pcmd->nargs; res++) {
187154359Sroberto		if (STREQ(pcmd->argval[res].string, "ntpport")) {
187254359Sroberto			cres.mflags |= RESM_NTPONLY;
187354359Sroberto		} else {
1874182007Sroberto			for (i = 0; resflagsV3[i].bit != 0; i++) {
187554359Sroberto				if (STREQ(pcmd->argval[res].string,
1876182007Sroberto					  resflagsV3[i].str))
1877290000Sglebius					break;
187854359Sroberto			}
1879182007Sroberto			if (resflagsV3[i].bit != 0) {
1880182007Sroberto				cres.flags |= resflagsV3[i].bit;
188154359Sroberto				if (req_code == REQ_UNRESTRICT) {
1882290000Sglebius					fprintf(fp,
1883290000Sglebius						"Flag %s inappropriate\n",
1884290000Sglebius						resflagsV3[i].str);
1885290000Sglebius					err = TRUE;
188654359Sroberto				}
188754359Sroberto			} else {
1888290000Sglebius				fprintf(fp, "Unknown flag %s\n",
1889290000Sglebius					pcmd->argval[res].string);
1890290000Sglebius				err = TRUE;
189154359Sroberto			}
189254359Sroberto		}
189354359Sroberto	}
1894182007Sroberto	cres.flags = htons(cres.flags);
1895182007Sroberto	cres.mflags = htons(cres.mflags);
189654359Sroberto
189754359Sroberto	/*
189854359Sroberto	 * Make sure mask for default address is zero.  Otherwise,
189954359Sroberto	 * make sure mask bits are contiguous.
190054359Sroberto	 */
1901290000Sglebius	if (IS_IPV4(&pcmd->argval[0].netnum)) {
1902132451Sroberto		if (cres.addr == 0) {
1903132451Sroberto			cres.mask = 0;
1904132451Sroberto		} else {
1905132451Sroberto			num = ntohl(cres.mask);
1906132451Sroberto			for (bit = 0x80000000; bit != 0; bit >>= 1)
1907290000Sglebius				if ((num & bit) == 0)
1908290000Sglebius					break;
1909132451Sroberto			for ( ; bit != 0; bit >>= 1)
1910290000Sglebius				if ((num & bit) != 0)
1911290000Sglebius					break;
1912132451Sroberto			if (bit != 0) {
1913290000Sglebius				fprintf(fp, "Invalid mask %s\n",
1914290000Sglebius					numtoa(cres.mask));
1915290000Sglebius				err = TRUE;
1916132451Sroberto			}
1917132451Sroberto		}
191854359Sroberto	} else {
1919132451Sroberto		/* XXX IPv6 sanity checking stuff */
192054359Sroberto	}
192154359Sroberto
192254359Sroberto	if (err)
1923290000Sglebius		return;
192454359Sroberto
1925290000Sglebius	res = doquery(impl_ver, req_code, 1, 1, sendsize, (char *)&cres,
1926290000Sglebius		      &items, &itemsize, &dummy, 0, sizeof(cres));
192754359Sroberto
1928132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1929132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
1930132451Sroberto		goto again;
1931132451Sroberto	}
1932132451Sroberto
193354359Sroberto	if (res == 0)
193454359Sroberto	    (void) fprintf(fp, "done!\n");
193554359Sroberto	return;
193654359Sroberto}
193754359Sroberto
193854359Sroberto
193954359Sroberto/*
194054359Sroberto * monlist - obtain and print the server's monitor data
194154359Sroberto */
194254359Sroberto/*ARGSUSED*/
194354359Srobertostatic void
194454359Srobertomonlist(
194554359Sroberto	struct parse *pcmd,
194654359Sroberto	FILE *fp
194754359Sroberto	)
194854359Sroberto{
1949293894Sglebius	const char *struct_star;
1950293894Sglebius	const struct info_monitor *ml;
1951293894Sglebius	const struct info_monitor_1 *m1;
1952293894Sglebius	const struct old_info_monitor *oml;
1953290000Sglebius	sockaddr_u addr;
1954290000Sglebius	sockaddr_u dstadr;
1955293894Sglebius	size_t items;
1956293894Sglebius	size_t itemsize;
195754359Sroberto	int res;
195854359Sroberto	int version = -1;
195954359Sroberto
1960290000Sglebius	if (pcmd->nargs > 0)
196154359Sroberto		version = pcmd->argval[0].ival;
196254359Sroberto
1963132451Srobertoagain:
1964132451Sroberto	res = doquery(impl_ver,
196554359Sroberto		      (version == 1 || version == -1) ? REQ_MON_GETLIST_1 :
1966290000Sglebius		      REQ_MON_GETLIST, 0, 0, 0, NULL,
196754359Sroberto		      &items, &itemsize, &struct_star,
1968132451Sroberto		      (version < 0) ? (1 << INFO_ERR_REQ) : 0,
1969132451Sroberto		      sizeof(struct info_monitor_1));
197054359Sroberto
1971132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1972132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
1973132451Sroberto		goto again;
1974132451Sroberto	}
1975132451Sroberto
197654359Sroberto	if (res == INFO_ERR_REQ && version < 0)
1977290000Sglebius		res = doquery(impl_ver, REQ_MON_GETLIST, 0, 0, 0, NULL,
1978290000Sglebius			      &items, &itemsize, &struct_star, 0,
1979290000Sglebius			      sizeof(struct info_monitor));
198054359Sroberto
1981182007Sroberto	if (res != 0)
1982290000Sglebius		return;
198354359Sroberto
198454359Sroberto	if (!checkitems(items, fp))
1985290000Sglebius		return;
198654359Sroberto
1987132451Sroberto	if (itemsize == sizeof(struct info_monitor_1) ||
1988132451Sroberto	    itemsize == v4sizeof(struct info_monitor_1)) {
198954359Sroberto
1990293894Sglebius	    m1 = (const void*)struct_star;
1991290000Sglebius		fprintf(fp,
1992290000Sglebius			"remote address          port local address      count m ver rstr avgint  lstint\n");
1993290000Sglebius		fprintf(fp,
1994290000Sglebius			"===============================================================================\n");
199554359Sroberto		while (items > 0) {
1996290000Sglebius			SET_ADDRS(dstadr, addr, m1, daddr, addr);
1997132451Sroberto			if ((pcmd->nargs == 0) ||
1998290000Sglebius			    ((pcmd->argval->ival == 6) && (m1->v6_flag != 0)) ||
1999290000Sglebius			    ((pcmd->argval->ival == 4) && (m1->v6_flag == 0)))
2000290000Sglebius				fprintf(fp,
2001290000Sglebius				    "%-22.22s %5d %-15s %8lu %1u %1u %6lx %6lu %7lu\n",
2002132451Sroberto				    nntohost(&addr),
2003290000Sglebius				    ntohs(m1->port),
2004132451Sroberto				    stoa(&dstadr),
2005290000Sglebius				    (u_long)ntohl(m1->count),
2006290000Sglebius				    m1->mode,
2007290000Sglebius				    m1->version,
2008290000Sglebius				    (u_long)ntohl(m1->restr),
2009290000Sglebius				    (u_long)ntohl(m1->avg_int),
2010290000Sglebius				    (u_long)ntohl(m1->last_int));
2011290000Sglebius			m1++;
201254359Sroberto			items--;
201354359Sroberto		}
2014132451Sroberto	} else if (itemsize == sizeof(struct info_monitor) ||
2015132451Sroberto	    itemsize == v4sizeof(struct info_monitor)) {
201654359Sroberto
2017293894Sglebius		ml = (const void *)struct_star;
2018290000Sglebius		fprintf(fp,
2019290000Sglebius			"     address               port     count mode ver rstr avgint  lstint\n");
2020290000Sglebius		fprintf(fp,
2021290000Sglebius			"===============================================================================\n");
202254359Sroberto		while (items > 0) {
2023290000Sglebius			SET_ADDR(dstadr, ml->v6_flag, ml->addr, ml->addr6);
2024132451Sroberto			if ((pcmd->nargs == 0) ||
2025132451Sroberto			    ((pcmd->argval->ival == 6) && (ml->v6_flag != 0)) ||
2026132451Sroberto			    ((pcmd->argval->ival == 4) && (ml->v6_flag == 0)))
2027290000Sglebius				fprintf(fp,
2028290000Sglebius				    "%-25.25s %5u %9lu %4u %2u %9lx %9lu %9lu\n",
2029132451Sroberto				    nntohost(&dstadr),
2030132451Sroberto				    ntohs(ml->port),
2031132451Sroberto				    (u_long)ntohl(ml->count),
2032132451Sroberto				    ml->mode,
2033132451Sroberto				    ml->version,
2034290000Sglebius				    (u_long)ntohl(ml->restr),
2035290000Sglebius				    (u_long)ntohl(ml->avg_int),
2036290000Sglebius				    (u_long)ntohl(ml->last_int));
203754359Sroberto			ml++;
203854359Sroberto			items--;
203954359Sroberto		}
204054359Sroberto	} else if (itemsize == sizeof(struct old_info_monitor)) {
2041290000Sglebius
2042293894Sglebius		oml = (const void *)struct_star;
2043290000Sglebius		fprintf(fp,
2044290000Sglebius			"     address          port     count  mode version  lasttime firsttime\n");
2045290000Sglebius		fprintf(fp,
2046290000Sglebius			"======================================================================\n");
204754359Sroberto		while (items > 0) {
2048290000Sglebius			SET_ADDR(dstadr, oml->v6_flag, oml->addr, oml->addr6);
2049290000Sglebius			fprintf(fp, "%-20.20s %5u %9lu %4u   %3u %9lu %9lu\n",
2050290000Sglebius				nntohost(&dstadr),
2051290000Sglebius				ntohs(oml->port),
2052290000Sglebius				(u_long)ntohl(oml->count),
2053290000Sglebius				oml->mode,
2054290000Sglebius				oml->version,
2055290000Sglebius				(u_long)ntohl(oml->lasttime),
2056290000Sglebius				(u_long)ntohl(oml->firsttime));
205754359Sroberto			oml++;
205854359Sroberto			items--;
205954359Sroberto		}
206054359Sroberto	} else {
206154359Sroberto		/* issue warning according to new info_monitor size */
206254359Sroberto		checkitemsize(itemsize, sizeof(struct info_monitor));
206354359Sroberto	}
206454359Sroberto}
206554359Sroberto
206654359Sroberto
206754359Sroberto/*
206854359Sroberto * Mapping between command line strings and stat reset flags
206954359Sroberto */
207054359Srobertostruct statreset {
2071290000Sglebius	const char * const	str;
2072290000Sglebius	const int		flag;
207354359Sroberto} sreset[] = {
2074290000Sglebius	{ "allpeers",	RESET_FLAG_ALLPEERS },
207554359Sroberto	{ "io",		RESET_FLAG_IO },
207654359Sroberto	{ "sys",	RESET_FLAG_SYS },
207754359Sroberto	{ "mem",	RESET_FLAG_MEM },
207854359Sroberto	{ "timer",	RESET_FLAG_TIMER },
207954359Sroberto	{ "auth",	RESET_FLAG_AUTH },
2080290000Sglebius	{ "ctl",	RESET_FLAG_CTL },
208154359Sroberto	{ "",		0 }
208254359Sroberto};
208354359Sroberto
208454359Sroberto/*
208554359Sroberto * reset - reset statistic counters
208654359Sroberto */
208754359Srobertostatic void
208854359Srobertoreset(
208954359Sroberto	struct parse *pcmd,
209054359Sroberto	FILE *fp
209154359Sroberto	)
209254359Sroberto{
209354359Sroberto	struct reset_flags rflags;
2094293894Sglebius	size_t items;
2095293894Sglebius	size_t itemsize;
2096293894Sglebius	const char *dummy;
209754359Sroberto	int i;
2098290000Sglebius	size_t res;
209954359Sroberto	int err;
210054359Sroberto
210154359Sroberto	err = 0;
210254359Sroberto	rflags.flags = 0;
210354359Sroberto	for (res = 0; res < pcmd->nargs; res++) {
210454359Sroberto		for (i = 0; sreset[i].flag != 0; i++) {
210554359Sroberto			if (STREQ(pcmd->argval[res].string, sreset[i].str))
2106290000Sglebius				break;
210754359Sroberto		}
210854359Sroberto		if (sreset[i].flag == 0) {
2109290000Sglebius			fprintf(fp, "Flag %s unknown\n",
2110290000Sglebius				pcmd->argval[res].string);
211154359Sroberto			err++;
211254359Sroberto		} else {
211354359Sroberto			rflags.flags |= sreset[i].flag;
211454359Sroberto		}
211554359Sroberto	}
2116182007Sroberto	rflags.flags = htonl(rflags.flags);
211754359Sroberto
211854359Sroberto	if (err) {
211954359Sroberto		(void) fprintf(fp, "Not done due to errors\n");
212054359Sroberto		return;
212154359Sroberto	}
212254359Sroberto
2123132451Srobertoagain:
2124132451Sroberto	res = doquery(impl_ver, REQ_RESET_STATS, 1, 1,
212554359Sroberto		      sizeof(struct reset_flags), (char *)&rflags, &items,
2126132451Sroberto		      &itemsize, &dummy, 0, sizeof(struct reset_flags));
212754359Sroberto
2128132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2129132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2130132451Sroberto		goto again;
2131132451Sroberto	}
2132132451Sroberto
213354359Sroberto	if (res == 0)
213454359Sroberto	    (void) fprintf(fp, "done!\n");
213554359Sroberto	return;
213654359Sroberto}
213754359Sroberto
213854359Sroberto
213954359Sroberto
214054359Sroberto/*
214154359Sroberto * preset - reset stat counters for particular peers
214254359Sroberto */
214354359Srobertostatic void
214454359Srobertopreset(
214554359Sroberto	struct parse *pcmd,
214654359Sroberto	FILE *fp
214754359Sroberto	)
214854359Sroberto{
214954359Sroberto	/* 8 is the maximum number of peers which will fit in a packet */
2150132451Sroberto	struct conf_unpeer *pl, plist[min(MAXARGS, 8)];
2151293894Sglebius	size_t qitemlim;
2152293894Sglebius	size_t qitems;
2153293894Sglebius	size_t items;
2154293894Sglebius	size_t itemsize;
2155293894Sglebius	const char *dummy;
215654359Sroberto	int res;
2157293894Sglebius	size_t sendsize;
215854359Sroberto
2159132451Srobertoagain:
2160132451Sroberto	if (impl_ver == IMPL_XNTPD)
2161132451Sroberto		sendsize = sizeof(struct conf_unpeer);
2162132451Sroberto	else
2163132451Sroberto		sendsize = v4sizeof(struct conf_unpeer);
2164132451Sroberto
2165290000Sglebius	qitemlim = min(pcmd->nargs, COUNTOF(plist));
2166290000Sglebius	for (qitems = 0, pl = plist; qitems < qitemlim; qitems++) {
2167290000Sglebius		if (IS_IPV4(&pcmd->argval[qitems].netnum)) {
2168290000Sglebius			pl->peeraddr = NSRCADR(&pcmd->argval[qitems].netnum);
2169132451Sroberto			if (impl_ver == IMPL_XNTPD)
2170132451Sroberto				pl->v6_flag = 0;
2171132451Sroberto		} else {
2172132451Sroberto			if (impl_ver == IMPL_XNTPD_OLD) {
2173132451Sroberto				fprintf(stderr,
2174132451Sroberto				    "***Server doesn't understand IPv6 addresses\n");
2175132451Sroberto				return;
2176132451Sroberto			}
2177132451Sroberto			pl->peeraddr6 =
2178290000Sglebius			    SOCK_ADDR6(&pcmd->argval[qitems].netnum);
2179132451Sroberto			pl->v6_flag = 1;
2180132451Sroberto		}
2181290000Sglebius		pl = (void *)((char *)pl + sendsize);
218254359Sroberto	}
218354359Sroberto
2184132451Sroberto	res = doquery(impl_ver, REQ_RESET_PEER, 1, qitems,
2185132451Sroberto		      sendsize, (char *)plist, &items,
2186132451Sroberto		      &itemsize, &dummy, 0, sizeof(struct conf_unpeer));
218754359Sroberto
2188132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2189132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2190132451Sroberto		goto again;
2191132451Sroberto	}
2192132451Sroberto
219354359Sroberto	if (res == 0)
219454359Sroberto	    (void) fprintf(fp, "done!\n");
219554359Sroberto}
219654359Sroberto
219754359Sroberto
219854359Sroberto/*
219954359Sroberto * readkeys - request the server to reread the keys file
220054359Sroberto */
220154359Sroberto/*ARGSUSED*/
220254359Srobertostatic void
220354359Srobertoreadkeys(
220454359Sroberto	struct parse *pcmd,
220554359Sroberto	FILE *fp
220654359Sroberto	)
220754359Sroberto{
2208293894Sglebius	size_t items;
2209293894Sglebius	size_t itemsize;
2210293894Sglebius	const char *dummy;
221154359Sroberto	int res;
221254359Sroberto
2213132451Srobertoagain:
2214132451Sroberto	res = doquery(impl_ver, REQ_REREAD_KEYS, 1, 0, 0, (char *)0,
2215132451Sroberto		      &items, &itemsize, &dummy, 0, sizeof(dummy));
221654359Sroberto
2217132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2218132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2219132451Sroberto		goto again;
2220132451Sroberto	}
2221132451Sroberto
222254359Sroberto	if (res == 0)
222354359Sroberto	    (void) fprintf(fp, "done!\n");
222454359Sroberto	return;
222554359Sroberto}
222654359Sroberto
222754359Sroberto
222854359Sroberto/*
222954359Sroberto * trustkey - add some keys to the trusted key list
223054359Sroberto */
223154359Srobertostatic void
223254359Srobertotrustkey(
223354359Sroberto	struct parse *pcmd,
223454359Sroberto	FILE *fp
223554359Sroberto	)
223654359Sroberto{
223754359Sroberto	do_trustkey(pcmd, fp, REQ_TRUSTKEY);
223854359Sroberto}
223954359Sroberto
224054359Sroberto
224154359Sroberto/*
224254359Sroberto * untrustkey - remove some keys from the trusted key list
224354359Sroberto */
224454359Srobertostatic void
224554359Srobertountrustkey(
224654359Sroberto	struct parse *pcmd,
224754359Sroberto	FILE *fp
224854359Sroberto	)
224954359Sroberto{
225054359Sroberto	do_trustkey(pcmd, fp, REQ_UNTRUSTKEY);
225154359Sroberto}
225254359Sroberto
225354359Sroberto
225454359Sroberto/*
225554359Sroberto * do_trustkey - do grunge work of adding/deleting keys
225654359Sroberto */
225754359Srobertostatic void
225854359Srobertodo_trustkey(
225954359Sroberto	struct parse *pcmd,
226054359Sroberto	FILE *fp,
226154359Sroberto	int req
226254359Sroberto	)
226354359Sroberto{
226454359Sroberto	u_long keyids[MAXARGS];
2265290000Sglebius	size_t i;
2266293894Sglebius	size_t items;
2267293894Sglebius	size_t itemsize;
2268293894Sglebius	const char *dummy;
226954359Sroberto	int ritems;
227054359Sroberto	int res;
227154359Sroberto
227254359Sroberto	ritems = 0;
227354359Sroberto	for (i = 0; i < pcmd->nargs; i++) {
227454359Sroberto		keyids[ritems++] = pcmd->argval[i].uval;
227554359Sroberto	}
227654359Sroberto
2277132451Srobertoagain:
2278132451Sroberto	res = doquery(impl_ver, req, 1, ritems, sizeof(u_long),
2279132451Sroberto		      (char *)keyids, &items, &itemsize, &dummy, 0,
2280132451Sroberto		      sizeof(dummy));
228154359Sroberto
2282132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2283132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2284132451Sroberto		goto again;
2285132451Sroberto	}
2286132451Sroberto
228754359Sroberto	if (res == 0)
228854359Sroberto	    (void) fprintf(fp, "done!\n");
228954359Sroberto	return;
229054359Sroberto}
229154359Sroberto
229254359Sroberto
229354359Sroberto
229454359Sroberto/*
229554359Sroberto * authinfo - obtain and print info about authentication
229654359Sroberto */
229754359Sroberto/*ARGSUSED*/
229854359Srobertostatic void
229954359Srobertoauthinfo(
230054359Sroberto	struct parse *pcmd,
230154359Sroberto	FILE *fp
230254359Sroberto	)
230354359Sroberto{
230454359Sroberto	struct info_auth *ia;
2305293894Sglebius	size_t items;
2306293894Sglebius	size_t itemsize;
230754359Sroberto	int res;
230854359Sroberto
2309132451Srobertoagain:
2310290000Sglebius	res = doquery(impl_ver, REQ_AUTHINFO, 0, 0, 0, NULL, &items,
2311290000Sglebius		      &itemsize, (void *)&ia, 0, sizeof(*ia));
231254359Sroberto
2313132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2314132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2315132451Sroberto		goto again;
2316132451Sroberto	}
2317132451Sroberto
2318182007Sroberto	if (res != 0)
2319290000Sglebius		return;
232054359Sroberto
232154359Sroberto	if (!check1item(items, fp))
2322290000Sglebius		return;
232354359Sroberto
2324290000Sglebius	if (!checkitemsize(itemsize, sizeof(*ia)))
2325290000Sglebius		return;
232654359Sroberto
2327290000Sglebius	fprintf(fp, "time since reset:     %lu\n",
2328290000Sglebius		(u_long)ntohl(ia->timereset));
2329290000Sglebius	fprintf(fp, "stored keys:          %lu\n",
2330290000Sglebius		(u_long)ntohl(ia->numkeys));
2331290000Sglebius	fprintf(fp, "free keys:            %lu\n",
2332290000Sglebius		(u_long)ntohl(ia->numfreekeys));
2333290000Sglebius	fprintf(fp, "key lookups:          %lu\n",
2334290000Sglebius		(u_long)ntohl(ia->keylookups));
2335290000Sglebius	fprintf(fp, "keys not found:       %lu\n",
2336290000Sglebius		(u_long)ntohl(ia->keynotfound));
2337290000Sglebius	fprintf(fp, "uncached keys:        %lu\n",
2338290000Sglebius		(u_long)ntohl(ia->keyuncached));
2339290000Sglebius	fprintf(fp, "encryptions:          %lu\n",
2340290000Sglebius		(u_long)ntohl(ia->encryptions));
2341290000Sglebius	fprintf(fp, "decryptions:          %lu\n",
2342290000Sglebius		(u_long)ntohl(ia->decryptions));
2343290000Sglebius	fprintf(fp, "expired keys:         %lu\n",
2344290000Sglebius		(u_long)ntohl(ia->expired));
234554359Sroberto}
234654359Sroberto
234754359Sroberto
234854359Sroberto
234954359Sroberto/*
235054359Sroberto * traps - obtain and print a list of traps
235154359Sroberto */
235254359Sroberto/*ARGSUSED*/
235354359Srobertostatic void
235454359Srobertotraps(
235554359Sroberto	struct parse *pcmd,
235654359Sroberto	FILE *fp
235754359Sroberto	)
235854359Sroberto{
2359293894Sglebius	size_t i;
236054359Sroberto	struct info_trap *it;
2361290000Sglebius	sockaddr_u trap_addr, local_addr;
2362293894Sglebius	size_t items;
2363293894Sglebius	size_t itemsize;
236454359Sroberto	int res;
236554359Sroberto
2366132451Srobertoagain:
2367290000Sglebius	res = doquery(impl_ver, REQ_TRAPS, 0, 0, 0, NULL, &items,
2368290000Sglebius		      &itemsize, (void *)&it, 0, sizeof(*it));
236954359Sroberto
2370132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2371132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2372132451Sroberto		goto again;
2373132451Sroberto	}
2374132451Sroberto
2375182007Sroberto	if (res != 0)
2376290000Sglebius		return;
237754359Sroberto
237854359Sroberto	if (!checkitems(items, fp))
2379290000Sglebius		return;
238054359Sroberto
2381132451Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_trap)) &&
2382132451Sroberto	    !checkitemsize(itemsize, v4sizeof(struct info_trap)))
2383290000Sglebius		return;
238454359Sroberto
238554359Sroberto	for (i = 0; i < items; i++ ) {
2386290000Sglebius		SET_ADDRS(trap_addr, local_addr, it, trap_address, local_address);
2387290000Sglebius		fprintf(fp, "%saddress %s, port %d\n",
2388290000Sglebius			(0 == i)
2389290000Sglebius			    ? ""
2390290000Sglebius			    : "\n",
2391290000Sglebius			stoa(&trap_addr), ntohs(it->trap_port));
2392290000Sglebius		fprintf(fp, "interface: %s, ",
2393290000Sglebius			(0 == it->local_address)
2394290000Sglebius			    ? "wildcard"
2395290000Sglebius			    : stoa(&local_addr));
239654359Sroberto		if (ntohl(it->flags) & TRAP_CONFIGURED)
2397290000Sglebius			fprintf(fp, "configured\n");
239854359Sroberto		else if (ntohl(it->flags) & TRAP_NONPRIO)
2399290000Sglebius			fprintf(fp, "low priority\n");
240054359Sroberto		else
2401290000Sglebius			fprintf(fp, "normal priority\n");
240254359Sroberto
2403290000Sglebius		fprintf(fp, "set for %ld secs, last set %ld secs ago\n",
2404290000Sglebius			(long)ntohl(it->origtime),
2405290000Sglebius			(long)ntohl(it->settime));
2406290000Sglebius		fprintf(fp, "sequence %d, number of resets %ld\n",
2407290000Sglebius			ntohs(it->sequence), (long)ntohl(it->resets));
240854359Sroberto	}
240954359Sroberto}
241054359Sroberto
241154359Sroberto
241254359Sroberto/*
241354359Sroberto * addtrap - configure a trap
241454359Sroberto */
241554359Srobertostatic void
241654359Srobertoaddtrap(
241754359Sroberto	struct parse *pcmd,
241854359Sroberto	FILE *fp
241954359Sroberto	)
242054359Sroberto{
242154359Sroberto	do_addclr_trap(pcmd, fp, REQ_ADD_TRAP);
242254359Sroberto}
242354359Sroberto
242454359Sroberto
242554359Sroberto/*
242654359Sroberto * clrtrap - clear a trap from the server
242754359Sroberto */
242854359Srobertostatic void
242954359Srobertoclrtrap(
243054359Sroberto	struct parse *pcmd,
243154359Sroberto	FILE *fp
243254359Sroberto	)
243354359Sroberto{
243454359Sroberto	do_addclr_trap(pcmd, fp, REQ_CLR_TRAP);
243554359Sroberto}
243654359Sroberto
243754359Sroberto
243854359Sroberto/*
243954359Sroberto * do_addclr_trap - do grunge work of adding/deleting traps
244054359Sroberto */
244154359Srobertostatic void
244254359Srobertodo_addclr_trap(
244354359Sroberto	struct parse *pcmd,
244454359Sroberto	FILE *fp,
244554359Sroberto	int req
244654359Sroberto	)
244754359Sroberto{
244854359Sroberto	struct conf_trap ctrap;
2449293894Sglebius	size_t items;
2450293894Sglebius	size_t itemsize;
2451293894Sglebius	const char *dummy;
245254359Sroberto	int res;
2453132451Sroberto	int sendsize;
245454359Sroberto
2455132451Srobertoagain:
2456132451Sroberto	if (impl_ver == IMPL_XNTPD)
2457132451Sroberto		sendsize = sizeof(struct conf_trap);
2458132451Sroberto	else
2459132451Sroberto		sendsize = v4sizeof(struct conf_trap);
2460132451Sroberto
2461290000Sglebius	if (IS_IPV4(&pcmd->argval[0].netnum)) {
2462290000Sglebius		ctrap.trap_address = NSRCADR(&pcmd->argval[0].netnum);
2463132451Sroberto		if (impl_ver == IMPL_XNTPD)
2464132451Sroberto			ctrap.v6_flag = 0;
2465132451Sroberto	} else {
2466132451Sroberto		if (impl_ver == IMPL_XNTPD_OLD) {
2467132451Sroberto			fprintf(stderr,
2468132451Sroberto			    "***Server doesn't understand IPv6 addresses\n");
2469132451Sroberto			return;
2470132451Sroberto		}
2471290000Sglebius		ctrap.trap_address6 = SOCK_ADDR6(&pcmd->argval[0].netnum);
2472132451Sroberto		ctrap.v6_flag = 1;
2473132451Sroberto	}
247454359Sroberto	ctrap.local_address = 0;
247554359Sroberto	ctrap.trap_port = htons(TRAPPORT);
247654359Sroberto	ctrap.unused = 0;
247754359Sroberto
247854359Sroberto	if (pcmd->nargs > 1) {
2479290000Sglebius		ctrap.trap_port	= htons((u_short)pcmd->argval[1].uval);
2480132451Sroberto		if (pcmd->nargs > 2) {
2481290000Sglebius			if (AF(&pcmd->argval[2].netnum) !=
2482290000Sglebius			    AF(&pcmd->argval[0].netnum)) {
2483132451Sroberto				fprintf(stderr,
2484132451Sroberto				    "***Cannot mix IPv4 and IPv6 addresses\n");
2485132451Sroberto				return;
2486132451Sroberto			}
2487290000Sglebius			if (IS_IPV4(&pcmd->argval[2].netnum))
2488290000Sglebius				ctrap.local_address = NSRCADR(&pcmd->argval[2].netnum);
2489132451Sroberto			else
2490290000Sglebius				ctrap.local_address6 = SOCK_ADDR6(&pcmd->argval[2].netnum);
2491132451Sroberto		}
249254359Sroberto	}
249354359Sroberto
2494132451Sroberto	res = doquery(impl_ver, req, 1, 1, sendsize,
2495132451Sroberto		      (char *)&ctrap, &items, &itemsize, &dummy, 0,
2496132451Sroberto		      sizeof(struct conf_trap));
249754359Sroberto
2498132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2499132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2500132451Sroberto		goto again;
2501132451Sroberto	}
2502132451Sroberto
250354359Sroberto	if (res == 0)
250454359Sroberto	    (void) fprintf(fp, "done!\n");
250554359Sroberto	return;
250654359Sroberto}
250754359Sroberto
250854359Sroberto
250954359Sroberto
251054359Sroberto/*
251154359Sroberto * requestkey - change the server's request key (a dangerous request)
251254359Sroberto */
251354359Srobertostatic void
251454359Srobertorequestkey(
251554359Sroberto	struct parse *pcmd,
251654359Sroberto	FILE *fp
251754359Sroberto	)
251854359Sroberto{
251954359Sroberto	do_changekey(pcmd, fp, REQ_REQUEST_KEY);
252054359Sroberto}
252154359Sroberto
252254359Sroberto
252354359Sroberto/*
252454359Sroberto * controlkey - change the server's control key
252554359Sroberto */
252654359Srobertostatic void
252754359Srobertocontrolkey(
252854359Sroberto	struct parse *pcmd,
252954359Sroberto	FILE *fp
253054359Sroberto	)
253154359Sroberto{
253254359Sroberto	do_changekey(pcmd, fp, REQ_CONTROL_KEY);
253354359Sroberto}
253454359Sroberto
253554359Sroberto
253654359Sroberto
253754359Sroberto/*
253854359Sroberto * do_changekey - do grunge work of changing keys
253954359Sroberto */
254054359Srobertostatic void
254154359Srobertodo_changekey(
254254359Sroberto	struct parse *pcmd,
254354359Sroberto	FILE *fp,
254454359Sroberto	int req
254554359Sroberto	)
254654359Sroberto{
254754359Sroberto	u_long key;
2548293894Sglebius	size_t items;
2549293894Sglebius	size_t itemsize;
2550293894Sglebius	const char *dummy;
255154359Sroberto	int res;
255254359Sroberto
255354359Sroberto
255454359Sroberto	key = htonl((u_int32)pcmd->argval[0].uval);
255554359Sroberto
2556132451Srobertoagain:
2557132451Sroberto	res = doquery(impl_ver, req, 1, 1, sizeof(u_int32),
2558132451Sroberto		      (char *)&key, &items, &itemsize, &dummy, 0,
2559132451Sroberto		      sizeof(dummy));
256054359Sroberto
2561132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2562132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2563132451Sroberto		goto again;
2564132451Sroberto	}
2565132451Sroberto
256654359Sroberto	if (res == 0)
256754359Sroberto	    (void) fprintf(fp, "done!\n");
256854359Sroberto	return;
256954359Sroberto}
257054359Sroberto
257154359Sroberto
257254359Sroberto
257354359Sroberto/*
257454359Sroberto * ctlstats - obtain and print info about authentication
257554359Sroberto */
257654359Sroberto/*ARGSUSED*/
257754359Srobertostatic void
257854359Srobertoctlstats(
257954359Sroberto	struct parse *pcmd,
258054359Sroberto	FILE *fp
258154359Sroberto	)
258254359Sroberto{
258354359Sroberto	struct info_control *ic;
2584293894Sglebius	size_t items;
2585293894Sglebius	size_t itemsize;
258654359Sroberto	int res;
258754359Sroberto
2588132451Srobertoagain:
2589290000Sglebius	res = doquery(impl_ver, REQ_GET_CTLSTATS, 0, 0, 0, NULL, &items,
2590290000Sglebius		      &itemsize, (void *)&ic, 0, sizeof(*ic));
259154359Sroberto
2592132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2593132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2594132451Sroberto		goto again;
2595132451Sroberto	}
2596132451Sroberto
2597182007Sroberto	if (res != 0)
2598290000Sglebius		return;
259954359Sroberto
260054359Sroberto	if (!check1item(items, fp))
2601290000Sglebius		return;
260254359Sroberto
2603290000Sglebius	if (!checkitemsize(itemsize, sizeof(*ic)))
2604290000Sglebius		return;
260554359Sroberto
2606290000Sglebius	fprintf(fp, "time since reset:       %lu\n",
2607290000Sglebius		(u_long)ntohl(ic->ctltimereset));
2608290000Sglebius	fprintf(fp, "requests received:      %lu\n",
2609290000Sglebius		(u_long)ntohl(ic->numctlreq));
2610290000Sglebius	fprintf(fp, "responses sent:         %lu\n",
2611290000Sglebius		(u_long)ntohl(ic->numctlresponses));
2612290000Sglebius	fprintf(fp, "fragments sent:         %lu\n",
2613290000Sglebius		(u_long)ntohl(ic->numctlfrags));
2614290000Sglebius	fprintf(fp, "async messages sent:    %lu\n",
2615290000Sglebius		(u_long)ntohl(ic->numasyncmsgs));
2616290000Sglebius	fprintf(fp, "error msgs sent:        %lu\n",
2617290000Sglebius		(u_long)ntohl(ic->numctlerrors));
2618290000Sglebius	fprintf(fp, "total bad pkts:         %lu\n",
2619290000Sglebius		(u_long)ntohl(ic->numctlbadpkts));
2620290000Sglebius	fprintf(fp, "packet too short:       %lu\n",
2621290000Sglebius		(u_long)ntohl(ic->numctltooshort));
2622290000Sglebius	fprintf(fp, "response on input:      %lu\n",
2623290000Sglebius		(u_long)ntohl(ic->numctlinputresp));
2624290000Sglebius	fprintf(fp, "fragment on input:      %lu\n",
2625290000Sglebius		(u_long)ntohl(ic->numctlinputfrag));
2626290000Sglebius	fprintf(fp, "error set on input:     %lu\n",
2627290000Sglebius		(u_long)ntohl(ic->numctlinputerr));
2628290000Sglebius	fprintf(fp, "bad offset on input:    %lu\n",
2629290000Sglebius		(u_long)ntohl(ic->numctlbadoffset));
2630290000Sglebius	fprintf(fp, "bad version packets:    %lu\n",
2631290000Sglebius		(u_long)ntohl(ic->numctlbadversion));
2632290000Sglebius	fprintf(fp, "data in pkt too short:  %lu\n",
2633290000Sglebius		(u_long)ntohl(ic->numctldatatooshort));
2634290000Sglebius	fprintf(fp, "unknown op codes:       %lu\n",
2635290000Sglebius		(u_long)ntohl(ic->numctlbadop));
263654359Sroberto}
263754359Sroberto
263854359Sroberto
263954359Sroberto/*
264054359Sroberto * clockstat - get and print clock status information
264154359Sroberto */
264254359Srobertostatic void
264354359Srobertoclockstat(
264454359Sroberto	struct parse *pcmd,
264554359Sroberto	FILE *fp
264654359Sroberto	)
264754359Sroberto{
264854359Sroberto	struct info_clock *cl;
264954359Sroberto	/* 8 is the maximum number of clocks which will fit in a packet */
265054359Sroberto	u_long clist[min(MAXARGS, 8)];
2651293894Sglebius	size_t qitemlim;
2652293894Sglebius	size_t qitems;
2653293894Sglebius	size_t items;
2654293894Sglebius	size_t itemsize;
265554359Sroberto	int res;
265654359Sroberto	l_fp ts;
265754359Sroberto	struct clktype *clk;
265854359Sroberto
2659290000Sglebius	qitemlim = min(pcmd->nargs, COUNTOF(clist));
2660290000Sglebius	for (qitems = 0; qitems < qitemlim; qitems++)
2661290000Sglebius		clist[qitems] = NSRCADR(&pcmd->argval[qitems].netnum);
266254359Sroberto
2663132451Srobertoagain:
2664132451Sroberto	res = doquery(impl_ver, REQ_GET_CLOCKINFO, 0, qitems,
266554359Sroberto		      sizeof(u_int32), (char *)clist, &items,
2666132451Sroberto		      &itemsize, (void *)&cl, 0, sizeof(struct info_clock));
266754359Sroberto
2668132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2669132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2670132451Sroberto		goto again;
2671132451Sroberto	}
2672132451Sroberto
2673182007Sroberto	if (res != 0)
2674290000Sglebius		return;
267554359Sroberto
267654359Sroberto	if (!checkitems(items, fp))
2677290000Sglebius		return;
267854359Sroberto
267954359Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_clock)))
2680290000Sglebius		return;
268154359Sroberto
268254359Sroberto	while (items-- > 0) {
268354359Sroberto		(void) fprintf(fp, "clock address:        %s\n",
268454359Sroberto			       numtoa(cl->clockadr));
268554359Sroberto		for (clk = clktypes; clk->code >= 0; clk++)
268654359Sroberto		    if (clk->code == cl->type)
268754359Sroberto			break;
268854359Sroberto		if (clk->code >= 0)
268954359Sroberto		    (void) fprintf(fp, "clock type:           %s\n",
269054359Sroberto				   clk->clocktype);
269154359Sroberto		else
269254359Sroberto		    (void) fprintf(fp, "clock type:           unknown type (%d)\n",
269354359Sroberto				   cl->type);
269454359Sroberto		(void) fprintf(fp, "last event:           %d\n",
269554359Sroberto			       cl->lastevent);
269654359Sroberto		(void) fprintf(fp, "current status:       %d\n",
269754359Sroberto			       cl->currentstatus);
269854359Sroberto		(void) fprintf(fp, "number of polls:      %lu\n",
269954359Sroberto			       (u_long)ntohl(cl->polls));
270054359Sroberto		(void) fprintf(fp, "no response to poll:  %lu\n",
270154359Sroberto			       (u_long)ntohl(cl->noresponse));
270254359Sroberto		(void) fprintf(fp, "bad format responses: %lu\n",
270354359Sroberto			       (u_long)ntohl(cl->badformat));
270454359Sroberto		(void) fprintf(fp, "bad data responses:   %lu\n",
270554359Sroberto			       (u_long)ntohl(cl->baddata));
270654359Sroberto		(void) fprintf(fp, "running time:         %lu\n",
270754359Sroberto			       (u_long)ntohl(cl->timestarted));
270854359Sroberto		NTOHL_FP(&cl->fudgetime1, &ts);
270954359Sroberto		(void) fprintf(fp, "fudge time 1:         %s\n",
271054359Sroberto			       lfptoa(&ts, 6));
271154359Sroberto		NTOHL_FP(&cl->fudgetime2, &ts);
271254359Sroberto		(void) fprintf(fp, "fudge time 2:         %s\n",
271354359Sroberto			       lfptoa(&ts, 6));
271454359Sroberto		(void) fprintf(fp, "stratum:              %ld\n",
271554359Sroberto			       (u_long)ntohl(cl->fudgeval1));
271654359Sroberto		(void) fprintf(fp, "reference ID:         %s\n",
2717182007Sroberto			       refid_string(ntohl(cl->fudgeval2), 0));
271854359Sroberto		(void) fprintf(fp, "fudge flags:          0x%x\n",
271954359Sroberto			       cl->flags);
272054359Sroberto
272154359Sroberto		if (items > 0)
272254359Sroberto		    (void) fprintf(fp, "\n");
272354359Sroberto		cl++;
272454359Sroberto	}
272554359Sroberto}
272654359Sroberto
272754359Sroberto
272854359Sroberto/*
272954359Sroberto * fudge - set clock fudge factors
273054359Sroberto */
273154359Srobertostatic void
273254359Srobertofudge(
273354359Sroberto	struct parse *pcmd,
273454359Sroberto	FILE *fp
273554359Sroberto	)
273654359Sroberto{
273754359Sroberto	struct conf_fudge fudgedata;
2738293894Sglebius	size_t items;
2739293894Sglebius	size_t itemsize;
2740293894Sglebius	const char *dummy;
274154359Sroberto	l_fp ts;
274254359Sroberto	int res;
274354359Sroberto	long val;
274454359Sroberto	u_long u_val;
274554359Sroberto	int err;
274654359Sroberto
274754359Sroberto
274854359Sroberto	err = 0;
2749290000Sglebius	ZERO(fudgedata);
2750290000Sglebius	fudgedata.clockadr = NSRCADR(&pcmd->argval[0].netnum);
275154359Sroberto
275254359Sroberto	if (STREQ(pcmd->argval[1].string, "time1")) {
275354359Sroberto		fudgedata.which = htonl(FUDGE_TIME1);
275454359Sroberto		if (!atolfp(pcmd->argval[2].string, &ts))
275554359Sroberto		    err = 1;
275654359Sroberto		else
275754359Sroberto		    NTOHL_FP(&ts, &fudgedata.fudgetime);
275854359Sroberto	} else if (STREQ(pcmd->argval[1].string, "time2")) {
275954359Sroberto		fudgedata.which = htonl(FUDGE_TIME2);
276054359Sroberto		if (!atolfp(pcmd->argval[2].string, &ts))
276154359Sroberto		    err = 1;
276254359Sroberto		else
276354359Sroberto		    NTOHL_FP(&ts, &fudgedata.fudgetime);
276454359Sroberto	} else if (STREQ(pcmd->argval[1].string, "val1")) {
276554359Sroberto		fudgedata.which = htonl(FUDGE_VAL1);
276654359Sroberto		if (!atoint(pcmd->argval[2].string, &val))
276754359Sroberto		    err = 1;
276854359Sroberto		else
276954359Sroberto		    fudgedata.fudgeval_flags = htonl(val);
277054359Sroberto	} else if (STREQ(pcmd->argval[1].string, "val2")) {
277154359Sroberto		fudgedata.which = htonl(FUDGE_VAL2);
277254359Sroberto		if (!atoint(pcmd->argval[2].string, &val))
277354359Sroberto		    err = 1;
277454359Sroberto		else
277554359Sroberto		    fudgedata.fudgeval_flags = htonl((u_int32)val);
277654359Sroberto	} else if (STREQ(pcmd->argval[1].string, "flags")) {
277754359Sroberto		fudgedata.which = htonl(FUDGE_FLAGS);
277854359Sroberto		if (!hextoint(pcmd->argval[2].string, &u_val))
277954359Sroberto		    err = 1;
278054359Sroberto		else
278154359Sroberto		    fudgedata.fudgeval_flags = htonl((u_int32)(u_val & 0xf));
278254359Sroberto	} else {
278354359Sroberto		(void) fprintf(stderr, "What fudge is %s?\n",
278454359Sroberto			       pcmd->argval[1].string);
278554359Sroberto		return;
278654359Sroberto	}
278754359Sroberto
278854359Sroberto	if (err) {
278954359Sroberto		(void) fprintf(stderr, "Unknown fudge parameter %s\n",
279054359Sroberto			       pcmd->argval[2].string);
279154359Sroberto		return;
279254359Sroberto	}
279354359Sroberto
2794132451Srobertoagain:
2795132451Sroberto	res = doquery(impl_ver, REQ_SET_CLKFUDGE, 1, 1,
279654359Sroberto		      sizeof(struct conf_fudge), (char *)&fudgedata, &items,
2797132451Sroberto		      &itemsize, &dummy, 0, sizeof(dummy));
279854359Sroberto
2799132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2800132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2801132451Sroberto		goto again;
2802132451Sroberto	}
2803132451Sroberto
280454359Sroberto	if (res == 0)
280554359Sroberto	    (void) fprintf(fp, "done!\n");
280654359Sroberto	return;
280754359Sroberto}
280854359Sroberto
280954359Sroberto/*
281054359Sroberto * clkbug - get and print clock debugging information
281154359Sroberto */
281254359Srobertostatic void
281354359Srobertoclkbug(
281454359Sroberto	struct parse *pcmd,
281554359Sroberto	FILE *fp
281654359Sroberto	)
281754359Sroberto{
281854359Sroberto	register int i;
281954359Sroberto	register int n;
282054359Sroberto	register u_int32 s;
282154359Sroberto	struct info_clkbug *cl;
282254359Sroberto	/* 8 is the maximum number of clocks which will fit in a packet */
282354359Sroberto	u_long clist[min(MAXARGS, 8)];
282454359Sroberto	u_int32 ltemp;
2825293894Sglebius	size_t qitemlim;
2826293894Sglebius	size_t qitems;
2827293894Sglebius	size_t items;
2828293894Sglebius	size_t itemsize;
282954359Sroberto	int res;
283054359Sroberto	int needsp;
283154359Sroberto	l_fp ts;
283254359Sroberto
2833290000Sglebius	qitemlim = min(pcmd->nargs, COUNTOF(clist));
2834290000Sglebius	for (qitems = 0; qitems < qitemlim; qitems++)
2835290000Sglebius		clist[qitems] = NSRCADR(&pcmd->argval[qitems].netnum);
283654359Sroberto
2837132451Srobertoagain:
2838132451Sroberto	res = doquery(impl_ver, REQ_GET_CLKBUGINFO, 0, qitems,
283954359Sroberto		      sizeof(u_int32), (char *)clist, &items,
2840132451Sroberto		      &itemsize, (void *)&cl, 0, sizeof(struct info_clkbug));
284154359Sroberto
2842132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2843132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2844132451Sroberto		goto again;
2845132451Sroberto	}
2846132451Sroberto
2847182007Sroberto	if (res != 0)
2848290000Sglebius		return;
284954359Sroberto
285054359Sroberto	if (!checkitems(items, fp))
2851290000Sglebius		return;
285254359Sroberto
285354359Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_clkbug)))
2854290000Sglebius		return;
285554359Sroberto
285654359Sroberto	while (items-- > 0) {
285754359Sroberto		(void) fprintf(fp, "clock address:        %s\n",
285854359Sroberto			       numtoa(cl->clockadr));
285954359Sroberto		n = (int)cl->nvalues;
286054359Sroberto		(void) fprintf(fp, "values: %d", n);
286154359Sroberto		s = ntohs(cl->svalues);
286254359Sroberto		if (n > NUMCBUGVALUES)
286354359Sroberto		    n = NUMCBUGVALUES;
286454359Sroberto		for (i = 0; i < n; i++) {
286554359Sroberto			ltemp = ntohl(cl->values[i]);
286654359Sroberto			ltemp &= 0xffffffff;	/* HMS: This does nothing now */
286754359Sroberto			if ((i & 0x3) == 0)
286854359Sroberto			    (void) fprintf(fp, "\n");
286954359Sroberto			if (s & (1 << i))
287054359Sroberto			    (void) fprintf(fp, "%12ld", (u_long)ltemp);
287154359Sroberto			else
287254359Sroberto			    (void) fprintf(fp, "%12lu", (u_long)ltemp);
287354359Sroberto		}
287454359Sroberto		(void) fprintf(fp, "\n");
287554359Sroberto
287654359Sroberto		n = (int)cl->ntimes;
287754359Sroberto		(void) fprintf(fp, "times: %d", n);
287854359Sroberto		s = ntohl(cl->stimes);
287954359Sroberto		if (n > NUMCBUGTIMES)
288054359Sroberto		    n = NUMCBUGTIMES;
288154359Sroberto		needsp = 0;
288254359Sroberto		for (i = 0; i < n; i++) {
288354359Sroberto			if ((i & 0x1) == 0) {
288454359Sroberto			    (void) fprintf(fp, "\n");
288554359Sroberto			} else {
288654359Sroberto				for (;needsp > 0; needsp--)
288754359Sroberto				    putc(' ', fp);
288854359Sroberto			}
288954359Sroberto			NTOHL_FP(&cl->times[i], &ts);
289054359Sroberto			if (s & (1 << i)) {
289154359Sroberto				(void) fprintf(fp, "%17s",
289254359Sroberto					       lfptoa(&ts, 6));
289354359Sroberto				needsp = 22;
289454359Sroberto			} else {
289554359Sroberto				(void) fprintf(fp, "%37s",
289654359Sroberto					       uglydate(&ts));
289754359Sroberto				needsp = 2;
289854359Sroberto			}
289954359Sroberto		}
290054359Sroberto		(void) fprintf(fp, "\n");
290154359Sroberto		if (items > 0) {
290254359Sroberto			cl++;
290354359Sroberto			(void) fprintf(fp, "\n");
290454359Sroberto		}
290554359Sroberto	}
290654359Sroberto}
290754359Sroberto
290854359Sroberto
290954359Sroberto/*
291054359Sroberto * kerninfo - display the kernel pll/pps variables
291154359Sroberto */
291254359Srobertostatic void
291354359Srobertokerninfo(
291454359Sroberto	struct parse *pcmd,
291554359Sroberto	FILE *fp
291654359Sroberto	)
291754359Sroberto{
291854359Sroberto	struct info_kernel *ik;
2919293894Sglebius	size_t items;
2920293894Sglebius	size_t itemsize;
292154359Sroberto	int res;
292254359Sroberto	unsigned status;
292354359Sroberto	double tscale = 1e-6;
292454359Sroberto
2925132451Srobertoagain:
2926132451Sroberto	res = doquery(impl_ver, REQ_GET_KERNEL, 0, 0, 0, (char *)NULL,
2927132451Sroberto		      &items, &itemsize, (void *)&ik, 0,
2928132451Sroberto		      sizeof(struct info_kernel));
2929132451Sroberto
2930132451Sroberto	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2931132451Sroberto		impl_ver = IMPL_XNTPD_OLD;
2932132451Sroberto		goto again;
2933132451Sroberto	}
2934132451Sroberto
2935182007Sroberto	if (res != 0)
293654359Sroberto	    return;
293754359Sroberto	if (!check1item(items, fp))
293854359Sroberto	    return;
293954359Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_kernel)))
294054359Sroberto	    return;
294154359Sroberto
294254359Sroberto	status = ntohs(ik->status) & 0xffff;
294354359Sroberto	/*
294454359Sroberto	 * pll variables. We know more than we should about the NANO bit.
294554359Sroberto	 */
294654359Sroberto#ifdef STA_NANO
294754359Sroberto	if (status & STA_NANO)
294854359Sroberto		tscale = 1e-9;
294954359Sroberto#endif
295054359Sroberto	(void)fprintf(fp, "pll offset:           %g s\n",
2951290000Sglebius	    (int32)ntohl(ik->offset) * tscale);
295254359Sroberto	(void)fprintf(fp, "pll frequency:        %s ppm\n",
295354359Sroberto	    fptoa((s_fp)ntohl(ik->freq), 3));
295454359Sroberto	(void)fprintf(fp, "maximum error:        %g s\n",
2955290000Sglebius	    (u_long)ntohl(ik->maxerror) * tscale);
295654359Sroberto	(void)fprintf(fp, "estimated error:      %g s\n",
2957290000Sglebius	    (u_long)ntohl(ik->esterror) * tscale);
295854359Sroberto	(void)fprintf(fp, "status:               %04x ", status);
295954359Sroberto#ifdef STA_PLL
296054359Sroberto	if (status & STA_PLL) (void)fprintf(fp, " pll");
296154359Sroberto#endif
296254359Sroberto#ifdef STA_PPSFREQ
296354359Sroberto	if (status & STA_PPSFREQ) (void)fprintf(fp, " ppsfreq");
296454359Sroberto#endif
296554359Sroberto#ifdef STA_PPSTIME
296654359Sroberto	if (status & STA_PPSTIME) (void)fprintf(fp, " ppstime");
296754359Sroberto#endif
296854359Sroberto#ifdef STA_FLL
296954359Sroberto	if (status & STA_FLL) (void)fprintf(fp, " fll");
297054359Sroberto#endif
297154359Sroberto#ifdef STA_INS
297254359Sroberto	if (status & STA_INS) (void)fprintf(fp, " ins");
297354359Sroberto#endif
297454359Sroberto#ifdef STA_DEL
297554359Sroberto	if (status & STA_DEL) (void)fprintf(fp, " del");
297654359Sroberto#endif
297754359Sroberto#ifdef STA_UNSYNC
297854359Sroberto	if (status & STA_UNSYNC) (void)fprintf(fp, " unsync");
297954359Sroberto#endif
298054359Sroberto#ifdef STA_FREQHOLD
298154359Sroberto	if (status & STA_FREQHOLD) (void)fprintf(fp, " freqhold");
298254359Sroberto#endif
298354359Sroberto#ifdef STA_PPSSIGNAL
298454359Sroberto	if (status & STA_PPSSIGNAL) (void)fprintf(fp, " ppssignal");
298554359Sroberto#endif
298654359Sroberto#ifdef STA_PPSJITTER
298754359Sroberto	if (status & STA_PPSJITTER) (void)fprintf(fp, " ppsjitter");
298854359Sroberto#endif
298954359Sroberto#ifdef STA_PPSWANDER
299054359Sroberto	if (status & STA_PPSWANDER) (void)fprintf(fp, " ppswander");
299154359Sroberto#endif
299254359Sroberto#ifdef STA_PPSERROR
299354359Sroberto	if (status & STA_PPSERROR) (void)fprintf(fp, " ppserror");
299454359Sroberto#endif
299554359Sroberto#ifdef STA_CLOCKERR
299654359Sroberto	if (status & STA_CLOCKERR) (void)fprintf(fp, " clockerr");
299754359Sroberto#endif
299854359Sroberto#ifdef STA_NANO
299954359Sroberto	if (status & STA_NANO) (void)fprintf(fp, " nano");
300054359Sroberto#endif
300154359Sroberto#ifdef STA_MODE
300254359Sroberto	if (status & STA_MODE) (void)fprintf(fp, " mode=fll");
300354359Sroberto#endif
300454359Sroberto#ifdef STA_CLK
300554359Sroberto	if (status & STA_CLK) (void)fprintf(fp, " src=B");
300654359Sroberto#endif
300754359Sroberto	(void)fprintf(fp, "\n");
300854359Sroberto	(void)fprintf(fp, "pll time constant:    %ld\n",
300954359Sroberto	    (u_long)ntohl(ik->constant));
301054359Sroberto	(void)fprintf(fp, "precision:            %g s\n",
301154359Sroberto	    (u_long)ntohl(ik->precision) * tscale);
301254359Sroberto	(void)fprintf(fp, "frequency tolerance:  %s ppm\n",
301354359Sroberto	    fptoa((s_fp)ntohl(ik->tolerance), 0));
301454359Sroberto
301554359Sroberto	/*
301654359Sroberto	 * For backwards compatibility (ugh), we find the pps variables
301754359Sroberto	 * only if the shift member is nonzero.
301854359Sroberto	 */
301954359Sroberto	if (!ik->shift)
302054359Sroberto	    return;
302154359Sroberto
302254359Sroberto	/*
302354359Sroberto	 * pps variables
302454359Sroberto	 */
302554359Sroberto	(void)fprintf(fp, "pps frequency:        %s ppm\n",
302654359Sroberto	    fptoa((s_fp)ntohl(ik->ppsfreq), 3));
302754359Sroberto	(void)fprintf(fp, "pps stability:        %s ppm\n",
302854359Sroberto	    fptoa((s_fp)ntohl(ik->stabil), 3));
302954359Sroberto	(void)fprintf(fp, "pps jitter:           %g s\n",
303054359Sroberto	    (u_long)ntohl(ik->jitter) * tscale);
303154359Sroberto	(void)fprintf(fp, "calibration interval: %d s\n",
303254359Sroberto		      1 << ntohs(ik->shift));
303354359Sroberto	(void)fprintf(fp, "calibration cycles:   %ld\n",
303454359Sroberto		      (u_long)ntohl(ik->calcnt));
303554359Sroberto	(void)fprintf(fp, "jitter exceeded:      %ld\n",
303654359Sroberto		      (u_long)ntohl(ik->jitcnt));
303754359Sroberto	(void)fprintf(fp, "stability exceeded:   %ld\n",
303854359Sroberto		      (u_long)ntohl(ik->stbcnt));
303954359Sroberto	(void)fprintf(fp, "calibration errors:   %ld\n",
304054359Sroberto		      (u_long)ntohl(ik->errcnt));
304154359Sroberto}
3042182007Sroberto
3043290000Sglebius#define IF_LIST_FMT     "%2d %c %48s %c %c %12.12s %03lx %3lu %2lu %5lu %5lu %5lu %2lu %3lu %7lu\n"
3044290000Sglebius#define IF_LIST_FMT_STR "%2s %c %48s %c %c %12.12s %3s %3s %2s %5s %5s %5s %2s %3s %7s\n"
3045182007Sroberto#define IF_LIST_AFMT_STR "     %48s %c\n"
3046290000Sglebius#define IF_LIST_LABELS  "#", 'A', "Address/Mask/Broadcast", 'T', 'E', "IF name", "Flg", "TL", "#M", "recv", "sent", "drop", "S", "PC", "uptime"
3047290000Sglebius#define IF_LIST_LINE    "==================================================================================================================\n"
3048182007Sroberto
3049182007Srobertostatic void
3050182007Srobertoiflist(
3051182007Sroberto	FILE *fp,
3052182007Sroberto	struct info_if_stats *ifs,
3053293894Sglebius	size_t items,
3054293894Sglebius	size_t itemsize,
3055182007Sroberto	int res
3056182007Sroberto	)
3057182007Sroberto{
3058290000Sglebius	static const char *actions = "?.+-";
3059290000Sglebius	sockaddr_u saddr;
3060182007Sroberto
3061182007Sroberto	if (res != 0)
3062182007Sroberto	    return;
3063182007Sroberto
3064182007Sroberto	if (!checkitems(items, fp))
3065182007Sroberto	    return;
3066182007Sroberto
3067182007Sroberto	if (!checkitemsize(itemsize, sizeof(struct info_if_stats)))
3068182007Sroberto	    return;
3069182007Sroberto
3070182007Sroberto	fprintf(fp, IF_LIST_FMT_STR, IF_LIST_LABELS);
3071182007Sroberto	fprintf(fp, IF_LIST_LINE);
3072182007Sroberto
3073182007Sroberto	while (items > 0) {
3074290000Sglebius		SET_ADDR(saddr, ntohl(ifs->v6_flag),
3075290000Sglebius			 ifs->unaddr.addr.s_addr, ifs->unaddr.addr6);
3076182007Sroberto		fprintf(fp, IF_LIST_FMT,
3077182007Sroberto			ntohl(ifs->ifnum),
3078182007Sroberto			actions[(ifs->action >= 1 && ifs->action < 4) ? ifs->action : 0],
3079182007Sroberto			stoa((&saddr)), 'A',
3080182007Sroberto			ifs->ignore_packets ? 'D' : 'E',
3081182007Sroberto			ifs->name,
3082290000Sglebius			(u_long)ntohl(ifs->flags),
3083290000Sglebius			(u_long)ntohl(ifs->last_ttl),
3084290000Sglebius			(u_long)ntohl(ifs->num_mcast),
3085290000Sglebius			(u_long)ntohl(ifs->received),
3086290000Sglebius			(u_long)ntohl(ifs->sent),
3087290000Sglebius			(u_long)ntohl(ifs->notsent),
3088290000Sglebius			(u_long)ntohl(ifs->scopeid),
3089290000Sglebius			(u_long)ntohl(ifs->peercnt),
3090290000Sglebius			(u_long)ntohl(ifs->uptime));
3091182007Sroberto
3092290000Sglebius		SET_ADDR(saddr, ntohl(ifs->v6_flag),
3093290000Sglebius			 ifs->unmask.addr.s_addr, ifs->unmask.addr6);
3094182007Sroberto		fprintf(fp, IF_LIST_AFMT_STR, stoa(&saddr), 'M');
3095182007Sroberto
3096182007Sroberto		if (!ntohl(ifs->v6_flag) && ntohl(ifs->flags) & (INT_BCASTOPEN)) {
3097290000Sglebius			SET_ADDR(saddr, ntohl(ifs->v6_flag),
3098290000Sglebius				 ifs->unbcast.addr.s_addr, ifs->unbcast.addr6);
3099182007Sroberto			fprintf(fp, IF_LIST_AFMT_STR, stoa(&saddr), 'B');
3100182007Sroberto
3101182007Sroberto		}
3102182007Sroberto
3103182007Sroberto		ifs++;
3104182007Sroberto		items--;
3105182007Sroberto	}
3106182007Sroberto}
3107182007Sroberto
3108182007Sroberto/*ARGSUSED*/
3109182007Srobertostatic void
3110182007Srobertoget_if_stats(
3111182007Sroberto	struct parse *pcmd,
3112182007Sroberto	FILE *fp
3113182007Sroberto	)
3114182007Sroberto{
3115182007Sroberto	struct info_if_stats *ifs;
3116293894Sglebius	size_t items;
3117293894Sglebius	size_t itemsize;
3118182007Sroberto	int res;
3119182007Sroberto
3120182007Sroberto	res = doquery(impl_ver, REQ_IF_STATS, 1, 0, 0, (char *)NULL, &items,
3121182007Sroberto		      &itemsize, (void *)&ifs, 0,
3122182007Sroberto		      sizeof(struct info_if_stats));
3123182007Sroberto	iflist(fp, ifs, items, itemsize, res);
3124182007Sroberto}
3125182007Sroberto
3126182007Sroberto/*ARGSUSED*/
3127182007Srobertostatic void
3128182007Srobertodo_if_reload(
3129182007Sroberto	struct parse *pcmd,
3130182007Sroberto	FILE *fp
3131182007Sroberto	)
3132182007Sroberto{
3133182007Sroberto	struct info_if_stats *ifs;
3134293894Sglebius	size_t items;
3135293894Sglebius	size_t itemsize;
3136182007Sroberto	int res;
3137182007Sroberto
3138182007Sroberto	res = doquery(impl_ver, REQ_IF_RELOAD, 1, 0, 0, (char *)NULL, &items,
3139182007Sroberto		      &itemsize, (void *)&ifs, 0,
3140182007Sroberto		      sizeof(struct info_if_stats));
3141182007Sroberto	iflist(fp, ifs, items, itemsize, res);
3142182007Sroberto}
3143