117680Spst/*
239300Sfenner * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017680Spst *
2117680Spst * Format and print ntp packets.
2217680Spst *	By Jeffrey Mogul/DECWRL
2317680Spst *	loosely based on print-bootp.c
2456896Sfenner *
2556896Sfenner * $FreeBSD$
2617680Spst */
2717680Spst
2817680Spst#ifndef lint
29127675Sbmsstatic const char rcsid[] _U_ =
30214478Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-ntp.c,v 1.43 2007-11-30 13:45:10 hannes Exp $ (LBL)";
3117680Spst#endif
3217680Spst
3356896Sfenner#ifdef HAVE_CONFIG_H
3456896Sfenner#include "config.h"
3556896Sfenner#endif
3656896Sfenner
37127675Sbms#include <tcpdump-stdinc.h>
3817680Spst
3917680Spst#include <stdio.h>
4017680Spst#include <string.h>
41127675Sbms#ifdef HAVE_STRFTIME
42127675Sbms#include <time.h>
43127675Sbms#endif
4417680Spst
4517680Spst#include "interface.h"
4617680Spst#include "addrtoname.h"
47127675Sbms#include "extract.h"
4839300Sfenner#ifdef MODEMASK
4917680Spst#undef MODEMASK					/* Solaris sucks */
5039300Sfenner#endif
5117680Spst#include "ntp.h"
5217680Spst
5317680Spststatic void p_sfix(const struct s_fixedpt *);
5417680Spststatic void p_ntp_time(const struct l_fixedpt *);
5517680Spststatic void p_ntp_delta(const struct l_fixedpt *, const struct l_fixedpt *);
5617680Spst
57146778Ssamstatic struct tok ntp_mode_values[] = {
58146778Ssam    { MODE_UNSPEC,    "unspecified" },
59146778Ssam    { MODE_SYM_ACT,   "symmetric active" },
60146778Ssam    { MODE_SYM_PAS,   "symmetric passive" },
61146778Ssam    { MODE_CLIENT,    "Client" },
62146778Ssam    { MODE_SERVER,    "Server" },
63146778Ssam    { MODE_BROADCAST, "Broadcast" },
64146778Ssam    { MODE_RES1,      "Reserved" },
65146778Ssam    { MODE_RES2,      "Reserved" },
66146778Ssam    { 0, NULL }
67146778Ssam};
68146778Ssam
69146778Ssamstatic struct tok ntp_leapind_values[] = {
70146778Ssam    { NO_WARNING,     "" },
71146778Ssam    { PLUS_SEC,       "+1s" },
72146778Ssam    { MINUS_SEC,      "-1s" },
73146778Ssam    { ALARM,          "clock unsynchronized" },
74146778Ssam    { 0, NULL }
75146778Ssam};
76146778Ssam
77214478Srpaulostatic struct tok ntp_stratum_values[] = {
78214478Srpaulo	{ UNSPECIFIED,	"unspecified" },
79214478Srpaulo	{ PRIM_REF, 	"primary reference" },
80214478Srpaulo	{ 0, NULL }
81214478Srpaulo};
82214478Srpaulo
8317680Spst/*
8417680Spst * Print ntp requests
8517680Spst */
8617680Spstvoid
8717680Spstntp_print(register const u_char *cp, u_int length)
8817680Spst{
8917680Spst	register const struct ntpdata *bp;
9017680Spst	int mode, version, leapind;
9117680Spst
9217680Spst	bp = (struct ntpdata *)cp;
9317680Spst
9417680Spst	TCHECK(bp->status);
9517680Spst
9626183Sfenner	version = (int)(bp->status & VERSIONMASK) >> 3;
97127675Sbms	printf("NTPv%d", version);
9817680Spst
9917680Spst	mode = bp->status & MODEMASK;
100146778Ssam        if (!vflag) {
101146778Ssam            printf (", %s, length %u",
102146778Ssam                    tok2str(ntp_mode_values, "Unknown mode", mode),
103146778Ssam                    length);
104146778Ssam            return;
105146778Ssam        }
106146778Ssam
107146778Ssam        printf (", length %u\n\t%s",
108146778Ssam                length,
109146778Ssam                tok2str(ntp_mode_values, "Unknown mode", mode));
11017680Spst
111146778Ssam	leapind = bp->status & LEAPMASK;
112146778Ssam        printf (", Leap indicator: %s (%u)",
113146778Ssam                tok2str(ntp_leapind_values, "Unknown", leapind),
114146778Ssam                leapind);
11517680Spst
11617680Spst	TCHECK(bp->stratum);
117214478Srpaulo	printf(", Stratum %u (%s)",
118214478Srpaulo		bp->stratum,
119214478Srpaulo		tok2str(ntp_stratum_values, (bp->stratum >=2 && bp->stratum<=15) ? "secondary reference" : "reserved", bp->stratum));
12017680Spst
12117680Spst	TCHECK(bp->ppoll);
122251158Sdelphij	printf(", poll %u (%us)", bp->ppoll, 1 << bp->ppoll);
12317680Spst
12417680Spst	/* Can't TCHECK bp->precision bitfield so bp->distance + 0 instead */
125146778Ssam	TCHECK2(bp->root_delay, 0);
126146778Ssam	printf(", precision %d", bp->precision);
12717680Spst
128146778Ssam	TCHECK(bp->root_delay);
129146778Ssam	fputs("\n\tRoot Delay: ", stdout);
130146778Ssam	p_sfix(&bp->root_delay);
13117680Spst
132146778Ssam	TCHECK(bp->root_dispersion);
133146778Ssam	fputs(", Root dispersion: ", stdout);
134146778Ssam	p_sfix(&bp->root_dispersion);
13517680Spst
13617680Spst	TCHECK(bp->refid);
137146778Ssam	fputs(", Reference-ID: ", stdout);
13817680Spst	/* Interpretation depends on stratum */
13917680Spst	switch (bp->stratum) {
14017680Spst
14117680Spst	case UNSPECIFIED:
14217680Spst		printf("(unspec)");
14317680Spst		break;
14417680Spst
14517680Spst	case PRIM_REF:
146147904Ssam		if (fn_printn((u_char *)&(bp->refid), 4, snapend))
147147904Ssam			goto trunc;
14817680Spst		break;
14917680Spst
15017680Spst	case INFO_QUERY:
15117680Spst		printf("%s INFO_QUERY", ipaddr_string(&(bp->refid)));
15217680Spst		/* this doesn't have more content */
15317680Spst		return;
15417680Spst
15517680Spst	case INFO_REPLY:
15617680Spst		printf("%s INFO_REPLY", ipaddr_string(&(bp->refid)));
15717680Spst		/* this is too complex to be worth printing */
15817680Spst		return;
15917680Spst
16017680Spst	default:
16117680Spst		printf("%s", ipaddr_string(&(bp->refid)));
16217680Spst		break;
16317680Spst	}
16417680Spst
165146778Ssam	TCHECK(bp->ref_timestamp);
166146778Ssam	fputs("\n\t  Reference Timestamp:  ", stdout);
167146778Ssam	p_ntp_time(&(bp->ref_timestamp));
16817680Spst
169146778Ssam	TCHECK(bp->org_timestamp);
170146778Ssam	fputs("\n\t  Originator Timestamp: ", stdout);
171146778Ssam	p_ntp_time(&(bp->org_timestamp));
17217680Spst
173146778Ssam	TCHECK(bp->rec_timestamp);
174146778Ssam	fputs("\n\t  Receive Timestamp:    ", stdout);
175146778Ssam	p_ntp_time(&(bp->rec_timestamp));
17617680Spst
177146778Ssam	TCHECK(bp->xmt_timestamp);
178146778Ssam	fputs("\n\t  Transmit Timestamp:   ", stdout);
179146778Ssam	p_ntp_time(&(bp->xmt_timestamp));
18017680Spst
181146778Ssam	fputs("\n\t    Originator - Receive Timestamp:  ", stdout);
182146778Ssam	p_ntp_delta(&(bp->org_timestamp), &(bp->rec_timestamp));
183146778Ssam
184146778Ssam	fputs("\n\t    Originator - Transmit Timestamp: ", stdout);
185146778Ssam	p_ntp_delta(&(bp->org_timestamp), &(bp->xmt_timestamp));
186146778Ssam
187214478Srpaulo	if ( (sizeof(struct ntpdata) - length) == 16) { 	/* Optional: key-id */
188214478Srpaulo		TCHECK(bp->key_id);
189214478Srpaulo		printf("\n\tKey id: %u", bp->key_id);
190214478Srpaulo	} else if ( (sizeof(struct ntpdata) - length) == 0) { 	/* Optional: key-id + authentication */
191214478Srpaulo		TCHECK(bp->key_id);
192214478Srpaulo		printf("\n\tKey id: %u", bp->key_id);
193214478Srpaulo		TCHECK2(bp->message_digest, sizeof (bp->message_digest));
194214478Srpaulo                printf("\n\tAuthentication: %08x%08x%08x%08x",
195214478Srpaulo        		       EXTRACT_32BITS(bp->message_digest),
196214478Srpaulo		               EXTRACT_32BITS(bp->message_digest + 4),
197214478Srpaulo		               EXTRACT_32BITS(bp->message_digest + 8),
198214478Srpaulo		               EXTRACT_32BITS(bp->message_digest + 12));
199214478Srpaulo        }
20017680Spst	return;
20117680Spst
20217680Spsttrunc:
20317680Spst	fputs(" [|ntp]", stdout);
20417680Spst}
20517680Spst
20617680Spststatic void
20717680Spstp_sfix(register const struct s_fixedpt *sfp)
20817680Spst{
20917680Spst	register int i;
21017680Spst	register int f;
21117680Spst	register float ff;
21217680Spst
213127675Sbms	i = EXTRACT_16BITS(&sfp->int_part);
214127675Sbms	f = EXTRACT_16BITS(&sfp->fraction);
21517680Spst	ff = f / 65536.0;	/* shift radix point by 16 bits */
21617680Spst	f = ff * 1000000.0;	/* Treat fraction as parts per million */
21717680Spst	printf("%d.%06d", i, f);
21817680Spst}
21917680Spst
22017680Spst#define	FMAXINT	(4294967296.0)	/* floating point rep. of MAXINT */
22117680Spst
22217680Spststatic void
22317680Spstp_ntp_time(register const struct l_fixedpt *lfp)
22417680Spst{
22517680Spst	register int32_t i;
22617680Spst	register u_int32_t uf;
22717680Spst	register u_int32_t f;
22817680Spst	register float ff;
22917680Spst
230127675Sbms	i = EXTRACT_32BITS(&lfp->int_part);
231127675Sbms	uf = EXTRACT_32BITS(&lfp->fraction);
23217680Spst	ff = uf;
23317680Spst	if (ff < 0.0)		/* some compilers are buggy */
23417680Spst		ff += FMAXINT;
23517680Spst	ff = ff / FMAXINT;	/* shift radix point by 32 bits */
23617680Spst	f = ff * 1000000000.0;	/* treat fraction as parts per billion */
23717680Spst	printf("%u.%09d", i, f);
238127675Sbms
239127675Sbms#ifdef HAVE_STRFTIME
240127675Sbms	/*
241146778Ssam	 * print the time in human-readable format.
242127675Sbms	 */
243146778Ssam	if (i) {
244127675Sbms	    time_t seconds = i - JAN_1970;
245127675Sbms	    struct tm *tm;
246127675Sbms	    char time_buf[128];
247127675Sbms
248127675Sbms	    tm = localtime(&seconds);
249127675Sbms	    strftime(time_buf, sizeof (time_buf), "%Y/%m/%d %H:%M:%S", tm);
250127675Sbms	    printf (" (%s)", time_buf);
251127675Sbms	}
252127675Sbms#endif
25317680Spst}
25417680Spst
25517680Spst/* Prints time difference between *lfp and *olfp */
25617680Spststatic void
25717680Spstp_ntp_delta(register const struct l_fixedpt *olfp,
25817680Spst	    register const struct l_fixedpt *lfp)
25917680Spst{
26017680Spst	register int32_t i;
261127675Sbms	register u_int32_t u, uf;
262127675Sbms	register u_int32_t ou, ouf;
26317680Spst	register u_int32_t f;
26417680Spst	register float ff;
26517680Spst	int signbit;
26617680Spst
267127675Sbms	u = EXTRACT_32BITS(&lfp->int_part);
268127675Sbms	ou = EXTRACT_32BITS(&olfp->int_part);
269127675Sbms	uf = EXTRACT_32BITS(&lfp->fraction);
270127675Sbms	ouf = EXTRACT_32BITS(&olfp->fraction);
271127675Sbms	if (ou == 0 && ouf == 0) {
272127675Sbms		p_ntp_time(lfp);
273127675Sbms		return;
274127675Sbms	}
27517680Spst
276127675Sbms	i = u - ou;
27717680Spst
27817680Spst	if (i > 0) {		/* new is definitely greater than old */
27917680Spst		signbit = 0;
28017680Spst		f = uf - ouf;
28117680Spst		if (ouf > uf)	/* must borrow from high-order bits */
28217680Spst			i -= 1;
28317680Spst	} else if (i < 0) {	/* new is definitely less than old */
28417680Spst		signbit = 1;
28517680Spst		f = ouf - uf;
28617680Spst		if (uf > ouf)	/* must carry into the high-order bits */
28717680Spst			i += 1;
28817680Spst		i = -i;
28917680Spst	} else {		/* int_part is zero */
29017680Spst		if (uf > ouf) {
29117680Spst			signbit = 0;
29217680Spst			f = uf - ouf;
29317680Spst		} else {
29417680Spst			signbit = 1;
29517680Spst			f = ouf - uf;
29617680Spst		}
29717680Spst	}
29817680Spst
29917680Spst	ff = f;
30017680Spst	if (ff < 0.0)		/* some compilers are buggy */
30117680Spst		ff += FMAXINT;
30217680Spst	ff = ff / FMAXINT;	/* shift radix point by 32 bits */
30317680Spst	f = ff * 1000000000.0;	/* treat fraction as parts per billion */
30417680Spst	if (signbit)
30517680Spst		putchar('-');
30617680Spst	else
30717680Spst		putchar('+');
30817680Spst	printf("%d.%09d", i, f);
30917680Spst}
310127675Sbms
311