17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
232e3b6467Skcpoon  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <fcntl.h>
287c478bd9Sstevel@tonic-gate #include <sys/socket.h>
297c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
307c478bd9Sstevel@tonic-gate #include <netinet/in.h>
317c478bd9Sstevel@tonic-gate #include <netdb.h>
327c478bd9Sstevel@tonic-gate #include <stdio.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <tzfile.h>
357c478bd9Sstevel@tonic-gate #include "snoop.h"
367c478bd9Sstevel@tonic-gate #include "ntp.h"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * In verbose mode, how many octets of the control-mode data payload
407c478bd9Sstevel@tonic-gate  * are displayed per line of output.  The value 64 fits well on an
417c478bd9Sstevel@tonic-gate  * 80-column screen and, as a power of 2, is easily correlated to
427c478bd9Sstevel@tonic-gate  * hexadecimal output.
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate #define	OCTETS_PER_LINE	64
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate extern char *dlc_header;
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static	char	*show_leap(int);
497c478bd9Sstevel@tonic-gate static	char	*show_mode(int);
507c478bd9Sstevel@tonic-gate static	char	*show_ref(int, ulong_t);
517c478bd9Sstevel@tonic-gate static	char	*show_time(struct l_fixedpt);
527c478bd9Sstevel@tonic-gate static	double	s_fixed_to_double(struct s_fixedpt *);
537c478bd9Sstevel@tonic-gate static	char	*iso_date_time(time_t);
547c478bd9Sstevel@tonic-gate static	char	*show_operation(int);
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate int
interpret_ntp(int flags,struct ntpdata * ntp_pkt,int fraglen)577c478bd9Sstevel@tonic-gate interpret_ntp(int flags, struct ntpdata *ntp_pkt, int fraglen)
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	unsigned int	i, j, macbytes;
607c478bd9Sstevel@tonic-gate 	unsigned int	proto_version;
617c478bd9Sstevel@tonic-gate 	unsigned int	datalen;
627c478bd9Sstevel@tonic-gate 	unsigned int	linelen = OCTETS_PER_LINE;
637c478bd9Sstevel@tonic-gate 	unsigned int	sofar = 0;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	char	*datap;
667c478bd9Sstevel@tonic-gate 	char	hbuf[2 * MAC_OCTETS_MAX + 1];
677c478bd9Sstevel@tonic-gate 	static	char *hexstr = "0123456789ABCDEF";
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	union	ntp_pkt_buf {
707c478bd9Sstevel@tonic-gate 		struct	ntpdata ntp_msg;
717c478bd9Sstevel@tonic-gate 		union ntpc_buf {
727c478bd9Sstevel@tonic-gate 			struct	ntp_control chdr;
737c478bd9Sstevel@tonic-gate 			uchar_t	data2[NTPC_DATA_MAXLEN - 1];
747c478bd9Sstevel@tonic-gate 		} ntpc_msg;
757c478bd9Sstevel@tonic-gate 		union ntpp_buf {
767c478bd9Sstevel@tonic-gate 			struct	ntp_private phdr;
777c478bd9Sstevel@tonic-gate 			uchar_t	data2[1];
787c478bd9Sstevel@tonic-gate 		} ntpp_msg;
797c478bd9Sstevel@tonic-gate 	} fragbuf;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	struct	ntpdata		*ntp = &fragbuf.ntp_msg;
827c478bd9Sstevel@tonic-gate 	struct	ntp_control	*ntpc = (struct ntp_control *)&fragbuf.ntpc_msg;
837c478bd9Sstevel@tonic-gate 	struct	ntp_private	*ntpp = (struct ntp_private *)&fragbuf.ntpp_msg;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	/*
867c478bd9Sstevel@tonic-gate 	 * Copying packet contents into a local buffer avoids
877c478bd9Sstevel@tonic-gate 	 * problems of interpretation if the packet is truncated.
887c478bd9Sstevel@tonic-gate 	 */
897c478bd9Sstevel@tonic-gate 	(void) memcpy(&fragbuf, ntp_pkt, MIN(sizeof (fragbuf), fraglen));
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
927c478bd9Sstevel@tonic-gate 		switch (ntp->li_vn_mode & NTPMODEMASK) {
937c478bd9Sstevel@tonic-gate 		case MODE_SYM_ACT:
947c478bd9Sstevel@tonic-gate 		case MODE_SYM_PAS:
957c478bd9Sstevel@tonic-gate 		case MODE_CLIENT:
967c478bd9Sstevel@tonic-gate 		case MODE_SERVER:
977c478bd9Sstevel@tonic-gate 		case MODE_BROADCAST:
987c478bd9Sstevel@tonic-gate 		    (void) sprintf(get_sum_line(),
997c478bd9Sstevel@tonic-gate 			"NTP  %s [st=%hd] (%s)",
1007c478bd9Sstevel@tonic-gate 			show_mode(ntp->li_vn_mode & NTPMODEMASK),
1017c478bd9Sstevel@tonic-gate 			ntp->stratum,
1027c478bd9Sstevel@tonic-gate 			show_time(ntp->xmt));
1037c478bd9Sstevel@tonic-gate 		    break;
1047c478bd9Sstevel@tonic-gate 		case MODE_CONTROL:
1057c478bd9Sstevel@tonic-gate 		    (void) sprintf(get_sum_line(),
1067c478bd9Sstevel@tonic-gate 			"NTP  %s "
1077c478bd9Sstevel@tonic-gate 			"(Flags/op=0x%02x Seq=%hu Status=0x%04hx Assoc=%hu)",
1087c478bd9Sstevel@tonic-gate 			show_mode(ntpc->li_vn_mode & NTPMODEMASK),
1097c478bd9Sstevel@tonic-gate 			ntpc->r_m_e_op,
1107c478bd9Sstevel@tonic-gate 			ntohs(ntpc->sequence),
1117c478bd9Sstevel@tonic-gate 			ntohs(ntpc->status),
1127c478bd9Sstevel@tonic-gate 			ntohs(ntpc->associd));
1137c478bd9Sstevel@tonic-gate 		    break;
1147c478bd9Sstevel@tonic-gate 		default:
1157c478bd9Sstevel@tonic-gate 		    (void) sprintf(get_sum_line(),
1167c478bd9Sstevel@tonic-gate 			"NTP  %s",
1177c478bd9Sstevel@tonic-gate 			show_mode(ntpp->rm_vn_mode & NTPMODEMASK));
1187c478bd9Sstevel@tonic-gate 		    break;
1197c478bd9Sstevel@tonic-gate 		}
1207c478bd9Sstevel@tonic-gate 	}
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	proto_version = (ntp->li_vn_mode & VERSIONMASK) >> 3;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
1257c478bd9Sstevel@tonic-gate 		show_header("NTP:  ", "Network Time Protocol", fraglen);
1267c478bd9Sstevel@tonic-gate 		show_space();
1277c478bd9Sstevel@tonic-gate 		switch (ntp->li_vn_mode & NTPMODEMASK) {
1287c478bd9Sstevel@tonic-gate 		case MODE_SYM_ACT:
1297c478bd9Sstevel@tonic-gate 		case MODE_SYM_PAS:
1307c478bd9Sstevel@tonic-gate 		case MODE_CLIENT:
1317c478bd9Sstevel@tonic-gate 		case MODE_SERVER:
1327c478bd9Sstevel@tonic-gate 		case MODE_BROADCAST:
1332e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
1347c478bd9Sstevel@tonic-gate 			dlc_header, 1),
1357c478bd9Sstevel@tonic-gate 			"Leap    = 0x%x (%s)",
1367c478bd9Sstevel@tonic-gate 			(int)(ntp->li_vn_mode & LEAPMASK) >> 6,
1377c478bd9Sstevel@tonic-gate 			show_leap(ntp->li_vn_mode & LEAPMASK));
1382e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
1397c478bd9Sstevel@tonic-gate 			dlc_header, 1),
1407c478bd9Sstevel@tonic-gate 			"Version = %lu", proto_version);
1412e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
1427c478bd9Sstevel@tonic-gate 			dlc_header, 1),
1437c478bd9Sstevel@tonic-gate 			"Mode    = %hu (%s)",
1447c478bd9Sstevel@tonic-gate 			ntp->li_vn_mode & NTPMODEMASK,
1457c478bd9Sstevel@tonic-gate 			show_mode(ntp->li_vn_mode & NTPMODEMASK));
1462e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->stratum -
1477c478bd9Sstevel@tonic-gate 			dlc_header, 1),
1487c478bd9Sstevel@tonic-gate 			"Stratum = %d (%s)",
1497c478bd9Sstevel@tonic-gate 			ntp->stratum,
1507c478bd9Sstevel@tonic-gate 			ntp->stratum == 0 ? "unspecified" :
1517c478bd9Sstevel@tonic-gate 			ntp->stratum == 1 ? "primary reference" :
1527c478bd9Sstevel@tonic-gate 			"secondary reference");
1532e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->ppoll -
1542e3b6467Skcpoon 			dlc_header, 1),	"Poll    = %hu", ntp->ppoll);
1552e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->precision -
1567c478bd9Sstevel@tonic-gate 			dlc_header, 1),
1577c478bd9Sstevel@tonic-gate 			"Precision = %d seconds",
1587c478bd9Sstevel@tonic-gate 			ntp->precision);
1592e3b6467Skcpoon 		    (void) sprintf(get_line(
1602e3b6467Skcpoon 			(char *)(uintptr_t)ntp->distance.int_part -
1617c478bd9Sstevel@tonic-gate 			dlc_header, 1),
1627c478bd9Sstevel@tonic-gate 			"Synchronizing distance   = 0x%04x.%04x  (%f)",
1637c478bd9Sstevel@tonic-gate 			ntohs(ntp->distance.int_part),
1647c478bd9Sstevel@tonic-gate 			ntohs(ntp->distance.fraction),
1657c478bd9Sstevel@tonic-gate 			s_fixed_to_double(&ntp->distance));
1662e3b6467Skcpoon 		    (void) sprintf(get_line(
1672e3b6467Skcpoon 			(char *)(uintptr_t)ntp->dispersion.int_part -
1687c478bd9Sstevel@tonic-gate 			dlc_header, 1),
1697c478bd9Sstevel@tonic-gate 			"Synchronizing dispersion = 0x%04x.%04x  (%f)",
1707c478bd9Sstevel@tonic-gate 			ntohs(ntp->dispersion.int_part),
1717c478bd9Sstevel@tonic-gate 			ntohs(ntp->dispersion.fraction),
1727c478bd9Sstevel@tonic-gate 			s_fixed_to_double(&ntp->dispersion));
1732e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->refid -
1742e3b6467Skcpoon 			dlc_header, 1), "Reference clock = %s",
1757c478bd9Sstevel@tonic-gate 			show_ref(ntp->stratum, ntp->refid));
1767c478bd9Sstevel@tonic-gate 
1772e3b6467Skcpoon 		    (void) sprintf(get_line(
1782e3b6467Skcpoon 			(char *)(uintptr_t)ntp->reftime.int_part - dlc_header,
1792e3b6467Skcpoon 			1), "Reference time = 0x%08lx.%08lx (%s)",
1807c478bd9Sstevel@tonic-gate 			ntohl(ntp->reftime.int_part),
1817c478bd9Sstevel@tonic-gate 			ntohl(ntp->reftime.fraction),
1827c478bd9Sstevel@tonic-gate 			show_time(ntp->reftime));
1837c478bd9Sstevel@tonic-gate 
1842e3b6467Skcpoon 		    (void) sprintf(get_line(
1852e3b6467Skcpoon 			(char *)(uintptr_t)ntp->org.int_part - dlc_header, 1),
1867c478bd9Sstevel@tonic-gate 			"Originate time = 0x%08lx.%08lx (%s)",
1877c478bd9Sstevel@tonic-gate 			ntohl(ntp->org.int_part),
1887c478bd9Sstevel@tonic-gate 			ntohl(ntp->org.fraction),
1897c478bd9Sstevel@tonic-gate 			show_time(ntp->org));
1907c478bd9Sstevel@tonic-gate 
1912e3b6467Skcpoon 		    (void) sprintf(get_line(
1922e3b6467Skcpoon 			(char *)(uintptr_t)ntp->rec.int_part - dlc_header, 1),
1937c478bd9Sstevel@tonic-gate 			"Receive   time = 0x%08lx.%08lx (%s)",
1947c478bd9Sstevel@tonic-gate 			ntohl(ntp->rec.int_part),
1957c478bd9Sstevel@tonic-gate 			ntohl(ntp->rec.fraction),
1967c478bd9Sstevel@tonic-gate 			show_time(ntp->rec));
1977c478bd9Sstevel@tonic-gate 
1982e3b6467Skcpoon 		    (void) sprintf(get_line(
1992e3b6467Skcpoon 			(char *)(uintptr_t)ntp->xmt.int_part - dlc_header, 1),
2007c478bd9Sstevel@tonic-gate 			"Transmit  time = 0x%08lx.%08lx (%s)",
2017c478bd9Sstevel@tonic-gate 			ntohl(ntp->xmt.int_part),
2027c478bd9Sstevel@tonic-gate 			ntohl(ntp->xmt.fraction),
2037c478bd9Sstevel@tonic-gate 			show_time(ntp->xmt));
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 		    if (proto_version > 3 ||
2067c478bd9Sstevel@tonic-gate 			fraglen < (LEN_PKT_NOMAC + MAC_OCTETS_MIN)) {
2077c478bd9Sstevel@tonic-gate 				/*
2087c478bd9Sstevel@tonic-gate 				 * A newer protocol version we can't parse,
2097c478bd9Sstevel@tonic-gate 				 * or v3 packet with no valid authentication.
2107c478bd9Sstevel@tonic-gate 				 */
2117c478bd9Sstevel@tonic-gate 				break;
2127c478bd9Sstevel@tonic-gate 		    }
2137c478bd9Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->keyid -
2147c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2157c478bd9Sstevel@tonic-gate 			"Key ID  = %8lu", ntohl(ntp->keyid));
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 		    macbytes = fraglen - (LEN_PKT_NOMAC + sizeof (uint32_t));
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		    for (i = 0, j = 0; i < macbytes; i++) {
2207c478bd9Sstevel@tonic-gate 			    hbuf[j++] = hexstr[ntp->mac[i] >> 4 & 0x0f];
2217c478bd9Sstevel@tonic-gate 			    hbuf[j++] = hexstr[ntp->mac[i] & 0x0f];
2227c478bd9Sstevel@tonic-gate 		    }
2237c478bd9Sstevel@tonic-gate 		    hbuf[j] = '\0';
2247c478bd9Sstevel@tonic-gate 		    (void) sprintf(get_line((char *)ntp->mac -
2257c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2267c478bd9Sstevel@tonic-gate 			"Authentication code = %s", hbuf);
2277c478bd9Sstevel@tonic-gate 		    break;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 		case MODE_CONTROL:
2307c478bd9Sstevel@tonic-gate 		    /* NTP Control Message, mode 6 */
2317c478bd9Sstevel@tonic-gate 
2322e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
2337c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2347c478bd9Sstevel@tonic-gate 			"Leap    = 0x%x (%s)",
2357c478bd9Sstevel@tonic-gate 			(int)(ntp->li_vn_mode & LEAPMASK) >> 6,
2367c478bd9Sstevel@tonic-gate 			show_leap(ntp->li_vn_mode & LEAPMASK));
2372e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
2387c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2397c478bd9Sstevel@tonic-gate 			"Version = %lu", proto_version);
2402e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
2417c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2427c478bd9Sstevel@tonic-gate 			"Mode    = %hu (%s)",
2437c478bd9Sstevel@tonic-gate 			ntp->li_vn_mode & NTPMODEMASK,
2447c478bd9Sstevel@tonic-gate 			show_mode(ntp->li_vn_mode & NTPMODEMASK));
2452e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2467c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2477c478bd9Sstevel@tonic-gate 			"Flags and operation code = 0x%02x",
2487c478bd9Sstevel@tonic-gate 			ntpc->r_m_e_op);
2492e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2507c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2517c478bd9Sstevel@tonic-gate 			"      %s",
2527c478bd9Sstevel@tonic-gate 			getflag(ntpc->r_m_e_op, CTL_RESPONSE, "response",
2537c478bd9Sstevel@tonic-gate 			"request"));
2542e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2557c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2567c478bd9Sstevel@tonic-gate 			"      %s",
2577c478bd9Sstevel@tonic-gate 			getflag(ntpc->r_m_e_op, CTL_ERROR, "error",
2587c478bd9Sstevel@tonic-gate 			"success"));
2592e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2607c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2617c478bd9Sstevel@tonic-gate 			"      %s",
2627c478bd9Sstevel@tonic-gate 			getflag(ntpc->r_m_e_op, CTL_MORE, "more",
2637c478bd9Sstevel@tonic-gate 			"no more"));
2642e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2657c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2667c478bd9Sstevel@tonic-gate 			"      ...x xxxx = %hd (%s)",
2677c478bd9Sstevel@tonic-gate 			ntpc->r_m_e_op & CTL_OP_MASK,
2687c478bd9Sstevel@tonic-gate 			show_operation(ntpc->r_m_e_op & CTL_OP_MASK));
2692e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpc->sequence -
2707c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2717c478bd9Sstevel@tonic-gate 			"Sequence = %hu",
2727c478bd9Sstevel@tonic-gate 			ntohs(ntpc->sequence));
2732e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpc->status -
2747c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2757c478bd9Sstevel@tonic-gate 			"Status = 0x%04hx",
2767c478bd9Sstevel@tonic-gate 			ntohs(ntpc->status));
2772e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpc->associd -
2787c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2797c478bd9Sstevel@tonic-gate 			"Assoc ID = %hu",
2807c478bd9Sstevel@tonic-gate 			ntohs(ntpc->associd));
2812e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpc->offset -
2827c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2837c478bd9Sstevel@tonic-gate 			"Data offset = %hu",
2847c478bd9Sstevel@tonic-gate 			ntohs(ntpc->offset));
2852e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpc->count -
2867c478bd9Sstevel@tonic-gate 			dlc_header, 1),
2877c478bd9Sstevel@tonic-gate 			"Data bytes = %hu",
2887c478bd9Sstevel@tonic-gate 			ntohs(ntpc->count));
2897c478bd9Sstevel@tonic-gate 		    datalen = ntohs(ntpc->count);
2907c478bd9Sstevel@tonic-gate 		    if (datalen == 0) {
2917c478bd9Sstevel@tonic-gate 			    break;
2927c478bd9Sstevel@tonic-gate 		    } else if (datalen > NTPC_DATA_MAXLEN) {
2937c478bd9Sstevel@tonic-gate 			    datalen = NTPC_DATA_MAXLEN;
2947c478bd9Sstevel@tonic-gate 		    }
2957c478bd9Sstevel@tonic-gate 		    show_space();
2967c478bd9Sstevel@tonic-gate 		    datap = (char *)ntpc->data;
2977c478bd9Sstevel@tonic-gate 		    do {
2987c478bd9Sstevel@tonic-gate 			    (void) sprintf(get_line(datap -
2997c478bd9Sstevel@tonic-gate 				dlc_header, 1),
3007c478bd9Sstevel@tonic-gate 				"\"%s\"",
3017c478bd9Sstevel@tonic-gate 				show_string(datap, linelen, datalen));
3027c478bd9Sstevel@tonic-gate 			    sofar += linelen;
3037c478bd9Sstevel@tonic-gate 			    datap += linelen;
3047c478bd9Sstevel@tonic-gate 			    if ((sofar + linelen) > datalen) {
3057c478bd9Sstevel@tonic-gate 				    linelen = datalen - sofar;
3067c478bd9Sstevel@tonic-gate 			    }
3077c478bd9Sstevel@tonic-gate 		    } while (sofar < datalen);
3087c478bd9Sstevel@tonic-gate 		    show_trailer();
3097c478bd9Sstevel@tonic-gate 		    break;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 		case MODE_PRIVATE:
3127c478bd9Sstevel@tonic-gate 		    /* NTP Private Message, mode 7 */
3137c478bd9Sstevel@tonic-gate 
3142e3b6467Skcpoon 		    (void) sprintf(get_line(
3152e3b6467Skcpoon 			(char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
3162e3b6467Skcpoon 			"Version = %hu", INFO_VERSION(ntpp->rm_vn_mode));
3172e3b6467Skcpoon 		    (void) sprintf(get_line(
3182e3b6467Skcpoon 			(char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
3192e3b6467Skcpoon 			"Mode    = %hu (%s)", INFO_MODE(ntpp->rm_vn_mode),
3207c478bd9Sstevel@tonic-gate 			show_mode(INFO_MODE(ntpp->rm_vn_mode)));
3212e3b6467Skcpoon 		    (void) sprintf(get_line(
3222e3b6467Skcpoon 			(char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
3232e3b6467Skcpoon 			"Flags = 0x%02hx", ntpp->rm_vn_mode);
3242e3b6467Skcpoon 		    (void) sprintf(get_line(
3252e3b6467Skcpoon 			(char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
3267c478bd9Sstevel@tonic-gate 			"      %s",
3277c478bd9Sstevel@tonic-gate 			getflag(ntpp->rm_vn_mode, RESP_BIT, "response",
3287c478bd9Sstevel@tonic-gate 			"request"));
3292e3b6467Skcpoon 		    (void) sprintf(get_line(
3302e3b6467Skcpoon 			(char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
3317c478bd9Sstevel@tonic-gate 			"      %s",
3322e3b6467Skcpoon 			getflag(ntpp->rm_vn_mode, MORE_BIT, "more", "no more"));
3332e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq -
3347c478bd9Sstevel@tonic-gate 			dlc_header, 1),
3352e3b6467Skcpoon 			"Authentication and sequence = 0x%02x", ntpp->auth_seq);
3362e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq -
3377c478bd9Sstevel@tonic-gate 			dlc_header, 1),
3387c478bd9Sstevel@tonic-gate 			"      %s",
3397c478bd9Sstevel@tonic-gate 			getflag(ntpp->auth_seq, AUTH_BIT, "authenticated",
3407c478bd9Sstevel@tonic-gate 			"unauthenticated"));
3412e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq -
3427c478bd9Sstevel@tonic-gate 			dlc_header, 1),
3437c478bd9Sstevel@tonic-gate 			"      .xxx xxxx = %hu (sequence number)",
3447c478bd9Sstevel@tonic-gate 			INFO_SEQ(ntpp->auth_seq));
3452e3b6467Skcpoon 		    (void) sprintf(get_line(
3462e3b6467Skcpoon 			(char *)(uintptr_t)ntpp->implementation - dlc_header,
3472e3b6467Skcpoon 			1), "Implementation = %hu", ntpp->implementation);
3482e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntpp->request -
3492e3b6467Skcpoon 			dlc_header, 1), "Request = %hu", ntpp->request);
3502e3b6467Skcpoon 		    (void) sprintf(get_line(
3512e3b6467Skcpoon 			(char *)(uintptr_t)ntpp->err_nitems - dlc_header, 1),
3522e3b6467Skcpoon 			"Error = %hu", INFO_ERR(ntpp->err_nitems));
3532e3b6467Skcpoon 		    (void) sprintf(get_line(
3542e3b6467Skcpoon 			(char *)(uintptr_t)ntpp->err_nitems - dlc_header, 1),
3552e3b6467Skcpoon 			"Items = %hu", INFO_NITEMS(ntpp->err_nitems));
3562e3b6467Skcpoon 		    (void) sprintf(get_line(
3572e3b6467Skcpoon 			(char *)(uintptr_t)ntpp->mbz_itemsize - dlc_header, 1),
3582e3b6467Skcpoon 			"Item size = %hu", INFO_ITEMSIZE(ntpp->mbz_itemsize));
3597c478bd9Sstevel@tonic-gate 		    break;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 		default:
3627c478bd9Sstevel@tonic-gate 		    /* Unknown mode */
3632e3b6467Skcpoon 		    (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
3642e3b6467Skcpoon 			dlc_header, 1),	"Mode    = %hu (%s)",
3657c478bd9Sstevel@tonic-gate 			ntp->li_vn_mode & NTPMODEMASK,
3667c478bd9Sstevel@tonic-gate 			show_mode(ntp->li_vn_mode & NTPMODEMASK));
3677c478bd9Sstevel@tonic-gate 		    break;
3687c478bd9Sstevel@tonic-gate 		}
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	return (fraglen);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate char *
show_leap(int leap)3757c478bd9Sstevel@tonic-gate show_leap(int leap)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate 	switch (leap) {
3787c478bd9Sstevel@tonic-gate 	case NO_WARNING: return ("OK");
3797c478bd9Sstevel@tonic-gate 	case PLUS_SEC:	return ("add a second (61 seconds)");
3807c478bd9Sstevel@tonic-gate 	case MINUS_SEC: return ("minus a second (59 seconds)");
3817c478bd9Sstevel@tonic-gate 	case ALARM:	return ("alarm condition (clock unsynchronized)");
3827c478bd9Sstevel@tonic-gate 	default:	return ("unknown");
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate char *
show_mode(int mode)3877c478bd9Sstevel@tonic-gate show_mode(int mode)
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate 	switch (mode) {
3907c478bd9Sstevel@tonic-gate 	case MODE_UNSPEC:	return ("unspecified");
3917c478bd9Sstevel@tonic-gate 	case MODE_SYM_ACT:	return ("symmetric active");
3927c478bd9Sstevel@tonic-gate 	case MODE_SYM_PAS:	return ("symmetric passive");
3937c478bd9Sstevel@tonic-gate 	case MODE_CLIENT:	return ("client");
3947c478bd9Sstevel@tonic-gate 	case MODE_SERVER:	return ("server");
3957c478bd9Sstevel@tonic-gate 	case MODE_BROADCAST:	return ("broadcast");
3967c478bd9Sstevel@tonic-gate 	case MODE_CONTROL:	return ("control");
3977c478bd9Sstevel@tonic-gate 	case MODE_PRIVATE:	return ("private");
3987c478bd9Sstevel@tonic-gate 	default:		return ("unknown");
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate char *
show_ref(int mode,ulong_t refid)4037c478bd9Sstevel@tonic-gate show_ref(int mode, ulong_t refid)
4047c478bd9Sstevel@tonic-gate {
4057c478bd9Sstevel@tonic-gate 	static char buff[MAXHOSTNAMELEN + 32];
4067c478bd9Sstevel@tonic-gate 	struct in_addr host;
4077c478bd9Sstevel@tonic-gate 	extern char *inet_ntoa();
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	switch (mode) {
4107c478bd9Sstevel@tonic-gate 	case 0:
4117c478bd9Sstevel@tonic-gate 	case 1:
4127c478bd9Sstevel@tonic-gate 		(void) strncpy(buff, (char *)&refid, 4);
4137c478bd9Sstevel@tonic-gate 		buff[4] = '\0';
4147c478bd9Sstevel@tonic-gate 		break;
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	default:
4177c478bd9Sstevel@tonic-gate 		host.s_addr = refid;
4187c478bd9Sstevel@tonic-gate 		(void) sprintf(buff, "%s (%s)",
4197c478bd9Sstevel@tonic-gate 		    inet_ntoa(host),
4207c478bd9Sstevel@tonic-gate 		    addrtoname(AF_INET, &host));
4217c478bd9Sstevel@tonic-gate 		break;
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	return (buff);
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate /*
4287c478bd9Sstevel@tonic-gate  *  Here we have to worry about the high order bit being signed
4297c478bd9Sstevel@tonic-gate  */
4307c478bd9Sstevel@tonic-gate double
s_fixed_to_double(struct s_fixedpt * t)4317c478bd9Sstevel@tonic-gate s_fixed_to_double(struct s_fixedpt *t)
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate 	double a;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if (ntohs(t->int_part) & 0x8000) {
4367c478bd9Sstevel@tonic-gate 		a = ntohs((int)(~t->fraction) & 0xFFFF);
4377c478bd9Sstevel@tonic-gate 		a = a / 65536.0;	/* shift dec point over by 16 bits */
4387c478bd9Sstevel@tonic-gate 		a +=  ntohs((int)(~t->int_part) & 0xFFFF);
4397c478bd9Sstevel@tonic-gate 		a = -a;
4407c478bd9Sstevel@tonic-gate 	} else {
4417c478bd9Sstevel@tonic-gate 		a = ntohs(t->fraction);
4427c478bd9Sstevel@tonic-gate 		a = a / 65536.0;	/* shift dec point over by 16 bits */
4437c478bd9Sstevel@tonic-gate 		a += ntohs(t->int_part);
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate 	return (a);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate  * Consistent with RFC-3339, ISO 8601.
4507c478bd9Sstevel@tonic-gate  */
4517c478bd9Sstevel@tonic-gate char *
iso_date_time(time_t input_time)4527c478bd9Sstevel@tonic-gate iso_date_time(time_t input_time)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	struct tm	*time_parts;
4557c478bd9Sstevel@tonic-gate 	static char	tbuf[sizeof ("yyyy-mm-dd hh:mm:ss")];
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	time_parts = localtime(&input_time);
4587c478bd9Sstevel@tonic-gate 	(void) strftime(tbuf, sizeof (tbuf), "%Y-%m-%d %H:%M:%S", time_parts);
4597c478bd9Sstevel@tonic-gate 	return (tbuf);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate /*
4637c478bd9Sstevel@tonic-gate  * The base of NTP timestamps is 1900-01-01 00:00:00.00000
4647c478bd9Sstevel@tonic-gate  */
4657c478bd9Sstevel@tonic-gate char *
show_time(struct l_fixedpt pkt_time)4667c478bd9Sstevel@tonic-gate show_time(struct l_fixedpt pkt_time)
4677c478bd9Sstevel@tonic-gate {
4687c478bd9Sstevel@tonic-gate 	struct l_fixedpt net_time;
4697c478bd9Sstevel@tonic-gate 	unsigned long	fracsec;
4707c478bd9Sstevel@tonic-gate 	static char	buff[32];
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	if (pkt_time.int_part == 0) {
4737c478bd9Sstevel@tonic-gate 		buff[0] = '\0';
4747c478bd9Sstevel@tonic-gate 		return (buff);
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	net_time.int_part = ntohl(pkt_time.int_part) - JAN_1970;
4787c478bd9Sstevel@tonic-gate 	net_time.fraction = ntohl(pkt_time.fraction);
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	fracsec = net_time.fraction / 42949;	/* fract / (2**32/10**6) */
4817c478bd9Sstevel@tonic-gate 
482*36ca3d63SToomas Soome 	(void) snprintf(buff, sizeof (buff), "%s.%05lu",
483*36ca3d63SToomas Soome 	    iso_date_time(net_time.int_part), fracsec);
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	return (buff);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate char *
show_operation(int op)4897c478bd9Sstevel@tonic-gate show_operation(int op)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	switch (op) {
4927c478bd9Sstevel@tonic-gate 	case CTL_OP_UNSPEC:	return ("unspecified");
4937c478bd9Sstevel@tonic-gate 	case CTL_OP_READSTAT:	return ("read stats");
4947c478bd9Sstevel@tonic-gate 	case CTL_OP_READVAR:	return ("read var");
4957c478bd9Sstevel@tonic-gate 	case CTL_OP_WRITEVAR:	return ("write var");
4967c478bd9Sstevel@tonic-gate 	case CTL_OP_READCLOCK:	return ("read clock");
4977c478bd9Sstevel@tonic-gate 	case CTL_OP_WRITECLOCK: return ("write clock");
4987c478bd9Sstevel@tonic-gate 	case CTL_OP_SETTRAP:	return ("set trap");
4997c478bd9Sstevel@tonic-gate 	case CTL_OP_ASYNCMSG:	return ("async msg");
5007c478bd9Sstevel@tonic-gate 	case CTL_OP_UNSETTRAP:	return ("unset trap");
5017c478bd9Sstevel@tonic-gate 	default:		return ("unknown");
5027c478bd9Sstevel@tonic-gate 	}
5037c478bd9Sstevel@tonic-gate }
504