Mercurial > illumos > onarm
diff usr/src/cmd/cmd-inet/usr.sbin/traceroute/traceroute_aux6.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/cmd-inet/usr.sbin/traceroute/traceroute_aux6.c Tue Jun 02 18:56:50 2009 +0900 @@ -0,0 +1,744 @@ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +/* + * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * @(#)$Header: traceroute.c,v 1.49 97/06/13 02:30:23 leres Exp $ (LBL) + */ + +#pragma ident "@(#)traceroute_aux6.c 1.8 06/01/12 SMI" + +#include <sys/socket.h> + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <strings.h> +#include <libintl.h> +#include <errno.h> +#include <netdb.h> + +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/ip_icmp.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/ip6.h> +#include <netinet/icmp6.h> + +#include <arpa/inet.h> + +#include <libinetutil.h> +#include "traceroute.h" + +int check_reply6(struct msghdr *, int, int, uchar_t *, uchar_t *); +void *find_ancillary_data(struct msghdr *, int, int); +extern char *inet_name(union any_in_addr *, int); +static int IPv6_hdrlen(ip6_t *, int, uint8_t *); +static char *pr_type6(uchar_t); +void print_addr6(uchar_t *, int, struct sockaddr *); +boolean_t print_icmp_other6(uchar_t, uchar_t); +void send_probe6(int, struct msghdr *, struct ip *, int, int, + struct timeval *, int); +void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int, uint_t); +struct ip *set_buffers6(int); +static boolean_t update_hoplimit_ancillary_data(struct msghdr *, int); + +/* + * prepares the buffer to be sent as an IP datagram + */ +struct ip * +set_buffers6(int plen) +{ + struct ip *outip; + uchar_t *outp; + struct udphdr *outudp; + struct icmp *outicmp; + int optlen = 0; + + outip = (struct ip *)malloc((size_t)plen); + if (outip == NULL) { + Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (gw_count > 0) { + /* ip6_rthdr0 structure includes one gateway address */ + optlen = sizeof (struct ip6_rthdr0) + + gw_count * sizeof (struct in6_addr); + } + + (void) memset((char *)outip, 0, (size_t)plen); + outp = (uchar_t *)(outip + 1); + + if (useicmp) { + /* LINTED E_BAD_PTR_CAST_ALIGN */ + outicmp = (struct icmp *)outp; + outicmp->icmp_type = ICMP6_ECHO_REQUEST; + outicmp->icmp_id = htons(ident); + } else { + /* LINTED E_BAD_PTR_CAST_ALIGN */ + outudp = (struct udphdr *)outp; + /* + * "source port" is set at bind() call, so we don't do it + * again + */ + outudp->uh_ulen = htons((ushort_t)(plen - + (sizeof (struct ip6_hdr) + optlen))); + } + + return (outip); +} + +/* + * Initialize the msghdr for specifying hoplimit, outgoing interface and routing + * header for the probe packets. + */ +void +set_ancillary_data(struct msghdr *msgp, int hoplimit, + union any_in_addr *gwIPlist, int gw_cnt, uint_t if_index) +{ + size_t hoplimit_space; + size_t rthdr_space; + size_t pktinfo_space; + size_t bufspace; + struct cmsghdr *cmsgp; + uchar_t *cmsg_datap; + int i; + + msgp->msg_control = NULL; + msgp->msg_controllen = 0; + + /* + * Need to figure out size of buffer needed for ancillary data + * containing routing header and packet info options. + * + * Portable heuristic to compute upper bound on space needed for + * N ancillary data options. It assumes up to _MAX_ALIGNMENT padding + * after both header and data as the worst possible upper bound on space + * consumed by padding. + * It also adds one extra "sizeof (struct cmsghdr)" for the last option. + * This is needed because we would like to use CMSG_NXTHDR() while + * composing the buffer. The CMSG_NXTHDR() macro is designed better for + * parsing than composing the buffer. It requires the pointer it returns + * to leave space in buffer for addressing a cmsghdr and we want to make + * sure it works for us while we skip beyond the last ancillary data + * option. + * + * bufspace[i] = sizeof(struct cmsghdr) + <pad after header> + + * <option[i] content length> + <pad after data>; + * + * total_bufspace = bufspace[0] + bufspace[1] + ... + * ... + bufspace[N-1] + sizeof (struct cmsghdr); + */ + + rthdr_space = 0; + pktinfo_space = 0; + /* We'll always set the hoplimit of the outgoing packets */ + hoplimit_space = sizeof (int); + bufspace = sizeof (struct cmsghdr) + _MAX_ALIGNMENT + + hoplimit_space + _MAX_ALIGNMENT; + + if (gw_cnt > 0) { + rthdr_space = inet6_rth_space(IPV6_RTHDR_TYPE_0, gw_cnt); + bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + + rthdr_space + _MAX_ALIGNMENT; + } + + if (if_index != 0) { + pktinfo_space = sizeof (struct in6_pktinfo); + bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + + pktinfo_space + _MAX_ALIGNMENT; + } + + /* + * We need to temporarily set the msgp->msg_controllen to bufspace + * (we will later trim it to actual length used). This is needed because + * CMSG_NXTHDR() uses it to check we have not exceeded the bounds. + */ + bufspace += sizeof (struct cmsghdr); + msgp->msg_controllen = bufspace; + + msgp->msg_control = (struct cmsghdr *)malloc(bufspace); + if (msgp->msg_control == NULL) { + Fprintf(stderr, "%s: malloc %s\n", prog, strerror(errno)); + exit(EXIT_FAILURE); + } + cmsgp = CMSG_FIRSTHDR(msgp); + + /* + * Fill ancillary data. First hoplimit, then rthdr and pktinfo if + * needed. + */ + + /* set hoplimit ancillary data */ + cmsgp->cmsg_level = IPPROTO_IPV6; + cmsgp->cmsg_type = IPV6_HOPLIMIT; + cmsg_datap = CMSG_DATA(cmsgp); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + *(int *)cmsg_datap = hoplimit; + cmsgp->cmsg_len = cmsg_datap + hoplimit_space - (uchar_t *)cmsgp; + cmsgp = CMSG_NXTHDR(msgp, cmsgp); + + /* set rthdr ancillary data if needed */ + if (gw_cnt > 0) { + struct ip6_rthdr0 *rthdr0p; + + cmsgp->cmsg_level = IPPROTO_IPV6; + cmsgp->cmsg_type = IPV6_RTHDR; + cmsg_datap = CMSG_DATA(cmsgp); + + /* + * Initialize rthdr structure + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + rthdr0p = (struct ip6_rthdr0 *)cmsg_datap; + if (inet6_rth_init(rthdr0p, rthdr_space, + IPV6_RTHDR_TYPE_0, gw_cnt) == NULL) { + Fprintf(stderr, "%s: inet6_rth_init failed\n", + prog); + exit(EXIT_FAILURE); + } + + /* + * Stuff in gateway addresses + */ + for (i = 0; i < gw_cnt; i++) { + if (inet6_rth_add(rthdr0p, + &gwIPlist[i].addr6) == -1) { + Fprintf(stderr, + "%s: inet6_rth_add\n", prog); + exit(EXIT_FAILURE); + } + } + + cmsgp->cmsg_len = cmsg_datap + rthdr_space - (uchar_t *)cmsgp; + cmsgp = CMSG_NXTHDR(msgp, cmsgp); + } + + /* set pktinfo ancillary data if needed */ + if (if_index != 0) { + struct in6_pktinfo *pktinfop; + + cmsgp->cmsg_level = IPPROTO_IPV6; + cmsgp->cmsg_type = IPV6_PKTINFO; + cmsg_datap = CMSG_DATA(cmsgp); + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + pktinfop = (struct in6_pktinfo *)cmsg_datap; + /* + * We don't know if pktinfop->ipi6_addr is aligned properly, + * therefore let's use bcopy, instead of assignment. + */ + (void) bcopy(&in6addr_any, &pktinfop->ipi6_addr, + sizeof (struct in6_addr)); + + /* + * We can assume pktinfop->ipi6_ifindex is 32 bit aligned. + */ + pktinfop->ipi6_ifindex = if_index; + cmsgp->cmsg_len = cmsg_datap + pktinfo_space - (uchar_t *)cmsgp; + cmsgp = CMSG_NXTHDR(msgp, cmsgp); + } + + msgp->msg_controllen = (char *)cmsgp - (char *)msgp->msg_control; +} + +/* + * Parses the given msg->msg_control to find the IPV6_HOPLIMIT ancillary data + * and update the hoplimit. + * Returns _B_FALSE if it can't find IPV6_HOPLIMIT ancillary data, _B_TRUE + * otherwise. + */ +static boolean_t +update_hoplimit_ancillary_data(struct msghdr *msg, int hoplimit) +{ + struct cmsghdr *cmsg; + int *intp; + + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level == IPPROTO_IPV6 && + cmsg->cmsg_type == IPV6_HOPLIMIT) { + /* LINTED E_BAD_PTR_CAST_ALIGN */ + intp = (int *)(CMSG_DATA(cmsg)); + *intp = hoplimit; + return (_B_TRUE); + } + } + + return (_B_FALSE); +} + +/* + * send a probe packet to the destination + */ +void +send_probe6(int sndsock, struct msghdr *msg6, struct ip *outip, int seq, + int ttl, struct timeval *tp, int packlen) +{ + uchar_t *outp; + struct icmp *outicmp; + struct outdata *outdata; + struct iovec iov; + int cc; + int optlen = 0; + int send_size; + struct sockaddr_in6 *to6; + + if (gw_count > 0) { + /* ip6_rthdr0 structure includes one gateway address */ + optlen = sizeof (struct ip6_rthdr0) + + gw_count * sizeof (struct in6_addr); + } + + send_size = packlen - sizeof (struct ip6_hdr) - optlen; + + /* if using UDP, further discount UDP header size */ + if (!useicmp) + send_size -= sizeof (struct udphdr); + + /* initialize buffer pointers */ + outp = (uchar_t *)(outip + 1); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + outicmp = (struct icmp *)outp; + /* LINTED E_BAD_PTR_CAST_ALIGN */ + outdata = (struct outdata *)(outp + ICMP6_MINLEN); + + if (!update_hoplimit_ancillary_data(msg6, ttl)) { + Fprintf(stderr, + "%s: can't find IPV6_HOPLIMIT ancillary data\n", prog); + exit(EXIT_FAILURE); + } + + /* Payload */ + outdata->seq = seq; + outdata->ttl = ttl; + outdata->tv = *tp; + + if (useicmp) { + outicmp->icmp_seq = htons(seq); + } else { + to6 = (struct sockaddr_in6 *)msg6->msg_name; + to6->sin6_port = htons((port + seq) % (MAX_PORT + 1)); + } + + iov.iov_base = outp; + iov.iov_len = send_size; + + msg6->msg_iov = &iov; + msg6->msg_iovlen = 1; + + cc = sendmsg(sndsock, msg6, 0); + + if (cc < 0 || cc != send_size) { + if (cc < 0) { + Fprintf(stderr, "%s: sendmsg: %s\n", prog, + strerror(errno)); + } + Printf("%s: wrote %s %d chars, ret=%d\n", + prog, hostname, send_size, cc); + (void) fflush(stdout); + } +} + +/* + * Return a pointer to the ancillary data for the given cmsg_level and + * cmsg_type. + * If not found return NULL. + */ +void * +find_ancillary_data(struct msghdr *msg, int cmsg_level, int cmsg_type) +{ + struct cmsghdr *cmsg; + + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level == cmsg_level && + cmsg->cmsg_type == cmsg_type) { + return (CMSG_DATA(cmsg)); + } + } + return (NULL); +} + +/* + * Check out the reply packet to see if it's what we were expecting. + * Returns REPLY_GOT_TARGET if the reply comes from the target + * REPLY_GOT_GATEWAY if an intermediate gateway sends TIME_EXCEEDED + * REPLY_GOT_OTHER for other kinds of unreachables indicating none of + * the above two cases + * + * It also sets the icmp type and icmp code values + */ +int +check_reply6(struct msghdr *msg, int cc, int seq, uchar_t *type, uchar_t *code) +{ + uchar_t *buf = msg->msg_iov->iov_base; + struct sockaddr_in6 *from_in6 = (struct sockaddr_in6 *)msg->msg_name; + icmp6_t *icp6; + ulong_t ip6hdr_len; + uint8_t last_hdr; + int save_cc = cc; + char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */ + + /* Ignore packets > 64k or control buffers that don't fit */ + if (msg->msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { + if (verbose) { + Printf("Truncated message: msg_flags 0x%x from %s\n", + msg->msg_flags, + inet_ntop(AF_INET6, + (void *)&(from_in6->sin6_addr), + temp_buf, sizeof (temp_buf))); + } + return (REPLY_SHORT_PKT); + } + if (cc < ICMP6_MINLEN) { + if (verbose) { + Printf("packet too short (%d bytes) from %s\n", + cc, + inet_ntop(AF_INET6, + (void *)&(from_in6->sin6_addr), + temp_buf, sizeof (temp_buf))); + } + return (REPLY_SHORT_PKT); + } + /* LINTED E_BAD_PTR_CAST_ALIGN */ + icp6 = (icmp6_t *)buf; + *type = icp6->icmp6_type; + *code = icp6->icmp6_code; + + /* + * traceroute interprets only ICMP6_TIME_EXCEED_TRANSIT, + * ICMP6_DST_UNREACH, ICMP6_ECHO_REPLY, ICMP6_PACKET_TOO_BIG and + * ICMP6_PARAMPROB_NEXTHEADER, ignores others + */ + if ((*type == ICMP6_TIME_EXCEEDED && + *code == ICMP6_TIME_EXCEED_TRANSIT) || + *type == ICMP6_DST_UNREACH || *type == ICMP6_ECHO_REPLY || + *type == ICMP6_PACKET_TOO_BIG || + (*type == ICMP6_PARAM_PROB && + *code == ICMP6_PARAMPROB_NEXTHEADER)) { + ip6_t *hip6; + struct udphdr *up; + icmp6_t *hicmp6; + + cc -= ICMP6_MINLEN; + hip6 = (ip6_t *)&(icp6->icmp6_data32[1]); + last_hdr = hip6->ip6_nxt; + ip6hdr_len = IPv6_hdrlen(hip6, cc, &last_hdr); + + cc -= ip6hdr_len; + if (useicmp) { + if (*type == ICMP6_ECHO_REPLY && + icp6->icmp6_id == htons(ident) && + icp6->icmp6_seq == htons(seq)) { + return (REPLY_GOT_TARGET); + } + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + hicmp6 = (icmp6_t *)((uchar_t *)hip6 + ip6hdr_len); + + if (ICMP6_MINLEN <= cc && + last_hdr == IPPROTO_ICMPV6 && + hicmp6->icmp6_id == htons(ident) && + hicmp6->icmp6_seq == htons(seq)) { + if (*type == ICMP6_TIME_EXCEEDED) { + return (REPLY_GOT_GATEWAY); + } else { + return (REPLY_GOT_OTHER); + } + } + } else { + /* LINTED E_BAD_PTR_CAST_ALIGN */ + up = (struct udphdr *)((uchar_t *)hip6 + ip6hdr_len); + /* + * at least 4 bytes of UDP header is required for this + * check + */ + if (4 <= cc && + last_hdr == IPPROTO_UDP && + up->uh_sport == htons(ident) && + up->uh_dport == htons((port + seq) % + (MAX_PORT + 1))) { + if (*type == ICMP6_DST_UNREACH && + *code == ICMP6_DST_UNREACH_NOPORT) { + return (REPLY_GOT_TARGET); + } else if (*type == ICMP6_TIME_EXCEEDED) { + return (REPLY_GOT_GATEWAY); + } else { + return (REPLY_GOT_OTHER); + } + } + } + } + + if (verbose) { + int i, j; + uchar_t *lp = (uchar_t *)icp6; + struct in6_addr *dst; + struct in6_pktinfo *pkti; + + pkti = (struct in6_pktinfo *)find_ancillary_data(msg, + IPPROTO_IPV6, IPV6_PKTINFO); + if (pkti == NULL) { + Fprintf(stderr, + "%s: can't find IPV6_PKTINFO ancillary data\n", + prog); + exit(EXIT_FAILURE); + } + dst = &pkti->ipi6_addr; + cc = save_cc; + Printf("\n%d bytes from %s to ", cc, + inet_ntop(AF_INET6, (const void *)&(from_in6->sin6_addr), + temp_buf, sizeof (temp_buf))); + Printf("%s: icmp type %d (%s) code %d\n", + inet_ntop(AF_INET6, (const void *)dst, + temp_buf, sizeof (temp_buf)), + *type, pr_type6(*type), *code); + for (i = 0; i < cc; i += 4) { + Printf("%2d: x", i); + for (j = 0; ((j < 4) && ((i + j) < cc)); j++) + Printf("%2.2x", *lp++); + (void) putchar('\n'); + } + } + + return (REPLY_SHORT_PKT); +} + +/* + * Return the length of the IPv6 related headers (including extension headers) + */ +static int +IPv6_hdrlen(ip6_t *ip6h, int pkt_len, uint8_t *last_hdr_rtrn) +{ + int length; + int exthdrlength; + uint8_t nexthdr; + uint8_t *whereptr; + ip6_hbh_t *hbhhdr; + ip6_dest_t *desthdr; + ip6_rthdr_t *rthdr; + ip6_frag_t *fraghdr; + uint8_t *endptr; + + length = sizeof (ip6_t); + + whereptr = ((uint8_t *)&ip6h[1]); /* point to next hdr */ + endptr = ((uint8_t *)ip6h) + pkt_len; + + nexthdr = ip6h->ip6_nxt; + *last_hdr_rtrn = IPPROTO_NONE; + + if (whereptr >= endptr) + return (length); + + while (whereptr < endptr) { + *last_hdr_rtrn = nexthdr; + switch (nexthdr) { + case IPPROTO_HOPOPTS: + hbhhdr = (ip6_hbh_t *)whereptr; + exthdrlength = 8 * (hbhhdr->ip6h_len + 1); + if ((uchar_t *)hbhhdr + exthdrlength > endptr) + return (length); + nexthdr = hbhhdr->ip6h_nxt; + length += exthdrlength; + break; + + case IPPROTO_DSTOPTS: + desthdr = (ip6_dest_t *)whereptr; + exthdrlength = 8 * (desthdr->ip6d_len + 1); + if ((uchar_t *)desthdr + exthdrlength > endptr) + return (length); + nexthdr = desthdr->ip6d_nxt; + length += exthdrlength; + break; + + case IPPROTO_ROUTING: + rthdr = (ip6_rthdr_t *)whereptr; + exthdrlength = 8 * (rthdr->ip6r_len + 1); + if ((uchar_t *)rthdr + exthdrlength > endptr) + return (length); + nexthdr = rthdr->ip6r_nxt; + length += exthdrlength; + break; + + case IPPROTO_FRAGMENT: + /* LINTED E_BAD_PTR_CAST_ALIGN */ + fraghdr = (ip6_frag_t *)whereptr; + if ((uchar_t *)&fraghdr[1] > endptr) + return (length); + nexthdr = fraghdr->ip6f_nxt; + length += sizeof (struct ip6_frag); + break; + + case IPPROTO_NONE: + default: + return (length); + } + whereptr = (uint8_t *)ip6h + length; + } + *last_hdr_rtrn = nexthdr; + + return (length); +} + +/* + * convert an ICMP6 "type" field to a printable string. + */ +static char * +pr_type6(uchar_t type) +{ + static struct icmptype_table ttab6[] = { + {ICMP6_DST_UNREACH, "Dest Unreachable"}, + {ICMP6_PACKET_TOO_BIG, "Packet Too Big"}, + {ICMP6_TIME_EXCEEDED, "Time Exceeded"}, + {ICMP6_PARAM_PROB, "Param Problem"}, + {ICMP6_ECHO_REQUEST, "Echo Request"}, + {ICMP6_ECHO_REPLY, "Echo Reply"}, + {MLD_LISTENER_QUERY, "Multicast Listener Query"}, + {MLD_LISTENER_REPORT, "Multicast Listener Report"}, + {MLD_LISTENER_REDUCTION, "Multicast Listener Done"}, + {ND_ROUTER_SOLICIT, "Router Solicitation"}, + {ND_ROUTER_ADVERT, "Router Advertisement"}, + {ND_NEIGHBOR_SOLICIT, "Neighbor Solicitation"}, + {ND_NEIGHBOR_ADVERT, "Neighbor Advertisement"}, + {ND_REDIRECT, "Redirect Message"} + }; + int i = 0; + + for (i = 0; i < A_CNT(ttab6); i++) { + if (ttab6[i].type == type) + return (ttab6[i].message); + } + + return ("OUT-OF-RANGE"); +} + + +/* + * print the IPv6 src address of the reply packet + */ +void +print_addr6(uchar_t *buf, int cc, struct sockaddr *from) +{ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + struct sockaddr_in6 *from_in6 = (struct sockaddr_in6 *)from; + ip6_t *ip; + union any_in_addr ip_addr; + char *resolved_name; + char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */ + + ip_addr.addr6 = from_in6->sin6_addr; + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + ip = (ip6_t *)buf; + + (void) inet_ntop(AF_INET6, &(from_in6->sin6_addr), temp_buf, + sizeof (temp_buf)); + if (!nflag) + resolved_name = inet_name(&ip_addr, AF_INET6); + /* + * If the IPv6 address cannot be resolved to hostname, inet_name() + * returns the IPv6 address as a string. In that case, we choose not + * to print it twice. This saves us space on display. + */ + if (nflag || (strcmp(temp_buf, resolved_name) == 0)) + Printf(" %s", temp_buf); + else + Printf(" %s (%s)", resolved_name, temp_buf); + + if (verbose) { + Printf(" %d bytes to %s", cc, inet_ntop(AF_INET6, + (const void *) &(ip->ip6_dst), temp_buf, + sizeof (temp_buf))); + } +} + +/* + * ICMP6 messages which doesn't mean we got the target, or we got a gateway, are + * processed here. It returns _B_TRUE if it's some sort of 'unreachable'. + */ +boolean_t +print_icmp_other6(uchar_t type, uchar_t code) +{ + boolean_t unreach = _B_FALSE; + + switch (type) { + + /* this corresponds to "ICMP_UNREACH_NEEDFRAG" in ICMP */ + case ICMP6_PACKET_TOO_BIG: + unreach = _B_TRUE; + Printf(" !B"); + break; + + case ICMP6_PARAM_PROB: + /* this corresponds to "ICMP_UNREACH_PROTOCOL" in ICMP */ + if (code == ICMP6_PARAMPROB_NEXTHEADER) { + unreach = _B_TRUE; + Printf(" !R"); + } + break; + + case ICMP6_DST_UNREACH: + switch (code) { + case ICMP6_DST_UNREACH_NOPORT: + break; + + case ICMP6_DST_UNREACH_NOROUTE: + unreach = _B_TRUE; + Printf(" !H"); + break; + + case ICMP6_DST_UNREACH_ADMIN: + unreach = _B_TRUE; + Printf(" !X"); + break; + + case ICMP6_DST_UNREACH_ADDR: + unreach = _B_TRUE; + Printf(" !A"); + break; + + case ICMP6_DST_UNREACH_NOTNEIGHBOR: + unreach = _B_TRUE; + Printf(" !E"); + break; + + default: + unreach = _B_TRUE; + Printf(" !<%d>", code); + break; + } + break; + default: + break; + } + + return (unreach); +}