print-icmp6.c revision 214478
16059Samurai/*
26059Samurai * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
36059Samurai *	The Regents of the University of California.  All rights reserved.
46059Samurai *
56059Samurai * Redistribution and use in source and binary forms, with or without
66059Samurai * modification, are permitted provided that: (1) source code distributions
76059Samurai * retain the above copyright notice and this paragraph in its entirety, (2)
86059Samurai * distributions including binary code include the above copyright notice and
96059Samurai * this paragraph in its entirety in the documentation or other materials
106059Samurai * provided with the distribution, and (3) all advertising materials mentioning
116059Samurai * features or use of this software display the following acknowledgement:
126059Samurai * ``This product includes software developed by the University of California,
136059Samurai * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
146059Samurai * the University nor the names of its contributors may be used to endorse
156059Samurai * or promote products derived from this software without specific prior
166059Samurai * written permission.
176059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
186059Samurai * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
198857Srgrimes * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2032663Sbrian */
218857Srgrimes
226059Samurai#ifndef lint
236059Samuraistatic const char rcsid[] _U_ =
2430715Sbrian    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.86 2008-02-05 19:36:13 guy Exp $";
2530715Sbrian#endif
2630715Sbrian
2730715Sbrian#ifdef HAVE_CONFIG_H
2830715Sbrian#include "config.h"
2930715Sbrian#endif
3030715Sbrian
3131343Sbrian#ifdef INET6
3230715Sbrian
3330715Sbrian#include <tcpdump-stdinc.h>
3430715Sbrian
3530715Sbrian#include <stdio.h>
366059Samurai#include <string.h>
376059Samurai
386059Samurai#include "interface.h"
3930733Sbrian#include "addrtoname.h"
4030733Sbrian#include "extract.h"
4130733Sbrian
4230733Sbrian#include "ip6.h"
4330733Sbrian#include "icmp6.h"
446059Samurai#include "ipproto.h"
4531343Sbrian
466059Samurai#include "udp.h"
4726142Sbrian#include "ah.h"
486735Samurai
4913389Sphkstatic const char *get_rtpref(u_int);
5013389Sphkstatic const char *get_lifetime(u_int32_t);
516059Samuraistatic void print_lladdr(const u_char *, size_t);
5232663Sbrianstatic void icmp6_opt_print(const u_char *, int);
5328679Sbrianstatic void mld6_print(const u_char *);
5428679Sbrianstatic void mldv2_report_print(const u_char *, u_int);
5528679Sbrianstatic void mldv2_query_print(const u_char *, u_int);
5628679Sbrianstatic struct udphdr *get_upperlayer(u_char *, u_int *);
5728679Sbrianstatic void dnsname_print(const u_char *, const u_char *);
586059Samuraistatic void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
5930715Sbrianstatic void icmp6_rrenum_print(const u_char *, const u_char *);
6030715Sbrian
6130715Sbrian#ifndef abs
626059Samurai#define abs(a)	((0 < (a)) ? (a) : -(a))
6332663Sbrian#endif
646059Samurai
6531343Sbrian/* inline the various RPL definitions */
666059Samurai#define ND_RPL_MESSAGE 0x9B
676059Samurai
6831537Sbrianstatic struct tok icmp6_type_values[] = {
6931343Sbrian    { ICMP6_DST_UNREACH, "destination unreachable"},
7031343Sbrian    { ICMP6_PACKET_TOO_BIG, "packet too big"},
7131343Sbrian    { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
7231343Sbrian    { ICMP6_PARAM_PROB, "parameter problem"},
7331343Sbrian    { ICMP6_ECHO_REQUEST, "echo request"},
7431343Sbrian    { ICMP6_ECHO_REPLY, "echo reply"},
7531343Sbrian    { MLD6_LISTENER_QUERY, "multicast listener query"},
7631343Sbrian    { MLD6_LISTENER_REPORT, "multicast listener report"},
7731343Sbrian    { MLD6_LISTENER_DONE, "multicast listener done"},
7831343Sbrian    { ND_ROUTER_SOLICIT, "router solicitation"},
7931343Sbrian    { ND_ROUTER_ADVERT, "router advertisement"},
806059Samurai    { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
816059Samurai    { ND_NEIGHBOR_ADVERT, "neighbor advertisement"},
8213760Sphk    { ND_REDIRECT, "redirect"},
8328679Sbrian    { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
8428679Sbrian    { IND_SOLICIT, "inverse neighbor solicitation"},
8528679Sbrian    { IND_ADVERT, "inverse neighbor advertisement"},
8628679Sbrian    { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
8728679Sbrian    { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
8828679Sbrian    { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
8928679Sbrian    { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
9028679Sbrian    { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
9128679Sbrian    { ICMP6_WRUREQUEST, "who-are-you request"},
9228679Sbrian    { ICMP6_WRUREPLY, "who-are-you reply"},
9328679Sbrian    { ICMP6_NI_QUERY, "node information query"},
9428679Sbrian    { ICMP6_NI_REPLY, "node information reply"},
9528679Sbrian    { MLD6_MTRACE, "mtrace message"},
9628679Sbrian    { MLD6_MTRACE_RESP, "mtrace response"},
9728679Sbrian    { ND_RPL_MESSAGE,   "RPL"},
9828679Sbrian    { 0,	NULL }
9928679Sbrian};
10028679Sbrian
10128679Sbrianstatic struct tok icmp6_dst_unreach_code_values[] = {
10228679Sbrian    { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
10328679Sbrian    { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
10428679Sbrian    { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
10528679Sbrian    { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
10628679Sbrian    { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
10728679Sbrian    { 0,	NULL }
10828679Sbrian};
10928679Sbrian
11028679Sbrianstatic struct tok icmp6_opt_pi_flag_values[] = {
11128679Sbrian    { ND_OPT_PI_FLAG_ONLINK, "onlink" },
11228679Sbrian    { ND_OPT_PI_FLAG_AUTO, "auto" },
11328679Sbrian    { ND_OPT_PI_FLAG_ROUTER, "router" },
11428679Sbrian    { 0,	NULL }
1156059Samurai};
1166059Samurai
11728679Sbrianstatic struct tok icmp6_opt_ra_flag_values[] = {
11828679Sbrian    { ND_RA_FLAG_MANAGED, "managed" },
1196059Samurai    { ND_RA_FLAG_OTHER, "other stateful"},
1206059Samurai    { ND_RA_FLAG_HOME_AGENT, "home agent"},
1216059Samurai    { 0,	NULL }
12232663Sbrian};
12332663Sbrian
1246059Samuraistatic struct tok icmp6_nd_na_flag_values[] = {
1256059Samurai    { ND_NA_FLAG_ROUTER, "router" },
1266059Samurai    { ND_NA_FLAG_SOLICITED, "solicited" },
1276059Samurai    { ND_NA_FLAG_OVERRIDE, "override" },
1286059Samurai    { 0,	NULL }
1296059Samurai};
1306059Samurai
13128679Sbrian
13228679Sbrianstatic struct tok icmp6_opt_values[] = {
1336059Samurai   { ND_OPT_SOURCE_LINKADDR, "source link-address"},
1346059Samurai   { ND_OPT_TARGET_LINKADDR, "destination link-address"},
1356059Samurai   { ND_OPT_PREFIX_INFORMATION, "prefix info"},
13628679Sbrian   { ND_OPT_REDIRECTED_HEADER, "redirected header"},
1376059Samurai   { ND_OPT_MTU, "mtu"},
1386059Samurai   { ND_OPT_RDNSS, "rdnss"},
13932663Sbrian   { ND_OPT_ADVINTERVAL, "advertisement interval"},
14031514Sbrian   { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
14131514Sbrian   { ND_OPT_ROUTE_INFO, "route info"},
14231514Sbrian   { 0,	NULL }
14331514Sbrian};
14431514Sbrian
14531514Sbrian/* mldv2 report types */
14631514Sbrianstatic struct tok mldv2report2str[] = {
14731514Sbrian	{ 1,	"is_in" },
14831514Sbrian	{ 2,	"is_ex" },
14931514Sbrian	{ 3,	"to_in" },
15031514Sbrian	{ 4,	"to_ex" },
15131514Sbrian	{ 5,	"allow" },
15231514Sbrian	{ 6,	"block" },
15331514Sbrian	{ 0,	NULL }
15431514Sbrian};
15531514Sbrian
15631514Sbrianstatic const char *
15731514Sbrianget_rtpref(u_int v)
15831514Sbrian{
1596059Samurai	static const char *rtpref_str[] = {
16028679Sbrian		"medium",		/* 00 */
1616059Samurai		"high",			/* 01 */
1626059Samurai		"rsv",			/* 10 */
1636059Samurai		"low"			/* 11 */
1646059Samurai	};
1656059Samurai
1666059Samurai	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
1676059Samurai}
16831514Sbrian
16931514Sbrianstatic const char *
17031514Sbrianget_lifetime(u_int32_t v)
17129294Sbrian{
17231514Sbrian	static char buf[20];
1736735Samurai
17432663Sbrian	if (v == (u_int32_t)~0UL)
1756735Samurai		return "infinity";
1766735Samurai	else {
17731514Sbrian		snprintf(buf, sizeof(buf), "%u", v);
1786059Samurai		return buf;
1796059Samurai	}
1806059Samurai}
1816059Samurai
1826059Samuraistatic void
1836059Samuraiprint_lladdr(const u_int8_t *p, size_t l)
1846059Samurai{
1856059Samurai	const u_int8_t *ep, *q;
18628679Sbrian
1876059Samurai	q = p;
18828679Sbrian	ep = p + l;
1896059Samurai	while (l > 0 && q < ep) {
1906059Samurai		if (q > p)
1916059Samurai			printf(":");
1926059Samurai		printf("%02x", *q++);
1936059Samurai		l--;
1946059Samurai	}
1956059Samurai}
1966059Samurai
1976059Samuraistatic int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
1986059Samurai	u_int len)
19931514Sbrian{
20031514Sbrian	size_t i;
2016059Samurai	register const u_int16_t *sp;
20231514Sbrian	u_int32_t sum;
2036059Samurai	union {
2046059Samurai		struct {
2056059Samurai			struct in6_addr ph_src;
2066059Samurai			struct in6_addr ph_dst;
2076059Samurai			u_int32_t	ph_len;
2086059Samurai			u_int8_t	ph_zero[3];
2096059Samurai			u_int8_t	ph_nxt;
2106059Samurai		} ph;
2116059Samurai		u_int16_t pa[20];
2126059Samurai	} phu;
2136059Samurai
2146059Samurai	/* pseudo-header */
2156059Samurai	memset(&phu, 0, sizeof(phu));
2166059Samurai	phu.ph.ph_src = ip6->ip6_src;
2176059Samurai	phu.ph.ph_dst = ip6->ip6_dst;
2186059Samurai	phu.ph.ph_len = htonl(len);
2196059Samurai	phu.ph.ph_nxt = IPPROTO_ICMPV6;
2206059Samurai
22128679Sbrian	sum = 0;
2226059Samurai	for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
2236735Samurai		sum += phu.pa[i];
22432381Sbrian
22532381Sbrian	sp = (const u_int16_t *)icp;
2266735Samurai
2276735Samurai	for (i = 0; i < (len & ~1); i += 2)
22828679Sbrian		sum += *sp++;
2296735Samurai
23032381Sbrian	if (len & 1)
2316735Samurai		sum += htons((*(const u_int8_t *)sp) << 8);
23226516Sbrian
2336059Samurai	while (sum > 0xffff)
2346059Samurai		sum = (sum & 0xffff) + (sum >> 16);
2356059Samurai	sum = ~sum & 0xffff;
2366059Samurai
23731514Sbrian	return (sum);
23831514Sbrian}
23931514Sbrian
2406735Samuraienum ND_RPL_CODE {
2416735Samurai        ND_RPL_DAG_IS=0x01,
2426735Samurai        ND_RPL_DAG_IO=0x02,
2436735Samurai        ND_RPL_DAO   =0x04
2446059Samurai};
2456059Samurai
24631537Sbrianenum ND_RPL_DIO_FLAGS {
24731537Sbrian        ND_RPL_DIO_GROUNDED = 0x80,
24831537Sbrian        ND_RPL_DIO_DATRIG   = 0x40,
24931537Sbrian        ND_RPL_DIO_DASUPPORT= 0x20,
25031537Sbrian        ND_RPL_DIO_RES4     = 0x10,
25131537Sbrian        ND_RPL_DIO_RES3     = 0x08,
25231537Sbrian        ND_RPL_DIO_PRF_MASK = 0x07,  /* 3-bit preference */
25331537Sbrian};
25431537Sbrian
25531537Sbrianstruct nd_rpl_dio {
25631537Sbrian        u_int8_t rpl_flags;
25731537Sbrian        u_int8_t rpl_seq;
25831537Sbrian        u_int8_t rpl_instanceid;
25931537Sbrian        u_int8_t rpl_dagrank;
26031537Sbrian        u_int8_t rpl_dagid[16];
26131537Sbrian};
26231537Sbrian
26331537Sbrianstatic void
26431537Sbrianrpl_print(netdissect_options *ndo,
26531537Sbrian          const struct icmp6_hdr *hdr,
26631537Sbrian          const u_char *bp, u_int length _U_)
26731537Sbrian{
26831537Sbrian        struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp;
26931537Sbrian
27031537Sbrian        ND_TCHECK(dio->rpl_dagid);
27131537Sbrian
27231537Sbrian        switch(hdr->icmp6_code) {
27331537Sbrian        case ND_RPL_DAG_IS:
27431537Sbrian                ND_PRINT((ndo, ", DAG Information Solicitation"));
27531537Sbrian                if(ndo->ndo_vflag) {
27631537Sbrian                }
27731537Sbrian                break;
27831537Sbrian        case ND_RPL_DAG_IO:
27931537Sbrian                ND_PRINT((ndo, ", DAG Information Object"));
28031537Sbrian                if(ndo->ndo_vflag) {
28131537Sbrian                        char dagid[65];
28231537Sbrian                        char *d = dagid;
28331537Sbrian                        int  i;
28431537Sbrian                        for(i=0;i<16;i++) {
28531537Sbrian                                if(isprint(dio->rpl_dagid[i])) {
28631537Sbrian                                        *d++ = dio->rpl_dagid[i];
28731537Sbrian                                } else {
28831537Sbrian                                        int cnt=snprintf(d,4,"0x%02x",
28931537Sbrian                                                         dio->rpl_dagid[i]);
29031537Sbrian                                        d += cnt;
29131537Sbrian                                }
29231537Sbrian                        }
29331537Sbrian                        *d++ = '\0';
29431537Sbrian                        ND_PRINT((ndo, " [seq:%u,instance:%u,rank:%u,dagid:%s]",
29531537Sbrian                                  dio->rpl_seq,
29631537Sbrian                                  dio->rpl_instanceid,
29731537Sbrian                                  dio->rpl_dagrank,
29831537Sbrian                                  dagid));
29931537Sbrian                }
30031537Sbrian                break;
30131537Sbrian        case ND_RPL_DAO:
30231537Sbrian                ND_PRINT((ndo, ", Destination Advertisement Object"));
30331537Sbrian                if(ndo->ndo_vflag) {
30431537Sbrian                }
30531537Sbrian                break;
30631537Sbrian        default:
30731537Sbrian                ND_PRINT((ndo, ", RPL message, unknown code %u",hdr->icmp6_code));
30831537Sbrian                break;
30931537Sbrian        }
31031537Sbrian	return;
31131537Sbriantrunc:
31231537Sbrian	ND_PRINT((ndo," [|truncated]"));
31331537Sbrian	return;
31431537Sbrian
31531537Sbrian}
31631537Sbrian
31731537Sbrian
31831537Sbrianvoid
31931537Sbrianicmp6_print(netdissect_options *ndo,
32031537Sbrian            const u_char *bp, u_int length, const u_char *bp2, int fragmented)
32131537Sbrian{
32231537Sbrian	const struct icmp6_hdr *dp;
32331537Sbrian	const struct ip6_hdr *ip;
32431537Sbrian	const struct ip6_hdr *oip;
32531537Sbrian	const struct udphdr *ouh;
32631537Sbrian	int dport;
32731537Sbrian	const u_char *ep;
32831537Sbrian	u_int prot;
32931537Sbrian
33031537Sbrian	dp = (struct icmp6_hdr *)bp;
33131537Sbrian	ip = (struct ip6_hdr *)bp2;
33231537Sbrian	oip = (struct ip6_hdr *)(dp + 1);
33331537Sbrian	/* 'ep' points to the end of available data. */
33431537Sbrian	ep = snapend;
33531537Sbrian
33631537Sbrian	TCHECK(dp->icmp6_cksum);
33731537Sbrian
33831537Sbrian	if (vflag && !fragmented) {
33931537Sbrian		int sum = dp->icmp6_cksum;
34031537Sbrian
34131537Sbrian		if (TTEST2(bp[0], length)) {
34231537Sbrian			sum = icmp6_cksum(ip, dp, length);
34331537Sbrian			if (sum != 0)
34431537Sbrian				(void)printf("[bad icmp6 cksum %x!] ", sum);
34531537Sbrian			else
34631537Sbrian				(void)printf("[icmp6 sum ok] ");
34731537Sbrian		}
34831537Sbrian	}
34931537Sbrian
35031537Sbrian        printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type));
35131537Sbrian
35231537Sbrian        /* display cosmetics: print the packet length for printer that use the vflag now */
35331537Sbrian        if (vflag && (dp->icmp6_type ==
35431537Sbrian                      ND_ROUTER_SOLICIT ||
35531537Sbrian                      ND_ROUTER_ADVERT ||
35631537Sbrian                      ND_NEIGHBOR_ADVERT ||
35731962Sbrian                      ND_NEIGHBOR_SOLICIT ||
35831537Sbrian                      ND_REDIRECT ||
35931537Sbrian                      ICMP6_HADISCOV_REPLY ||
36031537Sbrian                      ICMP6_MOBILEPREFIX_ADVERT ))
36131537Sbrian            printf(", length %u", length);
36231537Sbrian
36331537Sbrian	switch (dp->icmp6_type) {
36431537Sbrian	case ICMP6_DST_UNREACH:
36531537Sbrian		TCHECK(oip->ip6_dst);
36631537Sbrian                printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code));
36731537Sbrian		switch (dp->icmp6_code) {
36831537Sbrian
36931537Sbrian		case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
37031537Sbrian		case ICMP6_DST_UNREACH_ADMIN:
37131537Sbrian		case ICMP6_DST_UNREACH_ADDR:
37232663Sbrian                        printf(" %s",ip6addr_string(&oip->ip6_dst));
37328679Sbrian                        break;
3746059Samurai		case ICMP6_DST_UNREACH_BEYONDSCOPE:
3759448Samurai			printf(" %s, source address %s",
3769448Samurai			       ip6addr_string(&oip->ip6_dst),
37731514Sbrian			       ip6addr_string(&oip->ip6_src));
37826516Sbrian			break;
37931514Sbrian		case ICMP6_DST_UNREACH_NOPORT:
38031514Sbrian			if ((ouh = get_upperlayer((u_char *)oip, &prot))
38131514Sbrian			    == NULL)
38231514Sbrian				goto trunc;
38332381Sbrian
38432381Sbrian			dport = EXTRACT_16BITS(&ouh->uh_dport);
38532381Sbrian			switch (prot) {
38632381Sbrian			case IPPROTO_TCP:
38732381Sbrian				printf(", %s tcp port %s",
38831514Sbrian					ip6addr_string(&oip->ip6_dst),
38931514Sbrian					tcpport_string(dport));
3906059Samurai				break;
3916059Samurai			case IPPROTO_UDP:
3926059Samurai				printf(", %s udp port %s",
3936059Samurai					ip6addr_string(&oip->ip6_dst),
3946059Samurai					udpport_string(dport));
3956059Samurai				break;
3966059Samurai			default:
3976059Samurai				printf(", %s protocol %d port %d unreachable",
3986059Samurai					ip6addr_string(&oip->ip6_dst),
3996059Samurai					oip->ip6_nxt, dport);
4006059Samurai				break;
4016059Samurai			}
4026059Samurai			break;
4036059Samurai		default:
4046059Samurai                    if (vflag <= 1) {
4056059Samurai                            print_unknown_data(bp,"\n\t",length);
4066059Samurai                            return;
40732663Sbrian                    }
4086735Samurai                    break;
4096735Samurai		}
4106059Samurai		break;
4116059Samurai	case ICMP6_PACKET_TOO_BIG:
4126059Samurai		TCHECK(dp->icmp6_mtu);
4136059Samurai		printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu));
4146059Samurai		break;
4156059Samurai	case ICMP6_TIME_EXCEEDED:
4166059Samurai		TCHECK(oip->ip6_dst);
4176059Samurai		switch (dp->icmp6_code) {
4186059Samurai		case ICMP6_TIME_EXCEED_TRANSIT:
4196059Samurai			printf(" for %s",
4206059Samurai				ip6addr_string(&oip->ip6_dst));
42131537Sbrian			break;
42231537Sbrian		case ICMP6_TIME_EXCEED_REASSEMBLY:
4239448Samurai			printf(" (reassembly)");
4249448Samurai			break;
4259448Samurai		default:
42628679Sbrian			printf(", unknown code (%u)", dp->icmp6_code);
4276059Samurai			break;
4286059Samurai		}
4296059Samurai		break;
4306059Samurai	case ICMP6_PARAM_PROB:
4316059Samurai		TCHECK(oip->ip6_dst);
4326059Samurai		switch (dp->icmp6_code) {
4336059Samurai		case ICMP6_PARAMPROB_HEADER:
4346059Samurai			printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
43531343Sbrian			break;
4366059Samurai		case ICMP6_PARAMPROB_NEXTHEADER:
4376059Samurai			printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
4386059Samurai			break;
4396059Samurai		case ICMP6_PARAMPROB_OPTION:
4406059Samurai			printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
4416059Samurai			break;
4426059Samurai		default:
44326516Sbrian			printf(", code-#%d",
4446059Samurai			       dp->icmp6_code);
4456059Samurai			break;
44626516Sbrian		}
44728679Sbrian		break;
4486059Samurai	case ICMP6_ECHO_REQUEST:
44926516Sbrian	case ICMP6_ECHO_REPLY:
4506059Samurai		TCHECK(dp->icmp6_seq);
4516059Samurai		printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq));
4526059Samurai		break;
4536059Samurai	case ICMP6_MEMBERSHIP_QUERY:
45428679Sbrian		if (length == MLD_MINLEN) {
45532284Sbrian			mld6_print((const u_char *)dp);
4566059Samurai		} else if (length >= MLDV2_MINLEN) {
4576059Samurai			printf("v2 ");
4586059Samurai			mldv2_query_print((const u_char *)dp, length);
45931343Sbrian		} else {
4606059Samurai			printf(" unknown-version (len %u) ", length);
4616059Samurai		}
4626059Samurai		break;
46326516Sbrian	case ICMP6_MEMBERSHIP_REPORT:
46426516Sbrian		mld6_print((const u_char *)dp);
46526516Sbrian		break;
46628679Sbrian	case ICMP6_MEMBERSHIP_REDUCTION:
46726516Sbrian		mld6_print((const u_char *)dp);
46826516Sbrian		break;
4696059Samurai	case ND_ROUTER_SOLICIT:
4706059Samurai#define RTSOLLEN 8
4716059Samurai		if (vflag) {
4726059Samurai			icmp6_opt_print((const u_char *)dp + RTSOLLEN,
4736059Samurai					length - RTSOLLEN);
4746059Samurai		}
4756059Samurai		break;
4766059Samurai	case ND_ROUTER_ADVERT:
4776059Samurai#define RTADVLEN 16
4786059Samurai		if (vflag) {
47931962Sbrian			struct nd_router_advert *p;
48026516Sbrian
48128679Sbrian			p = (struct nd_router_advert *)dp;
48228679Sbrian			TCHECK(p->nd_ra_retransmit);
4836059Samurai			printf("\n\thop limit %u, Flags [%s]" \
4846059Samurai                               ", pref %s, router lifetime %us, reachable time %us, retrans time %us",
4856059Samurai                               (u_int)p->nd_ra_curhoplimit,
4866059Samurai                               bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)),
4876059Samurai                               get_rtpref(p->nd_ra_flags_reserved),
48828679Sbrian                               EXTRACT_16BITS(&p->nd_ra_router_lifetime),
4896059Samurai                               EXTRACT_32BITS(&p->nd_ra_reachable),
4906059Samurai                               EXTRACT_32BITS(&p->nd_ra_retransmit));
4916059Samurai
4926059Samurai			icmp6_opt_print((const u_char *)dp + RTADVLEN,
4936059Samurai					length - RTADVLEN);
49426516Sbrian		}
4956735Samurai		break;
4966735Samurai	case ND_NEIGHBOR_SOLICIT:
4976735Samurai	    {
4986735Samurai		struct nd_neighbor_solicit *p;
4996059Samurai		p = (struct nd_neighbor_solicit *)dp;
5006059Samurai		TCHECK(p->nd_ns_target);
50126516Sbrian		printf(", who has %s", ip6addr_string(&p->nd_ns_target));
50228679Sbrian		if (vflag) {
5036059Samurai#define NDSOLLEN 24
5046059Samurai			icmp6_opt_print((const u_char *)dp + NDSOLLEN,
50526516Sbrian					length - NDSOLLEN);
5066059Samurai		}
5076059Samurai	    }
5086059Samurai		break;
5096059Samurai	case ND_NEIGHBOR_ADVERT:
5106735Samurai	    {
5116735Samurai		struct nd_neighbor_advert *p;
51225019Sphk
51325019Sphk		p = (struct nd_neighbor_advert *)dp;
51428679Sbrian		TCHECK(p->nd_na_target);
51528679Sbrian		printf(", tgt is %s",
51625019Sphk			ip6addr_string(&p->nd_na_target));
5176059Samurai		if (vflag) {
5186059Samurai                        printf(", Flags [%s]",
5196059Samurai                               bittok2str(icmp6_nd_na_flag_values,
52028679Sbrian                                          "none",
5216059Samurai                                          EXTRACT_32BITS(&p->nd_na_flags_reserved)));
52228679Sbrian#define NDADVLEN 24
5236059Samurai			icmp6_opt_print((const u_char *)dp + NDADVLEN,
5246059Samurai					length - NDADVLEN);
5256059Samurai#undef NDADVLEN
5266059Samurai		}
5276059Samurai	    }
52826516Sbrian		break;
5296059Samurai	case ND_REDIRECT:
5306059Samurai#define RDR(i) ((struct nd_redirect *)(i))
5316059Samurai		TCHECK(RDR(dp)->nd_rd_dst);
5326059Samurai		printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst));
5336059Samurai		TCHECK(RDR(dp)->nd_rd_target);
5346059Samurai		printf(" to %s",
5356059Samurai		    getname6((const u_char*)&RDR(dp)->nd_rd_target));
53626516Sbrian#define REDIRECTLEN 40
5376059Samurai		if (vflag) {
5386059Samurai			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
5396059Samurai					length - REDIRECTLEN);
5406059Samurai		}
5416059Samurai		break;
5426059Samurai#undef REDIRECTLEN
54328679Sbrian#undef RDR
5446059Samurai	case ICMP6_ROUTER_RENUMBERING:
54528679Sbrian		icmp6_rrenum_print(bp, ep);
54628679Sbrian		break;
5476059Samurai	case ICMP6_NI_QUERY:
5486059Samurai	case ICMP6_NI_REPLY:
5496059Samurai		icmp6_nodeinfo_print(length, bp, ep);
5506059Samurai		break;
5516059Samurai	case IND_SOLICIT:
5526059Samurai	case IND_ADVERT:
5536059Samurai		break;
5546059Samurai	case ICMP6_V2_MEMBERSHIP_REPORT:
5556059Samurai		mldv2_report_print((const u_char *) dp, length);
55628679Sbrian		break;
55728679Sbrian	case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
55828679Sbrian	case ICMP6_HADISCOV_REQUEST:
5596059Samurai                TCHECK(dp->icmp6_data16[0]);
5606059Samurai                printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
5616059Samurai                break;
5626059Samurai	case ICMP6_HADISCOV_REPLY:
5636059Samurai		if (vflag) {
5646059Samurai			struct in6_addr *in6;
5656059Samurai			u_char *cp;
5666059Samurai
5676059Samurai			TCHECK(dp->icmp6_data16[0]);
5686059Samurai			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
5696059Samurai			cp = (u_char *)dp + length;
5706059Samurai			in6 = (struct in6_addr *)(dp + 1);
5716059Samurai			for (; (u_char *)in6 < cp; in6++) {
5726059Samurai				TCHECK(*in6);
5736059Samurai				printf(", %s", ip6addr_string(in6));
5746059Samurai			}
5756059Samurai		}
5766059Samurai		break;
577	case ICMP6_MOBILEPREFIX_ADVERT:
578		if (vflag) {
579			TCHECK(dp->icmp6_data16[0]);
580			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
581			if (dp->icmp6_data16[1] & 0xc0)
582				printf(" ");
583			if (dp->icmp6_data16[1] & 0x80)
584				printf("M");
585			if (dp->icmp6_data16[1] & 0x40)
586				printf("O");
587#define MPADVLEN 8
588			icmp6_opt_print((const u_char *)dp + MPADVLEN,
589					length - MPADVLEN);
590		}
591		break;
592        case ND_RPL_MESSAGE:
593                rpl_print(ndo, dp, &dp->icmp6_data8[0], length);
594                break;
595	default:
596                printf(", length %u", length);
597                if (vflag <= 1)
598                    print_unknown_data(bp,"\n\t", length);
599                return;
600        }
601        if (!vflag)
602            printf(", length %u", length);
603	return;
604trunc:
605	fputs("[|icmp6]", stdout);
606}
607
608static struct udphdr *
609get_upperlayer(u_char *bp, u_int *prot)
610{
611	const u_char *ep;
612	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
613	struct udphdr *uh;
614	struct ip6_hbh *hbh;
615	struct ip6_frag *fragh;
616	struct ah *ah;
617	u_int nh;
618	int hlen;
619
620	/* 'ep' points to the end of available data. */
621	ep = snapend;
622
623	if (!TTEST(ip6->ip6_nxt))
624		return NULL;
625
626	nh = ip6->ip6_nxt;
627	hlen = sizeof(struct ip6_hdr);
628
629	while (bp < ep) {
630		bp += hlen;
631
632		switch(nh) {
633		case IPPROTO_UDP:
634		case IPPROTO_TCP:
635			uh = (struct udphdr *)bp;
636			if (TTEST(uh->uh_dport)) {
637				*prot = nh;
638				return(uh);
639			}
640			else
641				return(NULL);
642			/* NOTREACHED */
643
644		case IPPROTO_HOPOPTS:
645		case IPPROTO_DSTOPTS:
646		case IPPROTO_ROUTING:
647			hbh = (struct ip6_hbh *)bp;
648			if (!TTEST(hbh->ip6h_len))
649				return(NULL);
650			nh = hbh->ip6h_nxt;
651			hlen = (hbh->ip6h_len + 1) << 3;
652			break;
653
654		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
655			fragh = (struct ip6_frag *)bp;
656			if (!TTEST(fragh->ip6f_offlg))
657				return(NULL);
658			/* fragments with non-zero offset are meaningless */
659			if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
660				return(NULL);
661			nh = fragh->ip6f_nxt;
662			hlen = sizeof(struct ip6_frag);
663			break;
664
665		case IPPROTO_AH:
666			ah = (struct ah *)bp;
667			if (!TTEST(ah->ah_len))
668				return(NULL);
669			nh = ah->ah_nxt;
670			hlen = (ah->ah_len + 2) << 2;
671			break;
672
673		default:	/* unknown or undecodable header */
674			*prot = nh; /* meaningless, but set here anyway */
675			return(NULL);
676		}
677	}
678
679	return(NULL);		/* should be notreached, though */
680}
681
682static void
683icmp6_opt_print(const u_char *bp, int resid)
684{
685	const struct nd_opt_hdr *op;
686	const struct nd_opt_hdr *opl;	/* why there's no struct? */
687	const struct nd_opt_prefix_info *opp;
688	const struct icmp6_opts_redirect *opr;
689	const struct nd_opt_mtu *opm;
690	const struct nd_opt_rdnss *oprd;
691	const struct nd_opt_advinterval *opa;
692	const struct nd_opt_homeagent_info *oph;
693	const struct nd_opt_route_info *opri;
694	const u_char *cp, *ep;
695	struct in6_addr in6, *in6p;
696	size_t l;
697	u_int i;
698
699#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
700
701	cp = bp;
702	/* 'ep' points to the end of available data. */
703	ep = snapend;
704
705	while (cp < ep) {
706		op = (struct nd_opt_hdr *)cp;
707
708		ECHECK(op->nd_opt_len);
709		if (resid <= 0)
710			return;
711		if (op->nd_opt_len == 0)
712			goto trunc;
713		if (cp + (op->nd_opt_len << 3) > ep)
714			goto trunc;
715
716                printf("\n\t  %s option (%u), length %u (%u): ",
717                       tok2str(icmp6_opt_values, "unknown", op->nd_opt_type),
718                       op->nd_opt_type,
719                       op->nd_opt_len << 3,
720                       op->nd_opt_len);
721
722		switch (op->nd_opt_type) {
723		case ND_OPT_SOURCE_LINKADDR:
724			opl = (struct nd_opt_hdr *)op;
725			l = (op->nd_opt_len << 3) - 2;
726			print_lladdr(cp + 2, l);
727			break;
728		case ND_OPT_TARGET_LINKADDR:
729			opl = (struct nd_opt_hdr *)op;
730			l = (op->nd_opt_len << 3) - 2;
731			print_lladdr(cp + 2, l);
732			break;
733		case ND_OPT_PREFIX_INFORMATION:
734			opp = (struct nd_opt_prefix_info *)op;
735			TCHECK(opp->nd_opt_pi_prefix);
736                        printf("%s/%u%s, Flags [%s], valid time %ss",
737                               ip6addr_string(&opp->nd_opt_pi_prefix),
738                               opp->nd_opt_pi_prefix_len,
739                               (op->nd_opt_len != 4) ? "badlen" : "",
740                               bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved),
741                               get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
742                        printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
743			break;
744		case ND_OPT_REDIRECTED_HEADER:
745			opr = (struct icmp6_opts_redirect *)op;
746                        print_unknown_data(bp,"\n\t    ",op->nd_opt_len<<3);
747			/* xxx */
748			break;
749		case ND_OPT_MTU:
750			opm = (struct nd_opt_mtu *)op;
751			TCHECK(opm->nd_opt_mtu_mtu);
752			printf(" %u%s",
753                               EXTRACT_32BITS(&opm->nd_opt_mtu_mtu),
754                               (op->nd_opt_len != 1) ? "bad option length" : "" );
755                        break;
756		case ND_OPT_RDNSS:
757			oprd = (struct nd_opt_rdnss *)op;
758			l = (op->nd_opt_len - 1) / 2;
759			printf(" lifetime %us,",
760				EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime));
761			for (i = 0; i < l; i++) {
762				TCHECK(oprd->nd_opt_rdnss_addr[i]);
763				printf(" addr: %s",
764				    ip6addr_string(&oprd->nd_opt_rdnss_addr[i]));
765			}
766			break;
767		case ND_OPT_ADVINTERVAL:
768			opa = (struct nd_opt_advinterval *)op;
769			TCHECK(opa->nd_opt_adv_interval);
770			printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval));
771			break;
772		case ND_OPT_HOMEAGENT_INFO:
773			oph = (struct nd_opt_homeagent_info *)op;
774			TCHECK(oph->nd_opt_hai_lifetime);
775			printf(" preference %u, lifetime %u",
776                               EXTRACT_16BITS(&oph->nd_opt_hai_preference),
777                               EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
778			break;
779		case ND_OPT_ROUTE_INFO:
780			opri = (struct nd_opt_route_info *)op;
781			TCHECK(opri->nd_opt_rti_lifetime);
782			memset(&in6, 0, sizeof(in6));
783			in6p = (struct in6_addr *)(opri + 1);
784			switch (op->nd_opt_len) {
785			case 1:
786				break;
787			case 2:
788				TCHECK2(*in6p, 8);
789				memcpy(&in6, opri + 1, 8);
790				break;
791			case 3:
792				TCHECK(*in6p);
793				memcpy(&in6, opri + 1, sizeof(in6));
794				break;
795			default:
796				goto trunc;
797			}
798			printf(" %s/%u", ip6addr_string(&in6),
799			    opri->nd_opt_rti_prefixlen);
800			printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
801			printf(", lifetime=%s",
802			    get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
803			break;
804		default:
805                        if (vflag <= 1) {
806                            print_unknown_data(cp+2,"\n\t  ", (op->nd_opt_len << 3) - 2); /* skip option header */
807                            return;
808                        }
809                        break;
810		}
811                /* do we want to see an additional hexdump ? */
812                if (vflag> 1)
813                    print_unknown_data(cp+2,"\n\t    ", (op->nd_opt_len << 3) - 2); /* skip option header */
814
815		cp += op->nd_opt_len << 3;
816		resid -= op->nd_opt_len << 3;
817	}
818	return;
819
820 trunc:
821	fputs("[ndp opt]", stdout);
822	return;
823#undef ECHECK
824}
825
826static void
827mld6_print(const u_char *bp)
828{
829	struct mld6_hdr *mp = (struct mld6_hdr *)bp;
830	const u_char *ep;
831
832	/* 'ep' points to the end of available data. */
833	ep = snapend;
834
835	if ((u_char *)mp + sizeof(*mp) > ep)
836		return;
837
838	printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
839	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
840}
841
842static void
843mldv2_report_print(const u_char *bp, u_int len)
844{
845    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
846    u_int group, nsrcs, ngroups;
847    u_int i, j;
848
849    /* Minimum len is 8 */
850    if (len < 8) {
851	printf(" [invalid len %d]", len);
852	return;
853    }
854
855    TCHECK(icp->icmp6_data16[1]);
856    ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]);
857    printf(", %d group record(s)", ngroups);
858    if (vflag > 0) {
859	/* Print the group records */
860	group = 8;
861        for (i = 0; i < ngroups; i++) {
862	    /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
863	    if (len < group + 20) {
864		printf(" [invalid number of groups]");
865		return;
866	    }
867            TCHECK2(bp[group + 4], sizeof(struct in6_addr));
868            printf(" [gaddr %s", ip6addr_string(&bp[group + 4]));
869	    printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]",
870								bp[group]));
871            nsrcs = (bp[group + 2] << 8) + bp[group + 3];
872	    /* Check the number of sources and print them */
873	    if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) {
874		printf(" [invalid number of sources %d]", nsrcs);
875		return;
876	    }
877            if (vflag == 1)
878                printf(", %d source(s)", nsrcs);
879            else {
880		/* Print the sources */
881                (void)printf(" {");
882                for (j = 0; j < nsrcs; j++) {
883                    TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)],
884                            sizeof(struct in6_addr));
885		    printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)]));
886		}
887                (void)printf(" }");
888            }
889	    /* Next group record */
890            group += 20 + nsrcs * sizeof(struct in6_addr);
891	    printf("]");
892        }
893    }
894    return;
895trunc:
896    (void)printf("[|icmp6]");
897    return;
898}
899
900static void
901mldv2_query_print(const u_char *bp, u_int len)
902{
903    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
904    u_int mrc;
905    int mrt, qqi;
906    u_int nsrcs;
907    register u_int i;
908
909    /* Minimum len is 28 */
910    if (len < 28) {
911	printf(" [invalid len %d]", len);
912	return;
913    }
914    TCHECK(icp->icmp6_data16[0]);
915    mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]);
916    if (mrc < 32768) {
917	mrt = mrc;
918    } else {
919        mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
920    }
921    if (vflag) {
922	(void)printf(" [max resp delay=%d]", mrt);
923    }
924    TCHECK2(bp[8], sizeof(struct in6_addr));
925    printf(" [gaddr %s", ip6addr_string(&bp[8]));
926
927    if (vflag) {
928        TCHECK(bp[25]);
929	if (bp[24] & 0x08) {
930		printf(" sflag");
931	}
932	if (bp[24] & 0x07) {
933		printf(" robustness=%d", bp[24] & 0x07);
934	}
935	if (bp[25] < 128) {
936		qqi = bp[25];
937	} else {
938		qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
939	}
940	printf(" qqi=%d", qqi);
941    }
942
943    TCHECK2(bp[26], 2);
944    nsrcs = EXTRACT_16BITS(&bp[26]);
945    if (nsrcs > 0) {
946	if (len < 28 + nsrcs * sizeof(struct in6_addr))
947	    printf(" [invalid number of sources]");
948	else if (vflag > 1) {
949	    printf(" {");
950	    for (i = 0; i < nsrcs; i++) {
951		TCHECK2(bp[28 + i * sizeof(struct in6_addr)],
952                        sizeof(struct in6_addr));
953		printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)]));
954	    }
955	    printf(" }");
956	} else
957	    printf(", %d source(s)", nsrcs);
958    }
959    printf("]");
960    return;
961trunc:
962    (void)printf("[|icmp6]");
963    return;
964}
965
966static void
967dnsname_print(const u_char *cp, const u_char *ep)
968{
969	int i;
970
971	/* DNS name decoding - no decompression */
972	printf(", \"");
973	while (cp < ep) {
974		i = *cp++;
975		if (i) {
976			if (i > ep - cp) {
977				printf("???");
978				break;
979			}
980			while (i-- && cp < ep) {
981				safeputchar(*cp);
982				cp++;
983			}
984			if (cp + 1 < ep && *cp)
985				printf(".");
986		} else {
987			if (cp == ep) {
988				/* FQDN */
989				printf(".");
990			} else if (cp + 1 == ep && *cp == '\0') {
991				/* truncated */
992			} else {
993				/* invalid */
994				printf("???");
995			}
996			break;
997		}
998	}
999	printf("\"");
1000}
1001
1002static void
1003icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
1004{
1005	struct icmp6_nodeinfo *ni6;
1006	struct icmp6_hdr *dp;
1007	const u_char *cp;
1008	size_t siz, i;
1009	int needcomma;
1010
1011	if (ep < bp)
1012		return;
1013	dp = (struct icmp6_hdr *)bp;
1014	ni6 = (struct icmp6_nodeinfo *)bp;
1015	siz = ep - bp;
1016
1017	switch (ni6->ni_type) {
1018	case ICMP6_NI_QUERY:
1019		if (siz == sizeof(*dp) + 4) {
1020			/* KAME who-are-you */
1021			printf(" who-are-you request");
1022			break;
1023		}
1024		printf(" node information query");
1025
1026		TCHECK2(*dp, sizeof(*ni6));
1027		ni6 = (struct icmp6_nodeinfo *)dp;
1028		printf(" (");	/*)*/
1029		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
1030		case NI_QTYPE_NOOP:
1031			printf("noop");
1032			break;
1033		case NI_QTYPE_SUPTYPES:
1034			printf("supported qtypes");
1035			i = EXTRACT_16BITS(&ni6->ni_flags);
1036			if (i)
1037				printf(" [%s]", (i & 0x01) ? "C" : "");
1038			break;
1039			break;
1040		case NI_QTYPE_FQDN:
1041			printf("DNS name");
1042			break;
1043		case NI_QTYPE_NODEADDR:
1044			printf("node addresses");
1045			i = ni6->ni_flags;
1046			if (!i)
1047				break;
1048			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
1049			printf(" [%s%s%s%s%s%s]",
1050			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1051			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1052			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1053			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1054			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
1055			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
1056			break;
1057		default:
1058			printf("unknown");
1059			break;
1060		}
1061
1062		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
1063		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
1064			if (siz != sizeof(*ni6))
1065				if (vflag)
1066					printf(", invalid len");
1067			/*(*/
1068			printf(")");
1069			break;
1070		}
1071
1072
1073		/* XXX backward compat, icmp-name-lookup-03 */
1074		if (siz == sizeof(*ni6)) {
1075			printf(", 03 draft");
1076			/*(*/
1077			printf(")");
1078			break;
1079		}
1080
1081		switch (ni6->ni_code) {
1082		case ICMP6_NI_SUBJ_IPV6:
1083			if (!TTEST2(*dp,
1084			    sizeof(*ni6) + sizeof(struct in6_addr)))
1085				break;
1086			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
1087				if (vflag)
1088					printf(", invalid subject len");
1089				break;
1090			}
1091			printf(", subject=%s",
1092			    getname6((const u_char *)(ni6 + 1)));
1093			break;
1094		case ICMP6_NI_SUBJ_FQDN:
1095			printf(", subject=DNS name");
1096			cp = (const u_char *)(ni6 + 1);
1097			if (cp[0] == ep - cp - 1) {
1098				/* icmp-name-lookup-03, pascal string */
1099				if (vflag)
1100					printf(", 03 draft");
1101				cp++;
1102				printf(", \"");
1103				while (cp < ep) {
1104					safeputchar(*cp);
1105					cp++;
1106				}
1107				printf("\"");
1108			} else
1109				dnsname_print(cp, ep);
1110			break;
1111		case ICMP6_NI_SUBJ_IPV4:
1112			if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
1113				break;
1114			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
1115				if (vflag)
1116					printf(", invalid subject len");
1117				break;
1118			}
1119			printf(", subject=%s",
1120			    getname((const u_char *)(ni6 + 1)));
1121			break;
1122		default:
1123			printf(", unknown subject");
1124			break;
1125		}
1126
1127		/*(*/
1128		printf(")");
1129		break;
1130
1131	case ICMP6_NI_REPLY:
1132		if (icmp6len > siz) {
1133			printf("[|icmp6: node information reply]");
1134			break;
1135		}
1136
1137		needcomma = 0;
1138
1139		ni6 = (struct icmp6_nodeinfo *)dp;
1140		printf(" node information reply");
1141		printf(" (");	/*)*/
1142		switch (ni6->ni_code) {
1143		case ICMP6_NI_SUCCESS:
1144			if (vflag) {
1145				printf("success");
1146				needcomma++;
1147			}
1148			break;
1149		case ICMP6_NI_REFUSED:
1150			printf("refused");
1151			needcomma++;
1152			if (siz != sizeof(*ni6))
1153				if (vflag)
1154					printf(", invalid length");
1155			break;
1156		case ICMP6_NI_UNKNOWN:
1157			printf("unknown");
1158			needcomma++;
1159			if (siz != sizeof(*ni6))
1160				if (vflag)
1161					printf(", invalid length");
1162			break;
1163		}
1164
1165		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
1166			/*(*/
1167			printf(")");
1168			break;
1169		}
1170
1171		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
1172		case NI_QTYPE_NOOP:
1173			if (needcomma)
1174				printf(", ");
1175			printf("noop");
1176			if (siz != sizeof(*ni6))
1177				if (vflag)
1178					printf(", invalid length");
1179			break;
1180		case NI_QTYPE_SUPTYPES:
1181			if (needcomma)
1182				printf(", ");
1183			printf("supported qtypes");
1184			i = EXTRACT_16BITS(&ni6->ni_flags);
1185			if (i)
1186				printf(" [%s]", (i & 0x01) ? "C" : "");
1187			break;
1188		case NI_QTYPE_FQDN:
1189			if (needcomma)
1190				printf(", ");
1191			printf("DNS name");
1192			cp = (const u_char *)(ni6 + 1) + 4;
1193			if (cp[0] == ep - cp - 1) {
1194				/* icmp-name-lookup-03, pascal string */
1195				if (vflag)
1196					printf(", 03 draft");
1197				cp++;
1198				printf(", \"");
1199				while (cp < ep) {
1200					safeputchar(*cp);
1201					cp++;
1202				}
1203				printf("\"");
1204			} else
1205				dnsname_print(cp, ep);
1206			if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
1207				printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
1208			break;
1209		case NI_QTYPE_NODEADDR:
1210			if (needcomma)
1211				printf(", ");
1212			printf("node addresses");
1213			i = sizeof(*ni6);
1214			while (i < siz) {
1215				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
1216					break;
1217				printf(" %s", getname6(bp + i));
1218				i += sizeof(struct in6_addr);
1219				printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
1220				i += sizeof(int32_t);
1221			}
1222			i = ni6->ni_flags;
1223			if (!i)
1224				break;
1225			printf(" [%s%s%s%s%s%s%s]",
1226			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1227			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1228			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1229			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1230			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
1231			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
1232			    (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
1233			break;
1234		default:
1235			if (needcomma)
1236				printf(", ");
1237			printf("unknown");
1238			break;
1239		}
1240
1241		/*(*/
1242		printf(")");
1243		break;
1244	}
1245	return;
1246
1247trunc:
1248	fputs("[|icmp6]", stdout);
1249}
1250
1251static void
1252icmp6_rrenum_print(const u_char *bp, const u_char *ep)
1253{
1254	struct icmp6_router_renum *rr6;
1255	const char *cp;
1256	struct rr_pco_match *match;
1257	struct rr_pco_use *use;
1258	char hbuf[NI_MAXHOST];
1259	int n;
1260
1261	if (ep < bp)
1262		return;
1263	rr6 = (struct icmp6_router_renum *)bp;
1264	cp = (const char *)(rr6 + 1);
1265
1266	TCHECK(rr6->rr_reserved);
1267	switch (rr6->rr_code) {
1268	case ICMP6_ROUTER_RENUMBERING_COMMAND:
1269		printf("router renum: command");
1270		break;
1271	case ICMP6_ROUTER_RENUMBERING_RESULT:
1272		printf("router renum: result");
1273		break;
1274	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1275		printf("router renum: sequence number reset");
1276		break;
1277	default:
1278		printf("router renum: code-#%d", rr6->rr_code);
1279		break;
1280	}
1281
1282	printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
1283
1284	if (vflag) {
1285#define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
1286		printf("[");	/*]*/
1287		if (rr6->rr_flags) {
1288			printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
1289			    F(ICMP6_RR_FLAGS_REQRESULT, "R"),
1290			    F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
1291			    F(ICMP6_RR_FLAGS_SPECSITE, "S"),
1292			    F(ICMP6_RR_FLAGS_PREVDONE, "P"));
1293		}
1294		printf("seg=%u,", rr6->rr_segnum);
1295		printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay));
1296		if (rr6->rr_reserved)
1297			printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved));
1298		/*[*/
1299		printf("]");
1300#undef F
1301	}
1302
1303	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
1304		match = (struct rr_pco_match *)cp;
1305		cp = (const char *)(match + 1);
1306
1307		TCHECK(match->rpm_prefix);
1308
1309		if (vflag > 1)
1310			printf("\n\t");
1311		else
1312			printf(" ");
1313		printf("match(");	/*)*/
1314		switch (match->rpm_code) {
1315		case RPM_PCO_ADD:	printf("add"); break;
1316		case RPM_PCO_CHANGE:	printf("change"); break;
1317		case RPM_PCO_SETGLOBAL:	printf("setglobal"); break;
1318		default:		printf("#%u", match->rpm_code); break;
1319		}
1320
1321		if (vflag) {
1322			printf(",ord=%u", match->rpm_ordinal);
1323			printf(",min=%u", match->rpm_minlen);
1324			printf(",max=%u", match->rpm_maxlen);
1325		}
1326		if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
1327			printf(",%s/%u", hbuf, match->rpm_matchlen);
1328		else
1329			printf(",?/%u", match->rpm_matchlen);
1330		/*(*/
1331		printf(")");
1332
1333		n = match->rpm_len - 3;
1334		if (n % 4)
1335			goto trunc;
1336		n /= 4;
1337		while (n-- > 0) {
1338			use = (struct rr_pco_use *)cp;
1339			cp = (const char *)(use + 1);
1340
1341			TCHECK(use->rpu_prefix);
1342
1343			if (vflag > 1)
1344				printf("\n\t");
1345			else
1346				printf(" ");
1347			printf("use(");	/*)*/
1348			if (use->rpu_flags) {
1349#define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
1350				printf("%s%s,",
1351				    F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
1352				    F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
1353#undef F
1354			}
1355			if (vflag) {
1356				printf("mask=0x%x,", use->rpu_ramask);
1357				printf("raflags=0x%x,", use->rpu_raflags);
1358				if (~use->rpu_vltime == 0)
1359					printf("vltime=infty,");
1360				else
1361					printf("vltime=%u,",
1362					    EXTRACT_32BITS(&use->rpu_vltime));
1363				if (~use->rpu_pltime == 0)
1364					printf("pltime=infty,");
1365				else
1366					printf("pltime=%u,",
1367					    EXTRACT_32BITS(&use->rpu_pltime));
1368			}
1369			if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
1370			    sizeof(hbuf)))
1371				printf("%s/%u/%u", hbuf, use->rpu_uselen,
1372				    use->rpu_keeplen);
1373			else
1374				printf("?/%u/%u", use->rpu_uselen,
1375				    use->rpu_keeplen);
1376			/*(*/
1377			printf(")");
1378		}
1379	}
1380
1381	return;
1382
1383trunc:
1384	fputs("[|icmp6]", stdout);
1385}
1386
1387#endif /* INET6 */
1388