10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*4564Swy83408 * Common Development and Distribution License (the "License"). 6*4564Swy83408 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*4564Swy83408 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <stdio.h> 290Sstevel@tonic-gate #include <string.h> 300Sstevel@tonic-gate #include <sys/types.h> 310Sstevel@tonic-gate #include <sys/socket.h> 320Sstevel@tonic-gate #include <net/if.h> 330Sstevel@tonic-gate #include <sys/stropts.h> 340Sstevel@tonic-gate #include <sys/sysmacros.h> 350Sstevel@tonic-gate #include <netinet/in_systm.h> 360Sstevel@tonic-gate #include <netinet/in.h> 370Sstevel@tonic-gate #include <netinet/ip.h> 380Sstevel@tonic-gate #include <netinet/ip_icmp.h> 390Sstevel@tonic-gate #include <netinet/udp.h> 400Sstevel@tonic-gate #include <netinet/tcp.h> 410Sstevel@tonic-gate #include <netinet/icmp6.h> 420Sstevel@tonic-gate #include <netinet/ip6.h> 430Sstevel@tonic-gate #include <inet/ip.h> 440Sstevel@tonic-gate #include <inet/ip6.h> 450Sstevel@tonic-gate #include <arpa/inet.h> 460Sstevel@tonic-gate #include <netdb.h> 470Sstevel@tonic-gate #include "snoop.h" 480Sstevel@tonic-gate #include "snoop_mip.h" 490Sstevel@tonic-gate 500Sstevel@tonic-gate static void interpret_options(char *, int); 510Sstevel@tonic-gate static void interpret_mldv2qry(icmp6_t *, int); 520Sstevel@tonic-gate static void interpret_mldv2rpt(icmp6_t *, int); 530Sstevel@tonic-gate 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* Mobile-IP routines from snoop_mip.c */ 560Sstevel@tonic-gate extern void interpret_icmp_mip_ext(uchar_t *, int); 570Sstevel@tonic-gate extern const char *get_mip_adv_desc(uint8_t); 580Sstevel@tonic-gate 590Sstevel@tonic-gate /* Router advertisement message structure. */ 600Sstevel@tonic-gate struct icmp_ra_addr { 610Sstevel@tonic-gate uint32_t addr; 620Sstevel@tonic-gate uint32_t preference; 630Sstevel@tonic-gate }; 640Sstevel@tonic-gate 650Sstevel@tonic-gate /*ARGSUSED*/ 660Sstevel@tonic-gate void 670Sstevel@tonic-gate interpret_icmp(int flags, struct icmp *icmp, int iplen, int ilen) 680Sstevel@tonic-gate { 690Sstevel@tonic-gate char *pt, *pc, *px; 700Sstevel@tonic-gate char *line; 710Sstevel@tonic-gate char buff[67627]; /* Router adv. can have 256 routers .... */ 720Sstevel@tonic-gate /* Each router has a name 256 char long .. */ 730Sstevel@tonic-gate char extbuff[MAXHOSTNAMELEN + 1]; 740Sstevel@tonic-gate struct udphdr *orig_uhdr; 750Sstevel@tonic-gate int num_rtr_addrs = 0; 760Sstevel@tonic-gate extern char *prot_nest_prefix; 770Sstevel@tonic-gate 780Sstevel@tonic-gate if (ilen < ICMP_MINLEN) 790Sstevel@tonic-gate return; /* incomplete header */ 800Sstevel@tonic-gate 810Sstevel@tonic-gate pt = "Unknown"; 820Sstevel@tonic-gate pc = ""; 830Sstevel@tonic-gate px = ""; 840Sstevel@tonic-gate 850Sstevel@tonic-gate switch (icmp->icmp_type) { 860Sstevel@tonic-gate case ICMP_ECHOREPLY: 870Sstevel@tonic-gate pt = "Echo reply"; 880Sstevel@tonic-gate (void) sprintf(buff, "ID: %d Sequence number: %d", 890Sstevel@tonic-gate ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq)); 900Sstevel@tonic-gate pc = buff; 910Sstevel@tonic-gate break; 920Sstevel@tonic-gate case ICMP_UNREACH: 930Sstevel@tonic-gate pt = "Destination unreachable"; 940Sstevel@tonic-gate switch (icmp->icmp_code) { 950Sstevel@tonic-gate case ICMP_UNREACH_NET: 960Sstevel@tonic-gate if (ilen >= ICMP_ADVLENMIN) { 970Sstevel@tonic-gate (void) sprintf(buff, "Net %s unreachable", 980Sstevel@tonic-gate addrtoname(AF_INET, 990Sstevel@tonic-gate &icmp->icmp_ip.ip_dst)); 1000Sstevel@tonic-gate pc = buff; 1010Sstevel@tonic-gate } else { 1020Sstevel@tonic-gate pc = "Bad net"; 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate break; 1050Sstevel@tonic-gate case ICMP_UNREACH_HOST: 1060Sstevel@tonic-gate if (ilen >= ICMP_ADVLENMIN) { 1070Sstevel@tonic-gate (void) sprintf(buff, "Host %s unreachable", 1080Sstevel@tonic-gate addrtoname(AF_INET, 1090Sstevel@tonic-gate &icmp->icmp_ip.ip_dst)); 1100Sstevel@tonic-gate pc = buff; 1110Sstevel@tonic-gate } else { 1120Sstevel@tonic-gate pc = "Bad host"; 1130Sstevel@tonic-gate } 1140Sstevel@tonic-gate break; 1150Sstevel@tonic-gate case ICMP_UNREACH_PROTOCOL: 1160Sstevel@tonic-gate if (ilen >= ICMP_ADVLENMIN) { 1170Sstevel@tonic-gate (void) sprintf(buff, "Bad protocol %d", 1180Sstevel@tonic-gate icmp->icmp_ip.ip_p); 1190Sstevel@tonic-gate pc = buff; 1200Sstevel@tonic-gate } else { 1210Sstevel@tonic-gate pc = "Bad protocol"; 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate break; 1240Sstevel@tonic-gate case ICMP_UNREACH_PORT: 1250Sstevel@tonic-gate if (ilen >= ICMP_ADVLENMIN) { 1260Sstevel@tonic-gate orig_uhdr = (struct udphdr *)((uchar_t *)icmp + 1270Sstevel@tonic-gate ICMP_MINLEN + icmp->icmp_ip.ip_hl * 4); 1280Sstevel@tonic-gate switch (icmp->icmp_ip.ip_p) { 1290Sstevel@tonic-gate case IPPROTO_TCP: 1300Sstevel@tonic-gate (void) sprintf(buff, "TCP port %d" 1310Sstevel@tonic-gate " unreachable", 1320Sstevel@tonic-gate ntohs(orig_uhdr->uh_dport)); 1330Sstevel@tonic-gate pc = buff; 1340Sstevel@tonic-gate break; 1350Sstevel@tonic-gate case IPPROTO_UDP: 1360Sstevel@tonic-gate (void) sprintf(buff, "UDP port %d" 1370Sstevel@tonic-gate " unreachable", 1380Sstevel@tonic-gate ntohs(orig_uhdr->uh_dport)); 1390Sstevel@tonic-gate pc = buff; 1400Sstevel@tonic-gate break; 1410Sstevel@tonic-gate default: 1420Sstevel@tonic-gate pc = "Port unreachable"; 1430Sstevel@tonic-gate break; 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate } else { 1460Sstevel@tonic-gate pc = "Bad port"; 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate break; 1490Sstevel@tonic-gate case ICMP_UNREACH_NEEDFRAG: 1500Sstevel@tonic-gate if (ntohs(icmp->icmp_nextmtu) != 0) { 1510Sstevel@tonic-gate (void) sprintf(buff, "Needed to fragment:" 1520Sstevel@tonic-gate " next hop MTU = %d", 1530Sstevel@tonic-gate ntohs(icmp->icmp_nextmtu)); 1540Sstevel@tonic-gate pc = buff; 1550Sstevel@tonic-gate } else { 1560Sstevel@tonic-gate pc = "Needed to fragment"; 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate break; 1590Sstevel@tonic-gate case ICMP_UNREACH_SRCFAIL: 1600Sstevel@tonic-gate pc = "Source route failed"; 1610Sstevel@tonic-gate break; 1620Sstevel@tonic-gate case ICMP_UNREACH_NET_UNKNOWN: 1630Sstevel@tonic-gate pc = "Unknown network"; 1640Sstevel@tonic-gate break; 1650Sstevel@tonic-gate case ICMP_UNREACH_HOST_UNKNOWN: 1660Sstevel@tonic-gate pc = "Unknown host"; 1670Sstevel@tonic-gate break; 1680Sstevel@tonic-gate case ICMP_UNREACH_ISOLATED: 1690Sstevel@tonic-gate pc = "Source host isolated"; 1700Sstevel@tonic-gate break; 1710Sstevel@tonic-gate case ICMP_UNREACH_NET_PROHIB: 1720Sstevel@tonic-gate pc = "Net administratively prohibited"; 1730Sstevel@tonic-gate break; 1740Sstevel@tonic-gate case ICMP_UNREACH_HOST_PROHIB: 1750Sstevel@tonic-gate pc = "Host administratively prohibited"; 1760Sstevel@tonic-gate break; 1770Sstevel@tonic-gate case ICMP_UNREACH_TOSNET: 1780Sstevel@tonic-gate pc = "Net unreachable for this TOS"; 1790Sstevel@tonic-gate break; 1800Sstevel@tonic-gate case ICMP_UNREACH_TOSHOST: 1810Sstevel@tonic-gate pc = "Host unreachable for this TOS"; 1820Sstevel@tonic-gate break; 1830Sstevel@tonic-gate case ICMP_UNREACH_FILTER_PROHIB: 1840Sstevel@tonic-gate pc = "Communication administratively prohibited"; 1850Sstevel@tonic-gate break; 1860Sstevel@tonic-gate case ICMP_UNREACH_HOST_PRECEDENCE: 1870Sstevel@tonic-gate pc = "Host precedence violation"; 1880Sstevel@tonic-gate break; 1890Sstevel@tonic-gate case ICMP_UNREACH_PRECEDENCE_CUTOFF: 1900Sstevel@tonic-gate pc = "Precedence cutoff in effect"; 1910Sstevel@tonic-gate break; 1920Sstevel@tonic-gate default: 1930Sstevel@tonic-gate break; 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate break; 1960Sstevel@tonic-gate case ICMP_SOURCEQUENCH: 1970Sstevel@tonic-gate pt = "Packet lost, slow down"; 1980Sstevel@tonic-gate break; 1990Sstevel@tonic-gate case ICMP_REDIRECT: 2000Sstevel@tonic-gate pt = "Redirect"; 2010Sstevel@tonic-gate switch (icmp->icmp_code) { 2020Sstevel@tonic-gate case ICMP_REDIRECT_NET: 2030Sstevel@tonic-gate pc = "for network"; 2040Sstevel@tonic-gate break; 2050Sstevel@tonic-gate case ICMP_REDIRECT_HOST: 2060Sstevel@tonic-gate pc = "for host"; 2070Sstevel@tonic-gate break; 2080Sstevel@tonic-gate case ICMP_REDIRECT_TOSNET: 2090Sstevel@tonic-gate pc = "for tos and net"; 2100Sstevel@tonic-gate break; 2110Sstevel@tonic-gate case ICMP_REDIRECT_TOSHOST: 2120Sstevel@tonic-gate pc = "for tos and host"; 2130Sstevel@tonic-gate break; 2140Sstevel@tonic-gate default: 2150Sstevel@tonic-gate break; 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate (void) sprintf(buff, "%s %s to %s", 2180Sstevel@tonic-gate pc, addrtoname(AF_INET, &icmp->icmp_ip.ip_dst), 2190Sstevel@tonic-gate addrtoname(AF_INET, &icmp->icmp_gwaddr)); 2200Sstevel@tonic-gate pc = buff; 2210Sstevel@tonic-gate break; 2220Sstevel@tonic-gate case ICMP_ECHO: 2230Sstevel@tonic-gate pt = "Echo request"; 2240Sstevel@tonic-gate (void) sprintf(buff, "ID: %d Sequence number: %d", 2250Sstevel@tonic-gate ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq)); 2260Sstevel@tonic-gate pc = buff; 2270Sstevel@tonic-gate break; 2280Sstevel@tonic-gate case ICMP_ROUTERADVERT: 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate #define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs 2310Sstevel@tonic-gate #define icmp_wpa icmp_hun.ih_rtradv.irt_wpa 2320Sstevel@tonic-gate #define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate pt = "Router advertisement"; 2350Sstevel@tonic-gate (void) sprintf(buff, "Lifetime %ds [%d]:", 2360Sstevel@tonic-gate ntohs(icmp->icmp_lifetime), icmp->icmp_num_addrs); 2370Sstevel@tonic-gate if (icmp->icmp_wpa == 2) { 2380Sstevel@tonic-gate struct icmp_ra_addr *ra; 2390Sstevel@tonic-gate char ra_buf[MAXHOSTNAMELEN + 32]; 2400Sstevel@tonic-gate char ra_ext_buf[50]; 2410Sstevel@tonic-gate struct in_addr sin; 2420Sstevel@tonic-gate int icmp_ra_len; 2430Sstevel@tonic-gate int i; 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate /* Cannot trust anything from the network... */ 2460Sstevel@tonic-gate num_rtr_addrs = MIN((ilen - ICMP_MINLEN) / 8, 2470Sstevel@tonic-gate icmp->icmp_num_addrs); 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate ra = (struct icmp_ra_addr *)icmp->icmp_data; 2500Sstevel@tonic-gate for (i = 0; i < num_rtr_addrs; i++) { 2510Sstevel@tonic-gate sin.s_addr = ra->addr; 2520Sstevel@tonic-gate (void) snprintf(ra_buf, sizeof (ra_buf), 2530Sstevel@tonic-gate " {%s %u}", 2540Sstevel@tonic-gate addrtoname(AF_INET, &sin), 2550Sstevel@tonic-gate ntohl(ra->preference)); 2560Sstevel@tonic-gate if (strlcat(buff, ra_buf, sizeof (buff)) >= 2570Sstevel@tonic-gate sizeof (buff)) { 2580Sstevel@tonic-gate buff[sizeof (buff) - 2590Sstevel@tonic-gate strlen("<Too Long>)")] = '\0'; 2600Sstevel@tonic-gate (void) strlcat(buff, "<Too Long>", 2610Sstevel@tonic-gate sizeof (buff)); 2620Sstevel@tonic-gate break; 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate ra++; 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate icmp_ra_len = ICMP_MINLEN + num_rtr_addrs * 2680Sstevel@tonic-gate sizeof (struct icmp_ra_addr); 2690Sstevel@tonic-gate if (ilen > icmp_ra_len) { 2700Sstevel@tonic-gate int curr_len = ilen - icmp_ra_len; 2710Sstevel@tonic-gate int ocurr_len; 2720Sstevel@tonic-gate exthdr_t *exthdr = (exthdr_t *)ra; 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate extbuff[0] = '\0'; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate while (curr_len > 0) { 2770Sstevel@tonic-gate /* Append Mobile-IP description */ 2780Sstevel@tonic-gate (void) snprintf(ra_ext_buf, 2790Sstevel@tonic-gate sizeof (ra_ext_buf), ", %s", 2800Sstevel@tonic-gate get_mip_adv_desc(exthdr->type)); 2810Sstevel@tonic-gate (void) strlcat(extbuff, ra_ext_buf, 2820Sstevel@tonic-gate sizeof (extbuff)); 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate /* Special case for padding */ 2850Sstevel@tonic-gate if (exthdr->type == 2860Sstevel@tonic-gate ICMP_ADV_MSG_PADDING_EXT) { 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate curr_len--; 2890Sstevel@tonic-gate exthdr = (exthdr_t *) 2900Sstevel@tonic-gate ((char *)exthdr + 1); 2910Sstevel@tonic-gate continue; 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate /* else normal extension */ 2950Sstevel@tonic-gate ocurr_len = curr_len; 2960Sstevel@tonic-gate curr_len -= sizeof (*exthdr) + 2970Sstevel@tonic-gate exthdr->length; 2980Sstevel@tonic-gate /* detect bad length */ 2990Sstevel@tonic-gate if (ocurr_len < curr_len) 3000Sstevel@tonic-gate break; 3010Sstevel@tonic-gate exthdr = (exthdr_t *) 3020Sstevel@tonic-gate ((char *)exthdr + 3030Sstevel@tonic-gate sizeof (*exthdr) + 3040Sstevel@tonic-gate exthdr->length); 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate px = extbuff; 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate pc = buff; 3090Sstevel@tonic-gate } 3100Sstevel@tonic-gate break; 3110Sstevel@tonic-gate case ICMP_ROUTERSOLICIT: 3120Sstevel@tonic-gate pt = "Router solicitation"; 3130Sstevel@tonic-gate break; 3140Sstevel@tonic-gate case ICMP_TIMXCEED: 3150Sstevel@tonic-gate pt = "Time exceeded"; 3160Sstevel@tonic-gate switch (icmp->icmp_code) { 3170Sstevel@tonic-gate case ICMP_TIMXCEED_INTRANS: 3180Sstevel@tonic-gate pc = "in transit"; 3190Sstevel@tonic-gate break; 3200Sstevel@tonic-gate case ICMP_TIMXCEED_REASS: 3210Sstevel@tonic-gate pc = "in reassembly"; 3220Sstevel@tonic-gate break; 3230Sstevel@tonic-gate default: 3240Sstevel@tonic-gate break; 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate break; 3270Sstevel@tonic-gate case ICMP_PARAMPROB: 3280Sstevel@tonic-gate pt = "IP parameter problem"; 3290Sstevel@tonic-gate switch (icmp->icmp_code) { 3300Sstevel@tonic-gate case ICMP_PARAMPROB_OPTABSENT: 3310Sstevel@tonic-gate pc = "Required option missing"; 3320Sstevel@tonic-gate break; 3330Sstevel@tonic-gate case ICMP_PARAMPROB_BADLENGTH: 3340Sstevel@tonic-gate pc = "Bad length"; 3350Sstevel@tonic-gate break; 3360Sstevel@tonic-gate case 0: /* Should this be the default? */ 3370Sstevel@tonic-gate (void) sprintf(buff, "Problem at octet %d\n", 3380Sstevel@tonic-gate icmp->icmp_pptr); 3390Sstevel@tonic-gate pc = buff; 3400Sstevel@tonic-gate default: 3410Sstevel@tonic-gate break; 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate break; 3440Sstevel@tonic-gate case ICMP_TSTAMP: 3450Sstevel@tonic-gate pt = "Timestamp request"; 3460Sstevel@tonic-gate break; 3470Sstevel@tonic-gate case ICMP_TSTAMPREPLY: 3480Sstevel@tonic-gate pt = "Timestamp reply"; 3490Sstevel@tonic-gate break; 3500Sstevel@tonic-gate case ICMP_IREQ: 3510Sstevel@tonic-gate pt = "Information request"; 3520Sstevel@tonic-gate break; 3530Sstevel@tonic-gate case ICMP_IREQREPLY: 3540Sstevel@tonic-gate pt = "Information reply"; 3550Sstevel@tonic-gate break; 3560Sstevel@tonic-gate case ICMP_MASKREQ: 3570Sstevel@tonic-gate pt = "Address mask request"; 3580Sstevel@tonic-gate break; 3590Sstevel@tonic-gate case ICMP_MASKREPLY: 3600Sstevel@tonic-gate pt = "Address mask reply"; 3610Sstevel@tonic-gate (void) sprintf(buff, "Mask = 0x%x", ntohl(icmp->icmp_mask)); 3620Sstevel@tonic-gate pc = buff; 3630Sstevel@tonic-gate break; 3640Sstevel@tonic-gate default: 3650Sstevel@tonic-gate break; 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate if (flags & F_SUM) { 3690Sstevel@tonic-gate line = get_sum_line(); 3700Sstevel@tonic-gate if (*pc) { 3710Sstevel@tonic-gate if (*px) { 3720Sstevel@tonic-gate (void) sprintf(line, "ICMP %s (%s)%s", 3730Sstevel@tonic-gate pt, pc, px); 3740Sstevel@tonic-gate } else { 3750Sstevel@tonic-gate (void) sprintf(line, "ICMP %s (%s)", pt, pc); 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate } else { 3780Sstevel@tonic-gate (void) sprintf(line, "ICMP %s", pt); 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate if (flags & F_DTAIL) { 3830Sstevel@tonic-gate show_header("ICMP: ", "ICMP Header", ilen); 3840Sstevel@tonic-gate show_space(); 3850Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Type = %d (%s)", 3860Sstevel@tonic-gate icmp->icmp_type, pt); 3870Sstevel@tonic-gate if (*pc) { 3880Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Code = %d (%s)", 3890Sstevel@tonic-gate icmp->icmp_code, pc); 3900Sstevel@tonic-gate } else { 3910Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Code = %d", 3920Sstevel@tonic-gate icmp->icmp_code); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Checksum = %x", 3950Sstevel@tonic-gate ntohs(icmp->icmp_cksum)); 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate if (icmp->icmp_type == ICMP_UNREACH || 3980Sstevel@tonic-gate icmp->icmp_type == ICMP_REDIRECT) { 3990Sstevel@tonic-gate if (ilen > 28) { 4000Sstevel@tonic-gate show_space(); 4010Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 4020Sstevel@tonic-gate "[ subject header follows ]"); 4030Sstevel@tonic-gate show_space(); 4040Sstevel@tonic-gate prot_nest_prefix = "ICMP:"; 4050Sstevel@tonic-gate (void) interpret_ip(flags, 4060Sstevel@tonic-gate (struct ip *)icmp->icmp_data, 28); 4070Sstevel@tonic-gate prot_nest_prefix = ""; 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate } else if (icmp->icmp_type == ICMP_PARAMPROB) { 4100Sstevel@tonic-gate if (ilen > 28) { 4110Sstevel@tonic-gate show_space(); 4120Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 4130Sstevel@tonic-gate "[ subject header follows ]"); 4140Sstevel@tonic-gate show_space(); 4150Sstevel@tonic-gate prot_nest_prefix = "ICMP:"; 4160Sstevel@tonic-gate (void) interpret_ip(flags, 4170Sstevel@tonic-gate (struct ip *)icmp->icmp_data, 28); 4180Sstevel@tonic-gate prot_nest_prefix = ""; 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate } else if (icmp->icmp_type == ICMP_ROUTERADVERT) { 4210Sstevel@tonic-gate if (icmp->icmp_wpa == 2) { 4220Sstevel@tonic-gate int icmp_ra_len; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate show_space(); 4250Sstevel@tonic-gate icmp_ra_len = ICMP_MINLEN + 4260Sstevel@tonic-gate num_rtr_addrs * 4270Sstevel@tonic-gate sizeof (struct icmp_ra_addr); 4280Sstevel@tonic-gate prot_nest_prefix = ""; 4290Sstevel@tonic-gate if (ilen > icmp_ra_len) { 4300Sstevel@tonic-gate interpret_icmp_mip_ext( 4310Sstevel@tonic-gate (uchar_t *)icmp + icmp_ra_len, 4320Sstevel@tonic-gate ilen - icmp_ra_len); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate show_space(); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate /*ARGSUSED*/ 4410Sstevel@tonic-gate void 4420Sstevel@tonic-gate interpret_icmpv6(flags, icmp6, iplen, ilen) 4430Sstevel@tonic-gate int flags; 4440Sstevel@tonic-gate icmp6_t *icmp6; 4450Sstevel@tonic-gate int iplen, ilen; 4460Sstevel@tonic-gate { 4470Sstevel@tonic-gate char *pt, *pc; 4480Sstevel@tonic-gate char *line; 4490Sstevel@tonic-gate extern char *prot_nest_prefix; 4500Sstevel@tonic-gate char addrstr[INET6_ADDRSTRLEN]; 4510Sstevel@tonic-gate char buff[2048]; 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate if (ilen < ICMP6_MINLEN) 4540Sstevel@tonic-gate return; /* incomplete header */ 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate pt = "Unknown"; 4570Sstevel@tonic-gate pc = ""; 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate switch (icmp6->icmp6_type) { 4600Sstevel@tonic-gate case ICMP6_DST_UNREACH: 4610Sstevel@tonic-gate pt = "Destination unreachable"; 4620Sstevel@tonic-gate switch (icmp6->icmp6_code) { 4630Sstevel@tonic-gate case ICMP6_DST_UNREACH_NOROUTE: 4640Sstevel@tonic-gate pc = "No route to destination"; 4650Sstevel@tonic-gate break; 4660Sstevel@tonic-gate case ICMP6_DST_UNREACH_ADMIN: 4670Sstevel@tonic-gate pc = "Communication administratively prohibited"; 4680Sstevel@tonic-gate break; 4690Sstevel@tonic-gate case ICMP6_DST_UNREACH_ADDR: 4700Sstevel@tonic-gate pc = "Address unreachable"; 4710Sstevel@tonic-gate break; 4720Sstevel@tonic-gate case ICMP6_DST_UNREACH_NOPORT: 4730Sstevel@tonic-gate if (ilen >= ICMP6_MINLEN + IPV6_HDR_LEN + 4740Sstevel@tonic-gate sizeof (struct udphdr)) { 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate ip6_t *orig_ip6hdr = (ip6_t *)&icmp6[1]; 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate switch (orig_ip6hdr->ip6_nxt) { 4790Sstevel@tonic-gate case IPPROTO_TCP: { 4800Sstevel@tonic-gate struct tcphdr *orig_thdr = 4810Sstevel@tonic-gate (struct tcphdr *)&orig_ip6hdr[1]; 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate (void) sprintf(buff, "TCP port %hu" 4840Sstevel@tonic-gate " unreachable", 4850Sstevel@tonic-gate ntohs(orig_thdr->th_dport)); 4860Sstevel@tonic-gate pc = buff; 4870Sstevel@tonic-gate break; 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate case IPPROTO_UDP: { 4900Sstevel@tonic-gate struct udphdr *orig_uhdr = 4910Sstevel@tonic-gate (struct udphdr *)&orig_ip6hdr[1]; 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate (void) sprintf(buff, "UDP port %hu" 4940Sstevel@tonic-gate " unreachable", 4950Sstevel@tonic-gate ntohs(orig_uhdr->uh_dport)); 4960Sstevel@tonic-gate pc = buff; 4970Sstevel@tonic-gate break; 4980Sstevel@tonic-gate } 4990Sstevel@tonic-gate default: 5000Sstevel@tonic-gate pc = "Port unreachable"; 5010Sstevel@tonic-gate break; 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate } else { 5040Sstevel@tonic-gate pc = "Bad port"; 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate break; 5070Sstevel@tonic-gate default: 5080Sstevel@tonic-gate break; 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate break; 5110Sstevel@tonic-gate case ICMP6_PACKET_TOO_BIG: 5120Sstevel@tonic-gate pt = "Packet too big"; 5130Sstevel@tonic-gate break; 5140Sstevel@tonic-gate case ND_REDIRECT: 5150Sstevel@tonic-gate pt = "Redirect"; 5160Sstevel@tonic-gate break; 5170Sstevel@tonic-gate case ICMP6_TIME_EXCEEDED: 5180Sstevel@tonic-gate pt = "Time exceeded"; 5190Sstevel@tonic-gate switch (icmp6->icmp6_code) { 5200Sstevel@tonic-gate case ICMP6_TIME_EXCEED_TRANSIT: 5210Sstevel@tonic-gate pc = "Hop limit exceeded in transit"; 5220Sstevel@tonic-gate break; 5230Sstevel@tonic-gate case ICMP6_TIME_EXCEED_REASSEMBLY: 5240Sstevel@tonic-gate pc = "Fragment reassembly time exceeded"; 5250Sstevel@tonic-gate break; 5260Sstevel@tonic-gate default: 5270Sstevel@tonic-gate break; 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate break; 5300Sstevel@tonic-gate case ICMP6_PARAM_PROB: 5310Sstevel@tonic-gate pt = "Parameter problem"; 5320Sstevel@tonic-gate switch (icmp6->icmp6_code) { 5330Sstevel@tonic-gate case ICMP6_PARAMPROB_HEADER: 5340Sstevel@tonic-gate pc = "Erroneous header field"; 5350Sstevel@tonic-gate break; 5360Sstevel@tonic-gate case ICMP6_PARAMPROB_NEXTHEADER: 5370Sstevel@tonic-gate pc = "Unrecognized next header type"; 5380Sstevel@tonic-gate break; 5390Sstevel@tonic-gate case ICMP6_PARAMPROB_OPTION: 5400Sstevel@tonic-gate pc = "Unrecognized IPv6 option"; 5410Sstevel@tonic-gate break; 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate break; 5440Sstevel@tonic-gate case ICMP6_ECHO_REQUEST: 5450Sstevel@tonic-gate pt = "Echo request"; 5460Sstevel@tonic-gate (void) sprintf(buff, "ID: %d Sequence number: %d", 5470Sstevel@tonic-gate ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq)); 5480Sstevel@tonic-gate pc = buff; 5490Sstevel@tonic-gate break; 5500Sstevel@tonic-gate case ICMP6_ECHO_REPLY: 5510Sstevel@tonic-gate pt = "Echo reply"; 5520Sstevel@tonic-gate (void) sprintf(buff, "ID: %d Sequence number: %d", 5530Sstevel@tonic-gate ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq)); 5540Sstevel@tonic-gate pc = buff; 5550Sstevel@tonic-gate break; 5560Sstevel@tonic-gate case MLD_LISTENER_QUERY: 5570Sstevel@tonic-gate if (ilen == MLD_MINLEN) 5580Sstevel@tonic-gate pt = "Group membership query - MLDv1"; 5590Sstevel@tonic-gate else if (ilen >= MLD_V2_QUERY_MINLEN) 5600Sstevel@tonic-gate pt = "Group membership query - MLDv2"; 5610Sstevel@tonic-gate else 5620Sstevel@tonic-gate pt = "Unknown membership query"; 5630Sstevel@tonic-gate break; 5640Sstevel@tonic-gate case MLD_LISTENER_REPORT: 5650Sstevel@tonic-gate pt = "Group membership report - MLDv1"; 5660Sstevel@tonic-gate break; 5670Sstevel@tonic-gate case MLD_LISTENER_REDUCTION: 5680Sstevel@tonic-gate pt = "Group membership termination - MLDv1"; 5690Sstevel@tonic-gate break; 5700Sstevel@tonic-gate case MLD_V2_LISTENER_REPORT: 5710Sstevel@tonic-gate pt = "Group membership report - MLDv2"; 5720Sstevel@tonic-gate break; 5730Sstevel@tonic-gate case ND_ROUTER_SOLICIT: 5740Sstevel@tonic-gate pt = "Router solicitation"; 5750Sstevel@tonic-gate break; 5760Sstevel@tonic-gate case ND_ROUTER_ADVERT: 5770Sstevel@tonic-gate pt = "Router advertisement"; 5780Sstevel@tonic-gate break; 5790Sstevel@tonic-gate case ND_NEIGHBOR_SOLICIT: 5800Sstevel@tonic-gate pt = "Neighbor solicitation"; 5810Sstevel@tonic-gate break; 5820Sstevel@tonic-gate case ND_NEIGHBOR_ADVERT: 5830Sstevel@tonic-gate pt = "Neighbor advertisement"; 5840Sstevel@tonic-gate break; 5850Sstevel@tonic-gate default: 5860Sstevel@tonic-gate break; 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate if (flags & F_SUM) { 5900Sstevel@tonic-gate line = get_sum_line(); 5910Sstevel@tonic-gate if (*pc) 5920Sstevel@tonic-gate (void) sprintf(line, "ICMPv6 %s (%s)", pt, pc); 5930Sstevel@tonic-gate else 5940Sstevel@tonic-gate (void) sprintf(line, "ICMPv6 %s", pt); 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate if (flags & F_DTAIL) { 5980Sstevel@tonic-gate show_header("ICMPv6: ", "ICMPv6 Header", ilen); 5990Sstevel@tonic-gate show_space(); 6000Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Type = %d (%s)", 6010Sstevel@tonic-gate icmp6->icmp6_type, pt); 6020Sstevel@tonic-gate if (*pc) 6030Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Code = %d (%s)", 6040Sstevel@tonic-gate icmp6->icmp6_code, pc); 6050Sstevel@tonic-gate else 6060Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Code = %d", 6070Sstevel@tonic-gate icmp6->icmp6_code); 6080Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Checksum = %x", 6090Sstevel@tonic-gate ntohs(icmp6->icmp6_cksum)); 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate switch (icmp6->icmp6_type) { 6120Sstevel@tonic-gate case ICMP6_DST_UNREACH: 6130Sstevel@tonic-gate if (ilen > ICMP6_MINLEN + IPV6_HDR_LEN) { 6140Sstevel@tonic-gate show_space(); 6150Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 6160Sstevel@tonic-gate "[ subject header follows ]"); 6170Sstevel@tonic-gate show_space(); 6180Sstevel@tonic-gate prot_nest_prefix = "ICMPv6:"; 6190Sstevel@tonic-gate (void) interpret_ipv6(flags, (ip6_t *)&icmp6[1], 6200Sstevel@tonic-gate ICMP6_MINLEN + IPV6_HDR_LEN); 6210Sstevel@tonic-gate prot_nest_prefix = ""; 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate break; 6240Sstevel@tonic-gate case ICMP6_PACKET_TOO_BIG: 6250Sstevel@tonic-gate show_space(); 6260Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 627*4564Swy83408 " Packet too big MTU = %d", 628*4564Swy83408 ntohl(icmp6->icmp6_mtu)); 6290Sstevel@tonic-gate show_space(); 6300Sstevel@tonic-gate break; 6310Sstevel@tonic-gate case ND_REDIRECT: { 6320Sstevel@tonic-gate nd_redirect_t *rd = (nd_redirect_t *)icmp6; 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Target address= %s", 6350Sstevel@tonic-gate inet_ntop(AF_INET6, (char *)&rd->nd_rd_target, 6360Sstevel@tonic-gate addrstr, INET6_ADDRSTRLEN)); 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 6390Sstevel@tonic-gate "Destination address= %s", 6400Sstevel@tonic-gate inet_ntop(AF_INET6, (char *)&rd->nd_rd_dst, 6410Sstevel@tonic-gate addrstr, INET6_ADDRSTRLEN)); 6420Sstevel@tonic-gate show_space(); 6430Sstevel@tonic-gate interpret_options((char *)icmp6 + sizeof (*rd), 6440Sstevel@tonic-gate ilen - sizeof (*rd)); 6450Sstevel@tonic-gate break; 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate case ND_NEIGHBOR_SOLICIT: { 6480Sstevel@tonic-gate struct nd_neighbor_solicit *ns; 6490Sstevel@tonic-gate if (ilen < sizeof (*ns)) 6500Sstevel@tonic-gate break; 6510Sstevel@tonic-gate ns = (struct nd_neighbor_solicit *)icmp6; 6520Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Target node = %s, %s", 6530Sstevel@tonic-gate inet_ntop(AF_INET6, (char *)&ns->nd_ns_target, 6540Sstevel@tonic-gate addrstr, INET6_ADDRSTRLEN), 6550Sstevel@tonic-gate addrtoname(AF_INET6, &ns->nd_ns_target)); 6560Sstevel@tonic-gate show_space(); 6570Sstevel@tonic-gate interpret_options((char *)icmp6 + sizeof (*ns), 6580Sstevel@tonic-gate ilen - sizeof (*ns)); 6590Sstevel@tonic-gate break; 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate case ND_NEIGHBOR_ADVERT: { 6630Sstevel@tonic-gate struct nd_neighbor_advert *na; 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate if (ilen < sizeof (*na)) 6660Sstevel@tonic-gate break; 6670Sstevel@tonic-gate na = (struct nd_neighbor_advert *)icmp6; 6680Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Target node = %s, %s", 6690Sstevel@tonic-gate inet_ntop(AF_INET6, (char *)&na->nd_na_target, 6700Sstevel@tonic-gate addrstr, INET6_ADDRSTRLEN), 6710Sstevel@tonic-gate addrtoname(AF_INET6, &na->nd_na_target)); 6720Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 6730Sstevel@tonic-gate "Router flag: %s, Solicited flag: %s, " 6740Sstevel@tonic-gate "Override flag: %s", 6750Sstevel@tonic-gate na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER ? 6760Sstevel@tonic-gate "SET" : "NOT SET", 6770Sstevel@tonic-gate na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED ? 6780Sstevel@tonic-gate "SET" : "NOT SET", 6790Sstevel@tonic-gate na->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE ? 6800Sstevel@tonic-gate "SET" : "NOT SET"); 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate show_space(); 6830Sstevel@tonic-gate interpret_options((char *)icmp6 + sizeof (*na), 6840Sstevel@tonic-gate ilen - sizeof (*na)); 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate break; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate case ND_ROUTER_SOLICIT: { 6890Sstevel@tonic-gate if (ilen < sizeof (struct nd_router_solicit)) 6900Sstevel@tonic-gate break; 6910Sstevel@tonic-gate interpret_options( 6920Sstevel@tonic-gate (char *)icmp6 + sizeof (struct nd_router_solicit), 6930Sstevel@tonic-gate ilen - sizeof (struct nd_router_solicit)); 6940Sstevel@tonic-gate break; 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate case ND_ROUTER_ADVERT: { 6980Sstevel@tonic-gate struct nd_router_advert *ra; 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate if (ilen < sizeof (*ra)) 7010Sstevel@tonic-gate break; 7020Sstevel@tonic-gate ra = (struct nd_router_advert *)icmp6; 7030Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 7040Sstevel@tonic-gate "Max hops= %d, Router lifetime= %d", 7050Sstevel@tonic-gate ra->nd_ra_curhoplimit, 7060Sstevel@tonic-gate ntohs(ra->nd_ra_router_lifetime)); 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 7090Sstevel@tonic-gate "Managed addr conf flag: %s, Other conf flag: %s", 7100Sstevel@tonic-gate ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED ? 7110Sstevel@tonic-gate "SET" : "NOT SET", 7120Sstevel@tonic-gate ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER ? 7130Sstevel@tonic-gate "SET" : "NOT SET"); 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 7160Sstevel@tonic-gate "Reachable time: %u, Reachable retrans time %u", 7170Sstevel@tonic-gate ntohl(ra->nd_ra_reachable), 7180Sstevel@tonic-gate ntohl(ra->nd_ra_retransmit)); 7190Sstevel@tonic-gate show_space(); 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate interpret_options((char *)icmp6 + sizeof (*ra), 7220Sstevel@tonic-gate ilen - sizeof (*ra)); 7230Sstevel@tonic-gate break; 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate case ICMP6_PARAM_PROB: 7260Sstevel@tonic-gate if (ilen < sizeof (*icmp6)) 7270Sstevel@tonic-gate break; 7280Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Ptr = %u", 7290Sstevel@tonic-gate ntohl(icmp6->icmp6_pptr)); 7300Sstevel@tonic-gate show_space(); 7310Sstevel@tonic-gate break; 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate case MLD_LISTENER_QUERY: { 7340Sstevel@tonic-gate struct mld_hdr *mldg = (struct mld_hdr *)icmp6; 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate if (ilen < MLD_MINLEN) 7370Sstevel@tonic-gate break; 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate if (ilen >= MLD_V2_QUERY_MINLEN) { 7400Sstevel@tonic-gate interpret_mldv2qry(icmp6, ilen); 7410Sstevel@tonic-gate } else { 7420Sstevel@tonic-gate (void) snprintf(get_line(0, 0), 7430Sstevel@tonic-gate get_line_remain(), 7440Sstevel@tonic-gate "Multicast address= %s", 7450Sstevel@tonic-gate inet_ntop(AF_INET6, mldg->mld_addr.s6_addr, 7460Sstevel@tonic-gate addrstr, INET6_ADDRSTRLEN)); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate show_space(); 7490Sstevel@tonic-gate break; 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate case MLD_LISTENER_REPORT: 7530Sstevel@tonic-gate case MLD_LISTENER_REDUCTION: { 7540Sstevel@tonic-gate struct mld_hdr *mldg; 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate if (ilen < sizeof (*mldg)) 7570Sstevel@tonic-gate break; 7580Sstevel@tonic-gate mldg = (struct mld_hdr *)icmp6; 7590Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 7600Sstevel@tonic-gate "Multicast address= %s", inet_ntop(AF_INET6, 7610Sstevel@tonic-gate mldg->mld_addr.s6_addr, addrstr, INET6_ADDRSTRLEN)); 7620Sstevel@tonic-gate show_space(); 7630Sstevel@tonic-gate break; 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate case MLD_V2_LISTENER_REPORT: { 7670Sstevel@tonic-gate interpret_mldv2rpt(icmp6, ilen); 7680Sstevel@tonic-gate show_space(); 7690Sstevel@tonic-gate break; 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate default: 7730Sstevel@tonic-gate break; 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate static void 7790Sstevel@tonic-gate interpret_options(optc, ilen) 7800Sstevel@tonic-gate char *optc; 7810Sstevel@tonic-gate int ilen; 7820Sstevel@tonic-gate { 7830Sstevel@tonic-gate #define PREFIX_OPTION_LENGTH 4 7840Sstevel@tonic-gate #define MTU_OPTION_LENGTH 1 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate #define PREFIX_INFINITY 0xffffffffUL 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate struct nd_opt_hdr *opt; 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate for (; ilen >= sizeof (*opt); ) { 7910Sstevel@tonic-gate opt = (struct nd_opt_hdr *)optc; 7920Sstevel@tonic-gate if (opt->nd_opt_len == 0) 7930Sstevel@tonic-gate return; 7940Sstevel@tonic-gate switch (opt->nd_opt_type) { 7950Sstevel@tonic-gate case ND_OPT_SOURCE_LINKADDR: 7960Sstevel@tonic-gate case ND_OPT_TARGET_LINKADDR: 7970Sstevel@tonic-gate { 7980Sstevel@tonic-gate struct nd_opt_lla *lopt; 7990Sstevel@tonic-gate char *buf, chbuf[128]; 8000Sstevel@tonic-gate uint_t addr_len; 8010Sstevel@tonic-gate int i; 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate if (ilen < (int)opt->nd_opt_len * 8) 8040Sstevel@tonic-gate break; 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate buf = chbuf; 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate lopt = (struct nd_opt_lla *)opt; 8090Sstevel@tonic-gate if (lopt->nd_opt_lla_type == ND_OPT_SOURCE_LINKADDR) { 8100Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 8110Sstevel@tonic-gate "+++ ICMPv6 Source LL Addr option +++"); 8120Sstevel@tonic-gate } else { 8130Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 8140Sstevel@tonic-gate "+++ ICMPv6 Target LL Addr option +++"); 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate /* 8180Sstevel@tonic-gate * The option length is in 8 octet units, and 8190Sstevel@tonic-gate * includes the first two bytes (the type and 8200Sstevel@tonic-gate * lenght fields) of the option. 8210Sstevel@tonic-gate */ 8220Sstevel@tonic-gate addr_len = lopt->nd_opt_lla_len * 8 - 2; 8230Sstevel@tonic-gate for (i = 0; i < addr_len; i++) { 8240Sstevel@tonic-gate snprintf(buf, sizeof (chbuf) - (buf - chbuf), 8250Sstevel@tonic-gate "%x:", lopt->nd_opt_lla_hdw_addr[i]); 8260Sstevel@tonic-gate buf += strlen(buf); 8270Sstevel@tonic-gate if (buf >= &chbuf[sizeof (chbuf)]) { 8280Sstevel@tonic-gate buf = NULL; 8290Sstevel@tonic-gate chbuf[sizeof (chbuf) - 8300Sstevel@tonic-gate strlen("<Too Long>)")] = '\0'; 8310Sstevel@tonic-gate (void) strlcat(chbuf, "<Too Long>", 8320Sstevel@tonic-gate sizeof (chbuf)); 8330Sstevel@tonic-gate break; 8340Sstevel@tonic-gate } 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate if (buf) 8370Sstevel@tonic-gate *(buf - 1) = '\0'; /* Erase last colon */ 8380Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 8390Sstevel@tonic-gate "Link Layer address: %s", chbuf); 8400Sstevel@tonic-gate show_space(); 8410Sstevel@tonic-gate break; 8420Sstevel@tonic-gate } 8430Sstevel@tonic-gate case ND_OPT_MTU: { 8440Sstevel@tonic-gate struct nd_opt_mtu *mopt; 8450Sstevel@tonic-gate if (opt->nd_opt_len != MTU_OPTION_LENGTH || 8460Sstevel@tonic-gate ilen < sizeof (struct nd_opt_mtu)) 8470Sstevel@tonic-gate break; 8480Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 8490Sstevel@tonic-gate "+++ ICMPv6 MTU option +++"); 8500Sstevel@tonic-gate mopt = (struct nd_opt_mtu *)opt; 8510Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 8520Sstevel@tonic-gate "MTU = %u ", mopt->nd_opt_mtu_mtu); 8530Sstevel@tonic-gate show_space(); 8540Sstevel@tonic-gate break; 8550Sstevel@tonic-gate } 8560Sstevel@tonic-gate case ND_OPT_PREFIX_INFORMATION: { 8570Sstevel@tonic-gate struct nd_opt_prefix_info *popt; 8580Sstevel@tonic-gate char validstr[30]; 8590Sstevel@tonic-gate char preferredstr[30]; 8600Sstevel@tonic-gate char prefixstr[INET6_ADDRSTRLEN]; 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate if (opt->nd_opt_len != PREFIX_OPTION_LENGTH || 8630Sstevel@tonic-gate ilen < sizeof (struct nd_opt_prefix_info)) 8640Sstevel@tonic-gate break; 8650Sstevel@tonic-gate popt = (struct nd_opt_prefix_info *)opt; 8660Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 8670Sstevel@tonic-gate "+++ ICMPv6 Prefix option +++"); 8680Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 8690Sstevel@tonic-gate "Prefix length = %d ", popt->nd_opt_pi_prefix_len); 8700Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 8710Sstevel@tonic-gate "Onlink flag: %s, Autonomous addr conf flag: %s", 8720Sstevel@tonic-gate popt->nd_opt_pi_flags_reserved & 8730Sstevel@tonic-gate ND_OPT_PI_FLAG_ONLINK ? "SET" : "NOT SET", 8740Sstevel@tonic-gate popt->nd_opt_pi_flags_reserved & 8750Sstevel@tonic-gate ND_OPT_PI_FLAG_AUTO ? "SET" : "NOT SET"); 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate if (ntohl(popt->nd_opt_pi_valid_time) == 8780Sstevel@tonic-gate PREFIX_INFINITY) 8790Sstevel@tonic-gate sprintf(validstr, "INFINITY"); 8800Sstevel@tonic-gate else 8810Sstevel@tonic-gate sprintf(validstr, "%lu", 8820Sstevel@tonic-gate ntohl(popt->nd_opt_pi_valid_time)); 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate if (ntohl(popt->nd_opt_pi_preferred_time) == 8850Sstevel@tonic-gate PREFIX_INFINITY) 8860Sstevel@tonic-gate sprintf(preferredstr, "INFINITY"); 8870Sstevel@tonic-gate else 8880Sstevel@tonic-gate sprintf(preferredstr, "%lu", 8890Sstevel@tonic-gate ntohl(popt->nd_opt_pi_preferred_time)); 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate (void) sprintf(get_line(0, 0), 8920Sstevel@tonic-gate "Valid Lifetime %s, Preferred Lifetime %s", 8930Sstevel@tonic-gate validstr, preferredstr); 8940Sstevel@tonic-gate (void) sprintf(get_line(0, 0), "Prefix %s", 8950Sstevel@tonic-gate inet_ntop(AF_INET6, 8960Sstevel@tonic-gate (char *)&popt->nd_opt_pi_prefix, prefixstr, 8970Sstevel@tonic-gate INET6_ADDRSTRLEN)); 8980Sstevel@tonic-gate show_space(); 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate default: 9010Sstevel@tonic-gate break; 9020Sstevel@tonic-gate } 9030Sstevel@tonic-gate optc += opt->nd_opt_len * 8; 9040Sstevel@tonic-gate ilen -= opt->nd_opt_len * 8; 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate static void 9090Sstevel@tonic-gate interpret_mldv2qry(icmp6_t *icmp6, int ilen) 9100Sstevel@tonic-gate { 9110Sstevel@tonic-gate mld2q_t *qry; 9120Sstevel@tonic-gate in6_addr_t *src; 9130Sstevel@tonic-gate int rem = ilen; 9140Sstevel@tonic-gate int srccnt; 9150Sstevel@tonic-gate char addrstr[INET6_ADDRSTRLEN]; 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate if (ilen < sizeof (*qry)) { 9180Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 9190Sstevel@tonic-gate "Malformed MLD Query"); 9200Sstevel@tonic-gate return; 9210Sstevel@tonic-gate } 9220Sstevel@tonic-gate qry = (mld2q_t *)icmp6; 9230Sstevel@tonic-gate rem -= sizeof (*qry); 9240Sstevel@tonic-gate srccnt = ntohs(qry->mld2q_numsrc); 9250Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 9260Sstevel@tonic-gate "Multicast address= %s", inet_ntop(AF_INET6, 9270Sstevel@tonic-gate &qry->mld2q_addr.s6_addr, addrstr, INET6_ADDRSTRLEN)); 9280Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 9290Sstevel@tonic-gate "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es"); 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate src = (in6_addr_t *)&qry[1]; 9320Sstevel@tonic-gate while (srccnt > 0 && rem >= sizeof (*src)) { 9330Sstevel@tonic-gate rem -= sizeof (*src); 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 9360Sstevel@tonic-gate inet_ntop(AF_INET6, src, addrstr, INET6_ADDRSTRLEN)); 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate srccnt--; 9390Sstevel@tonic-gate src++; 9400Sstevel@tonic-gate } 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate #define MAX_MLDV2_REPORT_TYPE 6 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate const char *mldv2rpt_types[] = { 9460Sstevel@tonic-gate "<unknown>", 9470Sstevel@tonic-gate "MODE_IS_INCLUDE", 9480Sstevel@tonic-gate "MODE_IS_EXCLUDE", 9490Sstevel@tonic-gate "CHANGE_TO_INCLUDE", 9500Sstevel@tonic-gate "CHANGE_TO_EXCLUDE", 9510Sstevel@tonic-gate "ALLOW_NEW_SOURCES", 9520Sstevel@tonic-gate "BLOCK_OLD_SOURCES", 9530Sstevel@tonic-gate }; 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate static void 9560Sstevel@tonic-gate interpret_mldv2rpt(icmp6_t *icmp6, int ilen) 9570Sstevel@tonic-gate { 9580Sstevel@tonic-gate mld2r_t *rpt; 9590Sstevel@tonic-gate mld2mar_t *mar; 9600Sstevel@tonic-gate in6_addr_t *src; 9610Sstevel@tonic-gate int rem = ilen, auxlen; 9620Sstevel@tonic-gate uint16_t marcnt, srccnt; 9630Sstevel@tonic-gate char addrstr[INET6_ADDRSTRLEN]; 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate if (ilen < sizeof (*rpt)) { 9660Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 9670Sstevel@tonic-gate "Malformed MLDv2 Report"); 9680Sstevel@tonic-gate return; 9690Sstevel@tonic-gate } 9700Sstevel@tonic-gate rpt = (mld2r_t *)icmp6; 9710Sstevel@tonic-gate mar = (mld2mar_t *)&rpt[1]; 9720Sstevel@tonic-gate marcnt = ntohs(rpt->mld2r_nummar); 9730Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 9740Sstevel@tonic-gate "%d Multicast Address Record%s:", marcnt, (marcnt == 1) ? "" : "s"); 9750Sstevel@tonic-gate rem -= sizeof (*rpt); 9760Sstevel@tonic-gate while (marcnt > 0 && rem >= sizeof (*mar)) { 9770Sstevel@tonic-gate rem -= sizeof (*mar); 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 9800Sstevel@tonic-gate "Multicast address= %s type = %s", inet_ntop(AF_INET6, 9810Sstevel@tonic-gate &mar->mld2mar_group.s6_addr, addrstr, INET6_ADDRSTRLEN), 9820Sstevel@tonic-gate (mar->mld2mar_type > MAX_MLDV2_REPORT_TYPE) ? 9830Sstevel@tonic-gate "<unknown>" : mldv2rpt_types[mar->mld2mar_type]); 9840Sstevel@tonic-gate srccnt = ntohs(mar->mld2mar_numsrc); 9850Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 9860Sstevel@tonic-gate "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es"); 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate src = (in6_addr_t *)&mar[1]; 9890Sstevel@tonic-gate while (srccnt > 0 && rem >= sizeof (*src)) { 9900Sstevel@tonic-gate rem -= sizeof (*src); 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 9930Sstevel@tonic-gate " %s", inet_ntop(AF_INET6, src, addrstr, 9940Sstevel@tonic-gate INET6_ADDRSTRLEN)); 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate srccnt--; 9970Sstevel@tonic-gate src++; 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate marcnt--; 10010Sstevel@tonic-gate auxlen = mar->mld2mar_auxlen * 4; 10020Sstevel@tonic-gate rem -= auxlen; 10030Sstevel@tonic-gate mar = (mld2mar_t *)((uint8_t *)src + auxlen); 10040Sstevel@tonic-gate } 10050Sstevel@tonic-gate } 1006