xref: /haiku/src/bin/network/ping/ping.c (revision a3e794ae459fec76826407f8ba8c94cd3535f128)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Mike Muuss.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 /*
38  *			P I N G . C
39  *
40  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
41  * measure round-trip-delays and packet loss across network paths.
42  *
43  * Author -
44  *	Mike Muuss
45  *	U. S. Army Ballistic Research Laboratory
46  *	December, 1983
47  *
48  * Status -
49  *	Public Domain.  Distribution Unlimited.
50  * Bugs -
51  *	More statistics could always be gathered.
52  *	This program has to run SUID to ROOT to access the ICMP socket.
53  */
54 
55 #include <OS.h>
56 
57 #include <sys/param.h>
58 #include <sys/socket.h>
59 #include <sys/time.h>
60 
61 #include <netinet/in.h>
62 #include "netinet/ip.h"
63 #include "netinet/ip_icmp.h"
64 #include <netinet/ip_var.h>
65 #include <arpa/inet.h>
66 #include <netdb.h>
67 #include <signal.h>
68 #include <unistd.h>
69 #include <stdio.h>
70 #include <ctype.h>
71 #include <errno.h>
72 #include <string.h>
73 #include <stdlib.h>
74 #include <sys/select.h>
75 
76 #define	DEFDATALEN	(64 - 8)		/* default data length */
77 #define	MAXIPLEN	60
78 #define	MAXICMPLEN	76
79 #define	MAXPAYLOAD	(IP_MAXPACKET - MAXIPLEN - 8) /* max ICMP payload size */
80 #define	MAXWAIT_DEFAULT	10			/* secs to wait for response */
81 #define	NROUTES		9			/* number of record route slots */
82 
83 #define	A(bit)		rcvd_tbl[(bit)>>3]	/* identify byte in array */
84 #define	B(bit)		(1 << ((bit) & 0x07))	/* identify bit in byte */
85 #define	SET(bit)	(A(bit) |= B(bit))
86 #define	CLR(bit)	(A(bit) &= (~B(bit)))
87 #define	TST(bit)	(A(bit) & B(bit))
88 
89 /* various options */
90 int options;
91 #define	F_FLOOD		0x001
92 #define	F_INTERVAL	0x002
93 #define	F_NUMERIC	0x004
94 #define	F_PINGFILLED	0x008
95 #define	F_QUIET		0x010
96 #define	F_RROUTE	0x020
97 #define	F_SO_DEBUG	0x040
98 #define	F_SO_DONTROUTE	0x080
99 #define	F_VERBOSE	0x100
100 #define	F_SADDR		0x200
101 #define	F_HDRINCL       0x400
102 #define	F_TTL		0x800
103 
104 /* multicast options */
105 int moptions;
106 #define	MULTICAST_NOLOOP	0x001
107 #define	MULTICAST_TTL		0x002
108 #define	MULTICAST_IF		0x004
109 
110 /*
111  * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
112  * number of received sequence numbers we can keep track of.  Change 128
113  * to 8192 for complete accuracy...
114  */
115 #define	MAX_DUP_CHK	(8 * 128)
116 int mx_dup_ck = MAX_DUP_CHK;
117 char rcvd_tbl[MAX_DUP_CHK / 8];
118 
119 struct sockaddr whereto;	/* who to ping */
120 struct sockaddr_in whence;		/* Which interface we come from */
121 int datalen = DEFDATALEN;
122 int s;				/* socket file descriptor */
123 u_char outpackhdr[IP_MAXPACKET]; /* Max packet size = 65535 */
124 u_char *outpack = outpackhdr+sizeof(struct ip);
125 char BSPACE = '\b';		/* characters written for flood */
126 char DOT = '.';
127 char *hostname;
128 int ident;			/* process id to identify our packets */
129 
130 /* counters */
131 long npackets;			/* max packets to transmit */
132 long nreceived;			/* # of packets we got back */
133 long nrepeats;			/* number of duplicates */
134 long ntransmitted;		/* sequence # for outbound packets = #sent */
135 double interval = 1;		/* interval between packets */
136 
137 /* timing */
138 int timing;			/* flag to do timing */
139 int maxwait = MAXWAIT_DEFAULT;	/* max seconds to wait for response */
140 uint64 tmin = 999999999;	/* minimum round trip time in millisec */
141 uint64 tmax = 0;		/* maximum round trip time in millisec */
142 uint64 tsum = 0;		/* sum of all times in millisec, for doing average */
143 uint64 tsumsq = 0;		/* sum of all times squared, for std. dev. */
144 
145 #ifdef SIGINFO
146 int reset_kerninfo;
147 #endif
148 
149 #define DEFAULT_BUFSPACE	60*1024 /* default read buffer size */
150 int bufspace = DEFAULT_BUFSPACE;
151 
152 void fill(char *, char *);
153 void catcher(int);
154 void prtsig(int);
155 void finish(int);
156 void summary(int);
157 int compute_in_cksum (u_short *, int);
158 void pinger(void);
159 char *pr_addr (in_addr_t);
160 int check_icmph (struct ip *);
161 void pr_icmph (struct icmp *);
162 void pr_pack (char *, int, struct sockaddr_in *);
163 void pr_retip (struct ip *);
164 void pr_iph(struct ip *ip);
165 uint64 qsqrt (uint64);
166 void usage(void);
167 
168 
169 static void err(int exitval, char *where)
170 {
171 	printf("error: %s: error %d [%s]\n", where, errno, strerror(errno));
172 	exit(exitval);
173 }
174 
175 static void errx(int exitval, char *fmt_string, char *value)
176 {
177 	printf("error: ");
178 	printf(fmt_string, value);
179 	printf("\n");
180 	exit(exitval);
181 }
182 
183 int main(int argc, char **argv)
184 {
185 	struct timeval timeout;
186 	struct hostent *hp;
187 	struct sockaddr_in *to;
188 	struct protoent *proto;
189 	struct in_addr saddr;
190 	int i;
191 	int ch, hold = 1, packlen, preload;
192 	int maxsize, fdmasks;
193 	socklen_t maxsizelen;
194 	u_char *datap, *packet;
195 	char *target, hnamebuf[MAXHOSTNAMELEN];
196 	u_char ttl = MAXTTL, loop = 1, df = 0;
197 	int tos = 0;
198 #ifdef IP_OPTIONS
199 	char rspace[3 + 4 * NROUTES + 1];	/* record route space */
200 #endif
201 	fd_set *fdmaskp;
202 
203 	if (!(proto = getprotobyname("icmp")))
204 		err(1, "unknown protocol icmp");
205 	if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0)
206 		err(1, "socket");
207 
208 	/* revoke privs */
209 //	seteuid(getuid());
210 //	setuid(getuid());
211 
212 	preload = 0;
213 	datap = &outpack[8 + sizeof(uint64)];
214 	while ((ch = getopt(argc, argv, "DI:LRS:c:dfh:i:l:np:qrs:T:t:vw:")) != -1)
215 		switch(ch) {
216 		case 'c':
217 			npackets = strtol(optarg, NULL, 0);
218 			if (npackets <= 0)
219 				errx(1, "bad number of packets to transmit: %s",
220 				    optarg);
221 			break;
222 		case 'D':
223 			options |= F_HDRINCL;
224 			df = -1;
225 			break;
226 		case 'd':
227 			options |= F_SO_DEBUG;
228 			break;
229 		case 'f':
230 			if (getuid())
231 				errx(1, "%s", strerror(EPERM));
232 			options |= F_FLOOD;
233 			setbuf(stdout, (char *)NULL);
234 			break;
235 		case 'I':
236 		case 'S':	/* deprecated */
237 			if (inet_aton(optarg, &saddr) == 0) {
238 				if ((hp = gethostbyname(optarg)) == NULL)
239 					errx(1, "bad interface address: %s",
240 					     optarg);
241 				memcpy(&saddr, hp->h_addr, sizeof(saddr));
242 			}
243 			options |= F_SADDR;
244 			break;
245 		case 'i':		/* wait between sending packets */
246 			interval = strtod(optarg, NULL);
247 
248 			if (interval <= 0 || interval >= INT_MAX)
249 				errx(1, "bad timing interval: %s", optarg);
250 
251 			if (interval < 1)
252 				if (getuid())
253 					errx(1, "%s: only root may use interval < 1s", strerror(EPERM));
254 
255 			if (interval < 0.01)
256 				interval = 0.01;
257 
258 			options |= F_INTERVAL;
259 			break;
260 		case 'L':
261 			moptions |= MULTICAST_NOLOOP;
262 			loop = 0;
263 			break;
264 		case 'l':
265 			if (getuid())
266 				errx(1, "%s", strerror(EPERM));
267 			preload = strtol(optarg, NULL, 0);
268 			if (preload < 0)
269 				errx(1, "bad preload value: %s", optarg);
270 			break;
271 		case 'n':
272 			options |= F_NUMERIC;
273 			break;
274 		case 'p':		/* fill buffer with user pattern */
275 			options |= F_PINGFILLED;
276 			fill((char *)datap, optarg);
277 				break;
278 		case 'q':
279 			options |= F_QUIET;
280 			break;
281 		case 'R':
282 			options |= F_RROUTE;
283 			break;
284 		case 'r':
285 			options |= F_SO_DONTROUTE;
286 			break;
287 		case 's':		/* size of packet to send */
288 			datalen = strtol(optarg, NULL, 0);
289 			if (datalen <= 0)
290 				errx(1, "bad packet size: %s", optarg);
291 			if (datalen > MAXPAYLOAD)
292 				errx(1, "packet size too large: %s", optarg);
293 			break;
294 		case 'T':
295 			options |= F_HDRINCL;
296 			tos = strtoul(optarg, NULL, 0);
297 			if (tos > 0xFF)
298 				errx(1, "bad tos value: %s", optarg);
299 			break;
300 		case 't':
301 			options |= F_TTL;
302 			ttl = strtol(optarg, NULL, 0);
303 			if (ttl <= 0)
304 				errx(1, "bad ttl value: %s", optarg);
305 			if (ttl > 255)
306 				errx(1, "ttl value too large: %s", optarg);
307 			break;
308 		case 'v':
309 			options |= F_VERBOSE;
310 			break;
311 		case 'w':
312 			maxwait = strtol(optarg, NULL, 0);
313 			if (maxwait <= 0)
314 				errx(1, "bad maxwait value: %s", optarg);
315 			break;
316 		default:
317 			usage();
318 		}
319 	argc -= optind;
320 	argv += optind;
321 
322 	if (argc != 1)
323 		usage();
324 
325 	target = *argv;
326 
327 	memset(&whereto, 0, sizeof(struct sockaddr));
328 	to = (struct sockaddr_in *)&whereto;
329 	to->sin_len = sizeof(struct sockaddr_in);
330 	to->sin_family = AF_INET;
331 	if (inet_aton(target, &to->sin_addr) != 0)
332 		hostname = target;
333 	else {
334 		hp = gethostbyname(target);
335 		if (!hp)
336 			errx(1, "unknown host: %s", target);
337 		to->sin_family = hp->h_addrtype;
338 		memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
339 		(void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf));
340 		hostname = hnamebuf;
341 	}
342 
343 	if (options & F_FLOOD && options & F_INTERVAL)
344 		err(1, "-f and -i options are incompatible");
345 
346 	if (datalen >= (int) sizeof(uint64))	/* can we time transfer */
347 		timing = 1;
348 	packlen = datalen + MAXIPLEN + MAXICMPLEN;
349 	if (!(packet = (u_char *)malloc((u_int)packlen)))
350 		err(1, "malloc");
351 	if (!(options & F_PINGFILLED))
352 		for (i = sizeof(bigtime_t); i < datalen; ++i)
353 			*datap++ = i;
354 
355 	ident = getpid() & 0xFFFF;
356 
357 	if (options & F_SADDR) {
358 		if (IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
359 			moptions |= MULTICAST_IF;
360 		else {
361 			memset(&whence, 0, sizeof(whence));
362 			whence.sin_len = sizeof(whence);
363 			whence.sin_family = AF_INET;
364 			memcpy(&whence.sin_addr.s_addr, &saddr, sizeof(saddr));
365 			if (bind(s, (struct sockaddr*)&whence,
366 			    sizeof(whence)) < 0)
367 				err(1, "bind");
368 		}
369 	}
370 
371 	if (options & F_SO_DEBUG)
372 		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
373 		    sizeof(hold));
374 	if (options & F_SO_DONTROUTE)
375 		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
376 		    sizeof(hold));
377 
378 	if (options & F_TTL) {
379 		if (IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
380 		    moptions |= MULTICAST_TTL;
381 		else
382 		    options |= F_HDRINCL;
383 	}
384 
385 	if (options & F_RROUTE && options & F_HDRINCL)
386 		err(1, "-R option and -D or -T, or -t to unicast destinations"
387 		     " are incompatible");
388 
389 	if (options & F_HDRINCL) {
390 		struct ip *ip = (struct ip*)outpackhdr;
391 
392 		setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold));
393 		ip->ip_v = IPVERSION;
394 		ip->ip_hl = sizeof(struct ip) >> 2;
395 		ip->ip_tos = tos;
396 		ip->ip_id = 0;
397 		ip->ip_off = htons(df?IP_DF:0);
398 		ip->ip_ttl = ttl;
399 		ip->ip_p = proto->p_proto;
400 		ip->ip_src.s_addr = INADDR_ANY;
401 		ip->ip_dst = to->sin_addr;
402 	}
403 
404 	/* record route option */
405 	if (options & F_RROUTE) {
406 		if (IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
407 			err(1, "record route not valid to multicast destinations");
408 #ifdef IP_OPTIONS
409 		rspace[IPOPT_OPTVAL] = IPOPT_RR;
410 		rspace[IPOPT_OLEN] = sizeof(rspace)-1;
411 		rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
412 		if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
413 		    sizeof(rspace)) < 0) {
414 			perror("ping: record route");
415 			exit(1);
416 		}
417 #else
418 		err(1, "record route not available in this implementation");
419 #endif /* IP_OPTIONS */
420 	}
421 
422 	if ((moptions & MULTICAST_NOLOOP) &&
423 	    setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
424 		       sizeof(loop)) < 0)
425 		err(1, "setsockopt IP_MULTICAST_LOOP");
426 	if ((moptions & MULTICAST_TTL) &&
427 	    setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
428 		       sizeof(ttl)) < 0)
429 		err(1, "setsockopt IP_MULTICAST_TTL");
430 	if ((moptions & MULTICAST_IF) &&
431 	    setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &saddr,
432 		       sizeof(saddr)) < 0)
433 		err(1, "setsockopt IP_MULTICAST_IF");
434 
435 	/*
436 	 * When trying to send large packets, you must increase the
437 	 * size of both the send and receive buffers...
438 	 */
439 	maxsizelen = sizeof maxsize;
440 	if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &maxsize, &maxsizelen) < 0)
441 		err(1, "getsockopt");
442 	if (maxsize < packlen &&
443 	    setsockopt(s, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(maxsize)) < 0)
444 		err(1, "setsockopt");
445 	/*
446 	 * When pinging the broadcast address, you can get a lot of answers.
447 	 * Doing something so evil is useful if you are trying to stress the
448 	 * ethernet, or just want to fill the arp cache to get some stuff for
449 	 * /etc/ethers.
450 	 */
451 	while (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
452 	    (void*)&bufspace, sizeof(bufspace)) < 0) {
453 		if ((bufspace -= 1024) <= 0)
454 			err(1, "Cannot set the receive buffer size");
455 	}
456 	if (bufspace < DEFAULT_BUFSPACE)
457 		printf("Could only allocate a receive buffer of %i bytes (default %i)\n",
458 		    bufspace, DEFAULT_BUFSPACE);
459 
460 	if (to->sin_family == AF_INET)
461 		(void)printf("PING %s (%s): %d data bytes\n", hostname,
462 		    inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),
463 		    datalen);
464 	else
465 		(void)printf("PING %s: %d data bytes\n", hostname, datalen);
466 
467 	(void)signal(SIGINT, finish);
468 	(void)signal(SIGALRM, catcher);
469 #ifdef SIGINFO
470 	(void)signal(SIGINFO, prtsig);
471 #endif
472 
473 	while (preload--)		/* fire off them quickies */
474 		pinger();
475 
476 	if ((options & F_FLOOD) == 0)
477 		catcher(0);		/* start things going */
478 
479 	fdmasks = _howmany(s+1, NFDBITS) * sizeof(fd_mask);
480 	if ((fdmaskp = (fd_set *)malloc(fdmasks)) == NULL)
481 		err(1, "malloc");
482 
483 	for (;;) {
484 		struct sockaddr_in from;
485 		int cc;
486 		socklen_t fromlen;
487 		sigset_t omask, nmask;
488 
489 		if (options & F_FLOOD) {
490 			pinger();
491 			timeout.tv_sec = 0;
492 			timeout.tv_usec = 10000;
493 			memset(fdmaskp, 0, fdmasks);
494 			FD_SET(s, fdmaskp);
495 			if (select(s + 1, (fd_set *)fdmaskp, (fd_set *)NULL,
496 			    (fd_set *)NULL, &timeout) < 1)
497 				continue;
498 		}
499 		fromlen = sizeof(from);
500 		if ((cc = recvfrom(s, (char *)packet, packlen, 0,
501 		    (struct sockaddr *)&from, &fromlen)) < 0) {
502 			if (errno == EINTR)
503 				continue;
504 			perror("ping: recvfrom");
505 			continue;
506 		}
507 		sigemptyset(&nmask);
508 		sigaddset(&nmask, SIGALRM);
509 		sigprocmask(SIG_BLOCK, &nmask, &omask);
510 		pr_pack((char *)packet, cc, &from);
511 		sigprocmask(SIG_SETMASK, &omask, NULL);
512 		if (npackets && nreceived >= npackets)
513 			break;
514 	}
515 	free(fdmaskp);
516 	finish(0);
517 	/* NOTREACHED */
518 	exit(0);	/* Make the compiler happy */
519 }
520 
521 /*
522  * catcher --
523  *	This routine causes another PING to be transmitted, and then
524  * schedules another SIGALRM for 1 second from now.
525  *
526  * bug --
527  *	Our sense of time will slowly skew (i.e., packets will not be
528  * launched exactly at 1-second intervals).  This does not affect the
529  * quality of the delay and loss statistics.
530  */
531 void catcher(int sig)
532 {
533 	int waittime;
534 	int save_errno = errno;
535 
536 	pinger();
537 	(void)signal(SIGALRM, catcher);
538 
539 	if (!npackets || ntransmitted < npackets)
540 		(void)alarm((uint)interval);
541 	else {
542 		if (nreceived) {
543 			waittime = 2 * tmax / 1000000;
544 			if (!waittime)
545 				waittime = 1;
546 		} else
547 			waittime = maxwait;
548 		(void)signal(SIGALRM, finish);
549 		(void)alarm((uint)waittime);
550 	}
551 	errno = save_errno;
552 }
553 
554 /*
555  * Print statistics when SIGINFO is received.
556  * XXX not race safe
557  */
558 void prtsig(int sig)
559 {
560 	int save_errno = errno;
561 
562 	summary(0);
563 	errno = save_errno;
564 }
565 
566 /*
567  * pinger --
568  *	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
569  * will be added on by the kernel.  The ID field is our UNIX process ID,
570  * and the sequence number is an ascending integer.  The first 8 bytes
571  * of the data portion are used to hold a UNIX "timeval" struct in VAX
572  * byte-order, to compute the round-trip time.
573  */
574 void pinger(void)
575 {
576 	struct icmp *icp;
577 	int cc;
578 	int i;
579 	char *packet = outpack;
580 
581 	icp = (struct icmp *)outpack;
582 	icp->icmp_type = ICMP_ECHO;
583 	icp->icmp_code = 0;
584 	icp->icmp_cksum = 0;
585 	icp->icmp_seq = htons(ntransmitted++);
586 	icp->icmp_id = ident;			/* ID */
587 
588 	CLR(ntohs(icp->icmp_seq) % mx_dup_ck);
589 
590 	if (timing) {
591 		bigtime_t tm = real_time_clock_usecs();
592 		memcpy(&outpack[8], &tm, sizeof(tm));
593 	}
594 
595 	cc = datalen + 8;			/* skips ICMP portion */
596 
597 	/* compute ICMP checksum here */
598 	icp->icmp_cksum = compute_in_cksum((u_short *)icp, cc);
599 
600 	if (options & F_HDRINCL) {
601 		struct ip *ip = (struct ip*)outpackhdr;
602 
603 		packet = (char*)ip;
604 		cc += sizeof(struct ip);
605 		ip->ip_len = htons(cc);
606 		ip->ip_sum = compute_in_cksum((u_short *)outpackhdr, cc);
607 	}
608 
609 	i = sendto(s, (char *)packet, cc, 0, &whereto,
610 		   sizeof(struct sockaddr));
611 
612 	if (i < 0 || i != cc)  {
613 		if (i < 0)
614 			perror("ping: sendto");
615 		(void)printf("ping: wrote %s %d chars, ret=%d\n",
616 		    hostname, cc, i);
617 	}
618 	if (!(options & F_QUIET) && options & F_FLOOD)
619 		(void)write(STDOUT_FILENO, &DOT, 1);
620 }
621 
622 /*
623  * pr_pack --
624  *	Print out the packet, if it came from us.  This logic is necessary
625  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
626  * which arrive ('tis only fair).  This permits multiple copies of this
627  * program to be run without having intermingled output (or statistics!).
628  */
629 void pr_pack(char *buf, int cc, struct sockaddr_in *from)
630 {
631 	struct icmp *icp;
632 	in_addr_t l;
633 	u_int i, j;
634 	u_char *cp, *dp;
635 	static int old_rrlen;
636 	static char old_rr[MAX_IPOPTLEN];
637 	struct ip *ip, *ip2;
638 //	struct timeval tv, tp;
639 	char *pkttime;
640 	uint64 triptime = 0;
641 	int hlen, hlen2, dupflag;
642 
643 //	(void)gettimeofday(&tv, (struct timezone *)NULL);
644 
645 	/* Check the IP header */
646 	ip = (struct ip *)buf;
647 	hlen = ip->ip_hl << 2;
648 	if (cc < hlen + ICMP_MINLEN) {
649 		if (options & F_VERBOSE)
650 			printf("packet too short (%d bytes) from %s\n", cc,
651 			  inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
652 		return;
653 	}
654 
655 	/* Now the ICMP part */
656 	cc -= hlen;
657 	icp = (struct icmp *)(buf + hlen);
658 	if (icp->icmp_type == ICMP_ECHOREPLY) {
659 		if (icp->icmp_id != ident)
660 			return;			/* 'Twas not our ECHO */
661 		++nreceived;
662 		if (timing) {
663 			bigtime_t tvi;
664 
665 #ifndef icmp_data
666 			pkttime = (char *)&icp->icmp_ip;
667 #else
668 			pkttime = (char *)icp->icmp_data;
669 #endif
670 			memcpy(&tvi, pkttime, sizeof tvi);
671 			triptime = real_time_clock_usecs() - tvi;
672 			tsum += triptime;
673 			tsumsq += triptime * triptime;
674 			if (triptime < tmin)
675 				tmin = triptime;
676 			if (triptime > tmax)
677 				tmax = triptime;
678 		}
679 
680 		if (TST(ntohs(icp->icmp_seq) % mx_dup_ck)) {
681 			++nrepeats;
682 			--nreceived;
683 			dupflag = 1;
684 		} else {
685 			SET(ntohs(icp->icmp_seq) % mx_dup_ck);
686 			dupflag = 0;
687 		}
688 
689 		if (options & F_QUIET)
690 			return;
691 
692 		if (options & F_FLOOD)
693 			(void)write(STDOUT_FILENO, &BSPACE, 1);
694 		else {
695 			(void)printf("%d bytes from %s: icmp_seq=%u", cc,
696 			   inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
697 			   ntohs(icp->icmp_seq));
698 			(void)printf(" ttl=%d", ip->ip_ttl);
699 			if (timing)
700 				(void)printf(" time=%d.%03d ms",
701 				    (int)(triptime / 1000),
702 				    (int)(triptime % 1000));
703 			if (dupflag)
704 				(void)printf(" (DUP!)");
705 			/* check the data */
706 			cp = (u_char*)&icp->icmp_data[sizeof(bigtime_t)];
707 			dp = &outpack[8 + sizeof(bigtime_t)];
708 			for (i = 8 + sizeof(bigtime_t); (int) i < datalen;
709 			    ++i, ++cp, ++dp) {
710 				if (*cp != *dp) {
711 	(void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
712 	    i, *dp, *cp);
713 					cp = (u_char*)&icp->icmp_data[0];
714 					for (i = 8; (int) i < datalen; ++i, ++cp) {
715 						if ((i % 32) == 8)
716 							(void)printf("\n\t");
717 						(void)printf("%x ", *cp);
718 					}
719 					break;
720 				}
721 			}
722 		}
723 	} else {
724 		/* We've got something other than an ECHOREPLY */
725 		if (!(options & F_VERBOSE))
726 			return;
727 		ip2 = (struct ip *) (buf + hlen + sizeof (struct icmp));
728 		hlen2 = ip2->ip_hl << 2;
729 		if (cc >= hlen2 + 8 && check_icmph((struct ip *)(icp +
730 		    sizeof (struct icmp))) != 1)
731 			return;
732 		(void)printf("%d bytes from %s: ", cc,
733 		    pr_addr(from->sin_addr.s_addr));
734 		pr_icmph(icp);
735 	}
736 
737 	/* Display any IP options */
738 	cp = (u_char *)buf + sizeof(struct ip);
739 
740 	for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
741 		switch (*cp) {
742 		case IPOPT_EOL:
743 			hlen = 0;
744 			break;
745 		case IPOPT_LSRR:
746 			(void)printf("\nLSRR: ");
747 			hlen -= 2;
748 			j = *++cp;
749 			++cp;
750 			i = 0;
751 			if (j > IPOPT_MINOFF) {
752 				for (;;) {
753 					l = *++cp;
754 					l = (l<<8) + *++cp;
755 					l = (l<<8) + *++cp;
756 					l = (l<<8) + *++cp;
757 					if (l == 0)
758 						(void)printf("\t0.0.0.0");
759 					else
760 						(void)printf("\t%s",
761 						    pr_addr(ntohl(l)));
762 					hlen -= 4;
763 					j -= 4;
764 					i += 4;
765 					if (j <= IPOPT_MINOFF)
766 						break;
767 					if (i >= MAX_IPOPTLEN) {
768 						(void)printf("\t(truncated route)");
769 						break;
770 					}
771 					(void)putchar('\n');
772 				}
773 			}
774 			break;
775 		case IPOPT_RR:
776 			j = *++cp;		/* get length */
777 			i = *++cp;		/* and pointer */
778 			hlen -= 2;
779 			if (i > j)
780 				i = j;
781 			i -= IPOPT_MINOFF;
782 			if (i <= 0)
783 				continue;
784 			if ((int) i == old_rrlen
785 			    && cp == (u_char *) buf + sizeof(struct ip) + 2
786 			    && !memcmp(cp, old_rr, i)
787 			    && !(options & F_FLOOD)) {
788 				(void)printf("\t(same route)");
789 				i = ((i + 3) / 4) * 4;
790 				hlen -= i;
791 				cp += i;
792 				break;
793 			}
794 			if (i < MAX_IPOPTLEN) {
795 				old_rrlen = i;
796 				memcpy(old_rr, cp, i);
797 			} else
798 				old_rrlen = 0;
799 
800 			(void)printf("\nRR: ");
801 			j = 0;
802 			for (;;) {
803 				l = *++cp;
804 				l = (l<<8) + *++cp;
805 				l = (l<<8) + *++cp;
806 				l = (l<<8) + *++cp;
807 				if (l == 0)
808 					(void)printf("\t0.0.0.0");
809 				else
810 					(void)printf("\t%s", pr_addr(ntohl(l)));
811 				hlen -= 4;
812 				i -= 4;
813 				j += 4;
814 				if (i <= 0)
815 					break;
816 				if (j >= MAX_IPOPTLEN) {
817 					(void)printf("\t(truncated route)");
818 					break;
819 				}
820 				(void)putchar('\n');
821 			}
822 			break;
823 		case IPOPT_NOP:
824 			(void)printf("\nNOP");
825 			break;
826 		default:
827 			(void)printf("\nunknown option %x", *cp);
828 			hlen = hlen + cp[1] - 1;
829 			cp = cp + cp[1] - 1;
830 			break;
831 		}
832 	if (!(options & F_FLOOD)) {
833 		(void)putchar('\n');
834 		(void)fflush(stdout);
835 	}
836 }
837 
838 /*
839  * compute_in_cksum --
840  *	Checksum routine for Internet Protocol family headers (C Version)
841  */
842 int
843 compute_in_cksum(addr, len)
844 	u_short *addr;
845 	int len;
846 {
847 	int nleft = len;
848 	u_short *w = addr;
849 	int sum = 0;
850 	u_short answer = 0;
851 
852 	/*
853 	 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
854 	 * sequential 16 bit words to it, and at the end, fold back all the
855 	 * carry bits from the top 16 bits into the lower 16 bits.
856 	 */
857 	while (nleft > 1)  {
858 		sum += *w++;
859 		nleft -= 2;
860 	}
861 
862 	/* mop up an odd byte, if necessary */
863 	if (nleft == 1) {
864 		*(u_char *)(&answer) = *(u_char *)w ;
865 		sum += answer;
866 	}
867 
868 	/* add back carry outs from top 16 bits to low 16 bits */
869 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
870 	sum += (sum >> 16);			/* add carry */
871 	answer = ~sum;				/* truncate to 16 bits */
872 	return(answer);
873 }
874 
875 void summary(int header)
876 {
877 	(void)putchar('\r');
878 	(void)fflush(stdout);
879 
880 	if (header)
881 		(void)printf("--- %s ping statistics ---\n", hostname);
882 
883 	(void)printf("%ld packets transmitted, ", ntransmitted);
884 	(void)printf("%ld packets received, ", nreceived);
885 	if (nrepeats)
886 		(void)printf("%ld duplicates, ", nrepeats);
887 	if (ntransmitted) {
888 		if (nreceived > ntransmitted)
889 			(void)printf("-- somebody's printing up packets!");
890 		else
891 			(void)printf("%d%% packet loss",
892 			    (int) (((ntransmitted - nreceived) * 100) /
893 			    ntransmitted));
894 	}
895 	(void)putchar('\n');
896 	if (nreceived && timing) {
897 		uint64 num = nreceived + nrepeats;
898 		uint64 avg = tsum / num;
899 		uint64 dev = qsqrt(tsumsq / num - avg * avg);
900 		(void)printf("round-trip min/avg/max/std-dev = "
901 		    "%d.%03d/%d.%03d/%d.%03d/%d.%03d ms\n",
902 		    (int)(tmin / 1000), (int)(tmin % 1000),
903 		    (int)(avg  / 1000), (int)(avg  % 1000),
904 		    (int)(tmax / 1000), (int)(tmax % 1000),
905 		    (int)(dev  / 1000), (int)(dev  % 1000));
906 	}
907 }
908 
909 uint64 qsqrt(uint64 qdev)
910 {
911 	int64 y, x = 1;
912 
913 	if (!qdev)
914 		return(0);
915 
916 	do { /* newton was a stinker */
917 		y = x;
918 		x = qdev / x;
919 		x += y;
920 		x /= 2;
921 	} while ((x - y) > 1 || (x - y) < -1);
922 
923 	return (uint64) x;
924 }
925 
926 /*
927  * finish --
928  *	Print out statistics, and give up.
929  */
930 void finish(int sig)
931 {
932 	(void)signal(SIGINT, SIG_IGN);
933 	(void)signal(SIGALRM, SIG_IGN);
934 
935 	summary(1);
936 	exit(nreceived ? 0 : 1);
937 }
938 
939 #ifdef notdef
940 static char *ttab[] = {
941 	"Echo Reply",		/* ip + seq + udata */
942 	"Dest Unreachable",	/* net, host, proto, port, frag, sr + IP */
943 	"Source Quench",	/* IP */
944 	"Redirect",		/* redirect type, gateway, + IP  */
945 	"Echo",
946 	"Time Exceeded",	/* transit, frag reassem + IP */
947 	"Parameter Problem",	/* pointer + IP */
948 	"Timestamp",		/* id + seq + three timestamps */
949 	"Timestamp Reply",	/* " */
950 	"Info Request",		/* id + sq */
951 	"Info Reply"		/* " */
952 };
953 #endif
954 
955 /*
956  * pr_icmph --
957  *	Print a descriptive string about an ICMP header.
958  */
959 void
960 pr_icmph(icp)
961 	struct icmp *icp;
962 {
963 	switch(icp->icmp_type) {
964 	case ICMP_ECHOREPLY:
965 		(void)printf("Echo Reply\n");
966 		/* XXX ID + Seq + Data */
967 		break;
968 	case ICMP_UNREACH:
969 		switch(icp->icmp_code) {
970 		case ICMP_UNREACH_NET:
971 			(void)printf("Destination Net Unreachable\n");
972 			break;
973 		case ICMP_UNREACH_HOST:
974 			(void)printf("Destination Host Unreachable\n");
975 			break;
976 		case ICMP_UNREACH_PROTOCOL:
977 			(void)printf("Destination Protocol Unreachable\n");
978 			break;
979 		case ICMP_UNREACH_PORT:
980 			(void)printf("Destination Port Unreachable\n");
981 			break;
982 		case ICMP_UNREACH_NEEDFRAG:
983 			if (icp->icmp_nextmtu != 0)
984 				(void)printf("frag needed and DF set (MTU %d)\n",
985 					ntohs(icp->icmp_nextmtu));
986 			else
987 				(void)printf("frag needed and DF set\n");
988 			break;
989 		case ICMP_UNREACH_SRCFAIL:
990 			(void)printf("Source Route Failed\n");
991 			break;
992 		case ICMP_UNREACH_NET_UNKNOWN:
993 			(void)printf("Network Unknown\n");
994 			break;
995 		case ICMP_UNREACH_HOST_UNKNOWN:
996 			(void)printf("Host Unknown\n");
997 			break;
998 		case ICMP_UNREACH_ISOLATED:
999 			(void)printf("Source Isolated\n");
1000 			break;
1001 		case ICMP_UNREACH_NET_PROHIB:
1002 			(void)printf("Dest. Net Administratively Prohibited\n");
1003 			break;
1004 		case ICMP_UNREACH_HOST_PROHIB:
1005 			(void)printf("Dest. Host Administratively Prohibited\n");
1006 			break;
1007 		case ICMP_UNREACH_TOSNET:
1008 			(void)printf("Destination Net Unreachable for TOS\n");
1009 			break;
1010 		case ICMP_UNREACH_TOSHOST:
1011 			(void)printf("Desination Host Unreachable for TOS\n");
1012 			break;
1013 		case ICMP_UNREACH_FILTER_PROHIB:
1014 			(void)printf("Route administratively prohibited\n");
1015 			break;
1016 		case ICMP_UNREACH_HOST_PRECEDENCE:
1017 			(void)printf("Host Precedence Violation\n");
1018 			break;
1019 		case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1020 			(void)printf("Precedence Cutoff\n");
1021 			break;
1022 		default:
1023 			(void)printf("Dest Unreachable, Unknown Code: %d\n",
1024 			    icp->icmp_code);
1025 			break;
1026 		}
1027 		/* Print returned IP header information */
1028 #ifndef icmp_data
1029 		pr_retip(&icp->icmp_ip);
1030 #else
1031 		pr_retip((struct ip *)icp->icmp_data);
1032 #endif
1033 		break;
1034 	case ICMP_SOURCEQUENCH:
1035 		(void)printf("Source Quench\n");
1036 #ifndef icmp_data
1037 		pr_retip(&icp->icmp_ip);
1038 #else
1039 		pr_retip((struct ip *)icp->icmp_data);
1040 #endif
1041 		break;
1042 	case ICMP_REDIRECT:
1043 		switch(icp->icmp_code) {
1044 		case ICMP_REDIRECT_NET:
1045 			(void)printf("Redirect Network");
1046 			break;
1047 		case ICMP_REDIRECT_HOST:
1048 			(void)printf("Redirect Host");
1049 			break;
1050 		case ICMP_REDIRECT_TOSNET:
1051 			(void)printf("Redirect Type of Service and Network");
1052 			break;
1053 		case ICMP_REDIRECT_TOSHOST:
1054 			(void)printf("Redirect Type of Service and Host");
1055 			break;
1056 		default:
1057 			(void)printf("Redirect, Unknown Code: %d", icp->icmp_code);
1058 			break;
1059 		}
1060 		(void)printf("(New addr: %s)\n",
1061 		    inet_ntoa(icp->icmp_gwaddr));
1062 #ifndef icmp_data
1063 		pr_retip(&icp->icmp_ip);
1064 #else
1065 		pr_retip((struct ip *)icp->icmp_data);
1066 #endif
1067 		break;
1068 	case ICMP_ECHO:
1069 		(void)printf("Echo Request\n");
1070 		/* XXX ID + Seq + Data */
1071 		break;
1072 //	case ICMP_ROUTERADVERT:
1073 		/* RFC1256 */
1074 /*
1075 		(void)printf("Router Discovery Advertisement\n");
1076 		(void)printf("(%d entries, lifetime %d seconds)\n",
1077 		    icp->icmp_num_addrs, ntohs(icp->icmp_lifetime));
1078 		break;
1079 */
1080 //	case ICMP_ROUTERSOLICIT:
1081 		/* RFC1256 */
1082 /*		(void)printf("Router Discovery Solicitation\n");
1083 		break;
1084 */
1085 	case ICMP_TIMXCEED:
1086 		switch(icp->icmp_code) {
1087 		case ICMP_TIMXCEED_INTRANS:
1088 			(void)printf("Time to live exceeded\n");
1089 			break;
1090 		case ICMP_TIMXCEED_REASS:
1091 			(void)printf("Frag reassembly time exceeded\n");
1092 			break;
1093 		default:
1094 			(void)printf("Time exceeded, Unknown Code: %d\n",
1095 			    icp->icmp_code);
1096 			break;
1097 		}
1098 #ifndef icmp_data
1099 		pr_retip(&icp->icmp_ip);
1100 #else
1101 		pr_retip((struct ip *)icp->icmp_data);
1102 #endif
1103 		break;
1104 	case ICMP_PARAMPROB:
1105 		switch(icp->icmp_code) {
1106 		case ICMP_PARAMPROB_OPTABSENT:
1107 			(void)printf(
1108 			    "Parameter problem, required option absent: pointer = 0x%02x\n",
1109 			    ntohs(icp->icmp_hun.ih_pptr));
1110 			break;
1111 		default:
1112 			(void)printf("Parameter problem: pointer = 0x%02x\n",
1113 			    ntohs(icp->icmp_hun.ih_pptr));
1114 			break;
1115 		}
1116 #ifndef icmp_data
1117 		pr_retip(&icp->icmp_ip);
1118 #else
1119 		pr_retip((struct ip *)icp->icmp_data);
1120 #endif
1121 		break;
1122 	case ICMP_TSTAMP:
1123 		(void)printf("Timestamp\n");
1124 		/* XXX ID + Seq + 3 timestamps */
1125 		break;
1126 	case ICMP_TSTAMPREPLY:
1127 		(void)printf("Timestamp Reply\n");
1128 		/* XXX ID + Seq + 3 timestamps */
1129 		break;
1130 	case ICMP_IREQ:
1131 		(void)printf("Information Request\n");
1132 		/* XXX ID + Seq */
1133 		break;
1134 	case ICMP_IREQREPLY:
1135 		(void)printf("Information Reply\n");
1136 		/* XXX ID + Seq */
1137 		break;
1138 #ifdef ICMP_MASKREQ
1139 	case ICMP_MASKREQ:
1140 		(void)printf("Address Mask Request\n");
1141 		break;
1142 #endif
1143 #ifdef ICMP_MASKREPLY
1144 	case ICMP_MASKREPLY:
1145 		(void)printf("Address Mask Reply (Mask 0x%08ld)\n",
1146 		    (long)ntohl(icp->icmp_mask));
1147 		break;
1148 #endif
1149 	default:
1150 		(void)printf("Unknown ICMP type: %u\n", icp->icmp_type);
1151 	}
1152 }
1153 
1154 /*
1155  * pr_iph --
1156  *	Print an IP header with options.
1157  */
1158 void pr_iph(struct ip *ip)
1159 {
1160 	int hlen;
1161 	u_char *cp;
1162 
1163 	hlen = ip->ip_hl << 2;
1164 	cp = (u_char *)ip + 20;		/* point to options */
1165 
1166 	(void)printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
1167 	(void)printf(" %1x  %1x  %02x %04x %04x",
1168 	    ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
1169 	(void)printf("   %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
1170 	    (ip->ip_off) & 0x1fff);
1171 	(void)printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
1172 	(void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
1173 	(void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
1174 	/* dump and option bytes */
1175 	while (hlen-- > 20) {
1176 		(void)printf("%02x", *cp++);
1177 	}
1178 	(void)putchar('\n');
1179 }
1180 
1181 /*
1182  * pr_addr --
1183  *	Return an ascii host address as a dotted quad and optionally with
1184  * a hostname.
1185  */
1186 char *
1187 pr_addr(a)
1188 	in_addr_t a;
1189 {
1190 	struct hostent *hp;
1191 	struct in_addr in;
1192 	static char buf[16+3+MAXHOSTNAMELEN];
1193 
1194 	in.s_addr = a;
1195 	if ((options & F_NUMERIC) ||
1196 	    !(hp = gethostbyaddr((char *)&in.s_addr, sizeof(in.s_addr), AF_INET)))
1197 		(void)snprintf(buf, sizeof buf, "%s", inet_ntoa(in));
1198 	else
1199 		(void)snprintf(buf, sizeof buf, "%s (%s)", hp->h_name,
1200 		    inet_ntoa(in));
1201 	return(buf);
1202 }
1203 
1204 /*
1205  * pr_retip --
1206  *	Dump some info on a returned (via ICMP) IP packet.
1207  */
1208 void pr_retip(struct ip *ip)
1209 {
1210 	int hlen;
1211 	u_char *cp;
1212 
1213 	pr_iph(ip);
1214 	hlen = ip->ip_hl << 2;
1215 	cp = (u_char *)ip + hlen;
1216 
1217 	if (ip->ip_p == 6)
1218 		(void)printf("TCP: from port %u, to port %u (decimal)\n",
1219 		    (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
1220 	else if (ip->ip_p == 17)
1221 		(void)printf("UDP: from port %u, to port %u (decimal)\n",
1222 			(*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
1223 }
1224 
1225 void
1226 fill(bp, patp)
1227 	char *bp, *patp;
1228 {
1229 	int ii, jj, kk;
1230 	int pat[16];
1231 	char *cp;
1232 
1233 	for (cp = patp; *cp; cp++)
1234 		if (!isxdigit(*cp))
1235 			err(1, "patterns must be specified as hex digits");
1236 	ii = sscanf(patp,
1237 	    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1238 	    &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
1239 	    &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
1240 	    &pat[13], &pat[14], &pat[15]);
1241 
1242 	if (ii > 0)
1243 		for (kk = 0;
1244 		    kk <= (int) (MAXPAYLOAD - (8 + sizeof(uint64) + ii));
1245 		    kk += ii)
1246 			for (jj = 0; jj < ii; ++jj)
1247 				bp[jj + kk] = pat[jj];
1248 	if (!(options & F_QUIET)) {
1249 		(void)printf("PATTERN: 0x");
1250 		for (jj = 0; jj < ii; ++jj)
1251 			(void)printf("%02x", bp[jj] & 0xFF);
1252 		(void)printf("\n");
1253 	}
1254 }
1255 
1256 /*
1257  * when we get types of ICMP message with parts of the orig. datagram
1258  * we want to try to assure ourselves that it is from this instance
1259  * of ping, and not say, a refused finger connection or something
1260  */
1261 int
1262 check_icmph(iph)
1263 	struct ip *iph;
1264 {
1265 	struct icmp *icmph;
1266 
1267 	/* only allow IP version 4 */
1268 	if (iph->ip_v != 4)
1269 		return 0;
1270 
1271 	/* Only allow ICMP */
1272 	if (iph->ip_p != IPPROTO_ICMP)
1273 		return 0;
1274 
1275 	icmph = (struct icmp *) (iph + (4 * iph->ip_hl));
1276 
1277 	/* make sure it is in response to an ECHO request */
1278 	if (icmph->icmp_type != 8)
1279 		return 0;
1280 
1281 	/* ok, make sure it has the right id on it */
1282 	if (icmph->icmp_hun.ih_idseq.icd_id != ident)
1283 		return 0;
1284 
1285 	return 1;
1286 }
1287 
1288 void
1289 usage()
1290 {
1291 	extern const char *__progname;
1292 
1293 	(void)fprintf(stderr,
1294 	    "usage: %s [-DdfLnqRrv] [-c count] [-I ifaddr] [-i wait]\n"
1295 	    "\t[-l preload] [-p pattern] [-s packetsize] [-t ttl]"
1296 	    " [-w maxwait] host\n", __progname);
1297 	exit(1);
1298 }
1299