10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*410Skcpoon * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <fcntl.h>
300Sstevel@tonic-gate #include <sys/socket.h>
310Sstevel@tonic-gate #include <sys/sysmacros.h>
320Sstevel@tonic-gate #include <netinet/in.h>
330Sstevel@tonic-gate #include <netdb.h>
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <string.h>
360Sstevel@tonic-gate #include <tzfile.h>
370Sstevel@tonic-gate #include "snoop.h"
380Sstevel@tonic-gate #include "ntp.h"
390Sstevel@tonic-gate
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate * In verbose mode, how many octets of the control-mode data payload
420Sstevel@tonic-gate * are displayed per line of output. The value 64 fits well on an
430Sstevel@tonic-gate * 80-column screen and, as a power of 2, is easily correlated to
440Sstevel@tonic-gate * hexadecimal output.
450Sstevel@tonic-gate */
460Sstevel@tonic-gate #define OCTETS_PER_LINE 64
470Sstevel@tonic-gate
480Sstevel@tonic-gate extern char *dlc_header;
490Sstevel@tonic-gate
500Sstevel@tonic-gate static char *show_leap(int);
510Sstevel@tonic-gate static char *show_mode(int);
520Sstevel@tonic-gate static char *show_ref(int, ulong_t);
530Sstevel@tonic-gate static char *show_time(struct l_fixedpt);
540Sstevel@tonic-gate static double s_fixed_to_double(struct s_fixedpt *);
550Sstevel@tonic-gate static char *iso_date_time(time_t);
560Sstevel@tonic-gate static char *show_operation(int);
570Sstevel@tonic-gate
580Sstevel@tonic-gate int
interpret_ntp(int flags,struct ntpdata * ntp_pkt,int fraglen)590Sstevel@tonic-gate interpret_ntp(int flags, struct ntpdata *ntp_pkt, int fraglen)
600Sstevel@tonic-gate {
610Sstevel@tonic-gate unsigned int i, j, macbytes;
620Sstevel@tonic-gate unsigned int proto_version;
630Sstevel@tonic-gate unsigned int datalen;
640Sstevel@tonic-gate unsigned int linelen = OCTETS_PER_LINE;
650Sstevel@tonic-gate unsigned int sofar = 0;
660Sstevel@tonic-gate
670Sstevel@tonic-gate char *datap;
680Sstevel@tonic-gate char hbuf[2 * MAC_OCTETS_MAX + 1];
690Sstevel@tonic-gate static char *hexstr = "0123456789ABCDEF";
700Sstevel@tonic-gate
710Sstevel@tonic-gate union ntp_pkt_buf {
720Sstevel@tonic-gate struct ntpdata ntp_msg;
730Sstevel@tonic-gate union ntpc_buf {
740Sstevel@tonic-gate struct ntp_control chdr;
750Sstevel@tonic-gate uchar_t data2[NTPC_DATA_MAXLEN - 1];
760Sstevel@tonic-gate } ntpc_msg;
770Sstevel@tonic-gate union ntpp_buf {
780Sstevel@tonic-gate struct ntp_private phdr;
790Sstevel@tonic-gate uchar_t data2[1];
800Sstevel@tonic-gate } ntpp_msg;
810Sstevel@tonic-gate } fragbuf;
820Sstevel@tonic-gate
830Sstevel@tonic-gate struct ntpdata *ntp = &fragbuf.ntp_msg;
840Sstevel@tonic-gate struct ntp_control *ntpc = (struct ntp_control *)&fragbuf.ntpc_msg;
850Sstevel@tonic-gate struct ntp_private *ntpp = (struct ntp_private *)&fragbuf.ntpp_msg;
860Sstevel@tonic-gate
870Sstevel@tonic-gate /*
880Sstevel@tonic-gate * Copying packet contents into a local buffer avoids
890Sstevel@tonic-gate * problems of interpretation if the packet is truncated.
900Sstevel@tonic-gate */
910Sstevel@tonic-gate (void) memcpy(&fragbuf, ntp_pkt, MIN(sizeof (fragbuf), fraglen));
920Sstevel@tonic-gate
930Sstevel@tonic-gate if (flags & F_SUM) {
940Sstevel@tonic-gate switch (ntp->li_vn_mode & NTPMODEMASK) {
950Sstevel@tonic-gate case MODE_SYM_ACT:
960Sstevel@tonic-gate case MODE_SYM_PAS:
970Sstevel@tonic-gate case MODE_CLIENT:
980Sstevel@tonic-gate case MODE_SERVER:
990Sstevel@tonic-gate case MODE_BROADCAST:
1000Sstevel@tonic-gate (void) sprintf(get_sum_line(),
1010Sstevel@tonic-gate "NTP %s [st=%hd] (%s)",
1020Sstevel@tonic-gate show_mode(ntp->li_vn_mode & NTPMODEMASK),
1030Sstevel@tonic-gate ntp->stratum,
1040Sstevel@tonic-gate show_time(ntp->xmt));
1050Sstevel@tonic-gate break;
1060Sstevel@tonic-gate case MODE_CONTROL:
1070Sstevel@tonic-gate (void) sprintf(get_sum_line(),
1080Sstevel@tonic-gate "NTP %s "
1090Sstevel@tonic-gate "(Flags/op=0x%02x Seq=%hu Status=0x%04hx Assoc=%hu)",
1100Sstevel@tonic-gate show_mode(ntpc->li_vn_mode & NTPMODEMASK),
1110Sstevel@tonic-gate ntpc->r_m_e_op,
1120Sstevel@tonic-gate ntohs(ntpc->sequence),
1130Sstevel@tonic-gate ntohs(ntpc->status),
1140Sstevel@tonic-gate ntohs(ntpc->associd));
1150Sstevel@tonic-gate break;
1160Sstevel@tonic-gate default:
1170Sstevel@tonic-gate (void) sprintf(get_sum_line(),
1180Sstevel@tonic-gate "NTP %s",
1190Sstevel@tonic-gate show_mode(ntpp->rm_vn_mode & NTPMODEMASK));
1200Sstevel@tonic-gate break;
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate proto_version = (ntp->li_vn_mode & VERSIONMASK) >> 3;
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate if (flags & F_DTAIL) {
1270Sstevel@tonic-gate show_header("NTP: ", "Network Time Protocol", fraglen);
1280Sstevel@tonic-gate show_space();
1290Sstevel@tonic-gate switch (ntp->li_vn_mode & NTPMODEMASK) {
1300Sstevel@tonic-gate case MODE_SYM_ACT:
1310Sstevel@tonic-gate case MODE_SYM_PAS:
1320Sstevel@tonic-gate case MODE_CLIENT:
1330Sstevel@tonic-gate case MODE_SERVER:
1340Sstevel@tonic-gate case MODE_BROADCAST:
135*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
1360Sstevel@tonic-gate dlc_header, 1),
1370Sstevel@tonic-gate "Leap = 0x%x (%s)",
1380Sstevel@tonic-gate (int)(ntp->li_vn_mode & LEAPMASK) >> 6,
1390Sstevel@tonic-gate show_leap(ntp->li_vn_mode & LEAPMASK));
140*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
1410Sstevel@tonic-gate dlc_header, 1),
1420Sstevel@tonic-gate "Version = %lu", proto_version);
143*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
1440Sstevel@tonic-gate dlc_header, 1),
1450Sstevel@tonic-gate "Mode = %hu (%s)",
1460Sstevel@tonic-gate ntp->li_vn_mode & NTPMODEMASK,
1470Sstevel@tonic-gate show_mode(ntp->li_vn_mode & NTPMODEMASK));
148*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->stratum -
1490Sstevel@tonic-gate dlc_header, 1),
1500Sstevel@tonic-gate "Stratum = %d (%s)",
1510Sstevel@tonic-gate ntp->stratum,
1520Sstevel@tonic-gate ntp->stratum == 0 ? "unspecified" :
1530Sstevel@tonic-gate ntp->stratum == 1 ? "primary reference" :
1540Sstevel@tonic-gate "secondary reference");
155*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->ppoll -
156*410Skcpoon dlc_header, 1), "Poll = %hu", ntp->ppoll);
157*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->precision -
1580Sstevel@tonic-gate dlc_header, 1),
1590Sstevel@tonic-gate "Precision = %d seconds",
1600Sstevel@tonic-gate ntp->precision);
161*410Skcpoon (void) sprintf(get_line(
162*410Skcpoon (char *)(uintptr_t)ntp->distance.int_part -
1630Sstevel@tonic-gate dlc_header, 1),
1640Sstevel@tonic-gate "Synchronizing distance = 0x%04x.%04x (%f)",
1650Sstevel@tonic-gate ntohs(ntp->distance.int_part),
1660Sstevel@tonic-gate ntohs(ntp->distance.fraction),
1670Sstevel@tonic-gate s_fixed_to_double(&ntp->distance));
168*410Skcpoon (void) sprintf(get_line(
169*410Skcpoon (char *)(uintptr_t)ntp->dispersion.int_part -
1700Sstevel@tonic-gate dlc_header, 1),
1710Sstevel@tonic-gate "Synchronizing dispersion = 0x%04x.%04x (%f)",
1720Sstevel@tonic-gate ntohs(ntp->dispersion.int_part),
1730Sstevel@tonic-gate ntohs(ntp->dispersion.fraction),
1740Sstevel@tonic-gate s_fixed_to_double(&ntp->dispersion));
175*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->refid -
176*410Skcpoon dlc_header, 1), "Reference clock = %s",
1770Sstevel@tonic-gate show_ref(ntp->stratum, ntp->refid));
1780Sstevel@tonic-gate
179*410Skcpoon (void) sprintf(get_line(
180*410Skcpoon (char *)(uintptr_t)ntp->reftime.int_part - dlc_header,
181*410Skcpoon 1), "Reference time = 0x%08lx.%08lx (%s)",
1820Sstevel@tonic-gate ntohl(ntp->reftime.int_part),
1830Sstevel@tonic-gate ntohl(ntp->reftime.fraction),
1840Sstevel@tonic-gate show_time(ntp->reftime));
1850Sstevel@tonic-gate
186*410Skcpoon (void) sprintf(get_line(
187*410Skcpoon (char *)(uintptr_t)ntp->org.int_part - dlc_header, 1),
1880Sstevel@tonic-gate "Originate time = 0x%08lx.%08lx (%s)",
1890Sstevel@tonic-gate ntohl(ntp->org.int_part),
1900Sstevel@tonic-gate ntohl(ntp->org.fraction),
1910Sstevel@tonic-gate show_time(ntp->org));
1920Sstevel@tonic-gate
193*410Skcpoon (void) sprintf(get_line(
194*410Skcpoon (char *)(uintptr_t)ntp->rec.int_part - dlc_header, 1),
1950Sstevel@tonic-gate "Receive time = 0x%08lx.%08lx (%s)",
1960Sstevel@tonic-gate ntohl(ntp->rec.int_part),
1970Sstevel@tonic-gate ntohl(ntp->rec.fraction),
1980Sstevel@tonic-gate show_time(ntp->rec));
1990Sstevel@tonic-gate
200*410Skcpoon (void) sprintf(get_line(
201*410Skcpoon (char *)(uintptr_t)ntp->xmt.int_part - dlc_header, 1),
2020Sstevel@tonic-gate "Transmit time = 0x%08lx.%08lx (%s)",
2030Sstevel@tonic-gate ntohl(ntp->xmt.int_part),
2040Sstevel@tonic-gate ntohl(ntp->xmt.fraction),
2050Sstevel@tonic-gate show_time(ntp->xmt));
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate if (proto_version > 3 ||
2080Sstevel@tonic-gate fraglen < (LEN_PKT_NOMAC + MAC_OCTETS_MIN)) {
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate * A newer protocol version we can't parse,
2110Sstevel@tonic-gate * or v3 packet with no valid authentication.
2120Sstevel@tonic-gate */
2130Sstevel@tonic-gate break;
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate (void) sprintf(get_line((char *)ntp->keyid -
2160Sstevel@tonic-gate dlc_header, 1),
2170Sstevel@tonic-gate "Key ID = %8lu", ntohl(ntp->keyid));
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate macbytes = fraglen - (LEN_PKT_NOMAC + sizeof (uint32_t));
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate for (i = 0, j = 0; i < macbytes; i++) {
2220Sstevel@tonic-gate hbuf[j++] = hexstr[ntp->mac[i] >> 4 & 0x0f];
2230Sstevel@tonic-gate hbuf[j++] = hexstr[ntp->mac[i] & 0x0f];
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate hbuf[j] = '\0';
2260Sstevel@tonic-gate (void) sprintf(get_line((char *)ntp->mac -
2270Sstevel@tonic-gate dlc_header, 1),
2280Sstevel@tonic-gate "Authentication code = %s", hbuf);
2290Sstevel@tonic-gate break;
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate case MODE_CONTROL:
2320Sstevel@tonic-gate /* NTP Control Message, mode 6 */
2330Sstevel@tonic-gate
234*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
2350Sstevel@tonic-gate dlc_header, 1),
2360Sstevel@tonic-gate "Leap = 0x%x (%s)",
2370Sstevel@tonic-gate (int)(ntp->li_vn_mode & LEAPMASK) >> 6,
2380Sstevel@tonic-gate show_leap(ntp->li_vn_mode & LEAPMASK));
239*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
2400Sstevel@tonic-gate dlc_header, 1),
2410Sstevel@tonic-gate "Version = %lu", proto_version);
242*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
2430Sstevel@tonic-gate dlc_header, 1),
2440Sstevel@tonic-gate "Mode = %hu (%s)",
2450Sstevel@tonic-gate ntp->li_vn_mode & NTPMODEMASK,
2460Sstevel@tonic-gate show_mode(ntp->li_vn_mode & NTPMODEMASK));
247*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2480Sstevel@tonic-gate dlc_header, 1),
2490Sstevel@tonic-gate "Flags and operation code = 0x%02x",
2500Sstevel@tonic-gate ntpc->r_m_e_op);
251*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2520Sstevel@tonic-gate dlc_header, 1),
2530Sstevel@tonic-gate " %s",
2540Sstevel@tonic-gate getflag(ntpc->r_m_e_op, CTL_RESPONSE, "response",
2550Sstevel@tonic-gate "request"));
256*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2570Sstevel@tonic-gate dlc_header, 1),
2580Sstevel@tonic-gate " %s",
2590Sstevel@tonic-gate getflag(ntpc->r_m_e_op, CTL_ERROR, "error",
2600Sstevel@tonic-gate "success"));
261*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2620Sstevel@tonic-gate dlc_header, 1),
2630Sstevel@tonic-gate " %s",
2640Sstevel@tonic-gate getflag(ntpc->r_m_e_op, CTL_MORE, "more",
2650Sstevel@tonic-gate "no more"));
266*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->r_m_e_op -
2670Sstevel@tonic-gate dlc_header, 1),
2680Sstevel@tonic-gate " ...x xxxx = %hd (%s)",
2690Sstevel@tonic-gate ntpc->r_m_e_op & CTL_OP_MASK,
2700Sstevel@tonic-gate show_operation(ntpc->r_m_e_op & CTL_OP_MASK));
271*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->sequence -
2720Sstevel@tonic-gate dlc_header, 1),
2730Sstevel@tonic-gate "Sequence = %hu",
2740Sstevel@tonic-gate ntohs(ntpc->sequence));
275*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->status -
2760Sstevel@tonic-gate dlc_header, 1),
2770Sstevel@tonic-gate "Status = 0x%04hx",
2780Sstevel@tonic-gate ntohs(ntpc->status));
279*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->associd -
2800Sstevel@tonic-gate dlc_header, 1),
2810Sstevel@tonic-gate "Assoc ID = %hu",
2820Sstevel@tonic-gate ntohs(ntpc->associd));
283*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->offset -
2840Sstevel@tonic-gate dlc_header, 1),
2850Sstevel@tonic-gate "Data offset = %hu",
2860Sstevel@tonic-gate ntohs(ntpc->offset));
287*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpc->count -
2880Sstevel@tonic-gate dlc_header, 1),
2890Sstevel@tonic-gate "Data bytes = %hu",
2900Sstevel@tonic-gate ntohs(ntpc->count));
2910Sstevel@tonic-gate datalen = ntohs(ntpc->count);
2920Sstevel@tonic-gate if (datalen == 0) {
2930Sstevel@tonic-gate break;
2940Sstevel@tonic-gate } else if (datalen > NTPC_DATA_MAXLEN) {
2950Sstevel@tonic-gate datalen = NTPC_DATA_MAXLEN;
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate show_space();
2980Sstevel@tonic-gate datap = (char *)ntpc->data;
2990Sstevel@tonic-gate do {
3000Sstevel@tonic-gate (void) sprintf(get_line(datap -
3010Sstevel@tonic-gate dlc_header, 1),
3020Sstevel@tonic-gate "\"%s\"",
3030Sstevel@tonic-gate show_string(datap, linelen, datalen));
3040Sstevel@tonic-gate sofar += linelen;
3050Sstevel@tonic-gate datap += linelen;
3060Sstevel@tonic-gate if ((sofar + linelen) > datalen) {
3070Sstevel@tonic-gate linelen = datalen - sofar;
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate } while (sofar < datalen);
3100Sstevel@tonic-gate show_trailer();
3110Sstevel@tonic-gate break;
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate case MODE_PRIVATE:
3140Sstevel@tonic-gate /* NTP Private Message, mode 7 */
3150Sstevel@tonic-gate
316*410Skcpoon (void) sprintf(get_line(
317*410Skcpoon (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
318*410Skcpoon "Version = %hu", INFO_VERSION(ntpp->rm_vn_mode));
319*410Skcpoon (void) sprintf(get_line(
320*410Skcpoon (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
321*410Skcpoon "Mode = %hu (%s)", INFO_MODE(ntpp->rm_vn_mode),
3220Sstevel@tonic-gate show_mode(INFO_MODE(ntpp->rm_vn_mode)));
323*410Skcpoon (void) sprintf(get_line(
324*410Skcpoon (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
325*410Skcpoon "Flags = 0x%02hx", ntpp->rm_vn_mode);
326*410Skcpoon (void) sprintf(get_line(
327*410Skcpoon (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
3280Sstevel@tonic-gate " %s",
3290Sstevel@tonic-gate getflag(ntpp->rm_vn_mode, RESP_BIT, "response",
3300Sstevel@tonic-gate "request"));
331*410Skcpoon (void) sprintf(get_line(
332*410Skcpoon (char *)(uintptr_t)ntpp->rm_vn_mode - dlc_header, 1),
3330Sstevel@tonic-gate " %s",
334*410Skcpoon getflag(ntpp->rm_vn_mode, MORE_BIT, "more", "no more"));
335*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq -
3360Sstevel@tonic-gate dlc_header, 1),
337*410Skcpoon "Authentication and sequence = 0x%02x", ntpp->auth_seq);
338*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq -
3390Sstevel@tonic-gate dlc_header, 1),
3400Sstevel@tonic-gate " %s",
3410Sstevel@tonic-gate getflag(ntpp->auth_seq, AUTH_BIT, "authenticated",
3420Sstevel@tonic-gate "unauthenticated"));
343*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpp->auth_seq -
3440Sstevel@tonic-gate dlc_header, 1),
3450Sstevel@tonic-gate " .xxx xxxx = %hu (sequence number)",
3460Sstevel@tonic-gate INFO_SEQ(ntpp->auth_seq));
347*410Skcpoon (void) sprintf(get_line(
348*410Skcpoon (char *)(uintptr_t)ntpp->implementation - dlc_header,
349*410Skcpoon 1), "Implementation = %hu", ntpp->implementation);
350*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntpp->request -
351*410Skcpoon dlc_header, 1), "Request = %hu", ntpp->request);
352*410Skcpoon (void) sprintf(get_line(
353*410Skcpoon (char *)(uintptr_t)ntpp->err_nitems - dlc_header, 1),
354*410Skcpoon "Error = %hu", INFO_ERR(ntpp->err_nitems));
355*410Skcpoon (void) sprintf(get_line(
356*410Skcpoon (char *)(uintptr_t)ntpp->err_nitems - dlc_header, 1),
357*410Skcpoon "Items = %hu", INFO_NITEMS(ntpp->err_nitems));
358*410Skcpoon (void) sprintf(get_line(
359*410Skcpoon (char *)(uintptr_t)ntpp->mbz_itemsize - dlc_header, 1),
360*410Skcpoon "Item size = %hu", INFO_ITEMSIZE(ntpp->mbz_itemsize));
3610Sstevel@tonic-gate break;
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate default:
3640Sstevel@tonic-gate /* Unknown mode */
365*410Skcpoon (void) sprintf(get_line((char *)(uintptr_t)ntp->li_vn_mode -
366*410Skcpoon dlc_header, 1), "Mode = %hu (%s)",
3670Sstevel@tonic-gate ntp->li_vn_mode & NTPMODEMASK,
3680Sstevel@tonic-gate show_mode(ntp->li_vn_mode & NTPMODEMASK));
3690Sstevel@tonic-gate break;
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate return (fraglen);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate char *
show_leap(int leap)3770Sstevel@tonic-gate show_leap(int leap)
3780Sstevel@tonic-gate {
3790Sstevel@tonic-gate switch (leap) {
3800Sstevel@tonic-gate case NO_WARNING: return ("OK");
3810Sstevel@tonic-gate case PLUS_SEC: return ("add a second (61 seconds)");
3820Sstevel@tonic-gate case MINUS_SEC: return ("minus a second (59 seconds)");
3830Sstevel@tonic-gate case ALARM: return ("alarm condition (clock unsynchronized)");
3840Sstevel@tonic-gate default: return ("unknown");
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate char *
show_mode(int mode)3890Sstevel@tonic-gate show_mode(int mode)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate switch (mode) {
3920Sstevel@tonic-gate case MODE_UNSPEC: return ("unspecified");
3930Sstevel@tonic-gate case MODE_SYM_ACT: return ("symmetric active");
3940Sstevel@tonic-gate case MODE_SYM_PAS: return ("symmetric passive");
3950Sstevel@tonic-gate case MODE_CLIENT: return ("client");
3960Sstevel@tonic-gate case MODE_SERVER: return ("server");
3970Sstevel@tonic-gate case MODE_BROADCAST: return ("broadcast");
3980Sstevel@tonic-gate case MODE_CONTROL: return ("control");
3990Sstevel@tonic-gate case MODE_PRIVATE: return ("private");
4000Sstevel@tonic-gate default: return ("unknown");
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate char *
show_ref(int mode,ulong_t refid)4050Sstevel@tonic-gate show_ref(int mode, ulong_t refid)
4060Sstevel@tonic-gate {
4070Sstevel@tonic-gate static char buff[MAXHOSTNAMELEN + 32];
4080Sstevel@tonic-gate struct in_addr host;
4090Sstevel@tonic-gate extern char *inet_ntoa();
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate switch (mode) {
4120Sstevel@tonic-gate case 0:
4130Sstevel@tonic-gate case 1:
4140Sstevel@tonic-gate (void) strncpy(buff, (char *)&refid, 4);
4150Sstevel@tonic-gate buff[4] = '\0';
4160Sstevel@tonic-gate break;
4170Sstevel@tonic-gate
4180Sstevel@tonic-gate default:
4190Sstevel@tonic-gate host.s_addr = refid;
4200Sstevel@tonic-gate (void) sprintf(buff, "%s (%s)",
4210Sstevel@tonic-gate inet_ntoa(host),
4220Sstevel@tonic-gate addrtoname(AF_INET, &host));
4230Sstevel@tonic-gate break;
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate
4260Sstevel@tonic-gate return (buff);
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate /*
4300Sstevel@tonic-gate * Here we have to worry about the high order bit being signed
4310Sstevel@tonic-gate */
4320Sstevel@tonic-gate double
s_fixed_to_double(struct s_fixedpt * t)4330Sstevel@tonic-gate s_fixed_to_double(struct s_fixedpt *t)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate double a;
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate if (ntohs(t->int_part) & 0x8000) {
4380Sstevel@tonic-gate a = ntohs((int)(~t->fraction) & 0xFFFF);
4390Sstevel@tonic-gate a = a / 65536.0; /* shift dec point over by 16 bits */
4400Sstevel@tonic-gate a += ntohs((int)(~t->int_part) & 0xFFFF);
4410Sstevel@tonic-gate a = -a;
4420Sstevel@tonic-gate } else {
4430Sstevel@tonic-gate a = ntohs(t->fraction);
4440Sstevel@tonic-gate a = a / 65536.0; /* shift dec point over by 16 bits */
4450Sstevel@tonic-gate a += ntohs(t->int_part);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate return (a);
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate * Consistent with RFC-3339, ISO 8601.
4520Sstevel@tonic-gate */
4530Sstevel@tonic-gate char *
iso_date_time(time_t input_time)4540Sstevel@tonic-gate iso_date_time(time_t input_time)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate struct tm *time_parts;
4570Sstevel@tonic-gate static char tbuf[sizeof ("yyyy-mm-dd hh:mm:ss")];
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate time_parts = localtime(&input_time);
4600Sstevel@tonic-gate (void) strftime(tbuf, sizeof (tbuf), "%Y-%m-%d %H:%M:%S", time_parts);
4610Sstevel@tonic-gate return (tbuf);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate /*
4650Sstevel@tonic-gate * The base of NTP timestamps is 1900-01-01 00:00:00.00000
4660Sstevel@tonic-gate */
4670Sstevel@tonic-gate char *
show_time(struct l_fixedpt pkt_time)4680Sstevel@tonic-gate show_time(struct l_fixedpt pkt_time)
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate struct l_fixedpt net_time;
4710Sstevel@tonic-gate unsigned long fracsec;
4720Sstevel@tonic-gate static char buff[32];
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate if (pkt_time.int_part == 0) {
4750Sstevel@tonic-gate buff[0] = '\0';
4760Sstevel@tonic-gate return (buff);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate
4790Sstevel@tonic-gate net_time.int_part = ntohl(pkt_time.int_part) - JAN_1970;
4800Sstevel@tonic-gate net_time.fraction = ntohl(pkt_time.fraction);
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate fracsec = net_time.fraction / 42949; /* fract / (2**32/10**6) */
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate (void) strlcpy(buff, iso_date_time(net_time.int_part), sizeof (buff));
4850Sstevel@tonic-gate (void) snprintf(buff, sizeof (buff), "%s.%05lu", buff, fracsec);
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate return (buff);
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate char *
show_operation(int op)4910Sstevel@tonic-gate show_operation(int op)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate switch (op) {
4940Sstevel@tonic-gate case CTL_OP_UNSPEC: return ("unspecified");
4950Sstevel@tonic-gate case CTL_OP_READSTAT: return ("read stats");
4960Sstevel@tonic-gate case CTL_OP_READVAR: return ("read var");
4970Sstevel@tonic-gate case CTL_OP_WRITEVAR: return ("write var");
4980Sstevel@tonic-gate case CTL_OP_READCLOCK: return ("read clock");
4990Sstevel@tonic-gate case CTL_OP_WRITECLOCK: return ("write clock");
5000Sstevel@tonic-gate case CTL_OP_SETTRAP: return ("set trap");
5010Sstevel@tonic-gate case CTL_OP_ASYNCMSG: return ("async msg");
5020Sstevel@tonic-gate case CTL_OP_UNSETTRAP: return ("unset trap");
5030Sstevel@tonic-gate default: return ("unknown");
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate }
506