/*
* Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* By Jeffrey Mogul/DECWRL
* loosely based on print-bootp.c
*/
/* \summary: Network Time Protocol (NTP) printer */
/* Length of the NTP data message with the mandatory fields ("the header")
* and without any optional fields (extension, Key Identifier,
* Message Digest).
*/
#define NTP_TIMEMSG_MINLEN 48U
struct ntp_time_data {
nd_uint8_t status; /* status of local clock and leap info */
nd_uint8_t stratum; /* Stratum level */
nd_int8_t ppoll; /* poll value */
nd_int8_t precision;
struct s_fixedpt root_delay;
struct s_fixedpt root_dispersion;
nd_uint32_t refid;
struct l_fixedpt ref_timestamp;
struct l_fixedpt org_timestamp;
struct l_fixedpt rec_timestamp;
struct l_fixedpt xmt_timestamp;
nd_uint32_t key_id;
nd_uint8_t message_digest[20];
};
/*
* Leap Second Codes (high order two bits)
*/
#define NO_WARNING 0x00 /* no warning */
#define PLUS_SEC 0x40 /* add a second (61 seconds) */
#define MINUS_SEC 0x80 /* minus a second (59 seconds) */
#define ALARM 0xc0 /* alarm condition (clock unsynchronized) */
/*
* Clock Status Bits that Encode Version
*/
#define NTPVERSION_1 0x08
#define VERSIONMASK 0x38
#define VERSIONSHIFT 3
#define LEAPMASK 0xc0
#define LEAPSHIFT 6
#ifdef MODEMASK
#undef MODEMASK /* Solaris sucks */
#endif
#define MODEMASK 0x07
#define MODESHIFT 0
/* Length of the NTP control message with the mandatory fields ("the header")
* and without any optional fields (Data, Padding, Authenticator).
*/
#define NTP_CTRLMSG_MINLEN 12U
struct ntp_control_data {
nd_uint8_t magic; /* LI, VN, Mode */
nd_uint8_t control; /* R, E, M, OpCode */
nd_uint16_t sequence; /* Sequence Number */
nd_uint16_t status; /* Status */
nd_uint16_t assoc; /* Association ID */
nd_uint16_t offset; /* Offset */
nd_uint16_t count; /* Count */
nd_uint8_t data[564]; /* Data, [Padding, [Authenticator]] */
};
case PRIM_REF:
if (nd_printn(ndo, (const u_char *)&(bp->refid), 4, ndo->ndo_snapend))
goto trunc;
break;
case INFO_QUERY:
ND_PRINT("%s INFO_QUERY", GET_IPADDR_STRING(bp->refid));
/* this doesn't have more content */
return;
case INFO_REPLY:
ND_PRINT("%s INFO_REPLY", GET_IPADDR_STRING(bp->refid));
/* this is too complex to be worth printing */
return;
default:
/* In NTPv4 (RFC 5905) refid is an IPv4 address or first 32 bits of
MD5 sum of IPv6 address */
ND_PRINT("0x%08x", GET_BE_U_4(bp->refid));
break;
}
case MODE_UNSPEC:
case MODE_SYM_ACT:
case MODE_SYM_PAS:
case MODE_CLIENT:
case MODE_SERVER:
case MODE_BROADCAST:
ntp_time_print(ndo, &bp->td, length);
break;
case MODE_CONTROL:
ntp_control_print(ndo, &bp->cd, length);
break;
default:
break; /* XXX: not implemented! */
}
}
static void
p_sfix(netdissect_options *ndo,
const struct s_fixedpt *sfp)
{
int i;
int f;
double ff;
i = GET_BE_U_2(sfp->int_part);
f = GET_BE_U_2(sfp->fraction);
ff = f / 65536.0; /* shift radix point by 16 bits */
f = (int)(ff * 1000000.0); /* Treat fraction as parts per million */
ND_PRINT("%d.%06d", i, f);
}
/* Prints time difference between *lfp and *olfp */
static void
p_ntp_delta(netdissect_options *ndo,
const struct l_fixedpt *olfp,
const struct l_fixedpt *lfp)
{
uint32_t u, uf;
uint32_t ou, ouf;
uint32_t i;
uint32_t f;
double ff;
int signbit;
u = GET_BE_U_4(lfp->int_part);
ou = GET_BE_U_4(olfp->int_part);
uf = GET_BE_U_4(lfp->fraction);
ouf = GET_BE_U_4(olfp->fraction);
if (ou == 0 && ouf == 0) {
p_ntp_time(ndo, lfp);
return;
}
if (u > ou) { /* new is definitely greater than old */
signbit = 0;
i = u - ou;
f = uf - ouf;
if (ouf > uf) /* must borrow from high-order bits */
i -= 1;
} else if (u < ou) { /* new is definitely less than old */
signbit = 1;
i = ou - u;
f = ouf - uf;
if (uf > ouf) /* must borrow from the high-order bits */
i -= 1;
} else { /* int_part is zero */
i = 0;
if (uf > ouf) {
signbit = 0;
f = uf - ouf;
} else {
signbit = 1;
f = ouf - uf;
}
}
ff = f;
if (ff < 0.0) /* some compilers are buggy */
ff += FMAXINT;
ff = ff / FMAXINT; /* shift radix point by 32 bits */
f = (uint32_t)(ff * 1000000000.0); /* treat fraction as parts per billion */
ND_PRINT("%s%u.%09u", signbit ? "-" : "+", i, f);
}
/* Prints polling interval in log2 as seconds or fraction of second */
static void
p_poll(netdissect_options *ndo,
const int poll_interval)
{
if (poll_interval <= -32 || poll_interval >= 32)
return;