static char sccsid
[] = "@(#)ping.c 4.3 (Berkeley) %G%";
* Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
* measure round-trip-delays and packet loss across network paths.
* U. S. Army Ballistic Research Laboratory
* Modified at Uc Berkeley
* Public Domain. Distribution Unlimited.
* More statistics could always be gathered.
* This program has to run SUID to ROOT to access the ICMP socket.
#include <netinet/in_systm.h>
#include <netinet/ip_icmp.h>
#define MAXWAIT 10 /* max time to wait for response, sec. */
int s
; /* Socket file descriptor */
struct hostent
*hp
; /* Pointer to host info */
struct timezone tz
; /* leftover */
struct sockaddr whereto
;/* Who to ping */
int datalen
; /* How much data */
char usage
[] = "Usage: ping [-drv] host [data size]\n";
int ntransmitted
= 0; /* sequence # for outbound packets = #sent */
int nreceived
= 0; /* # of packets we got back */
int tsum
= 0; /* sum of all times, for doing average */
struct sockaddr_in
*to
= (struct sockaddr_in
*) &whereto
;
while (argc
> 0 && *av
[0] == '-') {
while (*++av
[0]) switch (*av
[0]) {
bzero( (char *)&whereto
, sizeof(struct sockaddr
) );
hp
= gethostbyname(av
[0]);
to
->sin_family
= hp
->h_addrtype
;
bcopy(hp
->h_addr
, (caddr_t
)&to
->sin_addr
, hp
->h_length
);
to
->sin_family
= AF_INET
;
to
->sin_addr
.s_addr
= inet_addr(av
[1]);
if (to
->sin_addr
.s_addr
== -1) {
printf("%s: unknown host %s\n", argv
[0], av
[1]);
if (datalen
>= sizeof(struct timeval
))
ident
= getpid() & 0xFFFF;
if ((s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_ICMP
)) < 0) {
setsockopt(s
, SOL_SOCKET
, SO_DEBUG
, &on
, sizeof(on
));
if (options
& SO_DONTROUTE
)
setsockopt(s
, SOL_SOCKET
, SO_DONTROUTE
, &on
, sizeof(on
));
printf("PING %s: %d data bytes\n", hostname
, datalen
);
setbuffer( stdout
, ttyobuf
, sizeof(ttyobuf
) );
signal( SIGINT
, finish
);
signal(SIGALRM
, catcher
);
catcher(); /* start things going */
int len
= sizeof (packet
);
int fromlen
= sizeof (from
);
if ( (cc
=recvfrom(s
, packet
, len
, 0, &from
, &fromlen
)) < 0) {
perror("ping: recvfrom");
pr_pack( packet
, cc
, &from
);
if (npackets
&& nreceived
>= npackets
)
* This routine causes another PING to be transmitted, and then
* schedules another SIGALRM for 1 second from now.
* Our sense of time will slowly skew (ie, packets will not be launched
* exactly at 1-second intervals). This does not affect the quality
* of the delay and loss statistics.
if (npackets
== 0 || ntransmitted
< npackets
)
waittime
= 2 * tmax
/ 1000;
* 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 8 bytes
* of the data portion are used to hold a UNIX "timeval" struct in VAX
* byte-order, to compute the round-trip time.
static u_char outpack
[1024];
register struct icmp
*icp
= (struct icmp
*) outpack
;
register struct timeval
*tp
= (struct timeval
*) &outpack
[8];
register u_char
*datap
= &outpack
[8+sizeof(struct timeval
)];
icp
->icmp_type
= ICMP_ECHO
;
icp
->icmp_seq
= ntransmitted
++;
icp
->icmp_id
= ident
; /* ID */
cc
= datalen
+8; /* skips ICMP portion */
for( i
=8; i
<datalen
; i
++) /* skip 8 for time */
/* Compute ICMP checksum here */
icp
->icmp_cksum
= in_cksum( icp
, cc
);
/* cc = sendto(s, msg, len, flags, to, tolen) */
i
= sendto( s
, outpack
, cc
, 0, &whereto
, sizeof(struct sockaddr
) );
if( i
<0 ) perror("sendto");
printf("ping: wrote %s %d chars, ret=%d\n",
* Convert an ICMP "type" field to a printable string.
* Print out the packet, if it came from us. This logic is necessary
* because ALL readers of the ICMP socket get a copy of ALL ICMP packets
* which arrive ('tis only fair). This permits multiple copies of this
* program to be run without having intermingled output (or statistics!).
register struct icmp
*icp
;
struct sockaddr_in
*from
;
register long *lp
= (long *) packet
;
struct timeval
*tp
= (struct timeval
*) &packet
[8];
from
->sin_addr
.s_addr
= ntohl( from
->sin_addr
.s_addr
);
gettimeofday( &tv
, &tz
);
if( icp
->icmp_type
!= ICMP_ECHOREPLY
) {
printf("%d bytes from x%x: ", cc
, from
->sin_addr
.s_addr
);
printf("icmp_type=%d (%s)\n",
icp
->icmp_type
, pr_type(icp
->icmp_type
) );
printf("x%2.2x: x%8.8x\n", i
*sizeof(long), *lp
++ );
printf("icmp_code=%d\n", icp
->icmp_code
);
if( icp
->icmp_id
!= ident
)
return; /* 'Twas not our ECHO */
printf("%d bytes from x%x: ", cc
, from
->sin_addr
.s_addr
);
printf("icmp_seq=%d. ", icp
->icmp_seq
);
triptime
= tv
.tv_sec
*1000+(tv
.tv_usec
/1000);
printf("time=%d. ms\n", triptime
);
* Checksum routine for Internet Protocol family headers (VAX Version).
* Shamelessly pilfered from /sys/vax/in_cksum.c, with all the MBUF stuff
register int nleft
= len
; /* on vax, (user mode), r11 */
register int xxx
; /* on vax, (user mode), r10 */
register u_short
*w
= addr
; /* on vax, known to be r9 */
register int sum
= 0; /* on vax, known to be r8 */
* Force to long boundary so we do longword aligned
* memory operations. It is too hard to do byte
* adjustment, do only word adjustment.
if (((int)w
&0x2) && nleft
>= 2) {
* Do as much of the checksum as possible 32 bits at at time.
* In fact, this loop is unrolled to make overhead from
* We can do a 16 bit ones complement sum 32 bits at a time
* because the 32 bit register is acting as two 16 bit
* registers for adding, with carries from the low added
* into the high (by normal carry-chaining) and carries
* from the high carried into the low on the next word
* by use of the adwc instruction. This lets us run
* this loop at almost memory speed.
* Here there is the danger of high order carry out, and
while ((nleft
-= 32) >= 0) {
asm("clrl r0"); /* clears carry */
#define ADD asm("adwc (r9)+,r8;");
ADD
; ADD
; ADD
; ADD
; ADD
; ADD
; ADD
; ADD
;
while ((nleft
-= 8) >= 0) {
* Now eliminate the possibility of carry-out's by
* folding back to a 16 bit number (adding high and
* low parts together.) Then mop up trailing words
{ asm("ashl $-16,r8,r0; addw2 r0,r8");
asm("adwc $0,r8; movzwl r8,r8"); }
while ((nleft
-= 2) >= 0) {
asm("movzwl (r9)+,r0; addl2 r0,r8");
* Add together high and low parts of sum
* and carry to get cksum.
* Have to be careful to not drop the last
{ asm("ashl $-16,r8,r0; addw2 r0,r8; adwc $0,r8");
asm("mcoml r8,r8; movzwl r8,r8"); }
* Subtract 2 timeval structs: out = out - in.
* Out is assumed to be >= in.
register struct timeval
*out
, *in
;
if( (out
->tv_usec
-= in
->tv_usec
) < 0 ) {
out
->tv_sec
-= in
->tv_sec
;
* Print out statistics, and give up.
* Heavily buffered STDIO is used here, so that all the statistics
* will be written with 1 sys-write call. This is nice when more
* than one copy of the program is running on a terminal; it prevents
* the statistics output from becomming intermingled.
printf("\n----%s PING Statistics----\n", hostname
);
printf("%d packets transmitted, ", ntransmitted
);
printf("%d packets received, ", nreceived
);
printf("%d%% packet loss",
(int) (((ntransmitted
-nreceived
)*100) / ntransmitted
) );
printf("round-trip (ms) min/avg/max = %d/%d/%d\n",