Home | History | Annotate | Download | only in snoop
      1      0   stevel /*
      2      0   stevel  * CDDL HEADER START
      3      0   stevel  *
      4      0   stevel  * The contents of this file are subject to the terms of the
      5   4564  wy83408  * Common Development and Distribution License (the "License").
      6   4564  wy83408  * You may not use this file except in compliance with the License.
      7      0   stevel  *
      8      0   stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0   stevel  * or http://www.opensolaris.org/os/licensing.
     10      0   stevel  * See the License for the specific language governing permissions
     11      0   stevel  * and limitations under the License.
     12      0   stevel  *
     13      0   stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0   stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0   stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0   stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0   stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0   stevel  *
     19      0   stevel  * CDDL HEADER END
     20      0   stevel  */
     21      0   stevel /*
     22  10495     Erik  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0   stevel  * Use is subject to license terms.
     24      0   stevel  */
     25      0   stevel 
     26      0   stevel #include <stdio.h>
     27      0   stevel #include <string.h>
     28      0   stevel #include <sys/types.h>
     29      0   stevel #include <sys/socket.h>
     30      0   stevel #include <net/if.h>
     31      0   stevel #include <sys/stropts.h>
     32      0   stevel #include <sys/sysmacros.h>
     33      0   stevel #include <netinet/in_systm.h>
     34      0   stevel #include <netinet/in.h>
     35      0   stevel #include <netinet/ip.h>
     36      0   stevel #include <netinet/ip_icmp.h>
     37      0   stevel #include <netinet/udp.h>
     38      0   stevel #include <netinet/tcp.h>
     39      0   stevel #include <netinet/icmp6.h>
     40      0   stevel #include <netinet/ip6.h>
     41      0   stevel #include <inet/ip.h>
     42      0   stevel #include <inet/ip6.h>
     43      0   stevel #include <arpa/inet.h>
     44      0   stevel #include <netdb.h>
     45      0   stevel #include "snoop.h"
     46      0   stevel #include "snoop_mip.h"
     47      0   stevel 
     48      0   stevel static void interpret_options(char *, int);
     49      0   stevel static void interpret_mldv2qry(icmp6_t *, int);
     50      0   stevel static void interpret_mldv2rpt(icmp6_t *, int);
     51      0   stevel 
     52      0   stevel 
     53      0   stevel /* Mobile-IP routines from snoop_mip.c */
     54      0   stevel extern void interpret_icmp_mip_ext(uchar_t *, int);
     55      0   stevel extern const char *get_mip_adv_desc(uint8_t);
     56      0   stevel 
     57      0   stevel /* Router advertisement message structure. */
     58      0   stevel struct icmp_ra_addr {
     59      0   stevel 	uint32_t addr;
     60      0   stevel 	uint32_t preference;
     61      0   stevel };
     62      0   stevel 
     63      0   stevel /*ARGSUSED*/
     64      0   stevel void
     65      0   stevel interpret_icmp(int flags, struct icmp *icmp, int iplen, int ilen)
     66      0   stevel {
     67      0   stevel 	char *pt, *pc, *px;
     68      0   stevel 	char *line;
     69      0   stevel 	char buff[67627];	/* Router adv. can have 256 routers ....   */
     70      0   stevel 				/* Each router has a name 256 char long .. */
     71      0   stevel 	char extbuff[MAXHOSTNAMELEN + 1];
     72      0   stevel 	struct udphdr *orig_uhdr;
     73      0   stevel 	int num_rtr_addrs = 0;
     74      0   stevel 	extern char *prot_nest_prefix;
     75      0   stevel 
     76      0   stevel 	if (ilen < ICMP_MINLEN)
     77      0   stevel 		return;		/* incomplete header */
     78      0   stevel 
     79      0   stevel 	pt = "Unknown";
     80      0   stevel 	pc = "";
     81      0   stevel 	px = "";
     82      0   stevel 
     83      0   stevel 	switch (icmp->icmp_type) {
     84      0   stevel 	case ICMP_ECHOREPLY:
     85      0   stevel 		pt = "Echo reply";
     86      0   stevel 		(void) sprintf(buff, "ID: %d Sequence number: %d",
     87      0   stevel 		    ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq));
     88      0   stevel 		pc = buff;
     89      0   stevel 		break;
     90      0   stevel 	case ICMP_UNREACH:
     91      0   stevel 		pt = "Destination unreachable";
     92      0   stevel 		switch (icmp->icmp_code) {
     93      0   stevel 		case ICMP_UNREACH_NET:
     94      0   stevel 			if (ilen >= ICMP_ADVLENMIN) {
     95      0   stevel 				(void) sprintf(buff, "Net %s unreachable",
     96      0   stevel 				    addrtoname(AF_INET,
     97      0   stevel 				    &icmp->icmp_ip.ip_dst));
     98      0   stevel 				pc = buff;
     99      0   stevel 			} else {
    100      0   stevel 				pc = "Bad net";
    101      0   stevel 			}
    102      0   stevel 			break;
    103      0   stevel 		case ICMP_UNREACH_HOST:
    104      0   stevel 			if (ilen >= ICMP_ADVLENMIN) {
    105      0   stevel 				(void) sprintf(buff, "Host %s unreachable",
    106      0   stevel 				    addrtoname(AF_INET,
    107      0   stevel 				    &icmp->icmp_ip.ip_dst));
    108      0   stevel 				pc = buff;
    109      0   stevel 			} else {
    110      0   stevel 				pc = "Bad host";
    111      0   stevel 			}
    112      0   stevel 			break;
    113      0   stevel 		case ICMP_UNREACH_PROTOCOL:
    114      0   stevel 			if (ilen >= ICMP_ADVLENMIN) {
    115      0   stevel 				(void) sprintf(buff, "Bad protocol %d",
    116      0   stevel 				    icmp->icmp_ip.ip_p);
    117      0   stevel 				pc = buff;
    118      0   stevel 			} else {
    119      0   stevel 				pc = "Bad protocol";
    120      0   stevel 			}
    121      0   stevel 			break;
    122      0   stevel 		case ICMP_UNREACH_PORT:
    123      0   stevel 			if (ilen >= ICMP_ADVLENMIN) {
    124      0   stevel 				orig_uhdr = (struct udphdr *)((uchar_t *)icmp +
    125      0   stevel 				    ICMP_MINLEN + icmp->icmp_ip.ip_hl * 4);
    126      0   stevel 				switch (icmp->icmp_ip.ip_p) {
    127      0   stevel 				case IPPROTO_TCP:
    128      0   stevel 					(void) sprintf(buff, "TCP port %d"
    129      0   stevel 					    " unreachable",
    130      0   stevel 					    ntohs(orig_uhdr->uh_dport));
    131      0   stevel 					pc = buff;
    132      0   stevel 					break;
    133      0   stevel 				case IPPROTO_UDP:
    134      0   stevel 					(void) sprintf(buff, "UDP port %d"
    135      0   stevel 					    " unreachable",
    136      0   stevel 					    ntohs(orig_uhdr->uh_dport));
    137      0   stevel 					pc = buff;
    138      0   stevel 					break;
    139      0   stevel 				default:
    140      0   stevel 					pc = "Port unreachable";
    141      0   stevel 					break;
    142      0   stevel 				}
    143      0   stevel 			} else {
    144      0   stevel 				pc = "Bad port";
    145      0   stevel 			}
    146      0   stevel 			break;
    147      0   stevel 		case ICMP_UNREACH_NEEDFRAG:
    148      0   stevel 			if (ntohs(icmp->icmp_nextmtu) != 0) {
    149      0   stevel 				(void) sprintf(buff, "Needed to fragment:"
    150      0   stevel 				    " next hop MTU = %d",
    151      0   stevel 				    ntohs(icmp->icmp_nextmtu));
    152      0   stevel 				pc = buff;
    153      0   stevel 			} else {
    154      0   stevel 				pc = "Needed to fragment";
    155      0   stevel 			}
    156      0   stevel 			break;
    157      0   stevel 		case ICMP_UNREACH_SRCFAIL:
    158      0   stevel 			pc = "Source route failed";
    159      0   stevel 			break;
    160      0   stevel 		case ICMP_UNREACH_NET_UNKNOWN:
    161      0   stevel 			pc = "Unknown network";
    162      0   stevel 			break;
    163      0   stevel 		case ICMP_UNREACH_HOST_UNKNOWN:
    164      0   stevel 			pc = "Unknown host";
    165      0   stevel 			break;
    166      0   stevel 		case ICMP_UNREACH_ISOLATED:
    167      0   stevel 			pc = "Source host isolated";
    168      0   stevel 			break;
    169      0   stevel 		case ICMP_UNREACH_NET_PROHIB:
    170      0   stevel 			pc = "Net administratively prohibited";
    171      0   stevel 			break;
    172      0   stevel 		case ICMP_UNREACH_HOST_PROHIB:
    173      0   stevel 			pc = "Host administratively prohibited";
    174      0   stevel 			break;
    175      0   stevel 		case ICMP_UNREACH_TOSNET:
    176      0   stevel 			pc = "Net unreachable for this TOS";
    177      0   stevel 			break;
    178      0   stevel 		case ICMP_UNREACH_TOSHOST:
    179      0   stevel 			pc = "Host unreachable for this TOS";
    180      0   stevel 			break;
    181      0   stevel 		case ICMP_UNREACH_FILTER_PROHIB:
    182      0   stevel 			pc = "Communication administratively prohibited";
    183      0   stevel 			break;
    184      0   stevel 		case ICMP_UNREACH_HOST_PRECEDENCE:
    185      0   stevel 			pc = "Host precedence violation";
    186      0   stevel 			break;
    187      0   stevel 		case ICMP_UNREACH_PRECEDENCE_CUTOFF:
    188      0   stevel 			pc = "Precedence cutoff in effect";
    189      0   stevel 			break;
    190      0   stevel 		default:
    191      0   stevel 			break;
    192      0   stevel 		}
    193      0   stevel 		break;
    194      0   stevel 	case ICMP_SOURCEQUENCH:
    195      0   stevel 		pt = "Packet lost, slow down";
    196      0   stevel 		break;
    197      0   stevel 	case ICMP_REDIRECT:
    198      0   stevel 		pt = "Redirect";
    199      0   stevel 		switch (icmp->icmp_code) {
    200      0   stevel 		case ICMP_REDIRECT_NET:
    201      0   stevel 			pc = "for network";
    202      0   stevel 			break;
    203      0   stevel 		case ICMP_REDIRECT_HOST:
    204      0   stevel 			pc = "for host";
    205      0   stevel 			break;
    206      0   stevel 		case ICMP_REDIRECT_TOSNET:
    207      0   stevel 			pc = "for tos and net";
    208      0   stevel 			break;
    209      0   stevel 		case ICMP_REDIRECT_TOSHOST:
    210      0   stevel 			pc = "for tos and host";
    211      0   stevel 			break;
    212      0   stevel 		default:
    213      0   stevel 			break;
    214      0   stevel 		}
    215      0   stevel 		(void) sprintf(buff, "%s %s to %s",
    216      0   stevel 			pc, addrtoname(AF_INET, &icmp->icmp_ip.ip_dst),
    217      0   stevel 			addrtoname(AF_INET, &icmp->icmp_gwaddr));
    218      0   stevel 		pc = buff;
    219      0   stevel 		break;
    220      0   stevel 	case ICMP_ECHO:
    221      0   stevel 		pt = "Echo request";
    222      0   stevel 		(void) sprintf(buff, "ID: %d Sequence number: %d",
    223      0   stevel 		    ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq));
    224      0   stevel 		pc = buff;
    225      0   stevel 		break;
    226      0   stevel 	case ICMP_ROUTERADVERT:
    227      0   stevel 
    228      0   stevel #define	icmp_num_addrs	icmp_hun.ih_rtradv.irt_num_addrs
    229      0   stevel #define	icmp_wpa	icmp_hun.ih_rtradv.irt_wpa
    230      0   stevel #define	icmp_lifetime	icmp_hun.ih_rtradv.irt_lifetime
    231      0   stevel 
    232      0   stevel 		pt = "Router advertisement";
    233      0   stevel 		(void) sprintf(buff, "Lifetime %ds [%d]:",
    234      0   stevel 		    ntohs(icmp->icmp_lifetime), icmp->icmp_num_addrs);
    235      0   stevel 		if (icmp->icmp_wpa == 2) {
    236      0   stevel 			struct icmp_ra_addr *ra;
    237      0   stevel 			char ra_buf[MAXHOSTNAMELEN + 32];
    238      0   stevel 			char ra_ext_buf[50];
    239      0   stevel 			struct in_addr sin;
    240      0   stevel 			int icmp_ra_len;
    241      0   stevel 			int i;
    242      0   stevel 
    243      0   stevel 			/* Cannot trust anything from the network... */
    244      0   stevel 			num_rtr_addrs = MIN((ilen - ICMP_MINLEN) / 8,
    245      0   stevel 			    icmp->icmp_num_addrs);
    246      0   stevel 
    247      0   stevel 			ra = (struct icmp_ra_addr *)icmp->icmp_data;
    248      0   stevel 			for (i = 0; i < num_rtr_addrs; i++) {
    249      0   stevel 				sin.s_addr = ra->addr;
    250      0   stevel 				(void) snprintf(ra_buf, sizeof (ra_buf),
    251      0   stevel 				    " {%s %u}",
    252      0   stevel 				    addrtoname(AF_INET, &sin),
    253      0   stevel 				    ntohl(ra->preference));
    254      0   stevel 				if (strlcat(buff, ra_buf, sizeof (buff)) >=
    255      0   stevel 					sizeof (buff)) {
    256      0   stevel 					buff[sizeof (buff) -
    257      0   stevel 					    strlen("<Too Long>)")] = '\0';
    258      0   stevel 					(void) strlcat(buff, "<Too Long>",
    259      0   stevel 						sizeof (buff));
    260      0   stevel 					break;
    261      0   stevel 				}
    262      0   stevel 				ra++;
    263      0   stevel 			}
    264      0   stevel 
    265      0   stevel 			icmp_ra_len = ICMP_MINLEN + num_rtr_addrs *
    266      0   stevel 			    sizeof (struct icmp_ra_addr);
    267      0   stevel 			if (ilen > icmp_ra_len) {
    268      0   stevel 				int curr_len = ilen - icmp_ra_len;
    269      0   stevel 				int ocurr_len;
    270      0   stevel 				exthdr_t *exthdr = (exthdr_t *)ra;
    271      0   stevel 
    272      0   stevel 				extbuff[0] = '\0';
    273      0   stevel 
    274      0   stevel 				while (curr_len > 0) {
    275      0   stevel 				    /* Append Mobile-IP description */
    276      0   stevel 				    (void) snprintf(ra_ext_buf,
    277      0   stevel 					sizeof (ra_ext_buf), ", %s",
    278      0   stevel 					get_mip_adv_desc(exthdr->type));
    279      0   stevel 				    (void) strlcat(extbuff, ra_ext_buf,
    280      0   stevel 					sizeof (extbuff));
    281      0   stevel 
    282      0   stevel 				    /* Special case for padding */
    283      0   stevel 				    if (exthdr->type ==
    284      0   stevel 					ICMP_ADV_MSG_PADDING_EXT) {
    285      0   stevel 
    286      0   stevel 					curr_len--;
    287      0   stevel 					exthdr = (exthdr_t *)
    288      0   stevel 						((char *)exthdr + 1);
    289      0   stevel 					continue;
    290      0   stevel 				    }
    291      0   stevel 
    292      0   stevel 				    /* else normal extension */
    293      0   stevel 				    ocurr_len = curr_len;
    294      0   stevel 				    curr_len -= sizeof (*exthdr) +
    295      0   stevel 							exthdr->length;
    296      0   stevel 				    /* detect bad length */
    297      0   stevel 				    if (ocurr_len < curr_len)
    298      0   stevel 						break;
    299      0   stevel 				    exthdr = (exthdr_t *)
    300      0   stevel 						((char *)exthdr +
    301      0   stevel 						sizeof (*exthdr) +
    302      0   stevel 						exthdr->length);
    303      0   stevel 				}
    304      0   stevel 				px = extbuff;
    305      0   stevel 			}
    306      0   stevel 			pc = buff;
    307      0   stevel 		}
    308      0   stevel 		break;
    309      0   stevel 	case ICMP_ROUTERSOLICIT:
    310      0   stevel 		pt = "Router solicitation";
    311      0   stevel 		break;
    312      0   stevel 	case ICMP_TIMXCEED:
    313      0   stevel 		pt = "Time exceeded";
    314      0   stevel 		switch (icmp->icmp_code) {
    315      0   stevel 		case ICMP_TIMXCEED_INTRANS:
    316      0   stevel 			pc = "in transit";
    317      0   stevel 			break;
    318      0   stevel 		case ICMP_TIMXCEED_REASS:
    319      0   stevel 			pc = "in reassembly";
    320      0   stevel 			break;
    321      0   stevel 		default:
    322      0   stevel 			break;
    323      0   stevel 		}
    324      0   stevel 		break;
    325      0   stevel 	case ICMP_PARAMPROB:
    326      0   stevel 		pt = "IP parameter problem";
    327      0   stevel 		switch (icmp->icmp_code) {
    328      0   stevel 		case ICMP_PARAMPROB_OPTABSENT:
    329      0   stevel 			pc = "Required option missing";
    330      0   stevel 			break;
    331      0   stevel 		case ICMP_PARAMPROB_BADLENGTH:
    332      0   stevel 			pc = "Bad length";
    333      0   stevel 			break;
    334      0   stevel 		case 0: /* Should this be the default? */
    335      0   stevel 			(void) sprintf(buff, "Problem at octet %d\n",
    336      0   stevel 			    icmp->icmp_pptr);
    337      0   stevel 			pc = buff;
    338      0   stevel 		default:
    339      0   stevel 			break;
    340      0   stevel 		}
    341      0   stevel 		break;
    342      0   stevel 	case ICMP_TSTAMP:
    343      0   stevel 		pt = "Timestamp request";
    344      0   stevel 		break;
    345      0   stevel 	case ICMP_TSTAMPREPLY:
    346      0   stevel 		pt = "Timestamp reply";
    347      0   stevel 		break;
    348      0   stevel 	case ICMP_IREQ:
    349      0   stevel 		pt = "Information request";
    350      0   stevel 		break;
    351      0   stevel 	case ICMP_IREQREPLY:
    352      0   stevel 		pt = "Information reply";
    353      0   stevel 		break;
    354      0   stevel 	case ICMP_MASKREQ:
    355      0   stevel 		pt = "Address mask request";
    356      0   stevel 		break;
    357      0   stevel 	case ICMP_MASKREPLY:
    358      0   stevel 		pt = "Address mask reply";
    359      0   stevel 		(void) sprintf(buff, "Mask = 0x%x", ntohl(icmp->icmp_mask));
    360      0   stevel 		pc = buff;
    361      0   stevel 		break;
    362      0   stevel 	default:
    363      0   stevel 		break;
    364      0   stevel 	}
    365      0   stevel 
    366      0   stevel 	if (flags & F_SUM) {
    367      0   stevel 		line = get_sum_line();
    368      0   stevel 		if (*pc) {
    369      0   stevel 			if (*px) {
    370      0   stevel 				(void) sprintf(line, "ICMP %s (%s)%s",
    371      0   stevel 				    pt, pc, px);
    372      0   stevel 			} else {
    373      0   stevel 				(void) sprintf(line, "ICMP %s (%s)", pt, pc);
    374      0   stevel 			}
    375      0   stevel 		} else {
    376      0   stevel 			(void) sprintf(line, "ICMP %s", pt);
    377      0   stevel 		}
    378      0   stevel 	}
    379      0   stevel 
    380      0   stevel 	if (flags & F_DTAIL) {
    381      0   stevel 		show_header("ICMP:  ", "ICMP Header", ilen);
    382      0   stevel 		show_space();
    383      0   stevel 		(void) sprintf(get_line(0, 0), "Type = %d (%s)",
    384      0   stevel 		    icmp->icmp_type, pt);
    385      0   stevel 		if (*pc) {
    386      0   stevel 			(void) sprintf(get_line(0, 0), "Code = %d (%s)",
    387      0   stevel 			    icmp->icmp_code, pc);
    388      0   stevel 		} else {
    389      0   stevel 			(void) sprintf(get_line(0, 0), "Code = %d",
    390      0   stevel 			    icmp->icmp_code);
    391      0   stevel 		}
    392      0   stevel 		(void) sprintf(get_line(0, 0), "Checksum = %x",
    393      0   stevel 		    ntohs(icmp->icmp_cksum));
    394      0   stevel 
    395      0   stevel 		if (icmp->icmp_type == ICMP_UNREACH ||
    396      0   stevel 		    icmp->icmp_type == ICMP_REDIRECT) {
    397      0   stevel 			if (ilen > 28) {
    398      0   stevel 				show_space();
    399      0   stevel 				(void) sprintf(get_line(0, 0),
    400      0   stevel 				    "[ subject header follows ]");
    401      0   stevel 				show_space();
    402      0   stevel 				prot_nest_prefix = "ICMP:";
    403      0   stevel 				(void) interpret_ip(flags,
    404      0   stevel 				    (struct ip *)icmp->icmp_data, 28);
    405      0   stevel 				prot_nest_prefix = "";
    406      0   stevel 			}
    407      0   stevel 		} else if (icmp->icmp_type == ICMP_PARAMPROB) {
    408      0   stevel 			if (ilen > 28) {
    409      0   stevel 				show_space();
    410      0   stevel 				(void) sprintf(get_line(0, 0),
    411      0   stevel 				    "[ subject header follows ]");
    412      0   stevel 				show_space();
    413      0   stevel 				prot_nest_prefix = "ICMP:";
    414      0   stevel 				(void) interpret_ip(flags,
    415      0   stevel 				    (struct ip *)icmp->icmp_data, 28);
    416      0   stevel 				prot_nest_prefix = "";
    417      0   stevel 			}
    418      0   stevel 		} else if (icmp->icmp_type == ICMP_ROUTERADVERT) {
    419      0   stevel 			if (icmp->icmp_wpa == 2) {
    420      0   stevel 				int icmp_ra_len;
    421      0   stevel 
    422      0   stevel 				show_space();
    423      0   stevel 				icmp_ra_len = ICMP_MINLEN +
    424      0   stevel 				    num_rtr_addrs *
    425      0   stevel 					sizeof (struct icmp_ra_addr);
    426      0   stevel 				prot_nest_prefix = "";
    427      0   stevel 				if (ilen > icmp_ra_len) {
    428      0   stevel 					interpret_icmp_mip_ext(
    429      0   stevel 					    (uchar_t *)icmp + icmp_ra_len,
    430      0   stevel 					    ilen - icmp_ra_len);
    431      0   stevel 				}
    432      0   stevel 			}
    433      0   stevel 		}
    434      0   stevel 		show_space();
    435      0   stevel 	}
    436      0   stevel }
    437      0   stevel 
    438      0   stevel /*ARGSUSED*/
    439      0   stevel void
    440      0   stevel interpret_icmpv6(flags, icmp6, iplen, ilen)
    441      0   stevel 	int flags;
    442      0   stevel 	icmp6_t *icmp6;
    443      0   stevel 	int iplen, ilen;
    444      0   stevel {
    445      0   stevel 	char *pt, *pc;
    446      0   stevel 	char *line;
    447      0   stevel 	extern char *prot_nest_prefix;
    448      0   stevel 	char addrstr[INET6_ADDRSTRLEN];
    449      0   stevel 	char buff[2048];
    450      0   stevel 
    451      0   stevel 	if (ilen < ICMP6_MINLEN)
    452      0   stevel 		return;		/* incomplete header */
    453      0   stevel 
    454      0   stevel 	pt = "Unknown";
    455      0   stevel 	pc = "";
    456      0   stevel 
    457      0   stevel 	switch (icmp6->icmp6_type) {
    458      0   stevel 	case ICMP6_DST_UNREACH:
    459      0   stevel 		pt = "Destination unreachable";
    460      0   stevel 		switch (icmp6->icmp6_code) {
    461      0   stevel 		case ICMP6_DST_UNREACH_NOROUTE:
    462      0   stevel 			pc = "No route to destination";
    463      0   stevel 			break;
    464      0   stevel 		case ICMP6_DST_UNREACH_ADMIN:
    465      0   stevel 			pc = "Communication administratively prohibited";
    466      0   stevel 			break;
    467      0   stevel 		case ICMP6_DST_UNREACH_ADDR:
    468      0   stevel 			pc = "Address unreachable";
    469      0   stevel 			break;
    470      0   stevel 		case ICMP6_DST_UNREACH_NOPORT:
    471      0   stevel 			if (ilen >= ICMP6_MINLEN + IPV6_HDR_LEN +
    472      0   stevel 				sizeof (struct udphdr)) {
    473      0   stevel 
    474      0   stevel 				ip6_t *orig_ip6hdr = (ip6_t *)&icmp6[1];
    475      0   stevel 
    476      0   stevel 				switch (orig_ip6hdr->ip6_nxt) {
    477      0   stevel 				case IPPROTO_TCP: {
    478      0   stevel 					struct tcphdr *orig_thdr =
    479      0   stevel 					    (struct tcphdr *)&orig_ip6hdr[1];
    480      0   stevel 
    481      0   stevel 					(void) sprintf(buff, "TCP port %hu"
    482      0   stevel 					    " unreachable",
    483      0   stevel 					    ntohs(orig_thdr->th_dport));
    484      0   stevel 					pc = buff;
    485      0   stevel 					break;
    486      0   stevel 				    }
    487      0   stevel 				case IPPROTO_UDP: {
    488      0   stevel 					struct udphdr *orig_uhdr =
    489      0   stevel 					    (struct udphdr *)&orig_ip6hdr[1];
    490      0   stevel 
    491      0   stevel 					(void) sprintf(buff, "UDP port %hu"
    492      0   stevel 					    " unreachable",
    493      0   stevel 					    ntohs(orig_uhdr->uh_dport));
    494      0   stevel 					pc = buff;
    495      0   stevel 					break;
    496      0   stevel 				    }
    497      0   stevel 				default:
    498      0   stevel 					pc = "Port unreachable";
    499      0   stevel 					break;
    500      0   stevel 				}
    501      0   stevel 			} else {
    502      0   stevel 				pc = "Bad port";
    503      0   stevel 			}
    504      0   stevel 			break;
    505      0   stevel 		default:
    506      0   stevel 			break;
    507      0   stevel 		}
    508      0   stevel 		break;
    509      0   stevel 	case ICMP6_PACKET_TOO_BIG:
    510      0   stevel 		pt = "Packet too big";
    511      0   stevel 		break;
    512      0   stevel 	case ND_REDIRECT:
    513      0   stevel 		pt = "Redirect";
    514      0   stevel 		break;
    515      0   stevel 	case ICMP6_TIME_EXCEEDED:
    516      0   stevel 		pt = "Time exceeded";
    517      0   stevel 		switch (icmp6->icmp6_code) {
    518      0   stevel 		case ICMP6_TIME_EXCEED_TRANSIT:
    519      0   stevel 			pc = "Hop limit exceeded in transit";
    520      0   stevel 			break;
    521      0   stevel 		case ICMP6_TIME_EXCEED_REASSEMBLY:
    522      0   stevel 			pc = "Fragment reassembly time exceeded";
    523      0   stevel 			break;
    524      0   stevel 		default:
    525      0   stevel 			break;
    526      0   stevel 		}
    527      0   stevel 		break;
    528      0   stevel 	case ICMP6_PARAM_PROB:
    529      0   stevel 		pt = "Parameter problem";
    530      0   stevel 		switch (icmp6->icmp6_code) {
    531      0   stevel 		case ICMP6_PARAMPROB_HEADER:
    532      0   stevel 			pc = "Erroneous header field";
    533      0   stevel 			break;
    534      0   stevel 		case ICMP6_PARAMPROB_NEXTHEADER:
    535      0   stevel 			pc = "Unrecognized next header type";
    536      0   stevel 			break;
    537      0   stevel 		case ICMP6_PARAMPROB_OPTION:
    538      0   stevel 			pc = "Unrecognized IPv6 option";
    539      0   stevel 			break;
    540      0   stevel 		}
    541      0   stevel 		break;
    542      0   stevel 	case ICMP6_ECHO_REQUEST:
    543      0   stevel 		pt = "Echo request";
    544      0   stevel 		(void) sprintf(buff, "ID: %d Sequence number: %d",
    545      0   stevel 		    ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq));
    546      0   stevel 		pc = buff;
    547      0   stevel 		break;
    548      0   stevel 	case ICMP6_ECHO_REPLY:
    549      0   stevel 		pt = "Echo reply";
    550      0   stevel 		(void) sprintf(buff, "ID: %d Sequence number: %d",
    551      0   stevel 		    ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq));
    552      0   stevel 		pc = buff;
    553      0   stevel 		break;
    554      0   stevel 	case MLD_LISTENER_QUERY:
    555      0   stevel 		if (ilen == MLD_MINLEN)
    556      0   stevel 			pt = "Group membership query - MLDv1";
    557      0   stevel 		else if (ilen >= MLD_V2_QUERY_MINLEN)
    558      0   stevel 			pt = "Group membership query - MLDv2";
    559      0   stevel 		else
    560      0   stevel 			pt = "Unknown membership query";
    561      0   stevel 		break;
    562      0   stevel 	case MLD_LISTENER_REPORT:
    563      0   stevel 		pt = "Group membership report - MLDv1";
    564      0   stevel 		break;
    565      0   stevel 	case MLD_LISTENER_REDUCTION:
    566      0   stevel 		pt = "Group membership termination - MLDv1";
    567      0   stevel 		break;
    568      0   stevel 	case MLD_V2_LISTENER_REPORT:
    569      0   stevel 		pt = "Group membership report - MLDv2";
    570      0   stevel 		break;
    571      0   stevel 	case ND_ROUTER_SOLICIT:
    572      0   stevel 		pt = "Router solicitation";
    573      0   stevel 		break;
    574      0   stevel 	case ND_ROUTER_ADVERT:
    575      0   stevel 		pt = "Router advertisement";
    576      0   stevel 		break;
    577      0   stevel 	case ND_NEIGHBOR_SOLICIT:
    578      0   stevel 		pt = "Neighbor solicitation";
    579      0   stevel 		break;
    580      0   stevel 	case ND_NEIGHBOR_ADVERT:
    581      0   stevel 		pt = "Neighbor advertisement";
    582      0   stevel 		break;
    583      0   stevel 	default:
    584      0   stevel 		break;
    585      0   stevel 	}
    586      0   stevel 
    587      0   stevel 	if (flags & F_SUM) {
    588      0   stevel 		line = get_sum_line();
    589      0   stevel 		if (*pc)
    590      0   stevel 			(void) sprintf(line, "ICMPv6 %s (%s)", pt, pc);
    591      0   stevel 		else
    592      0   stevel 			(void) sprintf(line, "ICMPv6 %s", pt);
    593      0   stevel 	}
    594      0   stevel 
    595      0   stevel 	if (flags & F_DTAIL) {
    596      0   stevel 		show_header("ICMPv6:  ", "ICMPv6 Header", ilen);
    597      0   stevel 		show_space();
    598      0   stevel 		(void) sprintf(get_line(0, 0), "Type = %d (%s)",
    599      0   stevel 		    icmp6->icmp6_type, pt);
    600      0   stevel 		if (*pc)
    601      0   stevel 			(void) sprintf(get_line(0, 0), "Code = %d (%s)",
    602      0   stevel 			    icmp6->icmp6_code, pc);
    603      0   stevel 		else
    604      0   stevel 			(void) sprintf(get_line(0, 0), "Code = %d",
    605      0   stevel 			    icmp6->icmp6_code);
    606      0   stevel 		(void) sprintf(get_line(0, 0), "Checksum = %x",
    607      0   stevel 		    ntohs(icmp6->icmp6_cksum));
    608      0   stevel 
    609      0   stevel 		switch (icmp6->icmp6_type) {
    610      0   stevel 		case ICMP6_DST_UNREACH:
    611      0   stevel 			if (ilen > ICMP6_MINLEN + IPV6_HDR_LEN) {
    612      0   stevel 				show_space();
    613      0   stevel 				(void) sprintf(get_line(0, 0),
    614      0   stevel 				    "[ subject header follows ]");
    615      0   stevel 				show_space();
    616      0   stevel 				prot_nest_prefix = "ICMPv6:";
    617      0   stevel 				(void) interpret_ipv6(flags, (ip6_t *)&icmp6[1],
    618      0   stevel 				    ICMP6_MINLEN + IPV6_HDR_LEN);
    619      0   stevel 				prot_nest_prefix = "";
    620      0   stevel 			}
    621      0   stevel 			break;
    622      0   stevel 		case ICMP6_PACKET_TOO_BIG:
    623      0   stevel 			show_space();
    624      0   stevel 			(void) sprintf(get_line(0, 0),
    625   4564  wy83408 			    " Packet too big MTU = %d",
    626   4564  wy83408 			    ntohl(icmp6->icmp6_mtu));
    627      0   stevel 			show_space();
    628      0   stevel 			break;
    629      0   stevel 		case ND_REDIRECT: {
    630      0   stevel 			nd_redirect_t *rd = (nd_redirect_t *)icmp6;
    631      0   stevel 
    632      0   stevel 			(void) sprintf(get_line(0, 0), "Target address= %s",
    633      0   stevel 			    inet_ntop(AF_INET6, (char *)&rd->nd_rd_target,
    634      0   stevel 			    addrstr, INET6_ADDRSTRLEN));
    635      0   stevel 
    636      0   stevel 			(void) sprintf(get_line(0, 0),
    637      0   stevel 			    "Destination address= %s",
    638      0   stevel 			    inet_ntop(AF_INET6, (char *)&rd->nd_rd_dst,
    639      0   stevel 			    addrstr, INET6_ADDRSTRLEN));
    640      0   stevel 			show_space();
    641      0   stevel 			interpret_options((char *)icmp6 + sizeof (*rd),
    642      0   stevel 			    ilen - sizeof (*rd));
    643      0   stevel 			break;
    644      0   stevel 		}
    645      0   stevel 		case ND_NEIGHBOR_SOLICIT: {
    646      0   stevel 			struct nd_neighbor_solicit *ns;
    647      0   stevel 			if (ilen < sizeof (*ns))
    648      0   stevel 				break;
    649      0   stevel 			ns = (struct nd_neighbor_solicit *)icmp6;
    650      0   stevel 			(void) sprintf(get_line(0, 0), "Target node = %s, %s",
    651      0   stevel 			    inet_ntop(AF_INET6, (char *)&ns->nd_ns_target,
    652      0   stevel 			    addrstr, INET6_ADDRSTRLEN),
    653      0   stevel 			    addrtoname(AF_INET6, &ns->nd_ns_target));
    654      0   stevel 			show_space();
    655      0   stevel 			interpret_options((char *)icmp6 + sizeof (*ns),
    656      0   stevel 			    ilen - sizeof (*ns));
    657      0   stevel 			break;
    658      0   stevel 		}
    659      0   stevel 
    660      0   stevel 		case ND_NEIGHBOR_ADVERT: {
    661      0   stevel 			struct nd_neighbor_advert *na;
    662      0   stevel 
    663      0   stevel 			if (ilen < sizeof (*na))
    664      0   stevel 				break;
    665      0   stevel 			na = (struct nd_neighbor_advert *)icmp6;
    666      0   stevel 			(void) sprintf(get_line(0, 0), "Target node = %s, %s",
    667      0   stevel 			    inet_ntop(AF_INET6, (char *)&na->nd_na_target,
    668      0   stevel 			    addrstr, INET6_ADDRSTRLEN),
    669      0   stevel 			    addrtoname(AF_INET6, &na->nd_na_target));
    670      0   stevel 			(void) sprintf(get_line(0, 0),
    671      0   stevel 			    "Router flag: %s, Solicited flag: %s, "
    672      0   stevel 			    "Override flag: %s",
    673      0   stevel 			    na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER ?
    674      0   stevel 			    "SET" : "NOT SET",
    675      0   stevel 			    na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED ?
    676      0   stevel 			    "SET" : "NOT SET",
    677      0   stevel 			    na->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE ?
    678      0   stevel 			    "SET" : "NOT SET");
    679      0   stevel 
    680      0   stevel 			show_space();
    681      0   stevel 			interpret_options((char *)icmp6 + sizeof (*na),
    682      0   stevel 			    ilen - sizeof (*na));
    683      0   stevel 		}
    684      0   stevel 		break;
    685      0   stevel 
    686      0   stevel 		case ND_ROUTER_SOLICIT: {
    687      0   stevel 			if (ilen < sizeof (struct nd_router_solicit))
    688      0   stevel 				break;
    689      0   stevel 			interpret_options(
    690      0   stevel 			    (char *)icmp6 + sizeof (struct nd_router_solicit),
    691      0   stevel 			    ilen - sizeof (struct nd_router_solicit));
    692      0   stevel 			break;
    693      0   stevel 		}
    694      0   stevel 
    695      0   stevel 		case ND_ROUTER_ADVERT: {
    696      0   stevel 			struct nd_router_advert *ra;
    697      0   stevel 
    698      0   stevel 			if (ilen < sizeof (*ra))
    699      0   stevel 				break;
    700      0   stevel 			ra = (struct nd_router_advert *)icmp6;
    701      0   stevel 			(void) sprintf(get_line(0, 0),
    702      0   stevel 			    "Max hops= %d, Router lifetime= %d",
    703      0   stevel 			    ra->nd_ra_curhoplimit,
    704      0   stevel 			    ntohs(ra->nd_ra_router_lifetime));
    705      0   stevel 
    706      0   stevel 			(void) sprintf(get_line(0, 0),
    707      0   stevel 			    "Managed addr conf flag: %s, Other conf flag: %s",
    708      0   stevel 			    ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED ?
    709      0   stevel 			    "SET" : "NOT SET",
    710      0   stevel 			    ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER ?
    711      0   stevel 			    "SET" : "NOT SET");
    712      0   stevel 
    713      0   stevel 			(void) sprintf(get_line(0, 0),
    714      0   stevel 			    "Reachable time: %u, Reachable retrans time %u",
    715      0   stevel 			    ntohl(ra->nd_ra_reachable),
    716      0   stevel 			    ntohl(ra->nd_ra_retransmit));
    717      0   stevel 			show_space();
    718      0   stevel 
    719      0   stevel 			interpret_options((char *)icmp6 + sizeof (*ra),
    720      0   stevel 			    ilen - sizeof (*ra));
    721      0   stevel 			break;
    722      0   stevel 		}
    723      0   stevel 		case ICMP6_PARAM_PROB:
    724      0   stevel 			if (ilen < sizeof (*icmp6))
    725      0   stevel 				break;
    726      0   stevel 			(void) sprintf(get_line(0, 0), "Ptr = %u",
    727      0   stevel 			    ntohl(icmp6->icmp6_pptr));
    728      0   stevel 			show_space();
    729      0   stevel 			break;
    730      0   stevel 
    731      0   stevel 		case MLD_LISTENER_QUERY: {
    732      0   stevel 			struct mld_hdr *mldg = (struct mld_hdr *)icmp6;
    733      0   stevel 
    734      0   stevel 			if (ilen < MLD_MINLEN)
    735      0   stevel 				break;
    736      0   stevel 
    737      0   stevel 			if (ilen >= MLD_V2_QUERY_MINLEN) {
    738      0   stevel 				interpret_mldv2qry(icmp6, ilen);
    739      0   stevel 			} else {
    740      0   stevel 				(void) snprintf(get_line(0, 0),
    741      0   stevel 				    get_line_remain(),
    742      0   stevel 				    "Multicast address= %s",
    743      0   stevel 				    inet_ntop(AF_INET6, mldg->mld_addr.s6_addr,
    744      0   stevel 				    addrstr, INET6_ADDRSTRLEN));
    745      0   stevel 			}
    746      0   stevel 			show_space();
    747      0   stevel 			break;
    748      0   stevel 		}
    749      0   stevel 
    750      0   stevel 		case MLD_LISTENER_REPORT:
    751      0   stevel 		case MLD_LISTENER_REDUCTION: {
    752      0   stevel 			struct mld_hdr *mldg;
    753      0   stevel 
    754      0   stevel 			if (ilen < sizeof (*mldg))
    755      0   stevel 				break;
    756      0   stevel 			mldg = (struct mld_hdr *)icmp6;
    757      0   stevel 			(void) snprintf(get_line(0, 0), get_line_remain(),
    758      0   stevel 			    "Multicast address= %s", inet_ntop(AF_INET6,
    759      0   stevel 			    mldg->mld_addr.s6_addr, addrstr, INET6_ADDRSTRLEN));
    760      0   stevel 			show_space();
    761      0   stevel 			break;
    762      0   stevel 		}
    763      0   stevel 
    764      0   stevel 		case MLD_V2_LISTENER_REPORT: {
    765      0   stevel 			interpret_mldv2rpt(icmp6, ilen);
    766      0   stevel 			show_space();
    767      0   stevel 			break;
    768      0   stevel 		}
    769      0   stevel 
    770      0   stevel 		default:
    771      0   stevel 			break;
    772      0   stevel 		}
    773      0   stevel 	}
    774      0   stevel }
    775      0   stevel 
    776      0   stevel static void
    777      0   stevel interpret_options(optc, ilen)
    778      0   stevel 	char *optc;
    779      0   stevel 	int ilen;
    780      0   stevel {
    781      0   stevel #define	PREFIX_OPTION_LENGTH    4
    782      0   stevel #define	MTU_OPTION_LENGTH	1
    783      0   stevel 
    784      0   stevel #define	PREFIX_INFINITY		0xffffffffUL
    785      0   stevel 
    786      0   stevel 	struct nd_opt_hdr *opt;
    787      0   stevel 
    788      0   stevel 	for (; ilen >= sizeof (*opt); ) {
    789      0   stevel 		opt = (struct nd_opt_hdr *)optc;
    790      0   stevel 		if (opt->nd_opt_len == 0)
    791      0   stevel 			return;
    792      0   stevel 		switch (opt->nd_opt_type) {
    793      0   stevel 		case ND_OPT_SOURCE_LINKADDR:
    794      0   stevel 		case ND_OPT_TARGET_LINKADDR:
    795      0   stevel 		{
    796      0   stevel 			struct nd_opt_lla *lopt;
    797      0   stevel 			char	*buf, chbuf[128];
    798      0   stevel 			uint_t	addr_len;
    799      0   stevel 			int	i;
    800      0   stevel 
    801      0   stevel 			if (ilen < (int)opt->nd_opt_len * 8)
    802      0   stevel 				break;
    803      0   stevel 
    804      0   stevel 			buf = chbuf;
    805      0   stevel 
    806      0   stevel 			lopt = (struct nd_opt_lla *)opt;
    807      0   stevel 			if (lopt->nd_opt_lla_type == ND_OPT_SOURCE_LINKADDR) {
    808      0   stevel 				(void) sprintf(get_line(0, 0),
    809      0   stevel 				    "+++ ICMPv6 Source LL Addr option +++");
    810      0   stevel 			} else {
    811      0   stevel 				(void) sprintf(get_line(0, 0),
    812      0   stevel 				    "+++ ICMPv6 Target LL Addr option +++");
    813      0   stevel 			}
    814      0   stevel 
    815      0   stevel 			/*
    816      0   stevel 			 * The option length is in 8 octet units, and
    817      0   stevel 			 * includes the first two bytes (the type and
    818      0   stevel 			 * lenght fields) of the option.
    819      0   stevel 			 */
    820      0   stevel 			addr_len = lopt->nd_opt_lla_len * 8 - 2;
    821      0   stevel 			for (i = 0; i < addr_len; i++) {
    822      0   stevel 				snprintf(buf, sizeof (chbuf) - (buf - chbuf),
    823      0   stevel 				    "%x:", lopt->nd_opt_lla_hdw_addr[i]);
    824      0   stevel 				buf += strlen(buf);
    825      0   stevel 				if (buf >= &chbuf[sizeof (chbuf)]) {
    826      0   stevel 					buf = NULL;
    827      0   stevel 					chbuf[sizeof (chbuf) -
    828      0   stevel 					    strlen("<Too Long>)")] = '\0';
    829      0   stevel 					(void) strlcat(chbuf, "<Too Long>",
    830      0   stevel 						sizeof (chbuf));
    831      0   stevel 					break;
    832      0   stevel 				}
    833      0   stevel 			}
    834      0   stevel 			if (buf)
    835      0   stevel 				*(buf - 1) = '\0'; /* Erase last colon */
    836      0   stevel 			(void) sprintf(get_line(0, 0),
    837      0   stevel 			    "Link Layer address: %s", chbuf);
    838      0   stevel 			show_space();
    839      0   stevel 			break;
    840      0   stevel 		}
    841      0   stevel 		case ND_OPT_MTU: {
    842      0   stevel 			struct nd_opt_mtu *mopt;
    843      0   stevel 			if (opt->nd_opt_len != MTU_OPTION_LENGTH ||
    844      0   stevel 			    ilen < sizeof (struct nd_opt_mtu))
    845      0   stevel 				break;
    846      0   stevel 			(void) sprintf(get_line(0, 0),
    847      0   stevel 			    "+++ ICMPv6 MTU option +++");
    848      0   stevel 			mopt = (struct nd_opt_mtu *)opt;
    849      0   stevel 			(void) sprintf(get_line(0, 0),
    850  10495     Erik 			    "MTU = %u ", ntohl(mopt->nd_opt_mtu_mtu));
    851      0   stevel 			show_space();
    852      0   stevel 			break;
    853      0   stevel 		}
    854      0   stevel 		case ND_OPT_PREFIX_INFORMATION: {
    855      0   stevel 			struct nd_opt_prefix_info *popt;
    856      0   stevel 			char validstr[30];
    857      0   stevel 			char preferredstr[30];
    858      0   stevel 			char prefixstr[INET6_ADDRSTRLEN];
    859      0   stevel 
    860      0   stevel 			if (opt->nd_opt_len != PREFIX_OPTION_LENGTH ||
    861      0   stevel 			    ilen < sizeof (struct nd_opt_prefix_info))
    862      0   stevel 				break;
    863      0   stevel 			popt = (struct nd_opt_prefix_info *)opt;
    864      0   stevel 			(void) sprintf(get_line(0, 0),
    865      0   stevel 			    "+++ ICMPv6 Prefix option +++");
    866      0   stevel 			(void) sprintf(get_line(0, 0),
    867      0   stevel 			    "Prefix length = %d ", popt->nd_opt_pi_prefix_len);
    868      0   stevel 			(void) sprintf(get_line(0, 0),
    869      0   stevel 			    "Onlink flag: %s, Autonomous addr conf flag: %s",
    870      0   stevel 			    popt->nd_opt_pi_flags_reserved &
    871      0   stevel 			    ND_OPT_PI_FLAG_ONLINK ? "SET" : "NOT SET",
    872      0   stevel 			    popt->nd_opt_pi_flags_reserved &
    873      0   stevel 			    ND_OPT_PI_FLAG_AUTO ? "SET" : "NOT SET");
    874      0   stevel 
    875      0   stevel 			if (ntohl(popt->nd_opt_pi_valid_time) ==
    876      0   stevel 			    PREFIX_INFINITY)
    877      0   stevel 				sprintf(validstr, "INFINITY");
    878      0   stevel 			else
    879      0   stevel 				sprintf(validstr, "%lu",
    880      0   stevel 				    ntohl(popt->nd_opt_pi_valid_time));
    881      0   stevel 
    882      0   stevel 			if (ntohl(popt->nd_opt_pi_preferred_time) ==
    883      0   stevel 			    PREFIX_INFINITY)
    884      0   stevel 				sprintf(preferredstr, "INFINITY");
    885      0   stevel 			else
    886      0   stevel 				sprintf(preferredstr, "%lu",
    887      0   stevel 				    ntohl(popt->nd_opt_pi_preferred_time));
    888      0   stevel 
    889      0   stevel 			(void) sprintf(get_line(0, 0),
    890      0   stevel 			    "Valid Lifetime %s, Preferred Lifetime %s",
    891      0   stevel 			    validstr, preferredstr);
    892      0   stevel 			(void) sprintf(get_line(0, 0), "Prefix %s",
    893      0   stevel 			    inet_ntop(AF_INET6,
    894      0   stevel 			    (char *)&popt->nd_opt_pi_prefix, prefixstr,
    895      0   stevel 			    INET6_ADDRSTRLEN));
    896      0   stevel 			show_space();
    897      0   stevel 		}
    898      0   stevel 		default:
    899      0   stevel 			break;
    900      0   stevel 		}
    901      0   stevel 		optc += opt->nd_opt_len * 8;
    902      0   stevel 		ilen -= opt->nd_opt_len * 8;
    903      0   stevel 	}
    904      0   stevel }
    905      0   stevel 
    906      0   stevel static void
    907      0   stevel interpret_mldv2qry(icmp6_t *icmp6, int ilen)
    908      0   stevel {
    909      0   stevel 	mld2q_t *qry;
    910      0   stevel 	in6_addr_t *src;
    911      0   stevel 	int rem = ilen;
    912      0   stevel 	int srccnt;
    913      0   stevel 	char addrstr[INET6_ADDRSTRLEN];
    914      0   stevel 
    915      0   stevel 	if (ilen < sizeof (*qry)) {
    916      0   stevel 		(void) snprintf(get_line(0, 0), get_line_remain(),
    917      0   stevel 		    "Malformed MLD Query");
    918      0   stevel 		return;
    919      0   stevel 	}
    920      0   stevel 	qry = (mld2q_t *)icmp6;
    921      0   stevel 	rem -= sizeof (*qry);
    922      0   stevel 	srccnt = ntohs(qry->mld2q_numsrc);
    923      0   stevel 	(void) snprintf(get_line(0, 0), get_line_remain(),
    924      0   stevel 	    "Multicast address= %s", inet_ntop(AF_INET6,
    925      0   stevel 	    &qry->mld2q_addr.s6_addr, addrstr, INET6_ADDRSTRLEN));
    926      0   stevel 	(void) snprintf(get_line(0, 0), get_line_remain(),
    927      0   stevel 	    "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es");
    928      0   stevel 
    929      0   stevel 	src = (in6_addr_t *)&qry[1];
    930      0   stevel 	while (srccnt > 0 && rem >= sizeof (*src)) {
    931      0   stevel 		rem -= sizeof (*src);
    932      0   stevel 
    933      0   stevel 		(void) snprintf(get_line(0, 0), get_line_remain(), "    %s",
    934      0   stevel 		    inet_ntop(AF_INET6, src, addrstr, INET6_ADDRSTRLEN));
    935      0   stevel 
    936      0   stevel 		srccnt--;
    937      0   stevel 		src++;
    938      0   stevel 	}
    939      0   stevel }
    940      0   stevel 
    941      0   stevel #define	MAX_MLDV2_REPORT_TYPE	6
    942      0   stevel 
    943      0   stevel const char *mldv2rpt_types[] = {
    944      0   stevel 	"<unknown>",
    945      0   stevel 	"MODE_IS_INCLUDE",
    946      0   stevel 	"MODE_IS_EXCLUDE",
    947      0   stevel 	"CHANGE_TO_INCLUDE",
    948      0   stevel 	"CHANGE_TO_EXCLUDE",
    949      0   stevel 	"ALLOW_NEW_SOURCES",
    950      0   stevel 	"BLOCK_OLD_SOURCES",
    951      0   stevel };
    952      0   stevel 
    953      0   stevel static void
    954      0   stevel interpret_mldv2rpt(icmp6_t *icmp6, int ilen)
    955      0   stevel {
    956      0   stevel 	mld2r_t *rpt;
    957      0   stevel 	mld2mar_t *mar;
    958      0   stevel 	in6_addr_t *src;
    959      0   stevel 	int rem = ilen, auxlen;
    960      0   stevel 	uint16_t marcnt, srccnt;
    961      0   stevel 	char addrstr[INET6_ADDRSTRLEN];
    962      0   stevel 
    963      0   stevel 	if (ilen < sizeof (*rpt)) {
    964      0   stevel 		(void) snprintf(get_line(0, 0), get_line_remain(),
    965      0   stevel 		    "Malformed MLDv2 Report");
    966      0   stevel 		return;
    967      0   stevel 	}
    968      0   stevel 	rpt = (mld2r_t *)icmp6;
    969      0   stevel 	mar = (mld2mar_t *)&rpt[1];
    970      0   stevel 	marcnt = ntohs(rpt->mld2r_nummar);
    971      0   stevel 	(void) snprintf(get_line(0, 0), get_line_remain(),
    972      0   stevel 	    "%d Multicast Address Record%s:", marcnt, (marcnt == 1) ? "" : "s");
    973      0   stevel 	rem -= sizeof (*rpt);
    974      0   stevel 	while (marcnt > 0 && rem >= sizeof (*mar)) {
    975      0   stevel 		rem -= sizeof (*mar);
    976      0   stevel 
    977      0   stevel 		(void) snprintf(get_line(0, 0), get_line_remain(),
    978      0   stevel 		    "Multicast address= %s  type = %s", inet_ntop(AF_INET6,
    979      0   stevel 		    &mar->mld2mar_group.s6_addr, addrstr, INET6_ADDRSTRLEN),
    980      0   stevel 		    (mar->mld2mar_type > MAX_MLDV2_REPORT_TYPE) ?
    981      0   stevel 		    "<unknown>" : mldv2rpt_types[mar->mld2mar_type]);
    982      0   stevel 		srccnt = ntohs(mar->mld2mar_numsrc);
    983      0   stevel 		(void) snprintf(get_line(0, 0), get_line_remain(),
    984      0   stevel 		    "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es");
    985      0   stevel 
    986      0   stevel 		src = (in6_addr_t *)&mar[1];
    987      0   stevel 		while (srccnt > 0 && rem >= sizeof (*src)) {
    988      0   stevel 			rem -= sizeof (*src);
    989      0   stevel 
    990      0   stevel 			(void) snprintf(get_line(0, 0), get_line_remain(),
    991      0   stevel 			    "    %s", inet_ntop(AF_INET6, src, addrstr,
    992      0   stevel 			    INET6_ADDRSTRLEN));
    993      0   stevel 
    994      0   stevel 			srccnt--;
    995      0   stevel 			src++;
    996      0   stevel 		}
    997      0   stevel 
    998      0   stevel 		marcnt--;
    999      0   stevel 		auxlen = mar->mld2mar_auxlen * 4;
   1000      0   stevel 		rem -= auxlen;
   1001      0   stevel 		mar = (mld2mar_t *)((uint8_t *)src + auxlen);
   1002      0   stevel 	}
   1003      0   stevel }
   1004