xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ntp.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 1991, 2000, 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <fcntl.h>
30*0Sstevel@tonic-gate #include <sys/socket.h>
31*0Sstevel@tonic-gate #include <sys/sysmacros.h>
32*0Sstevel@tonic-gate #include <netinet/in.h>
33*0Sstevel@tonic-gate #include <netdb.h>
34*0Sstevel@tonic-gate #include <stdio.h>
35*0Sstevel@tonic-gate #include <string.h>
36*0Sstevel@tonic-gate #include <tzfile.h>
37*0Sstevel@tonic-gate #include "snoop.h"
38*0Sstevel@tonic-gate #include "ntp.h"
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate /*
41*0Sstevel@tonic-gate  * In verbose mode, how many octets of the control-mode data payload
42*0Sstevel@tonic-gate  * are displayed per line of output.  The value 64 fits well on an
43*0Sstevel@tonic-gate  * 80-column screen and, as a power of 2, is easily correlated to
44*0Sstevel@tonic-gate  * hexadecimal output.
45*0Sstevel@tonic-gate  */
46*0Sstevel@tonic-gate #define	OCTETS_PER_LINE	64
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate extern char *dlc_header;
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate static	char	*show_leap(int);
51*0Sstevel@tonic-gate static	char	*show_mode(int);
52*0Sstevel@tonic-gate static	char	*show_ref(int, ulong_t);
53*0Sstevel@tonic-gate static	char	*show_time(struct l_fixedpt);
54*0Sstevel@tonic-gate static	double	s_fixed_to_double(struct s_fixedpt *);
55*0Sstevel@tonic-gate static	char	*iso_date_time(time_t);
56*0Sstevel@tonic-gate static	char	*show_operation(int);
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate int
59*0Sstevel@tonic-gate interpret_ntp(int flags, struct ntpdata *ntp_pkt, int fraglen)
60*0Sstevel@tonic-gate {
61*0Sstevel@tonic-gate 	unsigned int	i, j, macbytes;
62*0Sstevel@tonic-gate 	unsigned int	proto_version;
63*0Sstevel@tonic-gate 	unsigned int	datalen;
64*0Sstevel@tonic-gate 	unsigned int	linelen = OCTETS_PER_LINE;
65*0Sstevel@tonic-gate 	unsigned int	sofar = 0;
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate 	char	*datap;
68*0Sstevel@tonic-gate 	char	hbuf[2 * MAC_OCTETS_MAX + 1];
69*0Sstevel@tonic-gate 	static	char *hexstr = "0123456789ABCDEF";
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	union	ntp_pkt_buf {
72*0Sstevel@tonic-gate 		struct	ntpdata ntp_msg;
73*0Sstevel@tonic-gate 		union ntpc_buf {
74*0Sstevel@tonic-gate 			struct	ntp_control chdr;
75*0Sstevel@tonic-gate 			uchar_t	data2[NTPC_DATA_MAXLEN - 1];
76*0Sstevel@tonic-gate 		} ntpc_msg;
77*0Sstevel@tonic-gate 		union ntpp_buf {
78*0Sstevel@tonic-gate 			struct	ntp_private phdr;
79*0Sstevel@tonic-gate 			uchar_t	data2[1];
80*0Sstevel@tonic-gate 		} ntpp_msg;
81*0Sstevel@tonic-gate 	} fragbuf;
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	struct	ntpdata		*ntp = &fragbuf.ntp_msg;
84*0Sstevel@tonic-gate 	struct	ntp_control	*ntpc = (struct ntp_control *)&fragbuf.ntpc_msg;
85*0Sstevel@tonic-gate 	struct	ntp_private	*ntpp = (struct ntp_private *)&fragbuf.ntpp_msg;
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	/*
88*0Sstevel@tonic-gate 	 * Copying packet contents into a local buffer avoids
89*0Sstevel@tonic-gate 	 * problems of interpretation if the packet is truncated.
90*0Sstevel@tonic-gate 	 */
91*0Sstevel@tonic-gate 	(void) memcpy(&fragbuf, ntp_pkt, MIN(sizeof (fragbuf), fraglen));
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 	if (flags & F_SUM) {
94*0Sstevel@tonic-gate 		switch (ntp->li_vn_mode & NTPMODEMASK) {
95*0Sstevel@tonic-gate 		case MODE_SYM_ACT:
96*0Sstevel@tonic-gate 		case MODE_SYM_PAS:
97*0Sstevel@tonic-gate 		case MODE_CLIENT:
98*0Sstevel@tonic-gate 		case MODE_SERVER:
99*0Sstevel@tonic-gate 		case MODE_BROADCAST:
100*0Sstevel@tonic-gate 		    (void) sprintf(get_sum_line(),
101*0Sstevel@tonic-gate 			"NTP  %s [st=%hd] (%s)",
102*0Sstevel@tonic-gate 			show_mode(ntp->li_vn_mode & NTPMODEMASK),
103*0Sstevel@tonic-gate 			ntp->stratum,
104*0Sstevel@tonic-gate 			show_time(ntp->xmt));
105*0Sstevel@tonic-gate 		    break;
106*0Sstevel@tonic-gate 		case MODE_CONTROL:
107*0Sstevel@tonic-gate 		    (void) sprintf(get_sum_line(),
108*0Sstevel@tonic-gate 			"NTP  %s "
109*0Sstevel@tonic-gate 			"(Flags/op=0x%02x Seq=%hu Status=0x%04hx Assoc=%hu)",
110*0Sstevel@tonic-gate 			show_mode(ntpc->li_vn_mode & NTPMODEMASK),
111*0Sstevel@tonic-gate 			ntpc->r_m_e_op,
112*0Sstevel@tonic-gate 			ntohs(ntpc->sequence),
113*0Sstevel@tonic-gate 			ntohs(ntpc->status),
114*0Sstevel@tonic-gate 			ntohs(ntpc->associd));
115*0Sstevel@tonic-gate 		    break;
116*0Sstevel@tonic-gate 		default:
117*0Sstevel@tonic-gate 		    (void) sprintf(get_sum_line(),
118*0Sstevel@tonic-gate 			"NTP  %s",
119*0Sstevel@tonic-gate 			show_mode(ntpp->rm_vn_mode & NTPMODEMASK));
120*0Sstevel@tonic-gate 		    break;
121*0Sstevel@tonic-gate 		}
122*0Sstevel@tonic-gate 	}
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	proto_version = (ntp->li_vn_mode & VERSIONMASK) >> 3;
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	if (flags & F_DTAIL) {
127*0Sstevel@tonic-gate 		show_header("NTP:  ", "Network Time Protocol", fraglen);
128*0Sstevel@tonic-gate 		show_space();
129*0Sstevel@tonic-gate 		switch (ntp->li_vn_mode & NTPMODEMASK) {
130*0Sstevel@tonic-gate 		case MODE_SYM_ACT:
131*0Sstevel@tonic-gate 		case MODE_SYM_PAS:
132*0Sstevel@tonic-gate 		case MODE_CLIENT:
133*0Sstevel@tonic-gate 		case MODE_SERVER:
134*0Sstevel@tonic-gate 		case MODE_BROADCAST:
135*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->li_vn_mode -
136*0Sstevel@tonic-gate 			dlc_header, 1),
137*0Sstevel@tonic-gate 			"Leap    = 0x%x (%s)",
138*0Sstevel@tonic-gate 			(int)(ntp->li_vn_mode & LEAPMASK) >> 6,
139*0Sstevel@tonic-gate 			show_leap(ntp->li_vn_mode & LEAPMASK));
140*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->li_vn_mode -
141*0Sstevel@tonic-gate 			dlc_header, 1),
142*0Sstevel@tonic-gate 			"Version = %lu", proto_version);
143*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->li_vn_mode -
144*0Sstevel@tonic-gate 			dlc_header, 1),
145*0Sstevel@tonic-gate 			"Mode    = %hu (%s)",
146*0Sstevel@tonic-gate 			ntp->li_vn_mode & NTPMODEMASK,
147*0Sstevel@tonic-gate 			show_mode(ntp->li_vn_mode & NTPMODEMASK));
148*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->stratum -
149*0Sstevel@tonic-gate 			dlc_header, 1),
150*0Sstevel@tonic-gate 			"Stratum = %d (%s)",
151*0Sstevel@tonic-gate 			ntp->stratum,
152*0Sstevel@tonic-gate 			ntp->stratum == 0 ? "unspecified" :
153*0Sstevel@tonic-gate 			ntp->stratum == 1 ? "primary reference" :
154*0Sstevel@tonic-gate 			"secondary reference");
155*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->ppoll - dlc_header, 1),
156*0Sstevel@tonic-gate 			"Poll    = %hu",
157*0Sstevel@tonic-gate 			ntp->ppoll);
158*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->precision -
159*0Sstevel@tonic-gate 			dlc_header, 1),
160*0Sstevel@tonic-gate 			"Precision = %d seconds",
161*0Sstevel@tonic-gate 			ntp->precision);
162*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->distance.int_part -
163*0Sstevel@tonic-gate 			dlc_header, 1),
164*0Sstevel@tonic-gate 			"Synchronizing distance   = 0x%04x.%04x  (%f)",
165*0Sstevel@tonic-gate 			ntohs(ntp->distance.int_part),
166*0Sstevel@tonic-gate 			ntohs(ntp->distance.fraction),
167*0Sstevel@tonic-gate 			s_fixed_to_double(&ntp->distance));
168*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->dispersion.int_part -
169*0Sstevel@tonic-gate 			dlc_header, 1),
170*0Sstevel@tonic-gate 			"Synchronizing dispersion = 0x%04x.%04x  (%f)",
171*0Sstevel@tonic-gate 			ntohs(ntp->dispersion.int_part),
172*0Sstevel@tonic-gate 			ntohs(ntp->dispersion.fraction),
173*0Sstevel@tonic-gate 			s_fixed_to_double(&ntp->dispersion));
174*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->refid - dlc_header, 1),
175*0Sstevel@tonic-gate 			"Reference clock = %s",
176*0Sstevel@tonic-gate 			show_ref(ntp->stratum, ntp->refid));
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->reftime.int_part -
179*0Sstevel@tonic-gate 			dlc_header, 1),
180*0Sstevel@tonic-gate 			"Reference time = 0x%08lx.%08lx (%s)",
181*0Sstevel@tonic-gate 			ntohl(ntp->reftime.int_part),
182*0Sstevel@tonic-gate 			ntohl(ntp->reftime.fraction),
183*0Sstevel@tonic-gate 			show_time(ntp->reftime));
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->org.int_part -
186*0Sstevel@tonic-gate 			dlc_header, 1),
187*0Sstevel@tonic-gate 			"Originate time = 0x%08lx.%08lx (%s)",
188*0Sstevel@tonic-gate 			ntohl(ntp->org.int_part),
189*0Sstevel@tonic-gate 			ntohl(ntp->org.fraction),
190*0Sstevel@tonic-gate 			show_time(ntp->org));
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->rec.int_part -
193*0Sstevel@tonic-gate 			dlc_header, 1),
194*0Sstevel@tonic-gate 			"Receive   time = 0x%08lx.%08lx (%s)",
195*0Sstevel@tonic-gate 			ntohl(ntp->rec.int_part),
196*0Sstevel@tonic-gate 			ntohl(ntp->rec.fraction),
197*0Sstevel@tonic-gate 			show_time(ntp->rec));
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->xmt.int_part -
200*0Sstevel@tonic-gate 			dlc_header, 1),
201*0Sstevel@tonic-gate 			"Transmit  time = 0x%08lx.%08lx (%s)",
202*0Sstevel@tonic-gate 			ntohl(ntp->xmt.int_part),
203*0Sstevel@tonic-gate 			ntohl(ntp->xmt.fraction),
204*0Sstevel@tonic-gate 			show_time(ntp->xmt));
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 		    if (proto_version > 3 ||
207*0Sstevel@tonic-gate 			fraglen < (LEN_PKT_NOMAC + MAC_OCTETS_MIN)) {
208*0Sstevel@tonic-gate 				/*
209*0Sstevel@tonic-gate 				 * A newer protocol version we can't parse,
210*0Sstevel@tonic-gate 				 * or v3 packet with no valid authentication.
211*0Sstevel@tonic-gate 				 */
212*0Sstevel@tonic-gate 				break;
213*0Sstevel@tonic-gate 		    }
214*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->keyid -
215*0Sstevel@tonic-gate 			dlc_header, 1),
216*0Sstevel@tonic-gate 			"Key ID  = %8lu", ntohl(ntp->keyid));
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 		    macbytes = fraglen - (LEN_PKT_NOMAC + sizeof (uint32_t));
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 		    for (i = 0, j = 0; i < macbytes; i++) {
221*0Sstevel@tonic-gate 			    hbuf[j++] = hexstr[ntp->mac[i] >> 4 & 0x0f];
222*0Sstevel@tonic-gate 			    hbuf[j++] = hexstr[ntp->mac[i] & 0x0f];
223*0Sstevel@tonic-gate 		    }
224*0Sstevel@tonic-gate 		    hbuf[j] = '\0';
225*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->mac -
226*0Sstevel@tonic-gate 			dlc_header, 1),
227*0Sstevel@tonic-gate 			"Authentication code = %s", hbuf);
228*0Sstevel@tonic-gate 		    break;
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 		case MODE_CONTROL:
231*0Sstevel@tonic-gate 		    /* NTP Control Message, mode 6 */
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->li_vn_mode -
234*0Sstevel@tonic-gate 			dlc_header, 1),
235*0Sstevel@tonic-gate 			"Leap    = 0x%x (%s)",
236*0Sstevel@tonic-gate 			(int)(ntp->li_vn_mode & LEAPMASK) >> 6,
237*0Sstevel@tonic-gate 			show_leap(ntp->li_vn_mode & LEAPMASK));
238*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->li_vn_mode -
239*0Sstevel@tonic-gate 			dlc_header, 1),
240*0Sstevel@tonic-gate 			"Version = %lu", proto_version);
241*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->li_vn_mode -
242*0Sstevel@tonic-gate 			dlc_header, 1),
243*0Sstevel@tonic-gate 			"Mode    = %hu (%s)",
244*0Sstevel@tonic-gate 			ntp->li_vn_mode & NTPMODEMASK,
245*0Sstevel@tonic-gate 			show_mode(ntp->li_vn_mode & NTPMODEMASK));
246*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpc->r_m_e_op -
247*0Sstevel@tonic-gate 			dlc_header, 1),
248*0Sstevel@tonic-gate 			"Flags and operation code = 0x%02x",
249*0Sstevel@tonic-gate 			ntpc->r_m_e_op);
250*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpc->r_m_e_op -
251*0Sstevel@tonic-gate 			dlc_header, 1),
252*0Sstevel@tonic-gate 			"      %s",
253*0Sstevel@tonic-gate 			getflag(ntpc->r_m_e_op, CTL_RESPONSE, "response",
254*0Sstevel@tonic-gate 			"request"));
255*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpc->r_m_e_op -
256*0Sstevel@tonic-gate 			dlc_header, 1),
257*0Sstevel@tonic-gate 			"      %s",
258*0Sstevel@tonic-gate 			getflag(ntpc->r_m_e_op, CTL_ERROR, "error",
259*0Sstevel@tonic-gate 			"success"));
260*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpc->r_m_e_op -
261*0Sstevel@tonic-gate 			dlc_header, 1),
262*0Sstevel@tonic-gate 			"      %s",
263*0Sstevel@tonic-gate 			getflag(ntpc->r_m_e_op, CTL_MORE, "more",
264*0Sstevel@tonic-gate 			"no more"));
265*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpc->r_m_e_op -
266*0Sstevel@tonic-gate 			dlc_header, 1),
267*0Sstevel@tonic-gate 			"      ...x xxxx = %hd (%s)",
268*0Sstevel@tonic-gate 			ntpc->r_m_e_op & CTL_OP_MASK,
269*0Sstevel@tonic-gate 			show_operation(ntpc->r_m_e_op & CTL_OP_MASK));
270*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpc->sequence -
271*0Sstevel@tonic-gate 			dlc_header, 1),
272*0Sstevel@tonic-gate 			"Sequence = %hu",
273*0Sstevel@tonic-gate 			ntohs(ntpc->sequence));
274*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpc->status -
275*0Sstevel@tonic-gate 			dlc_header, 1),
276*0Sstevel@tonic-gate 			"Status = 0x%04hx",
277*0Sstevel@tonic-gate 			ntohs(ntpc->status));
278*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpc->associd -
279*0Sstevel@tonic-gate 			dlc_header, 1),
280*0Sstevel@tonic-gate 			"Assoc ID = %hu",
281*0Sstevel@tonic-gate 			ntohs(ntpc->associd));
282*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpc->offset -
283*0Sstevel@tonic-gate 			dlc_header, 1),
284*0Sstevel@tonic-gate 			"Data offset = %hu",
285*0Sstevel@tonic-gate 			ntohs(ntpc->offset));
286*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpc->count -
287*0Sstevel@tonic-gate 			dlc_header, 1),
288*0Sstevel@tonic-gate 			"Data bytes = %hu",
289*0Sstevel@tonic-gate 			ntohs(ntpc->count));
290*0Sstevel@tonic-gate 		    datalen = ntohs(ntpc->count);
291*0Sstevel@tonic-gate 		    if (datalen == 0) {
292*0Sstevel@tonic-gate 			    break;
293*0Sstevel@tonic-gate 		    } else if (datalen > NTPC_DATA_MAXLEN) {
294*0Sstevel@tonic-gate 			    datalen = NTPC_DATA_MAXLEN;
295*0Sstevel@tonic-gate 		    }
296*0Sstevel@tonic-gate 		    show_space();
297*0Sstevel@tonic-gate 		    datap = (char *)ntpc->data;
298*0Sstevel@tonic-gate 		    do {
299*0Sstevel@tonic-gate 			    (void) sprintf(get_line(datap -
300*0Sstevel@tonic-gate 				dlc_header, 1),
301*0Sstevel@tonic-gate 				"\"%s\"",
302*0Sstevel@tonic-gate 				show_string(datap, linelen, datalen));
303*0Sstevel@tonic-gate 			    sofar += linelen;
304*0Sstevel@tonic-gate 			    datap += linelen;
305*0Sstevel@tonic-gate 			    if ((sofar + linelen) > datalen) {
306*0Sstevel@tonic-gate 				    linelen = datalen - sofar;
307*0Sstevel@tonic-gate 			    }
308*0Sstevel@tonic-gate 		    } while (sofar < datalen);
309*0Sstevel@tonic-gate 		    show_trailer();
310*0Sstevel@tonic-gate 		    break;
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 		case MODE_PRIVATE:
313*0Sstevel@tonic-gate 		    /* NTP Private Message, mode 7 */
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->rm_vn_mode -
316*0Sstevel@tonic-gate 			dlc_header, 1),
317*0Sstevel@tonic-gate 			"Version = %hu",
318*0Sstevel@tonic-gate 			INFO_VERSION(ntpp->rm_vn_mode));
319*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->rm_vn_mode -
320*0Sstevel@tonic-gate 			dlc_header, 1),
321*0Sstevel@tonic-gate 			"Mode    = %hu (%s)",
322*0Sstevel@tonic-gate 			INFO_MODE(ntpp->rm_vn_mode),
323*0Sstevel@tonic-gate 			show_mode(INFO_MODE(ntpp->rm_vn_mode)));
324*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->rm_vn_mode -
325*0Sstevel@tonic-gate 			dlc_header, 1),
326*0Sstevel@tonic-gate 			"Flags = 0x%02hx",
327*0Sstevel@tonic-gate 			ntpp->rm_vn_mode);
328*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->rm_vn_mode -
329*0Sstevel@tonic-gate 			dlc_header, 1),
330*0Sstevel@tonic-gate 			"      %s",
331*0Sstevel@tonic-gate 			getflag(ntpp->rm_vn_mode, RESP_BIT, "response",
332*0Sstevel@tonic-gate 			"request"));
333*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->rm_vn_mode -
334*0Sstevel@tonic-gate 			dlc_header, 1),
335*0Sstevel@tonic-gate 			"      %s",
336*0Sstevel@tonic-gate 			getflag(ntpp->rm_vn_mode, MORE_BIT, "more",
337*0Sstevel@tonic-gate 			"no more"));
338*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->auth_seq -
339*0Sstevel@tonic-gate 			dlc_header, 1),
340*0Sstevel@tonic-gate 			"Authentication and sequence = 0x%02x",
341*0Sstevel@tonic-gate 			ntpp->auth_seq);
342*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->auth_seq -
343*0Sstevel@tonic-gate 			dlc_header, 1),
344*0Sstevel@tonic-gate 			"      %s",
345*0Sstevel@tonic-gate 			getflag(ntpp->auth_seq, AUTH_BIT, "authenticated",
346*0Sstevel@tonic-gate 			"unauthenticated"));
347*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->auth_seq -
348*0Sstevel@tonic-gate 			dlc_header, 1),
349*0Sstevel@tonic-gate 			"      .xxx xxxx = %hu (sequence number)",
350*0Sstevel@tonic-gate 			INFO_SEQ(ntpp->auth_seq));
351*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->implementation -
352*0Sstevel@tonic-gate 			dlc_header, 1),
353*0Sstevel@tonic-gate 			"Implementation = %hu",
354*0Sstevel@tonic-gate 			ntpp->implementation);
355*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->request -
356*0Sstevel@tonic-gate 			dlc_header, 1),
357*0Sstevel@tonic-gate 			"Request = %hu",
358*0Sstevel@tonic-gate 			ntpp->request);
359*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->err_nitems -
360*0Sstevel@tonic-gate 			dlc_header, 1),
361*0Sstevel@tonic-gate 			"Error = %hu",
362*0Sstevel@tonic-gate 			INFO_ERR(ntpp->err_nitems));
363*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->err_nitems -
364*0Sstevel@tonic-gate 			dlc_header, 1),
365*0Sstevel@tonic-gate 			"Items = %hu",
366*0Sstevel@tonic-gate 			INFO_NITEMS(ntpp->err_nitems));
367*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntpp->mbz_itemsize -
368*0Sstevel@tonic-gate 			dlc_header, 1),
369*0Sstevel@tonic-gate 			"Item size = %hu",
370*0Sstevel@tonic-gate 			INFO_ITEMSIZE(ntpp->mbz_itemsize));
371*0Sstevel@tonic-gate 		    break;
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 		default:
374*0Sstevel@tonic-gate 		    /* Unknown mode */
375*0Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->li_vn_mode -
376*0Sstevel@tonic-gate 			dlc_header, 1),
377*0Sstevel@tonic-gate 			"Mode    = %hu (%s)",
378*0Sstevel@tonic-gate 			ntp->li_vn_mode & NTPMODEMASK,
379*0Sstevel@tonic-gate 			show_mode(ntp->li_vn_mode & NTPMODEMASK));
380*0Sstevel@tonic-gate 		    break;
381*0Sstevel@tonic-gate 		}
382*0Sstevel@tonic-gate 	}
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	return (fraglen);
385*0Sstevel@tonic-gate }
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate char *
388*0Sstevel@tonic-gate show_leap(int leap)
389*0Sstevel@tonic-gate {
390*0Sstevel@tonic-gate 	switch (leap) {
391*0Sstevel@tonic-gate 	case NO_WARNING: return ("OK");
392*0Sstevel@tonic-gate 	case PLUS_SEC:	return ("add a second (61 seconds)");
393*0Sstevel@tonic-gate 	case MINUS_SEC: return ("minus a second (59 seconds)");
394*0Sstevel@tonic-gate 	case ALARM:	return ("alarm condition (clock unsynchronized)");
395*0Sstevel@tonic-gate 	default:	return ("unknown");
396*0Sstevel@tonic-gate 	}
397*0Sstevel@tonic-gate }
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate char *
400*0Sstevel@tonic-gate show_mode(int mode)
401*0Sstevel@tonic-gate {
402*0Sstevel@tonic-gate 	switch (mode) {
403*0Sstevel@tonic-gate 	case MODE_UNSPEC:	return ("unspecified");
404*0Sstevel@tonic-gate 	case MODE_SYM_ACT:	return ("symmetric active");
405*0Sstevel@tonic-gate 	case MODE_SYM_PAS:	return ("symmetric passive");
406*0Sstevel@tonic-gate 	case MODE_CLIENT:	return ("client");
407*0Sstevel@tonic-gate 	case MODE_SERVER:	return ("server");
408*0Sstevel@tonic-gate 	case MODE_BROADCAST:	return ("broadcast");
409*0Sstevel@tonic-gate 	case MODE_CONTROL:	return ("control");
410*0Sstevel@tonic-gate 	case MODE_PRIVATE:	return ("private");
411*0Sstevel@tonic-gate 	default:		return ("unknown");
412*0Sstevel@tonic-gate 	}
413*0Sstevel@tonic-gate }
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate char *
416*0Sstevel@tonic-gate show_ref(int mode, ulong_t refid)
417*0Sstevel@tonic-gate {
418*0Sstevel@tonic-gate 	static char buff[MAXHOSTNAMELEN + 32];
419*0Sstevel@tonic-gate 	struct in_addr host;
420*0Sstevel@tonic-gate 	extern char *inet_ntoa();
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	switch (mode) {
423*0Sstevel@tonic-gate 	case 0:
424*0Sstevel@tonic-gate 	case 1:
425*0Sstevel@tonic-gate 		(void) strncpy(buff, (char *)&refid, 4);
426*0Sstevel@tonic-gate 		buff[4] = '\0';
427*0Sstevel@tonic-gate 		break;
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	default:
430*0Sstevel@tonic-gate 		host.s_addr = refid;
431*0Sstevel@tonic-gate 		(void) sprintf(buff, "%s (%s)",
432*0Sstevel@tonic-gate 		    inet_ntoa(host),
433*0Sstevel@tonic-gate 		    addrtoname(AF_INET, &host));
434*0Sstevel@tonic-gate 		break;
435*0Sstevel@tonic-gate 	}
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	return (buff);
438*0Sstevel@tonic-gate }
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate /*
441*0Sstevel@tonic-gate  *  Here we have to worry about the high order bit being signed
442*0Sstevel@tonic-gate  */
443*0Sstevel@tonic-gate double
444*0Sstevel@tonic-gate s_fixed_to_double(struct s_fixedpt *t)
445*0Sstevel@tonic-gate {
446*0Sstevel@tonic-gate 	double a;
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 	if (ntohs(t->int_part) & 0x8000) {
449*0Sstevel@tonic-gate 		a = ntohs((int)(~t->fraction) & 0xFFFF);
450*0Sstevel@tonic-gate 		a = a / 65536.0;	/* shift dec point over by 16 bits */
451*0Sstevel@tonic-gate 		a +=  ntohs((int)(~t->int_part) & 0xFFFF);
452*0Sstevel@tonic-gate 		a = -a;
453*0Sstevel@tonic-gate 	} else {
454*0Sstevel@tonic-gate 		a = ntohs(t->fraction);
455*0Sstevel@tonic-gate 		a = a / 65536.0;	/* shift dec point over by 16 bits */
456*0Sstevel@tonic-gate 		a += ntohs(t->int_part);
457*0Sstevel@tonic-gate 	}
458*0Sstevel@tonic-gate 	return (a);
459*0Sstevel@tonic-gate }
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate /*
462*0Sstevel@tonic-gate  * Consistent with RFC-3339, ISO 8601.
463*0Sstevel@tonic-gate  */
464*0Sstevel@tonic-gate char *
465*0Sstevel@tonic-gate iso_date_time(time_t input_time)
466*0Sstevel@tonic-gate {
467*0Sstevel@tonic-gate 	struct tm	*time_parts;
468*0Sstevel@tonic-gate 	static char	tbuf[sizeof ("yyyy-mm-dd hh:mm:ss")];
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	time_parts = localtime(&input_time);
471*0Sstevel@tonic-gate 	(void) strftime(tbuf, sizeof (tbuf), "%Y-%m-%d %H:%M:%S", time_parts);
472*0Sstevel@tonic-gate 	return (tbuf);
473*0Sstevel@tonic-gate }
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate /*
476*0Sstevel@tonic-gate  * The base of NTP timestamps is 1900-01-01 00:00:00.00000
477*0Sstevel@tonic-gate  */
478*0Sstevel@tonic-gate char *
479*0Sstevel@tonic-gate show_time(struct l_fixedpt pkt_time)
480*0Sstevel@tonic-gate {
481*0Sstevel@tonic-gate 	struct l_fixedpt net_time;
482*0Sstevel@tonic-gate 	unsigned long	fracsec;
483*0Sstevel@tonic-gate 	static char	buff[32];
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	if (pkt_time.int_part == 0) {
486*0Sstevel@tonic-gate 		buff[0] = '\0';
487*0Sstevel@tonic-gate 		return (buff);
488*0Sstevel@tonic-gate 	}
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	net_time.int_part = ntohl(pkt_time.int_part) - JAN_1970;
491*0Sstevel@tonic-gate 	net_time.fraction = ntohl(pkt_time.fraction);
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	fracsec = net_time.fraction / 42949;	/* fract / (2**32/10**6) */
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	(void) strlcpy(buff, iso_date_time(net_time.int_part), sizeof (buff));
496*0Sstevel@tonic-gate 	(void) snprintf(buff, sizeof (buff), "%s.%05lu", buff, fracsec);
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate 	return (buff);
499*0Sstevel@tonic-gate }
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate char *
502*0Sstevel@tonic-gate show_operation(int op)
503*0Sstevel@tonic-gate {
504*0Sstevel@tonic-gate 	switch (op) {
505*0Sstevel@tonic-gate 	case CTL_OP_UNSPEC:	return ("unspecified");
506*0Sstevel@tonic-gate 	case CTL_OP_READSTAT:	return ("read stats");
507*0Sstevel@tonic-gate 	case CTL_OP_READVAR:	return ("read var");
508*0Sstevel@tonic-gate 	case CTL_OP_WRITEVAR:	return ("write var");
509*0Sstevel@tonic-gate 	case CTL_OP_READCLOCK:	return ("read clock");
510*0Sstevel@tonic-gate 	case CTL_OP_WRITECLOCK: return ("write clock");
511*0Sstevel@tonic-gate 	case CTL_OP_SETTRAP:	return ("set trap");
512*0Sstevel@tonic-gate 	case CTL_OP_ASYNCMSG:	return ("async msg");
513*0Sstevel@tonic-gate 	case CTL_OP_UNSETTRAP:	return ("unset trap");
514*0Sstevel@tonic-gate 	default:		return ("unknown");
515*0Sstevel@tonic-gate 	}
516*0Sstevel@tonic-gate }
517