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 /*
23*2e3b6467Skcpoon * 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 #pragma ident "%Z%%M% %I% %E% SMI"
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include <fcntl.h>
307c478bd9Sstevel@tonic-gate #include <sys/socket.h>
317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
327c478bd9Sstevel@tonic-gate #include <netinet/in.h>
337c478bd9Sstevel@tonic-gate #include <netdb.h>
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <tzfile.h>
377c478bd9Sstevel@tonic-gate #include "snoop.h"
387c478bd9Sstevel@tonic-gate #include "ntp.h"
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate * In verbose mode, how many octets of the control-mode data payload
427c478bd9Sstevel@tonic-gate * are displayed per line of output. The value 64 fits well on an
437c478bd9Sstevel@tonic-gate * 80-column screen and, as a power of 2, is easily correlated to
447c478bd9Sstevel@tonic-gate * hexadecimal output.
457c478bd9Sstevel@tonic-gate */
467c478bd9Sstevel@tonic-gate #define OCTETS_PER_LINE 64
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate extern char *dlc_header;
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate static char *show_leap(int);
517c478bd9Sstevel@tonic-gate static char *show_mode(int);
527c478bd9Sstevel@tonic-gate static char *show_ref(int, ulong_t);
537c478bd9Sstevel@tonic-gate static char *show_time(struct l_fixedpt);
547c478bd9Sstevel@tonic-gate static double s_fixed_to_double(struct s_fixedpt *);
557c478bd9Sstevel@tonic-gate static char *iso_date_time(time_t);
567c478bd9Sstevel@tonic-gate static char *show_operation(int);
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate int
interpret_ntp(int flags,struct ntpdata * ntp_pkt,int fraglen)597c478bd9Sstevel@tonic-gate interpret_ntp(int flags, struct ntpdata *ntp_pkt, int fraglen)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate unsigned int i, j, macbytes;
627c478bd9Sstevel@tonic-gate unsigned int proto_version;
637c478bd9Sstevel@tonic-gate unsigned int datalen;
647c478bd9Sstevel@tonic-gate unsigned int linelen = OCTETS_PER_LINE;
657c478bd9Sstevel@tonic-gate unsigned int sofar = 0;
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate char *datap;
687c478bd9Sstevel@tonic-gate char hbuf[2 * MAC_OCTETS_MAX + 1];
697c478bd9Sstevel@tonic-gate static char *hexstr = "0123456789ABCDEF";
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate union ntp_pkt_buf {
727c478bd9Sstevel@tonic-gate struct ntpdata ntp_msg;
737c478bd9Sstevel@tonic-gate union ntpc_buf {
747c478bd9Sstevel@tonic-gate struct ntp_control chdr;
757c478bd9Sstevel@tonic-gate uchar_t data2[NTPC_DATA_MAXLEN - 1];
767c478bd9Sstevel@tonic-gate } ntpc_msg;
777c478bd9Sstevel@tonic-gate union ntpp_buf {
787c478bd9Sstevel@tonic-gate struct ntp_private phdr;
797c478bd9Sstevel@tonic-gate uchar_t data2[1];
807c478bd9Sstevel@tonic-gate } ntpp_msg;
817c478bd9Sstevel@tonic-gate } fragbuf;
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate struct ntpdata *ntp = &fragbuf.ntp_msg;
847c478bd9Sstevel@tonic-gate struct ntp_control *ntpc = (struct ntp_control *)&fragbuf.ntpc_msg;
857c478bd9Sstevel@tonic-gate struct ntp_private *ntpp = (struct ntp_private *)&fragbuf.ntpp_msg;
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate * Copying packet contents into a local buffer avoids
897c478bd9Sstevel@tonic-gate * problems of interpretation if the packet is truncated.
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate (void) memcpy(&fragbuf, ntp_pkt, MIN(sizeof (fragbuf), fraglen));
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate if (flags & F_SUM) {
947c478bd9Sstevel@tonic-gate switch (ntp->li_vn_mode & NTPMODEMASK) {
957c478bd9Sstevel@tonic-gate case MODE_SYM_ACT:
967c478bd9Sstevel@tonic-gate case MODE_SYM_PAS:
977c478bd9Sstevel@tonic-gate case MODE_CLIENT:
987c478bd9Sstevel@tonic-gate case MODE_SERVER:
997c478bd9Sstevel@tonic-gate case MODE_BROADCAST:
1007c478bd9Sstevel@tonic-gate (void) sprintf(get_sum_line(),
1017c478bd9Sstevel@tonic-gate "NTP %s [st=%hd] (%s)",
1027c478bd9Sstevel@tonic-gate show_mode(ntp->li_vn_mode & NTPMODEMASK),
1037c478bd9Sstevel@tonic-gate ntp->stratum,
1047c478bd9Sstevel@tonic-gate show_time(ntp->xmt));
1057c478bd9Sstevel@tonic-gate break;
1067c478bd9Sstevel@tonic-gate case MODE_CONTROL:
1077c478bd9Sstevel@tonic-gate (void) sprintf(get_sum_line(),
1087c478bd9Sstevel@tonic-gate "NTP %s "
1097c478bd9Sstevel@tonic-gate "(Flags/op=0x%02x Seq=%hu Status=0x%04hx Assoc=%hu)",
1107c478bd9Sstevel@tonic-gate show_mode(ntpc->li_vn_mode & NTPMODEMASK),
1117c478bd9Sstevel@tonic-gate ntpc->r_m_e_op,
1127c478bd9Sstevel@tonic-gate ntohs(ntpc->sequence),
1137c478bd9Sstevel@tonic-gate ntohs(ntpc->status),
1147c478bd9Sstevel@tonic-gate ntohs(ntpc->associd));
1157c478bd9Sstevel@tonic-gate break;
1167c478bd9Sstevel@tonic-gate default:
1177c478bd9Sstevel@tonic-gate (void) sprintf(get_sum_line(),
1187c478bd9Sstevel@tonic-gate "NTP %s",
1197c478bd9Sstevel@tonic-gate show_mode(ntpp->rm_vn_mode & NTPMODEMASK));
1207c478bd9Sstevel@tonic-gate break;
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate proto_version = (ntp->li_vn_mode & VERSIONMASK) >> 3;
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate if (flags & F_DTAIL) {
1277c478bd9Sstevel@tonic-gate show_header("NTP: ", "Network Time Protocol", fraglen);
1287c478bd9Sstevel@tonic-gate show_space();
1297c478bd9Sstevel@tonic-gate switch (ntp->li_vn_mode & NTPMODEMASK) {
1307c478bd9Sstevel@tonic-gate case MODE_SYM_ACT:
1317c478bd9Sstevel@tonic-gate case MODE_SYM_PAS:
1327c478bd9Sstevel@tonic-gate case MODE_CLIENT:
1337c478bd9Sstevel@tonic-gate case MODE_SERVER:
1347c478bd9Sstevel@tonic-gate case MODE_BROADCAST:
135*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
1367c478bd9Sstevel@tonic-gate dlc_header, 1),
1377c478bd9Sstevel@tonic-gate "Leap = 0x%x (%s)",
1387c478bd9Sstevel@tonic-gate (int)(ntp->li_vn_mode & LEAPMASK) >> 6,
1397c478bd9Sstevel@tonic-gate show_leap(ntp->li_vn_mode & LEAPMASK));
140*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
1417c478bd9Sstevel@tonic-gate dlc_header, 1),
1427c478bd9Sstevel@tonic-gate "Version = %lu", proto_version);
143*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
1447c478bd9Sstevel@tonic-gate dlc_header, 1),
1457c478bd9Sstevel@tonic-gate "Mode = %hu (%s)",
1467c478bd9Sstevel@tonic-gate ntp->li_vn_mode & NTPMODEMASK,
1477c478bd9Sstevel@tonic-gate show_mode(ntp->li_vn_mode & NTPMODEMASK));
148*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->stratum -
1497c478bd9Sstevel@tonic-gate dlc_header, 1),
1507c478bd9Sstevel@tonic-gate "Stratum = %d (%s)",
1517c478bd9Sstevel@tonic-gate ntp->stratum,
1527c478bd9Sstevel@tonic-gate ntp->stratum == 0 ? "unspecified" :
1537c478bd9Sstevel@tonic-gate ntp->stratum == 1 ? "primary reference" :
1547c478bd9Sstevel@tonic-gate "secondary reference");
155*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->ppoll -
156*2e3b6467Skcpoon dlc_header, 1), "Poll = %hu", ntp->ppoll);
157*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->precision -
1587c478bd9Sstevel@tonic-gate dlc_header, 1),
1597c478bd9Sstevel@tonic-gate "Precision = %d seconds",
1607c478bd9Sstevel@tonic-gate ntp->precision);
161*2e3b6467Skcpoon (void) sprintf(get_line(
162*2e3b6467Skcpoon (char *)(uintptr_t)ntp->distance.int_part -
1637c478bd9Sstevel@tonic-gate dlc_header, 1),
1647c478bd9Sstevel@tonic-gate "Synchronizing distance = 0x%04x.%04x (%f)",
1657c478bd9Sstevel@tonic-gate ntohs(ntp->distance.int_part),
1667c478bd9Sstevel@tonic-gate ntohs(ntp->distance.fraction),
1677c478bd9Sstevel@tonic-gate s_fixed_to_double(&ntp->distance));
168*2e3b6467Skcpoon (void) sprintf(get_line(
169*2e3b6467Skcpoon (char *)(uintptr_t)ntp->dispersion.int_part -
1707c478bd9Sstevel@tonic-gate dlc_header, 1),
1717c478bd9Sstevel@tonic-gate "Synchronizing dispersion = 0x%04x.%04x (%f)",
1727c478bd9Sstevel@tonic-gate ntohs(ntp->dispersion.int_part),
1737c478bd9Sstevel@tonic-gate ntohs(ntp->dispersion.fraction),
1747c478bd9Sstevel@tonic-gate s_fixed_to_double(&ntp->dispersion));
175*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->refid -
176*2e3b6467Skcpoon dlc_header, 1), "Reference clock = %s",
1777c478bd9Sstevel@tonic-gate show_ref(ntp->stratum, ntp->refid));
1787c478bd9Sstevel@tonic-gate
179*2e3b6467Skcpoon (void) sprintf(get_line(
180*2e3b6467Skcpoon (char *)(uintptr_t)ntp->reftime.int_part - dlc_header,
181*2e3b6467Skcpoon 1), "Reference time = 0x%08lx.%08lx (%s)",
1827c478bd9Sstevel@tonic-gate ntohl(ntp->reftime.int_part),
1837c478bd9Sstevel@tonic-gate ntohl(ntp->reftime.fraction),
1847c478bd9Sstevel@tonic-gate show_time(ntp->reftime));
1857c478bd9Sstevel@tonic-gate
186*2e3b6467Skcpoon (void) sprintf(get_line(
187*2e3b6467Skcpoon (char *)(uintptr_t)ntp->org.int_part - dlc_header, 1),
1887c478bd9Sstevel@tonic-gate "Originate time = 0x%08lx.%08lx (%s)",
1897c478bd9Sstevel@tonic-gate ntohl(ntp->org.int_part),
1907c478bd9Sstevel@tonic-gate ntohl(ntp->org.fraction),
1917c478bd9Sstevel@tonic-gate show_time(ntp->org));
1927c478bd9Sstevel@tonic-gate
193*2e3b6467Skcpoon (void) sprintf(get_line(
194*2e3b6467Skcpoon (char *)(uintptr_t)ntp->rec.int_part - dlc_header, 1),
1957c478bd9Sstevel@tonic-gate "Receive time = 0x%08lx.%08lx (%s)",
1967c478bd9Sstevel@tonic-gate ntohl(ntp->rec.int_part),
1977c478bd9Sstevel@tonic-gate ntohl(ntp->rec.fraction),
1987c478bd9Sstevel@tonic-gate show_time(ntp->rec));
1997c478bd9Sstevel@tonic-gate
200*2e3b6467Skcpoon (void) sprintf(get_line(
201*2e3b6467Skcpoon (char *)(uintptr_t)ntp->xmt.int_part - dlc_header, 1),
2027c478bd9Sstevel@tonic-gate "Transmit time = 0x%08lx.%08lx (%s)",
2037c478bd9Sstevel@tonic-gate ntohl(ntp->xmt.int_part),
2047c478bd9Sstevel@tonic-gate ntohl(ntp->xmt.fraction),
2057c478bd9Sstevel@tonic-gate show_time(ntp->xmt));
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate if (proto_version > 3 ||
2087c478bd9Sstevel@tonic-gate fraglen < (LEN_PKT_NOMAC + MAC_OCTETS_MIN)) {
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate * A newer protocol version we can't parse,
2117c478bd9Sstevel@tonic-gate * or v3 packet with no valid authentication.
2127c478bd9Sstevel@tonic-gate */
2137c478bd9Sstevel@tonic-gate break;
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)ntp->keyid -
2167c478bd9Sstevel@tonic-gate dlc_header, 1),
2177c478bd9Sstevel@tonic-gate "Key ID = %8lu", ntohl(ntp->keyid));
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate macbytes = fraglen - (LEN_PKT_NOMAC + sizeof (uint32_t));
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < macbytes; i++) {
2227c478bd9Sstevel@tonic-gate hbuf[j++] = hexstr[ntp->mac[i] >> 4 & 0x0f];
2237c478bd9Sstevel@tonic-gate hbuf[j++] = hexstr[ntp->mac[i] & 0x0f];
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate hbuf[j] = '\0';
2267c478bd9Sstevel@tonic-gate (void) sprintf(get_line((char *)ntp->mac -
2277c478bd9Sstevel@tonic-gate dlc_header, 1),
2287c478bd9Sstevel@tonic-gate "Authentication code = %s", hbuf);
2297c478bd9Sstevel@tonic-gate break;
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate case MODE_CONTROL:
2327c478bd9Sstevel@tonic-gate /* NTP Control Message, mode 6 */
2337c478bd9Sstevel@tonic-gate
234*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
2357c478bd9Sstevel@tonic-gate dlc_header, 1),
2367c478bd9Sstevel@tonic-gate "Leap = 0x%x (%s)",
2377c478bd9Sstevel@tonic-gate (int)(ntp->li_vn_mode & LEAPMASK) >> 6,
2387c478bd9Sstevel@tonic-gate show_leap(ntp->li_vn_mode & LEAPMASK));
239*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
2407c478bd9Sstevel@tonic-gate dlc_header, 1),
2417c478bd9Sstevel@tonic-gate "Version = %lu", proto_version);
242*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
2437c478bd9Sstevel@tonic-gate dlc_header, 1),
2447c478bd9Sstevel@tonic-gate "Mode = %hu (%s)",
2457c478bd9Sstevel@tonic-gate ntp->li_vn_mode & NTPMODEMASK,
2467c478bd9Sstevel@tonic-gate show_mode(ntp->li_vn_mode & NTPMODEMASK));
247*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2487c478bd9Sstevel@tonic-gate dlc_header, 1),
2497c478bd9Sstevel@tonic-gate "Flags and operation code = 0x%02x",
2507c478bd9Sstevel@tonic-gate ntpc->r_m_e_op);
251*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2527c478bd9Sstevel@tonic-gate dlc_header, 1),
2537c478bd9Sstevel@tonic-gate " %s",
2547c478bd9Sstevel@tonic-gate getflag(ntpc->r_m_e_op, CTL_RESPONSE, "response",
2557c478bd9Sstevel@tonic-gate "request"));
256*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2577c478bd9Sstevel@tonic-gate dlc_header, 1),
2587c478bd9Sstevel@tonic-gate " %s",
2597c478bd9Sstevel@tonic-gate getflag(ntpc->r_m_e_op, CTL_ERROR, "error",
2607c478bd9Sstevel@tonic-gate "success"));
261*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2627c478bd9Sstevel@tonic-gate dlc_header, 1),
2637c478bd9Sstevel@tonic-gate " %s",
2647c478bd9Sstevel@tonic-gate getflag(ntpc->r_m_e_op, CTL_MORE, "more",
2657c478bd9Sstevel@tonic-gate "no more"));
266*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2677c478bd9Sstevel@tonic-gate dlc_header, 1),
2687c478bd9Sstevel@tonic-gate " ...x xxxx = %hd (%s)",
2697c478bd9Sstevel@tonic-gate ntpc->r_m_e_op & CTL_OP_MASK,
2707c478bd9Sstevel@tonic-gate show_operation(ntpc->r_m_e_op & CTL_OP_MASK));
271*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->sequence -
2727c478bd9Sstevel@tonic-gate dlc_header, 1),
2737c478bd9Sstevel@tonic-gate "Sequence = %hu",
2747c478bd9Sstevel@tonic-gate ntohs(ntpc->sequence));
275*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->status -
2767c478bd9Sstevel@tonic-gate dlc_header, 1),
2777c478bd9Sstevel@tonic-gate "Status = 0x%04hx",
2787c478bd9Sstevel@tonic-gate ntohs(ntpc->status));
279*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->associd -
2807c478bd9Sstevel@tonic-gate dlc_header, 1),
2817c478bd9Sstevel@tonic-gate "Assoc ID = %hu",
2827c478bd9Sstevel@tonic-gate ntohs(ntpc->associd));
283*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->offset -
2847c478bd9Sstevel@tonic-gate dlc_header, 1),
2857c478bd9Sstevel@tonic-gate "Data offset = %hu",
2867c478bd9Sstevel@tonic-gate ntohs(ntpc->offset));
287*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->count -
2887c478bd9Sstevel@tonic-gate dlc_header, 1),
2897c478bd9Sstevel@tonic-gate "Data bytes = %hu",
2907c478bd9Sstevel@tonic-gate ntohs(ntpc->count));
2917c478bd9Sstevel@tonic-gate datalen = ntohs(ntpc->count);
2927c478bd9Sstevel@tonic-gate if (datalen == 0) {
2937c478bd9Sstevel@tonic-gate break;
2947c478bd9Sstevel@tonic-gate } else if (datalen > NTPC_DATA_MAXLEN) {
2957c478bd9Sstevel@tonic-gate datalen = NTPC_DATA_MAXLEN;
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate show_space();
2987c478bd9Sstevel@tonic-gate datap = (char *)ntpc->data;
2997c478bd9Sstevel@tonic-gate do {
3007c478bd9Sstevel@tonic-gate (void) sprintf(get_line(datap -
3017c478bd9Sstevel@tonic-gate dlc_header, 1),
3027c478bd9Sstevel@tonic-gate "\"%s\"",
3037c478bd9Sstevel@tonic-gate show_string(datap, linelen, datalen));
3047c478bd9Sstevel@tonic-gate sofar += linelen;
3057c478bd9Sstevel@tonic-gate datap += linelen;
3067c478bd9Sstevel@tonic-gate if ((sofar + linelen) > datalen) {
3077c478bd9Sstevel@tonic-gate linelen = datalen - sofar;
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate } while (sofar < datalen);
3107c478bd9Sstevel@tonic-gate show_trailer();
3117c478bd9Sstevel@tonic-gate break;
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate case MODE_PRIVATE:
3147c478bd9Sstevel@tonic-gate /* NTP Private Message, mode 7 */
3157c478bd9Sstevel@tonic-gate
316*2e3b6467Skcpoon (void) sprintf(get_line(
317*2e3b6467Skcpoon (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
318*2e3b6467Skcpoon "Version = %hu", INFO_VERSION(ntpp->rm_vn_mode));
319*2e3b6467Skcpoon (void) sprintf(get_line(
320*2e3b6467Skcpoon (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
321*2e3b6467Skcpoon "Mode = %hu (%s)", INFO_MODE(ntpp->rm_vn_mode),
3227c478bd9Sstevel@tonic-gate show_mode(INFO_MODE(ntpp->rm_vn_mode)));
323*2e3b6467Skcpoon (void) sprintf(get_line(
324*2e3b6467Skcpoon (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
325*2e3b6467Skcpoon "Flags = 0x%02hx", ntpp->rm_vn_mode);
326*2e3b6467Skcpoon (void) sprintf(get_line(
327*2e3b6467Skcpoon (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
3287c478bd9Sstevel@tonic-gate " %s",
3297c478bd9Sstevel@tonic-gate getflag(ntpp->rm_vn_mode, RESP_BIT, "response",
3307c478bd9Sstevel@tonic-gate "request"));
331*2e3b6467Skcpoon (void) sprintf(get_line(
332*2e3b6467Skcpoon (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
3337c478bd9Sstevel@tonic-gate " %s",
334*2e3b6467Skcpoon getflag(ntpp->rm_vn_mode, MORE_BIT, "more", "no more"));
335*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq -
3367c478bd9Sstevel@tonic-gate dlc_header, 1),
337*2e3b6467Skcpoon "Authentication and sequence = 0x%02x", ntpp->auth_seq);
338*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq -
3397c478bd9Sstevel@tonic-gate dlc_header, 1),
3407c478bd9Sstevel@tonic-gate " %s",
3417c478bd9Sstevel@tonic-gate getflag(ntpp->auth_seq, AUTH_BIT, "authenticated",
3427c478bd9Sstevel@tonic-gate "unauthenticated"));
343*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq -
3447c478bd9Sstevel@tonic-gate dlc_header, 1),
3457c478bd9Sstevel@tonic-gate " .xxx xxxx = %hu (sequence number)",
3467c478bd9Sstevel@tonic-gate INFO_SEQ(ntpp->auth_seq));
347*2e3b6467Skcpoon (void) sprintf(get_line(
348*2e3b6467Skcpoon (char *)(uintptr_t)ntpp->implementation - dlc_header,
349*2e3b6467Skcpoon 1), "Implementation = %hu", ntpp->implementation);
350*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpp->request -
351*2e3b6467Skcpoon dlc_header, 1), "Request = %hu", ntpp->request);
352*2e3b6467Skcpoon (void) sprintf(get_line(
353*2e3b6467Skcpoon (char *)(uintptr_t)ntpp->err_nitems - dlc_header, 1),
354*2e3b6467Skcpoon "Error = %hu", INFO_ERR(ntpp->err_nitems));
355*2e3b6467Skcpoon (void) sprintf(get_line(
356*2e3b6467Skcpoon (char *)(uintptr_t)ntpp->err_nitems - dlc_header, 1),
357*2e3b6467Skcpoon "Items = %hu", INFO_NITEMS(ntpp->err_nitems));
358*2e3b6467Skcpoon (void) sprintf(get_line(
359*2e3b6467Skcpoon (char *)(uintptr_t)ntpp->mbz_itemsize - dlc_header, 1),
360*2e3b6467Skcpoon "Item size = %hu", INFO_ITEMSIZE(ntpp->mbz_itemsize));
3617c478bd9Sstevel@tonic-gate break;
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate default:
3647c478bd9Sstevel@tonic-gate /* Unknown mode */
365*2e3b6467Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
366*2e3b6467Skcpoon dlc_header, 1), "Mode = %hu (%s)",
3677c478bd9Sstevel@tonic-gate ntp->li_vn_mode & NTPMODEMASK,
3687c478bd9Sstevel@tonic-gate show_mode(ntp->li_vn_mode & NTPMODEMASK));
3697c478bd9Sstevel@tonic-gate break;
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate return (fraglen);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate char *
show_leap(int leap)3777c478bd9Sstevel@tonic-gate show_leap(int leap)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate switch (leap) {
3807c478bd9Sstevel@tonic-gate case NO_WARNING: return ("OK");
3817c478bd9Sstevel@tonic-gate case PLUS_SEC: return ("add a second (61 seconds)");
3827c478bd9Sstevel@tonic-gate case MINUS_SEC: return ("minus a second (59 seconds)");
3837c478bd9Sstevel@tonic-gate case ALARM: return ("alarm condition (clock unsynchronized)");
3847c478bd9Sstevel@tonic-gate default: return ("unknown");
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate char *
show_mode(int mode)3897c478bd9Sstevel@tonic-gate show_mode(int mode)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate switch (mode) {
3927c478bd9Sstevel@tonic-gate case MODE_UNSPEC: return ("unspecified");
3937c478bd9Sstevel@tonic-gate case MODE_SYM_ACT: return ("symmetric active");
3947c478bd9Sstevel@tonic-gate case MODE_SYM_PAS: return ("symmetric passive");
3957c478bd9Sstevel@tonic-gate case MODE_CLIENT: return ("client");
3967c478bd9Sstevel@tonic-gate case MODE_SERVER: return ("server");
3977c478bd9Sstevel@tonic-gate case MODE_BROADCAST: return ("broadcast");
3987c478bd9Sstevel@tonic-gate case MODE_CONTROL: return ("control");
3997c478bd9Sstevel@tonic-gate case MODE_PRIVATE: return ("private");
4007c478bd9Sstevel@tonic-gate default: return ("unknown");
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate char *
show_ref(int mode,ulong_t refid)4057c478bd9Sstevel@tonic-gate show_ref(int mode, ulong_t refid)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate static char buff[MAXHOSTNAMELEN + 32];
4087c478bd9Sstevel@tonic-gate struct in_addr host;
4097c478bd9Sstevel@tonic-gate extern char *inet_ntoa();
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate switch (mode) {
4127c478bd9Sstevel@tonic-gate case 0:
4137c478bd9Sstevel@tonic-gate case 1:
4147c478bd9Sstevel@tonic-gate (void) strncpy(buff, (char *)&refid, 4);
4157c478bd9Sstevel@tonic-gate buff[4] = '\0';
4167c478bd9Sstevel@tonic-gate break;
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate default:
4197c478bd9Sstevel@tonic-gate host.s_addr = refid;
4207c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%s (%s)",
4217c478bd9Sstevel@tonic-gate inet_ntoa(host),
4227c478bd9Sstevel@tonic-gate addrtoname(AF_INET, &host));
4237c478bd9Sstevel@tonic-gate break;
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate return (buff);
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate /*
4307c478bd9Sstevel@tonic-gate * Here we have to worry about the high order bit being signed
4317c478bd9Sstevel@tonic-gate */
4327c478bd9Sstevel@tonic-gate double
s_fixed_to_double(struct s_fixedpt * t)4337c478bd9Sstevel@tonic-gate s_fixed_to_double(struct s_fixedpt *t)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate double a;
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate if (ntohs(t->int_part) & 0x8000) {
4387c478bd9Sstevel@tonic-gate a = ntohs((int)(~t->fraction) & 0xFFFF);
4397c478bd9Sstevel@tonic-gate a = a / 65536.0; /* shift dec point over by 16 bits */
4407c478bd9Sstevel@tonic-gate a += ntohs((int)(~t->int_part) & 0xFFFF);
4417c478bd9Sstevel@tonic-gate a = -a;
4427c478bd9Sstevel@tonic-gate } else {
4437c478bd9Sstevel@tonic-gate a = ntohs(t->fraction);
4447c478bd9Sstevel@tonic-gate a = a / 65536.0; /* shift dec point over by 16 bits */
4457c478bd9Sstevel@tonic-gate a += ntohs(t->int_part);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate return (a);
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate * Consistent with RFC-3339, ISO 8601.
4527c478bd9Sstevel@tonic-gate */
4537c478bd9Sstevel@tonic-gate char *
iso_date_time(time_t input_time)4547c478bd9Sstevel@tonic-gate iso_date_time(time_t input_time)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate struct tm *time_parts;
4577c478bd9Sstevel@tonic-gate static char tbuf[sizeof ("yyyy-mm-dd hh:mm:ss")];
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate time_parts = localtime(&input_time);
4607c478bd9Sstevel@tonic-gate (void) strftime(tbuf, sizeof (tbuf), "%Y-%m-%d %H:%M:%S", time_parts);
4617c478bd9Sstevel@tonic-gate return (tbuf);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gate /*
4657c478bd9Sstevel@tonic-gate * The base of NTP timestamps is 1900-01-01 00:00:00.00000
4667c478bd9Sstevel@tonic-gate */
4677c478bd9Sstevel@tonic-gate char *
show_time(struct l_fixedpt pkt_time)4687c478bd9Sstevel@tonic-gate show_time(struct l_fixedpt pkt_time)
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate struct l_fixedpt net_time;
4717c478bd9Sstevel@tonic-gate unsigned long fracsec;
4727c478bd9Sstevel@tonic-gate static char buff[32];
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate if (pkt_time.int_part == 0) {
4757c478bd9Sstevel@tonic-gate buff[0] = '\0';
4767c478bd9Sstevel@tonic-gate return (buff);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate net_time.int_part = ntohl(pkt_time.int_part) - JAN_1970;
4807c478bd9Sstevel@tonic-gate net_time.fraction = ntohl(pkt_time.fraction);
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate fracsec = net_time.fraction / 42949; /* fract / (2**32/10**6) */
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate (void) strlcpy(buff, iso_date_time(net_time.int_part), sizeof (buff));
4857c478bd9Sstevel@tonic-gate (void) snprintf(buff, sizeof (buff), "%s.%05lu", buff, fracsec);
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate return (buff);
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate char *
show_operation(int op)4917c478bd9Sstevel@tonic-gate show_operation(int op)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate switch (op) {
4947c478bd9Sstevel@tonic-gate case CTL_OP_UNSPEC: return ("unspecified");
4957c478bd9Sstevel@tonic-gate case CTL_OP_READSTAT: return ("read stats");
4967c478bd9Sstevel@tonic-gate case CTL_OP_READVAR: return ("read var");
4977c478bd9Sstevel@tonic-gate case CTL_OP_WRITEVAR: return ("write var");
4987c478bd9Sstevel@tonic-gate case CTL_OP_READCLOCK: return ("read clock");
4997c478bd9Sstevel@tonic-gate case CTL_OP_WRITECLOCK: return ("write clock");
5007c478bd9Sstevel@tonic-gate case CTL_OP_SETTRAP: return ("set trap");
5017c478bd9Sstevel@tonic-gate case CTL_OP_ASYNCMSG: return ("async msg");
5027c478bd9Sstevel@tonic-gate case CTL_OP_UNSETTRAP: return ("unset trap");
5037c478bd9Sstevel@tonic-gate default: return ("unknown");
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate }
506