xref: /titanic_52/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_icmp.c (revision 7ba7860f5af89005c23337fb7cdc48145cc6b8ac)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50ec92a15Swy83408  * Common Development and Distribution License (the "License").
60ec92a15Swy83408  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*7ba7860fSErik Nordmark  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <stdio.h>
277c478bd9Sstevel@tonic-gate #include <string.h>
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <sys/socket.h>
307c478bd9Sstevel@tonic-gate #include <net/if.h>
317c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
327c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
337c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
347c478bd9Sstevel@tonic-gate #include <netinet/in.h>
357c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
367c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h>
377c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
387c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
397c478bd9Sstevel@tonic-gate #include <netinet/icmp6.h>
407c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
417c478bd9Sstevel@tonic-gate #include <inet/ip.h>
427c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
437c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
447c478bd9Sstevel@tonic-gate #include <netdb.h>
457c478bd9Sstevel@tonic-gate #include "snoop.h"
467c478bd9Sstevel@tonic-gate #include "snoop_mip.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static void interpret_options(char *, int);
497c478bd9Sstevel@tonic-gate static void interpret_mldv2qry(icmp6_t *, int);
507c478bd9Sstevel@tonic-gate static void interpret_mldv2rpt(icmp6_t *, int);
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /* Mobile-IP routines from snoop_mip.c */
547c478bd9Sstevel@tonic-gate extern void interpret_icmp_mip_ext(uchar_t *, int);
557c478bd9Sstevel@tonic-gate extern const char *get_mip_adv_desc(uint8_t);
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /* Router advertisement message structure. */
587c478bd9Sstevel@tonic-gate struct icmp_ra_addr {
597c478bd9Sstevel@tonic-gate 	uint32_t addr;
607c478bd9Sstevel@tonic-gate 	uint32_t preference;
617c478bd9Sstevel@tonic-gate };
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*ARGSUSED*/
647c478bd9Sstevel@tonic-gate void
657c478bd9Sstevel@tonic-gate interpret_icmp(int flags, struct icmp *icmp, int iplen, int ilen)
667c478bd9Sstevel@tonic-gate {
677c478bd9Sstevel@tonic-gate 	char *pt, *pc, *px;
687c478bd9Sstevel@tonic-gate 	char *line;
697c478bd9Sstevel@tonic-gate 	char buff[67627];	/* Router adv. can have 256 routers ....   */
707c478bd9Sstevel@tonic-gate 				/* Each router has a name 256 char long .. */
717c478bd9Sstevel@tonic-gate 	char extbuff[MAXHOSTNAMELEN + 1];
727c478bd9Sstevel@tonic-gate 	struct udphdr *orig_uhdr;
737c478bd9Sstevel@tonic-gate 	int num_rtr_addrs = 0;
747c478bd9Sstevel@tonic-gate 	extern char *prot_nest_prefix;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	if (ilen < ICMP_MINLEN)
777c478bd9Sstevel@tonic-gate 		return;		/* incomplete header */
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	pt = "Unknown";
807c478bd9Sstevel@tonic-gate 	pc = "";
817c478bd9Sstevel@tonic-gate 	px = "";
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	switch (icmp->icmp_type) {
847c478bd9Sstevel@tonic-gate 	case ICMP_ECHOREPLY:
857c478bd9Sstevel@tonic-gate 		pt = "Echo reply";
867c478bd9Sstevel@tonic-gate 		(void) sprintf(buff, "ID: %d Sequence number: %d",
877c478bd9Sstevel@tonic-gate 		    ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq));
887c478bd9Sstevel@tonic-gate 		pc = buff;
897c478bd9Sstevel@tonic-gate 		break;
907c478bd9Sstevel@tonic-gate 	case ICMP_UNREACH:
917c478bd9Sstevel@tonic-gate 		pt = "Destination unreachable";
927c478bd9Sstevel@tonic-gate 		switch (icmp->icmp_code) {
937c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_NET:
947c478bd9Sstevel@tonic-gate 			if (ilen >= ICMP_ADVLENMIN) {
957c478bd9Sstevel@tonic-gate 				(void) sprintf(buff, "Net %s unreachable",
967c478bd9Sstevel@tonic-gate 				    addrtoname(AF_INET,
977c478bd9Sstevel@tonic-gate 				    &icmp->icmp_ip.ip_dst));
987c478bd9Sstevel@tonic-gate 				pc = buff;
997c478bd9Sstevel@tonic-gate 			} else {
1007c478bd9Sstevel@tonic-gate 				pc = "Bad net";
1017c478bd9Sstevel@tonic-gate 			}
1027c478bd9Sstevel@tonic-gate 			break;
1037c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_HOST:
1047c478bd9Sstevel@tonic-gate 			if (ilen >= ICMP_ADVLENMIN) {
1057c478bd9Sstevel@tonic-gate 				(void) sprintf(buff, "Host %s unreachable",
1067c478bd9Sstevel@tonic-gate 				    addrtoname(AF_INET,
1077c478bd9Sstevel@tonic-gate 				    &icmp->icmp_ip.ip_dst));
1087c478bd9Sstevel@tonic-gate 				pc = buff;
1097c478bd9Sstevel@tonic-gate 			} else {
1107c478bd9Sstevel@tonic-gate 				pc = "Bad host";
1117c478bd9Sstevel@tonic-gate 			}
1127c478bd9Sstevel@tonic-gate 			break;
1137c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_PROTOCOL:
1147c478bd9Sstevel@tonic-gate 			if (ilen >= ICMP_ADVLENMIN) {
1157c478bd9Sstevel@tonic-gate 				(void) sprintf(buff, "Bad protocol %d",
1167c478bd9Sstevel@tonic-gate 				    icmp->icmp_ip.ip_p);
1177c478bd9Sstevel@tonic-gate 				pc = buff;
1187c478bd9Sstevel@tonic-gate 			} else {
1197c478bd9Sstevel@tonic-gate 				pc = "Bad protocol";
1207c478bd9Sstevel@tonic-gate 			}
1217c478bd9Sstevel@tonic-gate 			break;
1227c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_PORT:
1237c478bd9Sstevel@tonic-gate 			if (ilen >= ICMP_ADVLENMIN) {
1247c478bd9Sstevel@tonic-gate 				orig_uhdr = (struct udphdr *)((uchar_t *)icmp +
1257c478bd9Sstevel@tonic-gate 				    ICMP_MINLEN + icmp->icmp_ip.ip_hl * 4);
1267c478bd9Sstevel@tonic-gate 				switch (icmp->icmp_ip.ip_p) {
1277c478bd9Sstevel@tonic-gate 				case IPPROTO_TCP:
1287c478bd9Sstevel@tonic-gate 					(void) sprintf(buff, "TCP port %d"
1297c478bd9Sstevel@tonic-gate 					    " unreachable",
1307c478bd9Sstevel@tonic-gate 					    ntohs(orig_uhdr->uh_dport));
1317c478bd9Sstevel@tonic-gate 					pc = buff;
1327c478bd9Sstevel@tonic-gate 					break;
1337c478bd9Sstevel@tonic-gate 				case IPPROTO_UDP:
1347c478bd9Sstevel@tonic-gate 					(void) sprintf(buff, "UDP port %d"
1357c478bd9Sstevel@tonic-gate 					    " unreachable",
1367c478bd9Sstevel@tonic-gate 					    ntohs(orig_uhdr->uh_dport));
1377c478bd9Sstevel@tonic-gate 					pc = buff;
1387c478bd9Sstevel@tonic-gate 					break;
1397c478bd9Sstevel@tonic-gate 				default:
1407c478bd9Sstevel@tonic-gate 					pc = "Port unreachable";
1417c478bd9Sstevel@tonic-gate 					break;
1427c478bd9Sstevel@tonic-gate 				}
1437c478bd9Sstevel@tonic-gate 			} else {
1447c478bd9Sstevel@tonic-gate 				pc = "Bad port";
1457c478bd9Sstevel@tonic-gate 			}
1467c478bd9Sstevel@tonic-gate 			break;
1477c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_NEEDFRAG:
1487c478bd9Sstevel@tonic-gate 			if (ntohs(icmp->icmp_nextmtu) != 0) {
1497c478bd9Sstevel@tonic-gate 				(void) sprintf(buff, "Needed to fragment:"
1507c478bd9Sstevel@tonic-gate 				    " next hop MTU = %d",
1517c478bd9Sstevel@tonic-gate 				    ntohs(icmp->icmp_nextmtu));
1527c478bd9Sstevel@tonic-gate 				pc = buff;
1537c478bd9Sstevel@tonic-gate 			} else {
1547c478bd9Sstevel@tonic-gate 				pc = "Needed to fragment";
1557c478bd9Sstevel@tonic-gate 			}
1567c478bd9Sstevel@tonic-gate 			break;
1577c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_SRCFAIL:
1587c478bd9Sstevel@tonic-gate 			pc = "Source route failed";
1597c478bd9Sstevel@tonic-gate 			break;
1607c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_NET_UNKNOWN:
1617c478bd9Sstevel@tonic-gate 			pc = "Unknown network";
1627c478bd9Sstevel@tonic-gate 			break;
1637c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_HOST_UNKNOWN:
1647c478bd9Sstevel@tonic-gate 			pc = "Unknown host";
1657c478bd9Sstevel@tonic-gate 			break;
1667c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_ISOLATED:
1677c478bd9Sstevel@tonic-gate 			pc = "Source host isolated";
1687c478bd9Sstevel@tonic-gate 			break;
1697c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_NET_PROHIB:
1707c478bd9Sstevel@tonic-gate 			pc = "Net administratively prohibited";
1717c478bd9Sstevel@tonic-gate 			break;
1727c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_HOST_PROHIB:
1737c478bd9Sstevel@tonic-gate 			pc = "Host administratively prohibited";
1747c478bd9Sstevel@tonic-gate 			break;
1757c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_TOSNET:
1767c478bd9Sstevel@tonic-gate 			pc = "Net unreachable for this TOS";
1777c478bd9Sstevel@tonic-gate 			break;
1787c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_TOSHOST:
1797c478bd9Sstevel@tonic-gate 			pc = "Host unreachable for this TOS";
1807c478bd9Sstevel@tonic-gate 			break;
1817c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_FILTER_PROHIB:
1827c478bd9Sstevel@tonic-gate 			pc = "Communication administratively prohibited";
1837c478bd9Sstevel@tonic-gate 			break;
1847c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_HOST_PRECEDENCE:
1857c478bd9Sstevel@tonic-gate 			pc = "Host precedence violation";
1867c478bd9Sstevel@tonic-gate 			break;
1877c478bd9Sstevel@tonic-gate 		case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1887c478bd9Sstevel@tonic-gate 			pc = "Precedence cutoff in effect";
1897c478bd9Sstevel@tonic-gate 			break;
1907c478bd9Sstevel@tonic-gate 		default:
1917c478bd9Sstevel@tonic-gate 			break;
1927c478bd9Sstevel@tonic-gate 		}
1937c478bd9Sstevel@tonic-gate 		break;
1947c478bd9Sstevel@tonic-gate 	case ICMP_SOURCEQUENCH:
1957c478bd9Sstevel@tonic-gate 		pt = "Packet lost, slow down";
1967c478bd9Sstevel@tonic-gate 		break;
1977c478bd9Sstevel@tonic-gate 	case ICMP_REDIRECT:
1987c478bd9Sstevel@tonic-gate 		pt = "Redirect";
1997c478bd9Sstevel@tonic-gate 		switch (icmp->icmp_code) {
2007c478bd9Sstevel@tonic-gate 		case ICMP_REDIRECT_NET:
2017c478bd9Sstevel@tonic-gate 			pc = "for network";
2027c478bd9Sstevel@tonic-gate 			break;
2037c478bd9Sstevel@tonic-gate 		case ICMP_REDIRECT_HOST:
2047c478bd9Sstevel@tonic-gate 			pc = "for host";
2057c478bd9Sstevel@tonic-gate 			break;
2067c478bd9Sstevel@tonic-gate 		case ICMP_REDIRECT_TOSNET:
2077c478bd9Sstevel@tonic-gate 			pc = "for tos and net";
2087c478bd9Sstevel@tonic-gate 			break;
2097c478bd9Sstevel@tonic-gate 		case ICMP_REDIRECT_TOSHOST:
2107c478bd9Sstevel@tonic-gate 			pc = "for tos and host";
2117c478bd9Sstevel@tonic-gate 			break;
2127c478bd9Sstevel@tonic-gate 		default:
2137c478bd9Sstevel@tonic-gate 			break;
2147c478bd9Sstevel@tonic-gate 		}
2157c478bd9Sstevel@tonic-gate 		(void) sprintf(buff, "%s %s to %s",
2167c478bd9Sstevel@tonic-gate 			pc, addrtoname(AF_INET, &icmp->icmp_ip.ip_dst),
2177c478bd9Sstevel@tonic-gate 			addrtoname(AF_INET, &icmp->icmp_gwaddr));
2187c478bd9Sstevel@tonic-gate 		pc = buff;
2197c478bd9Sstevel@tonic-gate 		break;
2207c478bd9Sstevel@tonic-gate 	case ICMP_ECHO:
2217c478bd9Sstevel@tonic-gate 		pt = "Echo request";
2227c478bd9Sstevel@tonic-gate 		(void) sprintf(buff, "ID: %d Sequence number: %d",
2237c478bd9Sstevel@tonic-gate 		    ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq));
2247c478bd9Sstevel@tonic-gate 		pc = buff;
2257c478bd9Sstevel@tonic-gate 		break;
2267c478bd9Sstevel@tonic-gate 	case ICMP_ROUTERADVERT:
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate #define	icmp_num_addrs	icmp_hun.ih_rtradv.irt_num_addrs
2297c478bd9Sstevel@tonic-gate #define	icmp_wpa	icmp_hun.ih_rtradv.irt_wpa
2307c478bd9Sstevel@tonic-gate #define	icmp_lifetime	icmp_hun.ih_rtradv.irt_lifetime
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		pt = "Router advertisement";
2337c478bd9Sstevel@tonic-gate 		(void) sprintf(buff, "Lifetime %ds [%d]:",
2347c478bd9Sstevel@tonic-gate 		    ntohs(icmp->icmp_lifetime), icmp->icmp_num_addrs);
2357c478bd9Sstevel@tonic-gate 		if (icmp->icmp_wpa == 2) {
2367c478bd9Sstevel@tonic-gate 			struct icmp_ra_addr *ra;
2377c478bd9Sstevel@tonic-gate 			char ra_buf[MAXHOSTNAMELEN + 32];
2387c478bd9Sstevel@tonic-gate 			char ra_ext_buf[50];
2397c478bd9Sstevel@tonic-gate 			struct in_addr sin;
2407c478bd9Sstevel@tonic-gate 			int icmp_ra_len;
2417c478bd9Sstevel@tonic-gate 			int i;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 			/* Cannot trust anything from the network... */
2447c478bd9Sstevel@tonic-gate 			num_rtr_addrs = MIN((ilen - ICMP_MINLEN) / 8,
2457c478bd9Sstevel@tonic-gate 			    icmp->icmp_num_addrs);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 			ra = (struct icmp_ra_addr *)icmp->icmp_data;
2487c478bd9Sstevel@tonic-gate 			for (i = 0; i < num_rtr_addrs; i++) {
2497c478bd9Sstevel@tonic-gate 				sin.s_addr = ra->addr;
2507c478bd9Sstevel@tonic-gate 				(void) snprintf(ra_buf, sizeof (ra_buf),
2517c478bd9Sstevel@tonic-gate 				    " {%s %u}",
2527c478bd9Sstevel@tonic-gate 				    addrtoname(AF_INET, &sin),
2537c478bd9Sstevel@tonic-gate 				    ntohl(ra->preference));
2547c478bd9Sstevel@tonic-gate 				if (strlcat(buff, ra_buf, sizeof (buff)) >=
2557c478bd9Sstevel@tonic-gate 					sizeof (buff)) {
2567c478bd9Sstevel@tonic-gate 					buff[sizeof (buff) -
2577c478bd9Sstevel@tonic-gate 					    strlen("<Too Long>)")] = '\0';
2587c478bd9Sstevel@tonic-gate 					(void) strlcat(buff, "<Too Long>",
2597c478bd9Sstevel@tonic-gate 						sizeof (buff));
2607c478bd9Sstevel@tonic-gate 					break;
2617c478bd9Sstevel@tonic-gate 				}
2627c478bd9Sstevel@tonic-gate 				ra++;
2637c478bd9Sstevel@tonic-gate 			}
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 			icmp_ra_len = ICMP_MINLEN + num_rtr_addrs *
2667c478bd9Sstevel@tonic-gate 			    sizeof (struct icmp_ra_addr);
2677c478bd9Sstevel@tonic-gate 			if (ilen > icmp_ra_len) {
2687c478bd9Sstevel@tonic-gate 				int curr_len = ilen - icmp_ra_len;
2697c478bd9Sstevel@tonic-gate 				int ocurr_len;
2707c478bd9Sstevel@tonic-gate 				exthdr_t *exthdr = (exthdr_t *)ra;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 				extbuff[0] = '\0';
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 				while (curr_len > 0) {
2757c478bd9Sstevel@tonic-gate 				    /* Append Mobile-IP description */
2767c478bd9Sstevel@tonic-gate 				    (void) snprintf(ra_ext_buf,
2777c478bd9Sstevel@tonic-gate 					sizeof (ra_ext_buf), ", %s",
2787c478bd9Sstevel@tonic-gate 					get_mip_adv_desc(exthdr->type));
2797c478bd9Sstevel@tonic-gate 				    (void) strlcat(extbuff, ra_ext_buf,
2807c478bd9Sstevel@tonic-gate 					sizeof (extbuff));
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 				    /* Special case for padding */
2837c478bd9Sstevel@tonic-gate 				    if (exthdr->type ==
2847c478bd9Sstevel@tonic-gate 					ICMP_ADV_MSG_PADDING_EXT) {
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 					curr_len--;
2877c478bd9Sstevel@tonic-gate 					exthdr = (exthdr_t *)
2887c478bd9Sstevel@tonic-gate 						((char *)exthdr + 1);
2897c478bd9Sstevel@tonic-gate 					continue;
2907c478bd9Sstevel@tonic-gate 				    }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 				    /* else normal extension */
2937c478bd9Sstevel@tonic-gate 				    ocurr_len = curr_len;
2947c478bd9Sstevel@tonic-gate 				    curr_len -= sizeof (*exthdr) +
2957c478bd9Sstevel@tonic-gate 							exthdr->length;
2967c478bd9Sstevel@tonic-gate 				    /* detect bad length */
2977c478bd9Sstevel@tonic-gate 				    if (ocurr_len < curr_len)
2987c478bd9Sstevel@tonic-gate 						break;
2997c478bd9Sstevel@tonic-gate 				    exthdr = (exthdr_t *)
3007c478bd9Sstevel@tonic-gate 						((char *)exthdr +
3017c478bd9Sstevel@tonic-gate 						sizeof (*exthdr) +
3027c478bd9Sstevel@tonic-gate 						exthdr->length);
3037c478bd9Sstevel@tonic-gate 				}
3047c478bd9Sstevel@tonic-gate 				px = extbuff;
3057c478bd9Sstevel@tonic-gate 			}
3067c478bd9Sstevel@tonic-gate 			pc = buff;
3077c478bd9Sstevel@tonic-gate 		}
3087c478bd9Sstevel@tonic-gate 		break;
3097c478bd9Sstevel@tonic-gate 	case ICMP_ROUTERSOLICIT:
3107c478bd9Sstevel@tonic-gate 		pt = "Router solicitation";
3117c478bd9Sstevel@tonic-gate 		break;
3127c478bd9Sstevel@tonic-gate 	case ICMP_TIMXCEED:
3137c478bd9Sstevel@tonic-gate 		pt = "Time exceeded";
3147c478bd9Sstevel@tonic-gate 		switch (icmp->icmp_code) {
3157c478bd9Sstevel@tonic-gate 		case ICMP_TIMXCEED_INTRANS:
3167c478bd9Sstevel@tonic-gate 			pc = "in transit";
3177c478bd9Sstevel@tonic-gate 			break;
3187c478bd9Sstevel@tonic-gate 		case ICMP_TIMXCEED_REASS:
3197c478bd9Sstevel@tonic-gate 			pc = "in reassembly";
3207c478bd9Sstevel@tonic-gate 			break;
3217c478bd9Sstevel@tonic-gate 		default:
3227c478bd9Sstevel@tonic-gate 			break;
3237c478bd9Sstevel@tonic-gate 		}
3247c478bd9Sstevel@tonic-gate 		break;
3257c478bd9Sstevel@tonic-gate 	case ICMP_PARAMPROB:
3267c478bd9Sstevel@tonic-gate 		pt = "IP parameter problem";
3277c478bd9Sstevel@tonic-gate 		switch (icmp->icmp_code) {
3287c478bd9Sstevel@tonic-gate 		case ICMP_PARAMPROB_OPTABSENT:
3297c478bd9Sstevel@tonic-gate 			pc = "Required option missing";
3307c478bd9Sstevel@tonic-gate 			break;
3317c478bd9Sstevel@tonic-gate 		case ICMP_PARAMPROB_BADLENGTH:
3327c478bd9Sstevel@tonic-gate 			pc = "Bad length";
3337c478bd9Sstevel@tonic-gate 			break;
3347c478bd9Sstevel@tonic-gate 		case 0: /* Should this be the default? */
3357c478bd9Sstevel@tonic-gate 			(void) sprintf(buff, "Problem at octet %d\n",
3367c478bd9Sstevel@tonic-gate 			    icmp->icmp_pptr);
3377c478bd9Sstevel@tonic-gate 			pc = buff;
3387c478bd9Sstevel@tonic-gate 		default:
3397c478bd9Sstevel@tonic-gate 			break;
3407c478bd9Sstevel@tonic-gate 		}
3417c478bd9Sstevel@tonic-gate 		break;
3427c478bd9Sstevel@tonic-gate 	case ICMP_TSTAMP:
3437c478bd9Sstevel@tonic-gate 		pt = "Timestamp request";
3447c478bd9Sstevel@tonic-gate 		break;
3457c478bd9Sstevel@tonic-gate 	case ICMP_TSTAMPREPLY:
3467c478bd9Sstevel@tonic-gate 		pt = "Timestamp reply";
3477c478bd9Sstevel@tonic-gate 		break;
3487c478bd9Sstevel@tonic-gate 	case ICMP_IREQ:
3497c478bd9Sstevel@tonic-gate 		pt = "Information request";
3507c478bd9Sstevel@tonic-gate 		break;
3517c478bd9Sstevel@tonic-gate 	case ICMP_IREQREPLY:
3527c478bd9Sstevel@tonic-gate 		pt = "Information reply";
3537c478bd9Sstevel@tonic-gate 		break;
3547c478bd9Sstevel@tonic-gate 	case ICMP_MASKREQ:
3557c478bd9Sstevel@tonic-gate 		pt = "Address mask request";
3567c478bd9Sstevel@tonic-gate 		break;
3577c478bd9Sstevel@tonic-gate 	case ICMP_MASKREPLY:
3587c478bd9Sstevel@tonic-gate 		pt = "Address mask reply";
3597c478bd9Sstevel@tonic-gate 		(void) sprintf(buff, "Mask = 0x%x", ntohl(icmp->icmp_mask));
3607c478bd9Sstevel@tonic-gate 		pc = buff;
3617c478bd9Sstevel@tonic-gate 		break;
3627c478bd9Sstevel@tonic-gate 	default:
3637c478bd9Sstevel@tonic-gate 		break;
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
3677c478bd9Sstevel@tonic-gate 		line = get_sum_line();
3687c478bd9Sstevel@tonic-gate 		if (*pc) {
3697c478bd9Sstevel@tonic-gate 			if (*px) {
3707c478bd9Sstevel@tonic-gate 				(void) sprintf(line, "ICMP %s (%s)%s",
3717c478bd9Sstevel@tonic-gate 				    pt, pc, px);
3727c478bd9Sstevel@tonic-gate 			} else {
3737c478bd9Sstevel@tonic-gate 				(void) sprintf(line, "ICMP %s (%s)", pt, pc);
3747c478bd9Sstevel@tonic-gate 			}
3757c478bd9Sstevel@tonic-gate 		} else {
3767c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "ICMP %s", pt);
3777c478bd9Sstevel@tonic-gate 		}
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
3817c478bd9Sstevel@tonic-gate 		show_header("ICMP:  ", "ICMP Header", ilen);
3827c478bd9Sstevel@tonic-gate 		show_space();
3837c478bd9Sstevel@tonic-gate 		(void) sprintf(get_line(0, 0), "Type = %d (%s)",
3847c478bd9Sstevel@tonic-gate 		    icmp->icmp_type, pt);
3857c478bd9Sstevel@tonic-gate 		if (*pc) {
3867c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0), "Code = %d (%s)",
3877c478bd9Sstevel@tonic-gate 			    icmp->icmp_code, pc);
3887c478bd9Sstevel@tonic-gate 		} else {
3897c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0), "Code = %d",
3907c478bd9Sstevel@tonic-gate 			    icmp->icmp_code);
3917c478bd9Sstevel@tonic-gate 		}
3927c478bd9Sstevel@tonic-gate 		(void) sprintf(get_line(0, 0), "Checksum = %x",
3937c478bd9Sstevel@tonic-gate 		    ntohs(icmp->icmp_cksum));
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		if (icmp->icmp_type == ICMP_UNREACH ||
3967c478bd9Sstevel@tonic-gate 		    icmp->icmp_type == ICMP_REDIRECT) {
3977c478bd9Sstevel@tonic-gate 			if (ilen > 28) {
3987c478bd9Sstevel@tonic-gate 				show_space();
3997c478bd9Sstevel@tonic-gate 				(void) sprintf(get_line(0, 0),
4007c478bd9Sstevel@tonic-gate 				    "[ subject header follows ]");
4017c478bd9Sstevel@tonic-gate 				show_space();
4027c478bd9Sstevel@tonic-gate 				prot_nest_prefix = "ICMP:";
4037c478bd9Sstevel@tonic-gate 				(void) interpret_ip(flags,
4047c478bd9Sstevel@tonic-gate 				    (struct ip *)icmp->icmp_data, 28);
4057c478bd9Sstevel@tonic-gate 				prot_nest_prefix = "";
4067c478bd9Sstevel@tonic-gate 			}
4077c478bd9Sstevel@tonic-gate 		} else if (icmp->icmp_type == ICMP_PARAMPROB) {
4087c478bd9Sstevel@tonic-gate 			if (ilen > 28) {
4097c478bd9Sstevel@tonic-gate 				show_space();
4107c478bd9Sstevel@tonic-gate 				(void) sprintf(get_line(0, 0),
4117c478bd9Sstevel@tonic-gate 				    "[ subject header follows ]");
4127c478bd9Sstevel@tonic-gate 				show_space();
4137c478bd9Sstevel@tonic-gate 				prot_nest_prefix = "ICMP:";
4147c478bd9Sstevel@tonic-gate 				(void) interpret_ip(flags,
4157c478bd9Sstevel@tonic-gate 				    (struct ip *)icmp->icmp_data, 28);
4167c478bd9Sstevel@tonic-gate 				prot_nest_prefix = "";
4177c478bd9Sstevel@tonic-gate 			}
4187c478bd9Sstevel@tonic-gate 		} else if (icmp->icmp_type == ICMP_ROUTERADVERT) {
4197c478bd9Sstevel@tonic-gate 			if (icmp->icmp_wpa == 2) {
4207c478bd9Sstevel@tonic-gate 				int icmp_ra_len;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 				show_space();
4237c478bd9Sstevel@tonic-gate 				icmp_ra_len = ICMP_MINLEN +
4247c478bd9Sstevel@tonic-gate 				    num_rtr_addrs *
4257c478bd9Sstevel@tonic-gate 					sizeof (struct icmp_ra_addr);
4267c478bd9Sstevel@tonic-gate 				prot_nest_prefix = "";
4277c478bd9Sstevel@tonic-gate 				if (ilen > icmp_ra_len) {
4287c478bd9Sstevel@tonic-gate 					interpret_icmp_mip_ext(
4297c478bd9Sstevel@tonic-gate 					    (uchar_t *)icmp + icmp_ra_len,
4307c478bd9Sstevel@tonic-gate 					    ilen - icmp_ra_len);
4317c478bd9Sstevel@tonic-gate 				}
4327c478bd9Sstevel@tonic-gate 			}
4337c478bd9Sstevel@tonic-gate 		}
4347c478bd9Sstevel@tonic-gate 		show_space();
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4397c478bd9Sstevel@tonic-gate void
4407c478bd9Sstevel@tonic-gate interpret_icmpv6(flags, icmp6, iplen, ilen)
4417c478bd9Sstevel@tonic-gate 	int flags;
4427c478bd9Sstevel@tonic-gate 	icmp6_t *icmp6;
4437c478bd9Sstevel@tonic-gate 	int iplen, ilen;
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	char *pt, *pc;
4467c478bd9Sstevel@tonic-gate 	char *line;
4477c478bd9Sstevel@tonic-gate 	extern char *prot_nest_prefix;
4487c478bd9Sstevel@tonic-gate 	char addrstr[INET6_ADDRSTRLEN];
4497c478bd9Sstevel@tonic-gate 	char buff[2048];
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	if (ilen < ICMP6_MINLEN)
4527c478bd9Sstevel@tonic-gate 		return;		/* incomplete header */
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	pt = "Unknown";
4557c478bd9Sstevel@tonic-gate 	pc = "";
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	switch (icmp6->icmp6_type) {
4587c478bd9Sstevel@tonic-gate 	case ICMP6_DST_UNREACH:
4597c478bd9Sstevel@tonic-gate 		pt = "Destination unreachable";
4607c478bd9Sstevel@tonic-gate 		switch (icmp6->icmp6_code) {
4617c478bd9Sstevel@tonic-gate 		case ICMP6_DST_UNREACH_NOROUTE:
4627c478bd9Sstevel@tonic-gate 			pc = "No route to destination";
4637c478bd9Sstevel@tonic-gate 			break;
4647c478bd9Sstevel@tonic-gate 		case ICMP6_DST_UNREACH_ADMIN:
4657c478bd9Sstevel@tonic-gate 			pc = "Communication administratively prohibited";
4667c478bd9Sstevel@tonic-gate 			break;
4677c478bd9Sstevel@tonic-gate 		case ICMP6_DST_UNREACH_ADDR:
4687c478bd9Sstevel@tonic-gate 			pc = "Address unreachable";
4697c478bd9Sstevel@tonic-gate 			break;
4707c478bd9Sstevel@tonic-gate 		case ICMP6_DST_UNREACH_NOPORT:
4717c478bd9Sstevel@tonic-gate 			if (ilen >= ICMP6_MINLEN + IPV6_HDR_LEN +
4727c478bd9Sstevel@tonic-gate 				sizeof (struct udphdr)) {
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 				ip6_t *orig_ip6hdr = (ip6_t *)&icmp6[1];
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 				switch (orig_ip6hdr->ip6_nxt) {
4777c478bd9Sstevel@tonic-gate 				case IPPROTO_TCP: {
4787c478bd9Sstevel@tonic-gate 					struct tcphdr *orig_thdr =
4797c478bd9Sstevel@tonic-gate 					    (struct tcphdr *)&orig_ip6hdr[1];
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 					(void) sprintf(buff, "TCP port %hu"
4827c478bd9Sstevel@tonic-gate 					    " unreachable",
4837c478bd9Sstevel@tonic-gate 					    ntohs(orig_thdr->th_dport));
4847c478bd9Sstevel@tonic-gate 					pc = buff;
4857c478bd9Sstevel@tonic-gate 					break;
4867c478bd9Sstevel@tonic-gate 				    }
4877c478bd9Sstevel@tonic-gate 				case IPPROTO_UDP: {
4887c478bd9Sstevel@tonic-gate 					struct udphdr *orig_uhdr =
4897c478bd9Sstevel@tonic-gate 					    (struct udphdr *)&orig_ip6hdr[1];
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 					(void) sprintf(buff, "UDP port %hu"
4927c478bd9Sstevel@tonic-gate 					    " unreachable",
4937c478bd9Sstevel@tonic-gate 					    ntohs(orig_uhdr->uh_dport));
4947c478bd9Sstevel@tonic-gate 					pc = buff;
4957c478bd9Sstevel@tonic-gate 					break;
4967c478bd9Sstevel@tonic-gate 				    }
4977c478bd9Sstevel@tonic-gate 				default:
4987c478bd9Sstevel@tonic-gate 					pc = "Port unreachable";
4997c478bd9Sstevel@tonic-gate 					break;
5007c478bd9Sstevel@tonic-gate 				}
5017c478bd9Sstevel@tonic-gate 			} else {
5027c478bd9Sstevel@tonic-gate 				pc = "Bad port";
5037c478bd9Sstevel@tonic-gate 			}
5047c478bd9Sstevel@tonic-gate 			break;
5057c478bd9Sstevel@tonic-gate 		default:
5067c478bd9Sstevel@tonic-gate 			break;
5077c478bd9Sstevel@tonic-gate 		}
5087c478bd9Sstevel@tonic-gate 		break;
5097c478bd9Sstevel@tonic-gate 	case ICMP6_PACKET_TOO_BIG:
5107c478bd9Sstevel@tonic-gate 		pt = "Packet too big";
5117c478bd9Sstevel@tonic-gate 		break;
5127c478bd9Sstevel@tonic-gate 	case ND_REDIRECT:
5137c478bd9Sstevel@tonic-gate 		pt = "Redirect";
5147c478bd9Sstevel@tonic-gate 		break;
5157c478bd9Sstevel@tonic-gate 	case ICMP6_TIME_EXCEEDED:
5167c478bd9Sstevel@tonic-gate 		pt = "Time exceeded";
5177c478bd9Sstevel@tonic-gate 		switch (icmp6->icmp6_code) {
5187c478bd9Sstevel@tonic-gate 		case ICMP6_TIME_EXCEED_TRANSIT:
5197c478bd9Sstevel@tonic-gate 			pc = "Hop limit exceeded in transit";
5207c478bd9Sstevel@tonic-gate 			break;
5217c478bd9Sstevel@tonic-gate 		case ICMP6_TIME_EXCEED_REASSEMBLY:
5227c478bd9Sstevel@tonic-gate 			pc = "Fragment reassembly time exceeded";
5237c478bd9Sstevel@tonic-gate 			break;
5247c478bd9Sstevel@tonic-gate 		default:
5257c478bd9Sstevel@tonic-gate 			break;
5267c478bd9Sstevel@tonic-gate 		}
5277c478bd9Sstevel@tonic-gate 		break;
5287c478bd9Sstevel@tonic-gate 	case ICMP6_PARAM_PROB:
5297c478bd9Sstevel@tonic-gate 		pt = "Parameter problem";
5307c478bd9Sstevel@tonic-gate 		switch (icmp6->icmp6_code) {
5317c478bd9Sstevel@tonic-gate 		case ICMP6_PARAMPROB_HEADER:
5327c478bd9Sstevel@tonic-gate 			pc = "Erroneous header field";
5337c478bd9Sstevel@tonic-gate 			break;
5347c478bd9Sstevel@tonic-gate 		case ICMP6_PARAMPROB_NEXTHEADER:
5357c478bd9Sstevel@tonic-gate 			pc = "Unrecognized next header type";
5367c478bd9Sstevel@tonic-gate 			break;
5377c478bd9Sstevel@tonic-gate 		case ICMP6_PARAMPROB_OPTION:
5387c478bd9Sstevel@tonic-gate 			pc = "Unrecognized IPv6 option";
5397c478bd9Sstevel@tonic-gate 			break;
5407c478bd9Sstevel@tonic-gate 		}
5417c478bd9Sstevel@tonic-gate 		break;
5427c478bd9Sstevel@tonic-gate 	case ICMP6_ECHO_REQUEST:
5437c478bd9Sstevel@tonic-gate 		pt = "Echo request";
5447c478bd9Sstevel@tonic-gate 		(void) sprintf(buff, "ID: %d Sequence number: %d",
5457c478bd9Sstevel@tonic-gate 		    ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq));
5467c478bd9Sstevel@tonic-gate 		pc = buff;
5477c478bd9Sstevel@tonic-gate 		break;
5487c478bd9Sstevel@tonic-gate 	case ICMP6_ECHO_REPLY:
5497c478bd9Sstevel@tonic-gate 		pt = "Echo reply";
5507c478bd9Sstevel@tonic-gate 		(void) sprintf(buff, "ID: %d Sequence number: %d",
5517c478bd9Sstevel@tonic-gate 		    ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq));
5527c478bd9Sstevel@tonic-gate 		pc = buff;
5537c478bd9Sstevel@tonic-gate 		break;
5547c478bd9Sstevel@tonic-gate 	case MLD_LISTENER_QUERY:
5557c478bd9Sstevel@tonic-gate 		if (ilen == MLD_MINLEN)
5567c478bd9Sstevel@tonic-gate 			pt = "Group membership query - MLDv1";
5577c478bd9Sstevel@tonic-gate 		else if (ilen >= MLD_V2_QUERY_MINLEN)
5587c478bd9Sstevel@tonic-gate 			pt = "Group membership query - MLDv2";
5597c478bd9Sstevel@tonic-gate 		else
5607c478bd9Sstevel@tonic-gate 			pt = "Unknown membership query";
5617c478bd9Sstevel@tonic-gate 		break;
5627c478bd9Sstevel@tonic-gate 	case MLD_LISTENER_REPORT:
5637c478bd9Sstevel@tonic-gate 		pt = "Group membership report - MLDv1";
5647c478bd9Sstevel@tonic-gate 		break;
5657c478bd9Sstevel@tonic-gate 	case MLD_LISTENER_REDUCTION:
5667c478bd9Sstevel@tonic-gate 		pt = "Group membership termination - MLDv1";
5677c478bd9Sstevel@tonic-gate 		break;
5687c478bd9Sstevel@tonic-gate 	case MLD_V2_LISTENER_REPORT:
5697c478bd9Sstevel@tonic-gate 		pt = "Group membership report - MLDv2";
5707c478bd9Sstevel@tonic-gate 		break;
5717c478bd9Sstevel@tonic-gate 	case ND_ROUTER_SOLICIT:
5727c478bd9Sstevel@tonic-gate 		pt = "Router solicitation";
5737c478bd9Sstevel@tonic-gate 		break;
5747c478bd9Sstevel@tonic-gate 	case ND_ROUTER_ADVERT:
5757c478bd9Sstevel@tonic-gate 		pt = "Router advertisement";
5767c478bd9Sstevel@tonic-gate 		break;
5777c478bd9Sstevel@tonic-gate 	case ND_NEIGHBOR_SOLICIT:
5787c478bd9Sstevel@tonic-gate 		pt = "Neighbor solicitation";
5797c478bd9Sstevel@tonic-gate 		break;
5807c478bd9Sstevel@tonic-gate 	case ND_NEIGHBOR_ADVERT:
5817c478bd9Sstevel@tonic-gate 		pt = "Neighbor advertisement";
5827c478bd9Sstevel@tonic-gate 		break;
5837c478bd9Sstevel@tonic-gate 	default:
5847c478bd9Sstevel@tonic-gate 		break;
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
5887c478bd9Sstevel@tonic-gate 		line = get_sum_line();
5897c478bd9Sstevel@tonic-gate 		if (*pc)
5907c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "ICMPv6 %s (%s)", pt, pc);
5917c478bd9Sstevel@tonic-gate 		else
5927c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "ICMPv6 %s", pt);
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
5967c478bd9Sstevel@tonic-gate 		show_header("ICMPv6:  ", "ICMPv6 Header", ilen);
5977c478bd9Sstevel@tonic-gate 		show_space();
5987c478bd9Sstevel@tonic-gate 		(void) sprintf(get_line(0, 0), "Type = %d (%s)",
5997c478bd9Sstevel@tonic-gate 		    icmp6->icmp6_type, pt);
6007c478bd9Sstevel@tonic-gate 		if (*pc)
6017c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0), "Code = %d (%s)",
6027c478bd9Sstevel@tonic-gate 			    icmp6->icmp6_code, pc);
6037c478bd9Sstevel@tonic-gate 		else
6047c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0), "Code = %d",
6057c478bd9Sstevel@tonic-gate 			    icmp6->icmp6_code);
6067c478bd9Sstevel@tonic-gate 		(void) sprintf(get_line(0, 0), "Checksum = %x",
6077c478bd9Sstevel@tonic-gate 		    ntohs(icmp6->icmp6_cksum));
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 		switch (icmp6->icmp6_type) {
6107c478bd9Sstevel@tonic-gate 		case ICMP6_DST_UNREACH:
6117c478bd9Sstevel@tonic-gate 			if (ilen > ICMP6_MINLEN + IPV6_HDR_LEN) {
6127c478bd9Sstevel@tonic-gate 				show_space();
6137c478bd9Sstevel@tonic-gate 				(void) sprintf(get_line(0, 0),
6147c478bd9Sstevel@tonic-gate 				    "[ subject header follows ]");
6157c478bd9Sstevel@tonic-gate 				show_space();
6167c478bd9Sstevel@tonic-gate 				prot_nest_prefix = "ICMPv6:";
6177c478bd9Sstevel@tonic-gate 				(void) interpret_ipv6(flags, (ip6_t *)&icmp6[1],
6187c478bd9Sstevel@tonic-gate 				    ICMP6_MINLEN + IPV6_HDR_LEN);
6197c478bd9Sstevel@tonic-gate 				prot_nest_prefix = "";
6207c478bd9Sstevel@tonic-gate 			}
6217c478bd9Sstevel@tonic-gate 			break;
6227c478bd9Sstevel@tonic-gate 		case ICMP6_PACKET_TOO_BIG:
6237c478bd9Sstevel@tonic-gate 			show_space();
6247c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
6250ec92a15Swy83408 			    " Packet too big MTU = %d",
6260ec92a15Swy83408 			    ntohl(icmp6->icmp6_mtu));
6277c478bd9Sstevel@tonic-gate 			show_space();
6287c478bd9Sstevel@tonic-gate 			break;
6297c478bd9Sstevel@tonic-gate 		case ND_REDIRECT: {
6307c478bd9Sstevel@tonic-gate 			nd_redirect_t *rd = (nd_redirect_t *)icmp6;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0), "Target address= %s",
6337c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (char *)&rd->nd_rd_target,
6347c478bd9Sstevel@tonic-gate 			    addrstr, INET6_ADDRSTRLEN));
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
6377c478bd9Sstevel@tonic-gate 			    "Destination address= %s",
6387c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (char *)&rd->nd_rd_dst,
6397c478bd9Sstevel@tonic-gate 			    addrstr, INET6_ADDRSTRLEN));
6407c478bd9Sstevel@tonic-gate 			show_space();
6417c478bd9Sstevel@tonic-gate 			interpret_options((char *)icmp6 + sizeof (*rd),
6427c478bd9Sstevel@tonic-gate 			    ilen - sizeof (*rd));
6437c478bd9Sstevel@tonic-gate 			break;
6447c478bd9Sstevel@tonic-gate 		}
6457c478bd9Sstevel@tonic-gate 		case ND_NEIGHBOR_SOLICIT: {
6467c478bd9Sstevel@tonic-gate 			struct nd_neighbor_solicit *ns;
6477c478bd9Sstevel@tonic-gate 			if (ilen < sizeof (*ns))
6487c478bd9Sstevel@tonic-gate 				break;
6497c478bd9Sstevel@tonic-gate 			ns = (struct nd_neighbor_solicit *)icmp6;
6507c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0), "Target node = %s, %s",
6517c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (char *)&ns->nd_ns_target,
6527c478bd9Sstevel@tonic-gate 			    addrstr, INET6_ADDRSTRLEN),
6537c478bd9Sstevel@tonic-gate 			    addrtoname(AF_INET6, &ns->nd_ns_target));
6547c478bd9Sstevel@tonic-gate 			show_space();
6557c478bd9Sstevel@tonic-gate 			interpret_options((char *)icmp6 + sizeof (*ns),
6567c478bd9Sstevel@tonic-gate 			    ilen - sizeof (*ns));
6577c478bd9Sstevel@tonic-gate 			break;
6587c478bd9Sstevel@tonic-gate 		}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 		case ND_NEIGHBOR_ADVERT: {
6617c478bd9Sstevel@tonic-gate 			struct nd_neighbor_advert *na;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 			if (ilen < sizeof (*na))
6647c478bd9Sstevel@tonic-gate 				break;
6657c478bd9Sstevel@tonic-gate 			na = (struct nd_neighbor_advert *)icmp6;
6667c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0), "Target node = %s, %s",
6677c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (char *)&na->nd_na_target,
6687c478bd9Sstevel@tonic-gate 			    addrstr, INET6_ADDRSTRLEN),
6697c478bd9Sstevel@tonic-gate 			    addrtoname(AF_INET6, &na->nd_na_target));
6707c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
6717c478bd9Sstevel@tonic-gate 			    "Router flag: %s, Solicited flag: %s, "
6727c478bd9Sstevel@tonic-gate 			    "Override flag: %s",
6737c478bd9Sstevel@tonic-gate 			    na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER ?
6747c478bd9Sstevel@tonic-gate 			    "SET" : "NOT SET",
6757c478bd9Sstevel@tonic-gate 			    na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED ?
6767c478bd9Sstevel@tonic-gate 			    "SET" : "NOT SET",
6777c478bd9Sstevel@tonic-gate 			    na->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE ?
6787c478bd9Sstevel@tonic-gate 			    "SET" : "NOT SET");
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 			show_space();
6817c478bd9Sstevel@tonic-gate 			interpret_options((char *)icmp6 + sizeof (*na),
6827c478bd9Sstevel@tonic-gate 			    ilen - sizeof (*na));
6837c478bd9Sstevel@tonic-gate 		}
6847c478bd9Sstevel@tonic-gate 		break;
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 		case ND_ROUTER_SOLICIT: {
6877c478bd9Sstevel@tonic-gate 			if (ilen < sizeof (struct nd_router_solicit))
6887c478bd9Sstevel@tonic-gate 				break;
6897c478bd9Sstevel@tonic-gate 			interpret_options(
6907c478bd9Sstevel@tonic-gate 			    (char *)icmp6 + sizeof (struct nd_router_solicit),
6917c478bd9Sstevel@tonic-gate 			    ilen - sizeof (struct nd_router_solicit));
6927c478bd9Sstevel@tonic-gate 			break;
6937c478bd9Sstevel@tonic-gate 		}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 		case ND_ROUTER_ADVERT: {
6967c478bd9Sstevel@tonic-gate 			struct nd_router_advert *ra;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 			if (ilen < sizeof (*ra))
6997c478bd9Sstevel@tonic-gate 				break;
7007c478bd9Sstevel@tonic-gate 			ra = (struct nd_router_advert *)icmp6;
7017c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
7027c478bd9Sstevel@tonic-gate 			    "Max hops= %d, Router lifetime= %d",
7037c478bd9Sstevel@tonic-gate 			    ra->nd_ra_curhoplimit,
7047c478bd9Sstevel@tonic-gate 			    ntohs(ra->nd_ra_router_lifetime));
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
7077c478bd9Sstevel@tonic-gate 			    "Managed addr conf flag: %s, Other conf flag: %s",
7087c478bd9Sstevel@tonic-gate 			    ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED ?
7097c478bd9Sstevel@tonic-gate 			    "SET" : "NOT SET",
7107c478bd9Sstevel@tonic-gate 			    ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER ?
7117c478bd9Sstevel@tonic-gate 			    "SET" : "NOT SET");
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
7147c478bd9Sstevel@tonic-gate 			    "Reachable time: %u, Reachable retrans time %u",
7157c478bd9Sstevel@tonic-gate 			    ntohl(ra->nd_ra_reachable),
7167c478bd9Sstevel@tonic-gate 			    ntohl(ra->nd_ra_retransmit));
7177c478bd9Sstevel@tonic-gate 			show_space();
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 			interpret_options((char *)icmp6 + sizeof (*ra),
7207c478bd9Sstevel@tonic-gate 			    ilen - sizeof (*ra));
7217c478bd9Sstevel@tonic-gate 			break;
7227c478bd9Sstevel@tonic-gate 		}
7237c478bd9Sstevel@tonic-gate 		case ICMP6_PARAM_PROB:
7247c478bd9Sstevel@tonic-gate 			if (ilen < sizeof (*icmp6))
7257c478bd9Sstevel@tonic-gate 				break;
7267c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0), "Ptr = %u",
7277c478bd9Sstevel@tonic-gate 			    ntohl(icmp6->icmp6_pptr));
7287c478bd9Sstevel@tonic-gate 			show_space();
7297c478bd9Sstevel@tonic-gate 			break;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		case MLD_LISTENER_QUERY: {
7327c478bd9Sstevel@tonic-gate 			struct mld_hdr *mldg = (struct mld_hdr *)icmp6;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 			if (ilen < MLD_MINLEN)
7357c478bd9Sstevel@tonic-gate 				break;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 			if (ilen >= MLD_V2_QUERY_MINLEN) {
7387c478bd9Sstevel@tonic-gate 				interpret_mldv2qry(icmp6, ilen);
7397c478bd9Sstevel@tonic-gate 			} else {
7407c478bd9Sstevel@tonic-gate 				(void) snprintf(get_line(0, 0),
7417c478bd9Sstevel@tonic-gate 				    get_line_remain(),
7427c478bd9Sstevel@tonic-gate 				    "Multicast address= %s",
7437c478bd9Sstevel@tonic-gate 				    inet_ntop(AF_INET6, mldg->mld_addr.s6_addr,
7447c478bd9Sstevel@tonic-gate 				    addrstr, INET6_ADDRSTRLEN));
7457c478bd9Sstevel@tonic-gate 			}
7467c478bd9Sstevel@tonic-gate 			show_space();
7477c478bd9Sstevel@tonic-gate 			break;
7487c478bd9Sstevel@tonic-gate 		}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 		case MLD_LISTENER_REPORT:
7517c478bd9Sstevel@tonic-gate 		case MLD_LISTENER_REDUCTION: {
7527c478bd9Sstevel@tonic-gate 			struct mld_hdr *mldg;
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 			if (ilen < sizeof (*mldg))
7557c478bd9Sstevel@tonic-gate 				break;
7567c478bd9Sstevel@tonic-gate 			mldg = (struct mld_hdr *)icmp6;
7577c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
7587c478bd9Sstevel@tonic-gate 			    "Multicast address= %s", inet_ntop(AF_INET6,
7597c478bd9Sstevel@tonic-gate 			    mldg->mld_addr.s6_addr, addrstr, INET6_ADDRSTRLEN));
7607c478bd9Sstevel@tonic-gate 			show_space();
7617c478bd9Sstevel@tonic-gate 			break;
7627c478bd9Sstevel@tonic-gate 		}
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 		case MLD_V2_LISTENER_REPORT: {
7657c478bd9Sstevel@tonic-gate 			interpret_mldv2rpt(icmp6, ilen);
7667c478bd9Sstevel@tonic-gate 			show_space();
7677c478bd9Sstevel@tonic-gate 			break;
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 		default:
7717c478bd9Sstevel@tonic-gate 			break;
7727c478bd9Sstevel@tonic-gate 		}
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate }
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate static void
7777c478bd9Sstevel@tonic-gate interpret_options(optc, ilen)
7787c478bd9Sstevel@tonic-gate 	char *optc;
7797c478bd9Sstevel@tonic-gate 	int ilen;
7807c478bd9Sstevel@tonic-gate {
7817c478bd9Sstevel@tonic-gate #define	PREFIX_OPTION_LENGTH    4
7827c478bd9Sstevel@tonic-gate #define	MTU_OPTION_LENGTH	1
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate #define	PREFIX_INFINITY		0xffffffffUL
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	struct nd_opt_hdr *opt;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	for (; ilen >= sizeof (*opt); ) {
7897c478bd9Sstevel@tonic-gate 		opt = (struct nd_opt_hdr *)optc;
7907c478bd9Sstevel@tonic-gate 		if (opt->nd_opt_len == 0)
7917c478bd9Sstevel@tonic-gate 			return;
7927c478bd9Sstevel@tonic-gate 		switch (opt->nd_opt_type) {
7937c478bd9Sstevel@tonic-gate 		case ND_OPT_SOURCE_LINKADDR:
7947c478bd9Sstevel@tonic-gate 		case ND_OPT_TARGET_LINKADDR:
7957c478bd9Sstevel@tonic-gate 		{
7967c478bd9Sstevel@tonic-gate 			struct nd_opt_lla *lopt;
7977c478bd9Sstevel@tonic-gate 			char	*buf, chbuf[128];
7987c478bd9Sstevel@tonic-gate 			uint_t	addr_len;
7997c478bd9Sstevel@tonic-gate 			int	i;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 			if (ilen < (int)opt->nd_opt_len * 8)
8027c478bd9Sstevel@tonic-gate 				break;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 			buf = chbuf;
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 			lopt = (struct nd_opt_lla *)opt;
8077c478bd9Sstevel@tonic-gate 			if (lopt->nd_opt_lla_type == ND_OPT_SOURCE_LINKADDR) {
8087c478bd9Sstevel@tonic-gate 				(void) sprintf(get_line(0, 0),
8097c478bd9Sstevel@tonic-gate 				    "+++ ICMPv6 Source LL Addr option +++");
8107c478bd9Sstevel@tonic-gate 			} else {
8117c478bd9Sstevel@tonic-gate 				(void) sprintf(get_line(0, 0),
8127c478bd9Sstevel@tonic-gate 				    "+++ ICMPv6 Target LL Addr option +++");
8137c478bd9Sstevel@tonic-gate 			}
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 			/*
8167c478bd9Sstevel@tonic-gate 			 * The option length is in 8 octet units, and
8177c478bd9Sstevel@tonic-gate 			 * includes the first two bytes (the type and
8187c478bd9Sstevel@tonic-gate 			 * lenght fields) of the option.
8197c478bd9Sstevel@tonic-gate 			 */
8207c478bd9Sstevel@tonic-gate 			addr_len = lopt->nd_opt_lla_len * 8 - 2;
8217c478bd9Sstevel@tonic-gate 			for (i = 0; i < addr_len; i++) {
8227c478bd9Sstevel@tonic-gate 				snprintf(buf, sizeof (chbuf) - (buf - chbuf),
8237c478bd9Sstevel@tonic-gate 				    "%x:", lopt->nd_opt_lla_hdw_addr[i]);
8247c478bd9Sstevel@tonic-gate 				buf += strlen(buf);
8257c478bd9Sstevel@tonic-gate 				if (buf >= &chbuf[sizeof (chbuf)]) {
8267c478bd9Sstevel@tonic-gate 					buf = NULL;
8277c478bd9Sstevel@tonic-gate 					chbuf[sizeof (chbuf) -
8287c478bd9Sstevel@tonic-gate 					    strlen("<Too Long>)")] = '\0';
8297c478bd9Sstevel@tonic-gate 					(void) strlcat(chbuf, "<Too Long>",
8307c478bd9Sstevel@tonic-gate 						sizeof (chbuf));
8317c478bd9Sstevel@tonic-gate 					break;
8327c478bd9Sstevel@tonic-gate 				}
8337c478bd9Sstevel@tonic-gate 			}
8347c478bd9Sstevel@tonic-gate 			if (buf)
8357c478bd9Sstevel@tonic-gate 				*(buf - 1) = '\0'; /* Erase last colon */
8367c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
8377c478bd9Sstevel@tonic-gate 			    "Link Layer address: %s", chbuf);
8387c478bd9Sstevel@tonic-gate 			show_space();
8397c478bd9Sstevel@tonic-gate 			break;
8407c478bd9Sstevel@tonic-gate 		}
8417c478bd9Sstevel@tonic-gate 		case ND_OPT_MTU: {
8427c478bd9Sstevel@tonic-gate 			struct nd_opt_mtu *mopt;
8437c478bd9Sstevel@tonic-gate 			if (opt->nd_opt_len != MTU_OPTION_LENGTH ||
8447c478bd9Sstevel@tonic-gate 			    ilen < sizeof (struct nd_opt_mtu))
8457c478bd9Sstevel@tonic-gate 				break;
8467c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
8477c478bd9Sstevel@tonic-gate 			    "+++ ICMPv6 MTU option +++");
8487c478bd9Sstevel@tonic-gate 			mopt = (struct nd_opt_mtu *)opt;
8497c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
850*7ba7860fSErik Nordmark 			    "MTU = %u ", ntohl(mopt->nd_opt_mtu_mtu));
8517c478bd9Sstevel@tonic-gate 			show_space();
8527c478bd9Sstevel@tonic-gate 			break;
8537c478bd9Sstevel@tonic-gate 		}
8547c478bd9Sstevel@tonic-gate 		case ND_OPT_PREFIX_INFORMATION: {
8557c478bd9Sstevel@tonic-gate 			struct nd_opt_prefix_info *popt;
8567c478bd9Sstevel@tonic-gate 			char validstr[30];
8577c478bd9Sstevel@tonic-gate 			char preferredstr[30];
8587c478bd9Sstevel@tonic-gate 			char prefixstr[INET6_ADDRSTRLEN];
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 			if (opt->nd_opt_len != PREFIX_OPTION_LENGTH ||
8617c478bd9Sstevel@tonic-gate 			    ilen < sizeof (struct nd_opt_prefix_info))
8627c478bd9Sstevel@tonic-gate 				break;
8637c478bd9Sstevel@tonic-gate 			popt = (struct nd_opt_prefix_info *)opt;
8647c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
8657c478bd9Sstevel@tonic-gate 			    "+++ ICMPv6 Prefix option +++");
8667c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
8677c478bd9Sstevel@tonic-gate 			    "Prefix length = %d ", popt->nd_opt_pi_prefix_len);
8687c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
8697c478bd9Sstevel@tonic-gate 			    "Onlink flag: %s, Autonomous addr conf flag: %s",
8707c478bd9Sstevel@tonic-gate 			    popt->nd_opt_pi_flags_reserved &
8717c478bd9Sstevel@tonic-gate 			    ND_OPT_PI_FLAG_ONLINK ? "SET" : "NOT SET",
8727c478bd9Sstevel@tonic-gate 			    popt->nd_opt_pi_flags_reserved &
8737c478bd9Sstevel@tonic-gate 			    ND_OPT_PI_FLAG_AUTO ? "SET" : "NOT SET");
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 			if (ntohl(popt->nd_opt_pi_valid_time) ==
8767c478bd9Sstevel@tonic-gate 			    PREFIX_INFINITY)
8777c478bd9Sstevel@tonic-gate 				sprintf(validstr, "INFINITY");
8787c478bd9Sstevel@tonic-gate 			else
8797c478bd9Sstevel@tonic-gate 				sprintf(validstr, "%lu",
8807c478bd9Sstevel@tonic-gate 				    ntohl(popt->nd_opt_pi_valid_time));
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 			if (ntohl(popt->nd_opt_pi_preferred_time) ==
8837c478bd9Sstevel@tonic-gate 			    PREFIX_INFINITY)
8847c478bd9Sstevel@tonic-gate 				sprintf(preferredstr, "INFINITY");
8857c478bd9Sstevel@tonic-gate 			else
8867c478bd9Sstevel@tonic-gate 				sprintf(preferredstr, "%lu",
8877c478bd9Sstevel@tonic-gate 				    ntohl(popt->nd_opt_pi_preferred_time));
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
8907c478bd9Sstevel@tonic-gate 			    "Valid Lifetime %s, Preferred Lifetime %s",
8917c478bd9Sstevel@tonic-gate 			    validstr, preferredstr);
8927c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0), "Prefix %s",
8937c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6,
8947c478bd9Sstevel@tonic-gate 			    (char *)&popt->nd_opt_pi_prefix, prefixstr,
8957c478bd9Sstevel@tonic-gate 			    INET6_ADDRSTRLEN));
8967c478bd9Sstevel@tonic-gate 			show_space();
8977c478bd9Sstevel@tonic-gate 		}
8987c478bd9Sstevel@tonic-gate 		default:
8997c478bd9Sstevel@tonic-gate 			break;
9007c478bd9Sstevel@tonic-gate 		}
9017c478bd9Sstevel@tonic-gate 		optc += opt->nd_opt_len * 8;
9027c478bd9Sstevel@tonic-gate 		ilen -= opt->nd_opt_len * 8;
9037c478bd9Sstevel@tonic-gate 	}
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate static void
9077c478bd9Sstevel@tonic-gate interpret_mldv2qry(icmp6_t *icmp6, int ilen)
9087c478bd9Sstevel@tonic-gate {
9097c478bd9Sstevel@tonic-gate 	mld2q_t *qry;
9107c478bd9Sstevel@tonic-gate 	in6_addr_t *src;
9117c478bd9Sstevel@tonic-gate 	int rem = ilen;
9127c478bd9Sstevel@tonic-gate 	int srccnt;
9137c478bd9Sstevel@tonic-gate 	char addrstr[INET6_ADDRSTRLEN];
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	if (ilen < sizeof (*qry)) {
9167c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
9177c478bd9Sstevel@tonic-gate 		    "Malformed MLD Query");
9187c478bd9Sstevel@tonic-gate 		return;
9197c478bd9Sstevel@tonic-gate 	}
9207c478bd9Sstevel@tonic-gate 	qry = (mld2q_t *)icmp6;
9217c478bd9Sstevel@tonic-gate 	rem -= sizeof (*qry);
9227c478bd9Sstevel@tonic-gate 	srccnt = ntohs(qry->mld2q_numsrc);
9237c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(),
9247c478bd9Sstevel@tonic-gate 	    "Multicast address= %s", inet_ntop(AF_INET6,
9257c478bd9Sstevel@tonic-gate 	    &qry->mld2q_addr.s6_addr, addrstr, INET6_ADDRSTRLEN));
9267c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(),
9277c478bd9Sstevel@tonic-gate 	    "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es");
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	src = (in6_addr_t *)&qry[1];
9307c478bd9Sstevel@tonic-gate 	while (srccnt > 0 && rem >= sizeof (*src)) {
9317c478bd9Sstevel@tonic-gate 		rem -= sizeof (*src);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(), "    %s",
9347c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, src, addrstr, INET6_ADDRSTRLEN));
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 		srccnt--;
9377c478bd9Sstevel@tonic-gate 		src++;
9387c478bd9Sstevel@tonic-gate 	}
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate #define	MAX_MLDV2_REPORT_TYPE	6
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate const char *mldv2rpt_types[] = {
9447c478bd9Sstevel@tonic-gate 	"<unknown>",
9457c478bd9Sstevel@tonic-gate 	"MODE_IS_INCLUDE",
9467c478bd9Sstevel@tonic-gate 	"MODE_IS_EXCLUDE",
9477c478bd9Sstevel@tonic-gate 	"CHANGE_TO_INCLUDE",
9487c478bd9Sstevel@tonic-gate 	"CHANGE_TO_EXCLUDE",
9497c478bd9Sstevel@tonic-gate 	"ALLOW_NEW_SOURCES",
9507c478bd9Sstevel@tonic-gate 	"BLOCK_OLD_SOURCES",
9517c478bd9Sstevel@tonic-gate };
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate static void
9547c478bd9Sstevel@tonic-gate interpret_mldv2rpt(icmp6_t *icmp6, int ilen)
9557c478bd9Sstevel@tonic-gate {
9567c478bd9Sstevel@tonic-gate 	mld2r_t *rpt;
9577c478bd9Sstevel@tonic-gate 	mld2mar_t *mar;
9587c478bd9Sstevel@tonic-gate 	in6_addr_t *src;
9597c478bd9Sstevel@tonic-gate 	int rem = ilen, auxlen;
9607c478bd9Sstevel@tonic-gate 	uint16_t marcnt, srccnt;
9617c478bd9Sstevel@tonic-gate 	char addrstr[INET6_ADDRSTRLEN];
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	if (ilen < sizeof (*rpt)) {
9647c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
9657c478bd9Sstevel@tonic-gate 		    "Malformed MLDv2 Report");
9667c478bd9Sstevel@tonic-gate 		return;
9677c478bd9Sstevel@tonic-gate 	}
9687c478bd9Sstevel@tonic-gate 	rpt = (mld2r_t *)icmp6;
9697c478bd9Sstevel@tonic-gate 	mar = (mld2mar_t *)&rpt[1];
9707c478bd9Sstevel@tonic-gate 	marcnt = ntohs(rpt->mld2r_nummar);
9717c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(),
9727c478bd9Sstevel@tonic-gate 	    "%d Multicast Address Record%s:", marcnt, (marcnt == 1) ? "" : "s");
9737c478bd9Sstevel@tonic-gate 	rem -= sizeof (*rpt);
9747c478bd9Sstevel@tonic-gate 	while (marcnt > 0 && rem >= sizeof (*mar)) {
9757c478bd9Sstevel@tonic-gate 		rem -= sizeof (*mar);
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
9787c478bd9Sstevel@tonic-gate 		    "Multicast address= %s  type = %s", inet_ntop(AF_INET6,
9797c478bd9Sstevel@tonic-gate 		    &mar->mld2mar_group.s6_addr, addrstr, INET6_ADDRSTRLEN),
9807c478bd9Sstevel@tonic-gate 		    (mar->mld2mar_type > MAX_MLDV2_REPORT_TYPE) ?
9817c478bd9Sstevel@tonic-gate 		    "<unknown>" : mldv2rpt_types[mar->mld2mar_type]);
9827c478bd9Sstevel@tonic-gate 		srccnt = ntohs(mar->mld2mar_numsrc);
9837c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
9847c478bd9Sstevel@tonic-gate 		    "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es");
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 		src = (in6_addr_t *)&mar[1];
9877c478bd9Sstevel@tonic-gate 		while (srccnt > 0 && rem >= sizeof (*src)) {
9887c478bd9Sstevel@tonic-gate 			rem -= sizeof (*src);
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
9917c478bd9Sstevel@tonic-gate 			    "    %s", inet_ntop(AF_INET6, src, addrstr,
9927c478bd9Sstevel@tonic-gate 			    INET6_ADDRSTRLEN));
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 			srccnt--;
9957c478bd9Sstevel@tonic-gate 			src++;
9967c478bd9Sstevel@tonic-gate 		}
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 		marcnt--;
9997c478bd9Sstevel@tonic-gate 		auxlen = mar->mld2mar_auxlen * 4;
10007c478bd9Sstevel@tonic-gate 		rem -= auxlen;
10017c478bd9Sstevel@tonic-gate 		mar = (mld2mar_t *)((uint8_t *)src + auxlen);
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate }
1004