xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/ping/ping_aux.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
32*7c478bd9Sstevel@tonic-gate  * under license from the Regents of the University of California.
33*7c478bd9Sstevel@tonic-gate  */
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <stdio.h>
38*7c478bd9Sstevel@tonic-gate #include <string.h>
39*7c478bd9Sstevel@tonic-gate #include <strings.h>
40*7c478bd9Sstevel@tonic-gate #include <errno.h>
41*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
42*7c478bd9Sstevel@tonic-gate #include <unistd.h>
43*7c478bd9Sstevel@tonic-gate #include <signal.h>
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
51*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
52*7c478bd9Sstevel@tonic-gate #include <net/if.h>
53*7c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
54*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
55*7c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
56*7c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h>
57*7c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
58*7c478bd9Sstevel@tonic-gate #include <netdb.h>
59*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #include <ifaddrlist.h>
62*7c478bd9Sstevel@tonic-gate #include "ping.h"
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate /*
66*7c478bd9Sstevel@tonic-gate  * IPv4 source routing option.
67*7c478bd9Sstevel@tonic-gate  * In order to avoid padding for the alignment of IPv4 addresses, ipsr_addrs
68*7c478bd9Sstevel@tonic-gate  * is defined as a 2-D array of uint8_t, instead of 1-D array of struct in_addr.
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate struct ip_sourceroute {
71*7c478bd9Sstevel@tonic-gate 	uint8_t ipsr_code;
72*7c478bd9Sstevel@tonic-gate 	uint8_t ipsr_len;
73*7c478bd9Sstevel@tonic-gate 	uint8_t ipsr_ptr;
74*7c478bd9Sstevel@tonic-gate 	/* up to 9 IPv4 addresses */
75*7c478bd9Sstevel@tonic-gate 	uint8_t ipsr_addrs[1][sizeof (struct in_addr)];
76*7c478bd9Sstevel@tonic-gate };
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate void check_reply(struct addrinfo *, struct msghdr *, int, ushort_t);
79*7c478bd9Sstevel@tonic-gate extern void find_dstaddr(ushort_t, union any_in_addr *);
80*7c478bd9Sstevel@tonic-gate extern boolean_t is_a_target(struct addrinfo *, union any_in_addr *);
81*7c478bd9Sstevel@tonic-gate extern char *pr_name(char *, int);
82*7c478bd9Sstevel@tonic-gate static void pr_options(uchar_t *, int);
83*7c478bd9Sstevel@tonic-gate extern char *pr_protocol(int);
84*7c478bd9Sstevel@tonic-gate static void pr_rropt(uchar_t *, int, boolean_t);
85*7c478bd9Sstevel@tonic-gate static void pr_tsopt(uchar_t *, int);
86*7c478bd9Sstevel@tonic-gate static char *pr_type(int);
87*7c478bd9Sstevel@tonic-gate extern void schedule_sigalrm();
88*7c478bd9Sstevel@tonic-gate extern void send_scheduled_probe();
89*7c478bd9Sstevel@tonic-gate extern boolean_t seq_match(ushort_t, int, ushort_t);
90*7c478bd9Sstevel@tonic-gate extern void sigalrm_handler();
91*7c478bd9Sstevel@tonic-gate void set_IPv4_options(int, union any_in_addr *, int, struct in_addr *,
92*7c478bd9Sstevel@tonic-gate     struct in_addr *);
93*7c478bd9Sstevel@tonic-gate extern void tvsub(struct timeval *, struct timeval *);
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate /*
96*7c478bd9Sstevel@tonic-gate  * Set IPv4 options
97*7c478bd9Sstevel@tonic-gate  */
98*7c478bd9Sstevel@tonic-gate void
99*7c478bd9Sstevel@tonic-gate set_IPv4_options(int sock, union any_in_addr *gw_IP_list, int gw_count,
100*7c478bd9Sstevel@tonic-gate     struct in_addr *src, struct in_addr *dst)
101*7c478bd9Sstevel@tonic-gate {
102*7c478bd9Sstevel@tonic-gate 	int req_size;
103*7c478bd9Sstevel@tonic-gate 	char srr[ROUTE_SIZE + 1];
104*7c478bd9Sstevel@tonic-gate 	char *bufp;
105*7c478bd9Sstevel@tonic-gate 	int optsize = ROUTE_SIZE;
106*7c478bd9Sstevel@tonic-gate 	struct ip_sourceroute *srp;
107*7c478bd9Sstevel@tonic-gate 	struct ip_timestamp *tsp;
108*7c478bd9Sstevel@tonic-gate 	int i;
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	if (rr_option || ts_option || gw_count > 0) {
111*7c478bd9Sstevel@tonic-gate 		bzero(srr, sizeof (srr));
112*7c478bd9Sstevel@tonic-gate 		bufp = srr;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 		if (gw_count > 0) {
115*7c478bd9Sstevel@tonic-gate 			/* 3 = 1 (code) + 1 (len) + 1 (ptr) of src route opt. */
116*7c478bd9Sstevel@tonic-gate 			req_size = 3 + (sizeof (struct in_addr)) * gw_count;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 			if (optsize < req_size) {
119*7c478bd9Sstevel@tonic-gate 				Fprintf(stderr, "%s: too many IPv4 gateways\n",
120*7c478bd9Sstevel@tonic-gate 				    progname);
121*7c478bd9Sstevel@tonic-gate 				exit(EXIT_FAILURE);
122*7c478bd9Sstevel@tonic-gate 			}
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 			srp = (struct ip_sourceroute *)bufp;
125*7c478bd9Sstevel@tonic-gate 			srp->ipsr_code = strict ? IPOPT_SSRR : IPOPT_LSRR;
126*7c478bd9Sstevel@tonic-gate 			srp->ipsr_len = req_size;
127*7c478bd9Sstevel@tonic-gate 			srp->ipsr_ptr = IPOPT_MINOFF;
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < gw_count; i++) {
130*7c478bd9Sstevel@tonic-gate 				bcopy((char *)&gw_IP_list[i].addr,
131*7c478bd9Sstevel@tonic-gate 				    &srp->ipsr_addrs[i],
132*7c478bd9Sstevel@tonic-gate 				    sizeof (struct in_addr));
133*7c478bd9Sstevel@tonic-gate 			}
134*7c478bd9Sstevel@tonic-gate 			optsize -= srp->ipsr_len;
135*7c478bd9Sstevel@tonic-gate 			bufp += srp->ipsr_len;
136*7c478bd9Sstevel@tonic-gate 		}
137*7c478bd9Sstevel@tonic-gate 		/* do we send a timestamp option? */
138*7c478bd9Sstevel@tonic-gate 		if (ts_option) {
139*7c478bd9Sstevel@tonic-gate 			if (optsize < IPOPT_MINOFF) {
140*7c478bd9Sstevel@tonic-gate 				Fprintf(stderr,
141*7c478bd9Sstevel@tonic-gate 				    "%s: no room for timestamp option\n",
142*7c478bd9Sstevel@tonic-gate 				    progname);
143*7c478bd9Sstevel@tonic-gate 				exit(EXIT_FAILURE);
144*7c478bd9Sstevel@tonic-gate 			}
145*7c478bd9Sstevel@tonic-gate 			/* LINTED */
146*7c478bd9Sstevel@tonic-gate 			tsp = (struct ip_timestamp *)bufp;
147*7c478bd9Sstevel@tonic-gate 			tsp->ipt_code = IPOPT_TS;
148*7c478bd9Sstevel@tonic-gate 			tsp->ipt_len = optsize;
149*7c478bd9Sstevel@tonic-gate 			tsp->ipt_ptr = IPOPT_MINOFF + 1;
150*7c478bd9Sstevel@tonic-gate 			tsp->ipt_flg = ts_flag & 0x0f;
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 			if (tsp->ipt_flg > IPOPT_TS_TSANDADDR) {
153*7c478bd9Sstevel@tonic-gate 				req_size = IPOPT_MINOFF +
154*7c478bd9Sstevel@tonic-gate 				    2 * sizeof (struct ipt_ta);
155*7c478bd9Sstevel@tonic-gate 				/*
156*7c478bd9Sstevel@tonic-gate 				 * Note: BSD/4.X is broken in their check so we
157*7c478bd9Sstevel@tonic-gate 				 * have to  bump up this number by at least one.
158*7c478bd9Sstevel@tonic-gate 				 */
159*7c478bd9Sstevel@tonic-gate 				req_size++;
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 				if (optsize < req_size) {
162*7c478bd9Sstevel@tonic-gate 					Fprintf(stderr, "%s: no room for "
163*7c478bd9Sstevel@tonic-gate 					    "timestamp option\n", progname);
164*7c478bd9Sstevel@tonic-gate 					exit(EXIT_FAILURE);
165*7c478bd9Sstevel@tonic-gate 				}
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 				bcopy((char *)dst,
168*7c478bd9Sstevel@tonic-gate 				    &tsp->ipt_timestamp.ipt_ta[0].ipt_addr,
169*7c478bd9Sstevel@tonic-gate 				    sizeof (struct in_addr));
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 				bcopy((char *)src,
172*7c478bd9Sstevel@tonic-gate 				    &tsp->ipt_timestamp.ipt_ta[1].ipt_addr,
173*7c478bd9Sstevel@tonic-gate 				    sizeof (struct in_addr));
174*7c478bd9Sstevel@tonic-gate 				tsp->ipt_len = req_size;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 			}
177*7c478bd9Sstevel@tonic-gate 			optsize -= tsp->ipt_len;
178*7c478bd9Sstevel@tonic-gate 			bufp += tsp->ipt_len;
179*7c478bd9Sstevel@tonic-gate 		}
180*7c478bd9Sstevel@tonic-gate 		/* do we send a record route option? */
181*7c478bd9Sstevel@tonic-gate 		if (rr_option) {
182*7c478bd9Sstevel@tonic-gate 			if (optsize < IPOPT_MINOFF) {
183*7c478bd9Sstevel@tonic-gate 				Fprintf(stderr,
184*7c478bd9Sstevel@tonic-gate 				    "%s: no room for record route option\n",
185*7c478bd9Sstevel@tonic-gate 				    progname);
186*7c478bd9Sstevel@tonic-gate 				exit(EXIT_FAILURE);
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 			}
189*7c478bd9Sstevel@tonic-gate 			/*
190*7c478bd9Sstevel@tonic-gate 			 * Format of record route option is same as source
191*7c478bd9Sstevel@tonic-gate 			 * route option.
192*7c478bd9Sstevel@tonic-gate 			 */
193*7c478bd9Sstevel@tonic-gate 			srp = (struct ip_sourceroute *)bufp;
194*7c478bd9Sstevel@tonic-gate 			srp->ipsr_code = IPOPT_RR;
195*7c478bd9Sstevel@tonic-gate 			srp->ipsr_len = optsize;
196*7c478bd9Sstevel@tonic-gate 			srp->ipsr_ptr = IPOPT_MINOFF;
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 			optsize -= srp->ipsr_len;
199*7c478bd9Sstevel@tonic-gate 			bufp += srp->ipsr_len;
200*7c478bd9Sstevel@tonic-gate 		}
201*7c478bd9Sstevel@tonic-gate 		optsize = bufp - srr;
202*7c478bd9Sstevel@tonic-gate 		/* Round up to 4 byte boundary */
203*7c478bd9Sstevel@tonic-gate 		if (optsize & 0x3)
204*7c478bd9Sstevel@tonic-gate 			optsize = (optsize & ~0x3) + 4;
205*7c478bd9Sstevel@tonic-gate 		if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, srr, optsize) <
206*7c478bd9Sstevel@tonic-gate 		    0) {
207*7c478bd9Sstevel@tonic-gate 			Fprintf(stderr, "%s: setsockopt IP_OPTIONS %s\n",
208*7c478bd9Sstevel@tonic-gate 			    progname, strerror(errno));
209*7c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
210*7c478bd9Sstevel@tonic-gate 		}
211*7c478bd9Sstevel@tonic-gate 	}
212*7c478bd9Sstevel@tonic-gate }
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate /*
215*7c478bd9Sstevel@tonic-gate  * Check out the packet to see if it came from us.  This logic is necessary
216*7c478bd9Sstevel@tonic-gate  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
217*7c478bd9Sstevel@tonic-gate  * which arrive ('tis only fair).  This permits multiple copies of this
218*7c478bd9Sstevel@tonic-gate  * program to be run without having intermingled output (or statistics!).
219*7c478bd9Sstevel@tonic-gate  */
220*7c478bd9Sstevel@tonic-gate void
221*7c478bd9Sstevel@tonic-gate check_reply(struct addrinfo *ai_dst, struct msghdr *msg, int cc,
222*7c478bd9Sstevel@tonic-gate     ushort_t udp_src_port)
223*7c478bd9Sstevel@tonic-gate {
224*7c478bd9Sstevel@tonic-gate 	struct ip *ip;
225*7c478bd9Sstevel@tonic-gate 	struct icmp *icp;
226*7c478bd9Sstevel@tonic-gate 	struct udphdr *up;
227*7c478bd9Sstevel@tonic-gate 	union any_in_addr dst_addr;
228*7c478bd9Sstevel@tonic-gate 	uchar_t *buf;
229*7c478bd9Sstevel@tonic-gate 	int32_t *intp;
230*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in *from;
231*7c478bd9Sstevel@tonic-gate 	struct timeval *tp;
232*7c478bd9Sstevel@tonic-gate 	struct timeval tv;
233*7c478bd9Sstevel@tonic-gate 	int hlen, hlen1;
234*7c478bd9Sstevel@tonic-gate 	int64_t triptime;
235*7c478bd9Sstevel@tonic-gate 	boolean_t valid_reply = _B_FALSE;
236*7c478bd9Sstevel@tonic-gate 	boolean_t reply_matched_current_target;	/* Is the source address of */
237*7c478bd9Sstevel@tonic-gate 						/* this reply same as where */
238*7c478bd9Sstevel@tonic-gate 						/* we're sending currently? */
239*7c478bd9Sstevel@tonic-gate 	boolean_t last_reply_from_targetaddr = _B_FALSE; /* Is this stats, */
240*7c478bd9Sstevel@tonic-gate 						/* probe all with npackets>0 */
241*7c478bd9Sstevel@tonic-gate 						/* and we received reply for */
242*7c478bd9Sstevel@tonic-gate 						/* the last probe sent to */
243*7c478bd9Sstevel@tonic-gate 						/* targetaddr */
244*7c478bd9Sstevel@tonic-gate 	int cc_left;
245*7c478bd9Sstevel@tonic-gate 	char tmp_buf[INET6_ADDRSTRLEN];
246*7c478bd9Sstevel@tonic-gate 	static char *unreach[] = {
247*7c478bd9Sstevel@tonic-gate 	    "Net Unreachable",
248*7c478bd9Sstevel@tonic-gate 	    "Host Unreachable",
249*7c478bd9Sstevel@tonic-gate 	    "Protocol Unreachable",
250*7c478bd9Sstevel@tonic-gate 	    "Port Unreachable",
251*7c478bd9Sstevel@tonic-gate 	    "Fragmentation needed and DF set",
252*7c478bd9Sstevel@tonic-gate 	    "Source Route Failed",
253*7c478bd9Sstevel@tonic-gate 	    /* The following are from RFC1700 */
254*7c478bd9Sstevel@tonic-gate 	    "Net Unknown",
255*7c478bd9Sstevel@tonic-gate 	    "Host Unknown",
256*7c478bd9Sstevel@tonic-gate 	    "Source Host Isolated",
257*7c478bd9Sstevel@tonic-gate 	    "Dest Net Prohibited",
258*7c478bd9Sstevel@tonic-gate 	    "Dest Host Prohibited",
259*7c478bd9Sstevel@tonic-gate 	    "Net Unreachable for TOS",
260*7c478bd9Sstevel@tonic-gate 	    "Host Unreachable for TOS",
261*7c478bd9Sstevel@tonic-gate 	    "Communication Administratively Prohibited",
262*7c478bd9Sstevel@tonic-gate 	    "Host Precedence Violation",
263*7c478bd9Sstevel@tonic-gate 	    "Precedence Cutoff in Effect"
264*7c478bd9Sstevel@tonic-gate 	};
265*7c478bd9Sstevel@tonic-gate 	static char *redirect[] = {
266*7c478bd9Sstevel@tonic-gate 	    "Net",
267*7c478bd9Sstevel@tonic-gate 	    "Host",
268*7c478bd9Sstevel@tonic-gate 	    "TOS Net",
269*7c478bd9Sstevel@tonic-gate 	    "TOS Host"
270*7c478bd9Sstevel@tonic-gate 	};
271*7c478bd9Sstevel@tonic-gate 	static char *timexceed[] = {
272*7c478bd9Sstevel@tonic-gate 	    "Time exceeded in transit",
273*7c478bd9Sstevel@tonic-gate 	    "Time exceeded during reassembly"
274*7c478bd9Sstevel@tonic-gate 	};
275*7c478bd9Sstevel@tonic-gate 	boolean_t print_newline = _B_FALSE;
276*7c478bd9Sstevel@tonic-gate 	int i;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	/* decompose msghdr into useful pieces */
279*7c478bd9Sstevel@tonic-gate 	buf = (uchar_t *)msg->msg_iov->iov_base;
280*7c478bd9Sstevel@tonic-gate 	from = (struct sockaddr_in *)msg->msg_name;
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	/* LINTED */
283*7c478bd9Sstevel@tonic-gate 	intp = (int32_t *)buf;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&tv, (struct timezone *)NULL);
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	/* LINTED */
288*7c478bd9Sstevel@tonic-gate 	ip = (struct ip *)buf;
289*7c478bd9Sstevel@tonic-gate 	hlen = ip->ip_hl << 2;
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	if ((cc < sizeof (struct ip)) || (cc < hlen + ICMP_MINLEN)) {
292*7c478bd9Sstevel@tonic-gate 		if (verbose) {
293*7c478bd9Sstevel@tonic-gate 			Printf("packet too short (%d bytes) from %s\n", cc,
294*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&from->sin_addr, AF_INET));
295*7c478bd9Sstevel@tonic-gate 		}
296*7c478bd9Sstevel@tonic-gate 		return;
297*7c478bd9Sstevel@tonic-gate 	}
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	cc -= hlen;
300*7c478bd9Sstevel@tonic-gate 	/* LINTED */
301*7c478bd9Sstevel@tonic-gate 	icp = (struct icmp *)(buf + hlen);
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	if (ip->ip_p == 0) {
304*7c478bd9Sstevel@tonic-gate 		/*
305*7c478bd9Sstevel@tonic-gate 		 * Assume that we are running on a pre-4.3BSD system
306*7c478bd9Sstevel@tonic-gate 		 * such as SunOS before 4.0
307*7c478bd9Sstevel@tonic-gate 		 */
308*7c478bd9Sstevel@tonic-gate 		/* LINTED */
309*7c478bd9Sstevel@tonic-gate 		icp = (struct icmp *)buf;
310*7c478bd9Sstevel@tonic-gate 	}
311*7c478bd9Sstevel@tonic-gate 	cc_left = cc - ICMP_MINLEN;
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	switch (icp->icmp_type) {
314*7c478bd9Sstevel@tonic-gate 	case ICMP_UNREACH:
315*7c478bd9Sstevel@tonic-gate 		ip = &icp->icmp_ip;
316*7c478bd9Sstevel@tonic-gate 		hlen1 = ip->ip_hl << 2;
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 		/* check if we have enough of the packet to work on */
319*7c478bd9Sstevel@tonic-gate 		if ((cc_left < sizeof (struct ip)) ||
320*7c478bd9Sstevel@tonic-gate 		    (cc_left < hlen1 + sizeof (struct udphdr))) {
321*7c478bd9Sstevel@tonic-gate 			if (verbose) {
322*7c478bd9Sstevel@tonic-gate 				Printf("packet too short (%d bytes) from %s\n",
323*7c478bd9Sstevel@tonic-gate 				    cc, pr_name((char *)&from->sin_addr,
324*7c478bd9Sstevel@tonic-gate 				    AF_INET));
325*7c478bd9Sstevel@tonic-gate 			}
326*7c478bd9Sstevel@tonic-gate 			return;
327*7c478bd9Sstevel@tonic-gate 		}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 		/* get the UDP packet */
330*7c478bd9Sstevel@tonic-gate 		cc_left -= hlen1 + sizeof (struct udphdr);
331*7c478bd9Sstevel@tonic-gate 		/* LINTED */
332*7c478bd9Sstevel@tonic-gate 		up = (struct udphdr *)((uchar_t *)ip + hlen1);
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 		/* check to see if this is what we sent */
335*7c478bd9Sstevel@tonic-gate 		if (icp->icmp_code == ICMP_UNREACH_PORT &&
336*7c478bd9Sstevel@tonic-gate 		    ip->ip_p == IPPROTO_UDP &&
337*7c478bd9Sstevel@tonic-gate 		    udp_src_port == up->uh_sport &&
338*7c478bd9Sstevel@tonic-gate 		    use_udp) {
339*7c478bd9Sstevel@tonic-gate 			valid_reply = _B_TRUE;
340*7c478bd9Sstevel@tonic-gate 		} else {
341*7c478bd9Sstevel@tonic-gate 			valid_reply = _B_FALSE;
342*7c478bd9Sstevel@tonic-gate 		}
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 		if (valid_reply) {
345*7c478bd9Sstevel@tonic-gate 			/*
346*7c478bd9Sstevel@tonic-gate 			 * For this valid reply, if we are still sending to
347*7c478bd9Sstevel@tonic-gate 			 * this target IP address, we'd like to do some
348*7c478bd9Sstevel@tonic-gate 			 * updates to targetaddr, so hold SIGALRMs.
349*7c478bd9Sstevel@tonic-gate 			 */
350*7c478bd9Sstevel@tonic-gate 			(void) sighold(SIGALRM);
351*7c478bd9Sstevel@tonic-gate 			is_alive = _B_TRUE;
352*7c478bd9Sstevel@tonic-gate 			nreceived++;
353*7c478bd9Sstevel@tonic-gate 			reply_matched_current_target =
354*7c478bd9Sstevel@tonic-gate 			    seq_match(current_targetaddr->starting_seq_num,
355*7c478bd9Sstevel@tonic-gate 				current_targetaddr->num_sent,
356*7c478bd9Sstevel@tonic-gate 				ntohs(up->uh_dport));
357*7c478bd9Sstevel@tonic-gate 			if (reply_matched_current_target) {
358*7c478bd9Sstevel@tonic-gate 				current_targetaddr->got_reply = _B_TRUE;
359*7c478bd9Sstevel@tonic-gate 				nreceived_last_target++;
360*7c478bd9Sstevel@tonic-gate 				/*
361*7c478bd9Sstevel@tonic-gate 				 * Determine if stats, probe-all, and
362*7c478bd9Sstevel@tonic-gate 				 * npackets != 0, and this is the reply for
363*7c478bd9Sstevel@tonic-gate 				 * the last probe we sent to current target
364*7c478bd9Sstevel@tonic-gate 				 * address.
365*7c478bd9Sstevel@tonic-gate 				 */
366*7c478bd9Sstevel@tonic-gate 				if (stats && probe_all && npackets > 0 &&
367*7c478bd9Sstevel@tonic-gate 				    ((current_targetaddr->starting_seq_num +
368*7c478bd9Sstevel@tonic-gate 				    current_targetaddr->num_probes - 1) %
369*7c478bd9Sstevel@tonic-gate 				    (MAX_PORT + 1) == ntohs(up->uh_dport)) &&
370*7c478bd9Sstevel@tonic-gate 				    (current_targetaddr->num_probes ==
371*7c478bd9Sstevel@tonic-gate 				    current_targetaddr->num_sent))
372*7c478bd9Sstevel@tonic-gate 					last_reply_from_targetaddr = _B_TRUE;
373*7c478bd9Sstevel@tonic-gate 			} else {
374*7c478bd9Sstevel@tonic-gate 				/*
375*7c478bd9Sstevel@tonic-gate 				 * If it's just probe_all and we just received
376*7c478bd9Sstevel@tonic-gate 				 * a reply from a target address we were
377*7c478bd9Sstevel@tonic-gate 				 * probing and had timed out (now we are probing
378*7c478bd9Sstevel@tonic-gate 				 * some other target address), we ignore
379*7c478bd9Sstevel@tonic-gate 				 * this reply.
380*7c478bd9Sstevel@tonic-gate 				 */
381*7c478bd9Sstevel@tonic-gate 				if (probe_all && !stats) {
382*7c478bd9Sstevel@tonic-gate 					valid_reply = _B_FALSE;
383*7c478bd9Sstevel@tonic-gate 					/*
384*7c478bd9Sstevel@tonic-gate 					 * Only if it's verbose, we get a
385*7c478bd9Sstevel@tonic-gate 					 * message regarding this reply,
386*7c478bd9Sstevel@tonic-gate 					 * otherwise we are done here.
387*7c478bd9Sstevel@tonic-gate 					 */
388*7c478bd9Sstevel@tonic-gate 					if (!verbose) {
389*7c478bd9Sstevel@tonic-gate 						(void) sigrelse(SIGALRM);
390*7c478bd9Sstevel@tonic-gate 						return;
391*7c478bd9Sstevel@tonic-gate 					}
392*7c478bd9Sstevel@tonic-gate 				}
393*7c478bd9Sstevel@tonic-gate 			}
394*7c478bd9Sstevel@tonic-gate 		}
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 		/* stats mode doesn't print 'alive' messages */
397*7c478bd9Sstevel@tonic-gate 		if (valid_reply && !stats) {
398*7c478bd9Sstevel@tonic-gate 			/*
399*7c478bd9Sstevel@tonic-gate 			 * if we are still sending to the same target address,
400*7c478bd9Sstevel@tonic-gate 			 * then stop it, because we know it's alive.
401*7c478bd9Sstevel@tonic-gate 			 */
402*7c478bd9Sstevel@tonic-gate 			if (reply_matched_current_target) {
403*7c478bd9Sstevel@tonic-gate 				(void) alarm(0);	/* cancel alarm */
404*7c478bd9Sstevel@tonic-gate 				(void) sigset(SIGALRM, SIG_IGN);
405*7c478bd9Sstevel@tonic-gate 				current_targetaddr->probing_done = _B_TRUE;
406*7c478bd9Sstevel@tonic-gate 			}
407*7c478bd9Sstevel@tonic-gate 			(void) sigrelse(SIGALRM);
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 			if (!probe_all) {
410*7c478bd9Sstevel@tonic-gate 				Printf("%s is alive\n", targethost);
411*7c478bd9Sstevel@tonic-gate 			} else {
412*7c478bd9Sstevel@tonic-gate 				(void) inet_ntop(AF_INET, (void *)&ip->ip_dst,
413*7c478bd9Sstevel@tonic-gate 				    tmp_buf, sizeof (tmp_buf));
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 				if (nflag) {
416*7c478bd9Sstevel@tonic-gate 					Printf("%s is alive\n", tmp_buf);
417*7c478bd9Sstevel@tonic-gate 				} else {
418*7c478bd9Sstevel@tonic-gate 					Printf("%s (%s) is alive\n",
419*7c478bd9Sstevel@tonic-gate 					    targethost, tmp_buf);
420*7c478bd9Sstevel@tonic-gate 				}
421*7c478bd9Sstevel@tonic-gate 			}
422*7c478bd9Sstevel@tonic-gate 			if (reply_matched_current_target) {
423*7c478bd9Sstevel@tonic-gate 				/*
424*7c478bd9Sstevel@tonic-gate 				 * Let's get things going again, but now
425*7c478bd9Sstevel@tonic-gate 				 * ping will start sending to next target IP
426*7c478bd9Sstevel@tonic-gate 				 * address.
427*7c478bd9Sstevel@tonic-gate 				 */
428*7c478bd9Sstevel@tonic-gate 				send_scheduled_probe();
429*7c478bd9Sstevel@tonic-gate 				(void) sigset(SIGALRM, sigalrm_handler);
430*7c478bd9Sstevel@tonic-gate 				schedule_sigalrm();
431*7c478bd9Sstevel@tonic-gate 			}
432*7c478bd9Sstevel@tonic-gate 			return;
433*7c478bd9Sstevel@tonic-gate 		} else {
434*7c478bd9Sstevel@tonic-gate 			/*
435*7c478bd9Sstevel@tonic-gate 			 * If we are not moving to next targetaddr, let's
436*7c478bd9Sstevel@tonic-gate 			 * release the SIGALRM now. We don't want to stall in
437*7c478bd9Sstevel@tonic-gate 			 * the middle of probing a targetaddr if the pr_name()
438*7c478bd9Sstevel@tonic-gate 			 * call (see below) takes longer.
439*7c478bd9Sstevel@tonic-gate 			 */
440*7c478bd9Sstevel@tonic-gate 			if (!last_reply_from_targetaddr)
441*7c478bd9Sstevel@tonic-gate 				(void) sigrelse(SIGALRM);
442*7c478bd9Sstevel@tonic-gate 			/* else, we'll release it later */
443*7c478bd9Sstevel@tonic-gate 		}
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 		dst_addr.addr = ip->ip_dst;
446*7c478bd9Sstevel@tonic-gate 		if (valid_reply) {
447*7c478bd9Sstevel@tonic-gate 			Printf("%d bytes from %s: ", cc,
448*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&from->sin_addr, AF_INET));
449*7c478bd9Sstevel@tonic-gate 			Printf("udp_port=%d. ", ntohs(up->uh_dport));
450*7c478bd9Sstevel@tonic-gate 			print_newline = _B_TRUE;
451*7c478bd9Sstevel@tonic-gate 		} else if (is_a_target(ai_dst, &dst_addr) || verbose) {
452*7c478bd9Sstevel@tonic-gate 			if (icp->icmp_code >= A_CNT(unreach)) {
453*7c478bd9Sstevel@tonic-gate 				Printf("ICMP %d Unreachable from gateway %s\n",
454*7c478bd9Sstevel@tonic-gate 				    icp->icmp_code,
455*7c478bd9Sstevel@tonic-gate 				    pr_name((char *)&from->sin_addr, AF_INET));
456*7c478bd9Sstevel@tonic-gate 			} else {
457*7c478bd9Sstevel@tonic-gate 				Printf("ICMP %s from gateway %s\n",
458*7c478bd9Sstevel@tonic-gate 				    unreach[icp->icmp_code],
459*7c478bd9Sstevel@tonic-gate 				    pr_name((char *)&from->sin_addr, AF_INET));
460*7c478bd9Sstevel@tonic-gate 			}
461*7c478bd9Sstevel@tonic-gate 			Printf(" for %s from %s", pr_protocol(ip->ip_p),
462*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&ip->ip_src, AF_INET));
463*7c478bd9Sstevel@tonic-gate 			Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
464*7c478bd9Sstevel@tonic-gate 			if (ip->ip_p == IPPROTO_TCP ||
465*7c478bd9Sstevel@tonic-gate 			    ip->ip_p == IPPROTO_UDP) {
466*7c478bd9Sstevel@tonic-gate 				Printf(" port %d ", ntohs(up->uh_dport));
467*7c478bd9Sstevel@tonic-gate 			}
468*7c478bd9Sstevel@tonic-gate 			print_newline = _B_TRUE;
469*7c478bd9Sstevel@tonic-gate 		}
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 		/* if we are timing and the reply has a timeval */
472*7c478bd9Sstevel@tonic-gate 		if (valid_reply && datalen >= sizeof (struct timeval) &&
473*7c478bd9Sstevel@tonic-gate 		    cc_left >= sizeof (struct timeval)) {
474*7c478bd9Sstevel@tonic-gate 			/* LINTED */
475*7c478bd9Sstevel@tonic-gate 			tp = (struct timeval *)((char *)up +
476*7c478bd9Sstevel@tonic-gate 			    sizeof (struct udphdr));
477*7c478bd9Sstevel@tonic-gate 			(void) tvsub(&tv, tp);
478*7c478bd9Sstevel@tonic-gate 			triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec;
479*7c478bd9Sstevel@tonic-gate 			Printf("time=" TIMEFORMAT " ms", triptime/1000.0);
480*7c478bd9Sstevel@tonic-gate 			tsum += triptime;
481*7c478bd9Sstevel@tonic-gate 			tsum2 += triptime*triptime;
482*7c478bd9Sstevel@tonic-gate 			if (triptime < tmin)
483*7c478bd9Sstevel@tonic-gate 				tmin = triptime;
484*7c478bd9Sstevel@tonic-gate 			if (triptime > tmax)
485*7c478bd9Sstevel@tonic-gate 				tmax = triptime;
486*7c478bd9Sstevel@tonic-gate 			print_newline = _B_TRUE;
487*7c478bd9Sstevel@tonic-gate 		}
488*7c478bd9Sstevel@tonic-gate 		if (print_newline)
489*7c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
490*7c478bd9Sstevel@tonic-gate 		/*
491*7c478bd9Sstevel@tonic-gate 		 * If it's stats, probe-all, npackets > 0, and we received reply
492*7c478bd9Sstevel@tonic-gate 		 * for the last probe sent to this target address, then we
493*7c478bd9Sstevel@tonic-gate 		 * don't need to wait anymore, let's move on to next target
494*7c478bd9Sstevel@tonic-gate 		 * address, now!
495*7c478bd9Sstevel@tonic-gate 		 */
496*7c478bd9Sstevel@tonic-gate 		if (last_reply_from_targetaddr) {
497*7c478bd9Sstevel@tonic-gate 			(void) alarm(0);	/* cancel alarm */
498*7c478bd9Sstevel@tonic-gate 			current_targetaddr->probing_done = _B_TRUE;
499*7c478bd9Sstevel@tonic-gate 			(void) sigrelse(SIGALRM);
500*7c478bd9Sstevel@tonic-gate 			send_scheduled_probe();
501*7c478bd9Sstevel@tonic-gate 			schedule_sigalrm();
502*7c478bd9Sstevel@tonic-gate 		}
503*7c478bd9Sstevel@tonic-gate 		break;
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	case ICMP_REDIRECT:
506*7c478bd9Sstevel@tonic-gate 		if (cc_left < sizeof (struct ip)) {
507*7c478bd9Sstevel@tonic-gate 			if (verbose) {
508*7c478bd9Sstevel@tonic-gate 				Printf("packet too short (%d bytes) from %s\n",
509*7c478bd9Sstevel@tonic-gate 				    cc, pr_name((char *)&from->sin_addr,
510*7c478bd9Sstevel@tonic-gate 				    AF_INET));
511*7c478bd9Sstevel@tonic-gate 			}
512*7c478bd9Sstevel@tonic-gate 			return;
513*7c478bd9Sstevel@tonic-gate 		}
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 		ip = &icp->icmp_ip;
516*7c478bd9Sstevel@tonic-gate 		dst_addr.addr = ip->ip_dst;
517*7c478bd9Sstevel@tonic-gate 		if (is_a_target(ai_dst, &dst_addr) || verbose) {
518*7c478bd9Sstevel@tonic-gate 			if (icp->icmp_code >= A_CNT(redirect)) {
519*7c478bd9Sstevel@tonic-gate 				Printf("ICMP %d redirect from gateway %s\n",
520*7c478bd9Sstevel@tonic-gate 				    icp->icmp_code,
521*7c478bd9Sstevel@tonic-gate 				    pr_name((char *)&from->sin_addr, AF_INET));
522*7c478bd9Sstevel@tonic-gate 			} else {
523*7c478bd9Sstevel@tonic-gate 				Printf("ICMP %s redirect from gateway %s\n",
524*7c478bd9Sstevel@tonic-gate 				    redirect[icp->icmp_code],
525*7c478bd9Sstevel@tonic-gate 				    pr_name((char *)&from->sin_addr, AF_INET));
526*7c478bd9Sstevel@tonic-gate 			}
527*7c478bd9Sstevel@tonic-gate 			Printf(" to %s",
528*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&icp->icmp_gwaddr, AF_INET));
529*7c478bd9Sstevel@tonic-gate 			Printf(" for %s\n",
530*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&ip->ip_dst, AF_INET));
531*7c478bd9Sstevel@tonic-gate 		}
532*7c478bd9Sstevel@tonic-gate 		break;
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 	case ICMP_ECHOREPLY:
535*7c478bd9Sstevel@tonic-gate 		if (ntohs(icp->icmp_id) == ident) {
536*7c478bd9Sstevel@tonic-gate 			if (!use_udp && !use_icmp_ts)
537*7c478bd9Sstevel@tonic-gate 				valid_reply = _B_TRUE;
538*7c478bd9Sstevel@tonic-gate 			else
539*7c478bd9Sstevel@tonic-gate 				valid_reply = _B_FALSE;
540*7c478bd9Sstevel@tonic-gate 		} else {
541*7c478bd9Sstevel@tonic-gate 			return;
542*7c478bd9Sstevel@tonic-gate 		}
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 		if (valid_reply) {
545*7c478bd9Sstevel@tonic-gate 			/*
546*7c478bd9Sstevel@tonic-gate 			 * For this valid reply, if we are still sending to
547*7c478bd9Sstevel@tonic-gate 			 * this target IP address, we'd like to do some
548*7c478bd9Sstevel@tonic-gate 			 * updates to targetaddr, so hold SIGALRMs.
549*7c478bd9Sstevel@tonic-gate 			 */
550*7c478bd9Sstevel@tonic-gate 			(void) sighold(SIGALRM);
551*7c478bd9Sstevel@tonic-gate 			is_alive = _B_TRUE;
552*7c478bd9Sstevel@tonic-gate 			nreceived++;
553*7c478bd9Sstevel@tonic-gate 			reply_matched_current_target =
554*7c478bd9Sstevel@tonic-gate 			    seq_match(current_targetaddr->starting_seq_num,
555*7c478bd9Sstevel@tonic-gate 				current_targetaddr->num_sent,
556*7c478bd9Sstevel@tonic-gate 				ntohs(icp->icmp_seq));
557*7c478bd9Sstevel@tonic-gate 			if (reply_matched_current_target) {
558*7c478bd9Sstevel@tonic-gate 				current_targetaddr->got_reply = _B_TRUE;
559*7c478bd9Sstevel@tonic-gate 				nreceived_last_target++;
560*7c478bd9Sstevel@tonic-gate 				/*
561*7c478bd9Sstevel@tonic-gate 				 * Determine if stats, probe-all, and
562*7c478bd9Sstevel@tonic-gate 				 * npackets != 0, and this is the reply for
563*7c478bd9Sstevel@tonic-gate 				 * the last probe we sent to current target
564*7c478bd9Sstevel@tonic-gate 				 * address.
565*7c478bd9Sstevel@tonic-gate 				 */
566*7c478bd9Sstevel@tonic-gate 				if (stats && probe_all && npackets > 0 &&
567*7c478bd9Sstevel@tonic-gate 				    ((current_targetaddr->starting_seq_num +
568*7c478bd9Sstevel@tonic-gate 				    current_targetaddr->num_probes - 1) %
569*7c478bd9Sstevel@tonic-gate 				    (MAX_ICMP_SEQ + 1) ==
570*7c478bd9Sstevel@tonic-gate 				    ntohs(icp->icmp_seq)) &&
571*7c478bd9Sstevel@tonic-gate 				    (current_targetaddr->num_probes ==
572*7c478bd9Sstevel@tonic-gate 				    current_targetaddr->num_sent))
573*7c478bd9Sstevel@tonic-gate 					last_reply_from_targetaddr = _B_TRUE;
574*7c478bd9Sstevel@tonic-gate 			} else {
575*7c478bd9Sstevel@tonic-gate 				/*
576*7c478bd9Sstevel@tonic-gate 				 * If it's just probe_all and we just received
577*7c478bd9Sstevel@tonic-gate 				 * a reply from a target address we were
578*7c478bd9Sstevel@tonic-gate 				 * probing and had timed out (now we are probing
579*7c478bd9Sstevel@tonic-gate 				 * some other target address), we ignore
580*7c478bd9Sstevel@tonic-gate 				 * this reply.
581*7c478bd9Sstevel@tonic-gate 				 */
582*7c478bd9Sstevel@tonic-gate 				if (probe_all && !stats) {
583*7c478bd9Sstevel@tonic-gate 					valid_reply = _B_FALSE;
584*7c478bd9Sstevel@tonic-gate 					/*
585*7c478bd9Sstevel@tonic-gate 					 * Only if it's verbose, we get a
586*7c478bd9Sstevel@tonic-gate 					 * message regarding this reply,
587*7c478bd9Sstevel@tonic-gate 					 * otherwise we are done here.
588*7c478bd9Sstevel@tonic-gate 					 */
589*7c478bd9Sstevel@tonic-gate 					if (!verbose) {
590*7c478bd9Sstevel@tonic-gate 						(void) sigrelse(SIGALRM);
591*7c478bd9Sstevel@tonic-gate 						return;
592*7c478bd9Sstevel@tonic-gate 					}
593*7c478bd9Sstevel@tonic-gate 				}
594*7c478bd9Sstevel@tonic-gate 			}
595*7c478bd9Sstevel@tonic-gate 		}
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 		if (!stats && valid_reply) {
598*7c478bd9Sstevel@tonic-gate 			/*
599*7c478bd9Sstevel@tonic-gate 			 * if we are still sending to the same target address,
600*7c478bd9Sstevel@tonic-gate 			 * then stop it, because we know it's alive.
601*7c478bd9Sstevel@tonic-gate 			 */
602*7c478bd9Sstevel@tonic-gate 			if (reply_matched_current_target) {
603*7c478bd9Sstevel@tonic-gate 				(void) alarm(0);	/* cancel alarm */
604*7c478bd9Sstevel@tonic-gate 				(void) sigset(SIGALRM, SIG_IGN);
605*7c478bd9Sstevel@tonic-gate 				current_targetaddr->probing_done = _B_TRUE;
606*7c478bd9Sstevel@tonic-gate 			}
607*7c478bd9Sstevel@tonic-gate 			(void) sigrelse(SIGALRM);
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 			if (!probe_all) {
610*7c478bd9Sstevel@tonic-gate 				Printf("%s is alive\n", targethost);
611*7c478bd9Sstevel@tonic-gate 			} else {
612*7c478bd9Sstevel@tonic-gate 				/*
613*7c478bd9Sstevel@tonic-gate 				 * If we are using send_reply, the real
614*7c478bd9Sstevel@tonic-gate 				 * target address is not the src address of the
615*7c478bd9Sstevel@tonic-gate 				 * replies. Use icmp_seq to find out where this
616*7c478bd9Sstevel@tonic-gate 				 * probe was sent to.
617*7c478bd9Sstevel@tonic-gate 				 */
618*7c478bd9Sstevel@tonic-gate 				if (send_reply) {
619*7c478bd9Sstevel@tonic-gate 					(void) find_dstaddr(
620*7c478bd9Sstevel@tonic-gate 					    ntohs(icp->icmp_seq), &dst_addr);
621*7c478bd9Sstevel@tonic-gate 					(void) inet_ntop(AF_INET,
622*7c478bd9Sstevel@tonic-gate 					    (void *)&dst_addr.addr,
623*7c478bd9Sstevel@tonic-gate 					    tmp_buf, sizeof (tmp_buf));
624*7c478bd9Sstevel@tonic-gate 				} else {
625*7c478bd9Sstevel@tonic-gate 					(void) inet_ntop(AF_INET,
626*7c478bd9Sstevel@tonic-gate 					    (void *)&from->sin_addr,
627*7c478bd9Sstevel@tonic-gate 					    tmp_buf, sizeof (tmp_buf));
628*7c478bd9Sstevel@tonic-gate 				}
629*7c478bd9Sstevel@tonic-gate 				if (nflag) {
630*7c478bd9Sstevel@tonic-gate 					Printf("%s is alive\n", tmp_buf);
631*7c478bd9Sstevel@tonic-gate 				} else {
632*7c478bd9Sstevel@tonic-gate 					Printf("%s (%s) is alive\n",
633*7c478bd9Sstevel@tonic-gate 					    targethost, tmp_buf);
634*7c478bd9Sstevel@tonic-gate 				}
635*7c478bd9Sstevel@tonic-gate 			}
636*7c478bd9Sstevel@tonic-gate 			if (reply_matched_current_target) {
637*7c478bd9Sstevel@tonic-gate 				/*
638*7c478bd9Sstevel@tonic-gate 				 * Let's get things going again, but now
639*7c478bd9Sstevel@tonic-gate 				 * ping will start sending to next target IP
640*7c478bd9Sstevel@tonic-gate 				 * address.
641*7c478bd9Sstevel@tonic-gate 				 */
642*7c478bd9Sstevel@tonic-gate 				send_scheduled_probe();
643*7c478bd9Sstevel@tonic-gate 				(void) sigset(SIGALRM, sigalrm_handler);
644*7c478bd9Sstevel@tonic-gate 				schedule_sigalrm();
645*7c478bd9Sstevel@tonic-gate 			}
646*7c478bd9Sstevel@tonic-gate 			return;
647*7c478bd9Sstevel@tonic-gate 		} else {
648*7c478bd9Sstevel@tonic-gate 			/*
649*7c478bd9Sstevel@tonic-gate 			 * If we are not moving to next targetaddr, let's
650*7c478bd9Sstevel@tonic-gate 			 * release the SIGALRM now. We don't want to stall in
651*7c478bd9Sstevel@tonic-gate 			 * the middle of probing a targetaddr if the pr_name()
652*7c478bd9Sstevel@tonic-gate 			 * call (see below) takes longer.
653*7c478bd9Sstevel@tonic-gate 			 */
654*7c478bd9Sstevel@tonic-gate 			if (!last_reply_from_targetaddr)
655*7c478bd9Sstevel@tonic-gate 				(void) sigrelse(SIGALRM);
656*7c478bd9Sstevel@tonic-gate 			/* else, we'll release it later */
657*7c478bd9Sstevel@tonic-gate 		}
658*7c478bd9Sstevel@tonic-gate 		/*
659*7c478bd9Sstevel@tonic-gate 		 * If we are using send_reply, the real target address is
660*7c478bd9Sstevel@tonic-gate 		 * not the src address of the replies. Use icmp_seq to find out
661*7c478bd9Sstevel@tonic-gate 		 * where this probe was sent to.
662*7c478bd9Sstevel@tonic-gate 		 */
663*7c478bd9Sstevel@tonic-gate 		if (send_reply) {
664*7c478bd9Sstevel@tonic-gate 			(void) find_dstaddr(ntohs(icp->icmp_seq), &dst_addr);
665*7c478bd9Sstevel@tonic-gate 			Printf("%d bytes from %s: ", cc,
666*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&dst_addr.addr,  AF_INET));
667*7c478bd9Sstevel@tonic-gate 		} else {
668*7c478bd9Sstevel@tonic-gate 			Printf("%d bytes from %s: ", cc,
669*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&from->sin_addr, AF_INET));
670*7c478bd9Sstevel@tonic-gate 		}
671*7c478bd9Sstevel@tonic-gate 		Printf("icmp_seq=%d. ", ntohs(icp->icmp_seq));
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 		if (valid_reply && datalen >= sizeof (struct timeval) &&
674*7c478bd9Sstevel@tonic-gate 		    cc_left >= sizeof (struct timeval)) {
675*7c478bd9Sstevel@tonic-gate 			/* LINTED */
676*7c478bd9Sstevel@tonic-gate 			tp = (struct timeval *)&icp->icmp_data[0];
677*7c478bd9Sstevel@tonic-gate 			(void) tvsub(&tv, tp);
678*7c478bd9Sstevel@tonic-gate 			triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec;
679*7c478bd9Sstevel@tonic-gate 			Printf("time=" TIMEFORMAT " ms", triptime/1000.0);
680*7c478bd9Sstevel@tonic-gate 			tsum += triptime;
681*7c478bd9Sstevel@tonic-gate 			tsum2 += triptime*triptime;
682*7c478bd9Sstevel@tonic-gate 			if (triptime < tmin)
683*7c478bd9Sstevel@tonic-gate 				tmin = triptime;
684*7c478bd9Sstevel@tonic-gate 			if (triptime > tmax)
685*7c478bd9Sstevel@tonic-gate 				tmax = triptime;
686*7c478bd9Sstevel@tonic-gate 		}
687*7c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 		/*
690*7c478bd9Sstevel@tonic-gate 		 * If it's stats, probe-all, npackets > 0, and we received reply
691*7c478bd9Sstevel@tonic-gate 		 * for the last probe sent to this target address, then we
692*7c478bd9Sstevel@tonic-gate 		 * don't need to wait anymore, let's move on to next target
693*7c478bd9Sstevel@tonic-gate 		 * address, now!
694*7c478bd9Sstevel@tonic-gate 		 */
695*7c478bd9Sstevel@tonic-gate 		if (last_reply_from_targetaddr) {
696*7c478bd9Sstevel@tonic-gate 			(void) alarm(0);	/* cancel alarm */
697*7c478bd9Sstevel@tonic-gate 			current_targetaddr->probing_done = _B_TRUE;
698*7c478bd9Sstevel@tonic-gate 			(void) sigrelse(SIGALRM);
699*7c478bd9Sstevel@tonic-gate 			send_scheduled_probe();
700*7c478bd9Sstevel@tonic-gate 			schedule_sigalrm();
701*7c478bd9Sstevel@tonic-gate 		}
702*7c478bd9Sstevel@tonic-gate 		break;
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 	case ICMP_SOURCEQUENCH:
705*7c478bd9Sstevel@tonic-gate 		if (cc_left < sizeof (struct ip)) {
706*7c478bd9Sstevel@tonic-gate 			if (verbose) {
707*7c478bd9Sstevel@tonic-gate 				Printf("packet too short (%d bytes) from %s\n",
708*7c478bd9Sstevel@tonic-gate 				    cc, pr_name((char *)&from->sin_addr,
709*7c478bd9Sstevel@tonic-gate 				    AF_INET));
710*7c478bd9Sstevel@tonic-gate 			}
711*7c478bd9Sstevel@tonic-gate 			return;
712*7c478bd9Sstevel@tonic-gate 		}
713*7c478bd9Sstevel@tonic-gate 		ip = &icp->icmp_ip;
714*7c478bd9Sstevel@tonic-gate 		hlen1 = ip->ip_hl << 2;
715*7c478bd9Sstevel@tonic-gate 		dst_addr.addr = ip->ip_dst;
716*7c478bd9Sstevel@tonic-gate 		if (is_a_target(ai_dst, &dst_addr) || verbose) {
717*7c478bd9Sstevel@tonic-gate 			Printf("ICMP Source Quench from %s\n",
718*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&from->sin_addr, AF_INET));
719*7c478bd9Sstevel@tonic-gate 			Printf(" for %s from %s", pr_protocol(ip->ip_p),
720*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&ip->ip_src, AF_INET));
721*7c478bd9Sstevel@tonic-gate 			Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 			/*
724*7c478bd9Sstevel@tonic-gate 			 * if it's a UDP or TCP packet, we need at least first
725*7c478bd9Sstevel@tonic-gate 			 * 4 bytes of it to see the src/dst ports
726*7c478bd9Sstevel@tonic-gate 			 */
727*7c478bd9Sstevel@tonic-gate 			if ((ip->ip_p == IPPROTO_TCP ||
728*7c478bd9Sstevel@tonic-gate 			    ip->ip_p == IPPROTO_UDP) &&
729*7c478bd9Sstevel@tonic-gate 			    (cc_left >= hlen1 + 4)) {
730*7c478bd9Sstevel@tonic-gate 				/* LINTED */
731*7c478bd9Sstevel@tonic-gate 				up = (struct udphdr *)((uchar_t *)ip + hlen1);
732*7c478bd9Sstevel@tonic-gate 				Printf(" port %d", ntohs(up->uh_dport));
733*7c478bd9Sstevel@tonic-gate 			}
734*7c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
735*7c478bd9Sstevel@tonic-gate 		}
736*7c478bd9Sstevel@tonic-gate 		break;
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 	case ICMP_PARAMPROB:
739*7c478bd9Sstevel@tonic-gate 		if (cc_left < sizeof (struct ip)) {
740*7c478bd9Sstevel@tonic-gate 			if (verbose) {
741*7c478bd9Sstevel@tonic-gate 				Printf("packet too short (%d bytes) from %s\n",
742*7c478bd9Sstevel@tonic-gate 				    cc, pr_name((char *)&from->sin_addr,
743*7c478bd9Sstevel@tonic-gate 				    AF_INET));
744*7c478bd9Sstevel@tonic-gate 			}
745*7c478bd9Sstevel@tonic-gate 			return;
746*7c478bd9Sstevel@tonic-gate 		}
747*7c478bd9Sstevel@tonic-gate 		ip = &icp->icmp_ip;
748*7c478bd9Sstevel@tonic-gate 		hlen1 = ip->ip_hl << 2;
749*7c478bd9Sstevel@tonic-gate 		dst_addr.addr = ip->ip_dst;
750*7c478bd9Sstevel@tonic-gate 		if (is_a_target(ai_dst, &dst_addr) || verbose) {
751*7c478bd9Sstevel@tonic-gate 			switch (icp->icmp_code) {
752*7c478bd9Sstevel@tonic-gate 			case ICMP_PARAMPROB_OPTABSENT:
753*7c478bd9Sstevel@tonic-gate 				Printf("ICMP Missing a Required Option "
754*7c478bd9Sstevel@tonic-gate 				    "parameter problem from %s\n",
755*7c478bd9Sstevel@tonic-gate 				    pr_name((char *)&from->sin_addr, AF_INET));
756*7c478bd9Sstevel@tonic-gate 				Printf(" option type = %d", icp->icmp_pptr);
757*7c478bd9Sstevel@tonic-gate 				break;
758*7c478bd9Sstevel@tonic-gate 			case ICMP_PARAMPROB_BADLENGTH:
759*7c478bd9Sstevel@tonic-gate 				Printf("ICMP Bad Length parameter problem "
760*7c478bd9Sstevel@tonic-gate 				    "from %s\n",
761*7c478bd9Sstevel@tonic-gate 				    pr_name((char *)&from->sin_addr, AF_INET));
762*7c478bd9Sstevel@tonic-gate 				Printf(" in byte %d", icp->icmp_pptr);
763*7c478bd9Sstevel@tonic-gate 				if (icp->icmp_pptr <= hlen1) {
764*7c478bd9Sstevel@tonic-gate 					Printf(" (value 0x%x)",
765*7c478bd9Sstevel@tonic-gate 					    *((char *)ip + icp->icmp_pptr));
766*7c478bd9Sstevel@tonic-gate 				}
767*7c478bd9Sstevel@tonic-gate 				break;
768*7c478bd9Sstevel@tonic-gate 			case 0:
769*7c478bd9Sstevel@tonic-gate 			default:
770*7c478bd9Sstevel@tonic-gate 				Printf("ICMP Parameter Problem from %s\n",
771*7c478bd9Sstevel@tonic-gate 				    pr_name((char *)&from->sin_addr, AF_INET));
772*7c478bd9Sstevel@tonic-gate 				Printf(" in byte %d", icp->icmp_pptr);
773*7c478bd9Sstevel@tonic-gate 				if (icp->icmp_pptr <= hlen1) {
774*7c478bd9Sstevel@tonic-gate 					Printf(" (value 0x%x)",
775*7c478bd9Sstevel@tonic-gate 					    *((char *)ip + icp->icmp_pptr));
776*7c478bd9Sstevel@tonic-gate 				}
777*7c478bd9Sstevel@tonic-gate 				break;
778*7c478bd9Sstevel@tonic-gate 			}
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 			Printf(" for %s from %s", pr_protocol(ip->ip_p),
781*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&ip->ip_src, AF_INET));
782*7c478bd9Sstevel@tonic-gate 			Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 			/*
785*7c478bd9Sstevel@tonic-gate 			 * if it's a UDP or TCP packet, we need at least first
786*7c478bd9Sstevel@tonic-gate 			 * 4 bytes of it to see the src/dst ports
787*7c478bd9Sstevel@tonic-gate 			 */
788*7c478bd9Sstevel@tonic-gate 			if ((ip->ip_p == IPPROTO_TCP ||
789*7c478bd9Sstevel@tonic-gate 			    ip->ip_p == IPPROTO_UDP) &&
790*7c478bd9Sstevel@tonic-gate 			    (cc_left >= hlen1 + 4)) {
791*7c478bd9Sstevel@tonic-gate 				/* LINTED */
792*7c478bd9Sstevel@tonic-gate 				up = (struct udphdr *)((uchar_t *)ip + hlen1);
793*7c478bd9Sstevel@tonic-gate 				Printf(" port %d", ntohs(up->uh_dport));
794*7c478bd9Sstevel@tonic-gate 			}
795*7c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
796*7c478bd9Sstevel@tonic-gate 		}
797*7c478bd9Sstevel@tonic-gate 		break;
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate 	case ICMP_TIMXCEED:
800*7c478bd9Sstevel@tonic-gate 		if (cc_left < sizeof (struct ip)) {
801*7c478bd9Sstevel@tonic-gate 			if (verbose) {
802*7c478bd9Sstevel@tonic-gate 				Printf("packet too short (%d bytes) from %s\n",
803*7c478bd9Sstevel@tonic-gate 				    cc, pr_name((char *)&from->sin_addr,
804*7c478bd9Sstevel@tonic-gate 				    AF_INET));
805*7c478bd9Sstevel@tonic-gate 			}
806*7c478bd9Sstevel@tonic-gate 			return;
807*7c478bd9Sstevel@tonic-gate 		}
808*7c478bd9Sstevel@tonic-gate 		ip = &icp->icmp_ip;
809*7c478bd9Sstevel@tonic-gate 		hlen1 = ip->ip_hl << 2;
810*7c478bd9Sstevel@tonic-gate 		dst_addr.addr = ip->ip_dst;
811*7c478bd9Sstevel@tonic-gate 		if (is_a_target(ai_dst, &dst_addr) || verbose) {
812*7c478bd9Sstevel@tonic-gate 			if (icp->icmp_code >= A_CNT(timexceed)) {
813*7c478bd9Sstevel@tonic-gate 				Printf("ICMP %d time exceeded from %s\n",
814*7c478bd9Sstevel@tonic-gate 				    icp->icmp_code,
815*7c478bd9Sstevel@tonic-gate 				    pr_name((char *)&from->sin_addr, AF_INET));
816*7c478bd9Sstevel@tonic-gate 			} else {
817*7c478bd9Sstevel@tonic-gate 				Printf("ICMP %s from %s\n",
818*7c478bd9Sstevel@tonic-gate 				    timexceed[icp->icmp_code],
819*7c478bd9Sstevel@tonic-gate 				    pr_name((char *)&from->sin_addr, AF_INET));
820*7c478bd9Sstevel@tonic-gate 			}
821*7c478bd9Sstevel@tonic-gate 			Printf(" for %s from %s", pr_protocol(ip->ip_p),
822*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&ip->ip_src, AF_INET));
823*7c478bd9Sstevel@tonic-gate 			Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
824*7c478bd9Sstevel@tonic-gate 			if ((ip->ip_p == IPPROTO_TCP ||
825*7c478bd9Sstevel@tonic-gate 			    ip->ip_p == IPPROTO_UDP) &&
826*7c478bd9Sstevel@tonic-gate 			    (cc_left >= hlen1 + 4)) {
827*7c478bd9Sstevel@tonic-gate 				/* LINTED */
828*7c478bd9Sstevel@tonic-gate 				up = (struct udphdr *)((uchar_t *)ip + hlen1);
829*7c478bd9Sstevel@tonic-gate 				Printf(" port %d", ntohs(up->uh_dport));
830*7c478bd9Sstevel@tonic-gate 			}
831*7c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
832*7c478bd9Sstevel@tonic-gate 		}
833*7c478bd9Sstevel@tonic-gate 		break;
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	case ICMP_TSTAMPREPLY:
836*7c478bd9Sstevel@tonic-gate 		/* the packet should have enough space to store timestamps */
837*7c478bd9Sstevel@tonic-gate 		if (cc_left < sizeof (struct id_ts)) {
838*7c478bd9Sstevel@tonic-gate 			if (verbose) {
839*7c478bd9Sstevel@tonic-gate 				Printf("packet too short (%d bytes) from %s\n",
840*7c478bd9Sstevel@tonic-gate 				    cc, pr_name((char *)&from->sin_addr,
841*7c478bd9Sstevel@tonic-gate 				    AF_INET));
842*7c478bd9Sstevel@tonic-gate 			}
843*7c478bd9Sstevel@tonic-gate 			return;
844*7c478bd9Sstevel@tonic-gate 		}
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 		if (ntohs(icp->icmp_id) == ident) {
847*7c478bd9Sstevel@tonic-gate 			if (use_icmp_ts)
848*7c478bd9Sstevel@tonic-gate 				valid_reply = _B_TRUE;
849*7c478bd9Sstevel@tonic-gate 			else
850*7c478bd9Sstevel@tonic-gate 				valid_reply = _B_FALSE;
851*7c478bd9Sstevel@tonic-gate 		} else {
852*7c478bd9Sstevel@tonic-gate 			return;
853*7c478bd9Sstevel@tonic-gate 		}
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 		if (valid_reply) {
856*7c478bd9Sstevel@tonic-gate 			/*
857*7c478bd9Sstevel@tonic-gate 			 * For this valid reply, if we are still sending to
858*7c478bd9Sstevel@tonic-gate 			 * this target IP address, we'd like to do some
859*7c478bd9Sstevel@tonic-gate 			 * updates to targetaddr, so hold SIGALRMs.
860*7c478bd9Sstevel@tonic-gate 			 */
861*7c478bd9Sstevel@tonic-gate 			(void) sighold(SIGALRM);
862*7c478bd9Sstevel@tonic-gate 			is_alive = _B_TRUE;
863*7c478bd9Sstevel@tonic-gate 			nreceived++;
864*7c478bd9Sstevel@tonic-gate 			reply_matched_current_target =
865*7c478bd9Sstevel@tonic-gate 			    seq_match(current_targetaddr->starting_seq_num,
866*7c478bd9Sstevel@tonic-gate 				current_targetaddr->num_sent,
867*7c478bd9Sstevel@tonic-gate 				ntohs(icp->icmp_seq));
868*7c478bd9Sstevel@tonic-gate 			if (reply_matched_current_target) {
869*7c478bd9Sstevel@tonic-gate 				current_targetaddr->got_reply = _B_TRUE;
870*7c478bd9Sstevel@tonic-gate 				nreceived_last_target++;
871*7c478bd9Sstevel@tonic-gate 				/*
872*7c478bd9Sstevel@tonic-gate 				 * Determine if stats, probe-all, and
873*7c478bd9Sstevel@tonic-gate 				 * npackets != 0, and this is the reply for
874*7c478bd9Sstevel@tonic-gate 				 * the last probe we sent to current target
875*7c478bd9Sstevel@tonic-gate 				 * address.
876*7c478bd9Sstevel@tonic-gate 				 */
877*7c478bd9Sstevel@tonic-gate 				if (stats && probe_all && npackets > 0 &&
878*7c478bd9Sstevel@tonic-gate 				    ((current_targetaddr->starting_seq_num +
879*7c478bd9Sstevel@tonic-gate 				    current_targetaddr->num_probes - 1) %
880*7c478bd9Sstevel@tonic-gate 				    (MAX_ICMP_SEQ + 1) ==
881*7c478bd9Sstevel@tonic-gate 				    ntohs(icp->icmp_seq)) &&
882*7c478bd9Sstevel@tonic-gate 				    (current_targetaddr->num_probes ==
883*7c478bd9Sstevel@tonic-gate 				    current_targetaddr->num_sent))
884*7c478bd9Sstevel@tonic-gate 					last_reply_from_targetaddr = _B_TRUE;
885*7c478bd9Sstevel@tonic-gate 			} else {
886*7c478bd9Sstevel@tonic-gate 				/*
887*7c478bd9Sstevel@tonic-gate 				 * If it's just probe_all and we just received
888*7c478bd9Sstevel@tonic-gate 				 * a reply from a target address we were
889*7c478bd9Sstevel@tonic-gate 				 * probing and had timed out (now we are probing
890*7c478bd9Sstevel@tonic-gate 				 * some other target address), we ignore
891*7c478bd9Sstevel@tonic-gate 				 * this reply.
892*7c478bd9Sstevel@tonic-gate 				 */
893*7c478bd9Sstevel@tonic-gate 				if (probe_all && !stats) {
894*7c478bd9Sstevel@tonic-gate 					valid_reply = _B_FALSE;
895*7c478bd9Sstevel@tonic-gate 					/*
896*7c478bd9Sstevel@tonic-gate 					 * Only if it's verbose, we get a
897*7c478bd9Sstevel@tonic-gate 					 * message regarding this reply,
898*7c478bd9Sstevel@tonic-gate 					 * otherwise we are done here.
899*7c478bd9Sstevel@tonic-gate 					 */
900*7c478bd9Sstevel@tonic-gate 					if (!verbose) {
901*7c478bd9Sstevel@tonic-gate 						(void) sigrelse(SIGALRM);
902*7c478bd9Sstevel@tonic-gate 						return;
903*7c478bd9Sstevel@tonic-gate 					}
904*7c478bd9Sstevel@tonic-gate 				}
905*7c478bd9Sstevel@tonic-gate 			}
906*7c478bd9Sstevel@tonic-gate 		}
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 		if (!stats && valid_reply) {
909*7c478bd9Sstevel@tonic-gate 			/*
910*7c478bd9Sstevel@tonic-gate 			 * if we are still sending to the same target address,
911*7c478bd9Sstevel@tonic-gate 			 * then stop it, because we know it's alive.
912*7c478bd9Sstevel@tonic-gate 			 */
913*7c478bd9Sstevel@tonic-gate 			if (reply_matched_current_target) {
914*7c478bd9Sstevel@tonic-gate 				(void) alarm(0);	/* cancel alarm */
915*7c478bd9Sstevel@tonic-gate 				(void) sigset(SIGALRM, SIG_IGN);
916*7c478bd9Sstevel@tonic-gate 				current_targetaddr->probing_done = _B_TRUE;
917*7c478bd9Sstevel@tonic-gate 			}
918*7c478bd9Sstevel@tonic-gate 			(void) sigrelse(SIGALRM);
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 			if (!probe_all) {
921*7c478bd9Sstevel@tonic-gate 				Printf("%s is alive\n", targethost);
922*7c478bd9Sstevel@tonic-gate 			} else {
923*7c478bd9Sstevel@tonic-gate 				/*
924*7c478bd9Sstevel@tonic-gate 				 * If we are using send_reply, the real
925*7c478bd9Sstevel@tonic-gate 				 * target address is not the src address of the
926*7c478bd9Sstevel@tonic-gate 				 * replies. Use icmp_seq to find out where this
927*7c478bd9Sstevel@tonic-gate 				 * probe was sent to.
928*7c478bd9Sstevel@tonic-gate 				 */
929*7c478bd9Sstevel@tonic-gate 				if (send_reply) {
930*7c478bd9Sstevel@tonic-gate 					(void) find_dstaddr(
931*7c478bd9Sstevel@tonic-gate 					    ntohs(icp->icmp_seq), &dst_addr);
932*7c478bd9Sstevel@tonic-gate 					(void) inet_ntop(AF_INET,
933*7c478bd9Sstevel@tonic-gate 					    (void *)&dst_addr.addr,
934*7c478bd9Sstevel@tonic-gate 					    tmp_buf, sizeof (tmp_buf));
935*7c478bd9Sstevel@tonic-gate 				} else {
936*7c478bd9Sstevel@tonic-gate 					(void) inet_ntop(AF_INET,
937*7c478bd9Sstevel@tonic-gate 					    (void *)&from->sin_addr,
938*7c478bd9Sstevel@tonic-gate 					    tmp_buf, sizeof (tmp_buf));
939*7c478bd9Sstevel@tonic-gate 				}
940*7c478bd9Sstevel@tonic-gate 				if (nflag) {
941*7c478bd9Sstevel@tonic-gate 					Printf("%s is alive\n", tmp_buf);
942*7c478bd9Sstevel@tonic-gate 				} else {
943*7c478bd9Sstevel@tonic-gate 					Printf("%s (%s) is alive\n",
944*7c478bd9Sstevel@tonic-gate 					    targethost, tmp_buf);
945*7c478bd9Sstevel@tonic-gate 				}
946*7c478bd9Sstevel@tonic-gate 			}
947*7c478bd9Sstevel@tonic-gate 			if (reply_matched_current_target) {
948*7c478bd9Sstevel@tonic-gate 				/*
949*7c478bd9Sstevel@tonic-gate 				 * Let's get things going again, but now
950*7c478bd9Sstevel@tonic-gate 				 * ping will start sending to next target IP
951*7c478bd9Sstevel@tonic-gate 				 * address.
952*7c478bd9Sstevel@tonic-gate 				 */
953*7c478bd9Sstevel@tonic-gate 				send_scheduled_probe();
954*7c478bd9Sstevel@tonic-gate 				(void) sigset(SIGALRM, sigalrm_handler);
955*7c478bd9Sstevel@tonic-gate 				schedule_sigalrm();
956*7c478bd9Sstevel@tonic-gate 			}
957*7c478bd9Sstevel@tonic-gate 			return;
958*7c478bd9Sstevel@tonic-gate 		} else {
959*7c478bd9Sstevel@tonic-gate 			/*
960*7c478bd9Sstevel@tonic-gate 			 * If we are not moving to next targetaddr, let's
961*7c478bd9Sstevel@tonic-gate 			 * release the SIGALRM now. We don't want to stall in
962*7c478bd9Sstevel@tonic-gate 			 * the middle of probing a targetaddr if the pr_name()
963*7c478bd9Sstevel@tonic-gate 			 * call (see below) takes longer.
964*7c478bd9Sstevel@tonic-gate 			 */
965*7c478bd9Sstevel@tonic-gate 			if (!last_reply_from_targetaddr)
966*7c478bd9Sstevel@tonic-gate 				(void) sigrelse(SIGALRM);
967*7c478bd9Sstevel@tonic-gate 			/* else, we'll release it later */
968*7c478bd9Sstevel@tonic-gate 		}
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 		/*
971*7c478bd9Sstevel@tonic-gate 		 * If we are using send_reply, the real target address is
972*7c478bd9Sstevel@tonic-gate 		 * not the src address of the replies. Use icmp_seq to find out
973*7c478bd9Sstevel@tonic-gate 		 * where this probe was sent to.
974*7c478bd9Sstevel@tonic-gate 		 */
975*7c478bd9Sstevel@tonic-gate 		if (send_reply) {
976*7c478bd9Sstevel@tonic-gate 			(void) find_dstaddr(ntohs(icp->icmp_seq), &dst_addr);
977*7c478bd9Sstevel@tonic-gate 			Printf("%d bytes from %s: ", cc,
978*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&dst_addr.addr,  AF_INET));
979*7c478bd9Sstevel@tonic-gate 		} else {
980*7c478bd9Sstevel@tonic-gate 			Printf("%d bytes from %s: ", cc,
981*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&from->sin_addr, AF_INET));
982*7c478bd9Sstevel@tonic-gate 		}
983*7c478bd9Sstevel@tonic-gate 		Printf("icmp_seq=%d. ", ntohs(icp->icmp_seq));
984*7c478bd9Sstevel@tonic-gate 		Printf("orig = %lu, recv = %lu, xmit = %lu ",
985*7c478bd9Sstevel@tonic-gate 		    (ulong_t)ntohl(icp->icmp_otime),
986*7c478bd9Sstevel@tonic-gate 		    (ulong_t)ntohl(icp->icmp_rtime),
987*7c478bd9Sstevel@tonic-gate 		    (ulong_t)ntohl(icp->icmp_ttime));
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 		if (valid_reply) {
990*7c478bd9Sstevel@tonic-gate 			/*
991*7c478bd9Sstevel@tonic-gate 			 * icp->icmp_otime is the time passed since midnight.
992*7c478bd9Sstevel@tonic-gate 			 * Therefore we need to adjust tv value, which is
993*7c478bd9Sstevel@tonic-gate 			 * the time passed since Jan 1, 1970.
994*7c478bd9Sstevel@tonic-gate 			 */
995*7c478bd9Sstevel@tonic-gate 			triptime = (tv.tv_sec % (24LL * 60 * 60)) * MILLISEC +
996*7c478bd9Sstevel@tonic-gate 			    (tv.tv_usec / (MICROSEC/MILLISEC));
997*7c478bd9Sstevel@tonic-gate 			triptime -= ntohl(icp->icmp_otime);
998*7c478bd9Sstevel@tonic-gate 			if (triptime < 0)
999*7c478bd9Sstevel@tonic-gate 				triptime += 24LL * 60 * 60 * MILLISEC;
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 			Printf("time=%d. ms", (int)triptime);
1002*7c478bd9Sstevel@tonic-gate 			triptime *= (MICROSEC/MILLISEC);
1003*7c478bd9Sstevel@tonic-gate 			tsum += triptime;
1004*7c478bd9Sstevel@tonic-gate 			tsum2 += triptime*triptime;
1005*7c478bd9Sstevel@tonic-gate 			if (triptime < tmin)
1006*7c478bd9Sstevel@tonic-gate 				tmin = triptime;
1007*7c478bd9Sstevel@tonic-gate 			if (triptime > tmax)
1008*7c478bd9Sstevel@tonic-gate 				tmax = triptime;
1009*7c478bd9Sstevel@tonic-gate 		}
1010*7c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
1011*7c478bd9Sstevel@tonic-gate 		/*
1012*7c478bd9Sstevel@tonic-gate 		 * If it's stats, probe-all, npackets > 0, and we received reply
1013*7c478bd9Sstevel@tonic-gate 		 * for the last probe sent to this target address, then we
1014*7c478bd9Sstevel@tonic-gate 		 * don't need to wait anymore, let's move on to next target
1015*7c478bd9Sstevel@tonic-gate 		 * address, now!
1016*7c478bd9Sstevel@tonic-gate 		 */
1017*7c478bd9Sstevel@tonic-gate 		if (last_reply_from_targetaddr) {
1018*7c478bd9Sstevel@tonic-gate 			(void) alarm(0);	/* cancel alarm */
1019*7c478bd9Sstevel@tonic-gate 			current_targetaddr->probing_done = _B_TRUE;
1020*7c478bd9Sstevel@tonic-gate 			(void) sigrelse(SIGALRM);
1021*7c478bd9Sstevel@tonic-gate 			send_scheduled_probe();
1022*7c478bd9Sstevel@tonic-gate 			schedule_sigalrm();
1023*7c478bd9Sstevel@tonic-gate 		}
1024*7c478bd9Sstevel@tonic-gate 		break;
1025*7c478bd9Sstevel@tonic-gate 	case ICMP_ROUTERADVERT:
1026*7c478bd9Sstevel@tonic-gate 	case ICMP_ROUTERSOLICIT:
1027*7c478bd9Sstevel@tonic-gate 		/* Router discovery messages */
1028*7c478bd9Sstevel@tonic-gate 		return;
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 	case ICMP_ECHO:
1031*7c478bd9Sstevel@tonic-gate 	case ICMP_TSTAMP:
1032*7c478bd9Sstevel@tonic-gate 	case ICMP_IREQ:
1033*7c478bd9Sstevel@tonic-gate 	case ICMP_MASKREQ:
1034*7c478bd9Sstevel@tonic-gate 		/* These were never passed out from the SunOS 4.X kernel. */
1035*7c478bd9Sstevel@tonic-gate 		return;
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 	case ICMP_IREQREPLY:
1038*7c478bd9Sstevel@tonic-gate 	case ICMP_MASKREPLY:
1039*7c478bd9Sstevel@tonic-gate 		/* Replies for information and address mask requests */
1040*7c478bd9Sstevel@tonic-gate 		return;
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 	default:
1043*7c478bd9Sstevel@tonic-gate 		if (verbose) {
1044*7c478bd9Sstevel@tonic-gate 			Printf("%d bytes from %s:\n", cc,
1045*7c478bd9Sstevel@tonic-gate 			    pr_name((char *)&from->sin_addr, AF_INET));
1046*7c478bd9Sstevel@tonic-gate 			Printf("icmp_type=%d (%s) ",
1047*7c478bd9Sstevel@tonic-gate 			    icp->icmp_type, pr_type(icp->icmp_type));
1048*7c478bd9Sstevel@tonic-gate 			Printf("icmp_code=%d\n", icp->icmp_code);
1049*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < 12; i++) {
1050*7c478bd9Sstevel@tonic-gate 				Printf("x%2.2x: x%8.8x\n",
1051*7c478bd9Sstevel@tonic-gate 				    i * sizeof (int32_t), *intp++);
1052*7c478bd9Sstevel@tonic-gate 			}
1053*7c478bd9Sstevel@tonic-gate 		}
1054*7c478bd9Sstevel@tonic-gate 		break;
1055*7c478bd9Sstevel@tonic-gate 	}
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate 	buf += sizeof (struct ip);
1058*7c478bd9Sstevel@tonic-gate 	hlen -= sizeof (struct ip);
1059*7c478bd9Sstevel@tonic-gate 
1060*7c478bd9Sstevel@tonic-gate 	/* if verbose and there exists IP options */
1061*7c478bd9Sstevel@tonic-gate 	if (verbose && hlen > 0)
1062*7c478bd9Sstevel@tonic-gate 		pr_options((uchar_t *)buf, hlen);
1063*7c478bd9Sstevel@tonic-gate }
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate /*
1066*7c478bd9Sstevel@tonic-gate  * Print out the ip options.
1067*7c478bd9Sstevel@tonic-gate  */
1068*7c478bd9Sstevel@tonic-gate static void
1069*7c478bd9Sstevel@tonic-gate pr_options(uchar_t *opt, int optlength)
1070*7c478bd9Sstevel@tonic-gate {
1071*7c478bd9Sstevel@tonic-gate 	int curlength;
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	Printf("  IP options: ");
1074*7c478bd9Sstevel@tonic-gate 	while (optlength > 0) {
1075*7c478bd9Sstevel@tonic-gate 		curlength = opt[1];
1076*7c478bd9Sstevel@tonic-gate 		switch (*opt) {
1077*7c478bd9Sstevel@tonic-gate 		case IPOPT_EOL:
1078*7c478bd9Sstevel@tonic-gate 			optlength = 0;
1079*7c478bd9Sstevel@tonic-gate 			break;
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate 		case IPOPT_NOP:
1082*7c478bd9Sstevel@tonic-gate 			opt++;
1083*7c478bd9Sstevel@tonic-gate 			optlength--;
1084*7c478bd9Sstevel@tonic-gate 			continue;
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 		case IPOPT_RR:
1087*7c478bd9Sstevel@tonic-gate 			Printf(" <record route> ");
1088*7c478bd9Sstevel@tonic-gate 			pr_rropt(opt, curlength, _B_TRUE);
1089*7c478bd9Sstevel@tonic-gate 			break;
1090*7c478bd9Sstevel@tonic-gate 
1091*7c478bd9Sstevel@tonic-gate 		case IPOPT_TS:
1092*7c478bd9Sstevel@tonic-gate 			Printf(" <time stamp> ");
1093*7c478bd9Sstevel@tonic-gate 			pr_tsopt(opt, curlength);
1094*7c478bd9Sstevel@tonic-gate 			break;
1095*7c478bd9Sstevel@tonic-gate 
1096*7c478bd9Sstevel@tonic-gate 		case IPOPT_SECURITY:
1097*7c478bd9Sstevel@tonic-gate 			Printf(" <security>");
1098*7c478bd9Sstevel@tonic-gate 			break;
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate 		case IPOPT_LSRR:
1101*7c478bd9Sstevel@tonic-gate 			Printf(" <loose source route> ");
1102*7c478bd9Sstevel@tonic-gate 			pr_rropt(opt, curlength, _B_FALSE);
1103*7c478bd9Sstevel@tonic-gate 			break;
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 		case IPOPT_SATID:
1106*7c478bd9Sstevel@tonic-gate 			Printf(" <stream id>");
1107*7c478bd9Sstevel@tonic-gate 			break;
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate 		case IPOPT_SSRR:
1110*7c478bd9Sstevel@tonic-gate 			Printf(" <strict source route> ");
1111*7c478bd9Sstevel@tonic-gate 			pr_rropt(opt, curlength, _B_FALSE);
1112*7c478bd9Sstevel@tonic-gate 			break;
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 		default:
1115*7c478bd9Sstevel@tonic-gate 			Printf(" <option %d, len %d>", *opt, curlength);
1116*7c478bd9Sstevel@tonic-gate 			break;
1117*7c478bd9Sstevel@tonic-gate 		}
1118*7c478bd9Sstevel@tonic-gate 		/*
1119*7c478bd9Sstevel@tonic-gate 		 * Following most options comes a length field
1120*7c478bd9Sstevel@tonic-gate 		 */
1121*7c478bd9Sstevel@tonic-gate 		opt += curlength;
1122*7c478bd9Sstevel@tonic-gate 		optlength -= curlength;
1123*7c478bd9Sstevel@tonic-gate 	}
1124*7c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
1125*7c478bd9Sstevel@tonic-gate }
1126*7c478bd9Sstevel@tonic-gate 
1127*7c478bd9Sstevel@tonic-gate /*
1128*7c478bd9Sstevel@tonic-gate  * Print out a recorded route option. If rrflag is _B_TRUE, it prints record
1129*7c478bd9Sstevel@tonic-gate  * route option, otherwise LSRR/SSRR.
1130*7c478bd9Sstevel@tonic-gate  */
1131*7c478bd9Sstevel@tonic-gate static void
1132*7c478bd9Sstevel@tonic-gate pr_rropt(uchar_t *opt, int length, boolean_t rrflag)
1133*7c478bd9Sstevel@tonic-gate {
1134*7c478bd9Sstevel@tonic-gate 	struct ip_sourceroute *rrp;
1135*7c478bd9Sstevel@tonic-gate 	int sr_index = 0;
1136*7c478bd9Sstevel@tonic-gate 	struct in_addr addr;
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate 	rrp = (struct ip_sourceroute *)opt;
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate 	/* data starts at offset 3 */
1141*7c478bd9Sstevel@tonic-gate 	length -= 3;
1142*7c478bd9Sstevel@tonic-gate 	while (length > 0) {
1143*7c478bd9Sstevel@tonic-gate 		/*
1144*7c478bd9Sstevel@tonic-gate 		 * Let's see if we are examining the addr pointed by ipsr_ptr
1145*7c478bd9Sstevel@tonic-gate 		 */
1146*7c478bd9Sstevel@tonic-gate 		if ((rrp->ipsr_ptr == (sr_index + 1) * sizeof (addr)) &&
1147*7c478bd9Sstevel@tonic-gate 		    rrflag) {
1148*7c478bd9Sstevel@tonic-gate 			Printf(" (End of record)");
1149*7c478bd9Sstevel@tonic-gate 			break;
1150*7c478bd9Sstevel@tonic-gate 		}
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate 		bcopy(&rrp->ipsr_addrs[sr_index], &addr, sizeof (addr));
1153*7c478bd9Sstevel@tonic-gate 		Printf("%s", pr_name((char *)&addr, AF_INET));
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 		if (rrp->ipsr_ptr == (sr_index + 1) * sizeof (addr)) {
1156*7c478bd9Sstevel@tonic-gate 			Printf("(Current)");
1157*7c478bd9Sstevel@tonic-gate 		}
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate 		sr_index++;
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate 		length -= sizeof (addr);
1162*7c478bd9Sstevel@tonic-gate 		if (length > 0)
1163*7c478bd9Sstevel@tonic-gate 			Printf(", ");
1164*7c478bd9Sstevel@tonic-gate 	}
1165*7c478bd9Sstevel@tonic-gate }
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate /*
1168*7c478bd9Sstevel@tonic-gate  * Print out a timestamp option.
1169*7c478bd9Sstevel@tonic-gate  */
1170*7c478bd9Sstevel@tonic-gate static void
1171*7c478bd9Sstevel@tonic-gate pr_tsopt(uchar_t *opt, int length)
1172*7c478bd9Sstevel@tonic-gate {
1173*7c478bd9Sstevel@tonic-gate 	boolean_t address_present;
1174*7c478bd9Sstevel@tonic-gate 	boolean_t rrflag;		/* End at current entry? */
1175*7c478bd9Sstevel@tonic-gate 	struct ip_timestamp *tsp;
1176*7c478bd9Sstevel@tonic-gate 	int ts_index = 0;
1177*7c478bd9Sstevel@tonic-gate 	struct in_addr addr;
1178*7c478bd9Sstevel@tonic-gate 	size_t data_len;
1179*7c478bd9Sstevel@tonic-gate 	int32_t time;
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 	/* LINTED */
1182*7c478bd9Sstevel@tonic-gate 	tsp = (struct ip_timestamp *)opt;
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	switch (tsp->ipt_flg) {
1185*7c478bd9Sstevel@tonic-gate 	case IPOPT_TS_TSONLY:
1186*7c478bd9Sstevel@tonic-gate 		address_present = _B_FALSE;
1187*7c478bd9Sstevel@tonic-gate 		data_len = sizeof (tsp->ipt_timestamp.ipt_time[0]);
1188*7c478bd9Sstevel@tonic-gate 		rrflag = _B_TRUE;
1189*7c478bd9Sstevel@tonic-gate 		break;
1190*7c478bd9Sstevel@tonic-gate 	case IPOPT_TS_TSANDADDR:
1191*7c478bd9Sstevel@tonic-gate 		address_present = _B_TRUE;
1192*7c478bd9Sstevel@tonic-gate 		data_len = sizeof (tsp->ipt_timestamp.ipt_ta[0]);
1193*7c478bd9Sstevel@tonic-gate 		rrflag = _B_TRUE;
1194*7c478bd9Sstevel@tonic-gate 		break;
1195*7c478bd9Sstevel@tonic-gate 	case IPOPT_TS_PRESPEC:
1196*7c478bd9Sstevel@tonic-gate 	case 3:
1197*7c478bd9Sstevel@tonic-gate 		address_present = _B_TRUE;
1198*7c478bd9Sstevel@tonic-gate 		data_len = sizeof (tsp->ipt_timestamp.ipt_ta[0]);
1199*7c478bd9Sstevel@tonic-gate 		rrflag = _B_FALSE;
1200*7c478bd9Sstevel@tonic-gate 		break;
1201*7c478bd9Sstevel@tonic-gate 	default:
1202*7c478bd9Sstevel@tonic-gate 		Printf("(Bad flag value: 0x%x)", tsp->ipt_flg);
1203*7c478bd9Sstevel@tonic-gate 		return;
1204*7c478bd9Sstevel@tonic-gate 	}
1205*7c478bd9Sstevel@tonic-gate 	if (tsp->ipt_oflw > 0)
1206*7c478bd9Sstevel@tonic-gate 		Printf("(Overflow: %d) ", tsp->ipt_oflw);
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	/* data starts at offset 4 */
1209*7c478bd9Sstevel@tonic-gate 	length -= 4;
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate 	while (length > 0) {
1212*7c478bd9Sstevel@tonic-gate 		if (length < data_len)
1213*7c478bd9Sstevel@tonic-gate 			break;
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 		/* the minimum value of ipt_ptr is 5 */
1216*7c478bd9Sstevel@tonic-gate 		if ((tsp->ipt_ptr == ts_index * data_len + 5) && rrflag) {
1217*7c478bd9Sstevel@tonic-gate 			Printf(" (End of record)");
1218*7c478bd9Sstevel@tonic-gate 			break;
1219*7c478bd9Sstevel@tonic-gate 		}
1220*7c478bd9Sstevel@tonic-gate 		if (address_present) {
1221*7c478bd9Sstevel@tonic-gate 			bcopy(&tsp->ipt_timestamp.ipt_ta[ts_index].ipt_addr,
1222*7c478bd9Sstevel@tonic-gate 			    &addr, sizeof (addr));
1223*7c478bd9Sstevel@tonic-gate 			Printf("%s: ", pr_name((char *)&addr, AF_INET));
1224*7c478bd9Sstevel@tonic-gate 			bcopy(&tsp->ipt_timestamp.ipt_ta[ts_index].ipt_time,
1225*7c478bd9Sstevel@tonic-gate 			    &time, sizeof (time));
1226*7c478bd9Sstevel@tonic-gate 		} else {
1227*7c478bd9Sstevel@tonic-gate 			bcopy(&tsp->ipt_timestamp.ipt_time[ts_index],
1228*7c478bd9Sstevel@tonic-gate 			    &time, sizeof (time));
1229*7c478bd9Sstevel@tonic-gate 		}
1230*7c478bd9Sstevel@tonic-gate 		Printf("%d", ntohl(time));
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 		if (tsp->ipt_ptr == ts_index * data_len + 5)
1233*7c478bd9Sstevel@tonic-gate 			Printf("(Current)");
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 		ts_index++;
1236*7c478bd9Sstevel@tonic-gate 		length -= data_len;
1237*7c478bd9Sstevel@tonic-gate 		if (length > 0)
1238*7c478bd9Sstevel@tonic-gate 			Printf(", ");
1239*7c478bd9Sstevel@tonic-gate 	}
1240*7c478bd9Sstevel@tonic-gate }
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate /*
1243*7c478bd9Sstevel@tonic-gate  * Convert an ICMP "type" field to a printable string.
1244*7c478bd9Sstevel@tonic-gate  */
1245*7c478bd9Sstevel@tonic-gate static char *
1246*7c478bd9Sstevel@tonic-gate pr_type(int icmp_type)
1247*7c478bd9Sstevel@tonic-gate {
1248*7c478bd9Sstevel@tonic-gate 	static struct icmptype_table ttab[] = {
1249*7c478bd9Sstevel@tonic-gate 		{ICMP_ECHOREPLY,	"Echo Reply"},
1250*7c478bd9Sstevel@tonic-gate 		{1,			"ICMP 1"},
1251*7c478bd9Sstevel@tonic-gate 		{2,			"ICMP 2"},
1252*7c478bd9Sstevel@tonic-gate 		{ICMP_UNREACH,		"Dest Unreachable"},
1253*7c478bd9Sstevel@tonic-gate 		{ICMP_SOURCEQUENCH,	"Source Quench"},
1254*7c478bd9Sstevel@tonic-gate 		{ICMP_REDIRECT,		"Redirect"},
1255*7c478bd9Sstevel@tonic-gate 		{6,			"ICMP 6"},
1256*7c478bd9Sstevel@tonic-gate 		{7,			"ICMP 7"},
1257*7c478bd9Sstevel@tonic-gate 		{ICMP_ECHO,		"Echo"},
1258*7c478bd9Sstevel@tonic-gate 		{ICMP_ROUTERADVERT,	"Router Advertisement"},
1259*7c478bd9Sstevel@tonic-gate 		{ICMP_ROUTERSOLICIT,	"Router Solicitation"},
1260*7c478bd9Sstevel@tonic-gate 		{ICMP_TIMXCEED,		"Time Exceeded"},
1261*7c478bd9Sstevel@tonic-gate 		{ICMP_PARAMPROB,	"Parameter Problem"},
1262*7c478bd9Sstevel@tonic-gate 		{ICMP_TSTAMP,		"Timestamp"},
1263*7c478bd9Sstevel@tonic-gate 		{ICMP_TSTAMPREPLY,	"Timestamp Reply"},
1264*7c478bd9Sstevel@tonic-gate 		{ICMP_IREQ,		"Info Request"},
1265*7c478bd9Sstevel@tonic-gate 		{ICMP_IREQREPLY,	"Info Reply"},
1266*7c478bd9Sstevel@tonic-gate 		{ICMP_MASKREQ,		"Netmask Request"},
1267*7c478bd9Sstevel@tonic-gate 		{ICMP_MASKREPLY,	"Netmask Reply"}
1268*7c478bd9Sstevel@tonic-gate 	};
1269*7c478bd9Sstevel@tonic-gate 	int i;
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < A_CNT(ttab); i++) {
1272*7c478bd9Sstevel@tonic-gate 		if (ttab[i].type == icmp_type)
1273*7c478bd9Sstevel@tonic-gate 			return (ttab[i].message);
1274*7c478bd9Sstevel@tonic-gate 	}
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate 	return ("OUT-OF-RANGE");
1277*7c478bd9Sstevel@tonic-gate }
1278