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