4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Copyright 2015, Joyent, Inc.
35 * Portions of this source code were derived from Berkeley 4.3 BSD
36 * under license from the Regents of the University of California.
48 #include <sys/param.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <sys/stropts.h>
53 #include <arpa/inet.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/in.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_icmp.h>
59 #include <netinet/ip6.h>
60 #include <netinet/icmp6.h>
61 #include <netinet/udp.h>
65 #include <libinetutil.h>
68 void check_reply6(struct addrinfo
*, struct msghdr
*, int, ushort_t
);
69 extern void find_dstaddr(ushort_t
, union any_in_addr
*);
70 static int IPv6_hdrlen(ip6_t
*, int, uint8_t *);
71 extern boolean_t
is_a_target(struct addrinfo
*, union any_in_addr
*);
72 static void pr_ext_headers(struct msghdr
*);
73 extern char *pr_name(char *, int);
74 extern char *pr_protocol(int);
75 static void pr_rthdr(unsigned char *);
76 static char *pr_type6(uchar_t
);
77 extern void schedule_sigalrm();
78 extern void send_scheduled_probe();
79 extern boolean_t
seq_match(ushort_t
, int, ushort_t
);
80 void set_ancillary_data(struct msghdr
*, int, union any_in_addr
*, int, uint_t
);
81 extern void sigalrm_handler();
82 extern void tvsub(struct timeval
*, struct timeval
*);
86 * Initialize the msghdr for specifying the hoplimit, outgoing interface and
90 set_ancillary_data(struct msghdr
*msgp
, int hoplimit
,
91 union any_in_addr
*gwIPlist
, int gw_cnt
, uint_t if_index
)
93 size_t hoplimit_space
;
97 struct cmsghdr
*cmsgp
;
99 static boolean_t first
= _B_TRUE
;
102 if (hoplimit
== -1 && gw_cnt
== 0 && if_index
== 0)
106 * Need to figure out size of buffer needed for ancillary data
107 * containing routing header and packet info options.
109 * Portable heuristic to compute upper bound on space needed for
110 * N ancillary data options. It assumes up to _MAX_ALIGNMENT padding
111 * after both header and data as the worst possible upper bound on space
112 * consumed by padding.
113 * It also adds one extra "sizeof (struct cmsghdr)" for the last option.
114 * This is needed because we would like to use CMSG_NXTHDR() while
115 * composing the buffer. The CMSG_NXTHDR() macro is designed better for
116 * parsing than composing the buffer. It requires the pointer it returns
117 * to leave space in buffer for addressing a cmsghdr and we want to make
118 * sure it works for us while we skip beyond the last ancillary data
121 * bufspace[i] = sizeof(struct cmsghdr) + <pad after header> +
122 * <option[i] content length> + <pad after data>;
124 * total_bufspace = bufspace[0] + bufspace[1] + ...
125 * ... + bufspace[N-1] + sizeof (struct cmsghdr);
133 if (hoplimit
!= -1) {
134 hoplimit_space
= sizeof (int);
135 bufspace
+= sizeof (struct cmsghdr
) + _MAX_ALIGNMENT
+
136 hoplimit_space
+ _MAX_ALIGNMENT
;
140 rthdr_space
= inet6_rth_space(IPV6_RTHDR_TYPE_0
, gw_cnt
);
141 bufspace
+= sizeof (struct cmsghdr
) + _MAX_ALIGNMENT
+
142 rthdr_space
+ _MAX_ALIGNMENT
;
146 pktinfo_space
= sizeof (struct in6_pktinfo
);
147 bufspace
+= sizeof (struct cmsghdr
) + _MAX_ALIGNMENT
+
148 pktinfo_space
+ _MAX_ALIGNMENT
;
152 * We need to temporarily set the msgp->msg_controllen to bufspace
153 * (we will later trim it to actual length used). This is needed because
154 * CMSG_NXTHDR() uses it to check we have not exceeded the bounds.
156 bufspace
+= sizeof (struct cmsghdr
);
157 msgp
->msg_controllen
= bufspace
;
160 * This function is called more than once only if -l/-S used,
161 * since we need to modify the middle gateway. So, don't alloc
162 * new memory, just reuse what msg6 points to.
166 msgp
->msg_control
= (struct cmsghdr
*)malloc(bufspace
);
167 if (msgp
->msg_control
== NULL
) {
168 Fprintf(stderr
, "%s: malloc %s\n",
169 progname
, strerror(errno
));
173 cmsgp
= CMSG_FIRSTHDR(msgp
);
176 * Fill ancillary data. First hoplimit, then rthdr and pktinfo.
179 /* set hoplimit ancillary data if needed */
180 if (hoplimit
!= -1) {
181 cmsgp
->cmsg_level
= IPPROTO_IPV6
;
182 cmsgp
->cmsg_type
= IPV6_HOPLIMIT
;
183 cmsg_datap
= CMSG_DATA(cmsgp
);
185 *(int *)cmsg_datap
= hoplimit
;
186 cmsgp
->cmsg_len
= cmsg_datap
+ hoplimit_space
-
188 cmsgp
= CMSG_NXTHDR(msgp
, cmsgp
);
191 /* set rthdr ancillary data if needed */
193 struct ip6_rthdr0
*rthdr0p
;
195 cmsgp
->cmsg_level
= IPPROTO_IPV6
;
196 cmsgp
->cmsg_type
= IPV6_RTHDR
;
197 cmsg_datap
= CMSG_DATA(cmsgp
);
200 * Initialize rthdr structure
203 rthdr0p
= (struct ip6_rthdr0
*)cmsg_datap
;
204 if (inet6_rth_init(rthdr0p
, rthdr_space
,
205 IPV6_RTHDR_TYPE_0
, gw_cnt
) == NULL
) {
206 Fprintf(stderr
, "%s: inet6_rth_init failed\n",
212 * Stuff in gateway addresses
214 for (i
= 0; i
< gw_cnt
; i
++) {
215 if (inet6_rth_add(rthdr0p
, &gwIPlist
[i
].addr6
) == -1) {
217 "%s: inet6_rth_add\n", progname
);
222 cmsgp
->cmsg_len
= cmsg_datap
+ rthdr_space
- (uchar_t
*)cmsgp
;
223 cmsgp
= CMSG_NXTHDR(msgp
, cmsgp
);
226 /* set pktinfo ancillary data if needed */
228 struct in6_pktinfo
*pktinfop
;
230 cmsgp
->cmsg_level
= IPPROTO_IPV6
;
231 cmsgp
->cmsg_type
= IPV6_PKTINFO
;
232 cmsg_datap
= CMSG_DATA(cmsgp
);
235 pktinfop
= (struct in6_pktinfo
*)cmsg_datap
;
237 * We don't know if pktinfop->ipi6_addr is aligned properly,
238 * therefore let's use bcopy, instead of assignment.
240 (void) bcopy(&in6addr_any
, &pktinfop
->ipi6_addr
,
241 sizeof (struct in6_addr
));
244 * We can assume pktinfop->ipi6_ifindex is 32 bit aligned.
246 pktinfop
->ipi6_ifindex
= if_index
;
247 cmsgp
->cmsg_len
= cmsg_datap
+ pktinfo_space
- (uchar_t
*)cmsgp
;
248 cmsgp
= CMSG_NXTHDR(msgp
, cmsgp
);
251 msgp
->msg_controllen
= (char *)cmsgp
- (char *)msgp
->msg_control
;
255 * Check out the packet to see if it came from us. This logic is necessary
256 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
257 * which arrive ('tis only fair). This permits multiple copies of this
258 * program to be run without having intermingled output (or statistics!).
261 check_reply6(struct addrinfo
*ai_dst
, struct msghdr
*msg
, int cc
,
262 ushort_t udp_src_port
)
264 struct icmp6_hdr
*icmp6
;
266 nd_redirect_t
*nd_rdrct
;
268 union any_in_addr dst_addr
;
271 struct sockaddr_in6
*from6
;
275 boolean_t valid_reply
= _B_FALSE
;
276 boolean_t reply_matched_current_target
= _B_FALSE
; /* Is the source */
277 /* address of this reply same */
278 /* as where we're sending */
280 boolean_t last_reply_from_targetaddr
= _B_FALSE
; /* Is this stats, */
281 /* probe all with npackets>0 */
282 /* and we received reply for */
283 /* the last probe sent to */
289 char tmp_buf
[INET6_ADDRSTRLEN
];
290 static char *unreach6
[] = {
291 "No Route to Destination",
292 "Communication Administratively Prohibited",
293 "Not a Neighbor (obsoleted ICMPv6 code)",
294 "Address Unreachable",
297 static char *timexceed6
[] = {
298 "Hop limit exceeded in transit",
299 "Fragment reassembly time exceeded"
301 static char *param_prob6
[] = {
302 "Erroneous header field encountered",
303 "Unrecognized next header type encountered",
304 "Unrecognized IPv6 option encountered"
306 boolean_t print_newline
= _B_FALSE
;
308 /* decompose msghdr into useful pieces */
309 buf
= (uchar_t
*)msg
->msg_iov
->iov_base
;
310 from6
= (struct sockaddr_in6
*)msg
->msg_name
;
313 intp
= (int32_t *)buf
;
315 ping_gettime(msg
, &tv
);
317 /* Ignore packets > 64k or control buffers that don't fit */
318 if (msg
->msg_flags
& (MSG_TRUNC
|MSG_CTRUNC
)) {
320 Printf("Truncated message: msg_flags 0x%x from %s\n",
322 pr_name((char *)&from6
->sin6_addr
, AF_INET6
));
326 if (cc
< ICMP6_MINLEN
) {
328 Printf("packet too short (%d bytes) from %s\n", cc
,
329 pr_name((char *)&from6
->sin6_addr
, AF_INET6
));
334 icmp6
= (struct icmp6_hdr
*)buf
;
335 cc_left
= cc
- ICMP6_MINLEN
;
337 switch (icmp6
->icmp6_type
) {
338 case ICMP6_DST_UNREACH
:
340 ip6h
= (ip6_t
*)((char *)icmp6
+ ICMP6_MINLEN
);
341 if (cc_left
< sizeof (ip6_t
)) {
343 Printf("packet too short (%d bytes) from %s\n",
345 pr_name((char *)&from6
->sin6_addr
,
352 * Determine the total length of IPv6 header and extension
353 * headers, also the upper layer header (UDP, TCP, ICMP, etc.)
356 ip6hdr_len
= IPv6_hdrlen(ip6h
, cc_left
, &last_hdr
);
358 cc_left
-= ip6hdr_len
;
361 up
= (struct udphdr
*)((char *)ip6h
+ ip6hdr_len
);
362 if (cc_left
< sizeof (struct udphdr
)) {
364 Printf("packet too short (%d bytes) from %s\n",
366 pr_name((char *)&from6
->sin6_addr
,
371 cc_left
-= sizeof (struct udphdr
);
373 /* determine if this is *the* reply */
374 if (icmp6
->icmp6_code
== ICMP6_DST_UNREACH_NOPORT
&&
375 last_hdr
== IPPROTO_UDP
&&
376 udp_src_port
== up
->uh_sport
&&
378 valid_reply
= _B_TRUE
;
380 valid_reply
= _B_FALSE
;
385 * For this valid reply, if we are still sending to
386 * this target IP address, we'd like to do some
387 * updates to targetaddr, so hold SIGALRMs.
389 (void) sighold(SIGALRM
);
392 reply_matched_current_target
=
393 seq_match(current_targetaddr
->starting_seq_num
,
394 current_targetaddr
->num_sent
,
395 ntohs(up
->uh_dport
));
396 if (reply_matched_current_target
) {
397 current_targetaddr
->got_reply
= _B_TRUE
;
398 nreceived_last_target
++;
400 * Determine if stats, probe-all, and
401 * npackets != 0, and this is the reply for
402 * the last probe we sent to current target
405 if (stats
&& probe_all
&& npackets
> 0 &&
406 ((current_targetaddr
->starting_seq_num
+
407 current_targetaddr
->num_probes
- 1) %
408 (MAX_PORT
+ 1) == ntohs(up
->uh_dport
)) &&
409 (current_targetaddr
->num_probes
==
410 current_targetaddr
->num_sent
))
411 last_reply_from_targetaddr
= _B_TRUE
;
414 * If it's just probe_all and we just received
415 * a reply from a target address we were
416 * probing and had timed out (now we are probing
417 * some other target address), we ignore
420 if (probe_all
&& !stats
) {
421 valid_reply
= _B_FALSE
;
423 * Only if it's verbose, we get a
424 * message regarding this reply,
425 * otherwise we are done here.
428 (void) sigrelse(SIGALRM
);
435 if (valid_reply
&& !stats
) {
437 * if we are still sending to the same target address,
438 * then stop it, because we know it's alive.
440 if (reply_matched_current_target
) {
441 (void) alarm(0); /* cancel alarm */
442 (void) sigset(SIGALRM
, SIG_IGN
);
443 current_targetaddr
->probing_done
= _B_TRUE
;
445 (void) sigrelse(SIGALRM
);
448 Printf("%s is alive\n", targethost
);
450 (void) inet_ntop(AF_INET6
,
451 (void *)&ip6h
->ip6_dst
,
452 tmp_buf
, sizeof (tmp_buf
));
454 Printf("%s is alive\n", tmp_buf
);
456 Printf("%s (%s) is alive\n",
457 targethost
, tmp_buf
);
460 if (reply_matched_current_target
) {
462 * Let's get things going again, but now
463 * ping will start sending to next target IP
466 send_scheduled_probe();
467 (void) sigset(SIGALRM
, sigalrm_handler
);
473 * If we are not moving to next targetaddr, let's
474 * release the SIGALRM now. We don't want to stall in
475 * the middle of probing a targetaddr if the pr_name()
476 * call (see below) takes longer.
478 if (!last_reply_from_targetaddr
)
479 (void) sigrelse(SIGALRM
);
480 /* else, we'll release it later */
483 dst_addr
.addr6
= ip6h
->ip6_dst
;
485 Printf("%d bytes from %s: ", cc
,
486 pr_name((char *)&from6
->sin6_addr
, AF_INET6
));
487 Printf("udp_port=%d. ", ntohs(up
->uh_dport
));
488 print_newline
= _B_TRUE
;
489 } else if (is_a_target(ai_dst
, &dst_addr
)|| verbose
) {
490 if (icmp6
->icmp6_code
>= A_CNT(unreach6
)) {
491 Printf("ICMPv6 %d Unreachable from gateway "
492 "%s\n", icmp6
->icmp6_code
,
493 pr_name((char *)&from6
->sin6_addr
,
496 Printf("ICMPv6 %s from gateway %s\n",
497 unreach6
[icmp6
->icmp6_code
],
498 pr_name((char *)&from6
->sin6_addr
,
501 Printf(" for %s from %s", pr_protocol(last_hdr
),
502 pr_name((char *)&ip6h
->ip6_src
, AF_INET6
));
503 Printf(" to %s", pr_name((char *)&ip6h
->ip6_dst
,
505 if (last_hdr
== IPPROTO_TCP
|| last_hdr
== IPPROTO_UDP
)
506 Printf(" port %d ", ntohs(up
->uh_dport
));
507 print_newline
= _B_TRUE
;
511 * Update and print the stats, if it's a valid reply and
512 * contains a timestamp.
514 if (valid_reply
&& datalen
>= sizeof (struct timeval
) &&
515 cc_left
>= sizeof (struct timeval
)) {
517 tp
= (struct timeval
*)((char *)up
+
518 sizeof (struct udphdr
));
519 (void) tvsub(&tv
, tp
);
520 triptime
= (int64_t)tv
.tv_sec
* MICROSEC
+ tv
.tv_usec
;
521 Printf("time=" TIMEFORMAT
" ms", triptime
/1000.0);
523 tsum2
+= triptime
*triptime
;
528 print_newline
= _B_TRUE
;
531 (void) putchar('\n');
533 * If it's stats, probe-all, npackets > 0, and we received reply
534 * for the last probe sent to this target address, then we
535 * don't need to wait anymore, let's move on to next target
538 if (last_reply_from_targetaddr
) {
539 (void) alarm(0); /* cancel alarm */
540 current_targetaddr
->probing_done
= _B_TRUE
;
541 (void) sigrelse(SIGALRM
);
542 send_scheduled_probe();
547 case ICMP6_PACKET_TOO_BIG
:
549 ip6h
= (ip6_t
*)((char *)icmp6
+ ICMP6_MINLEN
);
550 if (cc_left
< sizeof (ip6_t
)) {
552 Printf("packet too short (%d bytes) from %s\n",
553 cc
, pr_name((char *)&from6
->sin6_addr
,
558 ip6hdr_len
= IPv6_hdrlen(ip6h
, cc_left
, &last_hdr
);
560 dst_addr
.addr6
= ip6h
->ip6_dst
;
561 if (is_a_target(ai_dst
, &dst_addr
) || verbose
) {
562 Printf("ICMPv6 packet too big from %s\n",
563 pr_name((char *)&from6
->sin6_addr
, AF_INET6
));
565 Printf(" for %s from %s", pr_protocol(last_hdr
),
566 pr_name((char *)&ip6h
->ip6_src
, AF_INET6
));
567 Printf(" to %s", pr_name((char *)&ip6h
->ip6_dst
,
569 if ((last_hdr
== IPPROTO_TCP
||
570 last_hdr
== IPPROTO_UDP
) &&
571 (cc_left
>= (ip6hdr_len
+ 4))) {
573 up
= (struct udphdr
*)
574 ((char *)ip6h
+ ip6hdr_len
);
575 Printf(" port %d ", ntohs(up
->uh_dport
));
577 Printf(" MTU = %d\n", ntohl(icmp6
->icmp6_mtu
));
581 case ICMP6_TIME_EXCEEDED
:
583 ip6h
= (ip6_t
*)((char *)icmp6
+ ICMP6_MINLEN
);
584 if (cc_left
< sizeof (ip6_t
)) {
586 Printf("packet too short (%d bytes) from %s\n",
588 pr_name((char *)&from6
->sin6_addr
,
593 ip6hdr_len
= IPv6_hdrlen(ip6h
, cc_left
, &last_hdr
);
595 dst_addr
.addr6
= ip6h
->ip6_dst
;
596 if (is_a_target(ai_dst
, &dst_addr
) || verbose
) {
597 if (icmp6
->icmp6_code
>= A_CNT(timexceed6
)) {
598 Printf("ICMPv6 %d time exceeded from %s\n",
600 pr_name((char *)&from6
->sin6_addr
,
603 Printf("ICMPv6 %s from %s\n",
604 timexceed6
[icmp6
->icmp6_code
],
605 pr_name((char *)&from6
->sin6_addr
,
608 Printf(" for %s from %s", pr_protocol(last_hdr
),
609 pr_name((char *)&ip6h
->ip6_src
, AF_INET6
));
610 Printf(" to %s", pr_name((char *)&ip6h
->ip6_dst
,
612 if ((last_hdr
== IPPROTO_TCP
||
613 last_hdr
== IPPROTO_UDP
) &&
614 (cc_left
>= (ip6hdr_len
+ 4))) {
616 up
= (struct udphdr
*)
617 ((char *)ip6h
+ ip6hdr_len
);
618 Printf(" port %d", ntohs(up
->uh_dport
));
620 (void) putchar('\n');
624 case ICMP6_PARAM_PROB
:
626 ip6h
= (ip6_t
*)((char *)icmp6
+ ICMP6_MINLEN
);
627 if (cc_left
< sizeof (ip6_t
)) {
629 Printf("packet too short (%d bytes) from %s\n",
631 pr_name((char *)&from6
->sin6_addr
,
636 ip6hdr_len
= IPv6_hdrlen(ip6h
, cc_left
, &last_hdr
);
638 dst_addr
.addr6
= ip6h
->ip6_dst
;
639 if (is_a_target(ai_dst
, &dst_addr
) || verbose
) {
640 if (icmp6
->icmp6_code
>= A_CNT(param_prob6
)) {
641 Printf("ICMPv6 %d parameter problem from %s\n",
643 pr_name((char *)&from6
->sin6_addr
,
646 Printf("ICMPv6 %s from %s\n",
647 param_prob6
[icmp6
->icmp6_code
],
648 pr_name((char *)&from6
->sin6_addr
,
651 icmp6
->icmp6_pptr
= ntohl(icmp6
->icmp6_pptr
);
652 Printf(" in byte %d", icmp6
->icmp6_pptr
);
653 if (icmp6
->icmp6_pptr
<= ip6hdr_len
) {
654 Printf(" (value 0x%x)",
655 *((uchar_t
*)ip6h
+ icmp6
->icmp6_pptr
));
657 Printf(" for %s from %s", pr_protocol(last_hdr
),
658 pr_name((char *)&ip6h
->ip6_src
, AF_INET6
));
659 Printf(" to %s", pr_name((char *)&ip6h
->ip6_dst
,
661 if ((last_hdr
== IPPROTO_TCP
||
662 last_hdr
== IPPROTO_UDP
) &&
663 (cc_left
>= (ip6hdr_len
+ 4))) {
665 up
= (struct udphdr
*)
666 ((char *)ip6h
+ ip6hdr_len
);
667 Printf(" port %d", ntohs(up
->uh_dport
));
669 (void) putchar('\n');
673 case ICMP6_ECHO_REQUEST
:
676 case ICMP6_ECHO_REPLY
:
677 if (ntohs(icmp6
->icmp6_id
) == ident
) {
679 valid_reply
= _B_TRUE
;
681 valid_reply
= _B_FALSE
;
688 * For this valid reply, if we are still sending to
689 * this target IP address, we'd like to do some
690 * updates to targetaddr, so hold SIGALRMs.
692 (void) sighold(SIGALRM
);
695 reply_matched_current_target
=
696 seq_match(current_targetaddr
->starting_seq_num
,
697 current_targetaddr
->num_sent
,
698 ntohs(icmp6
->icmp6_seq
));
699 if (reply_matched_current_target
) {
700 current_targetaddr
->got_reply
= _B_TRUE
;
701 nreceived_last_target
++;
703 * Determine if stats, probe-all, and
704 * npackets != 0, and this is the reply for
705 * the last probe we sent to current target
708 if (stats
&& probe_all
&& npackets
> 0 &&
709 ((current_targetaddr
->starting_seq_num
+
710 current_targetaddr
->num_probes
- 1) %
711 (MAX_ICMP_SEQ
+ 1) ==
712 ntohs(icmp6
->icmp6_seq
)) &&
713 (current_targetaddr
->num_probes
==
714 current_targetaddr
->num_sent
))
715 last_reply_from_targetaddr
= _B_TRUE
;
718 * If it's just probe_all and we just received
719 * a reply from a target address we were
720 * probing and had timed out (now we are probing
721 * some other target address), we ignore
724 if (probe_all
&& !stats
) {
725 valid_reply
= _B_FALSE
;
727 * Only if it's verbose, we get a
728 * message regarding this reply,
729 * otherwise we are done here.
732 (void) sigrelse(SIGALRM
);
739 if (!stats
&& valid_reply
) {
741 * if we are still sending to the same target address,
742 * then stop it, because we know it's alive.
744 if (reply_matched_current_target
) {
745 (void) alarm(0); /* cancel alarm */
746 (void) sigset(SIGALRM
, SIG_IGN
);
747 current_targetaddr
->probing_done
= _B_TRUE
;
749 (void) sigrelse(SIGALRM
);
752 Printf("%s is alive\n", targethost
);
755 * If we are using send_reply, the real
756 * target address is not the src address of the
757 * replies. Use icmp_seq to find out where this
762 ntohs(icmp6
->icmp6_seq
), &dst_addr
);
763 (void) inet_ntop(AF_INET6
,
764 (void *)&dst_addr
.addr6
,
765 tmp_buf
, sizeof (tmp_buf
));
767 (void) inet_ntop(AF_INET6
,
768 (void *)&from6
->sin6_addr
,
769 tmp_buf
, sizeof (tmp_buf
));
773 Printf("%s is alive\n", tmp_buf
);
775 Printf("%s (%s) is alive\n",
776 targethost
, tmp_buf
);
779 if (reply_matched_current_target
) {
781 * Let's get things going again, but now
782 * ping will start sending to next target IP
785 send_scheduled_probe();
786 (void) sigset(SIGALRM
, sigalrm_handler
);
792 * If we are not moving to next targetaddr, let's
793 * release the SIGALRM now. We don't want to stall in
794 * the middle of probing a targetaddr if the pr_name()
795 * call (see below) takes longer.
797 if (!last_reply_from_targetaddr
)
798 (void) sigrelse(SIGALRM
);
799 /* else, we'll release it later */
803 * If we are using send_reply, the real target address is
804 * not the src address of the replies. Use icmp_seq to find out
805 * where this probe was sent to.
808 (void) find_dstaddr(ntohs(icmp6
->icmp6_seq
), &dst_addr
);
809 Printf("%d bytes from %s: ", cc
,
810 pr_name((char *)&dst_addr
.addr6
, AF_INET6
));
812 Printf("%d bytes from %s: ", cc
,
813 pr_name((char *)&from6
->sin6_addr
, AF_INET6
));
815 Printf("icmp_seq=%d. ", ntohs(icmp6
->icmp6_seq
));
817 if (valid_reply
&& datalen
>= sizeof (struct timeval
) &&
818 cc_left
>= sizeof (struct timeval
)) {
820 tp
= (struct timeval
*)&icmp6
->icmp6_data16
[2];
821 (void) tvsub(&tv
, tp
);
822 triptime
= (int64_t)tv
.tv_sec
* MICROSEC
+ tv
.tv_usec
;
823 Printf("time=" TIMEFORMAT
" ms", triptime
/1000.0);
825 tsum2
+= triptime
*triptime
;
831 (void) putchar('\n');
833 * If it's stats, probe-all, npackets > 0, and we received reply
834 * for the last probe sent to this target address, then we
835 * don't need to wait anymore, let's move on to next target
838 if (last_reply_from_targetaddr
) {
839 (void) alarm(0); /* cancel alarm */
840 current_targetaddr
->probing_done
= _B_TRUE
;
841 (void) sigrelse(SIGALRM
);
842 send_scheduled_probe();
847 case MLD_LISTENER_QUERY
:
848 case MLD_LISTENER_REPORT
:
849 case MLD_LISTENER_REDUCTION
:
850 case ND_ROUTER_SOLICIT
:
851 case ND_ROUTER_ADVERT
:
852 case ND_NEIGHBOR_SOLICIT
:
853 case ND_NEIGHBOR_ADVERT
:
857 nd_rdrct
= (nd_redirect_t
*)icmp6
;
859 if (cc_left
< sizeof (nd_redirect_t
) - ICMP6_MINLEN
) {
861 Printf("packet too short (%d bytes) from %s\n",
863 pr_name((char *)&from6
->sin6_addr
,
868 dst_addr
.addr6
= nd_rdrct
->nd_rd_dst
;
869 if (is_a_target(ai_dst
, &dst_addr
) || verbose
) {
870 Printf("ICMPv6 redirect from gateway %s\n",
871 pr_name((char *)&from6
->sin6_addr
, AF_INET6
));
874 pr_name((char *)&nd_rdrct
->nd_rd_target
, AF_INET6
));
876 pr_name((char *)&nd_rdrct
->nd_rd_dst
, AF_INET6
));
882 Printf("%d bytes from %s:\n", cc
,
883 pr_name((char *)&from6
->sin6_addr
, AF_INET6
));
884 Printf("icmp6_type=%d (%s) ", icmp6
->icmp6_type
,
885 pr_type6(icmp6
->icmp6_type
));
886 Printf("icmp6_code=%d\n", icmp6
->icmp6_code
);
887 for (i
= 0; i
< 12; i
++) {
888 Printf("x%2.2x: x%8.8x\n",
889 i
* sizeof (int32_t), *intp
++);
896 * If it's verbose mode and we recv'd ancillary data, print extension
899 if (verbose
&& msg
->msg_controllen
> 0)
904 * Convert an ICMP6 "type" field to a printable string.
907 pr_type6(uchar_t icmp6_type
)
909 static struct icmptype_table ttab6
[] = {
910 {ICMP6_DST_UNREACH
, "Dest Unreachable"},
911 {ICMP6_PACKET_TOO_BIG
, "Packet Too Big"},
912 {ICMP6_TIME_EXCEEDED
, "Time Exceeded"},
913 {ICMP6_PARAM_PROB
, "Parameter Problem"},
914 {ICMP6_ECHO_REQUEST
, "Echo Request"},
915 {ICMP6_ECHO_REPLY
, "Echo Reply"},
916 {MLD_LISTENER_QUERY
, "Multicast Listener Query"},
917 {MLD_LISTENER_REPORT
, "Multicast Listener Report"},
918 {MLD_LISTENER_REDUCTION
, "Multicast Listener Done"},
919 {ND_ROUTER_SOLICIT
, "Router Solicitation"},
920 {ND_ROUTER_ADVERT
, "Router Advertisement"},
921 {ND_NEIGHBOR_SOLICIT
, "Neighbor Solicitation"},
922 {ND_NEIGHBOR_ADVERT
, "Neighbor Advertisement"},
923 {ND_REDIRECT
, "Redirect Message"},
927 for (i
= 0; i
< A_CNT(ttab6
); i
++) {
928 if (ttab6
[i
].type
== icmp6_type
)
929 return (ttab6
[i
].message
);
933 return ("OUT-OF-RANGE");
937 * Return the length of the IPv6 related headers (including extension headers).
938 * It also sets the *last_hdr_rtrn to the first upper layer protocol header
939 * following IPv6 header and extension headers. If print_flag is _B_TRUE, it
940 * prints extension headers.
943 IPv6_hdrlen(ip6_t
*ip6h
, int pkt_len
, uint8_t *last_hdr_rtrn
)
955 length
= sizeof (ip6_t
);
957 whereptr
= ((uint8_t *)&ip6h
[1]); /* point to next hdr */
958 endptr
= ((uint8_t *)ip6h
) + pkt_len
;
960 nexthdr
= ip6h
->ip6_nxt
;
961 *last_hdr_rtrn
= IPPROTO_NONE
;
963 if (whereptr
>= endptr
)
966 while (whereptr
< endptr
) {
967 *last_hdr_rtrn
= nexthdr
;
969 case IPPROTO_HOPOPTS
:
970 hbhhdr
= (ip6_hbh_t
*)whereptr
;
971 exthdrlength
= 8 * (hbhhdr
->ip6h_len
+ 1);
972 if ((uchar_t
*)hbhhdr
+ exthdrlength
> endptr
)
974 nexthdr
= hbhhdr
->ip6h_nxt
;
975 length
+= exthdrlength
;
978 case IPPROTO_DSTOPTS
:
979 desthdr
= (ip6_dest_t
*)whereptr
;
980 exthdrlength
= 8 * (desthdr
->ip6d_len
+ 1);
981 if ((uchar_t
*)desthdr
+ exthdrlength
> endptr
)
983 nexthdr
= desthdr
->ip6d_nxt
;
984 length
+= exthdrlength
;
987 case IPPROTO_ROUTING
:
988 rthdr
= (ip6_rthdr_t
*)whereptr
;
989 exthdrlength
= 8 * (rthdr
->ip6r_len
+ 1);
990 if ((uchar_t
*)rthdr
+ exthdrlength
> endptr
)
992 nexthdr
= rthdr
->ip6r_nxt
;
993 length
+= exthdrlength
;
996 case IPPROTO_FRAGMENT
:
998 fraghdr
= (ip6_frag_t
*)whereptr
;
999 if ((uchar_t
*)&fraghdr
[1] > endptr
)
1001 nexthdr
= fraghdr
->ip6f_nxt
;
1002 length
+= sizeof (struct ip6_frag
);
1009 whereptr
= (uint8_t *)ip6h
+ length
;
1011 *last_hdr_rtrn
= nexthdr
;
1017 * Print extension headers
1020 pr_ext_headers(struct msghdr
*msg
)
1022 struct cmsghdr
*cmsg
;
1024 Printf(" IPv6 extension headers: ");
1026 for (cmsg
= CMSG_FIRSTHDR(msg
); cmsg
!= NULL
;
1027 cmsg
= CMSG_NXTHDR(msg
, cmsg
)) {
1028 if (cmsg
->cmsg_level
== IPPROTO_IPV6
) {
1029 switch (cmsg
->cmsg_type
) {
1031 Printf(" <hop-by-hop options>");
1035 Printf(" <destination options (after routing"
1039 case IPV6_RTHDRDSTOPTS
:
1040 Printf(" <destination options (before routing"
1045 pr_rthdr((uchar_t
*)CMSG_DATA(cmsg
));
1049 Printf(" <option type %d>", cmsg
->cmsg_type
);
1054 (void) putchar('\n');
1058 * Print the routing header 0 information
1061 pr_rthdr(uchar_t
*buf
)
1064 ip6_rthdr0_t
*rthdr0
;
1065 struct in6_addr
*gw_addr
;
1068 rthdr
= (ip6_rthdr_t
*)buf
;
1069 Printf(" <type %d routing header, segleft %u> ",
1070 rthdr
->ip6r_type
, rthdr
->ip6r_segleft
);
1072 if (rthdr
->ip6r_type
== 0) {
1074 rthdr0
= (ip6_rthdr0_t
*)buf
;
1075 gw_addr
= (struct in6_addr
*)(rthdr0
+ 1);
1076 num_addr
= rthdr0
->ip6r0_len
/ 2;
1078 for (i
= 0; i
< num_addr
; i
++) {
1079 Printf("%s", pr_name((char *)gw_addr
, AF_INET6
));
1080 if (i
== (num_addr
- rthdr0
->ip6r0_segleft
))
1081 Printf("(Current)");
1083 if (i
!= num_addr
- 1)