xref: /freebsd/contrib/ntp/ntpdc/ntpdc_ops.c (revision 9c2daa00c2315f101948c7144d62af5d5fb515cf)
1 /*
2  * ntpdc_ops.c - subroutines which are called to perform operations by xntpdc
3  */
4 
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8 
9 #include <stdio.h>
10 #include <stddef.h>
11 
12 #include "ntpdc.h"
13 #include "ntp_control.h"
14 #include "ntp_refclock.h"
15 #include "ntp_stdlib.h"
16 
17 #include <ctype.h>
18 #ifdef HAVE_SYS_TIMEX_H
19 # include <sys/timex.h>
20 #endif
21 #include <netdb.h>
22 #if !defined(__bsdi__) && !defined(apollo)
23 #include <netinet/in.h>
24 #endif
25 
26 #include <arpa/inet.h>
27 
28 /*
29  * Declarations for command handlers in here
30  */
31 static	int	checkitems	P((int, FILE *));
32 static	int	checkitemsize	P((int, int));
33 static	int	check1item	P((int, FILE *));
34 static	void	peerlist	P((struct parse *, FILE *));
35 static	void	peers		P((struct parse *, FILE *));
36 static void	doconfig	P((struct parse *pcmd, FILE *fp, int mode, int refc));
37 static	void	dmpeers		P((struct parse *, FILE *));
38 static	void	dopeers		P((struct parse *, FILE *, int));
39 static	void	printpeer	P((struct info_peer *, FILE *));
40 static	void	showpeer	P((struct parse *, FILE *));
41 static	void	peerstats	P((struct parse *, FILE *));
42 static	void	loopinfo	P((struct parse *, FILE *));
43 static	void	sysinfo		P((struct parse *, FILE *));
44 static	void	sysstats	P((struct parse *, FILE *));
45 static	void	iostats		P((struct parse *, FILE *));
46 static	void	memstats	P((struct parse *, FILE *));
47 static	void	timerstats	P((struct parse *, FILE *));
48 static	void	addpeer		P((struct parse *, FILE *));
49 static	void	addserver	P((struct parse *, FILE *));
50 static	void	addrefclock	P((struct parse *, FILE *));
51 static	void	broadcast	P((struct parse *, FILE *));
52 static	void	doconfig	P((struct parse *, FILE *, int, int));
53 static	void	unconfig	P((struct parse *, FILE *));
54 static	void	set		P((struct parse *, FILE *));
55 static	void	sys_clear	P((struct parse *, FILE *));
56 static	void	doset		P((struct parse *, FILE *, int));
57 static	void	reslist		P((struct parse *, FILE *));
58 static	void	new_restrict	P((struct parse *, FILE *));
59 static	void	unrestrict	P((struct parse *, FILE *));
60 static	void	delrestrict	P((struct parse *, FILE *));
61 static	void	do_restrict	P((struct parse *, FILE *, int));
62 static	void	monlist		P((struct parse *, FILE *));
63 static	void	reset		P((struct parse *, FILE *));
64 static	void	preset		P((struct parse *, FILE *));
65 static	void	readkeys	P((struct parse *, FILE *));
66 static	void	trustkey	P((struct parse *, FILE *));
67 static	void	untrustkey	P((struct parse *, FILE *));
68 static	void	do_trustkey	P((struct parse *, FILE *, int));
69 static	void	authinfo	P((struct parse *, FILE *));
70 static	void	traps		P((struct parse *, FILE *));
71 static	void	addtrap		P((struct parse *, FILE *));
72 static	void	clrtrap		P((struct parse *, FILE *));
73 static	void	do_addclr_trap	P((struct parse *, FILE *, int));
74 static	void	requestkey	P((struct parse *, FILE *));
75 static	void	controlkey	P((struct parse *, FILE *));
76 static	void	do_changekey	P((struct parse *, FILE *, int));
77 static	void	ctlstats	P((struct parse *, FILE *));
78 static	void	clockstat	P((struct parse *, FILE *));
79 static	void	fudge		P((struct parse *, FILE *));
80 static	void	clkbug		P((struct parse *, FILE *));
81 static	void	kerninfo	P((struct parse *, FILE *));
82 
83 /*
84  * Commands we understand.  Ntpdc imports this.
85  */
86 struct xcmd opcmds[] = {
87 	{ "listpeers",	peerlist,	{ OPT|IP_VERSION, NO, NO, NO },
88 	  { "-4|-6", "", "", "" },
89 	  "display list of peers the server knows about [IP Version]" },
90 	{ "peers",	peers,	{ OPT|IP_VERSION, NO, NO, NO },
91 	  { "-4|-6", "", "", "" },
92 	  "display peer summary information [IP Version]" },
93 	{ "dmpeers",	dmpeers,	{ OPT|IP_VERSION, NO, NO, NO },
94 	  { "-4|-6", "", "", "" },
95 	  "display peer summary info the way Dave Mills likes it (IP Version)" },
96 	{ "showpeer",	showpeer, 	{ ADD, OPT|ADD, OPT|ADD, OPT|ADD},
97 	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
98 	  "display detailed information for one or more peers" },
99 	{ "pstats",	peerstats,	{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
100 	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
101 	  "display statistical information for one or more peers" },
102 	{ "loopinfo",	loopinfo,	{ OPT|NTP_STR, NO, NO, NO },
103 	  { "oneline|multiline", "", "", "" },
104 	  "display loop filter information" },
105 	{ "sysinfo",	sysinfo,	{ NO, NO, NO, NO },
106 	  { "", "", "", "" },
107 	  "display local server information" },
108 	{ "sysstats",	sysstats,	{ NO, NO, NO, NO },
109 	  { "", "", "", "" },
110 	  "display local server statistics" },
111 	{ "memstats",	memstats,	{ NO, NO, NO, NO },
112 	  { "", "", "", "" },
113 	  "display peer memory usage statistics" },
114 	{ "iostats",	iostats,	{ NO, NO, NO, NO },
115 	  { "", "", "", "" },
116 	  "display I/O subsystem statistics" },
117 	{ "timerstats",	timerstats,	{ NO, NO, NO, NO },
118 	  { "", "", "", "" },
119 	  "display event timer subsystem statistics" },
120 	{ "addpeer",	addpeer,	{ ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR },
121 	  { "addr", "keyid", "version", "minpoll|prefer" },
122 	  "configure a new peer association" },
123 	{ "addserver",	addserver,	{ ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR },
124 	  { "addr", "keyid", "version", "minpoll|prefer" },
125 	  "configure a new server" },
126 	{ "addrefclock",addrefclock,	{ ADD, OPT|UINT, OPT|NTP_STR, OPT|NTP_STR },
127 	  { "addr", "mode", "minpoll|prefer", "minpoll|prefer" },
128 	  "configure a new server" },
129 	{ "broadcast",	broadcast,	{ ADD, OPT|UINT, OPT|UINT, OPT|NTP_STR },
130 	  { "addr", "keyid", "version", "minpoll" },
131 	  "configure broadcasting time service" },
132 	{ "unconfig",	unconfig,	{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
133 	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
134 	  "unconfigure existing peer assocations" },
135 	{ "enable",	set,		{ NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
136 	  { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." },
137 	  "set a system flag (auth, bclient, monitor, pll, kernel, stats)" },
138         { "disable",	sys_clear,      { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
139 	  { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." },
140 	  "clear a system flag (auth, bclient, monitor, pll, kernel, stats)" },
141 	{ "reslist",	reslist,	{OPT|IP_VERSION, NO, NO, NO },
142 	  { "-4|-6", "", "", "" },
143 	  "display the server's restrict list" },
144 	{ "restrict",	new_restrict,	{ ADD, ADD, NTP_STR, OPT|NTP_STR },
145 	  { "address", "mask",
146 	    "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer|version|kod",
147 	    "..." },
148 	  "create restrict entry/add flags to entry" },
149 	{ "unrestrict", unrestrict,	{ ADD, ADD, NTP_STR, OPT|NTP_STR },
150 	  { "address", "mask",
151 	    "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer|version|kod",
152 	    "..." },
153 	  "remove flags from a restrict entry" },
154 	{ "delrestrict", delrestrict,	{ ADD, ADD, OPT|NTP_STR, NO },
155 	  { "address", "mask", "ntpport", "" },
156 	  "delete a restrict entry" },
157 	{ "monlist",	monlist,	{ OPT|INT, NO, NO, NO },
158 	  { "version", "", "", "" },
159 	  "display data the server's monitor routines have collected" },
160 	{ "reset",	reset,		{ NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
161 	  { "io|sys|mem|timer|auth|allpeers", "...", "...", "..." },
162 	  "reset various subsystem statistics counters" },
163 	{ "preset",	preset,		{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
164 	  { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
165 	  "reset stat counters associated with particular peer(s)" },
166 	{ "readkeys",	readkeys,	{ NO, NO, NO, NO },
167 	  { "", "", "", "" },
168 	  "request a reread of the keys file and re-init of system keys" },
169 	{ "trustedkey",	trustkey,	{ UINT, OPT|UINT, OPT|UINT, OPT|UINT },
170 	  { "keyid", "keyid", "keyid", "keyid" },
171 	  "add one or more key ID's to the trusted list" },
172 	{ "untrustedkey", untrustkey,	{ UINT, OPT|UINT, OPT|UINT, OPT|UINT },
173 	  { "keyid", "keyid", "keyid", "keyid" },
174 	  "remove one or more key ID's from the trusted list" },
175 	{ "authinfo",	authinfo,	{ NO, NO, NO, NO },
176 	  { "", "", "", "" },
177 	  "display the state of the authentication code" },
178 	{ "traps",	traps,		{ NO, NO, NO, NO },
179 	  { "", "", "", "" },
180 	  "display the traps set in the server" },
181 	{ "addtrap",	addtrap,	{ ADD, OPT|UINT, OPT|ADD, NO },
182 	  { "address", "port", "interface", "" },
183 	  "configure a trap in the server" },
184 	{ "clrtrap",	clrtrap,	{ ADD, OPT|UINT, OPT|ADD, NO },
185 	  { "address", "port", "interface", "" },
186 	  "remove a trap (configured or otherwise) from the server" },
187 	{ "requestkey",	requestkey,	{ UINT, NO, NO, NO },
188 	  { "keyid", "", "", "" },
189 	  "change the keyid the server uses to authenticate requests" },
190 	{ "controlkey",	controlkey,	{ UINT, NO, NO, NO },
191 	  { "keyid", "", "", "" },
192 	  "change the keyid the server uses to authenticate control messages" },
193 	{ "ctlstats",	ctlstats,	{ NO, NO, NO, NO },
194 	  { "", "", "", "" },
195 	  "display packet count statistics from the control module" },
196 	{ "clockstat",	clockstat,	{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
197 	  { "address", "address", "address", "address" },
198 	  "display clock status information" },
199 	{ "fudge",	fudge,		{ ADD, NTP_STR, NTP_STR, NO },
200 	  { "address", "time1|time2|val1|val2|flags", "value", "" },
201 	  "set/change one of a clock's fudge factors" },
202 	{ "clkbug",	clkbug,		{ ADD, OPT|ADD, OPT|ADD, OPT|ADD },
203 	  { "address", "address", "address", "address" },
204 	  "display clock debugging information" },
205 	{ "kerninfo",	kerninfo,	{ NO, NO, NO, NO },
206 	  { "", "", "", "" },
207 	  "display the kernel pll/pps variables" },
208 
209 	{ 0,		0,		{ NO, NO, NO, NO },
210 	  { "", "", "", "" }, "" }
211 };
212 
213 /*
214  * For quick string comparisons
215  */
216 #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
217 
218 
219 /*
220  * checkitems - utility to print a message if no items were returned
221  */
222 static int
223 checkitems(
224 	int items,
225 	FILE *fp
226 	)
227 {
228 	if (items == 0) {
229 		(void) fprintf(fp, "No data returned in response to query\n");
230 		return 0;
231 	}
232 	return 1;
233 }
234 
235 
236 /*
237  * checkitemsize - utility to print a message if the item size is wrong
238  */
239 static int
240 checkitemsize(
241 	int itemsize,
242 	int expected
243 	)
244 {
245 	if (itemsize != expected) {
246 		(void) fprintf(stderr,
247 			       "***Incorrect item size returned by remote host (%d should be %d)\n",
248 			       itemsize, expected);
249 		return 0;
250 	}
251 	return 1;
252 }
253 
254 
255 /*
256  * check1item - check to make sure we have exactly one item
257  */
258 static int
259 check1item(
260 	int items,
261 	FILE *fp
262 	)
263 {
264 	if (items == 0) {
265 		(void) fprintf(fp, "No data returned in response to query\n");
266 		return 0;
267 	}
268 	if (items > 1) {
269 		(void) fprintf(fp, "Expected one item in response, got %d\n",
270 			       items);
271 		return 0;
272 	}
273 	return 1;
274 }
275 
276 
277 
278 /*
279  * peerlist - get a short list of peers
280  */
281 /*ARGSUSED*/
282 static void
283 peerlist(
284 	struct parse *pcmd,
285 	FILE *fp
286 	)
287 {
288 	struct info_peer_list *plist;
289 	struct sockaddr_storage paddr;
290 	int items;
291 	int itemsize;
292 	int res;
293 
294 again:
295 	res = doquery(impl_ver, REQ_PEER_LIST, 0, 0, 0, (char *)NULL, &items,
296 		      &itemsize, (void *)&plist, 0,
297 		      sizeof(struct info_peer_list));
298 
299 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
300 		impl_ver = IMPL_XNTPD_OLD;
301 		goto again;
302 	}
303 
304 	if (res != 0 && items == 0)
305 	    return;
306 
307 	if (!checkitems(items, fp))
308 	    return;
309 
310 	if (!checkitemsize(itemsize, sizeof(struct info_peer_list)) &&
311 	    !checkitemsize(itemsize, v4sizeof(struct info_peer_list)))
312 	    return;
313 
314 	while (items > 0) {
315 		memset((char *)&paddr, 0, sizeof(paddr));
316 		if (plist->v6_flag != 0) {
317 			GET_INADDR6(paddr) = plist->addr6;
318 			paddr.ss_family = AF_INET6;
319 		} else {
320 			GET_INADDR(paddr) = plist->addr;
321 			paddr.ss_family = AF_INET;
322 		}
323 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
324 		paddr.ss_len = SOCKLEN(&paddr);
325 #endif
326 		if ((pcmd->nargs == 0) ||
327 		    ((pcmd->argval->ival == 6) && (plist->v6_flag != 0)) ||
328 		    ((pcmd->argval->ival == 4) && (plist->v6_flag == 0)))
329 			(void) fprintf(fp, "%-9s %s\n",
330 				modetoa(plist->hmode),
331 				nntohost(&paddr));
332 		plist++;
333 		items--;
334 	}
335 }
336 
337 
338 /*
339  * peers - show peer summary
340  */
341 static void
342 peers(
343 	struct parse *pcmd,
344 	FILE *fp
345 	)
346 {
347 	dopeers(pcmd, fp, 0);
348 }
349 
350 /*
351  * dmpeers - show peer summary, Dave Mills style
352  */
353 static void
354 dmpeers(
355 	struct parse *pcmd,
356 	FILE *fp
357 	)
358 {
359 	dopeers(pcmd, fp, 1);
360 }
361 
362 
363 /*
364  * peers - show peer summary
365  */
366 /*ARGSUSED*/
367 static void
368 dopeers(
369 	struct parse *pcmd,
370 	FILE *fp,
371 	int dmstyle
372 	)
373 {
374 	struct info_peer_summary *plist;
375 	struct sockaddr_storage dstadr;
376 	struct sockaddr_storage srcadr;
377 	int items;
378 	int itemsize;
379 	int ntp_poll;
380 	int res;
381 	int c;
382 	l_fp tempts;
383 
384 again:
385 	res = doquery(impl_ver, REQ_PEER_LIST_SUM, 0, 0, 0, (char *)NULL,
386 		      &items, &itemsize, (void *)&plist, 0,
387 		      sizeof(struct info_peer_summary));
388 
389 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
390 		impl_ver = IMPL_XNTPD_OLD;
391 		goto again;
392 	}
393 
394 	if (res != 0 && items == 0)
395 	    return;
396 
397 	if (!checkitems(items, fp))
398 	    return;
399 
400 	if (!checkitemsize(itemsize, sizeof(struct info_peer_summary)) &&
401 	    !checkitemsize(itemsize, v4sizeof(struct info_peer_summary)))
402 		return;
403 
404 	(void) fprintf(fp,
405 		       "     remote           local      st poll reach  delay   offset    disp\n");
406 	(void) fprintf(fp,
407 		       "=======================================================================\n");
408 	while (items > 0) {
409 		if (!dmstyle) {
410 			if (plist->flags & INFO_FLAG_SYSPEER)
411 			    c = '*';
412 			else if (plist->hmode == MODE_ACTIVE)
413 			    c = '+';
414 			else if (plist->hmode == MODE_PASSIVE)
415 			    c = '-';
416 			else if (plist->hmode == MODE_CLIENT)
417 			    c = '=';
418 			else if (plist->hmode == MODE_BROADCAST)
419 			    c = '^';
420 			else if (plist->hmode == MODE_BCLIENT)
421 			    c = '~';
422 			else
423 			    c = ' ';
424 		} else {
425 			if (plist->flags & INFO_FLAG_SYSPEER)
426 			    c = '*';
427 			else if (plist->flags & INFO_FLAG_SHORTLIST)
428 			    c = '+';
429 			else if (plist->flags & INFO_FLAG_SEL_CANDIDATE)
430 			    c = '.';
431 			else
432 			    c = ' ';
433 		}
434 		NTOHL_FP(&(plist->offset), &tempts);
435 		ntp_poll = 1<<max(min3(plist->ppoll, plist->hpoll, NTP_MAXPOLL),
436 				  NTP_MINPOLL);
437 		memset((char *)&dstadr, 0, sizeof(dstadr));
438 		memset((char *)&srcadr, 0, sizeof(srcadr));
439 		if (plist->v6_flag != 0) {
440 			GET_INADDR6(dstadr) = plist->dstadr6;
441 			GET_INADDR6(srcadr) = plist->srcadr6;
442 			srcadr.ss_family = AF_INET6;
443 			dstadr.ss_family = AF_INET6;
444 		} else {
445 			GET_INADDR(dstadr) = plist->dstadr;
446 			GET_INADDR(srcadr) = plist->srcadr;
447 			srcadr.ss_family = AF_INET;
448 			dstadr.ss_family = AF_INET;
449 		}
450 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
451 		srcadr.ss_len = SOCKLEN(&srcadr);
452 		dstadr.ss_len = SOCKLEN(&dstadr);
453 #endif
454 		if ((pcmd->nargs == 0) ||
455 		    ((pcmd->argval->ival == 6) && (plist->v6_flag != 0)) ||
456 		    ((pcmd->argval->ival == 4) && (plist->v6_flag == 0)))
457 			(void) fprintf(fp,
458 			    "%c%-15.15s %-15.15s %2d %4d  %3o %7.7s %9.9s %7.7s\n",
459 			    c, nntohost(&srcadr), stoa(&dstadr),
460 			    plist->stratum, ntp_poll, plist->reach,
461 			    fptoa(NTOHS_FP(plist->delay), 5),
462 			    lfptoa(&tempts, 6),
463 			    ufptoa(NTOHS_FP(plist->dispersion), 5));
464 		plist++;
465 		items--;
466 	}
467 }
468 
469 /* Convert a refid & stratum (in host order) to a string */
470 static char*
471 refid_string(
472 	u_int32 refid,
473 	int stratum
474 	)
475 {
476 	if (stratum <= 1) {
477 		static char junk[5];
478 		junk[4] = 0;
479 		memmove(junk, (char *)&refid, 4);
480 		return junk;
481 	}
482 
483 	return numtoa(refid);
484 }
485 
486 /*
487  * printpeer - print detail information for a peer
488  */
489 static void
490 printpeer(
491 	register struct info_peer *pp,
492 	FILE *fp
493 	)
494 {
495 	register int i;
496 	const char *str;
497 	l_fp tempts;
498 	struct sockaddr_storage srcadr, dstadr;
499 
500 	memset((char *)&srcadr, 0, sizeof(srcadr));
501 	memset((char *)&dstadr, 0, sizeof(dstadr));
502 	if (pp->v6_flag != 0) {
503 		srcadr.ss_family = AF_INET6;
504 		dstadr.ss_family = AF_INET6;
505 		GET_INADDR6(srcadr) = pp->srcadr6;
506 		GET_INADDR6(dstadr) = pp->dstadr6;
507 	} else {
508 		srcadr.ss_family = AF_INET;
509 		dstadr.ss_family = AF_INET;
510 		GET_INADDR(srcadr) = pp->srcadr;
511 		GET_INADDR(dstadr) = pp->dstadr;
512 	}
513 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
514 	srcadr.ss_len = SOCKLEN(&srcadr);
515 	dstadr.ss_len = SOCKLEN(&dstadr);
516 #endif
517 	(void) fprintf(fp, "remote %s, local %s\n",
518 		       stoa(&srcadr), stoa(&dstadr));
519 	(void) fprintf(fp, "hmode %s, pmode %s, stratum %d, precision %d\n",
520 		       modetoa(pp->hmode), modetoa(pp->pmode),
521 		       pp->stratum, pp->precision);
522 
523 	(void) fprintf(fp,
524 		       "leap %c%c, refid [%s], rootdistance %s, rootdispersion %s\n",
525 		       pp->leap & 0x2 ? '1' : '0',
526 		       pp->leap & 0x1 ? '1' : '0',
527 		       refid_string(pp->refid, pp->stratum), fptoa(NTOHS_FP(pp->rootdelay), 5),
528 		       ufptoa(NTOHS_FP(pp->rootdispersion), 5));
529 
530 	(void) fprintf(fp,
531 		       "ppoll %d, hpoll %d, keyid %lu, version %d, association %u\n",
532 		       pp->ppoll, pp->hpoll, (u_long)pp->keyid, pp->version, ntohs(pp->associd));
533 
534 	(void) fprintf(fp,
535 		       "reach %03o, unreach %d, flash 0x%04x, ",
536 		       pp->reach, pp->unreach, pp->flash2);
537 
538 	(void) fprintf(fp, "boffset %s, ttl/mode %d\n",
539 		       fptoa(NTOHS_FP(pp->estbdelay), 5), pp->ttl);
540 
541 	(void) fprintf(fp, "timer %lds, flags", (long)ntohl(pp->timer));
542 	if (pp->flags == 0) {
543 		(void) fprintf(fp, " none\n");
544 	} else {
545 		str = "";
546 		if (pp->flags & INFO_FLAG_SYSPEER) {
547 			(void) fprintf(fp, " system_peer");
548 			str = ",";
549 		}
550 		if (pp->flags & INFO_FLAG_CONFIG) {
551 			(void) fprintf(fp, "%s config", str);
552 			str = ",";
553 		}
554 		if (pp->flags & INFO_FLAG_REFCLOCK) {
555 			(void) fprintf(fp, "%s refclock", str);
556 			str = ",";
557 		}
558 		if (pp->flags & INFO_FLAG_AUTHENABLE) {
559 			(void) fprintf(fp, "%s auth", str);
560 			str = ",";
561 		}
562 		if (pp->flags & INFO_FLAG_BCLIENT) {
563 			(void) fprintf(fp, "%s bclient", str);
564 			str = ",";
565 		}
566 		if (pp->flags & INFO_FLAG_PREFER) {
567 			(void) fprintf(fp, "%s prefer", str);
568 			str = ",";
569 		}
570 		if (pp->flags & INFO_FLAG_BURST) {
571 			(void) fprintf(fp, "%s burst", str);
572 		}
573 		(void) fprintf(fp, "\n");
574 	}
575 
576 	NTOHL_FP(&pp->reftime, &tempts);
577 	(void) fprintf(fp, "reference time:      %s\n",
578 		       prettydate(&tempts));
579 	NTOHL_FP(&pp->org, &tempts);
580 	(void) fprintf(fp, "originate timestamp: %s\n",
581 		       prettydate(&tempts));
582 	NTOHL_FP(&pp->rec, &tempts);
583 	(void) fprintf(fp, "receive timestamp:   %s\n",
584 		       prettydate(&tempts));
585 	NTOHL_FP(&pp->xmt, &tempts);
586 	(void) fprintf(fp, "transmit timestamp:  %s\n",
587 		       prettydate(&tempts));
588 
589 	(void) fprintf(fp, "filter delay: ");
590 	for (i = 0; i < NTP_SHIFT; i++) {
591 		(void) fprintf(fp, " %-8.8s",
592 			       fptoa(NTOHS_FP(pp->filtdelay[i]), 5));
593 		if (i == (NTP_SHIFT>>1)-1)
594 		    (void) fprintf(fp, "\n              ");
595 	}
596 	(void) fprintf(fp, "\n");
597 
598 	(void) fprintf(fp, "filter offset:");
599 	for (i = 0; i < NTP_SHIFT; i++) {
600 		NTOHL_FP(&pp->filtoffset[i], &tempts);
601 		(void) fprintf(fp, " %-8.8s", lfptoa(&tempts, 6));
602 		if (i == (NTP_SHIFT>>1)-1)
603 		    (void) fprintf(fp, "\n              ");
604 	}
605 	(void) fprintf(fp, "\n");
606 
607 	(void) fprintf(fp, "filter order: ");
608 	for (i = 0; i < NTP_SHIFT; i++) {
609 		(void) fprintf(fp, " %-8d", pp->order[i]);
610 		if (i == (NTP_SHIFT>>1)-1)
611 		    (void) fprintf(fp, "\n              ");
612 	}
613 	(void) fprintf(fp, "\n");
614 
615 
616 	NTOHL_FP(&pp->offset, &tempts);
617 	(void) fprintf(fp,
618 		       "offset %s, delay %s, error bound %s, filter error %s\n",
619 		       lfptoa(&tempts, 6), fptoa(NTOHS_FP(pp->delay), 5),
620 		       ufptoa(NTOHS_FP(pp->dispersion), 5),
621 		       ufptoa(NTOHS_FP(pp->selectdisp), 5));
622 }
623 
624 
625 /*
626  * showpeer - show detailed information for a peer
627  */
628 static void
629 showpeer(
630 	struct parse *pcmd,
631 	FILE *fp
632 	)
633 {
634 	struct info_peer *pp;
635 	/* 4 is the maximum number of peers which will fit in a packet */
636 	struct info_peer_list *pl, plist[min(MAXARGS, 4)];
637 	int qitems;
638 	int items;
639 	int itemsize;
640 	int res;
641 	int sendsize;
642 
643 again:
644 	if (impl_ver == IMPL_XNTPD)
645 		sendsize = sizeof(struct info_peer_list);
646 	else
647 		sendsize = v4sizeof(struct info_peer_list);
648 
649 	for (qitems = 0, pl = plist; qitems < min(pcmd->nargs, 4); qitems++) {
650 		if (pcmd->argval[qitems].netnum.ss_family == AF_INET) {
651 			pl->addr = GET_INADDR(pcmd->argval[qitems].netnum);
652 			if (impl_ver == IMPL_XNTPD)
653 				pl->v6_flag = 0;
654 		} else {
655 			if (impl_ver == IMPL_XNTPD_OLD) {
656 				fprintf(stderr,
657 				    "***Server doesn't understand IPv6 addresses\n");
658 				return;
659 			}
660 			pl->addr6 = GET_INADDR6(pcmd->argval[qitems].netnum);
661 			pl->v6_flag = 1;
662 		}
663 		pl->port = (u_short)s_port;
664 		pl->hmode = pl->flags = 0;
665 		pl = (struct info_peer_list *)((char *)pl + sendsize);
666 	}
667 
668 	res = doquery(impl_ver, REQ_PEER_INFO, 0, qitems,
669 		      sendsize, (char *)plist, &items,
670 		      &itemsize, (void *)&pp, 0, sizeof(struct info_peer));
671 
672 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
673 		impl_ver = IMPL_XNTPD_OLD;
674 		goto again;
675 	}
676 
677 	if (res != 0 && items == 0)
678 	    return;
679 
680 	if (!checkitems(items, fp))
681 	    return;
682 
683 	if (!checkitemsize(itemsize, sizeof(struct info_peer)) &&
684 	    !checkitemsize(itemsize, v4sizeof(struct info_peer)))
685 	    return;
686 
687 	while (items-- > 0) {
688 		printpeer(pp, fp);
689 		if (items > 0)
690 		    (void) fprintf(fp, "\n");
691 		pp++;
692 	}
693 }
694 
695 
696 /*
697  * peerstats - return statistics for a peer
698  */
699 static void
700 peerstats(
701 	struct parse *pcmd,
702 	FILE *fp
703 	)
704 {
705 	struct info_peer_stats *pp;
706 	/* 4 is the maximum number of peers which will fit in a packet */
707 	struct info_peer_list *pl, plist[min(MAXARGS, 4)];
708 	struct sockaddr_storage src, dst;
709 	int qitems;
710 	int items;
711 	int itemsize;
712 	int res;
713 	int sendsize;
714 
715 again:
716 	if (impl_ver == IMPL_XNTPD)
717 		sendsize = sizeof(struct info_peer_list);
718 	else
719 		sendsize = v4sizeof(struct info_peer_list);
720 
721 	memset((char *)plist, 0, sizeof(struct info_peer_list) * min(MAXARGS, 4));
722 	for (qitems = 0, pl = plist; qitems < min(pcmd->nargs, 4); qitems++) {
723 		if (pcmd->argval[qitems].netnum.ss_family == AF_INET) {
724 			pl->addr = GET_INADDR(pcmd->argval[qitems].netnum);
725 			if (impl_ver == IMPL_XNTPD)
726 				pl->v6_flag = 0;
727 		} else {
728 			if (impl_ver == IMPL_XNTPD_OLD) {
729 				fprintf(stderr,
730 				    "***Server doesn't understand IPv6 addresses\n");
731 				return;
732 			}
733 			pl->addr6 = GET_INADDR6(pcmd->argval[qitems].netnum);
734 			pl->v6_flag = 1;
735 		}
736 		pl->port = (u_short)s_port;
737 		pl->hmode = plist[qitems].flags = 0;
738 		pl = (struct info_peer_list *)((char *)pl + sendsize);
739 	}
740 
741 	res = doquery(impl_ver, REQ_PEER_STATS, 0, qitems,
742 		      sendsize, (char *)plist, &items,
743 		      &itemsize, (void *)&pp, 0,
744 		      sizeof(struct info_peer_stats));
745 
746 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
747 		impl_ver = IMPL_XNTPD_OLD;
748 		goto again;
749 	}
750 
751 	if (res != 0 && items == 0)
752 	    return;
753 
754 	if (!checkitems(items, fp))
755 	    return;
756 
757 	if (!checkitemsize(itemsize, sizeof(struct info_peer_stats)) &&
758 	    !checkitemsize(itemsize, v4sizeof(struct info_peer_stats)))
759 	    return;
760 
761 	while (items-- > 0) {
762 		memset((char *)&src, 0, sizeof(src));
763 		memset((char *)&dst, 0, sizeof(dst));
764 		if (pp->v6_flag != 0) {
765 			GET_INADDR6(src) = pp->srcadr6;
766 			GET_INADDR6(dst) = pp->dstadr6;
767 			src.ss_family = AF_INET6;
768 			dst.ss_family = AF_INET6;
769 		} else {
770 			GET_INADDR(src) = pp->srcadr;
771 			GET_INADDR(dst) = pp->dstadr;
772 			src.ss_family = AF_INET;
773 			dst.ss_family = AF_INET;
774 		}
775 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
776 		src.ss_len = SOCKLEN(&src);
777 		dst.ss_len = SOCKLEN(&dst);
778 #endif
779 		(void) fprintf(fp, "remote host:          %s\n",
780 			       nntohost(&src));
781 		(void) fprintf(fp, "local interface:      %s\n",
782 			       stoa(&dst));
783 		(void) fprintf(fp, "time last received:   %lds\n",
784 			       (long)ntohl(pp->timereceived));
785 		(void) fprintf(fp, "time until next send: %lds\n",
786 			       (long)ntohl(pp->timetosend));
787 		(void) fprintf(fp, "reachability change:  %lds\n",
788 			       (long)ntohl(pp->timereachable));
789 		(void) fprintf(fp, "packets sent:         %ld\n",
790 			       (long)ntohl(pp->sent));
791 		(void) fprintf(fp, "packets received:     %ld\n",
792 			       (long)ntohl(pp->processed));
793 		(void) fprintf(fp, "bad authentication:   %ld\n",
794 			       (long)ntohl(pp->badauth));
795 		(void) fprintf(fp, "bogus origin:         %ld\n",
796 			       (long)ntohl(pp->bogusorg));
797 		(void) fprintf(fp, "duplicate:            %ld\n",
798 			       (long)ntohl(pp->oldpkt));
799 		(void) fprintf(fp, "bad dispersion:       %ld\n",
800 			       (long)ntohl(pp->seldisp));
801 		(void) fprintf(fp, "bad reference time:   %ld\n",
802 			       (long)ntohl(pp->selbroken));
803 		(void) fprintf(fp, "candidate order:      %d\n",
804 			       (int)pp->candidate);
805 		if (items > 0)
806 		    (void) fprintf(fp, "\n");
807 		pp++;
808 	}
809 }
810 
811 
812 /*
813  * loopinfo - show loop filter information
814  */
815 static void
816 loopinfo(
817 	struct parse *pcmd,
818 	FILE *fp
819 	)
820 {
821 	struct info_loop *il;
822 	int items;
823 	int itemsize;
824 	int oneline = 0;
825 	int res;
826 	l_fp tempts;
827 
828 	if (pcmd->nargs > 0) {
829 		if (STREQ(pcmd->argval[0].string, "oneline"))
830 		    oneline = 1;
831 		else if (STREQ(pcmd->argval[0].string, "multiline"))
832 		    oneline = 0;
833 		else {
834 			(void) fprintf(stderr, "How many lines?\n");
835 			return;
836 		}
837 	}
838 
839 again:
840 	res = doquery(impl_ver, REQ_LOOP_INFO, 0, 0, 0, (char *)NULL,
841 		      &items, &itemsize, (void *)&il, 0,
842 		      sizeof(struct info_loop));
843 
844 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
845 		impl_ver = IMPL_XNTPD_OLD;
846 		goto again;
847 	}
848 
849 	if (res != 0 && items == 0)
850 	    return;
851 
852 	if (!check1item(items, fp))
853 	    return;
854 
855 	if (!checkitemsize(itemsize, sizeof(struct info_loop)))
856 	    return;
857 
858 	if (oneline) {
859 		l_fp temp2ts;
860 
861 		NTOHL_FP(&il->last_offset, &tempts);
862 		NTOHL_FP(&il->drift_comp, &temp2ts);
863 
864 		(void) fprintf(fp,
865 			       "offset %s, frequency %s, time_const %ld, watchdog %ld\n",
866 			       lfptoa(&tempts, 6),
867 			       lfptoa(&temp2ts, 3),
868 			       (u_long)ntohl(il->compliance),
869 			       (u_long)ntohl(il->watchdog_timer));
870 	} else {
871 		NTOHL_FP(&il->last_offset, &tempts);
872 		(void) fprintf(fp, "offset:               %s s\n",
873 			       lfptoa(&tempts, 6));
874 		NTOHL_FP(&il->drift_comp, &tempts);
875 		(void) fprintf(fp, "frequency:            %s ppm\n",
876 			       lfptoa(&tempts, 3));
877 		(void) fprintf(fp, "poll adjust:          %ld\n",
878 			       (u_long)ntohl(il->compliance));
879 		(void) fprintf(fp, "watchdog timer:       %ld s\n",
880 			       (u_long)ntohl(il->watchdog_timer));
881 	}
882 }
883 
884 
885 /*
886  * sysinfo - show current system state
887  */
888 /*ARGSUSED*/
889 static void
890 sysinfo(
891 	struct parse *pcmd,
892 	FILE *fp
893 	)
894 {
895 	struct info_sys *is;
896 	struct sockaddr_storage peeraddr;
897 	int items;
898 	int itemsize;
899 	int res;
900 	l_fp tempts;
901 
902 again:
903 	res = doquery(impl_ver, REQ_SYS_INFO, 0, 0, 0, (char *)NULL,
904 		      &items, &itemsize, (void *)&is, 0,
905 		      sizeof(struct info_sys));
906 
907 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
908 		impl_ver = IMPL_XNTPD_OLD;
909 		goto again;
910 	}
911 
912 	if (res != 0 && items == 0)
913 	    return;
914 
915 	if (!check1item(items, fp))
916 	    return;
917 
918 	if (!checkitemsize(itemsize, sizeof(struct info_sys)) &&
919 	    !checkitemsize(itemsize, v4sizeof(struct info_sys)))
920 	    return;
921 
922 	memset((char *)&peeraddr, 0, sizeof(peeraddr));
923 	if (is->v6_flag != 0) {
924 		GET_INADDR6(peeraddr) = is->peer6;
925 		peeraddr.ss_family = AF_INET6;
926 	} else {
927 		GET_INADDR(peeraddr) = is->peer;
928 		peeraddr.ss_family = AF_INET;
929 	}
930 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
931 	peeraddr.ss_len = SOCKLEN(&peeraddr);
932 #endif
933 	(void) fprintf(fp, "system peer:          %s\n", nntohost(&peeraddr));
934 	(void) fprintf(fp, "system peer mode:     %s\n", modetoa(is->peer_mode));
935 	(void) fprintf(fp, "leap indicator:       %c%c\n",
936 		       is->leap & 0x2 ? '1' : '0',
937 		       is->leap & 0x1 ? '1' : '0');
938 	(void) fprintf(fp, "stratum:              %d\n", (int)is->stratum);
939 	(void) fprintf(fp, "precision:            %d\n", (int)is->precision);
940 	(void) fprintf(fp, "root distance:        %s s\n",
941 		       fptoa(NTOHS_FP(is->rootdelay), 5));
942 	(void) fprintf(fp, "root dispersion:      %s s\n",
943 		       ufptoa(NTOHS_FP(is->rootdispersion), 5));
944 	(void) fprintf(fp, "reference ID:         [%s]\n",
945 		       refid_string(is->refid, is->stratum));
946 	NTOHL_FP(&is->reftime, &tempts);
947 	(void) fprintf(fp, "reference time:       %s\n", prettydate(&tempts));
948 
949 	(void) fprintf(fp, "system flags:         ");
950 	if ((is->flags & (INFO_FLAG_BCLIENT | INFO_FLAG_AUTHENABLE |
951 	    INFO_FLAG_NTP | INFO_FLAG_KERNEL| INFO_FLAG_CAL |
952 	    INFO_FLAG_PPS_SYNC | INFO_FLAG_MONITOR | INFO_FLAG_FILEGEN)) == 0) {
953 		(void) fprintf(fp, "none\n");
954 	} else {
955 		if (is->flags & INFO_FLAG_BCLIENT)
956 		    (void) fprintf(fp, "bclient ");
957 		if (is->flags & INFO_FLAG_AUTHENTICATE)
958 		    (void) fprintf(fp, "auth ");
959 		if (is->flags & INFO_FLAG_MONITOR)
960 		    (void) fprintf(fp, "monitor ");
961 		if (is->flags & INFO_FLAG_NTP)
962 		    (void) fprintf(fp, "ntp ");
963 		if (is->flags & INFO_FLAG_KERNEL)
964 		    (void) fprintf(fp, "kernel ");
965 		if (is->flags & INFO_FLAG_FILEGEN)
966 		    (void) fprintf(fp, "stats ");
967 		if (is->flags & INFO_FLAG_CAL)
968 		    (void) fprintf(fp, "calibrate ");
969 		if (is->flags & INFO_FLAG_PPS_SYNC)
970 		    (void) fprintf(fp, "pps ");
971 		(void) fprintf(fp, "\n");
972 	}
973 	(void) fprintf(fp, "jitter:               %s s\n",
974 		       fptoa(ntohl(is->frequency), 6));
975 	(void) fprintf(fp, "stability:            %s ppm\n",
976 		       ufptoa(ntohl(is->stability), 3));
977 	(void) fprintf(fp, "broadcastdelay:       %s s\n",
978 		       fptoa(NTOHS_FP(is->bdelay), 6));
979 	NTOHL_FP(&is->authdelay, &tempts);
980 	(void) fprintf(fp, "authdelay:            %s s\n", lfptoa(&tempts, 6));
981 }
982 
983 
984 /*
985  * sysstats - print system statistics
986  */
987 /*ARGSUSED*/
988 static void
989 sysstats(
990 	struct parse *pcmd,
991 	FILE *fp
992 	)
993 {
994 	struct info_sys_stats *ss;
995 	int items;
996 	int itemsize;
997 	int res;
998 
999 again:
1000 	res = doquery(impl_ver, REQ_SYS_STATS, 0, 0, 0, (char *)NULL,
1001 		      &items, &itemsize, (void *)&ss, 0,
1002 		      sizeof(struct info_sys_stats));
1003 
1004 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1005 		impl_ver = IMPL_XNTPD_OLD;
1006 		goto again;
1007 	}
1008 
1009 	if (res != 0 && items == 0)
1010 	    return;
1011 
1012 	if (!check1item(items, fp))
1013 	    return;
1014 
1015 	if (itemsize != sizeof(struct info_sys_stats) &&
1016 	    itemsize != sizeof(struct old_info_sys_stats)) {
1017 		/* issue warning according to new structure size */
1018 		checkitemsize(itemsize, sizeof(struct info_sys_stats));
1019 		return;
1020 	}
1021 	fprintf(fp, "time since restart:     %ld\n",
1022 	       (u_long)ntohl(ss->timeup));
1023 	fprintf(fp, "time since reset:       %ld\n",
1024 		(u_long)ntohl(ss->timereset));
1025         fprintf(fp, "packets received:       %ld\n",
1026 		(u_long)ntohl(ss->received));
1027 	fprintf(fp, "packets processed:      %ld\n",
1028 		(u_long)ntohl(ss->processed));
1029 	fprintf(fp, "current version:        %ld\n",
1030 	       (u_long)ntohl(ss->newversionpkt));
1031 	fprintf(fp, "previous version:       %ld\n",
1032 	       (u_long)ntohl(ss->oldversionpkt));
1033 	fprintf(fp, "bad version:            %ld\n",
1034 	       (u_long)ntohl(ss->unknownversion));
1035 	fprintf(fp, "access denied:          %ld\n",
1036 		(u_long)ntohl(ss->denied));
1037 	fprintf(fp, "bad length or format:   %ld\n",
1038 	       (u_long)ntohl(ss->badlength));
1039 	fprintf(fp, "bad authentication:     %ld\n",
1040 	       (u_long)ntohl(ss->badauth));
1041 	if (itemsize != sizeof(struct info_sys_stats))
1042 	    return;
1043 
1044 	fprintf(fp, "rate exceeded:          %ld\n",
1045 	       (u_long)ntohl(ss->limitrejected));
1046 }
1047 
1048 
1049 
1050 /*
1051  * iostats - print I/O statistics
1052  */
1053 /*ARGSUSED*/
1054 static void
1055 iostats(
1056 	struct parse *pcmd,
1057 	FILE *fp
1058 	)
1059 {
1060 	struct info_io_stats *io;
1061 	int items;
1062 	int itemsize;
1063 	int res;
1064 
1065 again:
1066 	res = doquery(impl_ver, REQ_IO_STATS, 0, 0, 0, (char *)NULL,
1067 		      &items, &itemsize, (void *)&io, 0,
1068 		      sizeof(struct info_io_stats));
1069 
1070 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1071 		impl_ver = IMPL_XNTPD_OLD;
1072 		goto again;
1073 	}
1074 
1075 	if (res != 0 && items == 0)
1076 	    return;
1077 
1078 	if (!check1item(items, fp))
1079 	    return;
1080 
1081 	if (!checkitemsize(itemsize, sizeof(struct info_io_stats)))
1082 	    return;
1083 
1084 	(void) fprintf(fp, "time since reset:     %ld\n",
1085 		       (u_long)ntohl(io->timereset));
1086 	(void) fprintf(fp, "receive buffers:      %d\n",
1087 		       ntohs(io->totalrecvbufs));
1088 	(void) fprintf(fp, "free receive buffers: %d\n",
1089 		       ntohs(io->freerecvbufs));
1090 	(void) fprintf(fp, "used receive buffers: %d\n",
1091 		       ntohs(io->fullrecvbufs));
1092 	(void) fprintf(fp, "low water refills:    %d\n",
1093 		       ntohs(io->lowwater));
1094 	(void) fprintf(fp, "dropped packets:      %ld\n",
1095 		       (u_long)ntohl(io->dropped));
1096 	(void) fprintf(fp, "ignored packets:      %ld\n",
1097 		       (u_long)ntohl(io->ignored));
1098 	(void) fprintf(fp, "received packets:     %ld\n",
1099 		       (u_long)ntohl(io->received));
1100 	(void) fprintf(fp, "packets sent:         %ld\n",
1101 		       (u_long)ntohl(io->sent));
1102 	(void) fprintf(fp, "packets not sent:     %ld\n",
1103 		       (u_long)ntohl(io->notsent));
1104 	(void) fprintf(fp, "interrupts handled:   %ld\n",
1105 		       (u_long)ntohl(io->interrupts));
1106 	(void) fprintf(fp, "received by int:      %ld\n",
1107 		       (u_long)ntohl(io->int_received));
1108 }
1109 
1110 
1111 /*
1112  * memstats - print peer memory statistics
1113  */
1114 /*ARGSUSED*/
1115 static void
1116 memstats(
1117 	struct parse *pcmd,
1118 	FILE *fp
1119 	)
1120 {
1121 	struct info_mem_stats *mem;
1122 	int i;
1123 	int items;
1124 	int itemsize;
1125 	int res;
1126 
1127 again:
1128 	res = doquery(impl_ver, REQ_MEM_STATS, 0, 0, 0, (char *)NULL,
1129 		      &items, &itemsize, (void *)&mem, 0,
1130 		      sizeof(struct info_mem_stats));
1131 
1132 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1133 		impl_ver = IMPL_XNTPD_OLD;
1134 		goto again;
1135 	}
1136 
1137 	if (res != 0 && items == 0)
1138 	    return;
1139 
1140 	if (!check1item(items, fp))
1141 	    return;
1142 
1143 	if (!checkitemsize(itemsize, sizeof(struct info_mem_stats)))
1144 	    return;
1145 
1146 	(void) fprintf(fp, "time since reset:     %ld\n",
1147 		       (u_long)ntohl(mem->timereset));
1148 	(void) fprintf(fp, "total peer memory:    %d\n",
1149 		       ntohs(mem->totalpeermem));
1150 	(void) fprintf(fp, "free peer memory:     %d\n",
1151 		       ntohs(mem->freepeermem));
1152 	(void) fprintf(fp, "calls to findpeer:    %ld\n",
1153 		       (u_long)ntohl(mem->findpeer_calls));
1154 	(void) fprintf(fp, "new peer allocations: %ld\n",
1155 		       (u_long)ntohl(mem->allocations));
1156 	(void) fprintf(fp, "peer demobilizations: %ld\n",
1157 		       (u_long)ntohl(mem->demobilizations));
1158 
1159 	(void) fprintf(fp, "hash table counts:   ");
1160 	for (i = 0; i < HASH_SIZE; i++) {
1161 		(void) fprintf(fp, "%4d", (int)mem->hashcount[i]);
1162 		if ((i % 8) == 7 && i != (HASH_SIZE-1)) {
1163 			(void) fprintf(fp, "\n                     ");
1164 		}
1165 	}
1166 	(void) fprintf(fp, "\n");
1167 }
1168 
1169 
1170 
1171 /*
1172  * timerstats - print timer statistics
1173  */
1174 /*ARGSUSED*/
1175 static void
1176 timerstats(
1177 	struct parse *pcmd,
1178 	FILE *fp
1179 	)
1180 {
1181 	struct info_timer_stats *tim;
1182 	int items;
1183 	int itemsize;
1184 	int res;
1185 
1186 again:
1187 	res = doquery(impl_ver, REQ_TIMER_STATS, 0, 0, 0, (char *)NULL,
1188 		      &items, &itemsize, (void *)&tim, 0,
1189 		      sizeof(struct info_timer_stats));
1190 
1191 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1192 		impl_ver = IMPL_XNTPD_OLD;
1193 		goto again;
1194 	}
1195 
1196 	if (res != 0 && items == 0)
1197 	    return;
1198 
1199 	if (!check1item(items, fp))
1200 	    return;
1201 
1202 	if (!checkitemsize(itemsize, sizeof(struct info_timer_stats)))
1203 	    return;
1204 
1205 	(void) fprintf(fp, "time since reset:  %ld\n",
1206 		       (u_long)ntohl(tim->timereset));
1207 	(void) fprintf(fp, "alarms handled:    %ld\n",
1208 		       (u_long)ntohl(tim->alarms));
1209 	(void) fprintf(fp, "alarm overruns:    %ld\n",
1210 		       (u_long)ntohl(tim->overflows));
1211 	(void) fprintf(fp, "calls to transmit: %ld\n",
1212 		       (u_long)ntohl(tim->xmtcalls));
1213 }
1214 
1215 
1216 /*
1217  * addpeer - configure an active mode association
1218  */
1219 static void
1220 addpeer(
1221 	struct parse *pcmd,
1222 	FILE *fp
1223 	)
1224 {
1225 	doconfig(pcmd, fp, MODE_ACTIVE, 0);
1226 }
1227 
1228 
1229 /*
1230  * addserver - configure a client mode association
1231  */
1232 static void
1233 addserver(
1234 	struct parse *pcmd,
1235 	FILE *fp
1236 	)
1237 {
1238 	doconfig(pcmd, fp, MODE_CLIENT, 0);
1239 }
1240 
1241 /*
1242  * addrefclock - configure a reference clock association
1243  */
1244 static void
1245 addrefclock(
1246 	struct parse *pcmd,
1247 	FILE *fp
1248 	)
1249 {
1250 	doconfig(pcmd, fp, MODE_CLIENT, 1);
1251 }
1252 
1253 /*
1254  * broadcast - configure a broadcast mode association
1255  */
1256 static void
1257 broadcast(
1258 	struct parse *pcmd,
1259 	FILE *fp
1260 	)
1261 {
1262 	doconfig(pcmd, fp, MODE_BROADCAST, 0);
1263 }
1264 
1265 
1266 /*
1267  * config - configure a new peer association
1268  */
1269 static void
1270 doconfig(
1271 	struct parse *pcmd,
1272 	FILE *fp,
1273 	int mode,
1274         int refc
1275 	)
1276 {
1277 	struct conf_peer cpeer;
1278 	int items;
1279 	int itemsize;
1280 	char *dummy;
1281 	u_long keyid;
1282 	u_int version;
1283 	u_char minpoll;
1284 	u_int flags;
1285 	u_char cmode;
1286 	int res;
1287 	int sendsize;
1288 
1289 again:
1290 	keyid = 0;
1291 	version = NTP_OLDVERSION + 1;
1292 	flags = 0;
1293 	res = 0;
1294 	cmode = 0;
1295 	minpoll = NTP_MINDPOLL;
1296 
1297 	if (impl_ver == IMPL_XNTPD)
1298 		sendsize = sizeof(struct conf_peer);
1299 	else
1300 		sendsize = v4sizeof(struct conf_peer);
1301 
1302 	items = pcmd->nargs;
1303 
1304 	if (refc) {
1305 		if (pcmd->nargs > 1) {
1306 			cmode = (u_char) pcmd->argval[1].uval;
1307 			items = 2;
1308 		}
1309 	} else {
1310 		if (pcmd->nargs > 1) {
1311 			keyid = pcmd->argval[1].uval;
1312 			if (keyid > 0) {
1313 				flags |= CONF_FLAG_AUTHENABLE;
1314 			}
1315 			if (pcmd->nargs > 2) {
1316 				version = (u_int)pcmd->argval[2].uval;
1317 				if (version > NTP_VERSION ||
1318 				    version < NTP_OLDVERSION) {
1319 					(void)fprintf(fp,
1320 					"invalid version number %u\n",
1321 					    version);
1322 					res++;
1323 				}
1324 				items = 3;
1325 			}
1326 		}
1327 	}
1328 
1329 	while (pcmd->nargs > items) {
1330 		if (STREQ(pcmd->argval[items].string, "prefer"))
1331 		    flags |= CONF_FLAG_PREFER;
1332 		else if (STREQ(pcmd->argval[items].string, "burst"))
1333 		    flags |= CONF_FLAG_BURST;
1334 		else {
1335 		        long val;
1336 			if (!atoint(pcmd->argval[items].string, &val)) {
1337 				(void) fprintf(fp,
1338 				    "%s not understood\n",
1339 				    pcmd->argval[items].string);
1340 				res++;
1341 				break;
1342 			} else {
1343 				if (val >= NTP_MINPOLL && val <= NTP_MAXPOLL) {
1344 					minpoll = (u_char)val;
1345 				} else {
1346 					(void) fprintf(fp,
1347 						       "minpol must be within %d..%d\n",
1348 						       NTP_MINPOLL, NTP_MAXPOLL);
1349 					res++;
1350 					break;
1351 				}
1352 			}
1353 		}
1354 		items++;
1355 	}
1356 
1357 	if (res)
1358 	    return;
1359 
1360 	memset((void *)&cpeer, 0, sizeof(cpeer));
1361 
1362 	if (pcmd->argval[0].netnum.ss_family == AF_INET) {
1363 		cpeer.peeraddr = GET_INADDR(pcmd->argval[0].netnum);
1364 		if (impl_ver == IMPL_XNTPD)
1365 			cpeer.v6_flag = 0;
1366 	} else {
1367 		if (impl_ver == IMPL_XNTPD_OLD) {
1368 			fprintf(stderr,
1369 			    "***Server doesn't understand IPv6 addresses\n");
1370 			return;
1371 		}
1372 		cpeer.peeraddr6 = GET_INADDR6(pcmd->argval[0].netnum);
1373 		cpeer.v6_flag = 1;
1374 	}
1375 	cpeer.hmode = (u_char) mode;
1376 	cpeer.keyid = keyid;
1377 	cpeer.version = (u_char) version;
1378 	cpeer.minpoll = minpoll;
1379 	cpeer.maxpoll = NTP_MAXDPOLL;
1380 	cpeer.flags = (u_char)flags;
1381 	cpeer.ttl = cmode;
1382 
1383 	res = doquery(impl_ver, REQ_CONFIG, 1, 1,
1384 		      sendsize, (char *)&cpeer, &items,
1385 		      &itemsize, &dummy, 0, sizeof(struct conf_peer));
1386 
1387 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1388 		impl_ver = IMPL_XNTPD_OLD;
1389 		goto again;
1390 	}
1391 
1392 	if (res == INFO_ERR_FMT) {
1393 		(void) fprintf(fp,
1394 		    "***Retrying command with old conf_peer size\n");
1395 		res = doquery(impl_ver, REQ_CONFIG, 1, 1,
1396 			      sizeof(struct old_conf_peer), (char *)&cpeer,
1397 			      &items, &itemsize, &dummy, 0,
1398 			      sizeof(struct conf_peer));
1399 	}
1400 	if (res == 0)
1401 	    (void) fprintf(fp, "done!\n");
1402 	return;
1403 }
1404 
1405 
1406 /*
1407  * unconfig - unconfigure some associations
1408  */
1409 static void
1410 unconfig(
1411 	struct parse *pcmd,
1412 	FILE *fp
1413 	)
1414 {
1415 	/* 8 is the maximum number of peers which will fit in a packet */
1416 	struct conf_unpeer *pl, plist[min(MAXARGS, 8)];
1417 	int qitems;
1418 	int items;
1419 	int itemsize;
1420 	char *dummy;
1421 	int res;
1422 	int sendsize;
1423 
1424 again:
1425 	if (impl_ver == IMPL_XNTPD)
1426 		sendsize = sizeof(struct conf_unpeer);
1427 	else
1428 		sendsize = v4sizeof(struct conf_unpeer);
1429 
1430 	for (qitems = 0, pl = plist; qitems < min(pcmd->nargs, 8); qitems++) {
1431 		if (pcmd->argval[0].netnum.ss_family == AF_INET) {
1432 			pl->peeraddr = GET_INADDR(pcmd->argval[qitems].netnum);
1433 			if (impl_ver == IMPL_XNTPD)
1434 				pl->v6_flag = 0;
1435 		} else {
1436 			if (impl_ver == IMPL_XNTPD_OLD) {
1437 				fprintf(stderr,
1438 				    "***Server doesn't understand IPv6 addresses\n");
1439 				return;
1440 			}
1441 			pl->peeraddr6 =
1442 			    GET_INADDR6(pcmd->argval[qitems].netnum);
1443 			pl->v6_flag = 1;
1444 		}
1445 		pl = (struct conf_unpeer *)((char *)pl + sendsize);
1446 	}
1447 
1448 	res = doquery(impl_ver, REQ_UNCONFIG, 1, qitems,
1449 		      sendsize, (char *)plist, &items,
1450 		      &itemsize, &dummy, 0, sizeof(struct conf_unpeer));
1451 
1452 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1453 		impl_ver = IMPL_XNTPD_OLD;
1454 		goto again;
1455 	}
1456 
1457 	if (res == 0)
1458 	    (void) fprintf(fp, "done!\n");
1459 }
1460 
1461 
1462 /*
1463  * set - set some system flags
1464  */
1465 static void
1466 set(
1467 	struct parse *pcmd,
1468 	FILE *fp
1469 	)
1470 {
1471 	doset(pcmd, fp, REQ_SET_SYS_FLAG);
1472 }
1473 
1474 
1475 /*
1476  * clear - clear some system flags
1477  */
1478 static void
1479 sys_clear(
1480 	struct parse *pcmd,
1481 	FILE *fp
1482 	)
1483 {
1484 	doset(pcmd, fp, REQ_CLR_SYS_FLAG);
1485 }
1486 
1487 
1488 /*
1489  * doset - set/clear system flags
1490  */
1491 static void
1492 doset(
1493 	struct parse *pcmd,
1494 	FILE *fp,
1495 	int req
1496 	)
1497 {
1498 	/* 8 is the maximum number of peers which will fit in a packet */
1499 	struct conf_sys_flags sys;
1500 	int items;
1501 	int itemsize;
1502 	char *dummy;
1503 	int res;
1504 
1505 	sys.flags = 0;
1506 	res = 0;
1507 	for (items = 0; items < pcmd->nargs; items++) {
1508 		if (STREQ(pcmd->argval[items].string, "auth"))
1509 			sys.flags |= SYS_FLAG_AUTH;
1510 		else if (STREQ(pcmd->argval[items].string, "bclient"))
1511 			sys.flags |= SYS_FLAG_BCLIENT;
1512 		else if (STREQ(pcmd->argval[items].string, "calibrate"))
1513 			sys.flags |= SYS_FLAG_CAL;
1514 		else if (STREQ(pcmd->argval[items].string, "kernel"))
1515 			sys.flags |= SYS_FLAG_KERNEL;
1516 		else if (STREQ(pcmd->argval[items].string, "monitor"))
1517 			sys.flags |= SYS_FLAG_MONITOR;
1518 		else if (STREQ(pcmd->argval[items].string, "ntp"))
1519 			sys.flags |= SYS_FLAG_NTP;
1520 		else if (STREQ(pcmd->argval[items].string, "pps"))
1521 			sys.flags |= SYS_FLAG_PPS;
1522 		else if (STREQ(pcmd->argval[items].string, "stats"))
1523 			sys.flags |= SYS_FLAG_FILEGEN;
1524 		else {
1525 			(void) fprintf(fp, "Unknown flag %s\n",
1526 			    pcmd->argval[items].string);
1527 			res = 1;
1528 		}
1529 	}
1530 
1531 	if (res || sys.flags == 0)
1532 	    return;
1533 
1534 again:
1535 	res = doquery(impl_ver, req, 1, 1,
1536 		      sizeof(struct conf_sys_flags), (char *)&sys, &items,
1537 		      &itemsize, &dummy, 0, sizeof(struct conf_sys_flags));
1538 
1539 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1540 		impl_ver = IMPL_XNTPD_OLD;
1541 		goto again;
1542 	}
1543 
1544 	if (res == 0)
1545 	    (void) fprintf(fp, "done!\n");
1546 }
1547 
1548 
1549 /*
1550  * data for printing/interrpreting the restrict flags
1551  */
1552 struct resflags {
1553   const char *str;
1554 	int bit;
1555 };
1556 
1557 static struct resflags resflags[] = {
1558 	{ "ignore",	RES_IGNORE },
1559 	{ "noserve",	RES_DONTSERVE },
1560 	{ "notrust",	RES_DONTTRUST },
1561 	{ "noquery",	RES_NOQUERY },
1562 	{ "nomodify",	RES_NOMODIFY },
1563 	{ "nopeer",	RES_NOPEER },
1564 	{ "notrap",	RES_NOTRAP },
1565 	{ "lptrap",	RES_LPTRAP },
1566 	{ "limited",	RES_LIMITED },
1567 	{ "version",	RES_VERSION },
1568 	{ "kod",	RES_DEMOBILIZE },
1569 	{ "timeout",	RES_TIMEOUT },
1570 
1571 	{ "",		0 }
1572 };
1573 
1574 static struct resflags resmflags[] = {
1575 	{ "ntpport",	RESM_NTPONLY },
1576 	{ "interface",	RESM_INTERFACE },
1577 	{ "",		0 }
1578 };
1579 
1580 
1581 /*
1582  * reslist - obtain and print the server's restrict list
1583  */
1584 /*ARGSUSED*/
1585 static void
1586 reslist(
1587 	struct parse *pcmd,
1588 	FILE *fp
1589 	)
1590 {
1591 	struct info_restrict *rl;
1592 	struct sockaddr_storage resaddr;
1593 	struct sockaddr_storage maskaddr;
1594 	int items;
1595 	int itemsize;
1596 	int res;
1597 	int skip;
1598 	char *addr;
1599 	char *mask;
1600 	struct resflags *rf;
1601 	u_int32 count;
1602 	u_short flags;
1603 	u_short mflags;
1604 	char flagstr[300];
1605 	static const char *comma = ", ";
1606 
1607 again:
1608 	res = doquery(impl_ver, REQ_GET_RESTRICT, 0, 0, 0, (char *)NULL,
1609 		      &items, &itemsize, (void *)&rl, 0,
1610 		      sizeof(struct info_restrict));
1611 
1612 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1613 		impl_ver = IMPL_XNTPD_OLD;
1614 		goto again;
1615 	}
1616 
1617 	if (res != 0 && items == 0)
1618 	    return;
1619 
1620 	if (!checkitems(items, fp))
1621 	    return;
1622 
1623 	if (!checkitemsize(itemsize, sizeof(struct info_restrict)) &&
1624 	    !checkitemsize(itemsize, v4sizeof(struct info_restrict)))
1625 	    return;
1626 
1627 	(void) fprintf(fp,
1628 	       "   address          mask            count        flags\n");
1629 	(void) fprintf(fp,
1630 		       "=====================================================================\n");
1631 
1632 	while (items > 0) {
1633 		memset((char *)&resaddr, 0, sizeof(resaddr));
1634 		memset((char *)&maskaddr, 0, sizeof(maskaddr));
1635 		if (rl->v6_flag != 0) {
1636 			GET_INADDR6(resaddr) = rl->addr6;
1637 			GET_INADDR6(maskaddr) = rl->mask6;
1638 			resaddr.ss_family = AF_INET6;
1639 			maskaddr.ss_family = AF_INET6;
1640 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1641 			resaddr.ss_len = SOCKLEN(&resaddr);
1642 #endif
1643 			addr = nntohost(&resaddr);
1644 		} else {
1645 			GET_INADDR(resaddr) = rl->addr;
1646 			GET_INADDR(maskaddr) = rl->mask;
1647 			resaddr.ss_family = AF_INET;
1648 			maskaddr.ss_family = AF_INET;
1649 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1650 			resaddr.ss_len = SOCKLEN(&resaddr);
1651 #endif
1652 			if ((rl->mask == (u_int32)0xffffffff))
1653 		    		addr = nntohost(&resaddr);
1654 			else
1655 				addr = stoa(&resaddr);
1656 		}
1657 		mask = stoa(&maskaddr);
1658 		skip = 1;
1659 		if ((pcmd->nargs == 0) ||
1660 		    ((pcmd->argval->ival == 6) && (rl->v6_flag != 0)) ||
1661 		    ((pcmd->argval->ival == 4) && (rl->v6_flag == 0)))
1662 			skip = 0;
1663 		count = ntohl(rl->count);
1664 		flags = ntohs(rl->flags);
1665 		mflags = ntohs(rl->mflags);
1666 		flagstr[0] = '\0';
1667 
1668 		res = 1;
1669 		rf = &resmflags[0];
1670 		while (rf->bit != 0) {
1671 			if (mflags & rf->bit) {
1672 				if (!res)
1673 				    (void) strcat(flagstr, comma);
1674 				res = 0;
1675 				(void) strcat(flagstr, rf->str);
1676 			}
1677 			rf++;
1678 		}
1679 
1680 		rf = &resflags[0];
1681 		while (rf->bit != 0) {
1682 			if (flags & rf->bit) {
1683 				if (!res)
1684 				    (void) strcat(flagstr, comma);
1685 				res = 0;
1686 				(void) strcat(flagstr, rf->str);
1687 			}
1688 			rf++;
1689 		}
1690 
1691 		if (flagstr[0] == '\0')
1692 		    (void) strcpy(flagstr, "none");
1693 
1694 		if (!skip)
1695 			(void) fprintf(fp, "%-15.15s %-15.15s %9ld  %s\n",
1696 					addr, mask, (u_long)count, flagstr);
1697 		rl++;
1698 		items--;
1699 	}
1700 }
1701 
1702 
1703 
1704 /*
1705  * new_restrict - create/add a set of restrictions
1706  */
1707 static void
1708 new_restrict(
1709 	struct parse *pcmd,
1710 	FILE *fp
1711 	)
1712 {
1713 	do_restrict(pcmd, fp, REQ_RESADDFLAGS);
1714 }
1715 
1716 
1717 /*
1718  * unrestrict - remove restriction flags from existing entry
1719  */
1720 static void
1721 unrestrict(
1722 	struct parse *pcmd,
1723 	FILE *fp
1724 	)
1725 {
1726 	do_restrict(pcmd, fp, REQ_RESSUBFLAGS);
1727 }
1728 
1729 
1730 /*
1731  * delrestrict - delete an existing restriction
1732  */
1733 static void
1734 delrestrict(
1735 	struct parse *pcmd,
1736 	FILE *fp
1737 	)
1738 {
1739 	do_restrict(pcmd, fp, REQ_UNRESTRICT);
1740 }
1741 
1742 
1743 /*
1744  * do_restrict - decode commandline restrictions and make the request
1745  */
1746 static void
1747 do_restrict(
1748 	struct parse *pcmd,
1749 	FILE *fp,
1750 	int req_code
1751 	)
1752 {
1753 	struct conf_restrict cres;
1754 	int items;
1755 	int itemsize;
1756 	char *dummy;
1757 	u_int32 num;
1758 	u_long bit;
1759 	int i;
1760 	int res;
1761 	int err;
1762 	int sendsize;
1763 
1764 	/* Initialize cres */
1765 	cres.addr = 0;
1766 	cres.mask = 0;
1767 	cres.flags = 0;
1768 	cres.mflags = 0;
1769 	cres.v6_flag = 0;
1770 
1771 again:
1772 	if (impl_ver == IMPL_XNTPD)
1773 		sendsize = sizeof(struct conf_restrict);
1774 	else
1775 		sendsize = v4sizeof(struct conf_restrict);
1776 
1777 	if (pcmd->argval[0].netnum.ss_family == AF_INET) {
1778 		cres.addr = GET_INADDR(pcmd->argval[0].netnum);
1779 		cres.mask = GET_INADDR(pcmd->argval[1].netnum);
1780 		if (impl_ver == IMPL_XNTPD)
1781 			cres.v6_flag = 0;
1782 	} else {
1783 		if (impl_ver == IMPL_XNTPD_OLD) {
1784 			fprintf(stderr,
1785 			    "***Server doesn't understand IPv6 addresses\n");
1786 			return;
1787 		}
1788 		cres.addr6 = GET_INADDR6(pcmd->argval[0].netnum);
1789 		cres.v6_flag = 1;
1790 	}
1791 	cres.flags = 0;
1792 	cres.mflags = 0;
1793 	err = 0;
1794 	for (res = 2; res < pcmd->nargs; res++) {
1795 		if (STREQ(pcmd->argval[res].string, "ntpport")) {
1796 			cres.mflags |= RESM_NTPONLY;
1797 		} else {
1798 			for (i = 0; resflags[i].bit != 0; i++) {
1799 				if (STREQ(pcmd->argval[res].string,
1800 					  resflags[i].str))
1801 				    break;
1802 			}
1803 			if (resflags[i].bit != 0) {
1804 				cres.flags |= resflags[i].bit;
1805 				if (req_code == REQ_UNRESTRICT) {
1806 					(void) fprintf(fp,
1807 						       "Flag %s inappropriate\n",
1808 						       resflags[i].str);
1809 					err++;
1810 				}
1811 			} else {
1812 				(void) fprintf(fp, "Unknown flag %s\n",
1813 					       pcmd->argval[res].string);
1814 				err++;
1815 			}
1816 		}
1817 	}
1818 
1819 	/*
1820 	 * Make sure mask for default address is zero.  Otherwise,
1821 	 * make sure mask bits are contiguous.
1822 	 */
1823 	if (pcmd->argval[0].netnum.ss_family == AF_INET) {
1824 		if (cres.addr == 0) {
1825 			cres.mask = 0;
1826 		} else {
1827 			num = ntohl(cres.mask);
1828 			for (bit = 0x80000000; bit != 0; bit >>= 1)
1829 			    if ((num & bit) == 0)
1830 				break;
1831 			for ( ; bit != 0; bit >>= 1)
1832 			    if ((num & bit) != 0)
1833 				break;
1834 			if (bit != 0) {
1835 				(void) fprintf(fp, "Invalid mask %s\n",
1836 					       numtoa(cres.mask));
1837 				err++;
1838 			}
1839 		}
1840 	} else {
1841 		/* XXX IPv6 sanity checking stuff */
1842 	}
1843 
1844 	if (err)
1845 	    return;
1846 
1847 	res = doquery(impl_ver, req_code, 1, 1,
1848 		      sendsize, (char *)&cres, &items,
1849 		      &itemsize, &dummy, 0, sizeof(struct conf_restrict));
1850 
1851 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1852 		impl_ver = IMPL_XNTPD_OLD;
1853 		goto again;
1854 	}
1855 
1856 	if (res == 0)
1857 	    (void) fprintf(fp, "done!\n");
1858 	return;
1859 }
1860 
1861 
1862 /*
1863  * monlist - obtain and print the server's monitor data
1864  */
1865 /*ARGSUSED*/
1866 static void
1867 monlist(
1868 	struct parse *pcmd,
1869 	FILE *fp
1870 	)
1871 {
1872 	char *struct_star;
1873 	struct sockaddr_storage addr;
1874 	struct sockaddr_storage dstadr;
1875 	int items;
1876 	int itemsize;
1877 	int res;
1878 	int version = -1;
1879 
1880 	if (pcmd->nargs > 0) {
1881 		version = pcmd->argval[0].ival;
1882 	}
1883 
1884 again:
1885 	res = doquery(impl_ver,
1886 		      (version == 1 || version == -1) ? REQ_MON_GETLIST_1 :
1887 		      REQ_MON_GETLIST, 0, 0, 0, (char *)NULL,
1888 		      &items, &itemsize, &struct_star,
1889 		      (version < 0) ? (1 << INFO_ERR_REQ) : 0,
1890 		      sizeof(struct info_monitor_1));
1891 
1892 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1893 		impl_ver = IMPL_XNTPD_OLD;
1894 		goto again;
1895 	}
1896 
1897 	if (res == INFO_ERR_REQ && version < 0)
1898 	    res = doquery(impl_ver, REQ_MON_GETLIST, 0, 0, 0, (char *)NULL,
1899 			  &items, &itemsize, &struct_star, 0,
1900 			  sizeof(struct info_monitor));
1901 
1902 	if (res != 0 && items == 0)
1903 	    return;
1904 
1905 	if (!checkitems(items, fp))
1906 	    return;
1907 
1908 	if (itemsize == sizeof(struct info_monitor_1) ||
1909 	    itemsize == v4sizeof(struct info_monitor_1)) {
1910 		struct info_monitor_1 *ml = (struct info_monitor_1 *) struct_star;
1911 
1912 		(void) fprintf(fp,
1913 			       "remote address          port local address      count m ver code avgint  lstint\n");
1914 		(void) fprintf(fp,
1915 			       "===============================================================================\n");
1916 		while (items > 0) {
1917 			memset((char *)&addr, 0, sizeof(addr));
1918 			memset((char *)&dstadr, 0, sizeof(dstadr));
1919 			if (ml->v6_flag != 0) {
1920 				GET_INADDR6(addr) = ml->addr6;
1921 				addr.ss_family = AF_INET6;
1922 				GET_INADDR6(dstadr) = ml->daddr6;
1923 				dstadr.ss_family = AF_INET6;
1924 			} else {
1925 				GET_INADDR(addr) = ml->addr;
1926 				addr.ss_family = AF_INET;
1927 				GET_INADDR(dstadr) = ml->daddr;
1928 				dstadr.ss_family = AF_INET;
1929 			}
1930 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1931 			addr.ss_len = SOCKLEN(&addr);
1932 			dstadr.ss_len = SOCKLEN(&dstadr);
1933 #endif
1934 			if ((pcmd->nargs == 0) ||
1935 			    ((pcmd->argval->ival == 6) && (ml->v6_flag != 0)) ||
1936 			    ((pcmd->argval->ival == 4) && (ml->v6_flag == 0)))
1937 				(void) fprintf(fp,
1938 				    "%-22.22s %5d %-15s %8ld %1d %1d %6lx %6lu %7lu\n",
1939 				    nntohost(&addr),
1940 				    ntohs(ml->port),
1941 				    stoa(&dstadr),
1942 				    (u_long)ntohl(ml->count),
1943 				    ml->mode,
1944 				    ml->version,
1945 				    (u_long)ntohl(ml->lastdrop),
1946 				    (u_long)ntohl(ml->lasttime),
1947 				    (u_long)ntohl(ml->firsttime));
1948 			ml++;
1949 			items--;
1950 		}
1951 	} else if (itemsize == sizeof(struct info_monitor) ||
1952 	    itemsize == v4sizeof(struct info_monitor)) {
1953 		struct info_monitor *ml = (struct info_monitor *) struct_star;
1954 
1955 		(void) fprintf(fp,
1956 			       "     address               port     count mode ver code avgint  lstint\n");
1957 		(void) fprintf(fp,
1958 			       "===============================================================================\n");
1959 		while (items > 0) {
1960 			memset((char *)&dstadr, 0, sizeof(dstadr));
1961 			if (ml->v6_flag != 0) {
1962 				GET_INADDR6(dstadr) = ml->addr6;
1963 				dstadr.ss_family = AF_INET6;
1964 			} else {
1965 				GET_INADDR(dstadr) = ml->addr;
1966 				dstadr.ss_family = AF_INET;
1967 			}
1968 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
1969 			dstadr.ss_len = SOCKLEN(&dstadr);
1970 #endif
1971 			if ((pcmd->nargs == 0) ||
1972 			    ((pcmd->argval->ival == 6) && (ml->v6_flag != 0)) ||
1973 			    ((pcmd->argval->ival == 4) && (ml->v6_flag == 0)))
1974 				(void) fprintf(fp,
1975 				    "%-25.25s %5d %9ld %4d %2d %9lx %9lu %9lu\n",
1976 				    nntohost(&dstadr),
1977 				    ntohs(ml->port),
1978 				    (u_long)ntohl(ml->count),
1979 				    ml->mode,
1980 				    ml->version,
1981 				    (u_long)ntohl(ml->lastdrop),
1982 				    (u_long)ntohl(ml->lasttime),
1983 				    (u_long)ntohl(ml->firsttime));
1984 			ml++;
1985 			items--;
1986 		}
1987 	} else if (itemsize == sizeof(struct old_info_monitor)) {
1988 		struct old_info_monitor *oml = (struct old_info_monitor *)struct_star;
1989 		(void) fprintf(fp,
1990 			       "     address          port     count  mode version  lasttime firsttime\n");
1991 		(void) fprintf(fp,
1992 			       "======================================================================\n");
1993 		while (items > 0) {
1994 			memset((char *)&dstadr, 0, sizeof(dstadr));
1995 			if (oml->v6_flag != 0) {
1996 				GET_INADDR6(dstadr) = oml->addr6;
1997 				dstadr.ss_family = AF_INET6;
1998 			} else {
1999 				GET_INADDR(dstadr) = oml->addr;
2000 				dstadr.ss_family = AF_INET;
2001 			}
2002 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
2003 			dstadr.ss_len = SOCKLEN(&dstadr);
2004 #endif
2005 			(void) fprintf(fp, "%-20.20s %5d %9ld %4d   %3d %9lu %9lu\n",
2006 				       nntohost(&dstadr),
2007 				       ntohs(oml->port),
2008 				       (u_long)ntohl(oml->count),
2009 				       oml->mode,
2010 				       oml->version,
2011 				       (u_long)ntohl(oml->lasttime),
2012 				       (u_long)ntohl(oml->firsttime));
2013 			oml++;
2014 			items--;
2015 		}
2016 	} else {
2017 		/* issue warning according to new info_monitor size */
2018 		checkitemsize(itemsize, sizeof(struct info_monitor));
2019 	}
2020 }
2021 
2022 
2023 /*
2024  * Mapping between command line strings and stat reset flags
2025  */
2026 struct statreset {
2027   const char *str;
2028 	int flag;
2029 } sreset[] = {
2030 	{ "io",		RESET_FLAG_IO },
2031 	{ "sys",	RESET_FLAG_SYS },
2032 	{ "mem",	RESET_FLAG_MEM },
2033 	{ "timer",	RESET_FLAG_TIMER },
2034 	{ "auth",	RESET_FLAG_AUTH },
2035 	{ "allpeers",	RESET_FLAG_ALLPEERS },
2036 	{ "",		0 }
2037 };
2038 
2039 /*
2040  * reset - reset statistic counters
2041  */
2042 static void
2043 reset(
2044 	struct parse *pcmd,
2045 	FILE *fp
2046 	)
2047 {
2048 	struct reset_flags rflags;
2049 	int items;
2050 	int itemsize;
2051 	char *dummy;
2052 	int i;
2053 	int res;
2054 	int err;
2055 
2056 	err = 0;
2057 	rflags.flags = 0;
2058 	for (res = 0; res < pcmd->nargs; res++) {
2059 		for (i = 0; sreset[i].flag != 0; i++) {
2060 			if (STREQ(pcmd->argval[res].string, sreset[i].str))
2061 			    break;
2062 		}
2063 		if (sreset[i].flag == 0) {
2064 			(void) fprintf(fp, "Flag %s unknown\n",
2065 				       pcmd->argval[res].string);
2066 			err++;
2067 		} else {
2068 			rflags.flags |= sreset[i].flag;
2069 		}
2070 	}
2071 
2072 	if (err) {
2073 		(void) fprintf(fp, "Not done due to errors\n");
2074 		return;
2075 	}
2076 
2077 again:
2078 	res = doquery(impl_ver, REQ_RESET_STATS, 1, 1,
2079 		      sizeof(struct reset_flags), (char *)&rflags, &items,
2080 		      &itemsize, &dummy, 0, sizeof(struct reset_flags));
2081 
2082 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2083 		impl_ver = IMPL_XNTPD_OLD;
2084 		goto again;
2085 	}
2086 
2087 	if (res == 0)
2088 	    (void) fprintf(fp, "done!\n");
2089 	return;
2090 }
2091 
2092 
2093 
2094 /*
2095  * preset - reset stat counters for particular peers
2096  */
2097 static void
2098 preset(
2099 	struct parse *pcmd,
2100 	FILE *fp
2101 	)
2102 {
2103 	/* 8 is the maximum number of peers which will fit in a packet */
2104 	struct conf_unpeer *pl, plist[min(MAXARGS, 8)];
2105 	int qitems;
2106 	int items;
2107 	int itemsize;
2108 	char *dummy;
2109 	int res;
2110 	int sendsize;
2111 
2112 again:
2113 	if (impl_ver == IMPL_XNTPD)
2114 		sendsize = sizeof(struct conf_unpeer);
2115 	else
2116 		sendsize = v4sizeof(struct conf_unpeer);
2117 
2118 	for (qitems = 0, pl = plist; qitems < min(pcmd->nargs, 8); qitems++) {
2119 		if (pcmd->argval[qitems].netnum.ss_family == AF_INET) {
2120 			pl->peeraddr = GET_INADDR(pcmd->argval[qitems].netnum);
2121 			if (impl_ver == IMPL_XNTPD)
2122 				pl->v6_flag = 0;
2123 		} else {
2124 			if (impl_ver == IMPL_XNTPD_OLD) {
2125 				fprintf(stderr,
2126 				    "***Server doesn't understand IPv6 addresses\n");
2127 				return;
2128 			}
2129 			pl->peeraddr6 =
2130 			    GET_INADDR6(pcmd->argval[qitems].netnum);
2131 			pl->v6_flag = 1;
2132 		}
2133 		pl = (struct conf_unpeer *)((char *)pl + sendsize);
2134 	}
2135 
2136 	res = doquery(impl_ver, REQ_RESET_PEER, 1, qitems,
2137 		      sendsize, (char *)plist, &items,
2138 		      &itemsize, &dummy, 0, sizeof(struct conf_unpeer));
2139 
2140 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2141 		impl_ver = IMPL_XNTPD_OLD;
2142 		goto again;
2143 	}
2144 
2145 	if (res == 0)
2146 	    (void) fprintf(fp, "done!\n");
2147 }
2148 
2149 
2150 /*
2151  * readkeys - request the server to reread the keys file
2152  */
2153 /*ARGSUSED*/
2154 static void
2155 readkeys(
2156 	struct parse *pcmd,
2157 	FILE *fp
2158 	)
2159 {
2160 	int items;
2161 	int itemsize;
2162 	char *dummy;
2163 	int res;
2164 
2165 again:
2166 	res = doquery(impl_ver, REQ_REREAD_KEYS, 1, 0, 0, (char *)0,
2167 		      &items, &itemsize, &dummy, 0, sizeof(dummy));
2168 
2169 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2170 		impl_ver = IMPL_XNTPD_OLD;
2171 		goto again;
2172 	}
2173 
2174 	if (res == 0)
2175 	    (void) fprintf(fp, "done!\n");
2176 	return;
2177 }
2178 
2179 
2180 /*
2181  * trustkey - add some keys to the trusted key list
2182  */
2183 static void
2184 trustkey(
2185 	struct parse *pcmd,
2186 	FILE *fp
2187 	)
2188 {
2189 	do_trustkey(pcmd, fp, REQ_TRUSTKEY);
2190 }
2191 
2192 
2193 /*
2194  * untrustkey - remove some keys from the trusted key list
2195  */
2196 static void
2197 untrustkey(
2198 	struct parse *pcmd,
2199 	FILE *fp
2200 	)
2201 {
2202 	do_trustkey(pcmd, fp, REQ_UNTRUSTKEY);
2203 }
2204 
2205 
2206 /*
2207  * do_trustkey - do grunge work of adding/deleting keys
2208  */
2209 static void
2210 do_trustkey(
2211 	struct parse *pcmd,
2212 	FILE *fp,
2213 	int req
2214 	)
2215 {
2216 	u_long keyids[MAXARGS];
2217 	int i;
2218 	int items;
2219 	int itemsize;
2220 	char *dummy;
2221 	int ritems;
2222 	int res;
2223 
2224 	ritems = 0;
2225 	for (i = 0; i < pcmd->nargs; i++) {
2226 		keyids[ritems++] = pcmd->argval[i].uval;
2227 	}
2228 
2229 again:
2230 	res = doquery(impl_ver, req, 1, ritems, sizeof(u_long),
2231 		      (char *)keyids, &items, &itemsize, &dummy, 0,
2232 		      sizeof(dummy));
2233 
2234 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2235 		impl_ver = IMPL_XNTPD_OLD;
2236 		goto again;
2237 	}
2238 
2239 	if (res == 0)
2240 	    (void) fprintf(fp, "done!\n");
2241 	return;
2242 }
2243 
2244 
2245 
2246 /*
2247  * authinfo - obtain and print info about authentication
2248  */
2249 /*ARGSUSED*/
2250 static void
2251 authinfo(
2252 	struct parse *pcmd,
2253 	FILE *fp
2254 	)
2255 {
2256 	struct info_auth *ia;
2257 	int items;
2258 	int itemsize;
2259 	int res;
2260 
2261 again:
2262 	res = doquery(impl_ver, REQ_AUTHINFO, 0, 0, 0, (char *)NULL,
2263 		      &items, &itemsize, (void *)&ia, 0,
2264 		      sizeof(struct info_auth));
2265 
2266 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2267 		impl_ver = IMPL_XNTPD_OLD;
2268 		goto again;
2269 	}
2270 
2271 	if (res != 0 && items == 0)
2272 	    return;
2273 
2274 	if (!check1item(items, fp))
2275 	    return;
2276 
2277 	if (!checkitemsize(itemsize, sizeof(struct info_auth)))
2278 	    return;
2279 
2280 	(void) fprintf(fp, "time since reset:     %ld\n",
2281 	    (u_long)ntohl(ia->timereset));
2282 	(void) fprintf(fp, "stored keys:          %ld\n",
2283 	    (u_long)ntohl(ia->numkeys));
2284 	(void) fprintf(fp, "free keys:            %ld\n",
2285 	    (u_long)ntohl(ia->numfreekeys));
2286 	(void) fprintf(fp, "key lookups:          %ld\n",
2287 	    (u_long)ntohl(ia->keylookups));
2288 	(void) fprintf(fp, "keys not found:       %ld\n",
2289 	    (u_long)ntohl(ia->keynotfound));
2290 	(void) fprintf(fp, "uncached keys:        %ld\n",
2291 	    (u_long)ntohl(ia->keyuncached));
2292 	(void) fprintf(fp, "encryptions:          %ld\n",
2293 	    (u_long)ntohl(ia->encryptions));
2294 	(void) fprintf(fp, "decryptions:          %ld\n",
2295 	    (u_long)ntohl(ia->decryptions));
2296 	(void) fprintf(fp, "expired keys:         %ld\n",
2297 	    (u_long)ntohl(ia->expired));
2298 }
2299 
2300 
2301 
2302 /*
2303  * traps - obtain and print a list of traps
2304  */
2305 /*ARGSUSED*/
2306 static void
2307 traps(
2308 	struct parse *pcmd,
2309 	FILE *fp
2310 	)
2311 {
2312 	int i;
2313 	struct info_trap *it;
2314 	struct sockaddr_storage trap_addr, local_addr;
2315 	int items;
2316 	int itemsize;
2317 	int res;
2318 
2319 again:
2320 	res = doquery(impl_ver, REQ_TRAPS, 0, 0, 0, (char *)NULL,
2321 		      &items, &itemsize, (void *)&it, 0,
2322 		      sizeof(struct info_trap));
2323 
2324 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2325 		impl_ver = IMPL_XNTPD_OLD;
2326 		goto again;
2327 	}
2328 
2329 	if (res != 0 && items == 0)
2330 	    return;
2331 
2332 	if (!checkitems(items, fp))
2333 	    return;
2334 
2335 	if (!checkitemsize(itemsize, sizeof(struct info_trap)) &&
2336 	    !checkitemsize(itemsize, v4sizeof(struct info_trap)))
2337 	    return;
2338 
2339 	for (i = 0; i < items; i++ ) {
2340 		if (i != 0)
2341 		    (void) fprintf(fp, "\n");
2342 		memset((char *)&trap_addr, 0, sizeof(trap_addr));
2343 		memset((char *)&local_addr, 0, sizeof(local_addr));
2344 		if (it->v6_flag != 0) {
2345 			GET_INADDR6(trap_addr) = it->trap_address6;
2346 			GET_INADDR6(local_addr) = it->local_address6;
2347 			trap_addr.ss_family = AF_INET6;
2348 			local_addr.ss_family = AF_INET6;
2349 		} else {
2350 			GET_INADDR(trap_addr) = it->trap_address;
2351 			GET_INADDR(local_addr) = it->local_address;
2352 			trap_addr.ss_family = AF_INET;
2353 			local_addr.ss_family = AF_INET;
2354 		}
2355 #ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR
2356 		trap_addr.ss_len = SOCKLEN(&trap_addr);
2357 		local_addr.ss_len = SOCKLEN(&local_addr);
2358 #endif
2359 		(void) fprintf(fp, "address %s, port %d\n",
2360 				stoa(&trap_addr),
2361 				ntohs(it->trap_port));
2362 		(void) fprintf(fp, "interface: %s, ",
2363 				(it->local_address == 0)
2364 				? "wildcard"
2365 				: stoa(&local_addr));
2366 		if (ntohl(it->flags) & TRAP_CONFIGURED)
2367 		    (void) fprintf(fp, "configured\n");
2368 		else if (ntohl(it->flags) & TRAP_NONPRIO)
2369 		    (void) fprintf(fp, "low priority\n");
2370 		else
2371 		    (void) fprintf(fp, "normal priority\n");
2372 
2373 		(void) fprintf(fp, "set for %ld secs, last set %ld secs ago\n",
2374 			       (long)ntohl(it->origtime),
2375 			       (long)ntohl(it->settime));
2376 		(void) fprintf(fp, "sequence %d, number of resets %ld\n",
2377 			       ntohs(it->sequence),
2378 			       (long)ntohl(it->resets));
2379 	}
2380 }
2381 
2382 
2383 /*
2384  * addtrap - configure a trap
2385  */
2386 static void
2387 addtrap(
2388 	struct parse *pcmd,
2389 	FILE *fp
2390 	)
2391 {
2392 	do_addclr_trap(pcmd, fp, REQ_ADD_TRAP);
2393 }
2394 
2395 
2396 /*
2397  * clrtrap - clear a trap from the server
2398  */
2399 static void
2400 clrtrap(
2401 	struct parse *pcmd,
2402 	FILE *fp
2403 	)
2404 {
2405 	do_addclr_trap(pcmd, fp, REQ_CLR_TRAP);
2406 }
2407 
2408 
2409 /*
2410  * do_addclr_trap - do grunge work of adding/deleting traps
2411  */
2412 static void
2413 do_addclr_trap(
2414 	struct parse *pcmd,
2415 	FILE *fp,
2416 	int req
2417 	)
2418 {
2419 	struct conf_trap ctrap;
2420 	int items;
2421 	int itemsize;
2422 	char *dummy;
2423 	int res;
2424 	int sendsize;
2425 
2426 again:
2427 	if (impl_ver == IMPL_XNTPD)
2428 		sendsize = sizeof(struct conf_trap);
2429 	else
2430 		sendsize = v4sizeof(struct conf_trap);
2431 
2432 	if (pcmd->argval[0].netnum.ss_family == AF_INET) {
2433 		ctrap.trap_address = GET_INADDR(pcmd->argval[0].netnum);
2434 		if (impl_ver == IMPL_XNTPD)
2435 			ctrap.v6_flag = 0;
2436 	} else {
2437 		if (impl_ver == IMPL_XNTPD_OLD) {
2438 			fprintf(stderr,
2439 			    "***Server doesn't understand IPv6 addresses\n");
2440 			return;
2441 		}
2442 		ctrap.trap_address6 = GET_INADDR6(pcmd->argval[0].netnum);
2443 		ctrap.v6_flag = 1;
2444 	}
2445 	ctrap.local_address = 0;
2446 	ctrap.trap_port = htons(TRAPPORT);
2447 	ctrap.unused = 0;
2448 
2449 	if (pcmd->nargs > 1) {
2450 		ctrap.trap_port
2451 			= htons((u_short)(pcmd->argval[1].uval & 0xffff));
2452 		if (pcmd->nargs > 2) {
2453 			if (pcmd->argval[2].netnum.ss_family !=
2454 			    pcmd->argval[0].netnum.ss_family) {
2455 				fprintf(stderr,
2456 				    "***Cannot mix IPv4 and IPv6 addresses\n");
2457 				return;
2458 			}
2459 			if (pcmd->argval[2].netnum.ss_family == AF_INET)
2460 				ctrap.local_address = GET_INADDR(pcmd->argval[2].netnum);
2461 			else
2462 				ctrap.local_address6 = GET_INADDR6(pcmd->argval[2].netnum);
2463 		}
2464 	}
2465 
2466 	res = doquery(impl_ver, req, 1, 1, sendsize,
2467 		      (char *)&ctrap, &items, &itemsize, &dummy, 0,
2468 		      sizeof(struct conf_trap));
2469 
2470 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2471 		impl_ver = IMPL_XNTPD_OLD;
2472 		goto again;
2473 	}
2474 
2475 	if (res == 0)
2476 	    (void) fprintf(fp, "done!\n");
2477 	return;
2478 }
2479 
2480 
2481 
2482 /*
2483  * requestkey - change the server's request key (a dangerous request)
2484  */
2485 static void
2486 requestkey(
2487 	struct parse *pcmd,
2488 	FILE *fp
2489 	)
2490 {
2491 	do_changekey(pcmd, fp, REQ_REQUEST_KEY);
2492 }
2493 
2494 
2495 /*
2496  * controlkey - change the server's control key
2497  */
2498 static void
2499 controlkey(
2500 	struct parse *pcmd,
2501 	FILE *fp
2502 	)
2503 {
2504 	do_changekey(pcmd, fp, REQ_CONTROL_KEY);
2505 }
2506 
2507 
2508 
2509 /*
2510  * do_changekey - do grunge work of changing keys
2511  */
2512 static void
2513 do_changekey(
2514 	struct parse *pcmd,
2515 	FILE *fp,
2516 	int req
2517 	)
2518 {
2519 	u_long key;
2520 	int items;
2521 	int itemsize;
2522 	char *dummy;
2523 	int res;
2524 
2525 
2526 	key = htonl((u_int32)pcmd->argval[0].uval);
2527 
2528 again:
2529 	res = doquery(impl_ver, req, 1, 1, sizeof(u_int32),
2530 		      (char *)&key, &items, &itemsize, &dummy, 0,
2531 		      sizeof(dummy));
2532 
2533 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2534 		impl_ver = IMPL_XNTPD_OLD;
2535 		goto again;
2536 	}
2537 
2538 	if (res == 0)
2539 	    (void) fprintf(fp, "done!\n");
2540 	return;
2541 }
2542 
2543 
2544 
2545 /*
2546  * ctlstats - obtain and print info about authentication
2547  */
2548 /*ARGSUSED*/
2549 static void
2550 ctlstats(
2551 	struct parse *pcmd,
2552 	FILE *fp
2553 	)
2554 {
2555 	struct info_control *ic;
2556 	int items;
2557 	int itemsize;
2558 	int res;
2559 
2560 again:
2561 	res = doquery(impl_ver, REQ_GET_CTLSTATS, 0, 0, 0, (char *)NULL,
2562 		      &items, &itemsize, (void *)&ic, 0,
2563 		      sizeof(struct info_control));
2564 
2565 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2566 		impl_ver = IMPL_XNTPD_OLD;
2567 		goto again;
2568 	}
2569 
2570 	if (res != 0 && items == 0)
2571 	    return;
2572 
2573 	if (!check1item(items, fp))
2574 	    return;
2575 
2576 	if (!checkitemsize(itemsize, sizeof(struct info_control)))
2577 	    return;
2578 
2579 	(void) fprintf(fp, "time since reset:       %ld\n",
2580 		       (u_long)ntohl(ic->ctltimereset));
2581 	(void) fprintf(fp, "requests received:      %ld\n",
2582 		       (u_long)ntohl(ic->numctlreq));
2583 	(void) fprintf(fp, "responses sent:         %ld\n",
2584 		       (u_long)ntohl(ic->numctlresponses));
2585 	(void) fprintf(fp, "fragments sent:         %ld\n",
2586 		       (u_long)ntohl(ic->numctlfrags));
2587 	(void) fprintf(fp, "async messages sent:    %ld\n",
2588 		       (u_long)ntohl(ic->numasyncmsgs));
2589 	(void) fprintf(fp, "error msgs sent:        %ld\n",
2590 		       (u_long)ntohl(ic->numctlerrors));
2591 	(void) fprintf(fp, "total bad pkts:         %ld\n",
2592 		       (u_long)ntohl(ic->numctlbadpkts));
2593 	(void) fprintf(fp, "packet too short:       %ld\n",
2594 		       (u_long)ntohl(ic->numctltooshort));
2595 	(void) fprintf(fp, "response on input:      %ld\n",
2596 		       (u_long)ntohl(ic->numctlinputresp));
2597 	(void) fprintf(fp, "fragment on input:      %ld\n",
2598 		       (u_long)ntohl(ic->numctlinputfrag));
2599 	(void) fprintf(fp, "error set on input:     %ld\n",
2600 		       (u_long)ntohl(ic->numctlinputerr));
2601 	(void) fprintf(fp, "bad offset on input:    %ld\n",
2602 		       (u_long)ntohl(ic->numctlbadoffset));
2603 	(void) fprintf(fp, "bad version packets:    %ld\n",
2604 		       (u_long)ntohl(ic->numctlbadversion));
2605 	(void) fprintf(fp, "data in pkt too short:  %ld\n",
2606 		       (u_long)ntohl(ic->numctldatatooshort));
2607 	(void) fprintf(fp, "unknown op codes:       %ld\n",
2608 		       (u_long)ntohl(ic->numctlbadop));
2609 }
2610 
2611 
2612 /*
2613  * clockstat - get and print clock status information
2614  */
2615 static void
2616 clockstat(
2617 	struct parse *pcmd,
2618 	FILE *fp
2619 	)
2620 {
2621 	struct info_clock *cl;
2622 	/* 8 is the maximum number of clocks which will fit in a packet */
2623 	u_long clist[min(MAXARGS, 8)];
2624 	int qitems;
2625 	int items;
2626 	int itemsize;
2627 	int res;
2628 	l_fp ts;
2629 	struct clktype *clk;
2630 	u_long ltemp;
2631 
2632 	for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++)
2633 	    clist[qitems] = GET_INADDR(pcmd->argval[qitems].netnum);
2634 
2635 again:
2636 	res = doquery(impl_ver, REQ_GET_CLOCKINFO, 0, qitems,
2637 		      sizeof(u_int32), (char *)clist, &items,
2638 		      &itemsize, (void *)&cl, 0, sizeof(struct info_clock));
2639 
2640 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2641 		impl_ver = IMPL_XNTPD_OLD;
2642 		goto again;
2643 	}
2644 
2645 	if (res != 0 && items == 0)
2646 	    return;
2647 
2648 	if (!checkitems(items, fp))
2649 	    return;
2650 
2651 	if (!checkitemsize(itemsize, sizeof(struct info_clock)))
2652 	    return;
2653 
2654 	while (items-- > 0) {
2655 		(void) fprintf(fp, "clock address:        %s\n",
2656 			       numtoa(cl->clockadr));
2657 		for (clk = clktypes; clk->code >= 0; clk++)
2658 		    if (clk->code == cl->type)
2659 			break;
2660 		if (clk->code >= 0)
2661 		    (void) fprintf(fp, "clock type:           %s\n",
2662 				   clk->clocktype);
2663 		else
2664 		    (void) fprintf(fp, "clock type:           unknown type (%d)\n",
2665 				   cl->type);
2666 		(void) fprintf(fp, "last event:           %d\n",
2667 			       cl->lastevent);
2668 		(void) fprintf(fp, "current status:       %d\n",
2669 			       cl->currentstatus);
2670 		(void) fprintf(fp, "number of polls:      %lu\n",
2671 			       (u_long)ntohl(cl->polls));
2672 		(void) fprintf(fp, "no response to poll:  %lu\n",
2673 			       (u_long)ntohl(cl->noresponse));
2674 		(void) fprintf(fp, "bad format responses: %lu\n",
2675 			       (u_long)ntohl(cl->badformat));
2676 		(void) fprintf(fp, "bad data responses:   %lu\n",
2677 			       (u_long)ntohl(cl->baddata));
2678 		(void) fprintf(fp, "running time:         %lu\n",
2679 			       (u_long)ntohl(cl->timestarted));
2680 		NTOHL_FP(&cl->fudgetime1, &ts);
2681 		(void) fprintf(fp, "fudge time 1:         %s\n",
2682 			       lfptoa(&ts, 6));
2683 		NTOHL_FP(&cl->fudgetime2, &ts);
2684 		(void) fprintf(fp, "fudge time 2:         %s\n",
2685 			       lfptoa(&ts, 6));
2686 		(void) fprintf(fp, "stratum:              %ld\n",
2687 			       (u_long)ntohl(cl->fudgeval1));
2688 		ltemp = ntohl(cl->fudgeval2);
2689 		(void) fprintf(fp, "reference ID:         %s\n",
2690 			       (char *)&ltemp);
2691 		(void) fprintf(fp, "fudge flags:          0x%x\n",
2692 			       cl->flags);
2693 
2694 		if (items > 0)
2695 		    (void) fprintf(fp, "\n");
2696 		cl++;
2697 	}
2698 }
2699 
2700 
2701 /*
2702  * fudge - set clock fudge factors
2703  */
2704 static void
2705 fudge(
2706 	struct parse *pcmd,
2707 	FILE *fp
2708 	)
2709 {
2710 	struct conf_fudge fudgedata;
2711 	int items;
2712 	int itemsize;
2713 	char *dummy;
2714 	l_fp ts;
2715 	int res;
2716 	long val;
2717 	u_long u_val;
2718 	int err;
2719 
2720 
2721 	err = 0;
2722 	memset((char *)&fudgedata, 0, sizeof fudgedata);
2723 	fudgedata.clockadr = GET_INADDR(pcmd->argval[0].netnum);
2724 
2725 	if (STREQ(pcmd->argval[1].string, "time1")) {
2726 		fudgedata.which = htonl(FUDGE_TIME1);
2727 		if (!atolfp(pcmd->argval[2].string, &ts))
2728 		    err = 1;
2729 		else
2730 		    NTOHL_FP(&ts, &fudgedata.fudgetime);
2731 	} else if (STREQ(pcmd->argval[1].string, "time2")) {
2732 		fudgedata.which = htonl(FUDGE_TIME2);
2733 		if (!atolfp(pcmd->argval[2].string, &ts))
2734 		    err = 1;
2735 		else
2736 		    NTOHL_FP(&ts, &fudgedata.fudgetime);
2737 	} else if (STREQ(pcmd->argval[1].string, "val1")) {
2738 		fudgedata.which = htonl(FUDGE_VAL1);
2739 		if (!atoint(pcmd->argval[2].string, &val))
2740 		    err = 1;
2741 		else
2742 		    fudgedata.fudgeval_flags = htonl(val);
2743 	} else if (STREQ(pcmd->argval[1].string, "val2")) {
2744 		fudgedata.which = htonl(FUDGE_VAL2);
2745 		if (!atoint(pcmd->argval[2].string, &val))
2746 		    err = 1;
2747 		else
2748 		    fudgedata.fudgeval_flags = htonl((u_int32)val);
2749 	} else if (STREQ(pcmd->argval[1].string, "flags")) {
2750 		fudgedata.which = htonl(FUDGE_FLAGS);
2751 		if (!hextoint(pcmd->argval[2].string, &u_val))
2752 		    err = 1;
2753 		else
2754 		    fudgedata.fudgeval_flags = htonl((u_int32)(u_val & 0xf));
2755 	} else {
2756 		(void) fprintf(stderr, "What fudge is %s?\n",
2757 			       pcmd->argval[1].string);
2758 		return;
2759 	}
2760 
2761 	if (err) {
2762 		(void) fprintf(stderr, "Unknown fudge parameter %s\n",
2763 			       pcmd->argval[2].string);
2764 		return;
2765 	}
2766 
2767 again:
2768 	res = doquery(impl_ver, REQ_SET_CLKFUDGE, 1, 1,
2769 		      sizeof(struct conf_fudge), (char *)&fudgedata, &items,
2770 		      &itemsize, &dummy, 0, sizeof(dummy));
2771 
2772 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2773 		impl_ver = IMPL_XNTPD_OLD;
2774 		goto again;
2775 	}
2776 
2777 	if (res == 0)
2778 	    (void) fprintf(fp, "done!\n");
2779 	return;
2780 }
2781 
2782 /*
2783  * clkbug - get and print clock debugging information
2784  */
2785 static void
2786 clkbug(
2787 	struct parse *pcmd,
2788 	FILE *fp
2789 	)
2790 {
2791 	register int i;
2792 	register int n;
2793 	register u_int32 s;
2794 	struct info_clkbug *cl;
2795 	/* 8 is the maximum number of clocks which will fit in a packet */
2796 	u_long clist[min(MAXARGS, 8)];
2797 	u_int32 ltemp;
2798 	int qitems;
2799 	int items;
2800 	int itemsize;
2801 	int res;
2802 	int needsp;
2803 	l_fp ts;
2804 
2805 	for (qitems = 0; qitems < min(pcmd->nargs, 8); qitems++)
2806 	    clist[qitems] = GET_INADDR(pcmd->argval[qitems].netnum);
2807 
2808 again:
2809 	res = doquery(impl_ver, REQ_GET_CLKBUGINFO, 0, qitems,
2810 		      sizeof(u_int32), (char *)clist, &items,
2811 		      &itemsize, (void *)&cl, 0, sizeof(struct info_clkbug));
2812 
2813 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2814 		impl_ver = IMPL_XNTPD_OLD;
2815 		goto again;
2816 	}
2817 
2818 	if (res != 0 && items == 0)
2819 	    return;
2820 
2821 	if (!checkitems(items, fp))
2822 	    return;
2823 
2824 	if (!checkitemsize(itemsize, sizeof(struct info_clkbug)))
2825 	    return;
2826 
2827 	while (items-- > 0) {
2828 		(void) fprintf(fp, "clock address:        %s\n",
2829 			       numtoa(cl->clockadr));
2830 		n = (int)cl->nvalues;
2831 		(void) fprintf(fp, "values: %d", n);
2832 		s = ntohs(cl->svalues);
2833 		if (n > NUMCBUGVALUES)
2834 		    n = NUMCBUGVALUES;
2835 		for (i = 0; i < n; i++) {
2836 			ltemp = ntohl(cl->values[i]);
2837 			ltemp &= 0xffffffff;	/* HMS: This does nothing now */
2838 			if ((i & 0x3) == 0)
2839 			    (void) fprintf(fp, "\n");
2840 			if (s & (1 << i))
2841 			    (void) fprintf(fp, "%12ld", (u_long)ltemp);
2842 			else
2843 			    (void) fprintf(fp, "%12lu", (u_long)ltemp);
2844 		}
2845 		(void) fprintf(fp, "\n");
2846 
2847 		n = (int)cl->ntimes;
2848 		(void) fprintf(fp, "times: %d", n);
2849 		s = ntohl(cl->stimes);
2850 		if (n > NUMCBUGTIMES)
2851 		    n = NUMCBUGTIMES;
2852 		needsp = 0;
2853 		for (i = 0; i < n; i++) {
2854 			if ((i & 0x1) == 0) {
2855 			    (void) fprintf(fp, "\n");
2856 			} else {
2857 				for (;needsp > 0; needsp--)
2858 				    putc(' ', fp);
2859 			}
2860 			NTOHL_FP(&cl->times[i], &ts);
2861 			if (s & (1 << i)) {
2862 				(void) fprintf(fp, "%17s",
2863 					       lfptoa(&ts, 6));
2864 				needsp = 22;
2865 			} else {
2866 				(void) fprintf(fp, "%37s",
2867 					       uglydate(&ts));
2868 				needsp = 2;
2869 			}
2870 		}
2871 		(void) fprintf(fp, "\n");
2872 		if (items > 0) {
2873 			cl++;
2874 			(void) fprintf(fp, "\n");
2875 		}
2876 	}
2877 }
2878 
2879 
2880 /*
2881  * kerninfo - display the kernel pll/pps variables
2882  */
2883 static void
2884 kerninfo(
2885 	struct parse *pcmd,
2886 	FILE *fp
2887 	)
2888 {
2889 	struct info_kernel *ik;
2890 	int items;
2891 	int itemsize;
2892 	int res;
2893 	unsigned status;
2894 	double tscale = 1e-6;
2895 
2896 again:
2897 	res = doquery(impl_ver, REQ_GET_KERNEL, 0, 0, 0, (char *)NULL,
2898 		      &items, &itemsize, (void *)&ik, 0,
2899 		      sizeof(struct info_kernel));
2900 
2901 	if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2902 		impl_ver = IMPL_XNTPD_OLD;
2903 		goto again;
2904 	}
2905 
2906 	if (res != 0 && items == 0)
2907 	    return;
2908 	if (!check1item(items, fp))
2909 	    return;
2910 	if (!checkitemsize(itemsize, sizeof(struct info_kernel)))
2911 	    return;
2912 
2913 	status = ntohs(ik->status) & 0xffff;
2914 	/*
2915 	 * pll variables. We know more than we should about the NANO bit.
2916 	 */
2917 #ifdef STA_NANO
2918 	if (status & STA_NANO)
2919 		tscale = 1e-9;
2920 #endif
2921 	(void)fprintf(fp, "pll offset:           %g s\n",
2922 	    (long)ntohl(ik->offset) * tscale);
2923 	(void)fprintf(fp, "pll frequency:        %s ppm\n",
2924 	    fptoa((s_fp)ntohl(ik->freq), 3));
2925 	(void)fprintf(fp, "maximum error:        %g s\n",
2926 	    (u_long)ntohl(ik->maxerror) * 1e-6);
2927 	(void)fprintf(fp, "estimated error:      %g s\n",
2928 	    (u_long)ntohl(ik->esterror) * 1e-6);
2929 	(void)fprintf(fp, "status:               %04x ", status);
2930 #ifdef STA_PLL
2931 	if (status & STA_PLL) (void)fprintf(fp, " pll");
2932 #endif
2933 #ifdef STA_PPSFREQ
2934 	if (status & STA_PPSFREQ) (void)fprintf(fp, " ppsfreq");
2935 #endif
2936 #ifdef STA_PPSTIME
2937 	if (status & STA_PPSTIME) (void)fprintf(fp, " ppstime");
2938 #endif
2939 #ifdef STA_FLL
2940 	if (status & STA_FLL) (void)fprintf(fp, " fll");
2941 #endif
2942 #ifdef STA_INS
2943 	if (status & STA_INS) (void)fprintf(fp, " ins");
2944 #endif
2945 #ifdef STA_DEL
2946 	if (status & STA_DEL) (void)fprintf(fp, " del");
2947 #endif
2948 #ifdef STA_UNSYNC
2949 	if (status & STA_UNSYNC) (void)fprintf(fp, " unsync");
2950 #endif
2951 #ifdef STA_FREQHOLD
2952 	if (status & STA_FREQHOLD) (void)fprintf(fp, " freqhold");
2953 #endif
2954 #ifdef STA_PPSSIGNAL
2955 	if (status & STA_PPSSIGNAL) (void)fprintf(fp, " ppssignal");
2956 #endif
2957 #ifdef STA_PPSJITTER
2958 	if (status & STA_PPSJITTER) (void)fprintf(fp, " ppsjitter");
2959 #endif
2960 #ifdef STA_PPSWANDER
2961 	if (status & STA_PPSWANDER) (void)fprintf(fp, " ppswander");
2962 #endif
2963 #ifdef STA_PPSERROR
2964 	if (status & STA_PPSERROR) (void)fprintf(fp, " ppserror");
2965 #endif
2966 #ifdef STA_CLOCKERR
2967 	if (status & STA_CLOCKERR) (void)fprintf(fp, " clockerr");
2968 #endif
2969 #ifdef STA_NANO
2970 	if (status & STA_NANO) (void)fprintf(fp, " nano");
2971 #endif
2972 #ifdef STA_MODE
2973 	if (status & STA_MODE) (void)fprintf(fp, " mode=fll");
2974 #endif
2975 #ifdef STA_CLK
2976 	if (status & STA_CLK) (void)fprintf(fp, " src=B");
2977 #endif
2978 	(void)fprintf(fp, "\n");
2979 	(void)fprintf(fp, "pll time constant:    %ld\n",
2980 	    (u_long)ntohl(ik->constant));
2981 	(void)fprintf(fp, "precision:            %g s\n",
2982 	    (u_long)ntohl(ik->precision) * tscale);
2983 	(void)fprintf(fp, "frequency tolerance:  %s ppm\n",
2984 	    fptoa((s_fp)ntohl(ik->tolerance), 0));
2985 
2986 	/*
2987 	 * For backwards compatibility (ugh), we find the pps variables
2988 	 * only if the shift member is nonzero.
2989 	 */
2990 	if (!ik->shift)
2991 	    return;
2992 
2993 	/*
2994 	 * pps variables
2995 	 */
2996 	(void)fprintf(fp, "pps frequency:        %s ppm\n",
2997 	    fptoa((s_fp)ntohl(ik->ppsfreq), 3));
2998 	(void)fprintf(fp, "pps stability:        %s ppm\n",
2999 	    fptoa((s_fp)ntohl(ik->stabil), 3));
3000 	(void)fprintf(fp, "pps jitter:           %g s\n",
3001 	    (u_long)ntohl(ik->jitter) * tscale);
3002 	(void)fprintf(fp, "calibration interval: %d s\n",
3003 		      1 << ntohs(ik->shift));
3004 	(void)fprintf(fp, "calibration cycles:   %ld\n",
3005 		      (u_long)ntohl(ik->calcnt));
3006 	(void)fprintf(fp, "jitter exceeded:      %ld\n",
3007 		      (u_long)ntohl(ik->jitcnt));
3008 	(void)fprintf(fp, "stability exceeded:   %ld\n",
3009 		      (u_long)ntohl(ik->stbcnt));
3010 	(void)fprintf(fp, "calibration errors:   %ld\n",
3011 		      (u_long)ntohl(ik->errcnt));
3012 }
3013