diff --git a/sbin/ping/ping.8 b/sbin/ping/ping.8 index a65dca790bfb..b368a890b7dc 100644 --- a/sbin/ping/ping.8 +++ b/sbin/ping/ping.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: ping.8,v 1.47 2006/03/21 22:54:46 pavel Exp $ +.\" $NetBSD: ping.8,v 1.48 2011/09/10 20:04:28 christos Exp $ .\" .\" Copyright (c) 1985, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" @(#)ping.8 8.2 (Berkeley) 12/11/93 .\" -.Dd March 21, 2006 +.Dd September 10, 2011 .Dt PING 8 .Os .Sh NAME @@ -40,7 +40,7 @@ packets to network hosts .Sh SYNOPSIS .Nm .Bk -words -.Op Fl adDfLnoPqQrRv +.Op Fl aCdDfLnoPqQrRv .Ek .Bk -words .Op Fl c Ar count @@ -93,7 +93,7 @@ datagrams (``pings'') have an IP and .Tn ICMP header, followed by a -.Dq struct timeval +.Dq struct timespec and then an arbitrary number of ``pad'' bytes used to fill out the packet. The options are as follows: @@ -108,6 +108,10 @@ Stop after sending (and waiting the specified delay to receive) .Ar count .Tn ECHO_RESPONSE packets. +.It Fl C +Send timestamps in compat format; two 32 bit words in little endian format, +the first one representing seconds, and the second one representing +microseconds. .It Fl d Set the .Dv SO_DEBUG @@ -322,12 +326,20 @@ will always be 8 bytes more than the requested data space (the .Tn ICMP header). .Pp -If the data space is at least eight bytes large, +If the data space is at least +.Dv sizeof(struct timespec) +(16) large, +.Nm +uses the first +.Dv sizeof(struct timespec) +byres to include a timestamp to compute round trip times. +Otherwise if the data space is at least eight bytes large (or the +.Fl C +flag is specified), .Nm uses the first eight bytes of this space to include a timestamp to compute round trip times. -If less than eight bytes of pad are specified, -no round trip times are given. +If there are not enough bytes of pad no round trip times are given. .Sh DUPLICATE AND DAMAGED PACKETS .Nm will report duplicate and damaged packets. diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c index 1f95c8d3c29d..39944dccf335 100644 --- a/sbin/ping/ping.c +++ b/sbin/ping/ping.c @@ -1,4 +1,4 @@ -/* $NetBSD: ping.c,v 1.98 2011/08/27 18:40:18 joerg Exp $ */ +/* $NetBSD: ping.c,v 1.99 2011/09/10 20:04:28 christos Exp $ */ /* * Copyright (c) 1989, 1993 @@ -58,7 +58,7 @@ #include #ifndef lint -__RCSID("$NetBSD: ping.c,v 1.98 2011/08/27 18:40:18 joerg Exp $"); +__RCSID("$NetBSD: ping.c,v 1.99 2011/09/10 20:04:28 christos Exp $"); #endif #include @@ -113,6 +113,7 @@ __RCSID("$NetBSD: ping.c,v 1.98 2011/08/27 18:40:18 joerg Exp $"); #define F_MCAST 0x2000 /* multicast target */ #define F_MCAST_NOLOOP 0x4000 /* no multicast loopback */ #define F_AUDIBLE 0x8000 /* audible output */ +#define F_TIMING64 0x10000 /* 64 bit time, nanoseconds */ #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC #define F_POLICY 0x10000 @@ -151,11 +152,13 @@ static char *fill_pat; static int s; /* Socket file descriptor */ static int sloop; /* Socket file descriptor/loopback */ -#define PHDR_LEN sizeof(struct tv32) /* size of timestamp header */ +#define PHDR_LEN sizeof(struct tv32) /* size of timestamp header */ +#define PHDR64_LEN sizeof(struct timespec) /* size of timestamp header */ static struct sockaddr_in whereto, send_addr; /* Who to ping */ static struct sockaddr_in src_addr; /* from where */ static struct sockaddr_in loc_addr; /* 127.1 */ -static int datalen = 64 - PHDR_LEN; /* How much data */ +static int datalen; /* How much data */ +static int phdrlen; #ifndef __NetBSD__ static char *progname; @@ -187,7 +190,7 @@ static int ident; /* our ID, in network byte order */ static int nreceived; /* # of packets we got back */ static double interval; /* interval between packets */ -static struct timeval interval_tv; +static struct timespec interval_tv; static double tmin = 999999999.0; static double tmax = 0.0; static double tsum = 0.0; /* sum of all times */ @@ -196,11 +199,11 @@ static double maxwait = 0.0; static int bufspace = IP_MAXPACKET; -static struct timeval now, clear_cache, last_tx, next_tx, first_tx; -static struct timeval last_rx, first_rx; +static struct timespec now, clear_cache, last_tx, next_tx, first_tx; +static struct timespec last_rx, first_rx; static int lastrcvd = 1; /* last ping sent has been received */ -static struct timeval jiggle_time; +static struct timespec jiggle_time; static int jiggle_cnt, total_jiggled, jiggle_direction = -1; __dead static void doit(void); @@ -211,10 +214,12 @@ static void summary(int); static void pinger(void); static void fill(void); static void rnd_fill(void); -static double diffsec(struct timeval *, struct timeval *); -static void timevaladd(struct timeval *, struct timeval *); -static void sec_to_timeval(const double, struct timeval *); -static double timeval_to_sec(const struct timeval *); +static double diffsec(struct timespec *, struct timespec *); +#if 0 +static void timespecadd(struct timespec *, struct timespec *); +#endif +static void sec_to_timespec(const double, struct timespec *); +static double timespec_to_sec(const struct timespec *); static void pr_pack(u_char *, int, struct sockaddr_in *); static u_int16_t in_cksum(u_int16_t *, u_int); static void pr_saddr(u_char *); @@ -232,6 +237,7 @@ main(int argc, char *argv[]) { int c, i, on = 1, hostind = 0; long l; + int len = -1, compat = 0; u_char ttl = 0; u_long tos = 0; char *p; @@ -275,12 +281,15 @@ main(int argc, char *argv[]) #endif /*IPSEC_POLICY_IPSEC*/ #endif while ((c = getopt(argc, argv, - "ac:dDfg:h:i:I:l:Lnop:PqQrRs:t:T:vw:" IPSECOPT)) != -1) { + "ac:CdDfg:h:i:I:l:Lnop:PqQrRs:t:T:vw:" IPSECOPT)) != -1) { #undef IPSECOPT switch (c) { case 'a': pingflags |= F_AUDIBLE; break; + case 'C': + compat = 1; + break; case 'c': npackets = strtol(optarg, &p, 0); if (*p != '\0' || npackets <= 0) @@ -341,7 +350,7 @@ main(int argc, char *argv[]) errx(1, "Bad/invalid packet size %s", optarg); if (l > MAXPACKET) errx(1, "packet size is too large"); - datalen = (int)l; + len = (int)l; break; case 'v': pingflags |= F_VERBOSE; @@ -416,7 +425,7 @@ main(int argc, char *argv[]) if (preload > 0 && prog_getuid()) errx(1, "Must be superuser to use -l"); #endif - sec_to_timeval(interval, &interval_tv); + sec_to_timespec(interval, &interval_tv); if ((pingflags & (F_AUDIBLE|F_FLOOD)) == (F_AUDIBLE|F_FLOOD)) warnx("Sorry, no audible output for flood pings"); @@ -446,8 +455,20 @@ main(int argc, char *argv[]) loc_addr.sin_len = sizeof(struct sockaddr_in); loc_addr.sin_addr.s_addr = htonl((127 << 24) + 1); - if (datalen >= (int)PHDR_LEN) /* can we time them? */ + if (len != -1) + datalen = len; + else + datalen = 64; + if (!compat && datalen >= (int)PHDR64_LEN) { /* can we time them? */ + pingflags |= F_TIMING64; + phdrlen = PHDR64_LEN; + } else if (datalen >= (int)PHDR_LEN) { /* can we time them? */ pingflags |= F_TIMING; + phdrlen = PHDR_LEN; + } else + phdrlen = 0; + datalen -= phdrlen; + packlen = datalen + 60 + 76; /* MAXIP + MAXICMP */ if ((packet = malloc(packlen)) == NULL) err(1, "Out of memory"); @@ -457,7 +478,7 @@ main(int argc, char *argv[]) } else if (pingflags & F_PING_RANDOM) { rnd_fill(); } else { - for (i = PHDR_LEN; i < datalen; i++) + for (i = phdrlen; i < datalen; i++) opack_icmp.icmp_data[i] = i; } @@ -649,7 +670,7 @@ main(int argc, char *argv[]) /* fire off them quickies */ for (i = 0; i < preload; i++) { - (void)gettimeofday(&now, 0); + clock_gettime(CLOCK_MONOTONIC, &now); pinger(); } @@ -667,9 +688,9 @@ doit(void) double sec, last, d_last; struct pollfd fdmaskp[1]; - (void)gettimeofday(&clear_cache,0); + (void)clock_gettime(CLOCK_MONOTONIC, &clear_cache); if (maxwait != 0) { - last = timeval_to_sec(&clear_cache) + maxwait; + last = timespec_to_sec(&clear_cache) + maxwait; d_last = 0; } else { last = 0; @@ -677,10 +698,10 @@ doit(void) } do { - (void)gettimeofday(&now,0); + clock_gettime(CLOCK_MONOTONIC, &now); if (last != 0) - d_last = last - timeval_to_sec(&now); + d_last = last - timespec_to_sec(&now); if (ntransmitted < npackets && d_last > 0) { /* send if within 100 usec or late for next packet */ @@ -708,7 +729,6 @@ doit(void) break; } - fdmaskp[0].fd = s; fdmaskp[0].events = POLLIN; cc = prog_poll(fdmaskp, 1, (int)(sec * 1000)); @@ -734,7 +754,7 @@ doit(void) } continue; } - (void)gettimeofday(&now, 0); + clock_gettime(CLOCK_MONOTONIC, &now); pr_pack(packet, cc, &from); } while (nreceived < npackets @@ -806,9 +826,10 @@ jiggle(int delta) /* * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet * will be added on by the kernel. The ID field is our UNIX process ID, - * and the sequence number is an ascending integer. The first PHDR_LEN bytes + * and the sequence number is an ascending integer. The first phdrlen bytes * of the data portion are used to hold a UNIX "timeval" struct in VAX - * byte-order, to compute the round-trip time. + * byte-order, to compute the round-trip time, or a UNIX "timespec" in native + * format. */ static void pinger(void) @@ -830,13 +851,13 @@ pinger(void) opack_icmp.icmp_id = ~ident; opack_icmp.icmp_cksum = 0; opack_icmp.icmp_cksum = in_cksum((u_int16_t *)&opack_icmp, - PHDR_LEN); + phdrlen); sw = 0; if (prog_setsockopt(sloop,IPPROTO_IP,IP_HDRINCL, (char *)&sw,sizeof(sw)) < 0) err(1, "Can't turn off special IP header"); if (prog_sendto(sloop, (char *) &opack_icmp, - PHDR_LEN, MSG_DONTROUTE, + phdrlen, MSG_DONTROUTE, (struct sockaddr *)&loc_addr, sizeof(struct sockaddr_in)) < 0) { /* @@ -853,16 +874,20 @@ pinger(void) (char *)&sw, sizeof(sw)) < 0) err(1, "Can't set special IP header"); - (void)gettimeofday(&clear_cache,0); + (void)clock_gettime(CLOCK_MONOTONIC, &clear_cache); } opack_icmp.icmp_type = ICMP_ECHO; opack_icmp.icmp_id = ident; - tv32.tv32_sec = (uint32_t)htonl(now.tv_sec); - tv32.tv32_usec = htonl(now.tv_usec); - if (pingflags & F_TIMING) + + if (pingflags & F_TIMING) { + tv32.tv32_sec = (uint32_t)htonl(now.tv_sec); + tv32.tv32_usec = htonl(now.tv_nsec / 1000); (void) memcpy(&opack_icmp.icmp_data[0], &tv32, sizeof(tv32)); - cc = datalen + PHDR_LEN; + } else if (pingflags & F_TIMING64) + (void) memcpy(&opack_icmp.icmp_data[0], &now, sizeof(now)); + + cc = datalen + phdrlen; opack_icmp.icmp_cksum = 0; opack_icmp.icmp_cksum = in_cksum((u_int16_t *)&opack_icmp, cc); @@ -896,7 +921,7 @@ pinger(void) */ if (diffsec(&next_tx, &now) <= interval) { do { - timevaladd(&next_tx, &interval_tv); + timespecadd(&next_tx, &interval_tv, &next_tx); } while (diffsec(&next_tx, &now) < -0.1); } @@ -928,7 +953,7 @@ pr_pack_sub(int cc, if (dupflag) (void)printf(" DUP!"); (void)printf(" ttl=%d", ttl); - if (pingflags & F_TIMING) + if (pingflags & (F_TIMING|F_TIMING64)) (void)printf(" time=%.3f ms", triptime*1000.0); /* @@ -983,6 +1008,8 @@ pr_pack(u_char *buf, icp = (struct icmp *)(buf + hlen); if (icp->icmp_type == ICMP_ECHOREPLY && icp->icmp_id == ident) { + struct timespec tv; + if (icp->icmp_seq == htons((u_int16_t)(ntransmitted-1))) lastrcvd = 1; last_rx = now; @@ -990,12 +1017,15 @@ pr_pack(u_char *buf, first_rx = last_rx; nreceived++; if (pingflags & F_TIMING) { - struct timeval tv; struct tv32 tv32; (void) memcpy(&tv32, icp->icmp_data, sizeof(tv32)); tv.tv_sec = (uint32_t)ntohl(tv32.tv32_sec); - tv.tv_usec = ntohl(tv32.tv32_usec); + tv.tv_nsec = ntohl(tv32.tv32_usec) * 1000; + } else if (pingflags & F_TIMING64) + (void) memcpy(&tv, icp->icmp_data, sizeof(tv)); + + if (pingflags & (F_TIMING|F_TIMING64)) { triptime = diffsec(&last_rx, &tv); tsum += triptime; tsumsq += triptime * triptime; @@ -1066,12 +1096,12 @@ pr_pack(u_char *buf, PR_PACK_SUB(); /* check the data */ - if (datalen > (int)PHDR_LEN + if (datalen > phdrlen && !(pingflags & F_PING_RANDOM) - && memcmp(icp->icmp_data + PHDR_LEN, - opack_icmp.icmp_data + PHDR_LEN, - datalen-PHDR_LEN)) { - for (i=PHDR_LEN; iicmp_data + phdrlen, + opack_icmp.icmp_data + phdrlen, + datalen - phdrlen)) { + for (i = phdrlen; i < datalen; i++) { if (icp->icmp_data[i] != opack_icmp.icmp_data[i]) break; @@ -1081,8 +1111,8 @@ pr_pack(u_char *buf, " %#x but was %#x", i, (u_char)opack_icmp.icmp_data[i], (u_char)icp->icmp_data[i]); - for (i=PHDR_LEN; iicmp_data[i]); } @@ -1235,44 +1265,46 @@ in_cksum(u_int16_t *p, u_int len) /* - * compute the difference of two timevals in seconds + * compute the difference of two timespecs in seconds */ static double -diffsec(struct timeval *timenow, - struct timeval *then) +diffsec(struct timespec *timenow, + struct timespec *then) { if (timenow->tv_sec == 0) return -1; - return ((int32_t)((uint32_t)timenow->tv_sec - (uint32_t)then->tv_sec) - * 1.0 + (timenow->tv_usec - then->tv_usec)/1000000.0); + return (timenow->tv_sec - then->tv_sec) + * 1.0 + (timenow->tv_nsec - then->tv_nsec) / 1000000000.0; } +#if 0 static void -timevaladd(struct timeval *t1, - struct timeval *t2) +timespecadd(struct timespec *t1, + struct timespec *t2) { t1->tv_sec += t2->tv_sec; - if ((t1->tv_usec += t2->tv_usec) >= 1000000) { + if ((t1->tv_nsec += t2->tv_nsec) >= 1000000000) { t1->tv_sec++; - t1->tv_usec -= 1000000; + t1->tv_nsec -= 1000000000; } } +#endif static void -sec_to_timeval(const double sec, struct timeval *tp) +sec_to_timespec(const double sec, struct timespec *tp) { tp->tv_sec = sec; - tp->tv_usec = (sec - tp->tv_sec) * 1000000.0; + tp->tv_nsec = (sec - tp->tv_sec) * 1000000000.0; } static double -timeval_to_sec(const struct timeval *tp) +timespec_to_sec(const struct timespec *tp) { - return tp->tv_sec + tp->tv_usec / 1000000.0; + return tp->tv_sec + tp->tv_nsec / 1000000000.0; } @@ -1768,7 +1800,7 @@ fill(void) &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], &pat[13], &pat[14], &pat[15]); - for (k=PHDR_LEN, j = 0; k <= datalen; k++) { + for (k = phdrlen, j = 0; k <= datalen; k++) { opack_icmp.icmp_data[k] = pat[j]; if (++j >= i) j = 0; @@ -1778,7 +1810,7 @@ fill(void) (void)printf("PATTERN: 0x"); for (j=0; j>24; } @@ -1856,7 +1888,7 @@ usage(void) #endif /*IPSEC*/ (void)fprintf(stderr, "usage: \n" - "%s [-adDfLnoPqQrRv] [-c count] [-g gateway] [-h host]" + "%s [-aCdDfLnoPqQrRv] [-c count] [-g gateway] [-h host]" " [-i interval] [-I addr]\n" " [-l preload] [-p pattern] [-s size] [-t tos] [-T ttl]" " [-w maxwait] " IPSECOPT "host\n",