156893Sfenner/*
256893Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
356893Sfenner *	The Regents of the University of California.  All rights reserved.
456893Sfenner *
556893Sfenner * Redistribution and use in source and binary forms, with or without
656893Sfenner * modification, are permitted provided that: (1) source code distributions
756893Sfenner * retain the above copyright notice and this paragraph in its entirety, (2)
856893Sfenner * distributions including binary code include the above copyright notice and
956893Sfenner * this paragraph in its entirety in the documentation or other materials
1056893Sfenner * provided with the distribution, and (3) all advertising materials mentioning
1156893Sfenner * features or use of this software display the following acknowledgement:
1256893Sfenner * ``This product includes software developed by the University of California,
1356893Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1456893Sfenner * the University nor the names of its contributors may be used to endorse
1556893Sfenner * or promote products derived from this software without specific prior
1656893Sfenner * written permission.
1756893Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1856893Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1956893Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2056893Sfenner */
2156893Sfenner
2256893Sfenner#ifndef lint
23127668Sbmsstatic const char rcsid[] _U_ =
24214478Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.86 2008-02-05 19:36:13 guy Exp $";
2556893Sfenner#endif
2656893Sfenner
2756893Sfenner#ifdef HAVE_CONFIG_H
2856893Sfenner#include "config.h"
2956893Sfenner#endif
3056893Sfenner
3156893Sfenner#ifdef INET6
3256893Sfenner
33127668Sbms#include <tcpdump-stdinc.h>
3456893Sfenner
3556893Sfenner#include <stdio.h>
3698524Sfenner#include <string.h>
3756893Sfenner
38147899Ssam#include "interface.h"
39147899Ssam#include "addrtoname.h"
40147899Ssam#include "extract.h"
41147899Ssam
4275115Sfenner#include "ip6.h"
4375115Sfenner#include "icmp6.h"
44127668Sbms#include "ipproto.h"
4556893Sfenner
4675115Sfenner#include "udp.h"
4775115Sfenner#include "ah.h"
4875115Sfenner
4998524Sfennerstatic const char *get_rtpref(u_int);
5098524Sfennerstatic const char *get_lifetime(u_int32_t);
5198524Sfennerstatic void print_lladdr(const u_char *, size_t);
52127668Sbmsstatic void icmp6_opt_print(const u_char *, int);
53127668Sbmsstatic void mld6_print(const u_char *);
54146773Ssamstatic void mldv2_report_print(const u_char *, u_int);
55146773Ssamstatic void mldv2_query_print(const u_char *, u_int);
56127668Sbmsstatic struct udphdr *get_upperlayer(u_char *, u_int *);
5775115Sfennerstatic void dnsname_print(const u_char *, const u_char *);
58127668Sbmsstatic void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
59127668Sbmsstatic void icmp6_rrenum_print(const u_char *, const u_char *);
6056893Sfenner
6175115Sfenner#ifndef abs
6275115Sfenner#define abs(a)	((0 < (a)) ? (a) : -(a))
6375115Sfenner#endif
6475115Sfenner
65214478Srpaulo/* inline the various RPL definitions */
66214478Srpaulo#define ND_RPL_MESSAGE 0x9B
67214478Srpaulo
68146773Ssamstatic struct tok icmp6_type_values[] = {
69146773Ssam    { ICMP6_DST_UNREACH, "destination unreachable"},
70146773Ssam    { ICMP6_PACKET_TOO_BIG, "packet too big"},
71146773Ssam    { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
72146773Ssam    { ICMP6_PARAM_PROB, "parameter problem"},
73146773Ssam    { ICMP6_ECHO_REQUEST, "echo request"},
74146773Ssam    { ICMP6_ECHO_REPLY, "echo reply"},
75147899Ssam    { MLD6_LISTENER_QUERY, "multicast listener query"},
76147899Ssam    { MLD6_LISTENER_REPORT, "multicast listener report"},
77147899Ssam    { MLD6_LISTENER_DONE, "multicast listener done"},
78147899Ssam    { ND_ROUTER_SOLICIT, "router solicitation"},
79146773Ssam    { ND_ROUTER_ADVERT, "router advertisement"},
80146773Ssam    { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
81162017Ssam    { ND_NEIGHBOR_ADVERT, "neighbor advertisement"},
82146773Ssam    { ND_REDIRECT, "redirect"},
83146773Ssam    { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
84146773Ssam    { IND_SOLICIT, "inverse neighbor solicitation"},
85146773Ssam    { IND_ADVERT, "inverse neighbor advertisement"},
86147899Ssam    { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
87146773Ssam    { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
88146773Ssam    { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
89146773Ssam    { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
90146773Ssam    { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
91146773Ssam    { ICMP6_WRUREQUEST, "who-are-you request"},
92146773Ssam    { ICMP6_WRUREPLY, "who-are-you reply"},
93146773Ssam    { ICMP6_NI_QUERY, "node information query"},
94146773Ssam    { ICMP6_NI_REPLY, "node information reply"},
95146773Ssam    { MLD6_MTRACE, "mtrace message"},
96146773Ssam    { MLD6_MTRACE_RESP, "mtrace response"},
97214478Srpaulo    { ND_RPL_MESSAGE,   "RPL"},
98146773Ssam    { 0,	NULL }
99146773Ssam};
100146773Ssam
101146773Ssamstatic struct tok icmp6_dst_unreach_code_values[] = {
102146773Ssam    { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
103146773Ssam    { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
104146773Ssam    { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
105146773Ssam    { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
106146773Ssam    { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
107146773Ssam    { 0,	NULL }
108146773Ssam};
109146773Ssam
110146773Ssamstatic struct tok icmp6_opt_pi_flag_values[] = {
111146773Ssam    { ND_OPT_PI_FLAG_ONLINK, "onlink" },
112146773Ssam    { ND_OPT_PI_FLAG_AUTO, "auto" },
113146773Ssam    { ND_OPT_PI_FLAG_ROUTER, "router" },
114146773Ssam    { 0,	NULL }
115146773Ssam};
116146773Ssam
117146773Ssamstatic struct tok icmp6_opt_ra_flag_values[] = {
118146773Ssam    { ND_RA_FLAG_MANAGED, "managed" },
119146773Ssam    { ND_RA_FLAG_OTHER, "other stateful"},
120146773Ssam    { ND_RA_FLAG_HOME_AGENT, "home agent"},
121146773Ssam    { 0,	NULL }
122146773Ssam};
123146773Ssam
124146773Ssamstatic struct tok icmp6_nd_na_flag_values[] = {
125146773Ssam    { ND_NA_FLAG_ROUTER, "router" },
126146773Ssam    { ND_NA_FLAG_SOLICITED, "solicited" },
127146773Ssam    { ND_NA_FLAG_OVERRIDE, "override" },
128146773Ssam    { 0,	NULL }
129146773Ssam};
130146773Ssam
131146773Ssam
132146773Ssamstatic struct tok icmp6_opt_values[] = {
133146773Ssam   { ND_OPT_SOURCE_LINKADDR, "source link-address"},
134146773Ssam   { ND_OPT_TARGET_LINKADDR, "destination link-address"},
135146773Ssam   { ND_OPT_PREFIX_INFORMATION, "prefix info"},
136146773Ssam   { ND_OPT_REDIRECTED_HEADER, "redirected header"},
137146773Ssam   { ND_OPT_MTU, "mtu"},
138214478Srpaulo   { ND_OPT_RDNSS, "rdnss"},
139252283Sdelphij   { ND_OPT_DNSSL, "dnssl"},
140162017Ssam   { ND_OPT_ADVINTERVAL, "advertisement interval"},
141146773Ssam   { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
142146773Ssam   { ND_OPT_ROUTE_INFO, "route info"},
143146773Ssam   { 0,	NULL }
144146773Ssam};
145146773Ssam
146146773Ssam/* mldv2 report types */
147146773Ssamstatic struct tok mldv2report2str[] = {
148146773Ssam	{ 1,	"is_in" },
149146773Ssam	{ 2,	"is_ex" },
150146773Ssam	{ 3,	"to_in" },
151146773Ssam	{ 4,	"to_ex" },
152146773Ssam	{ 5,	"allow" },
153146773Ssam	{ 6,	"block" },
154146773Ssam	{ 0,	NULL }
155146773Ssam};
156146773Ssam
15798524Sfennerstatic const char *
15898524Sfennerget_rtpref(u_int v)
15998524Sfenner{
16098524Sfenner	static const char *rtpref_str[] = {
16198524Sfenner		"medium",		/* 00 */
16298524Sfenner		"high",			/* 01 */
16398524Sfenner		"rsv",			/* 10 */
16498524Sfenner		"low"			/* 11 */
16598524Sfenner	};
16698524Sfenner
16798524Sfenner	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
16898524Sfenner}
16998524Sfenner
17098524Sfennerstatic const char *
17198524Sfennerget_lifetime(u_int32_t v)
17298524Sfenner{
17398524Sfenner	static char buf[20];
17498524Sfenner
17598524Sfenner	if (v == (u_int32_t)~0UL)
17698524Sfenner		return "infinity";
17798524Sfenner	else {
178252283Sdelphij		snprintf(buf, sizeof(buf), "%us", v);
17998524Sfenner		return buf;
18098524Sfenner	}
18198524Sfenner}
18298524Sfenner
18398524Sfennerstatic void
18498524Sfennerprint_lladdr(const u_int8_t *p, size_t l)
18598524Sfenner{
18698524Sfenner	const u_int8_t *ep, *q;
18798524Sfenner
18898524Sfenner	q = p;
18998524Sfenner	ep = p + l;
19098524Sfenner	while (l > 0 && q < ep) {
19198524Sfenner		if (q > p)
19298524Sfenner			printf(":");
19398524Sfenner		printf("%02x", *q++);
19498524Sfenner		l--;
19598524Sfenner	}
19698524Sfenner}
19798524Sfenner
198127668Sbmsstatic int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
199127668Sbms	u_int len)
200127668Sbms{
201236192Sdelphij	return (nextproto6_cksum(ip6, (const u_int8_t *)(void *)icp, len,
202236192Sdelphij	    IPPROTO_ICMPV6));
203127668Sbms}
204127668Sbms
205214478Srpauloenum ND_RPL_CODE {
206236192Sdelphij        ND_RPL_DIS   =0x00,
207236192Sdelphij        ND_RPL_DIO   =0x01,
208236192Sdelphij        ND_RPL_DAO   =0x02,
209236192Sdelphij        ND_RPL_DAO_ACK=0x03,
210236192Sdelphij        ND_RPL_SDIS  =0x80,
211236192Sdelphij        ND_RPL_SDIO  =0x81,
212236192Sdelphij        ND_RPL_SDAO  =0x82,
213236192Sdelphij        ND_RPL_SDAO_ACK=0x83,
214236192Sdelphij        ND_RPL_SCC   =0x8A,
215214478Srpaulo};
216214478Srpaulo
217214478Srpauloenum ND_RPL_DIO_FLAGS {
218214478Srpaulo        ND_RPL_DIO_GROUNDED = 0x80,
219214478Srpaulo        ND_RPL_DIO_DATRIG   = 0x40,
220214478Srpaulo        ND_RPL_DIO_DASUPPORT= 0x20,
221214478Srpaulo        ND_RPL_DIO_RES4     = 0x10,
222214478Srpaulo        ND_RPL_DIO_RES3     = 0x08,
223214478Srpaulo        ND_RPL_DIO_PRF_MASK = 0x07,  /* 3-bit preference */
224214478Srpaulo};
225214478Srpaulo
226214478Srpaulostruct nd_rpl_dio {
227214478Srpaulo        u_int8_t rpl_flags;
228214478Srpaulo        u_int8_t rpl_seq;
229214478Srpaulo        u_int8_t rpl_instanceid;
230214478Srpaulo        u_int8_t rpl_dagrank;
231214478Srpaulo        u_int8_t rpl_dagid[16];
232214478Srpaulo};
233214478Srpaulo
234214478Srpaulostatic void
235214478Srpaulorpl_print(netdissect_options *ndo,
236214478Srpaulo          const struct icmp6_hdr *hdr,
237214478Srpaulo          const u_char *bp, u_int length _U_)
238214478Srpaulo{
239214478Srpaulo        struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp;
240236192Sdelphij        int secured = hdr->icmp6_code & 0x80;
241236192Sdelphij        int basecode= hdr->icmp6_code & 0x7f;
242214478Srpaulo
243214478Srpaulo        ND_TCHECK(dio->rpl_dagid);
244214478Srpaulo
245236192Sdelphij        if(secured) {
246236192Sdelphij                ND_PRINT((ndo, ", (SEC)"));
247236192Sdelphij        } else {
248236192Sdelphij                ND_PRINT((ndo, ", (CLR)"));
249236192Sdelphij        }
250236192Sdelphij
251236192Sdelphij        switch(basecode) {
252236192Sdelphij        case ND_RPL_DIS:
253236192Sdelphij                ND_PRINT((ndo, "DODAG Information Solicitation"));
254214478Srpaulo                if(ndo->ndo_vflag) {
255214478Srpaulo                }
256214478Srpaulo                break;
257236192Sdelphij        case ND_RPL_DIO:
258236192Sdelphij                ND_PRINT((ndo, "DODAG Information Object"));
259214478Srpaulo                if(ndo->ndo_vflag) {
260214478Srpaulo                        char dagid[65];
261214478Srpaulo                        char *d = dagid;
262214478Srpaulo                        int  i;
263214478Srpaulo                        for(i=0;i<16;i++) {
264214478Srpaulo                                if(isprint(dio->rpl_dagid[i])) {
265214478Srpaulo                                        *d++ = dio->rpl_dagid[i];
266214478Srpaulo                                } else {
267214478Srpaulo                                        int cnt=snprintf(d,4,"0x%02x",
268214478Srpaulo                                                         dio->rpl_dagid[i]);
269214478Srpaulo                                        d += cnt;
270214478Srpaulo                                }
271214478Srpaulo                        }
272214478Srpaulo                        *d++ = '\0';
273214478Srpaulo                        ND_PRINT((ndo, " [seq:%u,instance:%u,rank:%u,dagid:%s]",
274214478Srpaulo                                  dio->rpl_seq,
275214478Srpaulo                                  dio->rpl_instanceid,
276214478Srpaulo                                  dio->rpl_dagrank,
277214478Srpaulo                                  dagid));
278214478Srpaulo                }
279214478Srpaulo                break;
280214478Srpaulo        case ND_RPL_DAO:
281236192Sdelphij                ND_PRINT((ndo, "Destination Advertisement Object"));
282214478Srpaulo                if(ndo->ndo_vflag) {
283214478Srpaulo                }
284214478Srpaulo                break;
285236192Sdelphij        case ND_RPL_DAO_ACK:
286236192Sdelphij                ND_PRINT((ndo, "Destination Advertisement Object Ack"));
287236192Sdelphij                if(ndo->ndo_vflag) {
288236192Sdelphij                }
289236192Sdelphij                break;
290214478Srpaulo        default:
291236192Sdelphij                ND_PRINT((ndo, "RPL message, unknown code %u",hdr->icmp6_code));
292214478Srpaulo                break;
293214478Srpaulo        }
294214478Srpaulo	return;
295214478Srpaulotrunc:
296214478Srpaulo	ND_PRINT((ndo," [|truncated]"));
297214478Srpaulo	return;
298214478Srpaulo
299214478Srpaulo}
300214478Srpaulo
301214478Srpaulo
30256893Sfennervoid
303214478Srpauloicmp6_print(netdissect_options *ndo,
304214478Srpaulo            const u_char *bp, u_int length, const u_char *bp2, int fragmented)
30556893Sfenner{
30675115Sfenner	const struct icmp6_hdr *dp;
30798524Sfenner	const struct ip6_hdr *ip;
30898524Sfenner	const struct ip6_hdr *oip;
30998524Sfenner	const struct udphdr *ouh;
31098524Sfenner	int dport;
31198524Sfenner	const u_char *ep;
312127668Sbms	u_int prot;
31356893Sfenner
31456893Sfenner	dp = (struct icmp6_hdr *)bp;
31556893Sfenner	ip = (struct ip6_hdr *)bp2;
31656893Sfenner	oip = (struct ip6_hdr *)(dp + 1);
31775115Sfenner	/* 'ep' points to the end of available data. */
31856893Sfenner	ep = snapend;
31956893Sfenner
320127668Sbms	TCHECK(dp->icmp6_cksum);
321127668Sbms
322127668Sbms	if (vflag && !fragmented) {
323236192Sdelphij		u_int16_t sum, udp_sum;
324127668Sbms
325127668Sbms		if (TTEST2(bp[0], length)) {
326236192Sdelphij			udp_sum = EXTRACT_16BITS(&dp->icmp6_cksum);
327127668Sbms			sum = icmp6_cksum(ip, dp, length);
328127668Sbms			if (sum != 0)
329236192Sdelphij				(void)printf("[bad icmp6 cksum 0x%04x -> 0x%04x!] ",
330236192Sdelphij				    udp_sum,
331236192Sdelphij				    in_cksum_shouldbe(udp_sum, sum));
332127668Sbms			else
333127668Sbms				(void)printf("[icmp6 sum ok] ");
334127668Sbms		}
335127668Sbms	}
336127668Sbms
337146773Ssam        printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type));
338146773Ssam
339146773Ssam        /* display cosmetics: print the packet length for printer that use the vflag now */
340229244Sdim        if (vflag && (dp->icmp6_type == ND_ROUTER_SOLICIT ||
341229244Sdim                      dp->icmp6_type == ND_ROUTER_ADVERT ||
342229244Sdim                      dp->icmp6_type == ND_NEIGHBOR_ADVERT ||
343229244Sdim                      dp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
344229244Sdim                      dp->icmp6_type == ND_REDIRECT ||
345229244Sdim                      dp->icmp6_type == ICMP6_HADISCOV_REPLY ||
346229244Sdim                      dp->icmp6_type == ICMP6_MOBILEPREFIX_ADVERT ))
347146773Ssam            printf(", length %u", length);
348146773Ssam
34975115Sfenner	switch (dp->icmp6_type) {
35056893Sfenner	case ICMP6_DST_UNREACH:
35156893Sfenner		TCHECK(oip->ip6_dst);
352146773Ssam                printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code));
35356893Sfenner		switch (dp->icmp6_code) {
354146773Ssam
355146773Ssam		case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
35656893Sfenner		case ICMP6_DST_UNREACH_ADMIN:
357146773Ssam		case ICMP6_DST_UNREACH_ADDR:
358146773Ssam                        printf(" %s",ip6addr_string(&oip->ip6_dst));
359146773Ssam                        break;
36056893Sfenner		case ICMP6_DST_UNREACH_BEYONDSCOPE:
361146773Ssam			printf(" %s, source address %s",
36256893Sfenner			       ip6addr_string(&oip->ip6_dst),
36356893Sfenner			       ip6addr_string(&oip->ip6_src));
36456893Sfenner			break;
36556893Sfenner		case ICMP6_DST_UNREACH_NOPORT:
36675115Sfenner			if ((ouh = get_upperlayer((u_char *)oip, &prot))
36775115Sfenner			    == NULL)
36875115Sfenner				goto trunc;
36975115Sfenner
370127668Sbms			dport = EXTRACT_16BITS(&ouh->uh_dport);
37175115Sfenner			switch (prot) {
37256893Sfenner			case IPPROTO_TCP:
373146773Ssam				printf(", %s tcp port %s",
37456893Sfenner					ip6addr_string(&oip->ip6_dst),
37556893Sfenner					tcpport_string(dport));
37656893Sfenner				break;
37756893Sfenner			case IPPROTO_UDP:
378146773Ssam				printf(", %s udp port %s",
37956893Sfenner					ip6addr_string(&oip->ip6_dst),
38056893Sfenner					udpport_string(dport));
38156893Sfenner				break;
38256893Sfenner			default:
383146773Ssam				printf(", %s protocol %d port %d unreachable",
38456893Sfenner					ip6addr_string(&oip->ip6_dst),
38556893Sfenner					oip->ip6_nxt, dport);
38656893Sfenner				break;
38756893Sfenner			}
38856893Sfenner			break;
38956893Sfenner		default:
390146773Ssam                    if (vflag <= 1) {
391146773Ssam                            print_unknown_data(bp,"\n\t",length);
392146773Ssam                            return;
393146773Ssam                    }
394146773Ssam                    break;
39556893Sfenner		}
39656893Sfenner		break;
39756893Sfenner	case ICMP6_PACKET_TOO_BIG:
39856893Sfenner		TCHECK(dp->icmp6_mtu);
399146773Ssam		printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu));
40056893Sfenner		break;
40156893Sfenner	case ICMP6_TIME_EXCEEDED:
40256893Sfenner		TCHECK(oip->ip6_dst);
40356893Sfenner		switch (dp->icmp6_code) {
40456893Sfenner		case ICMP6_TIME_EXCEED_TRANSIT:
405146773Ssam			printf(" for %s",
40656893Sfenner				ip6addr_string(&oip->ip6_dst));
40756893Sfenner			break;
40856893Sfenner		case ICMP6_TIME_EXCEED_REASSEMBLY:
409146773Ssam			printf(" (reassembly)");
41056893Sfenner			break;
41156893Sfenner		default:
412146773Ssam			printf(", unknown code (%u)", dp->icmp6_code);
41356893Sfenner			break;
41456893Sfenner		}
41556893Sfenner		break;
41656893Sfenner	case ICMP6_PARAM_PROB:
41756893Sfenner		TCHECK(oip->ip6_dst);
41856893Sfenner		switch (dp->icmp6_code) {
41956893Sfenner		case ICMP6_PARAMPROB_HEADER:
420146773Ssam			printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
42156893Sfenner			break;
42256893Sfenner		case ICMP6_PARAMPROB_NEXTHEADER:
423146773Ssam			printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
42456893Sfenner			break;
42556893Sfenner		case ICMP6_PARAMPROB_OPTION:
426146773Ssam			printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
42756893Sfenner			break;
42856893Sfenner		default:
429146773Ssam			printf(", code-#%d",
43056893Sfenner			       dp->icmp6_code);
43156893Sfenner			break;
43256893Sfenner		}
43356893Sfenner		break;
43456893Sfenner	case ICMP6_ECHO_REQUEST:
43556893Sfenner	case ICMP6_ECHO_REPLY:
436127668Sbms		TCHECK(dp->icmp6_seq);
437146773Ssam		printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq));
43856893Sfenner		break;
43956893Sfenner	case ICMP6_MEMBERSHIP_QUERY:
440146773Ssam		if (length == MLD_MINLEN) {
441146773Ssam			mld6_print((const u_char *)dp);
442146773Ssam		} else if (length >= MLDV2_MINLEN) {
443252283Sdelphij			printf(" v2");
444146773Ssam			mldv2_query_print((const u_char *)dp, length);
445146773Ssam		} else {
446146773Ssam			printf(" unknown-version (len %u) ", length);
447146773Ssam		}
44856893Sfenner		break;
44956893Sfenner	case ICMP6_MEMBERSHIP_REPORT:
45056893Sfenner		mld6_print((const u_char *)dp);
45156893Sfenner		break;
45256893Sfenner	case ICMP6_MEMBERSHIP_REDUCTION:
45356893Sfenner		mld6_print((const u_char *)dp);
45456893Sfenner		break;
45556893Sfenner	case ND_ROUTER_SOLICIT:
456146773Ssam#define RTSOLLEN 8
45756893Sfenner		if (vflag) {
45875115Sfenner			icmp6_opt_print((const u_char *)dp + RTSOLLEN,
459127668Sbms					length - RTSOLLEN);
46056893Sfenner		}
46156893Sfenner		break;
46256893Sfenner	case ND_ROUTER_ADVERT:
463146773Ssam#define RTADVLEN 16
46456893Sfenner		if (vflag) {
46556893Sfenner			struct nd_router_advert *p;
46656893Sfenner
46756893Sfenner			p = (struct nd_router_advert *)dp;
46856893Sfenner			TCHECK(p->nd_ra_retransmit);
469146773Ssam			printf("\n\thop limit %u, Flags [%s]" \
470146773Ssam                               ", pref %s, router lifetime %us, reachable time %us, retrans time %us",
471146773Ssam                               (u_int)p->nd_ra_curhoplimit,
472146773Ssam                               bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)),
473146773Ssam                               get_rtpref(p->nd_ra_flags_reserved),
474146773Ssam                               EXTRACT_16BITS(&p->nd_ra_router_lifetime),
475146773Ssam                               EXTRACT_32BITS(&p->nd_ra_reachable),
476146773Ssam                               EXTRACT_32BITS(&p->nd_ra_retransmit));
47798524Sfenner
47875115Sfenner			icmp6_opt_print((const u_char *)dp + RTADVLEN,
479127668Sbms					length - RTADVLEN);
48056893Sfenner		}
48156893Sfenner		break;
48256893Sfenner	case ND_NEIGHBOR_SOLICIT:
48356893Sfenner	    {
48456893Sfenner		struct nd_neighbor_solicit *p;
48556893Sfenner		p = (struct nd_neighbor_solicit *)dp;
48656893Sfenner		TCHECK(p->nd_ns_target);
487146773Ssam		printf(", who has %s", ip6addr_string(&p->nd_ns_target));
48856893Sfenner		if (vflag) {
48956893Sfenner#define NDSOLLEN 24
49075115Sfenner			icmp6_opt_print((const u_char *)dp + NDSOLLEN,
491127668Sbms					length - NDSOLLEN);
49256893Sfenner		}
49356893Sfenner	    }
49456893Sfenner		break;
49556893Sfenner	case ND_NEIGHBOR_ADVERT:
49656893Sfenner	    {
49756893Sfenner		struct nd_neighbor_advert *p;
49856893Sfenner
49956893Sfenner		p = (struct nd_neighbor_advert *)dp;
50056893Sfenner		TCHECK(p->nd_na_target);
501146773Ssam		printf(", tgt is %s",
50256893Sfenner			ip6addr_string(&p->nd_na_target));
50375115Sfenner		if (vflag) {
504146773Ssam                        printf(", Flags [%s]",
505146773Ssam                               bittok2str(icmp6_nd_na_flag_values,
506146773Ssam                                          "none",
507146773Ssam                                          EXTRACT_32BITS(&p->nd_na_flags_reserved)));
50856893Sfenner#define NDADVLEN 24
50975115Sfenner			icmp6_opt_print((const u_char *)dp + NDADVLEN,
510127668Sbms					length - NDADVLEN);
51175115Sfenner#undef NDADVLEN
51256893Sfenner		}
51356893Sfenner	    }
51456893Sfenner		break;
51556893Sfenner	case ND_REDIRECT:
51656893Sfenner#define RDR(i) ((struct nd_redirect *)(i))
51756893Sfenner		TCHECK(RDR(dp)->nd_rd_dst);
518146773Ssam		printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst));
519127668Sbms		TCHECK(RDR(dp)->nd_rd_target);
52075115Sfenner		printf(" to %s",
52175115Sfenner		    getname6((const u_char*)&RDR(dp)->nd_rd_target));
52256893Sfenner#define REDIRECTLEN 40
52356893Sfenner		if (vflag) {
52456893Sfenner			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
525127668Sbms					length - REDIRECTLEN);
52656893Sfenner		}
52756893Sfenner		break;
52875115Sfenner#undef REDIRECTLEN
52975115Sfenner#undef RDR
53056893Sfenner	case ICMP6_ROUTER_RENUMBERING:
531127668Sbms		icmp6_rrenum_print(bp, ep);
53256893Sfenner		break;
53375115Sfenner	case ICMP6_NI_QUERY:
53475115Sfenner	case ICMP6_NI_REPLY:
535127668Sbms		icmp6_nodeinfo_print(length, bp, ep);
53656893Sfenner		break;
537146773Ssam	case IND_SOLICIT:
538146773Ssam	case IND_ADVERT:
539146773Ssam		break;
540146773Ssam	case ICMP6_V2_MEMBERSHIP_REPORT:
541146773Ssam		mldv2_report_print((const u_char *) dp, length);
542146773Ssam		break;
543146773Ssam	case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
544127668Sbms	case ICMP6_HADISCOV_REQUEST:
545146773Ssam                TCHECK(dp->icmp6_data16[0]);
546146773Ssam                printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
547146773Ssam                break;
548127668Sbms	case ICMP6_HADISCOV_REPLY:
549127668Sbms		if (vflag) {
550127668Sbms			struct in6_addr *in6;
551127668Sbms			u_char *cp;
552127668Sbms
553127668Sbms			TCHECK(dp->icmp6_data16[0]);
554146773Ssam			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
555127668Sbms			cp = (u_char *)dp + length;
556127668Sbms			in6 = (struct in6_addr *)(dp + 1);
557127668Sbms			for (; (u_char *)in6 < cp; in6++) {
558127668Sbms				TCHECK(*in6);
559127668Sbms				printf(", %s", ip6addr_string(in6));
560127668Sbms			}
561127668Sbms		}
562127668Sbms		break;
563127668Sbms	case ICMP6_MOBILEPREFIX_ADVERT:
564127668Sbms		if (vflag) {
565127668Sbms			TCHECK(dp->icmp6_data16[0]);
566146773Ssam			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
567127668Sbms			if (dp->icmp6_data16[1] & 0xc0)
568127668Sbms				printf(" ");
569127668Sbms			if (dp->icmp6_data16[1] & 0x80)
570127668Sbms				printf("M");
571127668Sbms			if (dp->icmp6_data16[1] & 0x40)
572127668Sbms				printf("O");
573127668Sbms#define MPADVLEN 8
574127668Sbms			icmp6_opt_print((const u_char *)dp + MPADVLEN,
575127668Sbms					length - MPADVLEN);
576127668Sbms		}
577127668Sbms		break;
578214478Srpaulo        case ND_RPL_MESSAGE:
579214478Srpaulo                rpl_print(ndo, dp, &dp->icmp6_data8[0], length);
580214478Srpaulo                break;
58156893Sfenner	default:
582146773Ssam                printf(", length %u", length);
583146773Ssam                if (vflag <= 1)
584146773Ssam                    print_unknown_data(bp,"\n\t", length);
585146773Ssam                return;
586146773Ssam        }
587146773Ssam        if (!vflag)
588146773Ssam            printf(", length %u", length);
58956893Sfenner	return;
59056893Sfennertrunc:
59156893Sfenner	fputs("[|icmp6]", stdout);
59256893Sfenner}
59356893Sfenner
59475115Sfennerstatic struct udphdr *
595127668Sbmsget_upperlayer(u_char *bp, u_int *prot)
59675115Sfenner{
59798524Sfenner	const u_char *ep;
59875115Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
59975115Sfenner	struct udphdr *uh;
60075115Sfenner	struct ip6_hbh *hbh;
60175115Sfenner	struct ip6_frag *fragh;
60275115Sfenner	struct ah *ah;
603127668Sbms	u_int nh;
604127668Sbms	int hlen;
60575115Sfenner
60675115Sfenner	/* 'ep' points to the end of available data. */
60775115Sfenner	ep = snapend;
60875115Sfenner
609127668Sbms	if (!TTEST(ip6->ip6_nxt))
61075115Sfenner		return NULL;
61175115Sfenner
61275115Sfenner	nh = ip6->ip6_nxt;
61375115Sfenner	hlen = sizeof(struct ip6_hdr);
61475115Sfenner
615147899Ssam	while (bp < ep) {
61675115Sfenner		bp += hlen;
61775115Sfenner
61875115Sfenner		switch(nh) {
61975115Sfenner		case IPPROTO_UDP:
62075115Sfenner		case IPPROTO_TCP:
62175115Sfenner			uh = (struct udphdr *)bp;
62275115Sfenner			if (TTEST(uh->uh_dport)) {
62375115Sfenner				*prot = nh;
62475115Sfenner				return(uh);
62575115Sfenner			}
62675115Sfenner			else
62775115Sfenner				return(NULL);
62875115Sfenner			/* NOTREACHED */
62975115Sfenner
63075115Sfenner		case IPPROTO_HOPOPTS:
63175115Sfenner		case IPPROTO_DSTOPTS:
63275115Sfenner		case IPPROTO_ROUTING:
63375115Sfenner			hbh = (struct ip6_hbh *)bp;
634127668Sbms			if (!TTEST(hbh->ip6h_len))
63575115Sfenner				return(NULL);
63675115Sfenner			nh = hbh->ip6h_nxt;
63775115Sfenner			hlen = (hbh->ip6h_len + 1) << 3;
63875115Sfenner			break;
63975115Sfenner
64075115Sfenner		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
64175115Sfenner			fragh = (struct ip6_frag *)bp;
642127668Sbms			if (!TTEST(fragh->ip6f_offlg))
64375115Sfenner				return(NULL);
64475115Sfenner			/* fragments with non-zero offset are meaningless */
645127668Sbms			if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
64675115Sfenner				return(NULL);
64775115Sfenner			nh = fragh->ip6f_nxt;
64875115Sfenner			hlen = sizeof(struct ip6_frag);
64975115Sfenner			break;
65075115Sfenner
65175115Sfenner		case IPPROTO_AH:
65275115Sfenner			ah = (struct ah *)bp;
653127668Sbms			if (!TTEST(ah->ah_len))
65475115Sfenner				return(NULL);
65575115Sfenner			nh = ah->ah_nxt;
65675115Sfenner			hlen = (ah->ah_len + 2) << 2;
65775115Sfenner			break;
65875115Sfenner
65975115Sfenner		default:	/* unknown or undecodable header */
66075115Sfenner			*prot = nh; /* meaningless, but set here anyway */
66175115Sfenner			return(NULL);
66275115Sfenner		}
66375115Sfenner	}
66475115Sfenner
66575115Sfenner	return(NULL);		/* should be notreached, though */
66675115Sfenner}
66775115Sfenner
668127668Sbmsstatic void
66998524Sfennericmp6_opt_print(const u_char *bp, int resid)
67056893Sfenner{
67198524Sfenner	const struct nd_opt_hdr *op;
67298524Sfenner	const struct nd_opt_hdr *opl;	/* why there's no struct? */
67398524Sfenner	const struct nd_opt_prefix_info *opp;
67498524Sfenner	const struct icmp6_opts_redirect *opr;
67598524Sfenner	const struct nd_opt_mtu *opm;
676214478Srpaulo	const struct nd_opt_rdnss *oprd;
677252283Sdelphij	const struct nd_opt_dnssl *opds;
67898524Sfenner	const struct nd_opt_advinterval *opa;
679127668Sbms	const struct nd_opt_homeagent_info *oph;
68098524Sfenner	const struct nd_opt_route_info *opri;
681252283Sdelphij	const u_char *cp, *ep, *domp;
68298524Sfenner	struct in6_addr in6, *in6p;
68398524Sfenner	size_t l;
684214478Srpaulo	u_int i;
68556893Sfenner
68656893Sfenner#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
68756893Sfenner
68898524Sfenner	cp = bp;
68975115Sfenner	/* 'ep' points to the end of available data. */
69056893Sfenner	ep = snapend;
69156893Sfenner
69298524Sfenner	while (cp < ep) {
69398524Sfenner		op = (struct nd_opt_hdr *)cp;
69498524Sfenner
69598524Sfenner		ECHECK(op->nd_opt_len);
69698524Sfenner		if (resid <= 0)
69798524Sfenner			return;
69898524Sfenner		if (op->nd_opt_len == 0)
69956893Sfenner			goto trunc;
70098524Sfenner		if (cp + (op->nd_opt_len << 3) > ep)
70156893Sfenner			goto trunc;
70298524Sfenner
703146773Ssam                printf("\n\t  %s option (%u), length %u (%u): ",
704146773Ssam                       tok2str(icmp6_opt_values, "unknown", op->nd_opt_type),
705146773Ssam                       op->nd_opt_type,
706146773Ssam                       op->nd_opt_len << 3,
707146773Ssam                       op->nd_opt_len);
708146773Ssam
70998524Sfenner		switch (op->nd_opt_type) {
71098524Sfenner		case ND_OPT_SOURCE_LINKADDR:
71198524Sfenner			opl = (struct nd_opt_hdr *)op;
71298524Sfenner			l = (op->nd_opt_len << 3) - 2;
71398524Sfenner			print_lladdr(cp + 2, l);
71498524Sfenner			break;
71598524Sfenner		case ND_OPT_TARGET_LINKADDR:
71698524Sfenner			opl = (struct nd_opt_hdr *)op;
71798524Sfenner			l = (op->nd_opt_len << 3) - 2;
71898524Sfenner			print_lladdr(cp + 2, l);
71998524Sfenner			break;
72098524Sfenner		case ND_OPT_PREFIX_INFORMATION:
72198524Sfenner			opp = (struct nd_opt_prefix_info *)op;
72298524Sfenner			TCHECK(opp->nd_opt_pi_prefix);
723252283Sdelphij                        printf("%s/%u%s, Flags [%s], valid time %s",
724146773Ssam                               ip6addr_string(&opp->nd_opt_pi_prefix),
725146773Ssam                               opp->nd_opt_pi_prefix_len,
726146773Ssam                               (op->nd_opt_len != 4) ? "badlen" : "",
727146773Ssam                               bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved),
728146773Ssam                               get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
729252283Sdelphij                        printf(", pref. time %s", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
73098524Sfenner			break;
73198524Sfenner		case ND_OPT_REDIRECTED_HEADER:
73298524Sfenner			opr = (struct icmp6_opts_redirect *)op;
733146773Ssam                        print_unknown_data(bp,"\n\t    ",op->nd_opt_len<<3);
73498524Sfenner			/* xxx */
73598524Sfenner			break;
73698524Sfenner		case ND_OPT_MTU:
73798524Sfenner			opm = (struct nd_opt_mtu *)op;
73898524Sfenner			TCHECK(opm->nd_opt_mtu_mtu);
739146773Ssam			printf(" %u%s",
740146773Ssam                               EXTRACT_32BITS(&opm->nd_opt_mtu_mtu),
741146773Ssam                               (op->nd_opt_len != 1) ? "bad option length" : "" );
742146773Ssam                        break;
743214478Srpaulo		case ND_OPT_RDNSS:
744214478Srpaulo			oprd = (struct nd_opt_rdnss *)op;
745214478Srpaulo			l = (op->nd_opt_len - 1) / 2;
746214478Srpaulo			printf(" lifetime %us,",
747214478Srpaulo				EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime));
748214478Srpaulo			for (i = 0; i < l; i++) {
749214478Srpaulo				TCHECK(oprd->nd_opt_rdnss_addr[i]);
750214478Srpaulo				printf(" addr: %s",
751214478Srpaulo				    ip6addr_string(&oprd->nd_opt_rdnss_addr[i]));
752214478Srpaulo			}
753214478Srpaulo			break;
754252283Sdelphij		case ND_OPT_DNSSL:
755252283Sdelphij			opds = (struct nd_opt_dnssl *)op;
756252283Sdelphij			printf(" lifetime %us, domain(s):",
757252283Sdelphij				EXTRACT_32BITS(&opds->nd_opt_dnssl_lifetime));
758252283Sdelphij			domp = cp + 8; /* domain names, variable-sized, RFC1035-encoded */
759252283Sdelphij			while (domp < cp + (op->nd_opt_len << 3) && *domp != '\0')
760252283Sdelphij			{
761252283Sdelphij				printf (" ");
762252283Sdelphij				if ((domp = ns_nprint (domp, bp)) == NULL)
763252283Sdelphij					goto trunc;
764252283Sdelphij			}
765252283Sdelphij			break;
76698524Sfenner		case ND_OPT_ADVINTERVAL:
76798524Sfenner			opa = (struct nd_opt_advinterval *)op;
76898524Sfenner			TCHECK(opa->nd_opt_adv_interval);
769242485Sdelphij			printf(" %ums", EXTRACT_32BITS(&opa->nd_opt_adv_interval));
770127668Sbms			break;
771127668Sbms		case ND_OPT_HOMEAGENT_INFO:
772127668Sbms			oph = (struct nd_opt_homeagent_info *)op;
773127668Sbms			TCHECK(oph->nd_opt_hai_lifetime);
774146773Ssam			printf(" preference %u, lifetime %u",
775146773Ssam                               EXTRACT_16BITS(&oph->nd_opt_hai_preference),
776146773Ssam                               EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
777127668Sbms			break;
77898524Sfenner		case ND_OPT_ROUTE_INFO:
77998524Sfenner			opri = (struct nd_opt_route_info *)op;
78098524Sfenner			TCHECK(opri->nd_opt_rti_lifetime);
78198524Sfenner			memset(&in6, 0, sizeof(in6));
78298524Sfenner			in6p = (struct in6_addr *)(opri + 1);
78398524Sfenner			switch (op->nd_opt_len) {
78498524Sfenner			case 1:
78598524Sfenner				break;
78698524Sfenner			case 2:
78798524Sfenner				TCHECK2(*in6p, 8);
78898524Sfenner				memcpy(&in6, opri + 1, 8);
78998524Sfenner				break;
79098524Sfenner			case 3:
79198524Sfenner				TCHECK(*in6p);
79298524Sfenner				memcpy(&in6, opri + 1, sizeof(in6));
79398524Sfenner				break;
79498524Sfenner			default:
79598524Sfenner				goto trunc;
79698524Sfenner			}
79798524Sfenner			printf(" %s/%u", ip6addr_string(&in6),
79898524Sfenner			    opri->nd_opt_rti_prefixlen);
79998524Sfenner			printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
80098524Sfenner			printf(", lifetime=%s",
801127668Sbms			    get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
80298524Sfenner			break;
80398524Sfenner		default:
804146773Ssam                        if (vflag <= 1) {
805146773Ssam                            print_unknown_data(cp+2,"\n\t  ", (op->nd_opt_len << 3) - 2); /* skip option header */
806146773Ssam                            return;
807146773Ssam                        }
808146773Ssam                        break;
80956893Sfenner		}
810146773Ssam                /* do we want to see an additional hexdump ? */
811146773Ssam                if (vflag> 1)
812146773Ssam                    print_unknown_data(cp+2,"\n\t    ", (op->nd_opt_len << 3) - 2); /* skip option header */
81398524Sfenner
81498524Sfenner		cp += op->nd_opt_len << 3;
81598524Sfenner		resid -= op->nd_opt_len << 3;
81656893Sfenner	}
81756893Sfenner	return;
81898524Sfenner
81956893Sfenner trunc:
82056893Sfenner	fputs("[ndp opt]", stdout);
82156893Sfenner	return;
82256893Sfenner#undef ECHECK
82356893Sfenner}
82456893Sfenner
825127668Sbmsstatic void
82698524Sfennermld6_print(const u_char *bp)
82756893Sfenner{
82898524Sfenner	struct mld6_hdr *mp = (struct mld6_hdr *)bp;
82998524Sfenner	const u_char *ep;
83056893Sfenner
83175115Sfenner	/* 'ep' points to the end of available data. */
83256893Sfenner	ep = snapend;
83356893Sfenner
83456893Sfenner	if ((u_char *)mp + sizeof(*mp) > ep)
83556893Sfenner		return;
83656893Sfenner
837127668Sbms	printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
83856893Sfenner	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
83975115Sfenner}
84056893Sfenner
84175115Sfennerstatic void
842146773Ssammldv2_report_print(const u_char *bp, u_int len)
843146773Ssam{
844146773Ssam    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
845146773Ssam    u_int group, nsrcs, ngroups;
846146773Ssam    u_int i, j;
847146773Ssam
848146773Ssam    /* Minimum len is 8 */
849146773Ssam    if (len < 8) {
850146773Ssam	printf(" [invalid len %d]", len);
851146773Ssam	return;
852146773Ssam    }
853146773Ssam
854146773Ssam    TCHECK(icp->icmp6_data16[1]);
855214478Srpaulo    ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]);
856146773Ssam    printf(", %d group record(s)", ngroups);
857146773Ssam    if (vflag > 0) {
858146773Ssam	/* Print the group records */
859146773Ssam	group = 8;
860146773Ssam        for (i = 0; i < ngroups; i++) {
861146773Ssam	    /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
862146773Ssam	    if (len < group + 20) {
863146773Ssam		printf(" [invalid number of groups]");
864146773Ssam		return;
865146773Ssam	    }
866162017Ssam            TCHECK2(bp[group + 4], sizeof(struct in6_addr));
867146773Ssam            printf(" [gaddr %s", ip6addr_string(&bp[group + 4]));
868146773Ssam	    printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]",
869146773Ssam								bp[group]));
870146773Ssam            nsrcs = (bp[group + 2] << 8) + bp[group + 3];
871146773Ssam	    /* Check the number of sources and print them */
872162017Ssam	    if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) {
873146773Ssam		printf(" [invalid number of sources %d]", nsrcs);
874146773Ssam		return;
875146773Ssam	    }
876146773Ssam            if (vflag == 1)
877146773Ssam                printf(", %d source(s)", nsrcs);
878146773Ssam            else {
879146773Ssam		/* Print the sources */
880146773Ssam                (void)printf(" {");
881146773Ssam                for (j = 0; j < nsrcs; j++) {
882162017Ssam                    TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)],
883162017Ssam                            sizeof(struct in6_addr));
884162017Ssam		    printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)]));
885146773Ssam		}
886146773Ssam                (void)printf(" }");
887146773Ssam            }
888146773Ssam	    /* Next group record */
889162017Ssam            group += 20 + nsrcs * sizeof(struct in6_addr);
890146773Ssam	    printf("]");
891146773Ssam        }
892146773Ssam    }
893146773Ssam    return;
894146773Ssamtrunc:
895146773Ssam    (void)printf("[|icmp6]");
896146773Ssam    return;
897146773Ssam}
898146773Ssam
899146773Ssamstatic void
900146773Ssammldv2_query_print(const u_char *bp, u_int len)
901146773Ssam{
902146773Ssam    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
903146773Ssam    u_int mrc;
904146773Ssam    int mrt, qqi;
905146773Ssam    u_int nsrcs;
906146773Ssam    register u_int i;
907146773Ssam
908146773Ssam    /* Minimum len is 28 */
909146773Ssam    if (len < 28) {
910146773Ssam	printf(" [invalid len %d]", len);
911146773Ssam	return;
912146773Ssam    }
913146773Ssam    TCHECK(icp->icmp6_data16[0]);
914214478Srpaulo    mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]);
915146773Ssam    if (mrc < 32768) {
916146773Ssam	mrt = mrc;
917146773Ssam    } else {
918146773Ssam        mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
919146773Ssam    }
920146773Ssam    if (vflag) {
921146773Ssam	(void)printf(" [max resp delay=%d]", mrt);
922146773Ssam    }
923162017Ssam    TCHECK2(bp[8], sizeof(struct in6_addr));
924146773Ssam    printf(" [gaddr %s", ip6addr_string(&bp[8]));
925146773Ssam
926146773Ssam    if (vflag) {
927146773Ssam        TCHECK(bp[25]);
928146773Ssam	if (bp[24] & 0x08) {
929146773Ssam		printf(" sflag");
930146773Ssam	}
931146773Ssam	if (bp[24] & 0x07) {
932146773Ssam		printf(" robustness=%d", bp[24] & 0x07);
933146773Ssam	}
934146773Ssam	if (bp[25] < 128) {
935146773Ssam		qqi = bp[25];
936146773Ssam	} else {
937146773Ssam		qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
938146773Ssam	}
939146773Ssam	printf(" qqi=%d", qqi);
940146773Ssam    }
941146773Ssam
942146773Ssam    TCHECK2(bp[26], 2);
943214478Srpaulo    nsrcs = EXTRACT_16BITS(&bp[26]);
944146773Ssam    if (nsrcs > 0) {
945162017Ssam	if (len < 28 + nsrcs * sizeof(struct in6_addr))
946146773Ssam	    printf(" [invalid number of sources]");
947146773Ssam	else if (vflag > 1) {
948146773Ssam	    printf(" {");
949146773Ssam	    for (i = 0; i < nsrcs; i++) {
950162017Ssam		TCHECK2(bp[28 + i * sizeof(struct in6_addr)],
951162017Ssam                        sizeof(struct in6_addr));
952162017Ssam		printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)]));
953146773Ssam	    }
954146773Ssam	    printf(" }");
955146773Ssam	} else
956146773Ssam	    printf(", %d source(s)", nsrcs);
957146773Ssam    }
958146773Ssam    printf("]");
959146773Ssam    return;
960146773Ssamtrunc:
961146773Ssam    (void)printf("[|icmp6]");
962146773Ssam    return;
963146773Ssam}
964146773Ssam
965214478Srpaulostatic void
96675115Sfennerdnsname_print(const u_char *cp, const u_char *ep)
96775115Sfenner{
96875115Sfenner	int i;
96975115Sfenner
97075115Sfenner	/* DNS name decoding - no decompression */
97175115Sfenner	printf(", \"");
97275115Sfenner	while (cp < ep) {
97375115Sfenner		i = *cp++;
97475115Sfenner		if (i) {
97575115Sfenner			if (i > ep - cp) {
97675115Sfenner				printf("???");
97775115Sfenner				break;
97875115Sfenner			}
97975115Sfenner			while (i-- && cp < ep) {
98075115Sfenner				safeputchar(*cp);
98175115Sfenner				cp++;
98275115Sfenner			}
98375115Sfenner			if (cp + 1 < ep && *cp)
98475115Sfenner				printf(".");
98575115Sfenner		} else {
98675115Sfenner			if (cp == ep) {
98775115Sfenner				/* FQDN */
98875115Sfenner				printf(".");
98975115Sfenner			} else if (cp + 1 == ep && *cp == '\0') {
99075115Sfenner				/* truncated */
99175115Sfenner			} else {
99275115Sfenner				/* invalid */
99375115Sfenner				printf("???");
99475115Sfenner			}
99575115Sfenner			break;
99675115Sfenner		}
99775115Sfenner	}
99875115Sfenner	printf("\"");
99975115Sfenner}
100075115Sfenner
1001127668Sbmsstatic void
1002127668Sbmsicmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
100375115Sfenner{
100475115Sfenner	struct icmp6_nodeinfo *ni6;
100575115Sfenner	struct icmp6_hdr *dp;
100675115Sfenner	const u_char *cp;
1007127668Sbms	size_t siz, i;
100875115Sfenner	int needcomma;
100975115Sfenner
1010127668Sbms	if (ep < bp)
1011127668Sbms		return;
101275115Sfenner	dp = (struct icmp6_hdr *)bp;
101375115Sfenner	ni6 = (struct icmp6_nodeinfo *)bp;
101475115Sfenner	siz = ep - bp;
101575115Sfenner
101675115Sfenner	switch (ni6->ni_type) {
101775115Sfenner	case ICMP6_NI_QUERY:
101875115Sfenner		if (siz == sizeof(*dp) + 4) {
101975115Sfenner			/* KAME who-are-you */
1020146773Ssam			printf(" who-are-you request");
102175115Sfenner			break;
102275115Sfenner		}
1023146773Ssam		printf(" node information query");
102475115Sfenner
102575115Sfenner		TCHECK2(*dp, sizeof(*ni6));
102675115Sfenner		ni6 = (struct icmp6_nodeinfo *)dp;
102775115Sfenner		printf(" (");	/*)*/
1028127668Sbms		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
102975115Sfenner		case NI_QTYPE_NOOP:
103075115Sfenner			printf("noop");
103175115Sfenner			break;
103275115Sfenner		case NI_QTYPE_SUPTYPES:
103375115Sfenner			printf("supported qtypes");
1034127668Sbms			i = EXTRACT_16BITS(&ni6->ni_flags);
103575115Sfenner			if (i)
103675115Sfenner				printf(" [%s]", (i & 0x01) ? "C" : "");
103775115Sfenner			break;
103875115Sfenner			break;
103975115Sfenner		case NI_QTYPE_FQDN:
104075115Sfenner			printf("DNS name");
104175115Sfenner			break;
104275115Sfenner		case NI_QTYPE_NODEADDR:
104375115Sfenner			printf("node addresses");
104475115Sfenner			i = ni6->ni_flags;
104575115Sfenner			if (!i)
104675115Sfenner				break;
104775115Sfenner			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
104875115Sfenner			printf(" [%s%s%s%s%s%s]",
104975115Sfenner			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
105075115Sfenner			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
105175115Sfenner			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
105275115Sfenner			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
105375115Sfenner			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
105475115Sfenner			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
105575115Sfenner			break;
105675115Sfenner		default:
105775115Sfenner			printf("unknown");
105875115Sfenner			break;
105975115Sfenner		}
106075115Sfenner
106175115Sfenner		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
106275115Sfenner		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
106375115Sfenner			if (siz != sizeof(*ni6))
106475115Sfenner				if (vflag)
106575115Sfenner					printf(", invalid len");
106675115Sfenner			/*(*/
106775115Sfenner			printf(")");
106875115Sfenner			break;
106975115Sfenner		}
107075115Sfenner
107175115Sfenner
107275115Sfenner		/* XXX backward compat, icmp-name-lookup-03 */
107375115Sfenner		if (siz == sizeof(*ni6)) {
107475115Sfenner			printf(", 03 draft");
107575115Sfenner			/*(*/
107675115Sfenner			printf(")");
107775115Sfenner			break;
107875115Sfenner		}
107975115Sfenner
108075115Sfenner		switch (ni6->ni_code) {
108175115Sfenner		case ICMP6_NI_SUBJ_IPV6:
108275115Sfenner			if (!TTEST2(*dp,
108375115Sfenner			    sizeof(*ni6) + sizeof(struct in6_addr)))
108475115Sfenner				break;
108575115Sfenner			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
108675115Sfenner				if (vflag)
108775115Sfenner					printf(", invalid subject len");
108875115Sfenner				break;
108975115Sfenner			}
109075115Sfenner			printf(", subject=%s",
109175115Sfenner			    getname6((const u_char *)(ni6 + 1)));
109275115Sfenner			break;
109375115Sfenner		case ICMP6_NI_SUBJ_FQDN:
109475115Sfenner			printf(", subject=DNS name");
109575115Sfenner			cp = (const u_char *)(ni6 + 1);
109675115Sfenner			if (cp[0] == ep - cp - 1) {
109775115Sfenner				/* icmp-name-lookup-03, pascal string */
109875115Sfenner				if (vflag)
109975115Sfenner					printf(", 03 draft");
110075115Sfenner				cp++;
110175115Sfenner				printf(", \"");
110275115Sfenner				while (cp < ep) {
110375115Sfenner					safeputchar(*cp);
110475115Sfenner					cp++;
110575115Sfenner				}
110675115Sfenner				printf("\"");
110775115Sfenner			} else
110875115Sfenner				dnsname_print(cp, ep);
110975115Sfenner			break;
111075115Sfenner		case ICMP6_NI_SUBJ_IPV4:
111175115Sfenner			if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
111275115Sfenner				break;
111375115Sfenner			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
111475115Sfenner				if (vflag)
111575115Sfenner					printf(", invalid subject len");
111675115Sfenner				break;
111775115Sfenner			}
111875115Sfenner			printf(", subject=%s",
111975115Sfenner			    getname((const u_char *)(ni6 + 1)));
112075115Sfenner			break;
112175115Sfenner		default:
112275115Sfenner			printf(", unknown subject");
112375115Sfenner			break;
112475115Sfenner		}
112575115Sfenner
112675115Sfenner		/*(*/
112775115Sfenner		printf(")");
112875115Sfenner		break;
112975115Sfenner
113075115Sfenner	case ICMP6_NI_REPLY:
113175115Sfenner		if (icmp6len > siz) {
113275115Sfenner			printf("[|icmp6: node information reply]");
113375115Sfenner			break;
113475115Sfenner		}
113575115Sfenner
113675115Sfenner		needcomma = 0;
113775115Sfenner
113875115Sfenner		ni6 = (struct icmp6_nodeinfo *)dp;
1139146773Ssam		printf(" node information reply");
114075115Sfenner		printf(" (");	/*)*/
114175115Sfenner		switch (ni6->ni_code) {
114275115Sfenner		case ICMP6_NI_SUCCESS:
114375115Sfenner			if (vflag) {
114475115Sfenner				printf("success");
114575115Sfenner				needcomma++;
114675115Sfenner			}
114775115Sfenner			break;
114875115Sfenner		case ICMP6_NI_REFUSED:
114975115Sfenner			printf("refused");
115075115Sfenner			needcomma++;
115175115Sfenner			if (siz != sizeof(*ni6))
115275115Sfenner				if (vflag)
115375115Sfenner					printf(", invalid length");
115475115Sfenner			break;
115575115Sfenner		case ICMP6_NI_UNKNOWN:
115675115Sfenner			printf("unknown");
115775115Sfenner			needcomma++;
115875115Sfenner			if (siz != sizeof(*ni6))
115975115Sfenner				if (vflag)
116075115Sfenner					printf(", invalid length");
116175115Sfenner			break;
116275115Sfenner		}
116375115Sfenner
116475115Sfenner		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
116575115Sfenner			/*(*/
116675115Sfenner			printf(")");
116775115Sfenner			break;
116875115Sfenner		}
116975115Sfenner
1170127668Sbms		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
117175115Sfenner		case NI_QTYPE_NOOP:
117275115Sfenner			if (needcomma)
117375115Sfenner				printf(", ");
117475115Sfenner			printf("noop");
117575115Sfenner			if (siz != sizeof(*ni6))
117675115Sfenner				if (vflag)
117775115Sfenner					printf(", invalid length");
117875115Sfenner			break;
117975115Sfenner		case NI_QTYPE_SUPTYPES:
118075115Sfenner			if (needcomma)
118175115Sfenner				printf(", ");
118275115Sfenner			printf("supported qtypes");
1183127668Sbms			i = EXTRACT_16BITS(&ni6->ni_flags);
118475115Sfenner			if (i)
118575115Sfenner				printf(" [%s]", (i & 0x01) ? "C" : "");
118675115Sfenner			break;
118775115Sfenner		case NI_QTYPE_FQDN:
118875115Sfenner			if (needcomma)
118975115Sfenner				printf(", ");
119075115Sfenner			printf("DNS name");
119175115Sfenner			cp = (const u_char *)(ni6 + 1) + 4;
119275115Sfenner			if (cp[0] == ep - cp - 1) {
119375115Sfenner				/* icmp-name-lookup-03, pascal string */
119475115Sfenner				if (vflag)
119575115Sfenner					printf(", 03 draft");
119675115Sfenner				cp++;
119775115Sfenner				printf(", \"");
119875115Sfenner				while (cp < ep) {
119975115Sfenner					safeputchar(*cp);
120075115Sfenner					cp++;
120175115Sfenner				}
120275115Sfenner				printf("\"");
120375115Sfenner			} else
120475115Sfenner				dnsname_print(cp, ep);
1205127668Sbms			if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
120675115Sfenner				printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
120775115Sfenner			break;
120875115Sfenner		case NI_QTYPE_NODEADDR:
120975115Sfenner			if (needcomma)
121075115Sfenner				printf(", ");
121175115Sfenner			printf("node addresses");
121275115Sfenner			i = sizeof(*ni6);
121375115Sfenner			while (i < siz) {
121475115Sfenner				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
121575115Sfenner					break;
121675115Sfenner				printf(" %s", getname6(bp + i));
121775115Sfenner				i += sizeof(struct in6_addr);
1218127668Sbms				printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
121975115Sfenner				i += sizeof(int32_t);
122075115Sfenner			}
122175115Sfenner			i = ni6->ni_flags;
122275115Sfenner			if (!i)
122375115Sfenner				break;
122475115Sfenner			printf(" [%s%s%s%s%s%s%s]",
122575115Sfenner			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
122675115Sfenner			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
122775115Sfenner			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
122875115Sfenner			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
122975115Sfenner			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
123075115Sfenner			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
123175115Sfenner			    (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
123275115Sfenner			break;
123375115Sfenner		default:
123475115Sfenner			if (needcomma)
123575115Sfenner				printf(", ");
123675115Sfenner			printf("unknown");
123775115Sfenner			break;
123875115Sfenner		}
123975115Sfenner
124075115Sfenner		/*(*/
124175115Sfenner		printf(")");
124275115Sfenner		break;
124375115Sfenner	}
124456893Sfenner	return;
124575115Sfenner
124675115Sfennertrunc:
124775115Sfenner	fputs("[|icmp6]", stdout);
124856893Sfenner}
124975115Sfenner
1250127668Sbmsstatic void
1251127668Sbmsicmp6_rrenum_print(const u_char *bp, const u_char *ep)
125275115Sfenner{
125375115Sfenner	struct icmp6_router_renum *rr6;
125475115Sfenner	const char *cp;
125575115Sfenner	struct rr_pco_match *match;
125675115Sfenner	struct rr_pco_use *use;
125775115Sfenner	char hbuf[NI_MAXHOST];
125875115Sfenner	int n;
125975115Sfenner
1260127668Sbms	if (ep < bp)
1261127668Sbms		return;
126275115Sfenner	rr6 = (struct icmp6_router_renum *)bp;
126375115Sfenner	cp = (const char *)(rr6 + 1);
126475115Sfenner
126575115Sfenner	TCHECK(rr6->rr_reserved);
126675115Sfenner	switch (rr6->rr_code) {
126775115Sfenner	case ICMP6_ROUTER_RENUMBERING_COMMAND:
126875115Sfenner		printf("router renum: command");
126975115Sfenner		break;
127075115Sfenner	case ICMP6_ROUTER_RENUMBERING_RESULT:
127175115Sfenner		printf("router renum: result");
127275115Sfenner		break;
127375115Sfenner	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
127475115Sfenner		printf("router renum: sequence number reset");
127575115Sfenner		break;
127675115Sfenner	default:
127775115Sfenner		printf("router renum: code-#%d", rr6->rr_code);
127875115Sfenner		break;
127975115Sfenner	}
128075115Sfenner
1281127668Sbms	printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
128275115Sfenner
128375115Sfenner	if (vflag) {
128475115Sfenner#define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
128575115Sfenner		printf("[");	/*]*/
128675115Sfenner		if (rr6->rr_flags) {
128775115Sfenner			printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
128875115Sfenner			    F(ICMP6_RR_FLAGS_REQRESULT, "R"),
128998524Sfenner			    F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
129075115Sfenner			    F(ICMP6_RR_FLAGS_SPECSITE, "S"),
129175115Sfenner			    F(ICMP6_RR_FLAGS_PREVDONE, "P"));
129275115Sfenner		}
129375115Sfenner		printf("seg=%u,", rr6->rr_segnum);
1294190207Srpaulo		printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay));
129575115Sfenner		if (rr6->rr_reserved)
1296190207Srpaulo			printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved));
129775115Sfenner		/*[*/
129875115Sfenner		printf("]");
129975115Sfenner#undef F
130075115Sfenner	}
130175115Sfenner
130275115Sfenner	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
130375115Sfenner		match = (struct rr_pco_match *)cp;
130475115Sfenner		cp = (const char *)(match + 1);
130575115Sfenner
130675115Sfenner		TCHECK(match->rpm_prefix);
130775115Sfenner
130898524Sfenner		if (vflag > 1)
130975115Sfenner			printf("\n\t");
131075115Sfenner		else
131175115Sfenner			printf(" ");
131275115Sfenner		printf("match(");	/*)*/
131375115Sfenner		switch (match->rpm_code) {
131475115Sfenner		case RPM_PCO_ADD:	printf("add"); break;
131575115Sfenner		case RPM_PCO_CHANGE:	printf("change"); break;
131675115Sfenner		case RPM_PCO_SETGLOBAL:	printf("setglobal"); break;
131775115Sfenner		default:		printf("#%u", match->rpm_code); break;
131875115Sfenner		}
131975115Sfenner
132075115Sfenner		if (vflag) {
132175115Sfenner			printf(",ord=%u", match->rpm_ordinal);
132275115Sfenner			printf(",min=%u", match->rpm_minlen);
132375115Sfenner			printf(",max=%u", match->rpm_maxlen);
132475115Sfenner		}
132575115Sfenner		if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
132675115Sfenner			printf(",%s/%u", hbuf, match->rpm_matchlen);
132775115Sfenner		else
132875115Sfenner			printf(",?/%u", match->rpm_matchlen);
132975115Sfenner		/*(*/
133075115Sfenner		printf(")");
133175115Sfenner
133275115Sfenner		n = match->rpm_len - 3;
133375115Sfenner		if (n % 4)
133475115Sfenner			goto trunc;
133575115Sfenner		n /= 4;
133675115Sfenner		while (n-- > 0) {
133775115Sfenner			use = (struct rr_pco_use *)cp;
133875115Sfenner			cp = (const char *)(use + 1);
133975115Sfenner
134075115Sfenner			TCHECK(use->rpu_prefix);
134175115Sfenner
134298524Sfenner			if (vflag > 1)
134375115Sfenner				printf("\n\t");
134475115Sfenner			else
134575115Sfenner				printf(" ");
134675115Sfenner			printf("use(");	/*)*/
134775115Sfenner			if (use->rpu_flags) {
134875115Sfenner#define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
134975115Sfenner				printf("%s%s,",
135075115Sfenner				    F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
135175115Sfenner				    F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
135275115Sfenner#undef F
135375115Sfenner			}
135475115Sfenner			if (vflag) {
135575115Sfenner				printf("mask=0x%x,", use->rpu_ramask);
135675115Sfenner				printf("raflags=0x%x,", use->rpu_raflags);
135775115Sfenner				if (~use->rpu_vltime == 0)
135875115Sfenner					printf("vltime=infty,");
135975115Sfenner				else
136075115Sfenner					printf("vltime=%u,",
1361127668Sbms					    EXTRACT_32BITS(&use->rpu_vltime));
136275115Sfenner				if (~use->rpu_pltime == 0)
136375115Sfenner					printf("pltime=infty,");
136475115Sfenner				else
136575115Sfenner					printf("pltime=%u,",
1366127668Sbms					    EXTRACT_32BITS(&use->rpu_pltime));
136775115Sfenner			}
136875115Sfenner			if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
136975115Sfenner			    sizeof(hbuf)))
137075115Sfenner				printf("%s/%u/%u", hbuf, use->rpu_uselen,
137175115Sfenner				    use->rpu_keeplen);
137275115Sfenner			else
137375115Sfenner				printf("?/%u/%u", use->rpu_uselen,
137475115Sfenner				    use->rpu_keeplen);
137575115Sfenner			/*(*/
137675115Sfenner			printf(")");
137775115Sfenner		}
137875115Sfenner	}
137975115Sfenner
138075115Sfenner	return;
138175115Sfenner
138275115Sfennertrunc:
138375115Sfenner	fputs("[|icmp6]", stdout);
138475115Sfenner}
138575115Sfenner
138656893Sfenner#endif /* INET6 */
1387